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 }
239 fprintf(stderr
, "usage:\n");
240 for (i
= 0; pw_modules
[i
].pw_init
!= NULL
; i
++)
241 if (! (pw_modules
[i
].invalid
& INIT_INVALID
))
242 fprintf(stderr
, "\t%s %s [user]\n", getprogname(),
243 pw_modules
[i
].usage
);
248 main(int argc
, char **argv
)
252 char optstring
[64]; /* if we ever get more than 64 args, shoot me. */
253 const char *curopt
, *oopt
;
258 /* allow passwd modules to do argv[0] specific processing */
261 for (i
= 0; pw_modules
[i
].pw_init
!= NULL
; i
++) {
262 pw_modules
[i
].invalid
= 0;
263 if (pw_modules
[i
].argv0
) {
265 * If we have a module that matches this progname, be
266 * sure that no modules but those that match this
267 * progname can be used. If we have a module that
268 * matches against a particular progname, but does NOT
269 * match this one, don't use that module.
271 if ((strcmp(getprogname(), pw_modules
[i
].argv0
) == 0) &&
273 for (j
= 0; j
< i
; j
++) {
274 pw_modules
[j
].invalid
|= INIT_INVALID
;
275 (*pw_modules
[j
].pw_end
)();
278 } else if (use_always
== 0)
279 pw_modules
[i
].invalid
|= INIT_INVALID
;
280 } else if (use_always
)
281 pw_modules
[i
].invalid
|= INIT_INVALID
;
283 if (pw_modules
[i
].invalid
)
286 pw_modules
[i
].invalid
|=
287 (*pw_modules
[i
].pw_init
)(getprogname()) ?
288 /* zero on success, non-zero on error */
291 if (! pw_modules
[i
].invalid
)
296 errx(1, "Can't change password.");
298 /* Build the option string from the individual modules' option
299 * strings. Note that two modules can share a single option
303 for (i
= 0; pw_modules
[i
].pw_init
!= NULL
; i
++) {
304 if (pw_modules
[i
].invalid
)
307 curopt
= pw_modules
[i
].args
;
308 while (*curopt
!= '\0') {
309 if ((oopt
= strchr(optstring
, *curopt
)) == NULL
) {
310 optstring
[j
++] = *curopt
;
311 if (curopt
[1] == ':') {
313 optstring
[j
++] = *curopt
;
316 } else if ((oopt
[1] == ':' && curopt
[1] != ':') ||
317 (oopt
[1] != ':' && curopt
[1] == ':')) {
318 errx(1, "NetBSD ERROR! Different password "
319 "modules have two different ideas about "
320 "%c argument format.", curopt
[0]);
326 while ((ch
= getopt(argc
, argv
, optstring
)) != -1)
329 for (i
= 0; pw_modules
[i
].pw_init
!= NULL
; i
++) {
330 if (pw_modules
[i
].invalid
)
332 if ((oopt
= strchr(pw_modules
[i
].args
, ch
)) != NULL
) {
333 j
= (oopt
[1] == ':') ?
334 ! (*pw_modules
[i
].pw_arg
)(ch
, optarg
) :
335 ! (*pw_modules
[i
].pw_arg
)(ch
, NULL
);
337 pw_modules
[i
].invalid
|= ARG_INVALID
;
338 if (pw_modules
[i
].invalid
)
339 (*pw_modules
[i
].pw_end
)();
341 /* arg doesn't match this module */
342 pw_modules
[i
].invalid
|= ARG_INVALID
;
343 (*pw_modules
[i
].pw_end
)();
345 if (! pw_modules
[i
].invalid
)
354 /* select which module to use to actually change the password. */
357 for (i
= 0; pw_modules
[i
].pw_init
!= NULL
; i
++)
358 if (! pw_modules
[i
].invalid
) {
359 pw_modules
[i
].use_class
= (*pw_modules
[i
].pw_arg_end
)();
360 if (pw_modules
[i
].use_class
!= PW_DONT_USE
)
362 if (pw_modules
[i
].use_class
== PW_USE_FORCE
)
369 errx(1, "No valid password module specified.");
374 username
= getlogin();
375 if (username
== NULL
)
376 errx(1, "who are you ??");
389 /* allow for fallback to other chpw() methods. */
390 for (i
= 0; pw_modules
[i
].pw_init
!= NULL
; i
++) {
391 if (pw_modules
[i
].invalid
)
393 if ((use_always
&& pw_modules
[i
].use_class
== PW_USE_FORCE
) ||
394 (!use_always
&& pw_modules
[i
].use_class
== PW_USE
)) {
395 valid
= (*pw_modules
[i
].pw_chpw
)(username
);
396 (*pw_modules
[i
].pw_end
)();
399 /* return value < 0 indicates continuation. */