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