home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / kerberosIV / krb / send_to_kdc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-07  |  9.3 KB  |  318 lines

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