diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2007-11-25 15:21:55 +0000 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2007-11-25 15:21:55 +0000 |
commit | fd4d98e5fe02711367cb71a1a056f103efab87a2 (patch) | |
tree | 7f857b5ffda75658ac9bc4ffda44aab137968d66 | |
parent | d4ea43b6a2d559852a24ba3d6a9ae7de0abd2615 (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-- | AUTHORS | 2 | ||||
-rw-r--r-- | README | 14 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | man/nss-ldapd.conf.5.xml | 8 | ||||
-rw-r--r-- | nslcd/cfg.c | 106 |
5 files changed, 120 insertions, 11 deletions
@@ -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> @@ -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); |