Use strchr instead of index, and strrchr instead of rindex because the str*chr
[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.4 2004/08/30 18:06:49 eirikn 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 <stdio.h>
41 #include <rpc/rpc.h>
42 #include <rpc/key_prot.h>
43 #ifdef YP
44 #include <rpcsvc/yp_prot.h>
45 #include <rpcsvc/ypclnt.h>
46 #else
47 #define YPOP_STORE      4
48 #endif
49 #include <pwd.h>
50 #include <string.h>
51 #include <sys/fcntl.h>
52
53 extern char *getpass();
54 #define index strchr
55 extern char *crypt();
56 #ifdef YPPASSWD
57 struct passwd *ypgetpwuid();
58 #endif
59
60 #ifdef YP
61 static char *domain;
62 static char PKMAP[] = "publickey.byname";
63 #else
64 static char PKFILE[] = "/etc/publickey";
65 #endif  /* YP */
66 static char ROOTKEY[] = "/etc/.rootkey";
67
68 main(int argc, char **argv)
69 {
70         char name[MAXNETNAMELEN+1];
71         char public[HEXKEYBYTES + 1];
72         char secret[HEXKEYBYTES + 1];
73         char crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
74         char crypt2[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
75         int status;     
76         char *pass;
77         struct passwd *pw;
78         uid_t uid;
79         int force = 0;
80         char *self;
81 #ifdef YP
82         char *master;
83 #endif
84
85         self = argv[0];
86         for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
87                 if (argv[0][2] != 0) {
88                         usage(self);
89                 }
90                 switch (argv[0][1]) {
91                 case 'f':
92                         force = 1;
93                         break;
94                 default:
95                         usage(self);
96                 }
97         }
98         if (argc != 0) {
99                 usage(self);
100         }
101
102 #ifdef YP
103         (void)yp_get_default_domain(&domain);
104         if (yp_master(domain, PKMAP, &master) != 0) {
105                 (void)fprintf(stderr, 
106                         "can't find master of publickey database\n");
107                 exit(1);
108         }
109 #endif
110         uid = getuid() /*geteuid()*/;
111         if (uid == 0) {
112                 if (host2netname(name, NULL, NULL) == 0) {
113                         (void)fprintf(stderr,
114                         "chkey: cannot convert hostname to netname\n");
115                         exit(1);
116                 }
117         } else {
118                 if (user2netname(name, uid, NULL) == 0) {
119                         (void)fprintf(stderr,
120                         "chkey: cannot convert username to netname\n");
121                         exit(1);
122                 }
123         }
124         (void)printf("Generating new key for %s.\n", name);
125
126         if (!force) {
127                 if (uid != 0) {
128 #ifdef YPPASSWD
129                         pw = ypgetpwuid(uid);
130 #else
131                         pw = getpwuid(uid);
132 #endif
133                         if (pw == NULL) {
134 #ifdef YPPASSWD
135                                 (void)fprintf(stderr, 
136                 "No NIS password entry found: can't change key.\n");
137 #else
138                                 (void)fprintf(stderr,
139                 "No password entry found: can't change key.\n");
140 #endif
141                                 exit(1);
142                         }
143                 } else {
144                         pw = getpwuid(0);
145                         if (pw == NULL) {
146                                 (void)fprintf(stderr, 
147                                 "No password entry found: can't change key.\n");
148                                 exit(1);
149                         }
150                 }
151         }
152         pass = getpass("Password:");
153 #ifdef YPPASSWD
154         if (!force) {
155                 if (strcmp(crypt(pass, pw->pw_passwd), pw->pw_passwd) != 0) {
156                         (void)fprintf(stderr, "Invalid password.\n");
157                         exit(1);
158                 }
159         }
160 #else
161         force = 1;      /* Make this mandatory */
162 #endif
163         genkeys(public, secret, pass);  
164
165         memcpy(crypt1, secret, HEXKEYBYTES);
166         memcpy(crypt1 + HEXKEYBYTES, secret, KEYCHECKSUMSIZE);
167         crypt1[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0;
168         xencrypt(crypt1, pass);
169
170         if (force) {
171                 memcpy(crypt2, crypt1, HEXKEYBYTES + KEYCHECKSUMSIZE + 1);      
172                 xdecrypt(crypt2, getpass("Retype password:"));
173                 if (memcmp(crypt2, crypt2 + HEXKEYBYTES, KEYCHECKSUMSIZE) != 0 ||
174                     memcmp(crypt2, secret, HEXKEYBYTES) != 0) { 
175                         (void)fprintf(stderr, "Password incorrect.\n");
176                         exit(1);
177                 }
178         }
179
180 #ifdef YP
181         (void)printf("Sending key change request to %s...\n", master);
182 #endif
183         status = setpublicmap(name, public, crypt1);
184         if (status != 0) {
185 #ifdef YP
186                 (void)fprintf(stderr,
187                 "%s: unable to update NIS database (%u): %s\n",
188                                 self, status, yperr_string(status));
189 #else
190                 (void)fprintf(stderr,
191                 "%s: unable to update publickey database\n", self);
192 #endif
193                 exit(1);
194         }
195
196         if (uid == 0) {
197                 /*
198                  * Root users store their key in /etc/$ROOTKEY so
199                  * that they can auto reboot without having to be
200                  * around to type a password. Storing this in a file
201                  * is rather dubious: it should really be in the EEPROM
202                  * so it does not go over the net.
203                  */
204                 int fd;
205
206                 fd = open(ROOTKEY, O_WRONLY|O_TRUNC|O_CREAT, 0);
207                 if (fd < 0) {
208                         perror(ROOTKEY);
209                 } else {
210                         char newline = '\n';
211
212                         if (write(fd, secret, strlen(secret)) < 0 ||
213                             write(fd, &newline, sizeof(newline)) < 0) {
214                                 (void)fprintf(stderr, "%s: ", ROOTKEY);
215                                 perror("write");
216                         }
217                 }
218         }
219
220         if (key_setsecret(secret) < 0) {
221                 (void)printf("Unable to login with new secret key.\n");
222                 exit(1);
223         }
224         (void)printf("Done.\n");
225         exit(0);
226         /* NOTREACHED */
227 }
228
229 usage(char *name)
230 {
231         (void)fprintf(stderr, "usage: %s [-f]\n", name);
232         exit(1);
233         /* NOTREACHED */
234 }
235
236
237 /*
238  * Set the entry in the public key file
239  */
240 setpublicmap(char *name, char *public, char *secret)
241 {
242         char pkent[1024];
243         
244         (void)sprintf(pkent,"%s:%s", public, secret);
245 #ifdef YP
246         return (yp_update(domain, PKMAP, YPOP_STORE,
247                 name, strlen(name), pkent, strlen(pkent)));
248 #else
249         return (localupdate(name, PKFILE, YPOP_STORE,
250                 strlen(name), name, strlen(pkent), pkent));
251 #endif
252 }
253
254 #ifdef YPPASSWD
255 struct passwd *
256 ypgetpwuid(uid_t uid)
257 {
258         char uidstr[10];
259         char *val;
260         int vallen;
261         static struct passwd pw;
262         char *p;
263
264         (void)sprintf(uidstr, "%d", uid);
265         if (yp_match(domain, "passwd.byuid", uidstr, strlen(uidstr), 
266                         &val, &vallen) != 0) {
267                 return (NULL);
268         }
269         p = strchr(val, ':');
270         if (p == NULL) {        
271                 return (NULL);
272         }
273         pw.pw_passwd = p + 1;
274         p = strchr(pw.pw_passwd, ':');
275         if (p == NULL) {
276                 return (NULL);
277         }
278         *p = 0;
279         return (&pw);
280 }
281 #endif  /* YPPASSWD */