dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / krb5 / kadmin / cli / keytab.c
blob4cd6fef18ad931a11e6f395493688a847281d345
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
7 /*
8 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
10 * $Id: keytab.c,v 1.28 2004/05/31 12:39:16 epeisach Exp $
11 * $Source: /cvs/krbdev/krb5/src/kadmin/cli/keytab.c,v $
15 * Copyright (C) 1998 by the FundsXpress, INC.
17 * All rights reserved.
19 * Export of this software from the United States of America may require
20 * a specific license from the United States Government. It is the
21 * responsibility of any person or organization contemplating export to
22 * obtain such a license before exporting.
24 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
25 * distribute this software and its documentation for any purpose and
26 * without fee is hereby granted, provided that the above copyright
27 * notice appear in all copies and that both that copyright notice and
28 * this permission notice appear in supporting documentation, and that
29 * the name of FundsXpress. not be used in advertising or publicity pertaining
30 * to distribution of the software without specific, written prior
31 * permission. FundsXpress makes no representations about the suitability of
32 * this software for any purpose. It is provided "as is" without express
33 * or implied warranty.
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
36 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
37 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
40 static char *rcsid = "$Header: /cvs/krbdev/krb5/src/kadmin/cli/keytab.c,v 1.28 2004/05/31 12:39:16 epeisach Exp $";
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <libintl.h>
47 #include <kadm5/admin.h>
48 #include <krb5/adm_proto.h>
49 #include "kadmin.h"
50 #include <krb5.h>
52 static int add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,
53 krb5_boolean keepold,
54 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
55 char *princ_str);
56 static int remove_principal(char *keytab_str, krb5_keytab keytab, char
57 *princ_str, char *kvno_str);
58 static char *etype_string(krb5_enctype enctype);
59 static char *etype_istring(krb5_enctype enctype);
61 static int quiet;
63 static void add_usage()
65 fprintf(stderr, "%s: %s\n", gettext("Usage"),
66 "ktadd [-k[eytab] keytab] [-q] [-e keysaltlist] "
67 "[principal | -glob princ-exp] [...]\n");
70 static void rem_usage()
72 fprintf(stderr, "%s: %s\n",
73 gettext("Usage"),
74 "ktremove [-k[eytab] keytab] [-q] principal "
75 "[kvno|\"all\"|\"old\"]\n");
78 static int process_keytab(krb5_context my_context, char **keytab_str,
79 krb5_keytab *keytab)
81 int code;
82 char buf[BUFSIZ];
84 if (*keytab_str == NULL) {
85 if (code = krb5_kt_default(my_context, keytab)) {
86 com_err(whoami, code, gettext("while opening default keytab"));
87 return 1;
89 if (code = krb5_kt_get_name(my_context, *keytab, buf, BUFSIZ)) {
90 com_err(whoami, code, gettext("while retrieving keytab name"));
91 return 1;
93 if (!(*keytab_str = strdup(buf))) {
94 com_err(whoami, ENOMEM, gettext("while creating keytab name"));
95 return 1;
97 } else {
98 if (strchr(*keytab_str, ':') != NULL) {
99 *keytab_str = strdup(*keytab_str);
100 if (*keytab_str == NULL) {
101 com_err(whoami, ENOMEM,
102 gettext("while creating keytab name"));
103 return 1;
105 } else {
106 char *tmp = *keytab_str;
108 *keytab_str = (char *)
109 malloc(strlen("WRFILE:")+strlen(tmp)+1);
110 if (*keytab_str == NULL) {
111 com_err(whoami, ENOMEM,
112 gettext("while creating keytab name"));
113 return 1;
115 sprintf(*keytab_str, "WRFILE:%s", tmp);
118 code = krb5_kt_resolve(my_context, *keytab_str, keytab);
119 if (code != 0) {
120 com_err(whoami, code,
121 gettext("while resolving keytab %s"), *keytab_str);
122 free(keytab_str);
123 return 1;
127 return 0;
131 void kadmin_keytab_add(int argc, char **argv)
133 krb5_keytab keytab = 0;
134 char *keytab_str = NULL, **princs;
135 int code, num, i;
136 krb5_error_code retval;
137 int n_ks_tuple = 0;
138 krb5_boolean keepold = FALSE;
139 krb5_key_salt_tuple *ks_tuple = NULL;
141 argc--; argv++;
142 quiet = 0;
143 while (argc) {
144 if (strncmp(*argv, "-k", 2) == 0) {
145 argc--; argv++;
146 if (!argc || keytab_str) {
147 add_usage();
148 return;
150 keytab_str = *argv;
151 } else if (strcmp(*argv, "-q") == 0) {
152 quiet++;
153 } else if (strcmp(*argv, "-e") == 0) {
154 argc--;
155 if (argc < 1) {
156 add_usage();
157 return;
159 retval = krb5_string_to_keysalts(*++argv, ", \t", ":.-", 0,
160 &ks_tuple, &n_ks_tuple);
161 if (retval) {
162 com_err("ktadd", retval,
163 gettext("while parsing keysalts %s"),
164 *argv);
166 return;
168 } else
169 break;
170 argc--; argv++;
173 if (argc == 0) {
174 add_usage();
175 return;
178 if (process_keytab(context, &keytab_str, &keytab))
179 return;
181 while (*argv) {
182 if (strcmp(*argv, "-glob") == 0) {
183 if (*++argv == NULL) {
184 add_usage();
185 break;
188 code = kadm5_get_principals(handle, *argv, &princs, &num);
189 if (code) {
190 com_err(whoami, code,
191 gettext("while expanding expression "
192 "\"%s\"."),
193 *argv);
194 argv++;
195 continue;
198 for (i = 0; i < num; i++)
199 (void) add_principal(handle, keytab_str, keytab,
200 keepold, n_ks_tuple, ks_tuple,
201 princs[i]);
202 kadm5_free_name_list(handle, princs, num);
203 } else
204 (void) add_principal(handle, keytab_str, keytab,
205 keepold, n_ks_tuple, ks_tuple,
206 *argv);
207 argv++;
210 code = krb5_kt_close(context, keytab);
211 if (code != 0)
212 com_err(whoami, code, gettext("while closing keytab"));
214 free(keytab_str);
217 void kadmin_keytab_remove(int argc, char **argv)
219 krb5_keytab keytab = 0;
220 char *keytab_str = NULL;
221 int code;
223 argc--; argv++;
224 quiet = 0;
225 while (argc) {
226 if (strncmp(*argv, "-k", 2) == 0) {
227 argc--; argv++;
228 if (!argc || keytab_str) {
229 rem_usage();
230 return;
232 keytab_str = *argv;
233 } else if (strcmp(*argv, "-q") == 0) {
234 quiet++;
235 } else
236 break;
237 argc--; argv++;
240 if (argc != 1 && argc != 2) {
241 rem_usage();
242 return;
244 if (process_keytab(context, &keytab_str, &keytab))
245 return;
247 (void) remove_principal(keytab_str, keytab, argv[0], argv[1]);
249 code = krb5_kt_close(context, keytab);
250 if (code != 0)
251 com_err(whoami, code, gettext("while closing keytab"));
253 free(keytab_str);
256 static
257 int add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,
258 krb5_boolean keepold, int n_ks_tuple,
259 krb5_key_salt_tuple *ks_tuple,
260 char *princ_str)
262 kadm5_principal_ent_rec princ_rec;
263 krb5_principal princ;
264 krb5_keytab_entry new_entry;
265 krb5_keyblock *keys;
266 int code, nkeys, i;
267 int nktypes = 0;
268 krb5_key_salt_tuple *permitted_etypes = NULL;
270 (void) memset((char *)&princ_rec, 0, sizeof(princ_rec));
272 princ = NULL;
273 keys = NULL;
274 nkeys = 0;
276 code = krb5_parse_name(context, princ_str, &princ);
277 if (code != 0) {
278 com_err(whoami, code,
279 gettext("while parsing -add principal name %s"),
280 princ_str);
281 goto cleanup;
284 if (ks_tuple == NULL) {
285 krb5_enctype *ptr, *ktypes = NULL;
287 code = krb5_get_permitted_enctypes(context, &ktypes);
288 if (!code && ktypes && *ktypes) {
289 krb5_int32 salttype;
291 * Count the results. This is stupid, the API above
292 * should have included an output param to indicate
293 * the size of the list that is returned.
295 for (ptr = ktypes; *ptr; ptr++) nktypes++;
297 /* Allocate a new key-salt tuple set */
298 permitted_etypes = (krb5_key_salt_tuple *)malloc (
299 sizeof (krb5_key_salt_tuple) * nktypes);
300 if (permitted_etypes == NULL) {
301 free(ktypes);
302 return (ENOMEM);
306 * Because the keysalt parameter doesn't matter for
307 * keys stored in the keytab, use the default "normal"
308 * salt for all keys
310 (void) krb5_string_to_salttype("normal", &salttype);
311 for (i = 0; i < nktypes; i++) {
312 permitted_etypes[i].ks_enctype = ktypes[i];
313 permitted_etypes[i].ks_salttype = salttype;
315 free(ktypes);
316 } else {
317 free(ktypes);
318 goto cleanup;
320 } else {
321 permitted_etypes = ks_tuple;
322 nktypes = n_ks_tuple;
325 code = kadm5_randkey_principal_3(lhandle, princ,
326 keepold, nktypes, permitted_etypes,
327 &keys, &nkeys);
329 #ifndef _KADMIN_LOCAL_
330 /* this block is not needed in the kadmin.local client */
333 * If the above call failed, we may be talking to an older
334 * admin server, so try the older API.
336 if (code == KADM5_RPC_ERROR) {
337 code = kadm5_randkey_principal_old(handle, princ, &keys, &nkeys);
339 #endif /* !KADMIN_LOCAL */
340 if (code != 0) {
341 if (code == KADM5_UNK_PRINC) {
342 fprintf(stderr,
343 gettext("%s: Principal %s does not exist.\n"),
344 whoami, princ_str);
345 /* Solaris Kerberos: Better error messages */
346 } else if (code == KRB5_BAD_ENCTYPE) {
347 int i, et;
348 fprintf(stderr, gettext("%s: Error from the remote system: "
349 "%s while changing %s's key\n"), whoami,
350 error_message(code), princ_str);
351 if (nktypes) {
352 et = permitted_etypes[0].ks_enctype;
353 fprintf(stderr, gettext("%s: Encryption types "
354 "requested: %s (%d)"), whoami,
355 etype_istring(et), et);
357 for (i = 1; i < nktypes; i++) {
358 et = permitted_etypes[i].ks_enctype;
359 fprintf(stderr, ", %s (%d)",
360 etype_istring(et), et);
362 fprintf(stderr, "\n");
364 } else {
365 com_err(whoami, code,
366 gettext("while changing %s's key"),
367 princ_str);
369 goto cleanup;
372 code = kadm5_get_principal(lhandle, princ, &princ_rec,
373 KADM5_PRINCIPAL_NORMAL_MASK);
374 if (code != 0) {
375 com_err(whoami, code, gettext("while retrieving principal"));
376 goto cleanup;
379 for (i = 0; i < nkeys; i++) {
380 memset((char *) &new_entry, 0, sizeof(new_entry));
381 new_entry.principal = princ;
382 new_entry.key = keys[i];
383 new_entry.vno = princ_rec.kvno;
385 code = krb5_kt_add_entry(context, keytab, &new_entry);
386 if (code != 0) {
387 com_err(whoami, code,
388 gettext("while adding key to keytab"));
389 (void) kadm5_free_principal_ent(lhandle, &princ_rec);
390 goto cleanup;
393 if (!quiet)
394 printf(gettext("Entry for principal %s with kvno %d, "
395 "encryption type %s added to keytab %s.\n"),
396 princ_str, princ_rec.kvno,
397 etype_string(keys[i].enctype), keytab_str);
400 code = kadm5_free_principal_ent(lhandle, &princ_rec);
401 if (code != 0) {
402 com_err(whoami, code, gettext("while freeing principal entry"));
403 goto cleanup;
406 cleanup:
407 if (nkeys) {
408 for (i = 0; i < nkeys; i++)
409 krb5_free_keyblock_contents(context, &keys[i]);
410 free(keys);
412 if (princ)
413 krb5_free_principal(context, princ);
415 if (permitted_etypes != NULL && ks_tuple == NULL)
416 free(permitted_etypes);
418 return code;
421 int remove_principal(char *keytab_str, krb5_keytab keytab, char
422 *princ_str, char *kvno_str)
424 krb5_principal princ;
425 krb5_keytab_entry entry;
426 krb5_kt_cursor cursor;
427 enum { UNDEF, SPEC, HIGH, ALL, OLD } mode;
428 int code, did_something;
429 krb5_kvno kvno;
431 code = krb5_parse_name(context, princ_str, &princ);
432 if (code != 0) {
433 com_err(whoami, code,
434 gettext("while parsing principal name %s"),
435 princ_str);
436 return code;
439 mode = UNDEF;
440 if (kvno_str == NULL) {
441 mode = HIGH;
442 kvno = 0;
443 } else if (strcmp(kvno_str, "all") == 0) {
444 mode = ALL;
445 kvno = 0;
446 } else if (strcmp(kvno_str, "old") == 0) {
447 mode = OLD;
448 kvno = 0;
449 } else {
450 mode = SPEC;
451 kvno = atoi(kvno_str);
454 /* kvno is set to specified value for SPEC, 0 otherwise */
455 code = krb5_kt_get_entry(context, keytab, princ, kvno, 0, &entry);
456 if (code != 0) {
457 if (code == ENOENT) {
458 fprintf(stderr,
459 gettext("%s: Keytab %s does not exist.\n"),
460 whoami, keytab_str);
461 } else if (code == KRB5_KT_NOTFOUND) {
462 if (mode != SPEC)
463 fprintf(stderr,
464 gettext("%s: No entry for principal "
465 "%s exists in keytab %s\n"),
466 whoami, princ_str, keytab_str);
467 else
468 fprintf(stderr,
469 gettext("%s: No entry for principal "
470 "%s with kvno %d exists in "
471 "keytab %s.\n"),
472 whoami, princ_str, kvno, keytab_str);
473 } else {
474 com_err(whoami, code,
475 gettext("while retrieving highest "
476 "kvno from keytab"));
478 return code;
481 /* set kvno to spec'ed value for SPEC, highest kvno otherwise */
482 kvno = entry.vno;
483 krb5_kt_free_entry(context, &entry);
485 code = krb5_kt_start_seq_get(context, keytab, &cursor);
486 if (code != 0) {
487 com_err(whoami, code, gettext("while starting keytab scan"));
488 return code;
491 did_something = 0;
492 while ((code = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
493 if (krb5_principal_compare(context, princ, entry.principal) &&
494 ((mode == ALL) ||
495 (mode == SPEC && entry.vno == kvno) ||
496 (mode == OLD && entry.vno != kvno) ||
497 (mode == HIGH && entry.vno == kvno))) {
500 * Ack! What a kludge... the scanning functions lock
501 * the keytab so entries cannot be removed while they
502 * are operating.
504 code = krb5_kt_end_seq_get(context, keytab, &cursor);
505 if (code != 0) {
506 com_err(whoami, code,
507 gettext("while temporarily "
508 "ending keytab scan"));
509 return code;
511 code = krb5_kt_remove_entry(context, keytab, &entry);
512 if (code != 0) {
513 com_err(whoami, code,
514 gettext("while deleting entry "
515 "from keytab"));
516 return code;
518 code = krb5_kt_start_seq_get(context, keytab, &cursor);
519 if (code != 0) {
520 com_err(whoami, code,
521 gettext("while restarting keytab scan"));
522 return code;
525 did_something++;
526 if (!quiet)
527 printf(gettext("Entry for principal "
528 "%s with kvno %d "
529 "removed from keytab %s.\n"),
530 princ_str, entry.vno, keytab_str);
532 krb5_kt_free_entry(context, &entry);
534 if (code && code != KRB5_KT_END) {
535 com_err(whoami, code, gettext("while scanning keytab"));
536 return code;
538 if ((code = krb5_kt_end_seq_get(context, keytab, &cursor))) {
539 com_err(whoami, code, gettext("while ending keytab scan"));
540 return code;
544 * If !did_someting then mode must be OLD or we would have
545 * already returned with an error. But check it anyway just to
546 * prevent unexpected error messages...
548 if (!did_something && mode == OLD) {
549 fprintf(stderr,
550 gettext("%s: There is only one entry for principal "
551 "%s in keytab %s\n"),
552 whoami, princ_str, keytab_str);
553 return 1;
556 return 0;
560 * etype_string(enctype): return a string representation of the
561 * encryption type. XXX copied from klist.c; this should be a
562 * library function, or perhaps just #defines
564 static char *etype_string(enctype)
565 krb5_enctype enctype;
567 static char buf[100];
568 krb5_error_code ret;
570 if ((ret = krb5_enctype_to_string(enctype, buf, sizeof(buf))))
571 sprintf(buf, "etype %d", enctype);
573 return buf;
576 /* Solaris Kerberos */
577 static char *etype_istring(krb5_enctype enctype) {
578 static char buf[100];
579 krb5_error_code ret;
581 if ((ret = krb5_enctype_to_istring(enctype, buf, sizeof(buf))))
582 sprintf(buf, "unknown", enctype);
584 return (buf);