Change __signed to signed.
[dragonfly.git] / crypto / kerberosIV / lib / krb / get_host.c
1 /*
2  * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "krb_locl.h"
35
36 RCSID("$Id: get_host.c,v 1.48 1999/12/02 16:58:41 joda Exp $");
37
38 static struct host_list {
39     struct krb_host *this;
40     struct host_list *next;
41 } *hosts;
42
43 static int krb_port = 0;
44
45 static void
46 free_hosts(struct host_list *h)
47 {
48     struct host_list *t;
49     while(h){
50         if(h->this->realm)
51             free(h->this->realm);
52         if(h->this->host)
53             free(h->this->host);
54         t = h;
55         h = h->next;
56         free(t);
57     }
58 }
59
60 static int
61 parse_address(char *address, enum krb_host_proto *proto,
62               char **host, int *port)
63 {
64     char *p, *q;
65     int default_port = krb_port;
66     *proto = PROTO_UDP;
67     if(strncmp(address, "http://", 7) == 0){
68         p = address + 7;
69         *proto = PROTO_HTTP;
70         default_port = 80;
71     }else{
72         p = strchr(address, '/');
73         if(p){
74             char prot[32];
75             strlcpy (prot, address,
76                              min(p - address + 1, sizeof(prot)));
77             if(strcasecmp(prot, "udp") == 0) 
78                 *proto = PROTO_UDP;
79             else if(strcasecmp(prot, "tcp") == 0)
80                 *proto = PROTO_TCP;
81             else if(strcasecmp(prot, "http") == 0) {
82                 *proto = PROTO_HTTP;
83                 default_port = 80;
84             } else
85                 krb_warning("Unknown protocol `%s', Using default `udp'.\n", 
86                             prot);
87             p++;
88         }else
89             p = address;
90     }
91     q = strchr(p, ':');
92     if(q) {
93         *host = malloc(q - p + 1);
94         if (*host == NULL)
95             return -1;
96         strlcpy (*host, p, q - p + 1);
97         q++;
98         {
99             struct servent *sp = getservbyname(q, NULL);
100             if(sp)
101                 *port = ntohs(sp->s_port);
102             else
103                 if(sscanf(q, "%d", port) != 1){
104                     krb_warning("Bad port specification `%s', using port %d.", 
105                                 q, krb_port);
106                     *port = krb_port;
107                 }
108         }
109     } else {
110         *port = default_port;
111         q = strchr(p, '/');
112         if (q) {
113             *host = malloc(q - p + 1);
114             if (*host == NULL)
115                 return -1;
116             strlcpy (*host, p, q - p + 1);
117         } else {
118             *host = strdup(p);
119             if(*host == NULL)
120                 return -1;
121         }
122     }
123     return 0;
124 }
125
126 static int
127 add_host(const char *realm, char *address, int admin, int validate)
128 {
129     struct krb_host *host;
130     struct host_list *p, **last = &hosts;
131
132     host = (struct krb_host*)malloc(sizeof(struct krb_host));
133     if (host == NULL)
134         return 1;
135     if(parse_address(address, &host->proto, &host->host, &host->port) < 0) {
136         free(host);
137         return 1;
138     }
139     if (validate) {
140         if (krb_dns_debug)
141             krb_warning("Getting host entry for %s...", host->host);
142         if (gethostbyname(host->host) == NULL) {
143             if (krb_dns_debug)
144                 krb_warning("Didn't get it.\n");
145             free(host->host);
146             free(host);
147             return 1;
148         }
149         else if (krb_dns_debug)
150             krb_warning("Got it.\n");
151     }
152     host->admin = admin;
153     for(p = hosts; p; p = p->next){
154         if(strcmp(realm, p->this->realm) == 0 &&
155            strcmp(host->host, p->this->host) == 0 && 
156            host->proto == p->this->proto &&
157            host->port == p->this->port){
158             free(host->host);
159             free(host);
160             return 1;
161         }
162         last = &p->next;
163     }
164     host->realm = strdup(realm);
165     if (host->realm == NULL) {
166         free(host->host);
167         free(host);
168         return 1;
169     }
170     p = (struct host_list*)malloc(sizeof(struct host_list));
171     if (p == NULL) {
172         free(host->realm);
173         free(host->host);
174         free(host);
175         return 1;
176     }
177     p->this = host;
178     p->next = NULL;
179     *last = p;
180     return 0;
181 }
182
183 static int
184 read_file(const char *filename, const char *r)
185 {
186     char line[1024];
187     int nhosts = 0;
188     FILE *f = fopen(filename, "r");
189
190     if(f == NULL)
191         return -1;
192     while(fgets(line, sizeof(line), f) != NULL) {
193         char *realm, *address, *admin;
194         char *save;
195         
196         realm = strtok_r (line, " \t\n\r", &save);
197         if (realm == NULL)
198             continue;
199         if (strcmp(realm, r))
200             continue;
201         address = strtok_r (NULL, " \t\n\r", &save);
202         if (address == NULL)
203             continue;
204         admin = strtok_r (NULL, " \t\n\r", &save);
205         if (add_host(realm,
206                      address,
207                      admin != NULL && strcasecmp(admin, "admin") == 0,
208                      0) == 0)
209             ++nhosts;
210     }
211     fclose(f);
212     return nhosts;
213 }
214
215 #if 0
216 static int
217 read_cellservdb (const char *filename, const char *realm)
218 {
219     char line[1024];
220     FILE *f = fopen (filename, "r");
221     int nhosts = 0;
222
223     if (f == NULL)
224         return -1;
225     while (fgets (line, sizeof(line), f) != NULL) {
226         if (line[0] == '>'
227             && strncasecmp (line + 1, realm, strlen(realm)) == 0) {
228             while (fgets (line, sizeof(line), f) != NULL && *line != '>') {
229                 char *hash;
230
231                 if (line [strlen(line) - 1] == '\n')
232                     line [strlen(line) - 1] = '\0';
233
234                 hash = strchr (line, '#');
235
236                 if (hash != NULL
237                     && add_host (realm, hash + 1, 0, 0) == 0)
238                     ++nhosts;
239             }
240             break;
241         }
242     }
243     fclose (f);
244     return nhosts;
245 }
246 #endif
247
248 static int
249 init_hosts(char *realm)
250 {
251     int i, j, ret = 0;
252     char file[MaxPathLen];
253     
254     /*
255      * proto should really be NULL, but there are libraries out there
256      * that don't like that so we use "udp" instead.
257      */
258
259     krb_port = ntohs(k_getportbyname (KRB_SERVICE, "udp", htons(KRB_PORT)));
260     for(i = 0; krb_get_krbconf(i, file, sizeof(file)) == 0; i++) {
261       j = read_file(file, realm);
262       if (j > 0) ret += j;
263     }
264     return ret;
265 }
266
267 static void
268 srv_find_realm(char *realm, char *proto, char *service)
269 {
270     char *domain;
271     struct dns_reply *r;
272     struct resource_record *rr;
273     
274     roken_mconcat(&domain, 1024, service, ".", proto, ".", realm, ".", NULL);
275     
276     if(domain == NULL)
277         return;
278     
279     r = dns_lookup(domain, "srv");
280     if(r == NULL)
281         r = dns_lookup(domain, "txt");
282     if(r == NULL){
283         free(domain);
284         return;
285     }
286     for(rr = r->head; rr; rr = rr->next){
287         if(rr->type == T_SRV){
288             char buf[1024];
289
290             if (snprintf (buf,
291                           sizeof(buf),
292                           "%s/%s:%u",
293                           proto,
294                           rr->u.srv->target,
295                           rr->u.srv->port) < sizeof(buf))
296                 add_host(realm, buf, 0, 0);
297         }else if(rr->type == T_TXT)
298             add_host(realm, rr->u.txt, 0, 0);
299     }
300     dns_free_data(r);
301     free(domain);
302 }
303
304 struct krb_host*
305 krb_get_host(int nth, const char *realm, int admin)
306 {
307     struct host_list *p;
308     static char orealm[REALM_SZ];
309
310     if(orealm[0] == 0 || strcmp(realm, orealm)){
311         /* quick optimization */
312         if(realm && realm[0]){
313             strlcpy (orealm, realm, sizeof(orealm));
314         }else{
315             int ret = krb_get_lrealm(orealm, 1);
316             if(ret != KSUCCESS)
317                 return NULL;
318         }
319         
320         if(hosts){
321             free_hosts(hosts);
322             hosts = NULL;
323         }
324         
325         if (init_hosts(orealm) < nth) {
326           srv_find_realm(orealm, "udp", KRB_SERVICE);
327           srv_find_realm(orealm, "tcp", KRB_SERVICE);
328           srv_find_realm(orealm, "http", KRB_SERVICE);
329         
330           {
331             char *host;
332             int i = 0;
333
334             asprintf(&host, "kerberos.%s.", orealm);
335             if (host == NULL) {
336                 free_hosts(hosts);
337                 hosts = NULL;
338                 return NULL;
339             }
340             add_host(orealm, host, 1, 1);
341             do {
342                 i++;
343                 free(host);
344                 asprintf(&host, "kerberos-%d.%s.", i, orealm);
345             } while(host != NULL
346                    && i < 100000
347                    && add_host(orealm, host, 0, 1) == 0);
348             free(host);
349           }
350         }
351 #if 0
352         read_cellservdb ("/usr/vice/etc/CellServDB", orealm);
353         read_cellservdb ("/usr/arla/etc/CellServDB", orealm);
354 #endif
355     }
356     
357     for(p = hosts; p; p = p->next){
358         if(strcmp(orealm, p->this->realm) == 0 &&
359            (!admin || p->this->admin)) {
360             if(nth == 1)
361                 return p->this;
362             else
363                 nth--;
364         }
365     }
366     return NULL;
367 }
368
369 int
370 krb_get_krbhst(char *host, char *realm, int nth)
371 {
372     struct krb_host *p = krb_get_host(nth, realm, 0);
373     if(p == NULL)
374         return KFAILURE;
375     strlcpy (host, p->host, MaxHostNameLen);
376     return KSUCCESS;
377 }
378
379 int
380 krb_get_admhst(char *host, char *realm, int nth)
381 {
382     struct krb_host *p = krb_get_host(nth, realm, 1);
383     if(p == NULL)
384         return KFAILURE;
385     strlcpy (host, p->host, MaxHostNameLen);
386     return KSUCCESS;
387 }