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