Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / openldap / dist / libraries / libldap / dnssrv.c
blobf6d5ddc400aaf9007a67cfd1ec466e760d31fdb0
1 /* $OpenLDAP: pkg/ldap/libraries/libldap/dnssrv.c,v 1.39.2.4 2008/02/11 23:26:41 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
5 * All rights reserved.
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.
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>.
17 * locate LDAP servers using DNS SRV records.
18 * Location code based on MIT Kerberos KDC location code.
20 #include "portable.h"
22 #include <stdio.h>
24 #include <ac/stdlib.h>
26 #include <ac/param.h>
27 #include <ac/socket.h>
28 #include <ac/string.h>
29 #include <ac/time.h>
31 #include "ldap-int.h"
33 #ifdef HAVE_ARPA_NAMESER_H
34 #include <arpa/nameser.h>
35 #endif
36 #ifdef HAVE_RESOLV_H
37 #include <resolv.h>
38 #endif
40 int ldap_dn2domain(
41 LDAP_CONST char *dn_in,
42 char **domainp)
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");
53 assert( dn_in != NULL );
54 assert( domainp != NULL );
56 *domainp = NULL;
58 if ( ldap_str2dn( dn_in, &dn, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) {
59 return -2;
62 if( dn ) for( i=0; dn[i] != NULL; i++ ) {
63 rdn = dn[i];
65 for( j=0; rdn[j] != NULL; j++ ) {
66 ava = rdn[j];
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 ) )
74 if( domain.bv_len == 0 ) {
75 ndomain = LDAP_REALLOC( domain.bv_val,
76 ava->la_value.bv_len + 1);
78 if( ndomain == NULL ) {
79 goto return_error;
82 domain.bv_val = ndomain;
84 AC_MEMCPY( domain.bv_val, ava->la_value.bv_val,
85 ava->la_value.bv_len );
87 domain.bv_len = ava->la_value.bv_len;
88 domain.bv_val[domain.bv_len] = '\0';
90 } else {
91 ndomain = LDAP_REALLOC( domain.bv_val,
92 ava->la_value.bv_len + sizeof(".") + domain.bv_len );
94 if( ndomain == NULL ) {
95 goto return_error;
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';
105 } else {
106 domain.bv_len = 0;
112 if( domain.bv_len == 0 && domain.bv_val != NULL ) {
113 LDAP_FREE( domain.bv_val );
114 domain.bv_val = NULL;
117 ldap_dnfree( dn );
118 *domainp = domain.bv_val;
119 return 0;
121 return_error:
122 ldap_dnfree( dn );
123 LDAP_FREE( domain.bv_val );
124 return -1;
127 int ldap_domain2dn(
128 LDAP_CONST char *domain_in,
129 char **dnp)
131 char *domain, *s, *tok_r, *dn, *dntmp;
132 size_t loc;
134 assert( domain_in != NULL );
135 assert( dnp != NULL );
137 domain = LDAP_STRDUP(domain_in);
138 if (domain == NULL) {
139 return LDAP_NO_MEMORY;
141 dn = NULL;
142 loc = 0;
144 for (s = ldap_pvt_strtok(domain, ".", &tok_r);
145 s != NULL;
146 s = ldap_pvt_strtok(NULL, ".", &tok_r))
148 size_t len = strlen(s);
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;
158 dn = dntmp;
160 if (loc > 0) {
161 /* not first time. */
162 strcpy(dn + loc, ",");
163 loc++;
165 strcpy(dn + loc, "dc=");
166 loc += sizeof("dc=")-1;
168 strcpy(dn + loc, s);
169 loc += len;
172 LDAP_FREE(domain);
173 *dnp = dn;
174 return LDAP_SUCCESS;
178 * Lookup and return LDAP servers for domain (using the DNS
179 * SRV record _ldap._tcp.domain).
181 int ldap_domain2hostlist(
182 LDAP_CONST char *domain,
183 char **list )
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];
192 assert( domain != NULL );
193 assert( list != NULL );
195 if( *domain == '\0' ) {
196 return LDAP_PARAM_ERROR;
199 request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp."));
200 if (request == NULL) {
201 return LDAP_NO_MEMORY;
203 sprintf(request, "_ldap._tcp.%s", domain);
205 #ifdef LDAP_R_COMPILE
206 ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex);
207 #endif
209 rc = LDAP_UNAVAILABLE;
210 #ifdef NS_HFIXEDSZ
211 /* Bind 8/9 interface */
212 len = res_query(request, ns_c_in, ns_t_srv, reply, sizeof(reply));
213 # ifndef T_SRV
214 # define T_SRV ns_t_srv
215 # endif
216 #else
217 /* Bind 4 interface */
218 # ifndef T_SRV
219 # define T_SRV 33
220 # endif
222 len = res_query(request, C_IN, T_SRV, reply, sizeof(reply));
223 #endif
224 if (len >= 0) {
225 unsigned char *p;
226 char host[DNSBUFSIZ];
227 int status;
228 u_short port;
229 /* int priority, weight; */
231 /* Parse out query */
232 p = reply;
234 #ifdef NS_HFIXEDSZ
235 /* Bind 8/9 interface */
236 p += NS_HFIXEDSZ;
237 #elif defined(HFIXEDSZ)
238 /* Bind 4 interface w/ HFIXEDSZ */
239 p += HFIXEDSZ;
240 #else
241 /* Bind 4 interface w/o HFIXEDSZ */
242 p += sizeof(HEADER);
243 #endif
245 status = dn_expand(reply, reply + len, p, host, sizeof(host));
246 if (status < 0) {
247 goto out;
249 p += status;
250 p += 4;
252 while (p < reply + len) {
253 int type, class, ttl, size;
254 status = dn_expand(reply, reply + len, p, host, sizeof(host));
255 if (status < 0) {
256 goto out;
258 p += status;
259 type = (p[0] << 8) | p[1];
260 p += 2;
261 class = (p[0] << 8) | p[1];
262 p += 2;
263 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
264 p += 4;
265 size = (p[0] << 8) | p[1];
266 p += 2;
267 if (type == T_SRV) {
268 int buflen;
269 status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
270 if (status < 0) {
271 goto out;
273 /* ignore priority and weight for now */
274 /* priority = (p[0] << 8) | p[1]; */
275 /* weight = (p[2] << 8) | p[3]; */
276 port = (p[4] << 8) | p[5];
278 if ( port == 0 || host[ 0 ] == '\0' ) {
279 goto add_size;
282 buflen = strlen(host) + STRLENOF(":65355 ");
283 hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen + 1);
284 if (hostlist == NULL) {
285 rc = LDAP_NO_MEMORY;
286 goto out;
288 if (cur > 0) {
289 /* not first time around */
290 hostlist[cur++] = ' ';
292 cur += sprintf(&hostlist[cur], "%s:%hd", host, port);
294 add_size:;
295 p += size;
298 if (hostlist == NULL) {
299 /* No LDAP servers found in DNS. */
300 rc = LDAP_UNAVAILABLE;
301 goto out;
304 rc = LDAP_SUCCESS;
305 *list = hostlist;
307 out:
308 #ifdef LDAP_R_COMPILE
309 ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex);
310 #endif
312 if (request != NULL) {
313 LDAP_FREE(request);
315 if (rc != LDAP_SUCCESS && hostlist != NULL) {
316 LDAP_FREE(hostlist);
318 return rc;
319 #else
320 return LDAP_NOT_SUPPORTED;
321 #endif /* HAVE_RES_QUERY */