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