diff options
author | Antoine Jacoutot <ajacoutot@cvs.openbsd.org> | 2012-09-18 07:56:12 +0000 |
---|---|---|
committer | Antoine Jacoutot <ajacoutot@cvs.openbsd.org> | 2012-09-18 07:56:12 +0000 |
commit | b259c04c18573abbb28e8dcad96a5972e95bfff0 (patch) | |
tree | 510c0dae207bf0255f7aba681e72b6093416d51e /usr.sbin | |
parent | a238aa7e511c995fd6a0315ce2dc44834da03ba0 (diff) |
Add 2 new knobs to usermod(8):
-U to unlock an account
-Z to lock an account
Locking means adding a '*' prefix to the encrypted password and appending
a '-' to the user's shell... and obviously the opposite for unlocking.
some inputs from sthen@, otto@ and deraadt@
ok todd@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/user/user.c | 97 | ||||
-rw-r--r-- | usr.sbin/user/usermod.8 | 27 |
2 files changed, 117 insertions, 7 deletions
diff --git a/usr.sbin/user/user.c b/usr.sbin/user/user.c index 690b50a3d25..a03d53e13b0 100644 --- a/usr.sbin/user/user.c +++ b/usr.sbin/user/user.c @@ -1,4 +1,4 @@ -/* $OpenBSD: user.c,v 1.90 2012/01/29 08:38:54 ajacoutot Exp $ */ +/* $OpenBSD: user.c,v 1.91 2012/09/18 07:56:11 ajacoutot Exp $ */ /* $NetBSD: user.c,v 1.69 2003/04/14 17:40:07 agc Exp $ */ /* @@ -100,7 +100,9 @@ enum { 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,12 +1341,21 @@ moduser(char *login_name, char *newlogin, user_t *up) 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]; + char *shell_last_char; 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 locked = 0; + int unlocked = 0; int masterfd; int ptmpfd; int rval; @@ -1359,9 +1370,16 @@ moduser(char *login_name, char *newlogin, user_t *up) 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; + /* get the last char of the shell in case we need it for '-U' or '-Z' */ + shell_last_char = pwp->pw_shell+strlen(pwp->pw_shell) - 1; + if ((masterfd = open(_PATH_MASTERPASSWD, O_RDONLY)) < 0) { err(EXIT_FAILURE, "can't open `%s'", _PATH_MASTERPASSWD); } @@ -1410,6 +1428,63 @@ moduser(char *login_name, char *newlogin, user_t *up) pwp->pw_passwd = up->u_password; } } + if (up->u_flags & F_ACCTLOCK) { + /* lock the account */ + if (*shell_last_char != *acctlock_str) { + 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; + } else { + locked++; + } + /* 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; + } else { + locked++; + } + + if (locked > 1) + warnx("account `%s' is already locked", pwp->pw_name); + } + 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; + } else { + unlocked++; + } + /* unlock the account */ + if (*shell_last_char == *acctlock_str) { + 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; + } else { + unlocked++; + } + + if (unlocked > 1) + warnx("account `%s' is not locked", pwp->pw_name); + } 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 +1622,10 @@ moduser(char *login_name, char *newlogin, user_t *up) } } (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 +1696,7 @@ usermgmt_usage(const char *prog) "[-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 +1867,7 @@ usermod(int argc, char **argv) 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 +1893,12 @@ usermod(int argc, char **argv) } 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 +1968,10 @@ usermod(int argc, char **argv) } 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) { diff --git a/usr.sbin/user/usermod.8 b/usr.sbin/user/usermod.8 index 2c1d8197d2f..1e63ffab26c 100644 --- a/usr.sbin/user/usermod.8 +++ b/usr.sbin/user/usermod.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: usermod.8,v 1.28 2012/01/28 14:25:45 ajacoutot Exp $ +.\" $OpenBSD: usermod.8,v 1.29 2012/09/18 07:56:11 ajacoutot Exp $ .\" $NetBSD: usermod.8,v 1.17 2003/02/14 16:11:37 grant Exp $ .\" .\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved. @@ -31,7 +31,7 @@ .\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" -.Dd $Mdocdate: January 28 2012 $ +.Dd $Mdocdate: September 18 2012 $ .Dt USERMOD 8 .Os .Sh NAME @@ -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 @@ file. 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 \&* +prefix from the 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,16 @@ See 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 prefixing the password with +.Ql \&* . +.Fl Z +and +.Fl U +are mutually exclusive and cannot be used with +.Fl p . .El .Pp Once the information has been verified, |