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