chpass.c revision 1.16
1/*	$OpenBSD: chpass.c,v 1.16 2000/11/26 01:29:43 millert Exp $	*/
2/*	$NetBSD: chpass.c,v 1.8 1996/05/15 21:50:43 jtc Exp $	*/
3
4/*-
5 * Copyright (c) 1988, 1993, 1994
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright (c) 1988, 1993, 1994\n\
40	The Regents of the University of California.  All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44#if 0
45static char sccsid[] = "@(#)chpass.c	8.4 (Berkeley) 4/2/94";
46#else
47static char rcsid[] = "$OpenBSD: chpass.c,v 1.16 2000/11/26 01:29:43 millert Exp $";
48#endif
49#endif /* not lint */
50
51#include <sys/param.h>
52#include <sys/stat.h>
53#include <sys/time.h>
54#include <sys/resource.h>
55
56#include <ctype.h>
57#include <err.h>
58#include <errno.h>
59#include <fcntl.h>
60#include <pwd.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <string.h>
64#include <unistd.h>
65#include <util.h>
66
67#include "chpass.h"
68#include "pathnames.h"
69
70char tempname[] = __CONCAT(_PATH_VARTMP,"pw.XXXXXXXX");
71uid_t uid;
72
73extern char *__progname;
74
75#ifdef	YP
76int use_yp;
77int force_yp = 0;
78extern struct passwd *ypgetpwnam(), *ypgetpwuid();
79int _yp_check __P((char **));
80int pw_yp __P((struct passwd *, uid_t));
81#endif
82
83void	baduser __P((void));
84void	tempcleanup __P((void));
85void	usage __P((void));
86
87int
88main(argc, argv)
89	int argc;
90	char **argv;
91{
92	enum { NEWSH, LOADENTRY, EDITENTRY } op;
93	struct passwd *pw, lpw;
94	int ch, pfd, tfd, dfd;
95	char *arg;
96
97#ifdef	YP
98	use_yp = _yp_check(NULL);
99#endif
100
101	op = EDITENTRY;
102	while ((ch = getopt(argc, argv, "a:s:ly")) != -1)
103		switch(ch) {
104		case 'a':
105			op = LOADENTRY;
106			arg = optarg;
107			break;
108		case 's':
109			op = NEWSH;
110			arg = optarg;
111			break;
112#ifdef	YP
113		case 'l':
114			use_yp = 0;
115			break;
116		case 'y':
117			if (!use_yp) {
118				warnx("YP not in use.");
119				usage();
120			}
121			force_yp = 1;
122			break;
123#endif
124		case '?':
125		default:
126			usage();
127		}
128	argc -= optind;
129	argv += optind;
130
131#ifdef	YP
132	if (op == LOADENTRY && use_yp)
133		errx(1, "cannot load entry using NIS.\n\tUse the -l flag to load local.");
134#endif
135	uid = getuid();
136
137	if (op == EDITENTRY || op == NEWSH)
138		switch(argc) {
139		case 0:
140			pw = getpwuid(uid);
141#ifdef	YP
142			if (pw && !force_yp)
143				use_yp = 0;
144			else if (use_yp)
145				pw = ypgetpwuid(uid);
146#endif	/* YP */
147			if (!pw)
148				errx(1, "unknown user: uid %u\n", uid);
149			break;
150		case 1:
151			pw = getpwnam(*argv);
152#ifdef	YP
153			if (pw && !force_yp)
154				use_yp = 0;
155			else if (use_yp)
156				pw = ypgetpwnam(*argv);
157#endif	/* YP */
158			if (!pw)
159				errx(1, "unknown user: %s", *argv);
160			if (uid && uid != pw->pw_uid)
161				baduser();
162			break;
163		default:
164			usage();
165		}
166
167	if (op == NEWSH) {
168		/* protect p_shell -- it thinks NULL is /bin/sh */
169		if (!arg[0])
170			usage();
171		if (p_shell(arg, pw, NULL))
172			pw_error(NULL, 0, 1);
173	}
174
175	if (op == LOADENTRY) {
176		if (uid)
177			baduser();
178		pw = &lpw;
179		if (!pw_scan(arg, pw, NULL))
180			exit(1);
181	}
182
183	/* Get the passwd lock file and open the passwd file for reading. */
184	pw_init();
185	tfd = pw_lock(0);
186	if (tfd == -1 || fcntl(tfd, F_SETFD, 1) == -1) {
187		if (errno == EEXIST)
188			errx(1, "the passwd file is busy.");
189		else
190			err(1, "can't open passwd temp file");
191	}
192	pfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0);
193	if (pfd == -1 || fcntl(pfd, F_SETFD, 1) == -1)
194		pw_error(_PATH_MASTERPASSWD, 1, 1);
195
196	/* Edit the user passwd information if requested. */
197	if (op == EDITENTRY) {
198		dfd = mkstemp(tempname);
199		if (dfd == -1 || fcntl(dfd, F_SETFD, 1) == -1)
200			pw_error(tempname, 1, 1);
201		atexit(tempcleanup);
202		display(tempname, dfd, pw);
203		edit(tempname, pw);
204	}
205
206#ifdef	YP
207	if (use_yp) {
208		if (pw_yp(pw, uid)) {
209			pw_error(NULL, 0, 1);
210			exit(1);
211		} else {
212			pw_abort();
213			exit(0);
214		}
215	} else
216#endif	/* YP */
217	{
218		/* Copy the passwd file to the lock file, updating pw. */
219		pw_copy(pfd, tfd, pw);
220
221		/* Now finish the passwd file update. */
222		if (pw_mkdb(pw->pw_name) == -1)
223			pw_error(NULL, 0, 1);
224	}
225
226	exit(0);
227}
228
229void
230baduser()
231{
232
233	errx(1, "%s", strerror(EACCES));
234}
235
236void
237tempcleanup()
238{
239
240	unlink(tempname);
241}
242
243void
244usage()
245{
246
247#ifdef	YP
248	(void)fprintf(stderr,
249	    "usage: %s [-l%s] [-a list] [-s newshell] [user]\n",
250	    __progname, use_yp ? "y" : "");
251#else
252	(void)fprintf(stderr, "usage: %s [-a list] [-s newshell] [user]\n",
253	    __progname);
254#endif
255	exit(1);
256}
257