]> git.sur5r.net Git - openldap/blob - libraries/libldap/dnssrv.c
Fix ldap_int_get_controls for optional values
[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, 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;
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         size_t len = strlen(s);
141
142         dn = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len );
143         if (dn == NULL) {
144             LDAP_FREE(domain);
145             return LDAP_NO_MEMORY;
146         }
147         if (loc > 0) {
148             /* not first time. */
149             strcpy(dn + loc, ",");
150             loc++;
151         }
152         strcpy(dn + loc, "dc=");
153         loc += sizeof("dc=")-1;
154
155         strcpy(dn + loc, s);
156         loc += len;
157     }
158
159     LDAP_FREE(domain);
160
161     *dnp = dn;
162
163     return LDAP_SUCCESS;
164 }
165
166 /*
167  * Lookup and return LDAP servers for domain (using the DNS
168  * SRV record _ldap._tcp.domain).
169  */
170 int ldap_domain2hostlist(
171         LDAP_CONST char *domain,
172         char **list )
173 {
174 #ifdef HAVE_RES_QUERY
175 #define DNSBUFSIZ (64*1024)
176     char *request;
177     char *hostlist = NULL;
178     int rc, len, cur = 0;
179     unsigned char reply[DNSBUFSIZ];
180
181         assert( domain != NULL );
182         assert( list != NULL );
183
184         if( *domain == '\0' ) {
185                 return LDAP_PARAM_ERROR;
186         }
187
188     request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp."));
189     if (request == NULL) {
190                 return LDAP_NO_MEMORY;
191     }
192     sprintf(request, "_ldap._tcp.%s", domain);
193
194 #ifdef LDAP_R_COMPILE
195     ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex);
196 #endif
197
198     rc = LDAP_UNAVAILABLE;
199     len = res_query(request, C_IN, T_SRV, reply, sizeof(reply));
200     if (len >= 0) {
201         unsigned char *p;
202         char host[DNSBUFSIZ];
203         int status;
204         u_short port;
205         /* int priority, weight; */
206
207         /* Parse out query */
208         p = reply;
209         p += sizeof(HEADER);
210         status = dn_expand(reply, reply + len, p, host, sizeof(host));
211         if (status < 0) {
212             goto out;
213         }
214         p += status;
215         p += 4;
216
217         while (p < reply + len) {
218             int type, class, ttl, size;
219             status = dn_expand(reply, reply + len, p, host, sizeof(host));
220             if (status < 0) {
221                 goto out;
222             }
223             p += status;
224             type = (p[0] << 8) | p[1];
225             p += 2;
226             class = (p[0] << 8) | p[1];
227             p += 2;
228             ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
229             p += 4;
230             size = (p[0] << 8) | p[1];
231             p += 2;
232             if (type == T_SRV) {
233                 int buflen;
234                 status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
235                 if (status < 0) {
236                     goto out;
237                 }
238                 /* ignore priority and weight for now */
239                 /* priority = (p[0] << 8) | p[1]; */
240                 /* weight = (p[2] << 8) | p[3]; */
241                 port = (p[4] << 8) | p[5];
242
243                 buflen = strlen(host) + sizeof(":65355 ");
244                 hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen);
245                 if (hostlist == NULL) {
246                     rc = LDAP_NO_MEMORY;
247                     goto out;
248                 }
249                 if (cur > 0) {
250                     /* not first time around */
251                     hostlist[cur++] = ' ';
252                 }
253                 cur += sprintf(&hostlist[cur], "%s:%hd", host, port);
254             }
255             p += size;
256         }
257     }
258     if (hostlist == NULL) {
259         /* No LDAP servers found in DNS. */
260         rc = LDAP_UNAVAILABLE;
261         goto out;
262     }
263
264     rc = LDAP_SUCCESS;
265         *list = hostlist;
266
267   out:
268 #ifdef LDAP_R_COMPILE
269     ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex);
270 #endif
271
272     if (request != NULL) {
273         LDAP_FREE(request);
274     }
275     if (rc != LDAP_SUCCESS && hostlist != NULL) {
276         LDAP_FREE(hostlist);
277     }
278     return rc;
279 #else
280     return LDAP_NOT_SUPPORTED;
281 #endif /* HAVE_RES_QUERY */
282 }