Back to index

openldap  2.4.31
dnssrv.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 /*
00017  * locate LDAP servers using DNS SRV records.
00018  * Location code based on MIT Kerberos KDC location code.
00019  */
00020 #include "portable.h"
00021 
00022 #include <stdio.h>
00023 
00024 #include <ac/stdlib.h>
00025 
00026 #include <ac/param.h>
00027 #include <ac/socket.h>
00028 #include <ac/string.h>
00029 #include <ac/time.h>
00030 
00031 #include "ldap-int.h"
00032 
00033 #ifdef HAVE_ARPA_NAMESER_H
00034 #include <arpa/nameser.h>
00035 #endif
00036 #ifdef HAVE_RESOLV_H
00037 #include <resolv.h>
00038 #endif
00039 
00040 int ldap_dn2domain(
00041        LDAP_CONST char *dn_in,
00042        char **domainp)
00043 {
00044        int i, j;
00045        char *ndomain;
00046        LDAPDN dn = NULL;
00047        LDAPRDN rdn = NULL;
00048        LDAPAVA *ava = NULL;
00049        struct berval domain = BER_BVNULL;
00050        static const struct berval DC = BER_BVC("DC");
00051        static const struct berval DCOID = BER_BVC("0.9.2342.19200300.100.1.25");
00052 
00053        assert( dn_in != NULL );
00054        assert( domainp != NULL );
00055 
00056        *domainp = NULL;
00057 
00058        if ( ldap_str2dn( dn_in, &dn, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) {
00059               return -2;
00060        }
00061 
00062        if( dn ) for( i=0; dn[i] != NULL; i++ ) {
00063               rdn = dn[i];
00064 
00065               for( j=0; rdn[j] != NULL; j++ ) {
00066                      ava = rdn[j];
00067 
00068                      if( rdn[j+1] == NULL &&
00069                             (ava->la_flags & LDAP_AVA_STRING) &&
00070                             ava->la_value.bv_len &&
00071                             ( ber_bvstrcasecmp( &ava->la_attr, &DC ) == 0
00072                             || ber_bvcmp( &ava->la_attr, &DCOID ) == 0 ) )
00073                      {
00074                             if( domain.bv_len == 0 ) {
00075                                    ndomain = LDAP_REALLOC( domain.bv_val,
00076                                           ava->la_value.bv_len + 1);
00077 
00078                                    if( ndomain == NULL ) {
00079                                           goto return_error;
00080                                    }
00081 
00082                                    domain.bv_val = ndomain;
00083 
00084                                    AC_MEMCPY( domain.bv_val, ava->la_value.bv_val,
00085                                           ava->la_value.bv_len );
00086 
00087                                    domain.bv_len = ava->la_value.bv_len;
00088                                    domain.bv_val[domain.bv_len] = '\0';
00089 
00090                             } else {
00091                                    ndomain = LDAP_REALLOC( domain.bv_val,
00092                                           ava->la_value.bv_len + sizeof(".") + domain.bv_len );
00093 
00094                                    if( ndomain == NULL ) {
00095                                           goto return_error;
00096                                    }
00097 
00098                                    domain.bv_val = ndomain;
00099                                    domain.bv_val[domain.bv_len++] = '.';
00100                                    AC_MEMCPY( &domain.bv_val[domain.bv_len],
00101                                           ava->la_value.bv_val, ava->la_value.bv_len );
00102                                    domain.bv_len += ava->la_value.bv_len;
00103                                    domain.bv_val[domain.bv_len] = '\0';
00104                             }
00105                      } else {
00106                             domain.bv_len = 0;
00107                      }
00108               } 
00109        }
00110 
00111 
00112        if( domain.bv_len == 0 && domain.bv_val != NULL ) {
00113               LDAP_FREE( domain.bv_val );
00114               domain.bv_val = NULL;
00115        }
00116 
00117        ldap_dnfree( dn );
00118        *domainp = domain.bv_val;
00119        return 0;
00120 
00121 return_error:
00122        ldap_dnfree( dn );
00123        LDAP_FREE( domain.bv_val );
00124        return -1;
00125 }
00126 
00127 int ldap_domain2dn(
00128        LDAP_CONST char *domain_in,
00129        char **dnp)
00130 {
00131        char *domain, *s, *tok_r, *dn, *dntmp;
00132        size_t loc;
00133 
00134        assert( domain_in != NULL );
00135        assert( dnp != NULL );
00136 
00137        domain = LDAP_STRDUP(domain_in);
00138        if (domain == NULL) {
00139               return LDAP_NO_MEMORY;
00140        }
00141        dn = NULL;
00142        loc = 0;
00143 
00144        for (s = ldap_pvt_strtok(domain, ".", &tok_r);
00145               s != NULL;
00146               s = ldap_pvt_strtok(NULL, ".", &tok_r))
00147        {
00148               size_t len = strlen(s);
00149 
00150               dntmp = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len );
00151               if (dntmp == NULL) {
00152                   if (dn != NULL)
00153                      LDAP_FREE(dn);
00154                   LDAP_FREE(domain);
00155                   return LDAP_NO_MEMORY;
00156               }
00157 
00158               dn = dntmp;
00159 
00160               if (loc > 0) {
00161                   /* not first time. */
00162                   strcpy(dn + loc, ",");
00163                   loc++;
00164               }
00165               strcpy(dn + loc, "dc=");
00166               loc += sizeof("dc=")-1;
00167 
00168               strcpy(dn + loc, s);
00169               loc += len;
00170     }
00171 
00172        LDAP_FREE(domain);
00173        *dnp = dn;
00174        return LDAP_SUCCESS;
00175 }
00176 
00177 /*
00178  * Lookup and return LDAP servers for domain (using the DNS
00179  * SRV record _ldap._tcp.domain).
00180  */
00181 int ldap_domain2hostlist(
00182        LDAP_CONST char *domain,
00183        char **list )
00184 {
00185 #ifdef HAVE_RES_QUERY
00186 #define DNSBUFSIZ (64*1024)
00187     char *request;
00188     char *hostlist = NULL;
00189     int rc, len, cur = 0;
00190     unsigned char reply[DNSBUFSIZ];
00191 
00192        assert( domain != NULL );
00193        assert( list != NULL );
00194 
00195        if( *domain == '\0' ) {
00196               return LDAP_PARAM_ERROR;
00197        }
00198 
00199     request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp."));
00200     if (request == NULL) {
00201               return LDAP_NO_MEMORY;
00202     }
00203     sprintf(request, "_ldap._tcp.%s", domain);
00204 
00205     LDAP_MUTEX_LOCK(&ldap_int_resolv_mutex);
00206 
00207     rc = LDAP_UNAVAILABLE;
00208 #ifdef NS_HFIXEDSZ
00209        /* Bind 8/9 interface */
00210     len = res_query(request, ns_c_in, ns_t_srv, reply, sizeof(reply));
00211 #      ifndef T_SRV
00212 #             define T_SRV ns_t_srv
00213 #      endif
00214 #else
00215        /* Bind 4 interface */
00216 #      ifndef T_SRV
00217 #             define T_SRV 33
00218 #      endif
00219 
00220     len = res_query(request, C_IN, T_SRV, reply, sizeof(reply));
00221 #endif
00222     if (len >= 0) {
00223        unsigned char *p;
00224        char host[DNSBUFSIZ];
00225        int status;
00226        u_short port;
00227        /* int priority, weight; */
00228 
00229        /* Parse out query */
00230        p = reply;
00231 
00232 #ifdef NS_HFIXEDSZ
00233        /* Bind 8/9 interface */
00234        p += NS_HFIXEDSZ;
00235 #elif defined(HFIXEDSZ)
00236        /* Bind 4 interface w/ HFIXEDSZ */
00237        p += HFIXEDSZ;
00238 #else
00239        /* Bind 4 interface w/o HFIXEDSZ */
00240        p += sizeof(HEADER);
00241 #endif
00242 
00243        status = dn_expand(reply, reply + len, p, host, sizeof(host));
00244        if (status < 0) {
00245            goto out;
00246        }
00247        p += status;
00248        p += 4;
00249 
00250        while (p < reply + len) {
00251            int type, class, ttl, size;
00252            status = dn_expand(reply, reply + len, p, host, sizeof(host));
00253            if (status < 0) {
00254               goto out;
00255            }
00256            p += status;
00257            type = (p[0] << 8) | p[1];
00258            p += 2;
00259            class = (p[0] << 8) | p[1];
00260            p += 2;
00261            ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
00262            p += 4;
00263            size = (p[0] << 8) | p[1];
00264            p += 2;
00265            if (type == T_SRV) {
00266               int buflen;
00267               status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
00268               if (status < 0) {
00269                   goto out;
00270               }
00271               /* ignore priority and weight for now */
00272               /* priority = (p[0] << 8) | p[1]; */
00273               /* weight = (p[2] << 8) | p[3]; */
00274               port = (p[4] << 8) | p[5];
00275 
00276               if ( port == 0 || host[ 0 ] == '\0' ) {
00277                   goto add_size;
00278               }
00279 
00280               buflen = strlen(host) + STRLENOF(":65355 ");
00281               hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen + 1);
00282               if (hostlist == NULL) {
00283                   rc = LDAP_NO_MEMORY;
00284                   goto out;
00285               }
00286               if (cur > 0) {
00287                   /* not first time around */
00288                   hostlist[cur++] = ' ';
00289               }
00290               cur += sprintf(&hostlist[cur], "%s:%hu", host, port);
00291            }
00292 add_size:;
00293            p += size;
00294        }
00295     }
00296     if (hostlist == NULL) {
00297        /* No LDAP servers found in DNS. */
00298        rc = LDAP_UNAVAILABLE;
00299        goto out;
00300     }
00301 
00302     rc = LDAP_SUCCESS;
00303        *list = hostlist;
00304 
00305   out:
00306     LDAP_MUTEX_UNLOCK(&ldap_int_resolv_mutex);
00307 
00308     if (request != NULL) {
00309        LDAP_FREE(request);
00310     }
00311     if (rc != LDAP_SUCCESS && hostlist != NULL) {
00312        LDAP_FREE(hostlist);
00313     }
00314     return rc;
00315 #else
00316     return LDAP_NOT_SUPPORTED;
00317 #endif /* HAVE_RES_QUERY */
00318 }