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