1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
7 * Reserved.  This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License').  You may not use this file
10 * except in compliance with the License.  Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*-
25 * Copyright (c) 1990, 1993, 1994
26 *	The Regents of the University of California.  All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 *    notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 *    notice, this list of conditions and the following disclaimer in the
35 *    documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 *    must display the following acknowledgement:
38 *	This product includes software developed by the University of
39 *	California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 *    may be used to endorse or promote products derived from this software
42 *    without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57#ifndef lint
58#include <sys/cdefs.h>
59__unused static char sccsid[] = "@(#)pw_util.c	8.4 (Berkeley) 4/28/95";
60#endif /* not lint */
61
62/*
63 * This file is used by all the "password" programs; vipw(8), chpass(1),
64 * and passwd(1).
65 */
66
67#include <sys/param.h>
68#include <sys/time.h>
69#include <sys/resource.h>
70#include <sys/stat.h>
71#include <sys/wait.h>
72
73#include <err.h>
74#include <errno.h>
75#include <fcntl.h>
76#include <paths.h>
77#include <pwd.h>
78#include <signal.h>
79#include <stdio.h>
80#include <stdlib.h>
81#include <string.h>
82#include <unistd.h>
83
84#include "pw_util.h"
85
86extern char *tempname;
87static pid_t editpid = -1;
88static int lockfd;
89
90void
91pw_cont(sig)
92	int sig;
93{
94
95	if (editpid != -1)
96		kill(editpid, sig);
97}
98
99void
100pw_init()
101{
102	struct rlimit rlim;
103
104	/* Unlimited resource limits. */
105	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
106	(void)setrlimit(RLIMIT_CPU, &rlim);
107	(void)setrlimit(RLIMIT_FSIZE, &rlim);
108	(void)setrlimit(RLIMIT_STACK, &rlim);
109	(void)setrlimit(RLIMIT_DATA, &rlim);
110	(void)setrlimit(RLIMIT_RSS, &rlim);
111
112	/* Don't drop core (not really necessary, but GP's). */
113	rlim.rlim_cur = rlim.rlim_max = 0;
114	(void)setrlimit(RLIMIT_CORE, &rlim);
115
116	/* Turn off signals. */
117	(void)signal(SIGALRM, SIG_IGN);
118	(void)signal(SIGHUP, SIG_IGN);
119	(void)signal(SIGINT, SIG_IGN);
120	(void)signal(SIGPIPE, SIG_IGN);
121	(void)signal(SIGQUIT, SIG_IGN);
122	(void)signal(SIGTERM, SIG_IGN);
123	(void)signal(SIGCONT, pw_cont);
124
125	/* Create with exact permissions. */
126	(void)umask(0);
127}
128
129int
130pw_lock()
131{
132	/*
133	 * If the master password file doesn't exist, the system is hosed.
134	 * Might as well try to build one.  Set the close-on-exec bit so
135	 * that users can't get at the encrypted passwords while editing.
136	 * Open should allow flock'ing the file; see 4.4BSD.	XXX
137	 */
138	lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0);
139	if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
140		err(1, "%s", _PATH_MASTERPASSWD);
141	if (flock(lockfd, LOCK_EX|LOCK_NB))
142		errx(1, "the password db file is busy");
143	return (lockfd);
144}
145
146int
147pw_tmp()
148{
149	static char path[MAXPATHLEN] = _PATH_MASTERPASSWD;
150	int fd;
151	char *p;
152
153	if (p = strrchr(path, '/'))
154		++p;
155	else
156		p = path;
157	strcpy(p, "pw.XXXXXX");
158	if ((fd = mkstemp(path)) == -1)
159		err(1, "%s", path);
160	tempname = path;
161	return (fd);
162}
163
164int
165pw_mkdb()
166{
167	int pstat;
168	pid_t pid;
169
170	warnx("rebuilding the database...");
171	(void)fflush(stderr);
172	if (!(pid = vfork())) {
173		execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", tempname, NULL);
174		pw_error(_PATH_PWD_MKDB, 1, 1);
175	}
176	pid = waitpid(pid, &pstat, 0);
177	if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
178		return (1);
179	warnx("done");
180	return (0);
181}
182
183void
184pw_edit(notsetuid)
185	int notsetuid;
186{
187	int pstat;
188	char *p, *editor;
189
190	if (!(editor = getenv("EDITOR")))
191		editor = _PATH_VI;
192	if (p = strrchr(editor, '/'))
193		++p;
194	else
195		p = editor;
196
197	if (!(editpid = vfork())) {
198		if (notsetuid) {
199			(void)setgid(getgid());
200			(void)setuid(getuid());
201		}
202		execlp(editor, p, tempname, NULL);
203		_exit(1);
204	}
205	for (;;) {
206		editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
207		if (editpid == -1)
208			pw_error(editor, 1, 1);
209		else if (WIFSTOPPED(pstat))
210			raise(WSTOPSIG(pstat));
211		else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
212			break;
213		else
214			pw_error(editor, 1, 1);
215	}
216	editpid = -1;
217}
218
219void
220pw_prompt()
221{
222	int c;
223
224	(void)printf("re-edit the password file? [y]: ");
225	(void)fflush(stdout);
226	c = getchar();
227	if (c != EOF && c != '\n')
228		while (getchar() != '\n');
229	if (c == 'n')
230		pw_error(NULL, 0, 0);
231}
232
233void
234pw_error(name, err, eval)
235	char *name;
236	int err, eval;
237{
238	if (err)
239		warn("%s", name);
240
241	warnx("%s: unchanged", _PATH_MASTERPASSWD);
242	(void)unlink(tempname);
243	exit(eval);
244}
245