diff mbox

[06/11] nsdbc: Follow LDAP referrals in some NSDB administrative tools

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

Commit Message

Chuck Lever Dec. 14, 2012, 10:38 p.m. UTC
NSDB tools that perform fileserver queries are allowed to follow
LDAP referrals if the NSDB's "follow referrals" flag is on.

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

 src/nsdbc/nsdb-list.c        |   53 ++++++++++++++++++++++++++++++++++++++
 src/nsdbc/nsdb-resolve-fsn.c |   59 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 112 insertions(+), 0 deletions(-)
diff mbox

Patch

diff --git a/src/nsdbc/nsdb-list.c b/src/nsdbc/nsdb-list.c
index 0e271b2..e3a8ab0 100644
--- a/src/nsdbc/nsdb-list.c
+++ b/src/nsdbc/nsdb-list.c
@@ -142,6 +142,52 @@  nsdb_list_resolve_and_display_fsn(nsdb_t host, const char *nce, const char *fsn_
 }
 
 /**
+ * Attempt to follow an LDAP referral to another NSDB
+ *
+ * @param host OUT: pointer to an initialized nsdb_t that may be replaced
+ * @return a FedFsStatus code
+ */
+static FedFsStatus
+nsdb_list_follow_ldap_referral(nsdb_t *host)
+{
+	static unsigned int nest = 0;
+	FedFsStatus retval;
+	nsdb_t old, refer;
+
+	old = *host;
+	if (!nsdb_follow_referrals(old)) {
+		fprintf(stderr, "LDAP referrals for NSDB %s:%u disallowed\n",
+			nsdb_hostname(old), nsdb_port(old));
+		return FEDFS_ERR_NSDB_LDAP_REFERRAL_NOTFOLLOWED;
+	}
+
+	if (nest++ > 10) {
+		fprintf(stderr, "Possible referral loop for NSDB %s:%u\n",
+			nsdb_hostname(old), nsdb_port(old));
+		return FEDFS_ERR_NSDB_LDAP_REFERRAL_NOTFOLLOWED;
+	}
+
+	retval = nsdb_lookup_nsdb_by_uri(nsdb_referred_to(old), &refer);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_NSDB_PARAMS:
+		fprintf(stderr, "Encountered referral to unrecognized NSDB %s\n",
+			nsdb_referred_to(old));
+		return FEDFS_ERR_NSDB_LDAP_REFERRAL_NOTFOLLOWED;
+	default:
+		fprintf(stderr, "Problem following referral: %s",
+			nsdb_display_fedfsstatus(retval));
+		return retval;
+	}
+
+	nsdb_close_nsdb(old);
+	nsdb_free_nsdb(old);
+	*host = refer;
+	return FEDFS_OK;
+}
+
+/**
  * Program entry point
  *
  * @param argc count of command line arguments
@@ -232,6 +278,7 @@  main(int argc, char **argv)
 		goto out;
 	}
 
+again:
 	retval = nsdb_open_nsdb(host, NULL, NULL, &ldap_err);
 	switch (retval) {
 	case FEDFS_OK:
@@ -280,6 +327,12 @@  main(int argc, char **argv)
 			fprintf(stderr, "NCE %s does not exist\n", nce);
 		break;
 	case FEDFS_ERR_NSDB_LDAP_VAL:
+		if (ldap_err == LDAP_REFERRAL) {
+			retval = nsdb_list_follow_ldap_referral(&host);
+			if (retval != FEDFS_OK)
+				break;
+			goto again;
+		}
 		fprintf(stderr, "Failed to list FSNs: %s\n",
 			ldap_err2string(ldap_err));
 		break;
diff --git a/src/nsdbc/nsdb-resolve-fsn.c b/src/nsdbc/nsdb-resolve-fsn.c
index 0056200..23d292d 100644
--- a/src/nsdbc/nsdb-resolve-fsn.c
+++ b/src/nsdbc/nsdb-resolve-fsn.c
@@ -190,6 +190,52 @@  nsdb_resolve_fsn_display_fsls(struct fedfs_fsl *fsls)
 }
 
 /**
+ * Attempt to follow an LDAP referral to another NSDB
+ *
+ * @param host OUT: pointer to an initialized nsdb_t that may be replaced
+ * @return a FedFsStatus code
+ */
+static FedFsStatus
+nsdb_resolve_fsn_follow_ldap_referral(nsdb_t *host)
+{
+	static unsigned int nest = 0;
+	FedFsStatus retval;
+	nsdb_t old, refer;
+
+	old = *host;
+	if (!nsdb_follow_referrals(old)) {
+		fprintf(stderr, "LDAP referrals for NSDB %s:%u disallowed\n",
+			nsdb_hostname(old), nsdb_port(old));
+		return FEDFS_ERR_NSDB_LDAP_REFERRAL_NOTFOLLOWED;
+	}
+
+	if (nest++ > 10) {
+		fprintf(stderr, "Possible referral loop for NSDB %s:%u\n",
+			nsdb_hostname(old), nsdb_port(old));
+		return FEDFS_ERR_NSDB_LDAP_REFERRAL_NOTFOLLOWED;
+	}
+
+	retval = nsdb_lookup_nsdb_by_uri(nsdb_referred_to(old), &refer);
+	switch (retval) {
+	case FEDFS_OK:
+		break;
+	case FEDFS_ERR_NSDB_PARAMS:
+		fprintf(stderr, "Encountered referral to unrecognized NSDB %s\n",
+			nsdb_referred_to(old));
+		return FEDFS_ERR_NSDB_LDAP_REFERRAL_NOTFOLLOWED;
+	default:
+		fprintf(stderr, "Problem following referral: %s\n",
+			nsdb_display_fedfsstatus(retval));
+		return retval;
+	}
+
+	nsdb_close_nsdb(old);
+	nsdb_free_nsdb(old);
+	*host = refer;
+	return FEDFS_OK;
+}
+
+/**
  * Program entry point
  *
  * @param argc count of command line arguments
@@ -292,6 +338,7 @@  main(int argc, char **argv)
 		goto out;
 	}
 
+again:
 	retval = nsdb_open_nsdb(host, NULL, NULL, &ldap_err);
 	switch (retval) {
 	case FEDFS_OK:
@@ -332,6 +379,12 @@  main(int argc, char **argv)
 		fprintf(stderr, "Failed to find FSN %s\n", fsn_uuid);
 		goto out_close;
 	case FEDFS_ERR_NSDB_LDAP_VAL:
+		if (ldap_err == LDAP_REFERRAL) {
+			retval = nsdb_resolve_fsn_follow_ldap_referral(&host);
+			if (retval != FEDFS_OK)
+				goto out_close;
+			goto again;
+		}
 		fprintf(stderr, "NSDB LDAP error: %s\n",
 			ldap_err2string(ldap_err));
 		goto out_close;
@@ -366,6 +419,12 @@  main(int argc, char **argv)
 		fprintf(stderr, "Failed to find FSN %s\n", fsn_uuid);
 		break;
 	case FEDFS_ERR_NSDB_LDAP_VAL:
+		if (ldap_err == LDAP_REFERRAL) {
+			retval = nsdb_resolve_fsn_follow_ldap_referral(&host);
+			if (retval != FEDFS_OK)
+				break;
+			goto again;
+		}
 		fprintf(stderr, "NSDB LDAP error: %s\n",
 			ldap_err2string(ldap_err));
 		break;