Tobias Stoeckmann wrote:
> 
> 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.

ok. i was going to leave the behavior alone, but we can fix that too.

- use getline to read lines of any length.
- only consider lines that start with a /.
- truncate lines after a #, but not after spaces.


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 18:24:33 -0000
@@ -28,14 +28,13 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/stat.h>
-
 #include <ctype.h>
 #include <limits.h>
 #include <paths.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 /*
@@ -44,7 +43,7 @@
  */
 
 static char *okshells[] = { _PATH_BSHELL, _PATH_CSHELL, _PATH_KSHELL, NULL };
-static char **curshell, **shells, *strings;
+static char **curshell, **shells;
 static char **initshells(void);
 
 /*
@@ -66,11 +65,14 @@ getusershell(void)
 void
 endusershell(void)
 {
-       
+       char **s;
+
+       if ((s = shells))
+               while (*s)
+                       free(*s++);
        free(shells);
        shells = NULL;
-       free(strings);
-       strings = NULL;
+
        curshell = NULL;
 }
 
@@ -84,48 +86,50 @@ setusershell(void)
 static char **
 initshells(void)
 {
-       char **sp, *cp;
+       size_t nshells, nalloc, linesize;
+       char *line;
        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) {
-               while (*cp != '#' && *cp != '/' && *cp != '\0')
-                       cp++;
-               if (*cp == '#' || *cp == '\0')
+
+       line = NULL;
+       nalloc = 10; // just an initial guess
+       nshells = 0;
+       shells = reallocarray(NULL, nalloc, sizeof (char *));
+       if (shells == NULL)
+               goto fail;
+       linesize = 0;
+       while (getline(&line, &linesize, fp) != -1) {
+               if (*line != '/')
                        continue;
-               *sp++ = cp;
-               while (!isspace((unsigned char)*cp) && *cp != '#' && *cp != 
'\0')
-                       cp++;
-               *cp++ = '\0';
+               line[strcspn(line, "#\n")] = '\0';
+               if (!(shells[nshells] = strdup(line)))
+                       goto fail;
+
+               nshells++;
+               if (nshells == nalloc) {
+                       char **new = reallocarray(shells, nalloc * 2, 
sizeof(char *));
+                       if (!new)
+                               goto fail;
+                       shells = new;
+                       nalloc *= 2;
+               }
        }
-       *sp = NULL;
+       free(line);
+       shells[nshells] = NULL;
        (void)fclose(fp);
        return (shells);
+
+fail:
+       free(line);
+       while (nshells)
+               free(shells[nshells--]);
+       free(shells);
+       shells = NULL;
+       (void)fclose(fp);
+       return (okshells);
 }

Reply via email to