diff mbox

[02/11] libnsdb: Handle LDAP referrals in an LDAP_RES_SEARCH_RESULT

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

Commit Message

Chuck Lever Dec. 14, 2012, 10:37 p.m. UTC
So that callers can extract the location of the referred-to LDAP
server, change nsdb_parse_result() to parse an array of referral
URIs, if one is returned.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 src/libnsdb/administrator.c |    4 +--
 src/libnsdb/fileserver.c    |   10 ++++---
 src/libnsdb/ldap.c          |   60 +++++++++++++++++++++++++++++++++++++++++--
 src/libnsdb/nsdb-internal.h |    2 +
 4 files changed, 65 insertions(+), 11 deletions(-)
diff mbox

Patch

diff --git a/src/libnsdb/administrator.c b/src/libnsdb/administrator.c
index a664fa9..aa4aad3 100644
--- a/src/libnsdb/administrator.c
+++ b/src/libnsdb/administrator.c
@@ -474,7 +474,7 @@  again:
 			retval = nsdb_parse_reference(ld, message, ldap_err);
 			break;
 		case LDAP_RES_SEARCH_RESULT:
-			retval = nsdb_parse_result(ld, message, ldap_err);
+			retval = nsdb_parse_result(ld, message, NULL, ldap_err);
 			break;
 		default:
 			xlog(L_ERROR, "%s: Unrecognized LDAP message type",
@@ -1658,7 +1658,7 @@  again:
 			retval = nsdb_parse_reference(ld, message, ldap_err);
 			break;
 		case LDAP_RES_SEARCH_RESULT:
-			retval = nsdb_parse_result(ld, message, ldap_err);
+			retval = nsdb_parse_result(ld, message, NULL, ldap_err);
 			break;
 		default:
 			xlog(L_ERROR, "%s: Unrecognized LDAP message type",
diff --git a/src/libnsdb/fileserver.c b/src/libnsdb/fileserver.c
index cb25f3b..d4519d6 100644
--- a/src/libnsdb/fileserver.c
+++ b/src/libnsdb/fileserver.c
@@ -443,7 +443,7 @@  nsdb_get_ncedn_s(nsdb_t host, const char *naming_context, char **dn,
 			retval = nsdb_parse_reference(ld, message, ldap_err);
 			break;
 		case LDAP_RES_SEARCH_RESULT:
-			retval = nsdb_parse_result(ld, message, ldap_err);
+			retval = nsdb_parse_result(ld, message, NULL, ldap_err);
 			break;
 		default:
 			xlog(L_ERROR, "%s: Unrecognized LDAP message type",
@@ -632,7 +632,7 @@  nsdb_get_naming_contexts_s(nsdb_t host, char ***contexts,
 							message, ldap_err);
 			break;
 		case LDAP_RES_SEARCH_RESULT:
-			retval = nsdb_parse_result(ld, message, ldap_err);
+			retval = nsdb_parse_result(ld, message, NULL, ldap_err);
 			break;
 		default:
 			xlog(L_ERROR, "%s: Unrecognized LDAP message type",
@@ -1091,7 +1091,7 @@  nsdb_resolve_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid,
 			retval = nsdb_parse_reference(ld, message, ldap_err);
 			break;
 		case LDAP_RES_SEARCH_RESULT:
-			retval = nsdb_parse_result(ld, message, ldap_err);
+			retval = nsdb_parse_result(ld, message, NULL, ldap_err);
 			break;
 		default:
 			xlog(L_ERROR, "%s: Unrecognized LDAP message type",
@@ -1404,7 +1404,7 @@  nsdb_get_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid,
 			retval = nsdb_parse_reference(ld, message, ldap_err);
 			break;
 		case LDAP_RES_SEARCH_RESULT:
-			retval = nsdb_parse_result(ld, message, ldap_err);
+			retval = nsdb_parse_result(ld, message, NULL, ldap_err);
 			break;
 		default:
 			xlog(L_ERROR, "%s: Unrecognized LDAP message type",
@@ -1663,7 +1663,7 @@  nsdb_list_find_entries_s(LDAP *ld, const char *nce, char ***fsns,
 			retval = nsdb_parse_reference(ld, message, ldap_err);
 			break;
 		case LDAP_RES_SEARCH_RESULT:
-			retval = nsdb_parse_result(ld, message, ldap_err);
+			retval = nsdb_parse_result(ld, message, NULL, ldap_err);
 			break;
 		default:
 			xlog(L_ERROR, "%s: Unrecognized LDAP message type",
diff --git a/src/libnsdb/ldap.c b/src/libnsdb/ldap.c
index f6b430e..0abbdd2 100644
--- a/src/libnsdb/ldap.c
+++ b/src/libnsdb/ldap.c
@@ -810,18 +810,66 @@  nsdb_parse_reference(LDAP *ld, LDAPMessage *reference,
 }
 
 /**
+ * Duplicate an array of referral URIs
+ *
+ * @param refs an array of NUL-terminated C strings containing LDAP URIs
+ * @param referrals OUT: pointer to an array of NUL-terminated C strings
+ * @return a FedFsStatus code
+ *
+ * Caller must free "referrals" with nsdb_free_string_array().
+ */
+static FedFsStatus
+nsdb_copy_referrals_array(char **refs, char ***referrals)
+{
+	int i, count;
+	char **tmp;
+
+	for (i = 0; refs[i] != NULL; i++)
+		xlog(D_GENERAL, "%s: Referral: %s", __func__, refs[i]);
+	if (referrals == NULL)
+		return FEDFS_OK;
+	count = i;
+
+	tmp = calloc(count, sizeof(char *));
+	if (tmp == NULL) {
+		xlog(D_GENERAL, "%s: no memory for array", __func__);
+		return FEDFS_ERR_SVRFAULT;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp[i] = strdup(refs[i]);
+		if (tmp[i] == NULL) {
+			xlog(D_GENERAL, "%s: no memory for string", __func__);
+			nsdb_free_string_array(tmp);
+			return FEDFS_ERR_SVRFAULT;
+		}
+	}
+	tmp[i] = NULL;
+
+	*referrals = tmp;
+	return FEDFS_OK;
+}
+
+/**
  * Handle an LDAP search result message
  *
  * @param ld an initialized LDAP server descriptor
  * @param result an LDAP_RES_SEARCH_RESULT message
+ * @param referrals OUT: pointer to an array of NUL-terminated C strings
  * @param ldap_err OUT: possibly an LDAP error code
  * @return a FedFsStatus code
+ *
+ * If "ldap_err" contains LDAP_REFERRAL, caller must free "referrals"
+ * with nsdb_free_string_array().
  */
 FedFsStatus
-nsdb_parse_result(LDAP *ld, LDAPMessage *result, unsigned int *ldap_err)
+nsdb_parse_result(LDAP *ld, LDAPMessage *result, char ***referrals,
+		unsigned int *ldap_err)
 {
 	char *matched_dn = NULL, *error_msg = NULL;
 	int rc, result_code;
+	char **refs = NULL;
+	FedFsStatus retval;
 
 	if (ld == NULL || result == NULL || ldap_err == NULL) {
 		xlog(L_ERROR, "%s: Invalid parameter", __func__);
@@ -829,7 +877,7 @@  nsdb_parse_result(LDAP *ld, LDAPMessage *result, unsigned int *ldap_err)
 	}
 
 	rc = ldap_parse_result(ld, result, &result_code,
-					&matched_dn, &error_msg, NULL, NULL, 0);
+				&matched_dn, &error_msg, &refs, NULL, 0);
 	if (rc != LDAP_SUCCESS) {
 		xlog(D_GENERAL, "%s: Failed to parse result: %s",
 			__func__, ldap_err2string(rc));
@@ -857,11 +905,17 @@  nsdb_parse_result(LDAP *ld, LDAPMessage *result, unsigned int *ldap_err)
 		ber_memfree(error_msg);
 	}
 
+	retval = FEDFS_OK;
+	if (refs != NULL) {
+		retval = nsdb_copy_referrals_array(refs, referrals);
+		ber_memvfree((void **)refs);
+	}
+
 	if (result_code != LDAP_SUCCESS) {
 		*ldap_err = result_code;
 		return FEDFS_ERR_NSDB_LDAP_VAL;
 	}
-	return FEDFS_OK;
+	return retval;
 }
 
 /**
diff --git a/src/libnsdb/nsdb-internal.h b/src/libnsdb/nsdb-internal.h
index d293dd7..c2283ed 100644
--- a/src/libnsdb/nsdb-internal.h
+++ b/src/libnsdb/nsdb-internal.h
@@ -102,7 +102,7 @@  FedFsStatus	 nsdb_delete_attribute_all_s(LDAP *ld, const char *dn,
 FedFsStatus	 nsdb_parse_reference(LDAP *ld, LDAPMessage *reference,
 				unsigned int *ldap_err);
 FedFsStatus	 nsdb_parse_result(LDAP *ld, LDAPMessage *result,
-				unsigned int *ldap_err);
+				char ***referrals, unsigned int *ldap_err);
 _Bool		 nsdb_compare_dns(LDAPDN dn1, LDAPDN dn2);
 _Bool		 nsdb_compare_dn_string(LDAPDN dn1, const char *dn2_in,
 				unsigned int *ldap_err);