@@ -326,6 +326,8 @@ FedFsStatus nsdb_get_naming_contexts_s(nsdb_t host, char ***contexts,
FedFsStatus nsdb_split_nce_dn_s(nsdb_t host, const char *nce,
char **context, char **prefix,
unsigned int *ldap_err);
+FedFsStatus nsdb_find_naming_context_s(nsdb_t host, const char *entry,
+ char **context, unsigned int *ldap_err);
/**
* Resolve an FSN (5.2.2)
@@ -1143,8 +1143,8 @@ nsdb_add_nci_attributes_s(LDAP *ld, const char *context,
FedFsStatus
nsdb_update_nci_s(nsdb_t host, const char *nce, unsigned int *ldap_err)
{
- char *context, *prefix;
FedFsStatus retval;
+ char *context;
if (host->fn_ldap == NULL) {
xlog(L_ERROR, "%s: NSDB not open", __func__);
@@ -1156,14 +1156,13 @@ nsdb_update_nci_s(nsdb_t host, const char *nce, unsigned int *ldap_err)
return FEDFS_ERR_INVAL;
}
- retval = nsdb_split_nce_dn_s(host, nce, &context, &prefix, ldap_err);
+ retval = nsdb_find_naming_context_s(host, nce, &context, ldap_err);
if (retval != FEDFS_OK)
return retval;
retval = nsdb_add_nci_attributes_s(host->fn_ldap, context, nce,
ldap_err);
free(context);
- free(prefix);
return retval;
}
@@ -1228,8 +1227,8 @@ nsdb_remove_nci_attributes_s(LDAP *ld, const char *context,
FedFsStatus
nsdb_remove_nci_s(nsdb_t host, const char *nce, unsigned int *ldap_err)
{
- char *context, *prefix;
FedFsStatus retval;
+ char *context;
if (host->fn_ldap == NULL) {
xlog(L_ERROR, "%s: NSDB not open", __func__);
@@ -1241,14 +1240,13 @@ nsdb_remove_nci_s(nsdb_t host, const char *nce, unsigned int *ldap_err)
return FEDFS_ERR_INVAL;
}
- retval = nsdb_split_nce_dn_s(host, nce, &context, &prefix, ldap_err);
+ retval = nsdb_find_naming_context_s(host, nce, &context, ldap_err);
if (retval != FEDFS_OK)
return retval;
retval = nsdb_remove_nci_attributes_s(host->fn_ldap, context, ldap_err);
free(context);
- free(prefix);
return retval;
}
@@ -1653,3 +1653,85 @@ out:
__func__, nsdb_display_fedfsstatus(retval));
return retval;
}
+
+/**
+ * See if "entry" ends with one of the items of "contexts"
+ *
+ * @param entry a NUL-terminated C string containing DN of some entry
+ * @param contexts pointer to an array of NUL-terminated C strings
+ * @param context OUT: a NUL-terminated C string containing a suffix DN
+ * @param ldap_err OUT: possibly an LDAP error code
+ * @return a FedFsStatus code
+ */
+static FedFsStatus
+nsdb_match_root_suffix(const char *entry, char **contexts,
+ char **context, unsigned int *ldap_err)
+{
+ unsigned int i;
+
+ for (i = 0; contexts[i] != NULL; i++) {
+ _Bool result;
+
+ result = nsdb_dn_ends_with(entry, contexts[i], ldap_err);
+ if (*ldap_err != LDAP_SUCCESS)
+ return FEDFS_ERR_NSDB_LDAP_VAL;
+ if (result)
+ goto found;
+ }
+
+ xlog(D_CALL, "%s: context not found", __func__);
+ return FEDFS_ERR_NSDB_NONCE;
+
+found:
+ *context = strdup(contexts[i]);
+ if (*context == NULL) {
+ xlog(D_GENERAL, "%s: No memory", __func__);
+ return FEDFS_ERR_SVRFAULT;
+ }
+
+ xlog(D_CALL, "%s: context='%s'", __func__, contexts[i]);
+ return FEDFS_OK;
+}
+
+/**
+ * Discover naming context under which an entry resides
+ *
+ * @param host an initialized and bound nsdb_t object
+ * @param entry a NUL-terminated C string containing DN of some entry
+ * @param context OUT: a NUL-terminated C string containing a suffix DN
+ * @param ldap_err OUT: possibly an LDAP error code
+ * @return a FedFsStatus code
+ *
+ * "entry" must already exist on "host". Caller must free
+ * "context" with free(3).
+ *
+ * Strategy:
+ * 1. Retrieve the list of root suffixes on "host"
+ * 2. For each root suffix, see if "entry" ends with that suffix
+ */
+FedFsStatus
+nsdb_find_naming_context_s(nsdb_t host, const char *entry, char **context,
+ unsigned int *ldap_err)
+{
+ char **contexts = NULL;
+ FedFsStatus retval;
+
+ if (host->fn_ldap == NULL) {
+ xlog(L_ERROR, "%s: NSDB not open", __func__);
+ return FEDFS_ERR_INVAL;
+ }
+
+ if (context == NULL || ldap_err == NULL) {
+ xlog(L_ERROR, "%s: Invalid parameter", __func__);
+ return FEDFS_ERR_INVAL;
+ }
+
+ retval = nsdb_get_naming_contexts_s(host, &contexts, ldap_err);
+ if (retval != FEDFS_OK)
+ return retval;
+
+ retval = nsdb_match_root_suffix(entry, contexts, context, ldap_err);
+
+ nsdb_free_string_array(contexts);
+ return retval;
+}
@@ -1178,3 +1178,82 @@ out:
free(rstr);
return retval;
}
+
+/**
+ * Compare two LDAP distinguished names
+ *
+ * @param dn a structured LDAP distinguished name
+ * @param suffix a structured LDAP distinguished name
+ * @return if true, the DNs match
+ */
+static _Bool
+nsdb_ends_with(LDAPDN dn, LDAPDN suffix)
+{
+ unsigned int count_d, count_s;
+
+ for (count_d = 0; dn[count_d] != NULL; count_d++);
+ for (count_s = 0; suffix[count_s] != NULL; count_s++);
+
+ if (count_d < count_s || count_s == 0)
+ return false;
+
+ for (; count_s != 0; count_d--, count_s--)
+ if (!nsdb_compare_rdns(dn[count_d - 1], suffix[count_s - 1]))
+ return false;
+ return true;
+}
+
+/**
+ * Predicate: See if "dn" ends with "suffix"
+ *
+ * @param dn_in a NUL-terminated C string containing a distinguished name
+ * @param suffix_in a NUL-terminated C string containing a distinguished name
+ * @param ldap_err OUT: possibly an LDAP error code
+ * @return if true, "dn" ends with "suffix"
+ *
+ * On return, the return value is valid only if "ldap_err" is
+ * LDAP_SUCCESS.
+ */
+_Bool
+nsdb_dn_ends_with(const char *dn_in, const char *suffix_in,
+ unsigned int *ldap_err)
+{
+ LDAPDN dn = NULL;
+ LDAPDN suffix = NULL;
+ _Bool result;
+ int rc;
+
+ result = false;
+
+ if (dn_in == NULL || suffix_in == NULL || ldap_err == NULL) {
+ xlog(L_ERROR, "%s: Invalid parameter", __func__);
+ goto out;
+ }
+
+ rc = ldap_str2dn(dn_in, &dn, LDAP_DN_FORMAT_LDAPV3);
+ if (rc != LDAP_SUCCESS) {
+ *ldap_err = rc;
+ goto out;
+ }
+
+ rc = ldap_str2dn(suffix_in, &suffix, LDAP_DN_FORMAT_LDAPV3);
+ if (rc != LDAP_SUCCESS) {
+ *ldap_err = rc;
+ goto out;
+ }
+
+ *ldap_err = LDAP_SUCCESS;
+ result = nsdb_ends_with(dn, suffix);
+
+ if (result)
+ xlog(D_CALL, "%s: dn '%s' ends with '%s'",
+ __func__, dn_in, suffix_in);
+ else
+ xlog(D_CALL, "%s: dn '%s' does not end with '%s'",
+ __func__, dn_in, suffix_in);
+
+out:
+ ldap_dnfree(suffix);
+ ldap_dnfree(dn);
+ return result;
+}
@@ -112,6 +112,8 @@ _Bool nsdb_compare_dn_strings(const char *dn1_in,
FedFsStatus nsdb_left_remove_rdn(LDAPDN *dn, unsigned int *ldap_err);
FedFsStatus nsdb_right_append_rdn(LDAPDN *dn, LDAPRDN rdn,
unsigned int *ldap_err);
+_Bool nsdb_dn_ends_with(const char *dn_in, const char *suffix_in,
+ unsigned int *ldap_err);
/**
Thanks to recent changes in the NSDB protocol, we don't need to compute a DN prefix any more, so introduce a simpler API. I've prefer to have the LDAP server tell us which root suffix is the parent of a DN, but I haven't found a way to do this. The correct root suffix is still chosen by iteratively comparing the DN's suffix with the root suffix. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- src/include/nsdb.h | 2 + src/libnsdb/administrator.c | 10 ++--- src/libnsdb/fileserver.c | 82 +++++++++++++++++++++++++++++++++++++++++++ src/libnsdb/ldap.c | 79 +++++++++++++++++++++++++++++++++++++++++ src/libnsdb/nsdb-internal.h | 2 + 5 files changed, 169 insertions(+), 6 deletions(-)