From a466a643189d7a659da1d8331c53a9d54a021ab8 Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Mon, 3 Jan 2000 02:33:22 +0000 Subject: [PATCH] Added support for connecting to LDAP servers located using DNS SRV records. Added lock around resolver library which is shared by the DNS SRV code and the getdxbyname() code. --- include/ldap.h | 9 +- include/ldap_pvt.h | 5 + libraries/libldap/Makefile.in | 4 +- libraries/libldap/dnssrv.c | 209 ++++++++++++++++++++++++++++++++ libraries/libldap/getdxbyname.c | 8 ++ libraries/libldap/ldap-int.h | 5 + libraries/libldap/util-int.c | 7 ++ libraries/libldap_r/Makefile.in | 4 +- 8 files changed, 246 insertions(+), 5 deletions(-) create mode 100644 libraries/libldap/dnssrv.c diff --git a/include/ldap.h b/include/ldap.h index d2f1a145e3..322785c25d 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -554,7 +554,14 @@ LIBLDAP_F( void ) ldap_controls_free LDAP_P(( LDAPControl **ctrls )); - +/* + * in dnssrv.c: + */ +LIBLDAP_F( int ) +ldap_dnssrv_init LDAP_P(( + LDAP **ldp, + LDAP_CONST char *domain )); + /* * in extended.c: */ diff --git a/include/ldap_pvt.h b/include/ldap_pvt.h index d1b48c1c2e..a6674d7027 100644 --- a/include/ldap_pvt.h +++ b/include/ldap_pvt.h @@ -21,6 +21,11 @@ LDAP_BEGIN_DECL +LIBLDAP_F ( int ) +ldap_pvt_domain2dn LDAP_P(( + LDAP_CONST char *domain, + char **dn )); + struct hostent; /* avoid pulling in */ LIBLDAP_F( char * ) diff --git a/libraries/libldap/Makefile.in b/libraries/libldap/Makefile.in index 43bd9e7161..eb92ea5d18 100644 --- a/libraries/libldap/Makefile.in +++ b/libraries/libldap/Makefile.in @@ -17,7 +17,7 @@ SRCS = bind.c open.c result.c error.c compare.c search.c \ getdn.c getentry.c getattr.c getvalues.c addentry.c \ request.c getdxbyname.c os-ip.c url.c charset.c \ init.c options.c print.c string.c util-int.c schema.c \ - charray.c digest.c tls.c dn.c os-local.c + charray.c digest.c tls.c dn.c os-local.c dnssrv.c OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \ controls.lo messages.lo references.lo extended.lo \ modify.lo add.lo modrdn.lo delete.lo abandon.lo ufn.lo cache.lo \ @@ -26,7 +26,7 @@ OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \ getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \ request.lo getdxbyname.lo os-ip.lo url.lo charset.lo \ init.lo options.lo print.lo string.lo util-int.lo schema.lo \ - charray.lo digest.lo tls.lo dn.lo os-local.lo + charray.lo digest.lo tls.lo dn.lo os-local.lo dnssrv.lo LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries diff --git a/libraries/libldap/dnssrv.c b/libraries/libldap/dnssrv.c new file mode 100644 index 0000000000..3b87e3c9cc --- /dev/null +++ b/libraries/libldap/dnssrv.c @@ -0,0 +1,209 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +/* + * locate using DNS SRV records. Location code based on + * MIT Kerberos KDC location code. + */ +#include "portable.h" + +#include + +#include + +#include +#include +#include +#include + +#include "ldap-int.h" + +#ifdef HAVE_ARPA_NAMESER_H +#include +#endif +#ifdef HAVE_RESOLV_H +#include +#endif + +/* Sometimes this is not defined. */ +#ifndef T_SRV +#define T_SRV 33 +#endif /* T_SRV */ + +int ldap_pvt_domain2dn(LDAP_CONST char *domain_in, char **dnp) +{ + char *domain, *s, *tok_r, *dn; + size_t loc; + + if (domain_in == NULL || dnp == NULL) { + return LDAP_NO_MEMORY; + } + domain = LDAP_STRDUP(domain_in); + if (domain == NULL) { + return LDAP_NO_MEMORY; + } + dn = NULL; + loc = 0; + + for (s = ldap_pvt_strtok(domain, ".", &tok_r); + s != NULL; + s = ldap_pvt_strtok(NULL, ".", &tok_r)) { + size_t len = strlen(s); + + dn = (char *) LDAP_REALLOC(dn, loc + len + 4); + if (dn == NULL) { + LDAP_FREE(domain); + return LDAP_NO_MEMORY; + } + if (loc > 0) { + /* not first time. */ + strcpy(dn + loc, ","); + loc++; + } + strcpy(dn + loc, "dc="); + loc += 3; + + strcpy(dn + loc, s); + loc += len; + } + + LDAP_FREE(domain); + + *dnp = dn; + + return LDAP_SUCCESS; +} + +/* + * Lookup LDAP servers for domain (using the DNS + * SRV record _ldap._tcp.domain), set the default + * base using an algorithmic mapping of the domain, + * and return a session. + */ +int ldap_dnssrv_init(LDAP ** ldp, LDAP_CONST char *domain) +{ +#ifdef HAVE_RES_SEARCH + char *request; + char *dn; + char *hostlist = NULL; + LDAP *ld = NULL; + int rc, len, cur = 0; + unsigned char reply[1024]; + + request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp.")); + if (request == NULL) { + rc = LDAP_NO_MEMORY; + goto out; + } + sprintf(request, "_ldap._tcp.%s", domain); + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex); +#endif + + len = res_search(request, C_IN, T_SRV, reply, sizeof(reply)); + if (len >= 0) { + unsigned char *p; + char host[1024]; + int status; + u_short port; + int priority, weight; + + /* Parse out query */ + p = reply; + p += sizeof(HEADER); + status = dn_expand(reply, reply + len, p, host, sizeof(host)); + if (status < 0) { + goto out; + } + p += status; + p += 4; + + while (p < reply + len) { + int type, class, ttl, size; + status = dn_expand(reply, reply + len, p, host, sizeof(host)); + if (status < 0) { + goto out; + } + p += status; + type = (p[0] << 8) | p[1]; + p += 2; + class = (p[0] << 8) | p[1]; + p += 2; + ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + p += 4; + size = (p[0] << 8) | p[1]; + p += 2; + if (type == T_SRV) { + int buflen; + status = dn_expand(reply, reply + len, p + 6, host, sizeof(host)); + if (status < 0) { + goto out; + } + priority = (p[0] << 8) | p[1]; + weight = (p[2] << 8) | p[3]; + port = (p[4] << 8) | p[5]; + + buflen = strlen(host) + /* :XXXXX\0 */ 7; + hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen); + if (hostlist == NULL) { + rc = LDAP_NO_MEMORY; + goto out; + } + if (cur > 0) { + /* not first time around */ + hostlist[cur++] = ' '; + } + cur += sprintf(&hostlist[cur], "%s:%hd", host, port); + } + p += size; + } + } + if (hostlist == NULL) { + /* No LDAP servers found in DNS. */ + rc = LDAP_UNAVAILABLE; + goto out; + } + rc = ldap_create(&ld); + if (rc != LDAP_SUCCESS) { + goto out; + } + rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, hostlist); + if (rc != LDAP_SUCCESS) { + goto out; + } + rc = ldap_pvt_domain2dn(domain, &dn); + if (rc != LDAP_SUCCESS) { + goto out; + } + if (ld->ld_options.ldo_defbase != NULL) { + LDAP_FREE(ld->ld_options.ldo_defbase); + } + ld->ld_options.ldo_defbase = dn; + + *ldp = ld; + + rc = LDAP_SUCCESS; + + out: +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex); +#endif + + if (request != NULL) { + LDAP_FREE(request); + } + if (hostlist != NULL) { + LDAP_FREE(hostlist); + } + if (rc != LDAP_SUCCESS && ld != NULL) { + ldap_ld_free(ld, 1, NULL, NULL); + } + return rc; +#else + return LDAP_NOT_SUPPORTED; +#endif /* HAVE_RES_SEARCH */ +} diff --git a/libraries/libldap/getdxbyname.c b/libraries/libldap/getdxbyname.c index 602721a05e..841c311541 100644 --- a/libraries/libldap/getdxbyname.c +++ b/libraries/libldap/getdxbyname.c @@ -44,6 +44,10 @@ ldap_getdxbyname( const char *domain ) memset( buf, 0, sizeof( buf )); +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex); +#endif + if (( rc = res_search( domain, C_IN, T_TXT, buf, sizeof( buf ))) < 0 || ( dxs = decode_answer( buf, rc )) == NULL ) { /* @@ -60,6 +64,10 @@ ldap_getdxbyname( const char *domain ) } } +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex); +#endif + return( dxs ); } diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index 06914666c6..475c2ceb09 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -277,6 +277,11 @@ struct ldap { }; #define LDAP_VALID(ld) ( (ld)->ld_valid == LDAP_VALID_SESSION ) +#if defined(HAVE_RES_SEARCH) && defined(LDAP_R_COMPILE) +#include +extern ldap_pvt_thread_mutex_t ldap_int_resolv_mutex; +#endif /* HAVE_RES_SEARCH && LDAP_R_COMPILE */ + /* * in init.c */ diff --git a/libraries/libldap/util-int.c b/libraries/libldap/util-int.c index a3128e6e17..158f23472f 100644 --- a/libraries/libldap/util-int.c +++ b/libraries/libldap/util-int.c @@ -64,6 +64,9 @@ # ifndef HAVE_GETHOSTBYADDR_R static ldap_pvt_thread_mutex_t ldap_int_gethostbyaddr_mutex; # endif +# ifdef HAVE_RES_SEARCH + ldap_pvt_thread_mutex_t ldap_int_resolv_mutex; +# endif #endif /* LDAP_R_COMPILE */ char *ldap_pvt_ctime( const time_t *tp, char *buf ) @@ -274,6 +277,10 @@ void ldap_int_utils_init( void ) ldap_pvt_thread_mutex_init( &ldap_int_gethostbyaddr_mutex ); #endif +#ifdef HAVE_RES_SEARCH + ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex ); +#endif + /* call other module init functions here... */ #endif } diff --git a/libraries/libldap_r/Makefile.in b/libraries/libldap_r/Makefile.in index 3454faefee..43cf54d086 100644 --- a/libraries/libldap_r/Makefile.in +++ b/libraries/libldap_r/Makefile.in @@ -16,7 +16,7 @@ XXSRCS = apitest.c test.c tmpltest.c extended.c \ getdn.c getentry.c getattr.c getvalues.c addentry.c \ request.c getdxbyname.c os-ip.c url.c charset.c \ init.c options.c print.c string.c util-int.c schema.c \ - charray.c digest.c tls.c dn.c os-local.c + charray.c digest.c tls.c dn.c os-local.c dnssrv.c SRCS = thr_posix.c thr_cthreads.c thr_thr.c thr_lwp.c thr_nt.c \ thr_pth.c thr_sleep.c thr_stub.c rdwr.c OBJS = extended.lo \ @@ -29,7 +29,7 @@ OBJS = extended.lo \ init.lo options.lo print.lo string.lo util-int.lo schema.lo \ thr_posix.lo thr_cthreads.lo thr_thr.lo thr_lwp.lo thr_nt.lo \ thr_pth.lo thr_sleep.lo thr_stub.lo rdwr.lo \ - charray.lo digest.lo tls.lo dn.lo os-local.lo + charray.lo digest.lo tls.lo dn.lo os-local.lo dnssrv.lo LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries -- 2.39.5