xref: /onnv-gate/usr/src/cmd/krb5/kadmin/kclient/ksetpw.c (revision 11061:1e27eb9fbdd7)
16656Ssemery /*
26656Ssemery  * CDDL HEADER START
36656Ssemery  *
46656Ssemery  * The contents of this file are subject to the terms of the
56656Ssemery  * Common Development and Distribution License (the "License").
66656Ssemery  * You may not use this file except in compliance with the License.
76656Ssemery  *
86656Ssemery  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96656Ssemery  * or http://www.opensolaris.org/os/licensing.
106656Ssemery  * See the License for the specific language governing permissions
116656Ssemery  * and limitations under the License.
126656Ssemery  *
136656Ssemery  * When distributing Covered Code, include this CDDL HEADER in each
146656Ssemery  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156656Ssemery  * If applicable, add the following below this CDDL HEADER, with the
166656Ssemery  * fields enclosed by brackets "[]" replaced with your own identifying
176656Ssemery  * information: Portions Copyright [yyyy] [name of copyright owner]
186656Ssemery  *
196656Ssemery  * CDDL HEADER END
206656Ssemery  */
216656Ssemery 
226656Ssemery /*
239833SShawn.Emery@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
246656Ssemery  * Use is subject to license terms.
256656Ssemery  */
266656Ssemery 
276656Ssemery #include <stdio.h>
286656Ssemery #include <stdlib.h>
296656Ssemery #include <strings.h>
306656Ssemery #include <locale.h>
316656Ssemery #include <netdb.h>
326656Ssemery #include "k5-int.h"
336656Ssemery 
346656Ssemery #define	QUOTE(x)	#x
356656Ssemery #define	VAL2STR(x)	QUOTE(x)
366656Ssemery 
376656Ssemery static char *whoami = NULL;
386656Ssemery 
396656Ssemery static void kt_add_entry(krb5_context ctx, krb5_keytab kt,
409833SShawn.Emery@Sun.COM 	const krb5_principal princ, const krb5_principal sprinc,
419833SShawn.Emery@Sun.COM 	krb5_enctype enctype, krb5_kvno kvno, const char *pw);
426656Ssemery 
436656Ssemery static krb5_error_code kt_remove_entries(krb5_context ctx, krb5_keytab kt,
446656Ssemery 	const krb5_principal princ);
456656Ssemery 
466656Ssemery static void usage();
476656Ssemery 
486656Ssemery int
main(int argc,char ** argv)496656Ssemery main(int argc, char **argv)
506656Ssemery {
516656Ssemery 	krb5_context ctx = NULL;
526656Ssemery 	krb5_error_code code = 0;
536656Ssemery 	krb5_enctype *enctypes;
546656Ssemery 	int enctype_count = 0;
556656Ssemery 	krb5_ccache cc = NULL;
566656Ssemery 	krb5_keytab kt = NULL;
576656Ssemery 	krb5_kvno kvno = 1;
589833SShawn.Emery@Sun.COM 	krb5_principal victim, salt;
596656Ssemery 	char c, *vprincstr, *ktname, *token, *lasts, *newpw;
606656Ssemery 	int result_code, i, len, nflag = 0;
616656Ssemery 	krb5_data result_code_string, result_string;
626656Ssemery 
636656Ssemery 	(void) setlocale(LC_ALL, "");
646656Ssemery 
656656Ssemery #if !defined(TEXT_DOMAIN)
666656Ssemery #define	TEXT_DOMAIN "SYS_TEST"
676656Ssemery #endif /* TEXT_DOMAIN */
686656Ssemery 
696656Ssemery 	(void) textdomain(TEXT_DOMAIN);
706656Ssemery 
716656Ssemery 	/* Misc init stuff */
726656Ssemery 	(void) memset(&result_code_string, 0, sizeof (result_code_string));
736656Ssemery 	(void) memset(&result_string, 0, sizeof (result_string));
746656Ssemery 
756656Ssemery 	whoami = argv[0];
766656Ssemery 
776656Ssemery 	code = krb5_init_context(&ctx);
786656Ssemery 	if (code != 0) {
796656Ssemery 		com_err(whoami, code, gettext("krb5_init_context() failed"));
806656Ssemery 		exit(1);
816656Ssemery 	}
826656Ssemery 
839833SShawn.Emery@Sun.COM 	while ((c = getopt(argc, argv, "v:c:k:e:ns:")) != -1) {
846656Ssemery 		switch (c) {
856656Ssemery 		case 'n':
866656Ssemery 			nflag++;
876656Ssemery 			break;
886656Ssemery 		case 'k':
896656Ssemery 			if (kt != NULL)
906656Ssemery 				usage();
916656Ssemery 			len = snprintf(NULL, 0, "WRFILE:%s", optarg) + 1;
926656Ssemery 			if ((ktname = malloc(len)) == NULL) {
936656Ssemery 				(void) fprintf(stderr,
946656Ssemery 				    gettext("Couldn't allocate memory\n"));
956656Ssemery 				exit(1);
966656Ssemery 			}
976656Ssemery 			(void) snprintf(ktname, len, "WRFILE:%s", optarg);
986656Ssemery 			if ((code = krb5_kt_resolve(ctx, ktname, &kt)) != 0) {
996656Ssemery 				com_err(whoami, code,
1006656Ssemery 				    gettext("Couldn't open/create "
1016656Ssemery 				    "keytab %s"), optarg);
1026656Ssemery 				exit(1);
1036656Ssemery 			}
1046656Ssemery 			break;
1056656Ssemery 		case 'c':
1066656Ssemery 			if (cc != NULL)
1076656Ssemery 				usage();
1086656Ssemery 			if ((code = krb5_cc_resolve(ctx, optarg, &cc)) != 0) {
1096656Ssemery 				com_err(whoami, code,
1106656Ssemery 				    gettext("Couldn't open ccache %s"), optarg);
1116656Ssemery 				exit(1);
1126656Ssemery 			}
1136656Ssemery 			break;
1146656Ssemery 		case 'e':
1156656Ssemery 			len = strlen(optarg);
1166656Ssemery 			token = strtok_r(optarg, ",\t,", &lasts);
1176656Ssemery 
1186656Ssemery 			if (token == NULL)
1196656Ssemery 				usage();
1206656Ssemery 
1216656Ssemery 			do {
1226656Ssemery 				if (enctype_count++ == 0) {
1236656Ssemery 					enctypes = malloc(sizeof (*enctypes));
1246656Ssemery 				} else {
1256656Ssemery 					enctypes = realloc(enctypes,
1266656Ssemery 					    sizeof (*enctypes) * enctype_count);
1276656Ssemery 				}
1286656Ssemery 				if (enctypes == NULL) {
1296656Ssemery 					(void) fprintf(stderr, gettext
1306656Ssemery 					    ("Couldn't allocate memory"));
1316656Ssemery 					exit(1);
1326656Ssemery 				}
1336656Ssemery 				code = krb5_string_to_enctype(token,
1346656Ssemery 				    &enctypes[enctype_count - 1]);
1356656Ssemery 
1366656Ssemery 				if (code != 0) {
1376656Ssemery 					com_err(whoami, code, gettext("Unknown "
1386656Ssemery 					    "or unsupported enctype %s"),
1396656Ssemery 					    optarg);
1406656Ssemery 					exit(1);
1416656Ssemery 				}
1426656Ssemery 			} while ((token = strtok_r(NULL, ",\t ", &lasts)) !=
1436656Ssemery 			    NULL);
1446656Ssemery 			break;
1456656Ssemery 		case 'v':
1466656Ssemery 			kvno = (krb5_kvno) atoi(optarg);
1476656Ssemery 			break;
1489833SShawn.Emery@Sun.COM 		case 's':
1499833SShawn.Emery@Sun.COM 			vprincstr = optarg;
1509833SShawn.Emery@Sun.COM 			code = krb5_parse_name(ctx, vprincstr, &salt);
1519833SShawn.Emery@Sun.COM 			if (code != 0) {
1529833SShawn.Emery@Sun.COM 				com_err(whoami, code,
1539833SShawn.Emery@Sun.COM 				    gettext("krb5_parse_name(%s) failed"),
1549833SShawn.Emery@Sun.COM 				    vprincstr);
1559833SShawn.Emery@Sun.COM 				exit(1);
1569833SShawn.Emery@Sun.COM 			}
1579833SShawn.Emery@Sun.COM 			break;
1586656Ssemery 		default:
1596656Ssemery 			usage();
1606656Ssemery 			break;
1616656Ssemery 		}
1626656Ssemery 	}
1636656Ssemery 
1646656Ssemery 	if (nflag && enctype_count == 0)
1656656Ssemery 		usage();
1666656Ssemery 
1676656Ssemery 	if (nflag == 0 && cc == NULL &&
1686656Ssemery 	    (code = krb5_cc_default(ctx, &cc)) != 0) {
1696656Ssemery 		com_err(whoami, code, gettext("Could not find a ccache"));
1706656Ssemery 		exit(1);
1716656Ssemery 	}
1726656Ssemery 
1736656Ssemery 	if (enctype_count > 0 && kt == NULL &&
1746656Ssemery 	    (code = krb5_kt_default(ctx, &kt)) != 0) {
1756656Ssemery 		com_err(whoami, code, gettext("No keytab specified"));
1766656Ssemery 		exit(1);
1776656Ssemery 	}
1786656Ssemery 
1796656Ssemery 	if (argc != (optind + 1))
1806656Ssemery 		usage();
1816656Ssemery 
1826656Ssemery 	vprincstr = argv[optind];
1836656Ssemery 	code = krb5_parse_name(ctx, vprincstr, &victim);
1846656Ssemery 	if (code != 0) {
1856656Ssemery 		com_err(whoami, code, gettext("krb5_parse_name(%s) failed"),
1866656Ssemery 		    vprincstr);
1876656Ssemery 		exit(1);
1886656Ssemery 	}
1896656Ssemery 
1906656Ssemery 	if (!isatty(fileno(stdin))) {
1916656Ssemery 		char buf[PASS_MAX + 1];
1926656Ssemery 
1936656Ssemery 		if (scanf("%" VAL2STR(PASS_MAX) "s", &buf) != 1) {
1946656Ssemery 			(void) fprintf(stderr,
1956656Ssemery 			    gettext("Couldn't read new password\n"));
1966656Ssemery 			exit(1);
1976656Ssemery 		}
1986656Ssemery 
1996656Ssemery 		newpw = strdup(buf);
2006656Ssemery 		if (newpw == NULL) {
2016656Ssemery 			(void) fprintf(stderr,
2026656Ssemery 			    gettext("Couldn't allocate memory\n"));
2036656Ssemery 			exit(1);
2046656Ssemery 		}
2056656Ssemery 	} else {
2066656Ssemery 		newpw = getpassphrase(gettext("Enter new password: "));
2076656Ssemery 		if (newpw == NULL) {
2086656Ssemery 			(void) fprintf(stderr,
2096656Ssemery 			    gettext("Couldn't read new password\n"));
2106656Ssemery 			exit(1);
2116656Ssemery 		}
2126656Ssemery 
2136656Ssemery 		newpw = strdup(newpw);
2146656Ssemery 		if (newpw == NULL) {
2156656Ssemery 			(void) fprintf(stderr,
2166656Ssemery 			    gettext("Couldn't allocate memory\n"));
2176656Ssemery 			exit(1);
2186656Ssemery 		}
2196656Ssemery 	}
2206656Ssemery 
2216656Ssemery 	if (nflag == 0) {
2226656Ssemery 		code = krb5_set_password_using_ccache(ctx, cc, newpw, victim,
2236656Ssemery 		    &result_code, &result_code_string, &result_string);
2246656Ssemery 		if (code != 0) {
2256656Ssemery 			com_err(whoami, code,
2266656Ssemery 			    gettext("krb5_set_password() failed"));
2276656Ssemery 			exit(1);
2286656Ssemery 		}
2296656Ssemery 		krb5_cc_close(ctx, cc);
2306656Ssemery 
2316656Ssemery 		(void) printf("Result: %.*s (%d) %.*s\n",
2326656Ssemery 		    result_code == 0 ?
2336656Ssemery 		    strlen("success") : result_code_string.length,
2346656Ssemery 		    result_code == 0 ? "success" : result_code_string.data,
2356656Ssemery 		    result_code,
2366656Ssemery 		    result_string.length, result_string.data);
2376656Ssemery 
2386656Ssemery 		if (result_code != 0) {
2396656Ssemery 			(void) fprintf(stderr, gettext("Exiting...\n"));
2406656Ssemery 			exit(result_code);
2416656Ssemery 		}
2426656Ssemery 	}
2436656Ssemery 
2446656Ssemery 	if (enctype_count && (code = kt_remove_entries(ctx, kt, victim)))
2456656Ssemery 		goto error;
2466656Ssemery 
2476656Ssemery 	for (i = 0; i < enctype_count; i++)
2489833SShawn.Emery@Sun.COM 		kt_add_entry(ctx, kt, victim, salt, enctypes[i], kvno, newpw);
2496656Ssemery 
2506656Ssemery error:
2516656Ssemery 	if (kt != NULL)
2526656Ssemery 		krb5_kt_close(ctx, kt);
2536656Ssemery 
2546656Ssemery 	return (code ? 1 : 0);
2556656Ssemery }
2566656Ssemery 
2576656Ssemery static
2586656Ssemery krb5_error_code
kt_remove_entries(krb5_context ctx,krb5_keytab kt,const krb5_principal princ)2596656Ssemery kt_remove_entries(krb5_context ctx, krb5_keytab kt, const krb5_principal princ)
2606656Ssemery {
2616656Ssemery 	krb5_error_code code;
2626656Ssemery 	krb5_kt_cursor cursor;
2636656Ssemery 	krb5_keytab_entry entry;
2646656Ssemery 
2656656Ssemery 	/*
2666656Ssemery 	 * This is not a fatal error, we expect this to fail in the majority
2676656Ssemery 	 * of cases (when clients are first initialized).
2686656Ssemery 	 */
2696656Ssemery 	code = krb5_kt_get_entry(ctx, kt, princ, 0, 0, &entry);
2706656Ssemery 	if (code != 0) {
2716656Ssemery 		com_err(whoami, code,
2726656Ssemery 		    gettext("Could not retrieve entry in keytab"));
2736656Ssemery 		return (0);
2746656Ssemery 	}
2756656Ssemery 
2766656Ssemery 	krb5_kt_free_entry(ctx, &entry);
2776656Ssemery 
2786656Ssemery 	code = krb5_kt_start_seq_get(ctx, kt, &cursor);
2796656Ssemery 	if (code != 0) {
2806656Ssemery 		com_err(whoami, code, gettext("While starting keytab scan"));
2816656Ssemery 		return (code);
2826656Ssemery 	}
2836656Ssemery 
2846656Ssemery 	while ((code = krb5_kt_next_entry(ctx, kt, &entry, &cursor)) == 0) {
2856656Ssemery 		if (krb5_principal_compare(ctx, princ, entry.principal)) {
2866656Ssemery 
2876656Ssemery 			code = krb5_kt_end_seq_get(ctx, kt, &cursor);
2886656Ssemery 			if (code != 0) {
2896656Ssemery 				com_err(whoami, code,
2906656Ssemery 				    gettext("While temporarily "
2916656Ssemery 				    "ending keytab scan"));
2926656Ssemery 				return (code);
2936656Ssemery 			}
2946656Ssemery 
2956656Ssemery 			code = krb5_kt_remove_entry(ctx, kt, &entry);
2966656Ssemery 			if (code != 0) {
2976656Ssemery 				com_err(whoami, code,
2986656Ssemery 				    gettext("While deleting entry "
2996656Ssemery 				    "from keytab"));
3006656Ssemery 				return (code);
3016656Ssemery 			}
3026656Ssemery 
3036656Ssemery 			code = krb5_kt_start_seq_get(ctx, kt, &cursor);
3046656Ssemery 			if (code != 0) {
3056656Ssemery 				com_err(whoami, code,
3066656Ssemery 				    gettext("While restarting keytab scan"));
3076656Ssemery 				return (code);
3086656Ssemery 			}
3096656Ssemery 		}
3106656Ssemery 
3116656Ssemery 		krb5_kt_free_entry(ctx, &entry);
3126656Ssemery 	}
3136656Ssemery 
3146656Ssemery 	if (code && code != KRB5_KT_END) {
3156656Ssemery 		com_err(whoami, code, gettext("While scanning keytab"));
3166656Ssemery 		return (code);
3176656Ssemery 	}
3186656Ssemery 
3196656Ssemery 	if ((code = krb5_kt_end_seq_get(ctx, kt, &cursor))) {
3206656Ssemery 		com_err(whoami, code, gettext("While ending keytab scan"));
3216656Ssemery 		return (code);
3226656Ssemery 	}
3236656Ssemery 
3246656Ssemery 	return (0);
3256656Ssemery }
3266656Ssemery 
3276656Ssemery static
3286656Ssemery void
kt_add_entry(krb5_context ctx,krb5_keytab kt,const krb5_principal princ,const krb5_principal sprinc,krb5_enctype enctype,krb5_kvno kvno,const char * pw)3296656Ssemery kt_add_entry(krb5_context ctx, krb5_keytab kt, const krb5_principal princ,
3309833SShawn.Emery@Sun.COM 	const krb5_principal sprinc, krb5_enctype enctype, krb5_kvno kvno,
3319833SShawn.Emery@Sun.COM 	const char *pw)
3326656Ssemery {
3336656Ssemery 	krb5_keytab_entry *entry;
3346656Ssemery 	krb5_data password, salt;
3356656Ssemery 	krb5_keyblock key;
3366656Ssemery 	krb5_error_code code;
3376656Ssemery 	char buf[100];
3386656Ssemery 
3396656Ssemery 	if ((code = krb5_enctype_to_string(enctype, buf, sizeof (buf)))) {
3406656Ssemery 		com_err(whoami, code, gettext("Enctype %d has no name!"),
3416656Ssemery 		    enctype);
3426656Ssemery 		return;
3436656Ssemery 	}
3446656Ssemery 	if ((entry = (krb5_keytab_entry *) malloc(sizeof (*entry))) == NULL) {
3456656Ssemery 		(void) fprintf(stderr, gettext("Couldn't allocate memory"));
3466656Ssemery 		return;
3476656Ssemery 	}
3486656Ssemery 
3496656Ssemery 	(void) memset((char *)entry, 0, sizeof (*entry));
3506656Ssemery 
3516656Ssemery 	password.length = strlen(pw);
3526656Ssemery 	password.data = (char *)pw;
3536656Ssemery 
3549833SShawn.Emery@Sun.COM 	if ((code = krb5_principal2salt(ctx, sprinc, &salt)) != 0) {
3556656Ssemery 		com_err(whoami, code,
3566656Ssemery 		    gettext("Could not compute salt for %s"), enctype);
3576656Ssemery 		return;
3586656Ssemery 	}
3596656Ssemery 
3606656Ssemery 	code = krb5_c_string_to_key(ctx, enctype, &password, &salt, &key);
3616656Ssemery 
3626656Ssemery 	if (code != 0) {
3636656Ssemery 		com_err(whoami, code, gettext("Could not compute salt for %s"),
3646656Ssemery 		    enctype);
3656656Ssemery 		krb5_xfree(salt.data);
3666656Ssemery 		return;
3676656Ssemery 	}
3686656Ssemery 
3696656Ssemery 	(void) memcpy(&entry->key, &key, sizeof (krb5_keyblock));
3706656Ssemery 	entry->vno = kvno;
3716656Ssemery 	entry->principal = princ;
3726656Ssemery 
3736656Ssemery 	if ((code = krb5_kt_add_entry(ctx, kt, entry)) != 0) {
3746656Ssemery 		com_err(whoami, code,
3756656Ssemery 		    gettext("Could not add entry to keytab"));
3766656Ssemery 	}
3776656Ssemery }
3786656Ssemery 
3796656Ssemery static
3806656Ssemery void
usage()3816656Ssemery usage()
3826656Ssemery {
3836656Ssemery 	(void) fprintf(stderr, gettext("Usage: %s [-c ccache] [-k keytab] "
384*11061SShawn.Emery@Sun.COM 	    "[-e enctype_list] [-s salt_name] [-n] princ\n"), whoami);
3856656Ssemery 	(void) fprintf(stderr,
3866656Ssemery 	    gettext("\t-n\tDon't set the principal's password\n"));
3876656Ssemery 	(void) fprintf(stderr, gettext("\tenctype_list is a comma or whitespace"
3886656Ssemery 	    " separated list\n"));
3896656Ssemery 	(void) fprintf(stderr, gettext("\tIf -n is used then -k and -e must be "
3906656Ssemery 	    "used\n"));
3916656Ssemery 
3926656Ssemery 	exit(1);
3936656Ssemery }
394