xref: /minix3/usr.bin/passwd/krb5_passwd.c (revision e8235bc09a635feceeb988fee88e111ac52fa3fc)
1*e8235bc0SLionel Sambuc /* $NetBSD: krb5_passwd.c,v 1.20 2012/04/22 23:43:51 christos Exp $ */
25c007436SBen Gras 
35c007436SBen Gras /*
45c007436SBen Gras  * Copyright (c) 2000, 2005 The NetBSD Foundation, Inc.
55c007436SBen Gras  * All rights reserved.
65c007436SBen Gras  *
75c007436SBen Gras  * This code is derived from software contributed to The NetBSD Foundation
85c007436SBen Gras  * by Johan Danielsson; and by Jason R. Thorpe.
95c007436SBen Gras  *
105c007436SBen Gras  * Redistribution and use in source and binary forms, with or without
115c007436SBen Gras  * modification, are permitted provided that the following conditions
125c007436SBen Gras  * are met:
135c007436SBen Gras  *
145c007436SBen Gras  * 1. Redistributions of source code must retain the above copyright
155c007436SBen Gras  *    notice, this list of conditions and the following disclaimer.
165c007436SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
175c007436SBen Gras  *    notice, this list of conditions and the following disclaimer in the
185c007436SBen Gras  *    documentation and/or other materials provided with the distribution.
195c007436SBen Gras  *
205c007436SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
215c007436SBen Gras  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
225c007436SBen Gras  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
235c007436SBen Gras  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
245c007436SBen Gras  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
255c007436SBen Gras  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
265c007436SBen Gras  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
275c007436SBen Gras  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
285c007436SBen Gras  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
295c007436SBen Gras  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
305c007436SBen Gras  * POSSIBILITY OF SUCH DAMAGE.
315c007436SBen Gras  */
325c007436SBen Gras 
335c007436SBen Gras /* uses the `Kerberos Change Password Protocol' */
345c007436SBen Gras 
355c007436SBen Gras #include <stdio.h>
365c007436SBen Gras #include <stdlib.h>
375c007436SBen Gras #include <string.h>
385c007436SBen Gras #include <err.h>
395c007436SBen Gras #include <errno.h>
405c007436SBen Gras #include <pwd.h>
415c007436SBen Gras #include <unistd.h>
425c007436SBen Gras 
435c007436SBen Gras #include <openssl/ui.h>
445c007436SBen Gras #include <krb5.h>
455c007436SBen Gras 
465c007436SBen Gras #include "extern.h"
475c007436SBen Gras 
48*e8235bc0SLionel Sambuc static void
pwkrb5_warn(const char * msg,krb5_context context,krb5_error_code ret)49*e8235bc0SLionel Sambuc pwkrb5_warn(const char *msg, krb5_context context, krb5_error_code ret)
50*e8235bc0SLionel Sambuc {
51*e8235bc0SLionel Sambuc     const char *errtxt = krb5_get_error_message(context, ret);
52*e8235bc0SLionel Sambuc     if (errtxt != NULL) {
53*e8235bc0SLionel Sambuc 	    warnx("%s: %s", msg, errtxt);
54*e8235bc0SLionel Sambuc 	    krb5_free_error_message(context, errtxt);
55*e8235bc0SLionel Sambuc     } else
56*e8235bc0SLionel Sambuc 	    warnx("%s: %d", msg, ret);
57*e8235bc0SLionel Sambuc }
58*e8235bc0SLionel Sambuc 
595c007436SBen Gras #ifdef USE_PAM
605c007436SBen Gras 
615c007436SBen Gras void
pwkrb5_usage(const char * prefix)625c007436SBen Gras pwkrb5_usage(const char *prefix)
635c007436SBen Gras {
645c007436SBen Gras 
655c007436SBen Gras 	(void) fprintf(stderr, "%s %s [-d krb5 | -k] [principal]\n",
665c007436SBen Gras 	    prefix, getprogname());
675c007436SBen Gras }
685c007436SBen Gras 
695c007436SBen Gras void
pwkrb5_argv0_usage(const char * prefix)705c007436SBen Gras pwkrb5_argv0_usage(const char *prefix)
715c007436SBen Gras {
725c007436SBen Gras 
735c007436SBen Gras 	(void) fprintf(stderr, "%s %s [principal]\n",
745c007436SBen Gras 	    prefix, getprogname());
755c007436SBen Gras }
765c007436SBen Gras 
775c007436SBen Gras void
pwkrb5_process(const char * username,int argc,char ** argv)785c007436SBen Gras pwkrb5_process(const char *username, int argc, char **argv)
795c007436SBen Gras {
805c007436SBen Gras 	krb5_context context;
815c007436SBen Gras 	krb5_error_code ret;
82*e8235bc0SLionel Sambuc 	krb5_get_init_creds_opt *opt;
835c007436SBen Gras 	krb5_principal principal;
845c007436SBen Gras 	krb5_creds cred;
855c007436SBen Gras 	int result_code;
865c007436SBen Gras 	krb5_data result_code_string, result_string;
875c007436SBen Gras 	char pwbuf[BUFSIZ];
885c007436SBen Gras 	int ch;
895c007436SBen Gras 
905c007436SBen Gras 	while ((ch = getopt(argc, argv, "5ku:")) != -1) {
915c007436SBen Gras 		switch (ch) {
925c007436SBen Gras 		case '5':
935c007436SBen Gras 			/*
945c007436SBen Gras 			 * Compatibility option that historically
955c007436SBen Gras 			 * specified to use Kerberos 5.  Silently
965c007436SBen Gras 			 * ignore it.
975c007436SBen Gras 			 */
985c007436SBen Gras 			break;
995c007436SBen Gras 
1005c007436SBen Gras 		case 'k':
1015c007436SBen Gras 			/*
1025c007436SBen Gras 			 * Absorb the -k that may have gotten us here.
1035c007436SBen Gras 			 */
1045c007436SBen Gras 			break;
1055c007436SBen Gras 
1065c007436SBen Gras 		case 'u':
1075c007436SBen Gras 			/*
1085c007436SBen Gras 			 * Historical option to specify principal.
1095c007436SBen Gras 			 */
1105c007436SBen Gras 			username = optarg;
1115c007436SBen Gras 			break;
1125c007436SBen Gras 
1135c007436SBen Gras 		default:
1145c007436SBen Gras 			usage();
1155c007436SBen Gras 			/* NOTREACHED */
1165c007436SBen Gras 		}
1175c007436SBen Gras 	}
1185c007436SBen Gras 
1195c007436SBen Gras 	argc -= optind;
1205c007436SBen Gras 	argv += optind;
1215c007436SBen Gras 
1225c007436SBen Gras 	switch (argc) {
1235c007436SBen Gras 	case 0:
1245c007436SBen Gras 		/* username already provided */
1255c007436SBen Gras 		break;
1265c007436SBen Gras 	case 1:
1275c007436SBen Gras 		/* overrides -u <principal> */
1285c007436SBen Gras 		username = argv[0];
1295c007436SBen Gras 		break;
1305c007436SBen Gras 	default:
1315c007436SBen Gras 		usage();
1325c007436SBen Gras 		/* NOTREACHED */
1335c007436SBen Gras 	}
1345c007436SBen Gras 
1355c007436SBen Gras 	ret = krb5_init_context(&context);
1365c007436SBen Gras 	if (ret != 0) {
1375c007436SBen Gras 		if (ret == ENXIO)
1385c007436SBen Gras 			errx(1, "Kerberos 5 not in use.");
139*e8235bc0SLionel Sambuc 		errx(1, "Unable to initialize Kerberos 5: %s", strerror(ret));
140*e8235bc0SLionel Sambuc 	}
141*e8235bc0SLionel Sambuc 
142*e8235bc0SLionel Sambuc 	ret = krb5_get_init_creds_opt_alloc(context, &opt);
143*e8235bc0SLionel Sambuc 	if (ret) {
144*e8235bc0SLionel Sambuc 		pwkrb5_warn("failed to allocate opts", context, ret);
1455c007436SBen Gras 		goto bad;
1465c007436SBen Gras 	}
1475c007436SBen Gras 
148*e8235bc0SLionel Sambuc 	krb5_get_init_creds_opt_set_tkt_life(opt, 300L);
149*e8235bc0SLionel Sambuc 	krb5_get_init_creds_opt_set_forwardable(opt, FALSE);
150*e8235bc0SLionel Sambuc 	krb5_get_init_creds_opt_set_proxiable(opt, FALSE);
1515c007436SBen Gras 
1525c007436SBen Gras 	ret = krb5_parse_name(context, username, &principal);
1535c007436SBen Gras 	if (ret) {
154*e8235bc0SLionel Sambuc 		krb5_get_init_creds_opt_free(context, opt);
155*e8235bc0SLionel Sambuc 		pwkrb5_warn("failed to parse principal", context, ret);
1565c007436SBen Gras 		goto bad;
1575c007436SBen Gras 	}
1585c007436SBen Gras 
1595c007436SBen Gras 	ret = krb5_get_init_creds_password(context,
1605c007436SBen Gras 					   &cred,
1615c007436SBen Gras 					   principal,
1625c007436SBen Gras 					   NULL,
1635c007436SBen Gras 					   krb5_prompter_posix,
1645c007436SBen Gras 					   NULL,
1655c007436SBen Gras 					   0L,
1665c007436SBen Gras 					   "kadmin/changepw",
167*e8235bc0SLionel Sambuc 					   opt);
1685c007436SBen Gras 
169*e8235bc0SLionel Sambuc 	krb5_get_init_creds_opt_free(context, opt);
1705c007436SBen Gras 	switch (ret) {
1715c007436SBen Gras 	case 0:
1725c007436SBen Gras 		break;
1735c007436SBen Gras 
1745c007436SBen Gras 	case KRB5_LIBOS_PWDINTR :
1755c007436SBen Gras 		/* XXX */
1765c007436SBen Gras 		goto bad;
1775c007436SBen Gras 
1785c007436SBen Gras 	case KRB5KRB_AP_ERR_BAD_INTEGRITY :
1795c007436SBen Gras 	case KRB5KRB_AP_ERR_MODIFIED :
1805c007436SBen Gras 		fprintf(stderr, "Password incorrect\n");
1815c007436SBen Gras 		goto bad;
1825c007436SBen Gras 
1835c007436SBen Gras 	default:
184*e8235bc0SLionel Sambuc 		pwkrb5_warn("failed to get credentials", context, ret);
1855c007436SBen Gras 		goto bad;
1865c007436SBen Gras  	}
1875c007436SBen Gras 
1885c007436SBen Gras 	krb5_data_zero(&result_code_string);
1895c007436SBen Gras 	krb5_data_zero(&result_string);
1905c007436SBen Gras 
1915c007436SBen Gras 	/* XXX use getpass? It has a broken interface. */
1925c007436SBen Gras 	if (UI_UTIL_read_pw_string(pwbuf, sizeof(pwbuf),
1935c007436SBen Gras 				   "New password: ", 1) != 0)
1945c007436SBen Gras 		goto bad;
1955c007436SBen Gras 
1965c007436SBen Gras 	ret = krb5_set_password(context, &cred, pwbuf, NULL,
1975c007436SBen Gras 				&result_code,
1985c007436SBen Gras 				&result_code_string,
1995c007436SBen Gras 				&result_string);
2005c007436SBen Gras 	if (ret) {
201*e8235bc0SLionel Sambuc 		pwkrb5_warn("unable to set password", context, ret);
2025c007436SBen Gras 		goto bad;
2035c007436SBen Gras 	}
2045c007436SBen Gras 
2055c007436SBen Gras 	printf("%s%s%.*s\n",
2065c007436SBen Gras 	    krb5_passwd_result_to_string(context, result_code),
2075c007436SBen Gras 	    result_string.length > 0 ? " : " : "",
2085c007436SBen Gras 	    (int)result_string.length,
2095c007436SBen Gras 	    result_string.length > 0 ? (char *)result_string.data : "");
2105c007436SBen Gras 
2115c007436SBen Gras 	krb5_data_free(&result_code_string);
2125c007436SBen Gras 	krb5_data_free(&result_string);
2135c007436SBen Gras 
2145c007436SBen Gras 	krb5_free_cred_contents(context, &cred);
2155c007436SBen Gras 	krb5_free_context(context);
2165c007436SBen Gras 	if (result_code)
2175c007436SBen Gras 		exit(1);
2185c007436SBen Gras 	return;
2195c007436SBen Gras 
2205c007436SBen Gras  bad:
2215c007436SBen Gras 	krb5_free_context(context);
2225c007436SBen Gras 	exit(1);
2235c007436SBen Gras }
2245c007436SBen Gras 
2255c007436SBen Gras #else /* ! USE_PAM */
2265c007436SBen Gras 
2275c007436SBen Gras static krb5_context defcontext;
2285c007436SBen Gras static krb5_principal defprinc;
2295c007436SBen Gras static int kusage = PW_USE;
2305c007436SBen Gras 
2315c007436SBen Gras int
krb5_init(const char * progname)2325c007436SBen Gras krb5_init(const char *progname)
2335c007436SBen Gras {
2345c007436SBen Gras     return krb5_init_context(&defcontext);
2355c007436SBen Gras }
2365c007436SBen Gras 
2375c007436SBen Gras int
krb5_arg(char ch,const char * opt)2385c007436SBen Gras krb5_arg (char ch, const char *opt)
2395c007436SBen Gras {
2405c007436SBen Gras     krb5_error_code ret;
2415c007436SBen Gras     switch(ch) {
2425c007436SBen Gras     case '5':
2435c007436SBen Gras     case 'k':
2445c007436SBen Gras 	kusage = PW_USE_FORCE;
2455c007436SBen Gras 	return 1;
2465c007436SBen Gras     case 'u':
2475c007436SBen Gras 	ret = krb5_parse_name(defcontext, opt, &defprinc);
2485c007436SBen Gras 	if(ret) {
2495c007436SBen Gras 	    krb5_warn(defcontext, ret, "%s", opt);
2505c007436SBen Gras 	    return 0;
2515c007436SBen Gras 	}
2525c007436SBen Gras 	return 1;
2535c007436SBen Gras     }
2545c007436SBen Gras     return 0;
2555c007436SBen Gras }
2565c007436SBen Gras 
2575c007436SBen Gras int
krb5_arg_end(void)2585c007436SBen Gras krb5_arg_end(void)
2595c007436SBen Gras {
2605c007436SBen Gras     return kusage;
2615c007436SBen Gras }
2625c007436SBen Gras 
2635c007436SBen Gras void
krb5_end(void)2645c007436SBen Gras krb5_end(void)
2655c007436SBen Gras {
2665c007436SBen Gras     if (defcontext == NULL)
2675c007436SBen Gras 	return;
2685c007436SBen Gras     if(defprinc)
2695c007436SBen Gras 	krb5_free_principal(defcontext, defprinc);
2705c007436SBen Gras     krb5_free_context(defcontext);
2715c007436SBen Gras }
2725c007436SBen Gras 
2735c007436SBen Gras int
krb5_chpw(const char * username)2745c007436SBen Gras krb5_chpw(const char *username)
2755c007436SBen Gras {
2765c007436SBen Gras     krb5_error_code ret;
2775c007436SBen Gras     krb5_context context;
2785c007436SBen Gras     krb5_principal principal;
279*e8235bc0SLionel Sambuc     krb5_get_init_creds_opt *opt;
2805c007436SBen Gras     krb5_creds cred;
2815c007436SBen Gras     int result_code;
2825c007436SBen Gras     krb5_data result_code_string, result_string;
2835c007436SBen Gras     char pwbuf[BUFSIZ];
2845c007436SBen Gras 
2855c007436SBen Gras     ret = krb5_init_context (&context);
2865c007436SBen Gras     if (ret) {
287*e8235bc0SLionel Sambuc 	pwkrb5_warn("failed kerberos initialisation", context, ret);
2885c007436SBen Gras 	return 1;
2895c007436SBen Gras     }
2905c007436SBen Gras 
291*e8235bc0SLionel Sambuc     ret = krb5_get_init_creds_opt_alloc (context, &opt);
292*e8235bc0SLionel Sambuc     if (ret) {
293*e8235bc0SLionel Sambuc 	pwkrb5_warn("failed to allocate credential opt", context, ret);
294*e8235bc0SLionel Sambuc 	return 1;
295*e8235bc0SLionel Sambuc     }
2965c007436SBen Gras 
297*e8235bc0SLionel Sambuc     krb5_get_init_creds_opt_set_tkt_life (opt, 300);
298*e8235bc0SLionel Sambuc     krb5_get_init_creds_opt_set_forwardable (opt, FALSE);
299*e8235bc0SLionel Sambuc     krb5_get_init_creds_opt_set_proxiable (opt, FALSE);
3005c007436SBen Gras 
3015c007436SBen Gras     if(username != NULL) {
3025c007436SBen Gras         ret = krb5_parse_name (context, username, &principal);
3035c007436SBen Gras         if (ret) {
304*e8235bc0SLionel Sambuc 	    krb5_get_init_creds_opt_free (context, opt);
305*e8235bc0SLionel Sambuc 	    pwkrb5_warn("failed to parse principal", context, ret);
3065c007436SBen Gras 	    return 1;
3075c007436SBen Gras 	}
3085c007436SBen Gras     } else
3095c007436SBen Gras         principal = defprinc;
3105c007436SBen Gras 
3115c007436SBen Gras     ret = krb5_get_init_creds_password (context,
3125c007436SBen Gras                                         &cred,
3135c007436SBen Gras                                         principal,
3145c007436SBen Gras                                         NULL,
3155c007436SBen Gras                                         krb5_prompter_posix,
3165c007436SBen Gras                                         NULL,
3175c007436SBen Gras                                         0,
3185c007436SBen Gras                                         "kadmin/changepw",
319*e8235bc0SLionel Sambuc                                         opt);
3205c007436SBen Gras 
321*e8235bc0SLionel Sambuc     krb5_get_init_creds_opt_free (context, opt);
3225c007436SBen Gras     switch (ret) {
3235c007436SBen Gras     case 0:
3245c007436SBen Gras         break;
3255c007436SBen Gras     case KRB5_LIBOS_PWDINTR :
3265c007436SBen Gras 	/* XXX */
3275c007436SBen Gras         return 1;
3285c007436SBen Gras     case KRB5KRB_AP_ERR_BAD_INTEGRITY :
3295c007436SBen Gras     case KRB5KRB_AP_ERR_MODIFIED :
3305c007436SBen Gras 	fprintf(stderr, "Password incorrect\n");
3315c007436SBen Gras 	return 1;
3325c007436SBen Gras         break;
3335c007436SBen Gras     default:
334*e8235bc0SLionel Sambuc 	pwkrb5_warn("failed to get credentials", context, ret);
3355c007436SBen Gras 	return 1;
3365c007436SBen Gras     }
3375c007436SBen Gras     krb5_data_zero (&result_code_string);
3385c007436SBen Gras     krb5_data_zero (&result_string);
3395c007436SBen Gras 
3405c007436SBen Gras     /* XXX use getpass? It has a broken interface. */
3415c007436SBen Gras     if(UI_UTIL_read_pw_string(pwbuf, sizeof(pwbuf), "New password: ", 1) != 0)
3425c007436SBen Gras         return 1;
3435c007436SBen Gras 
3445c007436SBen Gras     ret = krb5_set_password (context, &cred, pwbuf, NULL,
3455c007436SBen Gras 			     &result_code,
3465c007436SBen Gras 			     &result_code_string,
3475c007436SBen Gras 			     &result_string);
3485c007436SBen Gras     if (ret)
3495c007436SBen Gras         krb5_err (context, 1, ret, "krb5_set_password");
3505c007436SBen Gras 
3515c007436SBen Gras     printf ("%s%s%.*s\n", krb5_passwd_result_to_string(context, result_code),
3525c007436SBen Gras 	    result_string.length > 0 ? " : " : "",
3535c007436SBen Gras 	    (int)result_string.length,
3545c007436SBen Gras 	    result_string.length > 0 ? (char *)result_string.data : "");
3555c007436SBen Gras 
3565c007436SBen Gras     krb5_data_free (&result_code_string);
3575c007436SBen Gras     krb5_data_free (&result_string);
3585c007436SBen Gras 
3595c007436SBen Gras     krb5_free_cred_contents (context, &cred);
3605c007436SBen Gras     krb5_free_context (context);
3615c007436SBen Gras     return result_code;
3625c007436SBen Gras }
3635c007436SBen Gras 
3645c007436SBen Gras #endif /* USE_PAM */
365