aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Nugent <davidn@FreeBSD.org>2000-06-18 05:51:35 +0000
committerDavid Nugent <davidn@FreeBSD.org>2000-06-18 05:51:35 +0000
commitd56e55b0a378cffb2c9b484b6957bedbc51ae7b6 (patch)
tree309fc0078f5028629261ba29a77a6e2ecc94e542
parent2b0ec9b9d68c5288e19cc6dcf670661d45bf0065 (diff)
downloadsrc-d56e55b0a378cffb2c9b484b6957bedbc51ae7b6.tar.gz
src-d56e55b0a378cffb2c9b484b6957bedbc51ae7b6.zip
MFC recent bug fixes and feature.
This commit unifies pw(8) code across all active branches. Still-Todo: manpage updates
Notes
Notes: svn path=/stable/3/; revision=61793
-rw-r--r--usr.sbin/pw/fileupd.c62
-rw-r--r--usr.sbin/pw/grupd.c5
-rw-r--r--usr.sbin/pw/pw.c29
-rw-r--r--usr.sbin/pw/pw.h2
-rw-r--r--usr.sbin/pw/pw_group.c34
-rw-r--r--usr.sbin/pw/pw_user.c226
-rw-r--r--usr.sbin/pw/pw_vpw.c4
-rw-r--r--usr.sbin/pw/pwupd.c31
-rw-r--r--usr.sbin/pw/pwupd.h14
9 files changed, 297 insertions, 110 deletions
diff --git a/usr.sbin/pw/fileupd.c b/usr.sbin/pw/fileupd.c
index 376f589ac1f7..a846513dbea3 100644
--- a/usr.sbin/pw/fileupd.c
+++ b/usr.sbin/pw/fileupd.c
@@ -71,38 +71,44 @@ extendarray(char ***buf, int * buflen, int needed)
int
fileupdate(char const * filename, mode_t fmode, char const * newline, char const * prefix, int pfxlen, int updmode)
{
- int rc = 0;
+ int rc = 0;
if (pfxlen <= 1)
- errno = EINVAL;
+ rc = EINVAL;
else {
- int infd = open(filename, O_RDWR | O_CREAT, fmode);
+ int infd = open(filename, O_RDWR | O_CREAT, fmode);
- if (infd != -1) {
- FILE *infp = fdopen(infd, "r+");
+ if (infd == -1)
+ rc = errno;
+ else {
+ FILE *infp = fdopen(infd, "r+");
- if (infp == NULL)
+ if (infp == NULL) {
+ rc = errno; /* Assumes fopen(3) sets errno from open(2) */
close(infd);
- else {
- int outfd;
- char file[MAXPATHLEN];
+ } else {
+ int outfd;
+ char file[MAXPATHLEN];
strcpy(file, filename);
strcat(file, ".new");
outfd = open(file, O_RDWR | O_CREAT | O_TRUNC | O_EXLOCK, fmode);
- if (outfd != -1) {
- FILE *outfp = fdopen(outfd, "w+");
+ if (outfd == -1)
+ rc = errno;
+ else {
+ FILE *outfp = fdopen(outfd, "w+");
- if (outfp == NULL)
+ if (outfp == NULL) {
+ rc = errno;
close(outfd);
- else {
- int updated = UPD_CREATE;
+ } else {
+ int updated = UPD_CREATE;
int linesize = PWBUFSZ;
- char *line = malloc(linesize);
+ char *line = malloc(linesize);
nextline:
while (fgets(line, linesize, infp) != NULL) {
- char *p = strchr(line, '\n');
+ char *p = strchr(line, '\n');
while ((p = strchr(line, '\n')) == NULL) {
int l;
@@ -143,7 +149,11 @@ fileupdate(char const * filename, mode_t fmode, char const * newline, char const
* then error
*/
if (updmode != updated)
- errno = (updmode == UPD_CREATE) ? EEXIST : ENOENT;
+ /* -1 return means:
+ * update,delete=no user entry
+ * create=entry exists
+ */
+ rc = -1;
else {
/*
@@ -155,9 +165,9 @@ fileupdate(char const * filename, mode_t fmode, char const * newline, char const
/*
* Flush the file and check for the result
*/
- rc = fflush(outfp) != EOF;
- if (rc) {
-
+ if (fflush(outfp) == EOF)
+ rc = errno; /* Failed to update */
+ else {
/*
* Copy data back into the
* original file and truncate
@@ -168,18 +178,16 @@ fileupdate(char const * filename, mode_t fmode, char const * newline, char const
fputs(line, infp);
/*
- * If there was a problem with copying
- * we will just rename 'file.new'
- * to 'file'.
+ * If there was a problem with copying
+ * we will just rename 'file.new'
+ * to 'file'.
* This is a gross hack, but we may have
* corrupted the original file
* Unfortunately, it will lose the inode
- * and hence the lock.
+ * and hence the lock.
*/
- if (fflush(infp) == EOF || ferror(infp)) {
- rc = errno; /* Preserve errno for return */
+ if (fflush(infp) == EOF || ferror(infp))
rename(file, filename);
- }
else
ftruncate(infd, ftell(infp));
}
diff --git a/usr.sbin/pw/grupd.c b/usr.sbin/pw/grupd.c
index 237fe950d5fc..edff76d1285c 100644
--- a/usr.sbin/pw/grupd.c
+++ b/usr.sbin/pw/grupd.c
@@ -142,8 +142,9 @@ gr_update(struct group * grp, char const * group, int mode)
if (grp != NULL && fmtgrentry(&grbuf, &grbuflen, grp, PWF_PASSWD) == -1)
l = -1;
else {
- if ((l = fileupdate(getgrpath(_GROUP), 0644, grbuf, pfx, l, mode)) != 0)
- l = grdb(NULL) == 0;
+ l = fileupdate(getgrpath(_GROUP), 0644, grbuf, pfx, l, mode);
+ if (l == 0)
+ l = grdb(NULL);
}
if (grbuf != NULL)
free(grbuf);
diff --git a/usr.sbin/pw/pw.c b/usr.sbin/pw/pw.c
index 1da063c0796b..6c070acb2665 100644
--- a/usr.sbin/pw/pw.c
+++ b/usr.sbin/pw/pw.c
@@ -35,16 +35,23 @@ static const char rcsid[] =
#include <sys/wait.h>
#include "pw.h"
-const char *Modes[] = {"add", "del", "mod", "show", "next", NULL};
+#if !defined(_PATH_YP)
+#define _PATH_YP "/var/yp/"
+#endif
+const char *Modes[] = {
+ "add", "del", "mod", "show", "next",
+ NULL};
const char *Which[] = {"user", "group", NULL};
static const char *Combo1[] = {
"useradd", "userdel", "usermod", "usershow", "usernext",
+ "lock", "unlock",
"groupadd", "groupdel", "groupmod", "groupshow", "groupnext",
NULL};
static const char *Combo2[] = {
"adduser", "deluser", "moduser", "showuser", "nextuser",
+ "lock", "unlock",
"addgroup", "delgroup", "modgroup", "showgroup", "nextgroup",
-NULL};
+ NULL};
struct pwf PWF =
{
@@ -102,6 +109,8 @@ main(int argc, char *argv[])
"V:C:qn:u:rY",
"V:C:qn:u:c:d:e:p:g:G:ml:k:s:w:L:h:FNPY",
"V:C:qn:u:FPa7",
+ "V:C:q",
+ "V:C:q",
"V:C:q"
},
{ /* grp */
@@ -144,14 +153,16 @@ main(int argc, char *argv[])
} else
break;
}
- else if ((tmp = getindex(Modes, argv[1])) != -1)
+ else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
mode = tmp;
- else if ((tmp = getindex(Which, argv[1])) != -1)
+ else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1)
which = tmp;
- else if ((tmp = getindex(Combo1, argv[1])) != -1 || (tmp = getindex(Combo2, argv[1])) != -1) {
+ else if ((mode == -1 && which == -1) &&
+ ((tmp = getindex(Combo1, argv[1])) != -1 ||
+ (tmp = getindex(Combo2, argv[1])) != -1)) {
which = tmp / M_NUM;
mode = tmp % M_NUM;
- } else if (strcmp(argv[1], "help") == 0)
+ } else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
cmdhelp(mode, which);
else if (which != -1 && mode != -1)
addarg(&arglist, 'n', argv[1]);
@@ -175,7 +186,7 @@ main(int argc, char *argv[])
while ((ch = getopt(argc, argv, opts[which][mode])) != -1) {
if (ch == '?')
- errx(EX_USAGE, NULL);
+ errx(EX_USAGE, "unknown switch");
else
addarg(&arglist, ch, optarg);
optarg = NULL;
@@ -272,9 +283,9 @@ static void
cmdhelp(int mode, int which)
{
if (which == -1)
- fprintf(stderr, "usage: pw [user|group] [add|del|mod|show|next] [ help | switches/values ]\n");
+ fprintf(stderr, "usage:\n pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n");
else if (mode == -1)
- fprintf(stderr, "usage: pw %s [add|del|mod|show|next] [ help | switches/values ]\n", Which[which]);
+ fprintf(stderr, "usage:\n pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]);
else {
/*
diff --git a/usr.sbin/pw/pw.h b/usr.sbin/pw/pw.h
index f85eac737db3..aa437ec3cd9a 100644
--- a/usr.sbin/pw/pw.h
+++ b/usr.sbin/pw/pw.h
@@ -50,6 +50,8 @@ enum _mode
M_UPDATE,
M_PRINT,
M_NEXT,
+ M_LOCK,
+ M_UNLOCK,
M_NUM
};
diff --git a/usr.sbin/pw/pw_group.c b/usr.sbin/pw/pw_group.c
index 3385752feafc..6042a683713d 100644
--- a/usr.sbin/pw/pw_group.c
+++ b/usr.sbin/pw/pw_group.c
@@ -44,12 +44,13 @@ static gid_t gr_gidpolicy(struct userconf * cnf, struct cargs * args);
int
pw_group(struct userconf * cnf, int mode, struct cargs * args)
{
+ int rc;
struct carg *a_name = getarg(args, 'n');
struct carg *a_gid = getarg(args, 'g');
struct carg *arg;
struct group *grp = NULL;
int grmembers = 0;
- char **members = NULL;
+ char **members = NULL;
static struct group fakegroup =
{
@@ -59,12 +60,14 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
NULL
};
+ if (mode == M_LOCK || mode == M_UNLOCK)
+ errx(EX_USAGE, "'lock' command is not available for groups");
+
/*
* With M_NEXT, we only need to return the
* next gid to stdout
*/
- if (mode == M_NEXT)
- {
+ if (mode == M_NEXT) {
gid_t next = gr_gidpolicy(cnf, args);
if (getarg(args, 'q'))
return next;
@@ -116,8 +119,13 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
if (mode == M_DELETE) {
gid_t gid = grp->gr_gid;
- if (delgrent(grp) == -1)
- err(EX_IOERR, "error updating group file");
+ rc = delgrent(grp);
+ if (rc == -1)
+ err(EX_IOERR, "group '%s' not available (NIS?)", grp->gr_name);
+ else if (rc != 0) {
+ warn("group update");
+ return EX_IOERR;
+ }
pw_log(cnf, mode, W_GROUP, "%s(%ld) removed", a_name->val, (long) gid);
return EXIT_SUCCESS;
} else if (mode == M_PRINT)
@@ -231,8 +239,17 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
if (getarg(args, 'N') != NULL)
return print_group(grp, getarg(args, 'P') != NULL);
- if ((mode == M_ADD && !addgrent(grp)) || (mode == M_UPDATE && !chggrent(a_name->val, grp))) {
- warn("group update");
+ if (mode == M_ADD && (rc = addgrent(grp)) != 0) {
+ if (rc == -1)
+ warnx("group '%s' already exists", grp->gr_name);
+ else
+ warn("group update");
+ return EX_IOERR;
+ } else if (mode == M_UPDATE && (rc = chggrent(a_name->val, grp)) != 0) {
+ if (rc == -1)
+ warnx("group '%s' not available (NIS?)", grp->gr_name);
+ else
+ warn("group update");
return EX_IOERR;
}
/* grp may have been invalidated */
@@ -282,7 +299,8 @@ gr_gidpolicy(struct userconf * cnf, struct cargs * args)
*/
SETGRENT();
while ((grp = GETGRENT()) != NULL)
- if (grp->gr_gid >= (int) cnf->min_gid && grp->gr_gid <= (int) cnf->max_gid)
+ if ((gid_t)grp->gr_gid >= (gid_t)cnf->min_gid &&
+ (gid_t)grp->gr_gid <= (gid_t)cnf->max_gid)
bm_setbit(&bm, grp->gr_gid - cnf->min_gid);
ENDGRENT();
diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c
index bba8a01e47bd..b70a4102a521 100644
--- a/usr.sbin/pw/pw_user.c
+++ b/usr.sbin/pw/pw_user.c
@@ -55,6 +55,7 @@ static const char rcsid[] =
#endif
static int randinit;
+static char locked_str[] = "*LOCKED*";
static int print_user(struct passwd * pwd, int pretty, int v7);
static uid_t pw_uidpolicy(struct userconf * cnf, struct cargs * args);
@@ -102,8 +103,9 @@ static void rmskey(char const * name);
int
pw_user(struct userconf * cnf, int mode, struct cargs * args)
{
- int r, r1;
+ int rc, edited = 0;
char *p = NULL;
+ char *passtmp;
struct carg *a_name;
struct carg *a_uid;
struct carg *arg;
@@ -121,12 +123,15 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
0,
"",
"User &",
+ "/nonexistent",
"/bin/sh",
- 0,
- 0,
0
+#if defined(__FreeBSD__)
+ ,0
+#endif
};
+
/*
* With M_NEXT, we only need to return the
* next uid to stdout
@@ -204,7 +209,6 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
errx(EX_OSFILE, "root home `%s' is not a directory", cnf->home);
}
-
if ((arg = getarg(args, 'e')) != NULL)
cnf->expire_days = atoi(arg->val);
@@ -226,7 +230,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
cnf->default_class = pw_checkname((u_char *)arg->val, 0);
if ((arg = getarg(args, 'G')) != NULL && arg->val) {
- int i = 0;
+ int i = 0;
for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) {
if ((grp = GETGRNAM(p)) == NULL) {
@@ -239,10 +243,12 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
while (i < cnf->numgroups)
cnf->groups[i++] = NULL;
}
+
if ((arg = getarg(args, 'k')) != NULL) {
if (stat(cnf->dotdir = arg->val, &st) == -1 || !S_ISDIR(st.st_mode))
errx(EX_OSFILE, "skeleton `%s' is not a directory or does not exist", cnf->dotdir);
}
+
if ((arg = getarg(args, 's')) != NULL)
cnf->shell_default = arg->val;
@@ -270,6 +276,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
warn("config update");
return EX_IOERR;
}
+
if (mode == M_PRINT && getarg(args, 'a')) {
int pretty = getarg(args, 'P') != NULL;
int v7 = getarg(args, '7') != NULL;
@@ -280,6 +287,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
ENDPWENT();
return EXIT_SUCCESS;
}
+
if ((a_name = getarg(args, 'n')) != NULL)
pwd = GETPWNAM(pw_checkname((u_char *)a_name->val, 0));
a_uid = getarg(args, 'u');
@@ -300,10 +308,13 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
a_name = NULL;
}
}
+
/*
* Update, delete & print require that the user exists
*/
- if (mode == M_UPDATE || mode == M_DELETE || mode == M_PRINT) {
+ if (mode == M_UPDATE || mode == M_DELETE ||
+ mode == M_PRINT || mode == M_LOCK || mode == M_UNLOCK) {
+
if (a_name == NULL && pwd == NULL) /* Try harder */
pwd = GETPWUID(atoi(a_uid->val));
@@ -319,13 +330,39 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
errx(EX_NOUSER, "no such uid `%s'", a_uid->val);
errx(EX_NOUSER, "no such user `%s'", a_name->val);
}
+
if (a_name == NULL) /* May be needed later */
a_name = addarg(args, 'n', newstr(pwd->pw_name));
/*
- * Handle deletions now
+ * The M_LOCK and M_UNLOCK functions simply add or remove
+ * a "*LOCKED*" prefix from in front of the password to
+ * prevent it decoding correctly, and therefore prevents
+ * access. Of course, this only prevents access via
+ * password authentication (not ssh, kerberos or any
+ * other method that does not use the UNIX password) but
+ * that is a known limitation.
*/
- if (mode == M_DELETE) {
+
+ if (mode == M_LOCK) {
+ if (strncmp(pwd->pw_passwd, locked_str, sizeof(locked_str)-1) == 0)
+ errx(EX_DATAERR, "user '%s' is already locked", pwd->pw_name);
+ passtmp = malloc(strlen(pwd->pw_passwd) + sizeof(locked_str));
+ if (passtmp == NULL) /* disaster */
+ errx(EX_UNAVAILABLE, "out of memory");
+ strcpy(passtmp, locked_str);
+ strcat(passtmp, pwd->pw_passwd);
+ pwd->pw_passwd = passtmp;
+ edited = 1;
+ } else if (mode == M_UNLOCK) {
+ if (strncmp(pwd->pw_passwd, locked_str, sizeof(locked_str)-1) != 0)
+ errx(EX_DATAERR, "user '%s' is not locked", pwd->pw_name);
+ pwd->pw_passwd += sizeof(locked_str)-1;
+ edited = 1;
+ } else if (mode == M_DELETE) {
+ /*
+ * Handle deletions now
+ */
char file[MAXPATHLEN];
char home[MAXPATHLEN];
uid_t uid = pwd->pw_uid;
@@ -357,12 +394,23 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
strncpy(home, pwd->pw_dir, sizeof home);
home[sizeof home - 1] = '\0';
- if (!delpwent(pwd))
- err(EX_IOERR, "error updating passwd file");
+ rc = delpwent(pwd);
+ if (rc == -1)
+ err(EX_IOERR, "user '%s' does not exist", pwd->pw_name);
+ else if (rc != 0) {
+ warn("passwd update");
+ return EX_IOERR;
+ }
+
+ if (cnf->nispasswd && *cnf->nispasswd=='/') {
+ rc = delnispwent(cnf->nispasswd, a_name->val);
+ if (rc == -1)
+ warnx("WARNING: user '%s' does not exist in NIS passwd", pwd->pw_name);
+ else if (rc != 0)
+ warn("WARNING: NIS passwd update");
+ /* non-fatal */
+ }
- if (cnf->nispasswd && *cnf->nispasswd=='/' && !delnispwent(cnf->nispasswd, a_name->val))
- warn("WARNING: NIS passwd update");
-
editgroups(a_name->val, NULL);
pw_log(cnf, mode, W_USER, "%s(%ld) account removed", a_name->val, (long) uid);
@@ -404,46 +452,84 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
if (strcmp(pwd->pw_name, "root") == 0)
errx(EX_DATAERR, "can't rename `root' account");
pwd->pw_name = pw_checkname((u_char *)arg->val, 0);
+ edited = 1;
}
+
if ((arg = getarg(args, 'u')) != NULL && isdigit(*arg->val)) {
pwd->pw_uid = (uid_t) atol(arg->val);
+ edited = 1;
if (pwd->pw_uid != 0 && strcmp(pwd->pw_name, "root") == 0)
errx(EX_DATAERR, "can't change uid of `root' account");
if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
warnx("WARNING: account `%s' will have a uid of 0 (superuser access!)", pwd->pw_name);
}
- if ((arg = getarg(args, 'g')) != NULL && pwd->pw_uid != 0) /* Already checked this */
- pwd->pw_gid = (gid_t) GETGRNAM(cnf->default_group)->gr_gid;
+
+ if ((arg = getarg(args, 'g')) != NULL && pwd->pw_uid != 0) { /* Already checked this */
+ gid_t newgid = (gid_t) GETGRNAM(cnf->default_group)->gr_gid;
+ if (newgid != pwd->pw_gid) {
+ edited = 1;
+ pwd->pw_gid = newgid;
+ }
+ }
if ((arg = getarg(args, 'p')) != NULL) {
- if (*arg->val == '\0' || strcmp(arg->val, "0") == 0)
- pwd->pw_change = 0;
+ if (*arg->val == '\0' || strcmp(arg->val, "0") == 0) {
+ if (pwd->pw_change != 0) {
+ pwd->pw_change = 0;
+ edited = 1;
+ }
+ }
else {
time_t now = time(NULL);
time_t expire = parse_date(now, arg->val);
if (now == expire)
errx(EX_DATAERR, "invalid password change date `%s'", arg->val);
- pwd->pw_change = expire;
+ if (pwd->pw_change != expire) {
+ pwd->pw_change = expire;
+ edited = 1;
+ }
}
}
+
if ((arg = getarg(args, 'e')) != NULL) {
- if (*arg->val == '\0' || strcmp(arg->val, "0") == 0)
- pwd->pw_expire = 0;
+ if (*arg->val == '\0' || strcmp(arg->val, "0") == 0) {
+ if (pwd->pw_expire != 0) {
+ pwd->pw_expire = 0;
+ edited = 1;
+ }
+ }
else {
time_t now = time(NULL);
time_t expire = parse_date(now, arg->val);
if (now == expire)
errx(EX_DATAERR, "invalid account expiry date `%s'", arg->val);
- pwd->pw_expire = expire;
+ if (pwd->pw_expire != expire) {
+ pwd->pw_expire = expire;
+ edited = 1;
+ }
}
}
- if ((arg = getarg(args, 's')) != NULL)
- pwd->pw_shell = shell_path(cnf->shelldir, cnf->shells, arg->val);
- if (getarg(args, 'L'))
- pwd->pw_class = cnf->default_class;
+ if ((arg = getarg(args, 's')) != NULL) {
+ char *shell = shell_path(cnf->shelldir, cnf->shells, arg->val);
+ if (shell == NULL)
+ shell = "";
+ if (strcmp(shell, pwd->pw_shell) != 0) {
+ pwd->pw_shell = shell;
+ edited = 1;
+ }
+ }
+
+ if (getarg(args, 'L')) {
+ if (cnf->default_class == NULL)
+ cnf->default_class = "";
+ if (strcmp(pwd->pw_class, cnf->default_class) != 0) {
+ pwd->pw_class = cnf->default_class;
+ edited = 1;
+ }
+ }
if ((arg = getarg(args, 'd')) != NULL) {
if (stat(pwd->pw_dir = arg->val, &st) == -1) {
@@ -453,10 +539,17 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
warnx("WARNING: home `%s' is not a directory", pwd->pw_dir);
}
- if ((arg = getarg(args, 'w')) != NULL && getarg(args, 'h') == NULL)
+ if ((arg = getarg(args, 'w')) != NULL && getarg(args, 'h') == NULL) {
pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
+ edited = 1;
+ }
} else {
+
+ /*
+ * Add code
+ */
+
if (a_name == NULL) /* Required */
errx(EX_DATAERR, "login name required");
else if ((pwd = GETPWNAM(a_name->val)) != NULL) /* Exists */
@@ -475,6 +568,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
pwd->pw_expire = pw_exppolicy(cnf, args);
pwd->pw_dir = pw_homepolicy(cnf, args, pwd->pw_name);
pwd->pw_shell = pw_shellpolicy(cnf, args, NULL);
+ edited = 1;
if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
warnx("WARNING: new account `%s' has a uid of 0 (superuser access!)", pwd->pw_name);
@@ -483,8 +577,13 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
/*
* Shared add/edit code
*/
- if ((arg = getarg(args, 'c')) != NULL)
- pwd->pw_gecos = pw_checkname((u_char *)arg->val, 1);
+ if ((arg = getarg(args, 'c')) != NULL) {
+ char *gecos = pw_checkname((u_char *)arg->val, 1);
+ if (strcmp(pwd->pw_gecos, gecos) != 0) {
+ pwd->pw_gecos = gecos;
+ edited = 1;
+ }
+ }
if ((arg = getarg(args, 'h')) != NULL) {
if (strcmp(arg->val, "-") == 0)
@@ -524,6 +623,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
if (!*line)
errx(EX_DATAERR, "empty password read on file descriptor %d", fd);
pwd->pw_passwd = pw_pwcrypt(line);
+ edited = 1;
}
}
@@ -535,23 +635,43 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
getarg(args, 'P') != NULL,
getarg(args, '7') != NULL);
- r = r1 = 1;
if (mode == M_ADD) {
- r = addpwent(pwd);
- if (r && cnf->nispasswd && *cnf->nispasswd=='/')
- r1 = addnispwent(cnf->nispasswd, pwd);
- } else if (mode == M_UPDATE) {
- r = chgpwent(a_name->val, pwd);
- if (r && cnf->nispasswd && *cnf->nispasswd=='/')
- r1 = chgnispwent(cnf->nispasswd, a_name->val, pwd);
- }
-
- if (!r) {
- warn("password update");
- return EX_IOERR;
- } else if (!r1) {
- warn("WARNING: NIS password update");
- /* Keep on trucking */
+ edited = 1; /* Always */
+ rc = addpwent(pwd);
+ if (rc == -1) {
+ warnx("user '%s' already exists", pwd->pw_name);
+ return EX_IOERR;
+ } else if (rc != 0) {
+ warn("passwd file update");
+ return EX_IOERR;
+ }
+ if (cnf->nispasswd && *cnf->nispasswd=='/') {
+ rc = addnispwent(cnf->nispasswd, pwd);
+ if (rc == -1)
+ warnx("User '%s' already exists in NIS passwd", pwd->pw_name);
+ else
+ warn("NIS passwd update");
+ /* NOTE: we treat NIS-only update errors as non-fatal */
+ }
+ } else if (mode == M_UPDATE || mode == M_LOCK || mode == M_UNLOCK) {
+ if (edited) { /* Only updated this if required */
+ rc = chgpwent(a_name->val, pwd);
+ if (rc == -1) {
+ warnx("user '%s' does not exist (NIS?)", pwd->pw_name);
+ return EX_IOERR;
+ } else if (rc != 0) {
+ warn("passwd file update");
+ return EX_IOERR;
+ }
+ if ( cnf->nispasswd && *cnf->nispasswd=='/') {
+ rc = chgnispwent(cnf->nispasswd, a_name->val, pwd);
+ if (rc == -1)
+ warn("User '%s' not found in NIS passwd", pwd->pw_name);
+ else
+ warn("NIS passwd update");
+ /* NOTE: NIS-only update errors are not fatal */
+ }
+ }
}
/*
@@ -561,8 +681,16 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
if (mode == M_ADD || getarg(args, 'G') != NULL)
editgroups(pwd->pw_name, cnf->groups);
- /* pwd may have been invalidated */
- if ((pwd = GETPWNAM(a_name->val)) == NULL)
+ /* go get a current version of pwd */
+ pwd = GETPWNAM(a_name->val);
+ if (pwd == NULL) {
+ /* This will fail when we rename, so special case that */
+ if (mode == M_UPDATE && (arg = getarg(args, 'l')) != NULL) {
+ a_name->val = arg->val; /* update new name */
+ pwd = GETPWNAM(a_name->val); /* refetch renamed rec */
+ }
+ }
+ if (pwd == NULL) /* can't go on without this */
errx(EX_NOUSER, "user '%s' disappeared during update", a_name->val);
grp = GETGRGID(pwd->pw_gid);
@@ -607,6 +735,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
}
}
}
+
/*
* Finally, let's create and populate the user's home directory. Note
* that this also `works' for editing users if -m is used, but
@@ -617,6 +746,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
pw_log(cnf, mode, W_USER, "%s(%ld) home %s made",
pwd->pw_name, (long) pwd->pw_uid, pwd->pw_dir);
}
+
return EXIT_SUCCESS;
}
@@ -1016,9 +1146,9 @@ print_user(struct passwd * pwd, int pretty, int v7)
*p = (char) toupper(*p);
}
if (pwd->pw_expire > (time_t)0 && (tptr = localtime(&pwd->pw_expire)) != NULL)
- strftime(acexpire, sizeof acexpire, "%c", tptr);
+ strftime(acexpire, sizeof acexpire, "%e-%b-%Y %T", tptr);
if (pwd->pw_change > (time_t)9 && (tptr = localtime(&pwd->pw_change)) != NULL)
- strftime(pwexpire, sizeof pwexpire, "%c", tptr);
+ strftime(pwexpire, sizeof pwexpire, "%e-%b-%Y %T", tptr);
printf("Login Name: %-15s #%-12ld Group: %-15s #%ld\n"
" Full Name: %s\n"
" Home: %-26.26s Class: %s\n"
diff --git a/usr.sbin/pw/pw_vpw.c b/usr.sbin/pw/pw_vpw.c
index ef12437a15ef..bc5713e82d32 100644
--- a/usr.sbin/pw/pw_vpw.c
+++ b/usr.sbin/pw/pw_vpw.c
@@ -190,11 +190,13 @@ vendgrent(void)
}
}
-int
+RET_SETGRENT
vsetgrent(void)
{
vendgrent();
+#if defined(__FreeBSD__)
return 0;
+#endif
}
static struct group *
diff --git a/usr.sbin/pw/pwupd.c b/usr.sbin/pw/pwupd.c
index 10a6066e198c..1f0d86fa7322 100644
--- a/usr.sbin/pw/pwupd.c
+++ b/usr.sbin/pw/pwupd.c
@@ -43,6 +43,7 @@ static const char rcsid[] =
#include "pwupd.h"
#define HAVE_PWDB_C 1
+#define HAVE_PWDB_U 1
static char pathpwd[] = _PATH_PWD;
static char * pwpath = pathpwd;
@@ -92,14 +93,14 @@ pwdb(char *arg,...)
args[i] = NULL;
if ((pid = fork()) == -1) /* Error (errno set) */
- i = -1;
+ i = errno;
else if (pid == 0) { /* Child */
execv(args[0], args);
_exit(1);
} else { /* Parent */
waitpid(pid, &i, 0);
- if ((i = WEXITSTATUS(i)) != 0)
- errno = EIO; /* set SOMETHING */
+ if (WEXITSTATUS(i))
+ i = EIO;
}
return i;
}
@@ -150,9 +151,12 @@ pw_update(struct passwd * pwd, char const * user, int mode)
#else
{ /* No -C */
#endif
- char pfx[32];
+ char pfx[PWBUFSZ];
char pwbuf[PWBUFSZ];
- int l = sprintf(pfx, "%s:", user);
+ int l = snprintf(pfx, PWBUFSZ, "%s:", user);
+#ifdef HAVE_PWDB_U
+ int isrename = strcmp(user, pwd->pw_name);
+#endif
/*
* Update the passwd file first
@@ -161,18 +165,25 @@ pw_update(struct passwd * pwd, char const * user, int mode)
*pwbuf = '\0';
else
fmtpwentry(pwbuf, pwd, PWF_PASSWD);
- if ((rc = fileupdate(getpwpath(_PASSWD), 0644, pwbuf, pfx, l, mode)) != 0) {
+
+ rc = fileupdate(getpwpath(_PASSWD), 0644, pwbuf, pfx, l, mode);
+ if (rc == 0) {
/*
* Then the master.passwd file
*/
if (pwd != NULL)
fmtpwentry(pwbuf, pwd, PWF_MASTER);
- if ((rc = fileupdate(getpwpath(_MASTERPASSWD), 0644, pwbuf, pfx, l, mode)) != 0) {
- if (mode == UPD_DELETE)
- rc = pwdb(NULL) == 0;
+ rc = fileupdate(getpwpath(_MASTERPASSWD), 0644, pwbuf, pfx, l, mode);
+ if (rc == 0) {
+#ifdef HAVE_PWDB_U
+ if (mode == UPD_DELETE || isrename)
+#endif
+ rc = pwdb(NULL);
+#ifdef HAVE_PWDB_U
else
- rc = pwdb("-u", user, NULL) == 0;
+ rc = pwdb("-u", user, NULL);
+#endif
}
}
}
diff --git a/usr.sbin/pw/pwupd.h b/usr.sbin/pw/pwupd.h
index 046bd2e464c9..8da036dbdf92 100644
--- a/usr.sbin/pw/pwupd.h
+++ b/usr.sbin/pw/pwupd.h
@@ -35,6 +35,12 @@
#include <sys/cdefs.h>
+#if defined(__FreeBSD__)
+#define RET_SETGRENT int
+#else
+#define RET_SETGRENT void
+#endif
+
enum updtype
{
UPD_DELETE = -1,
@@ -63,7 +69,7 @@ struct pwf
struct passwd * (*_getpwuid)(uid_t uid);
struct passwd * (*_getpwnam)(const char * nam);
int (*_pwdb)(char *arg, ...);
- int (*_setgrent)(void);
+ RET_SETGRENT (*_setgrent)(void);
void (*_endgrent)(void);
struct group * (*_getgrent)(void);
struct group * (*_getgrgid)(gid_t gid);
@@ -135,15 +141,13 @@ struct passwd * vgetpwnam __P((const char * nam));
struct passwd * vgetpwent __P((void));
int vpwdb __P((char *arg, ...));
-int vsetgrent __P((void));
-void vendgrent __P((void));
struct group * vgetgrent __P((void));
struct group * vgetgrgid __P((gid_t gid));
struct group * vgetgrnam __P((const char * nam));
struct group * vgetgrent __P((void));
int vgrdb __P((char *arg, ...));
-int vsetgrent __P((void));
-void vendgrent __P((void));
+RET_SETGRENT vsetgrent __P((void));
+void vendgrent __P((void));
void copymkdir __P((char const * dir, char const * skel, mode_t mode, uid_t uid, gid_t gid));
void rm_r __P((char const * dir, uid_t uid));