xref: /original-bsd/usr.bin/passwd/krb_passwd.c (revision f3f8e977)
1 /*-
2  * Copyright (c) 1990, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)krb_passwd.c	8.3 (Berkeley) 04/02/94";
10 #endif /* not lint */
11 
12 #ifdef KERBEROS
13 
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <sys/time.h>
17 #include <sys/resource.h>
18 #include <netinet/in.h>
19 #include <kerberosIV/des.h>
20 #include <kerberosIV/krb.h>
21 
22 #include <err.h>
23 #include <errno.h>
24 #include <netdb.h>
25 #include <pwd.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 #include "kpasswd_proto.h"
33 
34 #include "extern.h"
35 
36 #define	PROTO	"tcp"
37 
38 static void	send_update __P((int, char *, char *));
39 static void	recv_ack __P((int));
40 static void	cleanup __P((void));
41 static void	finish __P((void));
42 
43 static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 };
44 static struct kpasswd_data proto_data;
45 static des_cblock okey;
46 static Key_schedule osched;
47 static KTEXT_ST ticket;
48 static Key_schedule random_schedule;
49 static long authopts;
50 static char realm[REALM_SZ], krbhst[MAX_HSTNM];
51 static int sock;
52 
53 int
54 krb_passwd()
55 {
56 	struct servent *se;
57 	struct hostent *host;
58 	struct sockaddr_in sin;
59 	CREDENTIALS cred;
60 	fd_set readfds;
61 	int rval;
62 	char pass[_PASSWORD_LEN], password[_PASSWORD_LEN];
63 	static void finish();
64 
65 	static struct rlimit rl = { 0, 0 };
66 
67 	(void)signal(SIGHUP, SIG_IGN);
68 	(void)signal(SIGINT, SIG_IGN);
69 	(void)signal(SIGTSTP, SIG_IGN);
70 
71 	if (setrlimit(RLIMIT_CORE, &rl) < 0) {
72 		warn("setrlimit");
73 		return (1);
74 	}
75 
76 	if ((se = getservbyname(SERVICE, PROTO)) == NULL) {
77 		warnx("couldn't find entry for service %s/%s",
78 		    SERVICE, PROTO);
79 		return (1);
80 	}
81 
82 	if ((rval = krb_get_lrealm(realm,1)) != KSUCCESS) {
83 		warnx("couldn't get local Kerberos realm: %s",
84 		    krb_err_txt[rval]);
85 		return (1);
86 	}
87 
88 	if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) {
89 		warnx("couldn't get Kerberos host: %s",
90 		    krb_err_txt[rval]);
91 		return (1);
92 	}
93 
94 	if ((host = gethostbyname(krbhst)) == NULL) {
95 		warnx("couldn't get host entry for krb host %s",
96 		    krbhst);
97 		return (1);
98 	}
99 
100 	sin.sin_family = host->h_addrtype;
101 	memmove((char *) &sin.sin_addr, host->h_addr, host->h_length);
102 	sin.sin_port = se->s_port;
103 
104 	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
105 		warn("socket");
106 		return (1);
107 	}
108 
109 	if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
110 		warn("connect");
111 		(void)close(sock);
112 		return (1);
113 	}
114 
115 	rval = krb_sendauth(
116 		authopts,		/* NOT mutual */
117 		sock,
118 		&ticket,		/* (filled in) */
119 		SERVICE,
120 		krbhst,			/* instance (krbhst) */
121 		realm,			/* dest realm */
122 		(u_long) getpid(),	/* checksum */
123 		NULL,			/* msg data */
124 		NULL,			/* credentials */
125 		NULL,			/* schedule */
126 		NULL,			/* local addr */
127 		NULL,			/* foreign addr */
128 		"KPWDV0.1"
129 	);
130 
131 	if (rval != KSUCCESS) {
132 		warnx("Kerberos sendauth error: %s", krb_err_txt[rval]);
133 		return (1);
134 	}
135 
136 	krb_get_cred("krbtgt", realm, realm, &cred);
137 
138 	(void)printf("Changing Kerberos password for %s.%s@%s.\n",
139 	    cred.pname, cred.pinst, realm);
140 
141 	if (des_read_pw_string(pass,
142 	    sizeof(pass)-1, "Old Kerberos password:", 0)) {
143 		warnx("error reading old Kerberos password");
144 		return (1);
145 	}
146 
147 	(void)des_string_to_key(pass, okey);
148 	(void)des_key_sched(okey, osched);
149 	(void)des_set_key(okey, osched);
150 
151 	/* wait on the verification string */
152 
153 	FD_ZERO(&readfds);
154 	FD_SET(sock, &readfds);
155 
156 	rval =
157 	    select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout);
158 
159 	if ((rval < 1) || !FD_ISSET(sock, &readfds)) {
160 		if(rval == 0) {
161 			warnx("timed out (aborted)");
162 			cleanup();
163 			return (1);
164 		}
165 		warnx("select failed (aborted)");
166 		cleanup();
167 		return (1);
168 	}
169 
170 	/* read verification string */
171 
172 	if (des_read(sock, &proto_data, sizeof(proto_data)) !=
173 	    sizeof(proto_data)) {
174 		warnx("couldn't read verification string (aborted)");
175 		cleanup();
176 		return (1);
177 	}
178 
179 	(void)signal(SIGHUP, finish);
180 	(void)signal(SIGINT, finish);
181 
182 	if (strcmp(SECURE_STRING, proto_data.secure_msg) != 0) {
183 		cleanup();
184 		/* don't complain loud if user just hit return */
185 		if (pass == NULL || (!*pass))
186 			return (0);
187 		(void)fprintf(stderr, "Sorry\n");
188 		return (1);
189 	}
190 
191 	(void)des_key_sched(proto_data.random_key, random_schedule);
192 	(void)des_set_key(proto_data.random_key, random_schedule);
193 	(void)memset(pass, 0, sizeof(pass));
194 
195 	if (des_read_pw_string(pass,
196 	    sizeof(pass)-1, "New Kerberos password:", 0)) {
197 		warnx("error reading new Kerberos password (aborted)");
198 		cleanup();
199 		return (1);
200 	}
201 
202 	if (des_read_pw_string(password,
203 	    sizeof(password)-1, "Retype new Kerberos password:", 0)) {
204 		warnx("error reading new Kerberos password (aborted)");
205 		cleanup();
206 		return (1);
207 	}
208 
209 	if (strcmp(password, pass) != 0) {
210 		warnx("password mismatch (aborted)");
211 		cleanup();
212 		return (1);
213 	}
214 
215 	if (strlen(pass) == 0)
216 		(void)printf("using NULL password\n");
217 
218 	send_update(sock, password, SECURE_STRING);
219 
220 	/* wait for ACK */
221 
222 	FD_ZERO(&readfds);
223 	FD_SET(sock, &readfds);
224 
225 	rval =
226 	    select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout);
227 	if ((rval < 1) || !FD_ISSET(sock, &readfds)) {
228 		if(rval == 0) {
229 			warnx("timed out reading ACK (aborted)");
230 			cleanup();
231 			exit(1);
232 		}
233 		warnx("select failed (aborted)");
234 		cleanup();
235 		exit(1);
236 	}
237 	recv_ack(sock);
238 	cleanup();
239 	return (0);
240 }
241 
242 static void
243 send_update(dest, pwd, str)
244 	int dest;
245 	char *pwd, *str;
246 {
247 	static struct update_data ud;
248 
249 	(void)strncpy(ud.secure_msg, str, _PASSWORD_LEN);
250 	(void)strncpy(ud.pw, pwd, sizeof(ud.pw));
251 	if (des_write(dest, &ud, sizeof(ud)) != sizeof(ud)) {
252 		warnx("couldn't write pw update (abort)");
253 		memset((char *)&ud, 0, sizeof(ud));
254 		cleanup();
255 		exit(1);
256 	}
257 }
258 
259 static void
260 recv_ack(remote)
261 	int remote;
262 {
263 	int cc;
264 	char buf[BUFSIZ];
265 
266 	cc = des_read(remote, buf, sizeof(buf));
267 	if (cc <= 0) {
268 		warnx("error reading acknowledgement (aborted)");
269 		cleanup();
270 		exit(1);
271 	}
272 	(void)printf("%s", buf);
273 }
274 
275 static void
276 cleanup()
277 {
278 
279 	(void)memset((char *)&proto_data, 0, sizeof(proto_data));
280 	(void)memset((char *)okey, 0, sizeof(okey));
281 	(void)memset((char *)osched, 0, sizeof(osched));
282 	(void)memset((char *)random_schedule, 0, sizeof(random_schedule));
283 }
284 
285 static void
286 finish()
287 {
288 
289 	(void)close(sock);
290 	exit(1);
291 }
292 
293 #endif /* KERBEROS */
294