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