tech-userlevel archive

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

Modify chpass(1) so it can set arbitrary fields



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



Home | Main Index | Thread Index | Old Index