Remove building with NOCRYPTO option
[minix3.git] / usr.bin / passwd / passwd.c
blob15b0eec7509b45fbc44777306a21fbb7fa52357e
1 /* $NetBSD: passwd.c,v 1.30 2009/04/17 20:25:08 dyoung Exp $ */
3 /*
4 * Copyright (c) 1988, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
35 The Regents of the University of California. All rights reserved.");
36 #endif /* not lint */
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "from: @(#)passwd.c 8.3 (Berkeley) 4/2/94";
41 #else
42 __RCSID("$NetBSD: passwd.c,v 1.30 2009/04/17 20:25:08 dyoung Exp $");
43 #endif
44 #endif /* not lint */
46 #include <assert.h>
47 #include <err.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 #include <pwd.h>
54 #include "extern.h"
56 #ifdef USE_PAM
58 static void global_usage(const char *);
60 static const struct pw_module_s {
61 const char *argv0;
62 const char *dbname;
63 char compat_opt;
64 void (*pw_usage)(const char *);
65 void (*pw_process)(const char *, int, char **);
66 } pw_modules[] = {
67 /* "files" -- local password database */
68 { NULL, "files", 'l', pwlocal_usage, pwlocal_process },
69 #ifdef YP
70 /* "nis" -- YP/NIS password database */
71 { NULL, "nis", 'y', pwyp_usage, pwyp_process },
72 { "yppasswd", NULL, 0, pwyp_argv0_usage, pwyp_process },
73 #endif
74 #ifdef KERBEROS5
75 /* "krb5" -- Kerberos 5 password database */
76 { NULL, "krb5", 'k', pwkrb5_usage, pwkrb5_process },
77 { "kpasswd", NULL, 0, pwkrb5_argv0_usage, pwkrb5_process },
78 #endif
79 /* default -- use whatever PAM decides */
80 { NULL, NULL, 0, NULL, pwpam_process },
82 { NULL, NULL, 0, NULL, NULL }
85 static const struct pw_module_s *personality;
87 static void
88 global_usage(const char *prefix)
90 const struct pw_module_s *pwm;
92 (void) fprintf(stderr, "%s %s [user]\n", prefix, getprogname());
93 for (pwm = pw_modules; pwm->pw_process != NULL; pwm++) {
94 if (pwm->argv0 == NULL && pwm->pw_usage != NULL)
95 (*pwm->pw_usage)(" ");
99 void
100 usage(void)
103 if (personality != NULL && personality->pw_usage != NULL)
104 (*personality->pw_usage)("usage:");
105 else
106 global_usage("usage:");
107 exit(1);
111 main(int argc, char **argv)
113 const struct pw_module_s *pwm;
114 const char *username;
115 int ch, i;
116 char opts[16];
118 /* Build opts string from module compat_opts */
119 i = 0;
120 opts[i++] = 'd';
121 opts[i++] = ':';
122 for (pwm = pw_modules; pwm->pw_process != NULL; pwm++) {
123 if (pwm->compat_opt != 0)
124 opts[i++] = pwm->compat_opt;
126 opts[i++] = '\0';
128 /* First, look for personality based on argv[0]. */
129 for (pwm = pw_modules; pwm->pw_process != NULL; pwm++) {
130 if (pwm->argv0 != NULL &&
131 strcmp(pwm->argv0, getprogname()) == 0)
132 goto got_personality;
135 /* Try based on compat_opt or -d. */
136 for (ch = 0, pwm = pw_modules; pwm->pw_process != NULL; pwm++) {
137 if (pwm->argv0 == NULL && pwm->dbname == NULL &&
138 pwm->compat_opt == 0) {
140 * We have reached the default personality case.
141 * Make sure the user didn't provide a bogus
142 * personality name.
144 if (ch == 'd')
145 usage();
146 break;
149 ch = getopt(argc, argv, opts);
150 if (ch == '?')
151 usage();
153 if (ch == 'd' && pwm->dbname != NULL &&
154 strcmp(pwm->dbname, optarg) == 0) {
156 * "passwd -d dbname" matches; this is our
157 * chosen personality.
159 break;
162 if (pwm->compat_opt != 0 && ch == pwm->compat_opt) {
164 * Legacy "passwd -l" or similar matches; this
165 * is our chosen personality.
167 break;
170 /* Reset getopt() and go around again. */
171 optind = 1;
172 optreset = 1;
175 got_personality:
176 personality = pwm;
179 * At this point, optind should be either 1 ("passwd"),
180 * 2 ("passwd -l"), or 3 ("passwd -d files"). Consume
181 * these arguments and reset getopt() for the modules to use.
183 assert(optind >= 1 && optind <= 3);
184 argc -= optind;
185 argv += optind;
186 optind = 0;
187 optreset = 1;
189 username = getlogin();
190 if (username == NULL)
191 errx(1, "who are you ??");
193 (*personality->pw_process)(username, argc, argv);
194 return 0;
197 #else /* ! USE_PAM */
199 static struct pw_module_s {
200 const char *argv0;
201 const char *args;
202 const char *usage;
203 int (*pw_init) __P((const char *));
204 int (*pw_arg) __P((char, const char *));
205 int (*pw_arg_end) __P((void));
206 void (*pw_end) __P((void));
208 int (*pw_chpw) __P((const char*));
209 int invalid;
210 #define INIT_INVALID 1
211 #define ARG_INVALID 2
212 int use_class;
213 } pw_modules[] = {
214 #ifdef KERBEROS5
215 { NULL, "5ku:", "[-5] [-k] [-u principal]",
216 krb5_init, krb5_arg, krb5_arg_end, krb5_end, krb5_chpw, 0, 0 },
217 { "kpasswd", "5ku:", "[-5] [-k] [-u principal]",
218 krb5_init, krb5_arg, krb5_arg_end, krb5_end, krb5_chpw, 0, 0 },
219 #endif
220 #ifdef YP
221 { NULL, "y", "[-y]",
222 yp_init, yp_arg, yp_arg_end, yp_end, yp_chpw, 0, 0 },
223 { "yppasswd", "", "[-y]",
224 yp_init, yp_arg, yp_arg_end, yp_end, yp_chpw, 0, 0 },
225 #endif
226 /* local */
227 { NULL, "l", "[-l]",
228 local_init, local_arg, local_arg_end, local_end, local_chpw, 0, 0 },
230 /* terminator */
231 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
234 #if defined(__minix)
235 static __dead void
236 #else
237 static void
238 #endif /* defined(__minix) */
239 usage(void)
241 int i;
243 fprintf(stderr, "usage:\n");
244 for (i = 0; pw_modules[i].pw_init != NULL; i++)
245 if (! (pw_modules[i].invalid & INIT_INVALID))
246 fprintf(stderr, "\t%s %s [user]\n", getprogname(),
247 pw_modules[i].usage);
248 exit(1);
252 main(int argc, char **argv)
254 int ch;
255 char *username;
256 char optstring[64]; /* if we ever get more than 64 args, shoot me. */
257 const char *curopt, *oopt;
258 int i, j;
259 int valid;
260 int use_always;
262 /* allow passwd modules to do argv[0] specific processing */
263 use_always = 0;
264 valid = 0;
265 for (i = 0; pw_modules[i].pw_init != NULL; i++) {
266 pw_modules[i].invalid = 0;
267 if (pw_modules[i].argv0) {
269 * If we have a module that matches this progname, be
270 * sure that no modules but those that match this
271 * progname can be used. If we have a module that
272 * matches against a particular progname, but does NOT
273 * match this one, don't use that module.
275 if ((strcmp(getprogname(), pw_modules[i].argv0) == 0) &&
276 use_always == 0) {
277 for (j = 0; j < i; j++) {
278 pw_modules[j].invalid |= INIT_INVALID;
279 (*pw_modules[j].pw_end)();
281 use_always = 1;
282 } else if (use_always == 0)
283 pw_modules[i].invalid |= INIT_INVALID;
284 } else if (use_always)
285 pw_modules[i].invalid |= INIT_INVALID;
287 if (pw_modules[i].invalid)
288 continue;
290 pw_modules[i].invalid |=
291 (*pw_modules[i].pw_init)(getprogname()) ?
292 /* zero on success, non-zero on error */
293 INIT_INVALID : 0;
295 if (! pw_modules[i].invalid)
296 valid = 1;
299 if (valid == 0)
300 errx(1, "Can't change password.");
302 /* Build the option string from the individual modules' option
303 * strings. Note that two modules can share a single option
304 * letter. */
305 optstring[0] = '\0';
306 j = 0;
307 for (i = 0; pw_modules[i].pw_init != NULL; i++) {
308 if (pw_modules[i].invalid)
309 continue;
311 curopt = pw_modules[i].args;
312 while (*curopt != '\0') {
313 if ((oopt = strchr(optstring, *curopt)) == NULL) {
314 optstring[j++] = *curopt;
315 if (curopt[1] == ':') {
316 curopt++;
317 optstring[j++] = *curopt;
319 optstring[j] = '\0';
320 } else if ((oopt[1] == ':' && curopt[1] != ':') ||
321 (oopt[1] != ':' && curopt[1] == ':')) {
322 errx(1, "NetBSD ERROR! Different password "
323 "modules have two different ideas about "
324 "%c argument format.", curopt[0]);
326 curopt++;
330 while ((ch = getopt(argc, argv, optstring)) != -1)
332 valid = 0;
333 for (i = 0; pw_modules[i].pw_init != NULL; i++) {
334 if (pw_modules[i].invalid)
335 continue;
336 if ((oopt = strchr(pw_modules[i].args, ch)) != NULL) {
337 j = (oopt[1] == ':') ?
338 ! (*pw_modules[i].pw_arg)(ch, optarg) :
339 ! (*pw_modules[i].pw_arg)(ch, NULL);
340 if (j != 0)
341 pw_modules[i].invalid |= ARG_INVALID;
342 if (pw_modules[i].invalid)
343 (*pw_modules[i].pw_end)();
344 } else {
345 /* arg doesn't match this module */
346 pw_modules[i].invalid |= ARG_INVALID;
347 (*pw_modules[i].pw_end)();
349 if (! pw_modules[i].invalid)
350 valid = 1;
352 if (! valid) {
353 usage();
354 exit(1);
358 /* select which module to use to actually change the password. */
359 use_always = 0;
360 valid = 0;
361 for (i = 0; pw_modules[i].pw_init != NULL; i++)
362 if (! pw_modules[i].invalid) {
363 pw_modules[i].use_class = (*pw_modules[i].pw_arg_end)();
364 if (pw_modules[i].use_class != PW_DONT_USE)
365 valid = 1;
366 if (pw_modules[i].use_class == PW_USE_FORCE)
367 use_always = 1;
371 if (! valid)
372 /* hang the DJ */
373 errx(1, "No valid password module specified.");
375 argc -= optind;
376 argv += optind;
378 username = getlogin();
379 if (username == NULL)
380 errx(1, "who are you ??");
382 switch(argc) {
383 case 0:
384 break;
385 case 1:
386 username = argv[0];
387 break;
388 default:
389 usage();
390 exit(1);
393 /* allow for fallback to other chpw() methods. */
394 for (i = 0; pw_modules[i].pw_init != NULL; i++) {
395 if (pw_modules[i].invalid)
396 continue;
397 if ((use_always && pw_modules[i].use_class == PW_USE_FORCE) ||
398 (!use_always && pw_modules[i].use_class == PW_USE)) {
399 valid = (*pw_modules[i].pw_chpw)(username);
400 (*pw_modules[i].pw_end)();
401 if (valid >= 0)
402 exit(valid);
403 /* return value < 0 indicates continuation. */
406 exit(1);
409 #endif /* USE_PAM */