Bläddra i källkod

Ticket 534 - RFE: Add SASL mappings fallback

Bug Description:  If the mapping fails to find an entry the bind fails without
                  checking if other mappings would also match.

Fix Description:  Added the fallback functionality.  Also added the ability to prioritize
                  the mapping order, and to be able to modify the mappings while
                  the server is up.

https://fedorahosted.org/389/ticket/534

Reviewed by: noriko & richm (Thanks!)
Mark Reynolds 13 år sedan
förälder
incheckning
83f292c9b4
5 ändrade filer med 239 tillägg och 122 borttagningar
  1. 2 1
      ldap/schema/01core389.ldif
  2. 20 1
      ldap/servers/slapd/fe.h
  3. 34 33
      ldap/servers/slapd/fedse.c
  4. 146 62
      ldap/servers/slapd/sasl_map.c
  5. 37 25
      ldap/servers/slapd/saslbind.c

+ 2 - 1
ldap/schema/01core389.ldif

@@ -113,6 +113,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.9999999 NAME 'nsds5debugreplicatimeout'
 attributeTypes: ( 2.16.840.1.113730.3.1.2064 NAME 'nsSaslMapRegexString' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2065 NAME 'nsSaslMapBaseDNTemplate' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2066 NAME 'nsSaslMapFilterTemplate' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2142 NAME 'nsSaslMapPriority' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( nsCertfile-oid NAME 'nsCertfile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
 attributeTypes: ( nsKeyfile-oid NAME 'nsKeyfile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
 attributeTypes: ( nsSSL2-oid NAME 'nsSSL2' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
@@ -152,7 +153,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Netscape de
 objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nsParentUniqueId $ nscpEntryDN ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.39 NAME 'nsslapdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) MAY ( nsSaslMapPriority ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.43 NAME 'nsSNMP' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSNMPEnabled ) MAY ( nsSNMPOrganization $ nsSNMPLocation $ nsSNMPContact $ nsSNMPDescription $ nsSNMPName $ nsSNMPMasterHost $ nsSNMPMasterPort ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( nsEncryptionConfig-oid NAME 'nsEncryptionConfig' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsCertfile $ nsKeyfile $ nsSSL2 $ nsSSL3 $ nsTLS1 $ nsSSLSessionTimeout $ nsSSL3SessionTimeout $ nsSSLClientAuth $ nsSSL2Ciphers $ nsSSL3Ciphers $ nsSSLSupportedCiphers) X-ORIGIN 'Netscape' )
 objectClasses: ( nsEncryptionModule-oid NAME 'nsEncryptionModule' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsSSLToken $ nsSSLPersonalityssl $ nsSSLActivation ) X-ORIGIN 'Netscape' )

+ 20 - 1
ldap/servers/slapd/fe.h

@@ -190,10 +190,29 @@ int sasl_io_cleanup(Connection *c, void *data);
 /*
  * sasl_map.c
  */
+typedef struct sasl_map_data_ sasl_map_data;
+struct sasl_map_data_ {
+	char *name;
+	char *regular_expression;
+	char *template_base_dn;
+	char *template_search_filter;
+	int priority;
+	sasl_map_data *next; /* For linked list */
+	sasl_map_data *prev;
+};
+
+typedef struct _sasl_map_private {
+	Slapi_RWLock *lock;
+	sasl_map_data *map_data_list;
+} sasl_map_private;
+
 int sasl_map_config_add(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
 int sasl_map_config_delete(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
-int sasl_map_domap(char *sasl_user, char *sasl_realm, char **ldap_search_base, char **ldap_search_filter);
+int sasl_map_config_modify(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int sasl_map_domap(sasl_map_data **map, char *sasl_user, char *sasl_realm, char **ldap_search_base, char **ldap_search_filter);
 int sasl_map_init();
 int sasl_map_done();
+void sasl_map_read_lock();
+void sasl_map_read_unlock();
 
 #endif

+ 34 - 33
ldap/servers/slapd/fedse.c

@@ -1767,7 +1767,7 @@ search_snmp(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *ret
 int
 setup_internal_backends(char *configdir)
 {
-    int rc = init_schema_dse(configdir);
+	int rc = init_schema_dse(configdir);
 	Slapi_DN config;
 
 	slapi_sdn_init_ndn_byref(&config,"cn=config");
@@ -1777,15 +1777,15 @@ setup_internal_backends(char *configdir)
 		rc= init_dse_file(configdir, &config);
 	}
 
-    if(rc)
-    {
+	if(rc)
+	{
 		Slapi_DN monitor;
 		Slapi_DN counters;
 		Slapi_DN snmp;
 		Slapi_DN root;
-        Slapi_Backend *be;
-        Slapi_DN encryption;
-        Slapi_DN saslmapping;
+		Slapi_Backend *be;
+		Slapi_DN encryption;
+		Slapi_DN saslmapping;
 
 		slapi_sdn_init_ndn_byref(&monitor,"cn=monitor");
 		slapi_sdn_init_ndn_byref(&counters,"cn=counters,cn=monitor");
@@ -1795,50 +1795,51 @@ setup_internal_backends(char *configdir)
 		slapi_sdn_init_ndn_byref(&encryption,"cn=encryption,cn=config");
 		slapi_sdn_init_ndn_byref(&saslmapping,"cn=mapping,cn=sasl,cn=config");
 
-        /* Search */
-    	dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",read_config_dse,NULL);
-    	dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_BASE,"(objectclass=*)",monitor_info,NULL);
-    	dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",read_root_dse,NULL);
-        dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_SUBTREE,EGG_FILTER,search_easter_egg,NULL); /* Egg */
-        dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&counters,LDAP_SCOPE_BASE,"(objectclass=*)",search_counters,NULL);
-        dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&snmp,LDAP_SCOPE_BASE,"(objectclass=*)",search_snmp,NULL);
+		/* Search */
+		dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",read_config_dse,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_BASE,"(objectclass=*)",monitor_info,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",read_root_dse,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_SUBTREE,EGG_FILTER,search_easter_egg,NULL); /* Egg */
+		dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&counters,LDAP_SCOPE_BASE,"(objectclass=*)",search_counters,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&snmp,LDAP_SCOPE_BASE,"(objectclass=*)",search_snmp,NULL);
 		dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&encryption,LDAP_SCOPE_BASE,"(objectclass=*)",search_encryption,NULL);
 
-        /* Modify */
-    	dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",modify_config_dse,NULL);
-    	dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_POSTOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",postop_modify_config_dse,NULL);
-    	dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",modify_root_dse,NULL);
+		/* Modify */
+		dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",modify_config_dse,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_POSTOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",postop_modify_config_dse,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",modify_root_dse,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&saslmapping,LDAP_SCOPE_SUBTREE,"(objectclass=nsSaslMapping)",sasl_map_config_modify,NULL);
 		
-        /* Delete */
-    	dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
-    	dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
-    	dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&counters,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
-    	dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&snmp,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
-    	dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+		/* Delete */
+		dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&counters,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&snmp,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+		dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
 		dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&encryption,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
-
 		dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&saslmapping,LDAP_SCOPE_SUBTREE,"(objectclass=nsSaslMapping)",sasl_map_config_delete,NULL);
 
-        /* Write */
-        dse_register_callback(pfedse,DSE_OPERATION_WRITE,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_SUBTREE,EGG_FILTER,dont_allow_that,NULL); /* Egg */
+		/* Write */
+		dse_register_callback(pfedse,DSE_OPERATION_WRITE,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_SUBTREE,EGG_FILTER,dont_allow_that,NULL); /* Egg */
 
+		/* Add */
 		dse_register_callback(pfedse,SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,&saslmapping,LDAP_SCOPE_SUBTREE,"(objectclass=nsSaslMapping)",sasl_map_config_add,NULL);
 
-    	be= be_new_internal(pfedse, "DSE", DSE_BACKEND);
-        be_addsuffix(be,&root);
-        be_addsuffix(be,&monitor);
-        be_addsuffix(be,&config);
+		be = be_new_internal(pfedse, "DSE", DSE_BACKEND);
+		be_addsuffix(be,&root);
+		be_addsuffix(be,&monitor);
+		be_addsuffix(be,&config);
 
 		add_internal_entries();
 
-        add_easter_egg_entry();
+		add_easter_egg_entry();
 		
 		slapi_sdn_done(&monitor);
 		slapi_sdn_done(&counters);
 		slapi_sdn_done(&snmp);
 		slapi_sdn_done(&root);
 		slapi_sdn_done(&saslmapping);
-    } else {
+	} else {
 		slapi_log_error( SLAPI_LOG_FATAL, "dse",
 				"Please edit the file to correct the reported problems"
 				" and then restart the server.\n" );
@@ -1846,7 +1847,7 @@ setup_internal_backends(char *configdir)
 	}
 
 	slapi_sdn_done(&config);
