> --nextPart2143034.hU0dofkB2d
> 
> Actually, once you've got your head around the fact that nobody is
> there to hold your hand, it isn't too bad. The attached trial program
> has been tested and is always safe. I'm going to commit this to
> XForms cvs.
>

Unfrotunately Angus' fix is buggy too, because at least on some systems size_t
is unsigned (linux being a prime example). If so and fname_size>fname_capacity
then the last strncat gets a huge limit (more than INT_MAX) and the buffer
overflow will works anyway. Also it could be attacked by integer overflow,
albeit not on most systems.

Also Angus put the terminator in too early---unless strncat guarantees
termination tje '\0' might get clobbered. A suggested alternative, which
returns 1 if everything is OK and 0 if fname is too small, if attached. main
has been changed to reflect this change, without which people could use
overflows to get unexpected filenames.

I have replaced most of the str* functions with snprintf, which makes the code
*much* simpler. You could simplify it even more if you assumed everyone's
snprintf followed C99.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>

typedef struct {
        char * output_dir;
} FD_Opt;

FD_Opt fdopt;

static char const *
filename_only(char const * filename)
{
    char const * ptr = strrchr(filename, '/');
    if (ptr)
        return ptr+1;
    return filename;
}

static int
build_fname(char * fname, size_t fname_capacity,
            char const * filename, char const * ext)
{
    static const char null='\0';
    char const * const only_filename = filename_only(filename);
    size_t l;
    const char *dname;
    const char *slash;
    int npc;

    slash=&null;
    if (fdopt.output_dir) {     
        l = strlen(fdopt.output_dir);
        if (fdopt.output_dir[l-1]!='/')
            slash="/";
        dname=fdopt.output_dir;
    }
    else
        dname=&null;

    npc=snprintf(fname, fname_capacity, "%s%s%s", dname, slash,
                 only_filename);
    /* npc==-1 is glibc <= 2.0.6 and npc >= fname_capacity is C99 */
    return  (npc==-1 || npc>= fname_capacity) ? 0 : 1;
}

int main(int argc, char * argv[])
{
        size_t const fname_capacity = 10;
        char fname[fname_capacity + 1];

        fdopt.output_dir = 0;
        if (argc > 1) {
                fdopt.output_dir = (char *)malloc(strlen(argv[1]) + 1);
                strcpy(fdopt.output_dir, argv[1]);
        }

        if (build_fname(fname, fname_capacity, "foo/bar/bazabcde", ".h"))
            printf("Output fname is \"%s\"\n", fname);
        else
        {
            fprintf(stderr, "%s: output file name too big.\n", argv[0]);
            exit(EXIT_FAILURE);
        }

        return 0;
}       
Duncan (-:
"software industry, the: unique industry where selling substandard goods is
legal and you can charge extra for fixing the problems."


Reply via email to