powernow - only build for i386, BIOS macros currently broken for 64-bit.
[dragonfly.git] / usr.bin / chpass / chpass.c
blob2a86eddcffb2c62dc5850d984ac8d367410148a5
1 /*-
2 * Copyright (c) 1988, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2002 Networks Associates Technology, Inc.
5 * All rights reserved.
7 * Portions of this software were developed for the FreeBSD Project by
8 * ThinkSec AS and NAI Labs, the Security Research Division of Network
9 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
10 * ("CBOSS"), as part of the DARPA CHATS research program.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
40 * @(#) Copyright (c) 1988, 1993, 1994 The Regents of the University of California. All rights reserved.
41 * @(#)chpass.c 8.4 (Berkeley) 4/2/94
42 * $FreeBSD: src/usr.bin/chpass/chpass.c,v 1.28 2006/09/25 15:06:24 marck Exp $
43 * $DragonFly: src/usr.bin/chpass/chpass.c,v 1.4 2003/11/03 19:31:28 eirikn Exp $
46 #include <sys/param.h>
48 #include <err.h>
49 #include <errno.h>
50 #include <pwd.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #ifdef YP
56 #include <ypclnt.h>
57 #endif
59 #include <pw_scan.h>
60 #include <libutil.h>
62 #include "chpass.h"
64 int master_mode;
66 static void baduser(void);
67 static void usage(void);
69 int
70 main(int argc, char **argv)
72 enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op;
73 struct passwd lpw, *old_pw, *pw;
74 int ch, pfd, tfd;
75 const char *password;
76 char *arg = NULL;
77 uid_t uid;
78 #ifdef YP
79 struct ypclnt *ypclnt;
80 const char *yp_domain = NULL, *yp_host = NULL;
81 #endif
83 pw = old_pw = NULL;
84 op = EDITENTRY;
85 #ifdef YP
86 while ((ch = getopt(argc, argv, "a:p:s:e:d:h:loy")) != -1)
87 #else
88 while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1)
89 #endif
90 switch (ch) {
91 case 'a':
92 op = LOADENTRY;
93 arg = optarg;
94 break;
95 case 's':
96 op = NEWSH;
97 arg = optarg;
98 break;
99 case 'p':
100 op = NEWPW;
101 arg = optarg;
102 break;
103 case 'e':
104 op = NEWEXP;
105 arg = optarg;
106 break;
107 #ifdef YP
108 case 'd':
109 yp_domain = optarg;
110 break;
111 case 'h':
112 yp_host = optarg;
113 break;
114 case 'l':
115 case 'o':
116 case 'y':
117 /* compatibility */
118 break;
119 #endif
120 case '?':
121 default:
122 usage();
125 argc -= optind;
126 argv += optind;
128 if (argc > 1)
129 usage();
131 uid = getuid();
133 if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) {
134 if (argc == 0) {
135 if ((pw = getpwuid(uid)) == NULL)
136 errx(1, "unknown user: uid %lu",
137 (unsigned long)uid);
138 } else {
139 if ((pw = getpwnam(*argv)) == NULL)
140 errx(1, "unknown user: %s", *argv);
141 if (uid != 0 && uid != pw->pw_uid)
142 baduser();
145 /* Make a copy for later verification */
146 if ((pw = pw_dup(pw)) == NULL ||
147 (old_pw = pw_dup(pw)) == NULL)
148 err(1, "pw_dup");
151 #ifdef YP
152 if (pw != NULL && (pw->pw_fields & _PWF_SOURCE) == _PWF_NIS) {
153 ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
154 master_mode = (ypclnt != NULL &&
155 ypclnt_connect(ypclnt) != -1 &&
156 ypclnt_havepasswdd(ypclnt) == 1);
157 ypclnt_free(ypclnt);
158 } else
159 #endif
160 master_mode = (uid == 0);
162 if (op == NEWSH) {
163 /* protect p_shell -- it thinks NULL is /bin/sh */
164 if (!arg[0])
165 usage();
166 if (p_shell(arg, pw, NULL) == -1)
167 exit(1);
170 if (op == NEWEXP) {
171 if (uid) /* only root can change expire */
172 baduser();
173 if (p_expire(arg, pw, NULL) == -1)
174 exit(1);
177 if (op == LOADENTRY) {
178 if (uid)
179 baduser();
180 pw = &lpw;
181 old_pw = NULL;
182 if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER))
183 exit(1);
186 if (op == NEWPW) {
187 if (uid)
188 baduser();
190 if (strchr(arg, ':'))
191 errx(1, "invalid format for password");
192 pw->pw_passwd = arg;
195 if (op == EDITENTRY) {
197 * We don't really need pw_*() here, but pw_edit() (used
198 * by edit()) is just too useful...
200 if (pw_init(NULL, NULL))
201 err(1, "pw_init()");
202 if ((tfd = pw_tmp(-1)) == -1) {
203 pw_fini();
204 err(1, "pw_tmp()");
206 free(pw);
207 pw = edit(pw_tempname(), old_pw);
208 pw_fini();
209 if (pw == NULL)
210 err(1, "edit()");
212 * pw_equal does not check for crypted passwords, so we
213 * should do it explicitly
215 if (pw_equal(old_pw, pw) &&
216 strcmp(old_pw->pw_passwd, pw->pw_passwd) == 0)
217 errx(0, "user information unchanged");
220 if (old_pw && !master_mode) {
221 password = getpass("Password: ");
222 if (strcmp(crypt(password, old_pw->pw_passwd),
223 old_pw->pw_passwd) != 0)
224 baduser();
225 } else {
226 password = "";
229 if (old_pw != NULL)
230 pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE);
231 switch (pw->pw_fields & _PWF_SOURCE) {
232 #ifdef YP
233 case _PWF_NIS:
234 ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
235 if (ypclnt == NULL ||
236 ypclnt_connect(ypclnt) == -1 ||
237 ypclnt_passwd(ypclnt, pw, password) == -1) {
238 warnx("%s", ypclnt->error);
239 ypclnt_free(ypclnt);
240 exit(1);
242 ypclnt_free(ypclnt);
243 errx(0, "NIS user information updated");
244 #endif /* YP */
245 case 0:
246 case _PWF_FILES:
247 if (pw_init(NULL, NULL))
248 err(1, "pw_init()");
249 if ((pfd = pw_lock()) == -1) {
250 pw_fini();
251 err(1, "pw_lock()");
253 if ((tfd = pw_tmp(-1)) == -1) {
254 pw_fini();
255 err(1, "pw_tmp()");
257 if (pw_copy(pfd, tfd, pw, old_pw) == -1) {
258 pw_fini();
259 err(1, "pw_copy");
261 if (pw_mkdb(pw->pw_name) == -1) {
262 pw_fini();
263 err(1, "pw_mkdb()");
265 pw_fini();
266 errx(0, "user information updated");
267 break;
268 default:
269 errx(1, "unsupported passwd source");
273 static void
274 baduser(void)
277 errx(1, "%s", strerror(EACCES));
280 static void
281 usage(void)
284 fprintf(stderr,
285 "usage: chpass%s %s [user]\n",
286 #ifdef YP
287 " [-d domain] [-h host]",
288 #else
290 #endif
291 "[-a list] [-p encpass] [-s shell] [-e mmm dd yy]");
292 exit(1);