-    return rc;
+	return rc;
 }
 
 int fedse_create_startOK(char *filename,  char *startokfilename, const char *configdir)

+ 146 - 62
ldap/servers/slapd/sasl_map.c

@@ -48,25 +48,9 @@
  * Map SASL identities to LDAP searches
  */
 
-/* 
- * We maintain a list of mappings to consult
- */
-
-typedef struct sasl_map_data_ sasl_map_data;
-struct sasl_map_data_ {
-	char *name;
-	char *regular_expression;
-	char *template_base_dn;
-	char *template_search_filter;
-	sasl_map_data *next; /* For linked list */
-}; 
-
-typedef struct _sasl_map_private {
-	PRLock *lock;
-	sasl_map_data *map_data_list;
-} sasl_map_private;
-
 static char * configDN = "cn=mapping,cn=sasl,cn=config";
+#define LOW_PRIORITY 100
+#define LOW_PRIORITY_STR "100"
 
 /*
  * DBDB: this is ugly, but right now there is _no_ server-wide
@@ -87,7 +71,7 @@ sasl_map_private *sasl_map_get_global_priv()
 static 
 sasl_map_private *sasl_map_new_private()
 {
-	PRLock *new_lock = PR_NewLock();
+	Slapi_RWLock *new_lock =  slapi_new_rwlock();
 	sasl_map_private *new_priv = NULL;
 	if (NULL == new_lock) {
 		return NULL;
@@ -100,20 +84,23 @@ sasl_map_private *sasl_map_new_private()
 static void 
 sasl_map_free_private(sasl_map_private **priv)
 {
-	PR_DestroyLock((*priv)->lock);
+	slapi_destroy_rwlock((*priv)->lock);
 	slapi_ch_free((void**)priv);
 	*priv = NULL;
 }
 
 /* This function does a shallow copy on the payload data supplied, so the caller should not free it, and it needs to be allocated using slapi_ch_malloc() */
 static 
