diff options
author | Noriko Hosoi <nhosoi@redhat.com> | 2010-04-26 11:03:52 -0700 |
---|---|---|
committer | Noriko Hosoi <nhosoi@redhat.com> | 2010-04-26 11:03:52 -0700 |
commit | 78c50664d6421cc5d0836bb03820680dc2cb7acf (patch) | |
tree | 20fcfadad9057617daa0b159216f0a92006969f5 | |
parent | 4754291972668c37559a8f68d75ac6f8c477efb8 (diff) | |
download | ds-78c50664d6421cc5d0836bb03820680dc2cb7acf.tar.gz ds-78c50664d6421cc5d0836bb03820680dc2cb7acf.tar.xz ds-78c50664d6421cc5d0836bb03820680dc2cb7acf.zip |
Update to New DN Format
Fix Description:
. adding slapi_dn_normalize_ext and its siblings to normalize/validate
invalid DNs; deprecating slapi_dn_normalize and its siblings. (dn.c)
. replacing slapi_dn_normalize with new corresponding functions.
. normalizing hardcoded DNs (e.g., removing spaces around ',')
. setting correct DN syntax to nsslapd-suffix, nsslapd-ldapiautodnsuffix,
costemplatedn, nsslapd-changelogsuffix, nsBaseDN, nsBindDN
. if nsslapd-dn-validate-strict is enabled, incoming DN is examined and
rejected if it is invalid. Once approved, the DN is normalized.
. fixing compiler warnings and typos.
See also:
http://directory.fedoraproject.org/wiki/Upgrade_to_New_DN_Format
Related bugs:
Bug 199923 - subtree search fails to find items under a db containing special
characters
Bug 567968 - subtree/user level password policy created using 389-ds-console
doesn't work.
Bug 570107 - The import of LDIFs with base-64 encoded DNs fails, modrdn with
non-ASCII new rdn incorrect
Bug 570962 - ns-inactivate.pl does not work
Bug 572785 - DN syntax: old style of DN <type>="<DN>",<the_rest> is not
correctly normalized
Bug 573060 - DN normalizer: ESC HEX HEX is not normalized
Bug 574167 - An escaped space at the end of the RDN value is not handled
correctly
83 files changed, 3023 insertions, 783 deletions
diff --git a/ldap/admin/src/scripts/Migration.pm.in b/ldap/admin/src/scripts/Migration.pm.in index 44613a80..1942c8b2 100644 --- a/ldap/admin/src/scripts/Migration.pm.in +++ b/ldap/admin/src/scripts/Migration.pm.in @@ -125,7 +125,7 @@ You can supply default .inf data in this format: e.g. General.FullMachineName=foo.example.com or - "slapd.Suffix=dc=example, dc=com" + "slapd.Suffix=dc=example,dc=com" Values passed in this manner will override values in an .inf file given with the -f argument. diff --git a/ldap/admin/src/scripts/Setup.pm.in b/ldap/admin/src/scripts/Setup.pm.in index 021a99c7..52300db0 100644 --- a/ldap/admin/src/scripts/Setup.pm.in +++ b/ldap/admin/src/scripts/Setup.pm.in @@ -110,7 +110,7 @@ You can supply default .inf data in this format: e.g. General.FullMachineName=foo.example.com or - "slapd.Suffix=dc=example, dc=com" + "slapd.Suffix=dc=example,dc=com" Values passed in this manner will override values in an .inf file given with the -f argument. EOF } diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif index af445e7c..96e70a86 100644 --- a/ldap/schema/01core389.ldif +++ b/ldap/schema/01core389.ldif @@ -122,6 +122,8 @@ attributeTypes: ( nsSSLSupportedCiphers-oid NAME 'nsSSLSupportedCiphers' DESC 'N attributeTypes: ( nsSSLToken-oid NAME 'nsSSLToken' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' ) attributeTypes: ( nsSSLPersonalitySSL-oid NAME 'nsSSLPersonalitySSL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' ) attributeTypes: ( nsSSLActivation-oid NAME 'nsSSLActivation' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' ) +attributeTypes: ( 2.16.840.1.113730.3.1.2091 NAME 'nsslapd-suffix' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' ) +attributeTypes: ( 2.16.840.1.113730.3.1.2092 NAME 'nsslapd-ldapiautodnsuffix' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' ) # # objectclasses # diff --git a/ldap/schema/02common.ldif b/ldap/schema/02common.ldif index 7ea5594d..5269d3bd 100644 --- a/ldap/schema/02common.ldif +++ b/ldap/schema/02common.ldif @@ -110,7 +110,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.223 NAME ( 'passwordResetFailureCount' ' attributeTypes: ( 2.16.840.1.113730.3.1.550 NAME 'cosAttribute' 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.551 NAME 'cosspecifier' 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.552 NAME 'costargettree' 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.553 NAME 'costemplatedn' 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.553 NAME 'costemplatedn' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.35 NAME 'changeLog' DESC 'the distinguished name of the entry which contains the set of entries comprising this servers changelog' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Changelog Internet Draft' ) attributeTypes: ( 2.16.840.1.113730.3.1.200 NAME 'changeLogMaximumAge' 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.201 NAME 'changeLogMaximumSize' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' ) @@ -144,6 +144,7 @@ attributeTypes: ( 1.3.6.1.1.4 NAME 'vendorName' EQUALITY 1.3.6.1.4.1.1466.109.11 attributeTypes: ( 1.3.6.1.1.5 NAME 'vendorVersion' EQUALITY 1.3.6.1.4.1.1466.109.114.1 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation X-ORIGIN 'RFC 3045' ) attributeTypes: ( 2.16.840.1.113730.3.1.3023 NAME 'nsViewFilter' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.2063 NAME 'nsEncryptionAlgorithm' 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.2093 NAME 'nsslapd-changelogsuffix' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' ) # # objectclasses: # diff --git a/ldap/schema/30ns-common.ldif b/ldap/schema/30ns-common.ldif index a6b109d8..cee5a07b 100644 --- a/ldap/schema/30ns-common.ldif +++ b/ldap/schema/30ns-common.ldif @@ -42,8 +42,8 @@ # dn: cn=schema attributeTypes: ( nsServerID-oid NAME 'nsServerID' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' ) -attributeTypes: ( nsBaseDN-oid NAME 'nsBaseDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' ) -attributeTypes: ( nsBindDN-oid NAME 'nsBindDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' ) +attributeTypes: ( nsBaseDN-oid NAME 'nsBaseDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' ) +attributeTypes: ( nsBindDN-oid NAME 'nsBindDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' ) attributeTypes: ( nsBindPassword-oid NAME 'nsBindPassword' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' ) attributeTypes: ( nsServerPort-oid NAME 'nsServerPort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' ) attributeTypes: ( nsServerAddress-oid NAME 'nsServerAddress' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' ) diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c index aa22d566..715ad1ea 100644 --- a/ldap/servers/plugins/acl/acl.c +++ b/ldap/servers/plugins/acl/acl.c @@ -358,8 +358,8 @@ acl_access_allowed( if (oid && ((strcasecmp(oid, DN_SYNTAX_OID) == 0) || (strcasecmp(oid, NAMEANDOPTIONALUID_SYNTAX_OID) == 0))) { /* should use slapi_sdn_compare() but that'a an extra malloc/free */ - char *dn_val_to_write = slapi_dn_normalize(slapi_ch_strdup(val->bv_val)); - if ( aclpb->aclpb_authorization_sdn && + char *dn_val_to_write = slapi_create_dn_string("%s", val->bv_val); + if ( dn_val_to_write && aclpb->aclpb_authorization_sdn && slapi_utf8casecmp((ACLUCHP)dn_val_to_write, (ACLUCHP) slapi_sdn_get_ndn(aclpb->aclpb_authorization_sdn)) == 0) { access |= SLAPI_ACL_SELF; @@ -754,9 +754,10 @@ static void print_access_control_summary( char *source, int ret_val, char *clien if ( aclpb->aclpb_authorization_sdn != NULL ) { - proxy_user = (char *)(aclpb->aclpb_authorization_sdn->ndn ? - aclpb->aclpb_authorization_sdn->ndn: - null_user); + proxy_user = + (char *)(slapi_sdn_get_ndn(aclpb->aclpb_authorization_sdn)? + slapi_sdn_get_ndn(aclpb->aclpb_authorization_sdn): + null_user); slapi_log_error(loglevel, plugin_name, "conn=%" NSPRIu64 " op=%d (%s): %s %s on entry(%s).attr(%s) to proxy (%s)" @@ -1764,8 +1765,7 @@ acl_modified (Slapi_PBlock *pb, int optype, char *n_dn, void *change) if (parent_DN == NULL) { new_DN = new_RDN; } else { - new_DN = slapi_ch_smprintf("%s,%s", new_RDN, parent_DN); - slapi_dn_normalize (new_DN); + new_DN = slapi_create_dn_string("%s,%s", new_RDN, parent_DN); } /* Change the acls */ @@ -2028,8 +2028,7 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int * ** We have a single ACI which we need to find if it applies to ** the resource or not. */ - if ((aci->aci_type & ACI_TARGET_DN) && - (aclpb->aclpb_curr_entry_sdn)) { + if ((aci->aci_type & ACI_TARGET_DN) && (aclpb->aclpb_curr_entry_sdn)) { char *avaType; struct berval *avaValue; @@ -2246,10 +2245,10 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int * * */ - if ((aclpb->aclpb_access & SLAPI_ACL_ADD && - aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS )|| - (aclpb->aclpb_access & SLAPI_ACL_DELETE && - aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS ) ) { + if (((aclpb->aclpb_access & SLAPI_ACL_ADD) && + (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) )|| + ((aclpb->aclpb_access & SLAPI_ACL_DELETE) && + (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS) ) ) { Targetattrfilter **attrFilterArray; @@ -2367,10 +2366,10 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int * goto acl__resource_match_aci_EXIT; } - } else if ( (aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD && - aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) || - (aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL && - aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS ) ) { + } else if ( ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD) && + (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) || + ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL) && + (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)) ) { /* @@ -2381,28 +2380,28 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int * * match that filter. * * - */ + */ Targetattrfilter **attrFilterArray = NULL; Targetattrfilter *attrFilter; int found = 0; - if (aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD && - aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) { + if ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD) && + (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) { - attrFilterArray = aci->targetAttrAddFilters; + attrFilterArray = aci->targetAttrAddFilters; - } else if (aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL && - aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS) { + } else if ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL) && + (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)) { - attrFilterArray = aci->targetAttrDelFilters; + attrFilterArray = aci->targetAttrDelFilters; } /* * Scan this filter list for an applicable filter. - */ + */ found = 0; num_attrs = 0; @@ -2435,7 +2434,7 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int * attr_matched= acl__test_filter(aclpb->aclpb_filter_test_entry, attrFilter->filter, 1 /* Do filter sense evaluation below */ - ); + ); slapi_entry_free( aclpb->aclpb_filter_test_entry ); } @@ -2452,8 +2451,6 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int * */ attr_matched_in_targetattrfilters = 1; - - } } /* targetvaluefilters */ @@ -3233,9 +3230,6 @@ acl_match_substring ( Slapi_Filter *f, char *str, int exact_match) realval = tmp; } - slapi_dn_normalize (realval); - - /* What we have built is a regular pattaren expression. ** Now we will compile the pattern and compare wth the string to ** see if the input string matches with the patteren or not. diff --git a/ldap/servers/plugins/acl/acl.h b/ldap/servers/plugins/acl/acl.h index 36bdd43c..3f4b4e62 100644 --- a/ldap/servers/plugins/acl/acl.h +++ b/ldap/servers/plugins/acl/acl.h @@ -119,7 +119,11 @@ static char* const aci_targetattr = "targetattr"; static char* const aci_targetattrfilters = "targattrfilters"; static char* const aci_targetfilter = "targetfilter"; +static char* const LDAP_URL_prefix_core = "ldap://"; +static char* const LDAPS_URL_prefix_core = "ldaps://"; + static char* const LDAP_URL_prefix = "ldap:///"; +static char* const LDAPS_URL_prefix = "ldaps:///"; static char* const access_str_compare = "compare"; static char* const access_str_search = "search"; @@ -827,7 +831,7 @@ int acl_skip_access_check ( Slapi_PBlock *pb, Slapi_Entry *e ); int aclext_alloc_lockarray (); -int aclutil_str_appened(char **str1, const char *str2); +int aclutil_str_append(char **str1, const char *str2); void aclutil_print_err (int rv , const Slapi_DN *sdn, const struct berval* val, char **errbuf); void aclutil_print_aci (aci_t *aci_item, char *type); @@ -911,6 +915,7 @@ acl_replace_str(char * s, char *substr, char* replace_with); int acl_strstr(char * s, char *substr); int aclutil_evaluate_macro( char * rule, lasInfo *lasinfo, acl_eval_types evalType ); +int aclutil_str_append_ext(char **dest, size_t *dlen, const char *src, size_t slen); /* acl hash table functions */ void acl_ht_add_and_freeOld(acl_ht_t * acl_ht, PLHashNumber key,char *value); diff --git a/ldap/servers/plugins/acl/acl_ext.c b/ldap/servers/plugins/acl/acl_ext.c index 5e1d360b..d9494ec3 100644 --- a/ldap/servers/plugins/acl/acl_ext.c +++ b/ldap/servers/plugins/acl/acl_ext.c @@ -791,7 +791,7 @@ acl__done_aclpb ( struct acl_pblock *aclpb ) */ /* Nothing needs to be cleaned up in this case */ - if ( !aclpb->aclpb_state & ACLPB_INITIALIZED) + if (!(aclpb->aclpb_state & ACLPB_INITIALIZED)) return; /* Check the state */ diff --git a/ldap/servers/plugins/acl/aclanom.c b/ldap/servers/plugins/acl/aclanom.c index 773dad2f..b1d15ca1 100644 --- a/ldap/servers/plugins/acl/aclanom.c +++ b/ldap/servers/plugins/acl/aclanom.c @@ -205,6 +205,7 @@ aclanom_gen_anomProfile (acl_lock_flag_t lock_flag) /* see if this is a monitor acl */ if (( strcasecmp ( dn, "cn=monitor") == 0 ) || + /* cn=monitor,cn=ldbm: No such object */ ( strcasecmp ( dn, "cn=monitor,cn=ldbm") == 0 )) { aci = acllist_get_next_aci ( NULL, aci, &cookie); continue; diff --git a/ldap/servers/plugins/acl/acleffectiverights.c b/ldap/servers/plugins/acl/acleffectiverights.c index 9afac079..acf856cc 100644 --- a/ldap/servers/plugins/acl/acleffectiverights.c +++ b/ldap/servers/plugins/acl/acleffectiverights.c @@ -170,7 +170,7 @@ _ger_g_permission_granted ( goto bailout; } - aclutil_str_appened ( errbuf, "get-effective-rights: requestor has no g permission on the entry" ); + aclutil_str_append ( errbuf, "get-effective-rights: requestor has no g permission on the entry" ); slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_g_permission_granted: %s\n", *errbuf); rc = LDAP_INSUFFICIENT_ACCESS; @@ -195,7 +195,10 @@ _ger_parse_control ( LDAPControl **requestcontrols; struct berval *subjectber; BerElement *ber; - int subjectndnlen = 0; + size_t subjectndnlen = 0; + char *orig = NULL; + char *normed = NULL; + int rc = 0; if (NULL == subjectndn) { @@ -215,7 +218,7 @@ _ger_parse_control ( if ( subjectber == NULL || subjectber->bv_val == NULL || subjectber->bv_len == 0 ) { - aclutil_str_appened ( errbuf, "get-effective-rights: missing subject" ); + aclutil_str_append ( errbuf, "get-effective-rights: missing subject" ); slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf ); return LDAP_INVALID_SYNTAX; } @@ -227,23 +230,23 @@ _ger_parse_control ( * or base64 encoding string. Hence users using -J option in * ldapsearch don't have to do BER encoding for the subject. */ - *subjectndn = slapi_ch_malloc ( subjectber->bv_len + 1 ); - strncpy ( *subjectndn, subjectber->bv_val, subjectber->bv_len ); - *(*subjectndn + subjectber->bv_len) = '\0'; + orig = slapi_ch_malloc ( subjectber->bv_len + 1 ); + strncpy ( orig, subjectber->bv_val, subjectber->bv_len ); + *(orig + subjectber->bv_len) = '\0'; } else { ber = ber_init (subjectber); if ( ber == NULL ) { - aclutil_str_appened ( errbuf, "get-effective-rights: ber_init failed for the subject" ); + aclutil_str_append ( errbuf, "get-effective-rights: ber_init failed for the subject" ); slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf ); return LDAP_OPERATIONS_ERROR; } /* "a" means to allocate storage as needed for octet string */ - if ( ber_scanf (ber, "a", subjectndn) == LBER_ERROR ) + if ( ber_scanf (ber, "a", orig) == LBER_ERROR ) { - aclutil_str_appened ( errbuf, "get-effective-rights: invalid ber tag in the subject" ); + aclutil_str_append ( errbuf, "get-effective-rights: invalid ber tag in the subject" ); slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf ); ber_free ( ber, 1 ); return LDAP_INVALID_SYNTAX; @@ -256,18 +259,32 @@ _ger_parse_control ( * (see section 9 of RFC 2829) only. It also only supports the "dnAuthzId" * flavor, which looks like "dn:<DN>" where null <DN> is for anonymous. */ - subjectndnlen = strlen(*subjectndn); - if ( NULL == *subjectndn || subjectndnlen < 3 || - strncasecmp ( "dn:", *subjectndn, 3 ) != 0 ) + subjectndnlen = strlen(orig); + if ( NULL == orig || subjectndnlen < 3 || strncasecmp ( "dn:", orig, 3 ) != 0 ) { - aclutil_str_appened ( errbuf, "get-effective-rights: subject is not dnAuthzId" ); + aclutil_str_append ( errbuf, "get-effective-rights: subject is not dnAuthzId" ); slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf ); + slapi_ch_free_string(&orig); return LDAP_INVALID_SYNTAX; } /* memmove is safe for overlapping copy */ - memmove ( *subjectndn, *subjectndn + 3, subjectndnlen - 2);/* 1 for '\0' */ - slapi_dn_normalize ( *subjectndn ); + rc = slapi_dn_normalize_ext(orig + 3, 0, &normed, &subjectndnlen); + if (rc < 0) { + aclutil_str_append ( errbuf, "get-effective-rights: failed to normalize dn: "); + aclutil_str_append ( errbuf, orig); + slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf ); + slapi_ch_free_string(&orig); + return LDAP_INVALID_SYNTAX; + } + if (rc == 0) { /* orig+3 is passed in; not terminated */ + *(normed + subjectndnlen) = '\0'; + *subjectndn = slapi_ch_strdup(normed); + slapi_ch_free_string(&orig); + } else { + slapi_ch_free_string(&orig); + *subjectndn = normed; + } return LDAP_SUCCESS; } diff --git a/ldap/servers/plugins/acl/acllas.c b/ldap/servers/plugins/acl/acllas.c index 9a57d7c8..9fbd25bb 100644 --- a/ldap/servers/plugins/acl/acllas.c +++ b/ldap/servers/plugins/acl/acllas.c @@ -480,6 +480,7 @@ DS_LASUserDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, int rc; short len; const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix); + const size_t LDAPS_URL_prefix_len = strlen(LDAPS_URL_prefix); lasInfo lasinfo; int got_undefined = 0; @@ -530,15 +531,15 @@ DS_LASUserDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, ** userdn = "ldap:///DN1 || ldap:///DN2" */ - /* The DN is now "ldap:///DN" ** remove the "ldap:///" part */ - if (strncasecmp (user, LDAP_URL_prefix, - LDAP_URL_prefix_len) == 0) { + if (strncasecmp (user, LDAP_URL_prefix, LDAP_URL_prefix_len) == 0) { s_user = user; user += LDAP_URL_prefix_len; - + } else if (strncasecmp (user, LDAPS_URL_prefix, LDAPS_URL_prefix_len) == 0) { + s_user = user; + user += LDAPS_URL_prefix_len; } else { char ebuf[ BUFSIZ ]; slapi_log_error(SLAPI_LOG_FATAL, plugin_name, @@ -677,8 +678,19 @@ DS_LASUserDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, slapi_filter_free(f,1); } else { /* Must be a simple dn then */ - if (slapi_utf8casecmp((ACLUCHP)lasinfo.clientDn, - (ACLUCHP)slapi_dn_normalize(user)) == 0) { + char *normed = NULL; + size_t dnlen = 0; + rc = slapi_dn_normalize_ext(user, 0, &normed, &dnlen); + if (rc == 0) { /* user passed in; not terminated */ + *(normed + dnlen) = '\0'; + } else if (rc < 0) { /* normalization failed, user the original */ + normed = user; + } + rc = slapi_utf8casecmp((ACLUCHP)lasinfo.clientDn, (ACLUCHP)normed); + if (normed != user) { + slapi_ch_free_string(&normed); + } + if (0 == rc) { matched = ACL_TRUE; break; } @@ -1274,8 +1286,14 @@ DS_LASUserDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, while ( j != -1 ) { attrVal = slapi_value_get_berval ( sval ); /* Here if atleast 1 value matches then we are done.*/ - val = slapi_dn_normalize ( - slapi_ch_strdup( attrVal->bv_val)); + val = slapi_create_dn_string("%s", attrVal->bv_val); + if (NULL == val) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "DS_LASUserDnAttrEval: Invalid syntax: %s\n", + attrVal->bv_val ); + slapi_ch_free ( (void**) &s_attrName); + return LAS_EVAL_FAIL; + } if (slapi_utf8casecmp((ACLUCHP)val, (ACLUCHP)lasinfo.clientDn ) == 0) { char ebuf [ BUFSIZ ]; @@ -2380,7 +2398,13 @@ acllas__handle_group_entry (Slapi_Entry* e, void *callback_data) while ( i != -1 ) { struct member_info *groupMember = NULL; attrVal = slapi_value_get_berval ( sval ); - n_dn = slapi_dn_normalize ( slapi_ch_strdup( attrVal->bv_val )); + n_dn = slapi_create_dn_string( attrVal->bv_val ); + if (NULL == n_dn) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "acllas__handle_group_entry: Invalid syntax: %s\n", + attrVal->bv_val ); + return 0; + } n = ++info->lu_idx; if (n < 0) { slapi_log_error( SLAPI_LOG_FATAL, plugin_name, @@ -2433,7 +2457,14 @@ acllas__handle_group_entry (Slapi_Entry* e, void *callback_data) */ if (strncasecmp( attrVal->bv_val, "ldap://",7) == 0 || strncasecmp( attrVal->bv_val, "ldaps://",8) == 0) { - savURL = memberURL = slapi_ch_strdup ( attrVal->bv_val); + savURL = memberURL = + slapi_create_dn_string("%s", attrVal->bv_val); + if (NULL == savURL) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "acllas__handle_group_entry: Invalid syntax: %s\n", + attrVal->bv_val ); + return 0; + } slapi_log_error( SLAPI_LOG_ACL, plugin_name, "ACL Group Eval:MemberURL:%s\n", memberURL); info->result = acllas__client_match_URL ( @@ -2656,8 +2687,13 @@ DS_LASGroupDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, attr_i= slapi_attr_first_value ( attr,&sval ); while ( attr_i != -1 ) { attrVal = slapi_value_get_berval ( sval ); - n_groupdn = slapi_dn_normalize( - slapi_ch_strdup( attrVal->bv_val)); + n_groupdn = slapi_create_dn_string("%s", attrVal->bv_val); + if (NULL == n_groupdn) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "DS_LASGroupDnAttrEval: Invalid syntax: %s\n", + attrVal->bv_val ); + return 0; + } matched = acllas__user_ismember_of_group ( lasinfo.aclpb, n_groupdn, lasinfo.clientDn, ACLLAS_CACHE_MEMBER_GROUPS, @@ -2855,6 +2891,7 @@ acllas__eval_memberGroupDnAttr (char *attrName, Slapi_Entry *e, char *curMemberDn; int Done = 0; int ngr, tt; + char *normed = NULL; /* Add the scope to the list of scopes */ if (aclpb->aclpb_numof_bases >= (aclpb->aclpb_grpsearchbase_size-1)) { @@ -2866,9 +2903,15 @@ acllas__eval_memberGroupDnAttr (char *attrName, Slapi_Entry *e, sizeof (char *)); aclpb->aclpb_grpsearchbase_size += ACLPB_INCR_BASES; } - aclpb->aclpb_grpsearchbase[aclpb->aclpb_numof_bases++] = - slapi_dn_normalize(slapi_ch_strdup(base)); - + normed = slapi_create_dn_string("%s", base); + if (NULL == normed) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "acllas__eval_memberGroupDnAttr: Invalid syntax: %s\n", + base ); + slapi_ch_free ( (void **)&s_str ); + return ACL_FALSE; + } + aclpb->aclpb_grpsearchbase[aclpb->aclpb_numof_bases++] = normed; /* Set up info to do a search */ attrs[0] = type_member; attrs[1] = type_uniquemember; @@ -2991,8 +3034,14 @@ acllas__eval_memberGroupDnAttr (char *attrName, Slapi_Entry *e, while ( k != -1 ) { char *n_attrval; attrVal = slapi_value_get_berval ( sval ); - n_attrval = slapi_ch_strdup( attrVal->bv_val); - n_attrval = slapi_dn_normalize (n_attrval); + n_attrval = slapi_create_dn_string("%s", attrVal->bv_val); + if (NULL == n_attrval) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "acllas__eval_memberGroupDnAttr: Invalid syntax: %s\n", + attrVal->bv_val ); + slapi_ch_free ( (void **)&s_str ); + return ACL_FALSE; + } /* We support: The attribute value can be a USER or a GROUP. ** Let's compare with the client, thi might be just an user. If it is not @@ -3147,7 +3196,13 @@ acllas__verify_client (Slapi_Entry* e, void *callback_data) i = slapi_attr_first_value ( attr,&sval ); while ( i != -1 ) { attrVal = slapi_value_get_berval ( sval ); - val = slapi_dn_normalize(slapi_ch_strdup(attrVal->bv_val)); + val = slapi_create_dn_string("%s", attrVal->bv_val); + if (NULL == val) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "acllas__verify_client: Invalid syntax: %s\n", + attrVal->bv_val ); + return 0; + } if (slapi_utf8casecmp((ACLUCHP)val, (ACLUCHP)info->clientdn ) == 0) { info->result = 1; @@ -3235,7 +3290,12 @@ acllas__get_members (Slapi_Entry* e, void *callback_data) i = slapi_attr_first_value ( attr,&sval ); while ( i != -1 ) { attrVal =slapi_value_get_berval ( sval ); - info->member[i] = slapi_dn_normalize ( slapi_ch_strdup(attrVal->bv_val)); + info->member[i] = slapi_create_dn_string ("%s", attrVal->bv_val); + if (NULL == info->member[i]) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "acllas__get_members: Invalid syntax: %s\n", + attrVal->bv_val ); + } i = slapi_attr_next_value ( attr, i, &sval ); } return 0; @@ -3426,7 +3486,17 @@ acllas__client_match_URL (struct acl_pblock *aclpb, char *n_clientdn, char *url LDAPURLDesc *ludp; int rc; Slapi_Filter *f = NULL; - + char *rawdn = NULL; + char *dn = NULL; + size_t dnlen = 0; + char *p = NULL; + char *normed = NULL; + /* ldap(s)://host:port/suffix?attrs?scope?filter */ + const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix_core); + const size_t LDAPS_URL_prefix_len = strlen(LDAPS_URL_prefix_core); + size_t prefix_len = 0; + char Q = '?'; + char *hostport = NULL; /* Get the client's entry if we don't have already */ if ( aclpb && ( NULL == aclpb->aclpb_client_entry )) { @@ -3459,23 +3529,83 @@ acllas__client_match_URL (struct acl_pblock *aclpb, char *n_clientdn, char *url } if ( NULL == aclpb->aclpb_client_entry ) { - slapi_log_error ( SLAPI_LOG_ACL, plugin_name, - "DS_LASUserAttrEval: Unable to get client's entry\n"); + slapi_log_error (SLAPI_LOG_ACL, plugin_name, + "acllas__client_match_URL: Unable to get client's entry\n"); return ACL_FALSE; } - if (( rc = ldap_url_parse( url, &ludp)) != 0 ) { + /* DN potion of URL must be normalized before calling ldap_url_parse. + * lud_dn is pointing at the middle of lud_string. + * lud_dn won't be freed in ldap_free_urldesc. + */ + /* remove the "ldap{s}:///" part */ + if (strncasecmp (url, LDAP_URL_prefix, LDAP_URL_prefix_len) == 0) { + prefix_len = LDAP_URL_prefix_len; + } else if (strncasecmp (url, LDAPS_URL_prefix, LDAPS_URL_prefix_len) == 0) { + prefix_len = LDAPS_URL_prefix_len; + } else { + slapi_log_error (SLAPI_LOG_ACL, plugin_name, + "acllas__client_match_URL: url %s does not include ldap prefix: %s\n", url); + return ACL_FALSE; + } + rawdn = url + prefix_len; /* ldap(s)://host:port/... or ldap(s):///... */ + /* rawdn at ^ or ^ */ + /* let rawdn point the suffix */ + if ('/' == *(rawdn+1)) { /* ldap(s):/// */ + rawdn += 2; + hostport = "/"; + } else { + char *tmpp = rawdn; + rawdn = strchr(tmpp, '/'); + size_t hostport_len = 0; + if (NULL == rawdn) { + slapi_log_error (SLAPI_LOG_ACL, plugin_name, + "acllas__client_match_URL: url %s does not include correct ldap prefix: %s\n", url); + return ACL_FALSE; + } + hostport_len = ++rawdn - tmpp; /* ldap(s)://host:port/... */ + /* <--------> */ + hostport = (char *)slapi_ch_malloc(hostport_len + 1); + memcpy(hostport, tmpp, hostport_len); + *(hostport+hostport_len) = '\0'; + } + p = strchr(rawdn, Q); + if (p) { + /* url has scope and/or filter: ldap(s):///suffix?attr?scope?filter */ + *p = '\0'; + } + rc = slapi_dn_normalize_ext(rawdn, 0, &dn, &dnlen); + if (rc < 0) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "acllas__client_match_URL: Invalid syntax: %s\n", url); + return ACL_FALSE; + } else if (rc == 0) { /* url is passed in and not terminated with NULL*/ + *(dn + dnlen) = '\0'; + } + if (p) { + *p = Q; + } + normed = slapi_ch_smprintf("%s%s%s%s", + (prefix_len==LDAP_URL_prefix_len)? + LDAP_URL_prefix_core:LDAPS_URL_prefix_core, + hostport, dn, p?p:""); + if (rc > 0) { + /* dn was allocated in slapi_dn_normalize_ext */ + slapi_ch_free_string(&dn); + } + if ('/' != *hostport) { + slapi_ch_free_string(&hostport); + } + rc = ldap_url_parse(normed, &ludp); + slapi_ch_free_string(&normed); + if (rc) { return ACL_FALSE; - } if ( ( NULL == ludp->lud_dn) || ( NULL == ludp->lud_filter) ) { ldap_free_urldesc( ludp ); return ACL_FALSE; } - /* Normalize in place the dn */ - slapi_dn_normalize ( ludp->lud_dn ); - /* Check the scope */ if ( ludp->lud_scope == LDAP_SCOPE_SUBTREE ) { if (!slapi_dn_issuffix(n_clientdn, ludp->lud_dn)) { @@ -3777,8 +3907,13 @@ DS_LASRoleDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, Slapi_DN *roleDN; attrVal = slapi_value_get_berval ( sval ); - n_attrval = slapi_ch_strdup( attrVal->bv_val); - n_attrval = slapi_dn_normalize (n_attrval); + n_attrval = slapi_create_dn_string("%s", attrVal->bv_val); + if (NULL == n_attrval) { + slapi_log_error( SLAPI_LOG_FATAL, plugin_name, + "DS_LASRoleDnAttrEval: Invalid syntax: %s\n", + attrVal->bv_val ); + return LAS_EVAL_FAIL; + } roleDN = slapi_sdn_new_dn_byval(n_attrval); /* We support: The attribute value can be a USER or a GROUP. @@ -3831,14 +3966,12 @@ DS_LASRoleDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, * returns: ACL_TRUE for matched, * ACL_FALSE for matched. * ACL_DONT_KNOW otherwise. - * - * -*/ + */ int aclutil_evaluate_macro( char * rule, lasInfo *lasinfo, - acl_eval_types evalType ) { - + acl_eval_types evalType ) +{ int matched = 0; aci_t *aci; char *matched_val = NULL; diff --git a/ldap/servers/plugins/acl/aclparse.c b/ldap/servers/plugins/acl/aclparse.c index 8d4a21a0..0c8d0fa3 100644 --- a/ldap/servers/plugins/acl/aclparse.c +++ b/ldap/servers/plugins/acl/aclparse.c @@ -50,7 +50,6 @@ static int __aclp__sanity_check_acltxt(aci_t *aci_item, char *str); static char * __aclp__normalize_acltxt (aci_t *aci_item, char *str); static char * __aclp__getNextLASRule(aci_t *aci_item, char *str, char **endOfCurrRule); -static char * __aclp__dn_normalize( char *dn , char *end); static int __aclp__get_aci_right ( char *str); static int __aclp__init_targetattr (aci_t *aci, char *attr_val); static int __acl__init_targetattrfilters( aci_t *aci_item, char *str); @@ -239,10 +238,10 @@ __aclp__parse_aci (char *str, aci_t *aci_item) /* - * The targetattrfilters bit looks like this: - * (targetattrfilters="add= attr1:F1 && attr2:F2 ... && attrn:Fn, - * del= attr1:F1 && attr2:F2... && attrn:Fn") - */ + * The targetattrfilters bit looks like this: + * (targetattrfilters="add= attr1:F1 && attr2:F2 ... && attrn:Fn, + * del= attr1:F1 && attr2:F2... && attrn:Fn") + */ if ( 0 != (rv= __acl__init_targetattrfilters( aci_item, str))) { return rv; @@ -256,15 +255,14 @@ __aclp__parse_aci (char *str, aci_t *aci_item) } /* Get individual components of the targetattr. * (targetattr = "cn || u* || phone ||tel:add:(tel=1234) - * || sn:del:(gn=5678)") - * If it contains a value filter, the type will also be - * ACI_TARGET_VALUE_ATTR. - */ - if ( 0 != (rv= __aclp__init_targetattr( - aci_item, str))) { + * || sn:del:(gn=5678)") + * If it contains a value filter, the type will also be + * ACI_TARGET_VALUE_ATTR. + */ + if (0 != (rv = __aclp__init_targetattr(aci_item, str))) { return rv; } - } else if (strncmp(str, aci_targetfilter,tfilterlen ) == 0) { + } else if (strncmp(str, aci_targetfilter,tfilterlen ) == 0) { if ( aci_item->targetFilter) return ACL_SYNTAX_ERR; @@ -311,8 +309,8 @@ __aclp__parse_aci (char *str, aci_t *aci_item) } else if (strncmp(str, aci_targetdn, targetdnlen) == 0) { char *tstr = NULL; - const size_t LDAP_URL_prefix_len = strlen (LDAP_URL_prefix); - char *tt; + size_t LDAP_URL_prefix_len = 0; + size_t tmplen = 0; type = ACI_TARGET_DN; /* Keep a copy of the target attr */ if (aci_item->target) { @@ -322,30 +320,40 @@ __aclp__parse_aci (char *str, aci_t *aci_item) type |= ACI_TARGET_NOT; strncpy(s, " ", 1); } - - /* Convert it to lower as slapi_dn_normalize() does not */ - for (tt = str; *tt; tt++) *tt = TOLOWER ( *tt ); - if ( (s = strchr( str, '=' )) != NULL ) { value = s + 1; - slapi_dn_normalize(value); + __acl_strip_leading_space(&value); len = strlen ( value ); - if (*value == '"' && value[len-1] == '"'){ + /* strip double quotes */ + if (*value == '"' && value[len-1] == '"') { value[len-1] = '\0'; value++; } __acl_strip_leading_space(&value); - } else { + } else { return ( ACL_SYNTAX_ERR ); } - - if ( strncasecmp ( value, LDAP_URL_prefix , LDAP_URL_prefix_len) ) + if (0 == + strncasecmp(value, LDAP_URL_prefix, strlen(LDAP_URL_prefix))) { + LDAP_URL_prefix_len = strlen(LDAP_URL_prefix); + } else if (0 == strncasecmp(value, LDAPS_URL_prefix, + strlen(LDAPS_URL_prefix))) { + LDAP_URL_prefix_len = strlen(LDAPS_URL_prefix); + } else { return ( ACL_SYNTAX_ERR ); + } value += LDAP_URL_prefix_len; - len = strlen ( value ); - tstr = (char *) slapi_ch_malloc ( targetdnlen + len + 4 ); - sprintf ( tstr, "(target=%s)", value); + rv = slapi_dn_normalize_case_ext(value, 0, &tmpstr, &tmplen); + if (rv < 0) { + return ACL_SYNTAX_ERR; + } else if (rv == 0) { /* value passed in; not null terminated */ + *(tmpstr + tmplen) = '\0'; + } + tstr = slapi_ch_smprintf("(target=%s)", tmpstr); + if (rv > 0) { + slapi_ch_free_string(&tmpstr); + } if ( (rv = acl_check_for_target_macro( aci_item, value)) == -1) { slapi_ch_free ( (void **) &tstr ); return(ACL_SYNTAX_ERR); @@ -356,7 +364,7 @@ __aclp__parse_aci (char *str, aci_t *aci_item) /* it's a normal target with no macros inside */ f = slapi_str2filter ( tstr ); } - slapi_ch_free ( (void **) &tstr ); + slapi_ch_free_string ( &tstr ); } else { /* did start with a 't' but was not a recognsied keyword */ return(ACL_SYNTAX_ERR); @@ -492,20 +500,86 @@ __aclp__sanity_check_acltxt (aci_t *aci_item, char *str) slapi_log_error(SLAPI_LOG_ACL, plugin_name, "Normalized String:%s\n", newstr); /* check for acl syntax error */ - if ((handle = (ACLListHandle_t *) ACL_ParseString(&errp, - newstr)) == NULL) { + if ((handle = (ACLListHandle_t *) ACL_ParseString(&errp, newstr)) == NULL) { acl_print_acllib_err(&errp, str); - slapi_ch_free ( (void **) &newstr ); + slapi_ch_free_string(&newstr); return ACL_SYNTAX_ERR; } else { /* get the rights and the aci type */ aci_item->aci_handle = handle; nserrDispose(&errp); - slapi_ch_free ( (void **) &newstr ); + slapi_ch_free_string(&newstr); return 0; } } + +/* + * If the src includes "ldap(s):///<dn>", normalize <dn> and copy + * the string starting from start to *dest. + * If isstrict is non-zero, if ldap(s):/// is not included in the src + * string, it returns an error (-1). + * If isstrict is zero, the string is copied as is. + * + * return value: 0 or positive: success + * negative: failure + */ +int +__aclp__copy_normalized_str (char *src, char *endsrc, char *start, + char **dest, size_t *destlen, int isstrict) +{ + char *p = NULL; + int rc = -1; + char *dn = NULL; + size_t dnlen = 0; + + p = PL_strnstr(src, LDAP_URL_prefix, endsrc - src); + if (p) { + p += strlen(LDAP_URL_prefix); + } else { + p = PL_strnstr(src, LDAPS_URL_prefix, endsrc - src); + if (p) { + p += strlen(LDAPS_URL_prefix); + } + } + + if (isstrict && ((NULL == p) || 0 == strlen(p))) { + return rc; /* error */ + } + + rc = 0; + if (p && strlen(p) > 0) { + size_t len = 0; + /* strip the string starting from ? */ + char *q = PL_strnchr(p, '?', endsrc - p); + if (q) { + len = q - p; + } else { + len = endsrc - p; + } + /* Normalize the value of userdn and append it to ret_str */ + rc = slapi_dn_normalize_ext(p, len, &dn, &dnlen); + if (rc < 0) { + return rc; + } + /* append up to ldap(s):/// */ + aclutil_str_append_ext(dest, destlen, start, p - start); + /* append the DN part */ + aclutil_str_append_ext(dest, destlen, dn, dnlen); + if (rc > 0) { /* if rc == 0, p is passed in */ + slapi_ch_free_string(&dn); + } + if (q) { + /* append the rest from '?' */ + aclutil_str_append_ext(dest, destlen, q, endsrc - q); + } + } else { + aclutil_str_append_ext(dest, destlen, start, endsrc - start); + } + + return rc; +} + /****************************************************************************** * * acl__normalize_acltxt @@ -534,23 +608,25 @@ __aclp__normalize_acltxt ( aci_t * aci_item, char * str ) char *s, *p; char *end; char *aclstr, *s_aclstr; + char *prevend = NULL; char *ret_str = NULL; + size_t retstr_len = 0; int len; - char *ptr, *aclName; + char *aclName; char *nextACE; char *tmp_str = NULL; char *acestr = NULL; char *s_acestr = NULL; int aci_rights_val = 0; /* bug 389975 */ + int rc = 0; /* make a copy first */ s_aclstr = aclstr = slapi_ch_strdup ( str ); /* The rules are like this version 3.0; acl "xyz"; rule1; rule2; */ s = strchr (aclstr, ';'); - if ( NULL == s) { - slapi_ch_free ( (void **) &s_aclstr ); - return NULL; + if (NULL == s) { + goto error; } aclstr = ++s; @@ -564,9 +640,8 @@ __aclp__normalize_acltxt ( aci_t * aci_item, char * str ) aclName = s+3; s = strchr (aclstr, ';'); - if ( NULL == s) { - slapi_ch_free ( (void **) &s_aclstr ); - return NULL; + if (NULL == s) { + goto error; } aclstr = s; @@ -576,8 +651,10 @@ __aclp__normalize_acltxt ( aci_t * aci_item, char * str ) /* Here aclName is the acl description string */ aci_item->aclName = slapi_ch_strdup ( aclName ); - aclutil_str_appened (&ret_str, s_aclstr); - aclutil_str_appened (&ret_str, ";"); + retstr_len = strlen(str) * 3; + ret_str = (char *)slapi_ch_calloc(sizeof(char), retstr_len); + aclutil_str_append_ext (&ret_str, &retstr_len, s_aclstr, strlen(s_aclstr)); + aclutil_str_append_ext (&ret_str, &retstr_len, ";", 1); /* start with the string */ acestr = aclstr; @@ -586,37 +663,34 @@ __aclp__normalize_acltxt ( aci_t * aci_item, char * str ) * Here acestr is something like: * * " allow (all) groupdn = "ldap:///cn=Domain Administrators, o=$dn.o, o=ISP";)" - * - * - */ + */ normalize_nextACERule: /* now we are in the rule part */ tmp_str = acestr; s = strchr (tmp_str, ';'); - if ( s == NULL) { - if (ret_str) slapi_ch_free ( (void **) &ret_str ); - slapi_ch_free ( (void **) &s_aclstr ); - return NULL; + if (s == NULL) { + goto error; } + nextACE = s; LDAP_UTF8INC(nextACE); *s = '\0'; - /* acestr now will hold copy of the ACE. Also add + /* acestr now will hold copy of the ACE. Also add ** some more space in case we need to add "absolute" - ** for deny rule. We will never need more 2 times - ** the len. + ** for deny rule. We will never need more 3 times + ** the len (even if all the chars are escaped). */ __acl_strip_leading_space(&tmp_str); len = strlen (tmp_str); - s_acestr = acestr = slapi_ch_calloc ( 1, 2 * len); + s_acestr = acestr = slapi_ch_calloc (1, 3 * len); /* * Now it's something like: * allow (all) groupdn = "ldap:///cn=Domain Administrators, o=$dn.o, o=ISP"; - */ + */ if (strncasecmp(tmp_str, "allow", 5) == 0) { memcpy(acestr, tmp_str, len); tmp_str += 5; @@ -624,6 +698,14 @@ normalize_nextACERule: aci_rights_val = __aclp__get_aci_right (tmp_str);/* bug 389975 */ aci_item->aci_type |= ACI_HAS_ALLOW_RULE; + s = strchr(acestr, ')'); + if (NULL == s) { + /* wrong syntax */ + goto error; + } + /* add "allow(rights...)" */ + aclutil_str_append_ext(&ret_str, &retstr_len, acestr, s - acestr + 1); + prevend = s + 1; } else if (strncasecmp(tmp_str, "deny", 4) == 0) { char *d_rule ="deny absolute"; /* Then we have to add "absolute" to the deny rule @@ -652,6 +734,15 @@ normalize_nextACERule: len = strlen ( d_rule ); memcpy (acestr, d_rule, len ); memcpy (acestr+len, tmp_str, strlen (tmp_str) ); + + s = strchr(acestr, ')'); + if (NULL == s) { + /* wrong syntax */ + goto error; + } + /* add "deny(rights...)" */ + aclutil_str_append_ext(&ret_str, &retstr_len, acestr, s - acestr + 1); + prevend = s + 1; } else { /* wrong syntax */ aci_rights_val = -1 ; @@ -659,32 +750,32 @@ normalize_nextACERule: if (aci_rights_val == -1 ) { /* wrong syntax */ - slapi_ch_free ( (void **) &ret_str ); - slapi_ch_free ( (void **) &s_acestr ); - slapi_ch_free ( (void **) &s_aclstr ); - return NULL; + goto error; } else - aci_item->aci_access |= aci_rights_val; + aci_item->aci_access |= aci_rights_val; - - /* Normalize all the DNs in the userdn rule */ - + /* Normalize all the DNs in the userdn, groupdn, roledn rules */ /* * * Here acestr starts like this: - * " allow (all) groupdn = "ldap:///cn=Domain Administrators, o=$dn.o, o=ISP" - */ - + * " allow (all) groupdn = "ldap:///cn=Domain Administrators,o=$dn.o,o=ISP" + */ s = __aclp__getNextLASRule(aci_item, acestr, &end); while ( s ) { - if ( 0 == strncmp ( s, DS_LAS_USERDNATTR, 10) || - ( 0 == strncmp ( s, DS_LAS_USERATTR, 8))) { + if ( (0 == strncmp(s, DS_LAS_USERDNATTR, 10)) || + (0 == strncmp(s, DS_LAS_USERATTR, 8)) ) { /* ** For userdnattr/userattr rule, the resources changes and hence ** we cannot cache the result. See above for more comments. */ aci_item->aci_elevel = ACI_ELEVEL_USERDNATTR; - } else if ( 0== strncmp ( s, DS_LAS_USERDN, 6)) { + + rc = __aclp__copy_normalized_str(s, end, prevend, + &ret_str, &retstr_len, 0); + if (rc < 0) { + goto error; + } + } else if ( 0 == strncmp ( s, DS_LAS_USERDN, 6)) { p = strstr ( s, "="); p--; if ( strncmp (p, "!=", 2) == 0) @@ -699,22 +790,12 @@ normalize_nextACERule: * which would ensure that acl info is not cached from * one resource entry to the next. (bug 558519) */ - p = strstr ( p, "ldap"); - if (p == NULL) { - /* must start with ldap */ - if (s_acestr) slapi_ch_free ( (void **) &s_acestr ); - if (ret_str) slapi_ch_free ( (void **) &ret_str ); - slapi_ch_free ( (void **) &s_aclstr ); - return (NULL); - } - p += 8; /* for ldap:/// */ - if( __aclp__dn_normalize (p, end) == NULL) { - if (s_acestr) slapi_ch_free ( (void **) &s_acestr ); - if (ret_str) slapi_ch_free ( (void **) &ret_str ); - slapi_ch_free ( (void **) &s_aclstr ); - return (NULL); + rc = __aclp__copy_normalized_str(s, end, prevend, + &ret_str, &retstr_len, 1); + if (rc < 0) { + goto error; } - + /* we have a rule like userdn = "ldap:///blah". s points to blah now. ** let's find if we have a SELF rule like userdn = "ldap:///self". ** Since the resource changes on entry basis, we can't cache the @@ -750,6 +831,12 @@ normalize_nextACERule: aci_item->aci_elevel = ACI_ELEVEL_GROUPDNATTR; } aci_item->aci_ruleType |= ACI_GROUPDNATTR_RULE; + + rc = __aclp__copy_normalized_str(s, end, prevend, + &ret_str, &retstr_len, 0); + if (rc < 0) { + goto error; + } } else if ( 0 == strncmp ( s, DS_LAS_GROUPDN, 7)) { p = strstr ( s, "="); @@ -757,21 +844,12 @@ normalize_nextACERule: if ( strncmp (p, "!=", 2) == 0) aci_item->aci_type |= ACI_CONTAIN_NOT_GROUPDN; - p = strstr ( s, "ldap"); - if (p == NULL) { - /* must start with ldap */ - if (s_acestr) slapi_ch_free ( (void **) &s_acestr ); - if (ret_str) slapi_ch_free ( (void **) &ret_str ); - slapi_ch_free ( (void **) &s_aclstr ); - return (NULL); - } - p += 8; - if (__aclp__dn_normalize (p, end) == NULL) { - if (s_acestr) slapi_ch_free ( (void **) &s_acestr ); - if (ret_str) slapi_ch_free ( (void **) &ret_str ); - slapi_ch_free ( (void **) &s_aclstr ); - return (NULL); + rc = __aclp__copy_normalized_str(s, end, prevend, + &ret_str, &retstr_len, 1); + if (rc < 0) { + goto error; } + /* check for param rules */ __aclp_chk_paramRules ( aci_item, p, end ); @@ -786,21 +864,12 @@ normalize_nextACERule: if ( strncmp (p, "!=", 2) == 0) aci_item->aci_type |= ACI_CONTAIN_NOT_ROLEDN; - p = strstr ( s, "ldap"); - if (p == NULL) { - /* must start with ldap */ - if (s_acestr) slapi_ch_free ( (void **) &s_acestr ); - if (ret_str) slapi_ch_free ( (void **) &ret_str ); - slapi_ch_free ( (void **) &s_aclstr ); - return (NULL); - } - p += 8; - if (__aclp__dn_normalize (p, end) == NULL) { - if (s_acestr) slapi_ch_free ( (void **) &s_acestr ); - if (ret_str) slapi_ch_free ( (void **) &ret_str ); - slapi_ch_free ( (void **) &s_aclstr ); - return (NULL); + rc = __aclp__copy_normalized_str(s, end, prevend, + &ret_str, &retstr_len, 1); + if (rc < 0) { + goto error; } + /* check for param rules */ __aclp_chk_paramRules ( aci_item, p, end ); @@ -808,40 +877,47 @@ normalize_nextACERule: if ( aci_item->aci_elevel > ACI_ELEVEL_GROUPDN ) aci_item->aci_elevel = ACI_ELEVEL_GROUPDN;*/ aci_item->aci_ruleType |= ACI_ROLEDN_RULE; + } else { + /* adding the string no need to be processed + * (e.g., dns="lab.example.com)" */ + aclutil_str_append_ext(&ret_str, &retstr_len, + prevend, end - prevend); } + prevend = end; s = ++end; s = __aclp__getNextLASRule(aci_item, s, &end); - }/* while */ + if (NULL == s) { + /* adding the rest of the string, e.g. '\"' */ + aclutil_str_append_ext(&ret_str, &retstr_len, + prevend, strlen(prevend)); + } + } /* while */ - /* get the head of the string */ - acestr = s_acestr; - len = strlen( acestr); - ptr = acestr +len-1; - while (*ptr && *ptr != '\"' && *ptr != ')' ) *ptr-- = ' '; - ptr++; - *ptr = ';'; - - aclutil_str_appened (&ret_str, acestr); - if (s_acestr) { - slapi_ch_free ( (void **) &s_acestr ); - } - s_acestr = NULL; + slapi_ch_free_string (&s_acestr); + __acl_strip_trailing_space(ret_str); + aclutil_str_append_ext(&ret_str, &retstr_len, ";", 1); if (nextACE) { s = strstr (nextACE, "allow"); if (s == NULL) s = strstr (nextACE, "deny"); if (s == NULL) { if (nextACE && *nextACE != '\0') - aclutil_str_appened (&ret_str, nextACE); - slapi_ch_free ( (void **) &s_aclstr ); + aclutil_str_append (&ret_str, nextACE); + slapi_ch_free_string (&s_aclstr); return (ret_str); } acestr = nextACE; goto normalize_nextACERule; } - slapi_ch_free ( (void **) &s_aclstr ); + slapi_ch_free_string (&s_aclstr); return (ret_str); + +error: + slapi_ch_free_string (&ret_str); + slapi_ch_free_string (&s_aclstr); + slapi_ch_free_string (&s_acestr); + return NULL; } /* * @@ -857,7 +933,7 @@ __aclp__getNextLASRule (aci_t *aci_item, char *original_str , char **endOfCurrRu { char *newstr, *word, *next, *start, *end; char *ruleStart = NULL; - int len, ruleLen; + int len, ruleLen = 0; int in_dn_expr = 0; *endOfCurrRule = NULL; @@ -1029,43 +1105,7 @@ __aclp__getNextLASRule (aci_t *aci_item, char *original_str , char **endOfCurrRu return ( ruleStart ); } -/****************************************************************************** -* -* __aclp__dn_normalize -* -* Normalize the DN INPLACE. This routine is similar to slapi_dn_normalize() -* except various small stuff at the end. -* Normalize until the "end" and not to the end of string. -* -******************************************************************************/ -static char * -__aclp__dn_normalize( char *dn , char *end) -{ - char *d; - - if ((end - dn) < 0) { - return(NULL); - } - d = slapi_dn_normalize_to_end ( dn, end ); - - /* Do I have the quotes already */ - if (*d != '\"' ) { - /* - ** We are taking care of this situation - ** " ") ". We need to remove the space - ** infront and tack it after the quote like this. - ** "" ) ". - */ - - *d = '\"'; - d++; - while (*d && *d != '\"') *d++ = ' '; - *d = ' '; - } - - return( dn ); -} /*************************************************************************** * acl__get_aci_right * @@ -1263,6 +1303,7 @@ __aclp__init_targetattr (aci_t *aci, char *attr_val) } while (str != 0 && *str != 0) { + int lenstr = 0; __acl_strip_leading_space(&str); @@ -1292,23 +1333,28 @@ __aclp__init_targetattr (aci_t *aci, char *attr_val) attr = (Targetattr *) slapi_ch_malloc (sizeof (Targetattr)); memset (attr, 0, sizeof(Targetattr)); - if (strchr(str, '*')) { - + /* strip double quotes */ + lenstr = strlen(str); + if (*str == '"' && *(str + lenstr - 1) == '"') { + *(str + lenstr - 1) = '\0'; + str++; + } + if (strchr(str, '*')) { + /* It contains a * so it's something like * or cn* */ if (strcmp(str, "*" ) != 0) { char line[100]; char *lineptr = &line[0]; char *newline = NULL; - int lenstr = 0; struct slapi_filter *f = NULL; - if ((lenstr = strlen(str)) > 91) { /* 100 - 8 for "(attr =%s)" */ - newline = slapi_ch_malloc(lenstr + 9); + if (lenstr > 92) { /* 100 - 8 for "(attr=%s)\0" */ + newline = slapi_ch_malloc(lenstr + 8); lineptr = newline; } attr->attr_type = ACL_ATTR_FILTER; - sprintf (lineptr, "(attr =%s)", str); + sprintf (lineptr, "(attr=%s)", str); f = slapi_str2filter (lineptr); if (f == NULL) { @@ -1320,7 +1366,7 @@ __aclp__init_targetattr (aci_t *aci, char *attr_val) if (newline) slapi_ch_free((void **) &newline); } else { - attr->attr_type = ACL_ATTR_STAR; + attr->attr_type = ACL_ATTR_STAR; attr->u.attr_str = slapi_ch_strdup (str); } diff --git a/ldap/servers/plugins/acl/aclproxy.c b/ldap/servers/plugins/acl/aclproxy.c index d40f543f..9b28489a 100644 --- a/ldap/servers/plugins/acl/aclproxy.c +++ b/ldap/servers/plugins/acl/aclproxy.c @@ -87,7 +87,9 @@ parse_LDAPProxyAuth(struct berval *spec_ber, int version, char **errtextp, LDAPProxyAuth *spec = NULL; BerElement *ber = NULL; char *errstring = "unable to parse proxied authorization control"; - + int rc = 0; + char *normed = NULL; + size_t dnlen = 0; BEGIN ber_tag_t tag; @@ -132,11 +134,20 @@ parse_LDAPProxyAuth(struct berval *spec_ber, int version, char **errtextp, errstring = "proxied authorization id must be a DN (dn:...)"; break; } - strcpy( spec->auth_dn, spec->auth_dn + 3 ); + /* memmove is safe for overlapping copy */ + memmove ( spec->auth_dn, spec->auth_dn + 3, strlen(spec->auth_dn) - 2);/* 1 for '\0' */ } - slapi_dn_normalize(spec->auth_dn); lderr = LDAP_SUCCESS; /* got it! */ + rc = slapi_dn_normalize_ext(spec->auth_dn, 0, &normed, &dnlen); + if (rc < 0) { + lderr = LDAP_INVALID_SYNTAX; + } else if (rc == 0) { /* spec->auth_dn is passed in; not terminated */ + *(normed + dnlen) = '\0'; + } else { + slapi_ch_free_string(&spec->auth_dn); + spec->auth_dn = normed; + } END /* Cleanup */ diff --git a/ldap/servers/plugins/acl/aclutil.c b/ldap/servers/plugins/acl/aclutil.c index 4aebd477..c0b8f579 100644 --- a/ldap/servers/plugins/acl/aclutil.c +++ b/ldap/servers/plugins/acl/aclutil.c @@ -65,7 +65,7 @@ static PRIntn acl_ht_display_entry(PLHashEntry *he, PRIntn i, void *arg); /* UTILITY FUNCTIONS */ /***************************************************************************/ int -aclutil_str_appened(char **str1, const char *str2) +aclutil_str_append(char **str1, const char *str2) { int new_len; @@ -87,6 +87,43 @@ aclutil_str_appened(char **str1, const char *str2) return(0); } +/* + * dlen: the length of the buffer *dest (not the string length in *dest) + */ +int +aclutil_str_append_ext(char **dest, size_t *dlen, const char *src, size_t slen) +{ + char *ptr = NULL; + int rc = 0; + + if ( dest == NULL || src == NULL ) { + return rc; + } + + if (0 == slen) { + slen = strlen(src); + } + if (*dest && dlen > 0) { + size_t dest_strlen = strlen(*dest); + size_t new_len = dest_strlen + slen + 1; + if (new_len > *dlen) { + *dest = (char *)slapi_ch_realloc(*dest, new_len); + *dlen = new_len; + ptr = *dest + dest_strlen; + } else { + ptr = *dest + dest_strlen; + } + } else { + *dlen = slen + 1; + *dest = (char *)slapi_ch_malloc(*dlen); + ptr = *dest; + } + memcpy(ptr, src, slen); + *(ptr + slen) = '\0'; + + return rc; +} + /***************************************************************************/ /* Print routines */ /***************************************************************************/ @@ -104,9 +141,14 @@ acl_print_acllib_err (NSErr_t *errp , char * str) aclErrorFmt(errp, msgbuf, ACLUTIL_ACLLIB_MSGBUF_LEN, 1); msgbuf[ACLUTIL_ACLLIB_MSGBUF_LEN-1] = '\0'; - if (msgbuf) - slapi_log_error(SLAPI_LOG_ACL, plugin_name,"ACL LIB ERR:(%s)(%s)\n", - msgbuf, str ? str: "NULL"); + if (strlen(msgbuf) > 0) { + slapi_log_error(SLAPI_LOG_ACL, plugin_name,"ACL LIB ERR:(%s)(%s)\n", + msgbuf, str ? str: "NULL"); + } else { + slapi_log_error(SLAPI_LOG_ACL, plugin_name,"ACL LIB ERR:(%s)\n", + str ? str: "NULL"); + } + } void aclutil_print_aci (aci_t *aci_item, char *type) @@ -240,7 +282,7 @@ aclutil_print_err (int rv , const Slapi_DN *sdn, const struct berval* val, if (errbuf) { /* If a buffer is provided, then copy the error */ - aclutil_str_appened(errbuf, lineptr ); + aclutil_str_append(errbuf, lineptr ); } slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "%s", lineptr); @@ -436,7 +478,7 @@ acl_gen_err_msg(int access, char *edn, char *attr, char **errbuf) line = PR_smprintf( "Insufficient 'delete' privilege to delete the entry '%s'.\n",edn); } - aclutil_str_appened(errbuf, line ); + aclutil_str_append(errbuf, line ); if (line) { PR_smprintf_free(line); @@ -540,7 +582,7 @@ aclutil_expand_paramString ( char *str, Slapi_Entry *e ) goto cleanup; } *p = '\0'; - aclutil_str_appened ( &buf,a_dns[i]); + aclutil_str_append ( &buf,a_dns[i]); if ( type == 1 ) { /* xyz = $dn.o */ @@ -573,15 +615,15 @@ aclutil_expand_paramString ( char *str, Slapi_Entry *e ) kk= slapi_attr_next_value( attr, kk, &sval ); if ( kk != -1 ) /* can't handle multiple --error */ goto cleanup; + attrValue = slapi_value_get_berval ( t_sval ); + attrVal = attrValue->bv_val; } - attrValue = slapi_value_get_berval ( t_sval ); - attrVal = attrValue->bv_val; } } else { attrVal = a_dns[i]; } - aclutil_str_appened ( &buf, attrVal); - aclutil_str_appened ( &buf, ","); + aclutil_str_append ( &buf, attrVal); + aclutil_str_append ( &buf, ","); } rc = 0; /* everything is okay*/ /* remove the last comma */ @@ -607,7 +649,7 @@ __aclutil_extract_dn_component ( char **e_dns, int position, char *attrName ) int i, matched, len; char *s; - int matchedPosition; + int matchedPosition = 0; len = strlen ( attrName ); diff --git a/ldap/servers/plugins/chainingdb/cb_config.c b/ldap/servers/plugins/chainingdb/cb_config.c index 1dab8462..5659353c 100644 --- a/ldap/servers/plugins/chainingdb/cb_config.c +++ b/ldap/servers/plugins/chainingdb/cb_config.c @@ -63,24 +63,28 @@ int cb_config_add_dse_entries(cb_backend *cb, char **entries, char *string1, cha Slapi_PBlock *util_pb = NULL; int res, rc = 0; char entry_string[CB_BUFSIZE]; + char *dn = NULL; for(x = 0; strlen(entries[x]) > 0; x++) { util_pb = slapi_pblock_new(); PR_snprintf(entry_string, sizeof(entry_string), entries[x], string1, string2, string3); e = slapi_str2entry(entry_string, 0); + dn = slapi_ch_strdup(slapi_entry_get_dn(e)); /* for err msg */ slapi_add_entry_internal_set_pb(util_pb, e, NULL, cb->identity, 0); slapi_add_internal_pb(util_pb); slapi_pblock_get(util_pb, SLAPI_PLUGIN_INTOP_RESULT, &res); if ( LDAP_SUCCESS != res && LDAP_ALREADY_EXISTS != res ) { char ebuf[ BUFSIZ ]; - slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM, + slapi_log_error(SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM, "Unable to add config entry (%s) to the DSE: %s\n", - escape_string(slapi_entry_get_dn(e), ebuf), + escape_string(dn, ebuf), ldap_err2string(res)); rc = res; slapi_pblock_destroy(util_pb); + slapi_ch_free_string(&dn); break; } + slapi_ch_free_string(&dn); slapi_pblock_destroy(util_pb); } return rc; @@ -161,7 +165,7 @@ int cb_config_load_dse_info(Slapi_PBlock * pb) { /* Get the default instance value entry if it exists */ /* else create it */ - + /* This dn is already normalized */ PR_snprintf(defaultDn,sizeof(defaultDn),"cn=default instance config,%s",cb->pluginDN); default_pb = slapi_pblock_new(); diff --git a/ldap/servers/plugins/chainingdb/cb_init.c b/ldap/servers/plugins/chainingdb/cb_init.c index 21a54d54..3b4f7a0b 100644 --- a/ldap/servers/plugins/chainingdb/cb_init.c +++ b/ldap/servers/plugins/chainingdb/cb_init.c @@ -82,7 +82,9 @@ chaining_back_init( Slapi_PBlock *pb ) /* Initialize misc. fields */ cb->config.rwl_config_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "chaining_db"); - rc = slapi_pblock_set( pb, SLAPI_PLUGIN_PRIVATE, (void *) cb ); + rc = slapi_pblock_set( pb, SLAPI_PLUGIN_PRIVATE, (void *) cb ); + + /* These DNs are already normalized */ cb->pluginDN=slapi_ch_smprintf("cn=%s,%s",CB_PLUGIN_NAME,PLUGIN_BASE_DN); cb->configDN=slapi_ch_smprintf("cn=config,%s",cb->pluginDN); diff --git a/ldap/servers/plugins/chainingdb/cb_instance.c b/ldap/servers/plugins/chainingdb/cb_instance.c index 1c08bd9f..73d5e019 100644 --- a/ldap/servers/plugins/chainingdb/cb_instance.c +++ b/ldap/servers/plugins/chainingdb/cb_instance.c @@ -153,10 +153,10 @@ cb_dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, static char *cb_skeleton_entries[] = { - "dn:cn=monitor, cn=%s, cn=%s, cn=plugins, cn=config\n" - "objectclass:top\n" - "objectclass:extensibleObject\n" - "cn:monitor\n", + "dn: cn=monitor,cn=%s,cn=%s,cn=plugins,cn=config\n" + "objectclass: top\n" + "objectclass: extensibleObject\n" + "cn: monitor\n", "" }; diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c index a14e48ce..b5aace63 100644 --- a/ldap/servers/plugins/cos/cos_cache.c +++ b/ldap/servers/plugins/cos/cos_cache.c @@ -69,6 +69,8 @@ #include <stdio.h> #include <string.h> +#include <ctype.h> + #include "portable.h" #include "slapi-plugin.h" @@ -324,6 +326,8 @@ static int cos_cache_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Sl static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags); static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *ops); +static int hexchar2int( char c ); + /* compares s2 to s1 starting from end of string until the beginning of either matches result in the s2 value being clipped from s1 with a NULL char @@ -904,14 +908,29 @@ static int cos_dn_defs_cb (Slapi_Entry* e, void *callback_data) { { /* get the parent of the definition */ - char *parent = slapi_dn_parent(pDn->val); - slapi_dn_normalize( parent ); + char *parent = NULL; + size_t plen = 0; + int rc = 0; + char *orig = slapi_dn_parent(pDn->val); + rc = slapi_dn_normalize_ext(orig, + 0, &parent, &plen); + if (rc < 0) { + LDAPDebug(LDAP_DEBUG_ANY, + "cos_cache_build_definition_list: failed to normalize parent dn %s. Adding the pre normalized dn.\n", orig, 0, 0); + parent = orig; + } else if (rc == 0) { + /* passed in. not terminated */ + *(parent + plen) = '\0'; + } cos_cache_add_attrval(&pCosTargetTree, parent); if(!pCosTemplateDn) cos_cache_add_attrval(&pCosTemplateDn, parent); - slapi_ch_free((void**)&parent); + if (orig != parent) { + slapi_ch_free_string(&orig); + } + slapi_ch_free_string(&parent); } slapi_vattrspi_regattr((vattr_sp_handle *)vattr_handle, dnVals[valIndex]->bv_val, NULL, NULL); @@ -1916,16 +1935,33 @@ static int cos_cache_add_tmpl(cosTemplates **pTemplates, cosAttrValue *dn, cosAt theTemp = (cosTemplates*) slapi_ch_malloc(sizeof(cosTemplates)); if(theTemp) { - char *grade = (char*)slapi_ch_malloc(strlen(dn->val)+1); + char *grade = NULL; int grade_index = 0; int index = 0; + int lastindex = 0; int template_default = 0; - - slapi_dn_normalize(dn->val); + char *dnval = NULL; + size_t dnlen = 0; + int rc = 0; + + rc = slapi_dn_normalize_ext(dn->val, 0, &dnval, &dnlen); + if (rc < 0) { + LDAPDebug(LDAP_DEBUG_ANY, + "cos_cache_add_tmpl: failed to normalize dn %s. " + "Processing the pre normalized dn.\n", dn->val, 0, 0); + } else if (rc == 0) { + /* passed in. not terminated */ + *(dnval + dnlen) = '\0'; + } else { + slapi_ch_free_string(&dn->val); + dn->val = dnval; + } + grade = (char*)slapi_ch_malloc(strlen(dn->val)+1); /* extract the cos grade */ while(dn->val[index] != '=' && dn->val[index] != '\0') index++; + lastindex = strlen(dn->val) - 1; if(dn->val[index] == '=') { @@ -1945,7 +1981,29 @@ static int cos_cache_add_tmpl(cosTemplates **pTemplates, cosAttrValue *dn, cosAt } else { - if(dn->val[index] != '\\') /* skip escape chars */ + if(dn->val[index] == '\\') + { + if ((index+2 <= lastindex) && isxdigit(dn->val[index+1]) && + isxdigit(dn->val[index+2])) { + /* Convert ESC HEX HEX to a real char */ + int n = hexchar2int(dn->val[index+1]); + int n2 = hexchar2int(dn->val[index+2]); + n = (n << 4) + n2; + if (n == 0) { /* don't change \00 */ + grade[grade_index] = dn->val[index++]; /* '\\' */ + grade_index++; + grade[grade_index] = dn->val[index++]; /* 0 */ + grade_index++; + grade[grade_index] = dn->val[index]; /* 0 */ + grade_index++; + } else { + grade[grade_index] = n; + index += 2; + grade_index++; + } + } /* else: skip escape chars */ + } + else { grade[grade_index] = dn->val[index]; grade_index++; @@ -2329,8 +2387,24 @@ static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Sl /* is this entry a child of the target tree(s)? */ do { - if(pTargetTree) - slapi_dn_normalize( pTargetTree->val ); + if(pTargetTree) { + int rc = 0; + char *tval = NULL; + size_t tlen = 0; + rc = slapi_dn_normalize_ext(pTargetTree->val, 0, &tval, &tlen); + if (rc < 0) { + LDAPDebug(LDAP_DEBUG_ANY, + "cos_cache_query_attr: failed to normalize dn %s. " + "Processing the pre normalized dn.\n", + pTargetTree->val, 0, 0); + } else if (rc == 0) { + /* passed in. not terminated */ + *(tval + tlen) = '\0'; + } else { + slapi_ch_free_string(&pTargetTree->val); + pTargetTree->val = tval; + } + } if( pTargetTree->val == 0 || slapi_dn_issuffix(pDn, pTargetTree->val) != 0 || @@ -2800,7 +2874,23 @@ static int cos_cache_index_all(cosCache *pCache) while(pAttrVal) { - slapi_dn_normalize(pAttrVal->val); + int rc = 0; + char *dnval = NULL; + size_t dnlen = 0; + rc = slapi_dn_normalize_ext(pAttrVal->val, 0, + &dnval, &dnlen); + if (rc < 0) { + LDAPDebug(LDAP_DEBUG_ANY, + "cos_cache_index_all: failed to normalize dn %s. " + "Processing the pre normalized dn.\n", + pAttrVal->val, 0, 0); + } else if (rc == 0) { + /* passed in. not terminated */ + *(dnval + dnlen) = '\0'; + } else { + slapi_ch_free_string(&pAttrVal->val); + pAttrVal->val = dnval; + } pCache->ppTemplateList[tmpindex] = pAttrVal->val; tmpindex++; @@ -3519,3 +3609,20 @@ static int cos_cache_entry_is_cos_related( Slapi_Entry *e) { } return(rc); } + +/* copied from dn.c */ +static int +hexchar2int( char c ) +{ + if ( '0' <= c && c <= '9' ) { + return( c - '0' ); + } + if ( 'a' <= c && c <= 'f' ) { + return( c - 'a' + 10 ); + } + if ( 'A' <= c && c <= 'F' ) { + return( c - 'A' + 10 ); + } + return( -1 ); +} + diff --git a/ldap/servers/plugins/dna/dna.c b/ldap/servers/plugins/dna/dna.c index b8922d9d..94c4ab38 100644 --- a/ldap/servers/plugins/dna/dna.c +++ b/ldap/servers/plugins/dna/dna.c @@ -680,7 +680,7 @@ dna_parse_config_entry(Slapi_Entry * e, int apply) } entry = (struct configEntry *) - slapi_ch_calloc(1, sizeof(struct configEntry)); + slapi_ch_calloc(1, sizeof(struct configEntry)); if (NULL == entry) { ret = DNA_FAILURE; goto bail; @@ -787,7 +787,7 @@ dna_parse_config_entry(Slapi_Entry * e, int apply) if (value) { /* TODO - Allow multiple scope settings for a single range. This may * make ordering the scopes tough when we put them in the clist. */ - entry->scope = slapi_dn_normalize(value); + entry->scope = value; } else { slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, "dna_parse_config_entry: The %s config " @@ -817,6 +817,7 @@ dna_parse_config_entry(Slapi_Entry * e, int apply) if (value) { Slapi_Entry *shared_e = NULL; Slapi_DN *sdn = NULL; + char *normdn = NULL; sdn = slapi_sdn_new_dn_byref(value); @@ -840,15 +841,29 @@ dna_parse_config_entry(Slapi_Entry * e, int apply) shared_e = NULL; } - entry->shared_cfg_base = slapi_ch_strdup(value); - slapi_dn_normalize(entry->shared_cfg_base); + normdn = slapi_create_dn_string("%s", value); + if (NULL == normdn) { + slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, + "dna_parse_config_entry: failed to normalize dn: " + "%s\n", value); + ret = DNA_FAILURE; + goto bail; + } + entry->shared_cfg_base = normdn; /* We prepend the host & port of this instance as a * multi-part RDN for the shared config entry. */ - entry->shared_cfg_dn = slapi_ch_smprintf("%s=%s+%s=%s,%s", DNA_HOSTNAME, - hostname, DNA_PORTNUM, portnum, value); - slapi_ch_free_string(&value); - slapi_dn_normalize(entry->shared_cfg_dn); + normdn = slapi_create_dn_string("%s=%s+%s=%s,%s", DNA_HOSTNAME, + hostname, DNA_PORTNUM, portnum, normdn); + if (NULL == normdn) { + slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, + "dna_parse_config_entry: failed to create dn: " + "%s=%s+%s=%s,%s", DNA_HOSTNAME, + hostname, DNA_PORTNUM, portnum, value); + ret = DNA_FAILURE; + goto bail; + } + entry->shared_cfg_dn = normdn; slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, "----------> %s [%s]\n", DNA_SHARED_CFG_DN, @@ -1680,8 +1695,6 @@ static char *dna_get_dn(Slapi_PBlock * pb) goto bail; } -/* slapi_dn_normalize( dn ); -*/ bail: slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, "<-- dna_get_dn\n"); @@ -2310,7 +2323,14 @@ static int dna_is_replica_bind_dn(char *range_dn, char *bind_dn) * the shared config. We need to see what the configured * replica bind DN is. */ if (be_suffix) { - replica_dn = slapi_ch_smprintf("cn=replica,cn=\"%s\",cn=mapping tree,cn=config", be_suffix); + /* This function converts the old DN style to the new one. */ + replica_dn = slapi_create_dn_string("cn=replica,cn=\"%s\",cn=mapping tree,cn=config", be_suffix); + if (NULL == replica_dn) { + slapi_log_error(SLAPI_LOG_PLUGIN, DNA_PLUGIN_SUBSYSTEM, + "dna_is_replica_bind_dn: failed to create " + "replica dn for %s\n", be_suffix); + return 1; + } replica_sdn = slapi_sdn_new_dn_passin(replica_dn); attrs[0] = DNA_REPL_BIND_DN; @@ -2370,8 +2390,15 @@ static int dna_get_replica_bind_creds(char *range_dn, struct dnaServer *server, /* Fetch the replication agreement entry */ if (be_suffix) { - replica_dn = slapi_ch_smprintf("cn=replica,cn=\"%s\",cn=mapping tree,cn=config", - be_suffix); + /* This function converts the old DN style to the new one. */ + replica_dn = slapi_create_dn_string("cn=replica,cn=\"%s\",cn=mapping tree,cn=config", be_suffix); + if (NULL == replica_dn) { + slapi_log_error(SLAPI_LOG_PLUGIN, DNA_PLUGIN_SUBSYSTEM, + "dna_get_replica_bind_creds: failed to create " + "replica dn for %s\n", be_suffix); + ret = LDAP_PARAM_ERROR; + goto bail; + } filter = slapi_ch_smprintf("(&(nsds5ReplicaHost=%s)(|(" DNA_REPL_PORT "=%u)" "(" DNA_REPL_PORT "=%u)))", diff --git a/ldap/servers/plugins/linkedattrs/fixup_task.c b/ldap/servers/plugins/linkedattrs/fixup_task.c index 50d35d0e..d5505709 100644 --- a/ldap/servers/plugins/linkedattrs/fixup_task.c +++ b/ldap/servers/plugins/linkedattrs/fixup_task.c @@ -80,9 +80,9 @@ linked_attrs_fixup_task_add(Slapi_PBlock *pb, Slapi_Entry *e, goto out; } - if (linkdn) { + if (linkdn) { mytaskdata->linkdn = slapi_dn_normalize(slapi_ch_strdup(linkdn)); - } + } /* allocate new task now */ task = slapi_new_task(slapi_entry_get_ndn(e)); diff --git a/ldap/servers/plugins/mep/mep.c b/ldap/servers/plugins/mep/mep.c index e9d64fe4..ba142033 100644 --- a/ldap/servers/plugins/mep/mep.c +++ b/ldap/servers/plugins/mep/mep.c @@ -88,7 +88,6 @@ static int mep_modrdn_pre_op(Slapi_PBlock *pb); static int mep_load_config(); static void mep_delete_config(); static int mep_parse_config_entry(Slapi_Entry * e, int apply); -static void mep_insert_config_index(struct configEntry *entry); static void mep_free_config_entry(struct configEntry ** entry); /* @@ -949,7 +948,6 @@ mep_create_managed_entry(struct configEntry *config, Slapi_Entry *origin) Slapi_Entry *template = NULL; char *rdn_type = NULL; char **vals = NULL; - char *p = NULL; char *type = NULL; char *value = NULL; int vlen = 0; @@ -1055,7 +1053,7 @@ mep_create_managed_entry(struct configEntry *config, Slapi_Entry *origin) /* Create the DN using the mapped RDN value * and the base specified in the config. */ - dn = slapi_ch_smprintf("%s=%s,%s", rdn_type, rdn_val, config->managed_base); + dn = slapi_create_dn_string("%s=%s,%s", rdn_type, rdn_val, config->managed_base); slapi_ch_free_string(&rdn_val); diff --git a/ldap/servers/plugins/pwdstorage/smd5_pwd.c b/ldap/servers/plugins/pwdstorage/smd5_pwd.c index 65c6b2a9..cef3ee37 100644 --- a/ldap/servers/plugins/pwdstorage/smd5_pwd.c +++ b/ldap/servers/plugins/pwdstorage/smd5_pwd.c @@ -89,7 +89,7 @@ smd5_pw_cmp( const char *userpwd, const char *dbpwd ) memset( quick_dbhash, 0, sizeof(quick_dbhash) ); } - hashresult = PL_Base64Decode( dbpwd, 0, (char *)dbhash ); + hashresult = PL_Base64Decode( dbpwd, 0, dbhash ); if (NULL == hashresult) { slapi_log_error( SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME, "smd5_pw_cmp: userPassword \"%s\" is the wrong length " @@ -139,7 +139,7 @@ smd5_pw_enc( const char *pwd ) memset( hash_out, 0, sizeof(hash_out) ); /* generate a new random salt */ - slapi_rand_array( salt, MD5_DEFAULT_SALT_LENGTH ); + slapi_rand_array( (void *)salt, MD5_DEFAULT_SALT_LENGTH ); saltval.bv_val = (void*)salt; saltval.bv_len = MD5_DEFAULT_SALT_LENGTH; diff --git a/ldap/servers/plugins/referint/referint.c b/ldap/servers/plugins/referint/referint.c index b459a7ac..0f1598db 100644 --- a/ldap/servers/plugins/referint/referint.c +++ b/ldap/servers/plugins/referint/referint.c @@ -385,6 +385,7 @@ _update_one_per_mod(const char *entryDN, /* DN of the searched entry */ /* no need to free superior */ superior = slapi_dn_find_parent(origDN); } + /* newRDN and superior are already normalized. */ newDN = slapi_ch_smprintf("%s,%s", newRDN, superior); /* * Compare the modified dn with the value of @@ -409,9 +410,19 @@ _update_one_per_mod(const char *entryDN, /* DN of the searched entry */ nval != -1; nval = slapi_attr_next_value(attr, nval, &v)) { char *p = NULL; + size_t dnlen = 0; /* DN syntax, which should be a string */ sval = slapi_ch_strdup(slapi_value_get_string(v)); - slapi_dn_normalize_case(sval); + rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen); + if (rc == 0) { /* sval is passed in; not terminated */ + *(p + dnlen) = '\0'; + sval = p; + } else if (rc > 0) { + slapi_ch_free_string(&sval); + sval = p; + } + /* else: (rc < 0) Ignore the DN normalization error for now. */ + p = PL_strstr(sval, norm_origDN); if (p == sval) { /* (case 1) */ @@ -448,6 +459,7 @@ _update_one_per_mod(const char *entryDN, /* DN of the searched entry */ bak = *p; *p = '\0'; + /* newRDN and superior are already normalized. */ newvalue = slapi_ch_smprintf("%s%s", sval, newDN); *p = bak; values_add[0]=newvalue; @@ -579,9 +591,19 @@ _update_all_per_mod(const char *entryDN, /* DN of the searched entry */ nval != -1; nval = slapi_attr_next_value(attr, nval, &v)) { char *p = NULL; + size_t dnlen = 0; /* DN syntax, which should be a string */ sval = slapi_ch_strdup(slapi_value_get_string(v)); - slapi_dn_normalize_case(sval); + rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen); + if (rc == 0) { /* sval is passed in; not terminated */ + *(p + dnlen) = '\0'; + sval = p; + } else if (rc > 0) { + slapi_ch_free_string(&sval); + sval = p; + } + /* else: (rc < 0) Ignore the DN normalization error for now. */ + p = PL_strstr(sval, norm_origDN); if (p == sval) { /* (case 1) */ @@ -632,6 +654,7 @@ update_integrity(char **argv, char *origDN, int i, j; const char *search_base = NULL; char *norm_origDN = NULL; + size_t dnlen = 0; int rc; if ( argv == NULL ) { @@ -644,8 +667,14 @@ update_integrity(char **argv, char *origDN, /* for now, just putting attributes to keep integrity on in conf file, until resolve the other timing mode issue */ - norm_origDN = slapi_ch_strdup(origDN); - slapi_dn_normalize_case(norm_origDN); + rc = slapi_dn_normalize_case_ext(origDN, 0, &norm_origDN, &dnlen); + if (rc == 0) { /* origDN is passed in; not terminated */ + *(norm_origDN + dnlen) = '\0'; + norm_origDN = slapi_ch_strdup(norm_origDN); + } else if (rc < 0) { + /* Ignore the DN normalization error for now. */ + norm_origDN = slapi_ch_strdup(origDN); + } search_result_pb = slapi_pblock_new(); diff --git a/ldap/servers/plugins/replication/legacy_consumer.c b/ldap/servers/plugins/replication/legacy_consumer.c index 97745278..8a47e800 100644 --- a/ldap/servers/plugins/replication/legacy_consumer.c +++ b/ldap/servers/plugins/replication/legacy_consumer.c @@ -83,6 +83,7 @@ static void legacy_consumer_encode_pw (Slapi_Entry *e); static void set_legacy_purl (Slapi_PBlock *pb, const char *purl); static int get_legacy_referral (Slapi_Entry *e, char **referral, char **state); +/* LEGACY_CONSUMER_CONFIG_DN is no need to be normalized. */ #define LEGACY_CONSUMER_CONFIG_DN "cn=legacy consumer," REPL_CONFIG_TOP #define LEGACY_CONSUMER_FILTER "(objectclass=*)" diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h index c6859ddb..6be21ceb 100644 --- a/ldap/servers/plugins/replication/repl5.h +++ b/ldap/servers/plugins/replication/repl5.h @@ -319,8 +319,8 @@ char **agmt_validate_replicated_attributes(Repl_Agmt *ra); void* agmt_get_priv (const Repl_Agmt *agmt); void agmt_set_priv (Repl_Agmt *agmt, void* priv); - int get_agmt_agreement_type ( Repl_Agmt *agmt); +int agmt_has_protocol(Repl_Agmt *agmt); typedef struct replica Replica; diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c index 13db1acd..f60da022 100644 --- a/ldap/servers/plugins/replication/repl5_agmt.c +++ b/ldap/servers/plugins/replication/repl5_agmt.c @@ -2216,13 +2216,21 @@ agmt_get_consumer_rid ( Repl_Agmt *agmt, void *conn ) { if ( agmt->consumerRID <= 0 ) { - char mapping_tree_node[512]; + char *mapping_tree_node = NULL; struct berval **bvals = NULL; - PR_snprintf ( mapping_tree_node, - sizeof (mapping_tree_node), - "cn=replica,cn=\"%s\",cn=mapping tree,cn=config", - slapi_sdn_get_dn (agmt->replarea) ); + + /* This function converts the old style DN to the new one. */ + mapping_tree_node = + slapi_create_dn_string("cn=replica,cn=\"%s\",cn=mapping tree,cn=config", + slapi_sdn_get_dn (agmt->replarea) ); + if (NULL == mapping_tree_node) { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "agmt_get_consumer_rid: failed to normalize " + "replica dn for %s\n", + slapi_sdn_get_dn (agmt->replarea)); + agmt->consumerRID = 0; + } conn_read_entry_attribute ( conn, mapping_tree_node, "nsDS5ReplicaID", &bvals ); if ( NULL != bvals && NULL != bvals[0] ) { char *ridstr = slapi_ch_malloc( bvals[0]->bv_len + 1 ); @@ -2232,6 +2240,7 @@ agmt_get_consumer_rid ( Repl_Agmt *agmt, void *conn ) slapi_ch_free ( (void**) &ridstr ); ber_bvecfree ( bvals ); } + slapi_ch_free_string(&mapping_tree_node); } return agmt->consumerRID; diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c index 510757b6..f9aa610d 100644 --- a/ldap/servers/plugins/replication/repl5_agmtlist.c +++ b/ldap/servers/plugins/replication/repl5_agmtlist.c @@ -50,7 +50,8 @@ #include "repl5.h" #include <plstr.h> -#define AGMT_CONFIG_BASE "cn=mapping tree, cn=config" +/* normalized DN */ +#define AGMT_CONFIG_BASE "cn=mapping tree,cn=config" #define CONFIG_FILTER "(objectclass=nsds5replicationagreement)" #define WINDOWS_CONFIG_FILTER "(objectclass=nsdsWindowsreplicationagreement)" #define GLOBAL_CONFIG_FILTER "(|" CONFIG_FILTER WINDOWS_CONFIG_FILTER " )" diff --git a/ldap/servers/plugins/replication/repl5_protocol.c b/ldap/servers/plugins/replication/repl5_protocol.c index 31f6072b..b1ff730d 100644 --- a/ldap/servers/plugins/replication/repl5_protocol.c +++ b/ldap/servers/plugins/replication/repl5_protocol.c @@ -173,7 +173,6 @@ void prot_free(Repl_Protocol **rpp) { Repl_Protocol *rp = NULL; - PRIntervalTime interval; if (rpp == NULL || *rpp == NULL) return; diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c index f669900f..0d2f1956 100644 --- a/ldap/servers/plugins/replication/repl5_replica.c +++ b/ldap/servers/plugins/replication/repl5_replica.c @@ -1528,6 +1528,12 @@ _replica_get_config_entry (const Slapi_DN *root) Slapi_PBlock *pb = NULL; dn = _replica_get_config_dn (root); + if (NULL == dn) { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "_replica_get_config_entry: failed to get the config dn for %s\n", + slapi_sdn_get_dn (root)); + return NULL; + } pb = slapi_pblock_new (); slapi_search_internal_set_pb (pb, dn, LDAP_SCOPE_BASE, "objectclass=*", NULL, 0, NULL, @@ -1839,8 +1845,9 @@ _replica_get_config_dn (const Slapi_DN *root) PR_ASSERT (root); - dn = slapi_ch_smprintf("%s,cn=\"%s\",%s", REPLICA_RDN, slapi_sdn_get_dn (root), mp_base); - + /* This function converts the old style DN to the new style. */ + dn = slapi_create_dn_string("%s,cn=\"%s\",%s", + REPLICA_RDN, slapi_sdn_get_dn (root), mp_base); return dn; } @@ -2162,6 +2169,13 @@ _replica_update_state (time_t when, void *arg) r->repl_csn_assigned = PR_FALSE; dn = _replica_get_config_dn (r->repl_root); + if (NULL == dn) { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "_replica_update_state: failed to get the config dn for %s\n", + slapi_sdn_get_dn (r->repl_root)); + PR_Unlock(r->repl_lock); + goto done; + } pb = slapi_pblock_new(); mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod); @@ -3057,6 +3071,14 @@ replica_replace_ruv_tombstone(Replica *r) ruv_last_modified_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod_last_modified); dn = _replica_get_config_dn (r->repl_root); + if (NULL == dn) { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "replica_replace_ruv_tombstone: " + "failed to get the config dn for %s\n", + slapi_sdn_get_dn (r->repl_root)); + PR_Unlock(r->repl_lock); + goto bail; + } mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod); mods[1] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod_last_modified); @@ -3090,6 +3112,7 @@ replica_replace_ruv_tombstone(Replica *r) slapi_ch_free ((void**)&dn); slapi_pblock_destroy (pb); +bail: slapi_mod_done (&smod); slapi_mod_done (&smod_last_modified); } diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c index af5b6cd7..80b53616 100644 --- a/ldap/servers/plugins/replication/repl5_replica_config.c +++ b/ldap/servers/plugins/replication/repl5_replica_config.c @@ -47,6 +47,7 @@ #include "repl5.h" #include "cl5_api.h" +/* CONFIG_BASE: no need to optimize */ #define CONFIG_BASE "cn=mapping tree,cn=config" #define CONFIG_FILTER "(objectclass=nsDS5Replica)" #define TASK_ATTR "nsds5Task" diff --git a/ldap/servers/plugins/replication/repl_init.c b/ldap/servers/plugins/replication/repl_init.c index 5c897595..7a7c32cd 100644 --- a/ldap/servers/plugins/replication/repl_init.c +++ b/ldap/servers/plugins/replication/repl_init.c @@ -207,6 +207,7 @@ legacy_entry_init( Slapi_PBlock *pb ) static int create_config_top() { + /* DN part of this entry_string: no need to be optimized. */ char *entry_string = slapi_ch_strdup("dn: cn=replication,cn=config\nobjectclass: top\nobjectclass: extensibleobject\ncn: replication\n"); Slapi_PBlock *pb = slapi_pblock_new(); Slapi_Entry *e = slapi_str2entry(entry_string, 0); diff --git a/ldap/servers/plugins/retrocl/retrocl.c b/ldap/servers/plugins/retrocl/retrocl.c index 556dede2..aedd6165 100644 --- a/ldap/servers/plugins/retrocl/retrocl.c +++ b/ldap/servers/plugins/retrocl/retrocl.c @@ -266,6 +266,7 @@ char *retrocl_get_config_str(const char *attrt) int rc = 0; char *dn; + /* RETROCL_PLUGIN_DN is no need to be normalized. */ dn = RETROCL_PLUGIN_DN; pb = slapi_pblock_new(); diff --git a/ldap/servers/plugins/retrocl/retrocl_create.c b/ldap/servers/plugins/retrocl/retrocl_create.c index 88974b72..1ffdaae9 100644 --- a/ldap/servers/plugins/retrocl/retrocl_create.c +++ b/ldap/servers/plugins/retrocl/retrocl_create.c @@ -77,6 +77,7 @@ static int retrocl_create_be(const char *bedir) vals[1] = NULL; e = slapi_entry_alloc(); + /* RETROCL_LDBM_DN is no need to be normalized. */ slapi_entry_set_dn(e,slapi_ch_strdup(RETROCL_LDBM_DN)); /* Set the objectclass attribute */ @@ -142,6 +143,7 @@ static int retrocl_create_be(const char *bedir) /* we need the changenumber indexed */ e = slapi_entry_alloc(); + /* RETROCL_INDEX_DN is no need to be normalized. */ slapi_entry_set_dn(e,slapi_ch_strdup(RETROCL_INDEX_DN)); /* Set the objectclass attribute */ @@ -210,6 +212,7 @@ int retrocl_create_config(void) struct berval *vals[2]; struct berval val; int rc; + char *mappingtree_dn = NULL; vals[0] = &val; vals[1] = NULL; @@ -219,7 +222,15 @@ int retrocl_create_config(void) * in the errors file when the referenced backend does not exist. */ e = slapi_entry_alloc(); - slapi_entry_set_dn(e,slapi_ch_strdup(RETROCL_MAPPINGTREE_DN)); + /* This function converts the old DN style to the new one. */ + mappingtree_dn = slapi_create_dn_string("%s", RETROCL_MAPPINGTREE_DN); + if (NULL == mappingtree_dn) { + slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, + "retrocl_create_config: failed to normalize " + "mappingtree dn %s\n", RETROCL_MAPPINGTREE_DN); + return LDAP_PARAM_ERROR; + } + slapi_entry_set_dn(e, mappingtree_dn); /* mappingtree_dn is consumed */ /* Set the objectclass attribute */ val.bv_val = "top"; diff --git a/ldap/servers/plugins/syntaxes/string.c b/ldap/servers/plugins/syntaxes/string.c index 9b338335..21ff5d1b 100644 --- a/ldap/servers/plugins/syntaxes/string.c +++ b/ldap/servers/plugins/syntaxes/string.c @@ -63,6 +63,7 @@ string_filter_ava( struct berval *bvfilter, Slapi_Value **bvals, int syntax, { int i, rc; struct berval bvfilter_norm; + char *alt = NULL; if(retVal) { *retVal = NULL; @@ -74,7 +75,12 @@ string_filter_ava( struct berval *bvfilter, Slapi_Value **bvals, int syntax, bvfilter_norm.bv_val = slapi_ch_malloc( bvfilter->bv_len + 1 ); SAFEMEMCPY( bvfilter_norm.bv_val, bvfilter->bv_val, bvfilter->bv_len ); bvfilter_norm.bv_val[bvfilter->bv_len] = '\0'; - value_normalize( bvfilter_norm.bv_val, syntax, 1 /* trim leading blanks */ ); + /* 3rd arg: 1 - trim leading blanks */ + value_normalize_ext( bvfilter_norm.bv_val, syntax, 1, &alt ); + if (alt) { + slapi_ch_free_string(&bvfilter_norm.bv_val); + bvfilter_norm.bv_val = alt; + } bvfilter_norm.bv_len = strlen(bvfilter_norm.bv_val); for ( i = 0; (bvals != NULL) && (bvals[i] != NULL); i++ ) { @@ -211,6 +217,7 @@ string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final, Operation *op = NULL; Slapi_Regex *re = NULL; const char *re_result = NULL; + char *alt = NULL; LDAPDebug( LDAP_DEBUG_FILTER, "=> string_filter_sub\n", 0, 0, 0 ); @@ -260,27 +267,45 @@ string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final, } if ( initial != NULL ) { - value_normalize( initial, syntax, 1 /* trim leading blanks */ ); + /* 3rd arg: 1 - trim leading blanks */ + value_normalize_ext( initial, syntax, 1, &alt ); *p++ = '^'; - filter_strcpy_special_ext( p, initial, FILTER_STRCPY_ESCAPE_RECHARS ); + if (alt) { + filter_strcpy_special_ext( p, alt, FILTER_STRCPY_ESCAPE_RECHARS ); + slapi_ch_free_string(&alt); + } else { + filter_strcpy_special_ext( p, initial, FILTER_STRCPY_ESCAPE_RECHARS ); + } p = strchr( p, '\0' ); } if ( any != NULL ) { for ( i = 0; any[i] != NULL; i++ ) { - value_normalize( any[i], syntax, 0 /* DO NOT trim leading blanks */ ); + /* 3rd arg: 0 - DO NOT trim leading blanks */ + value_normalize_ext( any[i], syntax, 0, &alt ); /* ".*" + value */ *p++ = '.'; *p++ = '*'; - filter_strcpy_special_ext( p, any[i], FILTER_STRCPY_ESCAPE_RECHARS ); + if (alt) { + filter_strcpy_special_ext( p, alt, FILTER_STRCPY_ESCAPE_RECHARS ); + slapi_ch_free_string(&alt); + } else { + filter_strcpy_special_ext( p, any[i], FILTER_STRCPY_ESCAPE_RECHARS ); + } p = strchr( p, '\0' ); } } if ( final != NULL ) { - value_normalize( final, syntax, 0 /* DO NOT trim leading blanks */ ); + /* 3rd arg: 0 - DO NOT trim leading blanks */ + value_normalize_ext( final, syntax, 0, &alt ); /* ".*" + value */ *p++ = '.'; *p++ = '*'; - filter_strcpy_special_ext( p, final, FILTER_STRCPY_ESCAPE_RECHARS ); + if (alt) { + filter_strcpy_special_ext( p, alt, FILTER_STRCPY_ESCAPE_RECHARS ); + slapi_ch_free_string(&alt); + } else { + filter_strcpy_special_ext( p, final, FILTER_STRCPY_ESCAPE_RECHARS ); + } strcat( p, "$" ); } @@ -327,9 +352,15 @@ string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final, strcpy( tmpbuf, bvp->bv_val ); realval = tmpbuf; } - value_normalize( realval, syntax, 1 /* trim leading blanks */ ); + /* 3rd arg: 1 - trim leading blanks */ + value_normalize_ext( realval, syntax, 1, &alt ); - tmprc = slapi_re_exec( re, realval, time_up ); + if (alt) { + tmprc = slapi_re_exec( re, alt, time_up ); + slapi_ch_free_string(&alt); + } else { + tmprc = slapi_re_exec( re, realval, time_up ); + } LDAPDebug( LDAP_DEBUG_TRACE, "re_exec (%s) %i\n", escape_string( realval, ebuf ), tmprc, 0 ); @@ -359,6 +390,7 @@ string_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals, Slapi_Value **nbvals, **nbvlp; Slapi_Value **bvlp; char *w, *c, *p; + char *alt = NULL; if (NULL == ivals) { return 1; @@ -380,9 +412,16 @@ string_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals, { c = slapi_ch_strdup(slapi_value_get_string(*bvlp)); /* if the NORMALIZED flag is set, skip normalizing */ - if (!(slapi_value_get_flags(*bvlp) & SLAPI_ATTR_FLAG_NORMALIZED)) - value_normalize( c, syntax, 1 /* trim leading blanks */ ); - *nbvlp = slapi_value_new_string_passin(c); + if (!(slapi_value_get_flags(*bvlp) & SLAPI_ATTR_FLAG_NORMALIZED)) { + /* 3rd arg: 1 - trim leading blanks */ + value_normalize_ext( c, syntax, 1, &alt ); + } + if (alt) { + slapi_ch_free_string(&c); + *nbvlp = slapi_value_new_string_passin(alt); + } else { + *nbvlp = slapi_value_new_string_passin(c); + } } *ivals = nbvals; break; @@ -470,14 +509,16 @@ string_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals, for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) { /* * Note: this calculation may err on the high side, - * because value_normalize(), which is called below + * because value_normalize_ext(), which is called below * before we actually create the substring keys, may - * reduce the length of the value in some cases. For - * example, spaces are removed when space insensitive - * strings are normalized. But it's okay for nsubs to - * be too big. Since the ivals array is NULL terminated, - * the only downside is that we allocate more space than - * we really need. + * reduce the length of the value in some cases or + * increase the length in other cases. For example, + * spaces are removed when space insensitive strings + * are normalized. Or if the value includes '\"' (2 bytes), + * it's normalized to '\22' (3 bytes). But it's okay + * for nsubs to be too big. Since the ivals array is + * NULL terminated, the only downside is that we + * allocate more space than we really need. */ nsubs += slapi_value_get_length(*bvlp) - substrlens[INDEX_SUBSTRMIDDLE] + 3; } @@ -489,8 +530,14 @@ string_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals, bvdup= slapi_value_new(); for ( bvlp = bvals; bvlp && *bvlp; bvlp++ ) { c = slapi_ch_strdup(slapi_value_get_string(*bvlp)); - value_normalize( c, syntax, 1 /* trim leading blanks */ ); - slapi_value_set_string_passin(bvdup, c); + /* 3rd arg: 1 - trim leading blanks */ + value_normalize_ext( c, syntax, 1, &alt ); + if (alt) { + slapi_ch_free_string(&c); + slapi_value_set_string_passin(bvdup, alt); + } else { + slapi_value_set_string_passin(bvdup, c); + } bvp = slapi_value_get_berval(bvdup); @@ -554,6 +601,7 @@ string_assertion2keys_ava( size_t len; char *w, *c; Slapi_Value *tmpval=NULL; + char *alt = NULL; switch ( ftype ) { case LDAP_FILTER_EQUALITY_FAST: @@ -565,13 +613,23 @@ string_assertion2keys_ava( } memcpy(tmpval->bv.bv_val,slapi_value_get_string(val),len); tmpval->bv.bv_val[len]='\0'; - value_normalize(tmpval->bv.bv_val, syntax, 1 /* trim leading blanks */ ); + /* 3rd arg: 1 - trim leading blanks */ + value_normalize_ext(tmpval->bv.bv_val, syntax, 1, &alt ); + if (alt) { + slapi_ch_free_string(&tmpval->bv.bv_val); + tmpval->bv.bv_val = alt; + } tmpval->bv.bv_len=strlen(tmpval->bv.bv_val); break; case LDAP_FILTER_EQUALITY: (*ivals) = (Slapi_Value **) slapi_ch_malloc( 2 * sizeof(Slapi_Value *) ); (*ivals)[0] = slapi_value_dup( val ); - value_normalize( (*ivals)[0]->bv.bv_val, syntax, 1 /* trim leading blanks */ ); + /* 3rd arg: 1 - trim leading blanks */ + value_normalize_ext( (*ivals)[0]->bv.bv_val, syntax, 1, &alt ); + if (alt) { + slapi_ch_free_string(&(*ivals)[0]->bv.bv_val); + (*ivals)[0]->bv.bv_val = alt; + } (*ivals)[0]->bv.bv_len = strlen( (*ivals)[0]->bv.bv_val ); (*ivals)[1] = NULL; break; @@ -628,6 +686,10 @@ string_assertion2keys_sub( int localsublens[3] = {SUBBEGIN, SUBMIDDLE, SUBEND};/* default values */ int maxsublen; char *comp_buf = NULL; + char *altinit = NULL; + char **altany = NULL; + char *altfinal = NULL; + int anysize = 0; slapi_pblock_get(pb, SLAPI_SYNTAX_SUBSTRLENS, &substrlens); @@ -650,13 +712,17 @@ string_assertion2keys_sub( * First figure out how many keys we will return. The answer is based * on the length of each assertion value. Since normalization may * reduce the length (such as when spaces are removed from space - * insensitive strings), we call value_normalize() before checking + * insensitive strings), we call value_normalize_ext() before checking * the length. */ nsubs = 0; if ( initial != NULL ) { - value_normalize( initial, syntax, 0 /* do not trim leading blanks */ ); - initiallen = strlen( initial ); + /* 3rd arg: 0 - DO NOT trim leading blanks */ + value_normalize_ext( initial, syntax, 0, &altinit ); + if (NULL == altinit) { + altinit = initial; + } + initiallen = strlen( altinit ); if ( initiallen > substrlens[INDEX_SUBSTRBEGIN] - 2 ) { nsubs += 1; /* for the initial begin string key */ /* the rest of the sub keys are "any" keys for this case */ @@ -664,19 +730,31 @@ string_assertion2keys_sub( nsubs += initiallen - substrlens[INDEX_SUBSTRMIDDLE] + 1; } } else { - initial = NULL; /* save some work later */ + altinit = NULL; /* save some work later */ } } for ( i = 0; any != NULL && any[i] != NULL; i++ ) { - value_normalize( any[i], syntax, 0 /* do not trim leading blanks */ ); - len = strlen( any[i] ); + anysize++; + } + altany = (char **)slapi_ch_calloc(anysize + 1, sizeof(char *)); + for ( i = 0; any != NULL && any[i] != NULL; i++ ) { + /* 3rd arg: 0 - DO NOT trim leading blanks */ + value_normalize_ext( any[i], syntax, 0, &altany[i] ); + if (NULL == altany[i]) { + altany[i] = any[i]; + } + len = strlen( altany[i] ); if ( len >= substrlens[INDEX_SUBSTRMIDDLE] ) { nsubs += len - substrlens[INDEX_SUBSTRMIDDLE] + 1; } } if ( final != NULL ) { - value_normalize( final, syntax, 0 /* do not trim leading blanks */ ); - finallen = strlen( final ); + /* 3rd arg: 0 - DO NOT trim leading blanks */ + value_normalize_ext( final, syntax, 0, &altfinal ); + if (NULL == altfinal) { + altfinal = final; + } + finallen = strlen( altfinal ); if ( finallen > substrlens[INDEX_SUBSTREND] - 2 ) { nsubs += 1; /* for the final end string key */ /* the rest of the sub keys are "any" keys for this case */ @@ -684,7 +762,7 @@ string_assertion2keys_sub( nsubs += finallen - substrlens[INDEX_SUBSTRMIDDLE] + 1; } } else { - final = NULL; /* save some work later */ + altfinal = NULL; /* save some work later */ } } if ( nsubs == 0 ) { /* no keys to return */ @@ -703,21 +781,31 @@ string_assertion2keys_sub( nsubs = 0; comp_buf = (char *)slapi_ch_malloc(maxsublen + 1); - if ( initial != NULL ) { - substring_comp_keys( ivals, &nsubs, initial, initiallen, '^', syntax, + if ( altinit != NULL ) { + substring_comp_keys( ivals, &nsubs, altinit, initiallen, '^', syntax, comp_buf, substrlens ); + if (altinit != initial) { + slapi_ch_free_string(&altinit); + } } - for ( i = 0; any != NULL && any[i] != NULL; i++ ) { - len = strlen( any[i] ); + for ( i = 0; altany != NULL && altany[i] != NULL; i++ ) { + len = strlen( altany[i] ); if ( len < substrlens[INDEX_SUBSTRMIDDLE] ) { continue; } - substring_comp_keys( ivals, &nsubs, any[i], len, 0, syntax, + substring_comp_keys( ivals, &nsubs, altany[i], len, 0, syntax, comp_buf, substrlens ); + if (altany[i] != any[i]) { + slapi_ch_free_string(&altany[i]); + } } - if ( final != NULL ) { - substring_comp_keys( ivals, &nsubs, final, finallen, '$', syntax, + slapi_ch_free((void **)&altany); + if ( altfinal != NULL ) { + substring_comp_keys( ivals, &nsubs, altfinal, finallen, '$', syntax, comp_buf, substrlens ); + if (altfinal != final) { + slapi_ch_free_string(&final); + } } (*ivals)[nsubs] = NULL; slapi_ch_free_string(&comp_buf); diff --git a/ldap/servers/plugins/syntaxes/syntax.h b/ldap/servers/plugins/syntaxes/syntax.h index ec3d5f03..64942ec7 100644 --- a/ldap/servers/plugins/syntaxes/syntax.h +++ b/ldap/servers/plugins/syntaxes/syntax.h @@ -113,6 +113,7 @@ int string_assertion2keys_ava(Slapi_PBlock *pb,Slapi_Value *val,Slapi_Value ***i int string_assertion2keys_sub(Slapi_PBlock *pb,char *initial,char **any,char *final,Slapi_Value ***ivals,int syntax); int value_cmp(struct berval *v1,struct berval *v2,int syntax,int normalize); void value_normalize(char *s,int syntax,int trim_leading_blanks); +void value_normalize_ext(char *s,int syntax,int trim_leading_blanks, char **alt); char *first_word( char *s ); char *next_word( char *s ); diff --git a/ldap/servers/plugins/syntaxes/validate.c b/ldap/servers/plugins/syntaxes/validate.c index aab6d9c2..989137b5 100644 --- a/ldap/servers/plugins/syntaxes/validate.c +++ b/ldap/servers/plugins/syntaxes/validate.c @@ -362,7 +362,6 @@ int distinguishedname_validate( { int rc = 0; /* Assume value is valid */ char *val_copy = NULL; - int strict = 0; const char *p = begin; const char *last = NULL; @@ -377,17 +376,6 @@ int distinguishedname_validate( * attributeValue = string / hexstring */ - /* Check if we should be performing strict validation. */ - strict = config_get_dn_validate_strict(); - if (!strict) { - /* Create a normalized copy of the value to use - * for validation. The original value will be - * stored in the backend unmodified. */ - val_copy = PL_strndup(begin, end - begin + 1); - p = val_copy; - end = slapi_dn_normalize_to_end(val_copy, NULL) - 1; - } - /* Validate one RDN at a time in a loop. */ while (p <= end) { if ((rc = rdn_validate(p, end, &last)) != 0) { diff --git a/ldap/servers/plugins/syntaxes/value.c b/ldap/servers/plugins/syntaxes/value.c index f127b6b6..9b048f30 100644 --- a/ldap/servers/plugins/syntaxes/value.c +++ b/ldap/servers/plugins/syntaxes/value.c @@ -86,23 +86,40 @@ utf8isspace_fast( char* s ) ** Also note that this deviates from rfc 4517 INTEGER syntax, but we must ** support legacy clients for the time being */ +/* + * alt stores the normalized value in case the normalized value is longer + * than the original value. It may happen the value is DN. + */ void -value_normalize( +value_normalize_ext( char *s, int syntax, - int trim_spaces + int trim_spaces, + char **alt ) { char *head = s; char *d; int prevspace, curspace; + if (NULL == alt) { + return; + } + *alt = NULL; + if ( ! (syntax & SYNTAX_CIS) && ! (syntax & SYNTAX_CES) ) { return; } if ( syntax & SYNTAX_DN ) { - (void) slapi_dn_normalize_case( s ); + char *dest = NULL; + size_t dlen = 0; + int rc = slapi_dn_normalize_case_ext(s, 0, &dest, &dlen); + if (rc > 0) { + *alt = dest; + } else if (rc == 0) { /* normalized in line; not terminated */ + *(dest + dlen) = '\0'; + } return; } @@ -203,6 +220,16 @@ value_normalize( } } +void +value_normalize( + char *s, + int syntax, + int trim_spaces +) +{ + /* deprecated */ +} + int value_cmp( struct berval *v1, @@ -220,6 +247,7 @@ value_cmp( int free_v1 = 0; int free_v2 = 0; int v1sign = 1, v2sign = 1; /* default to positive */ + char *alt = NULL; /* This code used to call malloc up to four times in the copying * of attributes to be normalized. Now we attempt to keep everything @@ -233,13 +261,35 @@ value_cmp( bvcopy1.bv_val = &little_buffer[buffer_offset]; bvcopy1.bv_val[v1->bv_len] = '\0'; v1 = &bvcopy1; - buffer_space-= v1->bv_len+1; - buffer_offset+= v1->bv_len+1; } else { v1 = ber_bvdup( v1 ); free_v1 = 1; } - value_normalize( v1->bv_val, syntax, 1 /* trim leading blanks */ ); + value_normalize_ext( v1->bv_val, syntax, + 1 /* trim leading blanks */, &alt ); + if (alt) { + if (free_v1) { + slapi_ch_free_string(&v1->bv_val); + v1->bv_val = alt; + v1->bv_len = strlen(alt); + } else { + if (strlen(alt) < buffer_space) { + v1->bv_len = strlen(alt); + /* Copying to little_buffer */ + SAFEMEMCPY(v1->bv_val, alt, v1->bv_len); + *(v1->bv_val + v1->bv_len) = '\0'; + } else { + free_v1 = 1; + v1 = (struct berval *)slapi_ch_malloc(sizeof(struct berval)); + v1->bv_val = alt; + v1->bv_len = strlen(alt); + } + } + } + if (!free_v1) { + buffer_space -= v1->bv_len + 1; + buffer_offset += v1->bv_len + 1; + } } if ( normalize & 2 ) { /* Do we have space in the little buffer ? */ @@ -249,13 +299,35 @@ value_cmp( bvcopy2.bv_val = &little_buffer[buffer_offset]; bvcopy2.bv_val[v2->bv_len] = '\0'; v2 = &bvcopy2; - buffer_space-= v2->bv_len+1; - buffer_offset+= v2->bv_len+1; } else { v2 = ber_bvdup( v2 ); free_v2 = 1; } - value_normalize( v2->bv_val, syntax, 1 /* trim leading blanks */ ); + value_normalize_ext( v2->bv_val, syntax, + 1 /* trim leading blanks */, &alt ); + if (alt) { + if (free_v2) { + slapi_ch_free_string(&v2->bv_val); + v2->bv_val = alt; + v2->bv_len = strlen(alt); + } else { + if (strlen(alt) < buffer_space) { + v2->bv_len = strlen(alt); + /* Copying to little_buffer */ + SAFEMEMCPY(v2->bv_val, alt, v2->bv_len); + *(v2->bv_val + v2->bv_len) = '\0'; + } else { + free_v2 = 1; + v2 = (struct berval *)slapi_ch_malloc(sizeof(struct berval)); + v2->bv_val = alt; + v2->bv_len = strlen(alt); + } + } + } + if (!free_v2) { + buffer_space -= v2->bv_len + 1; + buffer_offset += v2->bv_len + 1; + } } if (syntax & SYNTAX_INT) { diff --git a/ldap/servers/plugins/usn/usn_cleanup.c b/ldap/servers/plugins/usn/usn_cleanup.c index bf13073a..1c92a5a1 100644 --- a/ldap/servers/plugins/usn/usn_cleanup.c +++ b/ldap/servers/plugins/usn/usn_cleanup.c @@ -194,8 +194,15 @@ _usn_cleanup_is_mmr_enabled(const char *suffix) char *base_dn = NULL; int rc = 0; /* disabled, by default */ - base_dn = slapi_ch_smprintf("cn=replica,cn=\"%s\",%s", - suffix, MAPPING_TREE_BASE_DN); + /* This function converts the old style DN to the new one */ + base_dn = slapi_create_dn_string("cn=replica,cn=\"%s\",%s", + suffix, MAPPING_TREE_BASE_DN); + if (NULL == base_dn) { + slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM, + "_usn_cleanup_is_mmr_enabled: failed to normalize " + "mappingtree dn for %s\n", suffix); + return 1; + } search_pb = slapi_pblock_new(); slapi_search_internal_set_pb(search_pb, base_dn, LDAP_SCOPE_ONELEVEL, "objectclass=nsDS5ReplicationAgreement", diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c index 1a1f8673..0e7d5c83 100644 --- a/ldap/servers/slapd/add.c +++ b/ldap/servers/slapd/add.c @@ -115,20 +115,47 @@ do_add( Slapi_PBlock *pb ) */ /* get the name */ { - char *dn = NULL; - if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) { - slapi_ch_free_string(&dn); - LDAPDebug( LDAP_DEBUG_ANY, - "ber_scanf failed (op=Add; params=DN)\n", 0, 0, 0 ); + char *rawdn = NULL; + char *dn = NULL; + size_t dnlen = 0; + if ( ber_scanf( ber, "{a", &rawdn ) == LBER_ERROR ) { + slapi_ch_free_string(&rawdn); + LDAPDebug( LDAP_DEBUG_ANY, + "ber_scanf failed (op=Add; params=DN)\n", 0, 0, 0 ); op_shared_log_error_access (pb, "ADD", "???", "decoding error"); - send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, - "decoding error", 0, NULL ); - return; - } - e = slapi_entry_alloc(); - slapi_entry_init(e,dn,NULL); /* Responsibility for DN is passed to the Entry. */ - } - LDAPDebug( LDAP_DEBUG_ARGS, " do_add: dn (%s)\n", slapi_entry_get_dn_const(e), 0, 0 ); + send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, + "decoding error", 0, NULL ); + return; + } + /* Check if we should be performing strict validation. */ + if (config_get_dn_validate_strict()) { + /* check that the dn is formatted correctly */ + rc = slapi_dn_syntax_check(pb, rawdn, 1); + if (rc) { /* syntax check failed */ + op_shared_log_error_access(pb, "ADD", rawdn?rawdn:"", + "strict: invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free_string(&rawdn); + return; + } + } + rc = slapi_dn_normalize_ext(rawdn, 0, &dn, &dnlen); + if (rc < 0) { + op_shared_log_error_access(pb, "ADD", rawdn?rawdn:"", "invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free_string(&rawdn); + return; + } else if (rc > 0) { + slapi_ch_free_string(&rawdn); + } else { /* rc == 0; rawdn is passed in; not null terminated */ + *(dn + dnlen) = '\0'; + } + e = slapi_entry_alloc(); + slapi_entry_init(e,dn,NULL); /* Responsibility for DN is passed to the Entry. */ + } + LDAPDebug( LDAP_DEBUG_ARGS, " do_add: dn (%s)\n", slapi_entry_get_dn_const(e), 0, 0 ); /* get the attrs */ for ( tag = ber_first_element( ber, &len, &last ); diff --git a/ldap/servers/slapd/attrlist.c b/ldap/servers/slapd/attrlist.c index b200472b..9c329902 100644 --- a/ldap/servers/slapd/attrlist.c +++ b/ldap/servers/slapd/attrlist.c @@ -289,6 +289,9 @@ int attrlist_replace(Slapi_Attr **alist, const char *type, struct berval **vals) } else { attrlist_find_or_create(alist, type, &a); valuearray_init_bervalarray(vals, &values); + if (slapi_attr_is_dn_syntax_attr(*a)) { + valuearray_normalize_value(values); + } rc = attr_replace(*a, values); } return rc; @@ -312,6 +315,9 @@ int attrlist_replace_with_flags(Slapi_Attr **alist, const char *type, struct ber } else { attrlist_find_or_create(alist, type, &a); valuearray_init_bervalarray_with_flags(vals, &values, flags); + if (slapi_attr_is_dn_syntax_attr(*a)) { + valuearray_normalize_value(values); + } rc = attr_replace(*a, values); } return rc; diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c index 698c1cd9..65f3bb02 100644 --- a/ldap/servers/slapd/attrsyntax.c +++ b/ldap/servers/slapd/attrsyntax.c @@ -819,6 +819,23 @@ slapi_attr_get_syntax_oid_copy( const Slapi_Attr *a, char **oidp ) } } +int +slapi_attr_is_dn_syntax_attr(Slapi_Attr *attr) +{ + char *syntaxoid = NULL; + int dn_syntax = 0; /* not DN, by default */ + + if (attr->a_plugin) { /* If not set, there is no way to get the info */ + slapi_attr_get_syntax_oid_copy(attr, &syntaxoid); + if (syntaxoid) { + dn_syntax = ((0 == strcmp(syntaxoid, NAMEANDOPTIONALUID_SYNTAX_OID)) + || (0 == strcmp(syntaxoid, DN_SYNTAX_OID))); + slapi_ch_free_string(&syntaxoid); + } + } + return dn_syntax; +} + #ifdef ATTR_LDAP_DEBUG PRIntn diff --git a/ldap/servers/slapd/auth.c b/ldap/servers/slapd/auth.c index 3a500eb7..e483f6e9 100644 --- a/ldap/servers/slapd/auth.c +++ b/ldap/servers/slapd/auth.c @@ -75,15 +75,33 @@ slapu_msgfree( LDAP* ld, LDAPMessage* msg ) } static int LDAP_CALL LDAP_CALLBACK -slapu_search_s( LDAP* ld, const char* baseDN, int scope, const char* filter, +slapu_search_s( LDAP* ld, const char* rawbaseDN, int scope, const char* filter, char** attrs, int attrsonly, LDAPMessage** result ) { int err = LDAP_NO_SUCH_OBJECT; - Slapi_PBlock* pb; + Slapi_PBlock* pb = NULL; LDAPControl **ctrls; + char *baseDN = slapi_ch_strdup(rawbaseDN); + char *normDN = NULL; + size_t dnlen = 0; + + err = slapi_dn_normalize_ext(baseDN, 0, &normDN, &dnlen); + if (err < 0) { + err = LDAP_INVALID_DN_SYNTAX; + LDAPDebug (LDAP_DEBUG_TRACE, "<= slapu_search_s %i\n", err, 0, 0); + return err; + } else if (err == 0) { /* baseDN is passed in; not terminated */ + *(normDN + dnlen) = '\0'; + } else { + slapi_ch_free_string(&baseDN); + baseDN = normDN; + } if (ld != internal_ld) { - return ldap_search_ext_s (ld, baseDN, scope, filter, attrs, attrsonly, NULL, NULL, NULL, -1, result); + err = ldap_search_ext_s(ld, baseDN, scope, filter, attrs, attrsonly, + NULL, NULL, NULL, -1, result); + slapi_ch_free_string(&baseDN); + return err; } LDAPDebug (LDAP_DEBUG_TRACE, "=> slapu_search_s (\"%s\", %i, %s)\n", baseDN, scope, filter); @@ -120,6 +138,7 @@ slapu_search_s( LDAP* ld, const char* baseDN, int scope, const char* filter, LDAPDebug (LDAP_DEBUG_ANY, "slapi_search_internal (\"%s\", %i, %s) NULL\n", escape_string( (char*)baseDN, ebuf ), scope, escape_string( (char*)filter, fbuf )); } + slapi_ch_free_string(&baseDN); *result = (LDAPMessage*)pb; LDAPDebug (LDAP_DEBUG_TRACE, "<= slapu_search_s %i\n", err, 0, 0); return err; @@ -486,8 +505,8 @@ handle_handshake_done (PRFileDesc *prfd, void* clientData) if (err == LDAPU_SUCCESS && chain) { LDAPMessage* entry = slapu_first_entry (internal_ld, chain); if (entry) { + /* clientDN is duplicated in slapu_get_dn */ clientDN = slapu_get_dn (internal_ld, entry); - if (clientDN) slapi_dn_normalize (clientDN); } else { extraErrorMsg = "no entry"; @@ -507,12 +526,27 @@ handle_handshake_done (PRFileDesc *prfd, void* clientData) if (clientDN != NULL) { char ebuf[ BUFSIZ ]; - slapi_log_access (LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " SSL client bound as %s\n", - conn->c_connid, escape_string( clientDN, ebuf )); + int rc = 0; + char *normedDN = NULL; + size_t dnlen = 0; + + rc = slapi_dn_normalize_ext(clientDN, 0, &normedDN, &dnlen); + if (rc < 0) { + /* ignoring the normalization error, use the pre normalized DN */ + } else if (rc == 0) { /* clientDN is passed in; not terminated */ + *(normedDN + dnlen) = '\0'; + } else { + slapi_ch_free_string(&clientDN); + clientDN = normedDN; + } + slapi_log_access (LDAP_DEBUG_STATS, + "conn=%" NSPRIu64 " SSL client bound as %s\n", + conn->c_connid, escape_string( clientDN, ebuf )); } else if (clientCert != NULL) { slapi_log_access (LDAP_DEBUG_STATS, - "conn=%" NSPRIu64 " SSL failed to map client certificate to LDAP DN (%s)\n", - conn->c_connid, extraErrorMsg ); + "conn=%" NSPRIu64 " SSL failed to map client " + "certificate to LDAP DN (%s)\n", + conn->c_connid, extraErrorMsg ); } /* diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c index 6cc1b66c..264eb90b 100644 --- a/ldap/servers/slapd/back-ldbm/import-threads.c +++ b/ldap/servers/slapd/back-ldbm/import-threads.c @@ -533,6 +533,7 @@ import_producer(void *param) FREE(estr); continue; } + /* get_value_from_string decodes base64 if it is encoded. */ rc = get_value_from_string((const char *)estr, "dn", &dn); if (rc) { import_log_notice(job, "WARNING: skipping bad LDIF entry (dn " diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c index 67176746..6600f008 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c @@ -142,13 +142,25 @@ attrcrypt_keymgmt_get_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEY { int ret = 0; Slapi_Entry *entry = NULL; - char *dn_template = "cn=%s,cn=encrypted attribute keys,cn=%s,cn=ldbm database,cn=plugins,cn=config"; + char *dn_template = "cn=%s,cn=encrypted attribute keys,cn=%s,cn=%s,cn=plugins,cn=config"; char *instance_name = li->inst_name; - char *dn_string = NULL; Slapi_Attr *keyattr = NULL; + char *dn_string = NULL; LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_keymgmt_get_key\n", 0, 0, 0); - dn_string = slapi_ch_smprintf(dn_template, acs->ace->cipher_display_name, instance_name); + dn_string = slapi_create_dn_string(dn_template, + acs->ace->cipher_display_name, instance_name, + li->inst_li->li_plugin->plg_name); + if (NULL == dn_string) { + LDAPDebug(LDAP_DEBUG_ANY, + "attrcrypt_keymgmt_get_key: " + "failed create attrcrypt key dn for plugin %s, " + "instance %s, cypher %s\n", + li->inst_li->li_plugin->plg_name, + li->inst_name, acs->ace->cipher_display_name); + ret = -1; + goto bail; + } /* Fetch the entry */ getConfigEntry(dn_string, &entry); /* Did we find the entry ? */ @@ -170,6 +182,7 @@ attrcrypt_keymgmt_get_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEY } else { ret = -2; /* Means: we didn't find the entry (which happens if the key has never been generated) */ } +bail: slapi_ch_free_string(&dn_string); LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_keymgmt_get_key\n", 0, 0, 0); return ret; diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.c b/ldap/servers/slapd/back-ldbm/ldbm_config.c index 60c3928b..ecef74bc 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_config.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_config.c @@ -1047,7 +1047,7 @@ static int ldbm_config_entryrdn_switch_set(void *arg, void *value, if (apply) { entryrdn_set_switch((int)((uintptr_t)value)); } - return LDAP_SUCCESS; + return LDAP_SUCCESS; } static void *ldbm_config_entryrdn_noancestorid_get(void *arg) @@ -1061,7 +1061,7 @@ static int ldbm_config_entryrdn_noancestorid_set(void *arg, void *value, if (apply) { entryrdn_set_noancestorid((int)((uintptr_t)value)); } - return LDAP_SUCCESS; + return LDAP_SUCCESS; } static void *ldbm_config_legacy_errcode_get(void *arg) @@ -1296,11 +1296,17 @@ void ldbm_config_read_instance_entries(struct ldbminfo *li, const char *backend_type) { Slapi_PBlock *tmp_pb; - char basedn[BUFSIZ]; Slapi_Entry **entries = NULL; + char *basedn = NULL; /* Construct the base dn of the subtree that holds the instance entries. */ - PR_snprintf(basedn, BUFSIZ, "cn=%s, cn=plugins, cn=config", backend_type); + basedn = slapi_create_dn_string("cn=%s,cn=plugins,cn=config", backend_type); + if (NULL == basedn) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "ldbm_config_read_instance_entries: " + "failed create backend dn for %s\n", backend_type); + return; + } /* Do a search of the subtree containing the instance entries */ tmp_pb = slapi_pblock_new(); @@ -1327,29 +1333,38 @@ int ldbm_config_load_dse_info(struct ldbminfo *li) { Slapi_PBlock *search_pb; Slapi_Entry **entries = NULL; - int res; - char dn[BUFSIZ]; + char *dn = NULL; + int rval = 0; /* We try to read the entry * cn=config, cn=ldbm database, cn=plugins, cn=config. If the entry is * there, then we process the config information it stores. */ - PR_snprintf(dn, BUFSIZ, "cn=config, cn=%s, cn=plugins, cn=config", - li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=config,cn=%s,cn=plugins,cn=config", + li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "ldbm_config_load_dse_info: " + "failed create config dn for %s\n", + li->li_plugin->plg_name); + rval = 1; + goto bail; + } search_pb = slapi_pblock_new(); slapi_search_internal_set_pb(search_pb, dn, LDAP_SCOPE_BASE, "objectclass=*", NULL, 0, NULL, NULL, li->li_identity, 0); slapi_search_internal_pb (search_pb); - slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res); + slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rval); - if (LDAP_NO_SUCH_OBJECT == res) { + if (LDAP_NO_SUCH_OBJECT == rval) { /* Add skeleten dse entries for the ldbm plugin */ ldbm_config_add_dse_entries(li, ldbm_skeleton_entries, li->li_plugin->plg_name, NULL, NULL, 0); - } else if (res != LDAP_SUCCESS) { + } else if (rval != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "Error accessing the ldbm config DSE\n", 0, 0, 0); - return 1; + rval = 1; + goto bail; } else { /* Need to parse the configuration information for the ldbm * plugin that is held in the DSE. */ @@ -1358,12 +1373,14 @@ int ldbm_config_load_dse_info(struct ldbminfo *li) if (NULL == entries || entries[0] == NULL) { LDAPDebug(LDAP_DEBUG_ANY, "Error accessing the ldbm config DSE\n", 0, 0, 0); - return 1; + rval = 1; + goto bail; } if (0 != parse_ldbm_config_entry(li, entries[0], ldbm_config)) { LDAPDebug(LDAP_DEBUG_ANY, "Error parsing the ldbm config DSE\n", 0, 0, 0); - return 1; + rval = 1; + goto bail; } } @@ -1377,8 +1394,6 @@ int ldbm_config_load_dse_info(struct ldbminfo *li) ldbm_config_read_instance_entries(li, li->li_plugin->plg_name); /* setup the dse callback functions for the ldbm backend config entry */ - PR_snprintf(dn, BUFSIZ, "cn=config, cn=%s, cn=plugins, cn=config", - li->li_plugin->plg_name); slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_config_search_entry_callback, (void *) li); @@ -1388,24 +1403,52 @@ int ldbm_config_load_dse_info(struct ldbminfo *li) slapi_config_register_callback(DSE_OPERATION_WRITE, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_config_search_entry_callback, (void *) li); + slapi_ch_free_string(&dn); /* setup the dse callback functions for the ldbm backend monitor entry */ - PR_snprintf(dn, BUFSIZ, "cn=monitor, cn=%s, cn=plugins, cn=config", - li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=monitor,cn=%s,cn=plugins,cn=config", + li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "ldbm_config_load_dse_info: " + "failed create monitor dn for %s\n", + li->li_plugin->plg_name); + rval = 1; + goto bail; + } slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_back_monitor_search, (void *)li); + slapi_ch_free_string(&dn); /* And the ldbm backend database monitor entry */ - PR_snprintf(dn, BUFSIZ, "cn=database, cn=monitor, cn=%s, cn=plugins, cn=config", - li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=database,cn=monitor,cn=%s,cn=plugins,cn=config", + li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "ldbm_config_load_dse_info: " + "failed create monitor database dn for %s\n", + li->li_plugin->plg_name); + rval = 1; + goto bail; + } slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_back_dbmonitor_search, (void *)li); + slapi_ch_free_string(&dn); /* setup the dse callback functions for the ldbm backend instance * entries */ - PR_snprintf(dn, BUFSIZ, "cn=%s, cn=plugins, cn=config", li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=%s,cn=plugins,cn=config", + li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "ldbm_config_load_dse_info: " + "failed create plugin dn for %s\n", + li->li_plugin->plg_name); + rval = 1; + goto bail; + } slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, "(objectclass=nsBackendInstance)", ldbm_instance_add_instance_entry_callback, (void *) li); @@ -1418,8 +1461,9 @@ int ldbm_config_load_dse_info(struct ldbminfo *li) slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_POSTOP, dn, LDAP_SCOPE_SUBTREE, "(objectclass=nsBackendInstance)", ldbm_instance_post_delete_instance_entry_callback, (void *) li); - - return 0; +bail: + slapi_ch_free_string(&dn); + return rval; } diff --git a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c index 9dc0f98d..503c0fc6 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c @@ -622,6 +622,7 @@ int ldbm_instance_config_add_index_entry( char tmpIndexesStr[256]; char tmpMatchingRulesStr[1024]; struct ldbminfo *li = inst->inst_li; + char *dn = NULL; if ((argc < 2) || (NULL == argv) || (NULL == argv[0]) || (NULL == argv[1])) { @@ -642,31 +643,42 @@ int ldbm_instance_config_add_index_entry( { if('\0' == attrs[i][0]) continue; basetype = slapi_attr_basetype(attrs[i], NULL, 0); + dn = slapi_create_dn_string("cn=%s,cn=index,cn=%s,cn=%s,cn=plugins,cn=config", + basetype, inst->inst_name, li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug(LDAP_DEBUG_ANY, + "ldbm_instance_config_add_index_entry: " + "failed create index dn with type %s for plugin %s, " + "instance %s\n", + basetype, inst->inst_li->li_plugin->plg_name, + inst->inst_name); + return -1; + } eBuf = PR_smprintf( - "dn: cn=%s, cn=index, cn=%s, cn=%s, cn=plugins, cn=config\n" - "objectclass:top\n" - "objectclass:nsIndex\n" - "cn:%s\n" - "nsSystemIndex:%s\n", - basetype, inst->inst_name, li->li_plugin->plg_name, - basetype, + "dn: %s\n" + "objectclass: top\n" + "objectclass: nsIndex\n" + "cn: %s\n" + "nsSystemIndex: %s\n", + dn, basetype, (ldbm_attribute_always_indexed(basetype)?"true":"false")); + slapi_ch_free_string(&dn); for(j=0; indexes[j] != NULL; j++) { - eBuf = PR_sprintf_append(eBuf, "nsIndexType:%s\n", indexes[j]); + eBuf = PR_sprintf_append(eBuf, "nsIndexType:%s\n", indexes[j]); } if((argc>2)&&(argv[2])) { for(j=0; matchingRules[j] != NULL; j++) { - eBuf = PR_sprintf_append(eBuf, "nsMatchingRule:%s\n", matchingRules[j]); + eBuf = PR_sprintf_append(eBuf, "nsMatchingRule:%s\n", matchingRules[j]); } } ldbm_config_add_dse_entry(li, eBuf, flags); - if (eBuf) { - PR_smprintf_free(eBuf); - } + if (eBuf) { + PR_smprintf_free(eBuf); + } slapi_ch_free((void**)&basetype); } @@ -722,10 +734,10 @@ int ldbm_instance_create_default_user_indexes(ldbm_instance *inst) Slapi_Value *sval = NULL; const struct berval *attrValue; char *argv[ 8 ]; - char basedn[BUFSIZ]; char tmpBuf[MAX_TMPBUF]; char tmpBuf2[MAX_TMPBUF]; int argc; + char *basedn = NULL; struct ldbminfo *li; @@ -742,8 +754,15 @@ int ldbm_instance_create_default_user_indexes(ldbm_instance *inst) strcpy(tmpBuf,""); /* Construct the base dn of the subtree that holds the default user indexes. */ - PR_snprintf(basedn, BUFSIZ, "cn=default indexes, cn=config, cn=%s, cn=plugins, cn=config", - li->li_plugin->plg_name); + basedn = slapi_create_dn_string("cn=default indexes,cn=config,cn=%s,cn=plugins,cn=config", + li->li_plugin->plg_name); + if (NULL == basedn) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "ldbm_instance_create_default_user_indexes: " + "failed create default index dn for plugin %s\n", + inst->inst_li->li_plugin->plg_name); + return -1; + } /* Do a search of the subtree containing the index entries */ aPb = slapi_pblock_new(); @@ -821,5 +840,6 @@ int ldbm_instance_create_default_user_indexes(ldbm_instance *inst) slapi_free_search_results_internal(aPb); slapi_pblock_destroy(aPb); + slapi_ch_free_string(&basedn); return 0; } diff --git a/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c b/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c index f20836b4..a6b11668 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c @@ -336,13 +336,20 @@ read_instance_index_entries(ldbm_instance *inst) { Slapi_PBlock *tmp_pb; int scope = LDAP_SCOPE_SUBTREE; - char basedn[BUFSIZ]; const char *searchfilter = "(objectclass=nsIndex)"; + char *basedn = NULL; /* Construct the base dn of the subtree that holds the index entries * for this instance. */ - PR_snprintf(basedn, BUFSIZ, "cn=index, cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, inst->inst_li->li_plugin->plg_name); + basedn = slapi_create_dn_string("cn=index,cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, inst->inst_li->li_plugin->plg_name); + if (NULL == basedn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "read_instance_index_entries: " + "failed create index dn for plugin %s, instance %s\n", + inst->inst_li->li_plugin->plg_name, inst->inst_name); + return 1; + } /* Set up a tmp callback that will handle the init for each index entry */ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, @@ -361,6 +368,7 @@ read_instance_index_entries(ldbm_instance *inst) slapi_free_search_results_internal(tmp_pb); slapi_pblock_destroy(tmp_pb); + slapi_ch_free_string(&basedn); return 0; } @@ -372,13 +380,21 @@ read_instance_attrcrypt_entries(ldbm_instance *inst) { Slapi_PBlock *tmp_pb; int scope = LDAP_SCOPE_SUBTREE; - char basedn[BUFSIZ]; const char *searchfilter = ldbm_instance_attrcrypt_filter; + char *basedn = NULL; /* Construct the base dn of the subtree that holds the index entries * for this instance. */ - PR_snprintf(basedn, BUFSIZ, "cn=encrypted attributes, cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, inst->inst_li->li_plugin->plg_name); + basedn = slapi_create_dn_string("cn=encrypted attributes,cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, inst->inst_li->li_plugin->plg_name); + if (NULL == basedn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "read_instance_attrcrypt_entries: " + "failed create encrypted attributes dn for plugin %s, " + "instance %s\n", + inst->inst_li->li_plugin->plg_name, inst->inst_name); + return 1; + } /* Set up a tmp callback that will handle the init for each index entry */ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, @@ -397,6 +413,7 @@ read_instance_attrcrypt_entries(ldbm_instance *inst) slapi_free_search_results_internal(tmp_pb); slapi_pblock_destroy(tmp_pb); + slapi_ch_free_string(&basedn); return 0; } @@ -427,10 +444,11 @@ parse_ldbm_instance_config_entry(ldbm_instance *inst, Slapi_Entry *e, config_inf Slapi_DN suffix; slapi_attr_first_value(attr, &sval); + bval = (struct berval *) slapi_value_get_berval(sval); slapi_sdn_init_dn_byref(&suffix, bval->bv_val); if (!slapi_be_issuffix(inst->inst_be, &suffix)) { - be_addsuffix(inst->inst_be, &suffix); + be_addsuffix(inst->inst_be, &suffix); } slapi_sdn_done(&suffix); continue; @@ -477,25 +495,34 @@ ldbm_instance_config_load_dse_info(ldbm_instance *inst) struct ldbminfo *li = inst->inst_li; Slapi_PBlock *search_pb; Slapi_Entry **entries = NULL; - int res; - char dn[BUFSIZ]; + char *dn = NULL; + int rval = 0; /* We try to read the entry * cn=instance_name, cn=ldbm database, cn=plugins, cn=config. If the * entry is there, then we process the config information it stores. */ - PR_snprintf(dn, BUFSIZ, "cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "ldbm_instance_config_load_dse_info: " + "failed create instance dn %s for plugin %s\n", + inst->inst_name, inst->inst_li->li_plugin->plg_name); + rval = 1; + goto bail; + } search_pb = slapi_pblock_new(); slapi_search_internal_set_pb(search_pb, dn, LDAP_SCOPE_BASE, "objectclass=*", NULL, 0, NULL, NULL, li->li_identity, 0); slapi_search_internal_pb (search_pb); - slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res); + slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rval); - if (res != LDAP_SUCCESS) { + if (rval != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "Error accessing the config DSE\n", 0, 0, 0); - return 1; + rval = 1; + goto bail; } else { /* Need to parse the configuration information for the ldbm * plugin that is held in the DSE. */ @@ -504,13 +531,15 @@ ldbm_instance_config_load_dse_info(ldbm_instance *inst) if ((!entries) || (!entries[0])) { LDAPDebug(LDAP_DEBUG_ANY, "Error accessing the config DSE\n", 0, 0, 0); - return 1; + rval = 1; + goto bail; } if (0 != parse_ldbm_instance_config_entry(inst, entries[0], ldbm_instance_config)) { LDAPDebug(LDAP_DEBUG_ANY, "Error parsing the config DSE\n", 0, 0, 0); - return 1; + rval = 1; + goto bail; } } @@ -527,8 +556,6 @@ ldbm_instance_config_load_dse_info(ldbm_instance *inst) inst->inst_name, 0); /* setup the dse callback functions for the ldbm instance config entry */ - PR_snprintf(dn, BUFSIZ, "cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, li->li_plugin->plg_name); slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_instance_search_config_entry_callback, (void *) inst); @@ -543,9 +570,20 @@ ldbm_instance_config_load_dse_info(ldbm_instance *inst) ldbm_instance_deny_config, (void *)inst); /* delete is handled by a callback set in ldbm_config.c */ + slapi_ch_free_string(&dn); + /* don't forget the monitor! */ - PR_snprintf(dn, BUFSIZ, "cn=monitor, cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=monitor,cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "ldbm_instance_config_load_dse_info: " + "failed create monitor instance dn for plugin %s, " + "instance %s\n", + inst->inst_li->li_plugin->plg_name, inst->inst_name); + rval = 1; + goto bail; + } /* make callback on search; deny add/modify/delete */ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_back_monitor_instance_search, @@ -557,10 +595,20 @@ ldbm_instance_config_load_dse_info(ldbm_instance *inst) LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_instance_deny_config, (void *)inst); /* delete is okay */ + slapi_ch_free_string(&dn); /* Callbacks to handle indexes */ - PR_snprintf(dn, BUFSIZ, "cn=index, cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=index,cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "ldbm_instance_config_load_dse_info: " + "failed create index instance dn for plugin %s, " + "instance %s\n", + inst->inst_li->li_plugin->plg_name, inst->inst_name); + rval = 1; + goto bail; + } slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)", ldbm_instance_index_config_add_callback, (void *) inst); @@ -570,10 +618,20 @@ ldbm_instance_config_load_dse_info(ldbm_instance *inst) slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)", ldbm_instance_index_config_modify_callback, (void *) inst); + slapi_ch_free_string(&dn); /* Callbacks to handle attribute encryption */ - PR_snprintf(dn, BUFSIZ, "cn=encrypted attributes, cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=encrypted attributes,cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "ldbm_instance_config_load_dse_info: " + "failed create encrypted attribute instance dn " + "for plugin %s, instance %s\n", + inst->inst_li->li_plugin->plg_name, inst->inst_name); + rval = 1; + goto bail; + } slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, ldbm_instance_attrcrypt_filter, ldbm_instance_attrcrypt_config_add_callback, (void *) inst); @@ -583,8 +641,10 @@ ldbm_instance_config_load_dse_info(ldbm_instance *inst) slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, ldbm_instance_attrcrypt_filter, ldbm_instance_attrcrypt_config_modify_callback, (void *) inst); - - return 0; + rval = 0; +bail: + slapi_ch_free_string(&dn); + return rval; } /* @@ -880,11 +940,19 @@ ldbm_instance_add_instance_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBe static void ldbm_instance_unregister_callbacks(ldbm_instance *inst) { struct ldbminfo *li = inst->inst_li; - char dn[BUFSIZ]; + char *dn = NULL; /* tear down callbacks for the instance config entry */ - PR_snprintf(dn, BUFSIZ, "cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "ldbm_instance_unregister_callbacks: " + "failed create instance dn for plugin %s, " + "instance %s\n", + inst->inst_li->li_plugin->plg_name, inst->inst_name); + goto bail; + } slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_instance_search_config_entry_callback); @@ -897,20 +965,38 @@ static void ldbm_instance_unregister_callbacks(ldbm_instance *inst) slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_instance_deny_config); + slapi_ch_free_string(&dn); /* now the cn=monitor entry */ - PR_snprintf(dn, BUFSIZ, "cn=monitor, cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=monitor,cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "ldbm_instance_unregister_callbacks: " + "failed create monitor instance dn for plugin %s, " + "instance %s\n", + inst->inst_li->li_plugin->plg_name, inst->inst_name); + goto bail; + } slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_back_monitor_instance_search); slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)", ldbm_instance_deny_config); slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn, LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_instance_deny_config); + slapi_ch_free_string(&dn); /* now the cn=index entries */ - PR_snprintf(dn, BUFSIZ, "cn=index, cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=index,cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "ldbm_instance_unregister_callbacks: " + "failed create index dn for plugin %s, " + "instance %s\n", + inst->inst_li->li_plugin->plg_name, inst->inst_name); + goto bail; + } slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)", ldbm_instance_index_config_add_callback); @@ -920,10 +1006,19 @@ static void ldbm_instance_unregister_callbacks(ldbm_instance *inst) slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)", ldbm_instance_index_config_modify_callback); + slapi_ch_free_string(&dn); /* now the cn=encrypted attributes entries */ - PR_snprintf(dn, BUFSIZ, "cn=encrypted attributes, cn=%s, cn=%s, cn=plugins, cn=config", - inst->inst_name, li->li_plugin->plg_name); + dn = slapi_create_dn_string("cn=encrypted attributes,cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, li->li_plugin->plg_name); + if (NULL == dn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "ldbm_instance_unregister_callbacks: " + "failed create encrypted attributes dn for plugin %s, " + "instance %s\n", + inst->inst_li->li_plugin->plg_name, inst->inst_name); + goto bail; + } slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, ldbm_instance_attrcrypt_filter, ldbm_instance_attrcrypt_config_add_callback); @@ -935,6 +1030,8 @@ static void ldbm_instance_unregister_callbacks(ldbm_instance *inst) ldbm_instance_attrcrypt_config_modify_callback); vlv_remove_callbacks(inst); +bail: + slapi_ch_free_string(&dn); } diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c index 6d0a440b..d30a3b93 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c @@ -277,13 +277,6 @@ ldbm_back_modrdn( Slapi_PBlock *pb ) /* find and lock the entry we are about to modify */ done_with_pblock_entry(pb,SLAPI_MODRDN_TARGET_ENTRY); /* Could be through this multiple times */ slapi_pblock_get (pb, SLAPI_TARGET_ADDRESS, &old_addr); - ldap_result_code = slapi_dn_syntax_check(pb, old_addr->dn, 1); - if (ldap_result_code) - { - ldap_result_code = LDAP_INVALID_DN_SYNTAX; - slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); - goto error_return; - } ldap_result_code= get_copy_of_entry(pb, old_addr, &txn, SLAPI_MODRDN_TARGET_ENTRY, !is_replicated_operation); if(ldap_result_code==LDAP_OPERATIONS_ERROR || ldap_result_code==LDAP_INVALID_DN_SYNTAX) diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c index 2ca6ad45..db1bd926 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_search.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c @@ -242,6 +242,7 @@ ldbm_back_search( Slapi_PBlock *pb ) dummyAttrs[0] = dummyAttr; + /* This dn is normalized. */ PR_snprintf(dn,sizeof(dn),"dn: oid=%s,cn=features,cn=config",LDAP_CONTROL_VLVREQUEST); feature= slapi_str2entry(dn,0); r= plugin_call_acl_plugin (pb, feature, dummyAttrs, NULL, SLAPI_ACL_READ, ACLPLUGIN_ACCESS_DEFAULT, NULL); diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c index b913d682..60b72db2 100644 --- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c +++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c @@ -619,6 +619,7 @@ int ldbm_back_ldif2ldbm( Slapi_PBlock *pb ) if (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) { /* initialize UniqueID generator - must be done once backends are started and event queue is initialized but before plugins are started */ + /* This dn is normalize. */ Slapi_DN *sdn = slapi_sdn_new_dn_byval ("cn=uniqueid generator,cn=config"); int rc = uniqueIDGenInit (NULL, sdn, 0 /* use single thread mode */); slapi_sdn_free (&sdn); diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c index 802370b9..759e37f3 100644 --- a/ldap/servers/slapd/back-ldbm/misc.c +++ b/ldap/servers/slapd/back-ldbm/misc.c @@ -143,7 +143,7 @@ compute_entry_tombstone_dn(const char *entrydn, const char *uniqueid) PR_ASSERT(NULL != entrydn); PR_ASSERT(NULL != uniqueid); - tombstone_dn = slapi_ch_smprintf("%s=%s, %s", + tombstone_dn = slapi_ch_smprintf("%s=%s,%s", SLAPI_ATTR_UNIQUEID, uniqueid, entrydn); @@ -158,7 +158,7 @@ compute_entry_tombstone_rdn(const char *entryrdn, const char *uniqueid) PR_ASSERT(NULL != entryrdn); PR_ASSERT(NULL != uniqueid); - tombstone_rdn = slapi_ch_smprintf("%s=%s, %s", + tombstone_rdn = slapi_ch_smprintf("%s=%s,%s", SLAPI_ATTR_UNIQUEID, uniqueid, entryrdn); diff --git a/ldap/servers/slapd/back-ldbm/nextid.c b/ldap/servers/slapd/back-ldbm/nextid.c index 6e8f6316..02d381b6 100644 --- a/ldap/servers/slapd/back-ldbm/nextid.c +++ b/ldap/servers/slapd/back-ldbm/nextid.c @@ -214,7 +214,7 @@ get_ids_from_disk(backend *be) void id_internal_to_stored(ID i,char *b) { if ( sizeof(ID) > 4 ) { - memset (b+4, 0, sizeof(ID)-4); + (void)memset (b+4, 0, sizeof(ID)-4); } b[0] = (char)(i >> 24); diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c index 2402017d..2f2cb48e 100644 --- a/ldap/servers/slapd/back-ldbm/vlv.c +++ b/ldap/servers/slapd/back-ldbm/vlv.c @@ -339,7 +339,7 @@ vlv_init(ldbm_instance *inst) /* The FE DSE *must* be initialised before we get here */ int return_value= LDAP_SUCCESS; int scope= LDAP_SCOPE_SUBTREE; - char *basedn, buf[512]; + char *basedn = NULL; const char *searchfilter = "(objectclass=vlvsearch)"; const char *indexfilter = "(objectclass=vlvindex)"; backend *be= inst->inst_be; @@ -368,9 +368,15 @@ vlv_init(ldbm_instance *inst) if (inst == NULL) { basedn = NULL; } else { - PR_snprintf(buf, sizeof(buf), "cn=%s,cn=%s,cn=plugins,cn=config", - inst->inst_name, inst->inst_li->li_plugin->plg_name); - basedn = buf; + basedn = slapi_create_dn_string("cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, inst->inst_li->li_plugin->plg_name); + if (NULL == basedn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "vlv_init: failed to create vlv dn for plugin %s, instance %s\n", + inst->inst_name, inst->inst_li->li_plugin->plg_name); + return_value = LDAP_PARAM_ERROR; + return return_value; + } } /* Find the VLV Search Entries */ @@ -405,6 +411,7 @@ vlv_init(ldbm_instance *inst) slapi_config_register_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_DeleteIndexEntry,(void*)inst); slapi_config_register_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifyRDNSearchEntry,(void*)inst); slapi_config_register_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyRDNIndexEntry,(void*)inst); + slapi_ch_free_string(&basedn); } return return_value; @@ -417,16 +424,22 @@ vlv_remove_callbacks(ldbm_instance *inst) { int return_value= LDAP_SUCCESS; int scope= LDAP_SCOPE_SUBTREE; - char *basedn, buf[512]; + char *basedn = NULL; const char *searchfilter = "(objectclass=vlvsearch)"; const char *indexfilter = "(objectclass=vlvindex)"; if (inst == NULL) { basedn = NULL; } else { - PR_snprintf(buf, sizeof(buf), "cn=%s,cn=%s,cn=plugins,cn=config", - inst->inst_name, inst->inst_li->li_plugin->plg_name); - basedn = buf; + basedn = slapi_create_dn_string("cn=%s,cn=%s,cn=plugins,cn=config", + inst->inst_name, inst->inst_li->li_plugin->plg_name); + if (NULL == basedn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "vlv_remove_callbacks: failed to create vlv dn for plugin %s, " + "instance %s\n", + inst->inst_name, inst->inst_li->li_plugin->plg_name); + return_value = LDAP_PARAM_ERROR; + } } if(basedn!=NULL) { @@ -439,8 +452,9 @@ vlv_remove_callbacks(ldbm_instance *inst) { slapi_config_remove_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_DeleteIndexEntry); slapi_config_remove_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifyRDNSearchEntry); slapi_config_remove_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyRDNIndexEntry); + slapi_ch_free_string(&basedn); } - return return_value; + return return_value; } /* Find an enabled index which matches this description. */ @@ -1980,17 +1994,13 @@ char *create_vlv_search_tag(const char* dn) { /* Builds strings from Slapi_DN similar console GUI. Uses those dns to delete vlvsearch's if they match. New write lock. */ - -#define LDBM_PLUGIN_ROOT ", cn=ldbm database, cn=plugins, cn=config" -#define TAG "cn=by MCC " - int vlv_delete_search_entry(Slapi_PBlock *pb, Slapi_Entry* e, ldbm_instance *inst) { int rc=0; Slapi_PBlock *tmppb; Slapi_DN *newdn; struct vlvSearch* p=NULL; - char *buf, *buf2, *tag1, *tag2; + char *base1 = NULL, *base2 = NULL, *tag1 = NULL, *tag2 = NULL; const char *dn= slapi_sdn_get_dn(&e->e_sdn); backend *be= NULL; if (NULL == inst) { @@ -2007,8 +2017,18 @@ int vlv_delete_search_entry(Slapi_PBlock *pb, Slapi_Entry* e, ldbm_instance *ins return LDAP_OPERATIONS_ERROR; } tag1=create_vlv_search_tag(dn); - buf=slapi_ch_smprintf("%s%s%s%s%s","cn=MCC ",tag1,", cn=",inst->inst_name,LDBM_PLUGIN_ROOT); - newdn=slapi_sdn_new_dn_byval(buf); + base1 = slapi_create_dn_string("cn=MCC %s,cn=%s,cn=%s,cn=plugins,cn=config", + tag1, inst->inst_name, inst->inst_li->li_plugin->plg_name); + if (NULL == base1) { + LDAPDebug(LDAP_DEBUG_ANY, + "vlv_delete_search_entry: " + "failed to craete vlv search entry dn (rdn: cn=MCC %s) for " + "plugin %s, instance %s\n", + tag1, inst->inst_li->li_plugin->plg_name, inst->inst_name); + rc = LDAP_PARAM_ERROR; + goto bail; + } + newdn = slapi_sdn_new_dn_byval(base1); /* vlvSearchList is modified; need Wlock */ PR_RWLock_Wlock(be->vlvSearchList_lock); p = vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, newdn); @@ -2016,37 +2036,49 @@ int vlv_delete_search_entry(Slapi_PBlock *pb, Slapi_Entry* e, ldbm_instance *ins { LDAPDebug( LDAP_DEBUG_ANY, "Deleted Virtual List View Search (%s).\n", p->vlv_name, 0, 0); tag2=create_vlv_search_tag(dn); - buf2=slapi_ch_smprintf("%s%s,%s",TAG,tag2,buf); + base2 = slapi_create_dn_string("cn=by MCC %s,%s", tag2, base1); + if (NULL == base2) { + LDAPDebug(LDAP_DEBUG_ANY, + "vlv_delete_search_entry: failed to create " + "vlv search entry dn (rdn: cn=by MCC %s) for " + "plugin %s, instance %s\n", + tag2, inst->inst_li->li_plugin->plg_name, inst->inst_name); + rc = LDAP_PARAM_ERROR; + slapi_ch_free((void **)&tag2); + PR_RWLock_Unlock(be->vlvSearchList_lock); + goto bail; + } vlvSearch_removefromlist((struct vlvSearch **)&be->vlvSearchList,p->vlv_dn); /* This line release lock to prevent recursive deadlock caused by slapi_internal_delete calling vlvDeleteSearchEntry */ PR_RWLock_Unlock(be->vlvSearchList_lock); vlvSearch_delete(&p); tmppb = slapi_pblock_new(); - slapi_delete_internal_set_pb(tmppb, buf2, NULL, NULL, + slapi_delete_internal_set_pb(tmppb, base2, NULL, NULL, (void *)plugin_get_default_component_id(), 0); slapi_delete_internal_pb(tmppb); slapi_pblock_get (tmppb, SLAPI_PLUGIN_INTOP_RESULT, &rc); if(rc != LDAP_SUCCESS) { - LDAPDebug(LDAP_DEBUG_ANY, "vlv_delete_search_entry:can't delete dse entry '%s'\n", buf2, 0, 0); + LDAPDebug(LDAP_DEBUG_ANY, "vlv_delete_search_entry:can't delete dse entry '%s'\n", base2, 0, 0); } pblock_done(tmppb); pblock_init(tmppb); - slapi_delete_internal_set_pb(tmppb, buf, NULL, NULL, + slapi_delete_internal_set_pb(tmppb, base1, NULL, NULL, (void *)plugin_get_default_component_id(), 0); slapi_delete_internal_pb(tmppb); slapi_pblock_get (tmppb, SLAPI_PLUGIN_INTOP_RESULT, &rc); if(rc != LDAP_SUCCESS) { - LDAPDebug(LDAP_DEBUG_ANY, "vlv_delete_search_entry:can't delete dse entry '%s'\n", buf, 0, 0); + LDAPDebug(LDAP_DEBUG_ANY, "vlv_delete_search_entry:can't delete dse entry '%s'\n", base1, 0, 0); } slapi_pblock_destroy(tmppb); slapi_ch_free((void **)&tag2); - slapi_ch_free((void **)&buf2); + slapi_ch_free((void **)&base2); } else { PR_RWLock_Unlock(be->vlvSearchList_lock); } +bail: instance_set_not_busy(inst); slapi_ch_free((void **)&tag1); - slapi_ch_free((void **)&buf); + slapi_ch_free((void **)&base1); slapi_sdn_free(&newdn); return rc; } diff --git a/ldap/servers/slapd/backend.c b/ldap/servers/slapd/backend.c index 4b2d9283..8784866b 100644 --- a/ldap/servers/slapd/backend.c +++ b/ldap/servers/slapd/backend.c @@ -47,18 +47,32 @@ void be_init( Slapi_Backend *be, const char *type, const char *name, int isprivate, int logchanges, int sizelimit, int timelimit ) { - char text[128]; slapdFrontendConfig_t *fecfg; be->be_suffix = NULL; be->be_suffixlock= PR_NewLock(); be->be_suffixcount= 0; /* e.g. dn: cn=config,cn=NetscapeRoot,cn=ldbm database,cn=plugins,cn=config */ - PR_snprintf(text, sizeof(text),"cn=%s,cn=%s,cn=plugins,cn=config", name, type); - be->be_basedn= slapi_ch_strdup(slapi_dn_normalize(text)); - PR_snprintf(text, sizeof(text), "cn=config,cn=%s,cn=%s,cn=plugins,cn=config", name, type); - be->be_configdn= slapi_ch_strdup(slapi_dn_normalize(text)); - PR_snprintf(text, sizeof(text), "cn=monitor,cn=%s,cn=%s,cn=plugins,cn=config", name, type); - be->be_monitordn= slapi_ch_strdup(slapi_dn_normalize(text)); + be->be_basedn = slapi_create_dn_string("cn=%s,cn=%s,cn=plugins,cn=config", + name, type); + if (NULL == be->be_basedn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "be_init: failed create instance dn for plugin %s, " + "instance %s\n", type, name); + } + be->be_configdn = slapi_create_dn_string("cn=config,cn=%s,cn=%s,cn=plugins,cn=config", + name, type); + if (NULL == be->be_configdn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "be_init: failed create instance config dn for " + "plugin %s, instance %s\n", type, name); + } + be->be_monitordn = slapi_create_dn_string("cn=monitor,cn=%s,cn=%s,cn=plugins,cn=config", + name, type); + if (NULL == be->be_configdn) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "be_init: failed create instance monitor dn for " + "plugin %s, instance %s\n", type, name); + } be->be_sizelimit = sizelimit; be->be_timelimit = timelimit; /* maximum group nesting level before giving up */ diff --git a/ldap/servers/slapd/backend_manager.c b/ldap/servers/slapd/backend_manager.c index 18184376..6456f299 100644 --- a/ldap/servers/slapd/backend_manager.c +++ b/ldap/servers/slapd/backend_manager.c @@ -423,12 +423,6 @@ be_nbackends_public() } /* backend instance management */ -/* JCM - These are hardcoded for the LDBM database */ -#define LDBM_CLASS_PREFIX "cn=ldbm database,cn=plugins,cn=config" -#define LDBM_CONFIG_ENTRY "cn=config,cn=ldbm database,cn=plugins,cn=config" -#define INSTANCE_ATTR "nsslapd-instance" -#define SUFFIX_ATTR "nsslapd-suffix" -#define CACHE_ATTR "nsslapd-cachememsize" void slapi_be_Rlock(Slapi_Backend * be) diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c index f0bdbae4..626494bc 100644 --- a/ldap/servers/slapd/bind.c +++ b/ldap/servers/slapd/bind.c @@ -123,6 +123,7 @@ do_bind( Slapi_PBlock *pb ) ber_int_t version = -1; int auth_response_requested = 0; int pw_response_requested = 0; + char *rawdn = NULL; char *dn = NULL, *saslmech = NULL; struct berval cred = {0}; Slapi_Backend *be = NULL; @@ -136,6 +137,7 @@ do_bind( Slapi_PBlock *pb ) int auto_bind = 0; int minssf = 0; char *test_bind_dn = NULL; + size_t dnlen = 0; LDAPDebug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 ); @@ -159,7 +161,7 @@ do_bind( Slapi_PBlock *pb ) * } */ - rc = ber_scanf( ber, "{iat", &version, &dn, &method ); + rc = ber_scanf( ber, "{iat", &version, &rawdn, &method ); if ( rc == LBER_ERROR ) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=Bind; params=Version,DN,Method)\n", @@ -167,11 +169,37 @@ do_bind( Slapi_PBlock *pb ) log_bind_access (pb, "???", method, version, saslmech, "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0, NULL ); - slapi_ch_free_string(&dn); + slapi_ch_free_string(&rawdn); return; } + /* Check if we should be performing strict validation. */ + if (config_get_dn_validate_strict()) { + /* check that the dn is formatted correctly */ + rc = slapi_dn_syntax_check(pb, rawdn, 1); + if (rc) { /* syntax check failed */ + op_shared_log_error_access(pb, "BIND", rawdn?rawdn:"", + "strict: invalid bind dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid bind dn", 0, NULL); + slapi_ch_free_string(&rawdn); + return; + } + } + rc = slapi_dn_normalize_ext(rawdn, 0, &dn, &dnlen); + if (rc < 0) { + op_shared_log_error_access(pb, "BIND", rawdn?rawdn:"", + "invalid bind dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid bind dn", 0, NULL); + slapi_ch_free_string(&rawdn); + return; + } else if (rc > 0) { /* if rc == 0, rawdn is passed in */ + slapi_ch_free_string(&rawdn); + } else { /* rc == 0; rawdn is passed in; not null terminated */ + *(dn + dnlen) = '\0'; + } - slapi_sdn_init_dn_passin(&sdn,dn); + slapi_sdn_init_dn_passin(&sdn, dn); LDAPDebug( LDAP_DEBUG_TRACE, "BIND dn=\"%s\" method=%d version=%d\n", dn, method, version ); diff --git a/ldap/servers/slapd/compare.c b/ldap/servers/slapd/compare.c index 5a0256ba..578d826a 100644 --- a/ldap/servers/slapd/compare.c +++ b/ldap/servers/slapd/compare.c @@ -65,7 +65,9 @@ void do_compare( Slapi_PBlock *pb ) { BerElement *ber = pb->pb_op->o_ber; + char *rawdn = NULL; char *dn = NULL; + size_t len = 0; struct ava ava = {0}; Slapi_Backend *be = NULL; int err; @@ -94,15 +96,40 @@ do_compare( Slapi_PBlock *pb ) * } */ - if ( ber_scanf( ber, "{a{ao}}", &dn, &ava.ava_type, + if ( ber_scanf( ber, "{a{ao}}", &rawdn, &ava.ava_type, &ava.ava_value ) == LBER_ERROR ) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=Compare; params=DN,Type,Value)\n", 0, 0, 0 ); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, - NULL ); + NULL ); goto free_and_return; } + /* Check if we should be performing strict validation. */ + if (config_get_dn_validate_strict()) { + /* check that the dn is formatted correctly */ + err = slapi_dn_syntax_check(pb, rawdn, 1); + if (err) { /* syntax check failed */ + op_shared_log_error_access(pb, "CMP", + rawdn?rawdn:"", "strict: invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free((void **) &rawdn); + return; + } + } + err = slapi_dn_normalize_ext(rawdn, 0, &dn, &len); + if (err < 0) { + op_shared_log_error_access(pb, "CMP", rawdn?rawdn:"", "invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free((void **) &rawdn); + return; + } else if (err > 0) { /* if rc == 0, rawdn is passed in */ + slapi_ch_free((void **) &rawdn); + } else { /* rc == 0; rawdn is passed in; not null terminated */ + *(dn + len) = '\0'; + } /* * in LDAPv3 there can be optional control extensions on * the end of an LDAPMessage. we need to read them in and diff --git a/ldap/servers/slapd/delete.c b/ldap/servers/slapd/delete.c index c17b669a..3a80eeba 100644 --- a/ldap/servers/slapd/delete.c +++ b/ldap/servers/slapd/delete.c @@ -71,8 +71,10 @@ do_delete( Slapi_PBlock *pb ) { Slapi_Operation *operation; BerElement *ber; + char *rawdn = NULL; char *dn = NULL; - int err; + size_t dnlen = 0; + int err = 0; LDAPDebug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 ); @@ -88,7 +90,7 @@ do_delete( Slapi_PBlock *pb ) * DelRequest := DistinguishedName */ - if ( ber_scanf( pb->pb_op->o_ber, "a", &dn ) == LBER_ERROR ) { + if ( ber_scanf( pb->pb_op->o_ber, "a", &rawdn ) == LBER_ERROR ) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=Delete; params=DN)\n", 0, 0, 0 ); op_shared_log_error_access (pb, "DEL", "???", "decoding error"); @@ -96,6 +98,31 @@ do_delete( Slapi_PBlock *pb ) NULL ); goto free_and_return; } + /* Check if we should be performing strict validation. */ + if (config_get_dn_validate_strict()) { + /* check that the dn is formatted correctly */ + err = slapi_dn_syntax_check(pb, rawdn, 1); + if (err) { /* syntax check failed */ + op_shared_log_error_access(pb, "DEL", rawdn?rawdn:"", + "strict: invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free_string(&rawdn); + goto free_and_return; + } + } + err = slapi_dn_normalize_ext(rawdn, 0, &dn, &dnlen); + if (err < 0) { + op_shared_log_error_access(pb, "DEL", "???", "invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free_string(&rawdn); + goto free_and_return; + } else if (err > 0) { /* if err == 0, rawdn is passed in */ + slapi_ch_free_string(&rawdn); + } else { /* err == 0; rawdn is passed in; not null terminated */ + *(dn + dnlen) = '\0'; + } /* * in LDAPv3 there can be optional control extensions on diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c index f9c22589..743aa361 100644 --- a/ldap/servers/slapd/dn.c +++ b/ldap/servers/slapd/dn.c @@ -57,9 +57,9 @@ static void add_rdn_av( char *avstart, char *avend, int *rdn_av_countp, struct berval **rdn_avsp, struct berval *avstack ); static void reset_rdn_avs( struct berval **rdn_avsp, int *rdn_av_countp ); -static void sort_rdn_avs( struct berval *avs, int count ); +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 ); +static void rdn_av_swap( struct berval *av1, struct berval *av2, int escape ); int @@ -77,24 +77,53 @@ hexchar2int( char c ) return( -1 ); } +#define ISBLANK(c) ((c) == ' ') +#define ISSPACE(c) (ISBLANK(c) || ((c) == '\n') || ((c) == '\r')) /* XXX 518524 */ + +#define ISEQUAL(c) ((c) == '=') +#define ISEQUALSTR(s) \ + ((*(s) == '3') && ((*((s)+1) == 'd') || (*((s)+1) == 'D'))) + +#define ISPLUS(c) ((c) == '+') +#define ISPLUSSTR(s) \ + ((*(s) == '2') && ((*((s)+1) == 'b') || (*((s)+1) == 'B'))) + +#define ISESCAPE(c) ((c) == '\\') +#define ISQUOTE(c) ((c) == '"') + #define DNSEPARATOR(c) (((c) == ',') || ((c) == ';')) -#define SEPARATOR(c) (((c) == ',') || ((c) == ';') || ((c) == '+')) -#define SPACE(c) (((c) == ' ') || ((c) == '\n')) /* XXX 518524 */ -#define NEEDSESCAPE(c) (((c) == '\\') || ((c) == '"') || ((c) == '+') || \ - ((c) == ',') || ((c) == ';') || ((c) == '<') || ((c) == '>') || ((c) == '=')) -#define LEADNEEDSESCAPE(c) (((c) == ' ') || ((c) == '#') || NEEDSESCAPE(c)) -#if 0 /* not used */ -#define ONLYTRAILNEEDSESCAPE(c) ((c) == ' ') -#define TRAILNEEDSESCAPE(c) (ONLYTRAILNEEDSESCAPE(c) || NEEDSESCAPE(c)) -#endif -#define B4TYPE 0 -#define INTYPE 1 -#define B4EQUAL 2 -#define B4VALUE 3 -#define INVALUE 4 -#define INQUOTEDVALUE 5 -#define B4SEPARATOR 6 -#define INVALUE1ST 7 +#define DNSEPARATORSTR(s) \ + (((*(s) == '2') && ((*((s)+1) == 'c') || (*((s)+1) == 'C'))) || \ + ((*(s) == '3') && ((*((s)+1) == 'b') || (*((s)+1) == 'B')))) + +#define SEPARATOR(c) (DNSEPARATOR(c) || ISPLUS(c)) +#define SEPARATORSTR(s) (DNSEPARATORSTR(s) || ISPLUSSTR(s)) + +#define NEEDSESCAPE(c) (ISESCAPE(c) || ISQUOTE(c) || SEPARATOR(c) || \ + ((c) == '<') || ((c) == '>') || ISEQUAL(c)) +#define NEEDSESCAPESTR(s) \ + (((*(s) == '2') && ((*((s)+1) == '2') || \ + (*((s)+1) == 'b') || (*((s)+1) == 'B') || \ + (*((s)+1) == 'c') || (*((s)+1) == 'C'))) || \ + ((*(s) == '3') && (((*((s)+1) >= 'b') && (*((s)+1) < 'f')) || \ + ((*((s)+1) >= 'B') && (*((s)+1) < 'F')))) || \ + ((*(s) == '5') && ((*((s)+1) == 'c') || (*((s)+1) == 'C')))) + +#define LEADNEEDSESCAPE(c) (ISBLANK(c) || ((c) == '#') || NEEDSESCAPE(c)) +#define LEADNEEDSESCAPESTR(s) (NEEDSESCAPESTR(s) || \ + ((*(s) == '2') && (*((s)+1) == '3'))) + +#define ISCLOSEBRACKET(c) (((c) == ')') || ((c) == ']')) + +#define B4TYPE 0 +#define INTYPE 1 +#define B4EQUAL 2 +#define B4VALUE 3 +#define INVALUE 4 +#define INQUOTEDVALUE 5 +#define B4SEPARATOR 6 +#define INVALUE1ST 7 +#define INQUOTEDVALUE1ST 8 #define SLAPI_DNNORM_INITIAL_RDN_AVS 10 #define SLAPI_DNNORM_SMALL_RDN_AV 512 @@ -137,13 +166,13 @@ hexchar2int( char c ) * * This function does not support UTF-8 multi-byte encoding for attribute * values, in particular it does not support UTF-8 whitespace. First the - * SPACE macro above is limited, but also its frequent use of '-1' indexing + * ISSPACE macro above is limited, but also its frequent use of '-1' indexing * into a char[] may hit the middle of a multi-byte UTF-8 whitespace character * encoding (518524). */ char * -substr_dn_normalize( char *dn, char *end ) +substr_dn_normalize_orig( char *dn, char *end ) { /* \xx is changed to \c. * \c is changed to c, unless this would change its meaning. @@ -166,7 +195,7 @@ substr_dn_normalize( char *dn, char *end ) for ( d = s = dn; s != end; s++ ) { switch ( state ) { case B4TYPE: - if ( ! SPACE( *s ) ) { + if ( ! ISSPACE( *s ) ) { state = INTYPE; typestart = d; *d++ = *s; @@ -176,7 +205,7 @@ substr_dn_normalize( char *dn, char *end ) if ( *s == '=' ) { state = B4VALUE; *d++ = *s; - } else if ( SPACE( *s ) ) { + } else if ( ISSPACE( *s ) ) { state = B4EQUAL; } else { *d++ = *s; @@ -186,13 +215,13 @@ substr_dn_normalize( char *dn, char *end ) if ( *s == '=' ) { state = B4VALUE; *d++ = *s; - } else if ( ! SPACE( *s ) ) { + } else if ( ! ISSPACE( *s ) ) { /* not a valid dn - but what can we do here? */ *d++ = *s; } break; case B4VALUE: - if ( *s == '"' || ! SPACE( *s ) ) { + if ( *s == '"' || ! ISSPACE( *s ) ) { value_separator = NULL; value = d; state = ( *s == '"' ) ? INQUOTEDVALUE : INVALUE1ST; @@ -223,7 +252,7 @@ substr_dn_normalize( char *dn, char *end ) * be if it does at the end of the RDN value */ /* e.g., ou=ABC \ ,o=XYZ --> ou=ABC \ ,o=XYZ */ if ( lastesc ) { - while ( SPACE( *(d - 1) ) && d > lastesc ) { + while ( ISSPACE( *(d - 1) ) && d > lastesc ) { d--; } if ( d == lastesc ) { @@ -231,7 +260,7 @@ substr_dn_normalize( char *dn, char *end ) *d++ = ' '; /* escaped trailing space */ } } else { - while ( SPACE( *(d - 1) ) ) { + while ( ISSPACE( *(d - 1) ) ) { d--; } } @@ -281,7 +310,7 @@ substr_dn_normalize( char *dn, char *end ) } if ( *s != '+' ) { /* at end of this RDN */ if ( rdn_av_count > 1 ) { - sort_rdn_avs( rdn_avs, rdn_av_count ); + sort_rdn_avs( rdn_avs, rdn_av_count, 0 ); } if ( rdn_av_count > 0 ) { reset_rdn_avs( &rdn_avs, &rdn_av_count ); @@ -304,7 +333,7 @@ substr_dn_normalize( char *dn, char *end ) } else if ( *s == '"' ) { state = B4SEPARATOR; if ( value_separator == dn /* 2 or more separators */ - || SPACE( value[1] ) || SPACE( d[-1] ) ) { + || ISSPACE( value[1] ) || ISSPACE( d[-1] ) ) { *d++ = *s; } else { /* convert to non-quoted value: */ @@ -338,7 +367,7 @@ substr_dn_normalize( char *dn, char *end ) } if ( *s != '+' ) { /* at end of this RDN */ if ( rdn_av_count > 1 ) { - sort_rdn_avs( rdn_avs, rdn_av_count ); + sort_rdn_avs( rdn_avs, rdn_av_count, 0 ); } if ( rdn_av_count > 0 ) { reset_rdn_avs( &rdn_avs, &rdn_av_count ); @@ -397,7 +426,7 @@ substr_dn_normalize( char *dn, char *end ) &rdn_avs, initial_rdn_av_stack ); } if ( rdn_av_count > 1 ) { - sort_rdn_avs( rdn_avs, rdn_av_count ); + sort_rdn_avs( rdn_avs, rdn_av_count, 0 ); } if ( rdn_av_count > 0 ) { reset_rdn_avs( &rdn_avs, &rdn_av_count ); @@ -408,7 +437,540 @@ substr_dn_normalize( char *dn, char *end ) return( d ); } +char * +substr_dn_normalize( char *dn, char *end ) +{ + /* no op */ + return end; +} + +/* + * 1) Escaped NEEDSESCAPE chars (e.g., ',', '<', '=', etc.) are converted to + * ESC HEX HEX (e.g., \2C, \3C, \3D, etc.) + * Input could be a string in double quotes + * (= old DN format: dn: cn="x=x,y=y",... --> dn: cn=x\3Dx\2Cy\3Dy,...) or + * an escaped string + * (= new DN format dn: cn=x\=x\,y\=y,... -> dn: cn=x\3Dx\2Cy\3Dy,...) + * + * 2) All the other ESC HEX HEX are converted to the real characters. + * + * 3) Spaces around separator ',', ';', and '+' are removed. + * + * Input: + * src: src DN + * src_len: length of src; 0 is acceptable if src is NULL terminated. + * Output: + * dest: address of the converted string; NULL terminated + * (could store src address if no need to convert) + * dest_len: length of dest + * + * Return values: + * 0: nothing was done; dest is identical to src (src is passed in). + * 1: successfully escaped; dest is different from src. src needs to be freed. + * -1: failed; dest is NULL; invalid DN + */ +int +slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len) +{ + int rc = -1; + int state = B4TYPE; + char *s = NULL; /* work pointer for src */ + char *d = NULL; /* work pointer for dest */ + char *ends = NULL; + char *endd = NULL; + char *typestart = NULL; + char *subtypestart = NULL; /* used for the nested DN */ + char *lastesc = NULL; + int rdn_av_count = 0; + struct berval *rdn_avs = NULL; + struct berval initial_rdn_av_stack[ SLAPI_DNNORM_INITIAL_RDN_AVS ]; + int chkblank = 0; + + if (NULL == dest) { + goto bail; + } + if (NULL == src) { + *dest = NULL; + *dest_len = 0; + goto bail; + } + if (0 == src_len) { + src_len = strlen(src); + } + s = PL_strnchr(src, '\\', src_len); + if (s) { + *dest_len = src_len * 3; + *dest = slapi_ch_malloc(*dest_len); /* max length */ + rc = 1; + } else { + s = PL_strnchr(src, '"', src_len); + if (s) { + *dest_len = src_len * 3; + *dest = slapi_ch_malloc(*dest_len); /* max length */ + rc = 1; + } else { + *dest_len = src_len; + *dest = src; /* just removing spaces around separators */ + rc = 0; + } + } + + ends = src + src_len; + endd = *dest + *dest_len; + for (s = src, d = *dest; s < ends && d < endd; ) { + switch (state) { + case B4TYPE: /* before type; cn=... */ + /* ^ */ + if (ISSPACE(*s)) { + s++; /* skip leading spaces */ + } else { + state = INTYPE; + typestart = d; + *d++ = *s++; + } + break; + case INTYPE: /* in type; cn=... */ + /* ^ */ + if (ISEQUAL(*s)) { + state = B4VALUE; + *d++ = *s++; + } else if (ISCLOSEBRACKET(*s)) { /* special care for ACL macro */ + state = INVALUE; /* skip a trailing space */ + *d++ = *s++; + } else if (ISSPACE(*s)) { + state = B4EQUAL; /* skip a trailing space */ + } else { + *d++ = *s++; + } + break; + case B4EQUAL: /* before equal; cn =... */ + /* ^ */ + if (ISEQUAL(*s)) { + state = B4VALUE; + *d++ = *s++; + } else if (ISSPACE(*s)) { + s++; /* skip trailing spaces */ + } else { + /* type includes spaces; not a valid dn */ + rc = -1; + goto bail; + } + break; + case B4VALUE: /* before value; cn= ABC */ + /* ^ */ + if (ISSPACE(*s)) { + s++; + } else { + if (ISQUOTE(*s)) { + s++; /* start with the first char in quotes */ + state = INQUOTEDVALUE1ST; + } else { + state = INVALUE1ST; + } + lastesc = NULL; + /* process *s in INVALUE or INQUOTEDVALUE */ + } + break; + case INVALUE1ST: /* 1st char in value; cn=ABC */ + /* ^ */ + if (ISSPACE(*s)) { /* skip leading spaces */ + s++; + continue; + } else if (SEPARATOR(*s)) { + /* 1st char in value is separator; invalid dn */ + rc = -1; + goto bail; + } /* otherwise, go through */ + case INVALUE: /* in value; cn=ABC */ + /* ^ */ + if (ISESCAPE(*s)) { + if (s + 1 >= ends) { + /* DN ends with '\'; invalid dn */ + rc = -1; + goto bail; + } + if (((state == INVALUE1ST) && LEADNEEDSESCAPE(*(s+1))) || + ((state == INVALUE) && NEEDSESCAPE(*(s+1)))) { + if (d + 2 >= endd) { + /* Not enough space for dest; this never happens! */ + rc = -1; + goto bail; + } else { + if (ISEQUAL(*(s+1))) { + if (NULL == subtypestart) { + /* e.g., cn=a\=b\,c\=d */ + /* ^ */ + *d = '\0'; + subtypestart = strrchr(*dest, '='); + if (subtypestart) { + /* pointing 'a' in the above example */ + subtypestart++; + } + /* else + * No equal for the nested DN looking value. + * Just through it. + */ + } + while (ISSPACE(*(d-1))) { + /* remove trailing spaces */ + d--; + } + } else if (SEPARATOR(*(s+1))) { + /* separator is a subset of needsescape */ + while (ISSPACE(*(d-1))) { + /* remove trailing spaces */ + d--; + chkblank = 1; + } + if (chkblank && ISESCAPE(*(d-1)) && ISBLANK(*d)) { + /* last space is escaped "cn=A\ ,ou=..." */ + /* ^ */ + PR_snprintf(d, 3, "%X", *d); /* hexpair */ + d += 2; + chkblank = 0; + } + /* + * Track and sort attribute values within + * multivalued RDNs. + */ + if (subtypestart && + (ISPLUS(*(s+1)) || rdn_av_count > 0)) { + add_rdn_av(subtypestart, d, &rdn_av_count, + &rdn_avs, initial_rdn_av_stack); + } + if (!ISPLUS(*(s+1))) { /* at end of this RDN */ + if (rdn_av_count > 1) { + sort_rdn_avs( rdn_avs, rdn_av_count, 1 ); + } + if (rdn_av_count > 0) { + reset_rdn_avs( &rdn_avs, &rdn_av_count ); + subtypestart = NULL; + } + } + } + /* dn: cn=x\=x\,... -> dn: cn=x\3Dx\2C,... */ + *d++ = *s++; /* '\\' */ + PR_snprintf(d, 3, "%X", *s); /* hexpair */ + d += 2; + if (ISPLUS(*s) && PL_strnstr(s, "\\=", ends - s)) { + /* next type start of multi values */ + subtypestart = d; + } + if (SEPARATOR(*s) || ISEQUAL(*s)) { + while (ISSPACE(*(s+1))) + s++; /* remove leading spaces */ + s++; + } else { + s++; + } + } + } else if (((state == INVALUE1ST) && (s+2 < ends) && + LEADNEEDSESCAPESTR(s+1)) || + ((state == INVALUE) && (s+2 < ends) && + NEEDSESCAPESTR(s+1))) { + if (ISEQUALSTR(s+1)) { + if (NULL == subtypestart) { + /* e.g., cn=a\3Db\2Cc\3Dd */ + /* ^ */ + *d = '\0'; + subtypestart = strrchr(*dest, '='); + if (subtypestart) { + /* pointing 'a' in the above example */ + subtypestart++; + } + /* else + * No equal for the nested DN looking value. + * Just through it. + */ + } + while (ISSPACE(*(d-1))) { + /* remove trailing spaces */ + d--; + } + } else if (SEPARATORSTR(s+1)) { + /* separator is a subset of needsescape */ + while (ISSPACE(*(d-1))) { + /* remove trailing spaces */ + d--; + chkblank = 1; + } + if (chkblank && ISESCAPE(*(d-1)) && ISBLANK(*d)) { + /* last space is escaped "cn=A\ ,ou=..." */ + /* ^ */ + PR_snprintf(d, 3, "%X", *d); /* hexpair */ + d += 2; + chkblank = 0; + } + /* + * Track and sort attribute values within + * multivalued RDNs. + */ + if (subtypestart && + (ISPLUSSTR(s+1) || rdn_av_count > 0)) { + add_rdn_av(subtypestart, d, &rdn_av_count, + &rdn_avs, initial_rdn_av_stack); + } + if (!ISPLUSSTR(s+1)) { /* at end of this RDN */ + if (rdn_av_count > 1) { + sort_rdn_avs( rdn_avs, rdn_av_count, 1 ); + } + if (rdn_av_count > 0) { + reset_rdn_avs( &rdn_avs, &rdn_av_count ); + } + } + } + *d++ = *s++; /* '\\' */ + *d++ = *s++; /* HEX */ + *d++ = *s++; /* HEX */ + if (ISPLUSSTR(s-2) && PL_strnstr(s, "\\=", ends - s)) { + /* next type start of multi values */ + subtypestart = d; + } + if (SEPARATORSTR(s-2) || ISEQUALSTR(s-2)) { + while (ISSPACE(*s)) /* remove leading spaces */ + s++; + } + } else if (s + 2 < ends && + isxdigit(*(s+1)) && isxdigit(*(s+2))) { + /* esc hexpair ==> real character */ + int n = hexchar2int(*(s+1)); + int n2 = hexchar2int(*(s+2)); + n = (n << 4) + n2; + if (n == 0) { /* don't change \00 */ + *d++ = *++s; + *d++ = *++s; + } else { + *d++ = n; + s += 3; + } + } else { + /* ignore an escape for now */ + lastesc = d; /* position of the previous escape */ + s++; + } + } else if (SEPARATOR(*s)) { /* cn=ABC , ... */ + /* ^ */ + /* handling a trailing escaped space */ + /* assuming a space is the only an extra character which + * is not escaped if it appears in the middle, but should + * be if it does at the end of the RDN value */ + /* e.g., ou=ABC \ ,o=XYZ --> ou=ABC \ ,o=XYZ */ + if (lastesc) { + while (ISSPACE(*(d-1)) && d > lastesc ) { + d--; + } + if (d == lastesc) { + /* esc hexpair of space: \20 */ + *d++ = '\\'; + *d++ = '2'; + *d++ = '0'; + } + } else { + while (ISSPACE(*(d-1))) { + d--; + } + } + state = B4SEPARATOR; + break; + } else { /* else if (SEPARATOR(*s)) */ + *d++ = *s++; + } + if (state == INVALUE1ST) { + state = INVALUE; + } + break; + case INQUOTEDVALUE1ST: + if (ISSPACE(*s) && (s+1 < ends && ISSPACE(*(s+1)))) { + /* skip leading spaces but need to leave one */ + s++; + continue; + } + subtypestart = d; /* prepare for '+' in the quoted value, if any */ + case INQUOTEDVALUE: + if (ISQUOTE(*s)) { + if (ISESCAPE(*(d-1))) { /* the quote is escaped */ + PR_snprintf(d, 3, "%X", *(s++)); /* hexpair */ + } else { /* end of INQUOTEVALUE */ + while (ISSPACE(*(d-1))) { /* eliminate trailing spaces */ + d--; + chkblank = 1; + } + /* We have to keep the last ' ' of a value in quotes. + * The same idea as the escaped last space: + * "cn=A,ou=B " */ + /* ^ */ + if (chkblank && ISBLANK(*d)) { + PR_snprintf(d, 4, "\\%X", *d); /* hexpair */ + d += 3; + chkblank = 0; + } + state = B4SEPARATOR; + s++; + } + } else if (((state == INQUOTEDVALUE1ST) && LEADNEEDSESCAPE(*s)) || + (state == INQUOTEDVALUE && NEEDSESCAPE(*s))) { + if (d + 2 >= endd) { + /* Not enough space for dest; this never happens! */ + rc = -1; + goto bail; + } else { + if (ISEQUAL(*s)) { + while (ISSPACE(*(d-1))) { /* remove trailing spaces */ + d--; + } + } else if (SEPARATOR(*s)) { + /* separator is a subset of needsescape */ + while (ISSPACE(*(d-1))) { /* remove trailing spaces */ + d--; + chkblank = 1; + } + /* We have to keep the last ' ' of a value in quotes. + * The same idea as the escaped last space: + * "cn=A\ ,ou=..." */ + /* ^ */ + if (chkblank && ISBLANK(*d)) { + PR_snprintf(d, 4, "\\%X", *d); /* hexpair */ + d += 3; + chkblank = 0; + } + /* + * Track and sort attribute values within + * multivalued RDNs. + */ + if (ISPLUS(*s) || rdn_av_count > 0) { + add_rdn_av(subtypestart, d, &rdn_av_count, + &rdn_avs, initial_rdn_av_stack); + } + if (!ISPLUS(*s)) { /* at end of this RDN */ + if (rdn_av_count > 1) { + sort_rdn_avs( rdn_avs, rdn_av_count, 1 ); + } + if (rdn_av_count > 0) { + reset_rdn_avs( &rdn_avs, &rdn_av_count ); + subtypestart = NULL; + } + } + } + + /* dn: cn="x=x,..",... -> dn: cn=x\3Dx\2C,... */ + *d++ = '\\'; + PR_snprintf(d, 3, "%X", *s); /* hexpair */ + d += 2; + if (ISPLUS(*s++)) { + subtypestart = d; /* next type start of multi values */ + } + if (SEPARATOR(*(s-1)) || ISEQUAL(*(s-1))) { + while (ISSPACE(*s)) /* remove leading spaces */ + s++; + } + } + } else { + *d++ = *s++; + } + if (state == INQUOTEDVALUE1ST) { + state = INQUOTEDVALUE; + } + break; + case B4SEPARATOR: + if (SEPARATOR(*s)) { + state = B4TYPE; + + /* + * Track and sort attribute values within + * multivalued RDNs. + */ + if (ISPLUS(*s) || rdn_av_count > 0) { + add_rdn_av(typestart, d, &rdn_av_count, + &rdn_avs, initial_rdn_av_stack); + } + if (!ISPLUS(*s)) { /* at end of this RDN */ + if (rdn_av_count > 1) { + sort_rdn_avs( rdn_avs, rdn_av_count, 0 ); + } + if (rdn_av_count > 0) { + reset_rdn_avs( &rdn_avs, &rdn_av_count ); + } + } + + *d++ = (ISPLUS(*s++)) ? '+' : ','; + } else { + s++; + } + break; + default: + LDAPDebug( LDAP_DEBUG_ANY, + "slapi_dn_normalize - unknown state %d\n", state, 0, 0 ); + break; + } + } + + /* + * Track and sort attribute values within multivalued RDNs. + */ + /* We may still be in an unexpected state, such as B4TYPE if + * we encountered something odd like a '+' at the end of the + * rdn. If this is the case, we don't want to add this bogus + * rdn to our list to sort. We should only be in the INVALUE + * or B4SEPARATOR state if we have a valid rdn component to + * be added. */ + if ((rdn_av_count > 0) && ((state == INVALUE1ST) || + (state == INVALUE) || (state == B4SEPARATOR))) { + add_rdn_av(typestart, d, &rdn_av_count, &rdn_avs, initial_rdn_av_stack); + } + if ( rdn_av_count > 1 ) { + sort_rdn_avs( rdn_avs, rdn_av_count, 0 ); + } + if ( rdn_av_count > 0 ) { + reset_rdn_avs( &rdn_avs, &rdn_av_count ); + } + /* Trim trailing spaces */ + while (d > *dest && ISBLANK(*(d-1))) { + --d; /* XXX 518524 */ + } + *dest_len = d - *dest; +bail: + if (rc < 0) { + if (*dest != src) { + slapi_ch_free_string(dest); + } else { + *dest = NULL; + } + *dest_len = 0; + } else if (rc > 0) { + /* We terminate the str with NULL only when we allocate the str */ + *d = '\0'; + } + return rc; +} + +char * +slapi_create_dn_string(const char *fmt, ...) +{ + char *src = NULL; + char *dest = NULL; + size_t dest_len = 0; + va_list ap; + int rc = 0; + + if (NULL == fmt) { + return NULL; + } + + va_start(ap, fmt); + src = PR_vsmprintf(fmt, ap); + va_end(ap); + rc = slapi_dn_normalize_ext(src, strlen(src), &dest, &dest_len); + if (rc < 0) { + slapi_ch_free_string(&src); + return NULL; + } else if (rc == 0) { /* src is passed in. */ + *(dest + dest_len) = '\0'; + } else { + slapi_ch_free_string(&src); + } + return dest; +} /* * Append previous AV to the attribute value array if multivalued RDN. @@ -418,21 +980,22 @@ substr_dn_normalize( char *dn, char *end ) */ static void add_rdn_av( char *avstart, char *avend, int *rdn_av_countp, - struct berval **rdn_avsp, struct berval *avstack ) + struct berval **rdn_avsp, struct berval *avstack ) { if ( *rdn_av_countp == 0 ) { - *rdn_avsp = avstack; + *rdn_avsp = avstack; } else if ( *rdn_av_countp == SLAPI_DNNORM_INITIAL_RDN_AVS ) { - struct berval *tmpavs; + struct berval *tmpavs; - tmpavs = (struct berval *)slapi_ch_calloc( - SLAPI_DNNORM_INITIAL_RDN_AVS * 2, sizeof( struct berval )); - memcpy( tmpavs, *rdn_avsp, - SLAPI_DNNORM_INITIAL_RDN_AVS * sizeof( struct berval )); - *rdn_avsp = tmpavs; + tmpavs = (struct berval *)slapi_ch_calloc( + SLAPI_DNNORM_INITIAL_RDN_AVS * 2, sizeof( struct berval )); + memcpy( tmpavs, *rdn_avsp, + SLAPI_DNNORM_INITIAL_RDN_AVS * sizeof( struct berval )); + *rdn_avsp = tmpavs; } else if (( *rdn_av_countp % SLAPI_DNNORM_INITIAL_RDN_AVS ) == 0 ) { - *rdn_avsp = (struct berval *)slapi_ch_realloc( (char *)*rdn_avsp, - (*rdn_av_countp + SLAPI_DNNORM_INITIAL_RDN_AVS)*sizeof(struct berval) ); + *rdn_avsp = (struct berval *)slapi_ch_realloc( (char *)*rdn_avsp, + (*rdn_av_countp + + SLAPI_DNNORM_INITIAL_RDN_AVS)*sizeof(struct berval) ); } /* @@ -453,7 +1016,7 @@ static void reset_rdn_avs( struct berval **rdn_avsp, int *rdn_av_countp ) { if ( *rdn_av_countp > SLAPI_DNNORM_INITIAL_RDN_AVS ) { - slapi_ch_free( (void **)rdn_avsp ); + slapi_ch_free( (void **)rdn_avsp ); } *rdn_avsp = NULL; *rdn_av_countp = 0; @@ -471,9 +1034,9 @@ reset_rdn_avs( struct berval **rdn_avsp, int *rdn_av_countp ) * Also note that the bv_val's in the "avas" array are not zero-terminated. */ static void -sort_rdn_avs( struct berval *avs, int count ) +sort_rdn_avs( struct berval *avs, int count, int escape ) { - int i, j, swaps; + int i, j, swaps; /* * Since we expect there to be a small number of AVs, we use a @@ -481,16 +1044,16 @@ sort_rdn_avs( struct berval *avs, int count ) * adjacent values anyway. */ for ( i = 0; i < count - 1; ++i ) { - swaps = 0; - for ( j = 0; j < count - 1; ++j ) { - if ( rdn_av_cmp( &avs[j], &avs[j+1] ) > 0 ) { - rdn_av_swap( &avs[j], &avs[j+1] ); - ++swaps; - } - } - if ( swaps == 0 ) { - break; /* stop early if no swaps made during the last pass */ - } + swaps = 0; + for ( j = 0; j < count - 1; ++j ) { + if ( rdn_av_cmp( &avs[j], &avs[j+1] ) > 0 ) { + rdn_av_swap( &avs[j], &avs[j+1], escape ); + ++swaps; + } + } + if ( swaps == 0 ) { + break; /* stop early if no swaps made during the last pass */ + } } } @@ -501,15 +1064,15 @@ sort_rdn_avs( struct berval *avs, int count ) static int rdn_av_cmp( struct berval *av1, struct berval *av2 ) { - int rc; + int rc; rc = strncasecmp( av1->bv_val, av2->bv_val, - ( av1->bv_len < av2->bv_len ) ? av1->bv_len : av2->bv_len ); + ( av1->bv_len < av2->bv_len ) ? av1->bv_len : av2->bv_len ); if ( rc == 0 ) { - return( av1->bv_len - av2->bv_len ); /* longer is greater */ + return( av1->bv_len - av2->bv_len ); /* longer is greater */ } else { - return( rc ); + return( rc ); } } @@ -519,12 +1082,12 @@ rdn_av_cmp( struct berval *av1, struct berval *av2 ) * Avoid allocating any heap memory for reasonably small AVs. */ static void -rdn_av_swap( struct berval *av1, struct berval *av2 ) +rdn_av_swap( struct berval *av1, struct berval *av2, int escape ) { - char *buf1, *buf2; - char stackbuf1[ SLAPI_DNNORM_SMALL_RDN_AV ]; - char stackbuf2[ SLAPI_DNNORM_SMALL_RDN_AV ]; - int len1, len2; + char *buf1, *buf2; + char stackbuf1[ SLAPI_DNNORM_SMALL_RDN_AV ]; + char stackbuf2[ SLAPI_DNNORM_SMALL_RDN_AV ]; + int len1, len2; /* * Copy the two avs into temporary buffers. We use stack-based buffers @@ -532,16 +1095,16 @@ rdn_av_swap( struct berval *av1, struct berval *av2 ) * large values. */ if (( len1 = av1->bv_len ) <= SLAPI_DNNORM_SMALL_RDN_AV ) { - buf1 = stackbuf1; + buf1 = stackbuf1; } else { - buf1 = slapi_ch_malloc( len1 ); + buf1 = slapi_ch_malloc( len1 ); } memcpy( buf1, av1->bv_val, len1 ); if (( len2 = av2->bv_len ) <= SLAPI_DNNORM_SMALL_RDN_AV ) { - buf2 = stackbuf2; + buf2 = stackbuf2; } else { - buf2 = slapi_ch_malloc( len2 ); + buf2 = slapi_ch_malloc( len2 ); } memcpy( buf2, av2->bv_val, len2 ); @@ -556,7 +1119,13 @@ rdn_av_swap( struct berval *av1, struct berval *av2 ) * Also reset av2 pointer and length. */ av2->bv_val = av1->bv_val + len2; - *(av2->bv_val)++ = '+'; + if (escape) { + *(av2->bv_val)++ = '\\'; + PR_snprintf(av2->bv_val, 3, "%X", '+'); /* hexpair */ + av2->bv_val += 2; + } else { + *(av2->bv_val)++ = '+'; + } memcpy( av2->bv_val, buf1, len1 ); av2->bv_len = len1; @@ -564,19 +1133,19 @@ rdn_av_swap( struct berval *av1, struct berval *av2 ) * Clean up. */ if ( len1 > SLAPI_DNNORM_SMALL_RDN_AV ) { - slapi_ch_free( (void **)&buf1 ); + slapi_ch_free( (void **)&buf1 ); } if ( len2 > SLAPI_DNNORM_SMALL_RDN_AV ) { - slapi_ch_free( (void **)&buf2 ); + slapi_ch_free( (void **)&buf2 ); } } /* + * DEPRECATED: this function does nothing. * slapi_dn_normalize - put dn into a canonical format. the dn is * normalized in place, as well as returned. */ - char * slapi_dn_normalize( char *dn ) { @@ -586,7 +1155,10 @@ slapi_dn_normalize( char *dn ) return dn; } -/* Note that this routine normalizes to the end and doesn't null terminate */ +/* + * DEPRECATED: this function does nothing. + * Note that this routine normalizes to the end and doesn't null terminate + */ char * slapi_dn_normalize_to_end( char *dn , char *end) { @@ -600,13 +1172,28 @@ slapi_dn_normalize_to_end( char *dn , char *end) char * slapi_dn_ignore_case( char *dn ) { - unsigned char *s, *d; + unsigned char *s = NULL, *d = NULL; + int ssz, dsz; + /* normalize case (including UTF-8 multi-byte chars) */ + for ( s = d = (unsigned char *)dn; s && *s; s += ssz, d += dsz ) { + slapi_utf8ToLower( s, d, &ssz, &dsz ); + } + if (d) { + *d = '\0'; /* utf8ToLower result may be shorter than the original */ + } + return( dn ); +} + +char * +dn_ignore_case_to_end( char *dn, char *end ) +{ + unsigned char *s = NULL, *d = NULL; int ssz, dsz; /* normalize case (including UTF-8 multi-byte chars) */ - for ( s = d = (unsigned char *)dn; *s; s += ssz, d += dsz ) { - slapi_utf8ToLower( s, d, &ssz, &dsz ); + for (s = d = (unsigned char *)dn; s && s < (unsigned char *)end && *s; + s += ssz, d += dsz) { + slapi_utf8ToLower( s, d, &ssz, &dsz ); } - *d = '\0'; /* utf8ToLower result may be shorter than the original */ return( dn ); } @@ -626,6 +1213,47 @@ slapi_dn_normalize_case( char *dn ) return( slapi_dn_ignore_case( dn )); } +int +slapi_dn_normalize_case_ext(char *src, size_t src_len, + char **dest, size_t *dest_len) +{ + int rc = slapi_dn_normalize_ext(src, src_len, dest, dest_len); + + if (rc >= 0) { + dn_ignore_case_to_end(*dest, *dest + *dest_len); + } + return rc; +} + +char * +slapi_create_dn_string_case(const char *fmt, ...) +{ + char *src = NULL; + char *dest = NULL; + size_t dest_len = 0; + va_list ap; + int rc = 0; + + if (NULL == fmt) { + return NULL; + } + + va_start(ap, fmt); + src = PR_vsmprintf(fmt, ap); + va_end(ap); + + rc = slapi_dn_normalize_ext(src, strlen(src), &dest, &dest_len); + if (rc < 0) { + slapi_ch_free_string(&src); + } else if (rc == 0) { /* src is passed in. */ + *(dest + dest_len) = '\0'; + } else { + slapi_ch_free_string(&src); + } + + return slapi_dn_ignore_case(dest); +} + /* * slapi_dn_beparent - return a copy of the dn of dn's parent, * NULL if the DN is a suffix of the backend. @@ -1129,10 +1757,7 @@ slapi_sdn_set_rdn(Slapi_DN *sdn, const Slapi_RDN *rdn) { /* NewDN= NewRDN + OldParent */ char *parentdn= slapi_dn_parent(sdn->dn); - char *newdn= slapi_ch_malloc(strlen(rawrdn)+1+strlen(parentdn)+1); - strcpy( newdn, rawrdn ); - strcat( newdn, "," ); - strcat( newdn, parentdn ); + char *newdn = slapi_ch_smprintf("%s,%s", rawrdn, parentdn); slapi_ch_free((void**)&parentdn); slapi_sdn_set_dn_passin(sdn,newdn); } @@ -1264,10 +1889,10 @@ slapi_sdn_get_ndn(const Slapi_DN *sdn) if(sdn->dn!=NULL) { char *p= slapi_ch_strdup(sdn->dn); - Slapi_DN *ncsdn= (Slapi_DN*)sdn; /* non-const Slapi_DN */ - slapi_dn_normalize_case(p); + Slapi_DN *ncsdn= (Slapi_DN*)sdn; /* non-const Slapi_DN */ + slapi_dn_ignore_case(p); /* dn is normalized; just ignore case */ ncsdn->ndn= p; - ncsdn->ndn_len=strlen(p); + ncsdn->ndn_len=strlen(p); ncsdn->flag= slapi_setbit_uchar(sdn->flag,FLAG_NDN); PR_INCREMENT_COUNTER(slapi_sdn_counter_ndn_created); PR_INCREMENT_COUNTER(slapi_sdn_counter_ndn_exist); diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c index 3816d42a..0a8c40d5 100644 --- a/ldap/servers/slapd/entry.c +++ b/ldap/servers/slapd/entry.c @@ -150,9 +150,9 @@ str2entry_state_information_from_type(char *s,CSNSet **csnset,CSN **attributedel } } -/* dn is not consumed. Caller needs to free it. */ +/* rawdn is not consumed. Caller needs to free it. */ static Slapi_Entry * -str2entry_fast( const char *dn, char *s, int flags, int read_stateinfo ) +str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo ) { Slapi_Entry *e; char *next, *ptype=NULL; @@ -163,6 +163,11 @@ str2entry_fast( const char *dn, char *s, int flags, int read_stateinfo ) CSN *attributedeletioncsn= NULL; /* Moved to this level so that the JCM csn_free call below gets useful */ CSNSet *valuecsnset= NULL; /* Moved to this level so that the JCM csn_free call below gets useful */ CSN *maxcsn = NULL; + char *normdn = NULL; + int strict = 0; + + /* Check if we should be performing strict validation. */ + strict = config_get_dn_validate_strict(); /* * In string format, an entry looks like either of these: @@ -267,13 +272,41 @@ str2entry_fast( const char *dn, char *s, int flags, int read_stateinfo ) a = NULL; } - if ( dn ) { - if ( NULL == slapi_entry_get_dn_const( e )) { - slapi_entry_set_dn( e, slapi_ch_strdup( dn )); + if ( rawdn ) { + if ( NULL == slapi_entry_get_dn_const( e )) { + normdn = slapi_create_dn_string("%s", rawdn); + if (NULL == normdn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "str2entry_fast: Invalid DN: %s\n", rawdn); + slapi_entry_free( e ); + if (retmalloc) slapi_ch_free_string(&valuecharptr); + if (freetype) slapi_ch_free_string(&type); + return NULL; + } + /* normdn is consumed in e */ + slapi_entry_set_dn(e, normdn); } - if ( NULL == slapi_entry_get_rdn_const( e )) { - slapi_entry_set_rdn( e, (char *)dn ); + if ( NULL == slapi_entry_get_rdn_const( e )) { + if (normdn) { + /* normdn is just referred in slapi_entry_set_rdn. */ + slapi_entry_set_rdn(e, normdn); + } else { + normdn = slapi_create_dn_string("%s", rawdn); + if (NULL == normdn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "str2entry_fast: Invalid DN: %s\n", rawdn); + slapi_entry_free( e ); + if (retmalloc) slapi_ch_free_string(&valuecharptr); + if (freetype) slapi_ch_free_string(&type); + return NULL; + } + /* normdn is just referred in slapi_entry_set_rdn. */ + slapi_entry_set_rdn(e, normdn); + slapi_ch_free_string(&normdn); + } } + rawdn = NULL; /* Set once in the loop. + This won't affect the caller's passed address. */ } if ( strcasecmp( type, "dn" ) == 0 ) { if ( slapi_entry_get_dn_const(e)!=NULL ) { @@ -288,11 +321,22 @@ str2entry_fast( const char *dn, char *s, int flags, int read_stateinfo ) if (freetype) slapi_ch_free_string(&type); continue; } - slapi_entry_set_dn(e,slapi_ch_strdup( valuecharptr )); + normdn = slapi_create_dn_string("%s", valuecharptr); + if (NULL == normdn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "str2entry_fast: Invalid DN: %s\n", valuecharptr); + slapi_entry_free( e ); + if (retmalloc) slapi_ch_free_string(&valuecharptr); + if (freetype) slapi_ch_free_string(&type); + return NULL; + } + /* normdn is consumed in e */ + slapi_entry_set_dn(e, normdn); + /* the memory below was not allocated by the slapi_ch_ functions */ if (retmalloc) slapi_ch_free_string(&valuecharptr); if (freetype) slapi_ch_free_string(&type); - continue; + continue; } if ( strcasecmp( type, "rdn" ) == 0 ) { @@ -302,7 +346,7 @@ str2entry_fast( const char *dn, char *s, int flags, int read_stateinfo ) /* the memory below was not allocated by the slapi_ch_ functions */ if (retmalloc) slapi_ch_free_string(&valuecharptr); if (freetype) slapi_ch_free_string(&type); - continue; + continue; } @@ -310,8 +354,9 @@ str2entry_fast( const char *dn, char *s, int flags, int read_stateinfo ) if ( strcasecmp (type, SLAPI_ATTR_UNIQUEID) == 0 ){ if (e->e_uniqueid != NULL){ - LDAPDebug (LDAP_DEBUG_ANY, "str2entry_fast: entry has multiple " - "uniqueids %s and %s (second ignored)\n", + LDAPDebug (LDAP_DEBUG_TRACE, + "str2entry_fast: entry has multiple uniqueids %s " + "and %s (second ignored)\n", e->e_uniqueid, valuecharptr, 0); }else{ /* name2asi will be locked in slapi_entry_set_uniqueid */ @@ -333,12 +378,7 @@ str2entry_fast( const char *dn, char *s, int flags, int read_stateinfo ) } { - Slapi_Value *value= value_new(NULL,CSN_TYPE_NONE,NULL); - slapi_value_set( value, valuecharptr, valuelen ); - /* the memory below was not allocated by the slapi_ch_ functions */ - if (retmalloc) slapi_ch_free_string(&valuecharptr); - value->v_csnset= valuecsnset; - valuecsnset= NULL; + Slapi_Value *value = NULL; if(a==NULL) { switch(attr_state) @@ -368,9 +408,51 @@ str2entry_fast( const char *dn, char *s, int flags, int read_stateinfo ) continue; /* break; ??? */ } - + } + /* moved the value setting code here to check Slapi_Attr 'a' + * to retrieve the attribute syntax info */ + value = value_new(NULL, CSN_TYPE_NONE, NULL); + if (slapi_attr_is_dn_syntax_attr(*a)) { + int rc = 0; + char *dn_aval = NULL; + size_t dnlen = 0; + if (strict) { + /* check that the dn is formatted correctly */ + rc = slapi_dn_syntax_check(NULL, valuecharptr, 1); + if (rc) { /* syntax check failed */ + LDAPDebug2Args(LDAP_DEBUG_TRACE, + "str2entry_fast: strict: Invalid DN value: %s: %s\n", + type, valuecharptr); + slapi_entry_free( e ); + if (retmalloc) slapi_ch_free_string(&valuecharptr); + if (freetype) slapi_ch_free_string(&type); + return NULL; + } + } + rc = slapi_dn_normalize_ext(valuecharptr, 0, &dn_aval, &dnlen); + if (rc < 0) { + /* Give up normalizing the attribute value */ + LDAPDebug2Args(LDAP_DEBUG_TRACE, + "str2entry_fast: Invalid DN value: %s: %s\n", + type, valuecharptr); + dn_aval = valuecharptr; + dnlen = valuelen; + } + slapi_value_set(value, dn_aval, dnlen); + if (rc > 0) { /* if rc == 0, valuecharptr is passed in */ + slapi_ch_free_string(&dn_aval); + } else if (rc == 0) { /* rc == 0; valuecharptr is passed in; + not null terminated */ + *(dn_aval + dnlen) = '\0'; + } + } else { + slapi_value_set(value, valuecharptr, valuelen); } if (freetype) slapi_ch_free_string(&type); /* don't need type anymore */ + /* the memory below was not allocated by the slapi_ch_ functions */ + if (retmalloc) slapi_ch_free_string(&valuecharptr); + value->v_csnset = valuecsnset; + valuecsnset = NULL; { const CSN *distinguishedcsn= csnset_get_csn_of_type(value->v_csnset,CSN_TYPE_VALUE_DISTINGUISHED); if(distinguishedcsn!=NULL) @@ -601,7 +683,7 @@ entry_attrs_find(entry_attrs *ea,char *type) /* dn is not consumed. Caller needs to free it. */ static Slapi_Entry * -str2entry_dupcheck( const char *dn, char *s, int flags, int read_stateinfo ) +str2entry_dupcheck( const char *rawdn, char *s, int flags, int read_stateinfo ) { Slapi_Entry *e; str2entry_attr stack_attrs[STR2ENTRY_SMALL_BUFFER_SIZE]; @@ -625,6 +707,11 @@ str2entry_dupcheck( const char *dn, char *s, int flags, int read_stateinfo ) ( 0 != ( flags & SLAPI_STR2ENTRY_REMOVEDUPVALS )); Slapi_Value *value = 0; CSN *maxcsn= NULL; + char *normdn = NULL; + int strict = 0; + + /* Check if we should be performing strict validation. */ + strict = config_get_dn_validate_strict(); LDAPDebug( LDAP_DEBUG_TRACE, "=> str2entry_dupcheck\n", 0, 0, 0 ); @@ -688,16 +775,44 @@ str2entry_dupcheck( const char *dn, char *s, int flags, int read_stateinfo ) csnset_free(&valuecsnset); } - if ( dn ) { - if ( NULL == slapi_entry_get_dn_const(e) ) { - slapi_entry_set_dn( e, slapi_ch_strdup( dn )); + if ( rawdn ) { + if ( NULL == slapi_entry_get_dn_const(e) ) { + normdn = slapi_create_dn_string("%s", rawdn); + if (NULL == normdn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "str2entry_dupcheck: Invalid DN: %s\n", rawdn); + slapi_entry_free( e ); + if (retmalloc) slapi_ch_free_string(&valuecharptr); + if (freetype) slapi_ch_free_string(&type); + return NULL; + } + /* normdn is consumed in e */ + slapi_entry_set_dn(e, normdn); } - if ( NULL == slapi_entry_get_rdn_const(e) ) { - slapi_entry_set_rdn( e, (char *)dn ); + if ( NULL == slapi_entry_get_rdn_const(e) ) { + if (normdn) { + /* normdn is just referred in slapi_entry_set_rdn. */ + slapi_entry_set_rdn(e, normdn); + } else { + normdn = slapi_create_dn_string("%s", rawdn); + if (NULL == normdn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "str2entry_fast: Invalid DN: %s\n", rawdn); + slapi_entry_free( e ); + if (retmalloc) slapi_ch_free_string(&valuecharptr); + if (freetype) slapi_ch_free_string(&type); + return NULL; + } + /* normdn is just referred in slapi_entry_set_rdn. */ + slapi_entry_set_rdn(e, normdn); + slapi_ch_free_string(&normdn); + } } + rawdn = NULL; /* Set once in the loop. + This won't affect the caller's passed address. */ } if ( strcasecmp( type, "dn" ) == 0 ) { - if ( slapi_entry_get_dn_const(e)!=NULL ) { + if ( slapi_entry_get_dn_const(e)!=NULL ) { char ebuf[ BUFSIZ ]; LDAPDebug( LDAP_DEBUG_TRACE, "str2entry_dupcheck: entry has multiple dns \"%s\" " @@ -708,8 +823,18 @@ str2entry_dupcheck( const char *dn, char *s, int flags, int read_stateinfo ) if (retmalloc) slapi_ch_free_string(&valuecharptr); if (freetype) slapi_ch_free_string(&type); continue; - } - slapi_entry_set_dn(e,slapi_ch_strdup( valuecharptr )); + } + normdn = slapi_create_dn_string("%s", valuecharptr); + if (NULL == normdn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, + "str2entry_dupcheck: Invalid DN: %s\n", valuecharptr); + slapi_entry_free( e ); e = NULL; + if (retmalloc) slapi_ch_free_string(&valuecharptr); + if (freetype) slapi_ch_free_string(&type); + goto free_and_return; + } + /* normdn is consumed in e */ + slapi_entry_set_dn(e, normdn); /* the memory below was not allocated by the slapi_ch_ functions */ if (retmalloc) slapi_ch_free_string(&valuecharptr); if (freetype) slapi_ch_free_string(&type); @@ -730,8 +855,9 @@ str2entry_dupcheck( const char *dn, char *s, int flags, int read_stateinfo ) if ( strcasecmp (type, SLAPI_ATTR_UNIQUEID) == 0 ){ if (e->e_uniqueid != NULL){ - LDAPDebug (LDAP_DEBUG_ANY, "str2entry_dupcheck: entry has multiple " - "uniqueids %s and %s (second ignored)\n", + LDAPDebug (LDAP_DEBUG_TRACE, + "str2entry_dupcheck: entry has multiple uniqueids %s " + "and %s (second ignored)\n", e->e_uniqueid, valuecharptr, 0); }else{ slapi_entry_set_uniqueid (e, slapi_ch_strdup(valuecharptr)); @@ -853,10 +979,44 @@ str2entry_dupcheck( const char *dn, char *s, int flags, int read_stateinfo ) nattrs++; } - if (freetype) slapi_ch_free_string(&type); sa = prev_attr; /* For readability */ - value= value_new(NULL,CSN_TYPE_NONE,NULL); - slapi_value_set( value, valuecharptr, valuelen ); + value= value_new(NULL, CSN_TYPE_NONE, NULL); + if (slapi_attr_is_dn_syntax_attr(&(sa->sa_attr))) { + char *dn_aval = NULL; + size_t dnlen = 0; + if (strict) { + /* check that the dn is formatted correctly */ + rc = slapi_dn_syntax_check(NULL, valuecharptr, 1); + if (rc) { /* syntax check failed */ + LDAPDebug2Args(LDAP_DEBUG_ANY, + "str2entry_dupcheck: strict: Invalid DN value: %s: %s\n", + type, valuecharptr); + slapi_entry_free( e ); e = NULL; + if (retmalloc) slapi_ch_free_string(&valuecharptr); + if (freetype) slapi_ch_free_string(&type); + goto free_and_return; + } + } + rc = slapi_dn_normalize_ext(valuecharptr, 0, &dn_aval, &dnlen); + if (rc < 0) { + /* Give up normalizing the attribute value */ + LDAPDebug2Args(LDAP_DEBUG_TRACE, + "str2entry_dupcheck: Invalid DN value: %s: %s\n", + type, valuecharptr); + dn_aval = valuecharptr; + dnlen = valuelen; + } + slapi_value_set(value, dn_aval, dnlen); + if (rc > 0) { /* if rc == 0, valuecharptr is passed in */ + slapi_ch_free_string(&dn_aval); + } else if (rc == 0) { /* rc == 0; valuecharptr is passed in; + not null terminated */ + *(dn_aval + dnlen) = '\0'; + } + } else { + slapi_value_set(value, valuecharptr, valuelen); + } + if (freetype) slapi_ch_free_string(&type); /* the memory below was not allocated by the slapi_ch_ functions */ if (retmalloc) slapi_ch_free_string(&valuecharptr); value->v_csnset= valuecsnset; @@ -1166,6 +1326,7 @@ slapi_str2entry( char *s, int flags ) /* * string s does not include dn. + * NOTE: the first arg "dn" should have been normalized before passing. */ Slapi_Entry * slapi_str2entry_ext( const char *dn, char *s, int flags ) @@ -1190,15 +1351,15 @@ slapi_str2entry_ext( const char *dn, char *s, int flags ) */ if ( 0 != ( flags & SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF ) || 0 != ( flags & ~SLAPI_STRENTRY_FLAGS_HANDLED_BY_STR2ENTRY_FAST )) - { + { e= str2entry_dupcheck( dn, s, flags, read_stateinfo ); - } - else - { + } + else + { e= str2entry_fast( dn, s, flags, read_stateinfo ); - } - if (!e) - return e; /* e == NULL */ + } + if (!e) + return e; /* e == NULL */ if ( flags & SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES ) { @@ -1770,8 +1931,12 @@ static size_t slapi_dn_size(Slapi_DN *sdn) if (sdn == NULL) return 0; - if (sdn->dn) size += strlen(sdn->dn) + 1; - if (sdn->ndn) size *= 2; + if (slapi_sdn_get_dn(sdn)) { + size += strlen(slapi_sdn_get_dn(sdn)) + 1; + } + if (slapi_sdn_get_ndn(sdn)) { + size += strlen(slapi_sdn_get_ndn(sdn)) + 1; + } return size; } @@ -2922,7 +3087,7 @@ entry_apply_mod( Slapi_Entry *e, const LDAPMod *mod ) case LDAP_MOD_ADD: LDAPDebug( LDAP_DEBUG_ARGS, " add: %s\n", mod->mod_type, 0, 0 ); if(sawsubentry) e->e_flags |= SLAPI_ENTRY_LDAPSUBENTRY; - err = slapi_entry_add_values( e, mod->mod_type, mod->mod_bvalues ); + err = slapi_entry_add_values( e, mod->mod_type, mod->mod_bvalues ); break; case LDAP_MOD_DELETE: @@ -2980,6 +3145,9 @@ slapi_entry_add_values_sv(Slapi_Entry *e, Slapi_Attr **a= NULL; Slapi_Attr **alist= &e->e_attrs; attrlist_find_or_create(alist, type, &a); + if (slapi_attr_is_dn_syntax_attr(*a)) { + valuearray_normalize_value(vals); + } rc= attr_add_valuearray(*a,vals,slapi_entry_get_dn_const(e)); } return( rc ); diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c index 6b51ef1c..01c160c2 100644 --- a/ldap/servers/slapd/entrywsi.c +++ b/ldap/servers/slapd/entrywsi.c @@ -450,6 +450,10 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b } a_flags_orig = a->a_flags; a->a_flags |= flags; + /* Check if the type of the to-be-added values has DN syntax or not. */ + if (slapi_attr_is_dn_syntax_attr(a)) { + valuearray_normalize_value(valuestoadd); + } if(urp) { /* @@ -566,6 +570,11 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval /* delete some specific values */ Slapi_Value **valuestodelete= NULL; valuearray_init_bervalarray(vals,&valuestodelete); /* JCM SLOW FUNCTION */ + /* Check if the type of the to-be-deleted values has DN syntax + * or not. */ + if (slapi_attr_is_dn_syntax_attr(a)) { + valuearray_normalize_value(valuestodelete); + } if(urp) { Slapi_Value **valuesupdated= NULL; diff --git a/ldap/servers/slapd/extendop.c b/ldap/servers/slapd/extendop.c index 003c2ab8..a521cb7b 100644 --- a/ldap/servers/slapd/extendop.c +++ b/ldap/servers/slapd/extendop.c @@ -53,7 +53,9 @@ static const char *extended_op_oid2string( const char *oid ); static void extop_handle_import_start(Slapi_PBlock *pb, char *extoid, struct berval *extval) { - char *suffix; + char *orig = NULL; + char *suffix = NULL; + size_t dnlen = 0; Slapi_DN *sdn = NULL; Slapi_Backend *be = NULL; struct berval bv; @@ -66,10 +68,34 @@ static void extop_handle_import_start(Slapi_PBlock *pb, char *extoid, "no data supplied", 0, NULL); return; } - suffix = slapi_ch_malloc(extval->bv_len+1); - strncpy(suffix, extval->bv_val, extval->bv_len); - suffix[extval->bv_len] = 0; - + orig = slapi_ch_malloc(extval->bv_len+1); + strncpy(orig, extval->bv_val, extval->bv_len); + orig[extval->bv_len] = 0; + /* Check if we should be performing strict validation. */ + if (config_get_dn_validate_strict()) { + /* check that the dn is formatted correctly */ + ret = slapi_dn_syntax_check(pb, orig, 1); + if (ret) { /* syntax check failed */ + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "extop_handle_import_start: strict: invalid suffix\n", + orig); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, + "invalid suffix", 0, NULL); + return; + } + } + ret = slapi_dn_normalize_ext(orig, 0, &suffix, &dnlen); + if (ret < 0) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "extop_handle_import_start: invalid suffix\n", orig); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, + "invalid suffix", 0, NULL); + return; + } else if (ret > 0) { + slapi_ch_free_string(&orig); + } else { /* ret == 0; orig is passed in; not null terminated */ + *(suffix + dnlen) = '\0'; + } sdn = slapi_sdn_new_dn_byval(suffix); if (!sdn) { LDAPDebug(LDAP_DEBUG_ANY, @@ -109,6 +135,7 @@ static void extop_handle_import_start(Slapi_PBlock *pb, char *extoid, /* slapi_str2entry modify its dn parameter so we must copy * this string each time we call it ! */ + /* This dn is no need to be normalized. */ PR_snprintf(dn, sizeof(dn), "dn: oid=%s,cn=features,cn=config", EXTOP_BULK_IMPORT_START_OID); diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c index 0439007b..642b6af9 100644 --- a/ldap/servers/slapd/fedse.c +++ b/ldap/servers/slapd/fedse.c @@ -76,6 +76,7 @@ extern char ** getSupportedCiphers(); +/* Note: These DNs are no need to be normalized */ static const char *internal_entries[] = { "dn:\n" diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c index dbeae654..b8e26d1c 100644 --- a/ldap/servers/slapd/libglobs.c +++ b/ldap/servers/slapd/libglobs.c @@ -870,7 +870,8 @@ FrontendConfig_init () { cfg->ldapi_map_entries = LDAP_OFF; cfg->ldapi_uidnumber_type = slapi_ch_strdup("uidNumber"); cfg->ldapi_gidnumber_type = slapi_ch_strdup("gidNumber"); - cfg->ldapi_search_base_dn = slapi_ch_strdup("dc=example, dc=com"); + /* These DNs are no need to be normalized. */ + cfg->ldapi_search_base_dn = slapi_ch_strdup("dc=example,dc=com"); #if defined(ENABLE_AUTO_DN_SUFFIX) cfg->ldapi_auto_dn_suffix = slapi_ch_strdup("cn=peercred,cn=external,cn=auth"); #endif @@ -4884,18 +4885,18 @@ config_set_instancedir(const char *attrname, char *value, char *errorbuf, int ap { int retVal = LDAP_SUCCESS; slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); - + if ( config_value_is_null( attrname, value, errorbuf, 0 )) { return LDAP_OPERATIONS_ERROR; } - + if (!apply) { return retVal; } - + CFG_LOCK_WRITE(slapdFrontendConfig); /* We don't want to allow users to modify instance dir. - * Set it once when the server starts. */ + * Set it once when the server starts. */ if (NULL == slapdFrontendConfig->instancedir) { slapdFrontendConfig->instancedir = slapi_ch_strdup(value); } diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c index 5023dcd2..3772a757 100644 --- a/ldap/servers/slapd/main.c +++ b/ldap/servers/slapd/main.c @@ -1107,6 +1107,7 @@ main( int argc, char **argv) /* initialize UniqueID generator - must be done once backends are started and event queue is initialized but before plugins are started */ + /* Note: This DN is no need to be normalized. */ sdn = slapi_sdn_new_dn_byval ("cn=uniqueid generator,cn=config"); rc = uniqueIDGenInit (NULL, sdn, slapd_exemode == SLAPD_EXEMODE_SLAPD); slapi_sdn_free (&sdn); @@ -1908,6 +1909,7 @@ lookup_instance_name_by_suffix(char *suffix, if (query == NULL) goto done; + /* Note: This DN is no need to be normalized. */ slapi_search_internal_set_pb(pb, "cn=mapping tree,cn=config", LDAP_SCOPE_SUBTREE, query, NULL, 0, NULL, NULL, (void *)plugin_get_default_component_id(), 0); @@ -1928,6 +1930,7 @@ lookup_instance_name_by_suffix(char *suffix, query = slapi_ch_smprintf("(&(objectclass=nsmappingtree)(|(cn=*%s\")(cn=*%s)))", suffixp, suffixp); if (query == NULL) goto done; + /* Note: This DN is no need to be normalized. */ slapi_search_internal_set_pb(pb, "cn=mapping tree,cn=config", LDAP_SCOPE_SUBTREE, query, NULL, 0, NULL, NULL, (void *)plugin_get_default_component_id(), 0); @@ -2015,6 +2018,7 @@ static struct slapdplugin *lookup_plugin_by_instance_name(const char *name) return NULL; } + /* Note: This DN is no need to be normalized. */ slapi_search_internal_set_pb(pb, "cn=plugins,cn=config", LDAP_SCOPE_SUBTREE, query, NULL, 0, NULL, NULL, (void *)plugin_get_default_component_id(), 0); diff --git a/ldap/servers/slapd/mapping_tree.c b/ldap/servers/slapd/mapping_tree.c index 645618c2..7503929d 100644 --- a/ldap/servers/slapd/mapping_tree.c +++ b/ldap/servers/slapd/mapping_tree.c @@ -133,6 +133,7 @@ static int extension_type = -1; /* type returned from the factory */ /* Need to add a modifier flag to the state - such as round robin */ +/* Note: This DN is no need to be normalized. */ #define MAPPING_TREE_BASE_DN "cn=mapping tree,cn=config" #define MAPPING_TREE_PARENT_ATTRIBUTE "nsslapd-parent-suffix" @@ -365,24 +366,30 @@ static Slapi_DN * get_parent_from_entry(Slapi_Entry * entry) { Slapi_Attr *attr = NULL; - char * parent; + char *origparent = NULL; + char *parent = NULL; Slapi_Value *val = NULL; - Slapi_DN *parent_sdn; + Slapi_DN *parent_sdn = NULL; if (slapi_entry_attr_find(entry, MAPPING_TREE_PARENT_ATTRIBUTE, &attr)) return NULL; slapi_attr_first_value(attr, &val); - parent = slapi_ch_strdup(slapi_value_get_string(val)); - if(parent[0]=='\"') - { - parent[strlen(parent) - 1] = '\0'; - parent_sdn = slapi_sdn_new_dn_byval(parent+1); + origparent = parent = slapi_ch_strdup(slapi_value_get_string(val)); + if (parent) { + if(*parent == '"') { + char *ptr = NULL; + parent++; /* skipping the starting '"' */ + ptr = PL_strnrchr(parent, '"', strlen(parent)); + if (ptr) { + *ptr = '\0'; + } + } + parent_sdn = + slapi_sdn_new_dn_passin(slapi_create_dn_string("%s", parent)); + slapi_ch_free_string(&origparent); } - else - parent_sdn = slapi_sdn_new_dn_byval(parent); - slapi_ch_free((void **) &parent); return parent_sdn; } @@ -393,9 +400,10 @@ static Slapi_DN * get_subtree_from_entry(Slapi_Entry * entry) { Slapi_Attr *attr = NULL; - char * cn; + char *origcn = NULL; + char *cn = NULL; Slapi_Value *val = NULL; - Slapi_DN *subtree; + Slapi_DN *subtree = NULL; if (slapi_entry_attr_find(entry, "cn", &attr)) return NULL; @@ -415,15 +423,19 @@ get_subtree_from_entry(Slapi_Entry * entry) /* GB : I think removing the first and last " in the cn value * is the right stuff to do */ - cn = slapi_ch_strdup(slapi_value_get_string(val)); - if(cn[0]=='\"') - { - cn[strlen(cn) - 1] = '\0'; - subtree = slapi_sdn_new_dn_byval(cn+1); + origcn = cn = slapi_ch_strdup(slapi_value_get_string(val)); + if (cn) { + if(*cn == '"') { + char *ptr = NULL; + cn++; /* skipping the starting '"' */ + ptr = PL_strnrchr(cn, '"', strlen(cn)); + if (ptr) { + *ptr = '\0'; + } + } + subtree = slapi_sdn_new_dn_passin(slapi_create_dn_string("%s", cn)); + slapi_ch_free_string(&origcn); } - else - subtree = slapi_sdn_new_dn_byval(cn); - slapi_ch_free((void **) &cn); return subtree; } @@ -2790,7 +2802,7 @@ get_mapping_tree_node_by_name(mapping_tree_node * node, char * be_name) char* slapi_get_mapping_tree_node_configdn (const Slapi_DN *root) { - char *dn; + char *dn = NULL; if(mapping_tree_freed){ /* shutdown detected */ @@ -2799,7 +2811,16 @@ slapi_get_mapping_tree_node_configdn (const Slapi_DN *root) if (root == NULL) return NULL; - dn = slapi_ch_smprintf("cn=\"%s\",%s", slapi_sdn_get_dn(root), MAPPING_TREE_BASE_DN); + /* This function converts the old DN style to the new one. */ + dn = slapi_create_dn_string("cn=\"%s\",%s", + slapi_sdn_get_dn(root), MAPPING_TREE_BASE_DN); + if (NULL == dn) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "slapi_get_mapping_tree_node_configdn: " + "failed to crate mapping tree dn for %s\n", + slapi_sdn_get_dn(root)); + return NULL; + } return dn; } @@ -3114,7 +3135,7 @@ slapi_mtn_set_referral(const Slapi_DN *sdn, char ** referral) } slapi_mods_done(&smods); - slapi_ch_free((void **) &node_dn); + slapi_ch_free_string(&node_dn); return rc; } @@ -3135,13 +3156,13 @@ slapi_mtn_set_state(const Slapi_DN *sdn, char *state) char * node_dn; char * value; - node_dn = slapi_get_mapping_tree_node_configdn(sdn); - if(!node_dn){ - /* shutdown has been detected */ + if (NULL == state) { return LDAP_OPERATIONS_ERROR; } - if (NULL == state) { + node_dn = slapi_get_mapping_tree_node_configdn(sdn); + if(!node_dn){ + /* shutdown has been detected */ return LDAP_OPERATIONS_ERROR; } @@ -3150,9 +3171,7 @@ slapi_mtn_set_state(const Slapi_DN *sdn, char *state) if ( strcasecmp(value, state) == 0 ) { /* Same state, don't change anything */ - slapi_ch_free((void **) &value); - slapi_ch_free((void **) &node_dn); - return rc; + goto bail; } } @@ -3168,10 +3187,10 @@ slapi_mtn_set_state(const Slapi_DN *sdn, char *state) slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); slapi_mods_done(&smods); - slapi_ch_free((void **) &node_dn); pblock_done(&pb); - slapi_ch_free((void **) &value); - +bail: + slapi_ch_free_string(&value); + slapi_ch_free_string(&node_dn); return rc; } @@ -3265,7 +3284,7 @@ slapi_mtn_get_referral(const Slapi_DN *sdn) slapi_attr_free(&attr); } - slapi_ch_free((void **) &node_dn); + slapi_ch_free_string(&node_dn); return referral; } @@ -3301,7 +3320,7 @@ slapi_mtn_get_state(const Slapi_DN *sdn) slapi_attr_free(&attr); } - slapi_ch_free((void **) &node_dn); + slapi_ch_free_string(&node_dn); return state; } diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c index 40646b2b..027bbefb 100644 --- a/ldap/servers/slapd/modify.c +++ b/ldap/servers/slapd/modify.c @@ -166,16 +166,43 @@ do_modify( Slapi_PBlock *pb ) */ { - if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) + char *rawdn = NULL; + size_t dnlen = 0; + int rc = 0; + if ( ber_scanf( ber, "{a", &rawdn ) == LBER_ERROR ) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=Modify; params=DN)\n", 0, 0, 0 ); op_shared_log_error_access (pb, "MOD", "???", "decoding error"); - send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, - NULL ); - slapi_ch_free_string(&dn); + send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL ); + slapi_ch_free_string(&rawdn); return; } + /* Check if we should be performing strict validation. */ + if (config_get_dn_validate_strict()) { + /* check that the dn is formatted correctly */ + rc = slapi_dn_syntax_check(pb, rawdn, 1); + if (rc) { /* syntax check failed */ + op_shared_log_error_access(pb, "MOD", rawdn?rawdn:"", + "strict: invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free((void **) &rawdn); + return; + } + } + rc = slapi_dn_normalize_ext(rawdn, 0, &dn, &dnlen); + if (rc < 0) { + op_shared_log_error_access(pb, "MOD", "???", "invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free((void **) &rawdn); + return; + } else if (rc > 0) { /* if rc == 0, rawdn is passed in */ + slapi_ch_free_string(&rawdn); + } else { /* rc == 0; rawdn is passed in; not null terminated */ + *(dn + dnlen) = '\0'; + } } LDAPDebug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 ); diff --git a/ldap/servers/slapd/modrdn.c b/ldap/servers/slapd/modrdn.c index b70377a9..6951fb05 100644 --- a/ldap/servers/slapd/modrdn.c +++ b/ldap/servers/slapd/modrdn.c @@ -72,10 +72,13 @@ do_modrdn( Slapi_PBlock *pb ) { Slapi_Operation *operation; BerElement *ber; + char *rawdn = NULL, *rawnewsuperior = NULL; char *dn = NULL, *newsuperior = NULL; + char *rawnewrdn = NULL; char *newrdn = NULL; int err = 0, deloldrdn = 0; ber_len_t len = 0; + size_t dnlen = 0; LDAPDebug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 ); @@ -96,7 +99,7 @@ do_modrdn( Slapi_PBlock *pb ) * } */ - if ( ber_scanf( ber, "{aab", &dn, &newrdn, &deloldrdn ) + if ( ber_scanf( ber, "{aab", &rawdn, &rawnewrdn, &deloldrdn ) == LBER_ERROR ) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=ModRDN; params=DN,newRDN,deleteOldRDN)\n", @@ -109,25 +112,116 @@ do_modrdn( Slapi_PBlock *pb ) } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_NEWSUPERIOR ) { + /* This "len" is not used... */ if ( pb->pb_conn->c_ldapversion < LDAP_VERSION3 ) { LDAPDebug( LDAP_DEBUG_ANY, "got newSuperior in LDAPv2 modrdn op\n", 0, 0, 0 ); - op_shared_log_error_access (pb, "MODRDN", dn, "decoding error"); + op_shared_log_error_access (pb, "MODRDN", + rawdn?rawdn:"", "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "received newSuperior in LDAPv2 modrdn", 0, NULL ); + slapi_ch_free_string( &rawdn ); + slapi_ch_free_string( &rawnewrdn ); goto free_and_return; } - if ( ber_scanf( ber, "a", &newsuperior ) == LBER_ERROR ) { + if ( ber_scanf( ber, "a", &rawnewsuperior ) == LBER_ERROR ) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=ModRDN; params=newSuperior)\n", 0, 0, 0 ); - op_shared_log_error_access (pb, "MODRDN", dn, "decoding error"); + op_shared_log_error_access (pb, "MODRDN", rawdn, "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "unable to decode newSuperior parameter", 0, NULL ); + slapi_ch_free_string( &rawdn ); + slapi_ch_free_string( &rawnewrdn ); goto free_and_return; } } + /* Check if we should be performing strict validation. */ + if (config_get_dn_validate_strict()) { + /* check that the dn is formatted correctly */ + err = slapi_dn_syntax_check(pb, rawdn, 1); + if (err) { /* syntax check failed */ + op_shared_log_error_access(pb, "MODRDN", rawdn?rawdn:"", + "strict: invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free_string( &rawdn ); + slapi_ch_free_string( &rawnewrdn ); + slapi_ch_free_string( &rawnewsuperior ); + goto free_and_return; + } + /* check that the new rdn is formatted correctly */ + err = slapi_dn_syntax_check(pb, rawnewrdn, 1); + if (err) { /* syntax check failed */ + op_shared_log_error_access(pb, "MODRDN", rawnewrdn?rawnewrdn:"", + "strict: invalid new rdn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid new rdn", 0, NULL); + slapi_ch_free_string( &rawdn ); + slapi_ch_free_string( &rawnewrdn ); + slapi_ch_free_string( &rawnewsuperior ); + goto free_and_return; + } + } + err = slapi_dn_normalize_ext(rawdn, 0, &dn, &dnlen); + if (err < 0) { + op_shared_log_error_access(pb, "MODRDN", rawdn?rawdn:"", "invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free_string( &rawdn ); + slapi_ch_free_string( &rawnewrdn ); + slapi_ch_free_string( &rawnewsuperior ); + goto free_and_return; + } else if (err > 0) { + slapi_ch_free((void **) &rawdn); + } else { /* err == 0; rawdn is passed in; not null terminated */ + *(dn + dnlen) = '\0'; + } + err = slapi_dn_normalize_ext(rawnewrdn, 0, &newrdn, &dnlen); + if (err < 0) { + op_shared_log_error_access(pb, "MODRDN", rawnewrdn?rawnewrdn:"", + "invalid new rdn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid new rdn", 0, NULL); + slapi_ch_free_string( &rawnewrdn ); + slapi_ch_free_string( &rawnewsuperior ); + goto free_and_return; + } else if (err > 0) { + slapi_ch_free((void **) &rawnewrdn); + } else { /* err == 0; rawnewdn is passed in; not null terminated */ + *(newrdn + dnlen) = '\0'; + } + if (rawnewsuperior) { + if (config_get_dn_validate_strict()) { + /* check that the dn is formatted correctly */ + err = slapi_dn_syntax_check(pb, rawnewsuperior, 1); + if (err) { /* syntax check failed */ + op_shared_log_error_access(pb, "MODRDN", + rawnewsuperior?rawnewsuperior:"", + "strict: invalid new superior"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid new superior", 0, NULL); + slapi_ch_free_string( &rawnewsuperior ); + goto free_and_return; + } + } + err = slapi_dn_normalize_ext(rawnewsuperior, 0, &newsuperior, &dnlen); + if (err < 0) { + op_shared_log_error_access(pb, "MODRDN", + rawnewsuperior?rawnewsuperior:"", + "invalid new superior"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid new superior", 0, NULL); + slapi_ch_free_string( &rawnewsuperior); + goto free_and_return; + } else if (err > 0) { + slapi_ch_free((void **) &rawnewsuperior); + } else { /* err == 0; rawnewsuperior is passed in; not terminated */ + *(newsuperior + dnlen) = '\0'; + } + } + /* * in LDAPv3 there can be optional control extensions on * the end of an LDAPMessage. we need to read them in and @@ -153,9 +247,9 @@ do_modrdn( Slapi_PBlock *pb ) return; free_and_return: - slapi_ch_free((void **) &dn ); - slapi_ch_free((void **) &newrdn ); - slapi_ch_free((void **) &newsuperior ); + slapi_ch_free_string( &dn ); + slapi_ch_free_string( &newrdn ); + slapi_ch_free_string( &newsuperior ); return; } diff --git a/ldap/servers/slapd/modutil.c b/ldap/servers/slapd/modutil.c index 9c5949d5..82147c69 100644 --- a/ldap/servers/slapd/modutil.c +++ b/ldap/servers/slapd/modutil.c @@ -188,11 +188,37 @@ void slapi_mods_insert_at(Slapi_Mods *smods, LDAPMod *mod, int pos) { int i; - slapi_mods_add_one_element(smods); - for( i=smods->num_mods-1; i>=pos; i--) + Slapi_Attr a = {0}; + + if (NULL == mod) { + return; + } + slapi_mods_add_one_element(smods); + for( i=smods->num_mods-1; i>=pos; i--) { smods->mods[i+1]= smods->mods[i]; } + slapi_attr_init(&a, mod->mod_type); + /* Check if the type of the to-be-added values has DN syntax or not. */ + if (slapi_attr_is_dn_syntax_attr(&a)) { + int rc = 0; + struct berval **mbvp = NULL; + char *normed = NULL; + size_t len = 0; + for (mbvp = mod->mod_bvalues; mbvp && *mbvp; mbvp++) { + rc = slapi_dn_normalize_ext((*mbvp)->bv_val, (*mbvp)->bv_len, + &normed, &len); + if (rc > 0) { + slapi_ch_free((void **)&((*mbvp)->bv_val)); + } else if (rc == 0) { + /* original is passed in; not null terminated */ + *(normed + len) = '\0'; + } + (*mbvp)->bv_val = normed; + (*mbvp)->bv_len = len; + } + } + attr_done(&a); smods->mods[pos]= mod; smods->num_mods++; smods->mods[smods->num_mods]= NULL; diff --git a/ldap/servers/slapd/passwd_extop.c b/ldap/servers/slapd/passwd_extop.c index 14341f94..ff2e19f3 100644 --- a/ldap/servers/slapd/passwd_extop.c +++ b/ldap/servers/slapd/passwd_extop.c @@ -455,7 +455,9 @@ passwd_modify_extop( Slapi_PBlock *pb ) char *oid = NULL; char *bindDN = NULL; char *authmethod = NULL; + char *rawdn = NULL; char *dn = NULL; + size_t dnlen = 0; char *otdn = NULL; char *oldPasswd = NULL; char *newPasswd = NULL; @@ -561,16 +563,43 @@ passwd_modify_extop( Slapi_PBlock *pb ) /* identify userID field by tags */ if (tag == LDAP_EXTOP_PASSMOD_TAG_USERID ) { - if ( ber_scanf( ber, "a", &dn) == LBER_ERROR ) + int rc = 0; + if ( ber_scanf( ber, "a", &rawdn) == LBER_ERROR ) { - slapi_ch_free_string(&dn); + slapi_ch_free_string(&rawdn); LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed :{\n", 0, 0, 0 ); errMesg = "ber_scanf failed at userID parse.\n"; rc = LDAP_PROTOCOL_ERROR; goto free_and_return; } - + + /* Check if we should be performing strict validation. */ + if (config_get_dn_validate_strict()) { + /* check that the dn is formatted correctly */ + rc = slapi_dn_syntax_check(pb, rawdn, 1); + if (rc) { /* syntax check failed */ + op_shared_log_error_access(pb, "EXT", rawdn?rawdn:"", + "strict: invalid target dn"); + errMesg = "invalid target dn.\n"; + slapi_ch_free_string(&rawdn); + rc = LDAP_INVALID_SYNTAX; + goto free_and_return; + } + } + rc = slapi_dn_normalize_ext(rawdn, 0, &dn, &dnlen); + if (rc < 0) { + op_shared_log_error_access(pb, "EXT", rawdn?rawdn:"", + "invalid target dn"); + slapi_ch_free_string(&rawdn); + errMesg = "invalid target dn.\n"; + rc = LDAP_INVALID_SYNTAX; + goto free_and_return; + } else if (rc == 0) { /* rawdn is passed in, not terminated */ + *(dn + dnlen) = '\0'; + } else { + slapi_ch_free_string(&rawdn); + } tag = ber_peek_tag( ber, &len); } diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c index 133f60e3..84dbcfe5 100644 --- a/ldap/servers/slapd/plugin.c +++ b/ldap/servers/slapd/plugin.c @@ -268,8 +268,15 @@ slapi_register_plugin_ext( { int ii = 0; int rc = 0; - Slapi_Entry *e = slapi_entry_alloc(); - char *dn = slapi_ch_smprintf("cn=%s, %s", name, PLUGIN_BASE_DN); + Slapi_Entry *e = NULL; + char *dn = slapi_create_dn_string("cn=%s,%s", name, PLUGIN_BASE_DN); + if (NULL == dn) { + slapi_log_error(SLAPI_LOG_FATAL, NULL, + "slapi_register_plugin_ext: " + "failed to create plugin dn (plugin name: %s)\n", name); + return 1; + } + e = slapi_entry_alloc(); /* this function consumes dn */ slapi_entry_init(e, dn, NULL); @@ -2461,7 +2468,7 @@ plugin_invoke_plugin_sdn (struct slapdplugin *plugin, int operation, Slapi_PBloc */ char* plugin_get_dn (const struct slapdplugin *plugin) { - char *plugindn; + char *plugindn = NULL; char *pattern = "cn=%s," PLUGIN_BASE_DN; if (plugin == NULL) /* old plugin that does not pass identity - use default */ @@ -2470,8 +2477,13 @@ char* plugin_get_dn (const struct slapdplugin *plugin) if (plugin->plg_name == NULL) return NULL; - plugindn = slapi_ch_smprintf(pattern, plugin->plg_name); - + plugindn = slapi_create_dn_string(pattern, plugin->plg_name); + if (NULL == plugindn) { + slapi_log_error(SLAPI_LOG_FATAL, NULL, + "plugin_get_dn: failed to create plugin dn " + "(plugin name: %s)\n", plugin->plg_name); + return NULL; + } return plugindn; } @@ -2965,7 +2977,7 @@ slapi_set_plugin_default_config(const char *type, Slapi_Value *value) /* cn=plugin default config,cn=config */ pblock_init(&pb); slapi_search_internal_set_pb(&pb, - SLAPI_PLUGIN_DEFAULT_CONFIG, /* Base DN */ + SLAPI_PLUGIN_DEFAULT_CONFIG, /* Base DN (normalized) */ LDAP_SCOPE_BASE, "(objectclass=*)", search_attrs, /* Attrs */ @@ -3069,7 +3081,7 @@ slapi_get_plugin_default_config(char *type, Slapi_ValueSet **valueset) /* cn=plugin default config,cn=config */ pblock_init(&pb); slapi_search_internal_set_pb(&pb, - SLAPI_PLUGIN_DEFAULT_CONFIG, /* Base DN */ + SLAPI_PLUGIN_DEFAULT_CONFIG, /* Base DN (normalized) */ LDAP_SCOPE_BASE, "(objectclass=*)", search_attrs, /* Attrs */ diff --git a/ldap/servers/slapd/plugin_syntax.c b/ldap/servers/slapd/plugin_syntax.c index 384692db..5018326e 100644 --- a/ldap/servers/slapd/plugin_syntax.c +++ b/ldap/servers/slapd/plugin_syntax.c @@ -334,7 +334,7 @@ slapi_dn_syntax_check( } /* See if we need to set the error text in the pblock. */ - if (errp != &errtext[0]) { + if (pb && errp != &errtext[0]) { /* SLAPI_PB_RESULT_TEXT duplicates the text in slapi_pblock_set */ slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext ); } diff --git a/ldap/servers/slapd/search.c b/ldap/servers/slapd/search.c index fc3000cf..2909a170 100644 --- a/ldap/servers/slapd/search.c +++ b/ldap/servers/slapd/search.c @@ -68,6 +68,7 @@ do_search( Slapi_PBlock *pb ) BerElement *ber; int i, err, attrsonly; ber_int_t scope, deref, sizelimit, timelimit; + char *rawbase = NULL; char *base = NULL, *fstr = NULL; struct slapi_filter *filter = NULL; char **attrs = NULL; @@ -80,6 +81,8 @@ do_search( Slapi_PBlock *pb ) int rc = -1; char *original_base = 0; char *new_base = 0; + size_t baselen = 0; + int strict = 0; LDAPDebug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 ); @@ -114,13 +117,41 @@ do_search( Slapi_PBlock *pb ) */ /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */ - if ( ber_scanf( ber, "{aiiiib", &base, &scope, &deref, &sizelimit, &timelimit, &attrsonly ) == LBER_ERROR ){ - slapi_ch_free((void**)&base ); + if ( ber_scanf( ber, "{aiiiib", &rawbase, &scope, &deref, &sizelimit, &timelimit, &attrsonly ) == LBER_ERROR ){ + slapi_ch_free((void**)&rawbase ); log_search_access (pb, "???", -1, "???", "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL ); return; } + /* Check if we should be performing strict validation. */ + strict = config_get_dn_validate_strict(); + if (strict) { + /* check that the dn is formatted correctly */ + rc = slapi_dn_syntax_check(pb, rawbase, 1); + if (rc) { /* syntax check failed */ + op_shared_log_error_access(pb, "SRCH", + rawbase?rawbase:"", "strict: invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free((void **) &rawbase); + return; + } + } + rc = slapi_dn_normalize_ext(rawbase, 0, &base, &baselen); + if (rc < 0) { + op_shared_log_error_access(pb, "SRCH", + rawbase?rawbase:"", "invalid dn"); + send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, + NULL, "invalid dn", 0, NULL); + slapi_ch_free((void **) &rawbase); + return; + } else if (rc > 0) { /* if rc == 0, rawbase is passed in */ + slapi_ch_free((void **) &rawbase); + } else { /* rc == 0; rawbase is passed in; not null terminated */ + *(base + baselen) = '\0'; + } + /* * ignore negative time and size limits since they make no sense */ diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index 140158a2..aa5a88b4 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -575,9 +575,9 @@ typedef int (*SyntaxEnumFunc)(char **names, Slapi_PluginDesc *plugindesc, struct slapi_dn { unsigned char flag; - const char *dn; /* DN */ + const char *dn; /* DN [normalized] */ const char *ndn; /* Case Normalised DN */ - int ndn_len; /* normalize dn len */ + int ndn_len; /* normalized dn length */ }; /* diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index f7683b5e..2922a527 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -3025,28 +3025,74 @@ int slapi_rdn_partial_dup(Slapi_RDN *from, Slapi_RDN **to, int idx); * utility routines for dealing with DNs */ /** - * Normalizes a DN. + * Does nothing. (DEPRECATED) * * \param dn The DN to normalize. * \return The normalized DN. - * \deprecated Use slapi_sdn_get_ndn() instead. + * \deprecated Use slapi_dn_normalized_ext. */ char *slapi_dn_normalize( char *dn ); /** - * Normalizes a portion of a DN value. + * Does nothing. (DEPRECATED) * * \param dn The DN value to normalize. * \param end Pointer to the end of what will be normalized from the DN * value in \c dn. If this parameter is \c NULL, the DN value * will be wholly normalized. - * \return A pointer to the end of the DN that has been normalized. - * \warning This function does not null-terminate the string. Use this - * function only if you know what you are doing. + * \return The normalized DN. + * \deprecated Use slapi_dn_normalized_ext. */ char *slapi_dn_normalize_to_end( char *dn, char *end ); /** + * Normalizes a DN. + * + * \param src The DN to normalize. + * \param src_len The length of src DN to normalize. If 0 is given, strlen(src) is used. + * \param dest The normalized DN. + * \param dest The length of the normalized DN dest. + * \return \c 0 if successful. The dest DN is normalized in line. Caller must not free dest. + * \return \c 1 if successful. The dest DN is allocated. Caller must free dest. + * \return \c -1 if an error occurs (for example, if the src DN cannot be normalized) + */ +int slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len); + +/** + * Normalizes a DN (in lower-case characters). + * + * \param src The DN to normalize. + * \param src_len The length of src DN to normalize. If 0 is given, strlen(src) is used internally. + * \param dest The normalized DN with the cases lowered. + * \param dest_len The length of the normalized DN dest. + * \return \c 0 if successful. The dest DN is normalized in line. Caller must not free dest. The string is NOT NULL terminated. + * \return \c 1 if successful. The dest DN is allocated. Caller must free dest. + * \return \c -1 if an error occurs (for example, if src DN cannot be normalized) + */ +int slapi_dn_normalize_case_ext(char *src, size_t src_len, char **dest, size_t *dest_len); + +/** + * Generate a valid DN string. + * + * \param fmt The format used to generate a DN string. + * \param ... The arguments to generate a DN string. + * \return A pointer to the generated DN. The + * \return NULL if failed. + * \note When a DN needs to be internally created, this function is supposed to be called. This function allocates the enough memory for the normalized DN and returns it filled with the normalized DN. + */ +char *slapi_create_dn_string(const char *fmt, ...); + +/** + * Generates a valid DN string (in lower-case characters). + * + * \param fmt The format used to generate a DN string. + * \param ... The arguments to generate a DN string. + * \return A pointer to the generated DN. + * \return NULL if failed. + */ +char *slapi_create_dn_string_case(const char *fmt, ...); + +/** * Converts a DN to lowercase. * * \param dn The DN to convert. @@ -3332,6 +3378,15 @@ int slapi_attr_get_oid_copy( const Slapi_Attr *attr, char **oidp ); int slapi_attr_get_syntax_oid_copy( const Slapi_Attr *a, char **oidp ); /** + * Checks if the attribute uses a DN syntax or not. + * + * \param attr The attribute to be checked. + * \return \c non 0 if the attribute uses a DN syntax. + * \return \c 0 if the attribute does not use a DN syntax. + */ +int slapi_attr_is_dn_syntax_attr(Slapi_Attr *attr); + +/** * Get the flags associated with a particular attribute. * * Valid flags are: diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h index 84c3eb14..382cded0 100644 --- a/ldap/servers/slapd/slapi-private.h +++ b/ldap/servers/slapd/slapi-private.h @@ -364,6 +364,7 @@ const CSN *value_get_csn( const Slapi_Value *value, CSNType t ); const CSNSet *value_get_csnset ( const Slapi_Value *value); Slapi_Value *value_remove_csn( Slapi_Value *value, CSNType t); int value_contains_csn( const Slapi_Value *value, CSN *csn); +int value_normalize_value(Slapi_Value *value); /* dn.c */ /* this functions should only be used for dns allocated on the stack */ @@ -820,6 +821,7 @@ void valuearray_add_value_fast(Slapi_Value ***vals, Slapi_Value *addval, int nva void valuearray_add_valuearray( Slapi_Value ***vals, Slapi_Value **addvals, PRUint32 flags ); void valuearray_add_valuearray_fast( Slapi_Value ***vals, Slapi_Value **addvals, int nvals, int naddvals, int *maxvals, int exact, int passin ); int valuearray_find(const Slapi_Attr *a, Slapi_Value **va, const Slapi_Value *v); +int valuearray_normalize_value(Slapi_Value **vals); /****************************************************************************** diff --git a/ldap/servers/slapd/snmp_collator.c b/ldap/servers/slapd/snmp_collator.c index 9beb878a..9c485de4 100644 --- a/ldap/servers/slapd/snmp_collator.c +++ b/ldap/servers/slapd/snmp_collator.c @@ -873,7 +873,8 @@ loadConfigStats() { static Slapi_Entry * getConfigEntry( Slapi_Entry **e ) { Slapi_DN sdn; - + + /* SNMP_CONFIG_DN: no need to be normalized */ slapi_sdn_init_dn_byref( &sdn, SNMP_CONFIG_DN ); slapi_search_internal_get_entry( &sdn, NULL, e, plugin_get_default_component_id()); diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c index 733618f2..a7fe7892 100644 --- a/ldap/servers/slapd/task.c +++ b/ldap/servers/slapd/task.c @@ -60,13 +60,13 @@ static int shutting_down = 0; /*********************************** * Private Defines ***********************************/ -#define TASK_BASE_DN "cn=tasks, cn=config" -#define TASK_IMPORT_DN "cn=import, cn=tasks, cn=config" -#define TASK_EXPORT_DN "cn=export, cn=tasks, cn=config" -#define TASK_BACKUP_DN "cn=backup, cn=tasks, cn=config" -#define TASK_RESTORE_DN "cn=restore, cn=tasks, cn=config" -#define TASK_INDEX_DN "cn=index, cn=tasks, cn=config" -#define TASK_UPGRADEDB_DN "cn=upgradedb, cn=tasks, cn=config" +#define TASK_BASE_DN "cn=tasks,cn=config" +#define TASK_IMPORT_DN "cn=import,cn=tasks,cn=config" +#define TASK_EXPORT_DN "cn=export,cn=tasks,cn=config" +#define TASK_BACKUP_DN "cn=backup,cn=tasks,cn=config" +#define TASK_RESTORE_DN "cn=restore,cn=tasks,cn=config" +#define TASK_INDEX_DN "cn=index,cn=tasks,cn=config" +#define TASK_UPGRADEDB_DN "cn=upgradedb,cn=tasks,cn=config" #define TASK_LOG_NAME "nsTaskLog" #define TASK_STATUS_NAME "nsTaskStatus" @@ -403,9 +403,12 @@ int slapi_task_register_handler(const char *name, dseCallbackFn func) int ret = -1; int x; - dn = slapi_ch_smprintf("cn=%s, %s", name, TASK_BASE_DN); - if (dn == NULL) { - goto out; + dn = slapi_create_dn_string("cn=%s,%s", name, TASK_BASE_DN); + if (NULL == dn) { + LDAPDebug1Arg( LDAP_DEBUG_ANY, + "slapi_task_register_handler: " + "failed to create task dn for %s\n", name); + return ret; } pb = slapi_pblock_new(); @@ -458,9 +461,7 @@ int slapi_task_register_handler(const char *name, dseCallbackFn func) ret = 0; out: - if (dn) { - slapi_ch_free((void **)&dn); - } + slapi_ch_free_string(&dn); if (pb) { slapi_pblock_destroy(pb); } @@ -487,18 +488,27 @@ void slapi_task_set_cancel_fn(Slapi_Task *task, TaskCallbackFn func) ***********************************/ /* create a new task, fill in DN, and setup modify callback */ static Slapi_Task * -new_task(const char *dn) +new_task(const char *rawdn) { - Slapi_Task *task = (Slapi_Task *)slapi_ch_calloc(1, sizeof(Slapi_Task)); + Slapi_Task *task = NULL; + char *dn = NULL; + + if (rawdn == NULL) { + return NULL; + } - if (task == NULL) + dn = slapi_create_dn_string("%s", rawdn); + if (NULL == dn) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "new_task failed: invalid task dn: %s\n", rawdn); return NULL; + } + task = (Slapi_Task *)slapi_ch_calloc(1, sizeof(Slapi_Task)); PR_Lock(global_task_lock); task->next = global_task_list; global_task_list = task; PR_Unlock(global_task_lock); - - task->task_dn = slapi_ch_strdup(dn); + task->task_dn = dn; task->task_state = SLAPI_TASK_SETUP; task->task_flags = SLAPI_TASK_RUNNING_AS_TASK; task->destructor = NULL; @@ -511,8 +521,8 @@ new_task(const char *dn) /* don't add entries under this one */ #if 0 /* don't know why, but this doesn't work. it makes the current add - * * operation fail. :( - * */ + * operation fail. :( + */ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)", task_deny, NULL); #endif diff --git a/ldap/servers/slapd/tools/dbscan.c b/ldap/servers/slapd/tools/dbscan.c index ad22b424..320f5eda 100644 --- a/ldap/servers/slapd/tools/dbscan.c +++ b/ldap/servers/slapd/tools/dbscan.c @@ -434,7 +434,7 @@ static ID id_stored_to_internal(char* b) static void id_internal_to_stored(ID i,char *b) { if ( sizeof(ID) > 4 ) { - memset (b+4, 0, sizeof(ID)-4); + (void)memset (b+4, 0, sizeof(ID)-4); } b[0] = (char)(i >> 24); diff --git a/ldap/servers/slapd/tools/ldclt/ldclt.h b/ldap/servers/slapd/tools/ldclt/ldclt.h index c8ead2c5..48c398be 100644 --- a/ldap/servers/slapd/tools/ldclt/ldclt.h +++ b/ldap/servers/slapd/tools/ldclt/ldclt.h @@ -741,6 +741,7 @@ extern char *dnFromMessage (thread_context *tttctx, LDAPMessage *res); extern int doAddEntry (thread_context *tttctx); extern int doAttrReplace (thread_context *tttctx); /*JLS 21-11-00*/ extern int doAttrFileReplace (thread_context *tttctx); + extern int doBindOnly (thread_context *tttctx); /*JLS 04-05-01*/ extern int doDeleteEntry (thread_context *tttctx); extern int doExactSearch (thread_context *tttctx); diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c index d26b0b98..8987e634 100644 --- a/ldap/servers/slapd/util.c +++ b/ldap/servers/slapd/util.c @@ -335,8 +335,9 @@ int slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs) * * normalize_mods2bvals * -* -* +* Return value: normalized mods +* The values/bvals are all duplicated in this function since +* the normalized mods are freed with ldap_mods_free by the caller. * *******************************************************************************/ @@ -360,6 +361,18 @@ normalize_mods2bvals(const LDAPMod **mods) for (w = 0; mods[w] != NULL; w++) { + Slapi_Attr a = {0}; + slapi_attr_init(&a, mods[w]->mod_type); + int is_dn_syntax = 0; + struct berval **normmbvp = NULL; + + /* Check if the type of the to-be-added values has DN syntax + * or not. */ + if (slapi_attr_is_dn_syntax_attr(&a)) { + is_dn_syntax = 1; + } + attr_done(&a); + /* copy each mod into a normalized modbvalue */ normalized_mods[w] = (LDAPMod *) slapi_ch_calloc(1, sizeof(LDAPMod)); normalized_mods[w]->mod_op = mods[w]->mod_op | LDAP_MOD_BVALUES; @@ -397,32 +410,79 @@ normalize_mods2bvals(const LDAPMod **mods) if (mods[w]->mod_op & LDAP_MOD_BVALUES) { - for (x = 0; mods[w]->mod_bvalues != NULL && - mods[w]->mod_bvalues[x] != NULL; x++) + struct berval **mbvp = NULL; + + for (mbvp = mods[w]->mod_bvalues, + normmbvp = normalized_mods[w]->mod_bvalues; + mbvp && *mbvp; mbvp++, normmbvp++) { - normalized_mods[w]->mod_bvalues[x] = ber_bvdup(mods[w]->mod_bvalues[x]); + if (is_dn_syntax) { + int rc = 0; + char *normed = NULL; + size_t dnlen = 0; + + rc = slapi_dn_normalize_ext((*mbvp)->bv_val, + (*mbvp)->bv_len, + &normed, &dnlen); + if (rc < 0) { /* normalization failed; use the original */ + *normmbvp = ber_bvdup(*mbvp); + } else if (rc == 0) { /* if rc == 0, value is passed in */ + *(normed + dnlen) = '\0'; + *normmbvp = ber_bvdup(*mbvp); + } else { + (*normmbvp)->bv_val = normed; + (*normmbvp)->bv_len = dnlen; + } + } else { + *normmbvp = ber_bvdup(*mbvp); + } } } else { - for (x = 0; mods[w]->mod_values != NULL && - mods[w]->mod_values[x] != NULL; x++) + char **mvp = NULL; + + for (mvp = mods[w]->mod_values, + normmbvp = normalized_mods[w]->mod_bvalues; + mvp && *mvp; mvp++, normmbvp++) { - normalized_mods[w]->mod_bvalues[ x ] = (struct berval *) - slapi_ch_calloc(1, sizeof(struct berval)); - - vlen = strlen(mods[w]->mod_values[x]); - normalized_mods[w]->mod_bvalues[ x ]->bv_val = - slapi_ch_calloc(vlen + 1, sizeof(char)); - memcpy(normalized_mods[w]->mod_bvalues[ x ]->bv_val, - mods[w]->mod_values[x], vlen); - normalized_mods[w]->mod_bvalues[ x ]->bv_val[vlen] = '\0'; - normalized_mods[w]->mod_bvalues[ x ]->bv_len = vlen; + *normmbvp = + (struct berval *)slapi_ch_malloc(sizeof(struct berval)); + + vlen = strlen(*mvp); + + if (is_dn_syntax) { + int rc = 0; + char *normed = NULL; + size_t dnlen = 0; + rc = slapi_dn_normalize_ext(*mvp, vlen, + &normed, &dnlen); + if (rc < 0) { /* normalization failed; use the original */ + (*normmbvp)->bv_val = slapi_ch_malloc(vlen + 1); + memcpy((*normmbvp)->bv_val, *mvp, vlen); + (*normmbvp)->bv_val[vlen] = '\0'; + (*normmbvp)->bv_len = vlen; + } else if (rc == 0) { /* if rc == 0, value is passed in */ + *(normed + dnlen) = '\0'; + (*normmbvp)->bv_val = slapi_ch_strdup(normed); + (*normmbvp)->bv_len = dnlen; + } else { + (*normmbvp)->bv_val = normed; + (*normmbvp)->bv_len = dnlen; + } + } else { + (*normmbvp)->bv_val = slapi_ch_malloc(vlen + 1); + memcpy((*normmbvp)->bv_val, *mvp, vlen); + (*normmbvp)->bv_val[vlen] = '\0'; + (*normmbvp)->bv_len = vlen; + } } } + PR_ASSERT(normmbvp - normalized_mods[w]->mod_bvalues <= num_values); + /* don't forget to null terminate it */ - if (num_values > 0) + if (num_values > 0) { - normalized_mods[w]->mod_bvalues[ x ] = NULL; + *normmbvp = NULL; } } diff --git a/ldap/servers/slapd/value.c b/ldap/servers/slapd/value.c index 72f94b93..c0cf66e9 100644 --- a/ldap/servers/slapd/value.c +++ b/ldap/servers/slapd/value.c @@ -551,3 +551,29 @@ value_dump( const Slapi_Value *value, const char *text) } #endif +int +value_normalize_value(Slapi_Value *value) +{ + char *normval = NULL; + size_t len = 0; + int rc = 0; + + if (NULL == value) { + return 0; + } + + rc = slapi_dn_normalize_ext(value->bv.bv_val, value->bv.bv_len, + &normval, &len); + if (rc < 0) { + return 1; + } else if (rc > 0) { /* if rc == 0, the original value is passed in */ + slapi_ch_free_string(&value->bv.bv_val); + } else { /* rc == 0; original is passed in; not null terminated */ + /* since bvalue, no need to terminate with null, tho */ + *(normval + len) = '\0'; + } + value->bv.bv_val = normval; + value->bv.bv_len = len; + + return 0; +} diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c index d6909ac8..22ffb4aa 100644 --- a/ldap/servers/slapd/valueset.c +++ b/ldap/servers/slapd/valueset.c @@ -1437,3 +1437,17 @@ valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slap *valuesupdated= vaf_valuesupdated.va; } } + +int +valuearray_normalize_value(Slapi_Value **vals) +{ + int rc = 0; + Slapi_Value **vp = NULL; + + for (vp = vals; vp && *vp; vp++) { + rc |= value_normalize_value(*vp); + } + + return rc; +} + |