tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Modify chpass(1) so it can set arbitrary fields



Hi,

> +     op = SINGLEENTRY;
> +     arg = calloc(1, sizeof(char)*(7 + strlen(optarg)));
> +     arg = strcpy(arg, "shell:");
> +     arg = strncat(arg, optarg, sizeof(arg) - 7);
> +     break;
> 
> First, you could use asprintf(3) instead of the calloc/string dance.
> 
> Second, unless mistaken, are you sure that your strncat() call is 
> correct? sizeof(arg) - 7 looks like a very nice overflow to me, at least 
> for anything that is 32 bits or lower. And for 64 bits, this would just 
> copy 1 byte.
of course you're right. I know I had asprintf here first, and then an PATH_MAX
array, but then changed it...

Attached is a version with asprintf.
Anyway, I just remembered this change is not possible anyway as users
couldn't change their login shells anymore, which is the current behaviour.

Regards, Julian
Index: chpass.c
===================================================================
RCS file: /cvsroot/src/usr.bin/chpass/chpass.c,v
retrieving revision 1.35
diff -u -r1.35 chpass.c
--- chpass.c    31 Aug 2011 16:24:57 -0000      1.35
+++ chpass.c    28 Nov 2011 21:31:38 -0000
@@ -80,13 +80,13 @@
 int
 main(int argc, char **argv)
 {
-       enum { NEWSH, LOADENTRY, EDITENTRY } op;
+       enum { LOADENTRY, EDITENTRY, SINGLEENTRY } op;
        struct passwd *pw, lpw, old_pw;
-       int ch, dfd, pfd, tfd;
+       int ch, dfd, pfd, tfd, i, ffound;
 #ifdef YP
        int yflag = 0;
 #endif
-       char *arg, *username = NULL;
+       char *arg, *opt, *username = NULL;
 
 #ifdef __GNUC__
        pw = NULL;              /* XXX gcc -Wuninitialized */
@@ -97,14 +97,19 @@
 #endif
 
        op = EDITENTRY;
-       while ((ch = getopt(argc, argv, "a:s:ly")) != -1)
+       while ((ch = getopt(argc, argv, "f:a:s:ly")) != -1)
                switch (ch) {
                case 'a':
                        op = LOADENTRY;
                        arg = optarg;
                        break;
                case 's':
-                       op = NEWSH;
+                       op = SINGLEENTRY;
+                       if (asprintf(&arg, "shell:%s", optarg) <= 0)
+                               errx(1, "asprintf");
+                       break;
+               case 'f':
+                       op = SINGLEENTRY;
                        arg = optarg;
                        break;
                case 'l':
@@ -182,7 +187,7 @@
                    "\tUse the -l flag to load local.");
 #endif
 
-       if (op == EDITENTRY || op == NEWSH) {
+       if (op == EDITENTRY || op == SINGLEENTRY) {
                if (username != NULL) {
                        pw = getpwnam(username);
                        if (pw == NULL)
@@ -204,12 +209,30 @@
                }
        }
 
-       if (op == NEWSH) {
-               /* protect p_shell -- it thinks NULL is /bin/sh */
-               if (!arg[0])
+       if (op == SINGLEENTRY) {
+               /* Separate option and value. */
+               opt = strsep(&arg, ":");
+               if (opt == NULL || !strlen(opt) | !strlen(arg))
                        usage();
-               if (p_shell(arg, pw, NULL))
-                       (*Pw_error)(NULL, 0, 1);
+               if (uid) // XXX: On the long run, let users change their own 
entries.
+                       baduser();
+
+               /* The option name has a space replaced by underscore. */
+               if (strchr(opt, '_'))
+                       *(strchr(opt, '_')) = ' ';
+
+               /* Search for the right field. */
+               ffound = 0;
+               for (i = 0; list[i].prompt != NULL; i++)
+                       if (!strcasecmp(opt, list[i].prompt)) {
+                               if (list[i].func(arg, pw, &list[i]))
+                                       (*Pw_error)(NULL, 0, 1);
+                               ffound = 1;
+                               break;
+                       }
+
+               if (!ffound)
+                       errx(1, "invalid field specification: %s", opt);
        }
 
        if (op == LOADENTRY) {
@@ -303,7 +326,10 @@
 
        (void)fprintf(stderr,
            "usage: %s [-a list] [-s shell] [-l] [user]\n"
-           "       %s [-a list] [-s shell] [-y] [user]\n",
+           "       %s [-a list] [-s shell] [-y] [user]\n"
+               "       %s [-f option:value] [-y] [user]\n"
+               "       %s [-f option:value] [-l] [user]\n",
+           getprogname(), getprogname(),
            getprogname(), getprogname());
        exit(1);
 }

Attachment: signature.asc
Description: PGP signature



Home | Main Index | Thread Index | Old Index