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