From 743986a38facd46576d36c6c22ec3cd598fa0a12 Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@redhat.com>
Date: Thu, 22 May 2014 13:48:43 -0700
Subject: [PATCH] Ticket #47720 - Normalization from old DN format to New DN
 format doesnt handel condition properly when there is space in a suffix after
 the seperator operator.

Description: DN normalizer (slapi_dn_normalize_ext) follows RFC 4514
and keeps a white space if the RDN attribute type is not based on the
DN syntax.  But Directory server's configuration entry sometimes uses
"cn" to store a DN value (e.g., dn: cn="dc=A,dc=com",cn=mapping tree,
cn=config), which expects the value of cn treated as DN although cn
is not a DN syntax type.  To solve the problem, this patch introduces
a configuration parameter "nsslapd-cn-uses-dn-syntax-in-dns" to "cn=
config" which takes "on" or "off".  If "on" is set, if the value of
cn under "cn=config" is quoted, it's processed as DN.  By default,
  nsslapd-cn-uses-dn-syntax-in-dns: off
---
 ldap/servers/slapd/dn.c         | 45 +++++++++++++++++++++++++++++++++++++++++
 ldap/servers/slapd/libglobs.c   | 35 ++++++++++++++++++++++++++++++++
 ldap/servers/slapd/proto-slap.h |  2 ++
 ldap/servers/slapd/slap.h       |  3 +++
 4 files changed, 85 insertions(+)

diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
index 76b33da..cea593b 100644
--- a/ldap/servers/slapd/dn.c
+++ b/ldap/servers/slapd/dn.c
@@ -61,6 +61,7 @@ static void reset_rdn_avs( struct berval **rdn_avsp, int *rdn_av_countp );
 static void sort_rdn_avs( struct berval *avs, int count, int escape );
 static int rdn_av_cmp( struct berval *av1, struct berval *av2 );
 static void rdn_av_swap( struct berval *av1, struct berval *av2, int escape );
+static int does_cn_uses_dn_syntax_in_dns(char *type, char *dn);
 
 /* normalized dn cache related definitions*/
 struct
@@ -621,6 +622,10 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
                 /* Reset the character we modified. */
                 *d = savechar;
 
+                if (!is_dn_syntax) {
+                    is_dn_syntax = does_cn_uses_dn_syntax_in_dns(typestart, src);
+                }
+
                 state = B4VALUE;
                 *d++ = *s++;
             } else if (ISCLOSEBRACKET(*s)) { /* special care for ACL macro */
@@ -639,6 +644,10 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
                 /* Reset the character we modified. */
                 *d = savechar;
 
+                if (!is_dn_syntax) {
+                    is_dn_syntax = does_cn_uses_dn_syntax_in_dns(typestart, src);
+                }
+
                 state = INVALUE; /* skip a trailing space */
                 *d++ = *s++;
             } else if (ISSPACE(*s)) {
@@ -657,6 +666,10 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
                 /* Reset the character we modified. */
                 *d = savechar;
 
+                if (!is_dn_syntax) {
+                    is_dn_syntax = does_cn_uses_dn_syntax_in_dns(typestart, src);
+                }
+
                 state = B4EQUAL; /* skip a trailing space */
             } else if (ISQUOTE(*s) || SEPARATOR(*s)) {
                 /* type includes quote / separator; not a valid dn */
@@ -1030,6 +1043,18 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
                             s++;
                     }
                 }
+            } else if (ISSPACE(*s)) {
+                while (ISSPACE(*s)) {
+                    s++;
+                }
+                /* 
+                 * dn_syntax_attr=ABC,   XYZ --> dn_syntax_attr=ABC,XYZ
+                 * non_dn_syntax_attr=ABC,   XYZ --> dn_syntax_attr=ABC, XYZ
+                 */
+                if (!is_dn_syntax) {
+                    --s;
+                    *d++ = *s++;
+                }
             } else {
                 *d++ = *s++;
             }
@@ -3172,3 +3197,23 @@ slapi_sdn_common_ancestor(Slapi_DN *dn1, Slapi_DN *dn2)
     charray_free(dns2);
     return slapi_sdn_new_ndn_passin(common);
 }
+
+/*
+ * Return 1 - if nsslapd-cn-uses-dn-syntax-in-dns is true &&
+ *            the type is "cn" && dn is under "cn=config"
+ * Return 0 - otherwise
+ */
+static int
+does_cn_uses_dn_syntax_in_dns(char *type, char *dn)
+{
+    int rc = 0;  /* by default off */
+    char *ptr = NULL;
+    if (type && dn && config_get_cn_uses_dn_syntax_in_dns() &&
+        (PL_strcasecmp(type, "cn") == 0) && (ptr = PL_strrchr(dn, ','))) {
+        if (PL_strcasecmp(++ptr, "cn=config") == 0) {
+            rc = 1;
+        }
+    }
+    return rc;
+}
+
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index d1a3dc0..040649b 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -271,6 +271,7 @@ slapi_int_t init_connection_buffer;
 slapi_int_t init_listen_backlog_size;
 slapi_onoff_t init_ignore_time_skew;
 slapi_onoff_t init_dynamic_plugins;
