]> git.sur5r.net Git - openldap/blob - libraries/libldap/dnssrv.c
d5597c57ecf7d7094be50c67cda75948f1cf59b4
[openldap] / libraries / libldap / dnssrv.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 /*
8  * locate LDAP servers using DNS SRV records.
9  * Location code based on MIT Kerberos KDC location code.
10  */
11 #include "portable.h"
12
13 #include <stdio.h>
14
15 #include <ac/stdlib.h>
16
17 #include <ac/param.h>
18 #include <ac/socket.h>
19 #include <ac/string.h>
20 #include <ac/time.h>
21
22 #include "ldap-int.h"
23
24 #ifdef HAVE_ARPA_NAMESER_H
25 #include <arpa/nameser.h>
26 #endif
27 #ifdef HAVE_RESOLV_H
28 #include <resolv.h>
29 #endif
30
31 /* Sometimes this is not defined. */
32 #ifndef T_SRV
33 #define T_SRV            33
34 #endif                          /* T_SRV */
35
36 int ldap_dn2domain(
37         LDAP_CONST char *dn_in,
38         char **domainp)
39 {
40         /* not yet implemented */
41         return LDAP_NOT_SUPPORTED;
42 }
43
44 int ldap_domain2dn(
45         LDAP_CONST char *domain_in,
46         char **dnp)
47 {
48     char *domain, *s, *tok_r, *dn;
49     size_t loc;
50
51     if (domain_in == NULL || dnp == NULL) {
52         return LDAP_NO_MEMORY;
53     }
54     domain = LDAP_STRDUP(domain_in);
55     if (domain == NULL) {
56         return LDAP_NO_MEMORY;
57     }
58     dn = NULL;
59     loc = 0;
60
61     for (s = ldap_pvt_strtok(domain, ".", &tok_r);
62          s != NULL;
63          s = ldap_pvt_strtok(NULL, ".", &tok_r)) {
64         size_t len = strlen(s);
65
66         dn = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len );
67         if (dn == NULL) {
68             LDAP_FREE(domain);
69             return LDAP_NO_MEMORY;
70         }
71         if (loc > 0) {
72             /* not first time. */
73             strcpy(dn + loc, ",");
74             loc++;
75         }
76         strcpy(dn + loc, "dc=");
77         loc += sizeof("dc=")-1;
78
79         strcpy(dn + loc, s);
80         loc += len;
81     }
82
83     LDAP_FREE(domain);
84
85     *dnp = dn;
86
87     return LDAP_SUCCESS;
88 }
89
90 /*
91  * Lookup and return LDAP servers for domain (using the DNS
92  * SRV record _ldap._tcp.domain).
93  */
94 int ldap_domain2hostlist(
95         LDAP_CONST char *domain,
96         char **list )
97 {
98 #ifdef HAVE_RES_SEARCH
99     char *request;
100     char *dn;
101     char *hostlist = NULL;
102     int rc, len, cur = 0;
103     unsigned char reply[1024];
104
105         if( domain == NULL || *domain == '\0' ) {
106                 return LDAP_PARAM_ERROR;
107         }
108
109         if( list == NULL ) {
110                 return LDAP_PARAM_ERROR;
111         }
112
113     request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp."));
114     if (request == NULL) {
115         rc = LDAP_NO_MEMORY;
116         goto out;
117     }
118     sprintf(request, "_ldap._tcp.%s", domain);
119
120 #ifdef LDAP_R_COMPILE
121     ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex);
122 #endif
123
124     len = res_search(request, C_IN, T_SRV, reply, sizeof(reply));
125     if (len >= 0) {
126         unsigned char *p;
127         char host[1024];
128         int status;
129         u_short port;
130         /* int priority, weight; */
131
132         /* Parse out query */
133         p = reply;
134         p += sizeof(HEADER);
135         status = dn_expand(reply, reply + len, p, host, sizeof(host));
136         if (status < 0) {
137             goto out;
138         }
139         p += status;
140         p += 4;
141
142         while (p < reply + len) {
143             int type, class, ttl, size;
144             status = dn_expand(reply, reply + len, p, host, sizeof(host));
145             if (status < 0) {
146                 goto out;
147             }
148             p += status;
149             type = (p[0] << 8) | p[1];
150             p += 2;
151             class = (p[0] << 8) | p[1];
152             p += 2;
153             ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
154             p += 4;
155             size = (p[0] << 8) | p[1];
156             p += 2;
157             if (type == T_SRV) {
158                 int buflen;
159                 status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
160                 if (status < 0) {
161                     goto out;
162                 }
163                 /* ignore priority and weight for now */
164                 /* priority = (p[0] << 8) | p[1]; */
165                 /* weight = (p[2] << 8) | p[3]; */
166                 port = (p[4] << 8) | p[5];
167
168                 buflen = strlen(host) + sizeof(":65355");
169                 hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen);
170                 if (hostlist == NULL) {
171                     rc = LDAP_NO_MEMORY;
172                     goto out;
173                 }
174                 if (cur > 0) {
175                     /* not first time around */
176                     hostlist[cur++] = ' ';
177                 }
178                 cur += sprintf(&hostlist[cur], "%s:%hd", host, port);
179             }
180             p += size;
181         }
182     }
183     if (hostlist == NULL) {
184         /* No LDAP servers found in DNS. */
185         rc = LDAP_UNAVAILABLE;
186         goto out;
187     }
188
189     rc = LDAP_SUCCESS;
190         *list = hostlist;
191
192   out:
193 #ifdef LDAP_R_COMPILE
194     ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex);
195 #endif
196
197     if (request != NULL) {
198         LDAP_FREE(request);
199     }
200     if (rc != LDAP_SUCCESS && hostlist != NULL) {
201         LDAP_FREE(hostlist);
202     }
203     return rc;
204 #else
205     return LDAP_NOT_SUPPORTED;
206 #endif                          /* HAVE_RES_SEARCH */
207 }