return talloc_strdup(mem_ctx, ldb_dn_get_casefold(dn));
}
-/* Determine if dn is below base, in the ldap tree. Used for
- * evaluating a subtree search.
- * 0 if they match, otherwise non-zero
+/**
+ * @brief Compare the linerarized part of DNs and see if the dn match the base one
+ *
+ * This function check if dn DN match the base DN, it assumes that both DN have
+ * a linearized version. There is no good reason to use this function directly
+ * it has been abstracted to a function in order to make the
+ * function ldb_dn_compare_base_internal more readable, you should use this one
+ * instead.
+ *
+ * @param[in] base The base DN that is checked against
+ *
+ * @param[in] dn The DN to test
+ *
+ * @param[in] onelevel A boolean to indicate if we validate only
+ * DN that are just 1 level bellow the DN
+ *
+ * @return 0 if the DN is bellow (as influenced by the
+ * onelevel parameter), > 0 if it's not, and < 0
+ * if a check on each componenent is needed
*/
+static int ldb_dn_linearized_compare_base(struct ldb_dn *base, struct ldb_dn *dn,
+ bool onelevel)
+{
+ int dif;
+ int i;
+ bool comma_found = false;
+ dif = strlen(dn->linearized) - strlen(base->linearized);
+ if (dif < 0) {
+ return 1;
+ }
+ if (!base->linearized[0]) {
+ if (onelevel) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
-int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn)
+ if (onelevel && dif == 0) {
+ /*
+ * dn has the same length as base, and we were
+ * asked for comparing only onelevel so this
+ * can't be ok whatever the comparison of the string returns
+ */
+ return 1;
+ }
+
+ if (strcmp(base->linearized, &dn->linearized[dif]) == 0) {
+ if (dif == 0) {
+ /*
+ * Same length, same content, not onelevel search
+ * that's ok, matched.
+ */
+ return 0;
+ }
+
+ /*
+ * So far we know that len(dn) > len(base) and that
+ * (char*)(dn->linearized+dif) match base->linearized
+ * We can have 0 or more comma ',' if it's 0 it's not a match
+ * (it's for instance dn: adc=sambacorp and base dc=sambacorp)
+ *
+ * As we already matched the string in base->linearized, we
+ * know that dn is a child of base only if chars between the
+ * last comma in the non matched part (from 0 to dif) and the
+ * end of the matched part are spaces.
+ * If there is comma it's also not a match.
+ *
+ * If there is more than 1 comma and if onelevel is true then
+ * it might be ok but in order to be sure and avoid costly
+ * checks for the vast majority of onelevel, we return -1,
+ * leaving it for more complete checks.
+ */
+ i = dif - 1;
+ /*
+ * Loop starting from then of the difference string
+ * we break if we found something else than a space or a comma
+ * ie. with basedn: dc=sambacorp
+ * if we have
+ * cn="foobar"dc=sambacorp
+ * or
+ * bdc=sambacorp
+ * or
+ * a=truc dc=sambacorp
+ */
+ while ((i > 0) && (!comma_found)) {
+ /* ',' or ' ' => ok, else fail */
+ if (dn->linearized[i] == ',') {
+ comma_found = true;
+ break;
+ }
+ if (dn->linearized[i] == ' ') {
+ i--;
+ continue;
+ }
+ break;
+ }
+ /*
+ * No comma, we already took care of dn1 == dn2 before
+ * so this can't be good
+ */
+ if (!comma_found) {
+ return 1;
+ }
+
+ /*
+ * Ok at least one separating comma and we are not doing a
+ * one level match so it's ok
+ */
+ if (!onelevel) {
+ return 0;
+ }
+ comma_found = false;
+ while ((i > 0) && (!comma_found)) {
+ if (dn->linearized[i] == ',' &&
+ dn->linearized[i-1] != '\\') {
+ comma_found = true;
+ break;
+ }
+ i--;
+ }
+ if (comma_found) {
+ /*
+ * Ok we are not sure, it looks like we have more than
+ * one ',' but it might be in between quote
+ * so we return -1, so the caller know that it
+ * has to use a more complex way of comparing
+ */
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ /*
+ * dn can differ in the case and still be the same so let's leave
+ * it to the caller to do a more complete check
+ */
+ return -1;
+}
+/**
+ * @brief compare if a DN is bellow the base
+ *
+ * A DN is said to be bellow another if the last n components of it are the same
+ * as the n component of the base DN
+ *
+ * @param[in] base The base DN that is checked against
+ *
+ * @param[in] dn The DN to test
+ *
+ * @param[in] onelevel A boolean to indicate if we validate only
+ * DN that are just 1 level bellow the DN
+ *
+ * @return 0 if the DN is bellow (as influenced by the
+ * onelevel parameter), non zero otherwise
+ */
+static int ldb_dn_compare_base_internal(struct ldb_dn *base, struct ldb_dn *dn,
+ bool onelevel)
{
int ret;
unsigned int n_base, n_dn;
if (( ! base->valid_case) || ( ! dn->valid_case)) {
if (base->linearized && dn->linearized && dn->special == base->special) {
- /* try with a normal compare first, if we are lucky
- * we will avoid exploding and casfolding */
- int dif;
- dif = strlen(dn->linearized) - strlen(base->linearized);
- if (dif < 0) {
- return dif;
- }
- if (strcmp(base->linearized,
- &dn->linearized[dif]) == 0) {
- return 0;
+ /*
+ * try with a normal compare first, if we are lucky
+ * we will avoid exploding and casefolding
+ */
+ ret = ldb_dn_linearized_compare_base(base, dn, onelevel);
+ if (ret >=0 ) {
+ return ret;
}
}
- if ( ! ldb_dn_casefold_internal(base)) {
+ if (!ldb_dn_casefold_internal(base)) {
return 1;
}
- if ( ! ldb_dn_casefold_internal(dn)) {
+ if (!ldb_dn_casefold_internal(dn)) {
return -1;
}
return (dn->comp_num - base->comp_num);
}
+ if (onelevel && (dn->comp_num != (base->comp_num + 1))) {
+ int v = dn->comp_num - base->comp_num;
+
+ return v == 0 ? 1: v;
+ }
+
if ((dn->comp_num == 0) || (base->comp_num == 0)) {
if (dn->special && base->special) {
return strcmp(base->linearized, dn->linearized);
return 0;
}
+/**
+ * @brief Determine if DN is bellow base DN
+ *
+ * @param[in] base The base DN of the comparison
+ *
+ * @param[in] dn The DN to test
+ *
+ * @return 0 if the DN is bellow base in the ldap tree,
+ * otherwise non-zero
+ */
+int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn)
+{
+ return ldb_dn_compare_base_internal(base, dn, false);
+}
+
+/**
+ * @brief Determine if DN is one level bellow base DN
+ *
+ * @param[in] base The base DN of the comparison
+ *
+ * @param[in] dn The DN to test
+ *
+ * @return 0 if the DN is one level bellow base in the ldap tree,
+ * otherwise non-zero
+ */
+int ldb_dn_compare_base_one(struct ldb_dn *base, struct ldb_dn *dn)
+{
+ return ldb_dn_compare_base_internal(base, dn, true);
+}
+
/* compare DNs using casefolding compare functions.
If they match, then return 0