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,

Reply via email to