Merge from vendor branch LESS:
[dragonfly.git] / usr.bin / chkey / chkey.c
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user or with the express written consent of
8  * Sun Microsystems, Inc.
9  *
10  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13  *
14  * Sun RPC is provided with no support and without any obligation on the
15  * part of Sun Microsystems, Inc. to assist in its use, correction,
16  * modification or enhancement.
17  *
18  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20  * OR ANY PART THEREOF.
21  *
22  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23  * or profits or other special, indirect and consequential damages, even if
24  * Sun has been advised of the possibility of such damages.
25  *
26  * Sun Microsystems, Inc.
27  * 2550 Garcia Avenue
28  * Mountain View, California  94043
29  *
30  * $DragonFly: src/usr.bin/chkey/chkey.c,v 1.5 2005/01/11 00:51:11 joerg Exp $
31  * @(#)chkey.c 1.7 91/03/11 Copyr 1986 Sun Micro
32  */
33 /*
34  * Copyright (C) 1986, Sun Microsystems, Inc.
35  */
36
37 /*
38  * Command to change one's public key in the public key database
39  */
40 #include <sys/fcntl.h>
41 #include <pwd.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46
47 #include <rpc/rpc.h>
48 #include <rpc/key_prot.h>
49 #ifdef YP
50 #include <rpcsvc/yp_prot.h>
51 #include <rpcsvc/ypclnt.h>
52 #include <rpcsvc/yppasswd.h>
53 #else
54 #define YPOP_STORE      4
55 #endif
56
57 #include "externs.h"
58
59 #ifdef YPPASSWD
60 static struct passwd    *ypgetpwuid(uid_t);
61 #endif
62
63 #ifdef YP
64 static char *domain;
65 static char PKMAP[] = "publickey.byname";
66 #else
67 static char PKFILE[] = "/etc/publickey";
68 #endif  /* YP */
69 static char ROOTKEY[] = "/etc/.rootkey";
70
71 static void     usage(char *);
72 static int      setpublicmap(char *, char *, char *);
73
74 int
75 main(int argc, char **argv)
76 {
77         char name[MAXNETNAMELEN+1];
78         char public[HEXKEYBYTES + 1];
79         char secret[HEXKEYBYTES + 1];
80         char crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
81         char crypt2[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
82         int status;     
83         char *pass;
84         struct passwd *pw;
85         uid_t uid;
86         int force = 0;
87         char *self;
88 #ifdef YP
89         char *master;
90 #endif
91
92         self = argv[0];
93         for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
94                 if (argv[0][2] != 0) {
95                         usage(self);
96                 }
97                 switch (argv[0][1]) {
98                 case 'f':
99                         force = 1;
100                         break;
101                 default:
102                         usage(self);
103                 }
104         }
105         if (argc != 0) {
106                 usage(self);
107         }
108
109 #ifdef YP
110         (void)yp_get_default_domain(&domain);
111         if (yp_master(domain, PKMAP, &master) != 0) {
112                 (void)fprintf(stderr, 
113                         "can't find master of publickey database\n");
114                 exit(1);
115         }
116 #endif
117         uid = getuid() /*geteuid()*/;
118         if (uid == 0) {
119                 if (host2netname(name, NULL, NULL) == 0) {
120                         (void)fprintf(stderr,
121                         "chkey: cannot convert hostname to netname\n");
122                         exit(1);
123                 }
124         } else {
125                 if (user2netname(name, uid, NULL) == 0) {
126                         (void)fprintf(stderr,
127                         "chkey: cannot convert username to netname\n");
128                         exit(1);
129                 }
130         }
131         (void)printf("Generating new key for %s.\n", name);
132
133         if (!force) {
134                 if (uid != 0) {
135 #ifdef YPPASSWD
136                         pw = ypgetpwuid(uid);
137 #else
138                         pw = getpwuid(uid);
139 #endif
140                         if (pw == NULL) {
141 #ifdef YPPASSWD
142                                 (void)fprintf(stderr, 
143                 "No NIS password entry found: can't change key.\n");
144 #else
145                                 (void)fprintf(stderr,
146                 "No password entry found: can't change key.\n");
147 #endif
148                                 exit(1);
149                         }
150                 } else {
151                         pw = getpwuid(0);
152                         if (pw == NULL) {
153                                 (void)fprintf(stderr, 
154                                 "No password entry found: can't change key.\n");
155                                 exit(1);
156                         }
157                 }
158         }
159         pass = getpass("Password:");
160 #ifdef YPPASSWD
161         if (!force) {
162                 if (strcmp(crypt(pass, pw->pw_passwd), pw->pw_passwd) != 0) {
163                         (void)fprintf(stderr, "Invalid password.\n");
164                         exit(1);
165                 }
166         }
167 #else
168         force = 1;      /* Make this mandatory */
169 #endif
170         genkeys(public, secret, pass);  
171
172         memcpy(crypt1, secret, HEXKEYBYTES);
173         memcpy(crypt1 + HEXKEYBYTES, secret, KEYCHECKSUMSIZE);
174         crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0;
175         xencrypt(crypt1, pass);
176
177         if (force) {
178                 memcpy(crypt2, crypt1, HEXKEYBYTES + KEYCHECKSUMSIZE + 1);      
179                 xdecrypt(crypt2, getpass("Retype password:"));
180                 if (memcmp(crypt2, crypt2 + HEXKEYBYTES, KEYCHECKSUMSIZE) != 0 ||
181                     memcmp(crypt2, secret, HEXKEYBYTES) != 0) { 
182                         (void)fprintf(stderr, "Password incorrect.\n");
183                         exit(1);
184                 }
185         }
186
187 #ifdef YP
188         (void)printf("Sending key change request to %s...\n", master);
189 #endif
190         status = setpublicmap(name, public, crypt1);
191         if (status != 0) {
192 #ifdef YP
193                 (void)fprintf(stderr,
194                 "%s: unable to update NIS database (%u): %s\n",
195                                 self, status, yperr_string(status));
196 #else
197                 (void)fprintf(stderr,
198                 "%s: unable to update publickey database\n", self);
199 #endif
200                 exit(1);
201         }
202
203         if (uid == 0) {
204                 /*
205                  * Root users store their key in /etc/$ROOTKEY so
206                  * that they can auto reboot without having to be
207                  * around to type a password. Storing this in a file
208                  * is rather dubious: it should really be in the EEPROM
209                  * so it does not go over the net.
210                  */
211                 int fd;
212
213                 fd = open(ROOTKEY, O_WRONLY|O_TRUNC|O_CREAT, 0);
214                 if (fd < 0) {
215                         perror(ROOTKEY);
216                 } else {
217                         char newline = '\n';
218
219                         if (write(fd, secret, strlen(secret)) < 0 ||
220                             write(fd, &newline, sizeof(newline)) < 0) {
221                                 (void)fprintf(stderr, "%s: ", ROOTKEY);
222                                 perror("write");
223                         }
224                 }
225         }
226
227         if (key_setsecret(secret) < 0) {
228                 (void)printf("Unable to login with new secret key.\n");
229                 exit(1);
230         }
231         (void)printf("Done.\n");
232         exit(0);
233         /* NOTREACHED */
234 }
235
236 static void
237 usage(char *name)
238 {
239         (void)fprintf(stderr, "usage: %s [-f]\n", name);
240         exit(1);
241         /* NOTREACHED */
242 }
243
244
245 /*
246  * Set the entry in the public key file
247  */
248 static int
249 setpublicmap(char *name, char *public, char *secret)
250 {
251         char pkent[1024];
252         
253         (void)sprintf(pkent,"%s:%s", public, secret);
254 #ifdef YP
255         return (yp_update(domain, PKMAP, YPOP_STORE,
256                 name, strlen(name), pkent, strlen(pkent)));
257 #else
258         return (localupdate(name, PKFILE, YPOP_STORE,
259                 strlen(name), name, strlen(pkent), pkent));
260 #endif
261 }
262
263 #ifdef YPPASSWD
264 static struct passwd *
265 ypgetpwuid(uid_t uid)
266 {
267         char uidstr[10];
268         char *val;
269         int vallen;
270         static struct passwd pw;
271         char *p;
272
273         (void)sprintf(uidstr, "%d", uid);
274         if (yp_match(domain, "passwd.byuid", uidstr, strlen(uidstr), 
275                         &val, &vallen) != 0) {
276                 return (NULL);
277         }
278         p = strchr(val, ':');
279         if (p == NULL) {        
280                 return (NULL);
281         }
282         pw.pw_passwd = p + 1;
283         p = strchr(pw.pw_passwd, ':');
284         if (p == NULL) {
285                 return (NULL);
286         }
287         *p = 0;
288         return (&pw);
289 }
290 #endif  /* YPPASSWD */