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