Home | History | Annotate | Line # | Download | only in passwd
krb5_passwd.c revision 1.13.18.1
      1  1.13.18.1     matt /* krb5_passwd.c,v 1.13 2005/02/26 07:19:25 thorpej Exp */
      2        1.2  thorpej 
      3        1.8  thorpej /*
      4       1.13  thorpej  * Copyright (c) 2000, 2005 The NetBSD Foundation, Inc.
      5        1.1   brezak  * All rights reserved.
      6        1.1   brezak  *
      7       1.13  thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8       1.13  thorpej  * by Johan Danielsson; and by Jason R. Thorpe.
      9        1.8  thorpej  *
     10        1.8  thorpej  * Redistribution and use in source and binary forms, with or without
     11        1.8  thorpej  * modification, are permitted provided that the following conditions
     12        1.8  thorpej  * are met:
     13        1.8  thorpej  *
     14        1.8  thorpej  * 1. Redistributions of source code must retain the above copyright
     15        1.8  thorpej  *    notice, this list of conditions and the following disclaimer.
     16        1.8  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     17        1.8  thorpej  *    notice, this list of conditions and the following disclaimer in the
     18        1.8  thorpej  *    documentation and/or other materials provided with the distribution.
     19       1.13  thorpej  * 3. All advertising materials mentioning features or use of this software
     20       1.13  thorpej  *    must display the following acknowledgement:
     21       1.13  thorpej  *      This product includes software developed by the NetBSD
     22       1.13  thorpej  *      Foundation, Inc. and its contributors.
     23       1.13  thorpej  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24        1.8  thorpej  *    contributors may be used to endorse or promote products derived
     25        1.8  thorpej  *    from this software without specific prior written permission.
     26        1.8  thorpej  *
     27        1.8  thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28        1.8  thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29        1.8  thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30        1.8  thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31        1.8  thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32        1.8  thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33        1.8  thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34        1.8  thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35        1.8  thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36        1.8  thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37        1.8  thorpej  * POSSIBILITY OF SUCH DAMAGE.
     38        1.1   brezak  */
     39        1.1   brezak 
     40        1.8  thorpej /* uses the `Kerberos Change Password Protocol' */
     41        1.8  thorpej 
     42        1.1   brezak #include <stdio.h>
     43        1.5    lukem #include <stdlib.h>
     44        1.1   brezak #include <string.h>
     45        1.8  thorpej #include <err.h>
     46       1.13  thorpej #include <errno.h>
     47        1.9       ad #include <pwd.h>
     48       1.13  thorpej #include <unistd.h>
     49        1.1   brezak 
     50       1.11   itojun #include <openssl/ui.h>
     51        1.8  thorpej #include <krb5.h>
     52        1.1   brezak 
     53        1.8  thorpej #include "extern.h"
     54        1.1   brezak 
     55       1.13  thorpej #ifdef USE_PAM
     56       1.13  thorpej 
     57       1.13  thorpej void
     58       1.13  thorpej pwkrb5_usage(const char *prefix)
     59       1.13  thorpej {
     60       1.13  thorpej 
     61       1.13  thorpej 	(void) fprintf(stderr, "%s %s [-d krb5 | -k] [principal]\n",
     62       1.13  thorpej 	    prefix, getprogname());
     63       1.13  thorpej }
     64       1.13  thorpej 
     65       1.13  thorpej void
     66       1.13  thorpej pwkrb5_argv0_usage(const char *prefix)
     67       1.13  thorpej {
     68       1.13  thorpej 
     69       1.13  thorpej 	(void) fprintf(stderr, "%s %s [principal]\n",
     70       1.13  thorpej 	    prefix, getprogname());
     71       1.13  thorpej }
     72       1.13  thorpej 
     73       1.13  thorpej void
     74       1.13  thorpej pwkrb5_process(const char *username, int argc, char **argv)
     75       1.13  thorpej {
     76       1.13  thorpej 	krb5_context context;
     77       1.13  thorpej 	krb5_error_code ret;
     78       1.13  thorpej 	krb5_get_init_creds_opt opt;
     79       1.13  thorpej 	krb5_principal principal;
     80       1.13  thorpej 	krb5_creds cred;
     81       1.13  thorpej 	int result_code;
     82       1.13  thorpej 	krb5_data result_code_string, result_string;
     83       1.13  thorpej 	char pwbuf[BUFSIZ];
     84       1.13  thorpej 	int ch;
     85       1.13  thorpej 
     86       1.13  thorpej 	while ((ch = getopt(argc, argv, "5ku:")) != -1) {
     87       1.13  thorpej 		switch (ch) {
     88       1.13  thorpej 		case '5':
     89       1.13  thorpej 			/*
     90       1.13  thorpej 			 * Compatibility option that historically
     91       1.13  thorpej 			 * specified to use Kerberos 5.  Silently
     92       1.13  thorpej 			 * ignore it.
     93       1.13  thorpej 			 */
     94       1.13  thorpej 			break;
     95       1.13  thorpej 
     96       1.13  thorpej 		case 'k':
     97       1.13  thorpej 			/*
     98       1.13  thorpej 			 * Absorb the -k that may have gotten us here.
     99       1.13  thorpej 			 */
    100       1.13  thorpej 			break;
    101       1.13  thorpej 
    102       1.13  thorpej 		case 'u':
    103       1.13  thorpej 			/*
    104       1.13  thorpej 			 * Historical option to specify principal.
    105       1.13  thorpej 			 */
    106       1.13  thorpej 			username = optarg;
    107       1.13  thorpej 			break;
    108       1.13  thorpej 
    109       1.13  thorpej 		default:
    110       1.13  thorpej 			usage();
    111       1.13  thorpej 			/* NOTREACHED */
    112       1.13  thorpej 		}
    113       1.13  thorpej 	}
    114       1.13  thorpej 
    115       1.13  thorpej 	argc -= optind;
    116       1.13  thorpej 	argv += optind;
    117       1.13  thorpej 
    118       1.13  thorpej 	switch (argc) {
    119       1.13  thorpej 	case 0:
    120       1.13  thorpej 		/* username already provided */
    121       1.13  thorpej 		break;
    122       1.13  thorpej 	case 1:
    123       1.13  thorpej 		/* overrides -u <principal> */
    124       1.13  thorpej 		username = argv[0];
    125       1.13  thorpej 		break;
    126       1.13  thorpej 	default:
    127       1.13  thorpej 		usage();
    128       1.13  thorpej 		/* NOTREACHED */
    129       1.13  thorpej 	}
    130       1.13  thorpej 
    131       1.13  thorpej 	ret = krb5_init_context(&context);
    132       1.13  thorpej 	if (ret != 0) {
    133       1.13  thorpej 		if (ret == ENXIO)
    134       1.13  thorpej 			errx(1, "Kerberos 5 not in use.");
    135       1.13  thorpej 		warnx("Unable to initialize Kerberos 5: %s",
    136       1.13  thorpej 		    krb5_get_err_text(context, ret));
    137       1.13  thorpej 		goto bad;
    138       1.13  thorpej 	}
    139       1.13  thorpej 
    140       1.13  thorpej 	krb5_get_init_creds_opt_init(&opt);
    141       1.13  thorpej 
    142  1.13.18.1     matt 	krb5_get_init_creds_opt_set_tkt_life(&opt, 300L);
    143       1.13  thorpej 	krb5_get_init_creds_opt_set_forwardable(&opt, FALSE);
    144       1.13  thorpej 	krb5_get_init_creds_opt_set_proxiable(&opt, FALSE);
    145       1.13  thorpej 
    146       1.13  thorpej 	ret = krb5_parse_name(context, username, &principal);
    147       1.13  thorpej 	if (ret) {
    148       1.13  thorpej 		warnx("failed to parse principal: %s",
    149       1.13  thorpej 		    krb5_get_err_text(context, ret));
    150       1.13  thorpej 		goto bad;
    151       1.13  thorpej 	}
    152       1.13  thorpej 
    153       1.13  thorpej 	ret = krb5_get_init_creds_password(context,
    154       1.13  thorpej 					   &cred,
    155       1.13  thorpej 					   principal,
    156       1.13  thorpej 					   NULL,
    157       1.13  thorpej 					   krb5_prompter_posix,
    158       1.13  thorpej 					   NULL,
    159  1.13.18.1     matt 					   0L,
    160       1.13  thorpej 					   "kadmin/changepw",
    161       1.13  thorpej 					   &opt);
    162       1.13  thorpej 
    163       1.13  thorpej 
    164       1.13  thorpej 	switch (ret) {
    165       1.13  thorpej 	case 0:
    166       1.13  thorpej 		break;
    167       1.13  thorpej 
    168       1.13  thorpej 	case KRB5_LIBOS_PWDINTR :
    169       1.13  thorpej 		/* XXX */
    170       1.13  thorpej 		goto bad;
    171       1.13  thorpej 
    172       1.13  thorpej 	case KRB5KRB_AP_ERR_BAD_INTEGRITY :
    173       1.13  thorpej 	case KRB5KRB_AP_ERR_MODIFIED :
    174       1.13  thorpej 		fprintf(stderr, "Password incorrect\n");
    175       1.13  thorpej 		goto bad;
    176       1.13  thorpej 
    177       1.13  thorpej 	default:
    178       1.13  thorpej 		warnx("failed to get credentials: %s",
    179       1.13  thorpej 		    krb5_get_err_text(context, ret));
    180       1.13  thorpej 		goto bad;
    181       1.13  thorpej  	}
    182       1.13  thorpej 
    183       1.13  thorpej 	krb5_data_zero(&result_code_string);
    184       1.13  thorpej 	krb5_data_zero(&result_string);
    185       1.13  thorpej 
    186       1.13  thorpej 	/* XXX use getpass? It has a broken interface. */
    187       1.13  thorpej 	if (UI_UTIL_read_pw_string(pwbuf, sizeof(pwbuf),
    188       1.13  thorpej 				   "New password: ", 1) != 0)
    189       1.13  thorpej 		goto bad;
    190       1.13  thorpej 
    191       1.13  thorpej 	ret = krb5_set_password(context, &cred, pwbuf, NULL,
    192       1.13  thorpej 				&result_code,
    193       1.13  thorpej 				&result_code_string,
    194       1.13  thorpej 				&result_string);
    195       1.13  thorpej 	if (ret) {
    196       1.13  thorpej 		warnx("unable to set password: %s",
    197       1.13  thorpej 		    krb5_get_err_text(context, ret));
    198       1.13  thorpej 		goto bad;
    199       1.13  thorpej 	}
    200       1.13  thorpej 
    201       1.13  thorpej 	printf("%s%s%.*s\n",
    202       1.13  thorpej 	    krb5_passwd_result_to_string(context, result_code),
    203       1.13  thorpej 	    result_string.length > 0 ? " : " : "",
    204       1.13  thorpej 	    (int)result_string.length,
    205       1.13  thorpej 	    result_string.length > 0 ? (char *)result_string.data : "");
    206       1.13  thorpej 
    207       1.13  thorpej 	krb5_data_free(&result_code_string);
    208       1.13  thorpej 	krb5_data_free(&result_string);
    209       1.13  thorpej 
    210       1.13  thorpej 	krb5_free_creds_contents(context, &cred);
    211       1.13  thorpej 	krb5_free_context(context);
    212       1.13  thorpej 	if (result_code)
    213       1.13  thorpej 		exit(1);
    214       1.13  thorpej 	return;
    215       1.13  thorpej 
    216       1.13  thorpej  bad:
    217       1.13  thorpej 	krb5_free_context(context);
    218       1.13  thorpej 	exit(1);
    219       1.13  thorpej }
    220       1.13  thorpej 
    221       1.13  thorpej #else /* ! USE_PAM */
    222       1.13  thorpej 
    223        1.8  thorpej static krb5_context context;
    224        1.8  thorpej static krb5_principal defprinc;
    225       1.13  thorpej static int kusage = PW_USE;
    226        1.1   brezak 
    227        1.3      tls int
    228        1.8  thorpej krb5_init(const char *progname)
    229        1.1   brezak {
    230        1.8  thorpej     return krb5_init_context(&context);
    231        1.8  thorpej }
    232        1.1   brezak 
    233        1.8  thorpej int
    234        1.8  thorpej krb5_arg (char ch, const char *optarg)
    235        1.1   brezak {
    236        1.8  thorpej     krb5_error_code ret;
    237        1.8  thorpej     switch(ch) {
    238        1.8  thorpej     case '5':
    239        1.8  thorpej     case 'k':
    240       1.13  thorpej 	kusage = PW_USE_FORCE;
    241        1.8  thorpej 	return 1;
    242        1.8  thorpej     case 'u':
    243        1.8  thorpej 	ret = krb5_parse_name(context, optarg, &defprinc);
    244        1.8  thorpej 	if(ret) {
    245        1.8  thorpej 	    krb5_warn(context, ret, "%s", optarg);
    246        1.8  thorpej 	    return 0;
    247        1.1   brezak 	}
    248        1.8  thorpej 	return 1;
    249        1.1   brezak     }
    250        1.8  thorpej     return 0;
    251        1.1   brezak }
    252        1.1   brezak 
    253        1.8  thorpej int
    254        1.8  thorpej krb5_arg_end(void)
    255        1.1   brezak {
    256       1.13  thorpej     return kusage;
    257        1.1   brezak }
    258        1.1   brezak 
    259        1.8  thorpej void
    260        1.8  thorpej krb5_end(void)
    261        1.1   brezak {
    262       1.10     fvdl     if (context == NULL)
    263       1.10     fvdl 	return;
    264        1.8  thorpej     if(defprinc)
    265        1.8  thorpej 	krb5_free_principal(context, defprinc);
    266        1.8  thorpej     krb5_free_context(context);
    267        1.1   brezak }
    268        1.1   brezak 
    269        1.1   brezak 
    270        1.8  thorpej int
    271        1.8  thorpej krb5_chpw(const char *username)
    272        1.1   brezak {
    273        1.8  thorpej     krb5_error_code ret;
    274        1.8  thorpej     krb5_context context;
    275        1.8  thorpej     krb5_principal principal;
    276        1.8  thorpej     krb5_get_init_creds_opt opt;
    277        1.8  thorpej     krb5_creds cred;
    278        1.8  thorpej     int result_code;
    279        1.8  thorpej     krb5_data result_code_string, result_string;
    280        1.8  thorpej     char pwbuf[BUFSIZ];
    281        1.8  thorpej 
    282        1.8  thorpej     ret = krb5_init_context (&context);
    283        1.8  thorpej     if (ret) {
    284        1.8  thorpej 	warnx("failed kerberos initialisation: %s",
    285        1.8  thorpej 	      krb5_get_err_text(context, ret));
    286        1.8  thorpej 	return 1;
    287        1.8  thorpej     }
    288        1.8  thorpej 
    289        1.8  thorpej     krb5_get_init_creds_opt_init (&opt);
    290        1.8  thorpej 
    291        1.8  thorpej     krb5_get_init_creds_opt_set_tkt_life (&opt, 300);
    292        1.8  thorpej     krb5_get_init_creds_opt_set_forwardable (&opt, FALSE);
    293        1.8  thorpej     krb5_get_init_creds_opt_set_proxiable (&opt, FALSE);
    294        1.8  thorpej 
    295        1.8  thorpej     if(username != NULL) {
    296        1.8  thorpej         ret = krb5_parse_name (context, username, &principal);
    297        1.8  thorpej         if (ret) {
    298        1.8  thorpej 	    warnx("failed to parse principal: %s",
    299        1.8  thorpej 		  krb5_get_err_text(context, ret));
    300        1.8  thorpej 	    return 1;
    301        1.1   brezak 	}
    302        1.8  thorpej     } else
    303        1.8  thorpej         principal = defprinc;
    304        1.1   brezak 
    305        1.8  thorpej     ret = krb5_get_init_creds_password (context,
    306        1.8  thorpej                                         &cred,
    307        1.8  thorpej                                         principal,
    308        1.8  thorpej                                         NULL,
    309        1.8  thorpej                                         krb5_prompter_posix,
    310        1.8  thorpej                                         NULL,
    311        1.8  thorpej                                         0,
    312        1.8  thorpej                                         "kadmin/changepw",
    313        1.8  thorpej                                         &opt);
    314        1.8  thorpej 
    315        1.8  thorpej     switch (ret) {
    316        1.8  thorpej     case 0:
    317        1.8  thorpej         break;
    318        1.8  thorpej     case KRB5_LIBOS_PWDINTR :
    319        1.8  thorpej 	/* XXX */
    320        1.8  thorpej         return 1;
    321        1.8  thorpej     case KRB5KRB_AP_ERR_BAD_INTEGRITY :
    322        1.8  thorpej     case KRB5KRB_AP_ERR_MODIFIED :
    323        1.8  thorpej 	fprintf(stderr, "Password incorrect\n");
    324        1.8  thorpej 	return 1;
    325        1.8  thorpej         break;
    326        1.8  thorpej     default:
    327        1.8  thorpej 	warnx("failed to get credentials: %s",
    328        1.8  thorpej 	      krb5_get_err_text(context, ret));
    329        1.8  thorpej 	return 1;
    330        1.8  thorpej     }
    331        1.8  thorpej     krb5_data_zero (&result_code_string);
    332        1.8  thorpej     krb5_data_zero (&result_string);
    333        1.8  thorpej 
    334        1.8  thorpej     /* XXX use getpass? It has a broken interface. */
    335       1.11   itojun     if(UI_UTIL_read_pw_string(pwbuf, sizeof(pwbuf), "New password: ", 1) != 0)
    336        1.8  thorpej         return 1;
    337        1.8  thorpej 
    338       1.12      lha     ret = krb5_set_password (context, &cred, pwbuf, NULL,
    339       1.12      lha 			     &result_code,
    340       1.12      lha 			     &result_code_string,
    341       1.12      lha 			     &result_string);
    342        1.8  thorpej     if (ret)
    343       1.12      lha         krb5_err (context, 1, ret, "krb5_set_password");
    344        1.8  thorpej 
    345       1.12      lha     printf ("%s%s%.*s\n", krb5_passwd_result_to_string(context, result_code),
    346       1.12      lha 	    result_string.length > 0 ? " : " : "",
    347       1.12      lha 	    (int)result_string.length,
    348       1.12      lha 	    result_string.length > 0 ? (char *)result_string.data : "");
    349        1.8  thorpej 
    350        1.8  thorpej     krb5_data_free (&result_code_string);
    351        1.8  thorpej     krb5_data_free (&result_string);
    352        1.8  thorpej 
    353        1.8  thorpej     krb5_free_creds_contents (context, &cred);
    354        1.8  thorpej     krb5_free_context (context);
    355        1.8  thorpej     return result_code;
    356        1.1   brezak }
    357       1.13  thorpej 
    358       1.13  thorpej #endif /* USE_PAM */
    359