-sasl_map_data *sasl_map_new_data(char *name, char *regex, char *dntemplate, char *filtertemplate)
+sasl_map_data *sasl_map_new_data(char *name, char *regex, char *dntemplate, char *filtertemplate, int priority)
 {
 	sasl_map_data *new_dp = (sasl_map_data *) slapi_ch_calloc(1,sizeof(sasl_map_data));
 	new_dp->name = name;
 	new_dp->regular_expression = regex;
 	new_dp->template_base_dn = dntemplate;
 	new_dp->template_search_filter = filtertemplate;
+	new_dp->priority = priority;
+	new_dp->next = NULL;
+	new_dp->prev = NULL;
 	return new_dp;
 }
 
@@ -139,31 +126,39 @@ sasl_map_remove_list_entry(sasl_map_private *priv, char *removeme)
 	int ret = 0;
 	int foundit = 0;
 	sasl_map_data *current = NULL;
-	sasl_map_data *previous = NULL;
-	PR_Lock(priv->lock);
+	sasl_map_data *prev = NULL;
+	sasl_map_data *next = NULL;
+
+	slapi_rwlock_wrlock(priv->lock);
 	current = priv->map_data_list;
 	while (current) {
+		next = current->next;
 		if (0 == strcmp(current->name,removeme)) {
 			foundit = 1;
-			if (previous) {
+			prev = current->prev;
+			if (prev) {
 				/* Unlink it */
-				previous->next = current->next;
+				if(next){
+				   next->prev = prev;
+				}
+				prev->next = next;
 			} else {
 				/* That was the first list entry */
 				priv->map_data_list = current->next;
+				priv->map_data_list->prev = NULL;
 			}
 			/* Payload free */
 			sasl_map_free_data(&current);
 			/* And no need to look further */
 			break;
 		}
-		previous = current;
-		current = current->next;
+		current = next;
 	}
+	slapi_rwlock_unlock(priv->lock);
 	if (!foundit) {
 		ret = -1;
 	}
-	PR_Unlock(priv->lock);
+
 	return ret;
 }
 
@@ -208,15 +203,21 @@ sasl_map_insert_list_entry(sasl_map_private *priv, sasl_map_data *dp)
 	int ret = 0;
 	int ishere = 0;
 	sasl_map_data *current = NULL;
