summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid E. O'Brien <obrien@FreeBSD.org>2013-02-08 16:10:16 +0000
committerDavid E. O'Brien <obrien@FreeBSD.org>2013-02-08 16:10:16 +0000
commit17bc9031bfed577deb2722150179f4c8c11abfe2 (patch)
tree9be766d6f5e109ffbe3ffdec25b319a8009cb1fb
parent23a2b3b59c24cacf1622e3ffb1274c07aca04840 (diff)
parent496692e30905aa38932d451f3324c659231b9e84 (diff)
downloadpw-darwin-17bc9031bfed577deb2722150179f4c8c11abfe2.tar.gz
pw-darwin-17bc9031bfed577deb2722150179f4c8c11abfe2.zip
Sync with HEAD.
-rw-r--r--chpass/chpass.c305
-rw-r--r--libutil/gr_util.c120
-rw-r--r--libutil/libutil.h2
-rw-r--r--libutil/pw_util.c7
-rw-r--r--pw/bitmap.c131
-rw-r--r--pw/grupd.c11
-rw-r--r--pw/pw_group.c5
-rw-r--r--pw/pw_log.c2
-rw-r--r--pw/pw_nis.c2
-rw-r--r--pw/pw_user.c29
-rw-r--r--pw/pw_vpw.c236
-rw-r--r--pw/pwupd.c16
-rw-r--r--pw/rm_r.c75
13 files changed, 691 insertions, 250 deletions
diff --git a/chpass/chpass.c b/chpass/chpass.c
new file mode 100644
index 0000000..9f9be53
--- /dev/null
+++ b/chpass/chpass.c
@@ -0,0 +1,305 @@
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef YP
+#include <ypclnt.h>
+#endif
+
+#include <pw_scan.h>
+#include <libutil.h>
+
+#include "chpass.h"
+
+int master_mode;
+
+static void baduser(void);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op;
+ struct passwd lpw, *old_pw, *pw;
+ int ch, pfd, tfd;
+ const char *password;
+ char *arg = NULL;
+ uid_t uid;
+#ifdef YP
+ struct ypclnt *ypclnt;
+ const char *yp_domain = NULL, *yp_host = NULL;
+#endif
+
+ pw = old_pw = NULL;
+ op = EDITENTRY;
+#ifdef YP
+ while ((ch = getopt(argc, argv, "a:p:s:e:d:h:loy")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1)
+#endif
+ switch (ch) {
+ case 'a':
+ op = LOADENTRY;
+ arg = optarg;
+ break;
+ case 's':
+ op = NEWSH;
+ arg = optarg;
+ break;
+ case 'p':
+ op = NEWPW;
+ arg = optarg;
+ break;
+ case 'e':
+ op = NEWEXP;
+ arg = optarg;
+ break;
+#ifdef YP
+ case 'd':
+ yp_domain = optarg;
+ break;
+ case 'h':
+ yp_host = optarg;
+ break;
+ case 'l':
+ case 'o':
+ case 'y':
+ /* compatibility */
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1)
+ usage();
+
+ uid = getuid();
+
+ if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) {
+ if (argc == 0) {
+ if ((pw = getpwuid(uid)) == NULL)
+ errx(1, "unknown user: uid %lu",
+ (unsigned long)uid);
+ } else {
+ if ((pw = getpwnam(*argv)) == NULL)
+ errx(1, "unknown user: %s", *argv);
+ if (uid != 0 && uid != pw->pw_uid)
+ baduser();
+ }
+
+ /* Make a copy for later verification */
+ if ((pw = pw_dup(pw)) == NULL ||
+ (old_pw = pw_dup(pw)) == NULL)
+ err(1, "pw_dup");
+ }
+
+#ifdef YP
+ if (pw != NULL && (pw->pw_fields & _PWF_SOURCE) == _PWF_NIS) {
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
+ master_mode = (ypclnt != NULL &&
+ ypclnt_connect(ypclnt) != -1 &&
+ ypclnt_havepasswdd(ypclnt) == 1);
+ ypclnt_free(ypclnt);
+ } else
+#endif
+ master_mode = (uid == 0);
+
+ if (op == NEWSH) {
+ /* protect p_shell -- it thinks NULL is /bin/sh */
+ if (!arg[0])
+ usage();
+ if (p_shell(arg, pw, (ENTRY *)NULL) == -1)
+ exit(1);
+ }
+
+ if (op == NEWEXP) {
+ if (uid) /* only root can change expire */
+ baduser();
+ if (p_expire(arg, pw, (ENTRY *)NULL) == -1)
+ exit(1);
+ }
+
+ if (op == LOADENTRY) {
+ if (uid)
+ baduser();
+ pw = &lpw;
+ old_pw = NULL;
+ if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER))
+ exit(1);
+ }
+
+ if (op == NEWPW) {
+ if (uid)
+ baduser();
+
+ if (strchr(arg, ':'))
+ errx(1, "invalid format for password");
+ pw->pw_passwd = arg;
+ }
+
+ if (op == EDITENTRY) {
+ /*
+ * We don't really need pw_*() here, but pw_edit() (used
+ * by edit()) is just too useful...
+ */
+ if (pw_init(NULL, NULL))
+ err(1, "pw_init()");
+ if ((tfd = pw_tmp(-1)) == -1) {
+ pw_fini();
+ err(1, "pw_tmp()");
+ }
+ free(pw);
+ pw = edit(pw_tempname(), old_pw);
+ pw_fini();
+ if (pw == NULL)
+ err(1, "edit()");
+ /*
+ * pw_equal does not check for crypted passwords, so we
+ * should do it explicitly
+ */
+ if (pw_equal(old_pw, pw) &&
+ strcmp(old_pw->pw_passwd, pw->pw_passwd) == 0)
+ errx(0, "user information unchanged");
+ }
+
+ if (old_pw && !master_mode) {
+ password = getpass("Password: ");
+ if (strcmp(crypt(password, old_pw->pw_passwd),
+ old_pw->pw_passwd) != 0)
+ baduser();
+ } else {
+ password = "";
+ }
+
+ if (old_pw != NULL)
+ pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE);
+ switch (pw->pw_fields & _PWF_SOURCE) {
+#ifdef YP
+ case _PWF_NIS:
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
+ if (ypclnt == NULL) {
+ warnx("ypclnt_new failed");
+ exit(1);
+ }
+ if (ypclnt_connect(ypclnt) == -1 ||
+ ypclnt_passwd(ypclnt, pw, password) == -1) {
+ warnx("%s", ypclnt->error);
+ ypclnt_free(ypclnt);
+ exit(1);
+ }
+ ypclnt_free(ypclnt);
+ errx(0, "NIS user information updated");
+#endif /* YP */
+ case 0:
+ case _PWF_FILES:
+ if (pw_init(NULL, NULL))
+ err(1, "pw_init()");
+ if ((pfd = pw_lock()) == -1) {
+ pw_fini();
+ err(1, "pw_lock()");
+ }
+ if ((tfd = pw_tmp(-1)) == -1) {
+ pw_fini();
+ err(1, "pw_tmp()");
+ }
+ if (pw_copy(pfd, tfd, pw, old_pw) == -1) {
+ pw_fini();
+ err(1, "pw_copy");
+ }
+ if (pw_mkdb(pw->pw_name) == -1) {
+ pw_fini();
+ err(1, "pw_mkdb()");
+ }
+ pw_fini();
+ errx(0, "user information updated");
+ break;
+ default:
+ errx(1, "unsupported passwd source");
+ }
+}
+
+static void
+baduser(void)
+{
+
+ errx(1, "%s", strerror(EACCES));
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: chpass%s %s [user]\n",
+#ifdef YP
+ " [-d domain] [-h host]",
+#else
+ "",
+#endif
+ "[-a list] [-p encpass] [-s shell] [-e mmm dd yy]");
+ exit(1);
+}
diff --git a/libutil/gr_util.c b/libutil/gr_util.c
index 6d96d5e..3f7e199 100644
--- a/libutil/gr_util.c
+++ b/libutil/gr_util.c
@@ -44,19 +44,12 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
-struct group_storage {
- struct group gr;
- char *members[];
-};
-
static int lockfd = -1;
static char group_dir[PATH_MAX];
static char group_file[PATH_MAX];
static char tempname[PATH_MAX];
static int initialized;
-static const char group_line_format[] = "%s:%s:%ju:";
-
/*
* Initialize statics
*/
@@ -106,10 +99,8 @@ gr_lock(void)
for (;;) {
struct stat st;
- lockfd = open(group_file, O_RDONLY, 0);
- if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
- err(1, "%s", group_file);
- if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
+ lockfd = flopen(group_file, O_RDONLY|O_NONBLOCK|O_CLOEXEC, 0);
+ if (lockfd == -1) {
if (errno == EWOULDBLOCK) {
errx(1, "the group file is busy");
} else {
@@ -318,11 +309,14 @@ gr_copy(int ffd, int tfd, const struct group *gr, struct group *old_gr)
int
gr_mkdb(void)
{
+ if (chmod(tempname, 0644) != 0)
+ return (-1);
+
return (rename(tempname, group_file));
}
/*
- * Clean up. Preserver errno for the caller's convenience.
+ * Clean up. Preserves errno for the caller's convenience.
*/
void
gr_fini(void)
@@ -350,7 +344,6 @@ gr_equal(const struct group *gr1, const struct group *gr2)
{
int gr1_ndx;
int gr2_ndx;
- bool found;
/* Check that the non-member information is the same. */
if (gr1->gr_name == NULL || gr2->gr_name == NULL) {
@@ -371,17 +364,15 @@ gr_equal(const struct group *gr1, const struct group *gr2)
if (gr1->gr_mem != gr2->gr_mem)
return (false);
} else {
- for (found = false, gr1_ndx = 0; gr1->gr_mem[gr1_ndx] != NULL;
- gr1_ndx++) {
- for (gr2_ndx = 0; gr2->gr_mem[gr2_ndx] != NULL;
- gr2_ndx++)
+ for (gr1_ndx = 0; gr1->gr_mem[gr1_ndx] != NULL; gr1_ndx++) {
+ for (gr2_ndx = 0;; gr2_ndx++) {
+ if (gr2->gr_mem[gr2_ndx] == NULL)
+ return (false);
if (strcmp(gr1->gr_mem[gr1_ndx],
gr2->gr_mem[gr2_ndx]) == 0) {
- found = true;
break;
}
- if (!found)
- return (false);
+ }
}
/* Check that group2 does not have more members than group1. */
@@ -398,7 +389,10 @@ gr_equal(const struct group *gr1, const struct group *gr2)
char *
gr_make(const struct group *gr)
{
+ const char *group_line_format = "%s:%s:%ju:";
+ const char *sep;
char *line;
+ char *p;
size_t line_size;
int ndx;
@@ -413,16 +407,18 @@ gr_make(const struct group *gr)
}
/* Create the group line and fill it. */
- if ((line = malloc(line_size)) == NULL)
+ if ((line = p = malloc(line_size)) == NULL)
return (NULL);
- snprintf(line, line_size, group_line_format, gr->gr_name, gr->gr_passwd,
+ p += sprintf(p, group_line_format, gr->gr_name, gr->gr_passwd,
(uintmax_t)gr->gr_gid);
- if (gr->gr_mem != NULL)
+ if (gr->gr_mem != NULL) {
+ sep = "";
for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) {
- strcat(line, gr->gr_mem[ndx]);
- if (gr->gr_mem[ndx + 1] != NULL)
- strcat(line, ",");
+ p = stpcpy(p, sep);
+ p = stpcpy(p, gr->gr_mem[ndx]);
+ sep = ",";
}
+ }
return (line);
}
@@ -433,14 +429,14 @@ gr_make(const struct group *gr)
struct group *
gr_dup(const struct group *gr)
{
+ struct group *newgr;
char *dst;
size_t len;
- struct group_storage *gs;
int ndx;
int num_mem;
/* Calculate size of the group. */
- len = sizeof(*gs);
+ len = sizeof(*newgr);
if (gr->gr_name != NULL)
len += strlen(gr->gr_name) + 1;
if (gr->gr_passwd != NULL)
@@ -451,30 +447,72 @@ gr_dup(const struct group *gr)
len += (num_mem + 1) * sizeof(*gr->gr_mem);
} else
num_mem = -1;
-
/* Create new group and copy old group into it. */
- if ((gs = calloc(1, len)) == NULL)
+ if ((newgr = malloc(len)) == NULL)
return (NULL);
- dst = (char *)&gs->members[num_mem + 1];
+ /* point new gr_mem to end of struct + 1 */
+ if (gr->gr_mem != NULL)
+ newgr->gr_mem = (char **)(newgr + 1);
+ else
+ newgr->gr_mem = NULL;
+ /* point dst after the end of all the gr_mem pointers in newgr */
+ dst = (char *)&newgr->gr_mem[num_mem + 1];
if (gr->gr_name != NULL) {
- gs->gr.gr_name = dst;
- dst = stpcpy(gs->gr.gr_name, gr->gr_name) + 1;
+ newgr->gr_name = dst;
+ dst = stpcpy(dst, gr->gr_name) + 1;
+ } else {
+ newgr->gr_name = NULL;
}
if (gr->gr_passwd != NULL) {
- gs->gr.gr_passwd = dst;
- dst = stpcpy(gs->gr.gr_passwd, gr->gr_passwd) + 1;
+ newgr->gr_passwd = dst;
+ dst = stpcpy(dst, gr->gr_passwd) + 1;
+ } else {
+ newgr->gr_passwd = NULL;
}
- gs->gr.gr_gid = gr->gr_gid;
+ newgr->gr_gid = gr->gr_gid;
if (gr->gr_mem != NULL) {
- gs->gr.gr_mem = gs->members;
for (ndx = 0; ndx < num_mem; ndx++) {
- gs->gr.gr_mem[ndx] = dst;
- dst = stpcpy(gs->gr.gr_mem[ndx], gr->gr_mem[ndx]) + 1;
+ newgr->gr_mem[ndx] = dst;
+ dst = stpcpy(dst, gr->gr_mem[ndx]) + 1;
}
- gs->gr.gr_mem[ndx] = NULL;
+ newgr->gr_mem[ndx] = NULL;
}
+ return (newgr);
+}
+
+/*
+ * Add a new member name to a struct group.
+ */
+struct group *
+gr_add(struct group *gr, char *newmember)
+{
+ size_t mlen;
+ int num_mem=0;
+ char **members;
+ struct group *newgr;
- return (&gs->gr);
+ if (newmember == NULL)
+ return(gr_dup(gr));
+
+ if (gr->gr_mem != NULL) {
+ for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++) {
+ if (strcmp(gr->gr_mem[num_mem], newmember) == 0) {
+ errno = EEXIST;
+ return (NULL);
+ }
+ }
+ }
+ /* Allocate enough for current pointers + 1 more and NULL marker */
+ mlen = (num_mem + 2) * sizeof(*gr->gr_mem);
+ if ((members = malloc(mlen)) == NULL)
+ return (NULL);
+ memcpy(members, gr->gr_mem, num_mem * sizeof(*gr->gr_mem));
+ members[num_mem++] = newmember;
+ members[num_mem] = NULL;
+ gr->gr_mem = members;
+ newgr = gr_dup(gr);
+ free(members);
+ return (newgr);
}
/*
diff --git a/libutil/libutil.h b/libutil/libutil.h
index bf42766..b1b2405 100644
--- a/libutil/libutil.h
+++ b/libutil/libutil.h
@@ -166,6 +166,8 @@ int gr_copy(int __ffd, int _tfd, const struct group *_gr,
struct group *_old_gr);
struct group *
gr_dup(const struct group *_gr);
+struct group *
+ gr_add(struct group *_gr, char *_newmember);
int gr_equal(const struct group *_gr1, const struct group *_gr2);
void gr_fini(void);
int gr_init(const char *_dir, const char *_master);
diff --git a/libutil/pw_util.c b/libutil/pw_util.c
index 4bf3001..befd1fb 100644
--- a/libutil/pw_util.c
+++ b/libutil/pw_util.c
@@ -179,11 +179,8 @@ pw_lock(void)
for (;;) {
struct stat st;
- lockfd = open(masterpasswd, O_RDONLY, 0);
- if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
- err(1, "%s", masterpasswd);
- /* XXX vulnerable to race conditions */
- if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
+ lockfd = flopen(masterpasswd, O_RDONLY|O_NONBLOCK|O_CLOEXEC, 0);
+ if (lockfd == -1) {
if (errno == EWOULDBLOCK) {
errx(1, "the password db file is busy");
} else {
diff --git a/pw/bitmap.c b/pw/bitmap.c
new file mode 100644
index 0000000..8e96bff
--- /dev/null
+++ b/pw/bitmap.c
@@ -0,0 +1,131 @@
+/*-
+ * 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)
+{
+ 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/grupd.c b/pw/grupd.c
index e9f6b5e..3f78e95 100644
--- a/pw/grupd.c
+++ b/pw/grupd.c
@@ -50,12 +50,11 @@ 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);
- }
+ else
+ grpath = strdup(dir);
+ if (grpath == NULL)
+ return -1;
+
return 0;
}
diff --git a/pw/pw_group.c b/pw/pw_group.c
index f4f2116..3259412 100644
--- a/pw/pw_group.c
+++ b/pw/pw_group.c
@@ -274,8 +274,7 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
pw_log(cnf, mode, W_GROUP, "%s(%ld)", grp->gr_name, (long) grp->gr_gid);
- if (members)
- free(members);
+ free(members);
return EXIT_SUCCESS;
}
@@ -408,7 +407,7 @@ print_group(struct group * grp, int pretty)
char *buf = NULL;
buf = gr_make(grp);
- fputs(buf, stdout);
+ printf("%s\n", buf);
free(buf);
} else {
int i;
diff --git a/pw/pw_log.c b/pw/pw_log.c
index f16274f..b774423 100644
--- a/pw/pw_log.c
+++ b/pw/pw_log.c
@@ -47,7 +47,6 @@ pw_log(struct userconf * cnf, int mode, int which, char const * fmt,...)
}
if (logfile != NULL) {
va_list argp;
- int l;
time_t now = time(NULL);
struct tm *t = localtime(&now);
char nfmt[256];
@@ -57,7 +56,6 @@ pw_log(struct userconf * cnf, int mode, int which, char const * fmt,...)
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);
diff --git a/pw/pw_nis.c b/pw/pw_nis.c
index af5901a..918fc30 100644
--- a/pw/pw_nis.c
+++ b/pw/pw_nis.c
@@ -66,6 +66,8 @@ pw_nisupdate(const char * path, struct passwd * pwd, char const * user)
pw_fini();
err(1, "pw_copy()");
}
+ if (chmod(pw_tempname(), 0644) == -1)
+ err(1, "chmod()");
if (rename(pw_tempname(), path) == -1)
err(1, "rename()");
diff --git a/pw/pw_user.c b/pw/pw_user.c
index abf1c35..5f4d7a9 100644
--- a/pw/pw_user.c
+++ b/pw/pw_user.c
@@ -394,7 +394,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
/*
* Remove crontabs
*/
- sprintf(file, "/var/cron/tabs/%s", pwd->pw_name);
+ snprintf(file, sizeof(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);
@@ -425,7 +425,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
}
grp = GETGRNAM(a_name->val);
- if (*grp->gr_mem == NULL)
+ if (grp != NULL && *grp->gr_mem == NULL)
delgrent(GETGRNAM(a_name->val));
SETGRENT();
while ((grp = GETGRENT()) != NULL) {
@@ -745,25 +745,20 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
*/
if (mode == M_ADD || getarg(args, 'G') != NULL) {
- int i, j;
+ int i;
for (i = 0; cnf->groups[i] != NULL; i++) {
grp = GETGRNAM(cnf->groups[i]);
- for (j = 0; grp->gr_mem[j] != NULL; j++) {
- if (!strcmp(grp->gr_mem[j], pwd->pw_name))
- break;
- }
- if (grp->gr_mem[j] != NULL) /* user already member of group */
+ grp = gr_add(grp, pwd->pw_name);
+ /*
+ * grp can only be NULL in 2 cases:
+ * - the new member is already a member
+ * - a problem with memory occurs
+ * in both cases we want to skip now.
+ */
+ if (grp == NULL)
continue;
-
- if (j == 0)
- grp->gr_mem = NULL;
-
- grp->gr_mem = reallocf(grp->gr_mem, sizeof(*grp->gr_mem) *
- (j + 2));
-
- grp->gr_mem[j] = pwd->pw_name;
- grp->gr_mem[j+1] = NULL;
chggrent(cnf->groups[i], grp);
+ free(grp);
}
}
diff --git a/pw/pw_vpw.c b/pw/pw_vpw.c
index 674b64f..99663be 100644
--- a/pw/pw_vpw.c
+++ b/pw/pw_vpw.c
@@ -30,6 +30,10 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
+#include <pwd.h>
+#include <grp.h>
+#include <libutil.h>
+#define _WITH_GETLINE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -55,101 +59,44 @@ vsetpwent(void)
}
static struct passwd *
-vnextpwent(char const * nam, uid_t uid, int doclose)
+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 == '#')
+ struct passwd *pw;
+ char *line;
+ size_t linecap;
+ ssize_t linelen;
+
+ pw = NULL;
+ line = NULL;
+ linecap = 0;
+ linelen = 0;
+
+ if (pwd_fp != NULL || (pwd_fp = fopen(getpwpath(_MASTERPASSWD), "r")) != NULL) {
+ while ((linelen = getline(&line, &linecap, pwd_fp)) > 0) {
+ /* Skip comments and empty lines */
+ if (*line == '\n' || *line == '#')
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;
- }
- }
- }
+ /* trim latest \n */
+ if (line[linelen - 1 ] == '\n')
+ line[linelen - 1] = '\0';
+ pw = pw_scan(line, PWSCAN_MASTER);
+ if (uid != (uid_t)-1) {
+ if (uid == pw->pw_uid)
+ break;
+ } else if (nam != NULL) {
+ if (strcmp(nam, pw->pw_name) == 0)
+ break;
+ } else
+ break;
+ free(pw);
+ pw = NULL;
+ }
if (doclose)
vendpwent();
- if (done && pwd.pw_name) {
- pw = &pwd;
+ }
+ free(line);
- #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;
+ return (pw);
}
struct passwd *
@@ -192,93 +139,44 @@ vsetgrent(void)
}
static struct group *
-vnextgrent(char const * nam, gid_t gid, int doclose)
+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;
- const 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 */
- }
+ struct group *gr;
+ char *line;
+ size_t linecap;
+ ssize_t linelen;
+
+ gr = NULL;
+ line = NULL;
+ linecap = 0;
+ linelen = 0;
+
+ if (grp_fp != NULL || (grp_fp = fopen(getgrpath(_GROUP), "r")) != NULL) {
+ while ((linelen = getline(&line, &linecap, grp_fp)) > 0) {
/* Skip comments and empty lines */
- if (*grtmp == '\n' || *grtmp == '#')
+ if (*line == '\n' || *line == '#')
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;
+ /* trim latest \n */
+ if (line[linelen - 1 ] == '\n')
+ line[linelen - 1] = '\0';
+ gr = gr_scan(line);
+ if (gid != (gid_t)-1) {
+ if (gid == gr->gr_gid)
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;
+ } else if (nam != NULL) {
+ if (strcmp(nam, gr->gr_name) == 0)
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;
- }
+ } else
+ break;
+ free(gr);
+ gr = NULL;
+ }
if (doclose)
vendgrent();
- if (done && grp.gr_name) {
- gr = &grp;
-
- CKNULL(grp.gr_passwd);
- }
}
- return gr;
+ free(line);
+
+ return (gr);
}
struct group *
diff --git a/pw/pwupd.c b/pw/pwupd.c
index 4ab0f01..22662db 100644
--- a/pw/pwupd.c
+++ b/pw/pwupd.c
@@ -56,12 +56,10 @@ 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);
- }
+ else
+ pwpath = strdup(dir);
+ if (pwpath == NULL)
+ return -1;
return 0;
}
@@ -148,7 +146,11 @@ pw_update(struct passwd * pwd, char const * user)
pw_fini();
err(1, "pw_copy()");
}
- if (pw_mkdb(user) == -1) {
+ /*
+ * in case of deletion of a user, the whole database
+ * needs to be regenerated
+ */
+ if (pw_mkdb(pw != NULL ? user : NULL) == -1) {
pw_fini();
err(1, "pw_mkdb()");
}
diff --git a/pw/rm_r.c b/pw/rm_r.c
new file mode 100644
index 0000000..797ca9d
--- /dev/null
+++ b/pw/rm_r.c
@@ -0,0 +1,75 @@
+/*-
+ * 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) {
+ snprintf(file, sizeof(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);
+ }
+ }
+}