BSD 4_3_Reno development
[unix-history] / usr / src / kerberosIV / krb / send_to_kdc.c
CommitLineData
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
12static 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
36extern int errno;
37extern int krb_debug;
38
39extern char *malloc(), *calloc(), *realloc();
40
41int 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 */
46static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0};
47static char *prog = "send_to_kdc";
48static 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
82send_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;
217rtn:
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
241static 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}