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
error_msg()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
usage()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
encryptkeys()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
initkeylist(bool_t nomech)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
getpublics()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
makenewkeys()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
cmp_passwd()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
getrpcpws(char * flavor)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
getsecrets()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
keylogin_des()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
keylogin(keylen_t keylen,algtype_t algtype)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 *
fgets_ignorenul(char * s,int n,FILE * stream)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
write_rootkey(char * secret,char * flavor,keylen_t keylen,algtype_t algtype)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
storekeys()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
addmechtolist(char * mechtype)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
main(int argc,char ** argv)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