diff options
| author | David E. O'Brien <obrien@FreeBSD.org> | 2013-02-08 16:10:16 +0000 |
|---|---|---|
| committer | David E. O'Brien <obrien@FreeBSD.org> | 2013-02-08 16:10:16 +0000 |
| commit | 17bc9031bfed577deb2722150179f4c8c11abfe2 (patch) | |
| tree | 9be766d6f5e109ffbe3ffdec25b319a8009cb1fb | |
| parent | 23a2b3b59c24cacf1622e3ffb1274c07aca04840 (diff) | |
| parent | 496692e30905aa38932d451f3324c659231b9e84 (diff) | |
| download | pw-darwin-17bc9031bfed577deb2722150179f4c8c11abfe2.tar.gz pw-darwin-17bc9031bfed577deb2722150179f4c8c11abfe2.zip | |
Sync with HEAD.
| -rw-r--r-- | chpass/chpass.c | 305 | ||||
| -rw-r--r-- | libutil/gr_util.c | 120 | ||||
| -rw-r--r-- | libutil/libutil.h | 2 | ||||
| -rw-r--r-- | libutil/pw_util.c | 7 | ||||
| -rw-r--r-- | pw/bitmap.c | 131 | ||||
| -rw-r--r-- | pw/grupd.c | 11 | ||||
| -rw-r--r-- | pw/pw_group.c | 5 | ||||
| -rw-r--r-- | pw/pw_log.c | 2 | ||||
| -rw-r--r-- | pw/pw_nis.c | 2 | ||||
| -rw-r--r-- | pw/pw_user.c | 29 | ||||
| -rw-r--r-- | pw/pw_vpw.c | 236 | ||||
| -rw-r--r-- | pw/pwupd.c | 16 | ||||
| -rw-r--r-- | pw/rm_r.c | 75 |
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; +} @@ -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 * @@ -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); + } + } +} |
