1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)register.c	1.12 (Berkeley) 09/06/90";
20 #endif /* not lint */
21 
22 #include <sys/types.h>
23 #include <sys/param.h>
24 #include <sys/time.h>
25 #include <sys/resource.h>
26 #include <sys/socket.h>
27 #include <sys/file.h>
28 #include <sys/signal.h>
29 #include <netinet/in.h>
30 #include <pwd.h>
31 #include <stdio.h>
32 #include <netdb.h>
33 #include <kerberosIV/des.h>
34 #include <kerberosIV/krb.h>
35 #include "pathnames.h"
36 #include "register_proto.h"
37 
38 #define	SERVICE	"krbupdate"	/* service to add to KDC's database */
39 #define	PROTO	"tcp"
40 
41 char	realm[REALM_SZ];
42 char	krbhst[MAX_HSTNM];
43 
44 static	char	pname[ANAME_SZ];
45 static	char	iname[INST_SZ];
46 static	char	password[_PASSWORD_LEN];
47 
48 /* extern char	*sys_errlist; */
49 int	die();
50 void	setup_key(), type_info(), cleanup();
51 
52 main(argc, argv)
53 	int	argc;
54 	char	**argv;
55 {
56 	struct servent	*se;
57 	struct hostent	*host;
58 	struct sockaddr_in	sin, local;
59 	int		rval;
60 	int		sock, llen;
61 	u_char		code;
62 	static struct rlimit rl = { 0, 0 };
63 
64 	signal(SIGPIPE, die);
65 
66 	if (setrlimit(RLIMIT_CORE, &rl) < 0) {
67 		perror("rlimit");
68 		exit(1);
69 	}
70 
71 	if ((se = getservbyname(SERVICE, PROTO)) == NULL) {
72 		fprintf(stderr, "couldn't find entry for service %s\n",
73 			SERVICE);
74 		exit(1);
75 	}
76 	if ((rval = krb_get_lrealm(realm,0)) != KSUCCESS) {
77 		fprintf(stderr, "couldn't get local Kerberos realm: %s\n",
78 			krb_err_txt[rval]);
79 		exit(1);
80 	}
81 
82 	if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) {
83 		fprintf(stderr, "couldn't get Kerberos host: %s\n",
84 			krb_err_txt[rval]);
85 		exit(1);
86 	}
87 
88 	if ((host = gethostbyname(krbhst)) == NULL) {
89 		fprintf(stderr, "couldn't get host entry for host %s\n",
90 			krbhst);
91 		exit(1);
92 	}
93 
94 	sin.sin_family = host->h_addrtype;
95 	(void)bcopy(host->h_addr, (char *) &sin.sin_addr, host->h_length);
96 	sin.sin_port = se->s_port;
97 
98 	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
99 		perror("socket");
100 		exit(1);
101 	}
102 
103 	if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
104 		perror("connect");
105 		(void)close(sock);
106 		exit(1);
107 	}
108 
109 	llen = sizeof(local);
110 	if (getsockname(sock, (struct sockaddr *) &local, &llen) < 0) {
111 		perror("getsockname");
112 		(void)close(sock);
113 		exit(1);
114 	}
115 
116 	setup_key(local);
117 
118 	type_info();
119 
120 	if (!get_user_info()) {
121 		code = ABORT;
122 		(void)des_write(sock, &code, 1);
123 		cleanup();
124 		exit(1);
125 	}
126 
127 	code = APPEND_DB;
128 	if (des_write(sock, &code, 1) != 1) {
129 		perror("write 1");
130 		cleanup();
131 		exit(1);
132 	}
133 
134 	if (des_write(sock, pname, ANAME_SZ) != ANAME_SZ) {
135 		perror("write principal name");
136 		cleanup();
137 		exit(1);
138 	}
139 
140 	if (des_write(sock, iname, INST_SZ) != INST_SZ) {
141 		perror("write instance name");
142 		cleanup();
143 		exit(1);
144 	}
145 
146 	if (des_write(sock, password, 255) != 255) {
147 		perror("write password");
148 		cleanup();
149 		exit(1);
150 	}
151 
152 	/* get return message */
153 
154 	{
155 		int	cc;
156 		char	msgbuf[BUFSIZ];
157 
158 		cc = read(sock, msgbuf, BUFSIZ);
159 		if (cc <= 0) {
160 			fprintf(stderr, "protocol error during key verification\n");
161 			cleanup();
162 			exit(1);
163 		}
164 		if (strncmp(msgbuf, GOTKEY_MSG, 6) != 0) {
165 			fprintf(stderr, "%s: %s", krbhst, msgbuf);
166 			cleanup();
167 			exit(1);
168 		}
169 
170 		cc = des_read(sock, msgbuf, BUFSIZ);
171 		if (cc <= 0) {
172 			fprintf(stderr, "protocol error during read\n");
173 			cleanup();
174 			exit(1);
175 		} else {
176 			printf("%s: %s", krbhst, msgbuf);
177 		}
178 	}
179 
180 	cleanup();
181 	(void)close(sock);
182 }
183 
184 void
185 cleanup()
186 {
187 	bzero(password, 255);
188 }
189 
190 extern	char	*crypt();
191 extern	char	*getpass();
192 
193 int
194 get_user_info()
195 {
196 	int	uid = getuid();
197 	int	valid = 0, i;
198 	struct	passwd	*pw;
199 	char	*pas, *namep;
200 
201 	/* NB: we must run setuid-root to get at the real pw file */
202 
203 	if ((pw = getpwuid(uid)) == NULL) {
204 		fprintf(stderr, "Who are you?\n");
205 		return(0);
206 	}
207 	(void)seteuid(uid);
208 	(void)strcpy(pname, pw->pw_name);	/* principal name */
209 
210 	for (i = 1; i < 3; i++) {
211 		pas = getpass("login password:");
212 		namep = crypt(pas, pw->pw_passwd);
213 		if (strcmp(namep, pw->pw_passwd)) {
214 			fprintf(stderr, "Password incorrect\n");
215 			continue;
216 		} else {
217 			valid = 1;
218 			break;
219 		}
220 	}
221 	if (!valid)
222 		return(0);
223 	pas = getpass("Kerberos password (may be the same):");
224 	while (*pas == NULL) {
225 		printf("<NULL> password not allowed\n");
226 		pas = getpass("Kerberos password (may be the same):");
227 	}
228 	(void)strcpy(password, pas);		/* password */
229 	pas = getpass("Retype Kerberos password:");
230 	if (strcmp(password, pas)) {
231 		fprintf(stderr, "Password mismatch -- aborted\n");
232 		return(0);
233 	}
234 
235 	iname[0] = NULL;	/* null instance name */
236 	return(1);
237 }
238 
239 void
240 setup_key(local)
241 	struct	sockaddr_in	local;
242 {
243 	static	struct	keyfile_data	kdata;
244 	static  Key_schedule		schedule;
245 	int	fd;
246 	char	namebuf[MAXPATHLEN];
247 	extern int errno;
248 
249 	(void) sprintf(namebuf, "%s%s",
250 		CLIENT_KEYFILE,
251 		inet_ntoa(local.sin_addr));
252 
253 	fd = open(namebuf, O_RDONLY);
254 	if (fd < 0) {
255 		fprintf(stderr, "couldn't open key file %s for local host: ",
256 			namebuf);
257 		perror("");
258 		exit(1);
259 	}
260 
261 	if (read(fd, (char *)&kdata, sizeof(kdata)) != sizeof(kdata)) {
262 		fprintf(stderr,"size error reading key file for local host %s\n",
263 			inet_ntoa(local.sin_addr));
264 		exit(1);
265 	}
266 	key_sched(kdata.kf_key, schedule);
267 	des_set_key(kdata.kf_key, schedule);
268 	return;
269 }
270 
271 void
272 type_info()
273 {
274 	printf("Kerberos user registration (realm %s)\n\n", realm);
275 	printf("Please enter your login password followed by your new Kerberos password.\n");
276 	printf("The Kerberos password you enter now will be used in the future\n");
277 	printf("as your Kerberos password for all machines in the %s realm.\n", realm);
278 	printf("You will only be allowed to perform this operation once, although you may run\n");
279 	printf("the %s program from now on to change your Kerberos password.\n\n", _PATH_KPASSWD);
280 }
281 
282 int
283 die()
284 {
285 	fprintf(stderr, "\nServer no longer listening\n");
286 	fflush(stderr);
287 	cleanup();
288 	exit(1);
289 }
290