8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / keyserv / chkey.c
blob25e3b9df4e500431d39e049c74714742d66c4ba1
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
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>
56 #define PK_FILES 1
57 #define PK_YP 2
58 #define PK_LDAP 4
60 #define CURMECH mechs[mcount]
61 #define DESCREDPASSLEN sizeof (des_block)
63 static char CRED_TABLE[] = "cred.org_dir";
64 static char PKMAP[] = "publickey.byname";
65 static char PKFILE[] = "/etc/publickey";
66 #define MAXHOSTNAMELEN 256
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
73 /* Should last up to 16384-bit keys */
74 #define MAXPKENTLEN 8500
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) */
81 char *program_name;
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 */
89 struct passwd *pw = NULL; /* passwd entry of user */
90 struct spwd *spw = NULL; /* shadow entry of user */
92 char *netname = NULL; /* RPC netname of user */
93 char local_domain[MAXNETNAMELEN + 1];
94 char *sec_domain = NULL;
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 */
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();
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 *);
133 static void
134 error_msg()
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);
146 static void
147 usage()
149 fprintf(stderr, "usage: %s [-p] [-s ldap | nis | files] \n",
150 program_name);
151 exit(1);
155 /* Encrypt secret key(s) with login_pw */
156 static void
157 encryptkeys()
159 int mcount, ccount = 0;
161 if (mechs) {
162 for (mcount = 0; CURMECH; mcount++) {
163 char *crypt = NULL;
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;
174 } else {
175 char *crypt = NULL;
177 if (!(crypt =
178 (char *)malloc(HEXKEYBYTES + KEYCHECKSUMSIZE + 1))) {
179 fprintf(stderr, "%s: Malloc failure.\n", program_name);
180 exit(1);
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);
188 clist[0] = crypt;
189 ccount++;
192 if (!ccount) {
193 fprintf(stderr, "%s: Could not encrypt any secret keys.\n",
194 program_name);
195 exit(1);
200 /* Initialize the array of public, secret, and encrypted secret keys */
201 static void
202 initkeylist(bool_t nomech)
204 int mcount;
206 if (!nomech) {
207 assert(mechs && mechs[0]);
208 for (mcount = 0; CURMECH; mcount++)
210 } else
211 mcount = 1;
213 if (!(plist = (char **)malloc(sizeof (char *) * mcount))) {
214 fprintf(stderr, "%s: Malloc failure.\n", program_name);
215 exit(1);
217 if (!(slist = (char **)malloc(sizeof (char *) * mcount))) {
218 fprintf(stderr, "%s: Malloc failure.\n", program_name);
219 exit(1);
221 if (!(clist = (char **)malloc(sizeof (char *) * mcount))) {
222 fprintf(stderr, "%s: Malloc failure.\n", program_name);
223 exit(1);
228 /* Retrieve public key(s) */
229 static void
230 getpublics()
232 int mcount;
233 int pcount = 0;
235 if (mechs) {
236 for (mcount = 0; CURMECH; mcount++) {
237 char *public;
238 size_t hexkeylen;
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);
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++;
259 plist[mcount] = public;
261 } else {
262 char *public;
264 if (!(public = (char *)malloc(HEXKEYBYTES + 1))) {
265 fprintf(stderr, "%s: Malloc failure.\n", program_name);
266 exit(1);
268 if (!getpublickey(netname, public)) {
269 free(public);
270 public = NULL;
271 } else
272 pcount++;
274 plist[0] = public;
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);
289 /* Generate a new set of public/secret key pair(s) */
290 static void
291 makenewkeys()
293 int mcount;
295 if (mechs) {
296 for (mcount = 0; CURMECH; mcount++) {
297 char *public, *secret;
298 size_t hexkeylen;
300 if (slist[mcount])
301 free(slist[mcount]);
303 hexkeylen = ((CURMECH->keylen / 8) * 2) + 1;
305 if (!(public = malloc(hexkeylen))) {
306 fprintf(stderr, "%s: Malloc failure.\n",
307 program_name);
308 exit(1);
310 if (!(secret = malloc(hexkeylen))) {
311 fprintf(stderr, "%s: Malloc failure.\n",
312 program_name);
313 exit(1);
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;
329 plist[mcount] = public;
330 slist[mcount] = secret;
332 } else {
333 char *public, *secret;
334 if (slist[0])
335 free(slist[0]);
337 if (!(public = malloc(HEXKEYBYTES + 1))) {
338 fprintf(stderr, "%s: Malloc failure.\n", program_name);
339 exit(1);
341 if (!(secret = malloc(HEXKEYBYTES + 1))) {
342 fprintf(stderr, "%s: Malloc failure.\n", program_name);
343 exit(1);
346 __gen_dhkeys(public, secret, short_login_pw);
348 plist[0] = public;
349 slist[0] = secret;
355 * Make sure that the entered Secure-RPC password(s) match the login
356 * password
358 static void
359 cmp_passwd()
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;
369 snprintf(prompt, BUFSIZ, "%s %s:", baseprompt, pw->pw_name);
371 (void) strlcpy(short_en_login_pw, en_login_pw,
372 sizeof (short_en_login_pw));
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;
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;
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);
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);
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);
450 /* Prompt the user for a Secure-RPC password and store it in a cache. */
451 static void
452 getrpcpws(char *flavor)
454 char *cur_pw = NULL;
455 char prompt[BUFSIZ + 1];
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);
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);
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);
480 rpc_pws[rpc_pw_count - 1] = cur_pw;
484 /* Retrieve the secret key(s) for the user and attempt to decrypt them */
485 static void
486 getsecrets()
488 int mcount, scount = 0;
489 int tries = 0;
491 getrpcpws(NULL);
493 if (mechs) {
494 for (mcount = 0; CURMECH; mcount++) {
495 char *secret;
496 int pcount;
497 size_t hexkeylen;
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);
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;
514 if (secret[0] == 0)
515 continue;
516 else
517 break;
520 tries = 0;
521 getsecrets_tryagain_g:
522 if (secret[0] == 0) {
523 if (!tries) {
525 * No existing pw can decrypt
526 * secret key
528 getrpcpws(CURMECH->alias);
529 if (!getsecretkey_g(netname,
530 CURMECH->keylen,
531 CURMECH->algtype,
532 secret,
533 hexkeylen,
534 rpc_pws[pcount])) {
536 * Could not retreive
537 * secret key, abort
539 free(secret);
540 secret = NULL;
541 goto getsecrets_abort;
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);
560 } else
561 scount++;
563 getsecrets_abort:
564 slist[mcount] = secret;
566 } else {
567 char *secret = NULL;
569 if (!(secret = (char *)malloc(HEXKEYBYTES + 1))) {
570 fprintf(stderr, "%s: Malloc failure.\n", program_name);
571 exit(1);
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);
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);
598 slist[0] = secret;
599 return;
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);
612 /* Register AUTH_DES secret key with keyserv */
613 static void
614 keylogin_des()
616 char *secret = slist[0];
617 struct key_netstarg netst;
620 * try to revoke the existing key/credentials, assuming
621 * one exists. this will effectively mark "stale" any
622 * cached credientials...
624 if (key_setsecret(secret) < 0) {
625 return;
628 #ifdef NFS_AUTH
630 * it looks like a credential already existed, so try and
631 * revoke any lingering Secure-NFS privledges.
634 nra.authtype = AUTH_DES;
635 nra.uid = getuid();
637 if (_nfssys(NFS_REVAUTH, &nra) < 0)
638 perror("Warning: NFS credentials not destroyed");
639 #endif /* NFS_AUTH */
641 (void) memcpy(netst.st_priv_key, secret, HEXKEYBYTES);
643 netst.st_pub_key[0] = '\0';
644 netst.st_netname = strdup(netname);
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");
654 /* Register a secret key with the keyserv */
655 static void
656 keylogin(keylen_t keylen, algtype_t algtype)
658 int mcount;
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 : "");
676 } else {
677 if (keylen == 192 && algtype == 0)
678 keylogin_des();
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.
689 static char *
690 fgets_ignorenul(char *s, int n, FILE *stream)
692 int fildes = fileno(stream);
693 int i = 0;
694 int rs = 0;
695 char c;
697 if (fildes < 0)
698 return (NULL);
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);
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;
726 s[i] = '\0';
727 return (s);
731 /* Write unencrypted secret key into root key file */
732 static void
733 write_rootkey(char *secret, char *flavor, keylen_t keylen, algtype_t algtype)
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;
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;
749 close(bakfd);
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;
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;
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;
778 hexkeybytes = ((keylen + 7) / 8) * 2;
780 while (fgets_ignorenul(line, MAXROOTKEY_LINE_LEN, bakfile)) {
781 if (sscanf(line, "%s %d", keyent, &atent) < 2) {
783 * No encryption algorithm found in the file
784 * (atent) so default to DES.
786 atent = AUTH_DES_ALGTYPE;
789 * 192-bit keys always go on the first line
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)) {
803 * Silently remove lines with the same
804 * keylen/algtype
806 if (gotit)
807 continue;
808 else
809 gotit = TRUE;
811 fprintf(rootfile, "%s %d\n", secret, algtype);
812 } else
813 fprintf(rootfile, "%s", line);
814 fflush(rootfile);
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);
828 fflush(rootfile);
829 fclose(rootfile);
830 fclose(bakfile);
831 unlink(ROOTKEY_FILE_BACKUP);
832 return;
834 rootkey_err:
835 fprintf(stderr, "WARNING: Could not write %s key to /etc/.rootkey\n",
836 flavor);
839 /* Store new key information in the specified name service */
840 static void
841 storekeys()
843 int mcount, ucount = 0;
844 char *ypmaster, *ypdomain = NULL, pkent[MAXPKENTLEN];
845 nis_name nis_princ;
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);
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);
870 break;
871 default:
872 fprintf(stderr,
873 "could not update; database %d unknown\n",
874 dest_service);
875 exit(1);
878 if (mechs) {
879 for (mcount = 0; CURMECH; mcount++) {
880 char authtype[MECH_MAXATNAME];
882 if (!plist[mcount] && !clist[mcount])
883 continue;
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;
894 snprintf(pkent, MAXPKENTLEN, "%s:%s:%d",
895 plist[mcount], clist[mcount],
896 CURMECH->algtype);
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;
910 case PK_YP:
911 /* Should never get here. */
912 break;
914 case PK_FILES:
915 /* Should never get here. */
916 break;
919 } else {
920 int status = 0;
922 assert(plist[0] && clist[0]);
923 snprintf(pkent, MAXPKENTLEN, "%s:%s", plist[0], clist[0]);
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);
935 break;
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);
948 break;
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);
957 break;
959 default:
960 /* Should never get here */
961 assert(0);
963 return;
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);
972 void
973 addmechtolist(char *mechtype)
975 mechanism_t **realmechlist;
976 int i;
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) {
985 * Match, add it to the mechs.
986 * Don't worry about qop or
987 * secserv since they are not
988 * used by chkey.
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);
999 if ((mechs[numspecmech - 1] =
1000 (mechanism_t *)malloc(
1001 sizeof (mechanism_t))) == NULL) {
1002 perror("Can not change keys");
1003 exit(1);
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;
1021 fprintf(stderr,
1022 "WARNING: Mechanism '%s' not configured, skipping...\n",
1023 mechtype);
1024 __nis_release_mechanisms(realmechlist);
1025 return;
1027 fprintf(stderr,
1028 "WARNING: Mechanism '%s' not configured, skipping...\n",
1029 mechtype);
1034 main(int argc, char **argv)
1036 int c, mcount;
1037 uid_t uid;
1038 uid_t orig_euid;
1039 char *service = NULL;
1040 program_name = argv[0];
1042 mechs = __nis_get_mechanisms(FALSE);
1044 while ((c = getopt(argc, argv, "fps:m:")) != -1) {
1045 switch (c) {
1046 case 'f':
1048 * Not documented as of on1093.
1049 * Temporarily supported
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;
1067 specmech = TRUE;
1068 addmechtolist(optarg);
1069 break;
1070 default:
1071 usage();
1075 if (optind < argc)
1076 usage();
1078 dest_service = get_pk_source(service);
1080 if (!(netname = malloc(MAXNETNAMELEN + 1))) {
1081 fprintf(stderr, "%s: Malloc failure.\n", program_name);
1082 exit(1);
1084 if (!__getnetnamebyuid(netname, uid = getuid())) {
1085 fprintf(stderr, "%s: cannot generate netname for uid %d\n",
1086 program_name, uid);
1087 exit(1);
1089 sec_domain = strdup(strchr(netname, '@') + 1);
1090 getdomainname(local_domain, MAXNETNAMELEN);
1092 if (makenew)
1093 fprintf(stdout, "Generating new key for '%s'.\n", netname);
1094 else
1095 fprintf(stdout, "Reencrypting key for '%s'.\n", netname);
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);
1110 uid = getuid();
1111 orig_euid = geteuid();
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);
1121 /* Set eUID to user */
1122 seteuid(uid);
1124 /* Obtain a list of decrypted secret keys */
1125 getsecrets();
1127 /* Keylogin user if not already done */
1128 if (mechs) {
1129 int mcount;
1131 for (mcount = 0; CURMECH; mcount++) {
1132 keylen_t keylen = CURMECH->keylen;
1133 algtype_t algtype = CURMECH->algtype;
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 :
1143 keylen, algtype);
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);
1155 /* Set eUID back to root */
1156 (void) seteuid(orig_euid);
1159 * Call getspnam() after the keylogin has been done so we have
1160 * the best chance of having read access to the encrypted pw.
1162 * The eUID must be 0 for the getspnam() so the name service
1163 * switch can handle the following eUID sensitive cases:
1165 * files/compat: read /etc/shadow
1168 if ((spw = getspnam(pw->pw_name)) == 0) {
1170 /* Set eUID back to user */
1171 (void) seteuid(uid);
1173 (void) fprintf(stderr,
1174 "%s: cannot find shadow entry for %s.\n",
1175 program_name, pw->pw_name);
1176 exit(1);
1179 /* Set eUID back to user */
1180 (void) seteuid(uid);
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);
1190 * force will be only supported for a while
1191 * -- it is NOT documented as of s1093
1193 if (force) {
1194 char *prompt = "Please enter New password:";
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);
1204 } else {
1206 * Reconsile rpc_pws and login_pw.
1208 * This function will either return with login_pw == rpc_pw
1209 * (and thus, the new pw to encrypt keys) or it will exit.
1211 cmp_passwd();
1214 if (makenew)
1215 makenewkeys();
1216 else
1217 getpublics();
1219 encryptkeys();
1221 storekeys();
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);
1234 } else {
1235 assert(slist[0]);
1236 write_rootkey(slist[0], "des", 192, 0);
1239 if (mechs) {
1240 for (mcount = 0; CURMECH; mcount++)
1241 keylogin(CURMECH->keylen,
1242 CURMECH->algtype);
1243 } else
1244 keylogin_des();
1246 return (0);