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