Annotation of src/usr.bin/chpass/chpass.c, Revision 1.36
1.36 ! sobrado 1: /* $OpenBSD: chpass.c,v 1.35 2008/06/19 19:16:04 tobias Exp $ */
1.2 deraadt 2: /* $NetBSD: chpass.c,v 1.8 1996/05/15 21:50:43 jtc Exp $ */
1.1 deraadt 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.
1.27 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: #ifndef lint
34: static char copyright[] =
35: "@(#) Copyright (c) 1988, 1993, 1994\n\
36: The Regents of the University of California. All rights reserved.\n";
37: #endif /* not lint */
38:
39: #ifndef lint
40: #if 0
41: static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94";
1.23 deraadt 42: #else
1.36 ! sobrado 43: static char rcsid[] = "$OpenBSD: chpass.c,v 1.35 2008/06/19 19:16:04 tobias Exp $";
1.1 deraadt 44: #endif
45: #endif /* not lint */
46:
47: #include <sys/param.h>
1.17 millert 48: #include <sys/resource.h>
1.1 deraadt 49: #include <sys/stat.h>
50: #include <sys/time.h>
1.17 millert 51: #include <sys/uio.h>
1.1 deraadt 52:
53: #include <err.h>
54: #include <errno.h>
55: #include <fcntl.h>
1.28 avsm 56: #include <paths.h>
1.1 deraadt 57: #include <pwd.h>
1.17 millert 58: #include <signal.h>
1.1 deraadt 59: #include <stdio.h>
60: #include <stdlib.h>
61: #include <string.h>
62: #include <unistd.h>
1.2 deraadt 63: #include <util.h>
1.1 deraadt 64:
65: #include "chpass.h"
66:
1.25 deraadt 67: extern char *__progname;
68:
1.17 millert 69: enum { NEWSH, LOADENTRY, EDITENTRY } op;
1.1 deraadt 70: uid_t uid;
71: #ifdef YP
1.25 deraadt 72: int use_yp;
73: int force_yp = 0;
1.1 deraadt 74: #endif
75:
1.21 millert 76: void baduser(void);
77: void kbintr(int);
78: void usage(void);
1.1 deraadt 79:
80: int
1.23 deraadt 81: main(int argc, char *argv[])
1.1 deraadt 82: {
1.33 otto 83: struct passwd *pw = NULL, *opw = NULL, lpw;
1.20 millert 84: int i, ch, pfd, tfd, dfd;
1.35 tobias 85: char *tz, *arg = NULL;
1.17 millert 86: sigset_t fullset;
1.1 deraadt 87:
88: #ifdef YP
89: use_yp = _yp_check(NULL);
90: #endif
1.35 tobias 91: /* We need to use the system timezone for date conversions. */
92: if ((tz = getenv("TZ")) != NULL) {
93: unsetenv("TZ");
94: tzset();
95: setenv("TZ", tz, 1);
96: }
1.1 deraadt 97:
98: op = EDITENTRY;
1.7 millert 99: while ((ch = getopt(argc, argv, "a:s:ly")) != -1)
1.1 deraadt 100: switch(ch) {
101: case 'a':
102: op = LOADENTRY;
103: arg = optarg;
104: break;
105: case 's':
106: op = NEWSH;
107: arg = optarg;
108: break;
109: #ifdef YP
110: case 'l':
111: use_yp = 0;
112: break;
113: case 'y':
114: if (!use_yp) {
115: warnx("YP not in use.");
116: usage();
117: }
118: force_yp = 1;
119: break;
120: #endif
121: case '?':
122: default:
123: usage();
124: }
125: argc -= optind;
126: argv += optind;
127:
128: #ifdef YP
129: if (op == LOADENTRY && use_yp)
1.23 deraadt 130: errx(1, "cannot load using YP, use -l to load local.");
1.1 deraadt 131: #endif
132: uid = getuid();
133:
134: if (op == EDITENTRY || op == NEWSH)
135: switch(argc) {
136: case 0:
137: pw = getpwuid(uid);
138: #ifdef YP
139: if (pw && !force_yp)
140: use_yp = 0;
141: else if (use_yp)
142: pw = ypgetpwuid(uid);
143: #endif /* YP */
144: if (!pw)
1.22 mpech 145: errx(1, "unknown user: uid %u", uid);
1.1 deraadt 146: break;
147: case 1:
148: pw = getpwnam(*argv);
149: #ifdef YP
150: if (pw && !force_yp)
151: use_yp = 0;
152: else if (use_yp)
153: pw = ypgetpwnam(*argv);
154: #endif /* YP */
155: if (!pw)
156: errx(1, "unknown user: %s", *argv);
157: if (uid && uid != pw->pw_uid)
158: baduser();
159: break;
160: default:
161: usage();
162: }
163:
164: if (op == LOADENTRY) {
1.33 otto 165: if (argc != 0)
166: errx(1, "option -a does not accept user argument");
1.1 deraadt 167: if (uid)
168: baduser();
169: pw = &lpw;
1.9 kstailey 170: if (!pw_scan(arg, pw, NULL))
1.1 deraadt 171: exit(1);
1.33 otto 172: opw = getpwnam(pw->pw_name);
1.1 deraadt 173: }
1.33 otto 174: if (opw == NULL && (opw = pw_dup(pw)) == NULL)
1.30 millert 175: err(1, NULL);
1.1 deraadt 176:
1.2 deraadt 177: /* Edit the user passwd information if requested. */
1.1 deraadt 178: if (op == EDITENTRY) {
1.29 espie 179: char tempname[] = _PATH_VARTMP "pw.XXXXXXXXXX";
1.26 millert 180: int edit_status;
1.24 millert 181:
1.30 millert 182: if ((pw = pw_dup(pw)) == NULL)
183: pw_error(NULL, 1, 1);
1.2 deraadt 184: dfd = mkstemp(tempname);
1.12 millert 185: if (dfd == -1 || fcntl(dfd, F_SETFD, 1) == -1)
1.2 deraadt 186: pw_error(tempname, 1, 1);
187: display(tempname, dfd, pw);
1.26 millert 188: edit_status = edit(tempname, pw);
1.24 millert 189: close(dfd);
190: unlink(tempname);
1.26 millert 191:
192: switch (edit_status) {
193: case EDIT_OK:
194: break;
195: case EDIT_NOCHANGE:
196: pw_error(NULL, 0, 0);
197: break;
198: case EDIT_ERROR:
199: default:
200: pw_error(tempname, 1, 1);
201: break;
202: }
1.31 wilfried 203: }
204:
205: if (op == NEWSH) {
206: /* protect p_shell -- it thinks NULL is /bin/sh */
207: if (!arg[0])
208: usage();
209: if (p_shell(arg, pw, NULL))
210: pw_error(NULL, 0, 1);
1.1 deraadt 211: }
1.2 deraadt 212:
1.17 millert 213: /* Drop user's real uid and block all signals to avoid a DoS. */
214: setuid(0);
215: sigfillset(&fullset);
216: sigdelset(&fullset, SIGINT);
217: sigprocmask(SIG_BLOCK, &fullset, NULL);
218:
219: /* Get the passwd lock file and open the passwd file for reading. */
220: pw_init();
1.20 millert 221: for (i = 1; (tfd = pw_lock(0)) == -1; i++) {
222: if (i == 4)
223: (void)fputs("Attempting lock password file, "
224: "please wait or press ^C to abort", stderr);
225: (void)signal(SIGINT, kbintr);
226: if (i % 16 == 0)
1.17 millert 227: fputc('.', stderr);
1.20 millert 228: usleep(250000);
1.17 millert 229: (void)signal(SIGINT, SIG_IGN);
230: }
1.20 millert 231: if (i >= 4)
232: fputc('\n', stderr);
1.17 millert 233: pfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0);
234: if (pfd == -1 || fcntl(pfd, F_SETFD, 1) == -1)
235: pw_error(_PATH_MASTERPASSWD, 1, 1);
236:
1.1 deraadt 237: #ifdef YP
238: if (use_yp) {
1.17 millert 239: if (pw_yp(pw, uid))
1.9 kstailey 240: pw_error(NULL, 0, 1);
1.17 millert 241: else {
1.5 deraadt 242: pw_abort();
1.1 deraadt 243: exit(0);
1.5 deraadt 244: }
1.4 deraadt 245: } else
1.1 deraadt 246: #endif /* YP */
1.8 deraadt 247: {
248: /* Copy the passwd file to the lock file, updating pw. */
1.30 millert 249: pw_copy(pfd, tfd, pw, opw);
250:
251: /* If username changed we need to rebuild the entire db. */
252: arg = !strcmp(opw->pw_name, pw->pw_name) ? pw->pw_name : NULL;
1.2 deraadt 253:
1.8 deraadt 254: /* Now finish the passwd file update. */
1.30 millert 255: if (pw_mkdb(arg, 0) == -1)
1.9 kstailey 256: pw_error(NULL, 0, 1);
1.8 deraadt 257: }
1.1 deraadt 258:
259: exit(0);
260: }
261:
262: void
1.23 deraadt 263: baduser(void)
1.1 deraadt 264: {
265:
266: errx(1, "%s", strerror(EACCES));
1.14 millert 267: }
268:
1.32 deraadt 269: /* ARGSUSED */
1.14 millert 270: void
1.23 deraadt 271: kbintr(int signo)
1.17 millert 272: {
273: struct iovec iv[5];
274:
275: iv[0].iov_base = "\n";
276: iv[0].iov_len = 1;
277: iv[1].iov_base = __progname;
278: iv[1].iov_len = strlen(__progname);
279: iv[2].iov_base = ": ";
280: iv[2].iov_len = 2;
281: iv[3].iov_base = _PATH_MASTERPASSWD;
282: iv[3].iov_len = sizeof(_PATH_MASTERPASSWD) - 1;
283: iv[4].iov_base = " unchanged\n";
284: iv[4].iov_len = 11;
285: writev(STDERR_FILENO, iv, 5);
286:
287: _exit(1);
1.1 deraadt 288: }
289:
290: void
1.23 deraadt 291: usage(void)
1.1 deraadt 292: {
293:
294: #ifdef YP
1.15 aaron 295: (void)fprintf(stderr,
1.34 jmc 296: "usage: %s [-l%s] [-s newshell] [user]\n",
1.15 aaron 297: __progname, use_yp ? "y" : "");
1.34 jmc 298: (void)fprintf(stderr,
1.36 ! sobrado 299: " %s [-l] -a list\n", __progname);
1.1 deraadt 300: #else
1.34 jmc 301: (void)fprintf(stderr, "usage: %s [-s newshell] [user]\n", __progname);
1.36 ! sobrado 302: (void)fprintf(stderr, " %s -a list\n", __progname);
1.1 deraadt 303: #endif
304: exit(1);
305: }