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