@@ -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],
@@ -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
@@ -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";
@@ -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
*
@@ -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 */
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 <chuck.lever@oracle.com> --- 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(-)