198514Sluigi/*-
298514Sluigi * Copyright (c) 1990, 1993, 1994
398514Sluigi *	The Regents of the University of California.  All rights reserved.
498514Sluigi *
598514Sluigi * Redistribution and use in source and binary forms, with or without
698514Sluigi * modification, are permitted provided that the following conditions
798514Sluigi * are met:
898514Sluigi * 1. Redistributions of source code must retain the above copyright
998514Sluigi *    notice, this list of conditions and the following disclaimer.
1098514Sluigi * 2. Redistributions in binary form must reproduce the above copyright
1198514Sluigi *    notice, this list of conditions and the following disclaimer in the
1298514Sluigi *    documentation and/or other materials provided with the distribution.
1398514Sluigi * 3. All advertising materials mentioning features or use of this software
1498514Sluigi *    must display the following acknowledgement:
1598514Sluigi *	This product includes software developed by the University of
1698514Sluigi *	California, Berkeley and its contributors.
1798514Sluigi * 4. Neither the name of the University nor the names of its contributors
1898514Sluigi *    may be used to endorse or promote products derived from this software
1998514Sluigi *    without specific prior written permission.
2098514Sluigi *
2198514Sluigi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2298514Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2398514Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2498514Sluigi * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2598514Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2698514Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2798514Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2898514Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2998514Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3098514Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3198514Sluigi * SUCH DAMAGE.
3298514Sluigi */
3398514Sluigi
3498514Sluigi#ifndef lint
3598514Sluigi#if 0
3698514Sluigistatic const char sccsid[] = "@(#)pw_util.c	8.3 (Berkeley) 4/2/94";
3798514Sluigi#endif
3898514Sluigistatic const char rcsid[] =
3998514Sluigi  "$FreeBSD$";
4098514Sluigi#endif /* not lint */
4198514Sluigi
4298514Sluigi/*
4398514Sluigi * This file is used by all the "password" programs; vipw(8), chpass(1),
4498514Sluigi * and passwd(1).
4598514Sluigi */
4698514Sluigi
4798514Sluigi#include <sys/param.h>
4898514Sluigi#include <sys/errno.h>
4998514Sluigi#include <sys/time.h>
5098514Sluigi#include <sys/resource.h>
5198514Sluigi#include <sys/stat.h>
5298514Sluigi#include <sys/wait.h>
5398514Sluigi
5498514Sluigi#include <err.h>
5598514Sluigi#include <fcntl.h>
5698514Sluigi#include <paths.h>
5798514Sluigi#include <pwd.h>
5898514Sluigi#include <signal.h>
5998514Sluigi#include <stdio.h>
6098514Sluigi#include <stdlib.h>
6198514Sluigi#include <string.h>
6298514Sluigi#include <unistd.h>
6398514Sluigi
6498514Sluigi#include "pw_util.h"
6598514Sluigi
6698514Sluigiextern char *tempname;
6798514Sluigistatic pid_t editpid = -1;
6898514Sluigistatic int lockfd;
6998514Sluigistatic char _default_editor[] = _PATH_VI;
7098514Sluigistatic char _default_mppath[] = _PATH_PWD;
7198514Sluigistatic char _default_masterpasswd[] = _PATH_MASTERPASSWD;
7298514Sluigichar *mppath = _default_mppath;
7398514Sluigichar *masterpasswd = _default_masterpasswd;
7498514Sluigi
7598514Sluigivoid		 pw_cont(int);
7698514Sluigi
7798514Sluigivoid
7898514Sluigipw_cont(int sig)
7998514Sluigi{
8098514Sluigi
8198514Sluigi	if (editpid != -1)
8298514Sluigi		kill(editpid, sig);
8398514Sluigi}
8498514Sluigi
8598514Sluigivoid
8698514Sluigipw_init(void)
8798514Sluigi{
8898514Sluigi	struct rlimit rlim;
8998514Sluigi
9098514Sluigi	/* Unlimited resource limits. */
9198514Sluigi	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
9298514Sluigi	(void)setrlimit(RLIMIT_CPU, &rlim);
9398514Sluigi	(void)setrlimit(RLIMIT_FSIZE, &rlim);
9498514Sluigi	(void)setrlimit(RLIMIT_STACK, &rlim);
9598514Sluigi	(void)setrlimit(RLIMIT_DATA, &rlim);
9698514Sluigi	(void)setrlimit(RLIMIT_RSS, &rlim);
9798514Sluigi
9898514Sluigi	/* Don't drop core (not really necessary, but GP's). */
9998514Sluigi	rlim.rlim_cur = rlim.rlim_max = 0;
10098514Sluigi	(void)setrlimit(RLIMIT_CORE, &rlim);
10198514Sluigi
10298514Sluigi	/* Turn off signals. */
10398514Sluigi	(void)signal(SIGALRM, SIG_IGN);
10498514Sluigi	(void)signal(SIGHUP, SIG_IGN);
10598514Sluigi	(void)signal(SIGINT, SIG_IGN);
10698514Sluigi	(void)signal(SIGPIPE, SIG_IGN);
10798514Sluigi	(void)signal(SIGQUIT, SIG_IGN);
10898514Sluigi	(void)signal(SIGTERM, SIG_IGN);
10998514Sluigi	(void)signal(SIGCONT, pw_cont);
11098514Sluigi
11198514Sluigi	/* Create with exact permissions. */
11298514Sluigi	(void)umask(0);
11398514Sluigi}
11498514Sluigi
11598514Sluigiint
11698514Sluigipw_lock(void)
11798514Sluigi{
11898514Sluigi	/*
11998514Sluigi	 * If the master password file doesn't exist, the system is hosed.
12098514Sluigi	 * Might as well try to build one.  Set the close-on-exec bit so
12198514Sluigi	 * that users can't get at the encrypted passwords while editing.
12298514Sluigi	 * Open should allow flock'ing the file; see 4.4BSD.	XXX
12398514Sluigi	 */
12498514Sluigi	for (;;) {
12598514Sluigi		struct stat st;
12698514Sluigi
12798514Sluigi		lockfd = open(masterpasswd, O_RDONLY, 0);
12898514Sluigi		if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
12998514Sluigi			err(1, "%s", masterpasswd);
13098514Sluigi		if (flock(lockfd, LOCK_EX|LOCK_NB))
13198514Sluigi			errx(1, "the password db file is busy");
13298514Sluigi
13398514Sluigi		/*
13498514Sluigi		 * If the password file was replaced while we were trying to
13598514Sluigi		 * get the lock, our hardlink count will be 0 and we have to
13698514Sluigi		 * close and retry.
13798514Sluigi		 */
13898514Sluigi		if (fstat(lockfd, &st) < 0)
13998514Sluigi			errx(1, "fstat() failed");
14098514Sluigi		if (st.st_nlink != 0)
14198514Sluigi			break;
14298514Sluigi		close(lockfd);
14398514Sluigi		lockfd = -1;
14498514Sluigi	}
14598514Sluigi	return (lockfd);
14698514Sluigi}
14798514Sluigi
14898514Sluigiint
14998514Sluigipw_tmp(void)
15098514Sluigi{
15198514Sluigi	static char path[MAXPATHLEN];
15298514Sluigi	int fd;
15398514Sluigi	char *p;
15498514Sluigi
15598514Sluigi	strncpy(path, masterpasswd, MAXPATHLEN - 1);
15698514Sluigi	path[MAXPATHLEN] = '\0';
15798514Sluigi
15898514Sluigi	if ((p = strrchr(path, '/')))
15998514Sluigi		++p;
16098514Sluigi	else
16198514Sluigi		p = path;
16298514Sluigi	strcpy(p, "pw.XXXXXX");
16398514Sluigi	if ((fd = mkstemp(path)) == -1)
16498514Sluigi		err(1, "%s", path);
16598514Sluigi	tempname = path;
16698514Sluigi	return (fd);
16798514Sluigi}
16898514Sluigi
16998514Sluigiint
17098514Sluigipw_mkdb(const char *username)
17198514Sluigi{
17298514Sluigi	int pstat;
17398514Sluigi	pid_t pid;
17498514Sluigi
17598514Sluigi	(void)fflush(stderr);
17698514Sluigi	if (!(pid = fork())) {
17798514Sluigi		if(!username) {
17898514Sluigi			warnx("rebuilding the database...");
17998514Sluigi			execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath,
18098514Sluigi			    tempname, (char *)NULL);
18198514Sluigi		} else {
18298514Sluigi			warnx("updating the database...");
18398514Sluigi			execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath,
18498514Sluigi			    "-u", username, tempname, (char *)NULL);
18598514Sluigi		}
18698514Sluigi		pw_error(_PATH_PWD_MKDB, 1, 1);
18798514Sluigi	}
18898514Sluigi	pid = waitpid(pid, &pstat, 0);
18998514Sluigi	if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
19098514Sluigi		return (0);
19198514Sluigi	warnx("done");
19298514Sluigi	return (1);
19398514Sluigi}
19498514Sluigi
19598514Sluigivoid
19698514Sluigipw_edit(int notsetuid)
19798514Sluigi{
19898514Sluigi	int pstat;
19998514Sluigi	char *p, *editor;
20098514Sluigi
20198514Sluigi	if (!(editor = getenv("EDITOR")))
20298514Sluigi		editor = _default_editor;
20398514Sluigi	if ((p = strrchr(editor, '/')))
20498514Sluigi		++p;
20598514Sluigi	else
20698514Sluigi		p = editor;
20798514Sluigi
20898514Sluigi	if (!(editpid = fork())) {
20998514Sluigi		if (notsetuid) {
21098514Sluigi			(void)setgid(getgid());
21198514Sluigi			(void)setuid(getuid());
21298514Sluigi		}
21398514Sluigi		errno = 0;
21498514Sluigi		execlp(editor, p, tempname, (char *)NULL);
21598514Sluigi		_exit(errno);
21698514Sluigi	}
21798514Sluigi	for (;;) {
21898514Sluigi		editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
21998514Sluigi		errno = WEXITSTATUS(pstat);
22098514Sluigi		if (editpid == -1)
22198514Sluigi			pw_error(editor, 1, 1);
22298514Sluigi		else if (WIFSTOPPED(pstat))
22398514Sluigi			raise(WSTOPSIG(pstat));
22498514Sluigi		else if (WIFEXITED(pstat) && errno == 0)
22598514Sluigi			break;
22698514Sluigi		else
22798514Sluigi			pw_error(editor, 1, 1);
22898514Sluigi	}
22998514Sluigi	editpid = -1;
23098514Sluigi}
23198514Sluigi
23298514Sluigivoid
23398514Sluigipw_prompt(void)
23498514Sluigi{
23598514Sluigi	int c, first;
23698514Sluigi
23798514Sluigi	(void)printf("re-edit the password file? [y]: ");
23898514Sluigi	(void)fflush(stdout);
23998514Sluigi	first = c = getchar();
24098514Sluigi	while (c != '\n' && c != EOF)
24198514Sluigi		c = getchar();
24298514Sluigi	if (first == 'n')
24398514Sluigi		pw_error(NULL, 0, 0);
24498514Sluigi}
24598514Sluigi
24698514Sluigivoid
24798514Sluigipw_error(const char *name, int error, int eval)
24898514Sluigi{
24998514Sluigi	if (error) {
25098514Sluigi		if (name != NULL)
25198514Sluigi			warn("%s", name);
25298514Sluigi		else
25398514Sluigi			warn(NULL);
25498514Sluigi	}
25598514Sluigi	warnx("password information unchanged");
25698514Sluigi	(void)unlink(tempname);
25798514Sluigi	exit(eval);
25898514Sluigi}
259