]> git.sur5r.net Git - openldap/blob - libraries/libldap/dnssrv.c
Move ldap_utf8_*() declarations from ldap-int.h to ldap_pvt.h.
[openldap] / libraries / libldap / dnssrv.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 /*
8  * locate using DNS SRV records. Location code based on
9  * 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_pvt_domain2dn(LDAP_CONST char *domain_in, char **dnp)
37 {
38     char *domain, *s, *tok_r, *dn;
39     size_t loc;
40
41     if (domain_in == NULL || dnp == NULL) {
42         return LDAP_NO_MEMORY;
43     }
44     domain = LDAP_STRDUP(domain_in);
45     if (domain == NULL) {
46         return LDAP_NO_MEMORY;
47     }
48     dn = NULL;
49     loc = 0;
50
51     for (s = ldap_pvt_strtok(domain, ".", &tok_r);
52          s != NULL;
53          s = ldap_pvt_strtok(NULL, ".", &tok_r)) {
54         size_t len = strlen(s);
55
56         dn = (char *) LDAP_REALLOC(dn, loc + len + 4);
57         if (dn == NULL) {
58             LDAP_FREE(domain);
59             return LDAP_NO_MEMORY;
60         }
61         if (loc > 0) {
62             /* not first time. */
63             strcpy(dn + loc, ",");
64             loc++;
65         }
66         strcpy(dn + loc, "dc=");
67         loc += 3;
68
69         strcpy(dn + loc, s);
70         loc += len;
71     }
72
73     LDAP_FREE(domain);
74
75     *dnp = dn;
76
77     return LDAP_SUCCESS;
78 }
79
80 /*
81  * Lookup LDAP servers for domain (using the DNS
82  * SRV record _ldap._tcp.domain), set the default
83  * base using an algorithmic mapping of the domain,
84  * and return a session.
85  */
86 int ldap_dnssrv_init(LDAP ** ldp, LDAP_CONST char *domain)
87 {
88 #ifdef HAVE_RES_SEARCH
89     char *request;
90     char *dn;
91     char *hostlist = NULL;
92     LDAP *ld = NULL;
93     int rc, len, cur = 0;
94     unsigned char reply[1024];
95
96     request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp."));
97     if (request == NULL) {
98         rc = LDAP_NO_MEMORY;
99         goto out;
100     }
101     sprintf(request, "_ldap._tcp.%s", domain);
102
103 #ifdef LDAP_R_COMPILE
104     ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex);
105 #endif
106
107     len = res_search(request, C_IN, T_SRV, reply, sizeof(reply));
108     if (len >= 0) {
109         unsigned char *p;
110         char host[1024];
111         int status;
112         u_short port;
113         int priority, weight;
114
115         /* Parse out query */
116         p = reply;
117         p += sizeof(HEADER);
118         status = dn_expand(reply, reply + len, p, host, sizeof(host));
119         if (status < 0) {
120             goto out;
121         }
122         p += status;
123         p += 4;
124
125         while (p < reply + len) {
126             int type, class, ttl, size;
127             status = dn_expand(reply, reply + len, p, host, sizeof(host));
128             if (status < 0) {
129                 goto out;
130             }
131             p += status;
132             type = (p[0] << 8) | p[1];
133             p += 2;
134             class = (p[0] << 8) | p[1];
135             p += 2;
136             ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
137             p += 4;
138             size = (p[0] << 8) | p[1];
139             p += 2;
140             if (type == T_SRV) {
141                 int buflen;
142                 status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
143                 if (status < 0) {
144                     goto out;
145                 }
146                 priority = (p[0] << 8) | p[1];
147                 weight = (p[2] << 8) | p[3];
148                 port = (p[4] << 8) | p[5];
149
150                 buflen = strlen(host) + /* :XXXXX\0 */ 7;
151                 hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen);
152                 if (hostlist == NULL) {
153                     rc = LDAP_NO_MEMORY;
154                     goto out;
155                 }
156                 if (cur > 0) {
157                     /* not first time around */
158                     hostlist[cur++] = ' ';
159                 }
160                 cur += sprintf(&hostlist[cur], "%s:%hd", host, port);
161             }
162             p += size;
163         }
164     }
165     if (hostlist == NULL) {
166         /* No LDAP servers found in DNS. */
167         rc = LDAP_UNAVAILABLE;
168         goto out;
169     }
170     rc = ldap_create(&ld);
171     if (rc != LDAP_SUCCESS) {
172         goto out;
173     }
174     rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, hostlist);
175     if (rc != LDAP_SUCCESS) {
176         goto out;
177     }
178     rc = ldap_pvt_domain2dn(domain, &dn);
179     if (rc != LDAP_SUCCESS) {
180         goto out;
181     }
182     if (ld->ld_options.ldo_defbase != NULL) {
183         LDAP_FREE(ld->ld_options.ldo_defbase);
184     }
185     ld->ld_options.ldo_defbase = dn;
186
187     *ldp = ld;
188
189     rc = LDAP_SUCCESS;
190
191   out:
192 #ifdef LDAP_R_COMPILE
193     ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex);
194 #endif
195
196     if (request != NULL) {
197         LDAP_FREE(request);
198     }
199     if (hostlist != NULL) {
200         LDAP_FREE(hostlist);
201     }
202     if (rc != LDAP_SUCCESS && ld != NULL) {
203         ldap_ld_free(ld, 1, NULL, NULL);
204     }
205     return rc;
206 #else
207     return LDAP_NOT_SUPPORTED;
208 #endif                          /* HAVE_RES_SEARCH */
209 }