summaryrefslogtreecommitdiff
path: root/usr.sbin/user
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/user')
-rw-r--r--usr.sbin/user/group.814
-rw-r--r--usr.sbin/user/groupadd.88
-rw-r--r--usr.sbin/user/groupdel.85
-rw-r--r--usr.sbin/user/groupinfo.812
-rw-r--r--usr.sbin/user/groupmod.88
-rw-r--r--usr.sbin/user/user.831
-rw-r--r--usr.sbin/user/user.c868
-rw-r--r--usr.sbin/user/useradd.8151
-rw-r--r--usr.sbin/user/userdel.856
-rw-r--r--usr.sbin/user/userinfo.812
-rw-r--r--usr.sbin/user/usermgmt.h4
-rw-r--r--usr.sbin/user/usermod.8102
12 files changed, 778 insertions, 493 deletions
diff --git a/usr.sbin/user/group.8 b/usr.sbin/user/group.8
index 6c40c858072..a8dc4b87c19 100644
--- a/usr.sbin/user/group.8
+++ b/usr.sbin/user/group.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: group.8,v 1.8 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: group.8,v 1.4 2000/02/28 05:10:56 enami Exp $ */
-.\"
+.\" $OpenBSD: group.8,v 1.9 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: group.8,v 1.5 2000/10/03 19:32:23 bjh21 Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
@@ -40,22 +39,19 @@
.Nd manage group information on the system
.Sh SYNOPSIS
.Nm group add
+.Op Fl ov
.Op Fl g Ar gid
-.Op Fl o
-.Op Fl v
.Ar group
.Nm group del
.Op Fl v
.Ar group
.Nm group info
-.Op Fl e
-.Op Fl v
+.Op Fl ev
.Ar group
.Nm group mod
+.Op Fl ov
.Op Fl g Ar gid
.Op Fl n Ar newname
-.Op Fl o
-.Op Fl v
.Ar group
.Sh DESCRIPTION
The
diff --git a/usr.sbin/user/groupadd.8 b/usr.sbin/user/groupadd.8
index 140dfc848eb..3a627c60c94 100644
--- a/usr.sbin/user/groupadd.8
+++ b/usr.sbin/user/groupadd.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: groupadd.8,v 1.7 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: groupadd.8,v 1.4 2000/02/28 05:10:56 enami Exp $ */
-.\"
+.\" $OpenBSD: groupadd.8,v 1.8 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: groupadd.8,v 1.5 2000/10/03 19:32:23 bjh21 Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
@@ -40,9 +39,8 @@
.Nd add a group to the system
.Sh SYNOPSIS
.Nm groupadd
+.Op Fl ov
.Op Fl g Ar gid
-.Op Fl o
-.Op Fl v
.Ar group
.Sh DESCRIPTION
The
diff --git a/usr.sbin/user/groupdel.8 b/usr.sbin/user/groupdel.8
index 611ae065d6a..c03717180da 100644
--- a/usr.sbin/user/groupdel.8
+++ b/usr.sbin/user/groupdel.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: groupdel.8,v 1.7 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: groupdel.8,v 1.5 2000/02/28 05:10:56 enami Exp $ */
-.\"
+.\" $OpenBSD: groupdel.8,v 1.8 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: groupdel.8,v 1.5 2000/02/28 05:10:56 enami Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
diff --git a/usr.sbin/user/groupinfo.8 b/usr.sbin/user/groupinfo.8
index bf00bfcc892..755158caf31 100644
--- a/usr.sbin/user/groupinfo.8
+++ b/usr.sbin/user/groupinfo.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: groupinfo.8,v 1.7 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: groupinfo.8,v 1.2 2000/02/28 05:10:56 enami Exp $ */
-.\"
+.\" $OpenBSD: groupinfo.8,v 1.8 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: groupinfo.8,v 1.3 2000/10/03 19:32:23 bjh21 Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
@@ -40,8 +39,7 @@
.Nd displays group information
.Sh SYNOPSIS
.Nm groupinfo
-.Op Fl e
-.Op Fl v
+.Op Fl ev
.Ar group
.Sh DESCRIPTION
The
@@ -60,7 +58,9 @@ name or gid is already in use on the system.
perform any actions in a verbose manner.
.El
.Pp
-The group argument may either be a group's name, or a gid.
+The
+.Ar group
+argument may either be a group's name, or a gid.
.Pp
The
.Nm
diff --git a/usr.sbin/user/groupmod.8 b/usr.sbin/user/groupmod.8
index 91e67299b5a..c994e17e588 100644
--- a/usr.sbin/user/groupmod.8
+++ b/usr.sbin/user/groupmod.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: groupmod.8,v 1.7 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: groupmod.8,v 1.4 2000/02/28 05:10:56 enami Exp $ */
-.\"
+.\" $OpenBSD: groupmod.8,v 1.8 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: groupmod.8,v 1.5 2000/10/03 19:32:23 bjh21 Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
@@ -40,10 +39,9 @@
.Nd modify an existing group on the system
.Sh SYNOPSIS
.Nm groupmod
+.Op Fl ov
.Op Fl g Ar gid
.Op Fl n Ar newname
-.Op Fl o
-.Op Fl v
.Ar group
.Sh DESCRIPTION
The
diff --git a/usr.sbin/user/user.8 b/usr.sbin/user/user.8
index 2fd9d20f427..ee7d9ed3f2e 100644
--- a/usr.sbin/user/user.8
+++ b/usr.sbin/user/user.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: user.8,v 1.8 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: user.8,v 1.5 2000/02/28 05:10:57 enami Exp $ */
-.\"
+.\" $OpenBSD: user.8,v 1.9 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: user.8,v 1.9 2001/06/05 11:31:21 wiz Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
@@ -32,7 +31,7 @@
.\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\"
-.Dd November 30, 1999
+.Dd September 5, 2001
.Dt USER 8
.Os
.Sh NAME
@@ -40,13 +39,15 @@
.Nd manage user login information on the system
.Sh SYNOPSIS
.Nm user add
-.Op Fl D
+.Fl D
.Op Fl b Ar base-dir
.Op Fl e Ar expiry-time
.Op Fl f Ar inactive-secs
.Op Fl g Ar gid/name/=uid
+.Op Fl L Ar login-class
.Op Fl r Ar low..high
.Nm user add
+.Op Fl mov
.Op Fl G Ar secondary-group
.Op Fl b Ar base-dir
.Op Fl c Ar comment
@@ -55,40 +56,34 @@
.Op Fl f Ar inactive-secs
.Op Fl g Ar gid/name/=uid
.Op Fl k Ar skel-dir
-.Op Fl m
-.Op Fl o
+.Op Fl L Ar login-class
.Op Fl p Ar password
.Op Fl r Ar low..high
.Op Fl s Ar shell
.Op Fl u Ar uid
-.Op Fl v
.Ar user
.Nm user del
-.Op Fl D
+.Fl D
.Op Fl p Ar preserve-value
.Nm user del
-.Op Fl p
-.Op Fl r
-.Op Fl v
+.Op Fl prv
.Ar user
.Nm user info
-.Op Fl e
-.Op Fl v
+.Op Fl ev
.Ar user
.Nm user mod
+.Op Fl mov
.Op Fl G Ar secondary-group
.Op Fl c Ar comment
.Op Fl d Ar home-dir
.Op Fl e Ar expiry-time
.Op Fl f Ar inactive-secs
.Op Fl g Ar gid/name/=uid
+.Op Fl L Ar login-class
.Op Fl l Ar new-login
-.Op Fl m
-.Op Fl o
.Op Fl p Ar password
.Op Fl s Ar shell
.Op Fl u Ar uid
-.Op Fl v
.Ar user
.Sh DESCRIPTION
The
@@ -109,7 +104,7 @@ utility exits 0 on success, and >0 if an error occurs.
.Sh FILES
.Bl -tag -width /etc/usermgmt.conf -compact
.It Pa /etc/skel/.[A-z]*
-Skelton dot files for new user
+Skeleton files for new user
.It Pa /etc/usermgmt.conf
Configuration file for
.Xr user 8 ,
diff --git a/usr.sbin/user/user.c b/usr.sbin/user/user.c
index 7de56665dd7..b6d5b1302d4 100644
--- a/usr.sbin/user/user.c
+++ b/usr.sbin/user/user.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: user.c,v 1.24 2001/08/16 18:29:27 millert Exp $ */
-/* $NetBSD: user.c,v 1.17 2000/04/14 06:26:55 simonb Exp $ */
+/* $OpenBSD: user.c,v 1.25 2001/09/18 01:50:44 millert Exp $ */
+/* $NetBSD: user.c,v 1.40 2001/08/17 08:29:00 joda Exp $ */
/*
* Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
@@ -40,6 +40,7 @@
#include <err.h>
#include <fcntl.h>
#include <grp.h>
+#include <paths.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
@@ -52,6 +53,7 @@
#include "defs.h"
#include "usermgmt.h"
+
/* this struct describes a uid range */
typedef struct range_t {
int r_from; /* low uid */
@@ -60,10 +62,10 @@ typedef struct range_t {
/* this struct encapsulates the user information */
typedef struct user_t {
+ int u_flags; /* see below */
int u_uid; /* uid of user */
char *u_password; /* encrypted password */
char *u_comment; /* comment field */
- int u_homeset; /* home dir has been set */
char *u_home; /* home directory */
char *u_primgrp; /* primary group */
int u_groupc; /* # of secondary groups */
@@ -72,9 +74,8 @@ typedef struct user_t {
char *u_basedir; /* base directory for home */
char *u_expire; /* when password will expire */
int u_inactive; /* inactive */
- int u_mkdir; /* make the home directory */
- int u_dupuid; /* duplicate uids are allowed */
char *u_skeldir; /* directory for startup files */
+ char *u_class; /* login class */
unsigned u_rsize; /* size of range array */
unsigned u_rc; /* # of ranges */
range_t *u_rv; /* the ranges */
@@ -82,6 +83,23 @@ typedef struct user_t {
int u_preserve; /* preserve uids on deletion */
} user_t;
+/* flags for which fields of the user_t replace the passwd entry */
+enum {
+ F_COMMENT = 0x0001,
+ F_DUPUID = 0x0002,
+ F_EXPIRE = 0x0004,
+ F_GROUP = 0x0008,
+ F_HOMEDIR = 0x0010,
+ F_MKDIR = 0x0020,
+ F_INACTIVE = 0x0040,
+ F_PASSWORD = 0x0080,
+ F_SECGROUP = 0x0100,
+ F_SHELL = 0x0200,
+ F_UID = 0x0400,
+ F_USERNAME = 0x0800,
+ F_CLASS = 0x1000
+};
+
#define CONFFILE "/etc/usermgmt.conf"
#ifndef DEF_GROUP
@@ -97,7 +115,7 @@ typedef struct user_t {
#endif
#ifndef DEF_SHELL
-#define DEF_SHELL "/bin/csh"
+#define DEF_SHELL _PATH_CSHELL
#endif
#ifndef DEF_COMMENT
@@ -117,7 +135,11 @@ typedef struct user_t {
#endif
#ifndef DEF_EXPIRE
-#define DEF_EXPIRE (char *) NULL
+#define DEF_EXPIRE NULL
+#endif
+
+#ifndef DEF_CLASS
+#define DEF_CLASS ""
#endif
#ifndef WAITSECS
@@ -134,8 +156,6 @@ enum {
MaxFileNameLen = MAXPATHLEN,
MaxUserNameLen = MAXLOGNAME,
MaxCommandLen = 2048,
- MaxEntryLen = 2048,
- MaxPasswordEntryLen = 1024,
PasswordLength = _PASSWORD_LEN,
LowGid = DEF_LOWUID,
@@ -143,6 +163,7 @@ enum {
};
/* Full paths of programs used here */
+#define CHMOD "/bin/chmod"
#define CHOWN "/sbin/chown"
#define MKDIR "/bin/mkdir"
#define MV "/bin/mv"
@@ -152,13 +173,16 @@ enum {
#define UNSET_EXPIRY "Null (unset)"
-static int verbose = 0;
+static int asystem(const char *fmt, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+
+static int verbose;
/* if *cpp is non-null, free it, then assign `n' chars of `s' to it */
static void
memsave(char **cpp, char *s, size_t n)
{
- if (*cpp != (char *) NULL) {
+ if (*cpp != NULL) {
FREE(*cpp);
}
NEWARRAY(char, *cpp, n + 1, exit(1));
@@ -168,7 +192,7 @@ memsave(char **cpp, char *s, size_t n)
/* a replacement for system(3) */
static int
-asystem(char *fmt, ...)
+asystem(const char *fmt, ...)
{
va_list vp;
char buf[MaxCommandLen];
@@ -186,6 +210,45 @@ asystem(char *fmt, ...)
return ret;
}
+/* remove a users home directory, returning 1 for success (ie, no problems encountered) */
+static int
+removehomedir(const char *user, int uid, const char *dir)
+{
+ struct stat st;
+
+ /* userid not root? */
+ if (uid == 0) {
+ warnx("Not deleting home directory `%s'; userid is 0", dir);
+ return 0;
+ }
+
+ /* directory exists (and is a directory!) */
+ if (stat(dir, &st) < 0) {
+ warnx("Home directory `%s' doesn't exist", dir);
+ return 0;
+ }
+ if (!S_ISDIR(st.st_mode)) {
+ warnx("Home directory `%s' is not a directory", dir);
+ return 0;
+ }
+
+ /* userid matches directory owner? */
+ if (st.st_uid != uid) {
+ warnx("User `%s' doesn't own directory `%s', not removed\n",
+ user, dir);
+ return 0;
+ }
+
+ (void) seteuid(uid);
+ /* we add the "|| true" to keep asystem() quiet if there is a non-zero exit status. */
+ (void) asystem("%s -rf %s > /dev/null 2>&1 || true", RM, dir);
+ (void) seteuid(0);
+ if (rmdir(dir) < 0) {
+ warnx("Unable to remove all files in `%s'\n", dir);
+ return 0;
+ }
+ return 1;
+}
/* return 1 if all of `s' is numeric */
static int
@@ -219,11 +282,11 @@ copydotfiles(char *skeldir, int uid, int gid, char *dir)
DIR *dirp;
int n;
- if ((dirp = opendir(skeldir)) == (DIR *) NULL) {
+ if ((dirp = opendir(skeldir)) == NULL) {
warn("can't open source . files dir `%s'", skeldir);
return 0;
}
- for (n = 0; (dp = readdir(dirp)) != (struct dirent *) NULL && n == 0 ; ) {
+ for (n = 0; (dp = readdir(dirp)) != NULL && n == 0 ; ) {
if (strcmp(dp->d_name, ".") == 0 ||
strcmp(dp->d_name, "..") == 0) {
continue;
@@ -238,40 +301,42 @@ copydotfiles(char *skeldir, int uid, int gid, char *dir)
skeldir, PAX, (verbose) ? "-v" : "", dir);
}
(void) asystem("%s -R -P %d:%d %s", CHOWN, uid, gid, dir);
+ (void) asystem("%s -R u+w %s", CHMOD, dir);
return n;
}
/* create a group entry with gid `gid' */
static int
-creategid(char *group, int gid)
+creategid(char *group, int gid, char *name)
{
struct stat st;
FILE *from;
FILE *to;
- char buf[MaxEntryLen];
+ char buf[LINE_MAX];
char f[MaxFileNameLen];
int fd;
int cc;
- if (getgrnam(group) != (struct group *) NULL) {
+ if (getgrnam(group) != NULL) {
warnx("group `%s' already exists", group);
return 0;
}
- if ((from = fopen(_PATH_GROUP, "r")) == (FILE *) NULL) {
- warn("can't create gid for %s: can't open %s", group, _PATH_GROUP);
+ if ((from = fopen(_PATH_GROUP, "r")) == NULL) {
+ warn("can't create gid for %s: can't open %s", group,
+ _PATH_GROUP);
return 0;
}
if (flock(fileno(from), LOCK_EX | LOCK_NB) < 0) {
warn("can't lock `%s'", _PATH_GROUP);
}
(void) fstat(fileno(from), &st);
- (void) snprintf(f, sizeof(f), "%s.XXXXXX", _PATH_GROUP);
+ (void) snprintf(f, sizeof(f), "%s.XXXXXXXX", _PATH_GROUP);
if ((fd = mkstemp(f)) < 0) {
(void) fclose(from);
warn("can't create gid: mkstemp failed");
return 0;
}
- if ((to = fdopen(fd, "w")) == (FILE *) NULL) {
+ if ((to = fdopen(fd, "w")) == NULL) {
(void) fclose(from);
(void) close(fd);
(void) unlink(f);
@@ -279,7 +344,7 @@ creategid(char *group, int gid)
return 0;
}
while ((cc = fread(buf, sizeof(char), sizeof(buf), from)) > 0) {
- if (fwrite(buf, sizeof(char), (unsigned) cc, to) != cc) {
+ if (fwrite(buf, sizeof(char), cc, to) != cc) {
(void) fclose(from);
(void) close(fd);
(void) unlink(f);
@@ -287,11 +352,12 @@ creategid(char *group, int gid)
return 0;
}
}
- (void) fprintf(to, "%s:*:%d:\n", group, gid);
+ (void) fprintf(to, "%s:*:%d:%s\n", group, gid, name);
(void) fclose(from);
(void) fclose(to);
if (rename(f, _PATH_GROUP) < 0) {
- warn("can't create gid: can't rename `%s' to `%s'", f, _PATH_GROUP);
+ warn("can't create gid: can't rename `%s' to `%s'", f,
+ _PATH_GROUP);
return 0;
}
(void) chmod(_PATH_GROUP, st.st_mode & 07777);
@@ -305,7 +371,7 @@ modify_gid(char *group, char *newent)
struct stat st;
FILE *from;
FILE *to;
- char buf[MaxEntryLen];
+ char buf[LINE_MAX];
char f[MaxFileNameLen];
char *colon;
int groupc;
@@ -313,7 +379,7 @@ modify_gid(char *group, char *newent)
int fd;
int cc;
- if ((from = fopen(_PATH_GROUP, "r")) == (FILE *) NULL) {
+ if ((from = fopen(_PATH_GROUP, "r")) == NULL) {
warn("can't create gid for %s: can't open %s", group, _PATH_GROUP);
return 0;
}
@@ -321,13 +387,13 @@ modify_gid(char *group, char *newent)
warn("can't lock `%s'", _PATH_GROUP);
}
(void) fstat(fileno(from), &st);
- (void) snprintf(f, sizeof(f), "%s.XXXXXX", _PATH_GROUP);
+ (void) snprintf(f, sizeof(f), "%s.XXXXXXXX", _PATH_GROUP);
if ((fd = mkstemp(f)) < 0) {
(void) fclose(from);
warn("can't create gid: mkstemp failed");
return 0;
}
- if ((to = fdopen(fd, "w")) == (FILE *) NULL) {
+ if ((to = fdopen(fd, "w")) == NULL) {
(void) fclose(from);
(void) close(fd);
(void) unlink(f);
@@ -337,12 +403,19 @@ modify_gid(char *group, char *newent)
groupc = strlen(group);
while (fgets(buf, sizeof(buf), from) != NULL) {
cc = strlen(buf);
+ if (buf[cc - 1] != '\n') {
+ while (!feof(from) && fgetc(from) != '\n')
+ cc++;
+ warn("line `%s' too long (%d bytes), skipping", buf,
+ cc);
+ continue;
+ }
if ((colon = strchr(buf, ':')) == NULL) {
warn("badly formed entry `%s'", buf);
continue;
}
entc = (int)(colon - buf);
- if (entc == groupc && strncmp(group, buf, (unsigned) entc) == 0) {
+ if (entc == groupc && strncmp(group, buf, entc) == 0) {
if (newent == NULL) {
continue;
} else {
@@ -350,7 +423,7 @@ modify_gid(char *group, char *newent)
(void) strlcpy(buf, newent, sizeof(buf));
}
}
- if (fwrite(buf, sizeof(char), (unsigned) cc, to) != cc) {
+ if (fwrite(buf, sizeof(char), cc, to) != cc) {
(void) fclose(from);
(void) close(fd);
(void) unlink(f);
@@ -368,105 +441,108 @@ modify_gid(char *group, char *newent)
return 1;
}
-/* (Re)write secondary groups */
+/* modify the group entries for all `groups', by adding `user' */
static int
-modify_groups (char *login, char *newlogin, user_t *up, char *primgrp)
+append_group(char *user, int ngroups, char **groups)
{
- struct stat st;
- FILE *from, *to;
- char *colon, *p;
- char buf[MaxEntryLen], tmpf[MaxFileNameLen];
- int fd, cc, g;
-
- /* XXX This function, and modify_gid() above could possibly be */
- /* combined into one function. */
-
- if ((from = fopen(_PATH_GROUP, "r")) == (FILE *) NULL) {
- warn("can't create/modify groups for login %s: can't open %s",
- login, _PATH_GROUP);
+ struct group *grp;
+ struct stat st;
+ FILE *from;
+ FILE *to;
+ char buf[LINE_MAX];
+ char f[MaxFileNameLen];
+ char *colon;
+ int groupc;
+ int entc;
+ int fd;
+ int nc;
+ int cc;
+ int i;
+ int j;
+
+ for (i = 0 ; i < ngroups ; i++) {
+ if ((grp = getgrnam(groups[i])) == NULL) {
+ warnx("can't append group `%s' for user `%s'",
+ groups[i], user);
+ } else {
+ for (j = 0 ; grp->gr_mem[j] ; j++) {
+ if (strcmp(user, grp->gr_mem[j]) == 0) {
+ /* already in it */
+ groups[i] = "";
+ }
+ }
+ }
+ }
+ if ((from = fopen(_PATH_GROUP, "r")) == NULL) {
+ warn("can't append group for %s: can't open %s", user,
+ _PATH_GROUP);
return 0;
}
if (flock(fileno(from), LOCK_EX | LOCK_NB) < 0) {
warn("can't lock `%s'", _PATH_GROUP);
}
(void) fstat(fileno(from), &st);
- (void) snprintf(tmpf, sizeof (tmpf), "%s.XXXXXX", _PATH_GROUP);
- if ((fd = mkstemp (tmpf)) < 0) {
+ (void) snprintf(f, sizeof(f), "%s.XXXXXXXX", _PATH_GROUP);
+ if ((fd = mkstemp(f)) < 0) {
(void) fclose(from);
- warn("can't modify secondary groups: mkstemp failed");
+ warn("can't create gid: mkstemp failed");
return 0;
}
- if ((to = fdopen(fd, "w")) == (FILE *) NULL) {
+ if ((to = fdopen(fd, "w")) == NULL) {
(void) fclose(from);
(void) close(fd);
- (void) unlink(tmpf);
- warn("can't create gid: fdopen `%s' failed", tmpf);
+ (void) unlink(f);
+ warn("can't create gid: fdopen `%s' failed", f);
return 0;
}
-
- while (fgets (buf, sizeof(buf), from) != NULL) {
- if ((colon = strchr (buf, ':')) == NULL) {
- warn ("badly formed entry `%s'", buf);
+ while (fgets(buf, sizeof(buf), from) != NULL) {
+ cc = strlen(buf);
+ if (buf[cc - 1] != '\n') {
+ while (!feof(from) && fgetc(from) != '\n')
+ cc++;
+ warn("line `%s' too long (%d bytes), skipping", buf,
+ cc);
continue;
}
-
- /* Does the user exist in this group? */
- cc = strlen (buf);
- g = strlen (login);
- p = colon;
- while (p < (buf + cc) && (p = strstr (p, login)) != NULL &&
- *(p + g) != ',' && *(p + g) != '\n')
- p += g;
- if (p && p < (buf + cc)) {
- /* Remove. XXX Un-obfuscate. */
- bcopy (*(p + g) == ',' ? (p + g + 1) : (p + g),
- *(p - 1) == ',' && *(p + g) != ',' ? p - 1 : p,
- strlen (p + g) + 1);
+ if ((colon = strchr(buf, ':')) == NULL) {
+ warn("badly formed entry `%s'", buf);
+ continue;
}
-
- /* Should the user exist in this group? */
- cc = strlen (primgrp);
- for (g = 0; g < up->u_groupc; g++) {
- if (!up->u_groupv[g] ||
- !strncmp (up->u_groupv[g], primgrp,
- MAX (strlen (up->u_groupv[g]), cc)))
- continue;
- if ((int)(colon - buf) == strlen (up->u_groupv[g]) &&
- !strncmp (up->u_groupv[g], buf,
- (int)(colon - buf))) {
- /* Add user. */
- p = buf + strlen(buf) - 1; /* No '\n' */
- snprintf (p, sizeof (buf), "%s%s\n",
- (*(p-1) == ':' ? "" : ",") ,
- (newlogin ? newlogin : login));
- up->u_groupv[g] = '\0'; /* Mark used. */
- g = up->u_groupc; /* Break loop. */
+ entc = (int)(colon - buf);
+ for (i = 0 ; i < ngroups ; i++) {
+ if ((groupc = strlen(groups[i])) == 0) {
+ continue;
+ }
+ if (cc >= sizeof(buf)) {
+ warn("line `%s' too long, skipping", buf);
+ continue;
+ }
+ if (entc == groupc && strncmp(groups[i], buf, entc) == 0) {
+ if ((nc = snprintf(&buf[cc - 1],
+ sizeof(buf) - cc + 1,
+ "%s%s\n",
+ (buf[cc - 2] == ':') ? "" : ",",
+ user)) >= sizeof(buf) - cc + 1) {
+ warnx("Warning: group `%s' entry too long", groups[i]);
+ }
+ cc += nc - 1;
}
}
-
- cc = strlen (buf);
- if (fwrite (buf, sizeof (char), cc, to) != cc) {
- (void) fclose (from);
- (void) close (fd);
- (void) unlink (tmpf);
- warn ("can't update secondary groups: "
- "short write to `%s'", tmpf);
+ if (fwrite(buf, sizeof(char), cc, to) != cc) {
+ (void) fclose(from);
+ (void) close(fd);
+ (void) unlink(f);
+ warn("can't create gid: short write to `%s'", f);
return 0;
}
}
- (void) fclose (from);
- (void) fclose (to);
- if (rename (tmpf, _PATH_GROUP) < 0) {
- warn("can't create gid: can't rename `%s' to `%s'", tmpf,
- _PATH_GROUP);
+ (void) fclose(from);
+ (void) fclose(to);
+ if (rename(f, _PATH_GROUP) < 0) {
+ warn("can't create gid: can't rename `%s' to `%s'", f, _PATH_GROUP);
return 0;
}
(void) chmod(_PATH_GROUP, st.st_mode & 07777);
- /* Warn about unselected groups. */
- for (g = 0; g < up->u_groupc; g++)
- if (up->u_groupv[g])
- warnx("extraneous group `%s' not added",
- up->u_groupv[g]);
return 1;
}
@@ -503,7 +579,7 @@ static int
getnextgid(int *gidp, int lo, int hi)
{
for (*gidp = lo ; *gidp < hi ; *gidp += 1) {
- if (getgrgid((gid_t)*gidp) == (struct group *) NULL) {
+ if (getgrgid((gid_t)*gidp) == NULL) {
return 1;
}
}
@@ -553,14 +629,16 @@ setdefaults(user_t *up)
FILE *fp;
int ret;
int fd;
+#ifdef EXTENSIONS
int i;
+#endif
- (void) snprintf(template, sizeof(template), "%s.XXXXXX", CONFFILE);
+ (void) snprintf(template, sizeof(template), "%s.XXXXXXXX", CONFFILE);
if ((fd = mkstemp(template)) < 0) {
warnx("can't mkstemp `%s' for writing", CONFFILE);
return 0;
}
- if ((fp = fdopen(fd, "w")) == (FILE *) NULL) {
+ if ((fp = fdopen(fd, "w")) == NULL) {
warn("can't fdopen `%s' for writing", CONFFILE);
return 0;
}
@@ -569,8 +647,12 @@ setdefaults(user_t *up)
fprintf(fp, "base_dir\t%s\n", up->u_basedir) <= 0 ||
fprintf(fp, "skel_dir\t%s\n", up->u_skeldir) <= 0 ||
fprintf(fp, "shell\t\t%s\n", up->u_shell) <= 0 ||
+#ifdef EXTENSIONS
+ fprintf(fp, "class\t\t%s\n", up->u_class) <= 0 ||
+#endif
fprintf(fp, "inactive\t%d\n", up->u_inactive) <= 0 ||
- fprintf(fp, "expire\t\t%s\n", (up->u_expire == NULL) ? UNSET_EXPIRY : up->u_expire) <= 0) {
+ fprintf(fp, "expire\t\t%s\n", (up->u_expire == NULL) ? UNSET_EXPIRY : up->u_expire) <= 0 ||
+ fprintf(fp, "preserve\t%s\n", (up->u_preserve == 0) ? "false" : "true") <= 0) {
warn("can't write to `%s'", CONFFILE);
ret = 0;
}
@@ -605,18 +687,21 @@ read_defaults(user_t *up)
memsave(&up->u_skeldir, DEF_SKELDIR, strlen(DEF_SKELDIR));
memsave(&up->u_shell, DEF_SHELL, strlen(DEF_SHELL));
memsave(&up->u_comment, DEF_COMMENT, strlen(DEF_COMMENT));
+#ifdef EXTENSIONS
+ memsave(&up->u_class, DEF_CLASS, strlen(DEF_CLASS));
+#endif
up->u_rsize = 16;
up->u_defrc = 0;
NEWARRAY(range_t, up->u_rv, up->u_rsize, exit(1));
up->u_inactive = DEF_INACTIVE;
up->u_expire = DEF_EXPIRE;
- if ((fp = fopen(CONFFILE, "r")) == (FILE *) NULL) {
+ if ((fp = fopen(CONFFILE, "r")) == NULL) {
if (stat(CONFFILE, &st) < 0 && !setdefaults(up)) {
warn("can't create `%s' defaults file", CONFFILE);
}
fp = fopen(CONFFILE, "r");
}
- if (fp != (FILE *) NULL) {
+ if (fp != NULL) {
while ((s = fparseln(fp, &len, &lineno, NULL, 0)) != NULL) {
if (strncmp(s, "group", 5) == 0) {
for (cp = s + 5 ; *cp && isspace(*cp) ; cp++) {
@@ -638,6 +723,12 @@ read_defaults(user_t *up)
for (cp = s + 8 ; *cp && isspace(*cp) ; cp++) {
}
memsave(&up->u_password, cp, strlen(cp));
+#ifdef EXTENSIONS
+ } else if (strncmp(s, "class", 5) == 0) {
+ for (cp = s + 5 ; *cp && isspace(*cp) ; cp++) {
+ }
+ memsave(&up->u_class, cp, strlen(cp));
+#endif
} else if (strncmp(s, "inactive", 8) == 0) {
for (cp = s + 8 ; *cp && isspace(*cp) ; cp++) {
}
@@ -685,9 +776,9 @@ static int
getnextuid(int sync_uid_gid, int *uid, int low_uid, int high_uid)
{
for (*uid = low_uid ; *uid <= high_uid ; (*uid)++) {
- if (getpwuid((uid_t)(*uid)) == (struct passwd *) NULL && *uid != NOBODY_UID) {
+ if (getpwuid((uid_t)(*uid)) == NULL && *uid != NOBODY_UID) {
if (sync_uid_gid) {
- if (getgrgid((gid_t)(*uid)) == (struct group *) NULL) {
+ if (getgrgid((gid_t)(*uid)) == NULL) {
return 1;
}
} else {
@@ -753,23 +844,23 @@ adduser(char *login, user_t *up)
}
}
/* check uid isn't already allocated */
- if (!up->u_dupuid && getpwuid((uid_t)(up->u_uid)) != (struct passwd *) NULL) {
+ if (!(up->u_flags & F_DUPUID) && getpwuid((uid_t)(up->u_uid)) != NULL) {
(void) close(ptmpfd);
(void) pw_abort();
errx(EXIT_FAILURE, "uid %d is already in use", up->u_uid);
}
/* if -g=uid was specified, check gid is unused */
if (sync_uid_gid) {
- if (getgrgid((gid_t)(up->u_uid)) != (struct group *) NULL) {
+ if (getgrgid((gid_t)(up->u_uid)) != NULL) {
(void) close(ptmpfd);
(void) pw_abort();
errx(EXIT_FAILURE, "gid %d is already in use", up->u_uid);
}
gid = up->u_uid;
- } else if ((grp = getgrnam(up->u_primgrp)) != (struct group *) NULL) {
+ } else if ((grp = getgrnam(up->u_primgrp)) != NULL) {
gid = grp->gr_gid;
} else if (is_number(up->u_primgrp) &&
- (grp = getgrgid((gid_t)atoi(up->u_primgrp))) != (struct group *) NULL) {
+ (grp = getgrgid((gid_t)atoi(up->u_primgrp))) != NULL) {
gid = grp->gr_gid;
} else {
(void) close(ptmpfd);
@@ -777,12 +868,12 @@ adduser(char *login, user_t *up)
errx(EXIT_FAILURE, "group %s not found", up->u_primgrp);
}
/* check name isn't already in use */
- if (!up->u_dupuid && getpwnam(login) != (struct passwd *) NULL) {
+ if (!(up->u_flags & F_DUPUID) && getpwnam(login) != NULL) {
(void) close(ptmpfd);
(void) pw_abort();
errx(EXIT_FAILURE, "already a `%s' user", login);
}
- if (up->u_homeset) {
+ if (up->u_flags & F_HOMEDIR) {
(void) strlcpy(home, up->u_home, sizeof(home));
} else {
/* if home directory hasn't been given, make it up */
@@ -797,6 +888,10 @@ adduser(char *login, user_t *up)
expire = mktime(&tm);
}
}
+ if (lstat(home, &st) < 0 && !(up->u_flags & F_MKDIR)) {
+ warnx("Warning: home directory `%s' doesn't exist, and -m was"
+ " not specified", home);
+ }
if (up->u_password != NULL &&
strlen(up->u_password) <= PasswordLength) {
(void) strlcpy(password, up->u_password, sizeof(password));
@@ -807,19 +902,24 @@ adduser(char *login, user_t *up)
up->u_password, password);
}
}
- cc = snprintf(buf, sizeof(buf), "%s:%s:%d:%d::%d:%ld:%s:%s:%s\n",
+ cc = snprintf(buf, sizeof(buf), "%s:%s:%d:%d:%s:%d:%ld:%s:%s:%s\n",
login,
password,
up->u_uid,
gid,
+#ifdef EXTENSIONS
+ up->u_class,
+#else
+ "",
+#endif
up->u_inactive,
(long) expire,
up->u_comment,
home,
up->u_shell);
- if (cc >= MaxPasswordEntryLen ||
+ if (cc >= sizeof(buf) ||
(strchr(up->u_comment, '&') != NULL &&
- cc + strlen(login) >= MaxPasswordEntryLen)) {
+ cc + strlen(login) >= sizeof(buf))) {
(void) close(ptmpfd);
(void) pw_abort();
errx(EXIT_FAILURE, "can't add `%s', line too long", buf);
@@ -829,29 +929,32 @@ adduser(char *login, user_t *up)
(void) pw_abort();
err(EXIT_FAILURE, "can't add `%s'", buf);
}
- if (up->u_mkdir) {
- if (lstat(home, &st) < 0 && asystem("%s -p %s", MKDIR, home) != 0) {
+ if (up->u_flags & F_MKDIR) {
+ if (lstat(home, &st) == 0) {
(void) close(ptmpfd);
(void) pw_abort();
- err(EXIT_FAILURE, "can't mkdir `%s'", home);
+ errx(EXIT_FAILURE, "home directory `%s' already exists",
+ home);
+ } else {
+ if (asystem("%s -p %s", MKDIR, home) != 0) {
+ (void) close(ptmpfd);
+ (void) pw_abort();
+ err(EXIT_FAILURE, "can't mkdir `%s'", home);
+ }
+ (void) copydotfiles(up->u_skeldir, up->u_uid, gid, home);
}
- (void) copydotfiles(up->u_skeldir, up->u_uid, gid, home);
}
- if (sync_uid_gid &&
- getgrnam(login) == (struct group *) NULL &&
- !creategid(login, gid)) {
+ if (strcmp(up->u_primgrp, "=uid") == 0 && getgrnam(login) == NULL &&
+ !creategid(login, gid, login)) {
(void) close(ptmpfd);
(void) pw_abort();
- err(EXIT_FAILURE, "can't create gid %d for login name %s", gid, login);
+ err(EXIT_FAILURE, "can't create gid %d for login name %s",
+ gid, login);
}
- /* Modify secondary groups */
- if (up->u_groupc != 0 &&
- !modify_groups (login, NULL, up,
- (sync_uid_gid ? login : up->u_primgrp))) {
- (void) close(ptmpfd);
- (void) pw_abort();
- err(EXIT_FAILURE,
- "failed to modify secondary groups for login %s", login);
+ if (up->u_groupc > 0 && !append_group(login, up->u_groupc, up->u_groupv)) {
+ (void) close(ptmpfd);
+ (void) pw_abort();
+ errx(EXIT_FAILURE, "can't append `%s' to new groups", login);
}
(void) close(ptmpfd);
if (pw_mkdb(login, 0) < 0) {
@@ -867,26 +970,25 @@ moduser(char *login, char *newlogin, user_t *up)
struct passwd *pwp;
struct group *grp;
struct tm tm;
- time_t expire;
- size_t loginc;
- size_t colonc;
+ const char *homedir;
+ char newdir[MaxFileNameLen];
+ char buf[LINE_MAX];
+ size_t colonc, len, loginc;
FILE *master;
- char password[PasswordLength + 1];
- char oldhome[MaxFileNameLen];
- char home[MaxFileNameLen];
- char buf[MaxFileNameLen];
- char *colon;
+ char *colon, *line;
int masterfd;
int ptmpfd;
- int gid;
- int cc;
+ int rval;
if (!valid_login(newlogin)) {
errx(EXIT_FAILURE, "`%s' is not a valid login name", login);
}
- if ((pwp = getpwnam(login)) == (struct passwd *) NULL) {
+ if ((pwp = getpwnam(login)) == NULL) {
errx(EXIT_FAILURE, "No such user `%s'", login);
}
+ /* keep dir name in case we need it for '-m' */
+ homedir = pwp->pw_dir;
+
if ((masterfd = open(_PATH_MASTERPASSWD, O_RDONLY)) < 0) {
err(EXIT_FAILURE, "can't open `%s'", _PATH_MASTERPASSWD);
}
@@ -898,139 +1000,155 @@ moduser(char *login, char *newlogin, user_t *up)
(void) close(masterfd);
err(EXIT_FAILURE, "can't obtain pw_lock");
}
- if ((master = fdopen(masterfd, "r")) == (FILE *) NULL) {
+ if ((master = fdopen(masterfd, "r")) == NULL) {
(void) close(masterfd);
(void) close(ptmpfd);
(void) pw_abort();
err(EXIT_FAILURE, "can't fdopen fd for %s", _PATH_MASTERPASSWD);
}
- if (up != (user_t *) NULL) {
- if (up->u_mkdir) {
- (void) strlcpy(oldhome, pwp->pw_dir, sizeof(oldhome));
- }
- if (up->u_uid == -1) {
- up->u_uid = pwp->pw_uid;
- }
- if (up->u_primgrp == NULL) {
- gid = pwp->pw_gid;
- } else if (strcmp(up->u_primgrp, "=uid") == 0) {
- /* if -g=uid was specified, check gid is unused */
- if (getgrgid((gid_t)(up->u_uid)) != (struct group *) NULL) {
+ if (up != NULL) {
+ if (up->u_flags & F_USERNAME) {
+ /* if changing name, check new name isn't already in use */
+ if (strcmp(login, newlogin) != 0 && getpwnam(newlogin) != NULL) {
(void) close(ptmpfd);
(void) pw_abort();
- errx(EXIT_FAILURE, "gid %d is already in use", up->u_uid);
+ errx(EXIT_FAILURE, "already a `%s' user", newlogin);
+ }
+ pwp->pw_name = newlogin;
+
+ /*
+ * Provide a new directory name in case the
+ * home directory is to be moved.
+ */
+ if (up->u_flags & F_MKDIR) {
+ (void) snprintf(newdir, sizeof(newdir),
+ "%s/%s", up->u_basedir, newlogin);
+ pwp->pw_dir = newdir;
}
- gid = up->u_uid;
- } else if ((grp = getgrnam(up->u_primgrp)) != (struct group *) NULL) {
- gid = grp->gr_gid;
- } else if (is_number(up->u_primgrp) &&
- (grp = getgrgid((gid_t)atoi(up->u_primgrp))) != (struct group *) NULL) {
- gid = grp->gr_gid;
- } else {
- (void) close(ptmpfd);
- (void) pw_abort();
- errx(EXIT_FAILURE, "group %s not found", up->u_primgrp);
}
- /* if changing name, check new name isn't already in use */
- if (strcmp(login, newlogin) != 0 && getpwnam(newlogin) != (struct passwd *) NULL) {
- (void) close(ptmpfd);
- (void) pw_abort();
- errx(EXIT_FAILURE, "already a `%s' user", newlogin);
+ if (up->u_flags & F_PASSWORD) {
+ if (up->u_password != NULL && strlen(up->u_password) == PasswordLength)
+ pwp->pw_passwd = up->u_password;
}
- /* if home directory hasn't been given, use the old one */
- if (!up->u_homeset) {
- (void) strlcpy(home, pwp->pw_dir, sizeof(home));
- } else {
- (void) strlcpy(home, up->u_home, sizeof(home));
+ 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) {
+ (void) close(ptmpfd);
+ (void) pw_abort();
+ errx(EXIT_FAILURE, "uid %d is already in use", up->u_uid);
+ }
+ pwp->pw_uid = up->u_uid;
}
- expire = 0;
- if (up->u_expire != NULL) {
- (void) memset(&tm, 0, sizeof(tm));
- if (strptime(up->u_expire, "%c", &tm) == NULL) {
- warnx("invalid time format `%s'", optarg);
+ if (up->u_flags & F_GROUP) {
+ /* if -g=uid was specified, check gid is unused */
+ if (strcmp(up->u_primgrp, "=uid") == 0) {
+ if (getgrgid((gid_t)(up->u_uid)) != NULL) {
+ (void) close(ptmpfd);
+ (void) pw_abort();
+ errx(EXIT_FAILURE, "gid %d is already in use", up->u_uid);
+ }
+ pwp->pw_gid = up->u_uid;
+ } else if ((grp = getgrnam(up->u_primgrp)) != NULL) {
+ pwp->pw_gid = grp->gr_gid;
+ } else if (is_number(up->u_primgrp) &&
+ (grp = getgrgid((gid_t)atoi(up->u_primgrp))) != NULL) {
+ pwp->pw_gid = grp->gr_gid;
} else {
- expire = mktime(&tm);
+ (void) close(ptmpfd);
+ (void) pw_abort();
+ errx(EXIT_FAILURE, "group %s not found", up->u_primgrp);
}
}
- if (up->u_password != NULL &&
- strlen(up->u_password) <= PasswordLength) {
- (void) strlcpy(password, up->u_password, sizeof(password));
- } else {
- (void) strlcpy(password, pwp->pw_passwd, sizeof(password));
- }
- if (strcmp(up->u_comment, DEF_COMMENT) == 0) {
- memsave(&up->u_comment, pwp->pw_gecos, strlen(pwp->pw_gecos));
- }
- if (strcmp(up->u_shell, DEF_SHELL) == 0 && strcmp(pwp->pw_shell, DEF_SHELL) != 0) {
- memsave(&up->u_shell, pwp->pw_shell, strlen(pwp->pw_shell));
+ if (up->u_flags |= F_INACTIVE)
+ pwp->pw_change = up->u_inactive;
+ if (up->u_flags & F_EXPIRE) {
+ (void) memset(&tm, 0, sizeof(tm));
+ if (strptime(up->u_expire, "%c", &tm) == NULL)
+ warnx("invalid time format `%s'", optarg);
+ else
+ pwp->pw_expire = mktime(&tm);
}
+ if (up->u_flags & F_COMMENT)
+ pwp->pw_gecos = up->u_comment;
+ if (up->u_flags & F_HOMEDIR)
+ pwp->pw_dir = up->u_home;
+ if (up->u_flags & F_SHELL)
+ pwp->pw_shell = up->u_shell;
+#ifdef EXTENSIONS
+ if (up->u_flags & F_CLASS)
+ pwp->pw_class = up->u_class;
+#endif
}
loginc = strlen(login);
- while (fgets(buf, sizeof(buf), master) != NULL) {
- cc = strlen(buf);
- if ((colon = strchr(buf, ':')) == NULL) {
- warnx("Malformed entry `%s'. Skipping", buf);
+ while ((line = fgetln(master, &len)) != NULL) {
+ if ((colon = strchr(line, ':')) == NULL) {
+ warnx("Malformed entry `%s'. Skipping", line);
continue;
}
- colonc = (size_t)(colon - buf);
- if (strncmp(login, buf, loginc) == 0 && loginc == colonc) {
- if (up != (user_t *) NULL) {
- cc = snprintf(buf, sizeof(buf), "%s:%s:%d:%d::%d:%ld:%s:%s:%s\n",
+ colonc = (size_t)(colon - line);
+ if (strncmp(login, line, loginc) == 0 && loginc == colonc) {
+ if (up != NULL) {
+ len = snprintf(buf, sizeof(buf),
+ "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
newlogin,
- password,
- up->u_uid,
- gid,
- up->u_inactive,
- (long) expire,
- up->u_comment,
- home,
- up->u_shell);
- if (cc >= MaxPasswordEntryLen ||
+ pwp->pw_passwd,
+ pwp->pw_uid,
+ pwp->pw_gid,
+#ifdef EXTENSIONS
+ pwp->pw_class,
+#else
+ "",
+#endif
+ (long)pwp->pw_change,
+ (long)pwp->pw_expire,
+ pwp->pw_gecos,
+ pwp->pw_dir,
+ pwp->pw_shell);
+ if (len >= sizeof(buf) ||
(strchr(up->u_comment, '&') != NULL &&
- cc + strlen(newlogin) >= MaxPasswordEntryLen)) {
+ len + strlen(newlogin) >= sizeof(buf))) {
(void) close(ptmpfd);
(void) pw_abort();
- errx(EXIT_FAILURE, "can't add `%s', line too long (%d bytes)", buf, cc + strlen(newlogin));
+ errx(EXIT_FAILURE, "can't add `%s', line too long (%d bytes)", buf, len + strlen(newlogin));
}
- if (write(ptmpfd, buf, (size_t) cc) != cc) {
+ if (write(ptmpfd, buf, len) != len) {
(void) close(ptmpfd);
(void) pw_abort();
err(EXIT_FAILURE, "can't add `%s'", buf);
}
- /* Modify secondary groups */
- grp = getgrgid (gid);
- if (up->u_groupc != 0 ||
- strcmp (login, newlogin))
- if (!modify_groups (login, NULL, up, grp ? grp->gr_name : newlogin)) {
- (void) close(ptmpfd);
- (void) pw_abort();
- err(EXIT_FAILURE,
- "failed to modify secondary groups for login %s",
- login);
- }
}
- } else if (write(ptmpfd, buf, (size_t)(cc)) != cc) {
+ } else if ((colonc = write(ptmpfd, line, len)) != len) {
(void) close(masterfd);
(void) close(ptmpfd);
(void) pw_abort();
- err(EXIT_FAILURE, "short write to /etc/ptmp (not %d chars)", cc);
+ err(EXIT_FAILURE, "short write to /etc/ptmp (%lld not %lld chars)",
+ (long long)colonc, (long long)len);
}
}
- if (up != (user_t *) NULL &&
- up->u_mkdir &&
- asystem("%s %s %s", MV, oldhome, home) != 0) {
- (void) close(ptmpfd);
- (void) pw_abort();
- err(EXIT_FAILURE, "can't move `%s' to `%s'", oldhome, home);
+ if (up != NULL) {
+ if ((up->u_flags & F_MKDIR) &&
+ asystem("%s %s %s", MV, homedir, pwp->pw_dir) != 0) {
+ (void) close(ptmpfd);
+ (void) pw_abort();
+ err(EXIT_FAILURE, "can't move `%s' to `%s'",
+ homedir, pwp->pw_dir);
+ }
+ if (up->u_groupc > 0 &&
+ !append_group(newlogin, up->u_groupc, up->u_groupv)) {
+ (void) close(ptmpfd);
+ (void) pw_abort();
+ errx(EXIT_FAILURE, "can't append `%s' to new groups",
+ newlogin);
+ }
}
(void) close(ptmpfd);
- if (up != (user_t *) NULL && strcmp(login, newlogin) == 0)
- cc = pw_mkdb(login, 0);
+ if (up != NULL && strcmp(login, newlogin) == 0)
+ rval = pw_mkdb(login, 0);
else
- cc = pw_mkdb(NULL, 0);
- if (cc < 0) {
+ rval = pw_mkdb(NULL, 0);
+ if (rval == -1)
err(EXIT_FAILURE, "pw_mkdb failed");
- }
+
return 1;
}
@@ -1042,13 +1160,13 @@ find_user_info(char *name)
{
struct passwd *pwp;
- if ((pwp = getpwnam(name)) != (struct passwd *) NULL) {
+ if ((pwp = getpwnam(name)) != NULL) {
return pwp;
}
- if (is_number(name) && (pwp = getpwuid((uid_t)atoi(name))) != (struct passwd *) NULL) {
+ if (is_number(name) && (pwp = getpwuid((uid_t)atoi(name))) != NULL) {
return pwp;
}
- return (struct passwd *) NULL;
+ return NULL;
}
#endif
@@ -1059,51 +1177,51 @@ find_group_info(char *name)
{
struct group *grp;
- if ((grp = getgrnam(name)) != (struct group *) NULL) {
+ if ((grp = getgrnam(name)) != NULL) {
return grp;
}
- if (is_number(name) && (grp = getgrgid((gid_t)atoi(name))) != (struct group *) NULL) {
+ if (is_number(name) && (grp = getgrgid((gid_t)atoi(name))) != NULL) {
return grp;
}
- return (struct group *) NULL;
+ return NULL;
}
#endif
/* print out usage message, and then exit */
void
-usermgmt_usage(char *prog)
+usermgmt_usage(const char *prog)
{
if (strcmp(prog, "useradd") == 0) {
(void) fprintf(stderr, "usage: %s -D [-b basedir] [-e expiry] "
- "[-f inactive] [-g group]\n\t\t[-r lowuid..highuid] "
- "[-s shell]\n", prog);
- (void) fprintf(stderr, "usage: %s [-G group[,group,...]] "
- "[-b basedir] [-c comment] [-d homedir]\n\t\t"
- "[-e expiry] [-f inactive] [-g group] "
- "[-k skeletondir]\n\t\t[-m] [-o] [-p password] "
- "[-r lowuid..highuid]\n\t\t[-s shell] [-u uid] "
- "[-v] user\n", prog);
+ "[-f changetime] [-g group]\n\t\t[-k skeletondir] "
+ "[-r low..high] [-s shell] [-L class]\n", prog);
+ (void) fprintf(stderr, "usage: %s [-mov] [-G group[,group,...]]"
+ " [-b basedir] [-c comment]\n\t\t"
+ "[-d homedir] [-e expiry] [-f changetime] [-g group]\n\t\t"
+ "[-k skeletondir] [-p password] "
+ "[-r lowuid..highuid]\n\t\t[-s shell] [-u uid] [-L class] "
+ "user\n", prog);
} else if (strcmp(prog, "usermod") == 0) {
- (void) fprintf(stderr, "usage: %s [-G group[,group,...]] "
- "[-c comment] [-d homedir] [-e expire]\n\t\t"
- "[-f inactive] [-g group] [-l newname] [-m] [-o]\n\t\t"
- "[-p password] [-s shell] [-u uid] [-v] user\n", prog);
+ (void) fprintf(stderr, "usage: %s [-mov] [-G group[,group,...]]"
+ " [-c comment] [-d homedir]\n\t\t"
+ "[-e expire] [-f changetime] [-g group] [-l newname]\n\t\t"
+ "[-p password] [-s shell] [-u uid] [-L class] user\n",
+ prog);
} else if (strcmp(prog, "userdel") == 0) {
(void) fprintf(stderr, "usage: %s -D [-p preserve]\n", prog);
- (void) fprintf(stderr, "usage: %s [-p preserve] [-r] [-v] "
- "user\n", prog);
+ (void) fprintf(stderr, "usage: %s [-prv] user\n", prog);
#ifdef EXTENSIONS
} else if (strcmp(prog, "userinfo") == 0) {
- (void) fprintf(stderr, "usage: %s [-e] [-v] user\n", prog);
+ (void) fprintf(stderr, "usage: %s [-ev] user\n", prog);
#endif
} else if (strcmp(prog, "groupadd") == 0) {
- (void) fprintf(stderr, "usage: %s [-g gid] [-o] [-v] group\n",
+ (void) fprintf(stderr, "usage: %s [-ov] [-g gid] group\n",
prog);
} else if (strcmp(prog, "groupdel") == 0) {
(void) fprintf(stderr, "usage: %s [-v] group\n", prog);
} else if (strcmp(prog, "groupmod") == 0) {
- (void) fprintf(stderr, "usage: %s [-g gid] [-o] [-n newname] "
- "[-v] group\n", prog);
+ (void) fprintf(stderr, "usage: %s [-ov] [-g gid] [-n newname] "
+ "group\n", prog);
} else if (strcmp(prog, "user") == 0 || strcmp(prog, "group") == 0) {
(void) fprintf(stderr, "usage: %s [ add | del | mod "
#ifdef EXTENSIONS
@@ -1113,7 +1231,7 @@ usermgmt_usage(char *prog)
prog);
#ifdef EXTENSIONS
} else if (strcmp(prog, "groupinfo") == 0) {
- (void) fprintf(stderr, "usage: %s [-e] [-v] group\n", prog);
+ (void) fprintf(stderr, "usage: %s [-ev] group\n", prog);
#endif
} else {
(void) fprintf(stderr, "This program must be called as {user,group}{add,del,mod,info},\n%s is not an understood name.\n", prog);
@@ -1123,7 +1241,7 @@ usermgmt_usage(char *prog)
}
#ifdef EXTENSIONS
-#define ADD_OPT_EXTENSIONS "p:r:v"
+#define ADD_OPT_EXTENSIONS "p:r:vL:"
#else
#define ADD_OPT_EXTENSIONS
#endif
@@ -1135,8 +1253,9 @@ useradd(int argc, char **argv)
int defaultfield;
int bigD;
int c;
+#ifdef EXTENSIONS
int i;
- char buf[MaxEntryLen], *s, *p;
+#endif
(void) memset(&u, 0, sizeof(u));
read_defaults(&u);
@@ -1148,14 +1267,15 @@ useradd(int argc, char **argv)
bigD = 1;
break;
case 'G':
- strlcpy (buf, optarg, sizeof(buf));
- p = buf;
- while ((s = strsep (&p, ",")) != NULL &&
- u.u_groupc < NGROUPS_MAX - 2)
- memsave (&u.u_groupv[u.u_groupc++], s,
- strlen(s));
- if (p != NULL)
- errx(EXIT_FAILURE, "too many groups for -G");
+ while ((u.u_groupv[u.u_groupc] = strsep(&optarg, ",")) != NULL &&
+ u.u_groupc < NGROUPS_MAX - 2) {
+ if (u.u_groupv[u.u_groupc][0] != 0) {
+ u.u_groupc++;
+ }
+ }
+ if (optarg != NULL) {
+ warnx("Truncated list of secondary groups to %d entries", NGROUPS_MAX - 2);
+ }
break;
case 'b':
defaultfield = 1;
@@ -1165,8 +1285,8 @@ useradd(int argc, char **argv)
memsave(&u.u_comment, optarg, strlen(optarg));
break;
case 'd':
- u.u_homeset = 1;
memsave(&u.u_home, optarg, strlen(optarg));
+ u.u_flags |= F_HOMEDIR;
break;
case 'e':
defaultfield = 1;
@@ -1183,11 +1303,17 @@ useradd(int argc, char **argv)
case 'k':
memsave(&u.u_skeldir, optarg, strlen(optarg));
break;
+#ifdef EXTENSIONS
+ case 'L':
+ defaultfield = 1;
+ memsave(&u.u_class, optarg, strlen(optarg));
+ break;
+#endif
case 'm':
- u.u_mkdir = 1;
+ u.u_flags |= F_MKDIR;
break;
case 'o':
- u.u_dupuid = 1;
+ u.u_flags |= F_DUPUID;
break;
#ifdef EXTENSIONS
case 'p':
@@ -1226,6 +1352,9 @@ useradd(int argc, char **argv)
(void) printf("base_dir\t%s\n", u.u_basedir);
(void) printf("skel_dir\t%s\n", u.u_skeldir);
(void) printf("shell\t\t%s\n", u.u_shell);
+#ifdef EXTENSIONS
+ (void) printf("class\t\t%s\n", u.u_class);
+#endif
(void) printf("inactive\t%d\n", u.u_inactive);
(void) printf("expire\t\t%s\n", (u.u_expire == NULL) ? UNSET_EXPIRY : u.u_expire);
#ifdef EXTENSIONS
@@ -1235,15 +1364,17 @@ useradd(int argc, char **argv)
#endif
return EXIT_SUCCESS;
}
- if (argc == optind) {
+ argc -= optind;
+ argv += optind;
+ if (argc != 1) {
usermgmt_usage("useradd");
}
checkeuid();
- return adduser(argv[optind], &u) ? EXIT_SUCCESS : EXIT_FAILURE;
+ return adduser(*argv, &u) ? EXIT_SUCCESS : EXIT_FAILURE;
}
#ifdef EXTENSIONS
-#define MOD_OPT_EXTENSIONS "p:v"
+#define MOD_OPT_EXTENSIONS "p:vL:"
#else
#define MOD_OPT_EXTENSIONS
#endif
@@ -1253,68 +1384,81 @@ usermod(int argc, char **argv)
{
user_t u;
char newuser[MaxUserNameLen + 1];
- int have_new_user;
- int c;
- char buf[MaxEntryLen], *s, *p;
+ int c, have_new_user;
(void) memset(&u, 0, sizeof(u));
(void) memset(newuser, 0, sizeof(newuser));
read_defaults(&u);
- u.u_uid = -1;
free(u.u_primgrp);
u.u_primgrp = NULL;
have_new_user = 0;
while ((c = getopt(argc, argv, "G:c:d:e:f:g:l:mos:u:" MOD_OPT_EXTENSIONS)) != -1) {
switch(c) {
case 'G':
- strlcpy (buf, optarg, sizeof(buf));
- p = buf;
- while ((s = strsep (&p, ",")) != NULL &&
- u.u_groupc < NGROUPS_MAX - 2)
- memsave (&u.u_groupv[u.u_groupc++], s,
- strlen(s));
- if (p != NULL)
- errx(EXIT_FAILURE, "too many groups for -G");
+ while ((u.u_groupv[u.u_groupc] = strsep(&optarg, ",")) != NULL &&
+ u.u_groupc < NGROUPS_MAX - 2) {
+ if (u.u_groupv[u.u_groupc][0] != 0) {
+ u.u_groupc++;
+ }
+ }
+ if (optarg != NULL) {
+ warnx("Truncated list of secondary groups to %d entries", NGROUPS_MAX - 2);
+ }
+ u.u_flags |= F_SECGROUP;
break;
case 'c':
memsave(&u.u_comment, optarg, strlen(optarg));
+ u.u_flags |= F_COMMENT;
break;
case 'd':
- u.u_homeset = 1;
memsave(&u.u_home, optarg, strlen(optarg));
+ u.u_flags |= F_HOMEDIR;
break;
case 'e':
memsave(&u.u_expire, optarg, strlen(optarg));
+ u.u_flags |= F_EXPIRE;
break;
case 'f':
u.u_inactive = atoi(optarg);
+ u.u_flags |= F_INACTIVE;
break;
case 'g':
memsave(&u.u_primgrp, optarg, strlen(optarg));
+ u.u_flags |= F_GROUP;
break;
case 'l':
- have_new_user = 1;
(void) strlcpy(newuser, optarg, sizeof(newuser));
+ have_new_user = 1;
+ u.u_flags |= F_USERNAME;
+ break;
+#ifdef EXTENSIONS
+ case 'L':
+ memsave(&u.u_class, optarg, strlen(optarg));
+ u.u_flags |= F_CLASS;
break;
+#endif
case 'm':
- u.u_mkdir = 1;
+ u.u_flags |= F_MKDIR;
break;
case 'o':
- u.u_dupuid = 1;
+ u.u_flags |= F_DUPUID;
break;
#ifdef EXTENSIONS
case 'p':
memsave(&u.u_password, optarg, strlen(optarg));
+ u.u_flags |= F_PASSWORD;
break;
#endif
case 's':
memsave(&u.u_shell, optarg, strlen(optarg));
+ u.u_flags |= F_SHELL;
break;
case 'u':
if (!is_number(optarg)) {
errx(EXIT_FAILURE, "When using [-u uid], the uid must be numeric");
}
u.u_uid = atoi(optarg);
+ u.u_flags |= F_UID;
break;
#ifdef EXTENSIONS
case 'v':
@@ -1323,12 +1467,19 @@ usermod(int argc, char **argv)
#endif
}
}
- if (argc == optind) {
+ if ((u.u_flags & F_MKDIR) && !(u.u_flags & F_HOMEDIR) &&
+ !(u.u_flags & F_USERNAME)) {
+ warnx("option 'm' useless without 'd' or 'l' -- ignored");
+ u.u_flags &= ~F_MKDIR;
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc != 1) {
usermgmt_usage("usermod");
}
checkeuid();
- return moduser(argv[optind], (have_new_user) ? newuser : argv[optind],
- &u) ? EXIT_SUCCESS : EXIT_FAILURE;
+ return moduser(*argv, (have_new_user) ? newuser : *argv, &u) ?
+ EXIT_SUCCESS : EXIT_FAILURE;
}
#ifdef EXTENSIONS
@@ -1341,7 +1492,6 @@ int
userdel(int argc, char **argv)
{
struct passwd *pwp;
- struct stat st;
user_t u;
char password[PasswordLength + 1];
int defaultfield;
@@ -1387,28 +1537,26 @@ userdel(int argc, char **argv)
return EXIT_SUCCESS;
}
#endif
- if (argc == optind) {
+ argc -= optind;
+ argv += optind;
+ if (argc != 1) {
usermgmt_usage("userdel");
}
checkeuid();
- if ((pwp = getpwnam(argv[optind])) == (struct passwd *) NULL) {
- warnx("No such user `%s'", argv[optind]);
+ if ((pwp = getpwnam(*argv)) == NULL) {
+ warnx("No such user `%s'", *argv);
return EXIT_FAILURE;
}
- if (rmhome) {
- if (stat(pwp->pw_dir, &st) < 0) {
- warn("Home directory `%s' does not exist", pwp->pw_dir);
- return EXIT_FAILURE;
- }
- (void) asystem("%s -rf %s", RM, pwp->pw_dir);
- }
+ if (rmhome)
+ (void)removehomedir(pwp->pw_name, pwp->pw_uid, pwp->pw_dir);
if (u.u_preserve) {
memsave(&u.u_shell, NOLOGIN, strlen(NOLOGIN));
(void) strlcpy(password, "*", sizeof(password));
memsave(&u.u_password, password, PasswordLength);
- return moduser(argv[optind], argv[optind], &u) ? EXIT_SUCCESS : EXIT_FAILURE;
+ u.u_flags |= F_PASSWORD;
+ return moduser(*argv, *argv, &u) ? EXIT_SUCCESS : EXIT_FAILURE;
}
- return moduser(argv[optind], argv[optind], (user_t *) NULL) ? EXIT_SUCCESS : EXIT_FAILURE;
+ return moduser(*argv, *argv, NULL) ? EXIT_SUCCESS : EXIT_FAILURE;
}
#ifdef EXTENSIONS
@@ -1445,21 +1593,24 @@ groupadd(int argc, char **argv)
#endif
}
}
- if (argc == optind) {
+ argc -= optind;
+ argv += optind;
+ if (argc != 1) {
usermgmt_usage("groupadd");
}
checkeuid();
if (gid < 0 && !getnextgid(&gid, LowGid, HighGid)) {
err(EXIT_FAILURE, "can't add group: can't get next gid");
}
- if (!dupgid && getgrgid((gid_t) gid) != (struct group *) NULL) {
+ if (!dupgid && getgrgid((gid_t) gid) != NULL) {
errx(EXIT_FAILURE, "can't add group: gid %d is a duplicate", gid);
}
- if (!valid_group(argv[optind])) {
- warnx("warning - invalid group name `%s'", argv[optind]);
+ if (!valid_group(*argv)) {
+ warnx("warning - invalid group name `%s'", *argv);
}
- if (!creategid(argv[optind], gid)) {
- err(EXIT_FAILURE, "can't add group: problems with %s file", _PATH_GROUP);
+ if (!creategid(*argv, gid, "")) {
+ err(EXIT_FAILURE, "can't add group: problems with %s file",
+ _PATH_GROUP);
}
return EXIT_SUCCESS;
}
@@ -1485,11 +1636,13 @@ groupdel(int argc, char **argv)
#endif
}
}
- if (argc == optind) {
+ argc -= optind;
+ argv += optind;
+ if (argc != 1) {
usermgmt_usage("groupdel");
}
checkeuid();
- if (!modify_gid(argv[optind], NULL)) {
+ if (!modify_gid(*argv, NULL)) {
err(EXIT_FAILURE, "can't change %s file", _PATH_GROUP);
}
return EXIT_SUCCESS;
@@ -1506,7 +1659,7 @@ int
groupmod(int argc, char **argv)
{
struct group *grp;
- char buf[MaxEntryLen];
+ char buf[LINE_MAX];
char *newname;
char **cpp;
int dupgid;
@@ -1538,7 +1691,9 @@ groupmod(int argc, char **argv)
#endif
}
}
- if (argc == optind) {
+ argc -= optind;
+ argv += optind;
+ if (argc != 1) {
usermgmt_usage("groupmod");
}
checkeuid();
@@ -1548,24 +1703,26 @@ groupmod(int argc, char **argv)
if (dupgid && gid < 0) {
err(EXIT_FAILURE, "Duplicate which gid?");
}
- if ((grp = getgrnam(argv[optind])) == (struct group *) NULL) {
- err(EXIT_FAILURE, "can't find group `%s' to modify", argv[optind]);
+ if ((grp = getgrnam(*argv)) == NULL) {
+ err(EXIT_FAILURE, "can't find group `%s' to modify", *argv);
}
if (newname != NULL && !valid_group(newname)) {
warn("warning - invalid group name `%s'", newname);
}
cc = snprintf(buf, sizeof(buf), "%s:%s:%d:",
- (newname) ? newname : grp->gr_name,
- grp->gr_passwd,
+ (newname) ? newname : grp->gr_name, grp->gr_passwd,
(gid < 0) ? grp->gr_gid : gid);
for (cpp = grp->gr_mem ; *cpp && cc < sizeof(buf) ; cpp++) {
cc += snprintf(&buf[cc], sizeof(buf) - cc, "%s%s", *cpp,
(cpp[1] == NULL) ? "" : ",");
}
- cc += snprintf(&buf[cc], sizeof(buf) - cc, "\n");
- if (!modify_gid(argv[optind], buf)) {
+ if (cc < sizeof(buf))
+ cc += snprintf(&buf[cc], sizeof(buf) - cc, "\n");
+ else
+ err(EXIT_FAILURE, "group `%s' entry too long", grp->gr_name);
+
+ if (!modify_gid(*argv, buf))
err(EXIT_FAILURE, "can't change %s file", _PATH_GROUP);
- }
return EXIT_SUCCESS;
}
@@ -1576,10 +1733,8 @@ userinfo(int argc, char **argv)
{
struct passwd *pwp;
struct group *grp;
- char buf[MaxEntryLen];
char **cpp;
int exists;
- int cc;
int i;
exists = 0;
@@ -1593,37 +1748,40 @@ userinfo(int argc, char **argv)
break;
}
}
- if (argc == optind) {
+ argc -= optind;
+ argv += optind;
+ if (argc != 1) {
usermgmt_usage("userinfo");
}
- pwp = find_user_info(argv[optind]);
+ pwp = find_user_info(*argv);
if (exists) {
exit((pwp) ? EXIT_SUCCESS : EXIT_FAILURE);
}
- if (pwp == (struct passwd *) NULL) {
- errx(EXIT_FAILURE, "can't find user `%s'", argv[optind]);
+ if (pwp == NULL) {
+ errx(EXIT_FAILURE, "can't find user `%s'", *argv);
}
(void) printf("login\t%s\n", pwp->pw_name);
(void) printf("passwd\t%s\n", pwp->pw_passwd);
(void) printf("uid\t%d\n", pwp->pw_uid);
- for (cc = 0 ; (grp = getgrent()) != (struct group *) NULL ; ) {
+ if ((grp = getgrgid(pwp->pw_gid)) == NULL)
+ (void) printf("groups\t%d", pwp->pw_gid);
+ else
+ (void) printf("groups\t%s", grp->gr_name);
+ while ((grp = getgrent()) != NULL) {
for (cpp = grp->gr_mem ; *cpp ; cpp++) {
- if (strcmp(*cpp, argv[optind]) == 0 && grp->gr_gid != pwp->pw_gid) {
- cc += snprintf(&buf[cc], sizeof(buf) - cc, "%s ", grp->gr_name);
- }
+ if (strcmp(*cpp, *argv) == 0 && grp->gr_gid != pwp->pw_gid)
+ (void) printf(" %s", grp->gr_name);
}
}
- if ((grp = getgrgid(pwp->pw_gid)) == (struct group *) NULL) {
- (void) printf("groups\t%d %s\n", pwp->pw_gid, buf);
- } else {
- (void) printf("groups\t%s %s\n", grp->gr_name, buf);
- }
- (void) printf("change\t%s", ctime(&pwp->pw_change));
+ (void) fputc('\n', stdout);
+ (void) printf("change\t%s", pwp->pw_change ? ctime(&pwp->pw_change) : "NEVER\n");
+#ifdef EXTENSIONS
(void) printf("class\t%s\n", pwp->pw_class);
+#endif
(void) printf("gecos\t%s\n", pwp->pw_gecos);
(void) printf("dir\t%s\n", pwp->pw_dir);
(void) printf("shell\t%s\n", pwp->pw_shell);
- (void) printf("expire\t%s", ctime(&pwp->pw_expire));
+ (void) printf("expire\t%s", pwp->pw_expire ? ctime(&pwp->pw_expire) : "NEVER\n");
return EXIT_SUCCESS;
}
#endif
@@ -1649,15 +1807,17 @@ groupinfo(int argc, char **argv)
break;
}
}
- if (argc == optind) {
+ argc -= optind;
+ argv += optind;
+ if (argc != 1) {
usermgmt_usage("groupinfo");
}
- grp = find_group_info(argv[optind]);
+ grp = find_group_info(*argv);
if (exists) {
exit((grp) ? EXIT_SUCCESS : EXIT_FAILURE);
}
- if (grp == (struct group *) NULL) {
- errx(EXIT_FAILURE, "can't find group `%s'", argv[optind]);
+ if (grp == NULL) {
+ errx(EXIT_FAILURE, "can't find group `%s'", *argv);
}
(void) printf("name\t%s\n", grp->gr_name);
(void) printf("passwd\t%s\n", grp->gr_passwd);
diff --git a/usr.sbin/user/useradd.8 b/usr.sbin/user/useradd.8
index a151eee6193..0c9adc7db85 100644
--- a/usr.sbin/user/useradd.8
+++ b/usr.sbin/user/useradd.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: useradd.8,v 1.10 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: useradd.8,v 1.5 2000/02/28 05:10:57 enami Exp $ */
-.\"
+.\" $OpenBSD: useradd.8,v 1.11 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: useradd.8,v 1.10 2001/02/21 12:16:07 agc Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
@@ -32,7 +31,7 @@
.\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\"
-.Dd November 30, 1999
+.Dd Septemper 5, 2001
.Dt USERADD 8
.Os
.Sh NAME
@@ -40,72 +39,108 @@
.Nd add a user to the system
.Sh SYNOPSIS
.Nm useradd
-.Op Fl D
+.Fl D
.Op Fl b Ar base-dir
.Op Fl e Ar expiry-time
-.Op Fl f Ar inactive-secs
-.Op Fl g Ar gid/name/=uid
-.Op Fl r Ar low..high
+.Op Fl f Ar password-change-secs
+.Oo
+.Fl g Ar gid | name | Li =uid Oc
+.Op Fl L Ar login-class
+.Oo
+.Op Fl k Ar skel-dir
+.Fl r Ar low Ns Li .. Ns Ar high
+.Oc
.Op Fl s Ar shell
.Nm useradd
+.Op Fl mov
.Op Fl G Ar secondary-group[,group,...]
.Op Fl b Ar base-dir
.Op Fl c Ar comment
.Op Fl d Ar home-dir
.Op Fl e Ar expiry-time
-.Op Fl f Ar inactive-secs
-.Op Fl g Ar gid/name/=uid
+.Op Fl f Ar password-change-secs
+.Oo
+.Fl g Ar gid | name | Li =uid Oc
.Op Fl k Ar skel-dir
-.Op Fl m
-.Op Fl o
+.Op Fl L Ar login-class
.Op Fl p Ar password
-.Op Fl r Ar low..high
+.Oo
+.Fl r Ar low Ns Li .. Ns Ar high
+.Oc
.Op Fl s Ar shell
.Op Fl u Ar uid
-.Op Fl v
.Ar user
.Sh DESCRIPTION
The
.Nm useradd
utility adds a user to the system, creating and
populating a home directory if necessary.
-Any skeleton dot files will be provided
+Any skeleton files will be provided
for the new user if they exist in the
.Pa /etc/skel
directory.
-Default values for the base directory, the time of password expiry,
+Default values for
+the base directory,
+the time of password expiry,
+seconds until password change,
+primary group,
the skeleton directory,
-seconds until password change, primary group, the range from which the uid will be
-allocated,
-and default login shell can be provided in the
+the range from which the uid will be allocated,
+and default login shell
+can be provided in the
.Pa /etc/usermgmt.conf
file.
.Pp
-The first format of the command shown above (utilising the -D option)
+The first format of the command shown above (utilising the
+.Fl D
+option)
sets and displays the defaults for the
.Nm
utility.
.Bl -tag -width Ds
.It Fl D
-without any further options, -D will show the current defaults which
+without any further options,
+.Fl D
+will show the current defaults which
will be used by the
.Nm
utility. Together with one of the options shown for the first version
-of the command, -D will set the default to be the new value.
+of the command,
+.Fl D
+will set the default to be the new value.
.It Fl b Ar base-dir
sets the base directory. This is the directory to which the user name
-is added, which will be created if the -m option is specified and no
--d option is specified.
+is added, which will be created if the
+.Fl m
+option is specified and no
+.Fl d
+option is specified.
.It Fl e Ar expiry-time
-sets the time at which the current password will expire for this user.
-.It Fl f Ar inactive-secs
-sets the number of seconds after which, if no login has occurred for
-the user during that time, the login will be "locked".
-.It Fl g Ar gid/groupname/=uid
+sets the time at which the current password will expire for new users.
+.It Fl f Ar password-change-secs
+provides the number of seconds since the epoch (UTC) at
+which the current password must be changed. This
+can be used to implement password aging.
+A value of
+0 can be used to switch off this feature.
+The default value for this field is 0.
+See
+.Xr passwd 5
+for more details.
+.It Fl g Ar gid | groupname | Li =uid
sets the default group for any user added using the
.Nm
command.
-.It Fl r Ar low..high
+.It Fl k Ar skel-dir
+sets the skeleton directory in which to find files with
+which to populate new users' home directories.
+.It Fl L Ar login-class
+This option sets the login class for the user being created. See
+.Xr login.conf 5
+for more information on login classes.
+.It Xo
+.Fl r Ar low Ns Li .. Ns Ar high
+.Xc
sets the low and high bounds of uid ranges for new users. A new user
can only be created if there are uids which can be assigned from one
of the free ranges.
@@ -130,7 +165,7 @@ by using the
field in the
.Pa /etc/usermgmt.conf
file - it has the format:
-.Ar base_dir <path-to-base-dir> .
+.D1 Ic base_dir Ar path-to-base-dir
.It Fl c Ar comment
is the comment field (also, for historical reasons known as the
GECOS field) which will be added for the user, and typically will include
@@ -154,11 +189,11 @@ by using the
field in the
.Pa /etc/usermgmt.conf
file - it has the format:
-.Ar expire <secs-to-expiry> .
-.It Fl g Ar gid/name/=uid
+.D1 Ic expire Ar secs-to-expiry
+.It Fl g Ar gid | name | Li =uid
gives the group name or identifier to be used for the new user's primary group.
If this is
-.Ar "-g=uid" ,
+.Ql =uid ,
then a uid and gid will be picked which are both unique
and the same, and a line added to
.Pa /etc/group
@@ -169,10 +204,30 @@ by using the
field in the
.Pa /etc/usermgmt.conf
file - it has the format:
-.Ar group <groupname/groupid/=uid> .
+.br \" XXX This shouldn't be needed -- mdoc bug? --bjh21
+.Bd -ragged -offset indent -compact
+.Ic group
+.Ar gid | name | Li =uid
+.Ed
.It Fl k Ar skeleton directory
-gives the skeleton directory in which to find dot files
+gives the skeleton directory in which to find files
with which to populate the new user's home directory.
+This value can be preset for all users by using the
+.Ar skel_dir
+field in the
+.Pa /etc/usermgmt.conf
+file - it has the format:
+.D1 Ic skel_dir Ar path-to-skeleton-dir
+.It Fl L Ar login-class
+This option sets the login class for the user being created. See
+.Xr login.conf 5
+for more information on login classes. This value can be preset
+for all users by using the
+.Ar class
+field in the
+.Pa /etc/usermgmt.conf
+file - it has the format:
+.D1 Ic class Ar login-class
.It Fl m
create a new home directory for the new user.
.It Fl o
@@ -188,7 +243,7 @@ by using the
field in the
.Pa /etc/usermgmt.conf
file - it has the format:
-.Ar password <encrypted-password> .
+.D1 Ic password Ar encrypted-password
.It Fl s Ar shell
specifies the login shell for the new user.
This value can be preset for all users
@@ -197,7 +252,7 @@ by using the
field in the
.Pa /etc/usermgmt.conf
file - it has the format:
-.Ar shell <login-shell> .
+.D1 Ic shell Ar login-shell
.It Fl u Ar uid
specifies a uid for the new user.
Boundaries for this value can be preset for all users
@@ -206,26 +261,40 @@ by using the
field in the
.Pa /etc/usermgmt.conf
file - they have the format:
-.Ar range <starting-uid>..<ending-uid> .
+.Bd -unfilled -offset indent -compact
+.Ic range Ar starting-uid Ns Li .. Ns Ar ending-uid
+.Ed
.It Fl v
enables verbose mode - explain the commands as they are executed.
.El
.Pp
+Once the information has been verified,
+.Nm
+uses
+.Xr pwd_mkdb 8
+to update the user database. This is run in the background, and,
+at very large sites could take several minutes. Until this update
+is completed, the password file is unavailable for other updates
+and the new information is not available to programs.
+.Pp
The
.Nm
utility exits 0 on success, and >0 if an error occurs.
.Sh FILES
.Bl -tag -width /etc/usermgmt.conf -compact
.It Pa /etc/usermgmt.conf
-.It Pa /etc/skel/.[A-z]*
+.It Pa /etc/skel/*
+.It Pa /etc/login.conf
.El
.Sh SEE ALSO
.Xr chpass 1 ,
.Xr passwd 5 ,
.Xr group 5 ,
+.Xr pwd_mkdb 8 ,
.Xr user 8 ,
.Xr userdel 8 ,
-.Xr usermod 8
+.Xr usermod 8 ,
+.Xr login.conf 5
.Sh HISTORY
The
.Nm
diff --git a/usr.sbin/user/userdel.8 b/usr.sbin/user/userdel.8
index 4abfd74f58f..74ffc597ffb 100644
--- a/usr.sbin/user/userdel.8
+++ b/usr.sbin/user/userdel.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: userdel.8,v 1.7 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: userdel.8,v 1.5 2000/03/13 23:22:55 soren Exp $ */
-.\"
+.\" $OpenBSD: userdel.8,v 1.8 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: userdel.8,v 1.5 2000/03/13 23:22:55 soren Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
@@ -40,13 +39,11 @@
.Nd remove a user from the system
.Sh SYNOPSIS
.Nm userdel
-.Op Fl D
+.Fl D
.Op Fl p Ar preserve-value
.Nm userdel
-.Op Fl p
-.Op Fl r
-.Op Fl v
-user
+.Op Fl prv
+.Ar user
.Sh DESCRIPTION
The
.Nm
@@ -59,13 +56,18 @@ sets and displays the defaults for the
utility.
.Bl -tag -width Ds
.It Fl D
-without any further options, -D will show the current defaults which
-will be used by the
+without any further options,
+.Fl D
+will show the current defaults which will be used by the
.Nm
utility. Together with one of the options shown for the first version
-of the command, -D will set the default to be the new value.
+of the command,
+.Fl D
+will set the default to be the new value.
.It Fl p Ar preserve-value
-sets the preservation value. If this value is one of "true", "false",
+sets the preservation value. If this value is one of
+.Ql true ,
+.Ql yes ,
or a non-zero number, then the user login information will be preserved.
.El
.Pp
@@ -74,16 +76,22 @@ The following command line options are recognised:
.It Fl p
preserve the user information in the password file,
but do not allow the user to login, by switching the
-password to an "impossible" one, and by setting the
-user's shell to the false(1) program.
-This option can be helpful in preserving a user's
+password to an
+.Dq impossible
+one, and by setting the
+user's shell to the
+.Xr false 1
+program. This option can be helpful in preserving a user's
files for later use by members of that person's
group after the user has moved on.
This value can also be set in the
.Pa /etc/usermgmt.conf
-file, using the "preserve" field. If the field
-has any of the values "true", "yes", or a non-zero number,
-then user information preservation will take place.
+file, using the
+.Ql preserve
+field. If the field has any of the values
+.Ql true ,
+.Ql yes ,
+or a non-zero number, then user information preservation will take place.
.It Fl r
remove the user's home directory, any subdirectories,
and any files and other entries in them.
@@ -91,6 +99,15 @@ and any files and other entries in them.
perform any actions in a verbose manner.
.El
.Pp
+Once the information has been verified,
+.Nm
+uses
+.Xr pwd_mkdb 8
+to update the user database. This is run in the background, and,
+at very large sites could take several minutes. Until this update
+is completed, the password file is unavailable for other updates
+and the new information is not available to programs.
+.Pp
The
.Nm
utility exits 0 on success, and >0 if an error occurs.
@@ -100,7 +117,8 @@ utility exits 0 on success, and >0 if an error occurs.
.El
.Sh SEE ALSO
.Xr false 1 ,
-.Xr passwd 5
+.Xr passwd 5 ,
+.Xr pwd_mkdb 8
.Sh HISTORY
The
.Nm
diff --git a/usr.sbin/user/userinfo.8 b/usr.sbin/user/userinfo.8
index 5e353492e03..f2fea9d2a1a 100644
--- a/usr.sbin/user/userinfo.8
+++ b/usr.sbin/user/userinfo.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: userinfo.8,v 1.7 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: userinfo.8,v 1.2 2000/02/28 05:10:57 enami Exp $ */
-.\"
+.\" $OpenBSD: userinfo.8,v 1.8 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: userinfo.8,v 1.4 2000/10/03 19:32:23 bjh21 Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
@@ -40,8 +39,7 @@
.Nd displays user information
.Sh SYNOPSIS
.Nm userinfo
-.Op Fl e
-.Op Fl v
+.Op Fl ev
.Ar user
.Sh DESCRIPTION
The
@@ -60,7 +58,9 @@ name or uid is already in use on the system.
perform any actions in a verbose manner.
.El
.Pp
-The user argument may either be a user's name, or a uid.
+The
+.Ar user
+argument may either be a user's name, or a uid.
.Pp
The
.Nm
diff --git a/usr.sbin/user/usermgmt.h b/usr.sbin/user/usermgmt.h
index 1066d3bd128..0acdf239588 100644
--- a/usr.sbin/user/usermgmt.h
+++ b/usr.sbin/user/usermgmt.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usermgmt.h,v 1.2 2000/04/24 22:31:29 jakob Exp $ */
+/* $OpenBSD: usermgmt.h,v 1.3 2001/09/18 01:50:44 millert Exp $ */
/* $NetBSD: usermgmt.h,v 1.4 1999/12/24 09:08:51 agc Exp $ */
/*
@@ -46,6 +46,6 @@ int userinfo __P((int, char **));
int groupinfo __P((int, char **));
#endif
-void usermgmt_usage __P((char *));
+__dead void usermgmt_usage __P((const char *));
#endif
diff --git a/usr.sbin/user/usermod.8 b/usr.sbin/user/usermod.8
index d8c1b0bf091..514a0b18cbd 100644
--- a/usr.sbin/user/usermod.8
+++ b/usr.sbin/user/usermod.8
@@ -1,6 +1,5 @@
-.\" $OpenBSD: usermod.8,v 1.10 2001/08/02 18:37:35 mpech Exp $ */
-.\" $NetBSD: usermod.8,v 1.4 2000/02/28 05:10:57 enami Exp $ */
-.\"
+.\" $OpenBSD: usermod.8,v 1.11 2001/09/18 01:50:44 millert Exp $
+.\" $NetBSD: usermod.8,v 1.10 2001/02/21 12:16:07 agc Exp $
.\"
.\" Copyright (c) 1999 Alistair G. Crooks. All rights reserved.
.\"
@@ -32,7 +31,7 @@
.\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\"
-.Dd April 3, 2001
+.Dd September 5, 2001
.Dt USERMOD 8
.Os
.Sh NAME
@@ -40,19 +39,20 @@
.Nd modify user login information
.Sh SYNOPSIS
.Nm usermod
+.Op Fl mov
.Op Fl G Ar secondary-group[,group,...]
.Op Fl c Ar comment
.Op Fl d Ar home-dir
.Op Fl e Ar expiry-time
.Op Fl f Ar password-change-secs
-.Op Fl g Ar gid/name/=uid
+.Oo
+.Fl g Ar gid | name | Li =uid
+.Oc
+.Op Fl L Ar login-class
.Op Fl l Ar new-login
-.Op Fl m
-.Op Fl o
.Op Fl p Ar password
.Op Fl s Ar shell
.Op Fl u Ar uid
-.Op Fl v
.Ar user
.Sh DESCRIPTION
The
@@ -69,24 +69,28 @@ the command line options are processed:
.It Fl G Ar secondary-group[,group,...]
are the secondary groups the user will be a member of in the
.Pa /etc/group
-file. This list of groups will replace any old group memberships.
+file.
.It Fl c Ar comment
is the comment field (also, for historical reasons known as the
GECOS field) which will be added for the user, and typically will include
the username, and, perhaps, contact information for the user.
.It Fl d Ar home-directory
-is the home directory which will be created and populated for the user,
-should the -m option be specified.
+Sets the home directory to
+.Ar home-directory
+without populating it; if the
+.Fl m
+option is specified, tries to move the old home directory to
+.Ar home-directory .
.It Fl e Ar expiry-time
provides the date at which the account expires. This should be given
in a standard time format (%c). This is unset by default.
This value can be preset for all users by using the
.Ar expire
field in /etc/usermgmt.conf file - it has the format:
-.Ar expire <expiry-time> .
+.D1 Ic expire Ar expiry-time
.It Fl f Ar password-change-secs
provides the number of seconds since the epoch (UTC) at
-which the current password change expire. This
+which the current password must be changed. This
can be used to implement password aging.
A value of
0 can be used to switch off this feature.
@@ -100,11 +104,13 @@ by using the
field in the
.Pa /etc/usermgmt.conf
file - it has the format:
-.Ar inactive <password-change-secs> .
-.It Fl g Ar gid/name/=uid
+.D1 Ic inactive Ar password-change-secs
+.It Xo
+.Fl g Ar gid | name | Li =uid
+.Xc
gives the group name or identifier to be used for the new user's primary group.
If this is
-.Ar "-g=uid" ,
+.Ql =uid ,
then a uid and gid will be picked which are both unique
and the same, and a line added to
.Pa /etc/group
@@ -113,14 +119,47 @@ This value can be preset for all users
by using the
.Ar gid
field in the
-.Xr /usr/share/adduser/defaults
+.Pa /etc/usermgmt.conf
file - it has the format:
-.Ar group <groupname/groupid/=uid> .
+.br \" XXX Shouldn't be necessary -- mdoc bug? --bjh21
+.Bd -ragged -offset indent -compact
+.Ic group
+.Ar gid | name | Li =uid
+.Ed
+.It Fl L Ar login-class
+This option sets the login class for the user being created. See
+.Xr login.conf 5
+for more information on user login classes. Thie value can be preset
+for all users by using the
+.Ar class
+field in the
+.Pa /etc/usermgmt.conf
+file - it has the format:
+.br \" XXX skip empty line? - HF
+.Bd -ragged -offset indent -compact
+.Ic class
+.Ar login-class
+.Ed
.It Fl l Ar new-user
gives the new user name.
-It must consist of alphanumeric characters, or the characters '.', '-' or '_'.
+It must consist of alphanumeric characters, or the characters
+.Ql \&. ,
+.Ql \&-
+or
+.Ql \&_ .
.It Fl m
moves the home directory from its old position to the new one.
+If
+.Fl d
+is not specified, the
+.Ar new-user
+argument of the
+.Fl l
+option is used; one of
+.Fl d
+and
+.Fl l
+is needed.
.It Fl o
allows duplicate uids to be given.
.It Fl p Ar password
@@ -134,16 +173,16 @@ by using the
field in the
.Pa /etc/usermgmt.conf
file - it has the format:
-.Ar password <encrypted-password> .
+.D1 Ic password Ar encrypted-password
.It Fl s Ar shell
specifies the login shell for the new user.
This value can be preset for all users
by using the
.Ar shell
field in the
-.Xr /usr/share/adduser/defaults
+.Pa /etc/usermgmt.conf
file - it has the format:
-.Ar shell <login-shell> .
+.D1 Ic shell Ar login-shell
.It Fl u Ar uid
specifies a new uid for the user.
Boundaries for this value can be preset for all users
@@ -152,23 +191,36 @@ by using the
field in the
.Pa /etc/usermgmt.conf
file - they have the format:
-.Ar range <starting-uid>..<ending_uid> .
+.br \" XXX
+.Bd -ragged -offset indent -compact
+.Ic range
+.Ar starting-uid Ns Li .. Ns Ar ending_uid
+.Ed
.It Fl v
enables verbose mode - explain the commands as they are executed.
.El
.Pp
+Once the information has been verified,
+.Nm
+uses
+.Xr pwd_mkdb 8
+to update the user database. This is run in the background, and,
+at very large sites could take several minutes. Until this update
+is completed, the password file is unavailable for other updates
+and the new information is not available to programs.
+.Pp
The
.Nm
utility exits 0 on success, and >0 if an error occurs.
.Sh FILES
.Bl -tag -width /etc/usermgmt.conf -compact
.It Pa /etc/usermgmt.conf
-.It Pa /etc/skel/.[A-z]*
.El
.Sh SEE ALSO
.Xr chpass 1 ,
.Xr passwd 5 ,
-.Xr group 5
+.Xr group 5 ,
+.Xr pwd_mkdb 8
.Sh HISTORY
The
.Nm