pw_util.c revision 302408
160484Sobrien/*-
289857Sobrien * Copyright (c) 1990, 1993, 1994
360484Sobrien *	The Regents of the University of California.  All rights reserved.
460484Sobrien *
560484Sobrien * Redistribution and use in source and binary forms, with or without
660484Sobrien * modification, are permitted provided that the following conditions
760484Sobrien * are met:
860484Sobrien * 1. Redistributions of source code must retain the above copyright
960484Sobrien *    notice, this list of conditions and the following disclaimer.
1060484Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1160484Sobrien *    notice, this list of conditions and the following disclaimer in the
1260484Sobrien *    documentation and/or other materials provided with the distribution.
1360484Sobrien * 3. All advertising materials mentioning features or use of this software
1460484Sobrien *    must display the following acknowledgement:
1560484Sobrien *	This product includes software developed by the University of
1660484Sobrien *	California, Berkeley and its contributors.
1760484Sobrien * 4. Neither the name of the University nor the names of its contributors
1860484Sobrien *    may be used to endorse or promote products derived from this software
1960484Sobrien *    without specific prior written permission.
2060484Sobrien *
2177298Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2260484Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2360484Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2460484Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2560484Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2660484Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2760484Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2860484Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2960484Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3060484Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3160484Sobrien * SUCH DAMAGE.
3260484Sobrien */
3360484Sobrien
3460484Sobrien#ifndef lint
3560484Sobrien#if 0
3660484Sobrienstatic const char sccsid[] = "@(#)pw_util.c	8.3 (Berkeley) 4/2/94";
3760484Sobrien#endif
3860484Sobrienstatic const char rcsid[] =
3960484Sobrien  "$FreeBSD: stable/11/release/picobsd/tinyware/passwd/pw_util.c 98514 2002-06-20 21:17:33Z luigi $";
4060484Sobrien#endif /* not lint */
4160484Sobrien
4260484Sobrien/*
4360484Sobrien * This file is used by all the "password" programs; vipw(8), chpass(1),
4460484Sobrien * and passwd(1).
4560484Sobrien */
4660484Sobrien
4760484Sobrien#include <sys/param.h>
4860484Sobrien#include <sys/errno.h>
4960484Sobrien#include <sys/time.h>
5077298Sobrien#include <sys/resource.h>
5160484Sobrien#include <sys/stat.h>
5277298Sobrien#include <sys/wait.h>
5360484Sobrien
5460484Sobrien#include <err.h>
5560484Sobrien#include <fcntl.h>
5660484Sobrien#include <paths.h>
5760484Sobrien#include <pwd.h>
5877298Sobrien#include <signal.h>
5989857Sobrien#include <stdio.h>
6060484Sobrien#include <stdlib.h>
6160484Sobrien#include <string.h>
6260484Sobrien#include <unistd.h>
6360484Sobrien
6460484Sobrien#include "pw_util.h"
6560484Sobrien
6660484Sobrienextern char *tempname;
6760484Sobrienstatic pid_t editpid = -1;
6860484Sobrienstatic int lockfd;
6960484Sobrienstatic char _default_editor[] = _PATH_VI;
7060484Sobrienstatic char _default_mppath[] = _PATH_PWD;
7160484Sobrienstatic char _default_masterpasswd[] = _PATH_MASTERPASSWD;
7260484Sobrienchar *mppath = _default_mppath;
7360484Sobrienchar *masterpasswd = _default_masterpasswd;
7460484Sobrien
7560484Sobrienvoid		 pw_cont(int);
7660484Sobrien
7760484Sobrienvoid
7860484Sobrienpw_cont(int sig)
7960484Sobrien{
8060484Sobrien
8160484Sobrien	if (editpid != -1)
8260484Sobrien		kill(editpid, sig);
8360484Sobrien}
8460484Sobrien
8589857Sobrienvoid
8689857Sobrienpw_init(void)
8789857Sobrien{
8889857Sobrien	struct rlimit rlim;
8989857Sobrien
9089857Sobrien	/* Unlimited resource limits. */
9189857Sobrien	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
9289857Sobrien	(void)setrlimit(RLIMIT_CPU, &rlim);
9389857Sobrien	(void)setrlimit(RLIMIT_FSIZE, &rlim);
9489857Sobrien	(void)setrlimit(RLIMIT_STACK, &rlim);
9589857Sobrien	(void)setrlimit(RLIMIT_DATA, &rlim);
9689857Sobrien	(void)setrlimit(RLIMIT_RSS, &rlim);
9789857Sobrien
9889857Sobrien	/* Don't drop core (not really necessary, but GP's). */
9989857Sobrien	rlim.rlim_cur = rlim.rlim_max = 0;
10089857Sobrien	(void)setrlimit(RLIMIT_CORE, &rlim);
10189857Sobrien
10289857Sobrien	/* Turn off signals. */
10389857Sobrien	(void)signal(SIGALRM, SIG_IGN);
10489857Sobrien	(void)signal(SIGHUP, SIG_IGN);
10589857Sobrien	(void)signal(SIGINT, SIG_IGN);
10689857Sobrien	(void)signal(SIGPIPE, SIG_IGN);
10789857Sobrien	(void)signal(SIGQUIT, SIG_IGN);
10889857Sobrien	(void)signal(SIGTERM, SIG_IGN);
10989857Sobrien	(void)signal(SIGCONT, pw_cont);
11089857Sobrien
11189857Sobrien	/* Create with exact permissions. */
11289857Sobrien	(void)umask(0);
11360484Sobrien}
11460484Sobrien
11560484Sobrienint
11660484Sobrienpw_lock(void)
11760484Sobrien{
11860484Sobrien	/*
11960484Sobrien	 * If the master password file doesn't exist, the system is hosed.
12060484Sobrien	 * Might as well try to build one.  Set the close-on-exec bit so
12160484Sobrien	 * that users can't get at the encrypted passwords while editing.
12260484Sobrien	 * Open should allow flock'ing the file; see 4.4BSD.	XXX
12360484Sobrien	 */
12460484Sobrien	for (;;) {
12560484Sobrien		struct stat st;
12660484Sobrien
12760484Sobrien		lockfd = open(masterpasswd, O_RDONLY, 0);
12860484Sobrien		if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
12960484Sobrien			err(1, "%s", masterpasswd);
13060484Sobrien		if (flock(lockfd, LOCK_EX|LOCK_NB))
13160484Sobrien			errx(1, "the password db file is busy");
13260484Sobrien
13360484Sobrien		/*
13460484Sobrien		 * If the password file was replaced while we were trying to
13560484Sobrien		 * get the lock, our hardlink count will be 0 and we have to
13660484Sobrien		 * close and retry.
13760484Sobrien		 */
13860484Sobrien		if (fstat(lockfd, &st) < 0)
13960484Sobrien			errx(1, "fstat() failed");
14060484Sobrien		if (st.st_nlink != 0)
14160484Sobrien			break;
14260484Sobrien		close(lockfd);
14360484Sobrien		lockfd = -1;
14460484Sobrien	}
14560484Sobrien	return (lockfd);
14660484Sobrien}
14760484Sobrien
14860484Sobrienint
14960484Sobrienpw_tmp(void)
15060484Sobrien{
15160484Sobrien	static char path[MAXPATHLEN];
15260484Sobrien	int fd;
15360484Sobrien	char *p;
15460484Sobrien
15560484Sobrien	strncpy(path, masterpasswd, MAXPATHLEN - 1);
15660484Sobrien	path[MAXPATHLEN] = '\0';
15760484Sobrien
15860484Sobrien	if ((p = strrchr(path, '/')))
15960484Sobrien		++p;
16060484Sobrien	else
16160484Sobrien		p = path;
16260484Sobrien	strcpy(p, "pw.XXXXXX");
16360484Sobrien	if ((fd = mkstemp(path)) == -1)
16460484Sobrien		err(1, "%s", path);
16560484Sobrien	tempname = path;
16660484Sobrien	return (fd);
16760484Sobrien}
16860484Sobrien
16960484Sobrienint
17060484Sobrienpw_mkdb(const char *username)
17160484Sobrien{
17260484Sobrien	int pstat;
17360484Sobrien	pid_t pid;
17460484Sobrien
17560484Sobrien	(void)fflush(stderr);
17660484Sobrien	if (!(pid = fork())) {
17760484Sobrien		if(!username) {
17860484Sobrien			warnx("rebuilding the database...");
17960484Sobrien			execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath,
18060484Sobrien			    tempname, (char *)NULL);
18160484Sobrien		} else {
18260484Sobrien			warnx("updating the database...");
18360484Sobrien			execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath,
18460484Sobrien			    "-u", username, tempname, (char *)NULL);
18560484Sobrien		}
18660484Sobrien		pw_error(_PATH_PWD_MKDB, 1, 1);
18760484Sobrien	}
18860484Sobrien	pid = waitpid(pid, &pstat, 0);
18960484Sobrien	if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
19060484Sobrien		return (0);
19160484Sobrien	warnx("done");
19260484Sobrien	return (1);
19360484Sobrien}
19460484Sobrien
19560484Sobrienvoid
19660484Sobrienpw_edit(int notsetuid)
19760484Sobrien{
19860484Sobrien	int pstat;
19960484Sobrien	char *p, *editor;
20077298Sobrien
20177298Sobrien	if (!(editor = getenv("EDITOR")))
20260484Sobrien		editor = _default_editor;
20360484Sobrien	if ((p = strrchr(editor, '/')))
20460484Sobrien		++p;
20560484Sobrien	else
20660484Sobrien		p = editor;
20760484Sobrien
20860484Sobrien	if (!(editpid = fork())) {
20960484Sobrien		if (notsetuid) {
21060484Sobrien			(void)setgid(getgid());
21160484Sobrien			(void)setuid(getuid());
21260484Sobrien		}
21360484Sobrien		errno = 0;
21460484Sobrien		execlp(editor, p, tempname, (char *)NULL);
21560484Sobrien		_exit(errno);
21660484Sobrien	}
21760484Sobrien	for (;;) {
21860484Sobrien		editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
21960484Sobrien		errno = WEXITSTATUS(pstat);
22060484Sobrien		if (editpid == -1)
22160484Sobrien			pw_error(editor, 1, 1);
22260484Sobrien		else if (WIFSTOPPED(pstat))
22360484Sobrien			raise(WSTOPSIG(pstat));
22460484Sobrien		else if (WIFEXITED(pstat) && errno == 0)
22560484Sobrien			break;
22689857Sobrien		else
22789857Sobrien			pw_error(editor, 1, 1);
22860484Sobrien	}
22960484Sobrien	editpid = -1;
23060484Sobrien}
23160484Sobrien
23260484Sobrienvoid
23360484Sobrienpw_prompt(void)
23460484Sobrien{
23560484Sobrien	int c, first;
23660484Sobrien
23760484Sobrien	(void)printf("re-edit the password file? [y]: ");
23860484Sobrien	(void)fflush(stdout);
23960484Sobrien	first = c = getchar();
24060484Sobrien	while (c != '\n' && c != EOF)
24160484Sobrien		c = getchar();
24260484Sobrien	if (first == 'n')
24360484Sobrien		pw_error(NULL, 0, 0);
24460484Sobrien}
24560484Sobrien
24660484Sobrienvoid
24789857Sobrienpw_error(const char *name, int error, int eval)
24889857Sobrien{
24989857Sobrien	if (error) {
25089857Sobrien		if (name != NULL)
25189857Sobrien			warn("%s", name);
25289857Sobrien		else
25360484Sobrien			warn(NULL);
25460484Sobrien	}
25560484Sobrien	warnx("password information unchanged");
25660484Sobrien	(void)unlink(tempname);
25760484Sobrien	exit(eval);
25860484Sobrien}
25960484Sobrien