1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
4 * All Rights Reserved.
5 *
6 * Export of this software from the United States of America may
7 * require a specific license from the United States Government.
8 * It is the responsibility of any person or organization contemplating
9 * export to obtain such a license before exporting.
10 *
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of M.I.T. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission. Furthermore if you modify this software you must label
19 * your software as modified software and not distribute it in such a
20 * fashion that it might be confused with the original M.I.T. software.
21 * M.I.T. makes no representations about the suitability of
22 * this software for any purpose. It is provided "as is" without express
23 * or implied warranty.
24 */
25 /*
26 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 /* Base functions for a kadmin command line interface using the OVSecure
31 * library */
32
33 /* for "_" macro */
34 #include "k5-int.h"
35 #include <kadm5/admin.h>
36 #include <adm_proto.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <sys/types.h>
42 #include <math.h>
43 #include <unistd.h>
44 #include <pwd.h>
45 /* #include <sys/timeb.h> */
46 #include <time.h>
47 #include "kadmin.h"
48
49 static krb5_boolean script_mode = FALSE;
50 int exit_status = 0;
51 char *def_realm = NULL;
52 char *whoami = NULL;
53
54 void *handle = NULL;
55 krb5_context context;
56 char *ccache_name = NULL;
57
58 int locked = 0;
59
60 static void
61 info(const char *fmt, ...)
62 #if !defined(__cplusplus) && (__GNUC__ > 2)
63 __attribute__((__format__(__printf__, 1, 2)))
64 #endif
65 ;
66
67 static void
68 error(const char *fmt, ...)
69 #if !defined(__cplusplus) && (__GNUC__ > 2)
70 __attribute__((__format__(__printf__, 1, 2)))
71 #endif
72 ;
73
74 /* Like printf, but suppressed if script_mode is set. */
75 static void
info(const char * fmt,...)76 info(const char *fmt, ...)
77 {
78 va_list ap;
79
80 if (script_mode)
81 return;
82 va_start(ap, fmt);
83 vprintf(fmt, ap);
84 va_end(ap);
85 }
86
87 /* Like fprintf to stderr; also set exit_status if script_mode is set. */
88 static void
error(const char * fmt,...)89 error(const char *fmt, ...)
90 {
91 va_list ap;
92
93 if (script_mode)
94 exit_status = 1;
95 va_start(ap, fmt);
96 vfprintf(stderr, fmt, ap);
97 va_end(ap);
98 }
99
100 static void
usage(void)101 usage(void)
102 {
103 error(_("Usage: %s [-r realm] [-p principal] [-q query] "
104 "[clnt|local args]\n"
105 " [command args...]\n"
106 "\tclnt args: [-s admin_server[:port]] "
107 "[[-c ccache]|[-k [-t keytab]]]|[-n] [-O | -N]\n"
108 "\tlocal args: [-x db_args]* [-d dbname] "
109 "[-e \"enc:salt ...\"] [-m] [-w password] "
110 "where,\n\t[-x db_args]* - any number of database specific "
111 "arguments.\n"
112 "\t\t\tLook at each database documentation for supported "
113 "arguments\n"), whoami);
114 exit(1);
115 }
116
117 static char *
strdur(time_t duration)118 strdur(time_t duration)
119 {
120 static char out[50];
121 int neg, days, hours, minutes, seconds;
122
123 if (duration < 0) {
124 duration *= -1;
125 neg = 1;
126 } else
127 neg = 0;
128 days = duration / (24 * 3600);
129 duration %= 24 * 3600;
130 hours = duration / 3600;
131 duration %= 3600;
132 minutes = duration / 60;
133 duration %= 60;
134 seconds = duration;
135 snprintf(out, sizeof(out), "%s%d %s %02d:%02d:%02d", neg ? "-" : "",
136 days, days == 1 ? "day" : "days",
137 hours, minutes, seconds);
138 return out;
139 }
140
141 static const char *
strdate(krb5_timestamp when)142 strdate(krb5_timestamp when)
143 {
144 struct tm *tm;
145 static char out[40];
146 time_t lcltim = ts2tt(when);
147
148 tm = localtime(&lcltim);
149 if (tm == NULL ||
150 strftime(out, sizeof(out), "%a %b %d %H:%M:%S %Z %Y", tm) == 0)
151 strlcpy(out, "(error)", sizeof(out));
152 return out;
153 }
154
155 /* Parse a date string using getdate.y. On failure, output an error message
156 * and return (time_t)-1. */
157 static time_t
parse_date(char * str,time_t now)158 parse_date(char *str, time_t now)
159 {
160 time_t date;
161
162 date = get_date_rel(str, now);
163 if (date == (time_t)-1)
164 error(_("Invalid date specification \"%s\".\n"), str);
165 return date;
166 }
167
168 /*
169 * Parse a time interval. Use krb5_string_to_deltat() if it works; otherwise
170 * use getdate.y and subtract now, with sanity checks. On failure, output an
171 * error message and return (time_t)-1.
172 */
173 static time_t
parse_interval(char * str,time_t now)174 parse_interval(char *str, time_t now)
175 {
176 time_t date;
177 krb5_deltat delta;
178
179 if (krb5_string_to_deltat(str, &delta) == 0)
180 return delta;
181
182 date = parse_date(str, now);
183 if (date == (time_t)-1)
184 return date;
185
186 /* Interpret an absolute time of 0 (e.g. "never") as an interval of 0. */
187 if (date == 0)
188 return 0;
189
190 /* Don't return a negative interval if the date is in the past. */
191 if (date < now) {
192 error(_("Interval specification \"%s\" is in the past.\n"), str);
193 return (time_t)-1;
194 }
195
196 return date - now;
197 }
198
199 /* this is a wrapper to go around krb5_parse_principal so we can set
200 the default realm up properly */
201 static krb5_error_code
kadmin_parse_name(char * name,krb5_principal * principal)202 kadmin_parse_name(char *name, krb5_principal *principal)
203 {
204 char *cp, *fullname;
205 krb5_error_code retval;
206 int result;
207
208 /* assumes def_realm is initialized! */
209 cp = strchr(name, '@');
210 while (cp) {
211 if (cp - name && *(cp - 1) != '\\')
212 break;
213 else
214 cp = strchr(cp + 1, '@');
215 }
216 if (cp == NULL)
217 result = asprintf(&fullname, "%s@%s", name, def_realm);
218 else
219 result = asprintf(&fullname, "%s", name);
220 if (result < 0)
221 return ENOMEM;
222 retval = krb5_parse_name(context, fullname, principal);
223 free(fullname);
224 return retval;
225 }
226
227 static void
extended_com_err_fn(const char * myprog,errcode_t code,const char * fmt,va_list args)228 extended_com_err_fn(const char *myprog, errcode_t code,
229 const char *fmt, va_list args)
230 {
231 const char *emsg;
232
233 if (code) {
234 emsg = krb5_get_error_message(context, code);
235 error("%s: %s ", myprog, emsg);
236 krb5_free_error_message(context, emsg);
237 } else {
238 error("%s: ", myprog);
239 }
240 vfprintf(stderr, fmt, args);
241 error("\n");
242 }
243
244 /* Create a principal using the oldest appropriate kadm5 API. */
245 static krb5_error_code
create_princ(kadm5_principal_ent_rec * princ,long mask,int n_ks,krb5_key_salt_tuple * ks,char * pass)246 create_princ(kadm5_principal_ent_rec *princ, long mask, int n_ks,
247 krb5_key_salt_tuple *ks, char *pass)
248 {
249 if (ks)
250 return kadm5_create_principal_3(handle, princ, mask, n_ks, ks, pass);
251 else
252 return kadm5_create_principal(handle, princ, mask, pass);
253 }
254
255 /* Randomize a principal's password using the appropriate kadm5 API. */
256 krb5_error_code
randkey_princ(void * lhandle,krb5_principal princ,krb5_boolean keepold,int n_ks,krb5_key_salt_tuple * ks,krb5_keyblock ** key,int * n_keys)257 randkey_princ(void *lhandle, krb5_principal princ, krb5_boolean keepold,
258 int n_ks, krb5_key_salt_tuple *ks, krb5_keyblock **key,
259 int *n_keys)
260 {
261 krb5_error_code ret;
262
263 /* Try the newer API first, because the Solaris kadmind only creates DES
264 * keys when the old API is used. */
265 ret = kadm5_randkey_principal_3(lhandle, princ, keepold, n_ks, ks, key,
266 n_keys);
267
268 /* Fall back to the old version if we get an error and aren't using any new
269 * parameters. */
270 if (ret == KADM5_RPC_ERROR && !keepold && ks == NULL)
271 ret = kadm5_randkey_principal(lhandle, princ, key, n_keys);
272
273 return ret;
274 }
275
276 static krb5_boolean
policy_exists(const char * name)277 policy_exists(const char *name)
278 {
279 kadm5_policy_ent_rec pol;
280
281 if (kadm5_get_policy(handle, (char *)name, &pol) != 0)
282 return FALSE;
283 kadm5_free_policy_ent(handle, &pol);
284 return TRUE;
285 }
286
287 void
kadmin_startup(int argc,char * argv[],char ** request_out,char *** args_out)288 kadmin_startup(int argc, char *argv[], char **request_out, char ***args_out)
289 {
290 extern char *optarg;
291 char *princstr = NULL, *keytab_name = NULL, *query = NULL;
292 char *password = NULL;
293 char *luser, *canon, *cp;
294 int optchar, freeprinc = 0, use_keytab = 0, use_anonymous = 0;
295 struct passwd *pw;
296 kadm5_ret_t retval;
297 krb5_ccache cc;
298 krb5_principal princ;
299 kadm5_config_params params;
300 char **db_args = NULL;
301 size_t db_args_size = 0;
302 char *db_name = NULL;
303 char *svcname, *realm;
304
305 memset(¶ms, 0, sizeof(params));
306
307 set_com_err_hook(extended_com_err_fn);
308
309 retval = kadm5_init_krb5_context(&context);
310 if (retval) {
311 com_err(whoami, retval, _("while initializing krb5 library"));
312 exit(1);
313 }
314
315 while ((optchar = getopt(argc, argv,
316 "+x:r:p:knq:w:d:s:mc:t:e:ON")) != EOF) {
317 switch (optchar) {
318 case 'x':
319 db_args_size++;
320 db_args = realloc(db_args, sizeof(char*) * (db_args_size + 1));
321 if (db_args == NULL) {
322 error(_("%s: Cannot initialize. Not enough memory\n"), whoami);
323 exit(1);
324 }
325 db_args[db_args_size - 1] = optarg;
326 db_args[db_args_size] = NULL;
327 break;
328
329 case 'r':
330 def_realm = optarg;
331 break;
332 case 'p':
333 princstr = optarg;
334 break;
335 case 'c':
336 ccache_name = optarg;
337 break;
338 case 'k':
339 use_keytab++;
340 break;
341 case 'n':
342 use_anonymous++;
343 break;
344 case 't':
345 keytab_name = optarg;
346 break;
347 case 'w':
348 password = optarg;
349 break;
350 case 'q':
351 query = optarg;
352 break;
353 case 'd':
354 /* db_name has to be passed as part of the db_args. */
355 free(db_name);
356 asprintf(&db_name, "dbname=%s", optarg);
357
358 db_args_size++;
359 db_args = realloc(db_args, sizeof(char*) * (db_args_size + 1));
360 if (db_args == NULL) {
361 error(_("%s: Cannot initialize. Not enough memory\n"), whoami);
362 exit(1);
363 }
364 db_args[db_args_size - 1] = db_name;
365 db_args[db_args_size] = NULL;
366 break;
367 case 's':
368 params.admin_server = optarg;
369 params.mask |= KADM5_CONFIG_ADMIN_SERVER;
370 break;
371 case 'm':
372 params.mkey_from_kbd = 1;
373 params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
374 break;
375 case 'e':
376 retval = krb5_string_to_keysalts(optarg, NULL, NULL, 0,
377 ¶ms.keysalts,
378 ¶ms.num_keysalts);
379 if (retval) {
380 com_err(whoami, retval, _("while parsing keysalts %s"),
381 optarg);
382 exit(1);
383 }
384 params.mask |= KADM5_CONFIG_ENCTYPES;
385 break;
386 case 'O':
387 params.mask |= KADM5_CONFIG_OLD_AUTH_GSSAPI;
388 break;
389 case 'N':
390 params.mask |= KADM5_CONFIG_AUTH_NOFALLBACK;
391 break;
392 default:
393 usage();
394 }
395 }
396 if ((ccache_name && use_keytab) ||
397 (keytab_name && !use_keytab) ||
398 (ccache_name && use_anonymous) ||
399 (use_anonymous && use_keytab))
400 usage();
401
402 if (query != NULL && argv[optind] != NULL) {
403 error(_("%s: -q is exclusive with command-line query"), whoami);
404 usage();
405 }
406
407 if (argv[optind] != NULL)
408 script_mode = TRUE;
409
410 if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) {
411 error(_("%s: unable to get default realm\n"), whoami);
412 exit(1);
413 }
414
415 params.mask |= KADM5_CONFIG_REALM;
416 params.realm = def_realm;
417
418 if (params.mask & KADM5_CONFIG_OLD_AUTH_GSSAPI)
419 svcname = KADM5_ADMIN_SERVICE;
420 else
421 svcname = NULL;
422
423 /*
424 * Set cc to an open credentials cache, either specified by the -c
425 * argument or the default.
426 */
427 if (ccache_name == NULL) {
428 retval = krb5_cc_default(context, &cc);
429 if (retval) {
430 com_err(whoami, retval,
431 _("while opening default credentials cache"));
432 exit(1);
433 }
434 } else {
435 retval = krb5_cc_resolve(context, ccache_name, &cc);
436 if (retval) {
437 com_err(whoami, retval, _("while opening credentials cache %s"),
438 ccache_name);
439 exit(1);
440 }
441 }
442
443 /*
444 * If no principal name is specified: If authenticating anonymously, use
445 * the anonymous principal for the local realm, else if a ccache was
446 * specified and its primary principal name can be read, it is used, else
447 * if a keytab was specified, the principal name is host/hostname,
448 * otherwise append "/admin" to the primary name of the default ccache,
449 * $USER, or pw_name.
450 *
451 * Gee, 100+ lines to figure out the client principal name. This
452 * should be compressed...
453 */
454
455 if (princstr == NULL) {
456 if (use_anonymous) {
457 if (asprintf(&princstr, "%s/%s@%s", KRB5_WELLKNOWN_NAMESTR,
458 KRB5_ANONYMOUS_PRINCSTR, def_realm) < 0) {
459 error(_("%s: out of memory\n"), whoami);
460 exit(1);
461 }
462 freeprinc++;
463 } else if (ccache_name != NULL &&
464 !krb5_cc_get_principal(context, cc, &princ)) {
465 retval = krb5_unparse_name(context, princ, &princstr);
466 if (retval) {
467 com_err(whoami, retval,
468 _("while canonicalizing principal name"));
469 exit(1);
470 }
471 krb5_free_principal(context, princ);
472 freeprinc++;
473 } else if (use_keytab != 0) {
474 retval = krb5_sname_to_principal(context, NULL, "host",
475 KRB5_NT_SRV_HST, &princ);
476 if (retval) {
477 com_err(whoami, retval, _("creating host service principal"));
478 exit(1);
479 }
480 retval = krb5_unparse_name(context, princ, &princstr);
481 if (retval) {
482 com_err(whoami, retval,
483 _("while canonicalizing principal name"));
484 exit(1);
485 }
486 krb5_free_principal(context, princ);
487 freeprinc++;
488 } else if (!krb5_cc_get_principal(context, cc, &princ)) {
489 if (krb5_unparse_name(context, princ, &canon)) {
490 error(_("%s: unable to canonicalize principal\n"), whoami);
491 exit(1);
492 }
493 /* Strip out realm of principal if it's there. */
494 realm = strchr(canon, '@');
495 while (realm) {
496 if (realm > canon && *(realm - 1) != '\\')
497 break;
498 realm = strchr(realm + 1, '@');
499 }
500 if (realm)
501 *realm++ = '\0';
502 cp = strchr(canon, '/');
503 while (cp) {
504 if (cp > canon && *(cp - 1) != '\\')
505 break;
506 cp = strchr(cp + 1, '/');
507 }
508 if (cp != NULL)
509 *cp = '\0';
510 if (asprintf(&princstr, "%s/admin%s%s", canon,
511 (realm) ? "@" : "",
512 (realm) ? realm : "") < 0) {
513 error(_("%s: out of memory\n"), whoami);
514 exit(1);
515 }
516 free(canon);
517 krb5_free_principal(context, princ);
518 freeprinc++;
519 } else if ((luser = getenv("USER"))) {
520 if (asprintf(&princstr, "%s/admin@%s", luser, def_realm) < 0) {
521 error(_("%s: out of memory\n"), whoami);
522 exit(1);
523 }
524 freeprinc++;
525 } else if ((pw = getpwuid(getuid()))) {
526 if (asprintf(&princstr, "%s/admin@%s", pw->pw_name,
527 def_realm) < 0) {
528 error(_("%s: out of memory\n"), whoami);
529 exit(1);
530 }
531 freeprinc++;
532 } else {
533 error(_("%s: unable to figure out a principal name\n"), whoami);
534 exit(1);
535 }
536 }
537
538 retval = krb5_klog_init(context, "admin_server", whoami, 0);
539 if (retval) {
540 com_err(whoami, retval, _("while setting up logging"));
541 exit(1);
542 }
543
544 /*
545 * Initialize the kadm5 connection. If we were given a ccache,
546 * use it. Otherwise, use/prompt for the password.
547 */
548 if (ccache_name) {
549 info(_("Authenticating as principal %s with existing "
550 "credentials.\n"), princstr);
551 retval = kadm5_init_with_creds(context, princstr, cc, svcname, ¶ms,
552 KADM5_STRUCT_VERSION,
553 KADM5_API_VERSION_4, db_args, &handle);
554 } else if (use_anonymous) {
555 info(_("Authenticating as principal %s with password; "
556 "anonymous requested.\n"), princstr);
557 retval = kadm5_init_anonymous(context, princstr, svcname, ¶ms,
558 KADM5_STRUCT_VERSION,
559 KADM5_API_VERSION_4, db_args, &handle);
560 } else if (use_keytab) {
561 if (keytab_name != NULL) {
562 info(_("Authenticating as principal %s with keytab %s.\n"),
563 princstr, keytab_name);
564 } else {
565 info(_("Authenticating as principal %s with default keytab.\n"),
566 princstr);
567 }
568 retval = kadm5_init_with_skey(context, princstr, keytab_name, svcname,
569 ¶ms, KADM5_STRUCT_VERSION,
570 KADM5_API_VERSION_4, db_args, &handle);
571 } else {
572 info(_("Authenticating as principal %s with password.\n"),
573 princstr);
574 retval = kadm5_init_with_password(context, princstr, password, svcname,
575 ¶ms, KADM5_STRUCT_VERSION,
576 KADM5_API_VERSION_4, db_args,
577 &handle);
578 }
579 if (retval) {
580 com_err(whoami, retval, _("while initializing %s interface"), whoami);
581 if (retval == KADM5_BAD_CLIENT_PARAMS ||
582 retval == KADM5_BAD_SERVER_PARAMS)
583 usage();
584 exit(1);
585 }
586 if (freeprinc)
587 free(princstr);
588
589 free(params.keysalts);
590 free(db_name);
591 free(db_args);
592
593 retval = krb5_cc_close(context, cc);
594 if (retval) {
595 com_err(whoami, retval, _("while closing ccache %s"), ccache_name);
596 exit(1);
597 }
598
599 retval = kadm5_init_iprop(handle, 0);
600 if (retval) {
601 com_err(whoami, retval, _("while mapping update log"));
602 exit(1);
603 }
604
605 *request_out = query;
606 *args_out = argv + optind;
607 }
608
609 int
quit(void)610 quit(void)
611 {
612 kadm5_ret_t retval;
613
614 if (locked) {
615 retval = kadm5_unlock(handle);
616 if (retval) {
617 com_err("quit", retval, _("while unlocking locked database"));
618 return 1;
619 }
620 locked = 0;
621 }
622
623 kadm5_destroy(handle);
624 if (ccache_name != NULL && !script_mode) {
625 fprintf(stderr, "\n\a\a\a%s",
626 _("Administration credentials NOT DESTROYED.\n"));
627 }
628
629 /* insert more random cleanup here */
630 krb5_klog_close(context);
631 krb5_free_context(context);
632 return 0;
633 }
634
635 void
kadmin_lock(int argc,char * argv[],int sci_idx,void * info_ptr)636 kadmin_lock(int argc, char *argv[], int sci_idx, void *info_ptr)
637 {
638 kadm5_ret_t retval;
639
640 if (locked)
641 return;
642 retval = kadm5_lock(handle);
643 if (retval) {
644 com_err("lock", retval, "");
645 return;
646 }
647 locked = 1;
648 }
649
650 void
kadmin_unlock(int argc,char * argv[],int sci_idx,void * info_ptr)651 kadmin_unlock(int argc, char *argv[], int sci_idx, void *info_ptr)
652 {
653 kadm5_ret_t retval;
654
655 if (!locked)
656 return;
657 retval = kadm5_unlock(handle);
658 if (retval) {
659 com_err("unlock", retval, "");
660 return;
661 }
662 locked = 0;
663 }
664
665 void
kadmin_delprinc(int argc,char * argv[],int sci_idx,void * info_ptr)666 kadmin_delprinc(int argc, char *argv[], int sci_idx, void *info_ptr)
667 {
668 kadm5_ret_t retval;
669 krb5_principal princ = NULL;
670 char *canon = NULL;
671 char reply[5];
672
673 if (! (argc == 2 ||
674 (argc == 3 && !strcmp("-force", argv[1])))) {
675 error(_("usage: delete_principal [-force] principal\n"));
676 return;
677 }
678 retval = kadmin_parse_name(argv[argc - 1], &princ);
679 if (retval) {
680 com_err("delete_principal", retval, _("while parsing principal name"));
681 return;
682 }
683 retval = krb5_unparse_name(context, princ, &canon);
684 if (retval) {
685 com_err("delete_principal", retval,
686 _("while canonicalizing principal"));
687 goto cleanup;
688 }
689 if (argc == 2 && !script_mode) {
690 printf(_("Are you sure you want to delete the principal \"%s\"? "
691 "(yes/no): "), canon);
692 fgets(reply, sizeof (reply), stdin);
693 if (strcmp("yes\n", reply)) {
694 fprintf(stderr, _("Principal \"%s\" not deleted\n"), canon);
695 goto cleanup;
696 }
697 }
698 retval = kadm5_delete_principal(handle, princ);
699 if (retval) {
700 com_err("delete_principal", retval,
701 _("while deleting principal \"%s\""), canon);
702 goto cleanup;
703 }
704 info(_("Principal \"%s\" deleted.\n"), canon);
705 info(_("Make sure that you have removed this principal from all ACLs "
706 "before reusing.\n"));
707
708 cleanup:
709 krb5_free_principal(context, princ);
710 free(canon);
711 }
712
713 void
kadmin_renameprinc(int argc,char * argv[],int sci_idx,void * info_ptr)714 kadmin_renameprinc(int argc, char *argv[], int sci_idx, void *info_ptr)
715 {
716 kadm5_ret_t retval;
717 krb5_principal oprinc = NULL, nprinc = NULL;
718 char *ocanon = NULL, *ncanon = NULL;
719 char reply[5];
720
721 if (!(argc == 3 || (argc == 4 && !strcmp("-force", argv[1])))) {
722 error(_("usage: rename_principal [-force] old_principal "
723 "new_principal\n"));
724 return;
725 }
726 retval = kadmin_parse_name(argv[argc - 2], &oprinc);
727 if (retval) {
728 com_err("rename_principal", retval,
729 _("while parsing old principal name"));
730 goto cleanup;
731 }
732 retval = kadmin_parse_name(argv[argc - 1], &nprinc);
733 if (retval) {
734 com_err("rename_principal", retval,
735 _("while parsing new principal name"));
736 goto cleanup;
737 }
738 retval = krb5_unparse_name(context, oprinc, &ocanon);
739 if (retval) {
740 com_err("rename_principal", retval,
741 _("while canonicalizing old principal"));
742 goto cleanup;
743 }
744 retval = krb5_unparse_name(context, nprinc, &ncanon);
745 if (retval) {
746 com_err("rename_principal", retval,
747 _("while canonicalizing new principal"));
748 goto cleanup;
749 }
750 if (argc == 3 && !script_mode) {
751 printf(_("Are you sure you want to rename the principal \"%s\" "
752 "to \"%s\"? (yes/no): "), ocanon, ncanon);
753 fgets(reply, sizeof(reply), stdin);
754 if (strcmp("yes\n", reply)) {
755 fprintf(stderr, _("Principal \"%s\" not renamed\n"), ocanon);
756 goto cleanup;
757 }
758 }
759 retval = kadm5_rename_principal(handle, oprinc, nprinc);
760 if (retval) {
761 com_err("rename_principal", retval,
762 _("while renaming principal \"%s\" to \"%s\""),
763 ocanon, ncanon);
764 goto cleanup;
765 }
766 info(_("Principal \"%s\" renamed to \"%s\".\n"), ocanon, ncanon);
767 info(_("Make sure that you have removed the old principal from all ACLs "
768 "before reusing.\n"));
769
770 cleanup:
771 krb5_free_principal(context, nprinc);
772 krb5_free_principal(context, oprinc);
773 free(ncanon);
774 free(ocanon);
775 }
776
777 void
kadmin_addalias(int argc,char * argv[],int sci_idx,void * info_ptr)778 kadmin_addalias(int argc, char *argv[], int sci_idx, void *info_ptr)
779 {
780 kadm5_ret_t retval;
781 krb5_principal alias = NULL, target = NULL;
782 char *acanon = NULL, *tcanon = NULL;
783
784 if (argc != 3) {
785 error(_("usage: add_alias alias_principal target_principal\n"));
786 return;
787 }
788 retval = kadmin_parse_name(argv[1], &alias);
789 if (retval) {
790 com_err("add_alias", retval, _("while parsing alias principal name"));
791 goto cleanup;
792 }
793 retval = kadmin_parse_name(argv[2], &target);
794 if (retval) {
795 com_err("add_alias", retval, _("while parsing target principal name"));
796 goto cleanup;
797 }
798 retval = krb5_unparse_name(context, alias, &acanon);
799 if (retval) {
800 com_err("add_alias", retval,
801 _("while canonicalizing alias principal"));
802 goto cleanup;
803 }
804 retval = krb5_unparse_name(context, target, &tcanon);
805 if (retval) {
806 com_err("add_alias", retval,
807 _("while canonicalizing target principal"));
808 goto cleanup;
809 }
810 retval = kadm5_create_alias(handle, alias, target);
811 if (retval) {
812 com_err("add_alias", retval,
813 _("while aliasing principal \"%s\" to \"%s\""),
814 acanon, tcanon);
815 goto cleanup;
816 }
817 info(_("Principal \"%s\" aliased to \"%s\".\n"), acanon, tcanon);
818
819 cleanup:
820 krb5_free_principal(context, alias);
821 krb5_free_principal(context, target);
822 free(acanon);
823 free(tcanon);
824 }
825
826 static void
cpw_usage(const char * str)827 cpw_usage(const char *str)
828 {
829 if (str)
830 error("%s\n", str);
831 error(_("usage: change_password [-randkey] [-keepold] "
832 "[-e keysaltlist] [-pw password] principal\n"));
833 }
834
835 void
kadmin_cpw(int argc,char * argv[],int sci_idx,void * info_ptr)836 kadmin_cpw(int argc, char *argv[], int sci_idx, void *info_ptr)
837 {
838 kadm5_ret_t retval;
839 static char newpw[1024];
840 static char prompt1[1024], prompt2[1024];
841 char *canon = NULL, *pwarg = NULL;
842 int n_ks_tuple = 0, randkey = 0;
843 krb5_boolean keepold = FALSE;
844 krb5_key_salt_tuple *ks_tuple = NULL;
845 krb5_principal princ = NULL;
846 char **db_args = NULL;
847 size_t db_args_size = 0;
848
849 if (argc < 1) {
850 cpw_usage(NULL);
851 return;
852 }
853 for (argv++, argc--; argc > 0 && **argv == '-'; argc--, argv++) {
854 if (!strcmp("-x", *argv)) {
855 argc--;
856 if (argc < 1) {
857 cpw_usage(_("change_password: missing db argument"));
858 goto cleanup;
859 }
860 db_args_size++;
861 db_args = realloc(db_args, sizeof(char*) * (db_args_size + 1));
862 if (db_args == NULL) {
863 error(_("change_password: Not enough memory\n"));
864 exit(1);
865 }
866 db_args[db_args_size - 1] = *++argv;
867 db_args[db_args_size] = NULL;
868 } else if (!strcmp("-pw", *argv)) {
869 argc--;
870 if (argc < 1) {
871 cpw_usage(_("change_password: missing password arg"));
872 goto cleanup;
873 }
874 pwarg = *++argv;
875 } else if (!strcmp("-randkey", *argv)) {
876 randkey++;
877 } else if (!strcmp("-keepold", *argv)) {
878 keepold = TRUE;
879 } else if (!strcmp("-e", *argv)) {
880 argc--;
881 if (argc < 1) {
882 cpw_usage(_("change_password: missing keysaltlist arg"));
883 goto cleanup;
884 }
885 retval = krb5_string_to_keysalts(*++argv, NULL, NULL, 0,
886 &ks_tuple, &n_ks_tuple);
887 if (retval) {
888 com_err("change_password", retval,
889 _("while parsing keysalts %s"), *argv);
890 goto cleanup;
891 }
892 } else {
893 com_err("change_password", 0, _("unrecognized option %s"), *argv);
894 cpw_usage(NULL);
895 goto cleanup;
896 }
897 }
898 if (argc != 1) {
899 if (argc < 1)
900 com_err("change_password", 0, _("missing principal name"));
901 else
902 com_err("change_password", 0, _("too many arguments"));
903 cpw_usage(NULL);
904 goto cleanup;
905 }
906 retval = kadmin_parse_name(*argv, &princ);
907 if (retval) {
908 com_err("change_password", retval, _("while parsing principal name"));
909 goto cleanup;
910 }
911 retval = krb5_unparse_name(context, princ, &canon);
912 if (retval) {
913 com_err("change_password", retval,
914 _("while canonicalizing principal"));
915 goto cleanup;
916 }
917 if (pwarg != NULL) {
918 if (keepold || ks_tuple != NULL) {
919 retval = kadm5_chpass_principal_3(handle, princ, keepold,
920 n_ks_tuple, ks_tuple, pwarg);
921 } else {
922 retval = kadm5_chpass_principal(handle, princ, pwarg);
923 }
924 if (retval) {
925 com_err("change_password", retval,
926 _("while changing password for \"%s\"."), canon);
927 goto cleanup;
928 }
929 info(_("Password for \"%s\" changed.\n"), canon);
930 } else if (randkey) {
931 retval = randkey_princ(handle, princ, keepold, n_ks_tuple, ks_tuple,
932 NULL, NULL);
933 if (retval) {
934 com_err("change_password", retval,
935 _("while randomizing key for \"%s\"."), canon);
936 goto cleanup;
937 }
938 info(_("Key for \"%s\" randomized.\n"), canon);
939 } else {
940 unsigned int i = sizeof (newpw) - 1;
941
942 snprintf(prompt1, sizeof(prompt1),
943 _("Enter password for principal \"%s\""), canon);
944 snprintf(prompt2, sizeof(prompt2),
945 _("Re-enter password for principal \"%s\""), canon);
946 retval = krb5_read_password(context, prompt1, prompt2,
947 newpw, &i);
948 if (retval) {
949 com_err("change_password", retval,
950 _("while reading password for \"%s\"."), canon);
951 goto cleanup;
952 }
953 if (keepold || ks_tuple != NULL) {
954 retval = kadm5_chpass_principal_3(handle, princ, keepold,
955 n_ks_tuple, ks_tuple,
956 newpw);
957 } else {
958 retval = kadm5_chpass_principal(handle, princ, newpw);
959 }
960 memset(newpw, 0, sizeof (newpw));
961 if (retval) {
962 com_err("change_password", retval,
963 _("while changing password for \"%s\"."), canon);
964 goto cleanup;
965 }
966 info(_("Password for \"%s\" changed.\n"), canon);
967 }
968 cleanup:
969 free(canon);
970 free(db_args);
971 krb5_free_principal(context, princ);
972 free(ks_tuple);
973 }
974
975 static void
kadmin_free_tl_data(krb5_int16 * n_tl_datap,krb5_tl_data ** tl_datap)976 kadmin_free_tl_data(krb5_int16 *n_tl_datap, krb5_tl_data **tl_datap)
977 {
978 krb5_tl_data *tl_data = *tl_datap, *next;
979 int n_tl_data = *n_tl_datap;
980 int i;
981
982 *n_tl_datap = 0;
983 *tl_datap = NULL;
984
985 for (i = 0; tl_data && (i < n_tl_data); i++) {
986 next = tl_data->tl_data_next;
987 free(tl_data->tl_data_contents);
988 free(tl_data);
989 tl_data = next;
990 }
991 }
992
993 /* Construct a tl_data element and add it to the tail of *tl_datap. */
994 static void
add_tl_data(krb5_int16 * n_tl_datap,krb5_tl_data ** tl_datap,krb5_int16 tl_type,krb5_ui_2 len,krb5_octet * contents)995 add_tl_data(krb5_int16 *n_tl_datap, krb5_tl_data **tl_datap,
996 krb5_int16 tl_type, krb5_ui_2 len, krb5_octet *contents)
997 {
998 krb5_tl_data *tl_data;
999 krb5_octet *copy;
1000
1001 copy = malloc(len);
1002 tl_data = calloc(1, sizeof(*tl_data));
1003 if (copy == NULL || tl_data == NULL) {
1004 error(_("Not enough memory\n"));
1005 exit(1);
1006 }
1007 memcpy(copy, contents, len);
1008
1009 tl_data->tl_data_type = tl_type;
1010 tl_data->tl_data_length = len;
1011 tl_data->tl_data_contents = copy;
1012 tl_data->tl_data_next = NULL;
1013
1014 for (; *tl_datap != NULL; tl_datap = &(*tl_datap)->tl_data_next);
1015 *tl_datap = tl_data;
1016 (*n_tl_datap)++;
1017 }
1018
1019 static void
unlock_princ(kadm5_principal_ent_t princ,long * mask,const char * caller)1020 unlock_princ(kadm5_principal_ent_t princ, long *mask, const char *caller)
1021 {
1022 krb5_error_code retval;
1023 krb5_timestamp now;
1024 krb5_octet timebuf[4];
1025
1026 /* Zero out the failed auth count. */
1027 princ->fail_auth_count = 0;
1028 *mask |= KADM5_FAIL_AUTH_COUNT;
1029
1030 /* Record the timestamp of this unlock operation so that replica KDCs will
1031 * see it, since fail_auth_count is unreplicated. */
1032 retval = krb5_timeofday(context, &now);
1033 if (retval) {
1034 com_err(caller, retval, _("while getting time"));
1035 exit(1);
1036 }
1037 store_32_le((krb5_int32)now, timebuf);
1038 add_tl_data(&princ->n_tl_data, &princ->tl_data,
1039 KRB5_TL_LAST_ADMIN_UNLOCK, 4, timebuf);
1040 *mask |= KADM5_TL_DATA;
1041 }
1042
1043 /*
1044 * Parse addprinc or modprinc arguments. Some output fields may be
1045 * filled in on error.
1046 */
1047 static int
kadmin_parse_princ_args(int argc,char * argv[],kadm5_principal_ent_t oprinc,long * mask,char ** pass,krb5_boolean * randkey,krb5_boolean * nokey,krb5_key_salt_tuple ** ks_tuple,int * n_ks_tuple,char * caller)1048 kadmin_parse_princ_args(int argc, char *argv[], kadm5_principal_ent_t oprinc,
1049 long *mask, char **pass, krb5_boolean *randkey,
1050 krb5_boolean *nokey, krb5_key_salt_tuple **ks_tuple,
1051 int *n_ks_tuple, char *caller)
1052 {
1053 int i;
1054 time_t now, date, interval;
1055 krb5_error_code retval;
1056
1057 *mask = 0;
1058 *pass = NULL;
1059 *n_ks_tuple = 0;
1060 *ks_tuple = NULL;
1061 time(&now);
1062 *randkey = FALSE;
1063 *nokey = FALSE;
1064 for (i = 1; i < argc - 1; i++) {
1065 if (!strcmp("-x",argv[i])) {
1066 if (++i > argc - 2)
1067 return -1;
1068
1069 add_tl_data(&oprinc->n_tl_data, &oprinc->tl_data,
1070 KRB5_TL_DB_ARGS, strlen(argv[i]) + 1,
1071 (krb5_octet *)argv[i]);
1072 *mask |= KADM5_TL_DATA;
1073 continue;
1074 }
1075 if (!strcmp("-expire", argv[i])) {
1076 if (++i > argc - 2)
1077 return -1;
1078 date = parse_date(argv[i], now);
1079 if (date == (time_t)-1)
1080 return -1;
1081 oprinc->princ_expire_time = date;
1082 *mask |= KADM5_PRINC_EXPIRE_TIME;
1083 continue;
1084 }
1085 if (!strcmp("-pwexpire", argv[i])) {
1086 if (++i > argc - 2)
1087 return -1;
1088 date = parse_date(argv[i], now);
1089 if (date == (time_t)-1)
1090 return -1;
1091 oprinc->pw_expiration = date;
1092 *mask |= KADM5_PW_EXPIRATION;
1093 continue;
1094 }
1095 if (!strcmp("-maxlife", argv[i])) {
1096 if (++i > argc - 2)
1097 return -1;
1098 interval = parse_interval(argv[i], now);
1099 if (interval == (time_t)-1)
1100 return -1;
1101 oprinc->max_life = interval;
1102 *mask |= KADM5_MAX_LIFE;
1103 continue;
1104 }
1105 if (!strcmp("-maxrenewlife", argv[i])) {
1106 if (++i > argc - 2)
1107 return -1;
1108 interval = parse_interval(argv[i], now);
1109 if (interval == (time_t)-1)
1110 return -1;
1111 oprinc->max_renewable_life = interval;
1112 *mask |= KADM5_MAX_RLIFE;
1113 continue;
1114 }
1115 if (!strcmp("-kvno", argv[i])) {
1116 if (++i > argc - 2)
1117 return -1;
1118 oprinc->kvno = atoi(argv[i]);
1119 *mask |= KADM5_KVNO;
1120 continue;
1121 }
1122 if (!strcmp("-policy", argv[i])) {
1123 if (++i > argc - 2)
1124 return -1;
1125 oprinc->policy = argv[i];
1126 *mask |= KADM5_POLICY;
1127 continue;
1128 }
1129 if (!strcmp("-clearpolicy", argv[i])) {
1130 oprinc->policy = NULL;
1131 *mask |= KADM5_POLICY_CLR;
1132 continue;
1133 }
1134 if (!strcmp("-pw", argv[i])) {
1135 if (++i > argc - 2)
1136 return -1;
1137 *pass = argv[i];
1138 continue;
1139 }
1140 if (!strcmp("-randkey", argv[i])) {
1141 *randkey = TRUE;
1142 continue;
1143 }
1144 if (!strcmp("-nokey", argv[i])) {
1145 *nokey = TRUE;
1146 continue;
1147 }
1148 if (!strcmp("-unlock", argv[i])) {
1149 unlock_princ(oprinc, mask, caller);
1150 continue;
1151 }
1152 if (!strcmp("-e", argv[i])) {
1153 if (++i > argc - 2)
1154 return -1;
1155 retval = krb5_string_to_keysalts(argv[i], NULL, NULL, 0,
1156 ks_tuple, n_ks_tuple);
1157 if (retval) {
1158 com_err(caller, retval, _("while parsing keysalts %s"),
1159 argv[i]);
1160 return -1;
1161 }
1162 continue;
1163 }
1164 retval = krb5_flagspec_to_mask(argv[i], &oprinc->attributes,
1165 &oprinc->attributes);
1166 if (retval)
1167 return -1;
1168 else
1169 *mask |= KADM5_ATTRIBUTES;
1170 }
1171 if (i != argc - 1)
1172 return -1;
1173 retval = kadmin_parse_name(argv[i], &oprinc->principal);
1174 if (retval) {
1175 com_err(caller, retval, _("while parsing principal"));
1176 return -1;
1177 }
1178 return 0;
1179 }
1180
1181 static void
kadmin_addprinc_usage(void)1182 kadmin_addprinc_usage(void)
1183 {
1184 error(_("usage: add_principal [options] principal\n"));
1185 error(_("\toptions are:\n"));
1186 error(_("\t\t[-randkey|-nokey] [-x db_princ_args]* [-expire expdate] "
1187 "[-pwexpire pwexpdate] [-maxlife maxtixlife]\n"
1188 "\t\t[-kvno kvno] [-policy policy] [-clearpolicy]\n"
1189 "\t\t[-pw password] [-maxrenewlife maxrenewlife]\n"
1190 "\t\t[-e keysaltlist]\n\t\t[{+|-}attribute]\n"));
1191 error(_("\tattributes are:\n"));
1192 error(_("\t\tallow_postdated allow_forwardable allow_tgs_req "
1193 "allow_renewable\n"
1194 "\t\tallow_proxiable allow_dup_skey allow_tix requires_preauth\n"
1195 "\t\trequires_hwauth needchange allow_svr "
1196 "password_changing_service\n"
1197 "\t\tok_as_delegate ok_to_auth_as_delegate no_auth_data_required\n"
1198 "\t\tlockdown_keys\n"
1199 "\nwhere,\n\t[-x db_princ_args]* - any number of database "
1200 "specific arguments.\n"
1201 "\t\t\tLook at each database documentation for supported "
1202 "arguments\n"));
1203 }
1204
1205 static void
kadmin_modprinc_usage(void)1206 kadmin_modprinc_usage(void)
1207 {
1208 error(_("usage: modify_principal [options] principal\n"));
1209 error(_("\toptions are:\n"));
1210 error(_("\t\t[-x db_princ_args]* [-expire expdate] "
1211 "[-pwexpire pwexpdate] [-maxlife maxtixlife]\n"
1212 "\t\t[-kvno kvno] [-policy policy] [-clearpolicy]\n"
1213 "\t\t[-maxrenewlife maxrenewlife] [-unlock] [{+|-}attribute]\n"));
1214 error(_("\tattributes are:\n"));
1215 error(_("\t\tallow_postdated allow_forwardable allow_tgs_req "
1216 "allow_renewable\n"
1217 "\t\tallow_proxiable allow_dup_skey allow_tix requires_preauth\n"
1218 "\t\trequires_hwauth needchange allow_svr "
1219 "password_changing_service\n"
1220 "\t\tok_as_delegate ok_to_auth_as_delegate no_auth_data_required\n"
1221 "\t\tlockdown_keys\n"
1222 "\nwhere,\n\t[-x db_princ_args]* - any number of database "
1223 "specific arguments.\n"
1224 "\t\t\tLook at each database documentation for supported "
1225 "arguments\n"));
1226 }
1227
1228 /* Create a dummy password for old-style (pre-1.8) randkey creation. */
1229 static void
prepare_dummy_password(char * buf,size_t sz)1230 prepare_dummy_password(char *buf, size_t sz)
1231 {
1232 size_t i;
1233
1234 /* Must try to pass any password policy in place, and be valid UTF-8. */
1235 strlcpy(buf, "6F a[", sz);
1236 for (i = strlen(buf); i < sz - 1; i++)
1237 buf[i] = 'a' + (i % 26);
1238 buf[sz - 1] = '\0';
1239 }
1240
1241 void
kadmin_addprinc(int argc,char * argv[],int sci_idx,void * info_ptr)1242 kadmin_addprinc(int argc, char *argv[], int sci_idx, void *info_ptr)
1243 {
1244 kadm5_principal_ent_rec princ;
1245 long mask;
1246 krb5_boolean randkey = FALSE, nokey = FALSE, old_style_randkey = FALSE;
1247 int n_ks_tuple;
1248 krb5_key_salt_tuple *ks_tuple = NULL;
1249 char *pass, *canon = NULL;
1250 krb5_error_code retval;
1251 char newpw[1024], dummybuf[256];
1252 static char prompt1[1024], prompt2[1024];
1253
1254 /* Zero all fields in request structure */
1255 memset(&princ, 0, sizeof(princ));
1256
1257 princ.attributes = 0;
1258 if (kadmin_parse_princ_args(argc, argv, &princ, &mask, &pass, &randkey,
1259 &nokey, &ks_tuple, &n_ks_tuple,
1260 "add_principal")) {
1261 kadmin_addprinc_usage();
1262 goto cleanup;
1263 }
1264
1265 retval = krb5_unparse_name(context, princ.principal, &canon);
1266 if (retval) {
1267 com_err("add_principal", retval, _("while canonicalizing principal"));
1268 goto cleanup;
1269 }
1270
1271 if (mask & KADM5_POLICY) {
1272 /* Warn if the specified policy does not exist. */
1273 if (!script_mode && !policy_exists(princ.policy)) {
1274 fprintf(stderr, _("WARNING: policy \"%s\" does not exist\n"),
1275 princ.policy);
1276 }
1277 } else if (!(mask & KADM5_POLICY_CLR)) {
1278 /* If the policy "default" exists, assign it. */
1279 if (policy_exists("default")) {
1280 if (!script_mode) {
1281 fprintf(stderr, _("No policy specified for %s; "
1282 "assigning \"default\"\n"), canon);
1283 }
1284 princ.policy = "default";
1285 mask |= KADM5_POLICY;
1286 } else if (!script_mode) {
1287 fprintf(stderr, _("No policy specified for %s; "
1288 "defaulting to no policy\n"), canon);
1289 }
1290 }
1291 /* Don't send KADM5_POLICY_CLR to the server. */
1292 mask &= ~KADM5_POLICY_CLR;
1293
1294 if (nokey) {
1295 pass = NULL;
1296 mask |= KADM5_KEY_DATA;
1297 } else if (randkey) {
1298 pass = NULL;
1299 } else if (pass == NULL) {
1300 unsigned int sz = sizeof(newpw) - 1;
1301
1302 snprintf(prompt1, sizeof(prompt1),
1303 _("Enter password for principal \"%s\""), canon);
1304 snprintf(prompt2, sizeof(prompt2),
1305 _("Re-enter password for principal \"%s\""), canon);
1306 retval = krb5_read_password(context, prompt1, prompt2, newpw, &sz);
1307 if (retval) {
1308 com_err("add_principal", retval,
1309 _("while reading password for \"%s\"."), canon);
1310 goto cleanup;
1311 }
1312 pass = newpw;
1313 }
1314 mask |= KADM5_PRINCIPAL;
1315 retval = create_princ(&princ, mask, n_ks_tuple, ks_tuple, pass);
1316 if (retval == EINVAL && randkey) {
1317 /*
1318 * The server doesn't support randkey creation. Create the principal
1319 * with a dummy password and disallow tickets.
1320 */
1321 prepare_dummy_password(dummybuf, sizeof(dummybuf));
1322 princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
1323 mask |= KADM5_ATTRIBUTES;
1324 pass = dummybuf;
1325 retval = create_princ(&princ, mask, n_ks_tuple, ks_tuple, pass);
1326 old_style_randkey = 1;
1327 }
1328 if (retval == KADM5_BAD_MASK && nokey) {
1329 error(_("Admin server does not support -nokey while creating "
1330 "\"%s\"\n"), canon);
1331 goto cleanup;
1332 }
1333 if (retval) {
1334 com_err("add_principal", retval, "while creating \"%s\".", canon);
1335 goto cleanup;
1336 }
1337 if (old_style_randkey) {
1338 /* Randomize the password and re-enable tickets. */
1339 retval = randkey_princ(handle, princ.principal, FALSE, n_ks_tuple,
1340 ks_tuple, NULL, NULL);
1341 if (retval) {
1342 com_err("add_principal", retval,
1343 _("while randomizing key for \"%s\"."), canon);
1344 goto cleanup;
1345 }
1346 princ.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX; /* clear notix */
1347 mask = KADM5_ATTRIBUTES;
1348 retval = kadm5_modify_principal(handle, &princ, mask);
1349 if (retval) {
1350 com_err("add_principal", retval,
1351 _("while clearing DISALLOW_ALL_TIX for \"%s\"."), canon);
1352 goto cleanup;
1353 }
1354 }
1355 info("Principal \"%s\" created.\n", canon);
1356
1357 cleanup:
1358 krb5_free_principal(context, princ.principal);
1359 free(ks_tuple);
1360 free(canon);
1361 kadmin_free_tl_data(&princ.n_tl_data, &princ.tl_data);
1362 }
1363
1364 void
kadmin_modprinc(int argc,char * argv[],int sci_idx,void * info_ptr)1365 kadmin_modprinc(int argc, char *argv[], int sci_idx, void *info_ptr)
1366 {
1367 kadm5_principal_ent_rec princ, oldprinc;
1368 krb5_principal kprinc = NULL;
1369 long mask;
1370 krb5_error_code retval;
1371 char *pass, *canon = NULL;
1372 krb5_boolean randkey = FALSE, nokey = FALSE;
1373 int n_ks_tuple = 0;
1374 krb5_key_salt_tuple *ks_tuple = NULL;
1375
1376 if (argc < 2) {
1377 kadmin_modprinc_usage();
1378 return;
1379 }
1380
1381 memset(&oldprinc, 0, sizeof(oldprinc));
1382 memset(&princ, 0, sizeof(princ));
1383
1384 retval = kadmin_parse_name(argv[argc - 1], &kprinc);
1385 if (retval) {
1386 com_err("modify_principal", retval, _("while parsing principal"));
1387 return;
1388 }
1389 retval = krb5_unparse_name(context, kprinc, &canon);
1390 if (retval) {
1391 com_err("modify_principal", retval,
1392 _("while canonicalizing principal"));
1393 goto cleanup;
1394 }
1395 retval = kadm5_get_principal(handle, kprinc, &oldprinc,
1396 KADM5_PRINCIPAL_NORMAL_MASK);
1397 if (retval) {
1398 com_err("modify_principal", retval, _("while getting \"%s\"."), canon);
1399 goto cleanup;
1400 }
1401 princ.attributes = oldprinc.attributes;
1402 kadm5_free_principal_ent(handle, &oldprinc);
1403 retval = kadmin_parse_princ_args(argc, argv,
1404 &princ, &mask,
1405 &pass, &randkey, &nokey,
1406 &ks_tuple, &n_ks_tuple,
1407 "modify_principal");
1408 if (retval || ks_tuple != NULL || randkey || nokey || pass) {
1409 kadmin_modprinc_usage();
1410 goto cleanup;
1411 }
1412 if (mask & KADM5_POLICY) {
1413 /* Warn if the specified policy does not exist. */
1414 if (!script_mode && !policy_exists(princ.policy)) {
1415 fprintf(stderr, _("WARNING: policy \"%s\" does not exist\n"),
1416 princ.policy);
1417 }
1418 }
1419 if (mask) {
1420 /* Skip this if all we're doing is setting certhash. */
1421 retval = kadm5_modify_principal(handle, &princ, mask);
1422 }
1423 if (retval) {
1424 com_err("modify_principal", retval, _("while modifying \"%s\"."),
1425 canon);
1426 goto cleanup;
1427 }
1428 info(_("Principal \"%s\" modified.\n"), canon);
1429 cleanup:
1430 krb5_free_principal(context, kprinc);
1431 krb5_free_principal(context, princ.principal);
1432 kadmin_free_tl_data(&princ.n_tl_data, &princ.tl_data);
1433 free(canon);
1434 free(ks_tuple);
1435 }
1436
1437 void
kadmin_getprinc(int argc,char * argv[],int sci_idx,void * info_ptr)1438 kadmin_getprinc(int argc, char *argv[], int sci_idx, void *info_ptr)
1439 {
1440 kadm5_principal_ent_rec dprinc;
1441 krb5_principal princ = NULL;
1442 krb5_error_code retval;
1443 const char *polname, *noexist;
1444 char *canon = NULL, *princstr = NULL, *modprincstr = NULL;
1445 char **sp = NULL, **attrstrs = NULL;
1446 int i;
1447
1448 if (!(argc == 2 || (argc == 3 && !strcmp("-terse", argv[1])))) {
1449 error(_("usage: get_principal [-terse] principal\n"));
1450 return;
1451 }
1452
1453 memset(&dprinc, 0, sizeof(dprinc));
1454
1455 retval = kadmin_parse_name(argv[argc - 1], &princ);
1456 if (retval) {
1457 com_err("get_principal", retval, _("while parsing principal"));
1458 return;
1459 }
1460 retval = krb5_unparse_name(context, princ, &canon);
1461 if (retval) {
1462 com_err("get_principal", retval, _("while canonicalizing principal"));
1463 goto cleanup;
1464 }
1465 retval = kadm5_get_principal(handle, princ, &dprinc,
1466 KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA);
1467 if (retval) {
1468 com_err("get_principal", retval, _("while retrieving \"%s\"."), canon);
1469 goto cleanup;
1470 }
1471 retval = krb5_unparse_name(context, dprinc.principal, &princstr);
1472 if (retval) {
1473 com_err("get_principal", retval, _("while unparsing principal"));
1474 goto cleanup;
1475 }
1476 retval = krb5_unparse_name(context, dprinc.mod_name, &modprincstr);
1477 if (retval) {
1478 com_err("get_principal", retval, _("while unparsing principal"));
1479 goto cleanup;
1480 }
1481 if (argc == 2) {
1482 printf(_("Principal: %s\n"), princstr);
1483 printf(_("Expiration date: %s\n"), dprinc.princ_expire_time ?
1484 strdate(dprinc.princ_expire_time) : _("[never]"));
1485 printf(_("Last password change: %s\n"), dprinc.last_pwd_change ?
1486 strdate(dprinc.last_pwd_change) : _("[never]"));
1487 printf(_("Password expiration date: %s\n"),
1488 dprinc.pw_expiration ?
1489 strdate(dprinc.pw_expiration) : _("[never]"));
1490 printf(_("Maximum ticket life: %s\n"), strdur(dprinc.max_life));
1491 printf(_("Maximum renewable life: %s\n"),
1492 strdur(dprinc.max_renewable_life));
1493 printf(_("Last modified: %s (%s)\n"), strdate(dprinc.mod_date),
1494 modprincstr);
1495 printf(_("Last successful authentication: %s\n"),
1496 dprinc.last_success ? strdate(dprinc.last_success) :
1497 _("[never]"));
1498 printf("Last failed authentication: %s\n",
1499 dprinc.last_failed ? strdate(dprinc.last_failed) :
1500 "[never]");
1501 printf(_("Failed password attempts: %d\n"),
1502 dprinc.fail_auth_count);
1503 printf(_("Number of keys: %d\n"), dprinc.n_key_data);
1504 for (i = 0; i < dprinc.n_key_data; i++) {
1505 krb5_key_data *key_data = &dprinc.key_data[i];
1506 char enctype[BUFSIZ], salttype[BUFSIZ];
1507 char *deprecated = "";
1508
1509 if (krb5_enctype_to_name(key_data->key_data_type[0], FALSE,
1510 enctype, sizeof(enctype)))
1511 snprintf(enctype, sizeof(enctype), _("<Encryption type 0x%x>"),
1512 key_data->key_data_type[0]);
1513 if (!krb5_c_valid_enctype(key_data->key_data_type[0]))
1514 deprecated = "UNSUPPORTED:";
1515 else if (krb5int_c_deprecated_enctype(key_data->key_data_type[0]))
1516 deprecated = "DEPRECATED:";
1517 printf("Key: vno %d, %s%s", key_data->key_data_kvno, deprecated,
1518 enctype);
1519 if (key_data->key_data_ver > 1 &&
1520 key_data->key_data_type[1] != KRB5_KDB_SALTTYPE_NORMAL) {
1521 if (krb5_salttype_to_string(key_data->key_data_type[1],
1522 salttype, sizeof(salttype)))
1523 snprintf(salttype, sizeof(salttype), _("<Salt type 0x%x>"),
1524 key_data->key_data_type[1]);
1525 printf(":%s", salttype);
1526 }
1527 printf("\n");
1528 }
1529 printf(_("MKey: vno %d\n"), dprinc.mkvno);
1530
1531 printf(_("Attributes:"));
1532 retval = krb5_flags_to_strings(dprinc.attributes, &attrstrs);
1533 if (retval) {
1534 com_err("get_principal", retval, _("while printing flags"));
1535 return;
1536 }
1537 for (sp = attrstrs; sp != NULL && *sp != NULL; sp++) {
1538 printf(" %s", *sp);
1539 free(*sp);
1540 }
1541 free(attrstrs);
1542 printf("\n");
1543 polname = (dprinc.policy != NULL) ? dprinc.policy : _("[none]");
1544 noexist = (dprinc.policy != NULL && !policy_exists(dprinc.policy)) ?
1545 _(" [does not exist]") : "";
1546 printf(_("Policy: %s%s\n"), polname, noexist);
1547 } else {
1548 printf("\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\t%d\t%d\t%d\t%d\t\"%s\""
1549 "\t%d\t%d\t%d\t%d\t%d",
1550 princstr, dprinc.princ_expire_time, dprinc.last_pwd_change,
1551 dprinc.pw_expiration, dprinc.max_life, modprincstr,
1552 dprinc.mod_date, dprinc.attributes, dprinc.kvno,
1553 dprinc.mkvno, dprinc.policy ? dprinc.policy : "[none]",
1554 dprinc.max_renewable_life, dprinc.last_success,
1555 dprinc.last_failed, dprinc.fail_auth_count,
1556 dprinc.n_key_data);
1557 for (i = 0; i < dprinc.n_key_data; i++)
1558 printf("\t%d\t%d\t%d\t%d",
1559 dprinc.key_data[i].key_data_ver,
1560 dprinc.key_data[i].key_data_kvno,
1561 dprinc.key_data[i].key_data_type[0],
1562 dprinc.key_data[i].key_data_type[1]);
1563 printf("\n");
1564 }
1565 cleanup:
1566 krb5_free_principal(context, princ);
1567 kadm5_free_principal_ent(handle, &dprinc);
1568 free(canon);
1569 free(princstr);
1570 free(modprincstr);
1571 }
1572
1573 void
kadmin_getprincs(int argc,char * argv[],int sci_idx,void * info_ptr)1574 kadmin_getprincs(int argc, char *argv[], int sci_idx, void *info_ptr)
1575 {
1576 krb5_error_code retval;
1577 char *expr, **names;
1578 int i, count;
1579
1580 expr = NULL;
1581 if (!(argc == 1 || (argc == 2 && (expr = argv[1])))) {
1582 error(_("usage: get_principals [expression]\n"));
1583 return;
1584 }
1585 retval = kadm5_get_principals(handle, expr, &names, &count);
1586 if (retval) {
1587 com_err("get_principals", retval, _("while retrieving list."));
1588 return;
1589 }
1590 for (i = 0; i < count; i++)
1591 printf("%s\n", names[i]);
1592 kadm5_free_name_list(handle, names, count);
1593 }
1594
1595 static int
kadmin_parse_policy_args(int argc,char * argv[],kadm5_policy_ent_t policy,long * mask,char * caller)1596 kadmin_parse_policy_args(int argc, char *argv[], kadm5_policy_ent_t policy,
1597 long *mask, char *caller)
1598 {
1599 krb5_error_code retval;
1600 int i;
1601 time_t now, interval;
1602
1603 time(&now);
1604 *mask = 0;
1605 for (i = 1; i < argc - 1; i++) {
1606 if (!strcmp(argv[i], "-maxlife")) {
1607 if (++i > argc -2)
1608 return -1;
1609 interval = parse_interval(argv[i], now);
1610 if (interval == (time_t)-1)
1611 return -1;
1612 policy->pw_max_life = interval;
1613 *mask |= KADM5_PW_MAX_LIFE;
1614 continue;
1615 } else if (!strcmp(argv[i], "-minlife")) {
1616 if (++i > argc - 2)
1617 return -1;
1618 interval = parse_interval(argv[i], now);
1619 if (interval == (time_t)-1)
1620 return -1;
1621 policy->pw_min_life = interval;
1622 *mask |= KADM5_PW_MIN_LIFE;
1623 continue;
1624 } else if (!strcmp(argv[i], "-minlength")) {
1625 if (++i > argc - 2)
1626 return -1;
1627 policy->pw_min_length = atoi(argv[i]);
1628 *mask |= KADM5_PW_MIN_LENGTH;
1629 continue;
1630 } else if (!strcmp(argv[i], "-minclasses")) {
1631 if (++i > argc - 2)
1632 return -1;
1633 policy->pw_min_classes = atoi(argv[i]);
1634 *mask |= KADM5_PW_MIN_CLASSES;
1635 continue;
1636 } else if (!strcmp(argv[i], "-history")) {
1637 if (++i > argc - 2)
1638 return -1;
1639 policy->pw_history_num = atoi(argv[i]);
1640 *mask |= KADM5_PW_HISTORY_NUM;
1641 continue;
1642 } else if (strlen(argv[i]) == 11 &&
1643 !strcmp(argv[i], "-maxfailure")) {
1644 if (++i > argc - 2)
1645 return -1;
1646 policy->pw_max_fail = atoi(argv[i]);
1647 *mask |= KADM5_PW_MAX_FAILURE;
1648 continue;
1649 } else if (strlen(argv[i]) == 21 &&
1650 !strcmp(argv[i], "-failurecountinterval")) {
1651 if (++i > argc - 2)
1652 return -1;
1653 interval = parse_interval(argv[i], now);
1654 if (interval == (time_t)-1)
1655 return -1;
1656 policy->pw_failcnt_interval = interval;
1657 *mask |= KADM5_PW_FAILURE_COUNT_INTERVAL;
1658 continue;
1659 } else if (strlen(argv[i]) == 16 &&
1660 !strcmp(argv[i], "-lockoutduration")) {
1661 if (++i > argc - 2)
1662 return -1;
1663 interval = parse_interval(argv[i], now);
1664 if (interval == (time_t)-1)
1665 return -1;
1666 policy->pw_lockout_duration = interval;
1667 *mask |= KADM5_PW_LOCKOUT_DURATION;
1668 continue;
1669 } else if (!strcmp(argv[i], "-allowedkeysalts")) {
1670 krb5_key_salt_tuple *ks_tuple = NULL;
1671 int n_ks_tuple = 0;
1672
1673 if (++i > argc - 2)
1674 return -1;
1675 if (strcmp(argv[i], "-")) {
1676 retval = krb5_string_to_keysalts(argv[i], ",", NULL, 0,
1677 &ks_tuple, &n_ks_tuple);
1678 if (retval) {
1679 com_err(caller, retval, _("while parsing keysalts %s"),
1680 argv[i]);
1681 return -1;
1682 }
1683 free(ks_tuple);
1684 policy->allowed_keysalts = argv[i];
1685 }
1686 *mask |= KADM5_POLICY_ALLOWED_KEYSALTS;
1687 continue;
1688 } else
1689 return -1;
1690 }
1691 if (i != argc -1) {
1692 error(_("%s: parser lost count!\n"), caller);
1693 return -1;
1694 } else
1695 return 0;
1696 }
1697
1698 static void
kadmin_addmodpol_usage(char * func)1699 kadmin_addmodpol_usage(char *func)
1700 {
1701 error(_("usage; %s [options] policy\n"), func);
1702 error(_("\toptions are:\n"));
1703 error(_("\t\t[-maxlife time] [-minlife time] [-minlength length]\n"
1704 "\t\t[-minclasses number] [-history number]\n"
1705 "\t\t[-maxfailure number] [-failurecountinterval time]\n"
1706 "\t\t[-allowedkeysalts keysalts]\n"));
1707 error(_("\t\t[-lockoutduration time]\n"));
1708 }
1709
1710 void
kadmin_addpol(int argc,char * argv[],int sci_idx,void * info_ptr)1711 kadmin_addpol(int argc, char *argv[], int sci_idx, void *info_ptr)
1712 {
1713 krb5_error_code retval;
1714 long mask;
1715 kadm5_policy_ent_rec policy;
1716
1717 memset(&policy, 0, sizeof(policy));
1718 if (kadmin_parse_policy_args(argc, argv, &policy, &mask, "add_policy")) {
1719 kadmin_addmodpol_usage("add_policy");
1720 return;
1721 }
1722 policy.policy = argv[argc - 1];
1723 mask |= KADM5_POLICY;
1724 retval = kadm5_create_policy(handle, &policy, mask);
1725 if (retval) {
1726 com_err("add_policy", retval, _("while creating policy \"%s\"."),
1727 policy.policy);
1728 }
1729 }
1730
1731 void
kadmin_modpol(int argc,char * argv[],int sci_idx,void * info_ptr)1732 kadmin_modpol(int argc, char *argv[], int sci_idx, void *info_ptr)
1733 {
1734 krb5_error_code retval;
1735 long mask;
1736 kadm5_policy_ent_rec policy;
1737
1738 memset(&policy, 0, sizeof(policy));
1739 if (kadmin_parse_policy_args(argc, argv, &policy, &mask,
1740 "modify_policy")) {
1741 kadmin_addmodpol_usage("modify_policy");
1742 return;
1743 }
1744 policy.policy = argv[argc - 1];
1745 retval = kadm5_modify_policy(handle, &policy, mask);
1746 if (retval) {
1747 com_err("modify_policy", retval, _("while modifying policy \"%s\"."),
1748 policy.policy);
1749 }
1750 }
1751
1752 void
kadmin_delpol(int argc,char * argv[],int sci_idx,void * info_ptr)1753 kadmin_delpol(int argc, char *argv[], int sci_idx, void *info_ptr)
1754 {
1755 krb5_error_code retval;
1756 char reply[5];
1757
1758 if (!(argc == 2 || (argc == 3 && !strcmp("-force", argv[1])))) {
1759 error(_("usage: delete_policy [-force] policy\n"));
1760 return;
1761 }
1762 if (argc == 2 && !script_mode) {
1763 printf(_("Are you sure you want to delete the policy \"%s\"? "
1764 "(yes/no): "), argv[1]);
1765 fgets(reply, sizeof(reply), stdin);
1766 if (strcmp("yes\n", reply)) {
1767 fprintf(stderr, _("Policy \"%s\" not deleted.\n"), argv[1]);
1768 return;
1769 }
1770 }
1771 retval = kadm5_delete_policy(handle, argv[argc - 1]);
1772 if (retval) {
1773 com_err("delete_policy:", retval, _("while deleting policy \"%s\""),
1774 argv[argc - 1]);
1775 }
1776 }
1777
1778 void
kadmin_getpol(int argc,char * argv[],int sci_idx,void * info_ptr)1779 kadmin_getpol(int argc, char *argv[], int sci_idx, void *info_ptr)
1780 {
1781 krb5_error_code retval;
1782 kadm5_policy_ent_rec policy;
1783
1784 if (!(argc == 2 || (argc == 3 && !strcmp("-terse", argv[1])))) {
1785 error(_("usage: get_policy [-terse] policy\n"));
1786 return;
1787 }
1788 retval = kadm5_get_policy(handle, argv[argc - 1], &policy);
1789 if (retval) {
1790 com_err("get_policy", retval, _("while retrieving policy \"%s\"."),
1791 argv[argc - 1]);
1792 return;
1793 }
1794 if (argc == 2) {
1795 printf(_("Policy: %s\n"), policy.policy);
1796 printf(_("Maximum password life: %s\n"), strdur(policy.pw_max_life));
1797 printf(_("Minimum password life: %s\n"), strdur(policy.pw_min_life));
1798 printf(_("Minimum password length: %ld\n"), policy.pw_min_length);
1799 printf(_("Minimum number of password character classes: %ld\n"),
1800 policy.pw_min_classes);
1801 printf(_("Number of old keys kept: %ld\n"), policy.pw_history_num);
1802 printf(_("Maximum password failures before lockout: %lu\n"),
1803 (unsigned long)policy.pw_max_fail);
1804 printf(_("Password failure count reset interval: %s\n"),
1805 strdur(policy.pw_failcnt_interval));
1806 printf(_("Password lockout duration: %s\n"),
1807 strdur(policy.pw_lockout_duration));
1808 if (policy.allowed_keysalts != NULL)
1809 printf(_("Allowed key/salt types: %s\n"), policy.allowed_keysalts);
1810 } else {
1811 /* Output 0 where we used to output policy_refcnt. */
1812 printf("\"%s\"\t%ld\t%ld\t%ld\t%ld\t%ld\t0\t%lu\t%ld\t%ld\t%s\n",
1813 policy.policy, policy.pw_max_life, policy.pw_min_life,
1814 policy.pw_min_length, policy.pw_min_classes,
1815 policy.pw_history_num, (unsigned long)policy.pw_max_fail,
1816 (long)policy.pw_failcnt_interval,
1817 (long)policy.pw_lockout_duration,
1818 (policy.allowed_keysalts == NULL) ? "-" :
1819 policy.allowed_keysalts);
1820 }
1821 kadm5_free_policy_ent(handle, &policy);
1822 }
1823
1824 void
kadmin_getpols(int argc,char * argv[],int sci_idx,void * info_ptr)1825 kadmin_getpols(int argc, char *argv[], int sci_idx, void *info_ptr)
1826 {
1827 krb5_error_code retval;
1828 char *expr, **names;
1829 int i, count;
1830
1831 expr = NULL;
1832 if (!(argc == 1 || (argc == 2 && (expr = argv[1])))) {
1833 error(_("usage: get_policies [expression]\n"));
1834 return;
1835 }
1836 retval = kadm5_get_policies(handle, expr, &names, &count);
1837 if (retval) {
1838 com_err("get_policies", retval, _("while retrieving list."));
1839 return;
1840 }
1841 for (i = 0; i < count; i++)
1842 printf("%s\n", names[i]);
1843 kadm5_free_name_list(handle, names, count);
1844 }
1845
1846 void
kadmin_getprivs(int argc,char * argv[],int sci_idx,void * info_ptr)1847 kadmin_getprivs(int argc, char *argv[], int sci_idx, void *info_ptr)
1848 {
1849 static char *privs[] = {"INQUIRE", "ADD", "MODIFY", "DELETE"};
1850 krb5_error_code retval;
1851 size_t i;
1852 long plist;
1853
1854 if (argc != 1) {
1855 error(_("usage: get_privs\n"));
1856 return;
1857 }
1858 retval = kadm5_get_privs(handle, &plist);
1859 if (retval) {
1860 com_err("get_privs", retval, _("while retrieving privileges"));
1861 return;
1862 }
1863 printf(_("current privileges:"));
1864 for (i = 0; i < sizeof (privs) / sizeof (char *); i++) {
1865 if (plist & 1 << i)
1866 printf(" %s", privs[i]);
1867 }
1868 printf("\n");
1869 }
1870
1871 void
kadmin_purgekeys(int argc,char * argv[],int sci_idx,void * info_ptr)1872 kadmin_purgekeys(int argc, char *argv[], int sci_idx, void *info_ptr)
1873 {
1874 kadm5_ret_t retval;
1875 int keepkvno = -1;
1876 char *pname = NULL, *canon = NULL;
1877 krb5_principal princ;
1878
1879 if (argc == 4 && strcmp(argv[1], "-keepkvno") == 0) {
1880 keepkvno = atoi(argv[2]);
1881 pname = argv[3];
1882 } else if (argc == 3 && strcmp(argv[1], "-all") == 0) {
1883 keepkvno = KRB5_INT32_MAX;
1884 pname = argv[2];
1885 } else if (argc == 2) {
1886 pname = argv[1];
1887 }
1888 if (pname == NULL) {
1889 error(_("usage: purgekeys [-all|-keepkvno oldest_kvno_to_keep] "
1890 "principal\n"));
1891 return;
1892 }
1893
1894 retval = kadmin_parse_name(pname, &princ);
1895 if (retval) {
1896 com_err("purgekeys", retval, _("while parsing principal"));
1897 return;
1898 }
1899
1900 retval = krb5_unparse_name(context, princ, &canon);
1901 if (retval) {
1902 com_err("purgekeys", retval, _("while canonicalizing principal"));
1903 goto cleanup;
1904 }
1905
1906 retval = kadm5_purgekeys(handle, princ, keepkvno);
1907 if (retval) {
1908 com_err("purgekeys", retval,
1909 _("while purging keys for principal \"%s\""), canon);
1910 goto cleanup;
1911 }
1912
1913 if (keepkvno == KRB5_INT32_MAX)
1914 info(_("All keys for principal \"%s\" removed.\n"), canon);
1915 else
1916 info(_("Old keys for principal \"%s\" purged.\n"), canon);
1917 cleanup:
1918 krb5_free_principal(context, princ);
1919 free(canon);
1920 return;
1921 }
1922
1923 void
kadmin_getstrings(int argc,char * argv[],int sci_idx,void * info_ptr)1924 kadmin_getstrings(int argc, char *argv[], int sci_idx, void *info_ptr)
1925 {
1926 kadm5_ret_t retval;
1927 char *pname, *canon = NULL;
1928 krb5_principal princ = NULL;
1929 krb5_string_attr *strings = NULL;
1930 int count, i;
1931
1932 if (argc != 2) {
1933 error(_("usage: get_strings principal\n"));
1934 return;
1935 }
1936 pname = argv[1];
1937
1938 retval = kadmin_parse_name(pname, &princ);
1939 if (retval) {
1940 com_err("get_strings", retval, _("while parsing principal"));
1941 return;
1942 }
1943
1944 retval = krb5_unparse_name(context, princ, &canon);
1945 if (retval) {
1946 com_err("get_strings", retval, _("while canonicalizing principal"));
1947 goto cleanup;
1948 }
1949
1950 retval = kadm5_get_strings(handle, princ, &strings, &count);
1951 if (retval) {
1952 com_err("get_strings", retval,
1953 _("while getting attributes for principal \"%s\""), canon);
1954 goto cleanup;
1955 }
1956
1957 if (count == 0)
1958 printf(_("(No string attributes.)\n"));
1959 for (i = 0; i < count; i++)
1960 printf("%s: %s\n", strings[i].key, strings[i].value);
1961 kadm5_free_strings(handle, strings, count);
1962
1963 cleanup:
1964 krb5_free_principal(context, princ);
1965 free(canon);
1966 return;
1967 }
1968
1969 void
kadmin_setstring(int argc,char * argv[],int sci_idx,void * info_ptr)1970 kadmin_setstring(int argc, char *argv[], int sci_idx, void *info_ptr)
1971 {
1972 kadm5_ret_t retval;
1973 char *pname, *canon = NULL, *key, *value;
1974 krb5_principal princ = NULL;
1975
1976 if (argc != 4) {
1977 error(_("usage: set_string principal key value\n"));
1978 return;
1979 }
1980 pname = argv[1];
1981 key = argv[2];
1982 value = argv[3];
1983
1984 retval = kadmin_parse_name(pname, &princ);
1985 if (retval) {
1986 com_err("set_string", retval, _("while parsing principal"));
1987 return;
1988 }
1989
1990 retval = krb5_unparse_name(context, princ, &canon);
1991 if (retval) {
1992 com_err("set_string", retval, _("while canonicalizing principal"));
1993 goto cleanup;
1994 }
1995
1996 retval = kadm5_set_string(handle, princ, key, value);
1997 if (retval) {
1998 com_err("set_string", retval,
1999 _("while setting attribute on principal \"%s\""), canon);
2000 goto cleanup;
2001 }
2002
2003 info(_("Attribute set for principal \"%s\".\n"), canon);
2004 cleanup:
2005 krb5_free_principal(context, princ);
2006 free(canon);
2007 return;
2008 }
2009
2010 void
kadmin_delstring(int argc,char * argv[],int sci_idx,void * info_ptr)2011 kadmin_delstring(int argc, char *argv[], int sci_idx, void *info_ptr)
2012 {
2013 kadm5_ret_t retval;
2014 char *pname, *canon = NULL, *key;
2015 krb5_principal princ = NULL;
2016
2017 if (argc != 3) {
2018 error(_("usage: del_string principal key\n"));
2019 return;
2020 }
2021 pname = argv[1];
2022 key = argv[2];
2023
2024 retval = kadmin_parse_name(pname, &princ);
2025 if (retval) {
2026 com_err("delstring", retval, _("while parsing principal"));
2027 return;
2028 }
2029
2030 retval = krb5_unparse_name(context, princ, &canon);
2031 if (retval) {
2032 com_err("del_string", retval, _("while canonicalizing principal"));
2033 goto cleanup;
2034 }
2035
2036 retval = kadm5_set_string(handle, princ, key, NULL);
2037 if (retval) {
2038 com_err("del_string", retval,
2039 _("while deleting attribute from principal \"%s\""), canon);
2040 goto cleanup;
2041 }
2042
2043 info(_("Attribute removed from principal \"%s\".\n"), canon);
2044 cleanup:
2045 krb5_free_principal(context, princ);
2046 free(canon);
2047 return;
2048 }
2049