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

Reply via email to