Hi, recently I needed chpass(1) to do change arbitrary fields without exporting intelligence to the caller (i.e., getting the passwd entry, changing the appropriate field, reput with -a). It seemed like this work was completely prepared, but not done. Why? Attached are diffs that introduce option -f to change exactly that, you can then set the fields, e.g. `chpass -l -f shell:/bin/sh gnrp`. Tested only locally, I don't have an yp setup. Perhaps it's of some use or you can tell my why I don't want to have it that way (as I said, it seemed to be prepared). Regards, Julian
Index: chpass.1 =================================================================== RCS file: /cvsroot/src/usr.bin/chpass/chpass.1,v retrieving revision 1.23 diff -u -r1.23 chpass.1 --- chpass.1 7 Oct 2006 20:09:09 -0000 1.23 +++ chpass.1 28 Nov 2011 18:23:59 -0000 @@ -48,6 +48,14 @@ .Op Fl s Ar newshell .Op Fl y .Op user +.Nm chpass +.Op Fl f Ar option:value +.Op Fl y +.Op user +.Nm chpass +.Op Fl f Ar option:value +.Op Fl l +.Op user .Sh DESCRIPTION .Nm allows editing of the user database information associated @@ -69,11 +77,21 @@ .Pq Dq \&: separated list of all the user database fields, although they may be empty. +.It Fl f +Set the field given by +.Ar option +to value +.Ar value . +If there is a space in the name of the option, you can either enquote it in +brackets (i.e. passing still as one argument) or replace the space either by an +underscore or just omit it. .It Fl s The .Fl s option attempts to change the user's shell to .Ar newshell . +This is maintained for compataibility reasons, actually it does the same as +.Fl f Ar shell:newshell . .It Fl l This option causes the password to be updated only in the local password file. @@ -240,6 +258,14 @@ .It Pa /etc/shells The list of approved shells .El +.Sh EXAMPLES +Set home directory for user +.Ar john +to +.Ar /home/john . +This can be achieved in two different ways +.D1 chpass Fl f Ar Home_Directory:/bin/sh Ar john +.D1 chpass Fl f Ar \*qHome Directory:/bin/sh\*q Ar john .Sh SEE ALSO .Xr finger 1 , .Xr login 1 ,
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 18:28:39 -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,20 @@ #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; + arg = calloc(1, sizeof(char)*(7 + strlen(optarg))); + arg = strcpy(arg, "shell:"); + arg = strncat(arg, optarg, sizeof(arg) - 7); + break; + case 'f': + op = SINGLEENTRY; arg = optarg; break; case 'l': @@ -182,7 +188,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 +210,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 +327,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); }
Index: chpass.h =================================================================== RCS file: /cvsroot/src/usr.bin/chpass/chpass.h,v retrieving revision 1.13 diff -u -r1.13 chpass.h --- chpass.h 29 Aug 2011 14:08:39 -0000 1.13 +++ chpass.h 28 Nov 2011 18:24:31 -0000 @@ -35,8 +35,11 @@ typedef struct _entry { const char *prompt; - int (*func)(const char *, struct passwd *, struct _entry *), restricted, len; - const char *except, *save; + int (*func)(const char *, struct passwd *, struct _entry *); + int restricted; + int len; + const char *except; + const char *save; } ENTRY; extern int use_yp;
Index: table.c =================================================================== RCS file: /cvsroot/src/usr.bin/chpass/table.c,v retrieving revision 1.7 diff -u -r1.7 table.c --- table.c 11 Apr 2009 12:10:02 -0000 1.7 +++ table.c 28 Nov 2011 18:23:42 -0000 @@ -45,6 +45,9 @@ char e1[] = ": "; char e2[] = ":,"; +/* Be careful when changing something here (though that might never happen...). + * The option names may not contain underscores, or the code in chpass.c needs + * to be changed! */ ENTRY list[] = { { "login", p_login, 1, 5, e1, NULL }, { "password", p_passwd, 1, 8, e1, NULL },
Attachment:
signature.asc
Description: PGP signature