Quellcode durchsuchen

- support for multi-value filtering when generating records
- client side filtering via set_dbopt ("client_side_filtering"), to enable resonable filtering of multivalue fields and fields without ordering rules
- all comparision operations supported by filter (requires appropriate rules at LDAP server), otherwise client side filtering may be applied
- generalized time timezone and localtime, ZULU support
- generalized time fraction seconds support
- support for alias dereferencing in openldap, option in table definition
- support for referral dereferencing in openldap, option in table definition
- doc added

Tomas Mandys vor 17 Jahren
Ursprung
Commit
8a5e170a07

+ 222 - 0
modules_s/ldap/README

@@ -0,0 +1,222 @@
+
+1. ldap module
+
+Jan Janak
+
+   Iptel.org
+
+   Copyright © 2008 Iptel.org GmBH
+   Revision History
+   Revision $Revision$ $Date$
+     _________________________________________________________________
+
+   1.1. Overview
+   1.2. Dependencies
+   1.3. Parameters
+
+        1.3.1. config (string)
+        1.3.2. reconnect_attempt (integer)
+
+   1.4. Functions
+
+1.1. Overview
+
+   The LDAP module is database driver, i.e. it implements DB API functions. The
+   goal is map database query defined by table, matching fields and result
+   fields to LDAP search in sub-tree defined by root, object class, attributes
+   and pass it to the OpenLDAP which communicates with the LDAP server.
+
+   This procedure is sometimes tricky because the LDAP does not support all
+   database features or supports them in different manner. Here we must express
+   especially filtering and multi-values. The multi-value is de facto array of
+   single values. If the LDAP module get a multi-value field then generates
+   record for every single value, respectively for every combination in case
+   the more fields contain multi-value.
+
+   The LDAP supports natively "AND", "OR", "NOT" logical operators and "equal",
+   "non-equal", "less-or-equal" and "greater-or-equal" comparison operators.
+   Therefore    "less"    and   "greater"   operators   are   mapped   as
+   "less/greater-or-equal-AND-not-equal". It's important realize it when the
+   attribute which will be used for filtering may contain multi-value. The LDAP
+   server evaluates comparison operator on multi-value so that the result for
+   record is true if the condition is satisfied for any single value. The
+   single values not satisfying condition are not truncated. It implies two
+   cases for positive comparison, e.g. "equal", the result contains values not
+   satisfying the condition, the case may be handled by additional filter in
+   the LDAP module, the negative comparison, e.g. "non-equal", does not return
+   record at all. Because the LDAP module cannot know if the LDAP attribute may
+   logically  contain  multi-value  so  there is introduced DB API option
+   client_side_filtering which forces filtering such fields in the LDAP module,
+   i.e.  the  LDAP server returns larger result set because the filtering
+   condition is not passed there.
+
+   The necessary condition of successful filtering of particular attribute at
+   the LDAP server is correct attribute definition. The "equal"/"non-equal"
+   operator requires equality matching rule, the "greater"/"less" operator
+   requires ordering matching rule. If required matching rule is missing the
+   LDAP server silently returns empty result set. In case of double filtering
+   both at the LDAP servar and the LDAP module, e.g. multi-value and equal
+   comparison, check the LDAP server matching rule satisfies your needs or use
+   client_side_filtering feature.
+
+   The LDAP server may be identified either complete specification of host,
+   user, password in URI or is specification reference to connection section of
+   config file. Note in the second case there is only one slash.
+
+   Example 1. URI example
+        ...
+        modparam("auth", "db_url", "ldap://admin:[email protected]");
+
+        modparam("auth", "db_url", "ldap:/ldap_server1");
+
+        ...
+
+   Features:
+     * simple, SASL authentication, TLS
+     * server and client side filtering
+     * read-only queries
+     * optional referral chasing by OpenLDAP
+     * optional reference chasing by OpenLDAP
+
+1.2. Dependencies
+
+   none
+
+1.3. Parameters
+
+1.3.1. config (string)
+
+   Default value is ldap.cfg.
+
+   The filename (relatively to ser config file) of mapping database to LDAP
+   definition. It is the main configuration file for the LDAP module in SER.
+   The  configuration  file maps database table names used in SER to LDAP
+   directory sub-trees to be searched. In addition to that the configuration
+   file also allows to configure the LDAP search filter and maps database field
+   names to LDAP attribute names and vice versa.
+
+   Example 2. Example config
+        ...
+        modparam("ldap", "config", "my-ldap.cfg");
+        ...
+
+   Example 3. Configuration file example
+# Supported Attribute Type Names:
+#  * GeneralizedTime
+#  * Integer
+#  * BitString
+#  * Boolean
+#  * String
+#  * Binary
+#  * Float
+#
+
+[connection:ldap_server1]
+host=127.0.0.1
+port=389
+username=ser
+password=heslo
+# LDAP or LDAP SASL authentication mechanism.
+# Allowed values: none (default), simple, digest-md5, external
+authtype=simple
+
+# tls encryption
+tls=off
+
+# Specifies the file that contains certificates for all of the Certificate
+# Authorities the ldap module will recognize.
+ca_list=/home/kg/work/openssl/demoCA/cacert.pem
+
+# Specifies what checks to perform on server certificates in a TLS session
+# allowed values are never/allow/try/demand
+# see the TLS_REQCERT tls option part of ldap.conf(8) man page for more details
+require_certificate=demand
+
+#
+# Table credentials contains SIP digest authentication credentials.
+#
+[table:credentials]
+
+# In our LDAP directory we store SIP digest credentials under
+# "Digest Credentials" organization unit so this is where searches for digest
+# credentials should start.
+base = "ou=Digest Credentials,dc=iptel,dc=org"
+
+# We search the whole subtree.
+scope = subtree
+
+# For digest credentials we are only interested in objects with objectClass
+# 'digestAuthCredentials', objects of all other types are ignored.
+filter = "(objectClass=digestAuthCredentials)"
+
+# Mapping of field names to LDAP attribute names and vice versa. Names are
+# delimited using ':', the first name is database field name as used in SER
+# modules, the second name (after :) is corresponding LDAP attribute name,
+# optionally preceeded with LDAP attribute syntax name in parentheses.
+field_map = password : (Binary) digestPassword
+field_map = realm : digestRealm
+field_map = auth_username : digestUsername
+field_map = uid : serUID
+field_map = flags : (BitString) serFlags
+
+# retrieve at most sizelimit entries for a search
+#sizelimit = 2147483647
+
+# wait at most timelimit seconds for a search to complete
+#timelimit = 120
+
+# chase references automatically by OpenLDAP. Default is "never"
+# chase_references = never | searching | finding | always
+
+# chase referrals automatically by OpenLDAP. Default is "no"
+# chase_referrals = yes | no
+
+#
+# Domain table stores information about virtual domains
+#
+[table:domain]
+
+# Objects mapping domain IDs to domain names and vice versa are stored
+# in the subtree with the following root:
+base = "ou=Domains,dc=iptel,dc=org"
+
+scope = subtree
+
+# We are only interested in serDomain objects when looking up information
+# about virtual domains.
+filter = "(objectClass=serDomain)"
+
+field_map = did : (String) serDID
+field_map = domain : (String) serDomain
+field_map = flags : (BitString) serFlags
+
+#
+# Table domain_attrs contains domain attributes, domain attributes store
+# extra information about virtual domains.
+#
+[table:domain_attrs]
+base = "ou=Domains, dc=iptel,dc=org"
+scope = subtree
+
+filter = "(objectClass=serDomainAttr)"
+
+field_map = did : serDID
+field_map = name : serAttrName
+field_map = type : (Integer) serAttrType
+field_map = value : serAttrValue
+field_map = flags : (BitString) serFlags
+
+1.3.2. reconnect_attempt (integer)
+
+   Default value is 3.
+
+   Number of reconnect attempts when connection to the LDAP server is lost.
+
+   Example 4. Example reconnect_attempt
+        ...
+        modparam("ldap", "reconnect_attempt", "5");
+        ...
+
+1.4. Functions
+
+   none

