liburiparser is the correct and standard way to construct and parse RFC 3986-complaint URIs. FedFS represents NFS locations as NFS URIs when storing locations in an NSDB.
Unfortunately not every Linux distribution packages liburiparser. The liburiparser build requirement puts fedfs-utils 0.9 and later offlimits for such distributions. As a stop-gap, provide hand-coded URI parsers which can fill in if liburiparser is not available. To use the new internal parsers instead of liburiparser, specify "--without-liburiparser" on the ./configure command line. The default setting is "--with-liburiparser". Signed-off-by: Chuck Lever <[email protected]> --- configure.ac | 10 ++ src/include/nsdb.h | 11 +++ src/libnsdb/administrator.c | 95 +++++++++++++++++++++++ src/libnsdb/fileserver.c | 175 +++++++++++++++++++++++++++++++++++++++++++ src/libnsdb/path.c | 5 + 5 files changed, 292 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 679dda3..570fcc1 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,12 @@ AC_ARG_WITH([statedir], AC_SUBST(statedir) AC_DEFINE_UNQUOTED([FEDFS_DEFAULT_STATEDIR], ["$statedir"], [Define to the default pathname of the directory where fedfsd maintains persistent state.]) +AC_ARG_WITH([liburiparser], + [AS_HELP_STRING([--with-liburiparser], + [Disable if liburiparser is not available @<:@default=enabled@:>@])], + with_uriparser=$withval, + with_uriparser=yes) + AC_SUBST(with_uriparser) # Publication date stamp for man pages pubdate=`date +"%e %B %Y"` @@ -124,11 +130,13 @@ AC_CHECK_LIB([xml2], [xmlParseFile], AC_DEFINE([HAVE_LIBXML2], [1], [Define if you have libxml2])], [AC_MSG_ERROR([libxml2 not found.])]) -AC_CHECK_LIB([uriparser], [uriParseUriA], +if test "$with_uriparser" = yes; then + AC_CHECK_LIB([uriparser], [uriParseUriA], [AC_SUBST([LIBURIPARSER], ["-luriparser"]) AC_DEFINE([HAVE_LIBURIPARSER], [1], [Define if you have liburiparser])], [AC_MSG_ERROR([liburiparser not found.])]) +fi AC_CHECK_LIB([crypto], [X509_LOOKUP_file], [AC_SUBST([LIBCRYPTO], ["-lcrypto"]) AC_DEFINE([HAVE_LIBCRYPTO], [1], diff --git a/src/include/nsdb.h b/src/include/nsdb.h index 4f6aadc..224b671 100644 --- a/src/include/nsdb.h +++ b/src/include/nsdb.h @@ -26,9 +26,16 @@ #ifndef _FEDFS_NSDB_H_ #define _FEDFS_NSDB_H_ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + #include <netdb.h> #include <ldap.h> + +#ifdef HAVE_LIBURIPARSER #include <uriparser/Uri.h> +#endif #include "fedfs_admin.h" #include "fedfs.h" @@ -452,12 +459,16 @@ FedFsStatus nsdb_path_array_to_fedfspathname(char * const *path_array, FedFsPathName *fpath); FedFsStatus nsdb_fedfspathname_to_path_array(FedFsPathName fpath, char ***path_array); + +#ifdef HAVE_LIBURIPARSER void nsdb_assign_textrange(UriTextRangeA *text, const char *string); FedFsStatus nsdb_path_array_to_uri_pathname(char * const *path_array, UriUriA *uri); FedFsStatus nsdb_uri_pathname_to_path_array(const UriUriA *uri, char ***path_array); +#endif /* HAVE_LIBURIPARSER */ + /** ** x.509 certificate utilities diff --git a/src/libnsdb/administrator.c b/src/libnsdb/administrator.c index 4fd93ec..81a2537 100644 --- a/src/libnsdb/administrator.c +++ b/src/libnsdb/administrator.c @@ -612,6 +612,8 @@ nsdb_construct_fsl_dn(const char *nce, const char *fsn_uuid, const char *fsl_uui return dn; } +#ifdef HAVE_LIBURIPARSER + /** * Build a UriUriA for the location information in "nfsfsl" * @@ -691,6 +693,99 @@ out: return retval; } +#else /* !HAVE_LIBURIPARSER */ + +/** + * Check if a hostname is an IPv6 presentation address + * + * @param hostname a NUL-terminated C string containing a hostname + * @return boolean + */ +static _Bool +nsdb_hostname_is_ipv6_addr(const char *hostname) +{ + struct addrinfo hints = { + .ai_flags = AI_NUMERICHOST, + .ai_family = AF_INET6, + }; + struct addrinfo *ai; + int err; + + err = getaddrinfo(hostname, NULL, &hints, &ai); + if (err) + return false; + freeaddrinfo(ai); + return true; +} + +/** + * Construct an NFS URI for this location + * + * @param nfsfsl an initialized struct fedfs_nfs_fsl + * @param nfsuri OUT: a NUL-terminated C string containing an NFS URI + * @return a FedFsStatus code + * + * Caller must free "nfsuri" with free(3). + */ +static FedFsStatus +nsdb_construct_nfsuri(const struct fedfs_nfs_fsl *nfsfsl, char **nfsuri) +{ + char *result, *pathname; + FedFsStatus retval; + size_t len; + + /* + * We're cheating here: in most cases, the POSIX pathname + * is appropriate to use for the URI. For cases that are + * broken here, use liburiparser. + */ + retval = nsdb_path_array_to_posix(nfsfsl->fn_nfspath, &pathname); + if (retval != FEDFS_OK) + goto out; + retval = FEDFS_ERR_SVRFAULT; + + len = strlen("nfs://") + 2 + strlen(nfsfsl->fn_fslhost) + 8 + + strlen(pathname) + 1; + result = calloc(len, sizeof(char)); + if (result == NULL) + goto out; + result[0] = '\0'; + + /* + * URI scheme + */ + strcat(result, "nfs://"); + + /* + * URI authority + */ + if (nsdb_hostname_is_ipv6_addr(nfsfsl->fn_fslhost)) { + strcat(result, "["); + strcat(result, nfsfsl->fn_fslhost); + strcat(result, "]"); + } else + strcat(result, nfsfsl->fn_fslhost); + if (nfsfsl->fn_fslport != NFS_PORT && nfsfsl->fn_fslport != 0) { + char portbuf[8]; + sprintf(portbuf, ":%u", nfsfsl->fn_fslport); + strcat(result, portbuf); + } + + /* + * URI path + */ + strcat(result, pathname); + + *nfsuri = result; + retval = FEDFS_OK; + +out: + free(pathname); + return retval; +} + +#endif /* !HAVE_LIBURIPARSER */ + static const char *nsdb_ldap_true = "TRUE"; static const char *nsdb_ldap_false = "FALSE"; diff --git a/src/libnsdb/fileserver.c b/src/libnsdb/fileserver.c index d3f7560..96fad2c 100644 --- a/src/libnsdb/fileserver.c +++ b/src/libnsdb/fileserver.c @@ -39,8 +39,6 @@ #include <unistd.h> #include <netdb.h> -#include <uriparser/Uri.h> - #include "nsdb.h" #include "nsdb-internal.h" #include "xlog.h" @@ -712,6 +710,8 @@ nsdb_parse_annotations(struct berval **values, char ***annotations) return FEDFS_OK; } +#ifdef HAVE_LIBURIPARSER + /** * Unmarshal a parsed NFS URI object into an NFS FSL * @@ -834,6 +834,177 @@ out: return retval; } +#else /* !HAVE_URIPARSER */ + +/** + * Check if a hostname is an IPv6 presentation address + * + * @param hostname a NUL-terminated C string containing a hostname + * @return boolean + */ +static _Bool +nsdb_hostname_is_ipv6_addr(const char *hostname) +{ + struct addrinfo hints = { + .ai_flags = AI_NUMERICHOST, + .ai_family = AF_INET6, + }; + struct addrinfo *ai; + int err; + + err = getaddrinfo(hostname, NULL, &hints, &ai); + if (err) + return false; + freeaddrinfo(ai); + return true; +} + +/** + * Parse authority portion of a URI that contains an IPv6 address + * + * @param authority a NUL-terminated C string containing authority portion of URI + * @param nfsl OUT: fedfs_nfs_fsl structure to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nsdb_parse_authority_with_ipv6(char *authority, struct fedfs_nfs_fsl *nfsl) +{ + char *pos, *hostname; + unsigned short port; + + hostname = authority + 1; + pos = strchr(hostname, ']'); + if (pos == NULL) { + xlog(L_ERROR, "%s: NFS URI contains unbalanced square brackets", + __func__); + return FEDFS_ERR_NSDB_RESPONSE; + } + *pos = '\0'; + if (!nsdb_hostname_is_ipv6_addr(hostname)) { + xlog(L_ERROR, "%s: NFS URI contains non-IPv6 address in square brackets", + __func__); + return FEDFS_ERR_NSDB_RESPONSE; + } + + pos++; + port = 0; + if (*pos == ':') { + pos++; + if (!nsdb_parse_port_string(pos, &port)) { + xlog(L_ERROR, "%s: NFS URI has invalid port", + __func__, pos); + return FEDFS_ERR_NSDB_RESPONSE; + } + } + + strcpy(nfsl->fn_fslhost, hostname); + nfsl->fn_fslport = port; + return FEDFS_OK; +} + +/** + * Parse authority portion of a URI that does not contain an IPv6 address + * + * @param authority a NUL-terminated C string containing authority portion of URI + * @param nfsl OUT: fedfs_nfs_fsl structure to fill in + * @return a FedFsStatus code + */ +static int +nsdb_parse_authority_without_ipv6(char *authority, struct fedfs_nfs_fsl *nfsl) +{ + char *pos, *hostname; + unsigned short port; + + port = 0; + hostname = authority; + pos = strchr(hostname, ':'); + if (pos != NULL) { + *pos++ = '\0'; + if (!nsdb_parse_port_string(pos, &port)) { + xlog(L_ERROR, "%s: NFS URI has invalid port", + __func__, pos); + return FEDFS_ERR_NSDB_RESPONSE; + } + } + + strcpy(nfsl->fn_fslhost, hostname); + nfsl->fn_fslport = port; + return FEDFS_OK; +} + +/** + * Parse an NFS URI into an NFS FSL + * + * @param uri a NUL-terminated C string containing URI to parse + * @param nfsl OUT: fedfs_nfs_fsl structure to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nsdb_parse_nfs_uri_freehand(const char *uri, struct fedfs_nfs_fsl *nfsl) +{ + static char authbuf[BUFSIZ]; + char *pos = (char *)uri; + char *pathname, **path; + FedFsStatus retval; + + if (strncasecmp(pos, "nfs://", 6) != 0) { + xlog(L_ERROR, "%s: non-NFS URI", __func__); + return FEDFS_ERR_NSDB_RESPONSE; + } + pos += 6; + + pathname = strchr(pos, '/'); + if (pathname == NULL) { + xlog(L_ERROR, "%s: NFS URI contains no pathname", __func__); + return FEDFS_ERR_NSDB_RESPONSE; + } + + retval = nsdb_posix_to_path_array(pathname, &path); + if (retval != FEDFS_OK) + return retval; + + authbuf[0] = '\0'; + strncpy(authbuf, pos, pathname - pos); + if (authbuf[0] == '[') + retval = nsdb_parse_authority_with_ipv6(authbuf, nfsl); + else + retval = nsdb_parse_authority_without_ipv6(authbuf, nfsl); + if (retval != FEDFS_OK) { + nsdb_free_string_array(path); + return retval; + } + nfsl->fn_nfspath = path; + return FEDFS_OK; +} + +/** + * Parse an NFS URI into a hostname and pathname + * + * @param attr NUL-terminated C string containing LDAP attribute name + * @param values URI string value returned from LDAP server + * @param nfsl OUT: fedfs_nfs_fsl structure to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nsdb_parse_nfs_uri(const char *attr, struct berval **values, + struct fedfs_nfs_fsl *nfsl) +{ + if (values[0] == NULL) { + xlog(L_ERROR, "%s: NULL value for attribute %s", + __func__, attr); + return FEDFS_ERR_NSDB_RESPONSE; + } + if (values[1] != NULL) { + xlog(L_ERROR, "%s: Expecting only one value for attribute %s", + __func__, attr); + return FEDFS_ERR_NSDB_RESPONSE; + } + + return nsdb_parse_nfs_uri_freehand((char *)values[0]->bv_val, nfsl); +} + +#endif /* !HAVE_URIPARSER */ + /** * Parse the values of each attribute in a fedfsFsl object * diff --git a/src/libnsdb/path.c b/src/libnsdb/path.c index 11bf73b..c14d516 100644 --- a/src/libnsdb/path.c +++ b/src/libnsdb/path.c @@ -38,7 +38,6 @@ #include <ldap.h> #include <netinet/in.h> -#include <uriparser/Uri.h> #include "nsdb.h" #include "junction.h" @@ -589,6 +588,8 @@ nsdb_fedfspathname_to_path_array(FedFsPathName fpath, char ***path_array) return FEDFS_OK; } +#ifdef HAVE_LIBURIPARSER + /** * Assign the value of "string" to a UriTextRangeA field * @@ -816,3 +817,5 @@ nsdb_uri_pathname_to_path_array(const UriUriA *uri, char ***path_array) *path_array = result; return FEDFS_OK; } + +#endif /* HAVE_LIBURIPARSER */ _______________________________________________ fedfs-utils-devel mailing list [email protected] https://oss.oracle.com/mailman/listinfo/fedfs-utils-devel
