diff mbox

[05/11] libnsdb: Add nsdb_find_naming_context_s()

Message ID 20121106173341.26310.45251.stgit@seurat.1015granger.net
State Accepted
Headers show

Commit Message

Chuck Lever Nov. 6, 2012, 5:33 p.m. UTC
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(-)
diff mbox

Patch

diff --git a/src/include/nsdb.h b/src/include/nsdb.h
index 89d2505..adb9bfb 100644
--- a/src/include/nsdb.h
+++ b/src/include/nsdb.h
@@ -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)
diff --git a/src/libnsdb/administrator.c b/src/libnsdb/administrator.c
index 896a8a8..00bdd10 100644
--- a/src/libnsdb/administrator.c
+++ b/src/libnsdb/administrator.c
@@ -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;
 }
 
diff --git a/src/libnsdb/fileserver.c b/src/libnsdb/fileserver.c
index 3cf3673..ad53605 100644
--- a/src/libnsdb/fileserver.c
+++ b/src/libnsdb/fileserver.c
@@ -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;
+}
diff --git a/src/libnsdb/ldap.c b/src/libnsdb/ldap.c
index 26331d6..404f6d1 100644
--- a/src/libnsdb/ldap.c
+++ b/src/libnsdb/ldap.c
@@ -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;
+}
diff --git a/src/libnsdb/nsdb-internal.h b/src/libnsdb/nsdb-internal.h
index 969fe48..7defe6d 100644
--- a/src/libnsdb/nsdb-internal.h
+++ b/src/libnsdb/nsdb-internal.h
@@ -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);
 
 
 /**