source: trunk/athena/bin/aklog/krb_util.c @ 6386

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