15c007436SBen Gras /* $NetBSD: passwd.c,v 1.30 2009/04/17 20:25:08 dyoung Exp $ */
25c007436SBen Gras
35c007436SBen Gras /*
45c007436SBen Gras * Copyright (c) 1988, 1993, 1994
55c007436SBen Gras * The Regents of the University of California. All rights reserved.
65c007436SBen Gras *
75c007436SBen Gras * Redistribution and use in source and binary forms, with or without
85c007436SBen Gras * modification, are permitted provided that the following conditions
95c007436SBen Gras * are met:
105c007436SBen Gras * 1. Redistributions of source code must retain the above copyright
115c007436SBen Gras * notice, this list of conditions and the following disclaimer.
125c007436SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
135c007436SBen Gras * notice, this list of conditions and the following disclaimer in the
145c007436SBen Gras * documentation and/or other materials provided with the distribution.
155c007436SBen Gras * 3. Neither the name of the University nor the names of its contributors
165c007436SBen Gras * may be used to endorse or promote products derived from this software
175c007436SBen Gras * without specific prior written permission.
185c007436SBen Gras *
195c007436SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
205c007436SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
215c007436SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
225c007436SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
235c007436SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
245c007436SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
255c007436SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
265c007436SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
275c007436SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
285c007436SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
295c007436SBen Gras * SUCH DAMAGE.
305c007436SBen Gras */
315c007436SBen Gras
325c007436SBen Gras #include <sys/cdefs.h>
335c007436SBen Gras #ifndef lint
345c007436SBen Gras __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
355c007436SBen Gras The Regents of the University of California. All rights reserved.");
365c007436SBen Gras #endif /* not lint */
375c007436SBen Gras
385c007436SBen Gras #ifndef lint
395c007436SBen Gras #if 0
405c007436SBen Gras static char sccsid[] = "from: @(#)passwd.c 8.3 (Berkeley) 4/2/94";
415c007436SBen Gras #else
425c007436SBen Gras __RCSID("$NetBSD: passwd.c,v 1.30 2009/04/17 20:25:08 dyoung Exp $");
435c007436SBen Gras #endif
445c007436SBen Gras #endif /* not lint */
455c007436SBen Gras
465c007436SBen Gras #include <assert.h>
475c007436SBen Gras #include <err.h>
485c007436SBen Gras #include <stdio.h>
495c007436SBen Gras #include <stdlib.h>
505c007436SBen Gras #include <string.h>
515c007436SBen Gras #include <unistd.h>
525c007436SBen Gras #include <pwd.h>
535c007436SBen Gras
545c007436SBen Gras #include "extern.h"
555c007436SBen Gras
565c007436SBen Gras #ifdef USE_PAM
575c007436SBen Gras
585c007436SBen Gras static void global_usage(const char *);
595c007436SBen Gras
605c007436SBen Gras static const struct pw_module_s {
615c007436SBen Gras const char *argv0;
625c007436SBen Gras const char *dbname;
635c007436SBen Gras char compat_opt;
645c007436SBen Gras void (*pw_usage)(const char *);
655c007436SBen Gras void (*pw_process)(const char *, int, char **);
665c007436SBen Gras } pw_modules[] = {
675c007436SBen Gras /* "files" -- local password database */
685c007436SBen Gras { NULL, "files", 'l', pwlocal_usage, pwlocal_process },
695c007436SBen Gras #ifdef YP
705c007436SBen Gras /* "nis" -- YP/NIS password database */
715c007436SBen Gras { NULL, "nis", 'y', pwyp_usage, pwyp_process },
725c007436SBen Gras { "yppasswd", NULL, 0, pwyp_argv0_usage, pwyp_process },
735c007436SBen Gras #endif
745c007436SBen Gras #ifdef KERBEROS5
755c007436SBen Gras /* "krb5" -- Kerberos 5 password database */
765c007436SBen Gras { NULL, "krb5", 'k', pwkrb5_usage, pwkrb5_process },
775c007436SBen Gras { "kpasswd", NULL, 0, pwkrb5_argv0_usage, pwkrb5_process },
785c007436SBen Gras #endif
795c007436SBen Gras /* default -- use whatever PAM decides */
805c007436SBen Gras { NULL, NULL, 0, NULL, pwpam_process },
815c007436SBen Gras
825c007436SBen Gras { NULL, NULL, 0, NULL, NULL }
835c007436SBen Gras };
845c007436SBen Gras
855c007436SBen Gras static const struct pw_module_s *personality;
865c007436SBen Gras
875c007436SBen Gras static void
global_usage(const char * prefix)885c007436SBen Gras global_usage(const char *prefix)
895c007436SBen Gras {
905c007436SBen Gras const struct pw_module_s *pwm;
915c007436SBen Gras
925c007436SBen Gras (void) fprintf(stderr, "%s %s [user]\n", prefix, getprogname());
935c007436SBen Gras for (pwm = pw_modules; pwm->pw_process != NULL; pwm++) {
945c007436SBen Gras if (pwm->argv0 == NULL && pwm->pw_usage != NULL)
955c007436SBen Gras (*pwm->pw_usage)(" ");
965c007436SBen Gras }
975c007436SBen Gras }
985c007436SBen Gras
995c007436SBen Gras void
usage(void)1005c007436SBen Gras usage(void)
1015c007436SBen Gras {
1025c007436SBen Gras
1035c007436SBen Gras if (personality != NULL && personality->pw_usage != NULL)
1045c007436SBen Gras (*personality->pw_usage)("usage:");
1055c007436SBen Gras else
1065c007436SBen Gras global_usage("usage:");
1075c007436SBen Gras exit(1);
1085c007436SBen Gras }
1095c007436SBen Gras
1105c007436SBen Gras int
main(int argc,char ** argv)1115c007436SBen Gras main(int argc, char **argv)
1125c007436SBen Gras {
1135c007436SBen Gras const struct pw_module_s *pwm;
1145c007436SBen Gras const char *username;
1155c007436SBen Gras int ch, i;
1165c007436SBen Gras char opts[16];
1175c007436SBen Gras
1185c007436SBen Gras /* Build opts string from module compat_opts */
1195c007436SBen Gras i = 0;
1205c007436SBen Gras opts[i++] = 'd';
1215c007436SBen Gras opts[i++] = ':';
1225c007436SBen Gras for (pwm = pw_modules; pwm->pw_process != NULL; pwm++) {
1235c007436SBen Gras if (pwm->compat_opt != 0)
1245c007436SBen Gras opts[i++] = pwm->compat_opt;
1255c007436SBen Gras }
1265c007436SBen Gras opts[i++] = '\0';
1275c007436SBen Gras
1285c007436SBen Gras /* First, look for personality based on argv[0]. */
1295c007436SBen Gras for (pwm = pw_modules; pwm->pw_process != NULL; pwm++) {
1305c007436SBen Gras if (pwm->argv0 != NULL &&
1315c007436SBen Gras strcmp(pwm->argv0, getprogname()) == 0)
1325c007436SBen Gras goto got_personality;
1335c007436SBen Gras }
1345c007436SBen Gras
1355c007436SBen Gras /* Try based on compat_opt or -d. */
1365c007436SBen Gras for (ch = 0, pwm = pw_modules; pwm->pw_process != NULL; pwm++) {
1375c007436SBen Gras if (pwm->argv0 == NULL && pwm->dbname == NULL &&
1385c007436SBen Gras pwm->compat_opt == 0) {
1395c007436SBen Gras /*
1405c007436SBen Gras * We have reached the default personality case.
1415c007436SBen Gras * Make sure the user didn't provide a bogus
1425c007436SBen Gras * personality name.
1435c007436SBen Gras */
1445c007436SBen Gras if (ch == 'd')
1455c007436SBen Gras usage();
1465c007436SBen Gras break;
1475c007436SBen Gras }
1485c007436SBen Gras
1495c007436SBen Gras ch = getopt(argc, argv, opts);
1505c007436SBen Gras if (ch == '?')
1515c007436SBen Gras usage();
1525c007436SBen Gras
1535c007436SBen Gras if (ch == 'd' && pwm->dbname != NULL &&
1545c007436SBen Gras strcmp(pwm->dbname, optarg) == 0) {
1555c007436SBen Gras /*
1565c007436SBen Gras * "passwd -d dbname" matches; this is our
1575c007436SBen Gras * chosen personality.
1585c007436SBen Gras */
1595c007436SBen Gras break;
1605c007436SBen Gras }
1615c007436SBen Gras
1625c007436SBen Gras if (pwm->compat_opt != 0 && ch == pwm->compat_opt) {
1635c007436SBen Gras /*
1645c007436SBen Gras * Legacy "passwd -l" or similar matches; this
1655c007436SBen Gras * is our chosen personality.
1665c007436SBen Gras */
1675c007436SBen Gras break;
1685c007436SBen Gras }
1695c007436SBen Gras
1705c007436SBen Gras /* Reset getopt() and go around again. */
1715c007436SBen Gras optind = 1;
1725c007436SBen Gras optreset = 1;
1735c007436SBen Gras }
1745c007436SBen Gras
1755c007436SBen Gras got_personality:
1765c007436SBen Gras personality = pwm;
1775c007436SBen Gras
1785c007436SBen Gras /*
1795c007436SBen Gras * At this point, optind should be either 1 ("passwd"),
1805c007436SBen Gras * 2 ("passwd -l"), or 3 ("passwd -d files"). Consume
1815c007436SBen Gras * these arguments and reset getopt() for the modules to use.
1825c007436SBen Gras */
1835c007436SBen Gras assert(optind >= 1 && optind <= 3);
1845c007436SBen Gras argc -= optind;
1855c007436SBen Gras argv += optind;
1865c007436SBen Gras optind = 0;
1875c007436SBen Gras optreset = 1;
1885c007436SBen Gras
1895c007436SBen Gras username = getlogin();
1905c007436SBen Gras if (username == NULL)
1915c007436SBen Gras errx(1, "who are you ??");
1925c007436SBen Gras
1935c007436SBen Gras (*personality->pw_process)(username, argc, argv);
1945c007436SBen Gras return 0;
1955c007436SBen Gras }
1965c007436SBen Gras
1975c007436SBen Gras #else /* ! USE_PAM */
1985c007436SBen Gras
1995c007436SBen Gras static struct pw_module_s {
2005c007436SBen Gras const char *argv0;
2015c007436SBen Gras const char *args;
2025c007436SBen Gras const char *usage;
2035c007436SBen Gras int (*pw_init) __P((const char *));
2045c007436SBen Gras int (*pw_arg) __P((char, const char *));
2055c007436SBen Gras int (*pw_arg_end) __P((void));
2065c007436SBen Gras void (*pw_end) __P((void));
2075c007436SBen Gras
2085c007436SBen Gras int (*pw_chpw) __P((const char*));
2095c007436SBen Gras int invalid;
2105c007436SBen Gras #define INIT_INVALID 1
2115c007436SBen Gras #define ARG_INVALID 2
2125c007436SBen Gras int use_class;
2135c007436SBen Gras } pw_modules[] = {
2145c007436SBen Gras #ifdef KERBEROS5
2155c007436SBen Gras { NULL, "5ku:", "[-5] [-k] [-u principal]",
2165c007436SBen Gras krb5_init, krb5_arg, krb5_arg_end, krb5_end, krb5_chpw, 0, 0 },
2175c007436SBen Gras { "kpasswd", "5ku:", "[-5] [-k] [-u principal]",
2185c007436SBen Gras krb5_init, krb5_arg, krb5_arg_end, krb5_end, krb5_chpw, 0, 0 },
2195c007436SBen Gras #endif
2205c007436SBen Gras #ifdef YP
2215c007436SBen Gras { NULL, "y", "[-y]",
2225c007436SBen Gras yp_init, yp_arg, yp_arg_end, yp_end, yp_chpw, 0, 0 },
2235c007436SBen Gras { "yppasswd", "", "[-y]",
2245c007436SBen Gras yp_init, yp_arg, yp_arg_end, yp_end, yp_chpw, 0, 0 },
2255c007436SBen Gras #endif
2265c007436SBen Gras /* local */
2275c007436SBen Gras { NULL, "l", "[-l]",
2285c007436SBen Gras local_init, local_arg, local_arg_end, local_end, local_chpw, 0, 0 },
2295c007436SBen Gras
2305c007436SBen Gras /* terminator */
2315c007436SBen Gras { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2325c007436SBen Gras };
2335c007436SBen Gras
234*4684ddb6SLionel Sambuc #if defined(__minix)
235*4684ddb6SLionel Sambuc static __dead void
236*4684ddb6SLionel Sambuc #else
2375c007436SBen Gras static void
238*4684ddb6SLionel Sambuc #endif /* defined(__minix) */
usage(void)2395c007436SBen Gras usage(void)
2405c007436SBen Gras {
2415c007436SBen Gras int i;
2425c007436SBen Gras
2435c007436SBen Gras fprintf(stderr, "usage:\n");
2445c007436SBen Gras for (i = 0; pw_modules[i].pw_init != NULL; i++)
2455c007436SBen Gras if (! (pw_modules[i].invalid & INIT_INVALID))
2465c007436SBen Gras fprintf(stderr, "\t%s %s [user]\n", getprogname(),
2475c007436SBen Gras pw_modules[i].usage);
2485c007436SBen Gras exit(1);
2495c007436SBen Gras }
2505c007436SBen Gras
2515c007436SBen Gras int
main(int argc,char ** argv)2525c007436SBen Gras main(int argc, char **argv)
2535c007436SBen Gras {
2545c007436SBen Gras int ch;
2555c007436SBen Gras char *username;
2565c007436SBen Gras char optstring[64]; /* if we ever get more than 64 args, shoot me. */
2575c007436SBen Gras const char *curopt, *oopt;
2585c007436SBen Gras int i, j;
2595c007436SBen Gras int valid;
2605c007436SBen Gras int use_always;
2615c007436SBen Gras
2625c007436SBen Gras /* allow passwd modules to do argv[0] specific processing */
2635c007436SBen Gras use_always = 0;
2645c007436SBen Gras valid = 0;
2655c007436SBen Gras for (i = 0; pw_modules[i].pw_init != NULL; i++) {
2665c007436SBen Gras pw_modules[i].invalid = 0;
2675c007436SBen Gras if (pw_modules[i].argv0) {
2685c007436SBen Gras /*
2695c007436SBen Gras * If we have a module that matches this progname, be
2705c007436SBen Gras * sure that no modules but those that match this
2715c007436SBen Gras * progname can be used. If we have a module that
2725c007436SBen Gras * matches against a particular progname, but does NOT
2735c007436SBen Gras * match this one, don't use that module.
2745c007436SBen Gras */
2755c007436SBen Gras if ((strcmp(getprogname(), pw_modules[i].argv0) == 0) &&
2765c007436SBen Gras use_always == 0) {
2775c007436SBen Gras for (j = 0; j < i; j++) {
2785c007436SBen Gras pw_modules[j].invalid |= INIT_INVALID;
2795c007436SBen Gras (*pw_modules[j].pw_end)();
2805c007436SBen Gras }
2815c007436SBen Gras use_always = 1;
2825c007436SBen Gras } else if (use_always == 0)
2835c007436SBen Gras pw_modules[i].invalid |= INIT_INVALID;
2845c007436SBen Gras } else if (use_always)
2855c007436SBen Gras pw_modules[i].invalid |= INIT_INVALID;
2865c007436SBen Gras
2875c007436SBen Gras if (pw_modules[i].invalid)
2885c007436SBen Gras continue;
2895c007436SBen Gras
2905c007436SBen Gras pw_modules[i].invalid |=
2915c007436SBen Gras (*pw_modules[i].pw_init)(getprogname()) ?
2925c007436SBen Gras /* zero on success, non-zero on error */
2935c007436SBen Gras INIT_INVALID : 0;
2945c007436SBen Gras
2955c007436SBen Gras if (! pw_modules[i].invalid)
2965c007436SBen Gras valid = 1;
2975c007436SBen Gras }
2985c007436SBen Gras
2995c007436SBen Gras if (valid == 0)
3005c007436SBen Gras errx(1, "Can't change password.");
3015c007436SBen Gras
3025c007436SBen Gras /* Build the option string from the individual modules' option
3035c007436SBen Gras * strings. Note that two modules can share a single option
3045c007436SBen Gras * letter. */
3055c007436SBen Gras optstring[0] = '\0';
3065c007436SBen Gras j = 0;
3075c007436SBen Gras for (i = 0; pw_modules[i].pw_init != NULL; i++) {
3085c007436SBen Gras if (pw_modules[i].invalid)
3095c007436SBen Gras continue;
3105c007436SBen Gras
3115c007436SBen Gras curopt = pw_modules[i].args;
3125c007436SBen Gras while (*curopt != '\0') {
3135c007436SBen Gras if ((oopt = strchr(optstring, *curopt)) == NULL) {
3145c007436SBen Gras optstring[j++] = *curopt;
3155c007436SBen Gras if (curopt[1] == ':') {
3165c007436SBen Gras curopt++;
3175c007436SBen Gras optstring[j++] = *curopt;
3185c007436SBen Gras }
3195c007436SBen Gras optstring[j] = '\0';
3205c007436SBen Gras } else if ((oopt[1] == ':' && curopt[1] != ':') ||
3215c007436SBen Gras (oopt[1] != ':' && curopt[1] == ':')) {
3225c007436SBen Gras errx(1, "NetBSD ERROR! Different password "
3235c007436SBen Gras "modules have two different ideas about "
3245c007436SBen Gras "%c argument format.", curopt[0]);
3255c007436SBen Gras }
3265c007436SBen Gras curopt++;
3275c007436SBen Gras }
3285c007436SBen Gras }
3295c007436SBen Gras
3305c007436SBen Gras while ((ch = getopt(argc, argv, optstring)) != -1)
3315c007436SBen Gras {
3325c007436SBen Gras valid = 0;
3335c007436SBen Gras for (i = 0; pw_modules[i].pw_init != NULL; i++) {
3345c007436SBen Gras if (pw_modules[i].invalid)
3355c007436SBen Gras continue;
3365c007436SBen Gras if ((oopt = strchr(pw_modules[i].args, ch)) != NULL) {
3375c007436SBen Gras j = (oopt[1] == ':') ?
3385c007436SBen Gras ! (*pw_modules[i].pw_arg)(ch, optarg) :
3395c007436SBen Gras ! (*pw_modules[i].pw_arg)(ch, NULL);
3405c007436SBen Gras if (j != 0)
3415c007436SBen Gras pw_modules[i].invalid |= ARG_INVALID;
3425c007436SBen Gras if (pw_modules[i].invalid)
3435c007436SBen Gras (*pw_modules[i].pw_end)();
3445c007436SBen Gras } else {
3455c007436SBen Gras /* arg doesn't match this module */
3465c007436SBen Gras pw_modules[i].invalid |= ARG_INVALID;
3475c007436SBen Gras (*pw_modules[i].pw_end)();
3485c007436SBen Gras }
3495c007436SBen Gras if (! pw_modules[i].invalid)
3505c007436SBen Gras valid = 1;
3515c007436SBen Gras }
3525c007436SBen Gras if (! valid) {
3535c007436SBen Gras usage();
3545c007436SBen Gras exit(1);
3555c007436SBen Gras }
3565c007436SBen Gras }
3575c007436SBen Gras
3585c007436SBen Gras /* select which module to use to actually change the password. */
3595c007436SBen Gras use_always = 0;
3605c007436SBen Gras valid = 0;
3615c007436SBen Gras for (i = 0; pw_modules[i].pw_init != NULL; i++)
3625c007436SBen Gras if (! pw_modules[i].invalid) {
3635c007436SBen Gras pw_modules[i].use_class = (*pw_modules[i].pw_arg_end)();
3645c007436SBen Gras if (pw_modules[i].use_class != PW_DONT_USE)
3655c007436SBen Gras valid = 1;
3665c007436SBen Gras if (pw_modules[i].use_class == PW_USE_FORCE)
3675c007436SBen Gras use_always = 1;
3685c007436SBen Gras }
3695c007436SBen Gras
3705c007436SBen Gras
3715c007436SBen Gras if (! valid)
3725c007436SBen Gras /* hang the DJ */
3735c007436SBen Gras errx(1, "No valid password module specified.");
3745c007436SBen Gras
3755c007436SBen Gras argc -= optind;
3765c007436SBen Gras argv += optind;
3775c007436SBen Gras
3785c007436SBen Gras username = getlogin();
3795c007436SBen Gras if (username == NULL)
3805c007436SBen Gras errx(1, "who are you ??");
3815c007436SBen Gras
3825c007436SBen Gras switch(argc) {
3835c007436SBen Gras case 0:
3845c007436SBen Gras break;
3855c007436SBen Gras case 1:
3865c007436SBen Gras username = argv[0];
3875c007436SBen Gras break;
3885c007436SBen Gras default:
3895c007436SBen Gras usage();
3905c007436SBen Gras exit(1);
3915c007436SBen Gras }
3925c007436SBen Gras
3935c007436SBen Gras /* allow for fallback to other chpw() methods. */
3945c007436SBen Gras for (i = 0; pw_modules[i].pw_init != NULL; i++) {
3955c007436SBen Gras if (pw_modules[i].invalid)
3965c007436SBen Gras continue;
3975c007436SBen Gras if ((use_always && pw_modules[i].use_class == PW_USE_FORCE) ||
3985c007436SBen Gras (!use_always && pw_modules[i].use_class == PW_USE)) {
3995c007436SBen Gras valid = (*pw_modules[i].pw_chpw)(username);
4005c007436SBen Gras (*pw_modules[i].pw_end)();
4015c007436SBen Gras if (valid >= 0)
4025c007436SBen Gras exit(valid);
4035c007436SBen Gras /* return value < 0 indicates continuation. */
4045c007436SBen Gras }
4055c007436SBen Gras }
4065c007436SBen Gras exit(1);
4075c007436SBen Gras }
4085c007436SBen Gras
4095c007436SBen Gras #endif /* USE_PAM */
410