1 | /* |
---|
2 | * This file replaces some of the routines in the Kerberos utilities. |
---|
3 | * It is based on the Kerberos library modules: |
---|
4 | * send_to_kdc.c |
---|
5 | * |
---|
6 | * Copyright 1987, 1988, 1992 by the Massachusetts Institute of Technology. |
---|
7 | * |
---|
8 | * For copying and distribution information, please see the file |
---|
9 | * <mit-copyright.h>. |
---|
10 | */ |
---|
11 | |
---|
12 | #ifndef lint |
---|
13 | static char rcsid_send_to_kdc_c[] = |
---|
14 | "$Header: /afs/dev.mit.edu/source/repository/athena/bin/aklog/krb_util.c,v 1.2 1992-12-11 13:26:12 probe Exp $"; |
---|
15 | #endif /* lint */ |
---|
16 | |
---|
17 | #include <mit-copyright.h> |
---|
18 | |
---|
19 | #include <krb.h> |
---|
20 | #include <stdio.h> |
---|
21 | #include <errno.h> |
---|
22 | #include <sys/time.h> |
---|
23 | #include <sys/types.h> |
---|
24 | #ifdef lint |
---|
25 | #include <sys/uio.h> /* struct iovec to make lint happy */ |
---|
26 | #endif /* lint */ |
---|
27 | #include <sys/socket.h> |
---|
28 | #include <netinet/in.h> |
---|
29 | #include <netdb.h> |
---|
30 | #include <strings.h> |
---|
31 | |
---|
32 | #include <afs/param.h> |
---|
33 | #include <afs/cellconfig.h> |
---|
34 | |
---|
35 | #define S_AD_SZ sizeof(struct sockaddr_in) |
---|
36 | |
---|
37 | extern int errno; |
---|
38 | extern int krb_debug; |
---|
39 | |
---|
40 | extern char *malloc(), *calloc(), *realloc(); |
---|
41 | |
---|
42 | int krb_udp_port = 0; |
---|
43 | |
---|
44 | /* CLIENT_KRB_TIMEOUT indicates the time to wait before |
---|
45 | * retrying a server. It's defined in "krb.h". |
---|
46 | */ |
---|
47 | static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0}; |
---|
48 | static char *prog = "send_to_kdc"; |
---|
49 | static send_recv(); |
---|
50 | |
---|
51 | /* |
---|
52 | * This file contains two routines, send_to_kdc() and send_recv(). |
---|
53 | * send_recv() is a static routine used by send_to_kdc(). |
---|
54 | */ |
---|
55 | |
---|
56 | /* |
---|
57 | * send_to_kdc() sends a message to the Kerberos authentication |
---|
58 | * server(s) in the given realm and returns the reply message. |
---|
59 | * The "pkt" argument points to the message to be sent to Kerberos; |
---|
60 | * the "rpkt" argument will be filled in with Kerberos' reply. |
---|
61 | * The "realm" argument indicates the realm of the Kerberos server(s) |
---|
62 | * to transact with. If the realm is null, the local realm is used. |
---|
63 | * |
---|
64 | * If more than one Kerberos server is known for a given realm, |
---|
65 | * different servers will be queried until one of them replies. |
---|
66 | * Several attempts (retries) are made for each server before |
---|
67 | * giving up entirely. |
---|
68 | * |
---|
69 | * If an answer was received from a Kerberos host, KSUCCESS is |
---|
70 | * returned. The following errors can be returned: |
---|
71 | * |
---|
72 | * SKDC_CANT - can't get local realm |
---|
73 | * - can't find "kerberos" in /etc/services database |
---|
74 | * - can't open socket |
---|
75 | * - can't bind socket |
---|
76 | * - all ports in use |
---|
77 | * - couldn't find any Kerberos host |
---|
78 | * |
---|
79 | * SKDC_RETRY - couldn't get an answer from any Kerberos server, |
---|
80 | * after several retries |
---|
81 | */ |
---|
82 | |
---|
83 | send_to_kdc(pkt,rpkt,realm) |
---|
84 | KTEXT pkt; |
---|
85 | KTEXT rpkt; |
---|
86 | char *realm; |
---|
87 | { |
---|
88 | int i, f; |
---|
89 | int no_host; /* was a kerberos host found? */ |
---|
90 | int retry; |
---|
91 | int n_hosts; |
---|
92 | int retval; |
---|
93 | struct sockaddr_in to; |
---|
94 | struct hostent *host, *hostlist; |
---|
95 | char *cp; |
---|
96 | char krbhst[MAX_HSTNM]; |
---|
97 | char lrealm[REALM_SZ]; |
---|
98 | |
---|
99 | /* |
---|
100 | * If "realm" is non-null, use that, otherwise get the |
---|
101 | * local realm. |
---|
102 | */ |
---|
103 | if (realm) |
---|
104 | (void) strcpy(lrealm, realm); |
---|
105 | else |
---|
106 | if (krb_get_lrealm(lrealm,1)) { |
---|
107 | if (krb_debug) |
---|
108 | fprintf(stderr, "%s: can't get local realm\n", prog); |
---|
109 | return(SKDC_CANT); |
---|
110 | } |
---|
111 | if (krb_debug) |
---|
112 | printf("lrealm is %s\n", lrealm); |
---|
113 | if (krb_udp_port == 0) { |
---|
114 | register struct servent *sp; |
---|
115 | if ((sp = getservbyname("kerberos","udp")) == 0) { |
---|
116 | if (krb_debug) |
---|
117 | fprintf(stderr, "%s: Can't get kerberos/udp service\n", |
---|
118 | prog); |
---|
119 | return(SKDC_CANT); |
---|
120 | } |
---|
121 | krb_udp_port = sp->s_port; |
---|
122 | if (krb_debug) |
---|
123 | printf("krb_udp_port is %d\n", krb_udp_port); |
---|
124 | } |
---|
125 | bzero((char *)&to, S_AD_SZ); |
---|
126 | hostlist = (struct hostent *) malloc(sizeof(struct hostent)); |
---|
127 | if (!hostlist) |
---|
128 | return (/*errno */SKDC_CANT); |
---|
129 | if ((f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
---|
130 | if (krb_debug) |
---|
131 | fprintf(stderr,"%s: Can't open socket\n", prog); |
---|
132 | return(SKDC_CANT); |
---|
133 | } |
---|
134 | /* from now on, exit through rtn label for cleanup */ |
---|
135 | |
---|
136 | no_host = 1; |
---|
137 | /* get an initial allocation */ |
---|
138 | n_hosts = 0; |
---|
139 | for (i = 1; krb_get_krbhst(krbhst, lrealm, i) == KSUCCESS; ++i) { |
---|
140 | if (krb_debug) { |
---|
141 | printf("Getting host entry for %s...",krbhst); |
---|
142 | (void) fflush(stdout); |
---|
143 | } |
---|
144 | host = gethostbyname(krbhst); |
---|
145 | if (krb_debug) { |
---|
146 | printf("%s.\n", |
---|
147 | host ? "Got it" : "Didn't get it"); |
---|
148 | (void) fflush(stdout); |
---|
149 | } |
---|
150 | if (!host) |
---|
151 | continue; |
---|
152 | no_host = 0; /* found at least one */ |
---|
153 | n_hosts++; |
---|
154 | /* preserve host network address to check later |
---|
155 | * (would be better to preserve *all* addresses, |
---|
156 | * take care of that later) |
---|
157 | */ |
---|
158 | hostlist = (struct hostent *) |
---|
159 | realloc((char *)hostlist, |
---|
160 | (unsigned) |
---|
161 | sizeof(struct hostent)*(n_hosts+1)); |
---|
162 | if (!hostlist) |
---|
163 | return /*errno */SKDC_CANT; |
---|
164 | bcopy((char *)host, (char *)&hostlist[n_hosts-1], |
---|
165 | sizeof(struct hostent)); |
---|
166 | host = &hostlist[n_hosts-1]; |
---|
167 | cp = malloc((unsigned)host->h_length); |
---|
168 | if (!cp) { |
---|
169 | retval = /*errno */SKDC_CANT; |
---|
170 | goto rtn; |
---|
171 | } |
---|
172 | bcopy((char *)host->h_addr, cp, host->h_length); |
---|
173 | /* At least Sun OS version 3.2 (or worse) and Ultrix version 2.2 |
---|
174 | (or worse) only return one name ... */ |
---|
175 | #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) |
---|
176 | host->h_addr_list = (char **)malloc(sizeof(char *)); |
---|
177 | if (!host->h_addr_list) { |
---|
178 | retval = /*errno */SKDC_CANT; |
---|
179 | goto rtn; |
---|
180 | } |
---|
181 | #endif /* ULTRIX022 || SunOS */ |
---|
182 | host->h_addr = cp; |
---|
183 | bzero((char *)&hostlist[n_hosts], |
---|
184 | sizeof(struct hostent)); |
---|
185 | to.sin_family = host->h_addrtype; |
---|
186 | bcopy(host->h_addr, (char *)&to.sin_addr, |
---|
187 | host->h_length); |
---|
188 | to.sin_port = krb_udp_port; |
---|
189 | if (send_recv(pkt, rpkt, f, &to, hostlist)) { |
---|
190 | retval = KSUCCESS; |
---|
191 | goto rtn; |
---|
192 | } |
---|
193 | if (krb_debug) { |
---|
194 | printf("Timeout, error, or wrong descriptor\n"); |
---|
195 | (void) fflush(stdout); |
---|
196 | } |
---|
197 | } |
---|
198 | /* retry each host in sequence */ |
---|
199 | for (retry = 0; retry < CLIENT_KRB_RETRY; ++retry) { |
---|
200 | extern struct afsconf_cell cellconfig; |
---|
201 | |
---|
202 | if (!no_host) { |
---|
203 | for (host = hostlist; host->h_name != (char *)NULL; host++) { |
---|
204 | to.sin_family = host->h_addrtype; |
---|
205 | bcopy(host->h_addr, (char *)&to.sin_addr, |
---|
206 | host->h_length); |
---|
207 | if (send_recv(pkt, rpkt, f, &to, hostlist)) { |
---|
208 | retval = KSUCCESS; |
---|
209 | goto rtn; |
---|
210 | } |
---|
211 | } |
---|
212 | } else { |
---|
213 | for (i=0; i<cellconfig.numServers; i++) { |
---|
214 | to.sin_family = cellconfig.hostAddr[i].sin_family; |
---|
215 | to.sin_addr = cellconfig.hostAddr[i].sin_addr; |
---|
216 | to.sin_port = krb_udp_port; |
---|
217 | if (send_recv(pkt, rpkt, f, &to, (struct hostent *)0)) { |
---|
218 | retval = KSUCCESS; |
---|
219 | goto rtn; |
---|
220 | } |
---|
221 | } |
---|
222 | } |
---|
223 | } |
---|
224 | retval = SKDC_RETRY; |
---|
225 | rtn: |
---|
226 | (void) close(f); |
---|
227 | if (hostlist) { |
---|
228 | if (no_host) { |
---|
229 | free((char *)hostlist); |
---|
230 | } |
---|
231 | else { |
---|
232 | register struct hostent *hp; |
---|
233 | for (hp = hostlist; hp->h_name; hp++) |
---|
234 | #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) |
---|
235 | if (hp->h_addr_list) { |
---|
236 | #endif /* ULTRIX022 || SunOS */ |
---|
237 | if (hp->h_addr) |
---|
238 | free(hp->h_addr); |
---|
239 | #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) |
---|
240 | free((char *)hp->h_addr_list); |
---|
241 | } |
---|
242 | #endif /* ULTRIX022 || SunOS */ |
---|
243 | free((char *)hostlist); |
---|
244 | } |
---|
245 | } |
---|
246 | return(retval); |
---|
247 | } |
---|
248 | |
---|
249 | /* |
---|
250 | * try to send out and receive message. |
---|
251 | * return 1 on success, 0 on failure |
---|
252 | */ |
---|
253 | |
---|
254 | static send_recv(pkt,rpkt,f,_to,addrs) |
---|
255 | KTEXT pkt; |
---|
256 | KTEXT rpkt; |
---|
257 | int f; |
---|
258 | struct sockaddr_in *_to; |
---|
259 | struct hostent *addrs; |
---|
260 | { |
---|
261 | fd_set readfds; |
---|
262 | register struct hostent *hp; |
---|
263 | struct sockaddr_in from; |
---|
264 | int sin_size; |
---|
265 | int numsent; |
---|
266 | |
---|
267 | if (krb_debug) { |
---|
268 | if (_to->sin_family == AF_INET) |
---|
269 | printf("Sending message to %s...", |
---|
270 | inet_ntoa(_to->sin_addr)); |
---|
271 | else |
---|
272 | printf("Sending message..."); |
---|
273 | (void) fflush(stdout); |
---|
274 | } |
---|
275 | if ((numsent = sendto(f,(char *)(pkt->dat), pkt->length, 0, |
---|
276 | (struct sockaddr *)_to, |
---|
277 | S_AD_SZ)) != pkt->length) { |
---|
278 | if (krb_debug) |
---|
279 | printf("sent only %d/%d\n",numsent, pkt->length); |
---|
280 | return 0; |
---|
281 | } |
---|
282 | if (krb_debug) { |
---|
283 | printf("Sent\nWaiting for reply..."); |
---|
284 | (void) fflush(stdout); |
---|
285 | } |
---|
286 | FD_ZERO(&readfds); |
---|
287 | FD_SET(f, &readfds); |
---|
288 | errno = 0; |
---|
289 | /* select - either recv is ready, or timeout */ |
---|
290 | /* see if timeout or error or wrong descriptor */ |
---|
291 | if (select(f + 1, &readfds, (fd_set *)0, (fd_set *)0, &timeout) < 1 |
---|
292 | || !FD_ISSET(f, &readfds)) { |
---|
293 | if (krb_debug) { |
---|
294 | fprintf(stderr, "select failed: readfds=%x", |
---|
295 | readfds); |
---|
296 | perror(""); |
---|
297 | } |
---|
298 | return 0; |
---|
299 | } |
---|
300 | sin_size = sizeof(from); |
---|
301 | if (recvfrom(f, (char *)(rpkt->dat), sizeof(rpkt->dat), 0, |
---|
302 | (struct sockaddr *)&from, &sin_size) |
---|
303 | < 0) { |
---|
304 | if (krb_debug) |
---|
305 | perror("recvfrom"); |
---|
306 | return 0; |
---|
307 | } |
---|
308 | if (krb_debug) { |
---|
309 | printf("received packet from %s\n", inet_ntoa(from.sin_addr)); |
---|
310 | fflush(stdout); |
---|
311 | } |
---|
312 | if (addrs) { |
---|
313 | for (hp = addrs; hp->h_name != (char *)NULL; hp++) { |
---|
314 | if (!bcmp(hp->h_addr, (char *)&from.sin_addr.s_addr, |
---|
315 | hp->h_length)) { |
---|
316 | if (krb_debug) { |
---|
317 | printf("Received it\n"); |
---|
318 | (void) fflush(stdout); |
---|
319 | } |
---|
320 | return 1; |
---|
321 | } |
---|
322 | if (krb_debug) |
---|
323 | fprintf(stderr, |
---|
324 | "packet not from %x\n", |
---|
325 | hp->h_addr); |
---|
326 | } |
---|
327 | } else { |
---|
328 | /* Only permit a response from the host we sent the packet to, |
---|
329 | * since we have not specified any alternate addresses. */ |
---|
330 | if (!bcmp(&from.sin_addr.s_addr, &_to->sin_addr.s_addr, |
---|
331 | sizeof(from.sin_addr.s_addr))) { |
---|
332 | if (krb_debug) { |
---|
333 | printf("Received it\n"); |
---|
334 | (void) fflush(stdout); |
---|
335 | } |
---|
336 | return 1; |
---|
337 | } |
---|
338 | } |
---|
339 | if (krb_debug) |
---|
340 | fprintf(stderr, "%s: received packet from wrong host! (%x)\n", |
---|
341 | "send_to_kdc(send_rcv)", from.sin_addr.s_addr); |
---|
342 | |
---|
343 | return 0; |
---|
344 | } |
---|