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