]> git.sur5r.net Git - openldap/blob - libraries/libldap/dnssrv.c
Merge remote-tracking branch 'origin/mdb.master'
[openldap] / libraries / libldap / dnssrv.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2013 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15
16 /*
17  * locate LDAP servers using DNS SRV records.
18  * Location code based on MIT Kerberos KDC location code.
19  */
20 #include "portable.h"
21
22 #include <stdio.h>
23
24 #include <ac/stdlib.h>
25
26 #include <ac/param.h>
27 #include <ac/socket.h>
28 #include <ac/string.h>
29 #include <ac/time.h>
30
31 #include "ldap-int.h"
32
33 #ifdef HAVE_ARPA_NAMESER_H
34 #include <arpa/nameser.h>
35 #endif
36 #ifdef HAVE_RESOLV_H
37 #include <resolv.h>
38 #endif
39
40 int ldap_dn2domain(
41         LDAP_CONST char *dn_in,
42         char **domainp)
43 {
44         int i, j;
45         char *ndomain;
46         LDAPDN dn = NULL;
47         LDAPRDN rdn = NULL;
48         LDAPAVA *ava = NULL;
49         struct berval domain = BER_BVNULL;
50         static const struct berval DC = BER_BVC("DC");
51         static const struct berval DCOID = BER_BVC("0.9.2342.19200300.100.1.25");
52
53         assert( dn_in != NULL );
54         assert( domainp != NULL );
55
56         *domainp = NULL;
57
58         if ( ldap_str2dn( dn_in, &dn, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) {
59                 return -2;
60         }
61
62         if( dn ) for( i=0; dn[i] != NULL; i++ ) {
63                 rdn = dn[i];
64
65                 for( j=0; rdn[j] != NULL; j++ ) {
66                         ava = rdn[j];
67
68                         if( rdn[j+1] == NULL &&
69                                 (ava->la_flags & LDAP_AVA_STRING) &&
70                                 ava->la_value.bv_len &&
71                                 ( ber_bvstrcasecmp( &ava->la_attr, &DC ) == 0
72                                 || ber_bvcmp( &ava->la_attr, &DCOID ) == 0 ) )
73                         {
74                                 if( domain.bv_len == 0 ) {
75                                         ndomain = LDAP_REALLOC( domain.bv_val,
76                                                 ava->la_value.bv_len + 1);
77
78                                         if( ndomain == NULL ) {
79                                                 goto return_error;
80                                         }
81
82                                         domain.bv_val = ndomain;
83
84                                         AC_MEMCPY( domain.bv_val, ava->la_value.bv_val,
85                                                 ava->la_value.bv_len );
86
87                                         domain.bv_len = ava->la_value.bv_len;
88                                         domain.bv_val[domain.bv_len] = '\0';
89
90                                 } else {
91                                         ndomain = LDAP_REALLOC( domain.bv_val,
92                                                 ava->la_value.bv_len + sizeof(".") + domain.bv_len );
93
94                                         if( ndomain == NULL ) {
95                                                 goto return_error;
96                                         }
97
98                                         domain.bv_val = ndomain;
99                                         domain.bv_val[domain.bv_len++] = '.';
100                                         AC_MEMCPY( &domain.bv_val[domain.bv_len],
101                                                 ava->la_value.bv_val, ava->la_value.bv_len );
102                                         domain.bv_len += ava->la_value.bv_len;
103                                         domain.bv_val[domain.bv_len] = '\0';
104                                 }
105                         } else {
106                                 domain.bv_len = 0;
107                         }
108                 } 
109         }
110
111
112         if( domain.bv_len == 0 && domain.bv_val != NULL ) {
113                 LDAP_FREE( domain.bv_val );
114                 domain.bv_val = NULL;
115         }
116
117         ldap_dnfree( dn );
118         *domainp = domain.bv_val;
119         return 0;
120
121 return_error:
122         ldap_dnfree( dn );
123         LDAP_FREE( domain.bv_val );
124         return -1;
125 }
126
127 int ldap_domain2dn(
128         LDAP_CONST char *domain_in,
129         char **dnp)
130 {
131         char *domain, *s, *tok_r, *dn, *dntmp;
132         size_t loc;
133
134         assert( domain_in != NULL );
135         assert( dnp != NULL );
136
137         domain = LDAP_STRDUP(domain_in);
138         if (domain == NULL) {
139                 return LDAP_NO_MEMORY;
140         }
141         dn = NULL;
142         loc = 0;
143
144         for (s = ldap_pvt_strtok(domain, ".", &tok_r);
145                 s != NULL;
146                 s = ldap_pvt_strtok(NULL, ".", &tok_r))
147         {
148                 size_t len = strlen(s);
149
150                 dntmp = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len );
151                 if (dntmp == NULL) {
152                     if (dn != NULL)
153                         LDAP_FREE(dn);
154                     LDAP_FREE(domain);
155                     return LDAP_NO_MEMORY;
156                 }
157
158                 dn = dntmp;
159
160                 if (loc > 0) {
161                     /* not first time. */
162                     strcpy(dn + loc, ",");
163                     loc++;
164                 }
165                 strcpy(dn + loc, "dc=");
166                 loc += sizeof("dc=")-1;
167
168                 strcpy(dn + loc, s);
169                 loc += len;
170     }
171
172         LDAP_FREE(domain);
173         *dnp = dn;
174         return LDAP_SUCCESS;
175 }
176
177 /*
178  * Lookup and return LDAP servers for domain (using the DNS
179  * SRV record _ldap._tcp.domain).
180  */
181 int ldap_domain2hostlist(
182         LDAP_CONST char *domain,
183         char **list )
184 {
185 #ifdef HAVE_RES_QUERY
186 #define DNSBUFSIZ (64*1024)
187     char *request;
188     char *hostlist = NULL;
189     int rc, len, cur = 0;
190     unsigned char reply[DNSBUFSIZ];
191
192         assert( domain != NULL );
193         assert( list != NULL );
194
195         if( *domain == '\0' ) {
196                 return LDAP_PARAM_ERROR;
197         }
198
199     request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp."));
200     if (request == NULL) {
201                 return LDAP_NO_MEMORY;
202     }
203     sprintf(request, "_ldap._tcp.%s", domain);
204
205     LDAP_MUTEX_LOCK(&ldap_int_resolv_mutex);
206
207     rc = LDAP_UNAVAILABLE;
208 #ifdef NS_HFIXEDSZ
209         /* Bind 8/9 interface */
210     len = res_query(request, ns_c_in, ns_t_srv, reply, sizeof(reply));
211 #       ifndef T_SRV
212 #               define T_SRV ns_t_srv
213 #       endif
214 #else
215         /* Bind 4 interface */
216 #       ifndef T_SRV
217 #               define T_SRV 33
218 #       endif
219
220     len = res_query(request, C_IN, T_SRV, reply, sizeof(reply));
221 #endif
222     if (len >= 0) {
223         unsigned char *p;
224         char host[DNSBUFSIZ];
225         int status;
226         u_short port;
227         /* int priority, weight; */
228
229         /* Parse out query */
230         p = reply;
231
232 #ifdef NS_HFIXEDSZ
233         /* Bind 8/9 interface */
234         p += NS_HFIXEDSZ;
235 #elif defined(HFIXEDSZ)
236         /* Bind 4 interface w/ HFIXEDSZ */
237         p += HFIXEDSZ;
238 #else
239         /* Bind 4 interface w/o HFIXEDSZ */
240         p += sizeof(HEADER);
241 #endif
242
243         status = dn_expand(reply, reply + len, p, host, sizeof(host));
244         if (status < 0) {
245             goto out;
246         }
247         p += status;
248         p += 4;
249
250         while (p < reply + len) {
251             int type, class, ttl, size;
252             status = dn_expand(reply, reply + len, p, host, sizeof(host));
253             if (status < 0) {
254                 goto out;
255             }
256             p += status;
257             type = (p[0] << 8) | p[1];
258             p += 2;
259             class = (p[0] << 8) | p[1];
260             p += 2;
261             ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
262             p += 4;
263             size = (p[0] << 8) | p[1];
264             p += 2;
265             if (type == T_SRV) {
266                 int buflen;
267                 status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
268                 if (status < 0) {
269                     goto out;
270                 }
271                 /* ignore priority and weight for now */
272                 /* priority = (p[0] << 8) | p[1]; */
273                 /* weight = (p[2] << 8) | p[3]; */
274                 port = (p[4] << 8) | p[5];
275
276                 if ( port == 0 || host[ 0 ] == '\0' ) {
277                     goto add_size;
278                 }
279
280                 buflen = strlen(host) + STRLENOF(":65355 ");
281                 hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen + 1);
282                 if (hostlist == NULL) {
283                     rc = LDAP_NO_MEMORY;
284                     goto out;
285                 }
286                 if (cur > 0) {
287                     /* not first time around */
288                     hostlist[cur++] = ' ';
289                 }
290                 cur += sprintf(&hostlist[cur], "%s:%hu", host, port);
291             }
292 add_size:;
293             p += size;
294         }
295     }
296     if (hostlist == NULL) {
297         /* No LDAP servers found in DNS. */
298         rc = LDAP_UNAVAILABLE;
299         goto out;
300     }
301
302     rc = LDAP_SUCCESS;
303         *list = hostlist;
304
305   out:
306     LDAP_MUTEX_UNLOCK(&ldap_int_resolv_mutex);
307
308     if (request != NULL) {
309         LDAP_FREE(request);
310     }
311     if (rc != LDAP_SUCCESS && hostlist != NULL) {
312         LDAP_FREE(hostlist);
313     }
314     return rc;
315 #else
316     return LDAP_NOT_SUPPORTED;
317 #endif /* HAVE_RES_QUERY */
318 }