diff options
author | 1996-05-22 11:34:43 +0000 | |
---|---|---|
committer | 1996-05-22 11:34:43 +0000 | |
commit | 4b826ba8ef7118cfb0442afaa8b454015556f1ee (patch) | |
tree | 4ee6d433b487f8be05483a9299c0c2291d4782e6 /lib/libutil/passwd.c | |
parent | new vi (diff) | |
download | wireguard-openbsd-4b826ba8ef7118cfb0442afaa8b454015556f1ee.tar.xz wireguard-openbsd-4b826ba8ef7118cfb0442afaa8b454015556f1ee.zip |
libutil
Diffstat (limited to 'lib/libutil/passwd.c')
-rw-r--r-- | lib/libutil/passwd.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/lib/libutil/passwd.c b/lib/libutil/passwd.c new file mode 100644 index 00000000000..c473eca72dc --- /dev/null +++ b/lib/libutil/passwd.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 1987, 1993, 1994, 1995 + * The Regents of the University of California. 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. + * 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 defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$NetBSD: passwd.c,v 1.1 1996/05/15 21:42:31 jtc Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> + +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <pwd.h> +#include <errno.h> +#include <paths.h> +#include <signal.h> +#include <limits.h> +#include <util.h> + +static void pw_cont __P((int sig)); + +int +pw_lock(retries) + int retries; +{ + int i, fd; + mode_t old_mode; + + /* Acquire the lock file. */ + old_mode = umask(0); + fd = open(_PATH_MASTERPASSWD_LOCK, O_WRONLY|O_CREAT|O_EXCL, 0600); + for (i = 0; i < retries && fd < 0 && errno == EEXIST; i++) { + sleep(1); + fd = open(_PATH_MASTERPASSWD_LOCK, O_WRONLY|O_CREAT|O_EXCL, + 0600); + } + umask(old_mode); + return(fd); +} + +int +pw_mkdb() +{ + int pstat; + pid_t pid; + + pid = vfork(); + if (pid == 0) { + execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", + _PATH_MASTERPASSWD_LOCK, NULL); + exit(1); + } + pid = waitpid(pid, &pstat, 0); + if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) { + unlink(_PATH_MASTERPASSWD_LOCK); + return(-1); + } + return(0); +} + +int +pw_abort() +{ + return(unlink(_PATH_MASTERPASSWD_LOCK)); +} + +/* Everything below this point is intended for the convenience of programs + * which allow a user to interactively edit the passwd file. Errors in the + * routines below will cause the process to abort. */ + +static pid_t editpid = -1; + +static void +pw_cont(sig) + int sig; +{ + + if (editpid != -1) + kill(editpid, sig); +} + +void +pw_init() +{ + struct rlimit rlim; + + /* 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); +} + +void +pw_edit(notsetuid, filename) + int notsetuid; + const char *filename; +{ + int pstat; + char *p, *editor; + + if (!filename) + filename = _PATH_MASTERPASSWD_LOCK; + if (!(editor = getenv("EDITOR"))) + editor = _PATH_VI; + if (p = strrchr(editor, '/')) + ++p; + else + p = editor; + + if (!(editpid = vfork())) { + if (notsetuid) { + setgid(getgid()); + setuid(getuid()); + } + execlp(editor, p, filename, NULL); + _exit(1); + } + for (;;) { + editpid = waitpid(editpid, (int *)&pstat, WUNTRACED); + if (editpid == -1) + pw_error(editor, 1, 1); + else if (WIFSTOPPED(pstat)) + raise(WSTOPSIG(pstat)); + else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) + break; + else + pw_error(editor, 1, 1); + } + editpid = -1; +} + +void +pw_prompt() +{ + int c; + + (void)printf("re-edit the password file? [y]: "); + (void)fflush(stdout); + c = getchar(); + if (c != EOF && c != '\n') + while (getchar() != '\n'); + if (c == 'n') + pw_error(NULL, 0, 0); +} + +void +pw_copy(ffd, tfd, pw) + int ffd, tfd; + struct passwd *pw; +{ + FILE *from, *to; + int done; + char *p, buf[8192]; + + if (!(from = fdopen(ffd, "r"))) + pw_error(_PATH_MASTERPASSWD, 1, 1); + if (!(to = fdopen(tfd, "w"))) + pw_error(_PATH_MASTERPASSWD_LOCK, 1, 1); + + for (done = 0; fgets(buf, sizeof(buf), from);) { + if (!strchr(buf, '\n')) { + warnx("%s: line too long", _PATH_MASTERPASSWD); + pw_error(NULL, 0, 1); + } + if (done) { + (void)fprintf(to, "%s", buf); + if (ferror(to)) + goto err; + continue; + } + if (!(p = strchr(buf, ':'))) { + warnx("%s: corrupted entry", _PATH_MASTERPASSWD); + pw_error(NULL, 0, 1); + } + *p = '\0'; + if (strcmp(buf, pw->pw_name)) { + *p = ':'; + (void)fprintf(to, "%s", buf); + if (ferror(to)) + goto err; + continue; + } + (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", + pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, + pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos, + pw->pw_dir, pw->pw_shell); + done = 1; + if (ferror(to)) + goto err; + } + if (!done) + (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", + pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, + pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos, + pw->pw_dir, pw->pw_shell); + + if (ferror(to)) +err: pw_error(NULL, 1, 1); + (void)fclose(to); +} + +int +pw_scan(bp, pw, flags) + char *bp; + struct passwd *pw; + int *flags; +{ + long id; + int root; + char *p, *sh; + + if (flags != (int *)NULL) + *flags = 0; + + if (!(pw->pw_name = strsep(&bp, ":"))) /* login */ + goto fmt; + root = !strcmp(pw->pw_name, "root"); + + if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */ + goto fmt; + + if (!(p = strsep(&bp, ":"))) /* uid */ + goto fmt; + id = atol(p); + if (root && id) { + warnx("root uid should be 0"); + return (0); + } + if (id > USHRT_MAX) { + warnx("%s > max uid value (%d)", p, USHRT_MAX); + return (0); + } + pw->pw_uid = id; + if ((*p == '\0') && (flags != (int *)NULL)) + *flags |= _PASSWORD_NOUID; + + if (!(p = strsep(&bp, ":"))) /* gid */ + goto fmt; + id = atol(p); + if (id > USHRT_MAX) { + warnx("%s > max gid value (%d)", p, USHRT_MAX); + return (0); + } + pw->pw_gid = id; + if ((*p == '\0') && (flags != (int *)NULL)) + *flags |= _PASSWORD_NOGID; + + pw->pw_class = strsep(&bp, ":"); /* class */ + if (!(p = strsep(&bp, ":"))) /* change */ + goto fmt; + pw->pw_change = atol(p); + if ((*p == '\0') && (flags != (int *)NULL)) + *flags |= _PASSWORD_NOCHG; + if (!(p = strsep(&bp, ":"))) /* expire */ + goto fmt; + pw->pw_expire = atol(p); + if ((*p == '\0') && (flags != (int *)NULL)) + *flags |= _PASSWORD_NOEXP; + pw->pw_gecos = strsep(&bp, ":"); /* gecos */ + pw->pw_dir = strsep(&bp, ":"); /* directory */ + if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */ + goto fmt; + + p = pw->pw_shell; + if (root && *p) /* empty == /bin/sh */ + for (setusershell();;) { + if (!(sh = getusershell())) { + warnx("warning, unknown root shell"); + break; + } + if (!strcmp(p, sh)) + break; + } + + if (p = strsep(&bp, ":")) { /* too many */ +fmt: warnx("corrupted entry"); + return (0); + } + + return (1); +} + +void +pw_error(name, err, eval) + const char *name; + int err, eval; +{ + if (err) + warn(name); + + warnx("%s: unchanged", _PATH_MASTERPASSWD); + pw_abort(); + exit(eval); +} + |