+slapi_onoff_t init_cn_uses_dn_syntax_in_dns;
 #if defined (LINUX)
 slapi_int_t init_malloc_mxfast;
 slapi_int_t init_malloc_trim_threshold;
@@ -1092,6 +1093,10 @@ static struct config_get_and_set {
 		NULL, 0,
 		(void**)&global_slapdFrontendConfig.dynamic_plugins, CONFIG_ON_OFF,
 		(ConfigGetFunc)config_get_dynamic_plugins, &init_dynamic_plugins},
+	{CONFIG_CN_USES_DN_SYNTAX_IN_DNS, config_set_cn_uses_dn_syntax_in_dns,
+		NULL, 0,
+		(void**)&global_slapdFrontendConfig.cn_uses_dn_syntax_in_dns, CONFIG_ON_OFF,
+		(ConfigGetFunc)config_get_cn_uses_dn_syntax_in_dns, &init_cn_uses_dn_syntax_in_dns},
 #if defined(LINUX)
 	{CONFIG_MALLOC_MXFAST, config_set_malloc_mxfast,
 		NULL, 0,
@@ -1558,6 +1563,7 @@ FrontendConfig_init () {
   init_listen_backlog_size = cfg->listen_backlog_size = DAEMON_LISTEN_SIZE;
   init_ignore_time_skew = cfg->ignore_time_skew = LDAP_OFF;
   init_dynamic_plugins = cfg->dynamic_plugins = LDAP_OFF;
+  init_cn_uses_dn_syntax_in_dns = cfg->cn_uses_dn_syntax_in_dns = LDAP_OFF;
 #if defined(LINUX)
   init_malloc_mxfast = cfg->malloc_mxfast = DEFAULT_MALLOC_UNSET;
   init_malloc_trim_threshold = cfg->malloc_trim_threshold = DEFAULT_MALLOC_UNSET;
@@ -3289,6 +3295,7 @@ config_set_dynamic_plugins( const char *attrname, char *value, char *errorbuf, i
 
   return retVal;
 }
+
 int
 config_get_dynamic_plugins() {
   slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
@@ -3302,6 +3309,34 @@ config_get_dynamic_plugins() {
 }
 
 int
+config_set_cn_uses_dn_syntax_in_dns(const char *attrname, char *value, char *errorbuf, int apply)
+{
+  int retVal = LDAP_SUCCESS;
+  slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+  retVal = config_set_onoff ( attrname,
+							  value,
+							  &(slapdFrontendConfig->cn_uses_dn_syntax_in_dns),
+							  errorbuf,
+							  apply);
+
+  return retVal;
+}
+
+int
+config_get_cn_uses_dn_syntax_in_dns()
+{
+  slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+  int retVal;
+
+  CFG_ONOFF_LOCK_READ(slapdFrontendConfig);
+  retVal = (int)slapdFrontendConfig->cn_uses_dn_syntax_in_dns;
+  CFG_ONOFF_UNLOCK_READ(slapdFrontendConfig);
+
+  return retVal;
+}
+
+int
 config_set_security( const char *attrname, char *value, char *errorbuf, int apply ) {
   int retVal = LDAP_SUCCESS;
   slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 4c3e517..34c4ac6 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -586,6 +586,8 @@ int config_set_plugin_logging(const char *attrname, char *value, char *errorbuf,
 int config_get_listen_backlog_size(void);
 int config_set_dynamic_plugins(const char *attrname, char *value, char *errorbuf, int apply);
 int config_get_dynamic_plugins();
+int config_set_cn_uses_dn_syntax_in_dns(const char *attrname, char *value, char *errorbuf, int apply);
+int config_get_cn_uses_dn_syntax_in_dns();
 
 PLHashNumber hashNocaseString(const void *key);
 PRIntn hashNocaseCompare(const void *v1, const void *v2);
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 642f3b2..5401a66 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -2152,6 +2152,8 @@ typedef struct _slapdEntryPoints {
 #define CONFIG_DYNAMIC_PLUGINS "nsslapd-dynamic-plugins"
 #define CONFIG_RETURN_DEFAULT_OPATTR "nsslapd-return-default-opattr"
 
+#define CONFIG_CN_USES_DN_SYNTAX_IN_DNS "nsslapd-cn-uses-dn-syntax-in-dns"
+
 /* getenv alternative */
 #define CONFIG_MALLOC_MXFAST "nsslapd-malloc-mxfast"
 #define CONFIG_MALLOC_TRIM_THRESHOLD "nsslapd-malloc-trim-threshold"
@@ -2415,6 +2417,7 @@ typedef struct _slapdFrontendConfig {
   slapi_onoff_t plugin_logging; /* log all internal plugin operations */
   slapi_onoff_t ignore_time_skew;
   slapi_onoff_t dynamic_plugins; /* allow plugins to be dynamically enabled/disabled */
+  slapi_onoff_t cn_uses_dn_syntax_in_dns; /* indicates the cn value in dns has dn syntax */
 #if defined(LINUX)
   int malloc_mxfast;            /* mallopt M_MXFAST */
   int malloc_trim_threshold;    /* mallopt M_TRIM_THRESHOLD */
-- 
1.8.1.4

