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