summaryrefslogtreecommitdiffstats
path: root/pw
diff options
context:
space:
mode:
Diffstat (limited to 'pw')
-rw-r--r--pw/Makefile14
-rw-r--r--pw/README22
-rw-r--r--pw/bitmap.c132
-rw-r--r--pw/bitmap.h50
-rw-r--r--pw/cpdir.c130
-rw-r--r--pw/edgroup.c229
-rw-r--r--pw/fileupd.c203
-rw-r--r--pw/grupd.c171
-rw-r--r--pw/psdate.c295
-rw-r--r--pw/psdate.h40
-rw-r--r--pw/pw.81001
-rw-r--r--pw/pw.c456
-rw-r--r--pw/pw.conf.5318
-rw-r--r--pw/pw.h132
-rw-r--r--pw/pw_conf.c516
-rw-r--r--pw/pw_group.c423
-rw-r--r--pw/pw_log.c68
-rw-r--r--pw/pw_nis.c72
-rw-r--r--pw/pw_user.c1274
-rw-r--r--pw/pw_vpw.c316
-rw-r--r--pw/pwupd.c213
-rw-r--r--pw/pwupd.h160
-rw-r--r--pw/rm_r.c75
23 files changed, 0 insertions, 6310 deletions
diff --git a/pw/Makefile b/pw/Makefile
deleted file mode 100644
index ae0023c..0000000
--- a/pw/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# $FreeBSD$
-
-PROG= pw
-MAN= pw.conf.5 pw.8
-SRCS= pw.c pw_conf.c pw_user.c pw_group.c pw_log.c pw_nis.c pw_vpw.c \
- grupd.c pwupd.c fileupd.c edgroup.c psdate.c \
- bitmap.c cpdir.c rm_r.c
-
-WARNS?= 1
-
-DPADD= ${LIBCRYPT} ${LIBUTIL}
-LDADD= -lcrypt -lutil
-
-.include <bsd.prog.mk>
diff --git a/pw/README b/pw/README
deleted file mode 100644
index bbb1539..0000000
--- a/pw/README
+++ /dev/null
@@ -1,22 +0,0 @@
-
-pw is a command-line driven passwd/group editor utility that provides
-an easy and safe means of modifying of any/all fields in the system
-password files, and has an add, modify and delete mode for user and
-group records. Command line options have been fashioned to be similar
-to those used by the Sun/shadow commands: useradd, usermod, userdel,
-groupadd, groupmod, groupdel, but combines all operations within the
-single command `pw'.
-
-User add mode also provides a means of easily setting system useradd
-defaults (see pw.conf.5), so that adding a user is as easy as issuing
-the command "pw useradd <loginid>". Creation of a unique primary
-group for each user and automatic membership in secondary groups
-is fully supported.
-
-This program may be FreeBSD specific, but should be trivial to port to
-other bsd4.4 variants.
-
-Author and maintainer: David L. Nugent, <davidn@blaze.net.au>
-
-$FreeBSD$
-
diff --git a/pw/bitmap.c b/pw/bitmap.c
deleted file mode 100644
index bcfea7e..0000000
--- a/pw/bitmap.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "bitmap.h"
-
-struct bitmap
-bm_alloc(int size)
-{
- struct bitmap bm;
- int szmap = (size / 8) + !!(size % 8);
-
- bm.size = size;
- bm.map = malloc(szmap);
- if (bm.map)
- memset(bm.map, 0, szmap);
- return bm;
-}
-
-void
-bm_dealloc(struct bitmap * bm)
-{
- if (bm->map)
- free(bm->map);
-}
-
-static void
-bm_getmask(int *pos, unsigned char *bmask)
-{
- *bmask = (unsigned char) (1 << (*pos % 8));
- *pos /= 8;
-}
-
-void
-bm_setbit(struct bitmap * bm, int pos)
-{
- unsigned char bmask;
-
- bm_getmask(&pos, &bmask);
- bm->map[pos] |= bmask;
-}
-
-void
-bm_clrbit(struct bitmap * bm, int pos)
-{
- unsigned char bmask;
-
- bm_getmask(&pos, &bmask);
- bm->map[pos] &= ~bmask;
-}
-
-int
-bm_isset(struct bitmap * bm, int pos)
-{
- unsigned char bmask;
-
- bm_getmask(&pos, &bmask);
- return !!(bm->map[pos] & bmask);
-}
-
-int
-bm_firstunset(struct bitmap * bm)
-{
- int szmap = (bm->size / 8) + !!(bm->size % 8);
- int at = 0;
- int pos = 0;
-
- while (pos < szmap) {
- unsigned char bmv = bm->map[pos++];
- unsigned char bmask = 1;
-
- while (bmask & 0xff) {
- if ((bmv & bmask) == 0)
- return at;
- bmask <<= 1;
- ++at;
- }
- }
- return at;
-}
-
-int
-bm_lastset(struct bitmap * bm)
-{
- int szmap = (bm->size / 8) + !!(bm->size % 8);
- int at = 0;
- int pos = 0;
- int ofs = 0;
-
- while (pos < szmap) {
- unsigned char bmv = bm->map[pos++];
- unsigned char bmask = 1;
-
- while (bmask & 0xff) {
- if ((bmv & bmask) != 0)
- ofs = at;
- bmask <<= 1;
- ++at;
- }
- }
- return ofs;
-}
diff --git a/pw/bitmap.h b/pw/bitmap.h
deleted file mode 100644
index 4d6cfe4..0000000
--- a/pw/bitmap.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _BITMAP_H_
-#define _BITMAP_H_
-
-#include <sys/cdefs.h>
-
-struct bitmap
-{
- int size;
- unsigned char *map;
-};
-
-__BEGIN_DECLS
-struct bitmap bm_alloc(int size);
-void bm_dealloc(struct bitmap * bm);
-void bm_setbit(struct bitmap * bm, int pos);
-void bm_clrbit(struct bitmap * bm, int pos);
-int bm_isset(struct bitmap * bm, int pos);
-int bm_firstunset(struct bitmap * bm);
-int bm_lastset(struct bitmap * bm);
-__END_DECLS
-
-#endif /* !_BITMAP_H */
diff --git a/pw/cpdir.c b/pw/cpdir.c
deleted file mode 100644
index f370421..0000000
--- a/pw/cpdir.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <dirent.h>
-
-#include "pwupd.h"
-
-void
-copymkdir(char const * dir, char const * skel, mode_t mode, uid_t uid, gid_t gid)
-{
- char src[MAXPATHLEN];
- char dst[MAXPATHLEN];
- char lnk[MAXPATHLEN];
- int len;
-
- if (mkdir(dir, mode) != 0 && errno != EEXIST) {
- warn("mkdir(%s)", dir);
- } else {
- int infd, outfd;
- struct stat st;
-
- static char counter = 0;
- static char *copybuf = NULL;
-
- ++counter;
- chown(dir, uid, gid);
- if (skel != NULL && *skel != '\0') {
- DIR *d = opendir(skel);
-
- if (d != NULL) {
- struct dirent *e;
-
- while ((e = readdir(d)) != NULL) {
- char *p = e->d_name;
-
- if (snprintf(src, sizeof(src), "%s/%s", skel, p) >= (int)sizeof(src))
- warn("warning: pathname too long '%s/%s' (skel not copied)", skel, p);
- else if (lstat(src, &st) == 0) {
- if (strncmp(p, "dot.", 4) == 0) /* Conversion */
- p += 3;
- if (snprintf(dst, sizeof(dst), "%s/%s", dir, p) >= (int)sizeof(dst))
- warn("warning: path too long '%s/%s' (skel file skipped)", dir, p);
- else {
- if (S_ISDIR(st.st_mode)) { /* Recurse for this */
- if (strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0)
- copymkdir(dst, src, (st.st_mode & 0777), uid, gid);
- chflags(dst, st.st_flags); /* propogate flags */
- } else if (S_ISLNK(st.st_mode) && (len = readlink(src, lnk, sizeof(lnk))) != -1) {
- lnk[len] = '\0';
- symlink(lnk, dst);
- lchown(dst, uid, gid);
- /*
- * Note: don't propogate special attributes
- * but do propogate file flags
- */
- } else if (S_ISREG(st.st_mode) && (outfd = open(dst, O_RDWR | O_CREAT | O_EXCL, st.st_mode)) != -1) {
- if ((infd = open(src, O_RDONLY)) == -1) {
- close(outfd);
- remove(dst);
- } else {
- int b;
-
- /*
- * Allocate our copy buffer if we need to
- */
- if (copybuf == NULL)
- copybuf = malloc(4096);
- while ((b = read(infd, copybuf, 4096)) > 0)
- write(outfd, copybuf, b);
- close(infd);
- /*
- * Propogate special filesystem flags
- */
- fchown(outfd, uid, gid);
- fchflags(outfd, st.st_flags);
- close(outfd);
- chown(dst, uid, gid);
- }
- }
- }
- }
- }
- closedir(d);
- }
- }
- if (--counter == 0 && copybuf != NULL) {
- free(copybuf);
- copybuf = NULL;
- }
- }
-}
-
diff --git a/pw/edgroup.c b/pw/edgroup.c
deleted file mode 100644
index 1cc46b4..0000000
--- a/pw/edgroup.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <pwd.h>
-#include <grp.h>
-#include <fcntl.h>
-#include <sys/param.h>
-#include <ctype.h>
-
-#include "pwupd.h"
-
-static int
-isingroup(char const * name, char **mem)
-{
- int i;
-
- for (i = 0; mem[i] != NULL; i++)
- if (strcmp(name, mem[i]) == 0)
- return i;
- return -1;
-}
-
-int
-editgroups(char *name, char **groups)
-{
- int rc = 0;
- int infd;
- char groupfile[MAXPATHLEN];
- char grouptmp[MAXPATHLEN];
-
- strncpy(groupfile, getgrpath(_GROUP), MAXPATHLEN - 5);
- groupfile[MAXPATHLEN - 5] = '\0';
- strcpy(grouptmp, groupfile);
- strcat(grouptmp, ".new");
-
- if ((infd = open(groupfile, O_RDWR | O_CREAT | O_EXLOCK, 0644)) != -1) {
- FILE *infp;
-
- if ((infp = fdopen(infd, "r+")) == NULL)
- close(infd);
- else {
- int outfd;
-
- if ((outfd = open(grouptmp, O_RDWR | O_CREAT | O_TRUNC, 0644)) != -1) {
- FILE *outfp;
-
- if ((outfp = fdopen(outfd, "w+")) == NULL)
- close(outfd);
- else {
- int linelen = PWBUFSZ;
- int outlen = PWBUFSZ;
- int memlen = 200; /* Arbitrary */
- char *line = malloc(linelen);
- char *outl = malloc(outlen);
- char **mems = malloc(memlen * sizeof(char *));
- int namlen = strlen(name);
-
- if (line == NULL || outl == NULL || mems == NULL) {
- mem_abort:
- rc = 0;
- } else {
- while (fgets(line, linelen, infp) != NULL) {
- char *p;
- int l;
-
- while ((p = strchr(line, '\n')) == NULL)
- {
- if (extendline(&line, &linelen, linelen + PWBUFSZ) == -1) {
- goto mem_abort;
- }
- l = strlen(line);
- if (fgets(line + l, linelen - l, infp) == NULL)
- break; /* No newline terminator on last line */
- }
- l = strlen(line) + namlen + 1;
- if (extendline(&outl, &outlen, l) == -1) {
- goto mem_abort;
- }
- if (*line == '#')
- strcpy(outl, line);
- else if (*line == '\n')
- *outl = '\0';
- else {
- int i,
- mno = 0;
- char *cp = line;
- char const *sep = ":\n";
- struct group grp;
-
- memset(&grp, 0, sizeof grp);
- for (i = 0; (p = strsep(&cp, sep)) != NULL; i++) {
- switch (i) {
- case 0: /* Group name */
- grp.gr_name = p;
- break;
- case 1: /* Group password */
- grp.gr_passwd = p;
- break;
- case 2: /* Group id */
- grp.gr_gid = atoi(p);
- break;
- case 3: /* Member list */
- cp = p;
- sep = ",\n";
- break;
- default: /* Individual members */
- if (*p) {
- if (extendarray(&mems, &memlen, mno + 2) == -1) {
- goto mem_abort;
- }
- mems[mno++] = p;
- }
- break;
- }
- }
- if (i < 2) /* Bail out - insufficient fields */
- continue;
-
- grp.gr_mem = mems;
- for (i = mno; i < memlen; i++)
- mems[i] = NULL;
-
- /*
- * Delete from group, or add to group?
- */
- if (groups == NULL || isingroup(grp.gr_name, groups) == -1) { /* Delete */
- int idx;
-
- while ((idx = isingroup(name, mems)) != -1) {
- for (i = idx; i < (memlen - 1); i++)
- mems[i] = mems[i + 1];
- mems[i] = NULL;
- --mno;
- }
- /*
- * Special case - deleting user and group may be user's own
- */
- if (groups == NULL && mems[0] == NULL && strcmp(name, grp.gr_name) == 0) {
- /*
- * First, make _sure_ we don't have other members
- */
- struct passwd *pwd;
-
- SETPWENT();
- while ((pwd = GETPWENT()) != NULL && (gid_t)pwd->pw_gid != (gid_t)grp.gr_gid);
- ENDPWENT();
- if (pwd == NULL) /* No members at all */
- continue; /* Drop the group */
- }
- } else if (isingroup(name, mems) == -1) {
- if (extendarray(&mems, &memlen, mno + 2) == -1) {
- goto mem_abort;
- }
- grp.gr_mem = mems; /* May have realloced() */
- mems[mno++] = name;
- mems[mno ] = NULL;
- }
- fmtgrentry(&outl, &outlen, &grp, PWF_GROUP);
- }
- fputs(outl, outfp);
- }
- if (fflush(outfp) != EOF) {
- rc = 1;
-
- /*
- * Copy data back into the original file and truncate
- */
- rewind(infp);
- rewind(outfp);
- while (fgets(outl, outlen, outfp) != NULL)
- fputs(outl, infp);
-
- /*
- * This is a gross hack, but we may have corrupted the
- * original file.
- */
- if (fflush(infp) == EOF || ferror(infp))
- rc = rename(grouptmp, groupfile) == 0;
- else
- ftruncate(infd, ftell(infp));
- }
- }
- free(mems);
- free(outl);
- free(line);
- fclose(outfp);
- }
- remove(grouptmp);
- }
- fclose(infp);
- }
- }
- return rc;
-}
diff --git a/pw/fileupd.c b/pw/fileupd.c
deleted file mode 100644
index b88f4fa..0000000
--- a/pw/fileupd.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "pwupd.h"
-
-int
-extendline(char **buf, int * buflen, int needed)
-{
- if (needed > *buflen) {
- char *tmp = realloc(*buf, needed);
- if (tmp == NULL)
- return -1;
- *buf = tmp;
- *buflen = needed;
- }
- return *buflen;
-}
-
-int
-extendarray(char ***buf, int * buflen, int needed)
-{
- if (needed > *buflen) {
- char **tmp = realloc(*buf, needed * sizeof(char *));
- if (tmp == NULL)
- return -1;
- *buf = tmp;
- *buflen = needed;
- }
- return *buflen;
-}
-
-
-int
-fileupdate(char const * filename, mode_t fmode, char const * newline, char const * prefix, int pfxlen, int updmode)
-{
- int rc = 0;
-
- if (pfxlen <= 1)
- rc = EINVAL;
- else {
- int infd = open(filename, O_RDWR | O_CREAT | O_EXLOCK, fmode);
-
- if (infd == -1)
- rc = errno;
- else {
- FILE *infp = fdopen(infd, "r+");
-
- if (infp == NULL) {
- rc = errno; /* Assumes fopen(3) sets errno from open(2) */
- close(infd);
- } else {
- int outfd;
- char file[MAXPATHLEN];
-
- strcpy(file, filename);
- strcat(file, ".new");
- outfd = open(file, O_RDWR | O_CREAT | O_TRUNC, fmode);
- if (outfd == -1)
- rc = errno;
- else {
- FILE *outfp = fdopen(outfd, "w+");
-
- if (outfp == NULL) {
- rc = errno;
- close(outfd);
- } else {
- int updated = UPD_CREATE;
- int linesize = PWBUFSZ;
- char *line = malloc(linesize);
-
- nextline:
- while (fgets(line, linesize, infp) != NULL) {
- char *p = strchr(line, '\n');
-
- while ((p = strchr(line, '\n')) == NULL) {
- int l;
- if (extendline(&line, &linesize, linesize + PWBUFSZ) == -1) {
- int ch;
- fputs(line, outfp);
- while ((ch = fgetc(infp)) != EOF) {
- fputc(ch, outfp);
- if (ch == '\n')
- break;
- }
- goto nextline;
- }
- l = strlen(line);
- if (fgets(line + l, linesize - l, infp) == NULL)
- break;
- }
- if (*line != '#' && *line != '\n') {
- if (!updated && strncmp(line, prefix, pfxlen) == 0) {
- updated = updmode == UPD_REPLACE ? UPD_REPLACE : UPD_DELETE;
-
- /*
- * Only actually write changes if updating
- */
- if (updmode == UPD_REPLACE)
- strcpy(line, newline);
- else if (updmode == UPD_DELETE)
- continue;
- }
- }
- fputs(line, outfp);
- }
-
- /*
- * Now, we need to decide what to do: If we are in
- * update mode, and no record was updated, then error If
- * we are in insert mode, and record already exists,
- * then error
- */
- if (updmode != updated)
- /* -1 return means:
- * update,delete=no user entry
- * create=entry exists
- */
- rc = -1;
- else {
-
- /*
- * If adding a new record, append it to the end
- */
- if (updmode == UPD_CREATE)
- fputs(newline, outfp);
-
- /*
- * Flush the file and check for the result
- */
- if (fflush(outfp) == EOF)
- rc = errno; /* Failed to update */
- else {
- /*
- * Copy data back into the
- * original file and truncate
- */
- rewind(infp);
- rewind(outfp);
- while (fgets(line, linesize, outfp) != NULL)
- fputs(line, infp);
-
- /*
- * If there was a problem with copying
- * we will just rename 'file.new'
- * to 'file'.
- * This is a gross hack, but we may have
- * corrupted the original file
- */
- if (fflush(infp) == EOF || ferror(infp))
- rename(file, filename);
- else
- ftruncate(infd, ftell(infp));
- }
- }
- free(line);
- fclose(outfp);
- }
- remove(file);
- }
- fclose(infp);
- }
- }
- }
- return rc;
-}
diff --git a/pw/grupd.c b/pw/grupd.c
deleted file mode 100644
index edff76d..0000000
--- a/pw/grupd.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-
-#include "pwupd.h"
-
-static char * grpath = _PATH_PWD;
-
-int
-setgrdir(const char * dir)
-{
- if (dir == NULL)
- return -1;
- else {
- char * d = malloc(strlen(dir)+1);
- if (d == NULL)
- return -1;
- grpath = strcpy(d, dir);
- }
- return 0;
-}
-
-char *
-getgrpath(const char * file)
-{
- static char pathbuf[MAXPATHLEN];
-
- snprintf(pathbuf, sizeof pathbuf, "%s/%s", grpath, file);
- return pathbuf;
-}
-
-int
-grdb(char *arg,...)
-{
- /*
- * This is a stub for now, but maybe eventually be functional
- * if ever an indexed version of /etc/groups is implemented.
- */
- arg=arg;
- return 0;
-}
-
-int
-fmtgrentry(char **buf, int * buflen, struct group * grp, int type)
-{
- int i, l;
-
- /*
- * Since a group line is of arbitrary length,
- * we need to calculate up-front just how long
- * it will need to be...
- */
- /* groupname : password : gid : */
- l = strlen(grp->gr_name) + 1 + strlen(grp->gr_passwd) + 1 + 5 + 1;
- /* group members + comma separator */
- for (i = 0; grp->gr_mem[i] != NULL; i++) {
- l += strlen(grp->gr_mem[i]) + 1;
- }
- l += 2; /* For newline & NUL */
- if (extendline(buf, buflen, l) == -1)
- l = -1;
- else{
- /*
- * Now we can safely format
- */
- if (type == PWF_STANDARD)
- l = sprintf(*buf, "%s:*:%ld:", grp->gr_name, (long) grp->gr_gid);
- else
- l = sprintf(*buf, "%s:%s:%ld:", grp->gr_name, grp->gr_passwd, (long) grp->gr_gid);
-
- /*
- * List members
- */
- for (i = 0; grp->gr_mem[i] != NULL; i++) {
- l += sprintf(*buf + l, "%s%s", i ? "," : "", grp->gr_mem[i]);
- }
-
- (*buf)[l++] = '\n';
- (*buf)[l] = '\0';
- }
- return l;
-}
-
-
-int
-fmtgrent(char **buf, int * buflen, struct group * grp)
-{
- return fmtgrentry(buf, buflen, grp, PWF_STANDARD);
-}
-
-
-static int
-gr_update(struct group * grp, char const * group, int mode)
-{
- int l;
- char pfx[64];
- int grbuflen = 0;
- char *grbuf = NULL;
-
- ENDGRENT();
- l = snprintf(pfx, sizeof pfx, "%s:", group);
-
- /*
- * Update the group file
- */
- if (grp != NULL && fmtgrentry(&grbuf, &grbuflen, grp, PWF_PASSWD) == -1)
- l = -1;
- else {
- l = fileupdate(getgrpath(_GROUP), 0644, grbuf, pfx, l, mode);
- if (l == 0)
- l = grdb(NULL);
- }
- if (grbuf != NULL)
- free(grbuf);
- return l;
-}
-
-
-int
-addgrent(struct group * grp)
-{
- return gr_update(grp, grp->gr_name, UPD_CREATE);
-}
-
-int
-chggrent(char const * login, struct group * grp)
-{
- return gr_update(grp, login, UPD_REPLACE);
-}
-
-int
-delgrent(struct group * grp)
-{
- return gr_update(NULL, grp->gr_name, UPD_DELETE);
-}
diff --git a/pw/psdate.c b/pw/psdate.c
deleted file mode 100644
index 3f4c010..0000000
--- a/pw/psdate.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "psdate.h"
-
-
-static int
-a2i(char const ** str)
-{
- int i = 0;
- char const *s = *str;
-
- if (isdigit((unsigned char)*s)) {
- i = atoi(s);
- while (isdigit((unsigned char)*s))
- ++s;
- *str = s;
- }
- return i;
-}
-
-static int
-numerics(char const * str)
-{
- int rc = isdigit((unsigned char)*str);
-
- if (rc)
- while (isdigit((unsigned char)*str) || *str == 'x')
- ++str;
- return rc && !*str;
-}
-
-static int
-aindex(char const * arr[], char const ** str, int len)
-{
- int l, i;
- char mystr[32];
-
- mystr[len] = '\0';
- l = strlen(strncpy(mystr, *str, len));
- for (i = 0; i < l; i++)
- mystr[i] = (char) tolower((unsigned char)mystr[i]);
- for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++);
- if (arr[i] == NULL)
- i = -1;
- else { /* Skip past it */
- while (**str && isalpha((unsigned char)**str))
- ++(*str);
- /* And any following whitespace */
- while (**str && (**str == ',' || isspace((unsigned char)**str)))
- ++(*str);
- } /* Return index */
- return i;
-}
-
-static int
-weekday(char const ** str)
-{
- static char const *days[] =
- {"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL};
-
- return aindex(days, str, 3);
-}
-
-static int
-month(char const ** str)
-{
- static char const *months[] =
- {"jan", "feb", "mar", "apr", "may", "jun", "jul",
- "aug", "sep", "oct", "nov", "dec", NULL};
-
- return aindex(months, str, 3);
-}
-
-static void
-parse_time(char const * str, int *hour, int *min, int *sec)
-{
- *hour = a2i(&str);
- if ((str = strchr(str, ':')) == NULL)
- *min = *sec = 0;
- else {
- ++str;
- *min = a2i(&str);
- *sec = ((str = strchr(str, ':')) == NULL) ? 0 : atoi(++str);
- }
-}
-
-
-static void
-parse_datesub(char const * str, int *day, int *mon, int *year)
-{
- int i;
-
- static char const nchrs[] = "0123456789 \t,/-.";
-
- if ((i = month(&str)) != -1) {
- *mon = i;
- if ((i = a2i(&str)) != 0)
- *day = i;
- } else if ((i = a2i(&str)) != 0) {
- *day = i;
- while (*str && strchr(nchrs + 10, *str) != NULL)
- ++str;
- if ((i = month(&str)) != -1)
- *mon = i;
- else if ((i = a2i(&str)) != 0)
- *mon = i - 1;
- } else
- return;
-
- while (*str && strchr(nchrs + 10, *str) != NULL)
- ++str;
- if (isdigit((unsigned char)*str)) {
- *year = atoi(str);
- if (*year > 1900)
- *year -= 1900;
- else if (*year < 32)
- *year += 100;
- }
-}
-
-
-/*-
- * Parse time must be flexible, it handles the following formats:
- * nnnnnnnnnnn UNIX timestamp (all numeric), 0 = now
- * 0xnnnnnnnn UNIX timestamp in hexadecimal
- * 0nnnnnnnnn UNIX timestamp in octal
- * 0 Given time
- * +nnnn[smhdwoy] Given time + nnnn hours, mins, days, weeks, months or years
- * -nnnn[smhdwoy] Given time - nnnn hours, mins, days, weeks, months or years
- * dd[ ./-]mmm[ ./-]yy Date }
- * hh:mm:ss Time } May be combined
- */
-
-time_t
-parse_date(time_t dt, char const * str)
-{
- char *p;
- int i;
- long val;
- struct tm *T;
-
- if (dt == 0)
- dt = time(NULL);
-
- while (*str && isspace((unsigned char)*str))
- ++str;
-
- if (numerics(str)) {
- dt = strtol(str, &p, 0);
- } else if (*str == '+' || *str == '-') {
- val = strtol(str, &p, 0);
- switch (*p) {
- case 'h':
- case 'H': /* hours */
- dt += (val * 3600L);
- break;
- case '\0':
- case 'm':
- case 'M': /* minutes */
- dt += (val * 60L);
- break;
- case 's':
- case 'S': /* seconds */
- dt += val;
- break;
- case 'd':
- case 'D': /* days */
- dt += (val * 86400L);
- break;
- case 'w':
- case 'W': /* weeks */
- dt += (val * 604800L);
- break;
- case 'o':
- case 'O': /* months */
- T = localtime(&dt);
- T->tm_mon += (int) val;
- i = T->tm_mday;
- goto fixday;
- case 'y':
- case 'Y': /* years */
- T = localtime(&dt);
- T->tm_year += (int) val;
- i = T->tm_mday;
- fixday:
- dt = mktime(T);
- T = localtime(&dt);
- if (T->tm_mday != i) {
- T->tm_mday = 1;
- dt = mktime(T);
- dt -= (time_t) 86400L;
- }
- default: /* unknown */
- break; /* leave untouched */
- }
- } else {
- char *q, tmp[64];
-
- /*
- * Skip past any weekday prefix
- */
- weekday(&str);
- strlcpy(tmp, str, sizeof(tmp));
- str = tmp;
- T = localtime(&dt);
-
- /*
- * See if we can break off any timezone
- */
- while ((q = strrchr(tmp, ' ')) != NULL) {
- if (strchr("(+-", q[1]) != NULL)
- *q = '\0';
- else {
- int j = 1;
-
- while (q[j] && isupper((unsigned char)q[j]))
- ++j;
- if (q[j] == '\0')
- *q = '\0';
- else
- break;
- }
- }
-
- /*
- * See if there is a time hh:mm[:ss]
- */
- if ((p = strchr(tmp, ':')) == NULL) {
-
- /*
- * No time string involved
- */
- T->tm_hour = T->tm_min = T->tm_sec = 0;
- parse_datesub(tmp, &T->tm_mday, &T->tm_mon, &T->tm_year);
- } else {
- char datestr[64], timestr[64];
-
- /*
- * Let's chip off the time string
- */
- if ((q = strpbrk(p, " \t")) != NULL) { /* Time first? */
- int l = q - str;
-
- strlcpy(timestr, str, l + 1);
- strlcpy(datestr, q + 1, sizeof(datestr));
- parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec);
- parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year);
- } else if ((q = strrchr(tmp, ' ')) != NULL) { /* Time last */
- int l = q - tmp;
-
- strlcpy(timestr, q + 1, sizeof(timestr));
- strlcpy(datestr, tmp, l + 1);
- } else /* Bail out */
- return dt;
- parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec);
- parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year);
- }
- dt = mktime(T);
- }
- return dt;
-}
diff --git a/pw/psdate.h b/pw/psdate.h
deleted file mode 100644
index a1e99d4..0000000
--- a/pw/psdate.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _PSDATE_H_
-#define _PSDATE_H_
-
-#include <time.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-time_t parse_date(time_t dt, char const * str);
-void print_date(char *buf, time_t t, int dotime);
-__END_DECLS
-
-#endif /* !_PSDATE_H_ */
diff --git a/pw/pw.8 b/pw/pw.8
deleted file mode 100644
index 4287055..0000000
--- a/pw/pw.8
+++ /dev/null
@@ -1,1001 +0,0 @@
-.\" Copyright (C) 1996
-.\" David L. Nugent. All rights reserved.
-.\"
-.\" 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.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd March 30, 2007
-.Dt PW 8
-.Os
-.Sh NAME
-.Nm pw
-.Nd create, remove, modify & display system users and groups
-.Sh SYNOPSIS
-.Nm
-.Op Fl V Ar etcdir
-.Ar useradd
-.Op name|uid
-.Op Fl C Ar config
-.Op Fl q
-.Op Fl n Ar name
-.Op Fl u Ar uid
-.Op Fl c Ar comment
-.Op Fl d Ar dir
-.Op Fl e Ar date
-.Op Fl p Ar date
-.Op Fl g Ar group
-.Op Fl G Ar grouplist
-.Op Fl m
-.Op Fl M Ar mode
-.Op Fl k Ar dir
-.Op Fl w Ar method
-.Op Fl s Ar shell
-.Op Fl o
-.Op Fl L Ar class
-.Op Fl h Ar fd | Fl H Ar fd
-.Op Fl N
-.Op Fl P
-.Op Fl Y
-.Nm
-.Op Fl V Ar etcdir
-.Ar useradd
-.Op name|uid
-.Fl D
-.Op Fl C Ar config
-.Op Fl q
-.Op Fl b Ar dir
-.Op Fl e Ar days
-.Op Fl p Ar days
-.Op Fl g Ar group
-.Op Fl G Ar grouplist
-.Op Fl k Ar dir
-.Op Fl M Ar mode
-.Op Fl u Ar min , Ns Ar max
-.Op Fl i Ar min , Ns Ar max
-.Op Fl w Ar method
-.Op Fl s Ar shell
-.Op Fl y Ar path
-.Nm
-.Op Fl V Ar etcdir
-.Ar userdel
-.Op name|uid
-.Op Fl n Ar name
-.Op Fl u Ar uid
-.Op Fl r
-.Op Fl Y
-.Nm
-.Op Fl V Ar etcdir
-.Ar usermod
-.Op name|uid
-.Op Fl C Ar config
-.Op Fl q
-.Op Fl n Ar name
-.Op Fl u Ar uid
-.Op Fl c Ar comment
-.Op Fl d Ar dir
-.Op Fl e Ar date
-.Op Fl p Ar date
-.Op Fl g Ar group
-.Op Fl G Ar grouplist
-.Op Fl l Ar name
-.Op Fl m
-.Op Fl M Ar mode
-.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 | Fl H Ar fd
-.Op Fl N
-.Op Fl P
-.Op Fl Y
-.Nm
-.Op Fl V Ar etcdir
-.Ar usershow
-.Op name|uid
-.Op Fl n Ar name
-.Op Fl u Ar uid
-.Op Fl F
-.Op Fl P
-.Op Fl 7
-.Op Fl a
-.Nm
-.Op Fl V Ar etcdir
-.Ar usernext
-.Op Fl C Ar config
-.Op Fl q
-.Nm
-.Op Fl V Ar etcdir
-.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 | Fl H Ar fd
-.Op Fl N
-.Op Fl P
-.Op Fl Y
-.Nm
-.Op Fl V Ar etcdir
-.Ar groupdel
-.Op group|gid
-.Op Fl n Ar name
-.Op Fl g Ar gid
-.Op Fl Y
-.Nm
-.Op Fl V Ar etcdir
-.Ar groupmod
-.Op group|gid
-.Op Fl C Ar config
-.Op Fl q
-.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 d Ar oldmembers
-.Op Fl h Ar fd | Fl H Ar fd
-.Op Fl N
-.Op Fl P
-.Op Fl Y
-.Nm
-.Op Fl V Ar etcdir
-.Ar groupshow
-.Op group|gid
-.Op Fl n Ar name
-.Op Fl g Ar gid
-.Op Fl F
-.Op Fl P
-.Op Fl a
-.Nm
-.Op Fl V Ar etcdir
-.Ar groupnext
-.Op Fl C Ar config
-.Op Fl q
-.Nm
-.Op Fl V Ar etcdir
-.Ar lock
-.Op name|uid
-.Op Fl C Ar config
-.Op Fl q
-.Nm
-.Op Fl V Ar etcdir
-.Ar unlock
-.Op name|uid
-.Op Fl C Ar config
-.Op Fl q
-.Sh DESCRIPTION
-The
-.Nm
-utility is a command-line based editor for the system
-.Ar user
-and
-.Ar group
-files, allowing the superuser an easy to use and standardized way of adding,
-modifying and removing users and groups.
-Note that
-.Nm
-only operates on the local user and group files.
-.Tn NIS
-users and groups must be
-maintained on the
-.Tn NIS
-server.
-The
-.Nm
-utility handles updating the
-.Pa passwd ,
-.Pa master.passwd ,
-.Pa group
-and the secure and insecure
-password database files, and must be run as root.
-.Pp
-The first one or two keywords provided to
-.Nm
-on the command line provide the context for the remainder of the arguments.
-The keywords
-.Ar user
-and
-.Ar group
-may be combined with
-.Ar add ,
-.Ar del ,
-.Ar mod ,
-.Ar show ,
-or
-.Ar next
-in any order.
-(For example,
-.Ar showuser ,
-.Ar usershow ,
-.Ar show user ,
-and
-.Ar user show
-all mean the same thing.)
-This flexibility is useful for interactive scripts calling
-.Nm
-for user and group database manipulation.
-Following these keywords, you may optionally specify the user or group name or numeric
-id as an alternative to using the
-.Fl n Ar name ,
-.Fl u Ar uid ,
-.Fl g Ar gid
-options.
-.Pp
-The following flags are common to most or all modes of operation:
-.Pp
-.Bl -tag -width "-G grouplist"
-.It Fl V Ar etcdir
-This flag sets an alternate location for the password, group and configuration files,
-and may be used to maintain a user/group database in an alternate location.
-If this switch is specified, the system
-.Pa /etc/pw.conf
-will not be sourced for default configuration data, but the file pw.conf in the
-specified directory will be used instead (or none, if it does not exist).
-The
-.Fl C
-flag may be used to override this behaviour.
-As an exception to the general rule where options must follow the operation
-type, the
-.Fl V
-flag may be used on the command line before the operation keyword.
-.It Fl C Ar config
-By default,
-.Nm
-reads the file
-.Pa /etc/pw.conf
-to obtain policy information on how new user accounts and groups are to be created.
-The
-.Fl C
-option specifies a different configuration file.
-While most of the contents of the configuration file may be overridden via
-command-line options, it may be more convenient to keep standard information in a
-configuration file.
-.It Fl q
-Use of this option causes
-.Nm
-to suppress error messages, which may be useful in interactive environments where it
-is preferable to interpret status codes returned by
-.Nm
-rather than messing up a carefully formatted display.
-.It Fl N
-This option is available in
-.Ar add
-and
-.Ar modify
-operations, and tells
-.Nm
-to output the result of the operation without updating the user or group
-databases.
-You may use the
-.Fl P
-option to switch between standard passwd and readable formats.
-.It Fl Y
-Using this option with any of the update modes causes
-.Nm
-to run
-.Xr make 1
-after changing to the directory
-.Pa /var/yp .
-This is intended to allow automatic updating of
-.Tn NIS
-database files.
-If separate passwd and group files are being used by
-.Tn NIS ,
-then use the
-.Fl y Ar path
-option to specify the location of the
-.Tn NIS
-passwd database so that
-.Nm
-will concurrently update it with the system password
-databases.
-.El
-.Sh USER OPTIONS
-The following options apply to the
-.Ar useradd
-and
-.Ar usermod
-commands:
-.Pp
-.Bl -tag -width "-G grouplist"
-.It Fl n Ar name
-Specify the user/account name.
-.It Fl u Ar uid
-Specify the user/account numeric id.
-.Pp
-Usually, you only need to provide one or the other of these options, as the account
-name will imply the uid, or vice versa.
-However, there are times when you need to provide both.
-For example, when changing the uid of an existing user with
-.Ar usermod ,
-or overriding the default uid when creating a new account.
-If you wish
-.Nm
-to automatically allocate the uid to a new user with
-.Ar useradd ,
-then you should
-.Em not
-use the
-.Fl u
-option.
-You may also provide either the account or userid immediately after the
-.Ar useradd ,
-.Ar userdel ,
-.Ar usermod
-or
-.Ar usershow
-keywords on the command line without using the
-.Fl n
-or
-.Fl u
-options.
-.El
-.Pp
-.Bl -tag -width "-G grouplist"
-.It Fl c Ar comment
-This field sets the contents of the passwd GECOS field, which normally contains up
-to four comma-separated fields containing the user's full name, office or location,
-and work and home phone numbers.
-These sub-fields are used by convention only, however, and are optional.
-If this field is to contain spaces, you need to quote the comment itself with double
-quotes
-.Ql \&" .
-Avoid using commas in this field as these are used as sub-field separators, and the
-colon
-.Ql \&:
-character also cannot be used as this is the field separator for the passwd
-file itself.
-.It Fl d Ar dir
-This option sets the account's home directory.
-Normally, you will only use this if the home directory is to be different from the
-default determined from
-.Pa /etc/pw.conf
-- normally
-.Pa /home
-with the account name as a subdirectory.
-.It Fl e Ar date
-Set the account's expiration date.
-Format of the date is either a UNIX time in decimal, or a date in
-.Ql dd-mmm-yy[yy]
-format, where dd is the day, mmm is the month, either in numeric or alphabetic format
-('Jan', 'Feb', etc) and year is either a two or four digit year.
-This option also accepts a relative date in the form
-.Ql \&+n[mhdwoy]
-where
-.Ql \&n
-is a decimal, octal (leading 0) or hexadecimal (leading 0x) digit followed by the
-number of Minutes, Hours, Days, Weeks, Months or Years from the current date at
-which the expiration date is to be set.
-.It Fl p Ar date
-Set the account's password expiration date.
-This field is similar to the account expiration date option, except that it
-applies to forced password changes.
-This is set in the same manner as the
-.Fl e
-option.
-.It Fl g Ar group
-Set the account's primary group to the given group.
-.Ar group
-may be defined by either its name or group number.
-.It Fl G Ar grouplist
-Set additional group memberships for an account.
-.Ar grouplist
-is a comma, space or tab-separated list of group names or group numbers.
-The user's name is added to the group lists in
-.Pa /etc/group ,
-and
-removed from any groups not specified in
-.Ar grouplist .
-Note: a user should not be added to their primary group with
-.Ar grouplist .
-Also, group membership changes do not take effect for current user login
-sessions, requiring the user to reconnect to be affected by the changes.
-.It Fl L Ar class
-This option sets the login class for the user being created.
-See
-.Xr login.conf 5
-and
-.Xr passwd 5
-for more information on user login classes.
-.It Fl m
-This option instructs
-.Nm
-to attempt to create the user's home directory.
-While primarily useful when adding a new account with
-.Ar useradd ,
-this may also be of use when moving an existing user's home directory elsewhere on
-the file system.
-The new home directory is populated with the contents of the
-.Ar skeleton
-directory, which typically contains a set of shell configuration files that the
-user may personalize to taste.
-Files in this directory are usually named
-.Pa dot . Ns Aq Ar config
-where the
-.Pa dot
-prefix will be stripped.
-When
-.Fl m
-is used on an account with
-.Ar usermod ,
-existing configuration files in the user's home directory are
-.Em not
-overwritten from the skeleton files.
-.Pp
-When a user's home directory is created, it will by default be a subdirectory of the
-.Ar basehome
-directory as specified by the
-.Fl b
-option (see below), bearing the name of the new account.
-This can be overridden by the
-.Fl d
-option on the command line, if desired.
-.It Fl M Ar mode
-Create the user's home directory with the specified
-.Ar mode ,
-modified by the current
-.Xr umask 2 .
-If omitted, it is derived from the parent process'
-.Xr umask 2 .
-This option is only useful in combination with the
-.Fl m
-flag.
-.It Fl k Ar dir
-Set the
-.Ar skeleton
-directory, from which basic startup and configuration files are copied when
-the user's home directory is created.
-This option only has meaning when used with the
-.Fl d
-or
-.Fl m
-flags.
-.It Fl s Ar shell
-Set or changes the user's login shell to
-.Ar shell .
-If the path to the shell program is omitted,
-.Nm
-searches the
-.Ar shellpath
-specified in
-.Pa /etc/pw.conf
-and fills it in as appropriate.
-Note that unless you have a specific reason to do so, you should avoid
-specifying the path - this will allow
-.Nm
-to validate that the program exists and is executable.
-Specifying a full path (or supplying a blank "" shell) avoids this check
-and allows for such entries as
-.Pa /nonexistent
-that should be set for accounts not intended for interactive login.
-.It Fl h Ar fd
-This option provides a special interface by which interactive scripts can
-set an account password using
-.Nm .
-Because the command line and environment are fundamentally insecure mechanisms
-by which programs can accept information,
-.Nm
-will only allow setting of account and group passwords via a file descriptor
-(usually a pipe between an interactive script and the program).
-.Ar sh ,
-.Ar bash ,
-.Ar ksh
-and
-.Ar perl
-all possess mechanisms by which this can be done.
-Alternatively,
-.Nm
-will prompt for the user's password if
-.Fl h Ar 0
-is given, nominating
-.Em stdin
-as the file descriptor on which to read the password.
-Note that this password will be read only once and is intended
-for use by a script rather than for interactive use.
-If you wish to have new password confirmation along the lines of
-.Xr passwd 1 ,
-this must be implemented as part of an interactive script that calls
-.Nm .
-.Pp
-If a value of
-.Ql \&-
-is given as the argument
-.Ar fd ,
-then the password will be set to
-.Ql \&* ,
-rendering the account inaccessible via password-based login.
-.It Fl H Ar fd
-Read an encrypted password string from the specified file descriptor.
-This is like
-.Fl h ,
-but the password should be supplied already encrypted in a form
-suitable for writing directly to the password database.
-.El
-.Pp
-It is possible to use
-.Ar useradd
-to create a new account that duplicates an existing user id.
-While this is normally considered an error and will be rejected, the
-.Fl o
-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
-.Fl D
-option.
-Instead of adding a new user,
-.Nm
-writes a new set of defaults to its configuration file,
-.Pa /etc/pw.conf .
-When using the
-.Fl D
-option, you must not use either
-.Fl n Ar name
-or
-.Fl u Ar uid
-or an error will result.
-Use of
-.Fl D
-changes the meaning of several command line switches in the
-.Ar useradd
-command.
-These are:
-.Bl -tag -width "-G grouplist"
-.It Fl D
-Set default values in
-.Pa /etc/pw.conf
-configuration file, or a different named configuration file if the
-.Fl C Ar config
-option is used.
-.It Fl b Ar dir
-Set the root directory in which user home directories are created.
-The default value for this is
-.Pa /home ,
-but it may be set elsewhere as desired.
-.It Fl e Ar days
-Set the default account expiration period in days.
-Unlike use without
-.Fl D ,
-the argument must be numeric, which specifies the number of days after creation when
-the account is to expire.
-A value of 0 suppresses automatic calculation of the expiry date.
-.It Fl p Ar days
-Set the default password expiration period in days.
-.It Fl g Ar group
-Set the default group for new users.
-If a blank group is specified using
-.Fl g Ar \&"" ,
-then new users will be allocated their own private primary group
-with the same name as their login name.
-If a group is supplied, either its name or uid may be given as an argument.
-.It Fl G Ar grouplist
-Set the default groups in which new users are granted membership.
-This is a separate set of groups from the primary group, and you should avoid
-nominating the same group as both primary and extra groups.
-In other words, these extra groups determine membership in groups
-.Em other than
-the primary group.
-.Ar grouplist
-is a comma-separated list of group names or ids, and are always
-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
-Set the default
-.Em skeleton
-directory, from which prototype shell and other initialization files are copied when
-.Nm
-creates a user's home directory.
-See description of
-.Fl k
-for naming conventions of these files.
-.It Xo
-.Fl u Ar min , Ns Ar max ,
-.Fl i Ar min , Ns Ar max
-.Xc
-These options set the minimum and maximum user and group ids allocated for new accounts
-and groups created by
-.Nm .
-The default values for each is 1000 minimum and 32000 maximum.
-.Ar min
-and
-.Ar max
-are both numbers, where max must be greater than min, and both must be between 0
-and 32767.
-In general, user and group ids less than 100 are reserved for use by the system,
-and numbers greater than 32000 may also be reserved for special purposes (used by
-some system daemons).
-.It Fl w Ar method
-The
-.Fl w
-option sets the default method used to set passwords for newly created user accounts.
-.Ar method
-is one of:
-.Pp
-.Bl -tag -width random -offset indent -compact
-.It no
-disable login on newly created accounts
-.It yes
-force the password to be the account name
-.It none
-force a blank password
-.It random
-generate a random password
-.El
-.Pp
-The
-.Ql \&random
-or
-.Ql \&no
-methods are the most secure; in the former case,
-.Nm
-generates a password and prints it to stdout, which is suitable where you issue
-users with passwords to access their accounts rather than having the user nominate
-their own (possibly poorly chosen) password.
-The
-.Ql \&no
-method requires that the superuser use
-.Xr passwd 1
-to render the account accessible with a password.
-.It Fl y Ar path
-This sets the pathname of the database used by
-.Tn NIS
-if you are not sharing
-the information from
-.Pa /etc/master.passwd
-directly with
-.Tn NIS .
-You should only set this option for
-.Tn NIS
-servers.
-.El
-.Pp
-The
-.Ar userdel
-command has only three valid options.
-The
-.Fl n Ar name
-and
-.Fl u Ar uid
-options have already been covered above.
-The additional option is:
-.Bl -tag -width "-G grouplist"
-.It Fl r
-This tells
-.Nm
-to remove the user's home directory and all of its contents.
-The
-.Nm
-utility errs on the side of caution when removing files from the system.
-Firstly, it will not do so if the uid of the account being removed is also used by
-another account on the system, and the 'home' directory in the password file is
-a valid path that commences with the character
-.Ql \&/ .
-Secondly, it will only remove files and directories that are actually owned by
-the user, or symbolic links owned by anyone under the user's home directory.
-Finally, after deleting all contents owned by the user only empty directories
-will be removed.
-If any additional cleanup work is required, this is left to the administrator.
-.El
-.Pp
-Mail spool files and crontabs are always removed when an account is deleted as these
-are unconditionally attached to the user name.
-Jobs queued for processing by
-.Ar at
-are also removed if the user's uid is unique and not also used by another account on the
-system.
-.Pp
-The
-.Ar usershow
-command allows viewing of an account in one of two formats.
-By default, the format is identical to the format used in
-.Pa /etc/master.passwd
-with the password field replaced with a
-.Ql \&* .
-If the
-.Fl P
-option is used, then
-.Nm
-outputs the account details in a more human readable form.
-If the
-.Fl 7
-option is used, the account details are shown in v7 format.
-The
-.Fl a
-option lists all users currently on file.
-Using
-.Fl F
-forces
-.Nm
-to print the details of an account even if it does not exist.
-.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 .
-.Sh GROUP OPTIONS
-The
-.Fl C
-and
-.Fl q
-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 "-m newmembers"
-.It Fl n Ar name
-Specify the group name.
-.It Fl g Ar gid
-Specify the group numeric id.
-.Pp
-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
-.Fl M ,
-this option allows the
-.Em addition
-of existing users to a group without replacing the existing list of
-members.
-Login names or user ids may be used, and duplicate users are
-silently eliminated.
-.It Fl d Ar oldmembers
-Similar to
-.Fl M ,
-this option allows the
-.Em deletion
-of existing users from a group without replacing the existing list of
-members.
-Login names or user ids may be used, and duplicate users are
-silently eliminated.
-.El
-.Pp
-.Ar groupadd
-also has a
-.Fl o
-option that allows allocation of an existing group id to a new group.
-The default action is to reject an attempt to add a group, and this option overrides
-the check for duplicate group ids.
-There is rarely any need to duplicate a group id.
-.Pp
-The
-.Ar groupmod
-command adds one additional option:
-.Pp
-.Bl -tag -width "-m newmembers"
-.It Fl l Ar name
-This option allows changing of an existing group name to
-.Ql \&name .
-The new name must not already exist, and any attempt to duplicate an existing group
-name will be rejected.
-.El
-.Pp
-Options for
-.Ar groupshow
-are the same as for
-.Ar usershow ,
-with the
-.Fl g Ar gid
-replacing
-.Fl u Ar uid
-to specify the group id.
-The
-.Fl 7
-option does not apply to the
-.Ar groupshow
-command.
-.Pp
-The command
-.Ar groupnext
-returns the next available group id on standard output.
-.Sh USER LOCKING
-The
-.Nm
-utility
-supports a simple password locking mechanism for users; it works by
-prepending the string
-.Ql *LOCKED*
-to the beginning of the password field in
-.Pa master.passwd
-to prevent successful authentication.
-.Pp
-The
-.Ar lock
-and
-.Ar unlock
-commands take a user name or uid of the account to lock or unlock,
-respectively.
-The
-.Fl V ,
-.Fl C ,
-and
-.Fl q
-options as described above are accepted by these commands.
-.Sh NOTES
-For a summary of options available with each command, you can use
-.Dl pw [command] help
-For example,
-.Dl pw useradd help
-lists all available options for the useradd operation.
-.Pp
-The
-.Nm
-utility allows 8-bit characters in the passwd GECOS field (user's full name,
-office, work and home phone number subfields), but disallows them in
-user login and group names.
-Use 8-bit characters with caution, as connection to the Internet will
-require that your mail transport program supports 8BITMIME, and will
-convert headers containing 8-bit characters to 7-bit quoted-printable
-format.
-.Xr sendmail 8
-does support this.
-Use of 8-bit characters in the GECOS field should be used in
-conjunction with the user's default locale and character set
-and should not be implemented without their use.
-Using 8-bit characters may also affect other
-programs that transmit the contents of the GECOS field over the
-Internet, such as
-.Xr fingerd 8 ,
-and a small number of TCP/IP clients, such as IRC, where full names
-specified in the passwd file may be used by default.
-.Pp
-The
-.Nm
-utility writes a log to the
-.Pa /var/log/userlog
-file when actions such as user or group additions or deletions occur.
-The location of this logfile can be changed in
-.Xr pw.conf 5 .
-.Sh FILES
-.Bl -tag -width /etc/master.passwd.new -compact
-.It Pa /etc/master.passwd
-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
-Temporary copy of the master password file
-.It Pa /etc/passwd.new
-Temporary copy of the Version 7 password file
-.It Pa /etc/group.new
-Temporary copy of the group file
-.It Pa /etc/pw.conf
-Pw default options file
-.It Pa /var/log/userlog
-User/group modification logfile
-.El
-.Sh EXIT STATUS
-The
-.Nm
-utility returns EXIT_SUCCESS on successful operation, otherwise
-.Nm
-returns 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 file 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-existent 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
-.Sh SEE ALSO
-.Xr chpass 1 ,
-.Xr passwd 1 ,
-.Xr umask 2 ,
-.Xr group 5 ,
-.Xr login.conf 5 ,
-.Xr passwd 5 ,
-.Xr pw.conf 5 ,
-.Xr pwd_mkdb 8 ,
-.Xr vipw 8
-.Sh HISTORY
-The
-.Nm
-utility was written to mimic many of the options used in the SYSV
-.Em shadow
-support suite, but is modified for passwd and group fields specific to
-the
-.Bx 4.4
-operating system, and combines all of the major elements
-into a single command.
diff --git a/pw/pw.c b/pw/pw.c
deleted file mode 100644
index e9d9363..0000000
--- a/pw/pw.c
+++ /dev/null
@@ -1,456 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <err.h>
-#include <fcntl.h>
-#include <locale.h>
-#include <paths.h>
-#include <sys/wait.h>
-#include "pw.h"
-
-#if !defined(_PATH_YP)
-#define _PATH_YP "/var/yp/"
-#endif
-const char *Modes[] = {
- "add", "del", "mod", "show", "next",
- NULL};
-const char *Which[] = {"user", "group", NULL};
-static const char *Combo1[] = {
- "useradd", "userdel", "usermod", "usershow", "usernext",
- "lock", "unlock",
- "groupadd", "groupdel", "groupmod", "groupshow", "groupnext",
- NULL};
-static const char *Combo2[] = {
- "adduser", "deluser", "moduser", "showuser", "nextuser",
- "lock", "unlock",
- "addgroup", "delgroup", "modgroup", "showgroup", "nextgroup",
- NULL};
-
-struct pwf PWF =
-{
- 0,
- setpwent,
- endpwent,
- getpwent,
- getpwuid,
- getpwnam,
- pwdb,
- setgrent,
- endgrent,
- getgrent,
- getgrgid,
- getgrnam,
- grdb
-
-};
-struct pwf VPWF =
-{
- 1,
- vsetpwent,
- vendpwent,
- vgetpwent,
- vgetpwuid,
- vgetpwnam,
- vpwdb,
- vsetgrent,
- vendgrent,
- vgetgrent,
- vgetgrgid,
- vgetgrnam,
- vgrdb
-};
-
-static struct cargs arglist;
-
-static int getindex(const char *words[], const char *word);
-static void cmdhelp(int mode, int which);
-
-
-int
-main(int argc, char *argv[])
-{
- int ch;
- int mode = -1;
- int which = -1;
- char *config = NULL;
- struct userconf *cnf;
-
- static const char *opts[W_NUM][M_NUM] =
- {
- { /* user */
- "V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y",
- "V:C:qn:u:rY",
- "V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY",
- "V:C:qn:u:FPa7",
- "V:C:q",
- "V:C:q",
- "V:C:q"
- },
- { /* grp */
- "V:C:qn:g:h:H:M:opNPY",
- "V:C:qn:g:Y",
- "V:C:qn:d:g:l:h:H:FM:m:NPY",
- "V:C:qn:g:FPa",
- "V:C:q"
- }
- };
-
- static int (*funcs[W_NUM]) (struct userconf * _cnf, int _mode, struct cargs * _args) =
- { /* Request handlers */
- pw_user,
- pw_group
- };
-
- LIST_INIT(&arglist);
-
- (void)setlocale(LC_ALL, "");
-
- /*
- * Break off the first couple of words to determine what exactly
- * we're being asked to do
- */
- while (argc > 1) {
- int tmp;
-
- if (*argv[1] == '-') {
- /*
- * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
- */
- if (argv[1][1] == 'V') {
- optarg = &argv[1][2];
- if (*optarg == '\0') {
- optarg = argv[2];
- ++argv;
- --argc;
- }
- addarg(&arglist, 'V', optarg);
- } else
- break;
- }
- else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
- mode = tmp;
- else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1)
- which = tmp;
- else if ((mode == -1 && which == -1) &&
- ((tmp = getindex(Combo1, argv[1])) != -1 ||
- (tmp = getindex(Combo2, argv[1])) != -1)) {
- which = tmp / M_NUM;
- mode = tmp % M_NUM;
- } else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
- cmdhelp(mode, which);
- else if (which != -1 && mode != -1)
- addarg(&arglist, 'n', argv[1]);
- else
- errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
- ++argv;
- --argc;
- }
-
- /*
- * Bail out unless the user is specific!
- */
- if (mode == -1 || which == -1)
- cmdhelp(mode, which);
-
- /*
- * 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.
- */
- optarg = NULL;
-
- while ((ch = getopt(argc, argv, opts[which][mode])) != -1) {
- if (ch == '?')
- errx(EX_USAGE, "unknown switch");
- else
- addarg(&arglist, ch, optarg);
- optarg = NULL;
- }
-
- /*
- * Must be root to attempt an update
- */
- if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL)
- errx(EX_NOPERM, "you must be root to run this program");
-
- /*
- * We should immediately look for the -q 'quiet' switch so that we
- * don't bother with extraneous errors
- */
- if (getarg(&arglist, 'q') != NULL)
- freopen(_PATH_DEVNULL, "w", stderr);
-
- /*
- * Set our base working path if not overridden
- */
-
- config = getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL;
-
- if (getarg(&arglist, 'V') != NULL) {
- char * etcpath = getarg(&arglist, 'V')->val;
- if (*etcpath) {
- if (config == NULL) { /* Only override config location if -C not specified */
- config = malloc(MAXPATHLEN);
- snprintf(config, MAXPATHLEN, "%s/pw.conf", etcpath);
- }
- memcpy(&PWF, &VPWF, sizeof PWF);
- setpwdir(etcpath);
- setgrdir(etcpath);
- }
- }
-
- /*
- * Now, let's do the common initialisation
- */
- cnf = read_userconfig(config);
-
- ch = funcs[which] (cnf, mode, &arglist);
-
- /*
- * If everything went ok, and we've been asked to update
- * the NIS maps, then do it now
- */
- if (ch == EXIT_SUCCESS && getarg(&arglist, 'Y') != NULL) {
- pid_t pid;
-
- fflush(NULL);
- if (chdir(_PATH_YP) == -1)
- warn("chdir(" _PATH_YP ")");
- else if ((pid = fork()) == -1)
- warn("fork()");
- else if (pid == 0) {
- /* Is make anywhere else? */
- execlp("/usr/bin/make", "make", (char *)NULL);
- _exit(1);
- } else {
- int i;
- waitpid(pid, &i, 0);
- if ((i = WEXITSTATUS(i)) != 0)
- errx(ch, "make exited with status %d", i);
- else
- pw_log(cnf, mode, which, "NIS maps updated");
- }
- }
- return ch;
-}
-
-
-static int
-getindex(const char *words[], const char *word)
-{
- int i = 0;
-
- while (words[i]) {
- if (strcmp(words[i], word) == 0)
- return i;
- i++;
- }
- return -1;
-}
-
-
-/*
- * This is probably an overkill for a cmdline help system, but it reflects
- * the complexity of the command line.
- */
-
-static void
-cmdhelp(int mode, int which)
-{
- if (which == -1)
- fprintf(stderr, "usage:\n pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n");
- else if (mode == -1)
- fprintf(stderr, "usage:\n pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]);
- else {
-
- /*
- * We need to give mode specific help
- */
- static const char *help[W_NUM][M_NUM] =
- {
- {
- "usage: pw useradd [name] [switches]\n"
- "\t-V etcdir alternate /etc location\n"
- "\t-C config configuration file\n"
- "\t-q quiet operation\n"
- " Adding users:\n"
- "\t-n name login name\n"
- "\t-u uid user id\n"
- "\t-c comment user name/comment\n"
- "\t-d directory home directory\n"
- "\t-e date account expiry date\n"
- "\t-p date password expiry date\n"
- "\t-g grp initial group\n"
- "\t-G grp1,grp2 additional groups\n"
- "\t-m [ -k dir ] create and set up home\n"
- "\t-M mode home directory permissions\n"
- "\t-s shell name of login shell\n"
- "\t-o duplicate uid ok\n"
- "\t-L class user class\n"
- "\t-h fd read password on fd\n"
- "\t-H fd read encrypted password on fd\n"
- "\t-Y update NIS maps\n"
- "\t-N no update\n"
- " Setting defaults:\n"
- "\t-V etcdir alternate /etc location\n"
- "\t-D set user defaults\n"
- "\t-b dir default home root dir\n"
- "\t-e period default expiry period\n"
- "\t-p period default password change period\n"
- "\t-g group default group\n"
- "\t-G grp1,grp2 additional groups\n"
- "\t-L class default user class\n"
- "\t-k dir default home skeleton\n"
- "\t-M mode home directory permissions\n"
- "\t-u min,max set min,max uids\n"
- "\t-i min,max set min,max gids\n"
- "\t-w method set default password method\n"
- "\t-s shell default shell\n"
- "\t-y path set NIS passwd file path\n",
- "usage: pw userdel [uid|name] [switches]\n"
- "\t-V etcdir alternate /etc location\n"
- "\t-n name login name\n"
- "\t-u uid user id\n"
- "\t-Y update NIS maps\n"
- "\t-r remove home & contents\n",
- "usage: pw usermod [uid|name] [switches]\n"
- "\t-V etcdir alternate /etc location\n"
- "\t-C config configuration file\n"
- "\t-q quiet operation\n"
- "\t-F force add if no user\n"
- "\t-n name login name\n"
- "\t-u uid user id\n"
- "\t-c comment user name/comment\n"
- "\t-d directory home directory\n"
- "\t-e date account expiry date\n"
- "\t-p date password expiry date\n"
- "\t-g grp initial group\n"
- "\t-G grp1,grp2 additional groups\n"
- "\t-l name new login name\n"
- "\t-L class user class\n"
- "\t-m [ -k dir ] create and set up home\n"
- "\t-M mode home directory permissions\n"
- "\t-s shell name of login shell\n"
- "\t-w method set new password using method\n"
- "\t-h fd read password on fd\n"
- "\t-H fd read encrypted password on fd\n"
- "\t-Y update NIS maps\n"
- "\t-N no update\n",
- "usage: pw usershow [uid|name] [switches]\n"
- "\t-V etcdir alternate /etc location\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-7 print in v7 format\n",
- "usage: pw usernext [switches]\n"
- "\t-V etcdir alternate /etc location\n"
- "\t-C config configuration file\n"
- "\t-q quiet operation\n",
- "usage pw: lock [switches]\n"
- "\t-V etcdir alternate /etc locations\n"
- "\t-C config configuration file\n"
- "\t-q quiet operation\n",
- "usage pw: unlock [switches]\n"
- "\t-V etcdir alternate /etc locations\n"
- "\t-C config configuration file\n"
- "\t-q quiet operation\n"
- },
- {
- "usage: pw groupadd [group|gid] [switches]\n"
- "\t-V etcdir alternate /etc location\n"
- "\t-C config configuration file\n"
- "\t-q quiet operation\n"
- "\t-n group group name\n"
- "\t-g gid group id\n"
- "\t-M usr1,usr2 add users as group members\n"
- "\t-o duplicate gid ok\n"
- "\t-Y update NIS maps\n"
- "\t-N no update\n",
- "usage: pw groupdel [group|gid] [switches]\n"
- "\t-V etcdir alternate /etc location\n"
- "\t-n name group name\n"
- "\t-g gid group id\n"
- "\t-Y update NIS maps\n",
- "usage: pw groupmod [group|gid] [switches]\n"
- "\t-V etcdir alternate /etc location\n"
- "\t-C config configuration file\n"
- "\t-q quiet operation\n"
- "\t-F force add if not exists\n"
- "\t-n name group name\n"
- "\t-g gid group id\n"
- "\t-M usr1,usr2 replaces users as group members\n"
- "\t-m usr1,usr2 add users as group members\n"
- "\t-d usr1,usr2 delete users as group members\n"
- "\t-l name new group name\n"
- "\t-Y update NIS maps\n"
- "\t-N no update\n",
- "usage: pw groupshow [group|gid] [switches]\n"
- "\t-V etcdir alternate /etc location\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",
- "usage: pw groupnext [switches]\n"
- "\t-V etcdir alternate /etc location\n"
- "\t-C config configuration file\n"
- "\t-q quiet operation\n"
- }
- };
-
- fprintf(stderr, "%s", help[which][mode]);
- }
- exit(EXIT_FAILURE);
-}
-
-struct carg *
-getarg(struct cargs * _args, int ch)
-{
- struct carg *c = LIST_FIRST(_args);
-
- while (c != NULL && c->ch != ch)
- c = LIST_NEXT(c, list);
- return c;
-}
-
-struct carg *
-addarg(struct cargs * _args, int ch, char *argstr)
-{
- struct carg *ca = malloc(sizeof(struct carg));
-
- if (ca == NULL)
- errx(EX_OSERR, "out of memory");
- ca->ch = ch;
- ca->val = argstr;
- LIST_INSERT_HEAD(_args, ca, list);
- return ca;
-}
diff --git a/pw/pw.conf.5 b/pw/pw.conf.5
deleted file mode 100644
index 3f023aa..0000000
--- a/pw/pw.conf.5
+++ /dev/null
@@ -1,318 +0,0 @@
-.\" Copyright (C) 1996
-.\" David L. Nugent. All rights reserved.
-.\"
-.\" 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.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd March 30, 2007
-.Dt PW.CONF 5
-.Os
-.Sh NAME
-.Nm pw.conf
-.Nd format of the pw.conf configuration file
-.Sh DESCRIPTION
-The file
-.In /etc/pw.conf
-contains configuration data for the
-.Xr pw 8
-utility.
-The
-.Xr pw 8
-utility is used for maintenance of the system password and group
-files, allowing users and groups to be added, deleted and changed.
-This file may be modified via the
-.Xr pw 8
-command using the
-.Ar useradd
-command and the
-.Fl D
-option, or by editing it directly with a text editor.
-.Pp
-Each line in
-.Pa /etc/pw.conf
-is treated either a comment or as configuration data;
-blank lines and lines commencing with a
-.Ql \&#
-character are considered comments, and any remaining lines are
-examined for a leading keyword, followed by corresponding data.
-.Pp
-Keywords recognized by
-.Xr pw 8
-are:
-.Bl -tag -width password_days -offset indent -compact
-.It defaultpasswd
-affect passwords generated for new users
-.It reuseuids
-reuse gaps in uid sequences
-.It reusegids
-reuse gaps in gid sequences
-.It nispasswd
-path to the
-.Tn NIS
-passwd database
-.It skeleton
-where to obtain default home contents
-.It newmail
-mail to send to new users
-.It logfile
-log user/group modifications to this file
-.It home
-root directory for home directories
-.It homemode
-permissions for home directory
-.It shellpath
-paths in which to locate shell programs
-.It shells
-list of valid shells (without path)
-.It defaultshell
-default shell (without path)
-.It defaultgroup
-default group
-.It extragroups
-add new users to this groups
-.It defaultclass
-place new users in this login class
-.It minuid
-.It maxuid
-range of valid default user ids
-.It mingid
-.It maxgid
-range of valid default group ids
-.It expire_days
-days after which account expires
-.It password_days
-days after which password expires
-.El
-.Pp
-Valid values for
-.Ar defaultpasswd
-are:
-.Bl -tag -width password_days -offset indent -compact
-.It no
-disable login on newly created accounts
-.It yes
-force the password to be the account name
-.It none
-force a blank password
-.It random
-generate a random password
-.El
-.Pp
-The second and third options are insecure and should be avoided if
-possible on a publicly accessible system.
-The first option requires that the superuser run
-.Xr passwd 1
-to set a password before the account may be used.
-This may also be useful for creating administrative accounts.
-The final option causes
-.Xr pw 8
-to respond by printing a randomly generated password on stdout.
-This is the preferred and most secure option.
-The
-.Xr pw 8
-utility also provides a method of setting a specific password for the new
-user via a filehandle (command lines are not secure).
-.Pp
-Both
-.Ar reuseuids
-and
-.Ar reusegids
-determine the method by which new user and group id numbers are
-generated.
-A
-.Ql \&yes
-in this field will cause
-.Xr pw 8
-to search for the first unused user or group id within the allowed
-range, whereas a
-.Ql \&no
-will ensure that no other existing user or group id within the range
-is numerically lower than the new one generated, and therefore avoids
-reusing gaps in the user or group id sequence that are caused by
-previous user or group deletions.
-Note that if the default group is not specified using the
-.Ar defaultgroup
-keyword,
-.Xr pw 8
-will create a new group for the user and attempt to keep the new
-user's uid and gid the same.
-If the new user's uid is currently in use as a group id, then the next
-available group id is chosen instead.
-.Pp
-On
-.Tn NIS
-servers which maintain a separate passwd database to
-.Pa /etc/master.passwd ,
-this option allows the additional file to be concurrently updated
-as user records are added, modified or removed.
-If blank or set to 'no', no additional database is updated.
-An absolute pathname must be used.
-.Pp
-The
-.Ar skeleton
-keyword nominates a directory from which the contents of a user's
-new home directory is constructed.
-This is
-.Pa /usr/share/skel
-by default.
-The
-.Xr pw 8 Ns 's
-.Fl m
-option causes the user's home directory to be created and populated
-using the files contained in the
-.Ar skeleton
-directory.
-.Pp
-To send an initial email to new users, the
-.Ar newmail
-keyword may be used to specify a path name to a file containing
-the message body of the message to be sent.
-To avoid sending mail when accounts are created, leave this entry
-blank or specify
-.Ql \&no .
-.Pp
-The
-.Ar logfile
-option allows logging of password file modifications into the
-nominated log file.
-To avoid creating or adding to such a logfile, then leave this
-field blank or specify
-.Ql \&no .
-.Pp
-The
-.Ar home
-keyword is mandatory.
-This specifies the location of the directory in which all new user
-home directories are created.
-.Pp
-The
-.Ar homemode
-keyword is optional.
-It specifies the creation mask of the user's home directory and is modified by
-.Xr umask 2 .
-.Pp
-The
-.Ar shellpath
-keyword specifies a list of directories - separated by colons
-.Ql \&:
-- which contain the programs used by the login shells.
-.Pp
-The
-.Ar shells
-keyword specifies a list of programs available for use as login
-shells.
-This list is a comma-separated list of shell names which should
-not contain a path.
-These shells must exist in one of the directories nominated by
-.Ar shellpath .
-.Pp
-The
-.Ar defaultshell
-keyword nominates which shell program to use for new users when
-none is specified on the
-.Xr pw 8
-command line.
-.Pp
-The
-.Ar defaultgroup
-keyword defines the primary group (the group id number in the
-password file) used for new accounts.
-If left blank, or the word
-.Ql \&no
-is used, then each new user will have a corresponding group of
-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
-normally used by the user.
-.Pp
-The
-.Ar extragroups
-keyword provides an automatic means of placing new users into groups within
-the
-.Pa /etc/groups
-file.
-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
-.Fl G
-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 ,
-.Ar maxgid
-keywords determine the allowed ranges of automatically allocated user
-and group id numbers.
-The default values for both user and group ids are 1000 and 32000 as
-minimum and maximum respectively.
-The user and group id's actually used when creating an account with
-.Xr pw 8
-may be overridden using the
-.Fl u
-and
-.Fl g
-command line options.
-.Pp
-The
-.Ar expire_days
-and
-.Ar password_days
-are used to automatically calculate the number of days from the date
-on which an account is created when the account will expire or the
-user will be forced to change the account's password.
-A value of
-.Ql \&0
-in either field will disable the corresponding (account or password)
-expiration date.
-.Sh LIMITS
-The maximum line length of
-.Pa /etc/pw.conf
-is 1024 characters.
-Longer lines will be skipped and treated
-as comments.
-.Sh FILES
-.Bl -tag -width /etc/master.passwd -compact
-.It Pa /etc/pw.conf
-.It Pa /etc/passwd
-.It Pa /etc/master.passwd
-.It Pa /etc/group
-.El
-.Sh SEE ALSO
-.Xr passwd 1 ,
-.Xr umask 2 ,
-.Xr group 5 ,
-.Xr login.conf 5 ,
-.Xr passwd 5 ,
-.Xr pw 8
diff --git a/pw/pw.h b/pw/pw.h
deleted file mode 100644
index 7568c22..0000000
--- a/pw/pw.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- *
- * $FreeBSD$
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/queue.h>
-#include <sysexits.h>
-
-#include "psdate.h"
-#include "pwupd.h"
-
-enum _mode
-{
- M_ADD,
- M_DELETE,
- M_UPDATE,
- M_PRINT,
- M_NEXT,
- M_LOCK,
- M_UNLOCK,
- M_NUM
-};
-
-enum _which
-{
- W_USER,
- W_GROUP,
- W_NUM
-};
-
-struct carg
-{
- int ch;
- char *val;
- LIST_ENTRY(carg) list;
-};
-
-LIST_HEAD(cargs, carg);
-
-struct userconf
-{
- int default_password; /* Default password for new users? */
- int reuse_uids; /* Reuse uids? */
- int reuse_gids; /* Reuse gids? */
- char *nispasswd; /* Path to NIS version of the passwd file */
- char *dotdir; /* Where to obtain skeleton files */
- char *newmail; /* Mail to send to new accounts */
- char *logfile; /* Where to log changes */
- char *home; /* Where to create home directory */
- mode_t homemode; /* Home directory permissions */
- char *shelldir; /* Where shells are located */
- char **shells; /* List of shells */
- char *shell_default; /* Default shell */
- char *default_group; /* Default group number */
- char **groups; /* Default (additional) groups */
- char *default_class; /* Default user class */
- uid_t min_uid, max_uid; /* Allowed range of uids */
- gid_t min_gid, max_gid; /* Allowed range of gids */
- int expire_days; /* Days to expiry */
- int password_days; /* Days to password expiry */
- int numgroups; /* (internal) size of default_group array */
-};
-
-#define _PATH_PW_CONF "/etc/pw.conf"
-#define _UC_MAXLINE 1024
-#define _UC_MAXSHELLS 32
-
-struct userconf *read_userconfig(char const * file);
-int write_userconfig(char const * file);
-struct carg *addarg(struct cargs * _args, int ch, char *argstr);
-struct carg *getarg(struct cargs * _args, int ch);
-
-int pw_user(struct userconf * cnf, int mode, struct cargs * _args);
-int pw_group(struct userconf * cnf, int mode, struct cargs * _args);
-char *pw_checkname(u_char *name, int gecos);
-
-int addpwent(struct passwd * pwd);
-int delpwent(struct passwd * pwd);
-int chgpwent(char const * login, struct passwd * pwd);
-int fmtpwent(char *buf, struct passwd * pwd);
-
-int addnispwent(const char *path, struct passwd *pwd);
-int delnispwent(const char *path, const char *login);
-int chgnispwent(const char *path, const char *login, struct passwd *pwd);
-
-int addgrent(struct group * grp);
-int delgrent(struct group * grp);
-int chggrent(char const * login, struct group * grp);
-
-int boolean_val(char const * str, int dflt);
-char const *boolean_str(int val);
-char *newstr(char const * p);
-
-void pw_log(struct userconf * cnf, int mode, int which, char const * fmt,...) __printflike(4, 5);
-char *pw_pwcrypt(char *password);
-
-extern const char *Modes[];
-extern const char *Which[];
diff --git a/pw/pw_conf.c b/pw/pw_conf.c
deleted file mode 100644
index 51672b9..0000000
--- a/pw/pw_conf.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-
-#include "pw.h"
-
-#define debugging 0
-
-enum {
- _UC_NONE,
- _UC_DEFAULTPWD,
- _UC_REUSEUID,
- _UC_REUSEGID,
- _UC_NISPASSWD,
- _UC_DOTDIR,
- _UC_NEWMAIL,
- _UC_LOGFILE,
- _UC_HOMEROOT,
- _UC_HOMEMODE,
- _UC_SHELLPATH,
- _UC_SHELLS,
- _UC_DEFAULTSHELL,
- _UC_DEFAULTGROUP,
- _UC_EXTRAGROUPS,
- _UC_DEFAULTCLASS,
- _UC_MINUID,
- _UC_MAXUID,
- _UC_MINGID,
- _UC_MAXGID,
- _UC_EXPIRE,
- _UC_PASSWORD,
- _UC_FIELDS
-};
-
-static char bourne_shell[] = "sh";
-
-static char *system_shells[_UC_MAXSHELLS] =
-{
- bourne_shell,
- "csh",
- "tcsh"
-};
-
-static char const *booltrue[] =
-{
- "yes", "true", "1", "on", NULL
-};
-static char const *boolfalse[] =
-{
- "no", "false", "0", "off", NULL
-};
-
-static struct userconf config =
-{
- 0, /* Default password for new users? (nologin) */
- 0, /* Reuse uids? */
- 0, /* Reuse gids? */
- NULL, /* NIS version of the passwd file */
- "/usr/share/skel", /* Where to obtain skeleton files */
- NULL, /* Mail to send to new accounts */
- "/var/log/userlog", /* Where to log changes */
- "/home", /* Where to create home directory */
- 0777, /* Home directory perms, modified by umask */
- "/bin", /* Where shells are located */
- system_shells, /* List of shells (first is default) */
- bourne_shell, /* Default shell */
- NULL, /* Default group name */
- NULL, /* Default (additional) groups */
- NULL, /* Default login class */
- 1000, 32000, /* Allowed range of uids */
- 1000, 32000, /* Allowed range of gids */
- 0, /* Days until account expires */
- 0, /* Days until password expires */
- 0 /* size of default_group array */
-};
-
-static char const *comments[_UC_FIELDS] =
-{
- "#\n# pw.conf - user/group configuration defaults\n#\n",
- "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
- "\n# Reuse gaps in uid sequence? (yes or no)\n",
- "\n# Reuse gaps in gid sequence? (yes or no)\n",
- "\n# Path to the NIS passwd file (blank or 'no' for none)\n",
- "\n# Obtain default dotfiles from this directory\n",
- "\n# Mail this file to new user (/etc/newuser.msg or no)\n",
- "\n# Log add/change/remove information in this file\n",
- "\n# Root directory in which $HOME directory is created\n",
- "\n# Mode for the new $HOME directory, will be modified by umask\n",
- "\n# Colon separated list of directories containing valid shells\n",
- "\n# Comma separated list of available shells (without paths)\n",
- "\n# Default shell (without path)\n",
- "\n# Default group (leave blank for new group per user)\n",
- "\n# Extra groups for new users\n",
- "\n# Default login class for new users\n",
- "\n# Range of valid default user ids\n",
- NULL,
- "\n# Range of valid default group ids\n",
- NULL,
- "\n# Days after which account expires (0=disabled)\n",
- "\n# Days after which password expires (0=disabled)\n"
-};
-
-static char const *kwds[] =
-{
- "",
- "defaultpasswd",
- "reuseuids",
- "reusegids",
- "nispasswd",
- "skeleton",
- "newmail",
- "logfile",
- "home",
- "homemode",
- "shellpath",
- "shells",
- "defaultshell",
- "defaultgroup",
- "extragroups",
- "defaultclass",
- "minuid",
- "maxuid",
- "mingid",
- "maxgid",
- "expire_days",
- "password_days",
- NULL
-};
-
-static char *
-unquote(char const * str)
-{
- if (str && (*str == '"' || *str == '\'')) {
- char *p = strchr(str + 1, *str);
-
- if (p != NULL)
- *p = '\0';
- return (char *) (*++str ? str : NULL);
- }
- return (char *) str;
-}
-
-int
-boolean_val(char const * str, int dflt)
-{
- if ((str = unquote(str)) != NULL) {
- int i;
-
- for (i = 0; booltrue[i]; i++)
- if (strcmp(str, booltrue[i]) == 0)
- return 1;
- for (i = 0; boolfalse[i]; i++)
- if (strcmp(str, boolfalse[i]) == 0)
- return 0;
-
- /*
- * Special cases for defaultpassword
- */
- if (strcmp(str, "random") == 0)
- return -1;
- if (strcmp(str, "none") == 0)
- return -2;
- }
- return dflt;
-}
-
-char const *
-boolean_str(int val)
-{
- if (val == -1)
- return "random";
- else if (val == -2)
- return "none";
- else
- return val ? booltrue[0] : boolfalse[0];
-}
-
-char *
-newstr(char const * p)
-{
- char *q = NULL;
-
- if ((p = unquote(p)) != NULL) {
- int l = strlen(p) + 1;
-
- if ((q = malloc(l)) != NULL)
- memcpy(q, p, l);
- }
- return q;
-}
-
-#define LNBUFSZ 1024
-
-
-struct userconf *
-read_userconfig(char const * file)
-{
- FILE *fp;
-
- extendarray(&config.groups, &config.numgroups, 200);
- memset(config.groups, 0, config.numgroups * sizeof(char *));
- if (file == NULL)
- file = _PATH_PW_CONF;
- if ((fp = fopen(file, "r")) != NULL) {
- int buflen = LNBUFSZ;
- char *buf = malloc(buflen);
-
- nextline:
- while (fgets(buf, buflen, fp) != NULL) {
- char *p;
-
- while ((p = strchr(buf, '\n')) == NULL) {
- int l;
- if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) {
- int ch;
- while ((ch = fgetc(fp)) != '\n' && ch != EOF);
- goto nextline; /* Ignore it */
- }
- l = strlen(buf);
- if (fgets(buf + l, buflen - l, fp) == NULL)
- break; /* Unterminated last line */
- }
-
- if (p != NULL)
- *p = '\0';
-
- if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
- static char const toks[] = " \t\r\n,=";
- char *q = strtok(NULL, toks);
- int i = 0;
- mode_t *modeset;
-
- while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
- ++i;
-#if debugging
- if (i == _UC_FIELDS)
- printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
- else
- printf("Got kwd[%s]=%s\n", p, q);
-#endif
- switch (i) {
- case _UC_DEFAULTPWD:
- config.default_password = boolean_val(q, 1);
- break;
- case _UC_REUSEUID:
- config.reuse_uids = boolean_val(q, 0);
- break;
- case _UC_REUSEGID:
- config.reuse_gids = boolean_val(q, 0);
- break;
- case _UC_NISPASSWD:
- config.nispasswd = (q == NULL || !boolean_val(q, 1))
- ? NULL : newstr(q);
- break;
- case _UC_DOTDIR:
- config.dotdir = (q == NULL || !boolean_val(q, 1))
- ? NULL : newstr(q);
- break;
- case _UC_NEWMAIL:
- config.newmail = (q == NULL || !boolean_val(q, 1))
- ? NULL : newstr(q);
- break;
- case _UC_LOGFILE:
- config.logfile = (q == NULL || !boolean_val(q, 1))
- ? NULL : newstr(q);
- break;
- case _UC_HOMEROOT:
- config.home = (q == NULL || !boolean_val(q, 1))
- ? "/home" : newstr(q);
- break;
- case _UC_HOMEMODE:
- modeset = setmode(q);
- config.homemode = (q == NULL || !boolean_val(q, 1))
- ? 0777 : getmode(modeset, 0777);
- free(modeset);
- break;
- case _UC_SHELLPATH:
- config.shelldir = (q == NULL || !boolean_val(q, 1))
- ? "/bin" : newstr(q);
- break;
- case _UC_SHELLS:
- for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
- system_shells[i] = newstr(q);
- if (i > 0)
- while (i < _UC_MAXSHELLS)
- system_shells[i++] = NULL;
- break;
- case _UC_DEFAULTSHELL:
- config.shell_default = (q == NULL || !boolean_val(q, 1))
- ? (char *) bourne_shell : newstr(q);
- break;
- case _UC_DEFAULTGROUP:
- q = unquote(q);
- config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
- ? NULL : newstr(q);
- break;
- case _UC_EXTRAGROUPS:
- for (i = 0; q != NULL; q = strtok(NULL, toks)) {
- if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
- config.groups[i++] = newstr(q);
- }
- if (i > 0)
- while (i < config.numgroups)
- config.groups[i++] = NULL;
- break;
- case _UC_DEFAULTCLASS:
- config.default_class = (q == NULL || !boolean_val(q, 1))
- ? NULL : newstr(q);
- break;
- case _UC_MINUID:
- if ((q = unquote(q)) != NULL && isdigit(*q))
- config.min_uid = (uid_t) atol(q);
- break;
- case _UC_MAXUID:
- if ((q = unquote(q)) != NULL && isdigit(*q))
- config.max_uid = (uid_t) atol(q);
- break;
- case _UC_MINGID:
- if ((q = unquote(q)) != NULL && isdigit(*q))
- config.min_gid = (gid_t) atol(q);
- break;
- case _UC_MAXGID:
- if ((q = unquote(q)) != NULL && isdigit(*q))
- config.max_gid = (gid_t) atol(q);
- break;
- case _UC_EXPIRE:
- if ((q = unquote(q)) != NULL && isdigit(*q))
- config.expire_days = atoi(q);
- break;
- case _UC_PASSWORD:
- if ((q = unquote(q)) != NULL && isdigit(*q))
- config.password_days = atoi(q);
- break;
- case _UC_FIELDS:
- case _UC_NONE:
- break;
- }
- }
- }
- free(buf);
- fclose(fp);
- }
- return &config;
-}
-
-
-int
-write_userconfig(char const * file)
-{
- int fd;
-
- if (file == NULL)
- file = _PATH_PW_CONF;
-
- if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) {
- FILE *fp;
-
- if ((fp = fdopen(fd, "w")) == NULL)
- close(fd);
- else {
- int i, j, k;
- int len = LNBUFSZ;
- char *buf = malloc(len);
-
- for (i = _UC_NONE; i < _UC_FIELDS; i++) {
- int quote = 1;
- char const *val = buf;
-
- *buf = '\0';
- switch (i) {
- case _UC_DEFAULTPWD:
- val = boolean_str(config.default_password);
- break;
- case _UC_REUSEUID:
- val = boolean_str(config.reuse_uids);
- break;
- case _UC_REUSEGID:
- val = boolean_str(config.reuse_gids);
- break;
- case _UC_NISPASSWD:
- val = config.nispasswd ? config.nispasswd : "";
- quote = 0;
- break;
- case _UC_DOTDIR:
- val = config.dotdir ? config.dotdir : boolean_str(0);
- break;
- case _UC_NEWMAIL:
- val = config.newmail ? config.newmail : boolean_str(0);
- break;
- case _UC_LOGFILE:
- val = config.logfile ? config.logfile : boolean_str(0);
- break;
- case _UC_HOMEROOT:
- val = config.home;
- break;
- case _UC_HOMEMODE:
- sprintf(buf, "%04o", config.homemode);
- quote = 0;
- break;
- case _UC_SHELLPATH:
- val = config.shelldir;
- break;
- case _UC_SHELLS:
- for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) {
- char lbuf[64];
- int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]);
- if (l < 0)
- l = 0;
- if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) {
- strcpy(buf + k, lbuf);
- k += l;
- }
- }
- quote = 0;
- break;
- case _UC_DEFAULTSHELL:
- val = config.shell_default ? config.shell_default : bourne_shell;
- break;
- case _UC_DEFAULTGROUP:
- val = config.default_group ? config.default_group : "";
- break;
- case _UC_EXTRAGROUPS:
- extendarray(&config.groups, &config.numgroups, 200);
- for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) {
- char lbuf[64];
- int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]);
- if (l < 0)
- l = 0;
- if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) {
- strcpy(buf + k, lbuf);
- k += l;
- }
- }
- quote = 0;
- break;
- case _UC_DEFAULTCLASS:
- val = config.default_class ? config.default_class : "";
- break;
- case _UC_MINUID:
- sprintf(buf, "%lu", (unsigned long) config.min_uid);
- quote = 0;
- break;
- case _UC_MAXUID:
- sprintf(buf, "%lu", (unsigned long) config.max_uid);
- quote = 0;
- break;
- case _UC_MINGID:
- sprintf(buf, "%lu", (unsigned long) config.min_gid);
- quote = 0;
- break;
- case _UC_MAXGID:
- sprintf(buf, "%lu", (unsigned long) config.max_gid);
- quote = 0;
- break;
- case _UC_EXPIRE:
- sprintf(buf, "%d", config.expire_days);
- quote = 0;
- break;
- case _UC_PASSWORD:
- sprintf(buf, "%d", config.password_days);
- quote = 0;
- break;
- case _UC_NONE:
- break;
- }
-
- if (comments[i])
- fputs(comments[i], fp);
-
- if (*kwds[i]) {
- if (quote)
- fprintf(fp, "%s = \"%s\"\n", kwds[i], val);
- else
- fprintf(fp, "%s = %s\n", kwds[i], val);
-#if debugging
- printf("WROTE: %s = %s\n", kwds[i], val);
-#endif
- }
- }
- free(buf);
- return fclose(fp) != EOF;
- }
- }
- return 0;
-}
diff --git a/pw/pw_group.c b/pw/pw_group.c
deleted file mode 100644
index a8f182c..0000000
--- a/pw/pw_group.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <ctype.h>
-#include <err.h>
-#include <termios.h>
-#include <stdbool.h>
-#include <unistd.h>
-
-#include "pw.h"
-#include "bitmap.h"
-
-
-static struct passwd *lookup_pwent(const char *user);
-static void delete_members(char ***members, int *grmembers, int *i,
- struct carg *arg, struct group *grp);
-static int print_group(struct group * grp, int pretty);
-static gid_t gr_gidpolicy(struct userconf * cnf, struct cargs * args);
-
-int
-pw_group(struct userconf * cnf, int mode, struct cargs * args)
-{
- int rc;
- struct carg *a_name = getarg(args, 'n');
- struct carg *a_gid = getarg(args, 'g');
- struct carg *arg;
- struct group *grp = NULL;
- int grmembers = 0;
- char **members = NULL;
-
- static struct group fakegroup =
- {
- "nogroup",
- "*",
- -1,
- NULL
- };
-
- if (mode == M_LOCK || mode == M_UNLOCK)
- errx(EX_USAGE, "'lock' command is not available for groups");
-
- /*
- * With M_NEXT, we only need to return the
- * next gid to stdout
- */
- if (mode == M_NEXT) {
- 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;
-
- SETGRENT();
- while ((grp = GETGRENT()) != NULL)
- print_group(grp, pretty);
- ENDGRENT();
- return EXIT_SUCCESS;
- }
- if (a_gid == NULL) {
- if (a_name == NULL)
- errx(EX_DATAERR, "group name or id required");
-
- if (mode != M_ADD && grp == NULL && isdigit((unsigned char)*a_name->val)) {
- (a_gid = a_name)->ch = 'g';
- a_name = NULL;
- }
- }
- grp = (a_name != NULL) ? GETGRNAM(a_name->val) : GETGRGID((gid_t) atoi(a_gid->val));
-
- if (mode == M_UPDATE || mode == M_DELETE || mode == M_PRINT) {
- if (a_name == NULL && grp == NULL) /* Try harder */
- grp = GETGRGID(atoi(a_gid->val));
-
- if (grp == NULL) {
- if (mode == M_PRINT && getarg(args, 'F')) {
- char *fmems[1];
- fmems[0] = NULL;
- fakegroup.gr_name = a_name ? a_name->val : "nogroup";
- fakegroup.gr_gid = a_gid ? (gid_t) atol(a_gid->val) : -1;
- fakegroup.gr_mem = fmems;
- return print_group(&fakegroup, getarg(args, 'P') != NULL);
- }
- errx(EX_DATAERR, "unknown group `%s'", a_name ? a_name->val : a_gid->val);
- }
- if (a_name == NULL) /* Needed later */
- a_name = addarg(args, 'n', grp->gr_name);
-
- /*
- * Handle deletions now
- */
- if (mode == M_DELETE) {
- gid_t gid = grp->gr_gid;
-
- rc = delgrent(grp);
- if (rc == -1)
- err(EX_IOERR, "group '%s' not available (NIS?)", grp->gr_name);
- else if (rc != 0) {
- warn("group update");
- return EX_IOERR;
- }
- pw_log(cnf, mode, W_GROUP, "%s(%ld) removed", a_name->val, (long) gid);
- return EXIT_SUCCESS;
- } else if (mode == M_PRINT)
- return print_group(grp, getarg(args, 'P') != NULL);
-
- if (a_gid)
- grp->gr_gid = (gid_t) atoi(a_gid->val);
-
- if ((arg = getarg(args, 'l')) != NULL)
- grp->gr_name = pw_checkname((u_char *)arg->val, 0);
- } else {
- if (a_name == NULL) /* Required */
- errx(EX_DATAERR, "group name required");
- else if (grp != NULL) /* Exists */
- errx(EX_DATAERR, "group name `%s' already exists", a_name->val);
-
- extendarray(&members, &grmembers, 200);
- members[0] = NULL;
- grp = &fakegroup;
- grp->gr_name = pw_checkname((u_char *)a_name->val, 0);
- grp->gr_passwd = "*";
- grp->gr_gid = gr_gidpolicy(cnf, args);
- grp->gr_mem = members;
- }
-
- /*
- * This allows us to set a group password Group passwords is an
- * antique idea, rarely used and insecure (no secure database) Should
- * be discouraged, but it is apparently still supported by some
- * software.
- */
-
- if ((arg = getarg(args, 'h')) != NULL ||
- (arg = getarg(args, 'H')) != NULL) {
- if (strcmp(arg->val, "-") == 0)
- grp->gr_passwd = "*"; /* No access */
- else {
- int fd = atoi(arg->val);
- int precrypt = (arg->ch == 'H');
- int b;
- int istty = isatty(fd);
- struct termios t;
- char *p, line[256];
-
- if (istty) {
- if (tcgetattr(fd, &t) == -1)
- istty = 0;
- else {
- struct termios n = t;
-
- /* Disable echo */
- n.c_lflag &= ~(ECHO);
- tcsetattr(fd, TCSANOW, &n);
- printf("%sassword for group %s:", (mode == M_UPDATE) ? "New p" : "P", grp->gr_name);
- fflush(stdout);
- }
- }
- b = read(fd, line, sizeof(line) - 1);
- if (istty) { /* Restore state */
- tcsetattr(fd, TCSANOW, &t);
- fputc('\n', stdout);
- fflush(stdout);
- }
- if (b < 0) {
- warn("-h file descriptor");
- return EX_OSERR;
- }
- line[b] = '\0';
- if ((p = strpbrk(line, " \t\r\n")) != NULL)
- *p = '\0';
- if (!*line)
- errx(EX_DATAERR, "empty password read on file descriptor %d", fd);
- if (precrypt) {
- if (strchr(line, ':') != NULL)
- return EX_DATAERR;
- grp->gr_passwd = line;
- } else
- grp->gr_passwd = pw_pwcrypt(line);
- }
- }
-
- if (((arg = getarg(args, 'M')) != NULL ||
- (arg = getarg(args, 'd')) != NULL ||
- (arg = getarg(args, 'm')) != NULL) && arg->val) {
- int i = 0;
- char *p;
- struct passwd *pwd;
-
- /* Make sure this is not stay NULL with -M "" */
- extendarray(&members, &grmembers, 200);
- if (arg->ch == 'd')
- delete_members(&members, &grmembers, &i, arg, grp);
- else if (arg->ch == 'm') {
- int k = 0;
-
- while (grp->gr_mem[k] != NULL) {
- if (extendarray(&members, &grmembers, i + 2) != -1)
- members[i++] = grp->gr_mem[k];
- k++;
- }
- }
-
- if (arg->ch != 'd')
- for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) {
- int j;
-
- /*
- * Check for duplicates
- */
- pwd = lookup_pwent(p);
- for (j = 0; j < i && strcmp(members[j], pwd->pw_name) != 0; j++)
- ;
- if (j == i && extendarray(&members, &grmembers, i + 2) != -1)
- members[i++] = newstr(pwd->pw_name);
- }
- while (i < grmembers)
- members[i++] = NULL;
- grp->gr_mem = members;
- }
-
- if (getarg(args, 'N') != NULL)
- return print_group(grp, getarg(args, 'P') != NULL);
-
- if (mode == M_ADD && (rc = addgrent(grp)) != 0) {
- if (rc == -1)
- warnx("group '%s' already exists", grp->gr_name);
- else
- warn("group update");
- return EX_IOERR;
- } else if (mode == M_UPDATE && (rc = chggrent(a_name->val, grp)) != 0) {
- if (rc == -1)
- warnx("group '%s' not available (NIS?)", grp->gr_name);
- else
- warn("group update");
- return EX_IOERR;
- }
- /* grp may have been invalidated */
- if ((grp = GETGRNAM(a_name->val)) == NULL)
- errx(EX_SOFTWARE, "group disappeared during update");
-
- pw_log(cnf, mode, W_GROUP, "%s(%ld)", grp->gr_name, (long) grp->gr_gid);
-
- if (members)
- free(members);
-
- return EXIT_SUCCESS;
-}
-
-
-/*
- * Lookup a passwd entry using a name or UID.
- */
-static struct passwd *
-lookup_pwent(const char *user)
-{
- struct passwd *pwd;
-
- if ((pwd = GETPWNAM(user)) == NULL &&
- (!isdigit((unsigned char)*user) ||
- (pwd = getpwuid((uid_t) atoi(user))) == NULL))
- errx(EX_NOUSER, "user `%s' does not exist", user);
-
- return (pwd);
-}
-
-
-/*
- * Delete requested members from a group.
- */
-static void
-delete_members(char ***members, int *grmembers, int *i, struct carg *arg,
- struct group *grp)
-{
- bool matchFound;
- char *user;
- char *valueCopy;
- char *valuePtr;
- int k;
- struct passwd *pwd;
-
- k = 0;
- while (grp->gr_mem[k] != NULL) {
- matchFound = false;
- if ((valueCopy = strdup(arg->val)) == NULL)
- errx(EX_UNAVAILABLE, "out of memory");
- valuePtr = valueCopy;
- while ((user = strsep(&valuePtr, ", \t")) != NULL) {
- pwd = lookup_pwent(user);
- if (strcmp(grp->gr_mem[k], pwd->pw_name) == 0) {
- matchFound = true;
- break;
- }
- }
- free(valueCopy);
-
- if (!matchFound &&
- extendarray(members, grmembers, *i + 2) != -1)
- (*members)[(*i)++] = grp->gr_mem[k];
-
- k++;
- }
-
- return;
-}
-
-
-static gid_t
-gr_gidpolicy(struct userconf * cnf, struct cargs * args)
-{
- struct group *grp;
- gid_t gid = (gid_t) - 1;
- struct carg *a_gid = getarg(args, 'g');
-
- /*
- * Check the given gid, if any
- */
- if (a_gid != NULL) {
- gid = (gid_t) atol(a_gid->val);
-
- if ((grp = GETGRGID(gid)) != NULL && getarg(args, 'o') == NULL)
- errx(EX_DATAERR, "gid `%ld' has already been allocated", (long) grp->gr_gid);
- } else {
- struct bitmap bm;
-
- /*
- * We need to allocate the next available gid under one of
- * two policies a) Grab the first unused gid b) Grab the
- * highest possible unused gid
- */
- if (cnf->min_gid >= cnf->max_gid) { /* Sanity claus^H^H^H^Hheck */
- cnf->min_gid = 1000;
- cnf->max_gid = 32000;
- }
- bm = bm_alloc(cnf->max_gid - cnf->min_gid + 1);
-
- /*
- * Now, let's fill the bitmap from the password file
- */
- SETGRENT();
- while ((grp = GETGRENT()) != NULL)
- if ((gid_t)grp->gr_gid >= (gid_t)cnf->min_gid &&
- (gid_t)grp->gr_gid <= (gid_t)cnf->max_gid)
- bm_setbit(&bm, grp->gr_gid - cnf->min_gid);
- ENDGRENT();
-
- /*
- * Then apply the policy, with fallback to reuse if necessary
- */
- if (cnf->reuse_gids)
- gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid);
- else {
- gid = (gid_t) (bm_lastset(&bm) + 1);
- if (!bm_isset(&bm, gid))
- gid += cnf->min_gid;
- else
- gid = (gid_t) (bm_firstunset(&bm) + cnf->min_gid);
- }
-
- /*
- * Another sanity check
- */
- if (gid < cnf->min_gid || gid > cnf->max_gid)
- errx(EX_SOFTWARE, "unable to allocate a new gid - range fully used");
- bm_dealloc(&bm);
- }
- return gid;
-}
-
-
-static int
-print_group(struct group * grp, int pretty)
-{
- if (!pretty) {
- int buflen = 0;
- char *buf = NULL;
-
- fmtgrent(&buf, &buflen, grp);
- fputs(buf, stdout);
- free(buf);
- } else {
- int i;
-
- printf("Group Name: %-15s #%lu\n"
- " Members: ",
- grp->gr_name, (long) grp->gr_gid);
- for (i = 0; grp->gr_mem[i]; i++)
- printf("%s%s", i ? "," : "", grp->gr_mem[i]);
- fputs("\n\n", stdout);
- }
- return EXIT_SUCCESS;
-}
diff --git a/pw/pw_log.c b/pw/pw_log.c
deleted file mode 100644
index fc85828..0000000
--- a/pw/pw_log.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <fcntl.h>
-
-#include "pw.h"
-
-static FILE *logfile = NULL;
-
-void
-pw_log(struct userconf * cnf, int mode, int which, char const * fmt,...)
-{
- if (cnf->logfile && *cnf->logfile) {
- if (logfile == NULL) { /* With umask==0 we need to control file access modes on create */
- int fd = open(cnf->logfile, O_WRONLY | O_CREAT | O_APPEND, 0600);
-
- if (fd != -1)
- logfile = fdopen(fd, "a");
- }
- if (logfile != NULL) {
- va_list argp;
- int l;
- time_t now = time(NULL);
- struct tm *t = localtime(&now);
- char nfmt[256];
- char *name;
-
- if ((name = getenv("LOGNAME")) == NULL && (name = getenv("USER")) == NULL)
- name = "unknown";
- /* ISO 8601 International Standard Date format */
- strftime(nfmt, sizeof nfmt, "%Y-%m-%d %T ", t);
- l = strlen(nfmt);
- sprintf(nfmt + strlen(nfmt), "[%s:%s%s] %s\n", name, Which[which], Modes[mode], fmt);
- va_start(argp, fmt);
- vfprintf(logfile, nfmt, argp);
- va_end(argp);
- fflush(logfile);
- }
- }
-}
diff --git a/pw/pw_nis.c b/pw/pw_nis.c
deleted file mode 100644
index 74a3ed0..0000000
--- a/pw/pw_nis.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "pw.h"
-
-static int
-pw_nisupdate(const char * path, struct passwd * pwd, char const * user, int mode)
-{
- char pfx[32];
- char pwbuf[PWBUFSZ];
- int l = sprintf(pfx, "%s:", user);
-
- /*
- * Update the passwd file first
- */
- if (pwd == NULL)
- *pwbuf = '\0';
- else
- fmtpwentry(pwbuf, pwd, PWF_MASTER);
- return fileupdate(path, 0600, pwbuf, pfx, l, mode) != 0;
-}
-
-int
-addnispwent(const char *path, struct passwd * pwd)
-{
- return pw_nisupdate(path, pwd, pwd->pw_name, UPD_CREATE);
-}
-
-int
-chgnispwent(const char *path, char const * login, struct passwd * pwd)
-{
- return pw_nisupdate(path, pwd, login, UPD_REPLACE);
-}
-
-int
-delnispwent(const char *path, const char *login)
-{
- return pw_nisupdate(path, NULL, login, UPD_DELETE);
-}
diff --git a/pw/pw_user.c b/pw/pw_user.c
deleted file mode 100644
index c8364ca..0000000
--- a/pw/pw_user.c
+++ /dev/null
@@ -1,1274 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- *
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <ctype.h>
-#include <err.h>
-#include <fcntl.h>
-#include <sys/param.h>
-#include <dirent.h>
-#include <paths.h>
-#include <termios.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <unistd.h>
-#include <login_cap.h>
-#include "pw.h"
-#include "bitmap.h"
-
-#define LOGNAMESIZE (MAXLOGNAME-1)
-
-static char locked_str[] = "*LOCKED*";
-
-static int print_user(struct passwd * pwd, int pretty, int v7);
-static uid_t pw_uidpolicy(struct userconf * cnf, struct cargs * args);
-static uid_t pw_gidpolicy(struct userconf * cnf, struct cargs * args, char *nam, gid_t prefer);
-static time_t pw_pwdpolicy(struct userconf * cnf, struct cargs * args);
-static time_t pw_exppolicy(struct userconf * cnf, struct cargs * args);
-static char *pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user);
-static char *pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell);
-static char *pw_password(struct userconf * cnf, struct cargs * args, char const * user);
-static char *shell_path(char const * path, char *shells[], char *sh);
-static void rmat(uid_t uid);
-static void rmopie(char const * name);
-
-/*-
- * -C config configuration file
- * -q quiet operation
- * -n name login name
- * -u uid user id
- * -c comment user name/comment
- * -d directory home directory
- * -e date account expiry date
- * -p date password expiry date
- * -g grp primary group
- * -G grp1,grp2 additional groups
- * -m [ -k dir ] create and set up home
- * -s shell name of login shell
- * -o duplicate uid ok
- * -L class user class
- * -l name new login name
- * -h fd password filehandle
- * -H fd encrypted password filehandle
- * -F force print or add
- * Setting defaults:
- * -D set user defaults
- * -b dir default home root dir
- * -e period default expiry period
- * -p period default password change period
- * -g group default group
- * -G grp1,grp2.. default additional groups
- * -L class default login class
- * -k dir default home skeleton
- * -s shell default shell
- * -w method default password method
- */
-
-int
-pw_user(struct userconf * cnf, int mode, struct cargs * args)
-{
- int rc, edited = 0;
- char *p = NULL;
- char *passtmp;
- struct carg *a_name;
- struct carg *a_uid;
- struct carg *arg;
- struct passwd *pwd = NULL;
- struct group *grp;
- struct stat st;
- char line[_PASSWORD_LEN+1];
- FILE *fp;
- mode_t dmode;
- char *dmode_c;
- void *set = NULL;
-
- static struct passwd fakeuser =
- {
- NULL,
- "*",
- -1,
- -1,
- 0,
- "",
- "User &",
- "/nonexistent",
- "/bin/sh",
- 0
-#if defined(__FreeBSD__)
- ,0
-#endif
- };
-
-
- /*
- * 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) {
- cnf->home = arg->val;
- }
-
- if ((arg = getarg(args, 'M')) != NULL) {
- dmode_c = arg->val;
- if ((set = setmode(dmode_c)) == NULL)
- errx(EX_DATAERR, "invalid directory creation mode '%s'",
- dmode_c);
- dmode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
- free(set);
- cnf->homemode = dmode;
- }
-
- /*
- * If we'll need to use it or we're updating it,
- * then create the base home directory if necessary
- */
- if (arg != NULL || getarg(args, 'm') != NULL) {
- int l = strlen(cnf->home);
-
- if (l > 1 && cnf->home[l-1] == '/') /* Shave off any trailing path delimiter */
- cnf->home[--l] = '\0';
-
- if (l < 2 || *cnf->home != '/') /* Check for absolute path name */
- errx(EX_DATAERR, "invalid base directory for home '%s'", cnf->home);
-
- if (stat(cnf->home, &st) == -1) {
- char dbuf[MAXPATHLEN];
-
- /*
- * This is a kludge especially for Joerg :)
- * If the home directory would be created in the root partition, then
- * we really create it under /usr which is likely to have more space.
- * But we create a symlink from cnf->home -> "/usr" -> cnf->home
- */
- if (strchr(cnf->home+1, '/') == NULL) {
- strcpy(dbuf, "/usr");
- strncat(dbuf, cnf->home, MAXPATHLEN-5);
- if (mkdir(dbuf, cnf->homemode) != -1 || errno == EEXIST) {
- chown(dbuf, 0, 0);
- /*
- * Skip first "/" and create symlink:
- * /home -> usr/home
- */
- symlink(dbuf+1, cnf->home);
- }
- /* If this falls, fall back to old method */
- }
- strlcpy(dbuf, cnf->home, sizeof(dbuf));
- p = dbuf;
- if (stat(dbuf, &st) == -1) {
- while ((p = strchr(++p, '/')) != NULL) {
- *p = '\0';
- if (stat(dbuf, &st) == -1) {
- if (mkdir(dbuf, cnf->homemode) == -1)
- goto direrr;
- chown(dbuf, 0, 0);
- } else if (!S_ISDIR(st.st_mode))
- errx(EX_OSFILE, "'%s' (root home parent) is not a directory", dbuf);
- *p = '/';
- }
- }
- if (stat(dbuf, &st) == -1) {
- if (mkdir(dbuf, cnf->homemode) == -1) {
- direrr: err(EX_OSFILE, "mkdir '%s'", dbuf);
- }
- chown(dbuf, 0, 0);
- }
- } else if (!S_ISDIR(st.st_mode))
- errx(EX_OSFILE, "root home `%s' is not a directory", cnf->home);
- }
-
- if ((arg = getarg(args, 'e')) != NULL)
- cnf->expire_days = atoi(arg->val);
-
- if ((arg = getarg(args, 'y')) != NULL)
- cnf->nispasswd = arg->val;
-
- if ((arg = getarg(args, 'p')) != NULL && arg->val)
- cnf->password_days = atoi(arg->val);
-
- if ((arg = getarg(args, 'g')) != NULL) {
- if (!*(p = arg->val)) /* Handle empty group list specially */
- cnf->default_group = "";
- else {
- if ((grp = GETGRNAM(p)) == NULL) {
- if (!isdigit((unsigned char)*p) || (grp = GETGRGID((gid_t) atoi(p))) == NULL)
- errx(EX_NOUSER, "group `%s' does not exist", p);
- }
- cnf->default_group = newstr(grp->gr_name);
- }
- }
- if ((arg = getarg(args, 'L')) != NULL)
- cnf->default_class = pw_checkname((u_char *)arg->val, 0);
-
- if ((arg = getarg(args, 'G')) != NULL && arg->val) {
- int i = 0;
-
- for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) {
- if ((grp = GETGRNAM(p)) == NULL) {
- if (!isdigit((unsigned char)*p) || (grp = GETGRGID((gid_t) atoi(p))) == NULL)
- errx(EX_NOUSER, "group `%s' does not exist", p);
- }
- if (extendarray(&cnf->groups, &cnf->numgroups, i + 2) != -1)
- cnf->groups[i++] = newstr(grp->gr_name);
- }
- while (i < cnf->numgroups)
- cnf->groups[i++] = NULL;
- }
-
- if ((arg = getarg(args, 'k')) != NULL) {
- if (stat(cnf->dotdir = arg->val, &st) == -1 || !S_ISDIR(st.st_mode))
- errx(EX_OSFILE, "skeleton `%s' is not a directory or does not exist", cnf->dotdir);
- }
-
- if ((arg = getarg(args, 's')) != NULL)
- cnf->shell_default = arg->val;
-
- if ((arg = getarg(args, 'w')) != NULL)
- cnf->default_password = boolean_val(arg->val, cnf->default_password);
- if (mode == M_ADD && getarg(args, 'D')) {
- if (getarg(args, 'n') != NULL)
- errx(EX_DATAERR, "can't combine `-D' with `-n name'");
- 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;
- if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_uid = (uid_t) atoi(p)) < cnf->min_uid)
- cnf->max_uid = 32000;
- }
- if ((arg = getarg(args, 'i')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) {
- if ((cnf->min_gid = (gid_t) atoi(p)) == 0)
- cnf->min_gid = 1000;
- if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_gid = (gid_t) atoi(p)) < cnf->min_gid)
- cnf->max_gid = 32000;
- }
-
- arg = getarg(args, 'C');
- if (write_userconfig(arg ? arg->val : NULL))
- return EXIT_SUCCESS;
- warn("config update");
- return EX_IOERR;
- }
-
- if (mode == M_PRINT && getarg(args, 'a')) {
- int pretty = getarg(args, 'P') != NULL;
- int v7 = getarg(args, '7') != NULL;
-
- SETPWENT();
- while ((pwd = GETPWENT()) != NULL)
- print_user(pwd, pretty, v7);
- ENDPWENT();
- return EXIT_SUCCESS;
- }
-
- if ((a_name = getarg(args, 'n')) != NULL)
- pwd = GETPWNAM(pw_checkname((u_char *)a_name->val, 0));
- a_uid = getarg(args, 'u');
-
- if (a_uid == NULL) {
- if (a_name == NULL)
- errx(EX_DATAERR, "user name or id required");
-
- /*
- * Determine whether 'n' switch is name or uid - we don't
- * really don't really care which we have, but we need to
- * know.
- */
- if (mode != M_ADD && pwd == NULL
- && strspn(a_name->val, "0123456789") == strlen(a_name->val)
- && atoi(a_name->val) > 0) { /* Assume uid */
- (a_uid = a_name)->ch = 'u';
- a_name = NULL;
- }
- }
-
- /*
- * Update, delete & print require that the user exists
- */
- if (mode == M_UPDATE || mode == M_DELETE ||
- mode == M_PRINT || mode == M_LOCK || mode == M_UNLOCK) {
-
- if (a_name == NULL && pwd == NULL) /* Try harder */
- pwd = GETPWUID(atoi(a_uid->val));
-
- if (pwd == NULL) {
- 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,
- getarg(args, '7') != NULL);
- }
- if (a_name == NULL)
- errx(EX_NOUSER, "no such uid `%s'", a_uid->val);
- errx(EX_NOUSER, "no such user `%s'", a_name->val);
- }
-
- if (a_name == NULL) /* May be needed later */
- a_name = addarg(args, 'n', newstr(pwd->pw_name));
-
- /*
- * The M_LOCK and M_UNLOCK functions simply add or remove
- * a "*LOCKED*" prefix from in front of the password to
- * prevent it decoding correctly, and therefore prevents
- * access. Of course, this only prevents access via
- * password authentication (not ssh, kerberos or any
- * other method that does not use the UNIX password) but
- * that is a known limitation.
- */
-
- if (mode == M_LOCK) {
- if (strncmp(pwd->pw_passwd, locked_str, sizeof(locked_str)-1) == 0)
- errx(EX_DATAERR, "user '%s' is already locked", pwd->pw_name);
- passtmp = malloc(strlen(pwd->pw_passwd) + sizeof(locked_str));
- if (passtmp == NULL) /* disaster */
- errx(EX_UNAVAILABLE, "out of memory");
- strcpy(passtmp, locked_str);
- strcat(passtmp, pwd->pw_passwd);
- pwd->pw_passwd = passtmp;
- edited = 1;
- } else if (mode == M_UNLOCK) {
- if (strncmp(pwd->pw_passwd, locked_str, sizeof(locked_str)-1) != 0)
- errx(EX_DATAERR, "user '%s' is not locked", pwd->pw_name);
- pwd->pw_passwd += sizeof(locked_str)-1;
- edited = 1;
- } else if (mode == M_DELETE) {
- /*
- * Handle deletions now
- */
- char file[MAXPATHLEN];
- char home[MAXPATHLEN];
- uid_t uid = pwd->pw_uid;
-
- if (strcmp(pwd->pw_name, "root") == 0)
- errx(EX_DATAERR, "cannot remove user 'root'");
-
- if (!PWALTDIR()) {
- /*
- * Remove opie record from /etc/opiekeys
- */
-
- rmopie(pwd->pw_name);
-
- /*
- * Remove crontabs
- */
- sprintf(file, "/var/cron/tabs/%s", pwd->pw_name);
- if (access(file, F_OK) == 0) {
- sprintf(file, "crontab -u %s -r", pwd->pw_name);
- system(file);
- }
- }
- /*
- * Save these for later, since contents of pwd may be
- * invalidated by deletion
- */
- sprintf(file, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
- strlcpy(home, pwd->pw_dir, sizeof(home));
-
- rc = delpwent(pwd);
- if (rc == -1)
- err(EX_IOERR, "user '%s' does not exist", pwd->pw_name);
- else if (rc != 0) {
- warn("passwd update");
- return EX_IOERR;
- }
-
- if (cnf->nispasswd && *cnf->nispasswd=='/') {
- rc = delnispwent(cnf->nispasswd, a_name->val);
- if (rc == -1)
- warnx("WARNING: user '%s' does not exist in NIS passwd", pwd->pw_name);
- else if (rc != 0)
- warn("WARNING: NIS passwd update");
- /* non-fatal */
- }
-
- editgroups(a_name->val, NULL);
-
- pw_log(cnf, mode, W_USER, "%s(%ld) account removed", a_name->val, (long) uid);
-
- if (!PWALTDIR()) {
- /*
- * Remove mail file
- */
- remove(file);
-
- /*
- * Remove at jobs
- */
- if (getpwuid(uid) == NULL)
- rmat(uid);
-
- /*
- * Remove home directory and contents
- */
- if (getarg(args, 'r') != NULL && *home == '/' && getpwuid(uid) == NULL) {
- if (stat(home, &st) != -1) {
- rm_r(home, uid);
- pw_log(cnf, mode, W_USER, "%s(%ld) home '%s' %sremoved",
- a_name->val, (long) uid, home,
- stat(home, &st) == -1 ? "" : "not completely ");
- }
- }
- }
- return EXIT_SUCCESS;
- } else if (mode == M_PRINT)
- return print_user(pwd,
- getarg(args, 'P') != NULL,
- getarg(args, '7') != NULL);
-
- /*
- * The rest is edit code
- */
- if ((arg = getarg(args, 'l')) != NULL) {
- if (strcmp(pwd->pw_name, "root") == 0)
- errx(EX_DATAERR, "can't rename `root' account");
- pwd->pw_name = pw_checkname((u_char *)arg->val, 0);
- edited = 1;
- }
-
- if ((arg = getarg(args, 'u')) != NULL && isdigit((unsigned char)*arg->val)) {
- pwd->pw_uid = (uid_t) atol(arg->val);
- edited = 1;
- if (pwd->pw_uid != 0 && strcmp(pwd->pw_name, "root") == 0)
- errx(EX_DATAERR, "can't change uid of `root' account");
- if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
- warnx("WARNING: account `%s' will have a uid of 0 (superuser access!)", pwd->pw_name);
- }
-
- if ((arg = getarg(args, 'g')) != NULL && pwd->pw_uid != 0) { /* Already checked this */
- gid_t newgid = (gid_t) GETGRNAM(cnf->default_group)->gr_gid;
- if (newgid != pwd->pw_gid) {
- edited = 1;
- pwd->pw_gid = newgid;
- }
- }
-
- if ((arg = getarg(args, 'p')) != NULL) {
- if (*arg->val == '\0' || strcmp(arg->val, "0") == 0) {
- if (pwd->pw_change != 0) {
- pwd->pw_change = 0;
- edited = 1;
- }
- }
- else {
- time_t now = time(NULL);
- time_t expire = parse_date(now, arg->val);
-
- if (now == expire)
- errx(EX_DATAERR, "invalid password change date `%s'", arg->val);
- if (pwd->pw_change != expire) {
- pwd->pw_change = expire;
- edited = 1;
- }
- }
- }
-
- if ((arg = getarg(args, 'e')) != NULL) {
- if (*arg->val == '\0' || strcmp(arg->val, "0") == 0) {
- if (pwd->pw_expire != 0) {
- pwd->pw_expire = 0;
- edited = 1;
- }
- }
- else {
- time_t now = time(NULL);
- time_t expire = parse_date(now, arg->val);
-
- if (now == expire)
- errx(EX_DATAERR, "invalid account expiry date `%s'", arg->val);
- if (pwd->pw_expire != expire) {
- pwd->pw_expire = expire;
- edited = 1;
- }
- }
- }
-
- if ((arg = getarg(args, 's')) != NULL) {
- char *shell = shell_path(cnf->shelldir, cnf->shells, arg->val);
- if (shell == NULL)
- shell = "";
- if (strcmp(shell, pwd->pw_shell) != 0) {
- pwd->pw_shell = shell;
- edited = 1;
- }
- }
-
- if (getarg(args, 'L')) {
- if (cnf->default_class == NULL)
- cnf->default_class = "";
- if (strcmp(pwd->pw_class, cnf->default_class) != 0) {
- pwd->pw_class = cnf->default_class;
- edited = 1;
- }
- }
-
- if ((arg = getarg(args, 'd')) != NULL) {
- if (strcmp(pwd->pw_dir, arg->val))
- edited = 1;
- if (stat(pwd->pw_dir = arg->val, &st) == -1) {
- if (getarg(args, 'm') == NULL && strcmp(pwd->pw_dir, "/nonexistent") != 0)
- warnx("WARNING: home `%s' does not exist", pwd->pw_dir);
- } else if (!S_ISDIR(st.st_mode))
- warnx("WARNING: home `%s' is not a directory", pwd->pw_dir);
- }
-
- if ((arg = getarg(args, 'w')) != NULL &&
- getarg(args, 'h') == NULL && getarg(args, 'H') == NULL) {
- login_cap_t *lc;
-
- lc = login_getpwclass(pwd);
- if (lc == NULL ||
- login_setcryptfmt(lc, "md5", NULL) == NULL)
- warn("setting crypt(3) format");
- login_close(lc);
- pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
- edited = 1;
- }
-
- } else {
- login_cap_t *lc;
-
- /*
- * Add code
- */
-
- if (a_name == NULL) /* Required */
- errx(EX_DATAERR, "login name required");
- else if ((pwd = GETPWNAM(a_name->val)) != NULL) /* Exists */
- errx(EX_DATAERR, "login name `%s' already exists", a_name->val);
-
- /*
- * Now, set up defaults for a new user
- */
- pwd = &fakeuser;
- pwd->pw_name = a_name->val;
- pwd->pw_class = cnf->default_class ? cnf->default_class : "";
- pwd->pw_uid = pw_uidpolicy(cnf, args);
- pwd->pw_gid = pw_gidpolicy(cnf, args, pwd->pw_name, (gid_t) pwd->pw_uid);
- pwd->pw_change = pw_pwdpolicy(cnf, args);
- pwd->pw_expire = pw_exppolicy(cnf, args);
- pwd->pw_dir = pw_homepolicy(cnf, args, pwd->pw_name);
- pwd->pw_shell = pw_shellpolicy(cnf, args, NULL);
- lc = login_getpwclass(pwd);
- if (lc == NULL || login_setcryptfmt(lc, "md5", NULL) == NULL)
- warn("setting crypt(3) format");
- login_close(lc);
- pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
- edited = 1;
-
- if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
- warnx("WARNING: new account `%s' has a uid of 0 (superuser access!)", pwd->pw_name);
- }
-
- /*
- * Shared add/edit code
- */
- if ((arg = getarg(args, 'c')) != NULL) {
- char *gecos = pw_checkname((u_char *)arg->val, 1);
- if (strcmp(pwd->pw_gecos, gecos) != 0) {
- pwd->pw_gecos = gecos;
- edited = 1;
- }
- }
-
- if ((arg = getarg(args, 'h')) != NULL ||
- (arg = getarg(args, 'H')) != NULL) {
- if (strcmp(arg->val, "-") == 0) {
- if (!pwd->pw_passwd || *pwd->pw_passwd != '*') {
- pwd->pw_passwd = "*"; /* No access */
- edited = 1;
- }
- } else {
- int fd = atoi(arg->val);
- int precrypt = (arg->ch == 'H');
- int b;
- int istty = isatty(fd);
- struct termios t;
- login_cap_t *lc;
-
- if (istty) {
- if (tcgetattr(fd, &t) == -1)
- istty = 0;
- else {
- struct termios n = t;
-
- /* Disable echo */
- n.c_lflag &= ~(ECHO);
- tcsetattr(fd, TCSANOW, &n);
- printf("%s%spassword for user %s:",
- (mode == M_UPDATE) ? "new " : "",
- precrypt ? "encrypted " : "",
- pwd->pw_name);
- fflush(stdout);
- }
- }
- b = read(fd, line, sizeof(line) - 1);
- if (istty) { /* Restore state */
- tcsetattr(fd, TCSANOW, &t);
- fputc('\n', stdout);
- fflush(stdout);
- }
- if (b < 0) {
- warn("-%c file descriptor", precrypt ? 'H' :
- 'h');
- return EX_IOERR;
- }
- line[b] = '\0';
- if ((p = strpbrk(line, "\r\n")) != NULL)
- *p = '\0';
- if (!*line)
- errx(EX_DATAERR, "empty password read on file descriptor %d", fd);
- if (precrypt) {
- if (strchr(line, ':') != NULL)
- return EX_DATAERR;
- pwd->pw_passwd = line;
- } else {
- lc = login_getpwclass(pwd);
- if (lc == NULL ||
- login_setcryptfmt(lc, "md5", NULL) == NULL)
- warn("setting crypt(3) format");
- login_close(lc);
- pwd->pw_passwd = pw_pwcrypt(line);
- }
- edited = 1;
- }
- }
-
- /*
- * Special case: -N only displays & exits
- */
- if (getarg(args, 'N') != NULL)
- return print_user(pwd,
- getarg(args, 'P') != NULL,
- getarg(args, '7') != NULL);
-
- if (mode == M_ADD) {
- edited = 1; /* Always */
- rc = addpwent(pwd);
- if (rc == -1) {
- warnx("user '%s' already exists", pwd->pw_name);
- return EX_IOERR;
- } else if (rc != 0) {
- warn("passwd file update");
- return EX_IOERR;
- }
- if (cnf->nispasswd && *cnf->nispasswd=='/') {
- rc = addnispwent(cnf->nispasswd, pwd);
- if (rc == -1)
- warnx("User '%s' already exists in NIS passwd", pwd->pw_name);
- else
- warn("NIS passwd update");
- /* NOTE: we treat NIS-only update errors as non-fatal */
- }
- } else if (mode == M_UPDATE || mode == M_LOCK || mode == M_UNLOCK) {
- if (edited) { /* Only updated this if required */
- rc = chgpwent(a_name->val, pwd);
- if (rc == -1) {
- warnx("user '%s' does not exist (NIS?)", pwd->pw_name);
- return EX_IOERR;
- } else if (rc != 0) {
- warn("passwd file update");
- return EX_IOERR;
- }
- if ( cnf->nispasswd && *cnf->nispasswd=='/') {
- rc = chgnispwent(cnf->nispasswd, a_name->val, pwd);
- if (rc == -1)
- warn("User '%s' not found in NIS passwd", pwd->pw_name);
- else
- warn("NIS passwd update");
- /* NOTE: NIS-only update errors are not fatal */
- }
- }
- }
-
- /*
- * Ok, user is created or changed - now edit group file
- */
-
- if (mode == M_ADD || getarg(args, 'G') != NULL)
- editgroups(pwd->pw_name, cnf->groups);
-
- /* go get a current version of pwd */
- pwd = GETPWNAM(a_name->val);
- if (pwd == NULL) {
- /* This will fail when we rename, so special case that */
- if (mode == M_UPDATE && (arg = getarg(args, 'l')) != NULL) {
- a_name->val = arg->val; /* update new name */
- pwd = GETPWNAM(a_name->val); /* refetch renamed rec */
- }
- }
- if (pwd == NULL) /* can't go on without this */
- errx(EX_NOUSER, "user '%s' disappeared during update", a_name->val);
-
- grp = GETGRGID(pwd->pw_gid);
- pw_log(cnf, mode, W_USER, "%s(%ld):%s(%ld):%s:%s:%s",
- pwd->pw_name, (long) pwd->pw_uid,
- grp ? grp->gr_name : "unknown", (long) (grp ? grp->gr_gid : -1),
- pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
-
- /*
- * If adding, let's touch and chown the user's mail file. This is not
- * strictly necessary under BSD with a 0755 maildir but it also
- * doesn't hurt anything to create the empty mailfile
- */
- if (mode == M_ADD) {
- if (!PWALTDIR()) {
- sprintf(line, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
- close(open(line, O_RDWR | O_CREAT, 0600)); /* Preserve contents &
- * mtime */
- chown(line, pwd->pw_uid, pwd->pw_gid);
- }
- }
-
- /*
- * Let's create and populate the user's home directory. Note
- * that this also `works' for editing users if -m is used, but
- * existing files will *not* be overwritten.
- */
- if (!PWALTDIR() && getarg(args, 'm') != NULL && pwd->pw_dir && *pwd->pw_dir == '/' && pwd->pw_dir[1]) {
- copymkdir(pwd->pw_dir, cnf->dotdir, cnf->homemode, pwd->pw_uid, pwd->pw_gid);
- pw_log(cnf, mode, W_USER, "%s(%ld) home %s made",
- pwd->pw_name, (long) pwd->pw_uid, pwd->pw_dir);
- }
-
-
- /*
- * Finally, send mail to the new user as well, if we are asked to
- */
- if (mode == M_ADD && !PWALTDIR() && cnf->newmail && *cnf->newmail && (fp = fopen(cnf->newmail, "r")) != NULL) {
- FILE *pfp = popen(_PATH_SENDMAIL " -t", "w");
-
- if (pfp == NULL)
- warn("sendmail");
- else {
- fprintf(pfp, "From: root\n" "To: %s\n" "Subject: Welcome!\n\n", pwd->pw_name);
- while (fgets(line, sizeof(line), fp) != NULL) {
- /* Do substitutions? */
- fputs(line, pfp);
- }
- pclose(pfp);
- pw_log(cnf, mode, W_USER, "%s(%ld) new user mail sent",
- pwd->pw_name, (long) pwd->pw_uid);
- }
- fclose(fp);
- }
-
- return EXIT_SUCCESS;
-}
-
-
-static uid_t
-pw_uidpolicy(struct userconf * cnf, struct cargs * args)
-{
- struct passwd *pwd;
- uid_t uid = (uid_t) - 1;
- struct carg *a_uid = getarg(args, 'u');
-
- /*
- * Check the given uid, if any
- */
- if (a_uid != NULL) {
- uid = (uid_t) atol(a_uid->val);
-
- if ((pwd = GETPWUID(uid)) != NULL && getarg(args, 'o') == NULL)
- errx(EX_DATAERR, "uid `%ld' has already been allocated", (long) pwd->pw_uid);
- } else {
- struct bitmap bm;
-
- /*
- * We need to allocate the next available uid under one of
- * two policies a) Grab the first unused uid b) Grab the
- * highest possible unused uid
- */
- if (cnf->min_uid >= cnf->max_uid) { /* Sanity
- * claus^H^H^H^Hheck */
- cnf->min_uid = 1000;
- cnf->max_uid = 32000;
- }
- bm = bm_alloc(cnf->max_uid - cnf->min_uid + 1);
-
- /*
- * Now, let's fill the bitmap from the password file
- */
- SETPWENT();
- while ((pwd = GETPWENT()) != NULL)
- if (pwd->pw_uid >= (uid_t) cnf->min_uid && pwd->pw_uid <= (uid_t) cnf->max_uid)
- bm_setbit(&bm, pwd->pw_uid - cnf->min_uid);
- ENDPWENT();
-
- /*
- * Then apply the policy, with fallback to reuse if necessary
- */
- if (cnf->reuse_uids || (uid = (uid_t) (bm_lastset(&bm) + cnf->min_uid + 1)) > cnf->max_uid)
- uid = (uid_t) (bm_firstunset(&bm) + cnf->min_uid);
-
- /*
- * Another sanity check
- */
- if (uid < cnf->min_uid || uid > cnf->max_uid)
- errx(EX_SOFTWARE, "unable to allocate a new uid - range fully used");
- bm_dealloc(&bm);
- }
- return uid;
-}
-
-
-static uid_t
-pw_gidpolicy(struct userconf * cnf, struct cargs * args, char *nam, gid_t prefer)
-{
- struct group *grp;
- gid_t gid = (uid_t) - 1;
- struct carg *a_gid = getarg(args, 'g');
-
- /*
- * If no arg given, see if default can help out
- */
- if (a_gid == NULL && cnf->default_group && *cnf->default_group)
- a_gid = addarg(args, 'g', cnf->default_group);
-
- /*
- * Check the given gid, if any
- */
- SETGRENT();
- if (a_gid != NULL) {
- if ((grp = GETGRNAM(a_gid->val)) == NULL) {
- gid = (gid_t) atol(a_gid->val);
- if ((gid == 0 && !isdigit((unsigned char)*a_gid->val)) || (grp = GETGRGID(gid)) == NULL)
- errx(EX_NOUSER, "group `%s' is not defined", a_gid->val);
- }
- 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];
-
- LIST_INIT(&grpargs);
- addarg(&grpargs, 'n', nam);
-
- /*
- * We need to auto-create a group with the user's name. We
- * can send all the appropriate output to our sister routine
- * bit first see if we can create a group with gid==uid so we
- * can keep the user and group ids in sync. We purposely do
- * NOT check the gid range if we can force the sync. If the
- * user's name dups an existing group, then the group add
- * function will happily handle that case for us and exit.
- */
- if (GETGRGID(prefer) == NULL) {
- sprintf(tmp, "%lu", (unsigned long) prefer);
- addarg(&grpargs, 'g', tmp);
- }
- 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 = LIST_FIRST(&grpargs);
- while (a_gid != NULL) {
- struct carg *t = LIST_NEXT(a_gid, list);
- LIST_REMOVE(a_gid, list);
- a_gid = t;
- }
- }
- ENDGRENT();
- return gid;
-}
-
-
-static time_t
-pw_pwdpolicy(struct userconf * cnf, struct cargs * args)
-{
- time_t result = 0;
- time_t now = time(NULL);
- struct carg *arg = getarg(args, 'p');
-
- if (arg != NULL) {
- if ((result = parse_date(now, arg->val)) == now)
- errx(EX_DATAERR, "invalid date/time `%s'", arg->val);
- } else if (cnf->password_days > 0)
- result = now + ((long) cnf->password_days * 86400L);
- return result;
-}
-
-
-static time_t
-pw_exppolicy(struct userconf * cnf, struct cargs * args)
-{
- time_t result = 0;
- time_t now = time(NULL);
- struct carg *arg = getarg(args, 'e');
-
- if (arg != NULL) {
- if ((result = parse_date(now, arg->val)) == now)
- errx(EX_DATAERR, "invalid date/time `%s'", arg->val);
- } else if (cnf->expire_days > 0)
- result = now + ((long) cnf->expire_days * 86400L);
- return result;
-}
-
-
-static char *
-pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user)
-{
- struct carg *arg = getarg(args, 'd');
-
- if (arg)
- return arg->val;
- else {
- static char home[128];
-
- if (cnf->home == NULL || *cnf->home == '\0')
- errx(EX_CONFIG, "no base home directory set");
- sprintf(home, "%s/%s", cnf->home, user);
- return home;
- }
-}
-
-static char *
-shell_path(char const * path, char *shells[], char *sh)
-{
- if (sh != NULL && (*sh == '/' || *sh == '\0'))
- return sh; /* specified full path or forced none */
- else {
- char *p;
- char paths[_UC_MAXLINE];
-
- /*
- * We need to search paths
- */
- strlcpy(paths, path, sizeof(paths));
- for (p = strtok(paths, ": \t\r\n"); p != NULL; p = strtok(NULL, ": \t\r\n")) {
- int i;
- static char shellpath[256];
-
- if (sh != NULL) {
- sprintf(shellpath, "%s/%s", p, sh);
- if (access(shellpath, X_OK) == 0)
- return shellpath;
- } else
- for (i = 0; i < _UC_MAXSHELLS && shells[i] != NULL; i++) {
- sprintf(shellpath, "%s/%s", p, shells[i]);
- if (access(shellpath, X_OK) == 0)
- return shellpath;
- }
- }
- if (sh == NULL)
- errx(EX_OSFILE, "can't find shell `%s' in shell paths", sh);
- errx(EX_CONFIG, "no default shell available or defined");
- return NULL;
- }
-}
-
-
-static char *
-pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell)
-{
- char *sh = newshell;
- struct carg *arg = getarg(args, 's');
-
- if (newshell == NULL && arg != NULL)
- sh = arg->val;
- return shell_path(cnf->shelldir, cnf->shells, sh ? sh : cnf->shell_default);
-}
-
-#define SALTSIZE 32
-
-static char const chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./";
-
-char *
-pw_pwcrypt(char *password)
-{
- int i;
- char salt[SALTSIZE + 1];
-
- static char buf[256];
-
- /*
- * Calculate a salt value
- */
- for (i = 0; i < SALTSIZE; i++)
- salt[i] = chars[arc4random_uniform(sizeof(chars) - 1)];
- salt[SALTSIZE] = '\0';
-
- return strcpy(buf, crypt(password, salt));
-}
-
-
-static char *
-pw_password(struct userconf * cnf, struct cargs * args, char const * user)
-{
- int i, l;
- char pwbuf[32];
-
- switch (cnf->default_password) {
- case -1: /* Random password */
- l = (arc4random() % 8 + 8); /* 8 - 16 chars */
- for (i = 0; i < l; i++)
- pwbuf[i] = chars[arc4random_uniform(sizeof(chars)-1)];
- pwbuf[i] = '\0';
-
- /*
- * We give this information back to the user
- */
- if (getarg(args, 'h') == NULL && getarg(args, 'H') == NULL &&
- getarg(args, 'N') == NULL) {
- if (isatty(STDOUT_FILENO))
- printf("Password for '%s' is: ", user);
- printf("%s\n", pwbuf);
- fflush(stdout);
- }
- break;
-
- case -2: /* No password at all! */
- return "";
-
- case 0: /* No login - default */
- default:
- return "*";
-
- case 1: /* user's name */
- strlcpy(pwbuf, user, sizeof(pwbuf));
- break;
- }
- return pw_pwcrypt(pwbuf);
-}
-
-
-static int
-print_user(struct passwd * pwd, int pretty, int v7)
-{
- if (!pretty) {
- char buf[_UC_MAXLINE];
-
- fmtpwentry(buf, pwd, v7 ? PWF_PASSWD : PWF_STANDARD);
- fputs(buf, stdout);
- } else {
- int j;
- char *p;
- struct group *grp = GETGRGID(pwd->pw_gid);
- char uname[60] = "User &", office[60] = "[None]",
- wphone[60] = "[None]", hphone[60] = "[None]";
- char acexpire[32] = "[None]", pwexpire[32] = "[None]";
- struct tm * tptr;
-
- if ((p = strtok(pwd->pw_gecos, ",")) != NULL) {
- strlcpy(uname, p, sizeof(uname));
- if ((p = strtok(NULL, ",")) != NULL) {
- strlcpy(office, p, sizeof(office));
- if ((p = strtok(NULL, ",")) != NULL) {
- strlcpy(wphone, p, sizeof(wphone));
- if ((p = strtok(NULL, "")) != NULL) {
- strlcpy(hphone, p,
- sizeof(hphone));
- }
- }
- }
- }
- /*
- * Handle '&' in gecos field
- */
- if ((p = strchr(uname, '&')) != NULL) {
- int l = strlen(pwd->pw_name);
- int m = strlen(p);
-
- memmove(p + l, p + 1, m);
- memmove(p, pwd->pw_name, l);
- *p = (char) toupper((unsigned char)*p);
- }
- if (pwd->pw_expire > (time_t)0 && (tptr = localtime(&pwd->pw_expire)) != NULL)
- strftime(acexpire, sizeof acexpire, "%c", tptr);
- if (pwd->pw_change > (time_t)0 && (tptr = localtime(&pwd->pw_change)) != NULL)
- strftime(pwexpire, sizeof pwexpire, "%c", tptr);
- printf("Login Name: %-15s #%-12ld Group: %-15s #%ld\n"
- " Full Name: %s\n"
- " Home: %-26.26s Class: %s\n"
- " Shell: %-26.26s Office: %s\n"
- "Work Phone: %-26.26s Home Phone: %s\n"
- "Acc Expire: %-26.26s Pwd Expire: %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,
- acexpire, pwexpire);
- SETGRENT();
- j = 0;
- while ((grp=GETGRENT()) != NULL)
- {
- int i = 0;
- while (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", j ? "\n" : "");
- }
- return EXIT_SUCCESS;
-}
-
-char *
-pw_checkname(u_char *name, int gecos)
-{
- char showch[8];
- u_char const *badchars, *ch, *showtype;
- int reject;
-
- ch = name;
- reject = 0;
- if (gecos) {
- /* See if the name is valid as a gecos (comment) field. */
- badchars = ":!@";
- showtype = "gecos field";
- } else {
- /* See if the name is valid as a userid or group. */
- badchars = " ,\t:+&#%$^()!@~*?<>=|\\/\"";
- showtype = "userid/group name";
- /* Userids and groups can not have a leading '-'. */
- if (*ch == '-')
- reject = 1;
- }
- if (!reject) {
- while (*ch) {
- if (strchr(badchars, *ch) != NULL || *ch < ' ' ||
- *ch == 127) {
- reject = 1;
- break;
- }
- /* 8-bit characters are only allowed in GECOS fields */
- if (!gecos && (*ch & 0x80)) {
- reject = 1;
- break;
- }
- ch++;
- }
- }
- /*
- * A `$' is allowed as the final character for userids and groups,
- * mainly for the benefit of samba.
- */
- if (reject && !gecos) {
- if (*ch == '$' && *(ch + 1) == '\0') {
- reject = 0;
- ch++;
- }
- }
- if (reject) {
- snprintf(showch, sizeof(showch), (*ch >= ' ' && *ch < 127)
- ? "`%c'" : "0x%02x", *ch);
- errx(EX_DATAERR, "invalid character %s at position %d in %s",
- showch, (ch - name), showtype);
- }
- if (!gecos && (ch - name) > LOGNAMESIZE)
- errx(EX_DATAERR, "name too long `%s' (max is %d)", name,
- LOGNAMESIZE);
- return (char *)name;
-}
-
-
-static void
-rmat(uid_t uid)
-{
- DIR *d = opendir("/var/at/jobs");
-
- if (d != NULL) {
- struct dirent *e;
-
- while ((e = readdir(d)) != NULL) {
- struct stat st;
-
- if (strncmp(e->d_name, ".lock", 5) != 0 &&
- stat(e->d_name, &st) == 0 &&
- !S_ISDIR(st.st_mode) &&
- st.st_uid == uid) {
- char tmp[MAXPATHLEN];
-
- sprintf(tmp, "/usr/bin/atrm %s", e->d_name);
- system(tmp);
- }
- }
- closedir(d);
- }
-}
-
-static void
-rmopie(char const * name)
-{
- static const char etcopie[] = "/etc/opiekeys";
- FILE *fp = fopen(etcopie, "r+");
-
- if (fp != NULL) {
- char tmp[1024];
- off_t atofs = 0;
- int length = strlen(name);
-
- while (fgets(tmp, sizeof tmp, fp) != NULL) {
- if (strncmp(name, tmp, length) == 0 && tmp[length]==' ') {
- if (fseek(fp, atofs, SEEK_SET) == 0) {
- fwrite("#", 1, 1, fp); /* Comment username out */
- }
- break;
- }
- atofs = ftell(fp);
- }
- /*
- * If we got an error of any sort, don't update!
- */
- fclose(fp);
- }
-}
-
diff --git a/pw/pw_vpw.c b/pw/pw_vpw.c
deleted file mode 100644
index 473cbb6..0000000
--- a/pw/pw_vpw.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- *
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/param.h>
-
-#include "pwupd.h"
-
-static FILE * pwd_fp = NULL;
-
-void
-vendpwent(void)
-{
- if (pwd_fp != NULL) {
- fclose(pwd_fp);
- pwd_fp = NULL;
- }
-}
-
-void
-vsetpwent(void)
-{
- vendpwent();
-}
-
-static struct passwd *
-vnextpwent(char const * nam, uid_t uid, int doclose)
-{
- struct passwd * pw = NULL;
- static char pwtmp[1024];
-
- strlcpy(pwtmp, getpwpath(_MASTERPASSWD), sizeof(pwtmp));
-
- if (pwd_fp != NULL || (pwd_fp = fopen(pwtmp, "r")) != NULL) {
- int done = 0;
-
- static struct passwd pwd;
-
- while (!done && fgets(pwtmp, sizeof pwtmp, pwd_fp) != NULL)
- {
- int i, quickout = 0;
- char * q;
- char * p = strchr(pwtmp, '\n');
-
- if (p == NULL) {
- while (fgets(pwtmp, sizeof pwtmp, pwd_fp) != NULL && strchr(pwtmp, '\n')==NULL)
- ; /* Skip long lines */
- continue;
- }
-
- /* skip comments & empty lines */
- if (*pwtmp =='\n' || *pwtmp == '#')
- continue;
-
- i = 0;
- q = p = pwtmp;
- bzero(&pwd, sizeof pwd);
- while (!quickout && (p = strsep(&q, ":\n")) != NULL) {
- switch (i++)
- {
- case 0: /* username */
- pwd.pw_name = p;
- if (nam) {
- if (strcmp(nam, p) == 0)
- done = 1;
- else
- quickout = 1;
- }
- break;
- case 1: /* password */
- pwd.pw_passwd = p;
- break;
- case 2: /* uid */
- pwd.pw_uid = atoi(p);
- if (uid != (uid_t)-1) {
- if (uid == pwd.pw_uid)
- done = 1;
- else
- quickout = 1;
- }
- break;
- case 3: /* gid */
- pwd.pw_gid = atoi(p);
- break;
- case 4: /* class */
- if (nam == NULL && uid == (uid_t)-1)
- done = 1;
- pwd.pw_class = p;
- break;
- case 5: /* change */
- pwd.pw_change = (time_t)atol(p);
- break;
- case 6: /* expire */
- pwd.pw_expire = (time_t)atol(p);
- break;
- case 7: /* gecos */
- pwd.pw_gecos = p;
- break;
- case 8: /* directory */
- pwd.pw_dir = p;
- break;
- case 9: /* shell */
- pwd.pw_shell = p;
- break;
- }
- }
- }
- if (doclose)
- vendpwent();
- if (done && pwd.pw_name) {
- pw = &pwd;
-
- #define CKNULL(s) s = s ? s : ""
- CKNULL(pwd.pw_passwd);
- CKNULL(pwd.pw_class);
- CKNULL(pwd.pw_gecos);
- CKNULL(pwd.pw_dir);
- CKNULL(pwd.pw_shell);
- }
- }
- return pw;
-}
-
-struct passwd *
-vgetpwent(void)
-{
- return vnextpwent(NULL, -1, 0);
-}
-
-struct passwd *
-vgetpwuid(uid_t uid)
-{
- return vnextpwent(NULL, uid, 1);
-}
-
-struct passwd *
-vgetpwnam(const char * nam)
-{
- return vnextpwent(nam, -1, 1);
-}
-
-int vpwdb(char *arg, ...)
-{
- arg=arg;
- return 0;
-}
-
-
-
-static FILE * grp_fp = NULL;
-
-void
-vendgrent(void)
-{
- if (grp_fp != NULL) {
- fclose(grp_fp);
- grp_fp = NULL;
- }
-}
-
-RET_SETGRENT
-vsetgrent(void)
-{
- vendgrent();
-#if defined(__FreeBSD__)
- return 0;
-#endif
-}
-
-static struct group *
-vnextgrent(char const * nam, gid_t gid, int doclose)
-{
- struct group * gr = NULL;
-
- static char * grtmp = NULL;
- static int grlen = 0;
- static char ** mems = NULL;
- static int memlen = 0;
-
- extendline(&grtmp, &grlen, MAXPATHLEN);
- strlcpy(grtmp, getgrpath(_GROUP), MAXPATHLEN);
-
- if (grp_fp != NULL || (grp_fp = fopen(grtmp, "r")) != NULL) {
- int done = 0;
-
- static struct group grp;
-
- while (!done && fgets(grtmp, grlen, grp_fp) != NULL)
- {
- int i, quickout = 0;
- int mno = 0;
- char * q, * p;
- char * sep = ":\n";
-
- if ((p = strchr(grtmp, '\n')) == NULL) {
- int l;
- extendline(&grtmp, &grlen, grlen + PWBUFSZ);
- l = strlen(grtmp);
- if (fgets(grtmp + l, grlen - l, grp_fp) == NULL)
- break; /* No newline terminator on last line */
- }
- /* Skip comments and empty lines */
- if (*grtmp == '\n' || *grtmp == '#')
- continue;
- i = 0;
- q = p = grtmp;
- bzero(&grp, sizeof grp);
- extendarray(&mems, &memlen, 200);
- while (!quickout && (p = strsep(&q, sep)) != NULL) {
- switch (i++)
- {
- case 0: /* groupname */
- grp.gr_name = p;
- if (nam) {
- if (strcmp(nam, p) == 0)
- done = 1;
- else
- quickout = 1;
- }
- break;
- case 1: /* password */
- grp.gr_passwd = p;
- break;
- case 2: /* gid */
- grp.gr_gid = atoi(p);
- if (gid != (gid_t)-1) {
- if (gid == (gid_t)grp.gr_gid)
- done = 1;
- else
- quickout = 1;
- } else if (nam == NULL)
- done = 1;
- break;
- case 3:
- q = p;
- sep = ",\n";
- break;
- default:
- if (*p) {
- extendarray(&mems, &memlen, mno + 2);
- mems[mno++] = p;
- }
- break;
- }
- }
- grp.gr_mem = mems;
- mems[mno] = NULL;
- }
- if (doclose)
- vendgrent();
- if (done && grp.gr_name) {
- gr = &grp;
-
- CKNULL(grp.gr_passwd);
- }
- }
- return gr;
-}
-
-struct group *
-vgetgrent(void)
-{
- return vnextgrent(NULL, -1, 0);
-}
-
-
-struct group *
-vgetgrgid(gid_t gid)
-{
- return vnextgrent(NULL, gid, 1);
-}
-
-struct group *
-vgetgrnam(const char * nam)
-{
- return vnextgrent(nam, -1, 1);
-}
-
-int
-vgrdb(char *arg, ...)
-{
- arg=arg;
- return 0;
-}
-
diff --git a/pw/pwupd.c b/pw/pwupd.c
deleted file mode 100644
index cb8456d..0000000
--- a/pw/pwupd.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <sys/wait.h>
-
-#include "pwupd.h"
-
-#define HAVE_PWDB_C 1
-#define HAVE_PWDB_U 1
-
-static char pathpwd[] = _PATH_PWD;
-static char * pwpath = pathpwd;
-
-int
-setpwdir(const char * dir)
-{
- if (dir == NULL)
- return -1;
- else {
- char * d = malloc(strlen(dir)+1);
- if (d == NULL)
- return -1;
- pwpath = strcpy(d, dir);
- }
- return 0;
-}
-
-char *
-getpwpath(char const * file)
-{
- static char pathbuf[MAXPATHLEN];
-
- snprintf(pathbuf, sizeof pathbuf, "%s/%s", pwpath, file);
- return pathbuf;
-}
-
-int
-pwdb(char *arg,...)
-{
- int i = 0;
- pid_t pid;
- va_list ap;
- char *args[10];
-
- args[i++] = _PATH_PWD_MKDB;
- va_start(ap, arg);
- while (i < 6 && arg != NULL) {
- args[i++] = arg;
- arg = va_arg(ap, char *);
- }
- if (pwpath != pathpwd) {
- args[i++] = "-d";
- args[i++] = pwpath;
- }
- args[i++] = getpwpath(_MASTERPASSWD);
- args[i] = NULL;
-
- if ((pid = fork()) == -1) /* Error (errno set) */
- i = errno;
- else if (pid == 0) { /* Child */
- execv(args[0], args);
- _exit(1);
- } else { /* Parent */
- waitpid(pid, &i, 0);
- if (WEXITSTATUS(i))
- i = EIO;
- }
- return i;
-}
-
-int
-fmtpwentry(char *buf, struct passwd * pwd, int type)
-{
- int l;
- char *pw;
-
- pw = (type == PWF_MASTER) ?
- ((pwd->pw_passwd == NULL) ? "" : pwd->pw_passwd) : "*";
-
- if (type == PWF_PASSWD)
- l = sprintf(buf, "%s:*:%ld:%ld:%s:%s:%s\n",
- pwd->pw_name, (long) pwd->pw_uid, (long) pwd->pw_gid,
- pwd->pw_gecos ? pwd->pw_gecos : "User &",
- pwd->pw_dir, pwd->pw_shell);
- else
- l = sprintf(buf, "%s:%s:%ld:%ld:%s:%lu:%lu:%s:%s:%s\n",
- pwd->pw_name, pw, (long) pwd->pw_uid, (long) pwd->pw_gid,
- pwd->pw_class ? pwd->pw_class : "",
- (unsigned long) pwd->pw_change,
- (unsigned long) pwd->pw_expire,
- pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
- return l;
-}
-
-
-int
-fmtpwent(char *buf, struct passwd * pwd)
-{
- return fmtpwentry(buf, pwd, PWF_STANDARD);
-}
-
-static int
-pw_update(struct passwd * pwd, char const * user, int mode)
-{
- int rc = 0;
-
- ENDPWENT();
-
- /*
- * 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
- rc = pwdb("-C", (char *)NULL); /* Check only */
- if (rc == 0) {
-#else
- { /* No -C */
-#endif
- char pfx[PWBUFSZ];
- char pwbuf[PWBUFSZ];
- int l = snprintf(pfx, PWBUFSZ, "%s:", user);
-#ifdef HAVE_PWDB_U
- int isrename = pwd!=NULL && strcmp(user, pwd->pw_name);
-#endif
-
- /*
- * Update the passwd file first
- */
- if (pwd == NULL)
- *pwbuf = '\0';
- else
- fmtpwentry(pwbuf, pwd, PWF_PASSWD);
-
- if (l < 0)
- l = 0;
- rc = fileupdate(getpwpath(_PASSWD), 0644, pwbuf, pfx, l, mode);
- if (rc == 0) {
-
- /*
- * Then the master.passwd file
- */
- if (pwd != NULL)
- fmtpwentry(pwbuf, pwd, PWF_MASTER);
- rc = fileupdate(getpwpath(_MASTERPASSWD), 0600, pwbuf, pfx, l, mode);
- if (rc == 0) {
-#ifdef HAVE_PWDB_U
- if (mode == UPD_DELETE || isrename)
-#endif
- rc = pwdb(NULL);
-#ifdef HAVE_PWDB_U
- else
- rc = pwdb("-u", user, (char *)NULL);
-#endif
- }
- }
- }
- return rc;
-}
-
-int
-addpwent(struct passwd * pwd)
-{
- return pw_update(pwd, pwd->pw_name, UPD_CREATE);
-}
-
-int
-chgpwent(char const * login, struct passwd * pwd)
-{
- return pw_update(pwd, login, UPD_REPLACE);
-}
-
-int
-delpwent(struct passwd * pwd)
-{
- return pw_update(NULL, pwd->pw_name, UPD_DELETE);
-}
diff --git a/pw/pwupd.h b/pw/pwupd.h
deleted file mode 100644
index 7289065..0000000
--- a/pw/pwupd.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _PWUPD_H_
-#define _PWUPD_H_
-
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include <sys/cdefs.h>
-
-#if defined(__FreeBSD__)
-#define RET_SETGRENT int
-#else
-#define RET_SETGRENT void
-#endif
-
-enum updtype
-{
- UPD_DELETE = -1,
- UPD_CREATE = 0,
- UPD_REPLACE = 1
-};
-
-__BEGIN_DECLS
-int fileupdate(char const * fname, mode_t fm, char const * nline, char const * pfx, int pfxlen, int updmode);
-__END_DECLS
-
-enum pwdfmttype
-{
- PWF_STANDARD, /* MASTER format but with '*' as password */
- PWF_PASSWD, /* V7 format */
- PWF_GROUP = PWF_PASSWD,
- PWF_MASTER /* MASTER format with password */
-};
-
-struct pwf
-{
- int _altdir;
- void (*_setpwent)(void);
- void (*_endpwent)(void);
- struct passwd * (*_getpwent)(void);
- struct passwd * (*_getpwuid)(uid_t uid);
- struct passwd * (*_getpwnam)(const char * nam);
- int (*_pwdb)(char *arg, ...);
- RET_SETGRENT (*_setgrent)(void);
- void (*_endgrent)(void);
- struct group * (*_getgrent)(void);
- struct group * (*_getgrgid)(gid_t gid);
- struct group * (*_getgrnam)(const char * nam);
- int (*_grdb)(char *arg, ...);
-};
-
-extern struct pwf PWF;
-extern struct pwf VPWF;
-
-#define SETPWENT() PWF._setpwent()
-#define ENDPWENT() PWF._endpwent()
-#define GETPWENT() PWF._getpwent()
-#define GETPWUID(uid) PWF._getpwuid(uid)
-#define GETPWNAM(nam) PWF._getpwnam(nam)
-#define PWDB(args) PWF._pwdb(args)
-
-#define SETGRENT() PWF._setgrent()
-#define ENDGRENT() PWF._endgrent()
-#define GETGRENT() PWF._getgrent()
-#define GETGRGID(gid) PWF._getgrgid(gid)
-#define GETGRNAM(nam) PWF._getgrnam(nam)
-#define GRDB(args) PWF._grdb(args)
-
-#define PWALTDIR() PWF._altdir
-#ifndef _PATH_PWD
-#define _PATH_PWD "/etc"
-#endif
-#ifndef _GROUP
-#define _GROUP "group"
-#endif
-#ifndef _PASSWD
-#define _PASSWD "passwd"
-#endif
-#ifndef _MASTERPASSWD
-#define _MASTERPASSWD "master.passwd"
-#endif
-#ifndef _GROUP
-#define _GROUP "group"
-#endif
-
-__BEGIN_DECLS
-int addpwent(struct passwd * pwd);
-int delpwent(struct passwd * pwd);
-int chgpwent(char const * login, struct passwd * pwd);
-int fmtpwent(char *buf, struct passwd * pwd);
-int fmtpwentry(char *buf, struct passwd * pwd, int type);
-
-int setpwdir(const char * dir);
-char * getpwpath(char const * file);
-int pwdb(char *arg, ...);
-
-int addgrent(struct group * grp);
-int delgrent(struct group * grp);
-int chggrent(char const * name, struct group * grp);
-int fmtgrent(char **buf, int * buflen, struct group * grp);
-int fmtgrentry(char **buf, int * buflen, struct group * grp, int type);
-int editgroups(char *name, char **groups);
-
-int setgrdir(const char * dir);
-char * getgrpath(const char *file);
-int grdb(char *arg, ...);
-
-void vsetpwent(void);
-void vendpwent(void);
-struct passwd * vgetpwent(void);
-struct passwd * vgetpwuid(uid_t uid);
-struct passwd * vgetpwnam(const char * nam);
-struct passwd * vgetpwent(void);
-int vpwdb(char *arg, ...);
-
-struct group * vgetgrent(void);
-struct group * vgetgrgid(gid_t gid);
-struct group * vgetgrnam(const char * nam);
-struct group * vgetgrent(void);
-int vgrdb(char *arg, ...);
-RET_SETGRENT vsetgrent(void);
-void vendgrent(void);
-
-void copymkdir(char const * dir, char const * skel, mode_t mode, uid_t uid, gid_t gid);
-void rm_r(char const * dir, uid_t uid);
-int extendline(char **buf, int *buflen, int needed);
-int extendarray(char ***buf, int *buflen, int needed);
-__END_DECLS
-
-#define PWBUFSZ 1024
-
-#endif /* !_PWUPD_H */
diff --git a/pw/rm_r.c b/pw/rm_r.c
deleted file mode 100644
index 4ad590b..0000000
--- a/pw/rm_r.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*-
- * Copyright (C) 1996
- * David L. Nugent. All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <unistd.h>
-#include <dirent.h>
-
-#include "pwupd.h"
-
-void
-rm_r(char const * dir, uid_t uid)
-{
- DIR *d = opendir(dir);
-
- if (d != NULL) {
- struct dirent *e;
- struct stat st;
- char file[MAXPATHLEN];
-
- while ((e = readdir(d)) != NULL) {
- if (strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0) {
- sprintf(file, "%s/%s", dir, e->d_name);
- if (lstat(file, &st) == 0) { /* Need symlinks, not
- * linked file */
- if (S_ISDIR(st.st_mode)) /* Directory - recurse */
- rm_r(file, uid);
- else {
- if (S_ISLNK(st.st_mode) || st.st_uid == uid)
- remove(file);
- }
- }
- }
- }
- closedir(d);
- if (lstat(dir, &st) == 0) {
- if (S_ISLNK(st.st_mode))
- remove(dir);
- else if (st.st_uid == uid)
- rmdir(dir);
- }
- }
-}