Annotation of src/usr.bin/chpass/chpass.c, Revision 1.37
1.37 ! deraadt 1: /* $OpenBSD: chpass.c,v 1.36 2008/07/08 21:30:15 sobrado 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: #include <sys/param.h>
1.17 millert 34: #include <sys/resource.h>
1.1 deraadt 35: #include <sys/stat.h>
36: #include <sys/time.h>
1.17 millert 37: #include <sys/uio.h>
1.1 deraadt 38:
39: #include <err.h>
40: #include <errno.h>
41: #include <fcntl.h>
1.28 avsm 42: #include <paths.h>
1.1 deraadt 43: #include <pwd.h>
1.17 millert 44: #include <signal.h>
1.1 deraadt 45: #include <stdio.h>
46: #include <stdlib.h>
47: #include <string.h>
48: #include <unistd.h>
1.2 deraadt 49: #include <util.h>
1.1 deraadt 50:
51: #include "chpass.h"
52:
1.25 deraadt 53: extern char *__progname;
54:
1.17 millert 55: enum { NEWSH, LOADENTRY, EDITENTRY } op;
1.1 deraadt 56: uid_t uid;
57: #ifdef YP
1.25 deraadt 58: int use_yp;
59: int force_yp = 0;
1.1 deraadt 60: #endif
61:
1.21 millert 62: void baduser(void);
63: void kbintr(int);
64: void usage(void);
1.1 deraadt 65:
66: int
1.23 deraadt 67: main(int argc, char *argv[])
1.1 deraadt 68: {
1.33 otto 69: struct passwd *pw = NULL, *opw = NULL, lpw;
1.20 millert 70: int i, ch, pfd, tfd, dfd;
1.35 tobias 71: char *tz, *arg = NULL;
1.17 millert 72: sigset_t fullset;
1.1 deraadt 73:
74: #ifdef YP
75: use_yp = _yp_check(NULL);
76: #endif
1.35 tobias 77: /* We need to use the system timezone for date conversions. */
78: if ((tz = getenv("TZ")) != NULL) {
79: unsetenv("TZ");
80: tzset();
81: setenv("TZ", tz, 1);
82: }
1.1 deraadt 83:
84: op = EDITENTRY;
1.7 millert 85: while ((ch = getopt(argc, argv, "a:s:ly")) != -1)
1.1 deraadt 86: switch(ch) {
87: case 'a':
88: op = LOADENTRY;
89: arg = optarg;
90: break;
91: case 's':
92: op = NEWSH;
93: arg = optarg;
94: break;
95: #ifdef YP
96: case 'l':
97: use_yp = 0;
98: break;
99: case 'y':
100: if (!use_yp) {
101: warnx("YP not in use.");
102: usage();
103: }
104: force_yp = 1;
105: break;
106: #endif
107: case '?':
108: default:
109: usage();
110: }
111: argc -= optind;
112: argv += optind;
113:
114: #ifdef YP
115: if (op == LOADENTRY && use_yp)
1.23 deraadt 116: errx(1, "cannot load using YP, use -l to load local.");
1.1 deraadt 117: #endif
118: uid = getuid();
119:
120: if (op == EDITENTRY || op == NEWSH)
121: switch(argc) {
122: case 0:
123: pw = getpwuid(uid);
124: #ifdef YP
125: if (pw && !force_yp)
126: use_yp = 0;
127: else if (use_yp)
128: pw = ypgetpwuid(uid);
129: #endif /* YP */
130: if (!pw)
1.22 mpech 131: errx(1, "unknown user: uid %u", uid);
1.1 deraadt 132: break;
133: case 1:
134: pw = getpwnam(*argv);
135: #ifdef YP
136: if (pw && !force_yp)
137: use_yp = 0;
138: else if (use_yp)
139: pw = ypgetpwnam(*argv);
140: #endif /* YP */
141: if (!pw)
142: errx(1, "unknown user: %s", *argv);
143: if (uid && uid != pw->pw_uid)
144: baduser();
145: break;
146: default:
147: usage();
148: }
149:
150: if (op == LOADENTRY) {
1.33 otto 151: if (argc != 0)
152: errx(1, "option -a does not accept user argument");
1.1 deraadt 153: if (uid)
154: baduser();
155: pw = &lpw;
1.9 kstailey 156: if (!pw_scan(arg, pw, NULL))
1.1 deraadt 157: exit(1);
1.33 otto 158: opw = getpwnam(pw->pw_name);
1.1 deraadt 159: }
1.33 otto 160: if (opw == NULL && (opw = pw_dup(pw)) == NULL)
1.30 millert 161: err(1, NULL);
1.1 deraadt 162:
1.2 deraadt 163: /* Edit the user passwd information if requested. */
1.1 deraadt 164: if (op == EDITENTRY) {
1.29 espie 165: char tempname[] = _PATH_VARTMP "pw.XXXXXXXXXX";
1.26 millert 166: int edit_status;
1.24 millert 167:
1.30 millert 168: if ((pw = pw_dup(pw)) == NULL)
169: pw_error(NULL, 1, 1);
1.2 deraadt 170: dfd = mkstemp(tempname);
1.12 millert 171: if (dfd == -1 || fcntl(dfd, F_SETFD, 1) == -1)
1.2 deraadt 172: pw_error(tempname, 1, 1);
173: display(tempname, dfd, pw);
1.26 millert 174: edit_status = edit(tempname, pw);
1.24 millert 175: close(dfd);
176: unlink(tempname);
1.26 millert 177:
178: switch (edit_status) {
179: case EDIT_OK:
180: break;
181: case EDIT_NOCHANGE:
182: pw_error(NULL, 0, 0);
183: break;
184: case EDIT_ERROR:
185: default:
186: pw_error(tempname, 1, 1);
187: break;
188: }
1.31 wilfried 189: }
190:
191: if (op == NEWSH) {
192: /* protect p_shell -- it thinks NULL is /bin/sh */
193: if (!arg[0])
194: usage();
195: if (p_shell(arg, pw, NULL))
196: pw_error(NULL, 0, 1);
1.1 deraadt 197: }
1.2 deraadt 198:
1.17 millert 199: /* Drop user's real uid and block all signals to avoid a DoS. */
200: setuid(0);
201: sigfillset(&fullset);
202: sigdelset(&fullset, SIGINT);
203: sigprocmask(SIG_BLOCK, &fullset, NULL);
204:
205: /* Get the passwd lock file and open the passwd file for reading. */
206: pw_init();
1.20 millert 207: for (i = 1; (tfd = pw_lock(0)) == -1; i++) {
208: if (i == 4)
209: (void)fputs("Attempting lock password file, "
210: "please wait or press ^C to abort", stderr);
211: (void)signal(SIGINT, kbintr);
212: if (i % 16 == 0)
1.17 millert 213: fputc('.', stderr);
1.20 millert 214: usleep(250000);
1.17 millert 215: (void)signal(SIGINT, SIG_IGN);
216: }
1.20 millert 217: if (i >= 4)
218: fputc('\n', stderr);
1.17 millert 219: pfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0);
220: if (pfd == -1 || fcntl(pfd, F_SETFD, 1) == -1)
221: pw_error(_PATH_MASTERPASSWD, 1, 1);
222:
1.1 deraadt 223: #ifdef YP
224: if (use_yp) {
1.17 millert 225: if (pw_yp(pw, uid))
1.9 kstailey 226: pw_error(NULL, 0, 1);
1.17 millert 227: else {
1.5 deraadt 228: pw_abort();
1.1 deraadt 229: exit(0);
1.5 deraadt 230: }
1.4 deraadt 231: } else
1.1 deraadt 232: #endif /* YP */
1.8 deraadt 233: {
234: /* Copy the passwd file to the lock file, updating pw. */
1.30 millert 235: pw_copy(pfd, tfd, pw, opw);
236:
237: /* If username changed we need to rebuild the entire db. */
238: arg = !strcmp(opw->pw_name, pw->pw_name) ? pw->pw_name : NULL;
1.2 deraadt 239:
1.8 deraadt 240: /* Now finish the passwd file update. */
1.30 millert 241: if (pw_mkdb(arg, 0) == -1)
1.9 kstailey 242: pw_error(NULL, 0, 1);
1.8 deraadt 243: }
1.1 deraadt 244:
245: exit(0);
246: }
247:
248: void
1.23 deraadt 249: baduser(void)
1.1 deraadt 250: {
251:
252: errx(1, "%s", strerror(EACCES));
1.14 millert 253: }
254:
1.32 deraadt 255: /* ARGSUSED */
1.14 millert 256: void
1.23 deraadt 257: kbintr(int signo)
1.17 millert 258: {
259: struct iovec iv[5];
260:
261: iv[0].iov_base = "\n";
262: iv[0].iov_len = 1;
263: iv[1].iov_base = __progname;
264: iv[1].iov_len = strlen(__progname);
265: iv[2].iov_base = ": ";
266: iv[2].iov_len = 2;
267: iv[3].iov_base = _PATH_MASTERPASSWD;
268: iv[3].iov_len = sizeof(_PATH_MASTERPASSWD) - 1;
269: iv[4].iov_base = " unchanged\n";
270: iv[4].iov_len = 11;
271: writev(STDERR_FILENO, iv, 5);
272:
273: _exit(1);
1.1 deraadt 274: }
275:
276: void
1.23 deraadt 277: usage(void)
1.1 deraadt 278: {
279:
280: #ifdef YP
1.15 aaron 281: (void)fprintf(stderr,
1.34 jmc 282: "usage: %s [-l%s] [-s newshell] [user]\n",
1.15 aaron 283: __progname, use_yp ? "y" : "");
1.34 jmc 284: (void)fprintf(stderr,
1.36 sobrado 285: " %s [-l] -a list\n", __progname);
1.1 deraadt 286: #else
1.34 jmc 287: (void)fprintf(stderr, "usage: %s [-s newshell] [user]\n", __progname);
1.36 sobrado 288: (void)fprintf(stderr, " %s -a list\n", __progname);
1.1 deraadt 289: #endif
290: exit(1);
291: }