xref: /openbsd-src/usr.bin/chpass/chpass.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
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
38 static 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
45 static char sccsid[] = "@(#)chpass.c	8.4 (Berkeley) 4/2/94";
46 #else
47 static 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 
70 char tempname[] = __CONCAT(_PATH_VARTMP,"pw.XXXXXXXX");
71 uid_t uid;
72 
73 extern char *__progname;
74 
75 #ifdef	YP
76 int use_yp;
77 int force_yp = 0;
78 extern struct passwd *ypgetpwnam(), *ypgetpwuid();
79 int _yp_check __P((char **));
80 int pw_yp __P((struct passwd *, uid_t));
81 #endif
82 
83 void	baduser __P((void));
84 void	tempcleanup __P((void));
85 void	usage __P((void));
86 
87 int
88 main(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 
229 void
230 baduser()
231 {
232 
233 	errx(1, "%s", strerror(EACCES));
234 }
235 
236 void
237 tempcleanup()
238 {
239 
240 	unlink(tempname);
241 }
242 
243 void
244 usage()
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