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