61abc2cef1835d649b022d37bd704a25d50ec2a4
[krb5.git] / src / lib / krb5 / os / locate_kdc.c
1 /*
2  * lib/krb5/os/locate_kdc.c
3  *
4  * Copyright 1990 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  *
24  * get socket addresses for KDC.
25  */
26
27 #define NEED_SOCKETS
28 #include "k5-int.h"
29 #include <stdio.h>
30
31 #ifdef KRB5_USE_INET
32 extern char *krb5_kdc_udp_portname;
33 extern char *krb5_kdc_sec_udp_portname;
34 #endif
35
36 /*
37  * returns count of number of addresses found
38  */
39
40 krb5_error_code INTERFACE
41 krb5_locate_kdc(context, realm, addr_pp, naddrs)
42     krb5_context context;
43     const krb5_data *realm;
44     struct sockaddr **addr_pp;
45     int *naddrs;
46 {
47     char **hostlist;
48     krb5_error_code code;
49     int i, j, out, count;
50     struct sockaddr *addr_p;
51     struct sockaddr_in *sin_p;
52     struct hostent *hp;
53     struct servent *sp;
54 #ifdef KRB5_USE_INET
55     u_short udpport = htons(KRB5_DEFAULT_PORT);
56     u_short sec_udpport = htons(KRB5_DEFAULT_SEC_PORT);
57 #endif
58
59     hostlist = 0;
60     
61     if (code = krb5_get_krbhst (context, realm, &hostlist))
62         return(code);
63
64 #ifdef KRB5_USE_INET
65     if (sp = getservbyname(krb5_kdc_udp_portname, "udp"))
66         udpport = sp->s_port;
67     if (krb5_kdc_sec_udp_portname)
68         if (sp = getservbyname(krb5_kdc_sec_udp_portname, "udp")) {
69 #ifdef KRB5_TRY_SECONDARY_PORT_FIRST
70             sec_udpport = udpport;
71             udpport = sp->s_port;
72 #else
73             sec_udpport = sp->s_port;
74 #endif
75         }
76 #endif
77
78     count = 0;
79     while (hostlist[count])
80             count++;
81     
82     if (count == 0) {
83         *naddrs = 0;
84         return 0;
85     }
86     
87 #ifdef KRB5_USE_INET
88     if (sec_udpport)
89             count = count * 2;
90 #endif
91
92     addr_p = (struct sockaddr *)malloc (sizeof (struct sockaddr) * count);
93
94     for (i=0, out=0; hostlist[i]; i++) {
95         hp = gethostbyname(hostlist[i]);
96         if (hp != 0) {
97             switch (hp->h_addrtype) {
98 #ifdef KRB5_USE_INET
99             case AF_INET:
100                 if (udpport) {          /* must have gotten a port # */
101                     for (j=0; hp->h_addr_list[j]; j++) {
102                         sin_p = (struct sockaddr_in *) &addr_p[out++];
103                         memset ((char *)sin_p, 0, sizeof(struct sockaddr));
104                         sin_p->sin_family = hp->h_addrtype;
105                         sin_p->sin_port = udpport;
106                         memcpy((char *)&sin_p->sin_addr,
107                                (char *)hp->h_addr_list[j],
108                                sizeof(struct in_addr));
109                         if (out >= count) {
110                             count *= 2;
111                             addr_p = (struct sockaddr *)
112                                 realloc ((char *)addr_p,
113                                          sizeof(struct sockaddr) * count);
114                         }
115                         if (sec_udpport) {
116                             addr_p[out] = addr_p[out-1];
117                             sin_p = (struct sockaddr_in *) &addr_p[out++];
118                             sin_p->sin_port = sec_udpport;
119                             if (out >= count) {
120                                 count *= 2;
121                                 addr_p = (struct sockaddr *)
122                                         realloc ((char *)addr_p,
123                                                  sizeof(struct sockaddr) * count);
124                             }
125                         }
126                     }
127                 }
128                 break;
129 #endif
130             default:
131                 break;
132             }
133         }
134         free(hostlist[i]);
135         hostlist[i] = 0;
136     }
137     free ((char *)hostlist);
138
139     if (out == 0) {     /* Couldn't resolve any KDC names */
140         free (addr_p);
141         return KRB5_REALM_CANT_RESOLVE;
142     }
143
144     *addr_pp = addr_p;
145     *naddrs = out;
146     return 0;
147 }