pw_util.c revision 75821
11553Srgrimes/*-
21553Srgrimes * Copyright (c) 1990, 1993, 1994
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 3. All advertising materials mentioning features or use of this software
141553Srgrimes *    must display the following acknowledgement:
151553Srgrimes *	This product includes software developed by the University of
161553Srgrimes *	California, Berkeley and its contributors.
171553Srgrimes * 4. Neither the name of the University nor the names of its contributors
181553Srgrimes *    may be used to endorse or promote products derived from this software
191553Srgrimes *    without specific prior written permission.
201553Srgrimes *
211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311553Srgrimes * SUCH DAMAGE.
321553Srgrimes */
331553Srgrimes
341553Srgrimes#ifndef lint
3530765Scharnier#if 0
3630113Sjkhstatic const char sccsid[] = "@(#)pw_util.c	8.3 (Berkeley) 4/2/94";
3730765Scharnier#endif
3830765Scharnierstatic const char rcsid[] =
3950479Speter  "$FreeBSD: head/lib/libutil/pw_util.c 75821 2001-04-22 03:00:09Z dd $";
401553Srgrimes#endif /* not lint */
411553Srgrimes
421553Srgrimes/*
431553Srgrimes * This file is used by all the "password" programs; vipw(8), chpass(1),
441553Srgrimes * and passwd(1).
451553Srgrimes */
461553Srgrimes
471553Srgrimes#include <sys/param.h>
4840538Sdes#include <sys/errno.h>
491553Srgrimes#include <sys/time.h>
501553Srgrimes#include <sys/resource.h>
511553Srgrimes#include <sys/stat.h>
521553Srgrimes#include <sys/wait.h>
531553Srgrimes
541553Srgrimes#include <err.h>
551553Srgrimes#include <fcntl.h>
561553Srgrimes#include <paths.h>
571553Srgrimes#include <pwd.h>
581553Srgrimes#include <signal.h>
591553Srgrimes#include <stdio.h>
601553Srgrimes#include <stdlib.h>
611553Srgrimes#include <string.h>
621553Srgrimes#include <unistd.h>
631553Srgrimes
641553Srgrimes#include "pw_util.h"
651553Srgrimes
661553Srgrimesextern char *tempname;
676972Sachestatic pid_t editpid = -1;
686972Sachestatic int lockfd;
6948232Ssheldonhchar *mppath = _PATH_PWD;
7048232Ssheldonhchar *masterpasswd = _PATH_MASTERPASSWD;
711553Srgrimes
721553Srgrimesvoid
736972Sachepw_cont(sig)
746972Sache	int sig;
756972Sache{
766972Sache
776972Sache	if (editpid != -1)
786972Sache		kill(editpid, sig);
796972Sache}
806972Sache
816972Sachevoid
821553Srgrimespw_init()
831553Srgrimes{
841553Srgrimes	struct rlimit rlim;
851553Srgrimes
861553Srgrimes	/* Unlimited resource limits. */
871553Srgrimes	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
881553Srgrimes	(void)setrlimit(RLIMIT_CPU, &rlim);
891553Srgrimes	(void)setrlimit(RLIMIT_FSIZE, &rlim);
901553Srgrimes	(void)setrlimit(RLIMIT_STACK, &rlim);
911553Srgrimes	(void)setrlimit(RLIMIT_DATA, &rlim);
921553Srgrimes	(void)setrlimit(RLIMIT_RSS, &rlim);
931553Srgrimes
941553Srgrimes	/* Don't drop core (not really necessary, but GP's). */
951553Srgrimes	rlim.rlim_cur = rlim.rlim_max = 0;
961553Srgrimes	(void)setrlimit(RLIMIT_CORE, &rlim);
971553Srgrimes
981553Srgrimes	/* Turn off signals. */
991553Srgrimes	(void)signal(SIGALRM, SIG_IGN);
1001553Srgrimes	(void)signal(SIGHUP, SIG_IGN);
1011553Srgrimes	(void)signal(SIGINT, SIG_IGN);
1021553Srgrimes	(void)signal(SIGPIPE, SIG_IGN);
1031553Srgrimes	(void)signal(SIGQUIT, SIG_IGN);
1041553Srgrimes	(void)signal(SIGTERM, SIG_IGN);
1056972Sache	(void)signal(SIGCONT, pw_cont);
10648328Spb
10748328Spb	/* Create with exact permissions. */
10848328Spb	(void)umask(0);
1091553Srgrimes}
1101553Srgrimes
1111553Srgrimesint
1121553Srgrimespw_lock()
1131553Srgrimes{
1148857Srgrimes	/*
1151553Srgrimes	 * If the master password file doesn't exist, the system is hosed.
1161553Srgrimes	 * Might as well try to build one.  Set the close-on-exec bit so
1171553Srgrimes	 * that users can't get at the encrypted passwords while editing.
1181553Srgrimes	 * Open should allow flock'ing the file; see 4.4BSD.	XXX
1191553Srgrimes	 */
12041710Sdillon	for (;;) {
12141711Sdillon		struct stat st;
12241710Sdillon
12348232Ssheldonh		lockfd = open(masterpasswd, O_RDONLY, 0);
12441711Sdillon		if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
12548232Ssheldonh			err(1, "%s", masterpasswd);
12641711Sdillon		if (flock(lockfd, LOCK_EX|LOCK_NB))
12741711Sdillon			errx(1, "the password db file is busy");
12841710Sdillon
12941711Sdillon		/*
13041711Sdillon		 * If the password file was replaced while we were trying to
13141711Sdillon		 * get the lock, our hardlink count will be 0 and we have to
13241711Sdillon		 * close and retry.
13341711Sdillon		 */
13441711Sdillon		if (fstat(lockfd, &st) < 0)
13541711Sdillon			errx(1, "fstat() failed");
13641711Sdillon		if (st.st_nlink != 0)
13741711Sdillon			break;
13841711Sdillon		close(lockfd);
13941711Sdillon		lockfd = -1;
14041710Sdillon	}
1411553Srgrimes	return (lockfd);
1421553Srgrimes}
1431553Srgrimes
1441553Srgrimesint
1451553Srgrimespw_tmp()
1461553Srgrimes{
14748232Ssheldonh	static char path[MAXPATHLEN];
1481553Srgrimes	int fd;
1491553Srgrimes	char *p;
1501553Srgrimes
15148232Ssheldonh	strncpy(path, masterpasswd, MAXPATHLEN - 1);
15248232Ssheldonh	path[MAXPATHLEN] = '\0';
15348232Ssheldonh
15430113Sjkh	if ((p = strrchr(path, '/')))
1551553Srgrimes		++p;
1561553Srgrimes	else
1571553Srgrimes		p = path;
1581553Srgrimes	strcpy(p, "pw.XXXXXX");
1591553Srgrimes	if ((fd = mkstemp(path)) == -1)
1601553Srgrimes		err(1, "%s", path);
1611553Srgrimes	tempname = path;
1621553Srgrimes	return (fd);
1631553Srgrimes}
1641553Srgrimes
1651553Srgrimesint
16616876Sguidopw_mkdb(username)
16716876Sguidochar *username;
1681553Srgrimes{
1691553Srgrimes	int pstat;
1701553Srgrimes	pid_t pid;
1711553Srgrimes
1721553Srgrimes	(void)fflush(stderr);
17340301Sdes	if (!(pid = fork())) {
17416876Sguido		if(!username) {
17528662Sjoerg			warnx("rebuilding the database...");
17648232Ssheldonh			execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath,
17748232Ssheldonh			    tempname, NULL);
17816876Sguido		} else {
17928662Sjoerg			warnx("updating the database...");
18048232Ssheldonh			execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath,
18148232Ssheldonh			    "-u", username, tempname, NULL);
18216876Sguido		}
1831553Srgrimes		pw_error(_PATH_PWD_MKDB, 1, 1);
1841553Srgrimes	}
1851553Srgrimes	pid = waitpid(pid, &pstat, 0);
1861553Srgrimes	if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
1871553Srgrimes		return (0);
1881553Srgrimes	warnx("done");
1891553Srgrimes	return (1);
1901553Srgrimes}
1911553Srgrimes
1921553Srgrimesvoid
1931553Srgrimespw_edit(notsetuid)
1941553Srgrimes	int notsetuid;
1951553Srgrimes{
1961553Srgrimes	int pstat;
1971553Srgrimes	char *p, *editor;
1981553Srgrimes
1991553Srgrimes	if (!(editor = getenv("EDITOR")))
2001553Srgrimes		editor = _PATH_VI;
20130113Sjkh	if ((p = strrchr(editor, '/')))
2021553Srgrimes		++p;
2038857Srgrimes	else
2041553Srgrimes		p = editor;
2051553Srgrimes
20640301Sdes	if (!(editpid = fork())) {
2071553Srgrimes		if (notsetuid) {
2081553Srgrimes			(void)setgid(getgid());
2091553Srgrimes			(void)setuid(getuid());
2101553Srgrimes		}
21140538Sdes		errno = 0;
2121553Srgrimes		execlp(editor, p, tempname, NULL);
21340538Sdes		_exit(errno);
2141553Srgrimes	}
2156972Sache	for (;;) {
2166972Sache		editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
21740538Sdes		errno = WEXITSTATUS(pstat);
2186972Sache		if (editpid == -1)
2196972Sache			pw_error(editor, 1, 1);
2206972Sache		else if (WIFSTOPPED(pstat))
2216972Sache			raise(WSTOPSIG(pstat));
22240538Sdes		else if (WIFEXITED(pstat) && errno == 0)
2236972Sache			break;
2246972Sache		else
2256972Sache			pw_error(editor, 1, 1);
2266972Sache	}
2276972Sache	editpid = -1;
2281553Srgrimes}
2291553Srgrimes
2301553Srgrimesvoid
2311553Srgrimespw_prompt()
2321553Srgrimes{
23329980Swosch	int c, first;
2341553Srgrimes
2351553Srgrimes	(void)printf("re-edit the password file? [y]: ");
2361553Srgrimes	(void)fflush(stdout);
23729980Swosch	first = c = getchar();
23829980Swosch	while (c != '\n' && c != EOF)
23929980Swosch		c = getchar();
24029980Swosch	if (first == 'n')
2411553Srgrimes		pw_error(NULL, 0, 0);
2421553Srgrimes}
2431553Srgrimes
2441553Srgrimesvoid
2451553Srgrimespw_error(name, err, eval)
2461553Srgrimes	char *name;
2471553Srgrimes	int err, eval;
2481553Srgrimes{
24910048Swpaul#ifdef YP
25010048Swpaul	extern int _use_yp;
25110048Swpaul#endif /* YP */
25275821Sdd	if (err) {
25375821Sdd		if (name != NULL)
25475821Sdd			warn("%s", name);
25575821Sdd		else
25675821Sdd			warn(NULL);
25775821Sdd	}
25810048Swpaul#ifdef YP
25910048Swpaul	if (_use_yp)
26010048Swpaul		warnx("NIS information unchanged");
26110048Swpaul	else
26210048Swpaul#endif /* YP */
26348232Ssheldonh	warnx("%s: unchanged", masterpasswd);
2641553Srgrimes	(void)unlink(tempname);
2651553Srgrimes	exit(eval);
2661553Srgrimes}
267