summaryrefslogtreecommitdiff
path: root/nslcd
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 /nslcd
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
Diffstat (limited to 'nslcd')
-rw-r--r--nslcd/cfg.c106
1 files changed, 96 insertions, 10 deletions
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);