> Index: gen/getusershell.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/gen/getusershell.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 getusershell.c
> --- gen/getusershell.c        14 Sep 2015 16:09:13 -0000      1.16
> +++ gen/getusershell.c        5 Dec 2015 16:08:56 -0000
> @@ -84,48 +86,52 @@ setusershell(void)
>  static char **
>  initshells(void)
>  {
> -     char **sp, *cp;
> +     char buf[PATH_MAX];
> +     int nshells = 0, nalloc;

I would prefer size_t for nshells and nalloc.

> +     char *cp;
>       FILE *fp;
> -     struct stat statb;
>  
>       free(shells);
>       shells = NULL;
> -     free(strings);
> -     strings = NULL;
> +
>       if ((fp = fopen(_PATH_SHELLS, "re")) == NULL)
>               return (okshells);
> -     if (fstat(fileno(fp), &statb) == -1) {
> -             (void)fclose(fp);
> -             return (okshells);
> -     }
> -     if (statb.st_size > SIZE_MAX) {
> -             (void)fclose(fp);
> -             return (okshells);
> -     }
> -     if ((strings = malloc((size_t)statb.st_size)) == NULL) {
> -             (void)fclose(fp);
> -             return (okshells);
> -     }
> -     shells = calloc((size_t)(statb.st_size / 3 + 2), sizeof (char *));
> -     if (shells == NULL) {
> -             (void)fclose(fp);
> -             free(strings);
> -             strings = NULL;
> -             return (okshells);
> -     }
> -     sp = shells;
> -     cp = strings;
> -     while (fgets(cp, PATH_MAX + 1, fp) != NULL) {
> +
> +     nalloc = 10; // just an initial guess
> +     nshells = 0;
> +     shells = reallocarray(NULL, nalloc, sizeof (char *));
> +     if (shells == NULL)
> +             goto fail;
> +     while ((cp = fgets(buf, sizeof(buf), fp)) != NULL) {

We already have to dynamically allocate memory anyway, so getline() would
fix some issues we could face while parsing files. The buffer is PATH_MAX
bytes long, which should be sufficient, but if a comment is PATH_MAX + x
bytes in size, we would parse the "x" part as a real path due to fgets'
truncation/wrapping.

>               while (*cp != '#' && *cp != '/' && *cp != '\0')
>                       cp++;
>               if (*cp == '#' || *cp == '\0')
>                       continue;
> -             *sp++ = cp;
> +             if (!(shells[nshells] = strdup(cp)))
> +                     goto fail;
> +             cp = shells[nshells];
>               while (!isspace((unsigned char)*cp) && *cp != '#' && *cp != 
> '\0')
>                       cp++;
>               *cp++ = '\0';

And I still think that the current code is a bit too permissive in parsing
things. I mean what's the point in allowing lines like:

sometextwithoutspace/bin/ksh should be used for logins # seriously!

Which would result in /bin/ksh, by the way.

Didn't notice the consequences that arise by keeping the descriptor open,
so I'm fine with an alternative approach. Yet we might make the code a
bit easier to review by not allowing such weird lines. What it should
expect and enforce:

- a valid line has to start with a slash
- comments are chopped off
- comments are supposed to be at the beginning of a line

So if somebody writes "/bin/ksh # comment", that actually leads to "/bin/ksh ",
with an additional whitespace at the end. Currently we couldn't even specify a
shell with a whitespace in its path.


Tobias

Reply via email to