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
krb_passwd()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
send_update(dest,pwd,str)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
recv_ack(remote)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
cleanup()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
finish()286 finish()
287 {
288
289 (void)close(sock);
290 exit(1);
291 }
292
293 #endif /* KERBEROS */
294