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
main(int argc,char ** argv)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
kt_remove_entries(krb5_context ctx,krb5_keytab kt,const krb5_principal princ)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
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)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
usage()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