summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2007-11-25 15:21:55 +0000
committerArthur de Jong <arthur@arthurdejong.org>2007-11-25 15:21:55 +0000
commitfd4d98e5fe02711367cb71a1a056f103efab87a2 (patch)
tree7f857b5ffda75658ac9bc4ffda44aab137968d66
parentd4ea43b6a2d559852a24ba3d6a9ae7de0abd2615 (diff)
implement LDAP server discovery through DNS, based on a patch by Ralf Haferkamp <rhafer@suse.de> and Michael Calmer <mc@suse.de>
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-ldapd@480 ef36b2f9-881f-0410-afb5-c4e39611909c
-rw-r--r--AUTHORS2
-rw-r--r--README14
-rw-r--r--configure.ac1
-rw-r--r--man/nss-ldapd.conf.5.xml8
-rw-r--r--nslcd/cfg.c106
5 files changed, 120 insertions, 11 deletions
diff --git a/AUTHORS b/AUTHORS
index 8b32f41..50f9041 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -68,3 +68,5 @@ Américo Monteiro <a_monteiro@netcabo.pt>
Cyril Brulebois <cyril.brulebois@enst-bretagne.fr>
Kenshi Muto <kmuto@debian.org>
Andreas Schneider <anschneider@suse.de>
+Ralf Haferkamp <rhafer@suse.de>
+Michael Calmer <mc@suse.de>
diff --git a/README b/README
index 5cef5ce..69d40c8 100644
--- a/README
+++ b/README
@@ -140,7 +140,6 @@ and may cause problems.
well as nested groups are currently unsupported (support will be re-added
later)
- SASL and Kerberos configuration is untested
-- server discovery using DNS has been removed
- rootbinddn/rootbindpw support is disabled (support will be added later)
In general, development is ongoing and a lot has to be cleaned up. The focus
@@ -209,6 +208,19 @@ contain something like:
# search base for all queries.
base dc=example,dc=net
+service discovery through DNS
+-----------------------------
+
+nss-ldapd supports looking up LDAP server names through DNS SRV records as
+specified in RFC 2782, except that Priority and Weight are not considered
+separately and a single list of servers in added as if they had been specified
+with uri options in the configuration file.
+
+To use this feature specify DNS as an uri in the configuration file and
+include something like the following in your zone:
+
+ _ldap._tcp SRV 10 0 389 bobo
+
LDAP SCHEMA
===========
diff --git a/configure.ac b/configure.ac
index cf326a9..08a2ede 100644
--- a/configure.ac
+++ b/configure.ac
@@ -310,6 +310,7 @@ AC_CHECK_FUNCS(ldap_init ldap_get_lderrno ldap_parse_result ldap_memfree ldap_co
AC_CHECK_FUNCS(ldap_ld_free ldap_explode_rdn ldap_set_option ldap_get_option)
AC_CHECK_FUNCS(ldap_sasl_interactive_bind_s ldap_initialize ldap_search_ext)
AC_CHECK_FUNCS(ldap_create_control ldap_create_page_control ldap_parse_page_control)
+AC_CHECK_FUNCS(ldap_domain2hostlist ldap_domain2dn)
AC_CHECK_FUNCS(ldap_set_rebind_proc)
AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, nss_ldap_cv_ldap_set_rebind_proc, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
diff --git a/man/nss-ldapd.conf.5.xml b/man/nss-ldapd.conf.5.xml
index 278e707..2936ca3 100644
--- a/man/nss-ldapd.conf.5.xml
+++ b/man/nss-ldapd.conf.5.xml
@@ -121,6 +121,9 @@
<acronym>LDAP</acronym> over <acronym>TCP</acronym>,
<acronym>ICP</acronym> or <acronym>SSL</acronym> respectively (if
supported by the <acronym>LDAP</acronym> library).
+ Alternitively, the value <emphasis remap="I">DNS</emphasis> may be
+ used to try to lookup the server using <acronym>DNS</acronym>
+ <acronym>SRV</acronym> records.
</para>
<para>
When using the ldapi scheme, %2f should be used to escape slashes
@@ -281,6 +284,11 @@
A global search base may be specified or a MAP-specific one.
If no MAP-specific search base is defined the global one is used.
</para>
+ <para>
+ If, instead of a <acronym>DN</acronym>, the value
+ <emphasis remap="I">DOMAIN</emphasis> is specified, the hosts
+ <acronym>DNS</acronym> domain is used to construct a basedn.
+ </para>
</listitem>
</varlistentry>
diff --git a/nslcd/cfg.c b/nslcd/cfg.c
index 82f8090..e64c2db 100644
--- a/nslcd/cfg.c
+++ b/nslcd/cfg.c
@@ -148,6 +148,71 @@ static void add_uri(const char *filename,int lnr,
cfg->ldc_uris[i+1]=NULL;
}
+/* return the domain name of the current host
+ we return part of the structure that is retured by gethostbyname()
+ so there should be no need to free() this entry, however we should
+ use the value before any other call to gethostbyname() */
+static const char *cfg_getdomainname(const char *filename,int lnr)
+{
+ char hostname[HOST_NAME_MAX],*domain;
+ struct hostent *host;
+ /* lookup the hostname and with that the fqdn to extract the domain */
+ if (gethostname(hostname,sizeof(hostname))<0)
+ {
+ log_log(LOG_ERR,"%s:%d: gethostname(): %s",filename,lnr,strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if ((host=gethostbyname(hostname))==NULL)
+ {
+ log_log(LOG_ERR,"%s:%d: gethostbyname(%s): %s",filename,lnr,hostname,hstrerror(h_errno));
+ exit(EXIT_FAILURE);
+ }
+ /* TODO: this may fail if the fqdn is in h_aliases */
+ if ((domain=strchr(host->h_name,'.'))==NULL)
+ {
+ log_log(LOG_ERR,"%s:%d: host name %s is not in fqdn form",filename,lnr,host->h_name);
+ exit(EXIT_FAILURE);
+ }
+ /* we're done */
+ return domain+1;
+}
+
+/* add URIs by doing DNS queries for SRV records */
+static void add_uris_from_dns(const char *filename,int lnr,
+ struct ldap_config *cfg)
+{
+ int ret=0;
+ const char *domain;
+ char *hostlist=NULL,*nxt;
+ char buf[HOST_NAME_MAX+sizeof("ldap://")];
+ domain=cfg_getdomainname(filename,lnr);
+ ret=ldap_domain2hostlist(domain,&hostlist);
+ /* FIXME: have better error handling */
+ if ((hostlist==NULL)||(*hostlist=='\0'))
+ {
+ log_log(LOG_ERR,"%s:%d: no servers found in DNS zone %s",filename,lnr,domain);
+ exit(EXIT_FAILURE);
+ }
+ /* hostlist is a space-separated list of host names that we use to build
+ URIs */
+ while(hostlist!=NULL)
+ {
+ /* find the next space and split the string there */
+ nxt=strchr(hostlist,' ');
+ if (nxt!=NULL)
+ {
+ *nxt='\0';
+ nxt++;
+ }
+ /* add the URI */
+ snprintf(buf,sizeof(buf),"ldap://%s",hostlist);
+ log_log(LOG_DEBUG,"add_uris_from_dns(): found uri: %s",buf);
+ add_uri(filename,lnr,cfg,buf);
+ /* get next entry from list */
+ hostlist=nxt;
+ }
+}
+
static int parse_boolean(const char *filename,int lnr,const char *value)
{
if ( (strcasecmp(value,"on")==0) ||
@@ -225,6 +290,28 @@ static inline void check_argumentcount(const char *filename,int lnr,
}
}
+/* assigns the base to the specified variable doing domain expansion
+ and a simple check to avoid overwriting duplicate values */
+static void set_base(const char *filename,int lnr,
+ const char *value,const char **var)
+{
+ char *domaindn=NULL;
+ /* if the base is "DOMAIN" use the domain name */
+ if (strcasecmp(value,"domain")==0)
+ {
+ ldap_domain2dn(cfg_getdomainname(filename,lnr),&domaindn);
+ log_log(LOG_DEBUG,"set_base(): setting base to %s from domain",domaindn);
+ value=domaindn;
+ }
+ /* check if the value will be changed */
+ if ((*var==NULL)||(strcmp(*var,value)!=0))
+ {
+ /* Note: we have a memory leak here if a single mapping is changed
+ multiple times in one config (deemed not a problem) */
+ *var=xstrdup(value);
+ }
+}
+
static void parse_base_statement(const char *filename,int lnr,
const char **opts,int nopts,
struct ldap_config *cfg)
@@ -232,7 +319,7 @@ static void parse_base_statement(const char *filename,int lnr,
enum ldap_map_selector map;
const char **var;
if (nopts==2)
- cfg->ldc_base=xstrdup(opts[1]);
+ set_base(filename,lnr,opts[1],(const char **)&(cfg->ldc_base));
else if (nopts==3)
{
/* get the map */
@@ -244,13 +331,7 @@ static void parse_base_statement(const char *filename,int lnr,
log_log(LOG_ERR,"%s:%d: unknown map: '%s'",filename,lnr,opts[1]);
exit(EXIT_FAILURE);
}
- /* check if the value will be changed */
- if ((*var==NULL)||(strcmp(*var,opts[2])!=0))
- {
- /* Note: we have a memory leak here if a single mapping is changed
- multiple times in one config (deemed not a problem) */
- *var=xstrdup(opts[2]);
- }
+ set_base(filename,lnr,opts[2],var);
}
else
check_argumentcount(filename,lnr,opts[0],0);
@@ -437,7 +518,12 @@ static void cfg_read(const char *filename,struct ldap_config *cfg)
{
check_argumentcount(filename,lnr,opts[0],nopts>1);
for (i=1;i<nopts;i++)
- add_uri(filename,lnr,cfg,opts[i]);
+ {
+ if (strcasecmp(opts[i],"dns")==0)
+ add_uris_from_dns(filename,lnr,cfg);
+ else
+ add_uri(filename,lnr,cfg,opts[i]);
+ }
}
else if (strcasecmp(opts[0],"ldap_version")==0)
{
@@ -694,7 +780,7 @@ void cfg_init(const char *fname)
/* read configfile */
cfg_read(fname,nslcd_cfg);
/* do some sanity checks */
- if (nslcd_cfg->ldc_uris[0] == NULL)
+ if (nslcd_cfg->ldc_uris[0]==NULL)
{
log_log(LOG_ERR,"no URIs defined in config");
exit(EXIT_FAILURE);