summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pw/Makefile2
-rw-r--r--pw/cpdir.c1
-rw-r--r--pw/pw.c90
-rw-r--r--pw/pw.conf.548
-rw-r--r--pw/pw.h17
-rw-r--r--pw/pw_group.c83
-rw-r--r--pw/pw_user.c153
-rw-r--r--pw/pwupd.c7
8 files changed, 274 insertions, 127 deletions
diff --git a/pw/Makefile b/pw/Makefile
index 749d256..fbd614f 100644
--- a/pw/Makefile
+++ b/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/pw/cpdir.c b/pw/cpdir.c
index b40b5c7..c203c89 100644
--- a/pw/cpdir.c
+++ b/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/pw/pw.c b/pw/pw.c
index 01fd919..afec6e1 100644
--- a/pw/pw.c
+++ b/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/pw/pw.conf.5 b/pw/pw.conf.5
index 7bbd09f..253735e 100644
--- a/pw/pw.conf.5
+++ b/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/pw/pw.h b/pw/pw.h
index 8635f44..26110f5 100644
--- a/pw/pw.h
+++ b/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/pw/pw_group.c b/pw/pw_group.c
index d189ccc..b319047 100644
--- a/pw/pw_group.c
+++ b/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/pw/pw_user.c b/pw/pw_user.c
index 928e649..d4c085f 100644
--- a/pw/pw_user.c
+++ b/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/pw/pwupd.c b/pw/pwupd.c
index e13ce5f..43e0968 100644
--- a/pw/pwupd.c
+++ b/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);