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.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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.
24 #include <ac/stdlib.h>
27 #include <ac/socket.h>
28 #include <ac/string.h>
33 #ifdef HAVE_ARPA_NAMESER_H
34 #include <arpa/nameser.h>
41 LDAP_CONST
char *dn_in
,
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
);
58 if ( ldap_str2dn( dn_in
, &dn
, LDAP_DN_FORMAT_LDAP
) != LDAP_SUCCESS
) {
62 if( dn
) for( i
=0; dn
[i
] != NULL
; i
++ ) {
65 for( j
=0; rdn
[j
] != NULL
; 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
) {
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';
91 ndomain
= LDAP_REALLOC( domain
.bv_val
,
92 ava
->la_value
.bv_len
+ sizeof(".") + domain
.bv_len
);
94 if( ndomain
== NULL
) {
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';
112 if( domain
.bv_len
== 0 && domain
.bv_val
!= NULL
) {
113 LDAP_FREE( domain
.bv_val
);
114 domain
.bv_val
= NULL
;
118 *domainp
= domain
.bv_val
;
123 LDAP_FREE( domain
.bv_val
);
128 LDAP_CONST
char *domain_in
,
131 char *domain
, *s
, *tok_r
, *dn
, *dntmp
;
134 assert( domain_in
!= NULL
);
135 assert( dnp
!= NULL
);
137 domain
= LDAP_STRDUP(domain_in
);
138 if (domain
== NULL
) {
139 return LDAP_NO_MEMORY
;
144 for (s
= ldap_pvt_strtok(domain
, ".", &tok_r
);
146 s
= ldap_pvt_strtok(NULL
, ".", &tok_r
))
148 size_t len
= strlen(s
);
150 dntmp
= (char *) LDAP_REALLOC(dn
, loc
+ sizeof(",dc=") + len
);
155 return LDAP_NO_MEMORY
;
161 /* not first time. */
162 strcpy(dn
+ loc
, ",");
165 strcpy(dn
+ loc
, "dc=");
166 loc
+= sizeof("dc=")-1;
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
,
185 #ifdef HAVE_RES_QUERY
186 #define DNSBUFSIZ (64*1024)
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
);
209 rc
= LDAP_UNAVAILABLE
;
211 /* Bind 8/9 interface */
212 len
= res_query(request
, ns_c_in
, ns_t_srv
, reply
, sizeof(reply
));
214 # define T_SRV ns_t_srv
217 /* Bind 4 interface */
222 len
= res_query(request
, C_IN
, T_SRV
, reply
, sizeof(reply
));
226 char host
[DNSBUFSIZ
];
229 /* int priority, weight; */
231 /* Parse out query */
235 /* Bind 8/9 interface */
237 #elif defined(HFIXEDSZ)
238 /* Bind 4 interface w/ HFIXEDSZ */
241 /* Bind 4 interface w/o HFIXEDSZ */
245 status
= dn_expand(reply
, reply
+ len
, p
, host
, sizeof(host
));
252 while (p
< reply
+ len
) {
253 int type
, class, ttl
, size
;
254 status
= dn_expand(reply
, reply
+ len
, p
, host
, sizeof(host
));
259 type
= (p
[0] << 8) | p
[1];
261 class = (p
[0] << 8) | p
[1];
263 ttl
= (p
[0] << 24) | (p
[1] << 16) | (p
[2] << 8) | p
[3];
265 size
= (p
[0] << 8) | p
[1];
269 status
= dn_expand(reply
, reply
+ len
, p
+ 6, host
, sizeof(host
));
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' ) {
282 buflen
= strlen(host
) + STRLENOF(":65355 ");
283 hostlist
= (char *) LDAP_REALLOC(hostlist
, cur
+ buflen
+ 1);
284 if (hostlist
== NULL
) {
289 /* not first time around */
290 hostlist
[cur
++] = ' ';
292 cur
+= sprintf(&hostlist
[cur
], "%s:%hd", host
, port
);
298 if (hostlist
== NULL
) {
299 /* No LDAP servers found in DNS. */
300 rc
= LDAP_UNAVAILABLE
;
308 #ifdef LDAP_R_COMPILE
309 ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex
);
312 if (request
!= NULL
) {
315 if (rc
!= LDAP_SUCCESS
&& hostlist
!= NULL
) {
320 return LDAP_NOT_SUPPORTED
;
321 #endif /* HAVE_RES_QUERY */