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