xref: /onnv-gate/usr/src/cmd/krb5/kadmin/kclient/ksetpw.c (revision 6656:229d08ee2c75)
1*6656Ssemery /*
2*6656Ssemery  * CDDL HEADER START
3*6656Ssemery  *
4*6656Ssemery  * The contents of this file are subject to the terms of the
5*6656Ssemery  * Common Development and Distribution License (the "License").
6*6656Ssemery  * You may not use this file except in compliance with the License.
7*6656Ssemery  *
8*6656Ssemery  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6656Ssemery  * or http://www.opensolaris.org/os/licensing.
10*6656Ssemery  * See the License for the specific language governing permissions
11*6656Ssemery  * and limitations under the License.
12*6656Ssemery  *
13*6656Ssemery  * When distributing Covered Code, include this CDDL HEADER in each
14*6656Ssemery  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6656Ssemery  * If applicable, add the following below this CDDL HEADER, with the
16*6656Ssemery  * fields enclosed by brackets "[]" replaced with your own identifying
17*6656Ssemery  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6656Ssemery  *
19*6656Ssemery  * CDDL HEADER END
20*6656Ssemery  */
21*6656Ssemery 
22*6656Ssemery /*
23*6656Ssemery  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*6656Ssemery  * Use is subject to license terms.
25*6656Ssemery  */
26*6656Ssemery 
27*6656Ssemery #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*6656Ssemery 
29*6656Ssemery #include <stdio.h>
30*6656Ssemery #include <stdlib.h>
31*6656Ssemery #include <strings.h>
32*6656Ssemery #include <locale.h>
33*6656Ssemery #include <netdb.h>
34*6656Ssemery #include "k5-int.h"
35*6656Ssemery 
36*6656Ssemery #define	QUOTE(x)	#x
37*6656Ssemery #define	VAL2STR(x)	QUOTE(x)
38*6656Ssemery 
39*6656Ssemery static char *whoami = NULL;
40*6656Ssemery 
41*6656Ssemery static void kt_add_entry(krb5_context ctx, krb5_keytab kt,
42*6656Ssemery 	const krb5_principal princ, krb5_enctype enctype, krb5_kvno kvno,
43*6656Ssemery 	const char *pw);
44*6656Ssemery 
45*6656Ssemery static krb5_error_code kt_remove_entries(krb5_context ctx, krb5_keytab kt,
46*6656Ssemery 	const krb5_principal princ);
47*6656Ssemery 
48*6656Ssemery static void usage();
49*6656Ssemery 
50*6656Ssemery int
51*6656Ssemery main(int argc, char **argv)
52*6656Ssemery {
53*6656Ssemery 	krb5_context ctx = NULL;
54*6656Ssemery 	krb5_error_code code = 0;
55*6656Ssemery 	krb5_enctype *enctypes;
56*6656Ssemery 	int enctype_count = 0;
57*6656Ssemery 	krb5_ccache cc = NULL;
58*6656Ssemery 	krb5_keytab kt = NULL;
59*6656Ssemery 	krb5_kvno kvno = 1;
60*6656Ssemery 	krb5_principal victim;
61*6656Ssemery 	char c, *vprincstr, *ktname, *token, *lasts, *newpw;
62*6656Ssemery 	int result_code, i, len, nflag = 0;
63*6656Ssemery 	krb5_data result_code_string, result_string;
64*6656Ssemery 
65*6656Ssemery 	(void) setlocale(LC_ALL, "");
66*6656Ssemery 
67*6656Ssemery #if !defined(TEXT_DOMAIN)
68*6656Ssemery #define	TEXT_DOMAIN "SYS_TEST"
69*6656Ssemery #endif /* TEXT_DOMAIN */
70*6656Ssemery 
71*6656Ssemery 	(void) textdomain(TEXT_DOMAIN);
72*6656Ssemery 
73*6656Ssemery 	/* Misc init stuff */
74*6656Ssemery 	(void) memset(&result_code_string, 0, sizeof (result_code_string));
75*6656Ssemery 	(void) memset(&result_string, 0, sizeof (result_string));
76*6656Ssemery 
77*6656Ssemery 	whoami = argv[0];
78*6656Ssemery 
79*6656Ssemery 	code = krb5_init_context(&ctx);
80*6656Ssemery 	if (code != 0) {
81*6656Ssemery 		com_err(whoami, code, gettext("krb5_init_context() failed"));
82*6656Ssemery 		exit(1);
83*6656Ssemery 	}
84*6656Ssemery 
85*6656Ssemery 	while ((c = getopt(argc, argv, "v:c:k:e:n")) != -1) {
86*6656Ssemery 		switch (c) {
87*6656Ssemery 		case 'n':
88*6656Ssemery 			nflag++;
89*6656Ssemery 			break;
90*6656Ssemery 		case 'k':
91*6656Ssemery 			if (kt != NULL)
92*6656Ssemery 				usage();
93*6656Ssemery 			len = snprintf(NULL, 0, "WRFILE:%s", optarg) + 1;
94*6656Ssemery 			if ((ktname = malloc(len)) == NULL) {
95*6656Ssemery 				(void) fprintf(stderr,
96*6656Ssemery 				    gettext("Couldn't allocate memory\n"));
97*6656Ssemery 				exit(1);
98*6656Ssemery 			}
99*6656Ssemery 			(void) snprintf(ktname, len, "WRFILE:%s", optarg);
100*6656Ssemery 			if ((code = krb5_kt_resolve(ctx, ktname, &kt)) != 0) {
101*6656Ssemery 				com_err(whoami, code,
102*6656Ssemery 				    gettext("Couldn't open/create "
103*6656Ssemery 				    "keytab %s"), optarg);
104*6656Ssemery 				exit(1);
105*6656Ssemery 			}
106*6656Ssemery 			break;
107*6656Ssemery 		case 'c':
108*6656Ssemery 			if (cc != NULL)
109*6656Ssemery 				usage();
110*6656Ssemery 			if ((code = krb5_cc_resolve(ctx, optarg, &cc)) != 0) {
111*6656Ssemery 				com_err(whoami, code,
112*6656Ssemery 				    gettext("Couldn't open ccache %s"), optarg);
113*6656Ssemery 				exit(1);
114*6656Ssemery 			}
115*6656Ssemery 			break;
116*6656Ssemery 		case 'e':
117*6656Ssemery 			len = strlen(optarg);
118*6656Ssemery 			token = strtok_r(optarg, ",\t,", &lasts);
119*6656Ssemery 
120*6656Ssemery 			if (token == NULL)
121*6656Ssemery 				usage();
122*6656Ssemery 
123*6656Ssemery 			do {
124*6656Ssemery 				if (enctype_count++ == 0) {
125*6656Ssemery 					enctypes = malloc(sizeof (*enctypes));
126*6656Ssemery 				} else {
127*6656Ssemery 					enctypes = realloc(enctypes,
128*6656Ssemery 					    sizeof (*enctypes) * enctype_count);
129*6656Ssemery 				}
130*6656Ssemery 				if (enctypes == NULL) {
131*6656Ssemery 					(void) fprintf(stderr, gettext
132*6656Ssemery 					    ("Couldn't allocate memory"));
133*6656Ssemery 					exit(1);
134*6656Ssemery 				}
135*6656Ssemery 				code = krb5_string_to_enctype(token,
136*6656Ssemery 				    &enctypes[enctype_count - 1]);
137*6656Ssemery 
138*6656Ssemery 				if (code != 0) {
139*6656Ssemery 					com_err(whoami, code, gettext("Unknown "
140*6656Ssemery 					    "or unsupported enctype %s"),
141*6656Ssemery 					    optarg);
142*6656Ssemery 					exit(1);
143*6656Ssemery 				}
144*6656Ssemery 			} while ((token = strtok_r(NULL, ",\t ", &lasts)) !=
145*6656Ssemery 			    NULL);
146*6656Ssemery 			break;
147*6656Ssemery 		case 'v':
148*6656Ssemery 			kvno = (krb5_kvno) atoi(optarg);
149*6656Ssemery 			break;
150*6656Ssemery 		default:
151*6656Ssemery 			usage();
152*6656Ssemery 			break;
153*6656Ssemery 		}
154*6656Ssemery 	}
155*6656Ssemery 
156*6656Ssemery 	if (nflag && enctype_count == 0)
157*6656Ssemery 		usage();
158*6656Ssemery 
159*6656Ssemery 	if (nflag == 0 && cc == NULL &&
160*6656Ssemery 	    (code = krb5_cc_default(ctx, &cc)) != 0) {
161*6656Ssemery 		com_err(whoami, code, gettext("Could not find a ccache"));
162*6656Ssemery 		exit(1);
163*6656Ssemery 	}
164*6656Ssemery 
165*6656Ssemery 	if (enctype_count > 0 && kt == NULL &&
166*6656Ssemery 	    (code = krb5_kt_default(ctx, &kt)) != 0) {
167*6656Ssemery 		com_err(whoami, code, gettext("No keytab specified"));
168*6656Ssemery 		exit(1);
169*6656Ssemery 	}
170*6656Ssemery 
171*6656Ssemery 	if (argc != (optind + 1))
172*6656Ssemery 		usage();
173*6656Ssemery 
174*6656Ssemery 	vprincstr = argv[optind];
175*6656Ssemery 	code = krb5_parse_name(ctx, vprincstr, &victim);
176*6656Ssemery 	if (code != 0) {
177*6656Ssemery 		com_err(whoami, code, gettext("krb5_parse_name(%s) failed"),
178*6656Ssemery 		    vprincstr);
179*6656Ssemery 		exit(1);
180*6656Ssemery 	}
181*6656Ssemery 
182*6656Ssemery 	if (!isatty(fileno(stdin))) {
183*6656Ssemery 		char buf[PASS_MAX + 1];
184*6656Ssemery 
185*6656Ssemery 		if (scanf("%" VAL2STR(PASS_MAX) "s", &buf) != 1) {
186*6656Ssemery 			(void) fprintf(stderr,
187*6656Ssemery 			    gettext("Couldn't read new password\n"));
188*6656Ssemery 			exit(1);
189*6656Ssemery 		}
190*6656Ssemery 
191*6656Ssemery 		newpw = strdup(buf);
192*6656Ssemery 		if (newpw == NULL) {
193*6656Ssemery 			(void) fprintf(stderr,
194*6656Ssemery 			    gettext("Couldn't allocate memory\n"));
195*6656Ssemery 			exit(1);
196*6656Ssemery 		}
197*6656Ssemery 	} else {
198*6656Ssemery 		newpw = getpassphrase(gettext("Enter new password: "));
199*6656Ssemery 		if (newpw == NULL) {
200*6656Ssemery 			(void) fprintf(stderr,
201*6656Ssemery 			    gettext("Couldn't read new password\n"));
202*6656Ssemery 			exit(1);
203*6656Ssemery 		}
204*6656Ssemery 
205*6656Ssemery 		newpw = strdup(newpw);
206*6656Ssemery 		if (newpw == NULL) {
207*6656Ssemery 			(void) fprintf(stderr,
208*6656Ssemery 			    gettext("Couldn't allocate memory\n"));
209*6656Ssemery 			exit(1);
210*6656Ssemery 		}
211*6656Ssemery 	}
212*6656Ssemery 
213*6656Ssemery 	if (nflag == 0) {
214*6656Ssemery 		code = krb5_set_password_using_ccache(ctx, cc, newpw, victim,
215*6656Ssemery 		    &result_code, &result_code_string, &result_string);
216*6656Ssemery 		if (code != 0) {
217*6656Ssemery 			com_err(whoami, code,
218*6656Ssemery 			    gettext("krb5_set_password() failed"));
219*6656Ssemery 			exit(1);
220*6656Ssemery 		}
221*6656Ssemery 		krb5_cc_close(ctx, cc);
222*6656Ssemery 
223*6656Ssemery 		(void) printf("Result: %.*s (%d) %.*s\n",
224*6656Ssemery 		    result_code == 0 ?
225*6656Ssemery 		    strlen("success") : result_code_string.length,
226*6656Ssemery 		    result_code == 0 ? "success" : result_code_string.data,
227*6656Ssemery 		    result_code,
228*6656Ssemery 		    result_string.length, result_string.data);
229*6656Ssemery 
230*6656Ssemery 		if (result_code != 0) {
231*6656Ssemery 			(void) fprintf(stderr, gettext("Exiting...\n"));
232*6656Ssemery 			exit(result_code);
233*6656Ssemery 		}
234*6656Ssemery 	}
235*6656Ssemery 
236*6656Ssemery 	if (enctype_count && (code = kt_remove_entries(ctx, kt, victim)))
237*6656Ssemery 		goto error;
238*6656Ssemery 
239*6656Ssemery 	for (i = 0; i < enctype_count; i++)
240*6656Ssemery 		kt_add_entry(ctx, kt, victim, enctypes[i], kvno, newpw);
241*6656Ssemery 
242*6656Ssemery error:
243*6656Ssemery 	if (kt != NULL)
244*6656Ssemery 		krb5_kt_close(ctx, kt);
245*6656Ssemery 
246*6656Ssemery 	return (code ? 1 : 0);
247*6656Ssemery }
248*6656Ssemery 
249*6656Ssemery static
250*6656Ssemery krb5_error_code
251*6656Ssemery kt_remove_entries(krb5_context ctx, krb5_keytab kt, const krb5_principal princ)
252*6656Ssemery {
253*6656Ssemery 	krb5_error_code code;
254*6656Ssemery 	krb5_kt_cursor cursor;
255*6656Ssemery 	krb5_keytab_entry entry;
256*6656Ssemery 
257*6656Ssemery 	/*
258*6656Ssemery 	 * This is not a fatal error, we expect this to fail in the majority
259*6656Ssemery 	 * of cases (when clients are first initialized).
260*6656Ssemery 	 */
261*6656Ssemery 	code = krb5_kt_get_entry(ctx, kt, princ, 0, 0, &entry);
262*6656Ssemery 	if (code != 0) {
263*6656Ssemery 		com_err(whoami, code,
264*6656Ssemery 		    gettext("Could not retrieve entry in keytab"));
265*6656Ssemery 		return (0);
266*6656Ssemery 	}
267*6656Ssemery 
268*6656Ssemery 	krb5_kt_free_entry(ctx, &entry);
269*6656Ssemery 
270*6656Ssemery 	code = krb5_kt_start_seq_get(ctx, kt, &cursor);
271*6656Ssemery 	if (code != 0) {
272*6656Ssemery 		com_err(whoami, code, gettext("While starting keytab scan"));
273*6656Ssemery 		return (code);
274*6656Ssemery 	}
275*6656Ssemery 
276*6656Ssemery 	while ((code = krb5_kt_next_entry(ctx, kt, &entry, &cursor)) == 0) {
277*6656Ssemery 		if (krb5_principal_compare(ctx, princ, entry.principal)) {
278*6656Ssemery 
279*6656Ssemery 			code = krb5_kt_end_seq_get(ctx, kt, &cursor);
280*6656Ssemery 			if (code != 0) {
281*6656Ssemery 				com_err(whoami, code,
282*6656Ssemery 				    gettext("While temporarily "
283*6656Ssemery 				    "ending keytab scan"));
284*6656Ssemery 				return (code);
285*6656Ssemery 			}
286*6656Ssemery 
287*6656Ssemery 			code = krb5_kt_remove_entry(ctx, kt, &entry);
288*6656Ssemery 			if (code != 0) {
289*6656Ssemery 				com_err(whoami, code,
290*6656Ssemery 				    gettext("While deleting entry "
291*6656Ssemery 				    "from keytab"));
292*6656Ssemery 				return (code);
293*6656Ssemery 			}
294*6656Ssemery 
295*6656Ssemery 			code = krb5_kt_start_seq_get(ctx, kt, &cursor);
296*6656Ssemery 			if (code != 0) {
297*6656Ssemery 				com_err(whoami, code,
298*6656Ssemery 				    gettext("While restarting keytab scan"));
299*6656Ssemery 				return (code);
300*6656Ssemery 			}
301*6656Ssemery 		}
302*6656Ssemery 
303*6656Ssemery 		krb5_kt_free_entry(ctx, &entry);
304*6656Ssemery 	}
305*6656Ssemery 
306*6656Ssemery 	if (code && code != KRB5_KT_END) {
307*6656Ssemery 		com_err(whoami, code, gettext("While scanning keytab"));
308*6656Ssemery 		return (code);
309*6656Ssemery 	}
310*6656Ssemery 
311*6656Ssemery 	if ((code = krb5_kt_end_seq_get(ctx, kt, &cursor))) {
312*6656Ssemery 		com_err(whoami, code, gettext("While ending keytab scan"));
313*6656Ssemery 		return (code);
314*6656Ssemery 	}
315*6656Ssemery 
316*6656Ssemery 	return (0);
317*6656Ssemery }
318*6656Ssemery 
319*6656Ssemery static
320*6656Ssemery void
321*6656Ssemery kt_add_entry(krb5_context ctx, krb5_keytab kt, const krb5_principal princ,
322*6656Ssemery 	krb5_enctype enctype, krb5_kvno kvno, const char *pw)
323*6656Ssemery {
324*6656Ssemery 	krb5_keytab_entry *entry;
325*6656Ssemery 	krb5_data password, salt;
326*6656Ssemery 	krb5_keyblock key;
327*6656Ssemery 	krb5_error_code code;
328*6656Ssemery 	char buf[100];
329*6656Ssemery 
330*6656Ssemery 	if ((code = krb5_enctype_to_string(enctype, buf, sizeof (buf)))) {
331*6656Ssemery 		com_err(whoami, code, gettext("Enctype %d has no name!"),
332*6656Ssemery 		    enctype);
333*6656Ssemery 		return;
334*6656Ssemery 	}
335*6656Ssemery 	if ((entry = (krb5_keytab_entry *) malloc(sizeof (*entry))) == NULL) {
336*6656Ssemery 		(void) fprintf(stderr, gettext("Couldn't allocate memory"));
337*6656Ssemery 		return;
338*6656Ssemery 	}
339*6656Ssemery 
340*6656Ssemery 	(void) memset((char *)entry, 0, sizeof (*entry));
341*6656Ssemery 
342*6656Ssemery 	password.length = strlen(pw);
343*6656Ssemery 	password.data = (char *)pw;
344*6656Ssemery 
345*6656Ssemery 	if ((code = krb5_principal2salt(ctx, princ, &salt)) != 0) {
346*6656Ssemery 		com_err(whoami, code,
347*6656Ssemery 		    gettext("Could not compute salt for %s"), enctype);
348*6656Ssemery 		return;
349*6656Ssemery 	}
350*6656Ssemery 
351*6656Ssemery 	code = krb5_c_string_to_key(ctx, enctype, &password, &salt, &key);
352*6656Ssemery 
353*6656Ssemery 	if (code != 0) {
354*6656Ssemery 		com_err(whoami, code, gettext("Could not compute salt for %s"),
355*6656Ssemery 		    enctype);
356*6656Ssemery 		krb5_xfree(salt.data);
357*6656Ssemery 		return;
358*6656Ssemery 	}
359*6656Ssemery 
360*6656Ssemery 	(void) memcpy(&entry->key, &key, sizeof (krb5_keyblock));
361*6656Ssemery 	entry->vno = kvno;
362*6656Ssemery 	entry->principal = princ;
363*6656Ssemery 
364*6656Ssemery 	if ((code = krb5_kt_add_entry(ctx, kt, entry)) != 0) {
365*6656Ssemery 		com_err(whoami, code,
366*6656Ssemery 		    gettext("Could not add entry to keytab"));
367*6656Ssemery 	}
368*6656Ssemery }
369*6656Ssemery 
370*6656Ssemery static
371*6656Ssemery void
372*6656Ssemery usage()
373*6656Ssemery {
374*6656Ssemery 	(void) fprintf(stderr, gettext("Usage: %s [-c ccache] [-k keytab] "
375*6656Ssemery 	    "[-e enctype_list] [-n] princ\n"), whoami);
376*6656Ssemery 	(void) fprintf(stderr,
377*6656Ssemery 	    gettext("\t-n\tDon't set the principal's password\n"));
378*6656Ssemery 	(void) fprintf(stderr, gettext("\tenctype_list is a comma or whitespace"
379*6656Ssemery 	    " separated list\n"));
380*6656Ssemery 	(void) fprintf(stderr, gettext("\tIf -n is used then -k and -e must be "
381*6656Ssemery 	    "used\n"));
382*6656Ssemery 
383*6656Ssemery 	exit(1);
384*6656Ssemery }
385