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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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