On Tue, Sep 11, 2012 at 04:46:57PM +0200, Antoine Jacoutot wrote: > On Mon, Sep 10, 2012 at 05:01:13PM +0200, Antoine Jacoutot wrote: > > Hi. > > > > This diff adds 2 new options to usermod(8): > > -U to unlock a user's password > > -Z to lock a user's password > > > > In effect locking/unlocking the password means to add a '!' in front of > > the encrypted entry in master.passwd. > > Note that this disable the _password_ not the account of course (you > > could still connect using ssh+key for e.g.). > > > > That said, I have some use for it and would like to be able to have this > > if at all possible. > > Behavior is basically the same as Linux's usermod(8) except that I am > > using -Z for locking the password (-Z is for SElinux in Linux land and > > -L is used instead but we use it ourselves for the login class). > > Ok new diff that does something slightly different. > Instead of putting a '!' in front of the password (which confused people), > lock/unlock means appending/removing a dash to the user's login shell. > While this is non standard behavior (but as I mentionned in a previous mail, > usermod(8) is already not standard accross unices) I think it is better > because: > - account is locked, period (no local login, no remote login -- no surprise > for tedu ;-) ) > - no values are touched > (e.g. one could disable an account by using 'usermod -e 1' but when he > wants to re-enable the account he'll be forced to change the expiration time)
New diff which also put a '*' in front of the encrypted password; i.e. both pre and post-auth become locked (req. by Theo). With some man page tweak from jmc. Index: user.c =================================================================== RCS file: /cvs/src/usr.sbin/user/user.c,v retrieving revision 1.90 diff -u -r1.90 user.c --- user.c 29 Jan 2012 08:38:54 -0000 1.90 +++ user.c 11 Sep 2012 16:20:11 -0000 @@ -100,7 +100,9 @@ F_UID = 0x0400, F_USERNAME = 0x0800, F_CLASS = 0x1000, - F_SETSECGROUP = 0x4000 + F_SETSECGROUP = 0x4000, + F_ACCTLOCK = 0x8000, + F_ACCTUNLOCK = 0x10000 }; #define CONFFILE "/etc/usermgmt.conf" @@ -1339,11 +1341,17 @@ struct group *grp; const char *homedir; char buf[LINE_MAX]; + char acctlock_str[] = "-"; + char pwlock_str[] = "*"; + char pw_len[PasswordLength + 1]; + char shell_len[MaxShellNameLen]; size_t colonc, loginc; size_t cc; FILE *master; char newdir[MaxFileNameLen]; char *colon; + char *pw_tmp = NULL; + char *shell_tmp = NULL; int len; int masterfd; int ptmpfd; @@ -1359,6 +1367,10 @@ if (!is_local(login_name, _PATH_MASTERPASSWD)) { errx(EXIT_FAILURE, "User `%s' must be a local user", login_name); } + if (up != NULL) { + if ((up->u_flags & (F_ACCTLOCK | F_ACCTUNLOCK)) && (pwp->pw_uid == 0)) + errx(EXIT_FAILURE, "(un)locking is not supported for the `%s' account", pwp->pw_name); + } /* keep dir name in case we need it for '-m' */ homedir = pwp->pw_dir; @@ -1410,6 +1422,48 @@ pwp->pw_passwd = up->u_password; } } + if (up->u_flags & F_ACCTLOCK) { + /* lock the account */ + if (strncmp(pwp->pw_shell+strlen(pwp->pw_shell) - 1, acctlock_str+strlen(acctlock_str) - 1, sizeof(acctlock_str) - 1) != 0) { + shell_tmp = malloc(strlen(pwp->pw_shell) + sizeof(acctlock_str)); + if (shell_tmp == NULL) { + (void) close(ptmpfd); + pw_abort(); + errx(EXIT_FAILURE, "account lock: cannot allocate memory"); + } + strlcpy(shell_tmp, pwp->pw_shell, sizeof(shell_len)); + strlcat(shell_tmp, acctlock_str, sizeof(shell_len)); + pwp->pw_shell = shell_tmp; + } + /* lock the password */ + if (strncmp(pwp->pw_passwd, pwlock_str, sizeof(pwlock_str)-1) != 0) { + pw_tmp = malloc(strlen(pwp->pw_passwd) + sizeof(pwlock_str)); + if (pw_tmp == NULL) { + (void) close(ptmpfd); + pw_abort(); + errx(EXIT_FAILURE, "password lock: cannot allocate memory"); + } + strlcpy(pw_tmp, pwlock_str, sizeof(pw_len)); + strlcat(pw_tmp, pwp->pw_passwd, sizeof(pw_len)); + pwp->pw_passwd = pw_tmp; + } + } + if (up->u_flags & F_ACCTUNLOCK) { + /* unlock the password */ + if (strncmp(pwp->pw_passwd, pwlock_str, sizeof(pwlock_str)-1) == 0) + pwp->pw_passwd += sizeof(pwlock_str)-1; + /* unlock the account */ + if (strncmp(pwp->pw_shell+strlen(pwp->pw_shell) - 1, acctlock_str+strlen(acctlock_str) - 1, sizeof(acctlock_str) - 1) == 0) { + shell_tmp = malloc(strlen(pwp->pw_shell) - sizeof(acctlock_str)); + if (shell_tmp == NULL) { + (void) close(ptmpfd); + pw_abort(); + errx(EXIT_FAILURE, "unlock: cannot allocate memory"); + } + strlcpy(shell_tmp, pwp->pw_shell, sizeof(shell_tmp) + 1); + pwp->pw_shell = shell_tmp; + } + } if (up->u_flags & F_UID) { /* check uid isn't already allocated */ if (!(up->u_flags & F_DUPUID) && getpwuid((uid_t)(up->u_uid)) != NULL) { @@ -1547,6 +1601,10 @@ } } (void) close(ptmpfd); + if (pw_tmp) + FREE(pw_tmp); + if (shell_tmp) + FREE(shell_tmp); if (up != NULL && strcmp(login_name, newlogin) == 0) rval = pw_mkdb(login_name, 0); else @@ -1617,7 +1675,7 @@ "[-p password] [-r low..high]\n" " [-s shell] [-u uid] user\n", prog); } else if (strcmp(prog, "usermod") == 0) { - (void) fprintf(stderr, "usage: %s [-mov] " + (void) fprintf(stderr, "usage: %s [-moUvZ] " "[-c comment] [-d home-directory] [-e expiry-time]\n" " [-f inactive-time] " "[-G secondary-group[,group,...]]\n" @@ -1788,7 +1846,7 @@ free(u.u_primgrp); u.u_primgrp = NULL; have_new_user = 0; - while ((c = getopt(argc, argv, "G:L:S:c:d:e:f:g:l:mop:s:u:v")) != -1) { + while ((c = getopt(argc, argv, "G:L:S:UZc:d:e:f:g:l:mop:s:u:v")) != -1) { switch(c) { case 'G': while ((u.u_groupv[u.u_groupc] = strsep(&optarg, ",")) != NULL && @@ -1814,6 +1872,12 @@ } u.u_flags |= F_SETSECGROUP; break; + case 'U': + u.u_flags |= F_ACCTUNLOCK; + break; + case 'Z': + u.u_flags |= F_ACCTLOCK; + break; case 'c': memsave(&u.u_comment, optarg, strlen(optarg)); u.u_flags |= F_COMMENT; @@ -1883,6 +1947,10 @@ } if ((u.u_flags & F_SECGROUP) && (u.u_flags & F_SETSECGROUP)) errx(EXIT_FAILURE, "options 'G' and 'S' are mutually exclusive"); + if ((u.u_flags & F_ACCTLOCK) && (u.u_flags & F_ACCTUNLOCK)) + errx(EXIT_FAILURE, "options 'U' and 'Z' are mutually exclusive"); + if ((u.u_flags & F_PASSWORD) && (u.u_flags & (F_ACCTLOCK | F_ACCTUNLOCK))) + errx(EXIT_FAILURE, "options 'U' or 'Z' with 'p' are mutually exclusive"); argc -= optind; argv += optind; if (argc != 1) { Index: usermod.8 =================================================================== RCS file: /cvs/src/usr.sbin/user/usermod.8,v retrieving revision 1.28 diff -u -r1.28 usermod.8 --- usermod.8 28 Jan 2012 14:25:45 -0000 1.28 +++ usermod.8 11 Sep 2012 16:20:11 -0000 @@ -40,7 +40,7 @@ .Sh SYNOPSIS .Nm usermod .Bk -words -.Op Fl mov +.Op Fl moUvZ .Op Fl c Ar comment .Op Fl d Ar home-directory .Op Fl e Ar expiry-time @@ -199,6 +199,17 @@ See .Xr usermgmt.conf 5 for more details. +.It Fl U +Unlock the account by removing the trailing +.Ql \&- +from the user's shell and the +.Ql \&* +in front of his password. +.Fl U +and +.Fl Z +are mutually exclusive and cannot be used with +.Fl p . .It Fl u Ar uid Specifies a new UID for the user. Boundaries for this value can be preset for all users @@ -212,6 +223,17 @@ for more details. .It Fl v Enables verbose mode - explain the commands as they are executed. +.It Fl Z +Lock the account by appending a +.Ql \&- +to the user's shell and putting a +.Ql \&* +in front of his password. +.Fl Z +and +.Fl U +are mutually exclusive and cannot be used with +.Fl p . .El .Pp Once the information has been verified,