From 048244add355d521a9f765ad9820e991ffcb8199 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Thu, 10 Jan 2013 11:52:31 -0500
Subject: [PATCH] Ticket 551 - Multivalued rootdn-days-allowed in RootDN Access Control plugin always results in access control violation

Bug Description:  The server allows you to add multiple rootdn-days-allowed attributes.

Fix Description:  The attribute needs to be single valued.  Added rootdn plugin attributes
                  to schema, and improved dse schema checking at server startupi & setup.

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

Reviewed by: ?
---
 ldap/ldif/template-dse.ldif.in |    2 +-
 ldap/schema/01core389.ldif     |   12 +++++++++++-
 ldap/servers/slapd/dse.c       |   28 ++++++++++++++++++++--------
 3 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/ldap/ldif/template-dse.ldif.in b/ldap/ldif/template-dse.ldif.in
index b854c47..95ed60c 100644
--- a/ldap/ldif/template-dse.ldif.in
+++ b/ldap/ldif/template-dse.ldif.in
@@ -741,7 +741,7 @@ nsslapd-plugin-depends-on-type: database
 dn: cn=RootDN Access Control,cn=plugins,cn=config
 objectclass: top
 objectclass: nsSlapdPlugin
-objectclass: extensibleObject
+objectclass: rootDNPluginConfig
 cn: RootDN Access Control
 nsslapd-pluginpath: librootdn-access-plugin.so
 nsslapd-plugininitfunc: rootdn_init
diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif
index 1c9112f..7fe8b13 100644
--- a/ldap/schema/01core389.ldif
+++ b/ldap/schema/01core389.ldif
@@ -141,11 +141,19 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2137 NAME 'nsds5ReplicaAbortCleanRUV' DE
 attributeTypes: ( 2.16.840.1.113730.3.1.2111 NAME 'tombstoneNumSubordinates' DESC 'count of immediate subordinates for tombstone entries' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN '389 directory server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2138 NAME 'nsslapd-readonly' 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.2143 NAME 'nsslapd-sasl-mapping-fallback' 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.2144 NAME 'rootdn-open-time' 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.2145 NAME 'rootdn-close-time' 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.2146 NAME 'rootdn-days-allowed' 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.2147 NAME 'rootdn-allow-host' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2148 NAME 'rootdn-deny-host' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2149 NAME 'rootdn-allow-ip' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2150 NAME 'rootdn-deny-ip' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2151 NAME 'nsslapd-plugin-depends-on-type' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
 #
 # objectclasses
 #
 objectClasses: ( 2.16.840.1.113730.3.2.40 NAME 'directoryServerFeature' DESC 'Netscape defined objectclass' SUP top MAY ( oid $ cn $ multiLineDescription ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.41 NAME 'nsslapdPlugin' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsslapd-pluginPath $ nsslapd-pluginInitFunc $ nsslapd-pluginType $ nsslapd-pluginId $ nsslapd-pluginVersion $ nsslapd-pluginVendor $ nsslapd-pluginDescription $ nsslapd-pluginEnabled ) MAY ( nsslapd-pluginConfigArea ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.41 NAME 'nsslapdPlugin' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsslapd-pluginPath $ nsslapd-pluginInitFunc $ nsslapd-pluginType $ nsslapd-pluginId $ nsslapd-pluginVersion $ nsslapd-pluginVendor $ nsslapd-pluginDescription $ nsslapd-pluginEnabled ) MAY ( nsslapd-pluginConfigArea $ nsslapd-plugin-depends-on-type ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.44 NAME 'nsIndex' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSystemIndex ) MAY ( description $ nsIndexType $ nsMatchingRule ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.109 NAME 'nsBackendInstance' DESC 'Netscape defined objectclass' SUP top  MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.110 NAME 'nsMappingTree' DESC 'Netscape defined objectclass' SUP top  MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
@@ -158,3 +166,5 @@ objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape d
 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' )
+objectClasses: ( 2.16.840.1.113730.3.2.327 NAME 'rootDNPluginConfig' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( rootdn-open-time $ rootdn-close-time $ rootdn-days-allowed $ rootdn-allow-host $ rootdn-deny-host $ rootdn-allow-ip $ rootdn-deny-ip ) X-ORIGIN 'Netscape' )
+
diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c
index fd40432..75b9502 100644
--- a/ldap/servers/slapd/dse.c
+++ b/ldap/servers/slapd/dse.c
@@ -81,6 +81,7 @@
 #define SLAPI_DSE_TRACELEVEL	LDAP_DEBUG_TRACE
 #endif /* SLAPI_DSE_DEBUG */
 
+#define SCHEMA_VIOLATION -2
 #define STOP_TRAVERSAL -2
 
 /* This is returned by dupentry_replace if the duplicate entry was found and
@@ -704,9 +705,9 @@ dse_read_one_file(struct dse *pdse, const char *filename, Slapi_PBlock *pb,
     if ( (NULL != pdse) && (NULL != filename) )
     {
         /* check if the "real" file exists and cam be used, if not try tmp as backup */
-	rc = dse_check_file((char *)filename, pdse->dse_tmpfile);
-	if (!rc) 
-	    rc = dse_check_file((char *)filename, pdse->dse_fileback);
+        rc = dse_check_file((char *)filename, pdse->dse_tmpfile);
+        if (!rc)
+            rc = dse_check_file((char *)filename, pdse->dse_fileback);
 
         if ( (rc = PR_GetFileInfo( filename, &prfinfo )) != PR_SUCCESS )
         {
@@ -799,9 +800,14 @@ dse_read_one_file(struct dse *pdse, const char *filename, Slapi_PBlock *pb,
                                     DSE_FLAG_PREOP, e, NULL, &returncode,
                                     returntext) == SLAPI_DSE_CALLBACK_OK)
                         {
-                            /* this will free the entry if not added, so it is
-                               definitely consumed by this call */
-                            dse_add_entry_pb(pdse, e, pb);
+                            /*
+                             * This will free the entry if not added, so it is
+                             * definitely consumed by this call
+                             */
+                            if(dse_add_entry_pb(pdse, e, pb) == SCHEMA_VIOLATION){
+                                /* schema violation, return failure */
+                                rc = 0;
+                            }
                         }
                         else /* free entry if not used */
                         {
@@ -1119,7 +1125,11 @@ dse_write_entry( caddr_t data, caddr_t arg )
   
 /*
  * Adds an entry to the dse backend.  The passed in entry will be
- * free'd always. */
+ * free'd always.
+ *
+ * return -1 for duplicate entry
+ * return -2 for schema violation (SCHEMA_VIOLATION)
+ */
 static int
 dse_add_entry_pb(struct dse* pdse, Slapi_Entry *e, Slapi_PBlock *pb)
 {
@@ -1190,7 +1200,9 @@ dse_add_entry_pb(struct dse* pdse, Slapi_Entry *e, Slapi_PBlock *pb)
 		 * Verify that the new or merged entry conforms to the schema.
 		 *		Errors are logged by slapi_entry_schema_check().
 		 */
-		(void)slapi_entry_schema_check( pb, schemacheckentry );
+		if(slapi_entry_schema_check( pb, schemacheckentry )){
+			rc = SCHEMA_VIOLATION;
+		}
 		slapi_entry_free(schemacheckentry);
 	}
 
-- 
1.7.1

