1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 40 #include <assert.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <pwd.h> 45 #include <shadow.h> 46 #include <crypt.h> 47 #include <sys/types.h> 48 #include <unistd.h> 49 #include <rpc/rpc.h> 50 #include <rpc/key_prot.h> 51 #include <rpcsvc/nis.h> 52 #include <rpcsvc/nis_dhext.h> 53 #include <rpcsvc/ypclnt.h> 54 #include <nsswitch.h> 55 56 #define PK_FILES 1 57 #define PK_YP 2 58 #define PK_LDAP 4 59 60 #define CURMECH mechs[mcount] 61 #define DESCREDPASSLEN sizeof (des_block) 62 63 static char CRED_TABLE[] = "cred.org_dir"; 64 static char PKMAP[] = "publickey.byname"; 65 static char PKFILE[] = "/etc/publickey"; 66 #define MAXHOSTNAMELEN 256 67 68 #define ROOTKEY_FILE "/etc/.rootkey" 69 #define ROOTKEY_FILE_BACKUP "/etc/.rootkey.bak" 70 #define MAXROOTKEY_LINE_LEN 4224 /* Good upto 16384-bit keys */ 71 #define MAXROOTKEY_LEN 4096 72 73 /* Should last up to 16384-bit keys */ 74 #define MAXPKENTLEN 8500 75 76 bool_t makenew = TRUE; /* Make new keys or reencrypt existing */ 77 bool_t specmech = FALSE; /* Specific mechs requested */ 78 bool_t force = FALSE; 79 int dest_service = 0; /* To which nameservice do we store key(s) */ 80 81 char *program_name; 82 83 mechanism_t **mechs = NULL; /* List of DH mechanisms */ 84 char **plist = NULL; /* List of public key(s) */ 85 char **slist = NULL; /* List of secret key(s) */ 86 char **clist = NULL; /* List of encrypted secret key(s) */ 87 int numspecmech = 0; /* Number of mechanisms specified */ 88 89 struct passwd *pw = NULL; /* passwd entry of user */ 90 struct spwd *spw = NULL; /* shadow entry of user */ 91 92 char *netname = NULL; /* RPC netname of user */ 93 char local_domain[MAXNETNAMELEN + 1]; 94 char *sec_domain = NULL; 95 96 char **rpc_pws = NULL; /* List of S-RPC passwords */ 97 int rpc_pw_count = 0; /* Number of passwords entered by user */ 98 char *login_pw = NULL; /* Unencrypted login password */ 99 char short_login_pw[DESCREDPASSLEN + 1]; 100 /* Short S-RPC password, which has first 8 chars of login_pw */ 101 102 static int add_cred_obj(nis_object *, char *); 103 static void cmp_passwd(); 104 static void encryptkeys(); 105 static void error_msg(); 106 static char *fgets_ignorenul(); 107 static void getpublics(); 108 static void getrpcpws(); 109 static void getsecrets(); 110 static void initkeylist(bool_t); 111 static void keylogin(keylen_t, algtype_t); 112 static void keylogin_des(); 113 static void makenewkeys(); 114 static int modify_cred_obj(nis_object *, char *); 115 static void storekeys(); 116 static void usage(); 117 static void write_rootkey(); 118 119 extern nis_object *init_entry(); 120 extern int get_pk_source(char *); 121 extern int localupdate(char *, char *, uint_t, char *); 122 extern int xencrypt(); 123 extern int xencrypt_g(); 124 extern int __gen_dhkeys(); 125 extern int key_setnet(); 126 extern int key_setnet_g(); 127 extern int key_secretkey_is_set_g(); 128 extern int __getnetnamebyuid(); 129 extern int getdomainname(); 130 extern int ldap_update(char *, char *, char *, char *, char *); 131 132 133 static void 134 error_msg() 135 { 136 if (sec_domain && *sec_domain && 137 strcasecmp(sec_domain, local_domain)) { 138 fprintf(stderr, 139 "The system default domain '%s' is different from the Secure RPC\n\ 140 domain %s where the key is stored. \n", local_domain, sec_domain); 141 exit(1); 142 } 143 } 144 145 146 static void 147 usage() 148 { 149 fprintf(stderr, "usage: %s [-p] [-s ldap | nis | files] \n", 150 program_name); 151 exit(1); 152 } 153 154 155 /* Encrypt secret key(s) with login_pw */ 156 static void 157 encryptkeys() 158 { 159 int mcount, ccount = 0; 160 161 if (mechs) { 162 for (mcount = 0; CURMECH; mcount++) { 163 char *crypt = NULL; 164 165 if (!xencrypt_g(slist[mcount], CURMECH->keylen, 166 CURMECH->algtype, short_login_pw, netname, 167 &crypt, TRUE)) { 168 /* Could not crypt key */ 169 crypt = NULL; 170 } else 171 ccount++; 172 clist[mcount] = crypt; 173 } 174 } else { 175 char *crypt = NULL; 176 177 if (!(crypt = 178 (char *)malloc(HEXKEYBYTES + KEYCHECKSUMSIZE + 1))) { 179 fprintf(stderr, "%s: Malloc failure.\n", program_name); 180 exit(1); 181 } 182 183 (void) memcpy(crypt, slist[0], HEXKEYBYTES); 184 (void) memcpy(crypt + HEXKEYBYTES, slist[0], KEYCHECKSUMSIZE); 185 crypt[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0; 186 xencrypt(crypt, short_login_pw); 187 188 clist[0] = crypt; 189 ccount++; 190 } 191 192 if (!ccount) { 193 fprintf(stderr, "%s: Could not encrypt any secret keys.\n", 194 program_name); 195 exit(1); 196 } 197 } 198 199 200 /* Initialize the array of public, secret, and encrypted secret keys */ 201 static void 202 initkeylist(bool_t nomech) 203 { 204 int mcount; 205 206 if (!nomech) { 207 assert(mechs && mechs[0]); 208 for (mcount = 0; CURMECH; mcount++) 209 ; 210 } else 211 mcount = 1; 212 213 if (!(plist = (char **)malloc(sizeof (char *) * mcount))) { 214 fprintf(stderr, "%s: Malloc failure.\n", program_name); 215 exit(1); 216 } 217 if (!(slist = (char **)malloc(sizeof (char *) * mcount))) { 218 fprintf(stderr, "%s: Malloc failure.\n", program_name); 219 exit(1); 220 } 221 if (!(clist = (char **)malloc(sizeof (char *) * mcount))) { 222 fprintf(stderr, "%s: Malloc failure.\n", program_name); 223 exit(1); 224 } 225 } 226 227 228 /* Retrieve public key(s) */ 229 static void 230 getpublics() 231 { 232 int mcount; 233 int pcount = 0; 234 235 if (mechs) { 236 for (mcount = 0; CURMECH; mcount++) { 237 char *public; 238 size_t hexkeylen; 239 240 hexkeylen = ((CURMECH->keylen / 8) * 2) + 1; 241 if (!(public = (char *)malloc(hexkeylen))) { 242 fprintf(stderr, "%s: Malloc failure.\n", 243 program_name); 244 exit(1); 245 } 246 if (!getpublickey_g(netname, CURMECH->keylen, 247 CURMECH->algtype, public, 248 hexkeylen)) { 249 /* Could not get public key */ 250 fprintf(stderr, 251 "Could not get %s public key.\n", 252 VALID_ALIAS(CURMECH->alias) ? 253 CURMECH->alias : ""); 254 free(public); 255 public = NULL; 256 } else 257 pcount++; 258 259 plist[mcount] = public; 260 } 261 } else { 262 char *public; 263 264 if (!(public = (char *)malloc(HEXKEYBYTES + 1))) { 265 fprintf(stderr, "%s: Malloc failure.\n", program_name); 266 exit(1); 267 } 268 if (!getpublickey(netname, public)) { 269 free(public); 270 public = NULL; 271 } else 272 pcount++; 273 274 plist[0] = public; 275 } 276 277 if (!pcount) { 278 fprintf(stderr, "%s: cannot get any public keys for %s.\n", 279 program_name, pw->pw_name); 280 error_msg(); 281 fprintf(stderr, 282 "Make sure that the public keys are stored in the domain %s.\n", 283 local_domain); 284 exit(1); 285 } 286 } 287 288 289 /* Generate a new set of public/secret key pair(s) */ 290 static void 291 makenewkeys() 292 { 293 int mcount; 294 295 if (mechs) { 296 for (mcount = 0; CURMECH; mcount++) { 297 char *public, *secret; 298 size_t hexkeylen; 299 300 if (slist[mcount]) 301 free(slist[mcount]); 302 303 hexkeylen = ((CURMECH->keylen / 8) * 2) + 1; 304 305 if (!(public = malloc(hexkeylen))) { 306 fprintf(stderr, "%s: Malloc failure.\n", 307 program_name); 308 exit(1); 309 } 310 if (!(secret = malloc(hexkeylen))) { 311 fprintf(stderr, "%s: Malloc failure.\n", 312 program_name); 313 exit(1); 314 } 315 316 if (!(__gen_dhkeys_g(public, secret, CURMECH->keylen, 317 CURMECH->algtype, short_login_pw))) { 318 /* Could not generate key pair */ 319 fprintf(stderr, 320 "WARNING Could not generate key pair %s\n", 321 VALID_ALIAS(CURMECH->alias) ? 322 CURMECH->alias : ""); 323 free(public); 324 free(secret); 325 public = NULL; 326 secret = NULL; 327 } 328 329 plist[mcount] = public; 330 slist[mcount] = secret; 331 } 332 } else { 333 char *public, *secret; 334 if (slist[0]) 335 free(slist[0]); 336 337 if (!(public = malloc(HEXKEYBYTES + 1))) { 338 fprintf(stderr, "%s: Malloc failure.\n", program_name); 339 exit(1); 340 } 341 if (!(secret = malloc(HEXKEYBYTES + 1))) { 342 fprintf(stderr, "%s: Malloc failure.\n", program_name); 343 exit(1); 344 } 345 346 __gen_dhkeys(public, secret, short_login_pw); 347 348 plist[0] = public; 349 slist[0] = secret; 350 } 351 } 352 353 354 /* 355 * Make sure that the entered Secure-RPC password(s) match the login 356 * password 357 */ 358 static void 359 cmp_passwd() 360 { 361 char baseprompt[] = "Please enter the login password for"; 362 char prompt[BUFSIZ]; 363 char *en_login_pw = spw->sp_pwdp; 364 char short_en_login_pw[DESCREDPASSLEN + 1]; 365 char *try_en_login_pw; 366 bool_t pwmatch = FALSE; 367 int done = 0, tries = 0, pcount; 368 369 snprintf(prompt, BUFSIZ, "%s %s:", baseprompt, pw->pw_name); 370 371 (void) strlcpy(short_en_login_pw, en_login_pw, 372 sizeof (short_en_login_pw)); 373 374 if (en_login_pw && (strlen(en_login_pw) != 0)) { 375 for (pcount = 0; pcount < rpc_pw_count; pcount++) { 376 char *try_en_rpc_pw; 377 378 try_en_rpc_pw = crypt(rpc_pws[pcount], short_en_login_pw); 379 if (strcmp(try_en_rpc_pw, short_en_login_pw) == 0) { 380 login_pw = rpc_pws[pcount]; 381 (void) strlcpy(short_login_pw, login_pw, 382 sizeof (short_login_pw)); 383 pwmatch = TRUE; 384 break; 385 } 386 } 387 if (!pwmatch) { 388 /* pw don't match */ 389 while (!done) { 390 /* ask for the pw */ 391 login_pw = getpassphrase(prompt); 392 (void) strlcpy(short_login_pw, login_pw, 393 sizeof (short_login_pw)); 394 if (login_pw && strlen(login_pw)) { 395 /* pw was not empty */ 396 try_en_login_pw = crypt(login_pw, 397 en_login_pw); 398 /* compare the pw's */ 399 if (!(strcmp(try_en_login_pw, 400 en_login_pw))) { 401 /* pw was correct */ 402 return; 403 } else { 404 /* pw was wrong */ 405 if (tries++) { 406 /* Sorry */ 407 fprintf(stderr, 408 "Sorry.\n"); 409 exit(1); 410 } else { 411 /* Try again */ 412 snprintf(prompt, 413 BUFSIZ, 414 "Try again. %s %s:", 415 baseprompt, 416 pw->pw_name); 417 } 418 } 419 } else { 420 /* pw was empty */ 421 if (tries++) { 422 /* Unchanged */ 423 fprintf(stderr, 424 "%s: key-pair(s) unchanged for %s.\n", 425 program_name, 426 pw->pw_name); 427 exit(1); 428 } else { 429 /* Need a password */ 430 snprintf(prompt, BUFSIZ, 431 "Need a password. %s %s:", 432 baseprompt, 433 pw->pw_name); 434 } 435 } 436 } 437 } 438 /* pw match */ 439 return; 440 } else { 441 /* no pw found */ 442 fprintf(stderr, 443 "%s: no passwd found for %s in the shadow passwd entry.\n", 444 program_name, pw->pw_name); 445 exit(1); 446 } 447 } 448 449 450 /* Prompt the user for a Secure-RPC password and store it in a cache. */ 451 static void 452 getrpcpws(char *flavor) 453 { 454 char *cur_pw = NULL; 455 char prompt[BUFSIZ + 1]; 456 457 if (flavor) 458 snprintf(prompt, BUFSIZ, 459 "Please enter the %s Secure-RPC password for %s:", 460 flavor, pw->pw_name); 461 else 462 snprintf(prompt, BUFSIZ, 463 "Please enter the Secure-RPC password for %s:", 464 pw->pw_name); 465 466 cur_pw = getpass(prompt); 467 if (!cur_pw) { 468 /* No changes */ 469 fprintf(stderr, "%s: key-pair(s) unchanged for %s.\n", 470 program_name, pw->pw_name); 471 exit(1); 472 } 473 474 rpc_pw_count++; 475 if (!(rpc_pws = 476 (char **)realloc(rpc_pws, sizeof (char *) * rpc_pw_count))) { 477 fprintf(stderr, "%s: Realloc failure.\n", program_name); 478 exit(1); 479 } 480 rpc_pws[rpc_pw_count - 1] = cur_pw; 481 } 482 483 484 /* Retrieve the secret key(s) for the user and attempt to decrypt them */ 485 static void 486 getsecrets() 487 { 488 int mcount, scount = 0; 489 int tries = 0; 490 491 getrpcpws(NULL); 492 493 if (mechs) { 494 for (mcount = 0; CURMECH; mcount++) { 495 char *secret; 496 int pcount; 497 size_t hexkeylen; 498 499 hexkeylen = ((CURMECH->keylen / 8) * 2) + 1; 500 if (!(secret = (char *)calloc(hexkeylen, 501 sizeof (char)))) { 502 fprintf(stderr, "%s: Malloc failure.\n", 503 program_name); 504 exit(1); 505 } 506 507 for (pcount = 0; pcount < rpc_pw_count; pcount++) { 508 if (!getsecretkey_g(netname, CURMECH->keylen, 509 CURMECH->algtype, secret, 510 hexkeylen, 511 rpc_pws[pcount])) 512 continue; 513 514 if (secret[0] == 0) 515 continue; 516 else 517 break; 518 } 519 520 tries = 0; 521 getsecrets_tryagain_g: 522 if (secret[0] == 0) { 523 if (!tries) { 524 /* 525 * No existing pw can decrypt 526 * secret key 527 */ 528 getrpcpws(CURMECH->alias); 529 if (!getsecretkey_g(netname, 530 CURMECH->keylen, 531 CURMECH->algtype, 532 secret, 533 hexkeylen, 534 rpc_pws[pcount])) { 535 /* 536 * Could not retreive 537 * secret key, abort 538 */ 539 free(secret); 540 secret = NULL; 541 goto getsecrets_abort; 542 } 543 544 if (secret[0] == 0) { 545 /* Still no go, ask again */ 546 free(rpc_pws[pcount]); 547 rpc_pw_count--; 548 tries++; 549 printf("Try again. "); 550 fflush(stdout); 551 goto getsecrets_tryagain_g; 552 } else 553 scount++; 554 } else { 555 fprintf(stderr, 556 "%s: key-pair unchanged for %s.\n", 557 program_name, pw->pw_name); 558 exit(1); 559 } 560 } else 561 scount++; 562 563 getsecrets_abort: 564 slist[mcount] = secret; 565 } 566 } else { 567 char *secret = NULL; 568 569 if (!(secret = (char *)malloc(HEXKEYBYTES + 1))) { 570 fprintf(stderr, "%s: Malloc failure.\n", program_name); 571 exit(1); 572 } 573 getsecrets_tryagain: 574 if (!getsecretkey(netname, secret, rpc_pws[0])) { 575 fprintf(stderr, 576 "%s: could not get secret key for '%s'\n", 577 program_name, netname); 578 exit(1); 579 } 580 581 if (secret[0] == 0) { 582 if (!tries) { 583 free(rpc_pws[0]); 584 rpc_pw_count = 0; 585 tries++; 586 printf("Try again. "); 587 fflush(stdout); 588 getrpcpws(NULL); 589 goto getsecrets_tryagain; 590 } else { 591 fprintf(stderr, 592 "%s: key-pair unchanged for %s.\n", 593 program_name, pw->pw_name); 594 exit(1); 595 } 596 } 597 598 slist[0] = secret; 599 return; 600 } 601 602 if (!scount) { 603 (void) fprintf(stderr, 604 "%s: could not get nor decrypt any secret keys for '%s'\n", 605 program_name, netname); 606 error_msg(); 607 exit(1); 608 } 609 } 610 611 612 /* Register AUTH_DES secret key with keyserv */ 613 static void 614 keylogin_des() 615 { 616 char *secret = slist[0]; 617 struct key_netstarg netst; 618 619 /* 620 * try to revoke the existing key/credentials, assuming 621 * one exists. this will effectively mark "stale" any 622 * cached credientials... 623 */ 624 if (key_setsecret(secret) < 0) { 625 return; 626 } 627 628 #ifdef NFS_AUTH 629 /* 630 * it looks like a credential already existed, so try and 631 * revoke any lingering Secure-NFS privledges. 632 */ 633 634 nra.authtype = AUTH_DES; 635 nra.uid = getuid(); 636 637 if (_nfssys(NFS_REVAUTH, &nra) < 0) 638 perror("Warning: NFS credentials not destroyed"); 639 #endif /* NFS_AUTH */ 640 641 (void) memcpy(netst.st_priv_key, secret, HEXKEYBYTES); 642 643 netst.st_pub_key[0] = '\0'; 644 netst.st_netname = strdup(netname); 645 646 /* do actual key login */ 647 if (key_setnet(&netst) < 0) { 648 fprintf(stderr, "Could not set %s's secret key\n", netname); 649 fprintf(stderr, "May be the keyserv is down?\n"); 650 } 651 } 652 653 654 /* Register a secret key with the keyserv */ 655 static void 656 keylogin(keylen_t keylen, algtype_t algtype) 657 { 658 int mcount; 659 660 if (mechs) { 661 for (mcount = 0; CURMECH; mcount++) { 662 if (keylen == CURMECH->keylen && 663 algtype == CURMECH->algtype) { 664 if (key_setnet_g(netname, slist[mcount], 665 CURMECH->keylen, 666 NULL, 0, 667 CURMECH->algtype) 668 < 0) 669 fprintf(stderr, 670 "Could not set %s's %s secret key\n", 671 netname, 672 VALID_ALIAS(CURMECH->alias) ? 673 CURMECH->alias : ""); 674 } 675 } 676 } else { 677 if (keylen == 192 && algtype == 0) 678 keylogin_des(); 679 } 680 } 681 682 683 /* 684 * fgets is "broken" in that if it reads a NUL character it will 685 * always return EOF for all reads, even when there is data left in 686 * the file. This replacement can deal with NUL's in a calm, rational 687 * manner. 688 */ 689 static char * 690 fgets_ignorenul(char *s, int n, FILE *stream) 691 { 692 int fildes = fileno(stream); 693 int i = 0; 694 int rs = 0; 695 char c; 696 697 if (fildes < 0) 698 return (NULL); 699 700 while (i < n - 1) { 701 rs = read(fildes, &c, 1); 702 switch (rs) { 703 case 1: 704 break; 705 case 0: 706 /* EOF */ 707 if (i > 0) 708 s[i] = '\0'; 709 return (NULL); 710 break; 711 default: 712 return (NULL); 713 } 714 switch (c) { 715 case '\0': 716 break; 717 case '\n': 718 s[i] = c; 719 s[++i] = '\0'; 720 return (s); 721 default: 722 if (c != '\0') 723 s[i++] = c; 724 } 725 } 726 s[i] = '\0'; 727 return (s); 728 } 729 730 731 /* Write unencrypted secret key into root key file */ 732 static void 733 write_rootkey(char *secret, char *flavor, keylen_t keylen, algtype_t algtype) 734 { 735 char line[MAXROOTKEY_LINE_LEN]; 736 char keyent[MAXROOTKEY_LEN]; 737 algtype_t atent; 738 int rootfd, bakfd, hexkeybytes; 739 bool_t lineone = TRUE; 740 bool_t gotit = FALSE; 741 FILE *rootfile, *bakfile; 742 743 unlink(ROOTKEY_FILE_BACKUP); 744 if ((rename(ROOTKEY_FILE, ROOTKEY_FILE_BACKUP)) < 0) { 745 if ((bakfd = creat(ROOTKEY_FILE_BACKUP, 0600)) < 0) { 746 perror("Could not create /etc/.rootkey.bak"); 747 goto rootkey_err; 748 } 749 close(bakfd); 750 } 751 752 if ((rootfd = open(ROOTKEY_FILE, O_WRONLY+O_CREAT, 0600)) < 0) { 753 perror("Could not open /etc/.rootkey for writing"); 754 fprintf(stderr, 755 "Attempting to restore original /etc/.rootkey\n"); 756 rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE); 757 goto rootkey_err; 758 } 759 if (!(rootfile = fdopen(rootfd, "w"))) { 760 perror("Could not open /etc/.rootkey for writing"); 761 fprintf(stderr, 762 "Attempting to restore original /etc/.rootkey\n"); 763 close(rootfd); 764 unlink(ROOTKEY_FILE); 765 rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE); 766 goto rootkey_err; 767 } 768 if (!(bakfile = fopen(ROOTKEY_FILE_BACKUP, "r"))) { 769 perror("Could not open /etc/.rootkey.bak for reading"); 770 fprintf(stderr, 771 "Attempting to restore original /etc/.rootkey\n"); 772 fclose(rootfile); 773 unlink(ROOTKEY_FILE); 774 rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE); 775 goto rootkey_err; 776 } 777 778 hexkeybytes = ((keylen + 7) / 8) * 2; 779 780 while (fgets_ignorenul(line, MAXROOTKEY_LINE_LEN, bakfile)) { 781 if (sscanf(line, "%s %d", keyent, &atent) < 2) { 782 /* 783 * No encryption algorithm found in the file 784 * (atent) so default to DES. 785 */ 786 atent = AUTH_DES_ALGTYPE; 787 } 788 /* 789 * 192-bit keys always go on the first line 790 */ 791 if (lineone) { 792 lineone = FALSE; 793 if (keylen == 192) { 794 gotit = TRUE; 795 fprintf(rootfile, "%s\n", secret); 796 } else 797 fprintf(rootfile, "%s", line); 798 fflush(rootfile); 799 } else { 800 if ((strlen(keyent) == hexkeybytes) && 801 (atent == algtype)) { 802 /* 803 * Silently remove lines with the same 804 * keylen/algtype 805 */ 806 if (gotit) 807 continue; 808 else 809 gotit = TRUE; 810 811 fprintf(rootfile, "%s %d\n", secret, algtype); 812 } else 813 fprintf(rootfile, "%s", line); 814 fflush(rootfile); 815 } 816 } 817 818 /* Append key to rootkey file */ 819 if (!gotit) { 820 if (keylen == 192) 821 fprintf(rootfile, "%s\n", secret); 822 else { 823 if (lineone) 824 fprintf(rootfile, "\n"); 825 fprintf(rootfile, "%s %d\n", secret, algtype); 826 } 827 } 828 fflush(rootfile); 829 fclose(rootfile); 830 fclose(bakfile); 831 unlink(ROOTKEY_FILE_BACKUP); 832 return; 833 834 rootkey_err: 835 fprintf(stderr, "WARNING: Could not write %s key to /etc/.rootkey\n", 836 flavor); 837 } 838 839 /* Store new key information in the specified name service */ 840 static void 841 storekeys() 842 { 843 int mcount, ucount = 0; 844 char *ypmaster, *ypdomain = NULL, pkent[MAXPKENTLEN]; 845 nis_name nis_princ; 846 847 848 /* Setup */ 849 switch (dest_service) { 850 case PK_LDAP: 851 break; 852 case PK_YP: 853 yp_get_default_domain(&ypdomain); 854 if (yp_master(ypdomain, PKMAP, &ypmaster) != 0) { 855 fprintf(stderr, 856 "%s: cannot find master of NIS publickey database\n", 857 program_name); 858 exit(1); 859 } 860 fprintf(stdout, 861 "Sending key change request to %s ...\n", ypmaster); 862 break; 863 case PK_FILES: 864 if (geteuid() != 0) { 865 fprintf(stderr, 866 "%s: non-root users cannot change their key-pair in %s\n", 867 program_name, PKFILE); 868 exit(1); 869 } 870 break; 871 default: 872 fprintf(stderr, 873 "could not update; database %d unknown\n", 874 dest_service); 875 exit(1); 876 } 877 878 if (mechs) { 879 for (mcount = 0; CURMECH; mcount++) { 880 char authtype[MECH_MAXATNAME]; 881 882 if (!plist[mcount] && !clist[mcount]) 883 continue; 884 885 __nis_mechalias2authtype(CURMECH->alias, authtype, 886 MECH_MAXATNAME); 887 if (!authtype) { 888 fprintf(stderr, 889 "Could not generate auth_type for %s.\n", 890 CURMECH->alias); 891 continue; 892 } 893 894 snprintf(pkent, MAXPKENTLEN, "%s:%s:%d", 895 plist[mcount], clist[mcount], 896 CURMECH->algtype); 897 898 switch (dest_service) { 899 case PK_LDAP: 900 if (ldap_update(CURMECH->alias, netname, 901 plist[mcount], clist[mcount], 902 login_pw)) 903 fprintf(stderr, 904 "%s: unable to update %s key in LDAP database\n", 905 program_name, authtype); 906 else 907 ucount++; 908 break; 909 910 case PK_YP: 911 /* Should never get here. */ 912 break; 913 914 case PK_FILES: 915 /* Should never get here. */ 916 break; 917 } 918 } 919 } else { 920 int status = 0; 921 922 assert(plist[0] && clist[0]); 923 snprintf(pkent, MAXPKENTLEN, "%s:%s", plist[0], clist[0]); 924 925 switch (dest_service) { 926 case PK_LDAP: 927 if (ldap_update("dh192-0", netname, 928 plist[0], clist[0], 929 login_pw)) { 930 fprintf(stderr, 931 "%s: unable to update %s key in LDAP database\n", 932 program_name); 933 exit(1); 934 } 935 break; 936 937 case PK_YP: 938 if (status = yp_update(ypdomain, PKMAP, 939 YPOP_STORE, netname, 940 strlen(netname), pkent, 941 strlen(pkent))) { 942 fprintf(stderr, 943 "%s: unable to update NIS database (%u): %s\n", 944 program_name, status, 945 yperr_string(status)); 946 exit(1); 947 } 948 break; 949 950 case PK_FILES: 951 if (localupdate(netname, PKFILE, YPOP_STORE, pkent)) { 952 fprintf(stderr, 953 "%s: hence, unable to update publickey database\n", 954 program_name); 955 exit(1); 956 } 957 break; 958 959 default: 960 /* Should never get here */ 961 assert(0); 962 } 963 return; 964 } 965 if (!ucount) { 966 fprintf(stderr, "%s: unable to update any key-pairs for %s.\n", 967 program_name, pw->pw_name); 968 exit(1); 969 } 970 } 971 972 void 973 addmechtolist(char *mechtype) 974 { 975 mechanism_t **realmechlist; 976 int i; 977 978 if (realmechlist = __nis_get_mechanisms(FALSE)) { 979 /* Match requested mech with list */ 980 for (i = 0; realmechlist[i]; i++) { 981 if (realmechlist[i]->alias) 982 if (strcmp(realmechlist[i]->alias, mechtype) 983 == 0) { 984 /* 985 * Match, add it to the mechs. 986 * Don't worry about qop or 987 * secserv since they are not 988 * used by chkey. 989 */ 990 numspecmech++; 991 if ((mechs = 992 (mechanism_t **)realloc(mechs, 993 sizeof (mechanism_t *) * 994 (numspecmech + 1))) == NULL) { 995 perror("Can not change keys"); 996 exit(1); 997 } 998 999 if ((mechs[numspecmech - 1] = 1000 (mechanism_t *)malloc( 1001 sizeof (mechanism_t))) == NULL) { 1002 perror("Can not change keys"); 1003 exit(1); 1004 } 1005 if (realmechlist[i]->mechname) 1006 mechs[numspecmech - 1]->mechname = 1007 strdup(realmechlist[i]->mechname); 1008 if (realmechlist[i]->alias) 1009 mechs[numspecmech - 1]->alias = 1010 strdup(realmechlist[i]->alias); 1011 mechs[numspecmech - 1]->keylen = 1012 realmechlist[i]->keylen; 1013 mechs[numspecmech - 1]->algtype = 1014 realmechlist[i]->algtype; 1015 mechs[numspecmech] = NULL; 1016 __nis_release_mechanisms(realmechlist); 1017 return; 1018 } 1019 } 1020 1021 fprintf(stderr, 1022 "WARNING: Mechanism '%s' not configured, skipping...\n", 1023 mechtype); 1024 __nis_release_mechanisms(realmechlist); 1025 return; 1026 } 1027 fprintf(stderr, 1028 "WARNING: Mechanism '%s' not configured, skipping...\n", 1029 mechtype); 1030 } 1031 1032 1033 int 1034 main(int argc, char **argv) 1035 { 1036 int c, mcount; 1037 uid_t uid; 1038 uid_t orig_euid; 1039 char *service = NULL; 1040 program_name = argv[0]; 1041 1042 mechs = __nis_get_mechanisms(FALSE); 1043 1044 while ((c = getopt(argc, argv, "fps:m:")) != -1) { 1045 switch (c) { 1046 case 'f': 1047 /* 1048 * Not documented as of on1093. 1049 * Temporarily supported 1050 */ 1051 force++; 1052 break; 1053 case 'p': 1054 makenew = FALSE; 1055 break; 1056 case 's': 1057 if (!service) 1058 service = strdup(optarg); 1059 else 1060 usage(); 1061 break; 1062 case 'm': 1063 if (mechs && specmech == FALSE) { 1064 __nis_release_mechanisms(mechs); 1065 mechs = NULL; 1066 } 1067 specmech = TRUE; 1068 addmechtolist(optarg); 1069 break; 1070 default: 1071 usage(); 1072 } 1073 } 1074 1075 if (optind < argc) 1076 usage(); 1077 1078 dest_service = get_pk_source(service); 1079 1080 if (!(netname = malloc(MAXNETNAMELEN + 1))) { 1081 fprintf(stderr, "%s: Malloc failure.\n", program_name); 1082 exit(1); 1083 } 1084 if (!__getnetnamebyuid(netname, uid = getuid())) { 1085 fprintf(stderr, "%s: cannot generate netname for uid %d\n", 1086 program_name, uid); 1087 exit(1); 1088 } 1089 sec_domain = strdup(strchr(netname, '@') + 1); 1090 getdomainname(local_domain, MAXNETNAMELEN); 1091 1092 if (makenew) 1093 fprintf(stdout, "Generating new key for '%s'.\n", netname); 1094 else 1095 fprintf(stdout, "Reencrypting key for '%s'.\n", netname); 1096 1097 if (mechs) { 1098 if (dest_service == PK_YP || dest_service == PK_FILES) { 1099 fprintf(stderr, 1100 "%s: can not add non-DES public keys to %s, skipping.\n", 1101 program_name, service); 1102 __nis_release_mechanisms(mechs); 1103 mechs = NULL; 1104 initkeylist(TRUE); 1105 } else 1106 initkeylist(FALSE); 1107 } else 1108 initkeylist(TRUE); 1109 1110 uid = getuid(); 1111 orig_euid = geteuid(); 1112 1113 /* Get password information */ 1114 if ((pw = getpwuid(uid)) == NULL) { 1115 fprintf(stderr, 1116 "%s: Can not find passwd information for %d.\n", 1117 program_name, uid); 1118 exit(1); 1119 } 1120 1121 /* Set eUID to user */ 1122 seteuid(uid); 1123 1124 /* Obtain a list of decrypted secret keys */ 1125 getsecrets(); 1126 1127 /* Keylogin user if not already done */ 1128 if (mechs) { 1129 int mcount; 1130 1131 for (mcount = 0; CURMECH; mcount++) { 1132 keylen_t keylen = CURMECH->keylen; 1133 algtype_t algtype = CURMECH->algtype; 1134 1135 if (!key_secretkey_is_set_g(keylen, algtype) && 1136 slist[mcount]) { 1137 keylogin(CURMECH->keylen, CURMECH->algtype); 1138 if ((uid == 0) && (makenew == FALSE)) 1139 write_rootkey(slist[mcount], 1140 VALID_ALIAS(CURMECH->alias) ? 1141 CURMECH->alias : 1142 "", 1143 keylen, algtype); 1144 } 1145 } 1146 } else { 1147 assert(slist[0]); 1148 if (!key_secretkey_is_set()) { 1149 keylogin_des(); 1150 if ((uid == 0) && (makenew == FALSE)) 1151 write_rootkey(slist[0], "des", 192, 0); 1152 } 1153 } 1154 1155 /* Set eUID back to root */ 1156 (void) seteuid(orig_euid); 1157 1158 /* 1159 * Call getspnam() after the keylogin has been done so we have 1160 * the best chance of having read access to the encrypted pw. 1161 * 1162 * The eUID must be 0 for the getspnam() so the name service 1163 * switch can handle the following eUID sensitive cases: 1164 * 1165 * files/compat: read /etc/shadow 1166 * 1167 */ 1168 if ((spw = getspnam(pw->pw_name)) == 0) { 1169 1170 /* Set eUID back to user */ 1171 (void) seteuid(uid); 1172 1173 (void) fprintf(stderr, 1174 "%s: cannot find shadow entry for %s.\n", 1175 program_name, pw->pw_name); 1176 exit(1); 1177 } 1178 1179 /* Set eUID back to user */ 1180 (void) seteuid(uid); 1181 1182 if (strcmp(spw->sp_pwdp, NOPWDRTR) == 0) { 1183 (void) fprintf(stderr, 1184 "%s: do not have read access to the passwd field for %s\n", 1185 program_name, pw->pw_name); 1186 exit(1); 1187 } 1188 1189 /* 1190 * force will be only supported for a while 1191 * -- it is NOT documented as of s1093 1192 */ 1193 if (force) { 1194 char *prompt = "Please enter New password:"; 1195 1196 login_pw = getpassphrase(prompt); 1197 (void) strlcpy(short_login_pw, login_pw, 1198 sizeof (short_login_pw)); 1199 if (!login_pw || !(strlen(login_pw))) { 1200 fprintf(stderr, "%s: key-pair(s) unchanged for %s.\n", 1201 program_name, pw->pw_name); 1202 exit(1); 1203 } 1204 } else { 1205 /* 1206 * Reconsile rpc_pws and login_pw. 1207 * 1208 * This function will either return with login_pw == rpc_pw 1209 * (and thus, the new pw to encrypt keys) or it will exit. 1210 */ 1211 cmp_passwd(); 1212 } 1213 1214 if (makenew) 1215 makenewkeys(); 1216 else 1217 getpublics(); 1218 1219 encryptkeys(); 1220 1221 storekeys(); 1222 1223 if (makenew) { 1224 if (uid == 0) { 1225 if (mechs) { 1226 for (mcount = 0; CURMECH; mcount++) { 1227 if (!slist[mcount]) 1228 continue; 1229 write_rootkey(slist[mcount], 1230 CURMECH->alias, 1231 CURMECH->keylen, 1232 CURMECH->algtype); 1233 } 1234 } else { 1235 assert(slist[0]); 1236 write_rootkey(slist[0], "des", 192, 0); 1237 } 1238 } 1239 if (mechs) { 1240 for (mcount = 0; CURMECH; mcount++) 1241 keylogin(CURMECH->keylen, 1242 CURMECH->algtype); 1243 } else 1244 keylogin_des(); 1245 } 1246 return (0); 1247 } 1248