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