*** empty log message ***
authorJohn Kohl <jtkohl@mit.edu>
Thu, 29 Mar 1990 16:01:40 +0000 (16:01 +0000)
committerJohn Kohl <jtkohl@mit.edu>
Thu, 29 Mar 1990 16:01:40 +0000 (16:01 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@429 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/os/sendto_kdc.c [new file with mode: 0644]

diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
new file mode 100644 (file)
index 0000000..be74b8a
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <krb5/mit-copyright.h>.
+ *
+ * Send packet to KDC for realm; wait for response, retransmitting
+ * as necessary.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_sendto_kdc_c[] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <krb5/copyright.h>
+
+#include <krb5/krb5.h>
+#include <krb5/krb5_err.h>
+#include <errno.h>
+#include <krb5/ext-proto.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#define MAX_DGRAM_SIZE 4096            /* XXX! */
+#define MAX_TIMEOUT 30                 /* XXX */
+#define TIMEOUT_SHIFT 2                        /* XXX */
+
+#include <stdio.h>
+#include <krb5/libos-proto.h>
+
+/*
+ * send the formatted request 'message' to a KDC for realm 'realm' and
+ * return the response (if any) in 'reply'.
+ *
+ * If the message is sent and a response is received, 0 is returned,
+ * otherwise an error code is returned.
+ *
+ * The storage for 'reply' is allocated and should be freed by the caller
+ * when finished.
+ *
+ */
+krb5_error_code
+krb5_sendto_kdc (DECLARG(krb5_data *, message),
+                DECLARG(krb5_data *, realm),
+                DECLARG(krb5_data *, reply))
+OLDDECLARG(krb5_data *, message)
+OLDDECLARG(krb5_data *, realm)
+OLDDECLARG(krb5_data *, reply)
+{
+    register int timeout, host, i;
+    struct sockaddr *addr;
+    int naddr;
+    int sent, nready;
+    krb5_error_code retval;
+    int socklist[AF_MAX];              /* one for each, if necessary! */
+    fd_set readable;
+    struct timeval waitlen;
+    struct sockaddr fromaddr;
+    int fromlen, cc;
+
+    /*
+     * find KDC location(s) for realm
+     */
+
+    if (retval = krb5_locate_kdc (realm, &addr, &naddr))
+       return retval;
+    if (naddr == 0)
+       return KRB5_REALM_UNKNOWN;
+    
+    for (i = 0; i < AF_MAX; i++)
+       socklist[i] = -1;
+
+    if (!(reply->data = malloc(MAX_DGRAM_SIZE))) { /* XXX size? */
+       free((char *)addr);
+       return ENOMEM;
+    }
+    reply->length = MAX_DGRAM_SIZE;
+
+    /*
+     * do exponential backoff.
+     */
+
+    for (timeout = 1; timeout < MAXTIMEOUT; timeout <<=TIMEOUT_SHIFT) {
+       sent = 0;
+       for (host = 0; host < naddr; host++) {
+           /* send to the host, wait timeout seconds for a response,
+              then move on. */
+           /* cache some sockets for various address families in the
+              list */
+           if (socklist[addr[host].sa_family] == -1) {
+               /* XXX 4.2/4.3BSD has PF_xxx = AF_xxx, so the socket
+                  creation here will work properly... */
+               socklist[addr[host].sa_family] = socket(addr[host].sa_family,
+                                                       SOCK_DGRAM,
+                                                       0); /* XXX always zero? */
+               if (socklist[addr[host].sa_family] == -1)
+                   continue;           /* try other hosts */
+           }
+           /* have a socket to send/recv from */
+           if (sendto(socklist[addr[host].sa_family],
+                      message->data,
+                      message->length,
+                      0,
+                      &addr[host],
+                      sizeof(addr[host])) != message->length)
+               continue;
+           else
+               sent = 1;
+           waitlen.tv_usec = 0;
+           waitlen.tv_sec = timeout;
+           FD_ZERO(&readable);
+           FD_SET(socklist[addr[host].sa_family], &readable);
+           if (nready = select(1<<socklist[addr[host].sa_family],
+                               &readable,
+                               0,
+                               0,
+                               &waitlen)) {
+               if (nready == -1)
+                   continue;           /* XXX */
+               if (cc = recvfrom(socklist[addr[host].sa_family],
+                                 reply->data,
+                                 reply->length,
+                                 0,
+                                 &fromaddr,
+                                 &fromlen) == -1)
+                   continue;           /* XXX */
+               if (bcmp((char *)&fromaddr, (char *)&addr[host],
+                        fromlen)) {
+                   /* not from this one, perhaps from an earlier
+                      request? */
+                   for (i = host-1; i >= 0; i--) {
+                       if (!bcmp((char *)&fromaddr, (char *)&addr[host],
+                                 fromlen))
+                           break;
+                   }
+                   if (i < 0)          /* not from someone we asked */
+                       continue;       /* XXX */
+               }
+               /* reply came from where we sent a request,
+                  so clean up and return. */
+               reply->length = cc;
+               retval = 0;
+               goto out;
+           }
+           /* not ready, go on to next server */
+       }
+       if (!sent) {
+           /* never were able to send to any servers; give up */
+           retval = KRB5_KDC_UNREACH;
+           break;
+       }
+    }
+    retval = KRB5_KDC_UNREACH;
+ out:
+    for (i = 0; i < AF_MAX; i++)
+       (void) close(i);
+    free((char *)addr);
+    if (retval) {
+       free(reply->data);
+       reply->data = 0;
+       reply->length = 0;
+    }
+    return retval;
+}