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