2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
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 #if !defined(lint) && !defined(__CODECENTER__)
41 static char *rcsid
= "$Header: /cvs/krbdev/krb5/src/kadmin/cli/keytab.c,v 1.28 2004/05/31 12:39:16 epeisach Exp $";
49 #include <kadm5/admin.h>
50 #include <krb5/adm_proto.h>
54 static int add_principal(void *lhandle
, char *keytab_str
, krb5_keytab keytab
,
56 int n_ks_tuple
, krb5_key_salt_tuple
*ks_tuple
,
58 static int remove_principal(char *keytab_str
, krb5_keytab keytab
, char
59 *princ_str
, char *kvno_str
);
60 static char *etype_string(krb5_enctype enctype
);
61 static char *etype_istring(krb5_enctype enctype
);
65 static void add_usage()
67 fprintf(stderr
, "%s: %s\n", gettext("Usage"),
68 "ktadd [-k[eytab] keytab] [-q] [-e keysaltlist] "
69 "[principal | -glob princ-exp] [...]\n");
72 static void rem_usage()
74 fprintf(stderr
, "%s: %s\n",
76 "ktremove [-k[eytab] keytab] [-q] principal "
77 "[kvno|\"all\"|\"old\"]\n");
80 static int process_keytab(krb5_context my_context
, char **keytab_str
,
86 if (*keytab_str
== NULL
) {
87 if (code
= krb5_kt_default(my_context
, keytab
)) {
88 com_err(whoami
, code
, gettext("while opening default keytab"));
91 if (code
= krb5_kt_get_name(my_context
, *keytab
, buf
, BUFSIZ
)) {
92 com_err(whoami
, code
, gettext("while retrieving keytab name"));
95 if (!(*keytab_str
= strdup(buf
))) {
96 com_err(whoami
, ENOMEM
, gettext("while creating keytab name"));
100 if (strchr(*keytab_str
, ':') != NULL
) {
101 *keytab_str
= strdup(*keytab_str
);
102 if (*keytab_str
== NULL
) {
103 com_err(whoami
, ENOMEM
,
104 gettext("while creating keytab name"));
108 char *tmp
= *keytab_str
;
110 *keytab_str
= (char *)
111 malloc(strlen("WRFILE:")+strlen(tmp
)+1);
112 if (*keytab_str
== NULL
) {
113 com_err(whoami
, ENOMEM
,
114 gettext("while creating keytab name"));
117 sprintf(*keytab_str
, "WRFILE:%s", tmp
);
120 code
= krb5_kt_resolve(my_context
, *keytab_str
, keytab
);
122 com_err(whoami
, code
,
123 gettext("while resolving keytab %s"), *keytab_str
);
133 void kadmin_keytab_add(int argc
, char **argv
)
135 krb5_keytab keytab
= 0;
136 char *keytab_str
= NULL
, **princs
;
138 krb5_error_code retval
;
140 krb5_boolean keepold
= FALSE
;
141 krb5_key_salt_tuple
*ks_tuple
= NULL
;
146 if (strncmp(*argv
, "-k", 2) == 0) {
148 if (!argc
|| keytab_str
) {
153 } else if (strcmp(*argv
, "-q") == 0) {
155 } else if (strcmp(*argv
, "-e") == 0) {
161 retval
= krb5_string_to_keysalts(*++argv
, ", \t", ":.-", 0,
162 &ks_tuple
, &n_ks_tuple
);
164 com_err("ktadd", retval
,
165 gettext("while parsing keysalts %s"),
180 if (process_keytab(context
, &keytab_str
, &keytab
))
184 if (strcmp(*argv
, "-glob") == 0) {
185 if (*++argv
== NULL
) {
190 code
= kadm5_get_principals(handle
, *argv
, &princs
, &num
);
192 com_err(whoami
, code
,
193 gettext("while expanding expression "
200 for (i
= 0; i
< num
; i
++)
201 (void) add_principal(handle
, keytab_str
, keytab
,
202 keepold
, n_ks_tuple
, ks_tuple
,
204 kadm5_free_name_list(handle
, princs
, num
);
206 (void) add_principal(handle
, keytab_str
, keytab
,
207 keepold
, n_ks_tuple
, ks_tuple
,
212 code
= krb5_kt_close(context
, keytab
);
214 com_err(whoami
, code
, gettext("while closing keytab"));
219 void kadmin_keytab_remove(int argc
, char **argv
)
221 krb5_keytab keytab
= 0;
222 char *keytab_str
= NULL
;
228 if (strncmp(*argv
, "-k", 2) == 0) {
230 if (!argc
|| keytab_str
) {
235 } else if (strcmp(*argv
, "-q") == 0) {
242 if (argc
!= 1 && argc
!= 2) {
246 if (process_keytab(context
, &keytab_str
, &keytab
))
249 (void) remove_principal(keytab_str
, keytab
, argv
[0], argv
[1]);
251 code
= krb5_kt_close(context
, keytab
);
253 com_err(whoami
, code
, gettext("while closing keytab"));
259 int add_principal(void *lhandle
, char *keytab_str
, krb5_keytab keytab
,
260 krb5_boolean keepold
, int n_ks_tuple
,
261 krb5_key_salt_tuple
*ks_tuple
,
264 kadm5_principal_ent_rec princ_rec
;
265 krb5_principal princ
;
266 krb5_keytab_entry new_entry
;
270 krb5_key_salt_tuple
*permitted_etypes
= NULL
;
272 (void) memset((char *)&princ_rec
, 0, sizeof(princ_rec
));
278 code
= krb5_parse_name(context
, princ_str
, &princ
);
280 com_err(whoami
, code
,
281 gettext("while parsing -add principal name %s"),
286 if (ks_tuple
== NULL
) {
287 krb5_enctype
*ptr
, *ktypes
= NULL
;
289 code
= krb5_get_permitted_enctypes(context
, &ktypes
);
290 if (!code
&& ktypes
&& *ktypes
) {
293 * Count the results. This is stupid, the API above
294 * should have included an output param to indicate
295 * the size of the list that is returned.
297 for (ptr
= ktypes
; *ptr
; ptr
++) nktypes
++;
299 /* Allocate a new key-salt tuple set */
300 permitted_etypes
= (krb5_key_salt_tuple
*)malloc (
301 sizeof (krb5_key_salt_tuple
) * nktypes
);
302 if (permitted_etypes
== NULL
) {
308 * Because the keysalt parameter doesn't matter for
309 * keys stored in the keytab, use the default "normal"
312 (void) krb5_string_to_salttype("normal", &salttype
);
313 for (i
= 0; i
< nktypes
; i
++) {
314 permitted_etypes
[i
].ks_enctype
= ktypes
[i
];
315 permitted_etypes
[i
].ks_salttype
= salttype
;
324 permitted_etypes
= ks_tuple
;
325 nktypes
= n_ks_tuple
;
328 code
= kadm5_randkey_principal_3(lhandle
, princ
,
329 keepold
, nktypes
, permitted_etypes
,
332 #ifndef _KADMIN_LOCAL_
333 /* this block is not needed in the kadmin.local client */
336 * If the above call failed, we may be talking to an older
337 * admin server, so try the older API.
339 if (code
== KADM5_RPC_ERROR
) {
340 code
= kadm5_randkey_principal_old(handle
, princ
, &keys
, &nkeys
);
342 #endif /* !KADMIN_LOCAL */
344 if (code
== KADM5_UNK_PRINC
) {
346 gettext("%s: Principal %s does not exist.\n"),
348 /* Solaris Kerberos: Better error messages */
349 } else if (code
== KRB5_BAD_ENCTYPE
) {
351 fprintf(stderr
, gettext("%s: Error from the remote system: "
352 "%s while changing %s's key\n"), whoami
,
353 error_message(code
), princ_str
);
355 et
= permitted_etypes
[0].ks_enctype
;
356 fprintf(stderr
, gettext("%s: Encryption types "
357 "requested: %s (%d)"), whoami
,
358 etype_istring(et
), et
);
360 for (i
= 1; i
< nktypes
; i
++) {
361 et
= permitted_etypes
[i
].ks_enctype
;
362 fprintf(stderr
, ", %s (%d)",
363 etype_istring(et
), et
);
365 fprintf(stderr
, "\n");
368 com_err(whoami
, code
,
369 gettext("while changing %s's key"),
375 code
= kadm5_get_principal(lhandle
, princ
, &princ_rec
,
376 KADM5_PRINCIPAL_NORMAL_MASK
);
378 com_err(whoami
, code
, gettext("while retrieving principal"));
382 for (i
= 0; i
< nkeys
; i
++) {
383 memset((char *) &new_entry
, 0, sizeof(new_entry
));
384 new_entry
.principal
= princ
;
385 new_entry
.key
= keys
[i
];
386 new_entry
.vno
= princ_rec
.kvno
;
388 code
= krb5_kt_add_entry(context
, keytab
, &new_entry
);
390 com_err(whoami
, code
,
391 gettext("while adding key to keytab"));
392 (void) kadm5_free_principal_ent(lhandle
, &princ_rec
);
397 printf(gettext("Entry for principal %s with kvno %d, "
398 "encryption type %s added to keytab %s.\n"),
399 princ_str
, princ_rec
.kvno
,
400 etype_string(keys
[i
].enctype
), keytab_str
);
403 code
= kadm5_free_principal_ent(lhandle
, &princ_rec
);
405 com_err(whoami
, code
, gettext("while freeing principal entry"));
411 for (i
= 0; i
< nkeys
; i
++)
412 krb5_free_keyblock_contents(context
, &keys
[i
]);
416 krb5_free_principal(context
, princ
);
418 if (permitted_etypes
!= NULL
&& ks_tuple
== NULL
)
419 free(permitted_etypes
);
424 int remove_principal(char *keytab_str
, krb5_keytab keytab
, char
425 *princ_str
, char *kvno_str
)
427 krb5_principal princ
;
428 krb5_keytab_entry entry
;
429 krb5_kt_cursor cursor
;
430 enum { UNDEF
, SPEC
, HIGH
, ALL
, OLD
} mode
;
431 int code
, did_something
;
434 code
= krb5_parse_name(context
, princ_str
, &princ
);
436 com_err(whoami
, code
,
437 gettext("while parsing principal name %s"),
443 if (kvno_str
== NULL
) {
446 } else if (strcmp(kvno_str
, "all") == 0) {
449 } else if (strcmp(kvno_str
, "old") == 0) {
454 kvno
= atoi(kvno_str
);
457 /* kvno is set to specified value for SPEC, 0 otherwise */
458 code
= krb5_kt_get_entry(context
, keytab
, princ
, kvno
, 0, &entry
);
460 if (code
== ENOENT
) {
462 gettext("%s: Keytab %s does not exist.\n"),
464 } else if (code
== KRB5_KT_NOTFOUND
) {
467 gettext("%s: No entry for principal "
468 "%s exists in keytab %s\n"),
469 whoami
, princ_str
, keytab_str
);
472 gettext("%s: No entry for principal "
473 "%s with kvno %d exists in "
475 whoami
, princ_str
, kvno
, keytab_str
);
477 com_err(whoami
, code
,
478 gettext("while retrieving highest "
479 "kvno from keytab"));
484 /* set kvno to spec'ed value for SPEC, highest kvno otherwise */
486 krb5_kt_free_entry(context
, &entry
);
488 code
= krb5_kt_start_seq_get(context
, keytab
, &cursor
);
490 com_err(whoami
, code
, gettext("while starting keytab scan"));
495 while ((code
= krb5_kt_next_entry(context
, keytab
, &entry
, &cursor
)) == 0) {
496 if (krb5_principal_compare(context
, princ
, entry
.principal
) &&
498 (mode
== SPEC
&& entry
.vno
== kvno
) ||
499 (mode
== OLD
&& entry
.vno
!= kvno
) ||
500 (mode
== HIGH
&& entry
.vno
== kvno
))) {
503 * Ack! What a kludge... the scanning functions lock
504 * the keytab so entries cannot be removed while they
507 code
= krb5_kt_end_seq_get(context
, keytab
, &cursor
);
509 com_err(whoami
, code
,
510 gettext("while temporarily "
511 "ending keytab scan"));
514 code
= krb5_kt_remove_entry(context
, keytab
, &entry
);
516 com_err(whoami
, code
,
517 gettext("while deleting entry "
521 code
= krb5_kt_start_seq_get(context
, keytab
, &cursor
);
523 com_err(whoami
, code
,
524 gettext("while restarting keytab scan"));
530 printf(gettext("Entry for principal "
532 "removed from keytab %s.\n"),
533 princ_str
, entry
.vno
, keytab_str
);
535 krb5_kt_free_entry(context
, &entry
);
537 if (code
&& code
!= KRB5_KT_END
) {
538 com_err(whoami
, code
, gettext("while scanning keytab"));
541 if ((code
= krb5_kt_end_seq_get(context
, keytab
, &cursor
))) {
542 com_err(whoami
, code
, gettext("while ending keytab scan"));
547 * If !did_someting then mode must be OLD or we would have
548 * already returned with an error. But check it anyway just to
549 * prevent unexpected error messages...
551 if (!did_something
&& mode
== OLD
) {
553 gettext("%s: There is only one entry for principal "
554 "%s in keytab %s\n"),
555 whoami
, princ_str
, keytab_str
);
563 * etype_string(enctype): return a string representation of the
564 * encryption type. XXX copied from klist.c; this should be a
565 * library function, or perhaps just #defines
567 static char *etype_string(enctype
)
568 krb5_enctype enctype
;
570 static char buf
[100];
573 if ((ret
= krb5_enctype_to_string(enctype
, buf
, sizeof(buf
))))
574 sprintf(buf
, "etype %d", enctype
);
579 /* Solaris Kerberos */
580 static char *etype_istring(krb5_enctype enctype
) {
581 static char buf
[100];
584 if ((ret
= krb5_enctype_to_istring(enctype
, buf
, sizeof(buf
))))
585 sprintf(buf
, "unknown", enctype
);