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