+	sasl_map_data *last = NULL;
+	sasl_map_data *prev = NULL;
+
 	if (NULL == dp) {
 		return ret;
 	}
-	PR_Lock(priv->lock);
+
+	slapi_rwlock_wrlock(priv->lock);
+
 	/* Check to see if it's here already */
 	current = priv->map_data_list;
 	while (current) {
 		if (0 == sasl_map_cmp_data(current, dp)) {
 			ishere = 1;
+			break;
 		}
 		if (current->next) {
 			current = current->next;
@@ -225,15 +226,39 @@ sasl_map_insert_list_entry(sasl_map_private *priv, sasl_map_data *dp)
 		}
 	}
 	if (ishere) {
+		slapi_rwlock_unlock(priv->lock);
 		return -1;
 	}
-	/* current now points to the end of the list or NULL */
+
+	/* insert the map in its proper place */
 	if (NULL == priv->map_data_list) {
 		priv->map_data_list = dp;
 	} else {
-		current->next = dp;
+		current = priv->map_data_list;
+		while (current) {
+			last = current;
+			if(current->priority > dp->priority){
+				prev = current->prev;
+				if(prev){
+				    prev->next = dp;
+				    dp->prev = prev;
+				} else {
+					/* this is now the head of the list */
+					priv->map_data_list = dp;
+				}
+				current->prev = dp;
+				dp->next = current;
+				slapi_rwlock_unlock(priv->lock);
+				return ret;
+			}
+			current = current->next;
+		}
+		/* add the map at the end of the list */
+		last->next = dp;
+		dp->prev = last;
 	}
-	PR_Unlock(priv->lock);
+	slapi_rwlock_unlock(priv->lock);
+
 	return ret;
 }
 
@@ -342,9 +367,11 @@ static int
 sasl_map_config_parse_entry(Slapi_Entry *entry, sasl_map_data **new_dp)
 {
 	int ret = 0;
+	int priority;
 	char *regex = NULL;
 	char *basedntemplate = NULL;
 	char *filtertemplate = NULL;
+	char *priority_str = NULL;
 	char *map_name = NULL;
 
 	*new_dp = NULL;
@@ -352,21 +379,43 @@ sasl_map_config_parse_entry(Slapi_Entry *entry, sasl_map_data **new_dp)
 	basedntemplate = slapi_entry_attr_get_charptr( entry, "nsSaslMapBaseDNTemplate" );
 	filtertemplate = slapi_entry_attr_get_charptr( entry, "nsSaslMapFilterTemplate" );
 	map_name = slapi_entry_attr_get_charptr( entry, "cn" );
+	priority_str = slapi_entry_attr_get_charptr( entry, "nsSaslMapPriority" );
 
+	if(priority_str){
+		priority = atoi(priority_str);
+	} else {
+		priority = LOW_PRIORITY;
+	}
+	if(priority == 0 || priority > LOW_PRIORITY){
+		struct berval desc;
+		struct berval *newval[2] = {0, 0};
+
+		desc.bv_val = LOW_PRIORITY_STR;
+		desc.bv_len = strlen(desc.bv_val);
+		newval[0] = &desc;
+		if (entry_replace_values(entry, "nsSaslMapPriority", newval) != 0){
+			LDAPDebug( LDAP_DEBUG_TRACE, "sasl_map_config_parse_entry: failed to reset priority to (%d)\n",
+					LOW_PRIORITY,0,0);
+		} else {
+			LDAPDebug( LDAP_DEBUG_ANY, "sasl_map_config_parse_entry: resetting nsSaslMapPriority to lowest priority(%d)\n",
+					LOW_PRIORITY,0,0);
+		}
+		priority = LOW_PRIORITY;
+	}
 	if ( (NULL == map_name) || (NULL == regex) ||
 		 (NULL == basedntemplate) || (NULL == filtertemplate) ) {
 		/* Invalid entry */
 		ret = -1;
 	} else {
 		/* Make the new dp */
-		*new_dp = sasl_map_new_data(map_name, regex, basedntemplate, filtertemplate);
+		*new_dp = sasl_map_new_data(map_name, regex, basedntemplate, filtertemplate, priority);
 	}
 
 	if (ret) {
-		slapi_ch_free((void **) &map_name);
-		slapi_ch_free((void **) &regex);
-		slapi_ch_free((void **) &basedntemplate);
-		slapi_ch_free((void **) &filtertemplate);
+		slapi_ch_free_string(&map_name);
+		slapi_ch_free_string(&regex);
+		slapi_ch_free_string(&basedntemplate);
+		slapi_ch_free_string(&filtertemplate);
 	}
 	return ret;
 }
