summaryrefslogtreecommitdiffstats
path: root/libutil/pw_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'libutil/pw_util.c')
-rw-r--r--libutil/pw_util.c621
1 files changed, 0 insertions, 621 deletions
diff --git a/libutil/pw_util.c b/libutil/pw_util.c
deleted file mode 100644
index 75459e3..0000000
--- a/libutil/pw_util.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*-
- * Copyright (c) 1990, 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.
- * 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.
- */
-
-#ifndef lint
-#if 0
-static const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94";
-#endif
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-/*
- * This file is used by all the "password" programs; vipw(8), chpass(1),
- * and passwd(1).
- */
-
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <paths.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <libutil.h>
-
-static pid_t editpid = -1;
-static int lockfd = -1;
-static char masterpasswd[PATH_MAX];
-static char passwd_dir[PATH_MAX];
-static char tempname[PATH_MAX];
-static int initialized;
-
-#if 0
-void
-pw_cont(int sig)
-{
-
- if (editpid != -1)
- kill(editpid, sig);
-}
-#endif
-
-/*
- * Initialize statics and set limits, signals & umask to try to avoid
- * interruptions, crashes etc. that might expose passord data.
- */
-int
-pw_init(const char *dir, const char *master)
-{
-#if 0
- struct rlimit rlim;
-#endif
-
- if (dir == NULL) {
- strcpy(passwd_dir, _PATH_ETC);
- } else {
- if (strlen(dir) >= sizeof(passwd_dir)) {
- errno = ENAMETOOLONG;
- return (-1);
- }
- strcpy(passwd_dir, dir);
- }
-
- if (master == NULL) {
- if (dir == NULL) {
- strcpy(masterpasswd, _PATH_MASTERPASSWD);
- } else if (snprintf(masterpasswd, sizeof(masterpasswd), "%s/%s",
- passwd_dir, _MASTERPASSWD) > (int)sizeof(masterpasswd)) {
- errno = ENAMETOOLONG;
- return (-1);
- }
- } else {
- if (strlen(master) >= sizeof(masterpasswd)) {
- errno = ENAMETOOLONG;
- return (-1);
- }
- strcpy(masterpasswd, master);
- }
-
- /*
- * The code that follows is extremely disruptive to the calling
- * process, and is therefore disabled until someone can conceive
- * of a realistic scenario where it would fend off a compromise.
- * Race conditions concerning the temporary files can be guarded
- * against in other ways than masking signals (by checking stat(2)
- * results after creation).
- */
-#if 0
- /* Unlimited resource limits. */
- rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
- (void)setrlimit(RLIMIT_CPU, &rlim);
- (void)setrlimit(RLIMIT_FSIZE, &rlim);
- (void)setrlimit(RLIMIT_STACK, &rlim);
- (void)setrlimit(RLIMIT_DATA, &rlim);
- (void)setrlimit(RLIMIT_RSS, &rlim);
-
- /* Don't drop core (not really necessary, but GP's). */
- rlim.rlim_cur = rlim.rlim_max = 0;
- (void)setrlimit(RLIMIT_CORE, &rlim);
-
- /* Turn off signals. */
- (void)signal(SIGALRM, SIG_IGN);
- (void)signal(SIGHUP, SIG_IGN);
- (void)signal(SIGINT, SIG_IGN);
- (void)signal(SIGPIPE, SIG_IGN);
- (void)signal(SIGQUIT, SIG_IGN);
- (void)signal(SIGTERM, SIG_IGN);
- (void)signal(SIGCONT, pw_cont);
-
- /* Create with exact permissions. */
- (void)umask(0);
-#endif
- initialized = 1;
- return (0);
-}
-
-/*
- * Lock the master password file.
- */
-int
-pw_lock(void)
-{
-
- if (*masterpasswd == '\0')
- return (-1);
-
- /*
- * If the master password file doesn't exist, the system is hosed.
- * Might as well try to build one. Set the close-on-exec bit so
- * that users can't get at the encrypted passwords while editing.
- * Open should allow flock'ing the file; see 4.4BSD. XXX
- */
- 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) {
- if (errno == EWOULDBLOCK) {
- errx(1, "the password db file is busy");
- } else {
- err(1, "could not lock the passwd file: ");
- }
- }
-
- /*
- * If the password file was replaced while we were trying to
- * get the lock, our hardlink count will be 0 and we have to
- * close and retry.
- */
- if (fstat(lockfd, &st) == -1)
- err(1, "fstat() failed: ");
- if (st.st_nlink != 0)
- break;
- close(lockfd);
- lockfd = -1;
- }
- return (lockfd);
-}
-
-/*
- * Create and open a presumably safe temp file for editing the password
- * data, and copy the master password file into it.
- */
-int
-pw_tmp(int mfd)
-{
- char buf[8192];
- ssize_t nr;
- const char *p;
- int tfd;
-
- if (*masterpasswd == '\0')
- return (-1);
- if ((p = strrchr(masterpasswd, '/')))
- ++p;
- else
- p = masterpasswd;
- if (snprintf(tempname, sizeof(tempname), "%.*spw.XXXXXX",
- (int)(p - masterpasswd), masterpasswd) >= (int)sizeof(tempname)) {
- errno = ENAMETOOLONG;
- return (-1);
- }
- if ((tfd = mkstemp(tempname)) == -1)
- return (-1);
- if (mfd != -1) {
- while ((nr = read(mfd, buf, sizeof(buf))) > 0)
- if (write(tfd, buf, (size_t)nr) != nr)
- break;
- if (nr != 0) {
- unlink(tempname);
- *tempname = '\0';
- close(tfd);
- return (-1);
- }
- }
- return (tfd);
-}
-
-/*
- * Regenerate the password database.
- */
-int
-pw_mkdb(const char *user)
-{
- int pstat;
- pid_t pid;
-
- (void)fflush(stderr);
- switch ((pid = fork())) {
- case -1:
- return (-1);
- case 0:
- /* child */
- if (user == NULL)
- execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
- "-d", passwd_dir, tempname, (char *)NULL);
- else
- execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
- "-d", passwd_dir, "-u", user, tempname,
- (char *)NULL);
- _exit(1);
- /* NOTREACHED */
- default:
- /* parent */
- break;
- }
- if (waitpid(pid, &pstat, 0) == -1)
- return (-1);
- if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
- return (0);
- errno = 0;
- return (-1);
-}
-
-/*
- * Edit the temp file. Return -1 on error, >0 if the file was modified, 0
- * if it was not.
- */
-int
-pw_edit(int notsetuid)
-{
- struct sigaction sa, sa_int, sa_quit;
- sigset_t oldsigset, nsigset;
- struct stat st1, st2;
- const char *editor;
- int pstat;
-
- if ((editor = getenv("EDITOR")) == NULL)
- editor = _PATH_VI;
- if (stat(tempname, &st1) == -1)
- return (-1);
- sa.sa_handler = SIG_IGN;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sigaction(SIGINT, &sa, &sa_int);
- sigaction(SIGQUIT, &sa, &sa_quit);
- sigemptyset(&nsigset);
- sigaddset(&nsigset, SIGCHLD);
- sigprocmask(SIG_BLOCK, &nsigset, &oldsigset);
- switch ((editpid = fork())) {
- case -1:
- return (-1);
- case 0:
- sigaction(SIGINT, &sa_int, NULL);
- sigaction(SIGQUIT, &sa_quit, NULL);
- sigprocmask(SIG_SETMASK, &oldsigset, NULL);
- if (notsetuid) {
- (void)setgid(getgid());
- (void)setuid(getuid());
- }
- errno = 0;
- execlp(editor, basename(editor), tempname, (char *)NULL);
- _exit(errno);
- default:
- /* parent */
- break;
- }
- for (;;) {
- if (waitpid(editpid, &pstat, WUNTRACED) == -1) {
- if (errno == EINTR)
- continue;
- unlink(tempname);
- editpid = -1;
- break;
- } else if (WIFSTOPPED(pstat)) {
- raise(WSTOPSIG(pstat));
- } else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) {
- editpid = -1;
- break;
- } else {
- unlink(tempname);
- editpid = -1;
- break;
- }
- }
- sigaction(SIGINT, &sa_int, NULL);
- sigaction(SIGQUIT, &sa_quit, NULL);
- sigprocmask(SIG_SETMASK, &oldsigset, NULL);
- if (stat(tempname, &st2) == -1)
- return (-1);
- return (st1.st_mtime != st2.st_mtime);
-}
-
-/*
- * Clean up. Preserve errno for the caller's convenience.
- */
-void
-pw_fini(void)
-{
- int serrno, status;
-
- if (!initialized)
- return;
- initialized = 0;
- serrno = errno;
- if (editpid != -1) {
- kill(editpid, SIGTERM);
- kill(editpid, SIGCONT);
- waitpid(editpid, &status, 0);
- editpid = -1;
- }
- if (*tempname != '\0') {
- unlink(tempname);
- *tempname = '\0';
- }
- if (lockfd != -1)
- close(lockfd);
- errno = serrno;
-}
-
-/*
- * Compares two struct pwds.
- */
-int
-pw_equal(const struct passwd *pw1, const struct passwd *pw2)
-{
- return (strcmp(pw1->pw_name, pw2->pw_name) == 0 &&
- pw1->pw_uid == pw2->pw_uid &&
- pw1->pw_gid == pw2->pw_gid &&
- strcmp(pw1->pw_class, pw2->pw_class) == 0 &&
- pw1->pw_change == pw2->pw_change &&
- pw1->pw_expire == pw2->pw_expire &&
- strcmp(pw1->pw_gecos, pw2->pw_gecos) == 0 &&
- strcmp(pw1->pw_dir, pw2->pw_dir) == 0 &&
- strcmp(pw1->pw_shell, pw2->pw_shell) == 0);
-}
-
-/*
- * Make a passwd line out of a struct passwd.
- */
-char *
-pw_make(const struct passwd *pw)
-{
- char *line;
-
- asprintf(&line, "%s:%s:%ju:%ju:%s:%ju:%ju:%s:%s:%s", pw->pw_name,
- pw->pw_passwd, (uintmax_t)pw->pw_uid, (uintmax_t)pw->pw_gid,
- pw->pw_class, (uintmax_t)pw->pw_change, (uintmax_t)pw->pw_expire,
- pw->pw_gecos, pw->pw_dir, pw->pw_shell);
- return line;
-}
-
-/*
- * Copy password file from one descriptor to another, replacing or adding
- * a single record on the way.
- */
-int
-pw_copy(int ffd, int tfd, const struct passwd *pw, struct passwd *old_pw)
-{
- char buf[8192], *end, *line, *p, *q, *r, t;
- struct passwd *fpw;
- size_t len;
- int eof, readlen;
-
- if ((line = pw_make(pw)) == NULL)
- return (-1);
-
- eof = 0;
- len = 0;
- p = q = end = buf;
- for (;;) {
- /* find the end of the current line */
- for (p = q; q < end && *q != '\0'; ++q)
- if (*q == '\n')
- break;
-
- /* if we don't have a complete line, fill up the buffer */
- if (q >= end) {
- if (eof)
- break;
- if ((size_t)(q - p) >= sizeof(buf)) {
- warnx("passwd line too long");
- errno = EINVAL; /* hack */
- goto err;
- }
- if (p < end) {
- q = memmove(buf, p, end - p);
- end -= p - buf;
- } else {
- p = q = end = buf;
- }
- readlen = read(ffd, end, sizeof(buf) - (end - buf));
- if (readlen == -1)
- goto err;
- else
- len = (size_t)readlen;
- if (len == 0 && p == buf)
- break;
- end += len;
- len = end - buf;
- if (len < (ssize_t)sizeof(buf)) {
- eof = 1;
- if (len > 0 && buf[len - 1] != '\n')
- ++len, *end++ = '\n';
- }
- continue;
- }
-
- /* is it a blank line or a comment? */
- for (r = p; r < q && isspace(*r); ++r)
- /* nothing */ ;
- if (r == q || *r == '#') {
- /* yep */
- if (write(tfd, p, q - p + 1) != q - p + 1)
- goto err;
- ++q;
- continue;
- }
-
- /* is it the one we're looking for? */
-
- t = *q;
- *q = '\0';
-
- fpw = pw_scan(r, PWSCAN_MASTER);
-
- /*
- * fpw is either the struct passwd for the current line,
- * or NULL if the line is malformed.
- */
-
- *q = t;
- if (fpw == NULL || strcmp(fpw->pw_name, pw->pw_name) != 0) {
- /* nope */
- if (fpw != NULL)
- free(fpw);
- if (write(tfd, p, q - p + 1) != q - p + 1)
- goto err;
- ++q;
- continue;
- }
- if (old_pw && !pw_equal(fpw, old_pw)) {
- warnx("entry inconsistent");
- free(fpw);
- errno = EINVAL; /* hack */
- goto err;
- }
- free(fpw);
-
- /* it is, replace it */
- len = strlen(line);
- if (write(tfd, line, len) != (int)len)
- goto err;
-
- /* we're done, just copy the rest over */
- for (;;) {
- if (write(tfd, q, end - q) != end - q)
- goto err;
- q = buf;
- readlen = read(ffd, buf, sizeof(buf));
- if (readlen == 0)
- break;
- else
- len = (size_t)readlen;
- if (readlen == -1)
- goto err;
- end = buf + len;
- }
- goto done;
- }
-
- /* if we got here, we have a new entry */
- len = strlen(line);
- if ((size_t)write(tfd, line, len) != len ||
- write(tfd, "\n", 1) != 1)
- goto err;
- done:
- free(line);
- return (0);
- err:
- free(line);
- return (-1);
-}
-
-/*
- * Return the current value of tempname.
- */
-const char *
-pw_tempname(void)
-{
-
- return (tempname);
-}
-
-/*
- * Duplicate a struct passwd.
- */
-struct passwd *
-pw_dup(const struct passwd *pw)
-{
- struct passwd *npw;
- ssize_t len;
-
- len = sizeof(*npw) +
- (pw->pw_name ? strlen(pw->pw_name) + 1 : 0) +
- (pw->pw_passwd ? strlen(pw->pw_passwd) + 1 : 0) +
- (pw->pw_class ? strlen(pw->pw_class) + 1 : 0) +
- (pw->pw_gecos ? strlen(pw->pw_gecos) + 1 : 0) +
- (pw->pw_dir ? strlen(pw->pw_dir) + 1 : 0) +
- (pw->pw_shell ? strlen(pw->pw_shell) + 1 : 0);
- if ((npw = malloc((size_t)len)) == NULL)
- return (NULL);
- memcpy(npw, pw, sizeof(*npw));
- len = sizeof(*npw);
- if (pw->pw_name) {
- npw->pw_name = ((char *)npw) + len;
- len += sprintf(npw->pw_name, "%s", pw->pw_name) + 1;
- }
- if (pw->pw_passwd) {
- npw->pw_passwd = ((char *)npw) + len;
- len += sprintf(npw->pw_passwd, "%s", pw->pw_passwd) + 1;
- }
- if (pw->pw_class) {
- npw->pw_class = ((char *)npw) + len;
- len += sprintf(npw->pw_class, "%s", pw->pw_class) + 1;
- }
- if (pw->pw_gecos) {
- npw->pw_gecos = ((char *)npw) + len;
- len += sprintf(npw->pw_gecos, "%s", pw->pw_gecos) + 1;
- }
- if (pw->pw_dir) {
- npw->pw_dir = ((char *)npw) + len;
- len += sprintf(npw->pw_dir, "%s", pw->pw_dir) + 1;
- }
- if (pw->pw_shell) {
- npw->pw_shell = ((char *)npw) + len;
- len += sprintf(npw->pw_shell, "%s", pw->pw_shell) + 1;
- }
- return (npw);
-}
-
-#include "pw_scan.h"
-
-/*
- * Wrapper around an internal libc function
- */
-struct passwd *
-pw_scan(const char *line, int flags)
-{
- struct passwd pw, *ret;
- char *bp;
-
- if ((bp = strdup(line)) == NULL)
- return (NULL);
- if (!__pw_scan(bp, &pw, flags)) {
- free(bp);
- return (NULL);
- }
- ret = pw_dup(&pw);
- free(bp);
- return (ret);
-}