1 /* 2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 /* 8 * Copyright 1994 by the Massachusetts Institute of Technology. 9 * All Rights Reserved. 10 * 11 * Export of this software from the United States of America may 12 * require a specific license from the United States Government. 13 * It is the responsibility of any person or organization contemplating 14 * export to obtain such a license before exporting. 15 * 16 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 17 * distribute this software and its documentation for any purpose and 18 * without fee is hereby granted, provided that the above copyright 19 * notice appear in all copies and that both that copyright notice and 20 * this permission notice appear in supporting documentation, and that 21 * the name of M.I.T. not be used in advertising or publicity pertaining 22 * to distribution of the software without specific, written prior 23 * permission. Furthermore if you modify this software you must label 24 * your software as modified software and not distribute it in such a 25 * fashion that it might be confused with the original M.I.T. software. 26 * M.I.T. makes no representations about the suitability of 27 * this software for any purpose. It is provided "as is" without express 28 * or implied warranty. 29 * 30 * kadmin.c: base functions for a kadmin command line interface using 31 * the OVSecure library 32 */ 33 34 #include <kadm5/admin.h> 35 #include <krb5/adm_proto.h> 36 #include <stdio.h> 37 #include <string.h> 38 #include <sys/types.h> 39 #include <math.h> 40 #include <unistd.h> 41 #include <pwd.h> 42 /* #include <sys/timeb.h> */ 43 #include <time.h> 44 #include "kadmin.h" 45 #include <libintl.h> 46 #include <krb5.h> 47 48 /* 49 * Solaris: the following are needed for paging 50 */ 51 #include <signal.h> 52 #include <sys/wait.h> 53 54 /* command name when called "locally" (i.e. non-networked client ) */ 55 #define KADMIN_LOCAL_NAME "kadmin.local" 56 57 /* functions defined in remote/local specific files */ 58 extern void usage(const char *); 59 60 /* special struct to convert flag names for principals 61 to actual krb5_flags for a principal */ 62 struct pflag { 63 char *flagname; /* name of flag as typed to CLI */ 64 int flaglen; /* length of string (not counting -,+) */ 65 krb5_flags theflag; /* actual principal flag to set/clear */ 66 int set; /* 0 means clear, 1 means set (on '-') */ 67 }; 68 69 static struct pflag flags[] = { 70 {"allow_postdated", 15, KRB5_KDB_DISALLOW_POSTDATED, 1}, 71 {"allow_forwardable", 17, KRB5_KDB_DISALLOW_FORWARDABLE, 1}, 72 {"allow_tgs_req", 13, KRB5_KDB_DISALLOW_TGT_BASED, 1}, 73 {"allow_renewable", 15, KRB5_KDB_DISALLOW_RENEWABLE, 1}, 74 {"allow_proxiable", 15, KRB5_KDB_DISALLOW_PROXIABLE, 1}, 75 {"allow_dup_skey", 14, KRB5_KDB_DISALLOW_DUP_SKEY, 1}, 76 {"allow_tix", 9, KRB5_KDB_DISALLOW_ALL_TIX, 1}, 77 {"requires_preauth", 16, KRB5_KDB_REQUIRES_PRE_AUTH, 0}, 78 {"requires_hwauth", 15, KRB5_KDB_REQUIRES_HW_AUTH, 0}, 79 {"needchange", 10, KRB5_KDB_REQUIRES_PWCHANGE, 0}, 80 {"allow_svr", 9, KRB5_KDB_DISALLOW_SVR, 1}, 81 {"password_changing_service", 25, KRB5_KDB_PWCHANGE_SERVICE, 0 }, 82 {"support_desmd5", 14, KRB5_KDB_SUPPORT_DESMD5, 0 } 83 }; 84 85 static char *prflags[] = { 86 "DISALLOW_POSTDATED", /* 0x00000001 */ 87 "DISALLOW_FORWARDABLE", /* 0x00000002 */ 88 "DISALLOW_TGT_BASED", /* 0x00000004 */ 89 "DISALLOW_RENEWABLE", /* 0x00000008 */ 90 "DISALLOW_PROXIABLE", /* 0x00000010 */ 91 "DISALLOW_DUP_SKEY", /* 0x00000020 */ 92 "DISALLOW_ALL_TIX", /* 0x00000040 */ 93 "REQUIRES_PRE_AUTH", /* 0x00000080 */ 94 "REQUIRES_HW_AUTH", /* 0x00000100 */ 95 "REQUIRES_PWCHANGE", /* 0x00000200 */ 96 "UNKNOWN_0x00000400", /* 0x00000400 */ 97 "UNKNOWN_0x00000800", /* 0x00000800 */ 98 "DISALLOW_SVR", /* 0x00001000 */ 99 "PWCHANGE_SERVICE", /* 0x00002000 */ 100 "SUPPORT_DESMD5", /* 0x00004000 */ 101 "NEW_PRINC", /* 0x00008000 */ 102 }; 103 104 char *getenv(); 105 int exit_status = 0; 106 char *def_realm = NULL; 107 char *whoami = NULL; 108 109 void *handle = NULL; 110 krb5_context context; 111 char *ccache_name = NULL; 112 113 int locked = 0; 114 static char *strdur(duration) 115 time_t duration; 116 { 117 static char out[50]; 118 int neg, days, hours, minutes, seconds; 119 120 if (duration < 0) { 121 duration *= -1; 122 neg = 1; 123 } else 124 neg = 0; 125 days = duration / (24 * 3600); 126 duration %= 24 * 3600; 127 hours = duration / 3600; 128 duration %= 3600; 129 minutes = duration / 60; 130 duration %= 60; 131 seconds = duration; 132 snprintf(out, sizeof (out), "%s%d %s %02d:%02d:%02d", neg ? "-" : "", 133 days, days == 1 ? gettext("day") : gettext("days"), 134 hours, minutes, seconds); 135 return out; 136 } 137 138 static char *strdate(when) 139 krb5_timestamp when; 140 { 141 struct tm *tm; 142 static char out[40]; 143 144 time_t lcltim = when; 145 tm = localtime(&lcltim); 146 strftime(out, sizeof(out), gettext("%a %b %d %H:%M:%S %Z %Y"), tm); 147 return out; 148 } 149 150 /* this is a wrapper to go around krb5_parse_principal so we can set 151 the default realm up properly */ 152 static krb5_error_code 153 kadmin_parse_name(name, principal) 154 char *name; 155 krb5_principal *principal; 156 { 157 char *cp, *fullname; 158 krb5_error_code retval; 159 160 if (name == NULL) 161 return (EINVAL); 162 163 /* assumes def_realm is initialized! */ 164 fullname = (char *)malloc(strlen(name) + 1 + strlen(def_realm) + 1); 165 if (fullname == NULL) 166 return ENOMEM; 167 strcpy(fullname, name); 168 cp = strchr(fullname, '@'); 169 while (cp) { 170 if (cp - fullname && *(cp - 1) != '\\') 171 break; 172 else 173 cp = strchr(cp + 1, '@'); 174 } 175 if (cp == NULL) { 176 strcat(fullname, "@"); 177 strcat(fullname, def_realm); 178 } 179 retval = krb5_parse_name(context, fullname, principal); 180 free(fullname); 181 return retval; 182 } 183 184 static void extended_com_err_fn (const char *myprog, errcode_t code, 185 const char *fmt, va_list args) 186 { 187 if (code) { 188 const char *emsg; 189 emsg = krb5_get_error_message (context, code); 190 fprintf (stderr, "%s: %s ", myprog, emsg); 191 krb5_free_error_message (context, emsg); 192 } else { 193 fprintf (stderr, "%s: ", myprog); 194 } 195 vfprintf (stderr, fmt, args); 196 fprintf (stderr, "\n"); 197 } 198 char *kadmin_startup(argc, argv) 199 int argc; 200 char *argv[]; 201 { 202 extern char *optarg; 203 char *princstr = NULL, *keytab_name = NULL, *query = NULL; 204 char *password = NULL; 205 char *luser, *canon, *cp; 206 int optchar, freeprinc = 0, use_keytab = 0; 207 struct passwd *pw; 208 kadm5_ret_t retval; 209 krb5_ccache cc; 210 krb5_principal princ; 211 kadm5_config_params params; 212 char **db_args = NULL; 213 int db_args_size = 0; 214 char *db_name = NULL; 215 char *svcname = NULL; 216 217 memset((char *) ¶ms, 0, sizeof(params)); 218 219 if (strcmp (whoami, "kadmin.local") == 0) 220 set_com_err_hook(extended_com_err_fn); 221 222 retval = kadm5_init_krb5_context(&context); 223 if (retval) { 224 com_err(whoami, retval, gettext("while initializing krb5 library")); 225 exit(1); 226 } 227 228 while ((optchar = getopt(argc, argv, "x:r:p:kq:w:d:s:mc:t:e:ON")) != EOF) { 229 switch (optchar) { 230 case 'x': 231 db_args_size++; 232 { 233 char **temp = realloc(db_args, sizeof(char*) * (db_args_size+1)); 234 if (temp == NULL) { 235 fprintf(stderr, gettext("%s: Cannot initialize. Not enough memory\n"), 236 argv[0]); 237 exit(1); 238 } 239 240 db_args = temp; 241 } 242 db_args[db_args_size-1] = optarg; 243 db_args[db_args_size] = NULL; 244 break; 245 246 case 'r': 247 def_realm = optarg; 248 break; 249 case 'p': 250 princstr = optarg; 251 break; 252 case 'c': 253 ccache_name = optarg; 254 break; 255 case 'k': 256 use_keytab++; 257 break; 258 case 't': 259 keytab_name = optarg; 260 break; 261 case 'w': 262 password = optarg; 263 break; 264 case 'q': 265 query = optarg; 266 break; 267 case 'd': 268 /* now db_name is not a seperate argument. It has to be passed as part of the db_args */ 269 if (!db_name) { 270 db_name = malloc(strlen(optarg) + sizeof("dbname=")); 271 } else { 272 db_name = realloc(db_name, strlen(optarg) + sizeof("dbname=")); 273 } 274 275 strcpy(db_name, "dbname="); 276 strcat(db_name, optarg); 277 278 db_args_size++; 279 { 280 char **temp = realloc(db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */ 281 if (temp == NULL) { 282 fprintf(stderr, 283 gettext("%s: Cannot initialize. Not enough memory\n"), 284 argv[0]); 285 exit(1); 286 } 287 288 db_args = temp; 289 } 290 db_args[db_args_size-1] = db_name; 291 db_args[db_args_size] = NULL; 292 break; 293 case 's': 294 params.admin_server = optarg; 295 params.mask |= KADM5_CONFIG_ADMIN_SERVER; 296 break; 297 case 'm': 298 params.mkey_from_kbd = 1; 299 params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; 300 break; 301 case 'e': 302 retval = krb5_string_to_keysalts(optarg, 303 ", \t", 304 ":.-", 305 0, 306 ¶ms.keysalts, 307 ¶ms.num_keysalts); 308 if (retval) { 309 com_err(whoami, retval, 310 gettext("while parsing keysalts %s"), optarg); 311 exit(1); 312 } 313 params.mask |= KADM5_CONFIG_ENCTYPES; 314 break; 315 case 'O': /* Undocumented option for testing only */ 316 svcname = KADM5_ADMIN_SERVICE_P; 317 break; 318 default: 319 usage(whoami); 320 } 321 } 322 if ((ccache_name && use_keytab) || 323 (keytab_name && !use_keytab)) 324 usage(whoami); 325 326 if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) { 327 if (freeprinc) 328 free(princstr); 329 fprintf(stderr, 330 gettext("%s: unable to get default realm\n"), whoami); 331 exit(1); 332 } 333 334 params.mask |= KADM5_CONFIG_REALM; 335 params.realm = def_realm; 336 337 if (svcname == NULL) { 338 if (kadm5_get_adm_host_srv_name(context, 339 def_realm, &svcname)) { 340 fprintf(stderr, 341 gettext("%s: unable to get host based " 342 "service name for realm %s\n"), 343 whoami, def_realm); 344 if (freeprinc) 345 free(princstr); 346 exit(1); 347 } 348 } 349 350 /* 351 * Set cc to an open credentials cache, either specified by the -c 352 * argument or the default. 353 */ 354 if (ccache_name == NULL) { 355 if ((retval = krb5_cc_default(context, &cc))) { 356 com_err(whoami, retval, 357 gettext("while opening default " 358 "credentials cache")); 359 exit(1); 360 } 361 } else { 362 if ((retval = krb5_cc_resolve(context, ccache_name, &cc))) { 363 com_err(whoami, retval, 364 gettext("while opening credentials cache %s"), 365 ccache_name); 366 exit(1); 367 } 368 } 369 370 /* 371 * If no principal name is specified: If a ccache was specified 372 * and its primary principal name can be read, it is used, else if 373 * a keytab was specified, the principal name is host/hostname, 374 * otherwise append "/admin" to the primary name of the default 375 * ccache, $USER, or pw_name. 376 * 377 * Gee, 100+ lines to figure out the client principal name. This 378 * should be compressed... 379 */ 380 381 if (princstr == NULL) { 382 if (ccache_name != NULL && 383 !krb5_cc_get_principal(context, cc, &princ)) { 384 if ((retval = krb5_unparse_name(context, princ, &princstr))) { 385 com_err(whoami, retval, 386 gettext("while canonicalizing principal name")); 387 krb5_free_principal(context, princ); 388 exit(1); 389 } 390 krb5_free_principal(context, princ); 391 freeprinc++; 392 } else if (use_keytab != 0) { 393 if ((retval = krb5_sname_to_principal(context, NULL, 394 "host", 395 KRB5_NT_SRV_HST, 396 &princ))) { 397 com_err(whoami, retval, 398 gettext("creating host service principal")); 399 exit(1); 400 } 401 if ((retval = krb5_unparse_name(context, princ, &princstr))) { 402 com_err(whoami, retval, 403 gettext("while canonicalizing principal name")); 404 krb5_free_principal(context, princ); 405 exit(1); 406 } 407 krb5_free_principal(context, princ); 408 freeprinc++; 409 } else if (!krb5_cc_get_principal(context, cc, &princ)) { 410 char *realm = NULL; 411 if (krb5_unparse_name(context, princ, &canon)) { 412 fprintf(stderr, 413 gettext("%s: unable to canonicalize " 414 "principal\n"), whoami); 415 krb5_free_principal(context, princ); 416 exit(1); 417 } 418 /* strip out realm of principal if it's there */ 419 realm = strchr(canon, '@'); 420 while (realm) { 421 if (realm - canon && *(realm - 1) != '\\') 422 break; 423 else 424 realm = strchr(realm+1, '@'); 425 } 426 if (realm) 427 *realm++ = '\0'; 428 cp = strchr(canon, '/'); 429 while (cp) { 430 if (cp - canon && *(cp - 1) != '\\') 431 break; 432 else 433 cp = strchr(cp+1, '/'); 434 } 435 if (cp != NULL) 436 *cp = '\0'; 437 princstr = (char*)malloc(strlen(canon) + 6 /* "/admin" */ + 438 (realm ? 1 + strlen(realm) : 0) + 1); 439 if (princstr == NULL) { 440 fprintf(stderr, 441 gettext("%s: out of memory\n"), 442 whoami); 443 exit(1); 444 } 445 strcpy(princstr, canon); 446 strcat(princstr, "/admin"); 447 if (realm) { 448 strcat(princstr, "@"); 449 strcat(princstr, realm); 450 } 451 free(canon); 452 krb5_free_principal(context, princ); 453 freeprinc++; 454 } else if ((luser = getenv("USER"))) { 455 princstr = (char *) malloc(strlen(luser) + 7 /* "/admin@" */ 456 + strlen(def_realm) + 1); 457 if (princstr == NULL) { 458 fprintf(stderr, 459 gettext("%s: out of memory\n"), 460 whoami); 461 exit(1); 462 } 463 strcpy(princstr, luser); 464 strcat(princstr, "/admin"); 465 strcat(princstr, "@"); 466 strcat(princstr, def_realm); 467 freeprinc++; 468 } else if ((pw = getpwuid(getuid()))) { 469 princstr = (char *) malloc(strlen(pw->pw_name) + 7 /* "/admin@" */ 470 + strlen(def_realm) + 1); 471 if (princstr == NULL) { 472 fprintf(stderr, 473 gettext("%s: out of memory\n"), 474 whoami); 475 exit(1); 476 } 477 strcpy(princstr, pw->pw_name); 478 strcat(princstr, "/admin@"); 479 strcat(princstr, def_realm); 480 freeprinc++; 481 } else { 482 fprintf(stderr, 483 gettext("%s: unable to figure out " 484 "a principal name\n"), 485 whoami); 486 exit(1); 487 } 488 } 489 490 retval = krb5_klog_init(context, "admin_server", whoami, 0); 491 if (retval) { 492 com_err(whoami, retval, "while setting up logging"); 493 exit(1); 494 } 495 496 /* 497 * Initialize the kadm5 connection. If we were given a ccache, 498 * use it. Otherwise, use/prompt for the password. 499 */ 500 501 /* Solaris Kerberos: 502 * Send warnings to stderr 503 */ 504 if (ccache_name) { 505 fprintf(stderr, gettext("Authenticating as principal %s with existing credentials.\n"), 506 princstr); 507 retval = kadm5_init_with_creds(princstr, cc, 508 svcname, 509 ¶ms, 510 KADM5_STRUCT_VERSION, 511 KADM5_API_VERSION_2, 512 db_args, 513 &handle); 514 } else if (use_keytab) { 515 if (keytab_name) 516 fprintf(stderr, gettext("Authenticating as principal %s with keytab %s.\n"), 517 princstr, keytab_name); 518 else 519 fprintf(stderr, gettext("Authenticating as principal %s with default keytab.\n"), 520 princstr); 521 retval = kadm5_init_with_skey(princstr, keytab_name, 522 svcname, 523 ¶ms, 524 KADM5_STRUCT_VERSION, 525 KADM5_API_VERSION_2, 526 db_args, 527 &handle); 528 } else { 529 fprintf(stderr, gettext("Authenticating as principal %s with password.\n"), 530 princstr); 531 retval = kadm5_init_with_password(princstr, password, 532 svcname, 533 ¶ms, 534 KADM5_STRUCT_VERSION, 535 KADM5_API_VERSION_2, 536 db_args, 537 &handle); 538 } 539 if (retval) { 540 if (retval == KADM5_RPC_ERROR_CANTENCODEARGS || 541 retval == KADM5_RPC_ERROR_CANTDECODEARGS) { 542 com_err(whoami, KADM5_RPC_ERROR, 543 gettext("while initializing %s interface"), whoami); 544 545 /* privacy-enabled mech probably not installed/configed */ 546 com_err(whoami, retval, gettext("."), whoami); 547 } else { 548 com_err(whoami, retval, 549 gettext("while initializing %s interface"), whoami); 550 if (retval == KADM5_BAD_CLIENT_PARAMS || 551 retval == KADM5_BAD_SERVER_PARAMS) 552 usage(whoami); 553 } 554 exit(1); 555 } 556 if (freeprinc) 557 free(princstr); 558 559 if (db_name) 560 free(db_name), db_name=NULL; 561 562 if (db_args) 563 free(db_args), db_args=NULL; 564 565 if ((retval = krb5_cc_close(context, cc))) { 566 com_err(whoami, retval, gettext("while closing ccache %s"), 567 ccache_name); 568 exit(1); 569 } 570 571 /* register the WRFILE keytab type and set it as the default */ 572 { 573 #define DEFAULT_KEYTAB "WRFILE:/etc/krb5/krb5.keytab" 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 /* 1387 * Solaris Kerberos: We unset KRB5_KDB_DISALLOW_ALL_TIX before 1388 * kadmin_parse_princ_args is called, because -allow_tix may 1389 * have been an argument. We still have to unset here because 1390 * kadmin_parse_princ_args will not reset the attribute unless 1391 * it is was explicity defined. 1392 */ 1393 princ.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX; 1394 (void) kadmin_parse_princ_args(argc, argv, &princ, &mask, &pass, 1395 &randkey, &ks_tuple, &n_ks_tuple, "add_principal"); 1396 mask = KADM5_ATTRIBUTES; 1397 retval = kadm5_modify_principal(handle, &princ, mask); 1398 if (retval) { 1399 com_err("add_principal", retval, 1400 gettext("while doing a modify_principal to restore flag " 1401 "settings for \"%s\"."), canon); 1402 krb5_free_principal(context, princ.principal); 1403 free(canon); 1404 if (ks_tuple != NULL) 1405 free(ks_tuple); 1406 kadmin_free_tl_data(&princ); 1407 return; 1408 } 1409 } 1410 krb5_free_principal(context, princ.principal); 1411 printf(gettext("Principal \"%s\" created.\n"), canon); 1412 if (ks_tuple != NULL) 1413 free(ks_tuple); 1414 free(canon); 1415 kadmin_free_tl_data(&princ); 1416 1417 } 1418 1419 void kadmin_modprinc(argc, argv) 1420 int argc; 1421 char *argv[]; 1422 { 1423 kadm5_principal_ent_rec princ, oldprinc; 1424 krb5_principal kprinc; 1425 long mask; 1426 krb5_error_code retval; 1427 char *pass, *canon; 1428 int randkey = 0; 1429 int n_ks_tuple = 0; 1430 krb5_key_salt_tuple *ks_tuple; 1431 1432 if (argc < 2) { 1433 kadmin_modprinc_usage("modify_principal"); 1434 return; 1435 } 1436 1437 memset(&oldprinc, 0, sizeof(oldprinc)); 1438 memset(&princ, 0, sizeof(princ)); 1439 1440 retval = kadmin_parse_name(argv[argc - 1], &kprinc); 1441 if (retval) { 1442 com_err("modify_principal", retval, 1443 gettext("while parsing principal")); 1444 return; 1445 } 1446 retval = krb5_unparse_name(context, kprinc, &canon); 1447 if (retval) { 1448 com_err("modify_principal", retval, 1449 gettext("while canonicalizing principal")); 1450 krb5_free_principal(context, kprinc); 1451 return; 1452 } 1453 retval = kadm5_get_principal(handle, kprinc, &oldprinc, 1454 KADM5_PRINCIPAL_NORMAL_MASK); 1455 krb5_free_principal(context, kprinc); 1456 if (retval) { 1457 com_err("modify_principal", retval, 1458 gettext("while getting \"%s\"."), canon); 1459 free(canon); 1460 return; 1461 } 1462 princ.attributes = oldprinc.attributes; 1463 kadm5_free_principal_ent(handle, &oldprinc); 1464 retval = kadmin_parse_princ_args(argc, argv, 1465 &princ, &mask, 1466 &pass, &randkey, 1467 &ks_tuple, &n_ks_tuple, 1468 "modify_principal"); 1469 if (ks_tuple != NULL) { 1470 free(ks_tuple); 1471 kadmin_modprinc_usage("modify_principal"); 1472 free(canon); 1473 kadmin_free_tl_data(&princ); 1474 return; 1475 } 1476 if (retval) { 1477 kadmin_modprinc_usage("modify_principal"); 1478 free(canon); 1479 kadmin_free_tl_data(&princ); 1480 return; 1481 } 1482 if (randkey) { 1483 fprintf(stderr, "modify_principal: -randkey %s ", 1484 gettext("not allowed\n")); 1485 krb5_free_principal(context, princ.principal); 1486 free(canon); 1487 kadmin_free_tl_data(&princ); 1488 return; 1489 } 1490 if (pass) { 1491 fprintf(stderr, 1492 "modify_principal: -pw %s change_password\n", 1493 gettext("not allowed; use")); 1494 krb5_free_principal(context, princ.principal); 1495 free(canon); 1496 kadmin_free_tl_data(&princ); 1497 return; 1498 } 1499 retval = kadm5_modify_principal(handle, &princ, mask); 1500 krb5_free_principal(context, princ.principal); 1501 if (retval) { 1502 com_err("modify_principal", retval, 1503 gettext("while modifying \"%s\"."), canon); 1504 free(canon); 1505 kadmin_free_tl_data(&princ); 1506 return; 1507 } 1508 printf(gettext("Principal \"%s\" modified.\n"), canon); 1509 kadmin_free_tl_data(&princ); 1510 free(canon); 1511 } 1512 1513 void kadmin_getprinc(argc, argv) 1514 int argc; 1515 char *argv[]; 1516 { 1517 kadm5_principal_ent_rec dprinc; 1518 krb5_principal princ; 1519 krb5_error_code retval; 1520 char *canon, *modcanon; 1521 int i; 1522 1523 if (! (argc == 2 || 1524 (argc == 3 && !strcmp("-terse", argv[1])))) { 1525 fprintf(stderr, "%s: get_principal [-terse] %s\n", 1526 gettext("usage"), gettext("principal")); 1527 return; 1528 } 1529 1530 1531 memset(&dprinc, 0, sizeof(dprinc)); 1532 memset(&princ, 0, sizeof(princ)); 1533 1534 retval = kadmin_parse_name(argv[argc - 1], &princ); 1535 if (retval) { 1536 com_err("get_principal", retval, 1537 gettext("while parsing principal")); 1538 return; 1539 } 1540 retval = krb5_unparse_name(context, princ, &canon); 1541 if (retval) { 1542 com_err("get_principal", retval, 1543 gettext("while canonicalizing principal")); 1544 krb5_free_principal(context, princ); 1545 return; 1546 } 1547 retval = kadm5_get_principal(handle, princ, &dprinc, 1548 KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA); 1549 krb5_free_principal(context, princ); 1550 if (retval) { 1551 com_err("get_principal", retval, 1552 gettext("while retrieving \"%s\"."), canon); 1553 free(canon); 1554 return; 1555 } 1556 retval = krb5_unparse_name(context, dprinc.mod_name, &modcanon); 1557 if (retval) { 1558 com_err("get_principal", retval, 1559 gettext("while unparsing modname")); 1560 kadm5_free_principal_ent(handle, &dprinc); 1561 free(canon); 1562 return; 1563 } 1564 if (argc == 2) { 1565 printf(gettext("Principal: %s\n"), canon); 1566 printf(gettext("Expiration date: %s\n"), 1567 dprinc.princ_expire_time ? 1568 strdate(dprinc.princ_expire_time) : 1569 gettext("[never]")); 1570 printf(gettext("Last password change: %s\n"), 1571 dprinc.last_pwd_change ? 1572 strdate(dprinc.last_pwd_change) : 1573 gettext("[never]")); 1574 printf(gettext("Password expiration date: %s\n"), 1575 dprinc.pw_expiration ? 1576 strdate(dprinc.pw_expiration) : gettext("[none]")); 1577 printf(gettext("Maximum ticket life: %s\n"), 1578 strdur(dprinc.max_life)); 1579 printf(gettext("Maximum renewable life: %s\n"), 1580 strdur(dprinc.max_renewable_life)); 1581 printf(gettext("Last modified: %s (%s)\n"), 1582 strdate(dprinc.mod_date), modcanon); 1583 printf(gettext("Last successful authentication: %s\n"), 1584 dprinc.last_success ? strdate(dprinc.last_success) : 1585 gettext("[never]")); 1586 printf(gettext("Last failed authentication: %s\n"), 1587 dprinc.last_failed ? strdate(dprinc.last_failed) : 1588 gettext("[never]")); 1589 printf(gettext("Failed password attempts: %d\n"), 1590 dprinc.fail_auth_count); 1591 printf(gettext("Number of keys: %d\n"), dprinc.n_key_data); 1592 for (i = 0; i < dprinc.n_key_data; i++) { 1593 krb5_key_data *key_data = &dprinc.key_data[i]; 1594 char enctype[BUFSIZ], salttype[BUFSIZ]; 1595 1596 if (krb5_enctype_to_string(key_data->key_data_type[0], 1597 enctype, sizeof(enctype))) 1598 snprintf(enctype, sizeof (enctype), gettext("<Encryption type 0x%x>"), 1599 key_data->key_data_type[0]); 1600 printf("Key: vno %d, %s, ", key_data->key_data_kvno, enctype); 1601 if (key_data->key_data_ver > 1) { 1602 if (krb5_salttype_to_string(key_data->key_data_type[1], 1603 salttype, sizeof(salttype))) 1604 snprintf(salttype, sizeof(salttype), gettext("<Salt type 0x%x>"), 1605 key_data->key_data_type[1]); 1606 printf("%s\n", salttype); 1607 } else 1608 printf(gettext("no salt\n")); 1609 } 1610 1611 printf(gettext("Attributes:")); 1612 for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) { 1613 if (dprinc.attributes & (krb5_flags) 1 << i) 1614 printf(" %s", prflags[i]); 1615 } 1616 printf("\n"); 1617 printf(gettext("Policy: %s\n"), 1618 dprinc.policy ? dprinc.policy : gettext("[none]")); 1619 } else { 1620 printf("\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"" 1621 "\t%d\t%d\t%d\t%d\t%d", 1622 canon, dprinc.princ_expire_time, dprinc.last_pwd_change, 1623 dprinc.pw_expiration, dprinc.max_life, modcanon, 1624 dprinc.mod_date, dprinc.attributes, dprinc.kvno, 1625 dprinc.mkvno, dprinc.policy ? dprinc.policy : gettext("[none]"), 1626 dprinc.max_renewable_life, dprinc.last_success, 1627 dprinc.last_failed, dprinc.fail_auth_count, 1628 dprinc.n_key_data); 1629 for (i = 0; i < dprinc.n_key_data; i++) 1630 printf("\t%d\t%d\t%d\t%d", 1631 dprinc.key_data[i].key_data_ver, 1632 dprinc.key_data[i].key_data_kvno, 1633 dprinc.key_data[i].key_data_type[0], 1634 dprinc.key_data[i].key_data_type[1]); 1635 printf("\n"); 1636 } 1637 free(modcanon); 1638 kadm5_free_principal_ent(handle, &dprinc); 1639 free(canon); 1640 } 1641 1642 void kadmin_getprincs(argc, argv) 1643 int argc; 1644 char *argv[]; 1645 { 1646 krb5_error_code retval; 1647 char *expr, **names; 1648 int i, count; 1649 1650 FILE *output; 1651 int fd; 1652 struct sigaction nsig, osig; 1653 sigset_t nmask, omask; 1654 int waitb; 1655 1656 expr = NULL; 1657 if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) { 1658 fprintf(stderr, "%s: get_principals %s\n", 1659 gettext("usage"), gettext("[expression]")); 1660 return; 1661 } 1662 retval = kadm5_get_principals(handle, expr, &names, &count); 1663 if (retval) { 1664 com_err("get_principals", retval, 1665 gettext("while retrieving list.")); 1666 return; 1667 } 1668 1669 /* 1670 * Solaris: the following code is used for paging 1671 */ 1672 1673 sigemptyset(&nmask); 1674 sigaddset(&nmask, SIGINT); 1675 sigprocmask(SIG_BLOCK, &nmask, &omask); 1676 1677 nsig.sa_handler = SIG_IGN; 1678 sigemptyset(&nsig.sa_mask); 1679 nsig.sa_flags = 0; 1680 sigaction(SIGINT, &nsig, &osig); 1681 1682 fd = ss_pager_create(); 1683 output = fdopen(fd, "w"); 1684 1685 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 1686 1687 for (i = 0; i < count; i++) 1688 fprintf(output, "%s\n", names[i]); 1689 1690 fclose(output); 1691 1692 wait(&waitb); 1693 1694 /* Solaris Kerberos: 1695 * Restore the original handler for SIGINT 1696 */ 1697 if (sigaction(SIGINT, &osig, (struct sigaction *)0) == -1) { 1698 perror("sigaction"); 1699 } 1700 1701 kadm5_free_name_list(handle, names, count); 1702 } 1703 1704 static int 1705 kadmin_parse_policy_args(argc, argv, policy, mask, caller) 1706 int argc; 1707 char *argv[]; 1708 kadm5_policy_ent_t policy; 1709 long *mask; 1710 char *caller; 1711 { 1712 int i; 1713 time_t now; 1714 time_t date; 1715 1716 time(&now); 1717 *mask = 0; 1718 for (i = 1; i < argc - 1; i++) { 1719 if (strlen(argv[i]) == 8 && 1720 !strcmp(argv[i], "-maxlife")) { 1721 if (++i > argc -2) 1722 return -1; 1723 else { 1724 date = get_date(argv[i]); 1725 if (date == (time_t)-1) { 1726 fprintf(stderr, gettext("Invalid date specification \"%s\".\n"), 1727 argv[i]); 1728 return -1; 1729 } 1730 policy->pw_max_life = date - now; 1731 *mask |= KADM5_PW_MAX_LIFE; 1732 continue; 1733 } 1734 } else if (strlen(argv[i]) == 8 && 1735 !strcmp(argv[i], "-minlife")) { 1736 if (++i > argc - 2) 1737 return -1; 1738 else { 1739 date = get_date(argv[i]); 1740 if (date == (time_t)-1) { 1741 fprintf(stderr, gettext("Invalid date specification \"%s\".\n"), 1742 argv[i]); 1743 return -1; 1744 } 1745 policy->pw_min_life = date - now; 1746 *mask |= KADM5_PW_MIN_LIFE; 1747 continue; 1748 } 1749 } else if (strlen(argv[i]) == 10 && 1750 !strcmp(argv[i], "-minlength")) { 1751 if (++i > argc - 2) 1752 return -1; 1753 else { 1754 policy->pw_min_length = atoi(argv[i]); 1755 *mask |= KADM5_PW_MIN_LENGTH; 1756 continue; 1757 } 1758 } else if (strlen(argv[i]) == 11 && 1759 !strcmp(argv[i], "-minclasses")) { 1760 if (++i > argc - 2) 1761 return -1; 1762 else { 1763 policy->pw_min_classes = atoi(argv[i]); 1764 *mask |= KADM5_PW_MIN_CLASSES; 1765 continue; 1766 } 1767 } else if (strlen(argv[i]) == 8 && 1768 !strcmp(argv[i], "-history")) { 1769 if (++i > argc - 2) 1770 return -1; 1771 else { 1772 policy->pw_history_num = atoi(argv[i]); 1773 *mask |= KADM5_PW_HISTORY_NUM; 1774 continue; 1775 } 1776 } else 1777 return -1; 1778 } 1779 if (i != argc -1) { 1780 fprintf(stderr, gettext("%s: parser lost count!\n"), caller); 1781 return -1; 1782 } else 1783 return 0; 1784 } 1785 1786 static void 1787 kadmin_addmodpol_usage(func) 1788 char *func; 1789 { 1790 fprintf(stderr, "%s: %s %s\n", gettext("usage"), func, 1791 gettext("[options] policy")); 1792 fprintf(stderr, gettext("\toptions are:\n")); 1793 fprintf(stderr, "\t\t[-maxlife time] [-minlife time] " 1794 "[-minlength length]\n\t\t[-minclasses number] " 1795 "[-history number]\n"); 1796 } 1797 1798 void kadmin_addpol(argc, argv) 1799 int argc; 1800 char *argv[]; 1801 { 1802 krb5_error_code retval; 1803 long mask; 1804 kadm5_policy_ent_rec policy; 1805 1806 memset(&policy, 0, sizeof(policy)); 1807 if (kadmin_parse_policy_args(argc, argv, &policy, &mask, "add_policy")) { 1808 kadmin_addmodpol_usage("add_policy"); 1809 return; 1810 } else { 1811 policy.policy = argv[argc - 1]; 1812 mask |= KADM5_POLICY; 1813 retval = kadm5_create_policy(handle, &policy, mask); 1814 if (retval) { 1815 com_err("add_policy", retval, 1816 gettext("while creating policy \"%s\"."), 1817 policy.policy); 1818 return; 1819 } 1820 } 1821 return; 1822 } 1823 1824 void kadmin_modpol(argc, argv) 1825 int argc; 1826 char *argv[]; 1827 { 1828 krb5_error_code retval; 1829 long mask; 1830 kadm5_policy_ent_rec policy; 1831 1832 memset(&policy, 0, sizeof(policy)); 1833 if (kadmin_parse_policy_args(argc, argv, &policy, &mask, 1834 "modify_policy")) { 1835 kadmin_addmodpol_usage("modify_policy"); 1836 return; 1837 } else { 1838 policy.policy = argv[argc - 1]; 1839 retval = kadm5_modify_policy(handle, &policy, mask); 1840 if (retval) { 1841 com_err("modify_policy", retval, gettext("while modifying policy \"%s\"."), 1842 policy.policy); 1843 return; 1844 } 1845 } 1846 return; 1847 } 1848 1849 void kadmin_delpol(argc, argv) 1850 int argc; 1851 char *argv[]; 1852 { 1853 krb5_error_code retval; 1854 char reply[32]; 1855 1856 if (! (argc == 2 || 1857 (argc == 3 && !strcmp("-force", argv[1])))) { 1858 fprintf(stderr, "%s: delete_policy [-force] %s\n", 1859 gettext("usage"), gettext("policy")); 1860 return; 1861 } 1862 if (argc == 2) { 1863 printf(gettext("Are you sure you want to delete the policy " 1864 "\"%s\"? (yes/no): "), argv[1]); 1865 fgets(reply, sizeof (reply), stdin); 1866 if (strncmp(gettext("yes\n"), reply, sizeof (reply)) && 1867 strncmp(gettext("y\n"), reply, sizeof (reply)) && 1868 strncmp(gettext("Y\n"), reply, sizeof (reply)) 1869 ) { 1870 fprintf(stderr, 1871 gettext("Policy \"%s\" not deleted.\n"), 1872 argv[1]); 1873 return; 1874 } 1875 } 1876 retval = kadm5_delete_policy(handle, argv[argc - 1]); 1877 if (retval) { 1878 com_err("delete_policy:", retval, 1879 gettext("while deleting policy \"%s\""), 1880 argv[argc - 1]); 1881 return; 1882 } 1883 return; 1884 } 1885 1886 void kadmin_getpol(argc, argv) 1887 int argc; 1888 char *argv[]; 1889 { 1890 krb5_error_code retval; 1891 kadm5_policy_ent_rec policy; 1892 1893 if (! (argc == 2 || 1894 (argc == 3 && !strcmp("-terse", argv[1])))) { 1895 fprintf(stderr, "%s: get_policy [-terse] %s\n", 1896 gettext("usage"), gettext("policy")); 1897 return; 1898 } 1899 retval = kadm5_get_policy(handle, argv[argc - 1], &policy); 1900 if (retval) { 1901 com_err("get_policy", retval, 1902 gettext("while retrieving policy \"%s\"."), 1903 argv[argc - 1]); 1904 return; 1905 } 1906 if (argc == 2) { 1907 printf(gettext("Policy: %s\n"), policy.policy); 1908 printf(gettext("Maximum password life: %ld\n"), 1909 policy.pw_max_life); 1910 printf(gettext("Minimum password life: %ld\n"), 1911 policy.pw_min_life); 1912 printf(gettext("Minimum password length: %ld\n"), 1913 policy.pw_min_length); 1914 printf(gettext("Minimum number of password " 1915 "character classes: %ld\n"), 1916 policy.pw_min_classes); 1917 printf(gettext("Number of old keys kept: %ld\n"), 1918 policy.pw_history_num); 1919 printf(gettext("Reference count: %ld\n"), policy.policy_refcnt); 1920 } else { 1921 printf("\"%s\"\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\n", 1922 policy.policy, policy.pw_max_life, policy.pw_min_life, 1923 policy.pw_min_length, policy.pw_min_classes, 1924 policy.pw_history_num, policy.policy_refcnt); 1925 } 1926 kadm5_free_policy_ent(handle, &policy); 1927 return; 1928 } 1929 1930 void kadmin_getpols(argc, argv) 1931 int argc; 1932 char *argv[]; 1933 { 1934 krb5_error_code retval; 1935 char *expr, **names; 1936 int i, count; 1937 1938 /* Solaris Kerberos: 1939 * Use a pager for listing policies (similar to listing princs) 1940 */ 1941 FILE *output = NULL; 1942 int fd; 1943 struct sigaction nsig, osig; 1944 sigset_t nmask, omask; 1945 int waitb; 1946 1947 expr = NULL; 1948 if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) { 1949 fprintf(stderr, "%s: get_policies %s\n", 1950 gettext("usage"), gettext("[expression]\n")); 1951 return; 1952 } 1953 retval = kadm5_get_policies(handle, expr, &names, &count); 1954 if (retval) { 1955 com_err("get_policies", retval, 1956 gettext("while retrieving list.")); 1957 return; 1958 } 1959 1960 if (sigemptyset(&nmask) == -1) { 1961 perror("sigemptyset"); 1962 kadm5_free_name_list(handle, names, count); 1963 return; 1964 } 1965 1966 if (sigaddset(&nmask, SIGINT) == -1) { 1967 perror("sigaddset"); 1968 kadm5_free_name_list(handle, names, count); 1969 return; 1970 } 1971 1972 if (sigemptyset(&nsig.sa_mask) == -1) { 1973 perror("sigemptyset"); 1974 kadm5_free_name_list(handle, names, count); 1975 return; 1976 } 1977 1978 if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1) { 1979 perror("sigprocmask"); 1980 kadm5_free_name_list(handle, names, count); 1981 return; 1982 } 1983 1984 nsig.sa_handler = SIG_IGN; 1985 nsig.sa_flags = 0; 1986 if (sigaction(SIGINT, &nsig, &osig) == -1) { 1987 perror("sigaction"); 1988 if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) { 1989 perror("sigprocmask"); 1990 } 1991 kadm5_free_name_list(handle, names, count); 1992 return; 1993 } 1994 1995 fd = ss_pager_create(); 1996 if (fd == -1) { 1997 fprintf(stderr, "%s: failed to create pager\n", whoami); 1998 if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) { 1999 perror("sigprocmask"); 2000 } 2001 2002 if (sigaction(SIGINT, &osig, (struct sigaction *)0) == -1) { 2003 perror("sigaction"); 2004 } 2005 2006 kadm5_free_name_list(handle, names, count); 2007 return; 2008 } 2009 2010 output = fdopen(fd, "w"); 2011 if (output == NULL) { 2012 perror("fdopen"); 2013 } 2014 2015 if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) { 2016 perror("sigprocmask"); 2017 } 2018 2019 if (output != NULL) { 2020 for (i = 0; i < count; i++) 2021 fprintf(output, "%s\n", names[i]); 2022 } 2023 2024 if (output != NULL && fclose(output) != 0) { 2025 perror("fclose"); 2026 } 2027 2028 if (wait(&waitb) == -1) { 2029 perror("wait"); 2030 } 2031 2032 if (sigaction(SIGINT, &osig, (struct sigaction *)0) == -1) { 2033 perror("sigaction"); 2034 } 2035 kadm5_free_name_list(handle, names, count); 2036 } 2037