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)
Thanks to Stuart for the idea.
Thoughts?
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 13:38:12 -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,14 @@
struct group *grp;
const char *homedir;
char buf[LINE_MAX];
+ char locked_str[] = "-";
+ char shell_len[MaxShellNameLen];
size_t colonc, loginc;
size_t cc;
FILE *master;
char newdir[MaxFileNameLen];
char *colon;
+ char *shell_tmp = NULL;
int len;
int masterfd;
int ptmpfd;
@@ -1359,6 +1364,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)) && (login_name
== 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 +1419,35 @@
pwp->pw_passwd = up->u_password;
}
}
+ if (up->u_flags & F_ACCTLOCK) {
+ if (strncmp(pwp->pw_shell+strlen(pwp->pw_shell) - 1,
locked_str+strlen(locked_str) - 1, sizeof(locked_str) - 1) == 0) {
+ warnx("account '%s' is already locked",
pwp->pw_name);
+ } else {
+ shell_tmp = malloc(strlen(pwp->pw_shell) +
sizeof(locked_str));
+ if (shell_tmp == NULL) {
+ (void) close(ptmpfd);
+ pw_abort();
+ errx(EXIT_FAILURE, "lock: cannot
allocate memory");
+ }
+ strlcpy(shell_tmp, pwp->pw_shell,
sizeof(shell_len));
+ strlcat(shell_tmp, locked_str,
sizeof(shell_len));
+ pwp->pw_shell = shell_tmp;
+ }
+ }
+ if (up->u_flags & F_ACCTUNLOCK) {
+ if (strncmp(pwp->pw_shell+strlen(pwp->pw_shell) - 1,
locked_str+strlen(locked_str) - 1, sizeof(locked_str) - 1) != 0) {
+ warnx("account '%s' is not locked",
pwp->pw_name);
+ } else {
+ shell_tmp = malloc(strlen(pwp->pw_shell) -
sizeof(locked_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 +1585,8 @@
}
}
(void) close(ptmpfd);
+ if (shell_tmp)
+ FREE(shell_tmp);
if (up != NULL && strcmp(login_name, newlogin) == 0)
rval = pw_mkdb(login_name, 0);
else
@@ -1617,7 +1657,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 [-UZmov] "
"[-c comment] [-d home-directory] [-e expiry-time]\n"
" [-f inactive-time] "
"[-G secondary-group[,group,...]]\n"
@@ -1788,7 +1828,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 +1854,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 +1929,8 @@
}
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");
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 13:38:12 -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,14 @@
See
.Xr usermgmt.conf 5
for more details.
+.It Fl U
+Unlock the account by removing the
+.Ql \&-
+from the user's shell.
+.Fl U
+and
+.Fl Z
+are mutually exclusive.
.It Fl u Ar uid
Specifies a new UID for the user.
Boundaries for this value can be preset for all users
@@ -212,6 +220,14 @@
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.
+.Fl Z
+and
+.Fl U
+are mutually exclusive.
.El
.Pp
Once the information has been verified,