@@ -430,6 +479,35 @@ sasl_map_config_add(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
 	return ret;
 }
 
+int
+sasl_map_config_modify(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+	sasl_map_private *priv = sasl_map_get_global_priv();
+	sasl_map_data *dp;
+	char *map_name = NULL;
+	int ret = SLAPI_DSE_CALLBACK_ERROR;
+
+	if((map_name = slapi_entry_attr_get_charptr( entryBefore, "cn" )) == NULL){
+		LDAPDebug( LDAP_DEBUG_TRACE, "sasl_map_config_modify: could not find name of map\n",0,0,0);
+		return ret;
+	}
+	if(sasl_map_remove_list_entry(priv, map_name) == 0){
+		ret = sasl_map_config_parse_entry(e, &dp);
+		if (!ret && dp) {
+			ret = sasl_map_insert_list_entry(priv, dp);
+			if(ret == 0){
+				ret = SLAPI_DSE_CALLBACK_OK;
+			}
+		}
+	}
+	if(ret == SLAPI_DSE_CALLBACK_ERROR){
+		LDAPDebug( LDAP_DEBUG_TRACE, "sasl_map_config_modify: failed to update map(%s)\n",map_name,0,0);
+	}
+	slapi_ch_free_string(&map_name);
+
+	return ret;
+}
+
 int
 sasl_map_config_delete(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
 {
@@ -485,30 +563,20 @@ int sasl_map_done()
 	}
 
 	/* Free the map list */
-	PR_Lock(priv->lock);
+	slapi_rwlock_wrlock(priv->lock);
 	dp = priv->map_data_list;
 	while (dp) {
 		sasl_map_data *dp_next = dp->next;
 		sasl_map_free_data(&dp);
 		dp = dp_next;
 	}
-	PR_Unlock(priv->lock);
+	slapi_rwlock_unlock(priv->lock);
 
 	/* Free the private structure */
 	sasl_map_free_private(&priv);
 	return ret;
 }
 
