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