summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoerg <joerg@FreeBSD.org>1996-12-09 23:55:27 +0000
committerjoerg <joerg@FreeBSD.org>1996-12-09 23:55:27 +0000
commitcb39d6c9763eb9cc95aaba2fd326ec3d45637ab0 (patch)
treece8b42cd0211fd35f14b3373a929b693bb8bf1c0
parent4a198ee0cbf4e9939c2a6e9a0de4afd27158e394 (diff)
downloadFreeBSD-src-cb39d6c9763eb9cc95aaba2fd326ec3d45637ab0.zip
FreeBSD-src-cb39d6c9763eb9cc95aaba2fd326ec3d45637ab0.tar.gz
Upgrade from the author, reflecting all my wishes resulting out of the
sysinstall use of this tool (plus some bug fixes). 2.2 candidate... Submitted by: David Nugent <davidn@nserver.usn.blaze.net.au>
-rw-r--r--usr.sbin/pw/Makefile2
-rw-r--r--usr.sbin/pw/cpdir.c1
-rw-r--r--usr.sbin/pw/pw.8264
-rw-r--r--usr.sbin/pw/pw.c90
-rw-r--r--usr.sbin/pw/pw.conf.548
-rw-r--r--usr.sbin/pw/pw.h17
-rw-r--r--usr.sbin/pw/pw_group.c83
-rw-r--r--usr.sbin/pw/pw_user.c153
-rw-r--r--usr.sbin/pw/pwupd.c7
9 files changed, 482 insertions, 183 deletions
diff --git a/usr.sbin/pw/Makefile b/usr.sbin/pw/Makefile
index 749d256..fbd614f 100644
--- a/usr.sbin/pw/Makefile
+++ b/usr.sbin/pw/Makefile
@@ -8,7 +8,7 @@ SRCS= pw.c pw_conf.c pw_user.c pw_group.c pw_log.c \
MAN5= pw.conf.5
MAN8= pw.8
-CFLAGS+= -Wall
+CFLAGS+= -Wall $(CDB)
LDADD= -lcrypt
DPADD= ${LIBCRYPT}
diff --git a/usr.sbin/pw/cpdir.c b/usr.sbin/pw/cpdir.c
index b40b5c7..c203c89 100644
--- a/usr.sbin/pw/cpdir.c
+++ b/usr.sbin/pw/cpdir.c
@@ -116,3 +116,4 @@ copymkdir(char const * dir, char const * skel, mode_t mode, uid_t uid, gid_t gid
}
}
}
+
diff --git a/usr.sbin/pw/pw.8 b/usr.sbin/pw/pw.8
index c7b021d..82dfb13 100644
--- a/usr.sbin/pw/pw.8
+++ b/usr.sbin/pw/pw.8
@@ -2,14 +2,40 @@
.\" David L. Nugent.
.\" Password Maintenance
.\"
-.\" $Id: pw.8,v 1.3 1996/11/18 03:09:01 davidn Exp $
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by David L. Nugent.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
.\"
-.Dd November 13, 1996
+.\" THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd December 9, 1996
.Dt PW 8
.Os
.Sh NAME
.Nm pw
-.Nd create, remove and modify system users and groups
+.Nd create, remove, modify & display system users and groups
.Sh SYNOPSIS
.Nm pw
.Ar useradd
@@ -30,6 +56,8 @@
.Op Fl o
.Op Fl L Ar class
.Op Fl h Ar fd
+.Op Fl N
+.Op Fl P
.Nm pw
.Ar useradd
.Op name|uid
@@ -68,26 +96,36 @@
.Op Fl l Ar name
.Op Fl m
.Op Fl k Ar dir
+.Op Fl w Ar method
.Op Fl s Ar shell
.Op Fl L Ar class
.Op Fl h Ar fd
+.Op Fl N
+.Op Fl P
.Nm pw
.Ar usershow
.Op name|uid
.Op Fl n Ar name
.Op Fl u Ar uid
.Op Fl F
-.Op Fl p
+.Op Fl P
.Op Fl a
.Nm pw
+.Ar usernext
+.Op Fl C Ar config
+.Op Fl q
+.Nm pw
.Ar groupadd
.Op group|gid
.Op Fl C Ar config
.Op Fl q
.Op Fl n Ar group
.Op Fl g Ar gid
+.Op Fl M Ar members
.Op Fl o
.Op Fl h Ar fd
+.Op Fl N
+.Op Fl P
.Nm pw
.Ar groupdel
.Op Fl n Ar name
@@ -100,14 +138,22 @@
.Op Fl n Ar name
.Op Fl g Ar gid
.Op Fl l Ar name
+.Op Fl M Ar members
+.Op Fl m Ar newmembers
.Op Fl h Ar fd
+.Op Fl N
+.Op Fl P
.Nm pw
.Ar groupshow
.Op Fl n Ar name
.Op Fl g Ar gid
.Op Fl F
-.Op Fl p
+.Op Fl P
.Op Fl a
+.Nm pw
+.Ar groupnext
+.Op Fl C Ar config
+.Op Fl q
.Sh DESCRIPTION
.Nm pw
is a command-line based editor for the system
@@ -134,9 +180,10 @@ and
may be combined or provided separately with
.Ar add ,
.Ar del ,
-.Ar mod
-or
+.Ar mod ,
.Ar show ,
+or
+.Ar next ,
and may be specified in either order (ie. showuser, usershow, show user and user show
are all considered to be the same thing).
This flexiblity is useful for interactive scripts which call
@@ -147,11 +194,11 @@ id as an alternative to using the
.Fl n Ar name ,
.Fl u Ar uid ,
.Fl g Ar gid
-switches.
+options.
.Pp
-The following flags are common to most modes of operation:
+The following flags are common to all modes of operation:
.Pp
-.Bl -tag -width "-C config"
+.Bl -tag -width "-G grouplist"
.It Fl C Ar config
By default,
.Nm pw
@@ -159,12 +206,11 @@ reads the file
.Pa /etc/pw.conf
to obtain policy information on how new user accounts and groups are to be created,
and the
-.Fl c
-option overrides this to read a different file.
+.Fl C
+option specifies a different configuration file.
Most of the contents in the configuration file may be overridden via command line
options, but it may be more useful to set up standard information for addition of
-new accounts in the configuration
-file.
+new accounts in the configuration file.
.It Fl q
Use of this option causes
.Nm pw
@@ -172,6 +218,14 @@ to suppress error messages, which may be useful in interactive environments wher
is preferable to interpret status codes returned by
.Nm pw
rather than messing up a carefully formatted display.
+.It Fl N
+This option is available in add and modify operations, and causes
+.Nm pw
+to skip updating the user/group databases and instead print the result
+of the operation without actually performing it.
+You may use the
+.Fl P
+option to switch between standard passwd and readable formats.
.El
.Pp
.Sh USER OPTIONS
@@ -181,7 +235,7 @@ and
.Ar usermod ,
commands:
.Pp
-.Bl -tag -width "-C config"
+.Bl -tag -width "-G grouplist"
.It Fl n Ar name
Specifies the user/account name.
.It Fl u Ar uid
@@ -211,7 +265,7 @@ then you should
.Em not
use the
.Ql Fl u
-switch.
+option.
.El
.Pp
Options available with both
@@ -272,6 +326,11 @@ Note: a user should not be added to their primary group in
.Pa /etc/group .
Also, group membership changes do not take effect immediately for current logins,
only logins subsequent to the change.
+.It Fl L Ar class
+This option sets the login class for the user being created.
+See
+.Xr login.conf 5
+for more information on user classes.
.It Fl m
This option instructs
.Nm pw
@@ -379,31 +438,32 @@ It is possible to use
to create a new account that duplicates an existing user id.
While this is normally considered an error and will be rejected, the
.Ql Fl o
-switch overrides the check for duplicates and allows the duplication of the user id.
-This may be useful if you allow the same user to login under different contexts
-(different group allocations, different home directory, different shell) while
-providing basically the same permissions for access to the user's files in each
-account.
+option overrides the check for duplicates and allows the duplication of
+the user id.
+This may be useful if you allow the same user to login under
+different contexts (different group allocations, different home
+directory, different shell) while providing basically the same
+permissions for access to the user's files in each account.
.Pp
The
.Ar useradd
command also has the ability to set new user and group defaults by using the
.Ql Fl D
-switch.
+option.
Instead of adding a new user,
.Nm pw
writes a new set of defaults to its configuration file,
.Pa /etc/pw.conf .
When using the
.Ql Fl D
-switch, you must not use either
+option, you must not use either
.Ql Fl n Ar name
or
.Ql Fl u Ar uid
or an error will result.
Use of
.Ql Fl D
-adds switches and changes the meaning of several command line switches in the
+changes the meaning of several command line switches in the
.Ar useradd
command.
These are:
@@ -413,7 +473,7 @@ Set default values in
.Pa /etc/pw.conf
configuration file, or a different named configuration file if the
.Ql Fl C Ar config
-switch is used.
+option is used.
.It Fl b Ar dir
Sets the root directory in which user home directories are created.
The default value for this is
@@ -447,15 +507,16 @@ is a comma-separated list of group names or ids, or a mixture of both, and are a
stored in
.Pa /etc/pw.conf
by their symbolic names.
+.It Fl L Ar class
+This option sets the default login class for new users.
.It Fl k Ar dir
Sets the default
.Em skeleton
directory, from which prototype shell and other initialisation files are copied when
.Nm pw
creates a user's home directory.
-.It Fl u Ar min,max
-.It Fl i Ar min,max
-These switches set the minimum and maximum user and group ids allocated for new accounts
+.It Fl u Ar min,max , Fl i Ar min,max
+These options set the minimum and maximum user and group ids allocated for new accounts
and groups created by
.Nm pw .
The default values for each is 1000 minimum and 32000 maximum.
@@ -470,7 +531,7 @@ some system daemons).
.It Fl w Ar method
The
.Ql Fl w
-switch sets the default method used to set passwords for newly created user accounts.
+option sets the default method used to set passwords for newly created user accounts.
.Ar method
is one of:
.Pp
@@ -503,13 +564,13 @@ to render the account accessible with a password.
.Pp
The
.Ar userdel
-command has only three valid switches. The
+command has only three valid options. The
.Ql Fl n Ar name
and
.Ql Fl u Ar uid
-switches have already been covered above.
-The additional switch is:
-.Bl -tag -width flag
+options have already been covered above.
+The additional option is:
+.Bl -tag -width "-G grouplist"
.It Fl r
This tells
.Nm pw
@@ -541,41 +602,56 @@ By default, the format is identical to the format used in
.Pa /etc/master.passwd
with the password field replaced with a
.Ql \&* .
-Class, account and password expiration fields will be blank or zero zero unless the user
-running
-.Nm pw
-has root priviledges, as the secure password file where these reside is not accessible
-to non-root users.
If the
-.Ql Fl p
-switch is used, then
+.Ql Fl P
+option is used, then
.Nm pw
outputs the account details in a more human readable form.
The
.Ql Fl a
-switch lists all users currently on file.
+option lists all users currently on file.
+.Pp
+The command
+.Ar usernext
+returns the next available user and group ids separated by a colon.
+This is normally of interest only to interactive scripts or front-ends
+that use
+.Nm pw .
.Pp
.Sh GROUP OPTIONS
The
.Ql Fl C Ar config
and
.Ql Fl q
-options (explained at the start of the previous section) are available with the
-.Ar groupadd
-and
-.Ar groupmod
-commands.
+options (explained at the start of the previous section) are available
+with the group manipulation commands.
Other common options to all group-related commands are:
-.Bl -tag -width "-n name"
+.Bl -tag -width "-m newmembers"
.It Fl n Ar name
Specifies the group name.
.It Fl g Ar gid
Specifies the group numeric id.
.Pp
-As with the account name and id fields, yo uwill usually only need to supply one of
-these, as the group name implies the uid and vice versa.
-You will only need to use both when setting a specific group id against a new group
-or when changing the uid of an existing group.
+As with the account name and id fields, you will usually only need
+to supply one of these, as the group name implies the uid and vice
+versa.
+You will only need to use both when setting a specific group id
+against a new group or when changing the uid of an existing group.
+.It Fl M Ar memberlist
+This option provides an alternative way to add existing users to a
+new group (in groupadd) or replace an existing membership list (in
+groupmod).
+.Ar memberlist
+is a comma separated list of valid and existing user names or uids.
+.It Fl m Ar newmembers
+Similar to
+.Op M ,
+this option allows the
+.Em addition
+of existing users to a group without first replacing the existing list of
+members.
+Login names or user ids may be used, and duplicated users are automatically
+and silently eliminated.
.El
.Pp
.Ar groupadd
@@ -588,9 +664,9 @@ There is rarely any need to duplicate a group id.
.Pp
The
.Ar groupmod
-command adds one additonal switch:
+command adds one additonal option:
.Pp
-.Bl -tag -width "-l name"
+.Bl -tag -width "-m newmembers"
.It Fl l Ar name
This option allows changing of an existing group name to
.Ql \&name .
@@ -608,6 +684,78 @@ replacing
.Ql Fl u Ar uid
to specify the group id.
.Pp
+The command
+.Ar groupnext
+returns the next available group id on standard output.
+.Sh DIAGNOSTICS
+.Nm pw
+returns EXIT_SUCCESS on successful operation, otherwise one of the
+following exit codes defined by
+.Xr sysexits 3
+as follows:
+.Bl -tag -width xxxx
+.It EX_USAGE
+.Bl -bullet -compact
+.It
+Command line syntax errors (invalid keyword, unknown option)
+.El
+.It EX_NOPERM
+.Bl -bullet -compact
+.It
+Attempting to run one of the update modes as non-root.
+.El
+.It EX_OSERR
+.Bl -bullet -compact
+.It
+Memory allocation error.
+.It
+Read error from password file descriptor.
+.El
+.It EX_DATAERR
+.Bl -bullet -compact
+.It
+Bad or invalid data provided or missing on the command line or
+via the password flie descriptor.
+.It
+Attempted to remove, rename root account or change its uid.
+.El
+.It EX_OSFILE
+.Bl -bullet -compact
+.It
+Skeleton directory is invalid or does not exist.
+.It
+Base home directory is invalid or does not exist.
+.It
+Invalid or non-existant shell specified.
+.El
+.It EX_NOUSER
+.Bl -bullet -compact
+.It
+User, user id, group or group id specified does not exist.
+.It
+User or group recorded added or modified unexpectedly disappeared.
+.El
+.It EX_SOFTWARE
+.Bl -bullet -compact
+.It
+No more group or user ids available within specified range.
+.El
+.It EX_IOERR
+.Bl -bullet -compact
+.It
+Unable to rewrite configuration file.
+.It
+Error updating group or user database files.
+.It
+Update error for passwd or group database files.
+.El
+.It EX_CONFIG
+.Bl -bullet -compact
+.It
+No base home directory configured.
+.El
+.El
+.Pp
.Sh NOTES
For a summary of options available with each command, you can use
.Dl pw [command] help
@@ -620,6 +768,8 @@ lists all available options for the useradd operation.
The user database
.It Pa /etc/passwd
A Version 7 format password file
+.It Pa /etc/login.conf
+The user capabilities database
.It Pa /etc/group
The group database
.It Pa /etc/master.passwd.new
@@ -638,11 +788,13 @@ Pw default options file
.Xr passwd 5 ,
.Xr group 5 ,
.Xr pwd_mkdb 8 ,
+.Xr login.conf 5 ,
.Xr vipw 5
.Sh HISTORY
.Nm pw
-was written to mimick many of the options used in the Linux
+was written to mimick many of the options used in the SYSV
.Em shadow
-suite, but is modified for passwd and group fields specific to
-the BSD 4.4 operating system.
+support suite, but is modified for passwd and group fields specific to
+the BSD 4.4 operating system, and combines all of the major elements
+into a single command.
diff --git a/usr.sbin/pw/pw.c b/usr.sbin/pw/pw.c
index 01fd919..afec6e1 100644
--- a/usr.sbin/pw/pw.c
+++ b/usr.sbin/pw/pw.c
@@ -36,13 +36,15 @@
static char *progname = "pw";
-const char *Modes[] = {"add", "del", "mod", "show", NULL};
+const char *Modes[] = {"add", "del", "mod", "show", "next", NULL};
const char *Which[] = {"user", "group", NULL};
-static const char *Combo1[] = {"useradd", "userdel", "usermod", "usershow",
- "groupadd", "groupdel", "groupmod", "groupshow",
-NULL};
-static const char *Combo2[] = {"adduser", "deluser", "moduser", "showuser",
- "addgroup", "delgroup", "modgroup", "showgroup",
+static const char *Combo1[] = {
+ "useradd", "userdel", "usermod", "usershow", "usernext",
+ "groupadd", "groupdel", "groupmod", "groupshow", "groupnext",
+ NULL};
+static const char *Combo2[] = {
+ "adduser", "deluser", "moduser", "showuser", "nextuser",
+ "addgroup", "delgroup", "modgroup", "showgroup", "nextgroup",
NULL};
static struct cargs arglist;
@@ -61,8 +63,20 @@ main(int argc, char *argv[])
static const char *opts[W_NUM][M_NUM] =
{
- /* user */ {"C:qn:u:c:d:e:p:g:G:mk:s:oL:i:w:h:Db", "C:qn:u:r", "C:qn:u:c:d:e:p:g:G:mk:s:L:h:F", "C:qn:u:Fpa"},
- /* grp */ {"C:qn:g:h:p", "C:qn:g:", "C:qn:g:l:h:F", "C:qn:g:Fpa"}
+ { /* user */
+ "C:qn:u:c:d:e:p:g:G:mk:s:oL:i:w:h:Db:NP",
+ "C:qn:u:r",
+ "C:qn:u:c:d:e:p:g:G:mk:s:w:L:h:FNP",
+ "C:qn:u:FPa",
+ "C:q"
+ },
+ { /* grp */
+ "C:qn:g:h:M:pNP",
+ "C:qn:g:",
+ "C:qn:g:l:h:FM:m:NP",
+ "C:qn:g:FPa",
+ "C:q"
+ }
};
static int (*funcs[W_NUM]) (struct userconf * _cnf, int _mode, struct cargs * _args) =
@@ -99,7 +113,7 @@ main(int argc, char *argv[])
else if (which != -1 && mode != -1 && arglist.lh_first == NULL)
addarg(&arglist, 'n', argv[1]);
else
- cmderr(X_CMDERR, "Unknown keyword `%s'\n", argv[1]);
+ cmderr(EX_USAGE, "Unknown keyword `%s'\n", argv[1]);
++argv;
--argc;
}
@@ -111,12 +125,6 @@ main(int argc, char *argv[])
cmdhelp(mode, which);
/*
- * Must be root to attempt an update
- */
- if (getuid() != 0 && mode != M_PRINT)
- cmderr(X_PERMERR, "you must be root to run this program\n");
-
- /*
* We know which mode we're in and what we're about to do, so now
* let's dispatch the remaining command line args in a genric way.
*/
@@ -125,32 +133,30 @@ main(int argc, char *argv[])
while ((ch = getopt(argc, argv, opts[which][mode])) != -1) {
if (ch == '?')
- cmderr(X_CMDERR, NULL);
+ cmderr(EX_USAGE, NULL);
else
addarg(&arglist, ch, optarg);
optarg = NULL;
}
/*
+ * Must be root to attempt an update
+ */
+ if (getuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL)
+ cmderr(EX_NOPERM, "you must be root to run this program\n");
+
+ /*
* We should immediately look for the -q 'quiet' switch so that we
* don't bother with extraneous errors
*/
if (getarg(&arglist, 'q') != NULL)
freopen("/dev/null", "w", stderr);
- ch = X_CMDERR;
-
/*
* Now, let's do the common initialisation
*/
cnf = read_userconfig(getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL);
-
- if (funcs[which])
- ch = funcs[which] (cnf, mode, &arglist);
- else
- fprintf(stderr, "%s: %s[%s] not yet implemented.\n", progname, Which[which], Modes[mode]);
-
- return ch;
+ return funcs[which] (cnf, mode, &arglist);
}
static int
@@ -197,9 +203,9 @@ cmdhelp(int mode, int which)
{
banner();
if (which == -1)
- fprintf(stderr, "usage: %s [user|group] [add|del|mod|show] [ help | switches/values ]\n", progname);
+ fprintf(stderr, "usage: %s [user|group] [add|del|mod|show|next] [ help | switches/values ]\n", progname);
else if (mode == -1)
- fprintf(stderr, "usage: %s %s [add|del|mod] [ help | switches/values ]\n", progname, Which[which]);
+ fprintf(stderr, "usage: %s %s [add|del|mod|show|next] [ help | switches/values ]\n", progname, Which[which]);
else {
/*
@@ -225,6 +231,7 @@ cmdhelp(int mode, int which)
"\t-o duplicate uid ok\n"
"\t-L class user class\n"
"\t-h fd read password on fd\n"
+ "\t-N no update\n"
" Setting defaults:\n"
"\t-D set user defaults\n"
"\t-b dir default home root dir\n"
@@ -258,13 +265,17 @@ cmdhelp(int mode, int which)
"\t-L class user class\n"
"\t-m [ -k dir ] create and set up home\n"
"\t-s shell name of login shell\n"
- "\t-h fd read password on fd\n",
+ "\t-w method set new password using method\n"
+ "\t-h fd read password on fd\n"
+ "\t-N no update\n",
"usage: %s usershow [uid|name] [switches]\n"
"\t-n name login name\n"
"\t-u uid user id\n"
"\t-F force print\n"
- "\t-p prettier format\n"
- "\t-a print all users\n"
+ "\t-P prettier format\n"
+ "\t-a print all users\n",
+ "usage: %s usernext [switches]\n"
+ "\t-C config configuration file\n"
},
{
"usage: %s groupadd [group|gid] [switches]\n"
@@ -272,7 +283,9 @@ cmdhelp(int mode, int which)
"\t-q quiet operation\n"
"\t-n group group name\n"
"\t-g gid group id\n"
- "\t-o duplicate gid ok\n",
+ "\t-M usr1,usr2 add users as group members\n"
+ "\t-o duplicate gid ok\n"
+ "\t-N no update\n",
"usage: %s groupdel [group|gid] [switches]\n"
"\t-n name group name\n"
"\t-g gid group id\n",
@@ -282,19 +295,24 @@ cmdhelp(int mode, int which)
"\t-F force add if not exists\n"
"\t-n name group name\n"
"\t-g gid group id\n"
- "\t-l name new group name\n",
+ "\t-M usr1,usr2 replaces users as group members\n"
+ "\t-m usr1,usr2 add users as group members\n"
+ "\t-l name new group name\n"
+ "\t-N no update\n",
"usage: %s groupshow [group|gid] [switches]\n"
"\t-n name group name\n"
"\t-g gid group id\n"
"\t-F force print\n"
- "\t-p prettier format\n"
- "\t-a print all accounting groups\n"
+ "\t-P prettier format\n"
+ "\t-a print all accounting groups\n",
+ "usage: %s groupnext [switches]\n"
+ "\t-C config configuration file\n"
}
};
fprintf(stderr, help[which][mode], progname);
}
- exit(X_CMDERR);
+ exit(EXIT_FAILURE);
}
struct carg *
@@ -313,7 +331,7 @@ addarg(struct cargs * _args, int ch, char *argstr)
struct carg *ca = malloc(sizeof(struct carg));
if (ca == NULL)
- cmderr(X_MEMERR, "Abort - out of memory\n");
+ cmderr(EX_OSERR, "Abort - out of memory\n");
ca->ch = ch;
ca->val = argstr;
LIST_INSERT_HEAD(_args, ca, list);
diff --git a/usr.sbin/pw/pw.conf.5 b/usr.sbin/pw/pw.conf.5
index 7bbd09f0..253735e 100644
--- a/usr.sbin/pw/pw.conf.5
+++ b/usr.sbin/pw/pw.conf.5
@@ -1,10 +1,36 @@
.\" Copyright (c) 1996
.\" David L. Nugent.
-.\" Password/Group file maintenance suite
+.\" Password Maintenance
.\"
-.\" $Id: pw.conf.5,v 1.2 1996/11/18 03:09:02 davidn Exp $
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by David L. Nugent.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
.\"
-.Dd November 13, 1996
+.\" THIS SOFTWARE IS PROVIDED BY THE DAVID L. NUGENT ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd December 9, 1996
.Dt PW.CONF 5
.Os
.Sh NAME
@@ -64,7 +90,7 @@ default shell (without path)
default group
.It extragroups
add new users to this groups
-.It loginclass
+.It defaultclass
place new users in this login class
.It minuid
.It maxuid
@@ -200,7 +226,7 @@ their own created automatically.
This is the recommended procedure for new users as it best secures each
user's files against interference by other users of the system
irrespective of the
-.Em umask .
+.Em umask
normally used by the user.
.Pp
.Ar extragroups
@@ -212,11 +238,18 @@ This is useful where all users share some resources, and is preferable
to placing users into the same primary group.
The effect of this keyword can be overridden using the
.Ql \&-G
-option on
-.Xr pw 8 's
+option on the
+.Xr pw 8
command line.
.Pp
The
+.Ar defaultclass
+field determines the login class (See
+.Xr login.conf 5 )
+that new users will be allocated unless overwritten by
+.Xr pw 8 .
+.Pp
+The
.Ar minuid ,
.Ar maxuid ,
.Ar mingid ,
@@ -259,6 +292,7 @@ as comments.
.El
.Sh SEE ALSO
.Xr pw 8 ,
+.Xr login.conf 5 ,
.Xr passwd 1 ,
.Xr passwd 5 ,
.Xr group 5
diff --git a/usr.sbin/pw/pw.h b/usr.sbin/pw/pw.h
index 8635f44..26110f5 100644
--- a/usr.sbin/pw/pw.h
+++ b/usr.sbin/pw/pw.h
@@ -43,6 +43,7 @@
#include <pwd.h>
#include <grp.h>
#include <sys/queue.h>
+#include <sysexits.h>
#include "psdate.h"
@@ -52,6 +53,7 @@ enum _mode
M_DELETE,
M_UPDATE,
M_PRINT,
+ M_NEXT,
M_NUM
};
@@ -62,21 +64,6 @@ enum _which
W_NUM
};
-enum _excode
-{
- X_ALLOK,
- X_CMDERR,
- X_PERMERR,
- X_MEMERR,
- X_NOUPDATE,
- X_NOTFOUND,
- X_UPDERROR,
- X_TOOMANY,
- X_EXISTS,
- X_DBERROR,
- X_CONFIG
-};
-
struct carg
{
int ch;
diff --git a/usr.sbin/pw/pw_group.c b/usr.sbin/pw/pw_group.c
index d189ccc..b319047 100644
--- a/usr.sbin/pw/pw_group.c
+++ b/usr.sbin/pw/pw_group.c
@@ -60,18 +60,31 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
NULL
};
+ /*
+ * With M_NEXT, we only need to return the
+ * next gid to stdout
+ */
+ if (mode == M_NEXT)
+ {
+ gid_t next = gr_gidpolicy(cnf, args);
+ if (getarg(args, 'q'))
+ return next;
+ printf("%ld\n", (long)next);
+ return EXIT_SUCCESS;
+ }
+
if (mode == M_PRINT && getarg(args, 'a')) {
- int pretty = getarg(args, 'p') != NULL;
+ int pretty = getarg(args, 'P') != NULL;
setgrent();
while ((grp = getgrent()) != NULL)
print_group(grp, pretty);
endgrent();
- return X_ALLOK;
+ return EXIT_SUCCESS;
}
if (a_gid == NULL) {
if (a_name == NULL)
- cmderr(X_CMDERR, "group name or id required\n");
+ cmderr(EX_DATAERR, "group name or id required\n");
if (mode != M_ADD && grp == NULL && isdigit(*a_name->val)) {
(a_gid = a_name)->ch = 'g';
@@ -88,9 +101,9 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
if (mode == M_PRINT && getarg(args, 'F')) {
fakegroup.gr_name = a_name ? a_name->val : "nogroup";
fakegroup.gr_gid = a_gid ? (gid_t) atol(a_gid->val) : -1;
- return print_group(&fakegroup, getarg(args, 'p') != NULL);
+ return print_group(&fakegroup, getarg(args, 'P') != NULL);
}
- cmderr(X_CMDERR, "unknown group `%s'\n", a_name ? a_name->val : a_gid->val);
+ cmderr(EX_DATAERR, "unknown group `%s'\n", a_name ? a_name->val : a_gid->val);
}
if (a_name == NULL) /* Needed later */
a_name = addarg(args, 'n', grp->gr_name);
@@ -102,11 +115,11 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
gid_t gid = grp->gr_gid;
if (delgrent(grp) == -1)
- cmderr(X_NOUPDATE, "Error updating group file: %s\n", strerror(errno));
+ cmderr(EX_IOERR, "Error updating group file: %s\n", strerror(errno));
pw_log(cnf, mode, W_GROUP, "%s(%ld) removed", a_name->val, (long) gid);
- return X_ALLOK;
+ return EXIT_SUCCESS;
} else if (mode == M_PRINT)
- return print_group(grp, getarg(args, 'p') != NULL);
+ return print_group(grp, getarg(args, 'P') != NULL);
if (a_gid)
grp->gr_gid = (gid_t) atoi(a_gid->val);
@@ -115,9 +128,9 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
grp->gr_name = arg->val;
} else {
if (a_name == NULL) /* Required */
- cmderr(X_CMDERR, "group name required\n");
+ cmderr(EX_DATAERR, "group name required\n");
else if (grp != NULL) /* Exists */
- cmderr(X_EXISTS, "group name `%s' already exists\n", a_name->val);
+ cmderr(EX_DATAERR, "group name `%s' already exists\n", a_name->val);
memset(members, 0, sizeof members);
grp = &fakegroup;
@@ -165,27 +178,61 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
}
if (b < 0) {
perror("-h file descriptor");
- return X_CMDERR;
+ return EX_OSERR;
}
line[b] = '\0';
if ((p = strpbrk(line, " \t\r\n")) != NULL)
*p = '\0';
if (!*line)
- cmderr(X_CMDERR, "empty password read on file descriptor %d\n", fd);
+ cmderr(EX_DATAERR, "empty password read on file descriptor %d\n", fd);
grp->gr_passwd = pw_pwcrypt(line);
}
}
+
+ if (((arg = getarg(args, 'M')) != NULL || (arg = getarg(args, 'm')) != NULL) && arg->val) {
+ int i = 0;
+ char *p;
+ struct passwd *pwd;
+
+ if (arg->ch == 'm') {
+ while (i < _UC_MAXGROUPS && grp->gr_mem[i] != NULL) {
+ members[i] = grp->gr_mem[i];
+ i++;
+ }
+ }
+ for (p = strtok(arg->val, ", \t"); i < _UC_MAXGROUPS && p != NULL; p = strtok(NULL, ", \t")) {
+ int j;
+ if ((pwd = getpwnam(p)) == NULL) {
+ if (!isdigit(*p) || (pwd = getpwuid((uid_t) atoi(p))) == NULL)
+ cmderr(EX_NOUSER, "user `%s' does not exist\n", p);
+ }
+ /*
+ * Check for duplicates
+ */
+ for (j = 0; j < i && strcmp(members[j], pwd->pw_name)!=0; j++)
+ ;
+ if (j == i)
+ members[i++] = newstr(pwd->pw_name);
+ }
+ while (i < _UC_MAXGROUPS)
+ members[i++] = NULL;
+ grp->gr_mem = members;
+ }
+
+ 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))) {
perror("group update");
- return X_NOUPDATE;
+ return EX_IOERR;
}
/* grp may have been invalidated */
if ((grp = getgrnam(a_name->val)) == NULL)
- cmderr(X_NOTFOUND, "group disappeared during update\n");
+ cmderr(EX_SOFTWARE, "group disappeared during update\n");
pw_log(cnf, mode, W_GROUP, "%s(%ld)", grp->gr_name, (long) grp->gr_gid);
- return X_ALLOK;
+ return EXIT_SUCCESS;
}
@@ -203,7 +250,7 @@ gr_gidpolicy(struct userconf * cnf, struct cargs * args)
gid = (gid_t) atol(a_gid->val);
if ((grp = getgrgid(gid)) != NULL && getarg(args, 'o') == NULL)
- cmderr(X_EXISTS, "gid `%ld' has already been allocated\n", (long) grp->gr_gid);
+ cmderr(EX_DATAERR, "gid `%ld' has already been allocated\n", (long) grp->gr_gid);
} else {
struct bitmap bm;
@@ -244,7 +291,7 @@ gr_gidpolicy(struct userconf * cnf, struct cargs * args)
* Another sanity check
*/
if (gid < cnf->min_gid || gid > cnf->max_gid)
- cmderr(X_EXISTS, "unable to allocate a new gid - range fully used\n");
+ cmderr(EX_SOFTWARE, "unable to allocate a new gid - range fully used\n");
bm_dealloc(&bm);
}
return gid;
@@ -269,5 +316,5 @@ print_group(struct group * grp, int pretty)
printf("%s%s", i ? "," : "", grp->gr_mem[i]);
fputs("\n\n", stdout);
}
- return X_ALLOK;
+ return EXIT_SUCCESS;
}
diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c
index 928e649..d4c085f 100644
--- a/usr.sbin/pw/pw_user.c
+++ b/usr.sbin/pw/pw_user.c
@@ -113,12 +113,27 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
};
/*
+ * With M_NEXT, we only need to return the
+ * next uid to stdout
+ */
+ if (mode == M_NEXT)
+ {
+ uid_t next = pw_uidpolicy(cnf, args);
+ if (getarg(args, 'q'))
+ return next;
+ printf("%ld:", (long)next);
+ pw_group(cnf, mode, args);
+ return EXIT_SUCCESS;
+ }
+
+ /*
* We can do all of the common legwork here
*/
if ((arg = getarg(args, 'b')) != NULL) {
- if (stat(cnf->home = arg->val, &st) == -1 || S_ISDIR(st.st_mode))
- cmderr(X_CMDERR, "root home `%s' is not a directory or does not exist\n", cnf->home);
+ cnf->home = arg->val;
+ if (stat(cnf->home, &st) == -1 || !S_ISDIR(st.st_mode))
+ cmderr(EX_OSFILE, "root home `%s' is not a directory or does not exist\n", cnf->home);
}
if ((arg = getarg(args, 'e')) != NULL)
cnf->expire_days = atoi(arg->val);
@@ -130,7 +145,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
p = arg->val;
if ((grp = getgrnam(p)) == NULL) {
if (!isdigit(*p) || (grp = getgrgid((gid_t) atoi(p))) == NULL)
- cmderr(X_NOTFOUND, "group `%s' does not exist\n", p);
+ cmderr(EX_NOUSER, "group `%s' does not exist\n", p);
}
cnf->default_group = newstr(grp->gr_name);
}
@@ -143,7 +158,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
for (p = strtok(arg->val, ", \t"); i < _UC_MAXGROUPS && p != NULL; p = strtok(NULL, ", \t")) {
if ((grp = getgrnam(p)) == NULL) {
if (!isdigit(*p) || (grp = getgrgid((gid_t) atoi(p))) == NULL)
- cmderr(X_NOTFOUND, "group `%s' does not exist\n", p);
+ cmderr(EX_NOUSER, "group `%s' does not exist\n", p);
}
cnf->groups[i++] = newstr(grp->gr_name);
}
@@ -152,14 +167,14 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
}
if ((arg = getarg(args, 'k')) != NULL) {
if (stat(cnf->dotdir = arg->val, &st) == -1 || S_ISDIR(st.st_mode))
- cmderr(X_CMDERR, "skeleton `%s' is not a directory or does not exist\n", cnf->dotdir);
+ cmderr(EX_OSFILE, "skeleton `%s' is not a directory or does not exist\n", cnf->dotdir);
}
if ((arg = getarg(args, 's')) != NULL)
cnf->shell_default = arg->val;
if (mode == M_ADD && getarg(args, 'D')) {
if (getarg(args, 'n') != NULL)
- cmderr(X_CMDERR, "can't combine `-D' with `-n name'\n");
+ cmderr(EX_DATAERR, "can't combine `-D' with `-n name'\n");
if ((arg = getarg(args, 'u')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) {
if ((cnf->min_uid = (uid_t) atoi(p)) == 0)
cnf->min_uid = 1000;
@@ -177,18 +192,18 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
arg = getarg(args, 'C');
if (write_userconfig(arg ? arg->val : NULL))
- return X_ALLOK;
+ return EXIT_SUCCESS;
perror("config update");
- return X_UPDERROR;
+ return EX_IOERR;
}
if (mode == M_PRINT && getarg(args, 'a')) {
- int pretty = getarg(args, 'p') != NULL;
+ int pretty = getarg(args, 'P') != NULL;
setpwent();
while ((pwd = getpwent()) != NULL)
print_user(pwd, pretty);
endpwent();
- return X_ALLOK;
+ return EXIT_SUCCESS;
}
if ((a_name = getarg(args, 'n')) != NULL)
pwd = getpwnam(pw_checkname(a_name->val, 0));
@@ -196,7 +211,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
if (a_uid == NULL) {
if (a_name == NULL)
- cmderr(X_CMDERR, "user name or id required\n");
+ cmderr(EX_DATAERR, "user name or id required\n");
/*
* Determine whether 'n' switch is name or uid - we don't
@@ -219,11 +234,11 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
if (mode == M_PRINT && getarg(args, 'F')) {
fakeuser.pw_name = a_name ? a_name->val : "nouser";
fakeuser.pw_uid = a_uid ? (uid_t) atol(a_uid->val) : -1;
- return print_user(&fakeuser, getarg(args, 'p') != NULL);
+ return print_user(&fakeuser, getarg(args, 'P') != NULL);
}
if (a_name == NULL)
- cmderr(X_NOTFOUND, "no such uid `%s'\n", a_uid->val);
- cmderr(X_NOTFOUND, "no such user `%s'\n", a_name->val);
+ cmderr(EX_NOUSER, "no such uid `%s'\n", a_uid->val);
+ cmderr(EX_NOUSER, "no such user `%s'\n", a_name->val);
}
if (a_name == NULL) /* May be needed later */
a_name = addarg(args, 'n', newstr(pwd->pw_name));
@@ -237,7 +252,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
uid_t uid = pwd->pw_uid;
if (strcmp(pwd->pw_name, "root") == 0)
- cmderr(X_CMDERR, "cannot remove user 'root'\n");
+ cmderr(EX_DATAERR, "cannot remove user 'root'\n");
/*
* Remove crontabs
@@ -256,7 +271,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
home[sizeof home - 1] = '\0';
if (!delpwent(pwd))
- cmderr(X_NOUPDATE, "Error updating passwd file: %s\n", strerror(errno));
+ cmderr(EX_IOERR, "Error updating passwd file: %s\n", strerror(errno));
editgroups(a_name->val, NULL);
pw_log(cnf, mode, W_USER, "%s(%ld) account removed", a_name->val, (long) uid);
@@ -283,22 +298,22 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
stat(home, &st) == -1 ? "" : "not completely ");
}
}
- return X_ALLOK;
+ return EXIT_SUCCESS;
} else if (mode == M_PRINT)
- return print_user(pwd, getarg(args, 'p') != NULL);
+ return print_user(pwd, getarg(args, 'P') != NULL);
/*
* The rest is edit code
*/
if ((arg = getarg(args, 'l')) != NULL) {
if (strcmp(pwd->pw_name, "root") == 0)
- cmderr(X_CMDERR, "can't rename `root' account\n");
+ cmderr(EX_DATAERR, "can't rename `root' account\n");
pwd->pw_name = pw_checkname(arg->val, 0);
}
if ((arg = getarg(args, 'u')) != NULL && isdigit(*arg->val)) {
pwd->pw_uid = (uid_t) atol(arg->val);
if (pwd->pw_uid != 0 && strcmp(pwd->pw_name, "root") == 0)
- cmderr(X_CMDERR, "can't change uid of `root' account\n");
+ cmderr(EX_DATAERR, "can't change uid of `root' account\n");
if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
fprintf(stderr, "WARNING: account `%s' will have a uid of 0 (superuser access!)\n", pwd->pw_name);
}
@@ -313,11 +328,11 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
time_t expire = parse_date(now, arg->val);
if (now == expire)
- cmderr(X_CMDERR, "Invalid password change date `%s'\n", arg->val);
+ cmderr(EX_DATAERR, "Invalid password change date `%s'\n", arg->val);
pwd->pw_change = expire;
}
}
- if ((arg = getarg(args, 'p')) != NULL) {
+ if ((arg = getarg(args, 'e')) != NULL) {
if (*arg->val == '\0' || strcmp(arg->val, "0") == 0)
pwd->pw_expire = 0;
else {
@@ -325,7 +340,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
time_t expire = parse_date(now, arg->val);
if (now == expire)
- cmderr(X_CMDERR, "Invalid password change date `%s'\n", arg->val);
+ cmderr(EX_DATAERR, "Invalid account expiry date `%s'\n", arg->val);
pwd->pw_expire = expire;
}
}
@@ -335,11 +350,14 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
if (getarg(args, 'L'))
pwd->pw_class = cnf->default_class;
+ if ((arg = getarg(args, 'w')) != NULL && getarg(args, 'h') == NULL)
+ pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
+
} else {
if (a_name == NULL) /* Required */
- cmderr(X_CMDERR, "login name required\n");
+ cmderr(EX_DATAERR, "login name required\n");
else if ((pwd = getpwnam(a_name->val)) != NULL) /* Exists */
- cmderr(X_EXISTS, "login name `%s' already exists\n", a_name->val);
+ cmderr(EX_DATAERR, "login name `%s' already exists\n", a_name->val);
/*
* Now, set up defaults for a new user
@@ -395,20 +413,27 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
}
if (b < 0) {
perror("-h file descriptor");
- return X_CMDERR;
+ return EX_IOERR;
}
line[b] = '\0';
if ((p = strpbrk(line, " \t\r\n")) != NULL)
*p = '\0';
if (!*line)
- cmderr(X_CMDERR, "empty password read on file descriptor %d\n", fd);
+ cmderr(EX_DATAERR, "empty password read on file descriptor %d\n", fd);
pwd->pw_passwd = pw_pwcrypt(line);
}
}
+
+ /*
+ * Special case: -N only displays & exits
+ */
+ if (getarg(args, 'N') != NULL)
+ return print_user(pwd, getarg(args, 'P') != NULL);
+
if ((mode == M_ADD && !addpwent(pwd)) ||
(mode == M_UPDATE && !chgpwent(a_name->val, pwd))) {
perror("password update");
- return X_NOUPDATE;
+ return EX_IOERR;
}
/*
* Ok, user is created or changed - now edit group file
@@ -419,7 +444,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
/* pwd may have been invalidated */
if ((pwd = getpwnam(a_name->val)) == NULL)
- cmderr(X_NOTFOUND, "user '%s' disappeared during update\n", a_name->val);
+ cmderr(EX_NOUSER, "user '%s' disappeared during update\n", a_name->val);
grp = getgrgid(pwd->pw_gid);
pw_log(cnf, mode, W_USER, "%s(%ld):%s(%d):%s:%s:%s",
@@ -471,7 +496,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 X_ALLOK;
+ return EXIT_SUCCESS;
}
@@ -489,7 +514,7 @@ pw_uidpolicy(struct userconf * cnf, struct cargs * args)
uid = (uid_t) atol(a_uid->val);
if ((pwd = getpwuid(uid)) != NULL && getarg(args, 'o') == NULL)
- cmderr(X_EXISTS, "uid `%ld' has already been allocated\n", (long) pwd->pw_uid);
+ cmderr(EX_DATAERR, "uid `%ld' has already been allocated\n", (long) pwd->pw_uid);
} else {
struct bitmap bm;
@@ -524,7 +549,7 @@ pw_uidpolicy(struct userconf * cnf, struct cargs * args)
* Another sanity check
*/
if (uid < cnf->min_uid || uid > cnf->max_uid)
- cmderr(X_EXISTS, "unable to allocate a new uid - range fully used\n");
+ cmderr(EX_SOFTWARE, "unable to allocate a new uid - range fully used\n");
bm_dealloc(&bm);
}
return uid;
@@ -547,15 +572,16 @@ pw_gidpolicy(struct userconf * cnf, struct cargs * args, char *nam, gid_t prefer
/*
* Check the given gid, if any
*/
+ setgrent();
if (a_gid != NULL) {
- setgrent();
if ((grp = getgrnam(a_gid->val)) == NULL) {
gid = (gid_t) atol(a_gid->val);
if ((gid == 0 && !isdigit(*a_gid->val)) || (grp = getgrgid(gid)) == NULL)
- cmderr(X_NOTFOUND, "group `%s' is not defined\n", a_gid->val);
+ cmderr(EX_NOUSER, "group `%s' is not defined\n", a_gid->val);
}
- endgrent();
gid = grp->gr_gid;
+ } else if ((grp = getgrnam(nam)) != NULL && grp->gr_mem[0] == NULL) {
+ gid = grp->gr_gid; /* Already created? Use it anyway... */
} else {
struct cargs grpargs;
char tmp[32];
@@ -576,18 +602,26 @@ pw_gidpolicy(struct userconf * cnf, struct cargs * args, char *nam, gid_t prefer
sprintf(tmp, "%lu", (unsigned long) prefer);
addarg(&grpargs, 'g', tmp);
}
- endgrent();
- pw_group(cnf, M_ADD, &grpargs);
+ if (getarg(args, 'N'))
+ {
+ addarg(&grpargs, 'N', NULL);
+ addarg(&grpargs, 'q', NULL);
+ gid = pw_group(cnf, M_NEXT, &grpargs);
+ }
+ else
+ {
+ pw_group(cnf, M_ADD, &grpargs);
+ if ((grp = getgrnam(nam)) != NULL)
+ gid = grp->gr_gid;
+ }
a_gid = grpargs.lh_first;
while (a_gid != NULL) {
struct carg *t = a_gid->list.le_next;
-
LIST_REMOVE(a_gid, list);
a_gid = t;
}
- if ((grp = getgrnam(nam)) != NULL)
- gid = grp->gr_gid;
}
+ endgrent();
return gid;
}
@@ -601,7 +635,7 @@ pw_pwdpolicy(struct userconf * cnf, struct cargs * args)
if (arg != NULL) {
if ((result = parse_date(now, arg->val)) == now)
- cmderr(X_NOTFOUND, "invalid date/time `%s'\n", arg->val);
+ cmderr(EX_DATAERR, "invalid date/time `%s'\n", arg->val);
} else if (cnf->password_days > 0)
result = now + ((long) cnf->password_days * 86400L);
return result;
@@ -617,7 +651,7 @@ pw_exppolicy(struct userconf * cnf, struct cargs * args)
if (arg != NULL) {
if ((result = parse_date(now, arg->val)) == now)
- cmderr(X_NOTFOUND, "invalid date/time `%s'\n", arg->val);
+ cmderr(EX_DATAERR, "invalid date/time `%s'\n", arg->val);
} else if (cnf->expire_days > 0)
result = now + ((long) cnf->expire_days * 86400L);
return result;
@@ -635,7 +669,7 @@ pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user)
static char home[128];
if (cnf->home == NULL || *cnf->home == '\0')
- cmderr(X_NOTFOUND, "no base home directory set\n");
+ cmderr(EX_CONFIG, "no base home directory set\n");
sprintf(home, "%s/%s", cnf->home, user);
return home;
}
@@ -671,8 +705,8 @@ shell_path(char const * path, char *shells[], char *sh)
}
}
if (sh == NULL)
- cmderr(X_CMDERR, "can't find shell `%s' in shell paths\n", sh);
- cmderr(X_CMDERR, "no default shell available or defined\n");
+ cmderr(EX_OSFILE, "can't find shell `%s' in shell paths\n", sh);
+ cmderr(EX_CONFIG, "no default shell available or defined\n");
return NULL;
}
}
@@ -728,7 +762,7 @@ pw_password(struct userconf * cnf, struct cargs * args, char const * user)
/*
* We give this information back to the user
*/
- if (getarg(args, 'h') == NULL) {
+ if (getarg(args, 'h') == NULL && getarg(args, 'N') == NULL) {
if (isatty(0))
printf("Password is: ");
printf("%s\n", pwbuf);
@@ -761,6 +795,7 @@ print_user(struct passwd * pwd, int pretty)
fmtpwent(buf, pwd);
fputs(buf, stdout);
} else {
+ int j;
char *p;
struct group *grp = getgrgid(pwd->pw_gid);
char uname[60] = "User &", office[60] = "[None]",
@@ -797,13 +832,31 @@ print_user(struct passwd * pwd, int pretty)
" Full Name : %s\n"
" Home : %-32.32s Class : %s\n"
" Shell : %-32.32s Office : %s\n"
- "Work Phone : %-32.32s Home Phone : %s\n\n",
+ "Work Phone : %-32.32s Home Phone : %s\n",
+
pwd->pw_name, (long) pwd->pw_uid,
grp ? grp->gr_name : "(invalid)", (long) pwd->pw_gid,
uname, pwd->pw_dir, pwd->pw_class,
pwd->pw_shell, office, wphone, hphone);
+ setgrent();
+ j = 0;
+ while ((grp=getgrent()) != NULL)
+ {
+ int i = 0;
+ while (i < _UC_MAXGROUPS && grp->gr_mem[i] != NULL)
+ {
+ if (strcmp(grp->gr_mem[i], pwd->pw_name)==0)
+ {
+ printf(j++ == 0 ? " Groups : %s" : ",%s", grp->gr_name);
+ break;
+ }
+ ++i;
+ }
+ }
+ endgrent();
+ printf("%s\n", j ? "\n" : "");
}
- return X_ALLOK;
+ return EXIT_SUCCESS;
}
static char *
@@ -814,11 +867,11 @@ pw_checkname(char *name, int gecos)
while (name[l]) {
if (strchr(notch, name[l]) != NULL || name[l] < ' ')
- cmderr(X_CMDERR, "invalid character `%c' in field\n", name[l]);
+ cmderr(EX_DATAERR, "invalid character `%c' in field\n", name[l]);
++l;
}
if (!gecos && l > 8)
- cmderr(X_CMDERR, "name too long `%s'\n", name);
+ cmderr(EX_DATAERR, "name too long `%s'\n", name);
return name;
}
diff --git a/usr.sbin/pw/pwupd.c b/usr.sbin/pw/pwupd.c
index e13ce5f..43e0968 100644
--- a/usr.sbin/pw/pwupd.c
+++ b/usr.sbin/pw/pwupd.c
@@ -45,6 +45,8 @@
#include "pwupd.h"
+#define HAVE_PWDB_C 1
+
static int
pwdb(char *arg,...)
{
@@ -114,8 +116,13 @@ pw_update(struct passwd * pwd, char const * user, int mode)
/*
* First, let's check the see if the database is alright
+ * Note: -c is only available in FreeBSD 2.2 and above
*/
+#ifdef HAVE_PWDB_C
if (pwdb("-c", NULL) == 0) { /* Check only */
+#else
+ { /* No -c */
+#endif
char pfx[32];
char pwbuf[MAXPWLINE];
int l = sprintf(pfx, "%s:", user);
OpenPOWER on IntegriCloud