-static sasl_map_data*
-sasl_map_first(sasl_map_private *priv)
-{
-	sasl_map_data *result = NULL;
-	PR_Lock(priv->lock);
-	result = priv->map_data_list;
-	PR_Unlock(priv->lock);
-	return result;
-}
-
 static int
 sasl_map_check(sasl_map_data *dp, char *sasl_user_and_realm, char **ldap_search_base, char **ldap_search_filter)
 {
@@ -610,28 +678,31 @@ sasl_map_str_concat(char *s1, char *s2)
  * returns 1 if matched, 0 otherwise
  */
 int
-sasl_map_domap(char *sasl_user, char *sasl_realm, char **ldap_search_base, char **ldap_search_filter)
+sasl_map_domap(sasl_map_data **map, char *sasl_user, char *sasl_realm, char **ldap_search_base, char **ldap_search_filter)
 {
-	int ret = 0;
-	sasl_map_data *this_map = NULL;
-	char *sasl_user_and_realm = NULL;
 	sasl_map_private *priv = sasl_map_get_global_priv();
+	char *sasl_user_and_realm = NULL;
+	int ret = 0;
+
+	LDAPDebug( LDAP_DEBUG_TRACE, "-> sasl_map_domap\n", 0, 0, 0 );
+	if(map == NULL){
+		LDAPDebug( LDAP_DEBUG_TRACE, "<- sasl_map_domap: Internal error, mapping is NULL\n",0,0,0);
+		return ret;
+	}
 	*ldap_search_base = NULL;
 	*ldap_search_filter = NULL;
-	LDAPDebug( LDAP_DEBUG_TRACE, "-> sasl_map_domap\n", 0, 0, 0 );
 	sasl_user_and_realm = sasl_map_str_concat(sasl_user,sasl_realm);
 	/* Walk the list of maps */
-	this_map = sasl_map_first(priv);
-	while (this_map) {
-		int matched = 0;
+	if(*map == NULL)
+		*map = priv->map_data_list;
+	while (*map) {
 		/* If one matches, then make the search params */
-		LDAPDebug( LDAP_DEBUG_TRACE, "sasl_map_domap - trying map [%s]\n", this_map->name, 0, 0 );
-		matched = sasl_map_check(this_map, sasl_user_and_realm, ldap_search_base, ldap_search_filter);
-		if (1 == matched) {
-			ret = 1;
+		LDAPDebug( LDAP_DEBUG_TRACE, "sasl_map_domap - trying map [%s]\n", (*map)->name, 0, 0 );
+		if((ret = sasl_map_check(*map, sasl_user_and_realm, ldap_search_base, ldap_search_filter))){
+			*map = sasl_map_next(*map);
 			break;
 		}
-		this_map = sasl_map_next(this_map);
+		*map = sasl_map_next(*map);
 	}
 	if (sasl_user_and_realm) {
 		slapi_ch_free((void**)&sasl_user_and_realm);
@@ -640,3 +711,16 @@ sasl_map_domap(char *sasl_user, char *sasl_realm, char **ldap_search_base, char
 	return ret;
 }
 
+void
+sasl_map_read_lock()
+{
+	sasl_map_private *priv = sasl_map_get_global_priv();
+	slapi_rwlock_rdlock(priv->lock);
+}
+
+void
+sasl_map_read_unlock()
+{
+	sasl_map_private *priv = sasl_map_get_global_priv();
+	slapi_rwlock_unlock(priv->lock);
+}

+ 37 - 25
ldap/servers/slapd/saslbind.c

@@ -323,14 +323,15 @@ static Slapi_Entry *ids_sasl_user_to_entry(
     const char *user_realm
 )
 {
-    int found = 0;
-    int attrsonly = 0, scope = LDAP_SCOPE_SUBTREE;
     LDAPControl **ctrls = NULL;
+    sasl_map_data *map = NULL;
     Slapi_Entry *entry = NULL;
     char **attrs = NULL;
-    int regexmatch = 0;
     char *base = NULL;
     char *filter = NULL;
+    int attrsonly = 0, scope = LDAP_SCOPE_SUBTREE;
+    int regexmatch = 0;
+    int found = 0;
 
     /* Check for wildcards in the authid and realm. If we encounter one,
      * just fail the mapping without performing a costly internal search. */
@@ -345,31 +346,42 @@ static Slapi_Entry *ids_sasl_user_to_entry(
     }
 
     /* New regex-based identity mapping */
-    regexmatch = sasl_map_domap((char*)user, (char*)user_realm, &base, &filter);
-    if (regexmatch) {
-        ids_sasl_user_search(base, scope, filter, 
-                             ctrls, attrs, attrsonly,
-                             &entry, &found);
-
-        if (found == 1) {
-            LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found this entry: dn:%s, "
-                "matching filter=%s\n", entry->e_sdn.dn, filter, 0);
-        } else if (found == 0) {
-            LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found no entries matching "
-                "filter=%s\n", filter, 0, 0);
-        } else {
-            LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found more than one entry "
-                "matching filter=%s\n", filter, 0, 0);
-            if (entry) {
-                slapi_entry_free(entry);
-                entry = NULL;
+    sasl_map_read_lock();
+    while(1){
+        regexmatch = sasl_map_domap(&map, (char*)user, (char*)user_realm, &base, &filter);
+        if (regexmatch) {
+            ids_sasl_user_search(base, scope, filter,
+                                 ctrls, attrs, attrsonly,
+                                 &entry, &found);
+            if (found == 1) {
+                LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found this entry: dn:%s, "
+                    "matching filter=%s\n", entry->e_sdn.dn, filter, 0);
+            } else if (found == 0) {
+                LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found no entries matching "
+                    "filter=%s\n", filter, 0, 0);
+            } else {
+                LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found more than one entry "
+                    "matching filter=%s\n", filter, 0, 0);
+                if (entry) {
+                    slapi_entry_free(entry);
+                    entry = NULL;
+                }
             }
-        }
 
-        /* Free the filter etc */
-        slapi_ch_free_string(&base);
-        slapi_ch_free_string(&filter);
+            /* Free the filter etc */
+            slapi_ch_free_string(&base);
+            slapi_ch_free_string(&filter);
+
+            /* If we didn't find an entry, look at the other maps */
+            if(found){
+                break;
+            }
+        }
+        if(map == NULL){
+            break;
+        }
     }
+    sasl_map_read_unlock();
 
     return entry;
 }