1 /* $NetBSD: passwd.c,v 1.30 2009/04/17 20:25:08 dyoung Exp $ */
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
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
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "from: @(#)passwd.c 8.3 (Berkeley) 4/2/94";
42 __RCSID("$NetBSD: passwd.c,v 1.30 2009/04/17 20:25:08 dyoung Exp $");
58 static void global_usage(const char *);
60 static const struct pw_module_s
{
64 void (*pw_usage
)(const char *);
65 void (*pw_process
)(const char *, int, char **);
67 /* "files" -- local password database */
68 { NULL
, "files", 'l', pwlocal_usage
, pwlocal_process
},
70 /* "nis" -- YP/NIS password database */
71 { NULL
, "nis", 'y', pwyp_usage
, pwyp_process
},
72 { "yppasswd", NULL
, 0, pwyp_argv0_usage
, pwyp_process
},
75 /* "krb5" -- Kerberos 5 password database */
76 { NULL
, "krb5", 'k', pwkrb5_usage
, pwkrb5_process
},
77 { "kpasswd", NULL
, 0, pwkrb5_argv0_usage
, pwkrb5_process
},
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
;
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
)(" ");
103 if (personality
!= NULL
&& personality
->pw_usage
!= NULL
)
104 (*personality
->pw_usage
)("usage:");
106 global_usage("usage:");
111 main(int argc
, char **argv
)
113 const struct pw_module_s
*pwm
;
114 const char *username
;
118 /* Build opts string from module compat_opts */
122 for (pwm
= pw_modules
; pwm
->pw_process
!= NULL
; pwm
++) {
123 if (pwm
->compat_opt
!= 0)
124 opts
[i
++] = pwm
->compat_opt
;
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
149 ch
= getopt(argc
, argv
, opts
);
153 if (ch
== 'd' && pwm
->dbname
!= NULL
&&
154 strcmp(pwm
->dbname
, optarg
) == 0) {
156 * "passwd -d dbname" matches; this is our
157 * chosen personality.
162 if (pwm
->compat_opt
!= 0 && ch
== pwm
->compat_opt
) {
164 * Legacy "passwd -l" or similar matches; this
165 * is our chosen personality.
170 /* Reset getopt() and go around again. */
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);
189 username
= getlogin();
190 if (username
== NULL
)
191 errx(1, "who are you ??");
193 (*personality
->pw_process
)(username
, argc
, argv
);
197 #else /* ! USE_PAM */
199 static struct pw_module_s
{
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*));
210 #define INIT_INVALID 1
211 #define ARG_INVALID 2
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 },
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 },
228 local_init
, local_arg
, local_arg_end
, local_end
, local_chpw
, 0, 0 },
231 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
238 #endif /* defined(__minix) */
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
);
252 main(int argc
, char **argv
)
256 char optstring
[64]; /* if we ever get more than 64 args, shoot me. */
257 const char *curopt
, *oopt
;
262 /* allow passwd modules to do argv[0] specific processing */
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) &&
277 for (j
= 0; j
< i
; j
++) {
278 pw_modules
[j
].invalid
|= INIT_INVALID
;
279 (*pw_modules
[j
].pw_end
)();
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
)
290 pw_modules
[i
].invalid
|=
291 (*pw_modules
[i
].pw_init
)(getprogname()) ?
292 /* zero on success, non-zero on error */
295 if (! pw_modules
[i
].invalid
)
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
307 for (i
= 0; pw_modules
[i
].pw_init
!= NULL
; i
++) {
308 if (pw_modules
[i
].invalid
)
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] == ':') {
317 optstring
[j
++] = *curopt
;
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]);
330 while ((ch
= getopt(argc
, argv
, optstring
)) != -1)
333 for (i
= 0; pw_modules
[i
].pw_init
!= NULL
; i
++) {
334 if (pw_modules
[i
].invalid
)
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
);
341 pw_modules
[i
].invalid
|= ARG_INVALID
;
342 if (pw_modules
[i
].invalid
)
343 (*pw_modules
[i
].pw_end
)();
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
)
358 /* select which module to use to actually change the password. */
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
)
366 if (pw_modules
[i
].use_class
== PW_USE_FORCE
)
373 errx(1, "No valid password module specified.");
378 username
= getlogin();
379 if (username
== NULL
)
380 errx(1, "who are you ??");
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
)
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
)();
403 /* return value < 0 indicates continuation. */