dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / keyserv / chkey.c
blob15d554753d3c52f33a686b3ac1f0aa9fbf2e7c16
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 free(slist[mcount]);
302 hexkeylen = ((CURMECH->keylen / 8) * 2) + 1;
304 if (!(public = malloc(hexkeylen))) {
305 fprintf(stderr, "%s: Malloc failure.\n",
306 program_name);
307 exit(1);
309 if (!(secret = malloc(hexkeylen))) {
310 fprintf(stderr, "%s: Malloc failure.\n",
311 program_name);
312 exit(1);
315 if (!(__gen_dhkeys_g(public, secret, CURMECH->keylen,
316 CURMECH->algtype, short_login_pw))) {
317 /* Could not generate key pair */
318 fprintf(stderr,
319 "WARNING Could not generate key pair %s\n",
320 VALID_ALIAS(CURMECH->alias) ?
321 CURMECH->alias : "");
322 free(public);
323 free(secret);
324 public = NULL;
325 secret = NULL;
328 plist[mcount] = public;
329 slist[mcount] = secret;
331 } else {
332 char *public, *secret;
333 free(slist[0]);
335 if (!(public = malloc(HEXKEYBYTES + 1))) {
336 fprintf(stderr, "%s: Malloc failure.\n", program_name);
337 exit(1);
339 if (!(secret = malloc(HEXKEYBYTES + 1))) {
340 fprintf(stderr, "%s: Malloc failure.\n", program_name);
341 exit(1);
344 __gen_dhkeys(public, secret, short_login_pw);
346 plist[0] = public;
347 slist[0] = secret;
353 * Make sure that the entered Secure-RPC password(s) match the login
354 * password
356 static void
357 cmp_passwd()
359 char baseprompt[] = "Please enter the login password for";
360 char prompt[BUFSIZ];
361 char *en_login_pw = spw->sp_pwdp;
362 char short_en_login_pw[DESCREDPASSLEN + 1];
363 char *try_en_login_pw;
364 bool_t pwmatch = FALSE;
365 int done = 0, tries = 0, pcount;
367 snprintf(prompt, BUFSIZ, "%s %s:", baseprompt, pw->pw_name);
369 (void) strlcpy(short_en_login_pw, en_login_pw,
370 sizeof (short_en_login_pw));
372 if (en_login_pw && (strlen(en_login_pw) != 0)) {
373 for (pcount = 0; pcount < rpc_pw_count; pcount++) {
374 char *try_en_rpc_pw;
376 try_en_rpc_pw = crypt(rpc_pws[pcount], short_en_login_pw);
377 if (strcmp(try_en_rpc_pw, short_en_login_pw) == 0) {
378 login_pw = rpc_pws[pcount];
379 (void) strlcpy(short_login_pw, login_pw,
380 sizeof (short_login_pw));
381 pwmatch = TRUE;
382 break;
385 if (!pwmatch) {
386 /* pw don't match */
387 while (!done) {
388 /* ask for the pw */
389 login_pw = getpassphrase(prompt);
390 (void) strlcpy(short_login_pw, login_pw,
391 sizeof (short_login_pw));
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);
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);
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);
448 /* Prompt the user for a Secure-RPC password and store it in a cache. */
449 static void
450 getrpcpws(char *flavor)
452 char *cur_pw = NULL;
453 char prompt[BUFSIZ + 1];
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);
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);
472 rpc_pw_count++;
473 if (!(rpc_pws =
474 reallocarray(rpc_pws, rpc_pw_count, sizeof (char *)))) {
475 fprintf(stderr, "%s: Realloc failure.\n", program_name);
476 exit(1);
478 rpc_pws[rpc_pw_count - 1] = cur_pw;
482 /* Retrieve the secret key(s) for the user and attempt to decrypt them */
483 static void
484 getsecrets()
486 int mcount, scount = 0;
487 int tries = 0;
489 getrpcpws(NULL);
491 if (mechs) {
492 for (mcount = 0; CURMECH; mcount++) {
493 char *secret;
494 int pcount;
495 size_t hexkeylen;
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);
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;
512 if (secret[0] == 0)
513 continue;
514 else
515 break;
518 tries = 0;
519 getsecrets_tryagain_g:
520 if (secret[0] == 0) {
521 if (!tries) {
523 * No existing pw can decrypt
524 * secret key
526 getrpcpws(CURMECH->alias);
527 if (!getsecretkey_g(netname,
528 CURMECH->keylen,
529 CURMECH->algtype,
530 secret,
531 hexkeylen,
532 rpc_pws[pcount])) {
534 * Could not retreive
535 * secret key, abort
537 free(secret);
538 secret = NULL;
539 goto getsecrets_abort;
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);
558 } else
559 scount++;
561 getsecrets_abort:
562 slist[mcount] = secret;
564 } else {
565 char *secret = NULL;
567 if (!(secret = (char *)malloc(HEXKEYBYTES + 1))) {
568 fprintf(stderr, "%s: Malloc failure.\n", program_name);
569 exit(1);
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);
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);
596 slist[0] = secret;
597 return;
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);
610 /* Register AUTH_DES secret key with keyserv */
611 static void
612 keylogin_des()
614 char *secret = slist[0];
615 struct key_netstarg netst;
618 * try to revoke the existing key/credentials, assuming
619 * one exists. this will effectively mark "stale" any
620 * cached credientials...
622 if (key_setsecret(secret) < 0) {
623 return;
626 #ifdef NFS_AUTH
628 * it looks like a credential already existed, so try and
629 * revoke any lingering Secure-NFS privledges.
632 nra.authtype = AUTH_DES;
633 nra.uid = getuid();
635 if (_nfssys(NFS_REVAUTH, &nra) < 0)
636 perror("Warning: NFS credentials not destroyed");
637 #endif /* NFS_AUTH */
639 (void) memcpy(netst.st_priv_key, secret, HEXKEYBYTES);
641 netst.st_pub_key[0] = '\0';
642 netst.st_netname = strdup(netname);
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");
652 /* Register a secret key with the keyserv */
653 static void
654 keylogin(keylen_t keylen, algtype_t algtype)
656 int mcount;
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 : "");
674 } else {
675 if (keylen == 192 && algtype == 0)
676 keylogin_des();
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.
687 static char *
688 fgets_ignorenul(char *s, int n, FILE *stream)
690 int fildes = fileno(stream);
691 int i = 0;
692 int rs = 0;
693 char c;
695 if (fildes < 0)
696 return (NULL);
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);
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;
724 s[i] = '\0';
725 return (s);
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)
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;
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;
747 close(bakfd);
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;
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;
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;
776 hexkeybytes = ((keylen + 7) / 8) * 2;
778 while (fgets_ignorenul(line, MAXROOTKEY_LINE_LEN, bakfile)) {
779 if (sscanf(line, "%s %d", keyent, &atent) < 2) {
781 * No encryption algorithm found in the file
782 * (atent) so default to DES.
784 atent = AUTH_DES_ALGTYPE;
787 * 192-bit keys always go on the first line
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)) {
801 * Silently remove lines with the same
802 * keylen/algtype
804 if (gotit)
805 continue;
806 else
807 gotit = TRUE;
809 fprintf(rootfile, "%s %d\n", secret, algtype);
810 } else
811 fprintf(rootfile, "%s", line);
812 fflush(rootfile);
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);
826 fflush(rootfile);
827 fclose(rootfile);
828 fclose(bakfile);
829 unlink(ROOTKEY_FILE_BACKUP);
830 return;
832 rootkey_err:
833 fprintf(stderr, "WARNING: Could not write %s key to /etc/.rootkey\n",
834 flavor);
837 /* Store new key information in the specified name service */
838 static void
839 storekeys()
841 int mcount, ucount = 0;
842 char *ypmaster, *ypdomain = NULL, pkent[MAXPKENTLEN];
843 nis_name nis_princ;
846 /* Setup */
847 switch (dest_service) {
848 case PK_LDAP:
849 break;
850 case PK_YP:
851 yp_get_default_domain(&ypdomain);
852 if (yp_master(ypdomain, PKMAP, &ypmaster) != 0) {
853 fprintf(stderr,
854 "%s: cannot find master of NIS publickey database\n",
855 program_name);
856 exit(1);
858 fprintf(stdout,
859 "Sending key change request to %s ...\n", ypmaster);
860 break;
861 case PK_FILES:
862 if (geteuid() != 0) {
863 fprintf(stderr,
864 "%s: non-root users cannot change their key-pair in %s\n",
865 program_name, PKFILE);
866 exit(1);
868 break;
869 default:
870 fprintf(stderr,
871 "could not update; database %d unknown\n",
872 dest_service);
873 exit(1);
876 if (mechs) {
877 for (mcount = 0; CURMECH; mcount++) {
878 char authtype[MECH_MAXATNAME];
880 if (!plist[mcount] && !clist[mcount])
881 continue;
883 __nis_mechalias2authtype(CURMECH->alias, authtype,
884 MECH_MAXATNAME);
885 if (!authtype) {
886 fprintf(stderr,
887 "Could not generate auth_type for %s.\n",
888 CURMECH->alias);
889 continue;
892 snprintf(pkent, MAXPKENTLEN, "%s:%s:%d",
893 plist[mcount], clist[mcount],
894 CURMECH->algtype);
896 switch (dest_service) {
897 case PK_LDAP:
898 if (ldap_update(CURMECH->alias, netname,
899 plist[mcount], clist[mcount],
900 login_pw))
901 fprintf(stderr,
902 "%s: unable to update %s key in LDAP database\n",
903 program_name, authtype);
904 else
905 ucount++;
906 break;
908 case PK_YP:
909 /* Should never get here. */
910 break;
912 case PK_FILES:
913 /* Should never get here. */
914 break;
917 } else {
918 int status = 0;
920 assert(plist[0] && clist[0]);
921 snprintf(pkent, MAXPKENTLEN, "%s:%s", plist[0], clist[0]);
923 switch (dest_service) {
924 case PK_LDAP:
925 if (ldap_update("dh192-0", netname,
926 plist[0], clist[0],
927 login_pw)) {
928 fprintf(stderr,
929 "%s: unable to update %s key in LDAP database\n",
930 program_name);
931 exit(1);
933 break;
935 case PK_YP:
936 if (status = yp_update(ypdomain, PKMAP,
937 YPOP_STORE, netname,
938 strlen(netname), pkent,
939 strlen(pkent))) {
940 fprintf(stderr,
941 "%s: unable to update NIS database (%u): %s\n",
942 program_name, status,
943 yperr_string(status));
944 exit(1);
946 break;
948 case PK_FILES:
949 if (localupdate(netname, PKFILE, YPOP_STORE, pkent)) {
950 fprintf(stderr,
951 "%s: hence, unable to update publickey database\n",
952 program_name);
953 exit(1);
955 break;
957 default:
958 /* Should never get here */
959 assert(0);
961 return;
963 if (!ucount) {
964 fprintf(stderr, "%s: unable to update any key-pairs for %s.\n",
965 program_name, pw->pw_name);
966 exit(1);
970 void
971 addmechtolist(char *mechtype)
973 mechanism_t **realmechlist;
974 int i;
976 if (realmechlist = __nis_get_mechanisms(FALSE)) {
977 /* Match requested mech with list */
978 for (i = 0; realmechlist[i]; i++) {
979 if (realmechlist[i]->alias)
980 if (strcmp(realmechlist[i]->alias, mechtype)
981 == 0) {
983 * Match, add it to the mechs.
984 * Don't worry about qop or
985 * secserv since they are not
986 * used by chkey.
988 numspecmech++;
989 if ((mechs =
990 reallocarray(mechs, numspecmech + 1,
991 sizeof (mechanism_t *))) == NULL) {
992 perror("Can not change keys");
993 exit(1);
996 if ((mechs[numspecmech - 1] =
997 (mechanism_t *)malloc(
998 sizeof (mechanism_t))) == NULL) {
999 perror("Can not change keys");
1000 exit(1);
1002 if (realmechlist[i]->mechname)
1003 mechs[numspecmech - 1]->mechname =
1004 strdup(realmechlist[i]->mechname);
1005 if (realmechlist[i]->alias)
1006 mechs[numspecmech - 1]->alias =
1007 strdup(realmechlist[i]->alias);
1008 mechs[numspecmech - 1]->keylen =
1009 realmechlist[i]->keylen;
1010 mechs[numspecmech - 1]->algtype =
1011 realmechlist[i]->algtype;
1012 mechs[numspecmech] = NULL;
1013 __nis_release_mechanisms(realmechlist);
1014 return;
1018 fprintf(stderr,
1019 "WARNING: Mechanism '%s' not configured, skipping...\n",
1020 mechtype);
1021 __nis_release_mechanisms(realmechlist);
1022 return;
1024 fprintf(stderr,
1025 "WARNING: Mechanism '%s' not configured, skipping...\n",
1026 mechtype);
1031 main(int argc, char **argv)
1033 int c, mcount;
1034 uid_t uid;
1035 uid_t orig_euid;
1036 char *service = NULL;
1037 program_name = argv[0];
1039 mechs = __nis_get_mechanisms(FALSE);
1041 while ((c = getopt(argc, argv, "fps:m:")) != -1) {
1042 switch (c) {
1043 case 'f':
1045 * Not documented as of on1093.
1046 * Temporarily supported
1048 force++;
1049 break;
1050 case 'p':
1051 makenew = FALSE;
1052 break;
1053 case 's':
1054 if (!service)
1055 service = strdup(optarg);
1056 else
1057 usage();
1058 break;
1059 case 'm':
1060 if (mechs && specmech == FALSE) {
1061 __nis_release_mechanisms(mechs);
1062 mechs = NULL;
1064 specmech = TRUE;
1065 addmechtolist(optarg);
1066 break;
1067 default:
1068 usage();
1072 if (optind < argc)
1073 usage();
1075 dest_service = get_pk_source(service);
1077 if (!(netname = malloc(MAXNETNAMELEN + 1))) {
1078 fprintf(stderr, "%s: Malloc failure.\n", program_name);
1079 exit(1);
1081 if (!__getnetnamebyuid(netname, uid = getuid())) {
1082 fprintf(stderr, "%s: cannot generate netname for uid %d\n",
1083 program_name, uid);
1084 exit(1);
1086 sec_domain = strdup(strchr(netname, '@') + 1);
1087 getdomainname(local_domain, MAXNETNAMELEN);
1089 if (makenew)
1090 fprintf(stdout, "Generating new key for '%s'.\n", netname);
1091 else
1092 fprintf(stdout, "Reencrypting key for '%s'.\n", netname);
1094 if (mechs) {
1095 if (dest_service == PK_YP || dest_service == PK_FILES) {
1096 fprintf(stderr,
1097 "%s: can not add non-DES public keys to %s, skipping.\n",
1098 program_name, service);
1099 __nis_release_mechanisms(mechs);
1100 mechs = NULL;
1101 initkeylist(TRUE);
1102 } else
1103 initkeylist(FALSE);
1104 } else
1105 initkeylist(TRUE);
1107 uid = getuid();
1108 orig_euid = geteuid();
1110 /* Get password information */
1111 if ((pw = getpwuid(uid)) == NULL) {
1112 fprintf(stderr,
1113 "%s: Can not find passwd information for %d.\n",
1114 program_name, uid);
1115 exit(1);
1118 /* Set eUID to user */
1119 seteuid(uid);
1121 /* Obtain a list of decrypted secret keys */
1122 getsecrets();
1124 /* Keylogin user if not already done */
1125 if (mechs) {
1126 int mcount;
1128 for (mcount = 0; CURMECH; mcount++) {
1129 keylen_t keylen = CURMECH->keylen;
1130 algtype_t algtype = CURMECH->algtype;
1132 if (!key_secretkey_is_set_g(keylen, algtype) &&
1133 slist[mcount]) {
1134 keylogin(CURMECH->keylen, CURMECH->algtype);
1135 if ((uid == 0) && (makenew == FALSE))
1136 write_rootkey(slist[mcount],
1137 VALID_ALIAS(CURMECH->alias) ?
1138 CURMECH->alias :
1140 keylen, algtype);
1143 } else {
1144 assert(slist[0]);
1145 if (!key_secretkey_is_set()) {
1146 keylogin_des();
1147 if ((uid == 0) && (makenew == FALSE))
1148 write_rootkey(slist[0], "des", 192, 0);
1152 /* Set eUID back to root */
1153 (void) seteuid(orig_euid);
1156 * Call getspnam() after the keylogin has been done so we have
1157 * the best chance of having read access to the encrypted pw.
1159 * The eUID must be 0 for the getspnam() so the name service
1160 * switch can handle the following eUID sensitive cases:
1162 * files/compat: read /etc/shadow
1165 if ((spw = getspnam(pw->pw_name)) == 0) {
1167 /* Set eUID back to user */
1168 (void) seteuid(uid);
1170 (void) fprintf(stderr,
1171 "%s: cannot find shadow entry for %s.\n",
1172 program_name, pw->pw_name);
1173 exit(1);
1176 /* Set eUID back to user */
1177 (void) seteuid(uid);
1179 if (strcmp(spw->sp_pwdp, NOPWDRTR) == 0) {
1180 (void) fprintf(stderr,
1181 "%s: do not have read access to the passwd field for %s\n",
1182 program_name, pw->pw_name);
1183 exit(1);
1187 * force will be only supported for a while
1188 * -- it is NOT documented as of s1093
1190 if (force) {
1191 char *prompt = "Please enter New password:";
1193 login_pw = getpassphrase(prompt);
1194 (void) strlcpy(short_login_pw, login_pw,
1195 sizeof (short_login_pw));
1196 if (!login_pw || !(strlen(login_pw))) {
1197 fprintf(stderr, "%s: key-pair(s) unchanged for %s.\n",
1198 program_name, pw->pw_name);
1199 exit(1);
1201 } else {
1203 * Reconsile rpc_pws and login_pw.
1205 * This function will either return with login_pw == rpc_pw
1206 * (and thus, the new pw to encrypt keys) or it will exit.
1208 cmp_passwd();
1211 if (makenew)
1212 makenewkeys();
1213 else
1214 getpublics();
1216 encryptkeys();
1218 storekeys();
1220 if (makenew) {
1221 if (uid == 0) {
1222 if (mechs) {
1223 for (mcount = 0; CURMECH; mcount++) {
1224 if (!slist[mcount])
1225 continue;
1226 write_rootkey(slist[mcount],
1227 CURMECH->alias,
1228 CURMECH->keylen,
1229 CURMECH->algtype);
1231 } else {
1232 assert(slist[0]);
1233 write_rootkey(slist[0], "des", 192, 0);
1236 if (mechs) {
1237 for (mcount = 0; CURMECH; mcount++)
1238 keylogin(CURMECH->keylen,
1239 CURMECH->algtype);
1240 } else
1241 keylogin_des();
1243 return (0);