xref: /minix3/usr.bin/passwd/passwd.c (revision 4684ddb6aab0b36791c8099bc705d6140b3d05d0)
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