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/nispasswd.h> 53 #include <rpcsvc/nis_dhext.h> 54 #include <rpcsvc/ypclnt.h> 55 #include <nsswitch.h> 56 57 #define PK_FILES 1 58 #define PK_YP 2 59 #define PK_NISPLUS 3 60 #define PK_LDAP 4 61 62 #define CURMECH mechs[mcount] 63 64 static char CRED_TABLE[] = "cred.org_dir"; 65 static char PKMAP[] = "publickey.byname"; 66 static char PKFILE[] = "/etc/publickey"; 67 #define MAXHOSTNAMELEN 256 68 69 #define ROOTKEY_FILE "/etc/.rootkey" 70 #define ROOTKEY_FILE_BACKUP "/etc/.rootkey.bak" 71 #define MAXROOTKEY_LINE_LEN 4224 /* Good upto 16384-bit keys */ 72 #define MAXROOTKEY_LEN 4096 73 74 /* Should last up to 16384-bit keys */ 75 #define MAXPKENTLEN 8500 76 77 bool_t makenew = TRUE; /* Make new keys or reencrypt existing */ 78 bool_t specmech = FALSE; /* Specific mechs requested */ 79 bool_t force = FALSE; 80 int dest_service = 0; /* To which nameservice do we store key(s) */ 81 82 char *program_name; 83 84 mechanism_t **mechs = NULL; /* List of DH mechanisms */ 85 char **plist = NULL; /* List of public key(s) */ 86 char **slist = NULL; /* List of secret key(s) */ 87 char **clist = NULL; /* List of encrypted secret key(s) */ 88 int numspecmech = 0; /* Number of mechanisms specified */ 89 90 struct passwd *pw = NULL; /* passwd entry of user */ 91 struct spwd *spw = NULL; /* shadow entry of user */ 92 93 char *netname = NULL; /* RPC netname of user */ 94 char local_domain[MAXNETNAMELEN + 1]; 95 char *sec_domain = NULL; 96 97 char **rpc_pws = NULL; /* List of S-RPC passwords */ 98 int rpc_pw_count = 0; /* Number of passwords entered by user */ 99 char *login_pw = NULL; /* Unencrypted login password */ 100 char short_login_pw[DESCREDPASSLEN + 1]; 101 /* Short S-RPC password, which has first 8 chars of login_pw */ 102 103 static int add_cred_obj(nis_object *, char *); 104 static nis_error auth_exists(char *, char *, char *, char *); 105 static void cmp_passwd(); 106 static nis_error cred_exists(const char *, const char *, const char *); 107 static void encryptkeys(); 108 static void error_msg(); 109 static char *fgets_ignorenul(); 110 static void getpublics(); 111 static void getrpcpws(); 112 static void getsecrets(); 113 static void initkeylist(bool_t); 114 static void keylogin(keylen_t, algtype_t); 115 static void keylogin_des(); 116 static void makenewkeys(); 117 static int modify_cred_obj(nis_object *, char *); 118 static int nisplus_update(nis_name, char *, char *, char *); 119 static int sanity_checks(char *, char *, char *); 120 static void storekeys(); 121 static void usage(); 122 static void write_rootkey(); 123 124 extern char *get_nisplus_principal(char *, uid_t); 125 extern nis_object *init_entry(); 126 extern int get_pk_source(char *); 127 extern int localupdate(char *, char *, uint_t, char *); 128 extern int xencrypt(); 129 extern int xencrypt_g(); 130 extern int __gen_dhkeys(); 131 extern int key_setnet(); 132 extern int key_setnet_g(); 133 extern int key_secretkey_is_set_g(); 134 extern int __getnetnamebyuid(); 135 extern int getdomainname(); 136 extern int ldap_update(char *, char *, char *, char *, char *); 137 138 139 static void 140 error_msg() 141 { 142 if (sec_domain && *sec_domain && 143 strcasecmp(sec_domain, local_domain)) { 144 fprintf(stderr, 145 "The system default domain '%s' is different from the Secure RPC\n\ 146 domain %s where the key is stored. The Secure RPC domainname is\n\ 147 defined by the directory object stored in the /var/nis/NIS_COLD_START file.\n\ 148 If you need to change this Secure RPC domainname, please use the nisinit(1M)\n\ 149 command with the `-k` option.\n", local_domain, sec_domain); 150 exit(1); 151 } 152 } 153 154 155 static void 156 usage() 157 { 158 fprintf(stderr, "usage: %s [-p] [-s ldap | nisplus | nis | files] \n", 159 program_name); 160 exit(1); 161 } 162 163 164 /* Encrypt secret key(s) with login_pw */ 165 static void 166 encryptkeys() 167 { 168 int mcount, ccount = 0; 169 170 if (mechs) { 171 for (mcount = 0; CURMECH; mcount++) { 172 char *crypt = NULL; 173 174 if (!xencrypt_g(slist[mcount], CURMECH->keylen, 175 CURMECH->algtype, short_login_pw, netname, 176 &crypt, TRUE)) { 177 /* Could not crypt key */ 178 crypt = NULL; 179 } else 180 ccount++; 181 clist[mcount] = crypt; 182 } 183 } else { 184 char *crypt = NULL; 185 186 if (!(crypt = 187 (char *)malloc(HEXKEYBYTES + KEYCHECKSUMSIZE + 1))) { 188 fprintf(stderr, "%s: Malloc failure.\n", program_name); 189 exit(1); 190 } 191 192 (void) memcpy(crypt, slist[0], HEXKEYBYTES); 193 (void) memcpy(crypt + HEXKEYBYTES, slist[0], KEYCHECKSUMSIZE); 194 crypt[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0; 195 xencrypt(crypt, short_login_pw); 196 197 clist[0] = crypt; 198 ccount++; 199 } 200 201 if (!ccount) { 202 fprintf(stderr, "%s: Could not encrypt any secret keys.\n", 203 program_name); 204 exit(1); 205 } 206 } 207 208 209 /* Initialize the array of public, secret, and encrypted secret keys */ 210 static void 211 initkeylist(bool_t nomech) 212 { 213 int mcount; 214 215 if (!nomech) { 216 assert(mechs && mechs[0]); 217 for (mcount = 0; CURMECH; mcount++) 218 ; 219 } else 220 mcount = 1; 221 222 if (!(plist = (char **)malloc(sizeof (char *) * mcount))) { 223 fprintf(stderr, "%s: Malloc failure.\n", program_name); 224 exit(1); 225 } 226 if (!(slist = (char **)malloc(sizeof (char *) * mcount))) { 227 fprintf(stderr, "%s: Malloc failure.\n", program_name); 228 exit(1); 229 } 230 if (!(clist = (char **)malloc(sizeof (char *) * mcount))) { 231 fprintf(stderr, "%s: Malloc failure.\n", program_name); 232 exit(1); 233 } 234 } 235 236 237 /* Retrieve public key(s) */ 238 static void 239 getpublics() 240 { 241 int mcount; 242 int pcount = 0; 243 244 if (mechs) { 245 for (mcount = 0; CURMECH; mcount++) { 246 char *public; 247 size_t hexkeylen; 248 249 hexkeylen = ((CURMECH->keylen / 8) * 2) + 1; 250 if (!(public = (char *)malloc(hexkeylen))) { 251 fprintf(stderr, "%s: Malloc failure.\n", 252 program_name); 253 exit(1); 254 } 255 if (!getpublickey_g(netname, CURMECH->keylen, 256 CURMECH->algtype, public, 257 hexkeylen)) { 258 /* Could not get public key */ 259 fprintf(stderr, 260 "Could not get %s public key.\n", 261 VALID_ALIAS(CURMECH->alias) ? 262 CURMECH->alias : ""); 263 free(public); 264 public = NULL; 265 } else 266 pcount++; 267 268 plist[mcount] = public; 269 } 270 } else { 271 char *public; 272 273 if (!(public = (char *)malloc(HEXKEYBYTES + 1))) { 274 fprintf(stderr, "%s: Malloc failure.\n", program_name); 275 exit(1); 276 } 277 if (!getpublickey(netname, public)) { 278 free(public); 279 public = NULL; 280 } else 281 pcount++; 282 283 plist[0] = public; 284 } 285 286 if (!pcount) { 287 fprintf(stderr, "%s: cannot get any public keys for %s.\n", 288 program_name, pw->pw_name); 289 error_msg(); 290 fprintf(stderr, 291 "Make sure that the public keys are stored in the domain %s.\n", 292 local_domain); 293 exit(1); 294 } 295 } 296 297 298 /* Generate a new set of public/secret key pair(s) */ 299 static void 300 makenewkeys() 301 { 302 int mcount; 303 304 if (mechs) { 305 for (mcount = 0; CURMECH; mcount++) { 306 char *public, *secret; 307 size_t hexkeylen; 308 309 if (slist[mcount]) 310 free(slist[mcount]); 311 312 hexkeylen = ((CURMECH->keylen / 8) * 2) + 1; 313 314 if (!(public = malloc(hexkeylen))) { 315 fprintf(stderr, "%s: Malloc failure.\n", 316 program_name); 317 exit(1); 318 } 319 if (!(secret = malloc(hexkeylen))) { 320 fprintf(stderr, "%s: Malloc failure.\n", 321 program_name); 322 exit(1); 323 } 324 325 if (!(__gen_dhkeys_g(public, secret, CURMECH->keylen, 326 CURMECH->algtype, short_login_pw))) { 327 /* Could not generate key pair */ 328 fprintf(stderr, 329 "WARNING Could not generate key pair %s\n", 330 VALID_ALIAS(CURMECH->alias) ? 331 CURMECH->alias : ""); 332 free(public); 333 free(secret); 334 public = NULL; 335 secret = NULL; 336 } 337 338 plist[mcount] = public; 339 slist[mcount] = secret; 340 } 341 } else { 342 char *public, *secret; 343 if (slist[0]) 344 free(slist[0]); 345 346 if (!(public = malloc(HEXKEYBYTES + 1))) { 347 fprintf(stderr, "%s: Malloc failure.\n", program_name); 348 exit(1); 349 } 350 if (!(secret = malloc(HEXKEYBYTES + 1))) { 351 fprintf(stderr, "%s: Malloc failure.\n", program_name); 352 exit(1); 353 } 354 355 __gen_dhkeys(public, secret, short_login_pw); 356 357 plist[0] = public; 358 slist[0] = secret; 359 } 360 } 361 362 363 /* 364 * Make sure that the entered Secure-RPC password(s) match the login 365 * password 366 */ 367 static void 368 cmp_passwd() 369 { 370 char baseprompt[] = "Please enter the login password for"; 371 char prompt[BUFSIZ]; 372 char *en_login_pw = spw->sp_pwdp; 373 char short_en_login_pw[DESCREDPASSLEN + 1]; 374 char *try_en_login_pw; 375 bool_t pwmatch = FALSE; 376 int done = 0, tries = 0, pcount; 377 378 snprintf(prompt, BUFSIZ, "%s %s:", baseprompt, pw->pw_name); 379 380 (void) strlcpy(short_en_login_pw, en_login_pw, 381 sizeof (short_en_login_pw)); 382 383 if (en_login_pw && (strlen(en_login_pw) != 0)) { 384 for (pcount = 0; pcount < rpc_pw_count; pcount++) { 385 char *try_en_rpc_pw; 386 387 try_en_rpc_pw = crypt(rpc_pws[pcount], short_en_login_pw); 388 if (strcmp(try_en_rpc_pw, short_en_login_pw) == 0) { 389 login_pw = rpc_pws[pcount]; 390 (void) strlcpy(short_login_pw, login_pw, 391 sizeof (short_login_pw)); 392 pwmatch = TRUE; 393 break; 394 } 395 } 396 if (!pwmatch) { 397 /* pw don't match */ 398 while (!done) { 399 /* ask for the pw */ 400 login_pw = getpassphrase(prompt); 401 (void) strlcpy(short_login_pw, login_pw, 402 sizeof (short_login_pw)); 403 if (login_pw && strlen(login_pw)) { 404 /* pw was not empty */ 405 try_en_login_pw = crypt(login_pw, 406 en_login_pw); 407 /* compare the pw's */ 408 if (!(strcmp(try_en_login_pw, 409 en_login_pw))) { 410 /* pw was correct */ 411 return; 412 } else { 413 /* pw was wrong */ 414 if (tries++) { 415 /* Sorry */ 416 fprintf(stderr, 417 "Sorry.\n"); 418 exit(1); 419 } else { 420 /* Try again */ 421 snprintf(prompt, 422 BUFSIZ, 423 "Try again. %s %s:", 424 baseprompt, 425 pw->pw_name); 426 } 427 } 428 } else { 429 /* pw was empty */ 430 if (tries++) { 431 /* Unchanged */ 432 fprintf(stderr, 433 "%s: key-pair(s) unchanged for %s.\n", 434 program_name, 435 pw->pw_name); 436 exit(1); 437 } else { 438 /* Need a password */ 439 snprintf(prompt, BUFSIZ, 440 "Need a password. %s %s:", 441 baseprompt, 442 pw->pw_name); 443 } 444 } 445 } 446 } 447 /* pw match */ 448 return; 449 } else { 450 /* no pw found */ 451 fprintf(stderr, 452 "%s: no passwd found for %s in the shadow passwd entry.\n", 453 program_name, pw->pw_name); 454 exit(1); 455 } 456 } 457 458 459 /* Prompt the user for a Secure-RPC password and store it in a cache. */ 460 static void 461 getrpcpws(char *flavor) 462 { 463 char *cur_pw = NULL; 464 char prompt[BUFSIZ + 1]; 465 466 if (flavor) 467 snprintf(prompt, BUFSIZ, 468 "Please enter the %s Secure-RPC password for %s:", 469 flavor, pw->pw_name); 470 else 471 snprintf(prompt, BUFSIZ, 472 "Please enter the Secure-RPC password for %s:", 473 pw->pw_name); 474 475 cur_pw = getpass(prompt); 476 if (!cur_pw) { 477 /* No changes */ 478 fprintf(stderr, "%s: key-pair(s) unchanged for %s.\n", 479 program_name, pw->pw_name); 480 exit(1); 481 } 482 483 rpc_pw_count++; 484 if (!(rpc_pws = 485 (char **)realloc(rpc_pws, sizeof (char *) * rpc_pw_count))) { 486 fprintf(stderr, "%s: Realloc failure.\n", program_name); 487 exit(1); 488 } 489 rpc_pws[rpc_pw_count - 1] = cur_pw; 490 } 491 492 493 /* Retrieve the secret key(s) for the user and attempt to decrypt them */ 494 static void 495 getsecrets() 496 { 497 int mcount, scount = 0; 498 int tries = 0; 499 500 getrpcpws(NULL); 501 502 if (mechs) { 503 for (mcount = 0; CURMECH; mcount++) { 504 char *secret; 505 int pcount; 506 size_t hexkeylen; 507 508 hexkeylen = ((CURMECH->keylen / 8) * 2) + 1; 509 if (!(secret = (char *)calloc(hexkeylen, 510 sizeof (char)))) { 511 fprintf(stderr, "%s: Malloc failure.\n", 512 program_name); 513 exit(1); 514 } 515 516 for (pcount = 0; pcount < rpc_pw_count; pcount++) { 517 if (!getsecretkey_g(netname, CURMECH->keylen, 518 CURMECH->algtype, secret, 519 hexkeylen, 520 rpc_pws[pcount])) 521 continue; 522 523 if (secret[0] == 0) 524 continue; 525 else 526 break; 527 } 528 529 tries = 0; 530 getsecrets_tryagain_g: 531 if (secret[0] == 0) { 532 if (!tries) { 533 /* 534 * No existing pw can decrypt 535 * secret key 536 */ 537 getrpcpws(CURMECH->alias); 538 if (!getsecretkey_g(netname, 539 CURMECH->keylen, 540 CURMECH->algtype, 541 secret, 542 hexkeylen, 543 rpc_pws[pcount])) { 544 /* 545 * Could not retreive 546 * secret key, abort 547 */ 548 free(secret); 549 secret = NULL; 550 goto getsecrets_abort; 551 } 552 553 if (secret[0] == 0) { 554 /* Still no go, ask again */ 555 free(rpc_pws[pcount]); 556 rpc_pw_count--; 557 tries++; 558 printf("Try again. "); 559 fflush(stdout); 560 goto getsecrets_tryagain_g; 561 } else 562 scount++; 563 } else { 564 fprintf(stderr, 565 "%s: key-pair unchanged for %s.\n", 566 program_name, pw->pw_name); 567 exit(1); 568 } 569 } else 570 scount++; 571 572 getsecrets_abort: 573 slist[mcount] = secret; 574 } 575 } else { 576 char *secret = NULL; 577 578 if (!(secret = (char *)malloc(HEXKEYBYTES + 1))) { 579 fprintf(stderr, "%s: Malloc failure.\n", program_name); 580 exit(1); 581 } 582 getsecrets_tryagain: 583 if (!getsecretkey(netname, secret, rpc_pws[0])) { 584 fprintf(stderr, 585 "%s: could not get secret key for '%s'\n", 586 program_name, netname); 587 exit(1); 588 } 589 590 if (secret[0] == 0) { 591 if (!tries) { 592 free(rpc_pws[0]); 593 rpc_pw_count = 0; 594 tries++; 595 printf("Try again. "); 596 fflush(stdout); 597 getrpcpws(NULL); 598 goto getsecrets_tryagain; 599 } else { 600 fprintf(stderr, 601 "%s: key-pair unchanged for %s.\n", 602 program_name, pw->pw_name); 603 exit(1); 604 } 605 } 606 607 slist[0] = secret; 608 return; 609 } 610 611 if (!scount) { 612 (void) fprintf(stderr, 613 "%s: could not get nor decrypt any secret keys for '%s'\n", 614 program_name, netname); 615 error_msg(); 616 exit(1); 617 } 618 } 619 620 621 /* Register AUTH_DES secret key with keyserv */ 622 static void 623 keylogin_des() 624 { 625 char *secret = slist[0]; 626 struct key_netstarg netst; 627 628 /* 629 * try to revoke the existing key/credentials, assuming 630 * one exists. this will effectively mark "stale" any 631 * cached credientials... 632 */ 633 if (key_setsecret(secret) < 0) { 634 return; 635 } 636 637 #ifdef NFS_AUTH 638 /* 639 * it looks like a credential already existed, so try and 640 * revoke any lingering Secure-NFS privledges. 641 */ 642 643 nra.authtype = AUTH_DES; 644 nra.uid = getuid(); 645 646 if (_nfssys(NFS_REVAUTH, &nra) < 0) 647 perror("Warning: NFS credentials not destroyed"); 648 #endif /* NFS_AUTH */ 649 650 (void) memcpy(netst.st_priv_key, secret, HEXKEYBYTES); 651 652 netst.st_pub_key[0] = '\0'; 653 netst.st_netname = strdup(netname); 654 655 /* do actual key login */ 656 if (key_setnet(&netst) < 0) { 657 fprintf(stderr, "Could not set %s's secret key\n", netname); 658 fprintf(stderr, "May be the keyserv is down?\n"); 659 } 660 } 661 662 663 /* Register a secret key with the keyserv */ 664 static void 665 keylogin(keylen_t keylen, algtype_t algtype) 666 { 667 int mcount; 668 669 if (mechs) { 670 for (mcount = 0; CURMECH; mcount++) { 671 if (keylen == CURMECH->keylen && 672 algtype == CURMECH->algtype) { 673 if (key_setnet_g(netname, slist[mcount], 674 CURMECH->keylen, 675 NULL, 0, 676 CURMECH->algtype) 677 < 0) 678 fprintf(stderr, 679 "Could not set %s's %s secret key\n", 680 netname, 681 VALID_ALIAS(CURMECH->alias) ? 682 CURMECH->alias : ""); 683 } 684 } 685 } else { 686 if (keylen == 192 && algtype == 0) 687 keylogin_des(); 688 } 689 } 690 691 692 /* 693 * fgets is "broken" in that if it reads a NUL character it will 694 * always return EOF for all reads, even when there is data left in 695 * the file. This replacement can deal with NUL's in a calm, rational 696 * manner. 697 */ 698 static char * 699 fgets_ignorenul(char *s, int n, FILE *stream) 700 { 701 int fildes = fileno(stream); 702 int i = 0; 703 int rs = 0; 704 char c; 705 706 if (fildes < 0) 707 return (NULL); 708 709 while (i < n - 1) { 710 rs = read(fildes, &c, 1); 711 switch (rs) { 712 case 1: 713 break; 714 case 0: 715 /* EOF */ 716 if (i > 0) 717 s[i] = '\0'; 718 return (NULL); 719 break; 720 default: 721 return (NULL); 722 } 723 switch (c) { 724 case '\0': 725 break; 726 case '\n': 727 s[i] = c; 728 s[++i] = '\0'; 729 return (s); 730 default: 731 if (c != '\0') 732 s[i++] = c; 733 } 734 } 735 s[i] = '\0'; 736 return (s); 737 } 738 739 740 /* Write unencrypted secret key into root key file */ 741 static void 742 write_rootkey(char *secret, char *flavor, keylen_t keylen, algtype_t algtype) 743 { 744 char line[MAXROOTKEY_LINE_LEN]; 745 char keyent[MAXROOTKEY_LEN]; 746 algtype_t atent; 747 int rootfd, bakfd, hexkeybytes; 748 bool_t lineone = TRUE; 749 bool_t gotit = FALSE; 750 FILE *rootfile, *bakfile; 751 752 unlink(ROOTKEY_FILE_BACKUP); 753 if ((rename(ROOTKEY_FILE, ROOTKEY_FILE_BACKUP)) < 0) { 754 if ((bakfd = creat(ROOTKEY_FILE_BACKUP, 0600)) < 0) { 755 perror("Could not create /etc/.rootkey.bak"); 756 goto rootkey_err; 757 } 758 close(bakfd); 759 } 760 761 if ((rootfd = open(ROOTKEY_FILE, O_WRONLY+O_CREAT, 0600)) < 0) { 762 perror("Could not open /etc/.rootkey for writing"); 763 fprintf(stderr, 764 "Attempting to restore original /etc/.rootkey\n"); 765 rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE); 766 goto rootkey_err; 767 } 768 if (!(rootfile = fdopen(rootfd, "w"))) { 769 perror("Could not open /etc/.rootkey for writing"); 770 fprintf(stderr, 771 "Attempting to restore original /etc/.rootkey\n"); 772 close(rootfd); 773 unlink(ROOTKEY_FILE); 774 rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE); 775 goto rootkey_err; 776 } 777 if (!(bakfile = fopen(ROOTKEY_FILE_BACKUP, "r"))) { 778 perror("Could not open /etc/.rootkey.bak for reading"); 779 fprintf(stderr, 780 "Attempting to restore original /etc/.rootkey\n"); 781 fclose(rootfile); 782 unlink(ROOTKEY_FILE); 783 rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE); 784 goto rootkey_err; 785 } 786 787 hexkeybytes = ((keylen + 7) / 8) * 2; 788 789 while (fgets_ignorenul(line, MAXROOTKEY_LINE_LEN, bakfile)) { 790 if (sscanf(line, "%s %d", keyent, &atent) < 2) { 791 /* 792 * No encryption algorithm found in the file 793 * (atent) so default to DES. 794 */ 795 atent = AUTH_DES_ALGTYPE; 796 } 797 /* 798 * 192-bit keys always go on the first line 799 */ 800 if (lineone) { 801 lineone = FALSE; 802 if (keylen == 192) { 803 gotit = TRUE; 804 fprintf(rootfile, "%s\n", secret); 805 } else 806 fprintf(rootfile, "%s", line); 807 fflush(rootfile); 808 } else { 809 if ((strlen(keyent) == hexkeybytes) && 810 (atent == algtype)) { 811 /* 812 * Silently remove lines with the same 813 * keylen/algtype 814 */ 815 if (gotit) 816 continue; 817 else 818 gotit = TRUE; 819 820 fprintf(rootfile, "%s %d\n", secret, algtype); 821 } else 822 fprintf(rootfile, "%s", line); 823 fflush(rootfile); 824 } 825 } 826 827 /* Append key to rootkey file */ 828 if (!gotit) { 829 if (keylen == 192) 830 fprintf(rootfile, "%s\n", secret); 831 else { 832 if (lineone) 833 fprintf(rootfile, "\n"); 834 fprintf(rootfile, "%s %d\n", secret, algtype); 835 } 836 } 837 fflush(rootfile); 838 fclose(rootfile); 839 fclose(bakfile); 840 unlink(ROOTKEY_FILE_BACKUP); 841 return; 842 843 rootkey_err: 844 fprintf(stderr, "WARNING: Could not write %s key to /etc/.rootkey\n", 845 flavor); 846 } 847 848 849 /* Returns 0 if check fails; 1 if successful. */ 850 static int 851 sanity_checks(char *nis_princ, char *domain, char *authtype) 852 { 853 char netdomainaux[MAXHOSTNAMELEN+1]; 854 char *princdomain, *netdomain; 855 int len; 856 857 /* Sanity check 0. Do we have a nis+ principal name to work with? */ 858 if (nis_princ == NULL) { 859 (void) fprintf(stderr, 860 "%s: you must create a \"LOCAL\" credential for '%s' first.\n", 861 program_name, netname); 862 (void) fprintf(stderr, "\tSee nisaddcred(1).\n"); 863 return (0); 864 } 865 866 /* Sanity check 0.5. NIS+ principal names must be dotted. */ 867 len = strlen(nis_princ); 868 if (nis_princ[len-1] != '.') { 869 (void) fprintf(stderr, 870 "%s: invalid principal name: '%s' (forgot ending dot?).\n", 871 program_name, nis_princ); 872 return (0); 873 } 874 875 /* Sanity check 1. We only deal with one type of netnames. */ 876 if (strncmp(netname, "unix", 4) != 0) { 877 (void) fprintf(stderr, 878 "%s: unrecognized netname type: '%s'.\n", 879 program_name, netname); 880 return (0); 881 } 882 883 /* Sanity check 2. Should only add DES cred in home domain. */ 884 princdomain = nis_domain_of(nis_princ); 885 if (strcasecmp(princdomain, domain) != 0) { 886 (void) fprintf(stderr, 887 "%s: domain of principal '%s' does not match destination domain '%s'.\n", 888 program_name, nis_princ, domain); 889 (void) fprintf(stderr, 890 "Should only add DES credential of principal in its home domain\n"); 891 return (0); 892 } 893 894 /* 895 * Sanity check 3: Make sure netname's domain same as principal's 896 * and don't have extraneous dot at the end. 897 */ 898 netdomain = (char *)strchr(netname, '@'); 899 if (! netdomain || netname[strlen(netname)-1] == '.') { 900 (void) fprintf(stderr, "%s: invalid netname: '%s'. \n", 901 program_name, netname); 902 return (0); 903 } 904 netdomain++; /* skip '@' */ 905 906 if (strlcpy(netdomainaux, netdomain, sizeof (netdomainaux)) >= 907 sizeof (netdomainaux)) { 908 (void) fprintf(stderr, "%s: net domain name %s is too long\n", 909 program_name, netdomain); 910 return (0); 911 } 912 913 if (netdomainaux[strlen(netdomainaux) - 1] != '.') { 914 if (strlcat(netdomainaux, ".", sizeof (netdomainaux)) >= 915 sizeof (netdomainaux)) { 916 (void) fprintf(stderr, 917 "%s: net domain name %s is too long\n", 918 program_name, netdomainaux); 919 return (0); 920 } 921 } 922 923 if (strcasecmp(princdomain, netdomainaux) != 0) { 924 (void) fprintf(stderr, 925 "%s: domain of netname %s should be same as that of principal %s\n", 926 program_name, netname, nis_princ); 927 return (0); 928 } 929 930 /* Another principal owns same credentials? (exits if that happens) */ 931 (void) auth_exists(nis_princ, netname, authtype, domain); 932 933 return (1); /* all passed */ 934 } 935 936 937 /* Store new key information in the specified name service */ 938 static void 939 storekeys() 940 { 941 int mcount, ucount = 0; 942 char *ypmaster, *ypdomain = NULL, pkent[MAXPKENTLEN]; 943 nis_name nis_princ; 944 945 946 /* Setup */ 947 switch (dest_service) { 948 case PK_LDAP: 949 break; 950 case PK_NISPLUS: 951 nis_princ = get_nisplus_principal(nis_local_directory(), 952 geteuid()); 953 break; 954 case PK_YP: 955 yp_get_default_domain(&ypdomain); 956 if (yp_master(ypdomain, PKMAP, &ypmaster) != 0) { 957 fprintf(stderr, 958 "%s: cannot find master of NIS publickey database\n", 959 program_name); 960 exit(1); 961 } 962 fprintf(stdout, 963 "Sending key change request to %s ...\n", ypmaster); 964 break; 965 case PK_FILES: 966 if (geteuid() != 0) { 967 fprintf(stderr, 968 "%s: non-root users cannot change their key-pair in %s\n", 969 program_name, PKFILE); 970 exit(1); 971 } 972 break; 973 default: 974 fprintf(stderr, 975 "could not update; database %d unknown\n", 976 dest_service); 977 exit(1); 978 } 979 980 if (mechs) { 981 for (mcount = 0; CURMECH; mcount++) { 982 char authtype[MECH_MAXATNAME]; 983 984 if (!plist[mcount] && !clist[mcount]) 985 continue; 986 987 __nis_mechalias2authtype(CURMECH->alias, authtype, 988 MECH_MAXATNAME); 989 if (!authtype) { 990 fprintf(stderr, 991 "Could not generate auth_type for %s.\n", 992 CURMECH->alias); 993 continue; 994 } 995 996 snprintf(pkent, MAXPKENTLEN, "%s:%s:%d", 997 plist[mcount], clist[mcount], 998 CURMECH->algtype); 999 1000 switch (dest_service) { 1001 case PK_LDAP: 1002 if (ldap_update(CURMECH->alias, netname, 1003 plist[mcount], clist[mcount], 1004 login_pw)) 1005 fprintf(stderr, 1006 "%s: unable to update %s key in LDAP database\n", 1007 program_name, authtype); 1008 else 1009 ucount++; 1010 break; 1011 1012 case PK_NISPLUS: 1013 if (nisplus_update(nis_princ, 1014 authtype, 1015 plist[mcount], 1016 clist[mcount])) 1017 fprintf(stderr, 1018 "%s: unable to update %s key in nisplus database\n", 1019 program_name, authtype); 1020 else 1021 ucount++; 1022 break; 1023 1024 case PK_YP: 1025 /* Should never get here. */ 1026 break; 1027 1028 case PK_FILES: 1029 /* Should never get here. */ 1030 break; 1031 } 1032 } 1033 } else { 1034 int status = 0; 1035 1036 assert(plist[0] && clist[0]); 1037 snprintf(pkent, MAXPKENTLEN, "%s:%s", plist[0], clist[0]); 1038 1039 switch (dest_service) { 1040 case PK_LDAP: 1041 if (ldap_update("dh192-0", netname, 1042 plist[0], clist[0], 1043 login_pw)) { 1044 fprintf(stderr, 1045 "%s: unable to update %s key in LDAP database\n", 1046 program_name); 1047 exit(1); 1048 } 1049 break; 1050 1051 case PK_NISPLUS: 1052 assert(plist[0] && clist[0]); 1053 if (nisplus_update(nis_princ, 1054 AUTH_DES_AUTH_TYPE, 1055 plist[0], 1056 clist[0])) { 1057 fprintf(stderr, 1058 "%s: unable to update nisplus database\n", 1059 program_name); 1060 exit(1); 1061 } 1062 break; 1063 1064 case PK_YP: 1065 if (status = yp_update(ypdomain, PKMAP, 1066 YPOP_STORE, netname, 1067 strlen(netname), pkent, 1068 strlen(pkent))) { 1069 fprintf(stderr, 1070 "%s: unable to update NIS database (%u): %s\n", 1071 program_name, status, 1072 yperr_string(status)); 1073 exit(1); 1074 } 1075 break; 1076 1077 case PK_FILES: 1078 if (localupdate(netname, PKFILE, YPOP_STORE, pkent)) { 1079 fprintf(stderr, 1080 "%s: hence, unable to update publickey database\n", 1081 program_name); 1082 exit(1); 1083 } 1084 break; 1085 1086 default: 1087 /* Should never get here */ 1088 assert(0); 1089 } 1090 return; 1091 } 1092 if (!ucount) { 1093 fprintf(stderr, "%s: unable to update any key-pairs for %s.\n", 1094 program_name, pw->pw_name); 1095 exit(1); 1096 } 1097 } 1098 1099 /* Check that someone else don't have the same auth information already */ 1100 static 1101 nis_error 1102 auth_exists(char *princname, char *auth_name, char *auth_type, char *domain) 1103 { 1104 char sname[NIS_MAXNAMELEN+1]; 1105 nis_result *res; 1106 nis_error status; 1107 char *foundprinc; 1108 1109 (void) sprintf(sname, "[auth_name=%s,auth_type=%s],%s.%s", 1110 auth_name, auth_type, CRED_TABLE, domain); 1111 if (sname[strlen(sname)-1] != '.') 1112 strcat(sname, "."); 1113 /* Don't want FOLLOW_PATH here */ 1114 res = nis_list(sname, 1115 MASTER_ONLY+USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS, 1116 NULL, NULL); 1117 1118 status = res->status; 1119 switch (res->status) { 1120 case NIS_NOTFOUND: 1121 break; 1122 case NIS_TRYAGAIN: 1123 (void) fprintf(stderr, 1124 "%s: NIS+ server busy, try again later.\n", 1125 program_name); 1126 exit(1); 1127 break; 1128 case NIS_PERMISSION: 1129 (void) fprintf(stderr, 1130 "%s: insufficient permission to look up old credentials.\n", 1131 program_name); 1132 exit(1); 1133 break; 1134 case NIS_SUCCESS: 1135 foundprinc = ENTRY_VAL(res->objects.objects_val, 0); 1136 if (nis_dir_cmp(foundprinc, princname) != SAME_NAME) { 1137 (void) fprintf(stderr, 1138 "%s: %s credentials with auth_name '%s' already belong to '%s'.\n", 1139 program_name, auth_type, auth_name, foundprinc); 1140 exit(1); 1141 } 1142 break; 1143 default: 1144 (void) fprintf(stderr, 1145 "%s: error looking at cred table, NIS+ error: %s\n", 1146 program_name, nis_sperrno(res->status)); 1147 exit(1); 1148 } 1149 nis_freeresult(res); 1150 return (status); 1151 } 1152 1153 1154 /* Check whether this principal already has this type of credentials */ 1155 static nis_error 1156 cred_exists(const char *nisprinc, const char *flavor, const char *domain) 1157 { 1158 char sname[NIS_MAXNAMELEN+1]; 1159 nis_result *res; 1160 nis_error status; 1161 1162 snprintf(sname, NIS_MAXNAMELEN, 1163 "[cname=\"%s\",auth_type=%s],%s.%s", 1164 nisprinc, flavor, CRED_TABLE, domain); 1165 if (sname[strlen(sname)-1] != '.') 1166 strcat(sname, "."); 1167 1168 /* Don't want FOLLOW_PATH here */ 1169 res = nis_list(sname, 1170 MASTER_ONLY+USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS, 1171 NULL, NULL); 1172 1173 status = res->status; 1174 switch (status) { 1175 case NIS_NOTFOUND: 1176 break; 1177 case NIS_TRYAGAIN: 1178 fprintf(stderr, 1179 "%s: NIS+ server busy, try again later.\n", 1180 program_name); 1181 exit(1); 1182 break; 1183 case NIS_PERMISSION: 1184 (void) fprintf(stderr, 1185 "%s: insufficient permission to look at credentials table\n", 1186 program_name); 1187 exit(1); 1188 break; 1189 case NIS_SUCCESS: 1190 case NIS_S_SUCCESS: 1191 break; 1192 default: 1193 (void) fprintf(stderr, 1194 "%s: error looking at cred table, NIS+ error: %s\n", 1195 program_name, nis_sperrno(res->status)); 1196 exit(1); 1197 } 1198 nis_freeresult(res); 1199 return (status); 1200 } 1201 1202 1203 static int 1204 modify_cred_obj(nis_object *obj, char *domain) 1205 { 1206 int status = 0; 1207 char sname[NIS_MAXNAMELEN+1]; 1208 nis_result *res; 1209 1210 (void) sprintf(sname, "%s.%s", CRED_TABLE, domain); 1211 res = nis_modify_entry(sname, obj, 0); 1212 switch (res->status) { 1213 case NIS_TRYAGAIN: 1214 (void) fprintf(stderr, 1215 "%s: NIS+ server busy, try again later.\n", 1216 program_name); 1217 exit(1); 1218 break; 1219 case NIS_PERMISSION: 1220 (void) fprintf(stderr, 1221 "%s: insufficient permission to update credentials.\n", 1222 program_name); 1223 exit(1); 1224 break; 1225 case NIS_SUCCESS: 1226 status = 1; 1227 break; 1228 default: 1229 (void) fprintf(stderr, 1230 "%s: error modifying credential, NIS+ error: %s.\n", 1231 program_name, nis_sperrno(res->status)); 1232 exit(1); 1233 } 1234 nis_freeresult(res); 1235 return (status); 1236 } 1237 1238 1239 static int 1240 add_cred_obj(nis_object *obj, char *domain) 1241 { 1242 int status = 0; 1243 char sname[NIS_MAXNAMELEN+1]; 1244 nis_result *res; 1245 1246 /* Assume check for cred_exists performed already */ 1247 1248 (void) sprintf(sname, "%s.%s", CRED_TABLE, domain); 1249 res = nis_add_entry(sname, obj, 0); 1250 switch (res->status) { 1251 case NIS_TRYAGAIN: 1252 (void) fprintf(stderr, 1253 "%s: NIS+ server busy, try again later.\n", 1254 program_name); 1255 exit(1); 1256 break; 1257 case NIS_PERMISSION: 1258 (void) fprintf(stderr, 1259 "%s: insufficient permission to update credentials.\n", 1260 program_name); 1261 exit(1); 1262 break; 1263 case NIS_SUCCESS: 1264 status = 1; 1265 break; 1266 default: 1267 (void) fprintf(stderr, 1268 "%s: error creating credential, NIS+ error: %s.\n", 1269 program_name, nis_sperrno(res->status)); 1270 exit(1); 1271 } 1272 nis_freeresult(res); 1273 return (status); 1274 } 1275 1276 1277 /* Update NIS+ table with new key information */ 1278 static int 1279 nisplus_update(nis_name nis_princ, char *authtype, char *public, char *crypt) 1280 { 1281 nis_object *obj = init_entry(); 1282 int status; 1283 bool_t addition; 1284 char cmpdomain[MAXHOSTNAMELEN + 1]; 1285 char *userdomain, *domain; 1286 1287 if (!(userdomain = strchr(netname, '@'))) { 1288 fprintf(stderr, "%s: invalid netname: '%s'.\n", 1289 program_name, netname); 1290 exit(1); 1291 } 1292 userdomain++; 1293 1294 if (strlcpy(cmpdomain, userdomain, sizeof (cmpdomain)) >= 1295 sizeof (cmpdomain)) { 1296 (void) fprintf(stderr, 1297 "%s: net domain name %s is too long\n", 1298 program_name, cmpdomain); 1299 exit(1); 1300 } 1301 1302 if (cmpdomain[strlen(cmpdomain) - 1] != '.') { 1303 if (strlcat(cmpdomain, ".", sizeof (cmpdomain)) >= 1304 sizeof (cmpdomain)) { 1305 (void) fprintf(stderr, 1306 "%s: net domain name %s is too long\n", 1307 program_name, cmpdomain); 1308 exit(1); 1309 } 1310 } 1311 1312 domain = nis_domain_of(nis_princ); 1313 if (strcasecmp(domain, cmpdomain) != 0) 1314 domain = nis_local_directory(); 1315 1316 if (!sanity_checks(nis_princ, domain, authtype)) 1317 exit(1); 1318 1319 addition = (cred_exists(nis_princ, authtype, domain) == NIS_NOTFOUND); 1320 1321 ENTRY_VAL(obj, 0) = nis_princ; 1322 ENTRY_LEN(obj, 0) = strlen(nis_princ) + 1; 1323 1324 ENTRY_VAL(obj, 1) = authtype; 1325 ENTRY_LEN(obj, 1) = strlen(authtype) + 1; 1326 1327 ENTRY_VAL(obj, 2) = netname; 1328 ENTRY_LEN(obj, 2) = strlen(netname) + 1; 1329 1330 ENTRY_VAL(obj, 3) = public; 1331 ENTRY_LEN(obj, 3) = strlen(public) + 1; 1332 1333 ENTRY_VAL(obj, 4) = crypt; 1334 ENTRY_LEN(obj, 4) = strlen(crypt) + 1; 1335 1336 if (addition) { 1337 obj->zo_owner = nis_princ; 1338 obj->zo_group = nis_local_group(); 1339 obj->zo_domain = domain; 1340 /* owner: r, group: rmcd */ 1341 obj->zo_access = ((NIS_READ_ACC<<16)| 1342 (NIS_READ_ACC|NIS_MODIFY_ACC|NIS_CREATE_ACC| 1343 NIS_DESTROY_ACC)<<8); 1344 status = add_cred_obj(obj, domain); 1345 } else { 1346 obj->EN_data.en_cols.en_cols_val[3].ec_flags |= EN_MODIFIED; 1347 obj->EN_data.en_cols.en_cols_val[4].ec_flags |= EN_MODIFIED; 1348 status = modify_cred_obj(obj, domain); 1349 } 1350 return (status == 1 ? 0 : 1); 1351 } 1352 1353 1354 void 1355 addmechtolist(char *mechtype) 1356 { 1357 mechanism_t **realmechlist; 1358 int i; 1359 1360 if (realmechlist = __nis_get_mechanisms(FALSE)) { 1361 /* Match requested mech with list */ 1362 for (i = 0; realmechlist[i]; i++) { 1363 if (realmechlist[i]->alias) 1364 if (strcmp(realmechlist[i]->alias, mechtype) 1365 == 0) { 1366 /* 1367 * Match, add it to the mechs. 1368 * Don't worry about qop or 1369 * secserv since they are not 1370 * used by chkey. 1371 */ 1372 numspecmech++; 1373 if ((mechs = 1374 (mechanism_t **)realloc(mechs, 1375 sizeof (mechanism_t *) * 1376 (numspecmech + 1))) == NULL) { 1377 perror("Can not change keys"); 1378 exit(1); 1379 } 1380 1381 if ((mechs[numspecmech - 1] = 1382 (mechanism_t *)malloc( 1383 sizeof (mechanism_t))) == NULL) { 1384 perror("Can not change keys"); 1385 exit(1); 1386 } 1387 if (realmechlist[i]->mechname) 1388 mechs[numspecmech - 1]->mechname = 1389 strdup(realmechlist[i]->mechname); 1390 if (realmechlist[i]->alias) 1391 mechs[numspecmech - 1]->alias = 1392 strdup(realmechlist[i]->alias); 1393 mechs[numspecmech - 1]->keylen = 1394 realmechlist[i]->keylen; 1395 mechs[numspecmech - 1]->algtype = 1396 realmechlist[i]->algtype; 1397 mechs[numspecmech] = NULL; 1398 __nis_release_mechanisms(realmechlist); 1399 return; 1400 } 1401 } 1402 1403 fprintf(stderr, 1404 "WARNING: Mechanism '%s' not configured, skipping...\n", 1405 mechtype); 1406 __nis_release_mechanisms(realmechlist); 1407 return; 1408 } 1409 fprintf(stderr, 1410 "WARNING: Mechanism '%s' not configured, skipping...\n", 1411 mechtype); 1412 } 1413 1414 1415 int 1416 main(int argc, char **argv) 1417 { 1418 int c, mcount; 1419 uid_t uid; 1420 uid_t orig_euid; 1421 char *service = NULL; 1422 program_name = argv[0]; 1423 1424 mechs = __nis_get_mechanisms(FALSE); 1425 1426 while ((c = getopt(argc, argv, "fps:m:")) != -1) { 1427 switch (c) { 1428 case 'f': 1429 /* 1430 * Not documented as of on1093. 1431 * Temporarily supported 1432 */ 1433 force++; 1434 break; 1435 case 'p': 1436 makenew = FALSE; 1437 break; 1438 case 's': 1439 if (!service) 1440 service = strdup(optarg); 1441 else 1442 usage(); 1443 break; 1444 case 'm': 1445 if (mechs && specmech == FALSE) { 1446 __nis_release_mechanisms(mechs); 1447 mechs = NULL; 1448 } 1449 specmech = TRUE; 1450 addmechtolist(optarg); 1451 break; 1452 default: 1453 usage(); 1454 } 1455 } 1456 1457 if (optind < argc) 1458 usage(); 1459 1460 dest_service = get_pk_source(service); 1461 1462 if (!(netname = malloc(MAXNETNAMELEN + 1))) { 1463 fprintf(stderr, "%s: Malloc failure.\n", program_name); 1464 exit(1); 1465 } 1466 if (!__getnetnamebyuid(netname, uid = getuid())) { 1467 fprintf(stderr, "%s: cannot generate netname for uid %d\n", 1468 program_name, uid); 1469 exit(1); 1470 } 1471 sec_domain = strdup(strchr(netname, '@') + 1); 1472 getdomainname(local_domain, MAXNETNAMELEN); 1473 1474 if (makenew) 1475 fprintf(stdout, "Generating new key for '%s'.\n", netname); 1476 else 1477 fprintf(stdout, "Reencrypting key for '%s'.\n", netname); 1478 1479 if (mechs) { 1480 if (dest_service == PK_YP || dest_service == PK_FILES) { 1481 fprintf(stderr, 1482 "%s: can not add non-DES public keys to %s, skipping.\n", 1483 program_name, service); 1484 __nis_release_mechanisms(mechs); 1485 mechs = NULL; 1486 initkeylist(TRUE); 1487 } else 1488 initkeylist(FALSE); 1489 } else 1490 initkeylist(TRUE); 1491 1492 uid = getuid(); 1493 orig_euid = geteuid(); 1494 1495 /* Get password information */ 1496 if ((pw = getpwuid(uid)) == NULL) { 1497 fprintf(stderr, 1498 "%s: Can not find passwd information for %d.\n", 1499 program_name, uid); 1500 exit(1); 1501 } 1502 1503 /* Set eUID to user */ 1504 seteuid(uid); 1505 1506 /* Obtain a list of decrypted secret keys */ 1507 getsecrets(); 1508 1509 /* Keylogin user if not already done */ 1510 if (mechs) { 1511 int mcount; 1512 1513 for (mcount = 0; CURMECH; mcount++) { 1514 keylen_t keylen = CURMECH->keylen; 1515 algtype_t algtype = CURMECH->algtype; 1516 1517 if (!key_secretkey_is_set_g(keylen, algtype) && 1518 slist[mcount]) { 1519 keylogin(CURMECH->keylen, CURMECH->algtype); 1520 if ((uid == 0) && (makenew == FALSE)) 1521 write_rootkey(slist[mcount], 1522 VALID_ALIAS(CURMECH->alias) ? 1523 CURMECH->alias : 1524 "", 1525 keylen, algtype); 1526 } 1527 } 1528 } else { 1529 assert(slist[0]); 1530 if (!key_secretkey_is_set()) { 1531 keylogin_des(); 1532 if ((uid == 0) && (makenew == FALSE)) 1533 write_rootkey(slist[0], "des", 192, 0); 1534 } 1535 } 1536 1537 /* Set eUID back to root */ 1538 (void) seteuid(orig_euid); 1539 1540 /* 1541 * Call getspnam() after the keylogin has been done so we have 1542 * the best chance of having read access to the encrypted pw. 1543 * 1544 * The eUID must be 0 for the getspnam() so the name service 1545 * switch can handle the following eUID sensitive cases: 1546 * 1547 * files/compat: read /etc/shadow 1548 * 1549 * nisplus: try to read the encrypted pw as the root 1550 * principal and if that fails, and if the 1551 * user's secret key is set, seteuid(user) 1552 * and retry the read. 1553 */ 1554 if ((spw = getspnam(pw->pw_name)) == 0) { 1555 1556 /* Set eUID back to user */ 1557 (void) seteuid(uid); 1558 1559 (void) fprintf(stderr, 1560 "%s: cannot find shadow entry for %s.\n", 1561 program_name, pw->pw_name); 1562 exit(1); 1563 } 1564 1565 /* Set eUID back to user */ 1566 (void) seteuid(uid); 1567 1568 if (strcmp(spw->sp_pwdp, NOPWDRTR) == 0) { 1569 (void) fprintf(stderr, 1570 "%s: do not have read access to the passwd field for %s\n", 1571 program_name, pw->pw_name); 1572 exit(1); 1573 } 1574 1575 /* 1576 * force will be only supported for a while 1577 * -- it is NOT documented as of s1093 1578 */ 1579 if (force) { 1580 char *prompt = "Please enter New password:"; 1581 1582 login_pw = getpassphrase(prompt); 1583 (void) strlcpy(short_login_pw, login_pw, 1584 sizeof (short_login_pw)); 1585 if (!login_pw || !(strlen(login_pw))) { 1586 fprintf(stderr, "%s: key-pair(s) unchanged for %s.\n", 1587 program_name, pw->pw_name); 1588 exit(1); 1589 } 1590 } else { 1591 /* 1592 * Reconsile rpc_pws and login_pw. 1593 * 1594 * This function will either return with login_pw == rpc_pw 1595 * (and thus, the new pw to encrypt keys) or it will exit. 1596 */ 1597 cmp_passwd(); 1598 } 1599 1600 if (makenew) 1601 makenewkeys(); 1602 else 1603 getpublics(); 1604 1605 encryptkeys(); 1606 1607 storekeys(); 1608 1609 if (makenew) { 1610 if (uid == 0) { 1611 if (mechs) { 1612 for (mcount = 0; CURMECH; mcount++) { 1613 if (!slist[mcount]) 1614 continue; 1615 write_rootkey(slist[mcount], 1616 CURMECH->alias, 1617 CURMECH->keylen, 1618 CURMECH->algtype); 1619 } 1620 } else { 1621 assert(slist[0]); 1622 write_rootkey(slist[0], "des", 192, 0); 1623 } 1624 } 1625 if (mechs) { 1626 for (mcount = 0; CURMECH; mcount++) 1627 keylogin(CURMECH->keylen, 1628 CURMECH->algtype); 1629 } else 1630 keylogin_des(); 1631 } 1632 return (0); 1633 } 1634