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