From patchwork Wed Nov 13 21:54:41 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 291062 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from userp1040.oracle.com (userp1040.oracle.com [156.151.31.81]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "userp1040.oracle.com", Issuer "VeriSign Class 3 International Server CA - G3" (not verified)) by ozlabs.org (Postfix) with ESMTPS id D5D6C2C00AB for ; Thu, 14 Nov 2013 08:54:54 +1100 (EST) Received: from acsinet22.oracle.com (acsinet22.oracle.com [141.146.126.238]) by userp1040.oracle.com (Sentrion-MTA-4.3.1/Sentrion-MTA-4.3.1) with ESMTP id rADLspa7026429 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 13 Nov 2013 21:54:52 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 rADLsprk000965 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 13 Nov 2013 21:54:51 GMT Received: from localhost ([127.0.0.1] helo=oss.oracle.com) by oss.oracle.com with esmtp (Exim 4.63) (envelope-from ) id 1VgiOh-000716-1O; Wed, 13 Nov 2013 13:54:51 -0800 Received: from acsinet22.oracle.com ([141.146.126.238]) by oss.oracle.com with esmtp (Exim 4.63) (envelope-from ) id 1VgiOa-00070u-Km for fedfs-utils-devel@oss.oracle.com; Wed, 13 Nov 2013 13:54:44 -0800 Received: from aserp1030.oracle.com (aserp1030.oracle.com [141.146.126.68]) by acsinet22.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id rADLsiow000767 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 13 Nov 2013 21:54:44 GMT Received: from mail-yh0-f45.google.com (mail-yh0-f45.google.com [209.85.213.45]) by aserp1030.oracle.com (Sentrion-MTA-4.3.1/Sentrion-MTA-4.3.1) with ESMTP id rADLshfF011445 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Wed, 13 Nov 2013 21:54:43 GMT Received: by mail-yh0-f45.google.com with SMTP id i7so576625yha.4 for ; Wed, 13 Nov 2013 13:54:43 -0800 (PST) X-Received: by 10.236.86.42 with SMTP id v30mr3362641yhe.92.1384379683293; Wed, 13 Nov 2013 13:54:43 -0800 (PST) Received: from seurat.1015granger.net ([2604:8800:100:81fc:20c:29ff:fe44:ec31]) by mx.google.com with ESMTPSA id v96sm59708126yhp.3.2013.11.13.13.54.42 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 13 Nov 2013 13:54:42 -0800 (PST) To: fedfs-utils-devel@oss.oracle.com From: Chuck Lever Date: Wed, 13 Nov 2013 16:54:41 -0500 Message-ID: <20131113215441.23593.41634.stgit@seurat.1015granger.net> In-Reply-To: <20131113214635.23593.36381.stgit@seurat.1015granger.net> References: <20131113214635.23593.36381.stgit@seurat.1015granger.net> User-Agent: StGit/0.16 MIME-Version: 1.0 X-Flow-Control-Info: class=Pass-to-MM reputation=ipRisk-All ip=209.85.213.45 ct-class=R5 ct-vol1=0 ct-vol2=7 ct-vol3=7 ct-risk=47 ct-spam1=75 ct-spam2=8 ct-bulk=3 rcpts=1 size=8112 X-SPF-Info: PASS::mail-yh0-f45.google.com X-Sendmail-CM-Score: 0.00% X-Sendmail-CM-Analysis: v=2.1 cv=MJJZxqpl c=1 sm=1 tr=0 a=fC+xSgr/yK7uU9fo7/vqfQ==:117 a=dzsqy3y4QnMA:10 a=ZFKtgnv4WhgA:10 a=dPGociXpb70A:10 a=IkcTkHD0fZMA:10 a=xqWC_Br6kY4A:10 a=yPCof4ZbAAAA:8 a=Lb1rMZzfAAAA:8 a=1XWaLZrsAAAA:8 a=vNSlxmQ6zzAA:10 a=fStOTuXxc2wXt oCUVuEA:9 a=QEXdDO2ut3YA:10 a=7DSvI1NPTFQA:10 X-Sendmail-CT-Classification: not spam X-Sendmail-CT-RefID: str=0001.0A090203.5283F524.001D, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0 Subject: [fedfs-utils] [PATCH 8/8] libnsdb: simplify NCE discovery 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] When constructing an NSDB, part of the process currently involves adding a fedfsNceDN attribute to one or more root suffix entries in an LDAP server's root DSE. Simo Sorce (FreeIPA) points out it may be difficult or impossible for some LDAP server implementations to allow modification of their root DSE. Or it could be a problem for some deployments to allow root DSE modification. For this reason, LDAP applications typically use an approach that does not require root DSE modification. My own experience with OpenLDAP and 389-ds is that root DSE modification is quite awkward. Long-term, we'd like to replace fedfsNsdbContainerInfo and fedfsNceDN with a form of NCE discovery that is simpler to configure. Old-style NCE discovery works like this: For each of the server's naming contexts, an NSDB client performs this query: ldapsearch -b "naming_context" -s base (objectClass=*) fedfsNceDN The fedfsNceDN attribute contains the full distinguished name of the NCE residing under that naming context (root suffix). New-style NCE discovery works like this: An NCE contains an auxiliary object class called fedfsNsdbContainerEntry. For each of the server's naming contexts, an NSDB client performs this query: ldapsearch -b "naming_context" -s subtree \ (objectClass=fedfsNsdbContainerEntry) The response carries the distinguished name of the NCE residing under that naming context, or NO_SUCH_OBJECT. Our client maintains compatibility with old-style NSDBs by using new-style discovery first, and then trying old-style discovery if new-style discovery fails. For now, the client can throw an error if it discovers more than one NCE in a single naming context. Signed-off-by: Chuck Lever --- src/libnsdb/fileserver.c | 184 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 171 insertions(+), 13 deletions(-) diff --git a/src/libnsdb/fileserver.c b/src/libnsdb/fileserver.c index 4cda9d7..fdd0878 100644 --- a/src/libnsdb/fileserver.c +++ b/src/libnsdb/fileserver.c @@ -357,7 +357,7 @@ nsdb_parse_ncedn_entry(LDAP *ld, LDAPMessage *entry, char **dn) } /** - * Get the naming context's NSDB DN, if it has one + * Get the naming context's NSDB DN, if it has one (old-style) * * @param host an initialized and bound nsdb_t object * @param naming_context NUL-terminated C string containing one naming context @@ -376,8 +376,8 @@ nsdb_parse_ncedn_entry(LDAP *ld, LDAPMessage *entry, char **dn) * * The full DN for the NSDB container entry is returned in "dn." */ -FedFsStatus -nsdb_get_ncedn_s(nsdb_t host, const char *naming_context, char **dn, +static FedFsStatus +nsdb_old_get_ncedn_s(nsdb_t host, const char *naming_context, char **dn, unsigned int *ldap_err) { LDAPMessage *response, *message; @@ -386,16 +386,6 @@ nsdb_get_ncedn_s(nsdb_t host, const char *naming_context, char **dn, char *tmp = NULL; int rc; - if (host->fn_ldap == NULL) { - xlog(L_ERROR, "%s: NSDB not open", __func__); - return FEDFS_ERR_INVAL; - } - - if (dn == NULL || ldap_err == NULL) { - xlog(L_ERROR, "%s: Invalid parameter", __func__); - return FEDFS_ERR_INVAL; - } - rc = nsdb_search_nsdb_attr_s(ld, naming_context, "(objectClass=*)", "fedfsNceDN", &response); switch (rc) { @@ -466,6 +456,174 @@ out: } /** + * Extract DN for naming context's NSDB Container Entry + * + * @param ld an initialized LDAP descriptor + * @param entry an LDAP_RES_SEARCH_ENTRY message + * @param dn OUT: pointer to a NUL-terminated C string containing resulting DN + * @return a FedFsStatus code + * + * Caller must free "dn" with free(3) + */ +static FedFsStatus +nsdb_parse_ncedn(LDAP *ld, LDAPMessage *entry, char **dn) +{ + FedFsStatus retval; + char *tmp; + + retval = FEDFS_ERR_SVRFAULT; + + tmp = ldap_get_dn(ld, entry); + if (tmp == NULL) { + xlog(D_GENERAL, "%s: ldap_get_dn failed", + __func__); + goto out; + } + + *dn = strdup(tmp); + if (*dn == NULL) { + xlog(D_GENERAL, "%s: strdup failed", + __func__); + goto out; + } + + retval = FEDFS_OK; + +out: + ldap_memfree(tmp); + return retval; +} + +/** + * Get the naming context's NSDB DN, if it has one (new-style) + * + * @param host an initialized and bound nsdb_t object + * @param naming_context NUL-terminated C string containing one naming context + * @param dn OUT: pointer to a NUL-terminated C string containing full DN of NSDB container + * @param ldap_err OUT: possibly an LDAP error code + * @return a FedFsStatus code + * + * Caller must free "dn" with free(3) + * + * ldapsearch equivalent: + * + * @verbatim + + ldapsearch -b "naming_context" (objectClass=fedfsNsdbContainerEntry) + @endverbatim + * + * The full DN for the NSDB container entry is returned in "dn." + */ +static FedFsStatus +nsdb_new_get_ncedn_s(nsdb_t host, const char *naming_context, char **dn, + unsigned int *ldap_err) +{ + LDAPMessage *response, *message; + LDAP *ld = host->fn_ldap; + FedFsStatus retval; + unsigned count; + int rc; + + rc = nsdb_search_nsdb_all_s(ld, naming_context, LDAP_SCOPE_SUBTREE, + "(objectClass=fedfsNsdbContainerEntry)", + &response); + switch (rc) { + case LDAP_SUCCESS: + case LDAP_REFERRAL: + break; + case LDAP_NO_SUCH_OBJECT: + xlog(D_GENERAL, "%s: %s does not contain an NCE", + __func__, naming_context); + return FEDFS_ERR_NSDB_NONCE; + default: + xlog(D_GENERAL, "%s: Failed to retrieve naming_context " + "entry %s: %s", __func__, naming_context, + ldap_err2string(rc)); + *ldap_err = rc; + return FEDFS_ERR_NSDB_LDAP_VAL; + } + if (response == NULL) { + xlog(D_GENERAL, "%s: Empty LDAP response\n", __func__); + return FEDFS_ERR_NSDB_FAULT; + } + + rc = ldap_count_messages(ld, response); + if (rc == -1) { + xlog(D_GENERAL, "%s: Empty LDAP response\n", __func__); + retval = FEDFS_ERR_NSDB_FAULT; + goto out; + } + xlog(D_CALL, "%s: received %d messages", __func__, rc); + + retval = FEDFS_OK; + for (message = ldap_first_message(ld, response), count = 0; + message != NULL && retval == FEDFS_OK; + message = ldap_next_message(ld, message)) { + switch (ldap_msgtype(message)) { + case LDAP_RES_SEARCH_ENTRY: + if (++count > 1) { + xlog(D_CALL, "%s: more than one NCE under %s", + __func__, naming_context); + retval = FEDFS_ERR_NSDB_NONCE; + goto out; + } + retval = nsdb_parse_ncedn(ld, message, dn); + if (retval == FEDFS_OK) + xlog(D_CALL, "%s: %s contains NCE %s", + __func__, naming_context, *dn); + goto out; + case LDAP_RES_SEARCH_RESULT: + retval = nsdb_parse_result(ld, message, + &host->fn_referrals, + ldap_err); + break; + default: + xlog(L_ERROR, "%s: Unrecognized LDAP message type", + __func__); + retval = FEDFS_ERR_NSDB_FAULT; + } + } + +out: + ldap_msgfree(response); + return retval; +} + +/** + * Get the naming context's NSDB DN, if it has one + * + * @param host an initialized and bound nsdb_t object + * @param naming_context NUL-terminated C string containing one naming context + * @param dn OUT: pointer to a NUL-terminated C string containing full DN of NSDB container + * @param ldap_err OUT: possibly an LDAP error code + * @return a FedFsStatus code + * + * Caller must free "dn" with free(3) + */ +FedFsStatus +nsdb_get_ncedn_s(nsdb_t host, const char *naming_context, char **dn, + unsigned int *ldap_err) +{ + FedFsStatus retval; + + if (host->fn_ldap == NULL) { + xlog(L_ERROR, "%s: NSDB not open", __func__); + return FEDFS_ERR_INVAL; + } + + if (dn == NULL || ldap_err == NULL) { + xlog(L_ERROR, "%s: Invalid parameter", __func__); + return FEDFS_ERR_INVAL; + } + + retval = nsdb_new_get_ncedn_s(host, naming_context, dn, ldap_err); + if (retval != FEDFS_OK) + retval = nsdb_old_get_ncedn_s(host, naming_context, + dn, ldap_err); + return retval; +} + +/** * Parse namingContext attribute * * @param ld an initialized LDAP descriptor