From patchwork Fri Dec 14 22:38:01 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 206579 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from aserp1040.oracle.com (aserp1040.oracle.com [141.146.126.69]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "aserp1040.oracle.com", Issuer "VeriSign Class 3 International Server CA - G3" (not verified)) by ozlabs.org (Postfix) with ESMTPS id B2B4B2C008F for ; Sat, 15 Dec 2012 09:38:13 +1100 (EST) Received: from acsinet22.oracle.com (acsinet22.oracle.com [141.146.126.238]) by aserp1040.oracle.com (Sentrion-MTA-4.2.2/Sentrion-MTA-4.2.2) with ESMTP id qBEMcAMS027456 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 14 Dec 2012 22:38:10 GMT Received: from oss.oracle.com (oss-external.oracle.com [137.254.96.51]) by acsinet22.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id qBEMc9HR003510 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 14 Dec 2012 22:38:10 GMT Received: from localhost ([127.0.0.1] helo=oss.oracle.com) by oss.oracle.com with esmtp (Exim 4.63) (envelope-from ) id 1TjdtR-0005ug-RE; Fri, 14 Dec 2012 14:38:09 -0800 Received: from acsinet21.oracle.com ([141.146.126.237]) by oss.oracle.com with esmtp (Exim 4.63) (envelope-from ) id 1TjdtN-0005uC-Ge for fedfs-utils-devel@oss.oracle.com; Fri, 14 Dec 2012 14:38:05 -0800 Received: from userp1020.oracle.com (userp1020.oracle.com [156.151.31.79]) by acsinet21.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id qBEMc487010938 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 14 Dec 2012 22:38:05 GMT Received: from mail-ia0-f171.google.com (mail-ia0-f171.google.com [209.85.210.171]) by userp1020.oracle.com (Sentrion-MTA-4.2.2/Sentrion-MTA-4.2.2) with ESMTP id qBEMc3pn012072 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Fri, 14 Dec 2012 22:38:04 GMT Received: by mail-ia0-f171.google.com with SMTP id k27so3643162iad.2 for ; Fri, 14 Dec 2012 14:38:03 -0800 (PST) Received: by 10.50.193.170 with SMTP id hp10mr3161418igc.63.1355524683529; Fri, 14 Dec 2012 14:38:03 -0800 (PST) Received: from seurat.1015granger.net ([99.26.161.222]) by mx.google.com with ESMTPS id fv6sm7741060igc.17.2012.12.14.14.38.02 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 14 Dec 2012 14:38:02 -0800 (PST) From: Chuck Lever To: fedfs-utils-devel@oss.oracle.com Date: Fri, 14 Dec 2012 17:38:01 -0500 Message-ID: <20121214223801.22243.23891.stgit@seurat.1015granger.net> In-Reply-To: <20121214221556.22243.9462.stgit@seurat.1015granger.net> References: <20121214221556.22243.9462.stgit@seurat.1015granger.net> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Flow-Control-Info: class=Default reputation=ipRepBelow100 ip=209.85.210.171 ct-class=R5 ct-vol1=0 ct-vol2=8 ct-vol3=7 ct-risk=49 ct-spam1=75 ct-spam2=7 ct-bulk=5 rcpts=1 size=16638 X-MM-CT-Classification: not spam X-MM-CT-RefID: str=0001.0A090201.50CBAA4C.00D4,ss=1,re=-2.300,fgs=0 Subject: [fedfs-utils] [PATCH 05/11] libnsdb: Handle LDAP referrals correctly X-BeenThere: fedfs-utils-devel@oss.oracle.com X-Mailman-Version: 2.1.9 Precedence: list Reply-To: fedfs-utils Developers List-Id: fedfs-utils Developers List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: fedfs-utils-devel-bounces@oss.oracle.com Errors-To: fedfs-utils-devel-bounces@oss.oracle.com X-Source-IP: acsinet22.oracle.com [141.146.126.238] Handle LDAP referrals during NSDB fileserver queries. The original design is wrong, referrals are returned in the LDAP_RES_SEARCH_RESULT message. We hand an array of LDAP URIs back to the caller, and let them figure out if they want to retry the request with referred-to LDAP server. Signed-off-by: Chuck Lever --- src/include/nsdb.h | 6 ++ src/libnsdb/fileserver.c | 130 +++++++++++++++++++++---------------------- src/libnsdb/ldap.c | 1 src/libnsdb/nsdb-internal.h | 1 src/libnsdb/nsdb.c | 67 ++++++++++++++++++++++ 5 files changed, 137 insertions(+), 68 deletions(-) diff --git a/src/include/nsdb.h b/src/include/nsdb.h index 030b1d2..2895433 100644 --- a/src/include/nsdb.h +++ b/src/include/nsdb.h @@ -181,6 +181,11 @@ FedFsStatus nsdb_lookup_nsdb(const char *hostname, struct fedfs_secdata *sec); /** + * Instantiate an nsdb_t object based on stored connection parameters + */ +FedFsStatus nsdb_lookup_nsdb_by_uri(const char *uri, nsdb_t *host); + +/** * Update stored connection parameters for an NSDB */ FedFsStatus nsdb_update_nsdb(const char *hostname, @@ -240,6 +245,7 @@ unsigned short nsdb_port(const nsdb_t host); const char *nsdb_default_binddn(const nsdb_t host); const char *nsdb_default_nce(const nsdb_t host); _Bool nsdb_follow_referrals(const nsdb_t host); +const char *nsdb_referred_to(const nsdb_t host); /** * Data type helpers for nsdb_t objects diff --git a/src/libnsdb/fileserver.c b/src/libnsdb/fileserver.c index cdceb37..362e056 100644 --- a/src/libnsdb/fileserver.c +++ b/src/libnsdb/fileserver.c @@ -137,6 +137,9 @@ __nsdb_search_nsdb_attr_s(const char *func, LDAP *ld, const char *base, void nsdb_free_fedfs_fsn(struct fedfs_fsn *fsn) { + if (fsn == NULL) + return; + nsdb_free_string_array(fsn->fn_description); nsdb_free_string_array(fsn->fn_annotations); free(fsn->fn_dn); @@ -397,6 +400,7 @@ nsdb_get_ncedn_s(nsdb_t host, const char *naming_context, char **dn, "fedfsNceDN", &response); switch (rc) { case LDAP_SUCCESS: + case LDAP_REFERRAL: break; case LDAP_NO_SUCH_OBJECT: xlog(D_GENERAL, "%s: %s is not an NSDB container entry", @@ -415,20 +419,12 @@ nsdb_get_ncedn_s(nsdb_t host, const char *naming_context, char **dn, } rc = ldap_count_messages(ld, response); - switch (rc) { - case -1: + if (rc == -1) { xlog(D_GENERAL, "%s: Empty LDAP response\n", __func__); retval = FEDFS_ERR_NSDB_FAULT; goto out; - case 1: - xlog(L_ERROR, "Naming context entry %s is inaccessible", - naming_context); - retval = FEDFS_ERR_NSDB_NONCE; - goto out; - default: - xlog(D_CALL, "%s: received %d messages", __func__, rc); - break; } + xlog(D_CALL, "%s: received %d messages", __func__, rc); tmp = NULL; retval = FEDFS_OK; @@ -440,7 +436,9 @@ nsdb_get_ncedn_s(nsdb_t host, const char *naming_context, char **dn, retval = nsdb_parse_ncedn_entry(ld, message, &tmp); break; case LDAP_RES_SEARCH_RESULT: - retval = nsdb_parse_result(ld, message, NULL, ldap_err); + retval = nsdb_parse_result(ld, message, + &host->fn_referrals, + ldap_err); break; default: xlog(L_ERROR, "%s: Unrecognized LDAP message type", @@ -1001,7 +999,7 @@ nsdb_resolve_fsn_parse_entry(LDAP *ld, LDAPMessage *entry, /** * Retrieve and display the FSL entries associated with an FSN UUID * - * @param ld an initialized LDAP server descriptor + * @param host an initialized and bound nsdb_t object * @param nce a NUL-terminated C string containing DN of NSDB container entry * @param fsn_uuid a NUL-terminated C string containing FSN UUID * @param fsls OUT: a list of fedfs_fsl structures @@ -1017,10 +1015,11 @@ nsdb_resolve_fsn_parse_entry(LDAP *ld, LDAPMessage *entry, @endverbatim */ static FedFsStatus -nsdb_resolve_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, +nsdb_resolve_fsn_find_entry_s(nsdb_t host, const char *nce, const char *fsn_uuid, struct fedfs_fsl **fsls, unsigned int *ldap_err) { LDAPMessage *response, *message; + LDAP *ld = host->fn_ldap; struct fedfs_fsl *tmp; FedFsStatus retval; char filter[128]; @@ -1038,6 +1037,7 @@ nsdb_resolve_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, filter, &response); switch (rc) { case LDAP_SUCCESS: + case LDAP_REFERRAL: break; case LDAP_NO_SUCH_OBJECT: xlog(D_GENERAL, "%s: No entry for FSN UUID %s exists", @@ -1055,20 +1055,12 @@ nsdb_resolve_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, } rc = ldap_count_messages(ld, response); - switch (rc) { - case -1: + if (rc == -1) { xlog(D_GENERAL, "%s: Empty LDAP response", __func__); ldap_msgfree(response); return FEDFS_ERR_NSDB_FAULT; - case 1: - xlog(D_CALL, "%s: No FSL entries for FSN UUID %s", - __func__, fsn_uuid); - ldap_msgfree(response); - return FEDFS_ERR_NSDB_NOFSL; - default: - xlog(D_CALL, "%s: Received %d messages", __func__, rc); - break; } + xlog(D_CALL, "%s: Received %d messages", __func__, rc); tmp = NULL; retval = FEDFS_OK; @@ -1081,7 +1073,9 @@ nsdb_resolve_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, message, &tmp); break; case LDAP_RES_SEARCH_RESULT: - retval = nsdb_parse_result(ld, message, NULL, ldap_err); + retval = nsdb_parse_result(ld, message, + &host->fn_referrals, + ldap_err); break; default: xlog(L_ERROR, "%s: Unrecognized LDAP message type", @@ -1092,8 +1086,14 @@ nsdb_resolve_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, ldap_msgfree(response); if (retval == FEDFS_OK) { - xlog(D_CALL, "%s: returning fsls", __func__); - *fsls = tmp; + if (tmp == NULL) { + xlog(D_CALL, "%s: No FSL entries for FSN UUID %s", + __func__, fsn_uuid); + retval = FEDFS_ERR_NSDB_NOFSL; + } else { + xlog(D_CALL, "%s: returning fsls", __func__); + *fsls = tmp; + } } else nsdb_free_fedfs_fsls(tmp); return retval; @@ -1132,7 +1132,7 @@ nsdb_resolve_fsn_s(nsdb_t host, const char *nce, const char *fsn_uuid, } if (nce != NULL) - return nsdb_resolve_fsn_find_entry_s(host->fn_ldap, nce, + return nsdb_resolve_fsn_find_entry_s(host, nce, fsn_uuid, fsls, ldap_err); /* @@ -1163,9 +1163,9 @@ nsdb_resolve_fsn_s(nsdb_t host, const char *nce, const char *fsn_uuid, goto out; for (j = 0; nce_list[j] != NULL; j++) { - retval = nsdb_resolve_fsn_find_entry_s(host->fn_ldap, - nce_list[j], fsn_uuid, - fsls, ldap_err); + retval = nsdb_resolve_fsn_find_entry_s(host, nce_list[j], + fsn_uuid, fsls, + ldap_err); if (retval == FEDFS_OK) break; } @@ -1310,7 +1310,7 @@ nsdb_get_fsn_parse_entry(LDAP *ld, LDAPMessage *entry, /** * Retrieve an FSN entry associated with an FSN UUID * - * @param ld an initialized LDAP server descriptor + * @param host an initialized and bound nsdb_t object * @param nce a NUL-terminated C string containing DN of NSDB container entry * @param fsn_uuid a NUL-terminated C string containing FSN UUID * @param fsn OUT: a fedfs_fsn structures @@ -1328,10 +1328,11 @@ nsdb_get_fsn_parse_entry(LDAP *ld, LDAPMessage *entry, @endverbatim */ static FedFsStatus -nsdb_get_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, +nsdb_get_fsn_find_entry_s(nsdb_t host, const char *nce, const char *fsn_uuid, struct fedfs_fsn **fsn, unsigned int *ldap_err) { LDAPMessage *response, *message; + LDAP *ld = host->fn_ldap; struct fedfs_fsn *tmp; FedFsStatus retval; char filter[128]; @@ -1349,6 +1350,7 @@ nsdb_get_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, filter, &response); switch (rc) { case LDAP_SUCCESS: + case LDAP_REFERRAL: break; case LDAP_NO_SUCH_OBJECT: xlog(D_GENERAL, "%s: No FSN record for FSN UUID %s exists", @@ -1366,20 +1368,12 @@ nsdb_get_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, } rc = ldap_count_messages(ld, response); - switch (rc) { - case -1: + if (rc == -1) { xlog(D_GENERAL, "%s: Empty LDAP response", __func__); ldap_msgfree(response); return FEDFS_ERR_NSDB_FAULT; - case 1: - xlog(D_GENERAL, "%s: No FSN record for FSN UUID %s exists", - __func__, fsn_uuid); - ldap_msgfree(response); - return FEDFS_ERR_NSDB_NOFSN; - default: - xlog(D_CALL, "%s: Received %d messages", __func__, rc); - break; } + xlog(D_CALL, "%s: Received %d messages", __func__, rc); tmp = NULL; retval = FEDFS_OK; @@ -1391,7 +1385,9 @@ nsdb_get_fsn_find_entry_s(LDAP *ld, const char *nce, const char *fsn_uuid, retval = nsdb_get_fsn_parse_entry(ld, message, &tmp); break; case LDAP_RES_SEARCH_RESULT: - retval = nsdb_parse_result(ld, message, NULL, ldap_err); + retval = nsdb_parse_result(ld, message, + &host->fn_referrals, + ldap_err); break; default: xlog(L_ERROR, "%s: Unrecognized LDAP message type", @@ -1442,8 +1438,8 @@ nsdb_get_fsn_s(nsdb_t host, const char *nce, const char *fsn_uuid, } if (nce != NULL) - return nsdb_get_fsn_find_entry_s(host->fn_ldap, nce, - fsn_uuid, fsn, ldap_err); + return nsdb_get_fsn_find_entry_s(host, nce, fsn_uuid, + fsn, ldap_err); /* * Caller did not provide an nce. Generate a list @@ -1473,8 +1469,7 @@ nsdb_get_fsn_s(nsdb_t host, const char *nce, const char *fsn_uuid, goto out; for (j = 0; nce_list[j] != NULL; j++) { - retval = nsdb_get_fsn_find_entry_s(host->fn_ldap, - nce_list[j], fsn_uuid, + retval = nsdb_get_fsn_find_entry_s(host, nce_list[j], fsn_uuid, fsn, ldap_err); if (retval == FEDFS_OK) break; @@ -1571,7 +1566,7 @@ nsdb_parse_fsn_entry(LDAP *ld, LDAPMessage *entry, char ***fsns) /** * Retrieve and display the FSN entries associated with an NSDB container * - * @param ld an initialized LDAP server descriptor + * @param host an initialized and bound nsdb_t object * @param nce a NUL-terminated C string containing the DN of the NSDB container * @param fsns OUT: pointer to an array of NUL-terminated C strings containing FSN UUIDs * @param ldap_err OUT: possibly an LDAP error code @@ -1585,10 +1580,11 @@ nsdb_parse_fsn_entry(LDAP *ld, LDAPMessage *entry, char ***fsns) @endverbatim */ static FedFsStatus -nsdb_list_find_entries_s(LDAP *ld, const char *nce, char ***fsns, +nsdb_list_find_entries_s(nsdb_t host, const char *nce, char ***fsns, unsigned int *ldap_err) { LDAPMessage *response, *message; + LDAP *ld = host->fn_ldap; FedFsStatus retval; char **tmp; int rc; @@ -1597,6 +1593,7 @@ nsdb_list_find_entries_s(LDAP *ld, const char *nce, char ***fsns, "(objectClass=fedfsFsn)", &response); switch (rc) { case LDAP_SUCCESS: + case LDAP_REFERRAL: break; case LDAP_NO_SUCH_OBJECT: xlog(D_GENERAL, "%s: No entry for %s exists", @@ -1614,21 +1611,12 @@ nsdb_list_find_entries_s(LDAP *ld, const char *nce, char ***fsns, } rc = ldap_count_messages(ld, response); - switch (rc) { - case -1: + if (rc == -1) { xlog(D_GENERAL, "%s: Empty LDAP response", __func__); ldap_msgfree(response); return FEDFS_ERR_NSDB_FAULT; - case 1: - xlog(D_CALL, "%s: No FSN entries under %s", - __func__, nce); - ldap_msgfree(response); - return FEDFS_ERR_NSDB_NOFSN; - default: - xlog(D_CALL, "%s: Received %d messages", - __func__, rc); - break; } + xlog(D_CALL, "%s: Received %d messages", __func__, rc); /* Assume one FSN per LDAP message, minus the RESULT message, * plus the NULL pointer on the end of the array */ @@ -1647,7 +1635,9 @@ nsdb_list_find_entries_s(LDAP *ld, const char *nce, char ***fsns, retval = nsdb_parse_fsn_entry(ld, message, &tmp); break; case LDAP_RES_SEARCH_RESULT: - retval = nsdb_parse_result(ld, message, NULL, ldap_err); + retval = nsdb_parse_result(ld, message, + &host->fn_referrals, + ldap_err); break; default: xlog(L_ERROR, "%s: Unrecognized LDAP message type", @@ -1657,8 +1647,14 @@ nsdb_list_find_entries_s(LDAP *ld, const char *nce, char ***fsns, } if (retval == FEDFS_OK) { - xlog(D_CALL, "%s: returning fsn list", __func__); - *fsns = tmp; + if (tmp[0] == NULL) { + xlog(D_CALL, "%s: No FSN entries under %s", + __func__, nce); + retval = FEDFS_ERR_NSDB_NOFSN; + } else { + xlog(D_CALL, "%s: returning fsn list", __func__); + *fsns = tmp; + } } else nsdb_free_string_array(tmp); @@ -1696,8 +1692,7 @@ nsdb_list_s(nsdb_t host, const char *nce, char ***fsns, unsigned int *ldap_err) } if (nce != NULL) - return nsdb_list_find_entries_s(host->fn_ldap, nce, - fsns, ldap_err); + return nsdb_list_find_entries_s(host, nce, fsns, ldap_err); /* * Caller did not provide an nce. Discover the server's NSDB @@ -1728,9 +1723,8 @@ nsdb_list_s(nsdb_t host, const char *nce, char ***fsns, unsigned int *ldap_err) goto out; for (j = 0; nce_list[j] != NULL; j++) { - retval = nsdb_list_find_entries_s(host->fn_ldap, - nce_list[j], - fsns, ldap_err); + retval = nsdb_list_find_entries_s(host, nce_list[j], + fsns, ldap_err); if (retval == FEDFS_OK) break; } diff --git a/src/libnsdb/ldap.c b/src/libnsdb/ldap.c index 8b4291e..e5e2133 100644 --- a/src/libnsdb/ldap.c +++ b/src/libnsdb/ldap.c @@ -803,6 +803,7 @@ nsdb_copy_referrals_array(char **refs, char ***referrals) } tmp[i] = NULL; + nsdb_free_string_array(*referrals); *referrals = tmp; return FEDFS_OK; } diff --git a/src/libnsdb/nsdb-internal.h b/src/libnsdb/nsdb-internal.h index 55b146f..6cf96c9 100644 --- a/src/libnsdb/nsdb-internal.h +++ b/src/libnsdb/nsdb-internal.h @@ -45,6 +45,7 @@ struct fedfs_nsdb { char * fn_default_binddn; char * fn_default_nce; _Bool fn_follow_referrals; + char ** fn_referrals; }; /** diff --git a/src/libnsdb/nsdb.c b/src/libnsdb/nsdb.c index 46b7845..20d9e55 100644 --- a/src/libnsdb/nsdb.c +++ b/src/libnsdb/nsdb.c @@ -378,6 +378,22 @@ nsdb_follow_referrals(const nsdb_t host) } /** + * Return NSDB's default NCE + * + * @param host an instantiated nsdb_t object + * @return a NUL-terminated UTF-8 string containing an LDAP URI + * + * Lifetime of this string is the same as the lifetime of the + * nsdb_t. Caller must not free this string, and must not use + * it after the nsdb_t is freed. + */ +const char * +nsdb_referred_to(const nsdb_t host) +{ + return host->fn_referrals[0]; +} + +/** * Retrieve NSDB-related environment variables * * @param nsdbname OUT: pointer to statically allocated NUL-terminated C string containing NSDB hostname @@ -1126,6 +1142,55 @@ nsdb_lookup_nsdb(const char *hostname, const unsigned short port, } /** + * Read NSDB info from NSDB database, using LDAP URI + * + * @param uri NUL-terminated ASCII string containing an LDAP URI + * @param host OUT: an initialized nsdb_t object + * @return a FedFsStatus code + * + * On success, FEDFS_OK is returned and a fresh nsdb_t is returned. + * + * Caller must free "host" with nsdb_free_nsdb(). + */ +FedFsStatus +nsdb_lookup_nsdb_by_uri(const char *uri, nsdb_t *host) +{ + FedFsStatus retval; + LDAPURLDesc *lud; + nsdb_t new; + int rc; + + rc = ldap_url_parse(uri, &lud); + if (rc != LDAP_URL_SUCCESS) { + xlog(D_GENERAL, "%s: Failed to parse URI %s", __func__, uri); + return FEDFS_ERR_INVAL; + } + + if (lud->lud_scheme == NULL || + strcasecmp(lud->lud_scheme, "ldap") != 0) { + xlog(D_GENERAL, "%s: Invalid URI %s", __func__, uri); + retval = FEDFS_ERR_INVAL; + goto out; + } + + xlog(D_CALL, "%s: Looking up NSDB %s:%u", + __func__, lud->lud_host, lud->lud_port); + retval = nsdb_new_nsdb(lud->lud_host, lud->lud_port, &new); + if (retval != FEDFS_OK) + goto out; + + retval = nsdb_read_nsdbparams(new, NULL); + if (retval != FEDFS_OK) + nsdb_free_nsdb(new); + else + *host = new; + +out: + ldap_free_urldesc(lud); + return retval; +} + +/** * Update connection parameters for an NSDB * * @param host an instantiated nsdb_t object @@ -1510,6 +1575,8 @@ nsdb_close_nsdb(nsdb_t host) { (void)ldap_unbind_ext_s(host->fn_ldap, NULL, NULL); host->fn_ldap = NULL; + nsdb_free_string_array(host->fn_referrals); + host->fn_referrals = NULL; } /**