+ 29 - 0
modules_s/ldap/doc/Makefile

@@ -0,0 +1,29 @@
+#
+# The list of documents to build (without extensions)
+#
+DOCUMENTS = ldap
+
+#
+# The root directory containing Makefile.doc
+#
+ROOT_DIR=../../..
+
+#
+# Validate docbook documents before generating output
+# (may be slow)
+#
+#VALIDATE=1
+
+#
+# You can override the stylesheet used to generate
+# xhtml documents here
+#
+#XHTML_XSL=$(ROOT_DIR)/doc/stylesheets/xhtml.xsl
+
+#
+# You can override the stylesheet used to generate
+# plain text documents here
+#
+#TXT_XSL=$(XHTML_XSL)
+
+include $(ROOT_DIR)/Makefile.doc

+ 310 - 0
modules_s/ldap/doc/ldap.xml

@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="ldap" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<authorgroup>
+	    <author>
+		<firstname>Jan</firstname>
+		<surname>Janak</surname>
+		<affiliation><orgname>Iptel.org</orgname></affiliation>
+		<address>
+		    <email>jan  at iptel dot org</email>
+		</address>
+	    </author>
+	</authorgroup>
+	<copyright>
+	    <year>2008</year>
+	    <holder>Iptel.org GmBH</holder>
+	</copyright>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+
+    </sectioninfo>
+
+    <title>ldap module</title>
+
+    <section id="ldap.overview">
+		<title>Overview</title>
+		<para>
+		The LDAP module is database driver, i.e. it implements DB API functions.
+		The goal is map database query defined by table, matching fields and result fields
+		to LDAP search in sub-tree defined by root, object class, attributes and
+		pass it to the <emphasis>OpenLDAP</emphasis> which communicates with the LDAP server.
+		</para>
+		
+		<para>
+		This procedure is sometimes tricky because the LDAP does not support
+		all database features or supports them in different manner. Here we
+		must express especially <emphasis>filtering</emphasis> and <emphasis>
+		multi-values</emphasis>. The multi-value is de facto array of single
+		values. If the LDAP module get a multi-value field then generates
+		record for every single value, respectively for every combination
+		in case the more fields contain multi-value.
+		</para>
+
+		<para>		
+		The LDAP supports natively "AND", "OR", "NOT" logical operators and "equal", "non-equal",
+		"less-or-equal" and "greater-or-equal" comparison operators. Therefore
+		"less" and "greater" operators are mapped as "less/greater-or-equal-AND-not-equal".
+		It's important realize it when the attribute which will be used for
+		filtering may contain multi-value. 
+		The LDAP server evaluates comparison operator on multi-value so that
+		the result for record is true if the condition is satisfied for any single
+		value. The single values not satisfying condition are not truncated. It implies two cases
+		for positive comparison, e.g. "equal", the result contains values not satisfying the
+		condition, the case may be handled by additional filter in the LDAP module,
+		the negative comparison, e.g. "non-equal", does not return record at all.
+		Because the LDAP module cannot know if the LDAP attribute may
+		logically contain multi-value so there is introduced DB API option <emphasis>client_side_filtering</emphasis>
+		which forces filtering such fields in the LDAP module, i.e. the LDAP server returns
+		larger result set because the filtering condition is not passed there.
+		</para>
+
+		<para>
+		The necessary condition of successful filtering of particular
+		attribute at the LDAP server is correct attribute definition.
+		The "equal"/"non-equal" operator requires <emphasis>equality matching rule</emphasis>,
+		the "greater"/"less" operator requires <emphasis>ordering matching rule</emphasis>.
+		If required matching rule is missing the LDAP server silently returns
+		empty result set. In case of double filtering both at the LDAP servar and the LDAP
+		module, e.g. multi-value and equal comparison, check the LDAP server matching
+		rule satisfies your needs or use <emphasis>client_side_filtering</emphasis> feature. 
+		</para>
+
+		<para>
+		The LDAP server may be identified either 
+		complete specification of host, user, password in URI or
+		is specification reference to <varname>connection</varname> section
+		of <varname>config</varname> file. Note in the second case there is only
+		one slash.
+		</para>
+
+		<example>
+			<title>URI example</title>
+			<programlisting>
+	...
+	modparam("auth", "db_url", "ldap://admin:[email protected]");
+
+	modparam("auth", "db_url", "ldap:/ldap_server1");
+
+	...
+			</programlisting>
+		</example>
+
+		<para>
+			Features:
+			<itemizedlist>
+				<listitem>
+					<para>
+						simple, SASL authentication, TLS
+					</para>
+				</listitem>
+				<listitem>
+					<para>
+						server and client side filtering
+					</para>
+				</listitem>
+				<listitem>
+					<para>
+						read-only queries
+					</para>
+				</listitem>
+				<listitem>
+					<para>
+						optional referral chasing by OpenLDAP
+					</para>
+				</listitem>
+				<listitem>
+					<para>
+						optional reference chasing by OpenLDAP
+
+					</para>
+				</listitem>
+			</itemizedlist>
+		</para>
+    </section>
+
+	<section id="ldap.dep">
+		<title>Dependencies</title>
+				   
+		<para>
+		none
+		</para>
+	</section>
+
+	<section id="ldap.parameters">
+
+		<title>Parameters</title>
+
+		<section id="config">
+			<title><varname>config</varname> (string)</title>
+			<para>
+				Default value is <emphasis>ldap.cfg</emphasis>.
+			</para>
+			<para>
+			The filename (relatively to ser config file) of mapping database to LDAP definition.
+
+			It is the main configuration file for the LDAP module in SER.
+			The configuration file maps database table names used in SER to LDAP directory
+			sub-trees to be searched. In addition to that the configuration file also allows to
+			configure the LDAP search filter and maps database field names to
+			LDAP attribute names and vice versa. 
+			</para>
+			<example>
+				<title>Example <varname>config</varname></title>
+				<programlisting>
+	...
+	modparam("ldap", "config", "my-ldap.cfg");
+	...
+				</programlisting>
+			</example>
+
+
+			<example>
+				<title>Configuration file example</title>
+				<programlisting>
+# Supported Attribute Type Names:
+#  * GeneralizedTime
+#  * Integer
+#  * BitString
+#  * Boolean
+#  * String
+#  * Binary
+#  * Float
+#
+
+[connection:ldap_server1]
+host=127.0.0.1
+port=389
+username=ser
+password=heslo
+# LDAP or LDAP SASL authentication mechanism.
+# Allowed values: none (default), simple, digest-md5, external
+authtype=simple
+
+# tls encryption
+tls=off
+
+# Specifies the file that contains certificates for all of the Certificate
+# Authorities the ldap module will recognize.
+ca_list=/home/kg/work/openssl/demoCA/cacert.pem
+
+# Specifies what checks to perform on server certificates in a TLS session
+# allowed values are never/allow/try/demand
+# see the TLS_REQCERT tls option part of ldap.conf(8) man page for more details
+require_certificate=demand
+
+#
+# Table credentials contains SIP digest authentication credentials.
+#
+[table:credentials]
+
+# In our LDAP directory we store SIP digest credentials under 
+# "Digest Credentials" organization unit so this is where searches for digest 
+# credentials should start.
+base = "ou=Digest Credentials,dc=iptel,dc=org"
+
+# We search the whole subtree.
+scope = subtree
+
+# For digest credentials we are only interested in objects with objectClass 
+# 'digestAuthCredentials', objects of all other types are ignored.
+filter = "(objectClass=digestAuthCredentials)"
+
+# Mapping of field names to LDAP attribute names and vice versa. Names are
+# delimited using ':', the first name is database field name as used in SER
+# modules, the second name (after :) is corresponding LDAP attribute name,
+# optionally preceeded with LDAP attribute syntax name in parentheses.
+field_map = password : (Binary) digestPassword
+field_map = realm : digestRealm
+field_map = auth_username : digestUsername
+field_map = uid : serUID
+field_map = flags : (BitString) serFlags
+
+# retrieve at most sizelimit entries for a search
+#sizelimit = 2147483647
+
+# wait at most timelimit seconds for a search to complete
+#timelimit = 120
+
+# chase references automatically by OpenLDAP. Default is "never"
+# chase_references = never | searching | finding | always
+
+# chase referrals automatically by OpenLDAP. Default is "no"
+# chase_referrals = yes | no
+
+#
+# Domain table stores information about virtual domains
+#
+[table:domain]
+
+# Objects mapping domain IDs to domain names and vice versa are stored
+# in the subtree with the following root:
+base = "ou=Domains,dc=iptel,dc=org"
+
+scope = subtree
+
+# We are only interested in serDomain objects when looking up information
+# about virtual domains.
+filter = "(objectClass=serDomain)"
+
+field_map = did : (String) serDID
+field_map = domain : (String) serDomain
+field_map = flags : (BitString) serFlags
+
+#
+# Table domain_attrs contains domain attributes, domain attributes store
+# extra information about virtual domains.
+#
+[table:domain_attrs]
+base = "ou=Domains, dc=iptel,dc=org"
+scope = subtree
+
+filter = "(objectClass=serDomainAttr)"
+
+field_map = did : serDID
+field_map = name : serAttrName
+field_map = type : (Integer) serAttrType
+field_map = value : serAttrValue
+field_map = flags : (BitString) serFlags			
+				</programlisting>
+			</example>
+			
+		</section>
+
+		<section id="reconnect_attempt">
+			<title><varname>reconnect_attempt</varname> (integer)</title>
+			<para>
+			Default value is <emphasis>3</emphasis>.
+			</para>
+			<para>
+			Number of reconnect attempts when connection to the LDAP server is lost.
+			</para>
+
+			<example>
+				<title>Example <varname>reconnect_attempt</varname></title>
+				<programlisting>
+	...
+	modparam("ldap", "reconnect_attempt", "5");
+	...
+				</programlisting>
+			</example>
+		</section>
+
+	</section>
+
+	<section id="ldap.functions">
+		<title>Functions</title>
+		<para>
+		none
+		</para>
+	</section>
+
+</section>
+

