]> git.sur5r.net Git - openldap/blob - libraries/libldap/dnssrv.c
ad9d5e05b7e3e08c7f3694fa27b1b000409064f2
[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         int i;
41         char *domain = NULL;
42         char **dn;
43
44         if( dn_in == NULL || domainp == NULL ) {
45                 return -1;
46         }
47
48         dn = ldap_explode_dn( dn_in, 0 );
49
50         if( dn == NULL ) {
51                 return -2;
52         }
53
54         for( i=0; dn[i] != NULL; i++ ) {
55                 char ** rdn = ldap_explode_rdn( dn[i], 0 );
56
57                 if( rdn == NULL || *rdn == NULL ) {
58                         LDAP_FREE( rdn );
59                         LDAP_FREE( domain );
60                         LDAP_VFREE( dn );
61                         return -3;
62                 }
63
64 #define LDAP_DC "dc="
65 #define LDAP_DCOID "0.9.2342.19200300.100.1.25="
66
67                 if( rdn[1] == NULL ) {
68                         char *dc;
69                         /* single RDN */
70
71                         if( strncasecmp( rdn[0],
72                                 LDAP_DC, sizeof(LDAP_DC)-1 ) == 0 )
73                         {
74                                 dc = &rdn[0][sizeof(LDAP_DC)-1];
75
76                         } else if( strncmp( rdn[0],
77                                 LDAP_DCOID, sizeof(LDAP_DCOID)-1 ) == 0 )
78                         {
79                                 dc = &rdn[0][sizeof(LDAP_DCOID)-1];
80
81                         } else {
82                                 dc = NULL;
83                         }
84
85                         if( dc != NULL ) {
86                                 char *ndomain;
87
88                                 if( *dc == '\0' ) {
89                                         /* dc value is empty! */
90                                         LDAP_FREE( rdn );
91                                         LDAP_FREE( domain );
92                                         LDAP_VFREE( dn );
93                                         LDAP_VFREE( rdn );
94                                         return -4;
95                                 }
96
97                                 ndomain = LDAP_REALLOC( domain,
98                                         ( domain == NULL ? 0 : strlen(domain) )
99                                         + strlen(dc) + 2 );
100
101                                 if( ndomain == NULL ) {
102                                         LDAP_FREE( rdn );
103                                         LDAP_FREE( domain );
104                                         LDAP_VFREE( dn );
105                                         LDAP_VFREE( rdn );
106                                         return -5;
107                                 }
108
109                                 if( domain == NULL ) {
110                                         ndomain[0] = '\0';
111                                 } else {
112                                         strcat( ndomain, "." );
113                                 }
114                                 strcat( ndomain, dc );
115                                 domain = ndomain;
116                                 continue;
117                         }
118                 }
119
120                 LDAP_VFREE( rdn );
121                 LDAP_FREE( domain );
122                 domain = NULL;
123         } 
124
125         *domainp = domain;
126         return 0;
127 }
128
129 int ldap_domain2dn(
130         LDAP_CONST char *domain_in,
131         char **dnp)
132 {
133     char *domain, *s, *tok_r, *dn;
134     size_t loc;
135
136     if (domain_in == NULL || dnp == NULL) {
137         return LDAP_NO_MEMORY;
138     }
139     domain = LDAP_STRDUP(domain_in);
140     if (domain == NULL) {
141         return LDAP_NO_MEMORY;
142     }
143     dn = NULL;
144     loc = 0;
145
146     for (s = ldap_pvt_strtok(domain, ".", &tok_r);
147          s != NULL;
148          s = ldap_pvt_strtok(NULL, ".", &tok_r)) {
149         size_t len = strlen(s);
150
151         dn = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len );
152         if (dn == NULL) {
153             LDAP_FREE(domain);
154             return LDAP_NO_MEMORY;
155         }
156         if (loc > 0) {
157             /* not first time. */
158             strcpy(dn + loc, ",");
159             loc++;
160         }
161         strcpy(dn + loc, "dc=");
162         loc += sizeof("dc=")-1;
163
164         strcpy(dn + loc, s);
165         loc += len;
166     }
167
168     LDAP_FREE(domain);
169
170     *dnp = dn;
171
172     return LDAP_SUCCESS;
173 }
174
175 /*
176  * Lookup and return LDAP servers for domain (using the DNS
177  * SRV record _ldap._tcp.domain).
178  */
179 int ldap_domain2hostlist(
180         LDAP_CONST char *domain,
181         char **list )
182 {
183 #ifdef HAVE_RES_SEARCH
184     char *request;
185     char *dn;
186     char *hostlist = NULL;
187     int rc, len, cur = 0;
188     unsigned char reply[1024];
189
190         if( domain == NULL || *domain == '\0' ) {
191                 return LDAP_PARAM_ERROR;
192         }
193
194         if( list == NULL ) {
195                 return LDAP_PARAM_ERROR;
196         }
197
198     request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp."));
199     if (request == NULL) {
200         rc = LDAP_NO_MEMORY;
201         goto out;
202     }
203     sprintf(request, "_ldap._tcp.%s", domain);
204
205 #ifdef LDAP_R_COMPILE
206     ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex);
207 #endif
208
209     len = res_search(request, C_IN, T_SRV, reply, sizeof(reply));
210     if (len >= 0) {
211         unsigned char *p;
212         char host[1024];
213         int status;
214         u_short port;
215         /* int priority, weight; */
216
217         /* Parse out query */
218         p = reply;
219         p += sizeof(HEADER);
220         status = dn_expand(reply, reply + len, p, host, sizeof(host));
221         if (status < 0) {
222             goto out;
223         }
224         p += status;
225         p += 4;
226
227         while (p < reply + len) {
228             int type, class, ttl, size;
229             status = dn_expand(reply, reply + len, p, host, sizeof(host));
230             if (status < 0) {
231                 goto out;
232             }
233             p += status;
234             type = (p[0] << 8) | p[1];
235             p += 2;
236             class = (p[0] << 8) | p[1];
237             p += 2;
238             ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
239             p += 4;
240             size = (p[0] << 8) | p[1];
241             p += 2;
242             if (type == T_SRV) {
243                 int buflen;
244                 status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
245                 if (status < 0) {
246                     goto out;
247                 }
248                 /* ignore priority and weight for now */
249                 /* priority = (p[0] << 8) | p[1]; */
250                 /* weight = (p[2] << 8) | p[3]; */
251                 port = (p[4] << 8) | p[5];
252
253                 buflen = strlen(host) + sizeof(":65355");
254                 hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen);
255                 if (hostlist == NULL) {
256                     rc = LDAP_NO_MEMORY;
257                     goto out;
258                 }
259                 if (cur > 0) {
260                     /* not first time around */
261                     hostlist[cur++] = ' ';
262                 }
263                 cur += sprintf(&hostlist[cur], "%s:%hd", host, port);
264             }
265             p += size;
266         }
267     }
268     if (hostlist == NULL) {
269         /* No LDAP servers found in DNS. */
270         rc = LDAP_UNAVAILABLE;
271         goto out;
272     }
273
274     rc = LDAP_SUCCESS;
275         *list = hostlist;
276
277   out:
278 #ifdef LDAP_R_COMPILE
279     ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex);
280 #endif
281
282     if (request != NULL) {
283         LDAP_FREE(request);
284     }
285     if (rc != LDAP_SUCCESS && hostlist != NULL) {
286         LDAP_FREE(hostlist);
287     }
288     return rc;
289 #else
290     return LDAP_NOT_SUPPORTED;
291 #endif                          /* HAVE_RES_SEARCH */
292 }