4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
35 #define VAL2STR(x) QUOTE(x)
37 static char *whoami
= NULL
;
39 static void kt_add_entry(krb5_context ctx
, krb5_keytab kt
,
40 const krb5_principal princ
, const krb5_principal sprinc
,
41 krb5_enctype enctype
, krb5_kvno kvno
, const char *pw
);
43 static krb5_error_code
kt_remove_entries(krb5_context ctx
, krb5_keytab kt
,
44 const krb5_principal princ
);
49 main(int argc
, char **argv
)
51 krb5_context ctx
= NULL
;
52 krb5_error_code code
= 0;
53 krb5_enctype
*enctypes
;
54 int enctype_count
= 0;
55 krb5_ccache cc
= NULL
;
56 krb5_keytab kt
= NULL
;
58 krb5_principal victim
, salt
;
59 char c
, *vprincstr
, *ktname
, *token
, *lasts
, *newpw
;
60 int result_code
, i
, len
, nflag
= 0;
61 krb5_data result_code_string
, result_string
;
63 (void) setlocale(LC_ALL
, "");
65 #if !defined(TEXT_DOMAIN)
66 #define TEXT_DOMAIN "SYS_TEST"
67 #endif /* TEXT_DOMAIN */
69 (void) textdomain(TEXT_DOMAIN
);
72 (void) memset(&result_code_string
, 0, sizeof (result_code_string
));
73 (void) memset(&result_string
, 0, sizeof (result_string
));
77 code
= krb5_init_context(&ctx
);
79 com_err(whoami
, code
, gettext("krb5_init_context() failed"));
83 while ((c
= getopt(argc
, argv
, "v:c:k:e:ns:")) != -1) {
91 len
= snprintf(NULL
, 0, "WRFILE:%s", optarg
) + 1;
92 if ((ktname
= malloc(len
)) == NULL
) {
93 (void) fprintf(stderr
,
94 gettext("Couldn't allocate memory\n"));
97 (void) snprintf(ktname
, len
, "WRFILE:%s", optarg
);
98 if ((code
= krb5_kt_resolve(ctx
, ktname
, &kt
)) != 0) {
100 gettext("Couldn't open/create "
101 "keytab %s"), optarg
);
108 if ((code
= krb5_cc_resolve(ctx
, optarg
, &cc
)) != 0) {
109 com_err(whoami
, code
,
110 gettext("Couldn't open ccache %s"), optarg
);
115 len
= strlen(optarg
);
116 token
= strtok_r(optarg
, ",\t,", &lasts
);
122 if (enctype_count
++ == 0) {
123 enctypes
= malloc(sizeof (*enctypes
));
125 enctypes
= reallocarray(enctypes
,
126 enctype_count
, sizeof (*enctypes
));
128 if (enctypes
== NULL
) {
129 (void) fprintf(stderr
, gettext
130 ("Couldn't allocate memory"));
133 code
= krb5_string_to_enctype(token
,
134 &enctypes
[enctype_count
- 1]);
137 com_err(whoami
, code
, gettext("Unknown "
138 "or unsupported enctype %s"),
142 } while ((token
= strtok_r(NULL
, ",\t ", &lasts
)) !=
146 kvno
= (krb5_kvno
) atoi(optarg
);
150 code
= krb5_parse_name(ctx
, vprincstr
, &salt
);
152 com_err(whoami
, code
,
153 gettext("krb5_parse_name(%s) failed"),
164 if (nflag
&& enctype_count
== 0)
167 if (nflag
== 0 && cc
== NULL
&&
168 (code
= krb5_cc_default(ctx
, &cc
)) != 0) {
169 com_err(whoami
, code
, gettext("Could not find a ccache"));
173 if (enctype_count
> 0 && kt
== NULL
&&
174 (code
= krb5_kt_default(ctx
, &kt
)) != 0) {
175 com_err(whoami
, code
, gettext("No keytab specified"));
179 if (argc
!= (optind
+ 1))
182 vprincstr
= argv
[optind
];
183 code
= krb5_parse_name(ctx
, vprincstr
, &victim
);
185 com_err(whoami
, code
, gettext("krb5_parse_name(%s) failed"),
190 if (!isatty(fileno(stdin
))) {
191 char buf
[PASS_MAX
+ 1];
193 if (scanf("%" VAL2STR(PASS_MAX
) "s", &buf
) != 1) {
194 (void) fprintf(stderr
,
195 gettext("Couldn't read new password\n"));
201 (void) fprintf(stderr
,
202 gettext("Couldn't allocate memory\n"));
206 newpw
= getpassphrase(gettext("Enter new password: "));
208 (void) fprintf(stderr
,
209 gettext("Couldn't read new password\n"));
213 newpw
= strdup(newpw
);
215 (void) fprintf(stderr
,
216 gettext("Couldn't allocate memory\n"));
222 code
= krb5_set_password_using_ccache(ctx
, cc
, newpw
, victim
,
223 &result_code
, &result_code_string
, &result_string
);
225 com_err(whoami
, code
,
226 gettext("krb5_set_password() failed"));
229 krb5_cc_close(ctx
, cc
);
231 (void) printf("Result: %.*s (%d) %.*s\n",
233 strlen("success") : result_code_string
.length
,
234 result_code
== 0 ? "success" : result_code_string
.data
,
236 result_string
.length
, result_string
.data
);
238 if (result_code
!= 0) {
239 (void) fprintf(stderr
, gettext("Exiting...\n"));
244 if (enctype_count
&& (code
= kt_remove_entries(ctx
, kt
, victim
)))
247 for (i
= 0; i
< enctype_count
; i
++)
248 kt_add_entry(ctx
, kt
, victim
, salt
, enctypes
[i
], kvno
, newpw
);
252 krb5_kt_close(ctx
, kt
);
254 return (code
? 1 : 0);
259 kt_remove_entries(krb5_context ctx
, krb5_keytab kt
, const krb5_principal princ
)
261 krb5_error_code code
;
262 krb5_kt_cursor cursor
;
263 krb5_keytab_entry entry
;
266 * This is not a fatal error, we expect this to fail in the majority
267 * of cases (when clients are first initialized).
269 code
= krb5_kt_get_entry(ctx
, kt
, princ
, 0, 0, &entry
);
271 com_err(whoami
, code
,
272 gettext("Could not retrieve entry in keytab"));
276 krb5_kt_free_entry(ctx
, &entry
);
278 code
= krb5_kt_start_seq_get(ctx
, kt
, &cursor
);
280 com_err(whoami
, code
, gettext("While starting keytab scan"));
284 while ((code
= krb5_kt_next_entry(ctx
, kt
, &entry
, &cursor
)) == 0) {
285 if (krb5_principal_compare(ctx
, princ
, entry
.principal
)) {
287 code
= krb5_kt_end_seq_get(ctx
, kt
, &cursor
);
289 com_err(whoami
, code
,
290 gettext("While temporarily "
291 "ending keytab scan"));
295 code
= krb5_kt_remove_entry(ctx
, kt
, &entry
);
297 com_err(whoami
, code
,
298 gettext("While deleting entry "
303 code
= krb5_kt_start_seq_get(ctx
, kt
, &cursor
);
305 com_err(whoami
, code
,
306 gettext("While restarting keytab scan"));
311 krb5_kt_free_entry(ctx
, &entry
);
314 if (code
&& code
!= KRB5_KT_END
) {
315 com_err(whoami
, code
, gettext("While scanning keytab"));
319 if ((code
= krb5_kt_end_seq_get(ctx
, kt
, &cursor
))) {
320 com_err(whoami
, code
, gettext("While ending keytab scan"));
329 kt_add_entry(krb5_context ctx
, krb5_keytab kt
, const krb5_principal princ
,
330 const krb5_principal sprinc
, krb5_enctype enctype
, krb5_kvno kvno
,
333 krb5_keytab_entry
*entry
;
334 krb5_data password
, salt
;
336 krb5_error_code code
;
339 if ((code
= krb5_enctype_to_string(enctype
, buf
, sizeof (buf
)))) {
340 com_err(whoami
, code
, gettext("Enctype %d has no name!"),
344 if ((entry
= (krb5_keytab_entry
*) malloc(sizeof (*entry
))) == NULL
) {
345 (void) fprintf(stderr
, gettext("Couldn't allocate memory"));
349 (void) memset((char *)entry
, 0, sizeof (*entry
));
351 password
.length
= strlen(pw
);
352 password
.data
= (char *)pw
;
354 if ((code
= krb5_principal2salt(ctx
, sprinc
, &salt
)) != 0) {
355 com_err(whoami
, code
,
356 gettext("Could not compute salt for %s"), enctype
);
360 code
= krb5_c_string_to_key(ctx
, enctype
, &password
, &salt
, &key
);
363 com_err(whoami
, code
, gettext("Could not compute salt for %s"),
365 krb5_xfree(salt
.data
);
369 (void) memcpy(&entry
->key
, &key
, sizeof (krb5_keyblock
));
371 entry
->principal
= princ
;
373 if ((code
= krb5_kt_add_entry(ctx
, kt
, entry
)) != 0) {
374 com_err(whoami
, code
,
375 gettext("Could not add entry to keytab"));
383 (void) fprintf(stderr
, gettext("Usage: %s [-c ccache] [-k keytab] "
384 "[-e enctype_list] [-s salt_name] [-n] princ\n"), whoami
);
385 (void) fprintf(stderr
,
386 gettext("\t-n\tDon't set the principal's password\n"));
387 (void) fprintf(stderr
, gettext("\tenctype_list is a comma or whitespace"
388 " separated list\n"));
389 (void) fprintf(stderr
, gettext("\tIf -n is used then -k and -e must be "