+ 16 - 2
modules_s/ldap/ld_cfg.c

@@ -249,6 +249,14 @@ static cfg_option_t scope_values[] = {
 };
 };
 
 
 
 
+static cfg_option_t deref_values[] = {
+	{"never",     .val = LDAP_DEREF_NEVER },   /* default, 0x00 */
+	{"searching", .val = LDAP_DEREF_SEARCHING},
+	{"finding",   .val = LDAP_DEREF_FINDING },
+	{"always",    .val = LDAP_DEREF_ALWAYS },
+	{0}
+};
+
 static cfg_option_t ldap_tab_options[] = {
 static cfg_option_t ldap_tab_options[] = {
 	{"scope",     .param = scope_values, .f = cfg_parse_enum_opt},
 	{"scope",     .param = scope_values, .f = cfg_parse_enum_opt},
 	{"field_map", .f = parse_field_map},
 	{"field_map", .f = parse_field_map},
@@ -256,6 +264,8 @@ static cfg_option_t ldap_tab_options[] = {
 	{"base",      .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
 	{"base",      .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
 	{"timelimit", .f = cfg_parse_int_opt},
 	{"timelimit", .f = cfg_parse_int_opt},
 	{"sizelimit", .f = cfg_parse_int_opt},
 	{"sizelimit", .f = cfg_parse_int_opt},
+	{"chase_references",  .param = deref_values, .f = cfg_parse_enum_opt},
+	{"chase_referrals",   .f = cfg_parse_bool_opt},
 	{0}
 	{0}
 };
 };
 
 
@@ -275,9 +285,9 @@ static cfg_option_t ldap_con_options[] = {
 	{"username", 		    .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
 	{"username", 		    .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
 	{"password", 		    .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
 	{"password", 		    .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
 	{"authtype", 		    .param = auth_values, .f = cfg_parse_enum_opt},
 	{"authtype", 		    .param = auth_values, .f = cfg_parse_enum_opt},
-	{"tls",			        .f = cfg_parse_bool_opt},
+	{"tls",			    .f = cfg_parse_bool_opt},
 	{"ca_list",  		    .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
 	{"ca_list",  		    .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
-	{"require_certificate", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
+	{"require_certificate",     .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
 	{0}
 	{0}
 };
 };
 
 
@@ -332,6 +342,10 @@ static int parse_section(void* param, cfg_parser_t* st, unsigned int flags)
 		}
 		}
 		ldap_tab_options[4].param = &cfg->timelimit;
 		ldap_tab_options[4].param = &cfg->timelimit;
 		ldap_tab_options[5].param = &cfg->sizelimit;
 		ldap_tab_options[5].param = &cfg->sizelimit;
+		for(i = 0; deref_values[i].name; i++) {
+			deref_values[i].param = &cfg->chase_references;
+		}
+		ldap_tab_options[7].param = &cfg->chase_referrals;
 	} else if (type == LDAP_CON_SECTION) {
 	} else if (type == LDAP_CON_SECTION) {
 		if ((cinfo = pkg_malloc(sizeof(*cinfo))) == NULL) {
 		if ((cinfo = pkg_malloc(sizeof(*cinfo))) == NULL) {
 			ERR("ldap:%s:%d: Out of memory\n", st->file, st->line);
 			ERR("ldap:%s:%d: Out of memory\n", st->file, st->line);

+ 2 - 0
modules_s/ldap/ld_cfg.h

@@ -45,6 +45,8 @@ struct ld_cfg {
 	int n;          /**< Number of fields in the arrays */
 	int n;          /**< Number of fields in the arrays */
 	int sizelimit; /**< retrieve at most sizelimit entries for a search */
 	int sizelimit; /**< retrieve at most sizelimit entries for a search */
 	int timelimit; /**< wait at most timelimit seconds for a search to complete */
 	int timelimit; /**< wait at most timelimit seconds for a search to complete */
+	int chase_references;  /**< dereference option for LDAP library */
+	int chase_referrals;   /**< follow referrals option for LDAP library */
 	struct ld_cfg* next; /**< The next table in the list */
 	struct ld_cfg* next; /**< The next table in the list */
 };
 };
 
 

+ 85 - 17
modules_s/ldap/ld_cmd.c

@@ -90,6 +90,8 @@ int ld_cmd(db_cmd_t* cmd)
 {
 {
 	struct ld_cmd* lcmd;
 	struct ld_cmd* lcmd;
 	struct ld_cfg* cfg;
 	struct ld_cfg* cfg;
+	struct ld_fld* lfld;
+	int i, j;
 
 
 	lcmd = (struct ld_cmd*)pkg_malloc(sizeof(struct ld_cmd));
 	lcmd = (struct ld_cmd*)pkg_malloc(sizeof(struct ld_cmd));
 	if (lcmd == NULL) {
 	if (lcmd == NULL) {
@@ -134,11 +136,37 @@ int ld_cmd(db_cmd_t* cmd)
 	if (cfg->filter.s) {
 	if (cfg->filter.s) {
 		lcmd->filter = cfg->filter;
 		lcmd->filter = cfg->filter;
 	}
 	}
+	lcmd->chase_references = cfg->chase_references;
+	lcmd->chase_referrals = cfg->chase_referrals;
 
 
 	if (ld_resolve_fld(cmd->match, cfg) < 0) goto error;
 	if (ld_resolve_fld(cmd->match, cfg) < 0) goto error;
 	if (ld_resolve_fld(cmd->result, cfg) < 0) goto error;
 	if (ld_resolve_fld(cmd->result, cfg) < 0) goto error;
 
 
+	/* prepare filter for each result field */
+	for(i = 0; !DB_FLD_EMPTY(cmd->result) && !DB_FLD_LAST(cmd->result[i]); i++) {
+		int n;
+		lfld = DB_GET_PAYLOAD(cmd->result + i);
+		lfld->filter = NULL;
+	
+		for(j = 0, n = 0; !DB_FLD_EMPTY(cmd->match) && !DB_FLD_LAST(cmd->match[j]); j++) {
+			if (strcmp(cmd->result[i].name, cmd->match[j].name) == 0)
+				n++;	
+		}
+		
+		if (n > 0) {
+			lfld->filter = pkg_malloc((n+1)*sizeof(*(lfld->filter)));
+			if (!lfld->filter) return -1 /* E_OUT_OF_MEM*/;
+			for(j = 0, n = 0; !DB_FLD_EMPTY(cmd->match) && !DB_FLD_LAST(cmd->match[j]); j++) {
+				if (strcmp(cmd->result[i].name, cmd->match[j].name) == 0) {
+					lfld->filter[n] = cmd->match+j;
+					n++;
+				}
+			}
+			lfld->filter[n] = NULL;
+		}
+	}
 	if (build_result_array(&lcmd->result, cmd) < 0) goto error;
 	if (build_result_array(&lcmd->result, cmd) < 0) goto error;
+
 	DB_SET_PAYLOAD(cmd, lcmd);
 	DB_SET_PAYLOAD(cmd, lcmd);
 	return 0;
 	return 0;
 
 
@@ -162,13 +190,12 @@ int ld_cmd_exec(db_res_t* res, db_cmd_t* cmd)
 	char* filter, *err_desc;
 	char* filter, *err_desc;
 	int ret, err;
 	int ret, err;
 	LDAPMessage *msg, *resmsg;
 	LDAPMessage *msg, *resmsg;
-	int reconn_cnt = glb_reconn_cnt;
+	int reconn_cnt;
 	int msgid;
 	int msgid;
 	char *oid;
 	char *oid;
 	struct berval *data;
 	struct berval *data;
 	struct timeval restimeout;
 	struct timeval restimeout;
 
 
-
 	filter = NULL;
 	filter = NULL;
 	err_desc = NULL;
 	err_desc = NULL;
 	resmsg = NULL;
 	resmsg = NULL;
@@ -179,14 +206,21 @@ int ld_cmd_exec(db_res_t* res, db_cmd_t* cmd)
 	con = cmd->ctx->con[db_payload_idx];
 	con = cmd->ctx->con[db_payload_idx];
 	lcmd = DB_GET_PAYLOAD(cmd);
 	lcmd = DB_GET_PAYLOAD(cmd);
 	lcon = DB_GET_PAYLOAD(con);
 	lcon = DB_GET_PAYLOAD(con);
+	
+	reconn_cnt = ld_reconnect_attempt;
 
 
-	if (ld_fld2ldap(&filter, cmd->match, &lcmd->filter) < 0) {
+	if (ld_prepare_ldap_filter(&filter, cmd, &lcmd->filter) < 0) {
 		ERR("ldap: Error while building LDAP search filter\n");
 		ERR("ldap: Error while building LDAP search filter\n");
 		goto error;
 		goto error;
 	}
 	}
 
 
+	DBG("ldap: ldap_search(base:'%s', filter:'%s')\n", lcmd->base, filter);
 	do {
 	do {
 		if (lcon->flags & LD_CONNECTED) {
 		if (lcon->flags & LD_CONNECTED) {
+			ldap_set_option(lcon->con, LDAP_OPT_DEREF, ((void *)&lcmd->chase_references));
+			/* there is alternative method using LDAP_CONTROL_REFERRALS per request but is not well documented */
+			ldap_set_option(lcon->con, LDAP_OPT_REFERRALS, lcmd->chase_referrals?LDAP_OPT_ON:LDAP_OPT_OFF);
+		
 			ret = ldap_search_ext(lcon->con, lcmd->base, lcmd->scope, filter,
 			ret = ldap_search_ext(lcon->con, lcmd->base, lcmd->scope, filter,
 								  lcmd->result, 0, NULL, NULL,
 								  lcmd->result, 0, NULL, NULL,
 								  lcmd->timelimit.tv_sec ? &lcmd->timelimit : NULL,
 								  lcmd->timelimit.tv_sec ? &lcmd->timelimit : NULL,
@@ -232,7 +266,6 @@ int ld_cmd_exec(db_res_t* res, db_cmd_t* cmd)
 		}
 		}
 	} while (ret <= 0);
 	} while (ret <= 0);
 
 
-
 	/* looking for unsolicited messages */
 	/* looking for unsolicited messages */
 	for (msg = ldap_first_message(lcon->con, resmsg);
 	for (msg = ldap_first_message(lcon->con, resmsg);
 		 msg != NULL;
 		 msg != NULL;
@@ -302,7 +335,7 @@ static int search_entry(db_res_t* res, int init)
 	db_con_t* con;
 	db_con_t* con;
 	struct ld_res* lres;
 	struct ld_res* lres;
 	struct ld_con* lcon;
 	struct ld_con* lcon;
-
+	int r;
 	lres = DB_GET_PAYLOAD(res);
 	lres = DB_GET_PAYLOAD(res);
 	/* FIXME */
 	/* FIXME */
 	con = res->cmd->ctx->con[db_payload_idx];
 	con = res->cmd->ctx->con[db_payload_idx];
@@ -314,19 +347,24 @@ static int search_entry(db_res_t* res, int init)
 	    /* there is no more value combination result left */
 	    /* there is no more value combination result left */
 	    || ld_incindex(res->cmd->result)) {
 	    || ld_incindex(res->cmd->result)) {
 
 
-		if (init)
-			lres->current = ldap_first_message(lcon->con, lres->msg);
-		else
-			lres->current = ldap_next_message(lcon->con, lres->current);
-
-		while(lres->current) {
-			if (ldap_msgtype(lres->current) == LDAP_RES_SEARCH_ENTRY) {
-				break;
+		do {
+			if (init) {
+				lres->current = ldap_first_message(lcon->con, lres->msg);
+				init = 0;
 			}
 			}
-			lres->current = ldap_next_message(lcon->con, lres->current);
-		}
-		if (lres->current == NULL) return 1;
-		if (ld_ldap2fldinit(res->cmd->result, lcon->con, lres->current) < 0) return -1;
+			else
+				lres->current = ldap_next_message(lcon->con, lres->current);
+			
+			while(lres->current) {
+				if (ldap_msgtype(lres->current) == LDAP_RES_SEARCH_ENTRY) {
+					break;
+				}
+				lres->current = ldap_next_message(lcon->con, lres->current);
+			}
+			if (lres->current == NULL) return 1;
+			r = ld_ldap2fldinit(res->cmd->result, lcon->con, lres->current);
+		} while (r > 0);
+		if (r < 0) return -1;
 	} else {
 	} else {
 		if (ld_ldap2fld(res->cmd->result, lcon->con, lres->current) < 0) return -1;
 		if (ld_ldap2fld(res->cmd->result, lcon->con, lres->current) < 0) return -1;
 	}
 	}
@@ -347,5 +385,35 @@ int ld_cmd_next(db_res_t* res)
 	return search_entry(res, 0);
 	return search_entry(res, 0);
 }
 }
 
 
+#define is_space(c) ((c)==' '||(c)==','||(c)==';'||(c)=='\t'||(c)=='\n'||(c)=='\r'||(c)=='\0')
+
+int ld_cmd_setopt(db_cmd_t* cmd, char* optname, va_list ap)
+{
+	struct ld_fld* lfld;
+	char* val, *c;
+	int i;
+		
+	if (!strcasecmp("client_side_filtering", optname)) {
+		val = va_arg(ap, char*);
+
+		for(i = 0; !DB_FLD_EMPTY(cmd->result) && !DB_FLD_LAST(cmd->result[i]); i++) {
+			c = val;
+			do {
+				c = strstr(c, cmd->result[i].name);
+				if (c) {
+					if ((c == val || is_space(*(c-1))) && is_space(*(c+strlen(cmd->result[i].name)))) {
+						lfld = (struct ld_fld*)DB_GET_PAYLOAD(cmd->result + i);
+						lfld->client_side_filtering = 1;
+						break;
+					}
+					c += strlen(cmd->result[i].name);
+				}
+			} while (c != NULL);
+		}
+	}
+	else
+		return 1;
+        return 0;
+}
 
 
 /** @} */
 /** @} */

+ 4 - 0
modules_s/ldap/ld_cmd.h

@@ -55,6 +55,8 @@ struct ld_cmd {
 	char** result; /**< An array with result attribute names for ldap_search */
 	char** result; /**< An array with result attribute names for ldap_search */
 	int sizelimit; /**< retrieve at most sizelimit entries for a search */
 	int sizelimit; /**< retrieve at most sizelimit entries for a search */
 	struct timeval timelimit; /**< wait at most timelimit seconds for a search to complete */
 	struct timeval timelimit; /**< wait at most timelimit seconds for a search to complete */
+	int chase_references;  /**< dereference option for LDAP library */
+	int chase_referrals;   /**< follow referrals option for LDAP library */
 };
 };
 
 
 
 
@@ -86,6 +88,8 @@ int ld_cmd_first(db_res_t* res);
 
 
 int ld_cmd_next(db_res_t* res);
 int ld_cmd_next(db_res_t* res);
 
 
+int ld_cmd_setopt(db_cmd_t* cmd, char* optname, va_list ap);
+
 /** @} */
 /** @} */
 
 
 #endif /* _LD_CMD_H */
 #endif /* _LD_CMD_H */

+ 0 - 2
modules_s/ldap/ld_con.c

@@ -30,8 +30,6 @@
  * Functions related to connections to LDAP servers.
  * Functions related to connections to LDAP servers.
  */
  */
 
 
-#define LDAP_DEPRECATED 1
-
 #include "ld_con.h"
 #include "ld_con.h"
 #include "ld_uri.h"
 #include "ld_uri.h"
 
 

Datei-Diff unterdrückt, da er zu groß ist
+ 461 - 299
modules_s/ldap/ld_fld.c


+ 5 - 4
modules_s/ldap/ld_fld.h

@@ -40,6 +40,7 @@ struct ld_cfg;
 
 
 #include "../../db/db_gen.h"
 #include "../../db/db_gen.h"
 #include "../../db/db_fld.h"
 #include "../../db/db_fld.h"
+#include "../../db/db_cmd.h"
 
 
 #include <ldap.h>
 #include <ldap.h>
 
 
@@ -57,9 +58,11 @@ struct ld_fld {
 	db_drv_t gen;
 	db_drv_t gen;
 	str attr;               /**< Name of corresponding LDAP attribute */
 	str attr;               /**< Name of corresponding LDAP attribute */
 	enum ld_syntax syntax;  /**< LDAP attribute syntax */
 	enum ld_syntax syntax;  /**< LDAP attribute syntax */
-	struct berval** values; /**< Values retrieved from the LDAP result */
+	struct berval** values; /**< Values retrieved from the LDAP result */    	
 	unsigned int valuesnum;
 	unsigned int valuesnum;
 	unsigned int index;
 	unsigned int index;
+	db_fld_t** filter;	/**< filter applied on the field pointing to db_cmd_t.match[] */
+	int client_side_filtering;  /**< do not pass filter to LDAP server but filter result set */
 };
 };
 
 
 
 
@@ -76,9 +79,7 @@ int ld_fld(db_fld_t* fld, char* table);
 
 
 int ld_resolve_fld(db_fld_t* fld, struct ld_cfg* cfg);
 int ld_resolve_fld(db_fld_t* fld, struct ld_cfg* cfg);
 
 
-int ld_ldap2fld(db_fld_t* fld, LDAP* ldap, LDAPMessage* msg);
-
-int ld_fld2ldap(char** filter, db_fld_t* fld, str* add);
+int ld_prepare_ldap_filter(char** filter, db_cmd_t* cmd, str* add);
 
 
 int ld_incindex(db_fld_t* fld);
 int ld_incindex(db_fld_t* fld);
 
 

+ 3 - 3
modules_s/ldap/ld_mod.c

@@ -49,7 +49,7 @@
 #include <ldap.h>
 #include <ldap.h>
 
 
 str ld_cfg_file = STR_STATIC_INIT("ldap.cfg");
 str ld_cfg_file = STR_STATIC_INIT("ldap.cfg");
-int glb_reconn_cnt = 3;
+int ld_reconnect_attempt = 3;
 
 
 static int ld_mod_init(void);
 static int ld_mod_init(void);
 static void ld_mod_destroy(void);
 static void ld_mod_destroy(void);
@@ -73,7 +73,7 @@ static cmd_export_t cmds[] = {
 	{"db_fld",    (cmd_function)ld_fld, 0, 0, 0},
 	{"db_fld",    (cmd_function)ld_fld, 0, 0, 0},
 	{"db_first",  (cmd_function)ld_cmd_first, 0, 0, 0},
 	{"db_first",  (cmd_function)ld_cmd_first, 0, 0, 0},
 	{"db_next",   (cmd_function)ld_cmd_next, 0, 0, 0},
 	{"db_next",   (cmd_function)ld_cmd_next, 0, 0, 0},
-	{"db_setopt", (cmd_function)NULL, 0, 0, 0},
+	{"db_setopt", (cmd_function)ld_cmd_setopt, 0, 0, 0},
 	{"db_getopt", (cmd_function)NULL, 0, 0, 0},
 	{"db_getopt", (cmd_function)NULL, 0, 0, 0},
 	{0, 0, 0, 0, 0}
 	{0, 0, 0, 0, 0}
 };
 };
@@ -84,7 +84,7 @@ static cmd_export_t cmds[] = {
  */
  */
 static param_export_t params[] = {
 static param_export_t params[] = {
 	{"config", PARAM_STR, &ld_cfg_file},
 	{"config", PARAM_STR, &ld_cfg_file},
-	{"reconnect_attempt", PARAM_INT, &glb_reconn_cnt},
+	{"reconnect_attempt", PARAM_INT, &ld_reconnect_attempt},
 	{0, 0, 0}
 	{0, 0, 0}
 };
 };
 
 

+ 1 - 2
modules_s/ldap/ld_mod.h

@@ -30,12 +30,11 @@
  */
  */
 /** @{ */
 /** @{ */
 
 
-extern int glb_reconn_cnt;
-
 /** \file
 /** \file
  * LDAP module interface.
  * LDAP module interface.
  */
  */
 
 
+extern int ld_reconnect_attempt;
 /** @} */
 /** @} */
 
 
 #endif /* _LD_MOD_H */
 #endif /* _LD_MOD_H */

+ 6 - 0
modules_s/ldap/ldap.cfg

@@ -69,6 +69,12 @@ field_map = flags : (BitString) serFlags
 # wait at most timelimit seconds for a search to complete
 # wait at most timelimit seconds for a search to complete
 #timelimit = 120
 #timelimit = 120
 
 
+# chase references automatically by OpenLDAP. Default is "never"
+# chase_references = never | searching | finding | always
+
+# chase referrals automatically by OpenLDAP. Default is "no"
+# chase_referrals = yes | no
+
 #
 #
 # Domain table stores information about virtual domains
 # Domain table stores information about virtual domains
 #
 #

+ 3 - 0
modules_s/ldap/standards.txt

@@ -30,6 +30,9 @@ RFC2798: Definition of the inetOrgPerson LDAP Object Class
 
 
   This document has been updated by RFC 3698, RFC 4519 and RFC 4524.
   This document has been updated by RFC 3698, RFC 4519 and RFC 4524.
 
 
+RFC4514: Lightweight Directory Access Protocol (LDAP): String Representation
+        of Distinguished Names
+
 RFC4515: Lightweight Directory Access Protocol (LDAP): String Representation
 RFC4515: Lightweight Directory Access Protocol (LDAP): String Representation
          of Search Filters
          of Search Filters
 
 

+ 4 - 4
modules_s/ldap/todo.txt

@@ -66,11 +66,11 @@ X Escape Values of Parameters Injected Into the Search Filter
   internally as time_t, but the parses should be able to skip fractions of
   internally as time_t, but the parses should be able to skip fractions of
   seconds gracefully.
   seconds gracefully.
 
 
-* Eliminate Use of All libldap Functions Marked as Deprecated (SER-401)
+X Eliminate Use of All libldap Functions Marked as Deprecated (SER-401)
 
 
   We should eliminate the use of all functions that are marked as deprecated
   We should eliminate the use of all functions that are marked as deprecated
   in the header field and remove LDAP_DEPRECATED define from all files.
   in the header field and remove LDAP_DEPRECATED define from all files.
-
+  
 X Support for Bool Attribute Types
 X Support for Bool Attribute Types
 
 
   The module should be able to convert boolean attributes from the LDAP result
   The module should be able to convert boolean attributes from the LDAP result
@@ -83,11 +83,11 @@ X Support for Syntax Specification in the Config File
   attributes in the configuration file so that the module knows how to convert
   attributes in the configuration file so that the module knows how to convert
   DB API fields into attribute values in command parameters.
   DB API fields into attribute values in command parameters.
 
 
-* Support DB_NEQ Operator in Integer Attributes (SER-402)
+X Support DB_NEQ Operator in Integer Attributes (SER-402)
  
  
   fld!=10 could be converted to the search filter as: (|(fld<=9)(fld>=11))
   fld!=10 could be converted to the search filter as: (|(fld<=9)(fld>=11))
 
 
-* Indicate Underflow/Overflow in Integer Attributes (SER-403)
+X Indicate Underflow/Overflow in Integer Attributes (SER-403)
 
 
   The operators < and > cannot be used in LDAP search filter, RFC4515 only
   The operators < and > cannot be used in LDAP search filter, RFC4515 only
   supports <= and >= so we create the search filter like this: fld<10 ->
   supports <= and >= so we create the search filter like this: fld<10 ->

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.