@@ -145,6 +145,11 @@ AC_CHECK_LIB([attr], [fgetxattr],
AC_DEFINE([HAVE_LIBATTR], [1],
[Define if you have libattr])],
[AC_MSG_ERROR([libattr not found.])])
+AC_CHECK_LIB([gssapi_krb5], [gss_acquire_cred],
+ [AC_SUBST([LIBGSSAPI_KRB5], ["-lgssapi_krb5"])
+ AC_DEFINE([HAVE_LIBGSSAPI_KRB5], [1],
+ [Define if you have libgssapi_krb5])],
+ [AC_MSG_ERROR([libgssapi_krb5 not found.])])
# Checks for header files.
AC_CHECK_HEADERS([fcntl.h langinfo.h locale.h memory.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h syslog.h termios.h unistd.h wchar.h])
@@ -36,7 +36,7 @@ LDADD = $(top_builddir)/src/libadmin/libadmin.la \
$(top_builddir)/src/libxlog/libxlog.la \
$(LIBTIRPC) $(LIBLDAP) $(LIBLBER) $(LIBXML2) \
$(LIBSQLITE3) $(LIBIDN) $(LIBUUID) \
- $(LIBCRYPTO) $(LIBSSL)
+ $(LIBCRYPTO) $(LIBSSL) $(LIBGSSAPI_KRB5)
CLEANFILES = cscope.in.out cscope.out cscope.po.out *~
DISTCLEANFILES = Makefile.in
@@ -24,8 +24,8 @@
##
include_HEADERS = nfs-plugin.h
-noinst_HEADERS = fedfs_admin.h fedfs.h getsrvinfo.h gpl-boiler.h \
- junction.h list.h nsdb.h parse_opt.h \
+noinst_HEADERS = admin.h fedfs_admin.h fedfs.h getsrvinfo.h \
+ gpl-boiler.h junction.h list.h nsdb.h parse_opt.h \
token.h xlog.h
CLEANFILES = cscope.in.out cscope.out cscope.po.out *~
new file mode 100644
@@ -0,0 +1,286 @@
+/*
+ * @file src/include/admin.h
+ * @brief Common public declarations for the ADMIN API
+ */
+
+/*
+ * Copyright 2013 Oracle. All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils. If not, see:
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#ifndef _FEDFS_ADMIN_API_H_
+#define _FEDFS_ADMIN_API_H_
+
+#include <stdbool.h>
+#include <netdb.h>
+
+#include "fedfs_admin.h"
+#include "fedfs.h"
+#include "nsdb.h"
+
+/*
+ * Client-side failures are reported as an errno, via the return value
+ * of the API functions.
+ *
+ * Server-side failures are reported as a FedFsStatus code, extracted with
+ * the admin_status() function.
+ *
+ * Client API error codes
+ *
+ * 0: RPC successful, check ad_srv_status for server result
+ * EACCES: Security failure
+ * EIO: RPC call or network transport failure
+ * EINVAL: Function was passed invalid parameters, or parameters
+ * that could not be marshalled
+ * ENAMETOOLONG: Problem parsing outgoing or incoming path_array
+ * ENOMEM: Local resource allocation error occurred
+ * ENOTCONN: admin_t object is not connected to remote ADMIN service
+ * EOPNOTSUPP: Client does not support this operation
+ */
+
+/**
+ ** Arguments and results
+ **/
+
+/**
+ * NSDB
+ */
+struct admin_nsdb {
+ const char *an_hostname;
+ uint16_t an_port;
+};
+
+/**
+ * FileSet Name
+ */
+struct admin_fsn {
+ const char *af_uuid;
+ struct admin_nsdb af_nsdb;
+};
+
+/**
+ * FileSet Location
+ */
+struct admin_fsl {
+ struct admin_fsl *al_next;
+ const char *al_uuid;
+ const char *al_hostname;
+ uint16_t al_port;
+ char * const *al_pathname;
+};
+
+/**
+ * X.509 certificate material
+ */
+struct admin_cert {
+ unsigned int ac_len;
+ const char *ac_data;
+};
+
+/**
+ * Free an in-memory FSN data structure
+ */
+void admin_free_fsn(struct admin_fsn *fsn);
+
+/**
+ * Free a list of in-memory FSL data structures
+ */
+void admin_free_fsls(struct admin_fsl *fsls);
+
+/**
+ * Free a certificate buffer
+ */
+void admin_free_cert(struct admin_cert *cert);
+
+/**
+ ** API for managing admin_t objects
+ **/
+
+/**
+ * Object that internally represents an ADMIN service
+ */
+struct fedfs_admin;
+typedef struct fedfs_admin *admin_t;
+
+/**
+ * Construct a new admin_t object
+ */
+int admin_create(const char *hostname, const char *nettype,
+ const char *security, admin_t *result);
+
+/**
+ * Release all resources associated with an admin_t object
+ */
+void admin_release(admin_t host);
+
+/**
+ * Get ADMIN service's DNS hostname
+ */
+const char *admin_hostname(const admin_t host);
+
+/**
+ * Get the length of ADMIN service's DNS hostname
+ */
+size_t admin_hostname_len(const admin_t host);
+
+/**
+ * Get the RPC nettype used to connect to ADMIN service
+ */
+const char *admin_nettype(const admin_t host);
+
+/**
+ * Get the authentication flavor used to connect to ADMIN service
+ */
+uint32_t admin_flavor(const admin_t host);
+
+/**
+ * Get the FedFsStatus code returned by the last ADMIN service operation
+ */
+FedFsStatus admin_status(const admin_t host);
+
+/**
+ * LDAP status if server returned FEDFS_ERR_NSDB_LDAP_VAL
+ */
+int admin_ldaperr(const admin_t host);
+
+/**
+ * Predicate: is "host" connected to a remote ADMIN service?
+ */
+_Bool admin_is_connected(admin_t host);
+
+/**
+ * Return an RPC create error message string
+ */
+const char *admin_open_perror(const char *prefix);
+
+/**
+ * Return an RPC error message string
+ */
+const char *admin_perror(admin_t host, const char *prefix);
+
+
+/**
+ ** ADMIN operations defined in the
+ ** ADMIN protocol draft, Chapter 5)
+ **/
+
+/**
+ * FEDFS_NULL (5.1)
+ */
+int admin_null(admin_t host);
+
+/**
+ * FEDFS_CREATE_JUNCTION (5.2)
+ */
+int admin_create_junction(admin_t host,
+ char * const *path_array,
+ struct admin_fsn *fsn);
+
+/**
+ * FEDFS_DELETE_JUNCTION (5.3)
+ */
+int admin_delete_junction(admin_t host,
+ char * const *path_array);
+
+/**
+ * FEDFS_LOOKUP_JUNCTION (5.4) - ResolveType None
+ */
+int admin_lookup_junction_none(admin_t host,
+ char * const *path_array,
+ struct admin_fsn **fsn);
+
+/**
+ * FEDFS_LOOKUP_JUNCTION (5.4) - ResolveType Cached
+ */
+int admin_lookup_junction_cached(admin_t host,
+ char * const *path_array,
+ struct admin_fsn **fsn,
+ struct admin_fsl **fsls);
+
+/**
+ * FEDFS_LOOKUP_JUNCTION (5.4) - ResolveType Nsdb
+ */
+int admin_lookup_junction_nsdb(admin_t host,
+ char * const *path_array,
+ struct admin_fsn **fsn,
+ struct admin_fsl **fsls);
+
+/**
+ * FEDFS_CREATE_REPLICATION (5.5)
+ */
+int admin_create_replication(admin_t host,
+ char * const *path_array,
+ struct admin_fsn *fsn);
+
+/**
+ * FEDFS_DELETE_REPLICATION (5.6)
+ */
+int admin_delete_replication(admin_t host,
+ char * const *path_array);
+/**
+ * FEDFS_LOOKUP_REPLICATION (5.7) - ResolveType None
+ */
+int admin_lookup_replication_none(admin_t host,
+ char * const *path_array,
+ struct admin_fsn **fsn);
+
+/**
+ * FEDFS_LOOKUP_REPLICATION (5.7) - ResolveType Cached
+ */
+int admin_lookup_replication_cached(admin_t host,
+ char * const *path_array,
+ struct admin_fsn **fsn,
+ struct admin_fsl **fsls);
+
+/**
+ * FEDFS_LOOKUP_REPLICATION (5.7) - ResolveType Nsdb
+ */
+int admin_lookup_replication_nsdb(admin_t host,
+ char * const *path_array,
+ struct admin_fsn **fsn,
+ struct admin_fsl **fsls);
+
+/**
+ * FEDFS_SET_NSDB_PARAMS (5.8) - ConnectionSec NONE
+ */
+int admin_set_nsdb_params_none(admin_t host,
+ const struct admin_nsdb *nsdb);
+
+/**
+ * FEDFS_SET_NSDB_PARAMS (5.8) - ConnectionSec TLS
+ */
+int admin_set_nsdb_params_tls(admin_t host,
+ const struct admin_nsdb *nsdb,
+ const struct admin_cert *cert);
+
+/**
+ * FEDFS_GET_NSDB_PARAMS (5.9)
+ */
+int admin_get_nsdb_params(admin_t host,
+ struct admin_nsdb *nsdb,
+ FedFsConnectionSec *sectype,
+ struct admin_cert **cert);
+
+/**
+ * FEDFS_GET_LIMITED_NSDB_PARAMS (5.10)
+ */
+int admin_get_limited_nsdb_params(admin_t host,
+ struct admin_nsdb *nsdb,
+ FedFsConnectionSec *sectype);
+
+#endif /* !_FEDFS_ADMIN_API_H_ */
@@ -47,6 +47,11 @@
#define FEDFS_DATABASE_FILE "nsdbparam.sqlite3"
/**
+ * From draft-cel-nfsv4-federated-fs-security-addendum
+ */
+#define FEDFS_ADMIN_GSS_SERVICE_NAME "fedfs-admin"
+
+/**
* Initial number of seconds to wait after receiving FEDFS_ERR_DELAY
*/
#define FEDFS_DELAY_MIN_SECS 2
@@ -23,8 +23,11 @@
## http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
##
+noinst_HEADERS = admin-internal.h
+
noinst_LTLIBRARIES = libadmin.la
-libadmin_la_SOURCES = fedfs_admin_xdr.c
+libadmin_la_SOURCES = admin.c fedfs_admin_xdr.c gss.c junction.c \
+ nsdb.c null.c
CLEANFILES = cscope.in.out cscope.out cscope.po.out *~
DISTCLEANFILES = Makefile.in
new file mode 100644
@@ -0,0 +1,61 @@
+/*
+ * @file src/libadmin/admin-internal.h
+ * @brief Private declarations for the ADMIN API
+ */
+
+/*
+ * Copyright 2013 Oracle. All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils. If not, see:
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#ifndef _FEDFS_ADMIN_INTERNAL_H_
+#define _FEDFS_ADMIN_INTERNAL_H_
+
+#include <time.h>
+#include <rpc/clnt.h>
+#include <rpc/auth_gss.h>
+
+#include "fedfs_admin.h"
+#include "admin.h"
+
+/**
+ * object that internally represents an ADMIN service
+ */
+struct fedfs_admin {
+ char *ad_hostname;
+ char *ad_nettype;
+ int ad_secflavor;
+ rpc_gss_svc_t ad_gss_svc;
+ CLIENT *ad_client;
+ enum clnt_stat ad_rpc_status;
+ struct timeval ad_timeout;
+ FedFsStatus ad_srv_status;
+ int ad_ldaperr;
+};
+
+/**
+ * Reset error status values
+ */
+void admin_reset(admin_t host);
+
+/**
+ * Create an AUTH and GSS context
+ */
+int admin_authgss_create(CLIENT *clnt, admin_t host, AUTH **auth);
+
+#endif /* !_FEDFS_ADMIN_INTERNAL_H_ */
new file mode 100644
@@ -0,0 +1,386 @@
+/**
+ * @file src/libadmin/admin.c
+ * @brief Manage admin_t objects
+ */
+
+/*
+ * Copyright 2013 Oracle. All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils. If not, see:
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <sys/types.h>
+
+#include <stdbool.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "fedfs_admin.h"
+#include "fedfs.h"
+#include "admin-internal.h"
+#include "admin.h"
+#include "xlog.h"
+
+/**
+ * Default RPC request timeout
+ */
+static const struct timeval admin_rpc_timeout = { 25, 0 };
+
+/**
+ * Return admin_t's hostname
+ *
+ * @param host an initialized admin_t
+ * @return NUL-terminated C string containing "host's" hostname
+ *
+ * Lifetime of this string is the same as the lifetime of the
+ * admin_t. Caller must not free this string, and must not use
+ * it after the admin_t is freed.
+ */
+const char *admin_hostname(const admin_t host)
+{
+ if (host == NULL)
+ return NULL;
+ return host->ad_hostname;
+}
+
+/**
+ * Return length of admin_t's hostname, in bytes
+ *
+ * @param host an initialized admin_t
+ * @return the number of bytes in "host's" hostname, excluding the terminating NUL
+ */
+size_t admin_hostname_len(const admin_t host)
+{
+ if (host == NULL)
+ return 0;
+ return strlen(host->ad_hostname);
+}
+
+/**
+ * Return admin_t's nettype
+ *
+ * @param host an initialized admin_t
+ * @return NUL-terminated C string containing "host's" nettype
+ *
+ * Lifetime of this string is the same as the lifetime of the
+ * admin_t. Caller must not free this string, and must not use
+ * it after the admin_t is freed.
+ */
+const char *admin_nettype(const admin_t host)
+{
+ if (host == NULL)
+ return NULL;
+ return host->ad_nettype;
+}
+
+/**
+ * Predicate: is "host" connected to a remote ADMIN service?
+ *
+ * @param host an initialized admin_t struct
+ * @return true if the "host" is connected
+ */
+_Bool
+admin_is_connected(admin_t host)
+{
+ return host->ad_client != NULL;
+}
+
+/**
+ * Create an AUTH_UNIX Auth
+ *
+ * @param auth OUT: a fresh AUTH object
+ * @return zero or an errno
+ *
+ * Caller must destroy returned object with auth_destroy()
+ */
+static int
+admin_authunix_create(AUTH **auth)
+{
+ AUTH *result;
+
+ result = authunix_create_default();
+ if (result == NULL) {
+ xlog(D_GENERAL, "%s", clnt_spcreateerror(__func__));
+ return EACCES;
+ }
+
+ *auth = result;
+ return 0;
+}
+
+/**
+ * Connect to a remote ADMIN service
+ *
+ * @param host an initialized admin_t struct
+ * @return zero or an errno
+ */
+static int
+admin_open(admin_t host)
+{
+ CLIENT *clnt;
+ AUTH *auth;
+ int err;
+
+ if (admin_is_connected(host))
+ return 0;
+
+ xlog(D_CALL, "opening admin_t for %s",
+ admin_hostname(host));
+
+ clnt = clnt_create(admin_hostname(host),
+ FEDFS_PROG, FEDFS_V1, admin_nettype(host));
+ if (clnt == NULL)
+ return ENOTCONN;
+
+ switch (host->ad_secflavor) {
+ case AUTH_UNIX:
+ err = admin_authunix_create(&auth);
+ break;
+ case RPCSEC_GSS:
+ err = admin_authgss_create(clnt, host, &auth);
+ break;
+ default:
+ xlog(D_GENERAL, "%s: Unsupported security flavor", __func__);
+ return EINVAL;
+ }
+ if (err != 0) {
+ (void)clnt_destroy(clnt);
+ return err;
+ }
+
+ host->ad_client = clnt;
+ clnt->cl_auth = auth;
+ return 0;
+}
+
+/**
+ * Free TI-RPC library and network resources
+ *
+ * @param host an initialized admin_t struct
+ */
+static int
+admin_close(admin_t host)
+{
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ xlog(D_CALL, "closing admin_t for %s",
+ admin_hostname(host));
+
+ auth_destroy(host->ad_client->cl_auth);
+ (void)clnt_destroy(host->ad_client);
+ host->ad_client = NULL;
+ return 0;
+}
+
+/**
+ * Release all resources associated with an admin_t object
+ *
+ * @param host admin_t allocated by admin_new()
+ *
+ * This API performs an implicit admin_close().
+ */
+void
+admin_release(admin_t host)
+{
+ if (host == NULL)
+ return;
+
+ xlog(D_CALL, "freeing admin_t for %s",
+ admin_hostname(host));
+
+ (void)admin_close(host);
+
+ free(host->ad_hostname);
+ free(host->ad_nettype);
+ free(host);
+}
+
+/**
+ * Reset error status values
+ *
+ * @param host admin_t allocated by admin_new()
+ */
+void
+admin_reset(admin_t host)
+{
+ host->ad_srv_status = FEDFS_ERR_SVRFAULT;
+ host->ad_rpc_status = RPC_FAILED;
+ host->ad_ldaperr = LDAP_OTHER;
+}
+
+/**
+ * Materialize a new admin_t object
+ *
+ * @param hostname NUL-terminated UTF-8 string containing ADMIN server's hostname
+ * @param nettype NUL-terminated C string containing nettype to use for connection
+ * @param security NUL-terminated C string containing name of security mode
+ * @param result OUT: an initialized admin_t
+ * @return zero or an errno
+ *
+ * Caller must free returned object with admin_release()
+ */
+static int
+admin_new(const char *hostname, const char *nettype, const char *security,
+ admin_t *result)
+{
+ rpc_gss_svc_t svc;
+ admin_t new;
+ int flavor;
+
+ svc = RPCSEC_GSS_SVC_NONE;
+ if (strcasecmp(security, "sys") == 0)
+ flavor = AUTH_UNIX;
+ else if (strcasecmp(security, "unix") == 0)
+ flavor = AUTH_UNIX;
+ else if (strcasecmp(security, "krb5") == 0) {
+ flavor = RPCSEC_GSS;
+ } else if (strcasecmp(security, "krb5i") == 0) {
+ flavor = RPCSEC_GSS;
+ svc = RPCSEC_GSS_SVC_INTEGRITY;
+ } else if (strcasecmp(security, "krb5p") == 0) {
+ flavor = RPCSEC_GSS;
+ svc = RPCSEC_GSS_SVC_PRIVACY;
+ } else
+ return EINVAL;
+
+ new = calloc(1, sizeof(struct fedfs_admin));
+ if (new == NULL)
+ return ENOMEM;
+
+ new->ad_hostname = strdup(hostname);
+ new->ad_nettype = strdup(nettype);
+ new->ad_secflavor = flavor;
+ new->ad_gss_svc = svc;
+ new->ad_client = NULL;
+ new->ad_timeout = admin_rpc_timeout;
+
+ if (new->ad_hostname == NULL || new->ad_nettype == NULL) {
+ admin_release(new);
+ return ENOMEM;
+ }
+
+ xlog(D_CALL, "created admin_t for %s", hostname);
+
+ admin_reset(new);
+ *result = new;
+ return 0;
+}
+
+/**
+ * Create an admin_t and open it
+ *
+ * @param hostname NUL-terminated UTF-8 string containing ADMIN server's hostname
+ * @param nettype NUL-terminated C string containing nettype to use for connection
+ * @param security NUL-terminated C string containing name of security mode
+ * @param result OUT: an initialized admin_t
+ * @return zero or an errno
+ *
+ * Caller must free returned object with admin_release()
+ */
+int
+admin_create(const char *hostname, const char *nettype, const char *security,
+ admin_t *result)
+{
+ admin_t new;
+ int err;
+
+ if (hostname == NULL || nettype == NULL ||
+ result == NULL || security == NULL)
+ return EINVAL;
+
+ if (strlen(hostname) == 0 || strlen(nettype) == 0 ||
+ strlen(security) == 0)
+ return EINVAL;
+
+ err = admin_new(hostname, nettype, security, &new);
+ if (err != 0)
+ return err;
+
+ err = admin_open(new);
+ if (err != 0)
+ return err;
+
+ *result = new;
+ return 0;
+}
+
+/**
+ * Server status code returned by the last FedFS operation
+ *
+ * @param host an initialized admin_t
+ * @return a FedFsStatus code
+ */
+FedFsStatus
+admin_status(const admin_t host)
+{
+ if (host == NULL)
+ return FEDFS_ERR_SVRFAULT;
+ return host->ad_srv_status;
+}
+
+/**
+ * LDAP status if server returned FEDFS_ERR_NSDB_LDAP_VAL
+ *
+ * @param host an initialized admin_t
+ * @return an LDAP operation return code
+ */
+int
+admin_ldaperr(const admin_t host)
+{
+ if (host == NULL)
+ return LDAP_OTHER;
+ return host->ad_ldaperr;
+}
+
+/**
+ * Return an RPC create error message string
+ *
+ * @param prefix NUL-terminated C string containing prefix message
+ * @return NUL-terminated C string containing an error message, or NULL
+ *
+ * Caller must not free the returned buffer.
+ */
+const char *
+admin_open_perror(const char *prefix)
+{
+ if (prefix == NULL)
+ return NULL;
+ return clnt_spcreateerror(prefix);
+}
+
+/**
+ * Return an RPC error message string
+ *
+ * @param host an initialized admin_t
+ * @param prefix NUL-terminated C string containing prefix message
+ * @return NUL-terminated C string containing an error message, or NULL
+ *
+ * Caller must not free the returned buffer.
+ */
+const char *
+admin_perror(admin_t host, const char *prefix)
+{
+ if (host == NULL || prefix == NULL || host->ad_client == NULL)
+ return NULL;
+ if (!admin_is_connected(host))
+ return NULL;
+ return clnt_sperror(host->ad_client, prefix);
+}
new file mode 100644
@@ -0,0 +1,281 @@
+/**
+ * @file src/libadmin/gss.c
+ * @brief RPCSEC GSS utility functions
+ */
+
+/*
+ * Copyright 2013 Oracle. All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils. If not, see:
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <netdb.h>
+#include <gssapi/gssapi.h>
+
+#include "fedfs_admin.h"
+#include "fedfs.h"
+#include "admin-internal.h"
+#include "admin.h"
+#include "xlog.h"
+
+/**
+ * OID for Kerberos v5 GSS mechanism (RFC 2743, section 1.1.4)
+ */
+static gss_OID_desc admin_gss_krb5_oid =
+ { 9, "\052\206\110\206\367\022\001\002\002" };
+
+/**
+ * List of GSS mechanisms supported by this implementation
+ */
+static gss_OID_set_desc admin_gss_mechs = { 1, &admin_gss_krb5_oid };
+
+/**
+ * Log a major GSS error
+ *
+ * @param prefix NUL-terminated C string containing log entry prefix
+ * @param maj_stat major status to report
+ * @param min_stat minor status to report
+ */
+static void
+admin_log_gss_major_error(const char *prefix, OM_uint32 maj_stat,
+ OM_uint32 min_stat)
+{
+ gss_buffer_desc maj_msg, min_msg;
+ OM_uint32 min, msg_ctx;
+
+ msg_ctx = 0;
+ gss_display_status(&min, maj_stat, GSS_C_GSS_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &maj_msg);
+ gss_display_status(&min, min_stat, GSS_C_MECH_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &min_msg);
+
+ xlog(D_GENERAL, "%s: %s - %s",
+ prefix, (char *)maj_msg.value, (char *)min_msg.value);
+
+ (void)gss_release_buffer(&min, &min_msg);
+ (void)gss_release_buffer(&min, &maj_msg);
+}
+
+/**
+ * Log an unspecified GSS error
+ *
+ * @param prefix NUL-terminated C string containing log entry prefix
+ * @param min_stat minor status to report
+ */
+static void
+admin_log_gss_unspec_error(const char *prefix, OM_uint32 min_stat)
+{
+ gss_buffer_desc min_msg;
+ OM_uint32 min, msg_ctx;
+
+ msg_ctx = 0;
+ gss_display_status(&min, min_stat, GSS_C_MECH_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &min_msg);
+
+ xlog(D_GENERAL, "%s: %s",
+ prefix, (char *)min_msg.value);
+
+ (void)gss_release_buffer(&min, &min_msg);
+}
+
+/**
+ * Log a GSS error
+ *
+ * @param prefix NUL-terminated C string containing log entry prefix
+ * @param maj_stat major status to report
+ * @param min_stat minor status to report
+ */
+static void
+admin_log_gss_error(const char *prefix, OM_uint32 maj_stat, OM_uint32 min_stat)
+{
+ if (GSS_ROUTINE_ERROR(maj_stat) != GSS_S_FAILURE)
+ admin_log_gss_major_error(prefix, maj_stat, min_stat);
+ else
+ admin_log_gss_unspec_error(prefix, min_stat);
+}
+
+/**
+ * Return the GSS service name for the ADMIN server
+ *
+ * @param server NUL-terminated C string containing hostname of server
+ * @return a NUL-terminated C string containing the GSS service name
+ *
+ * Caller must free the returned string with free(3).
+ */
+static char *
+admin_get_gss_svc_name(const char *server)
+{
+ struct addrinfo hint, *ai;
+ char *buffer;
+ size_t len;
+ int err;
+
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_socktype = SOCK_DGRAM;
+ hint.ai_family = AF_UNSPEC;
+ hint.ai_flags = AI_CANONNAME;
+
+ err = getaddrinfo(server, NULL, &hint, &ai);
+ if (err) {
+ xlog(D_GENERAL, "%s: %s", __func__, gai_strerror(err));
+ return NULL;
+ }
+
+ len = strlen(FEDFS_ADMIN_GSS_SERVICE_NAME) + 1 +
+ strlen(ai->ai_canonname) + 1;
+
+ buffer = calloc(len, sizeof(char));
+ if (buffer == NULL) {
+ goto out;
+ }
+
+ buffer[0] = '\0';
+ strcpy(buffer, FEDFS_ADMIN_GSS_SERVICE_NAME);
+ strcat(buffer, "@");
+ strcat(buffer, ai->ai_canonname);
+
+ xlog(D_CALL, "Using service name '%s'", buffer);
+
+out:
+ freeaddrinfo(ai);
+ return buffer;
+}
+
+/**
+ * Acquire a GSS credential for a user
+ *
+ * @param name string form of a UID
+ * @param cred OUT: fresh credential
+ * @return zero or an errno
+ *
+ * Caller must free the returned credential with gss_release_cred()
+ */
+static int
+admin_acquire_cred(gss_name_t name, gss_cred_id_t *cred)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_cred_id_t result;
+
+ maj_stat = gss_acquire_cred(&min_stat, name, GSS_C_INDEFINITE,
+ &admin_gss_mechs, GSS_C_INITIATE,
+ &result, NULL, NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ admin_log_gss_error("Failed to acquire credential",
+ maj_stat, min_stat);
+ return EKEYEXPIRED;
+ }
+
+ *cred = result;
+ return 0;
+}
+
+/**
+ * Construct a GSS credential for the current user
+ *
+ * @param cred OUT: fresh credential
+ * @return zero or an errno
+ *
+ * Caller must free the returned credential with gss_release_cred()
+ */
+static int
+admin_acquire_user_cred(gss_cred_id_t *cred)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc name_buf;
+ gss_name_t name;
+ int retval, len;
+ char buf[16];
+
+ len = snprintf(buf, sizeof(buf), "%u", geteuid());
+ name_buf.value = buf;
+ name_buf.length = len;
+
+ maj_stat = gss_import_name(&min_stat, &name_buf,
+ (gss_OID)GSS_C_NT_STRING_UID_NAME, &name);
+ if (maj_stat != GSS_S_COMPLETE) {
+ admin_log_gss_error("Failed to import name",
+ maj_stat, min_stat);
+ return ENOMEM;
+ }
+
+ retval = admin_acquire_cred(name, cred);
+
+ (void)gss_release_name(&min_stat, &name);
+ return retval;
+}
+
+/**
+ * Create an AUTH and an associated GSS context
+ *
+ * @param clnt RPC client
+ * @param host an initialized admin_t struct
+ * @param auth OUT: a fresh AUTH object
+ * @return zero or an errno
+ *
+ * Caller must destroy returned object with auth_destroy()
+ */
+int
+admin_authgss_create(CLIENT *clnt, admin_t host, AUTH **auth)
+{
+ struct rpc_gss_sec sec;
+ OM_uint32 min_stat;
+ char *svc_name;
+ int retval;
+ AUTH *tmp;
+
+ xlog(D_CALL, "Creating GSS context for server %s",
+ admin_hostname(host));
+
+ retval = ENOMEM;
+ svc_name = admin_get_gss_svc_name(admin_hostname(host));
+ if (svc_name == NULL)
+ goto out;
+
+ retval = admin_acquire_user_cred(&sec.cred);
+ if (retval != 0)
+ goto out;
+
+ sec.mech = &admin_gss_krb5_oid;
+ sec.qop = GSS_C_QOP_DEFAULT;
+ sec.svc = host->ad_gss_svc;
+ sec.req_flags = GSS_C_MUTUAL_FLAG;
+
+ tmp = authgss_create_default(clnt, svc_name, &sec);
+ if (tmp == NULL) {
+ xlog(D_GENERAL, "cf_stat = %d", rpc_createerr.cf_stat);
+ xlog(D_GENERAL, "%s", clnt_spcreateerror(__func__));
+ return EACCES;
+ }
+
+ *auth = tmp;
+ retval = 0;
+
+ (void)gss_release_cred(&min_stat, &sec.cred);
+
+out:
+ free(svc_name);
+ return retval;
+}
new file mode 100644
@@ -0,0 +1,801 @@
+/**
+ * @file src/libadmin/junction.c
+ * @brief Handle junction-related ADMIN RPC operations
+ */
+
+/*
+ * Copyright 2013 Oracle. All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils. If not, see:
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <sys/types.h>
+
+#include <stdbool.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <uuid/uuid.h>
+
+#include "fedfs_admin.h"
+#include "fedfs.h"
+#include "admin-internal.h"
+#include "admin.h"
+#include "xlog.h"
+
+/**
+ * Unmarshal a UUID
+ *
+ * @param uuid UUID in packed wire format
+ * @return NUL-terminated C string containing a text UUID
+ */
+__attribute_malloc__
+static char *
+admin_get_uuid(FedFsUuid uuid)
+{
+ char buf[FEDFS_UUID_STRLEN];
+ uuid_t uu;
+
+ memcpy(uu, uuid, sizeof(uu));
+ uuid_unparse(uu, buf);
+ return strdup(buf);
+}
+
+/**
+ * Allocate an in-memory FSN data structure
+ *
+ * @return a freshly allocated FSN, or NULL
+ */
+__attribute_malloc__
+static struct admin_fsn *
+admin_new_fsn(void)
+{
+ return calloc(1, sizeof(struct admin_fsn));
+}
+
+/**
+ * Free an in-memory FSN data structure
+ *
+ * @param fsn FSN to free
+ */
+void
+admin_free_fsn(struct admin_fsn *fsn)
+{
+ if (fsn == NULL)
+ return;
+
+ free((void *)fsn->af_nsdb.an_hostname);
+ free((void *)fsn->af_uuid);
+ free(fsn);
+}
+
+/**
+ * Dig returned FSN out of lookup results
+ *
+ * @param result RPC lookup results
+ * @param fsn OUT: in-memory FSN structure
+ * @return zero or an errno
+ *
+ * The caller must free "fsn" with admin_free_fsn().
+ */
+static int
+admin_set_fsn(FedFsFsn result, struct admin_fsn **fsn)
+{
+ struct admin_fsn *new;
+
+ new = admin_new_fsn();
+ if (new == NULL)
+ return ENOMEM;
+
+ new->af_uuid = admin_get_uuid(result.fsnUuid);
+ if (new->af_uuid == NULL) {
+ admin_free_fsn(new);
+ return ENOMEM;
+ }
+
+ if (result.nsdbName.hostname.utf8string_val == NULL ||
+ result.nsdbName.hostname.utf8string_len == 0)
+ goto out;
+
+ new->af_nsdb.an_hostname =
+ strndup(result.nsdbName.hostname.utf8string_val,
+ result.nsdbName.hostname.utf8string_len);
+ if (new->af_nsdb.an_hostname == NULL) {
+ admin_free_fsn(new);
+ return ENOMEM;
+ }
+ new->af_nsdb.an_port = result.nsdbName.port;
+
+out:
+ *fsn = new;
+ return 0;
+}
+
+/**
+ * Allocate an in-memory FSL data structure
+ *
+ * @return a freshly allocated FSL, or NULL
+ */
+__attribute_malloc__
+static struct admin_fsl *
+admin_new_fsl(void)
+{
+ return calloc(1, sizeof(struct admin_fsl));
+}
+
+/**
+ * Free one in-memory FSL data structure
+ *
+ * @param fsl FSL to free
+ */
+static void
+admin_free_fsl(struct admin_fsl *fsl)
+{
+ if (fsl == NULL)
+ return;
+
+ nsdb_free_string_array((char **)fsl->al_pathname);
+ free((void *)fsl->al_hostname);
+ free((void *)fsl->al_uuid);
+ free(fsl);
+}
+
+/**
+ * Free a list of in-memory FSL data structures
+ *
+ * @param fsls FSL list to free
+ */
+void
+admin_free_fsls(struct admin_fsl *fsls)
+{
+ struct admin_fsl *fsl;
+
+ while (fsls != NULL) {
+ fsl = fsls;
+ fsls = fsl->al_next;
+ admin_free_fsl(fsl);
+ }
+}
+
+/**
+ * Materialize one NFS FSL and link it onto the list
+ *
+ * @param result one NFS FSL in the result
+ * @param fsls OUT: list of in-memory FSL structures
+ * @return zero or an errno
+ */
+static int
+admin_add_nfsfsl(FedFsNfsFsl result, struct admin_fsl **fsls)
+{
+ struct admin_fsl *new = NULL;
+ int retval;
+
+ retval = ENAMETOOLONG;
+ if (result.hostname.utf8string_val == NULL ||
+ result.hostname.utf8string_len == 0)
+ goto out_err;
+
+ retval = ENOMEM;
+ new = admin_new_fsl();
+ if (new == NULL)
+ goto out_err;
+
+ new->al_uuid = admin_get_uuid(result.fslUuid);
+ if (new->al_uuid == NULL)
+ goto out_err;
+
+ new->al_hostname = strndup(result.hostname.utf8string_val,
+ result.hostname.utf8string_len);
+ if (new->al_hostname == NULL)
+ goto out_err;
+ new->al_port = result.port;
+
+ retval = ENAMETOOLONG;
+ if (nsdb_fedfspathname_to_path_array(result.path,
+ (char ***)&new->al_pathname) != FEDFS_OK)
+ goto out_err;
+
+ new->al_next = *fsls;
+ *fsls = new;
+ return 0;
+
+out_err:
+ admin_free_fsl(new);
+ return retval;
+}
+
+/**
+ * Materialize one FSL and link it onto the list
+ *
+ * @param results one FSL in the result
+ * @param fsls OUT: list of in-memory FSL structures
+ * @return zero or an errno
+ */
+static int
+admin_add_fsl(FedFsFsl results, struct admin_fsl **fsls)
+{
+ switch (results.type) {
+ case FEDFS_NFS_FSL:
+ return admin_add_nfsfsl(results.FedFsFsl_u.nfsFsl, fsls);
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Dig returned FSLs out of lookup results
+ *
+ * @param results RPC lookup results
+ * @param fsls OUT: list of in-memory FSL structures
+ * @return zero or an errno
+ *
+ * The caller must free "fsls" with admin_free_fsls().
+ */
+static int
+admin_set_fsls(FedFsLookupResOk results, struct admin_fsl **fsls)
+{
+ struct admin_fsl *new = NULL;
+ int retval = 0;
+ u_int i;
+
+ for (i = 0; i < results.fsl.fsl_len && retval == 0; i++)
+ retval = admin_add_fsl(results.fsl.fsl_val[i], &new);
+
+ *fsls = new;
+ return retval;
+}
+
+/**
+ * Create a junction or replication on a remote fileserver
+ *
+ * @param host an initialized and opened admin_t
+ * @param procedure RPC procedure to call
+ * @param arg call arguments
+ * @return zero or an errno
+ */
+static int
+admin_create_rpc(admin_t host, rpcproc_t procedure, FedFsCreateArgs *arg)
+{
+ FedFsStatus result;
+ unsigned int delay;
+
+ delay = FEDFS_DELAY_MIN_SECS;
+ do {
+ xlog(D_CALL, "sending CREATE to %s",
+ admin_hostname(host));
+
+ memset((char *)&result, 0, sizeof(result));
+ host->ad_rpc_status = clnt_call(host->ad_client, procedure,
+ (xdrproc_t)xdr_FedFsCreateArgs,
+ (caddr_t)arg,
+ (xdrproc_t)xdr_FedFsStatus, (caddr_t)&result,
+ host->ad_timeout);
+
+ xlog(D_CALL, "RPC CREATE returned %d",
+ host->ad_rpc_status);
+
+ if (host->ad_rpc_status == RPC_AUTHERROR)
+ return EACCES;
+ if (host->ad_rpc_status != RPC_SUCCESS)
+ return EIO;
+
+ if (result != FEDFS_ERR_DELAY)
+ break;
+
+ (void)sleep(delay);
+ delay = fedfs_delay(delay);
+ } while (1);
+
+ host->ad_srv_status = result;
+ return 0;
+}
+
+/**
+ * Create a junction or replication on a remote fileserver
+ *
+ * @param host an initialized admin_t
+ * @param procedure RPC procedure to call
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn FileSet Name to set
+ * @return zero or an errno
+ */
+static int
+admin_create_call(admin_t host, rpcproc_t procedure,
+ char * const *path_array, struct admin_fsn *fsn)
+{
+ FedFsCreateArgs arg;
+ int retval;
+ uuid_t uu;
+
+ if (host == NULL)
+ return EINVAL;
+ admin_reset(host);
+
+ if (path_array == NULL || fsn == NULL)
+ return EINVAL;
+
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ memset(&arg, 0, sizeof(arg));
+ if (uuid_parse(fsn->af_uuid, uu) != 0)
+ return EINVAL;
+ memcpy(arg.fsn.fsnUuid, uu, sizeof(FedFsUuid));
+ arg.fsn.nsdbName.hostname.utf8string_len =
+ strlen(fsn->af_nsdb.an_hostname);
+ arg.fsn.nsdbName.hostname.utf8string_val =
+ (char *)fsn->af_nsdb.an_hostname;
+ arg.fsn.nsdbName.port = fsn->af_nsdb.an_port;
+
+ arg.path.type = FEDFS_PATH_SYS;
+ if (nsdb_path_array_to_fedfspathname(path_array,
+ &arg.path.FedFsPath_u.adminPath) != FEDFS_OK)
+ return ENAMETOOLONG;
+
+ retval = admin_create_rpc(host, procedure, &arg);
+
+ nsdb_free_fedfspathname(&arg.path.FedFsPath_u.adminPath);
+ return retval;
+}
+
+/**
+ * Delete a junction or replication on a remote fileserver
+ *
+ * @param host an initialized and opened admin_t
+ * @param procedure RPC procedure to call
+ * @param arg call arguments
+ * @return zero or an errno
+ */
+static int
+admin_delete_rpc(admin_t host, rpcproc_t procedure, FedFsPath *arg)
+{
+ FedFsStatus result;
+ unsigned int delay;
+
+ delay = FEDFS_DELAY_MIN_SECS;
+ do {
+ xlog(D_CALL, "sending DELETE to %s",
+ admin_hostname(host));
+
+ memset((char *)&result, 0, sizeof(result));
+ host->ad_rpc_status = clnt_call(host->ad_client, procedure,
+ (xdrproc_t)xdr_FedFsPath, (caddr_t)&arg,
+ (xdrproc_t)xdr_FedFsStatus, (caddr_t)&result,
+ host->ad_timeout);
+
+ xlog(D_CALL, "RPC DELETE returned %d",
+ host->ad_rpc_status);
+
+ if (host->ad_rpc_status == RPC_AUTHERROR)
+ return EACCES;
+ if (host->ad_rpc_status != RPC_SUCCESS)
+ return EIO;
+
+ if (result != FEDFS_ERR_DELAY)
+ break;
+
+ (void)sleep(delay);
+ delay = fedfs_delay(delay);
+ } while (1);
+
+ host->ad_srv_status = result;
+ return 0;
+}
+
+/**
+ * Delete a junction or replication on a remote fileserver
+ *
+ * @param host an initialized admin_t
+ * @param procedure RPC procedure to call
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @return zero or an errno
+ */
+static int
+admin_delete_call(admin_t host, rpcproc_t procedure,
+ char * const *path_array)
+{
+ FedFsPath arg;
+ int retval;
+
+ if (host == NULL)
+ return EINVAL;
+ admin_reset(host);
+
+ if (path_array == NULL)
+ return EINVAL;
+
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ memset(&arg, 0, sizeof(arg));
+ if (nsdb_path_array_to_fedfspathname(path_array,
+ &arg.FedFsPath_u.adminPath) != FEDFS_OK)
+ return ENAMETOOLONG;
+
+ retval = admin_delete_rpc(host, procedure, &arg);
+
+ nsdb_free_fedfspathname(&arg.FedFsPath_u.adminPath);
+ return retval;
+}
+
+/**
+ * Request FSN stored in a remote junction
+ *
+ * @param host an initialized and opened admin_t
+ * @param procedure RPC procedure to call
+ * @param arg call arguments
+ * @param result OUT: call results (filled-in)
+ * @return zero or an errno
+ */
+static int
+admin_lookup_rpc(admin_t host, rpcproc_t procedure,
+ FedFsLookupArgs *arg, FedFsLookupRes *result)
+{
+ unsigned int delay;
+
+ delay = FEDFS_DELAY_MIN_SECS;
+ do {
+ xlog(D_CALL, "sending LOOKUP to %s",
+ admin_hostname(host));
+
+ memset((char *)result, 0, sizeof(*result));
+ host->ad_rpc_status = clnt_call(host->ad_client,
+ procedure,
+ (xdrproc_t)xdr_FedFsLookupArgs, (caddr_t)&arg,
+ (xdrproc_t)xdr_FedFsLookupRes, (caddr_t)result,
+ host->ad_timeout);
+
+ xlog(D_CALL, "RPC DELETE returned %d",
+ host->ad_rpc_status);
+
+ if (host->ad_rpc_status == RPC_AUTHERROR)
+ return EACCES;
+ if (host->ad_rpc_status != RPC_SUCCESS)
+ return EIO;
+
+ if (result->status != FEDFS_ERR_DELAY)
+ break;
+
+ clnt_freeres(host->ad_client,
+ (xdrproc_t)xdr_FedFsLookupRes, (caddr_t)result);
+ (void)sleep(delay);
+ delay = fedfs_delay(delay);
+ } while (1);
+
+ host->ad_srv_status = result->status;
+ return 0;
+}
+
+/**
+ * Request FSN stored in a remote junction
+ *
+ * @param host an initialized admin_t
+ * @param procedure RPC procedure to call
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn OUT: the FSN stored in the requested junction
+ * @return zero or an errno
+ *
+ * The caller must free "fsn" with admin_free_fsn().
+ */
+static int
+admin_lookup_none_call(admin_t host, rpcproc_t procedure,
+ char * const *path_array, struct admin_fsn **fsn)
+{
+ FedFsLookupRes result;
+ FedFsLookupArgs arg;
+ int retval;
+
+ if (host == NULL)
+ return EINVAL;
+ admin_reset(host);
+
+ if (path_array == NULL || fsn == NULL)
+ return EINVAL;
+
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.resolve = FEDFS_RESOLVE_NONE;
+ arg.path.type = FEDFS_PATH_SYS;
+ if (nsdb_path_array_to_fedfspathname(path_array,
+ &arg.path.FedFsPath_u.adminPath) != FEDFS_OK)
+ return ENAMETOOLONG;
+
+ retval = admin_lookup_rpc(host, procedure, &arg, &result);
+
+ nsdb_free_fedfspathname(&arg.path.FedFsPath_u.adminPath);
+
+ if (retval == 0 && result.status == FEDFS_OK)
+ retval = admin_set_fsn(result.FedFsLookupRes_u.resok.fsn, fsn);
+
+ clnt_freeres(host->ad_client,
+ (xdrproc_t)xdr_FedFsLookupRes, (caddr_t)&result);
+ return retval;
+}
+
+/**
+ * Request FSN stored in a remote junction and FSLs that FSN resolves to
+ *
+ * @param host an initialized admin_t
+ * @param procedure RPC procedure to call
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param type whether to perturb the server's FSL cache
+ * @param fsn OUT: the FSN stored in the requested junction
+ * @param fsls OUT: list of FSLs cached on the fileserver
+ * @return zero or an errno
+ *
+ * The caller must free "fsn" with admin_free_fsn(). The caller must
+ * free "fsls" with admin_free_fsls().
+ */
+static int
+admin_lookup_typed_call(admin_t host, rpcproc_t procedure,
+ char * const *path_array, FedFsResolveType type,
+ struct admin_fsn **fsn, struct admin_fsl **fsls)
+{
+ struct admin_fsn *tmp_fsn;
+ struct admin_fsl *tmp_fsls;
+ FedFsLookupRes result;
+ FedFsLookupArgs arg;
+ int retval;
+
+ if (host == NULL)
+ return EINVAL;
+ admin_reset(host);
+
+ if (path_array == NULL || fsn == NULL || fsls == NULL)
+ return EINVAL;
+
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.resolve = type;
+ arg.path.type = FEDFS_PATH_SYS;
+ if (nsdb_path_array_to_fedfspathname(path_array,
+ &arg.path.FedFsPath_u.adminPath) != FEDFS_OK)
+ return ENAMETOOLONG;
+
+ retval = admin_lookup_rpc(host, procedure, &arg, &result);
+
+ nsdb_free_fedfspathname(&arg.path.FedFsPath_u.adminPath);
+
+ if (retval != 0)
+ goto out;
+
+ switch (result.status) {
+ case FEDFS_OK:
+ retval = admin_set_fsn(result.FedFsLookupRes_u.resok.fsn, &tmp_fsn);
+ if (retval != 0)
+ break;
+
+ retval = admin_set_fsls(result.FedFsLookupRes_u.resok, &tmp_fsls);
+ if (retval != 0) {
+ admin_free_fsn(tmp_fsn);
+ break;
+ }
+
+ *fsn = tmp_fsn;
+ *fsls = tmp_fsls;
+ break;
+ case FEDFS_ERR_NSDB_LDAP_VAL:
+ host->ad_ldaperr = result.FedFsLookupRes_u.ldapResultCode;
+ break;
+ default:
+ break;
+ }
+
+out:
+ clnt_freeres(host->ad_client,
+ (xdrproc_t)xdr_FedFsLookupRes, (caddr_t)&result);
+ return retval;
+}
+
+/**
+ * FEDFS_CREATE_JUNCTION (5.2) - Create a junction on a remote fileserver
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn FileSet Name to set
+ * @return zero or an errno
+ */
+int
+admin_create_junction(admin_t host, char * const *path_array,
+ struct admin_fsn *fsn)
+{
+ return admin_create_call(host, FEDFS_CREATE_JUNCTION,
+ path_array, fsn);
+}
+
+/**
+ * FEDFS_DELETE_JUNCTION (5.3) - Delete a junction on a remote fileserver
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @return zero or an errno
+ */
+int
+admin_delete_junction(admin_t host, char * const *path_array)
+{
+ return admin_delete_call(host, FEDFS_DELETE_JUNCTION,
+ path_array);
+}
+
+/**
+ * FEDFS_LOOKUP_JUNCTION (5.4) - Request FSN stored in a remote junction
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn OUT: the FSN stored in the requested junction
+ * @return zero or an errno
+ *
+ * The caller must free "fsn" with admin_free_fsn().
+ */
+int
+admin_lookup_junction_none(admin_t host, char * const *path_array,
+ struct admin_fsn **fsn)
+{
+ return admin_lookup_none_call(host, FEDFS_LOOKUP_JUNCTION,
+ path_array, fsn);
+}
+
+/**
+ * FEDFS_LOOKUP_JUNCTION (5.4) - Request FSLs cached by remote server
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn OUT: the FSN stored in the requested junction
+ * @param fsls OUT: list of FSLs cached on the fileserver
+ * @return zero or an errno
+ *
+ * The fileserver does not perform FSN resolution unless it hasn't
+ * already done so.
+ *
+ * The caller must free "fsn" with admin_free_fsn(). The caller must
+ * free "fsls" with admin_free_fsls().
+ */
+int
+admin_lookup_junction_cached(admin_t host, char * const *path_array,
+ struct admin_fsn **fsn, struct admin_fsl **fsls)
+{
+ return admin_lookup_typed_call(host, FEDFS_LOOKUP_JUNCTION,
+ path_array, FEDFS_RESOLVE_CACHE,
+ fsn, fsls);
+}
+
+/**
+ * FEDFS_LOOKUP_JUNCTION (5.4) - Request FSLs from NSDB via remote server
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn OUT: the FSN stored in the requested junction
+ * @param fsls OUT: list of FSLs cached on the fileserver
+ * @return zero or an errno
+ *
+ * The fileserver performs a fresh FSN resolution and renews its
+ * FSL cache before returning.
+ *
+ * The caller must free "fsn" with admin_free_fsn(). The caller must
+ * free "fsls" with admin_free_fsls().
+ */
+int
+admin_lookup_junction_nsdb(admin_t host, char * const *path_array,
+ struct admin_fsn **fsn, struct admin_fsl **fsls)
+{
+ return admin_lookup_typed_call(host, FEDFS_LOOKUP_JUNCTION,
+ path_array, FEDFS_RESOLVE_NSDB,
+ fsn, fsls);
+}
+
+/**
+ * FEDFS_CREATE_REPLICATION (5.5)
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn FileSet Name to set
+ * @return zero or an errno
+ */
+int
+admin_create_replication(admin_t host, char * const*path_array,
+ struct admin_fsn *fsn)
+{
+ return admin_create_call(host, FEDFS_CREATE_REPLICATION,
+ path_array, fsn);
+}
+
+/**
+ * FEDFS_DELETE_REPLICATION (5.6)
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @return zero or an errno
+ */
+int
+admin_delete_replication(admin_t host, char * const*path_array)
+{
+ return admin_delete_call(host, FEDFS_DELETE_REPLICATION,
+ path_array);
+}
+
+/**
+ * FEDFS_LOOKUP_REPLICATION (5.7) - Request FSN stored in a remote replication
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn OUT: the FSN stored in the requested junction
+ * @return zero or an errno
+ *
+ * The caller must free "fsn" with admin_free_fsn().
+ */
+int
+admin_lookup_replication_none(admin_t host, char * const*path_array,
+ struct admin_fsn **fsn)
+{
+ return admin_lookup_none_call(host, FEDFS_LOOKUP_REPLICATION,
+ path_array, fsn);
+}
+
+/**
+ * FEDFS_LOOKUP_REPLICATION (5.7) - Request FSLs cached by remote server
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn OUT: the FSN stored in the requested junction
+ * @param fsls OUT: list of FSLs cached on the fileserver
+ * @return zero or an errno
+ *
+ * The fileserver does not perform FSN resolution unless it hasn't
+ * already done so.
+ *
+ * The caller must free "fsn" with admin_free_fsn(). The caller must
+ * free "fsls" with admin_free_fsls().
+ */
+int
+admin_lookup_replication_cached(admin_t host, char * const*path_array,
+ struct admin_fsn **fsn, struct admin_fsl **fsls)
+{
+ return admin_lookup_typed_call(host, FEDFS_LOOKUP_REPLICATION,
+ path_array, FEDFS_RESOLVE_CACHE,
+ fsn, fsls);
+}
+
+/**
+ * FEDFS_LOOKUP_REPLICATION (5.7)
+ *
+ * @param host an initialized admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname components
+ * @param fsn OUT: the FSN stored in the requested junction
+ * @param fsls OUT: list of FSLs cached on the fileserver
+ * @return zero or an errno
+ *
+ * The fileserver performs a fresh FSN resolution and renews its
+ * FSL cache before returning.
+ *
+ * The caller must free "fsn" with admin_free_fsn(). The caller must
+ * free "fsls" with admin_free_fsls().
+ */
+int
+admin_lookup_replication_nsdb(admin_t host, char * const*path_array,
+ struct admin_fsn **fsn, struct admin_fsl **fsls)
+{
+ return admin_lookup_typed_call(host, FEDFS_LOOKUP_REPLICATION,
+ path_array, FEDFS_RESOLVE_NSDB,
+ fsn, fsls);
+}
new file mode 100644
@@ -0,0 +1,407 @@
+/**
+ * @file src/libadmin/nsdb.c
+ * @brief Handle NSDB-related ADMIN RPC operations
+ */
+
+/*
+ * Copyright 2013 Oracle. All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils. If not, see:
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <sys/types.h>
+
+#include <stdbool.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <uuid/uuid.h>
+
+#include "fedfs_admin.h"
+#include "fedfs.h"
+#include "admin-internal.h"
+#include "admin.h"
+#include "xlog.h"
+
+/**
+ * Set up a FedFsNsdbName argument
+ *
+ * @param nsdb NSDB hostname and port
+ * @param arg OUT: FedFsNsdbName (filled-in)
+ */
+static void
+admin_set_nsdb_arg(const struct admin_nsdb *nsdb, FedFsNsdbName *arg)
+{
+ arg->hostname.utf8string_len = strlen(nsdb->an_hostname);
+ arg->hostname.utf8string_val = (char *)nsdb->an_hostname;
+ arg->port = nsdb->an_port;
+}
+
+/**
+ * Allocate a structure for carrying an x.509 certificate
+ *
+ * @return a freshly allocated admin_cert, or NULL
+ */
+__attribute_malloc__
+static struct admin_cert *
+admin_new_cert(void)
+{
+ return calloc(1, sizeof(struct admin_cert));
+}
+
+/**
+ * Free an admin_cert
+ *
+ * @param cert admin_cert to free
+ */
+void
+admin_free_cert(struct admin_cert *cert)
+{
+ if (cert == NULL)
+ return;
+
+ free((void *)cert->ac_data);
+ free(cert);
+}
+
+/**
+ * Dig returned certificate out of results
+ *
+ * @param result RPC results
+ * @param sectype OUT: connection security for specified NSDB
+ * @param cert OUT: returned x.509 certificate data in DER format
+ * @return zero or an errno
+ *
+ * Caller must free "cert" with admin_free_cert().
+ */
+static int
+admin_set_nsdb_secdata(FedFsGetNsdbParamsRes result,
+ FedFsConnectionSec *sectype, struct admin_cert **cert)
+{
+ FedFsNsdbParams *params = &result.FedFsGetNsdbParamsRes_u.params;
+ unsigned int len = params->FedFsNsdbParams_u.secData.secData_len;
+ char *buf = params->FedFsNsdbParams_u.secData.secData_val;
+ struct admin_cert *new;
+
+ new = admin_new_cert();
+ if (new == NULL)
+ return ENOMEM;
+
+ new->ac_data = malloc(len);
+ if (new->ac_data == NULL) {
+ free(new);
+ return ENOMEM;
+ }
+
+ memcpy((void *)new->ac_data, buf, len);
+ new->ac_len = len;
+ *cert = new;
+ *sectype = params->secType;
+ return 0;
+}
+
+/**
+ * Set NSDB connection parameters on a remote fileserver
+ *
+ * @param host an initialized and opened admin_t
+ * @param arg call arguments
+ * @return zero or an errno
+ */
+static int
+admin_set_nsdb_params_rpc(admin_t host, FedFsSetNsdbParamsArgs *arg)
+{
+ FedFsStatus result;
+ unsigned int delay;
+
+ delay = FEDFS_DELAY_MIN_SECS;
+ do {
+ xlog(D_CALL, "sending SET_NSDB_PARAMS to %s",
+ admin_hostname(host));
+
+ memset((char *)&result, 0, sizeof(result));
+ host->ad_rpc_status = clnt_call(host->ad_client,
+ FEDFS_SET_NSDB_PARAMS,
+ (xdrproc_t)xdr_FedFsSetNsdbParamsArgs, (caddr_t)arg,
+ (xdrproc_t)xdr_FedFsStatus, (caddr_t)&result,
+ host->ad_timeout);
+
+ xlog(D_CALL, "RPC SET_NSDB_PARAMS returned %d",
+ host->ad_rpc_status);
+
+ if (host->ad_rpc_status == RPC_AUTHERROR)
+ return EACCES;
+ if (host->ad_rpc_status != RPC_SUCCESS)
+ return EIO;
+
+ if (result != FEDFS_ERR_DELAY)
+ break;
+
+ (void)sleep(delay);
+ delay = fedfs_delay(delay);
+ } while (1);
+
+ host->ad_srv_status = result;
+ return 0;
+}
+
+/**
+ * FEDFS_SET_NSDB_PARAMS (5.8) - Set NSDB connection parameters on a remote fileserver
+ *
+ * @param host an initialized admin_t
+ * @param nsdb hostname and port of an NSDB service
+ * @return zero or an errno
+ */
+int
+admin_set_nsdb_params_none(admin_t host, const struct admin_nsdb *nsdb)
+{
+ FedFsSetNsdbParamsArgs arg;
+
+ if (host == NULL)
+ return EINVAL;
+ admin_reset(host);
+
+ if (nsdb == NULL)
+ return EINVAL;
+
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.params.secType = FEDFS_SEC_NONE;
+ admin_set_nsdb_arg(nsdb, &arg.nsdbName);
+
+ return admin_set_nsdb_params_rpc(host, &arg);
+}
+
+/**
+ * FEDFS_SET_NSDB_PARAMS (5.8) - Set NSDB connection parameters on a remote fileserver
+ *
+ * @param host an initialized admin_t
+ * @param nsdb hostname and port of an NSDB service
+ * @param cert x.509 certificate data in DER format
+ * @return zero or an errno
+ */
+int
+admin_set_nsdb_params_tls(admin_t host, const struct admin_nsdb *nsdb,
+ const struct admin_cert *cert)
+{
+ FedFsSetNsdbParamsArgs arg;
+ int retval;
+
+ if (host == NULL)
+ return EINVAL;
+ admin_reset(host);
+
+ if (nsdb == NULL || cert == NULL)
+ return EINVAL;
+
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.params.secType = FEDFS_SEC_TLS;
+ arg.params.FedFsNsdbParams_u.secData.secData_len = cert->ac_len;
+ arg.params.FedFsNsdbParams_u.secData.secData_val =
+ (char *)cert->ac_data;
+ admin_set_nsdb_arg(nsdb, &arg.nsdbName);
+
+ retval = admin_set_nsdb_params_rpc(host, &arg);
+
+ free(arg.params.FedFsNsdbParams_u.secData.secData_val);
+ return retval;
+}
+
+/**
+ * Retrieve NSDB connection parameters
+ *
+ * @param host an initialized and opened admin_t
+ * @param arg call arguments
+ * @param result call result (filled-in)
+ * @return zero or an errno
+ */
+static int
+admin_get_nsdb_params_rpc(admin_t host, FedFsNsdbName *arg,
+ FedFsGetNsdbParamsRes *result)
+{
+ unsigned int delay;
+
+ delay = FEDFS_DELAY_MIN_SECS;
+ do {
+ xlog(D_CALL, "sending GET_NSDB_PARAMS to %s",
+ admin_hostname(host));
+
+ memset((char *)result, 0, sizeof(*result));
+ host->ad_rpc_status = clnt_call(host->ad_client,
+ FEDFS_GET_NSDB_PARAMS,
+ (xdrproc_t)xdr_FedFsNsdbName, (caddr_t)&arg,
+ (xdrproc_t)xdr_FedFsGetNsdbParamsRes, (caddr_t)&result,
+ host->ad_timeout);
+
+ xlog(D_CALL, "RPC GET_NSDB_PARAMS returned %d",
+ host->ad_rpc_status);
+
+ if (host->ad_rpc_status == RPC_AUTHERROR)
+ return EACCES;
+ if (host->ad_rpc_status != RPC_SUCCESS)
+ return EIO;
+
+ if (result->status != FEDFS_ERR_DELAY)
+ break;
+
+ clnt_freeres(host->ad_client,
+ (xdrproc_t)xdr_FedFsGetNsdbParamsRes,
+ (caddr_t)result);
+ (void)sleep(delay);
+ delay = fedfs_delay(delay);
+ } while (1);
+
+ host->ad_srv_status = result->status;
+ return 0;
+}
+
+/**
+ * FEDFS_GET_NSDB_PARAMS (5.9)
+ *
+ * @param host an initialized admin_t
+ * @param nsdb hostname and port of an NSDB service
+ * @param sectype OUT: connection security for specified NSDB
+ * @param cert OUT: returned x.509 certificate data in DER format
+ * @return zero or an errno
+ *
+ * Caller must free "cert" with admin_free_cert().
+ */
+int
+admin_get_nsdb_params(admin_t host, struct admin_nsdb *nsdb,
+ FedFsConnectionSec *sectype, struct admin_cert **cert)
+{
+ FedFsGetNsdbParamsRes result;
+ FedFsNsdbName arg;
+ int retval;
+
+ if (host == NULL)
+ return EINVAL;
+ admin_reset(host);
+
+ if (nsdb == NULL || sectype == NULL || cert == NULL)
+ return EINVAL;
+
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ memset(&arg, 0, sizeof(arg));
+ admin_set_nsdb_arg(nsdb, &arg);
+
+ retval = admin_get_nsdb_params_rpc(host, &arg, &result);
+
+ if (retval == 0 && result.status == FEDFS_OK)
+ retval = admin_set_nsdb_secdata(result, sectype, cert);
+
+ clnt_freeres(host->ad_client, (xdrproc_t)xdr_FedFsGetNsdbParamsRes,
+ (caddr_t)&result);
+ return retval;
+}
+
+/**
+ * Retrieve limited NSDB connection parameters
+ *
+ * @param host an initialized and opened admin_t
+ * @param arg call arguments
+ * @param result call result (filled-in)
+ * @return zero or an errno
+ */
+static int
+admin_get_limited_nsdb_params_rpc(admin_t host, FedFsNsdbName *arg,
+ FedFsGetLimitedNsdbParamsRes *result)
+{
+ unsigned int delay;
+
+ delay = FEDFS_DELAY_MIN_SECS;
+ do {
+ xlog(D_CALL, "sending GET_LIMITED_NSDB_PARAMS to %s",
+ admin_hostname(host));
+
+ memset((char *)result, 0, sizeof(*result));
+ host->ad_rpc_status = clnt_call(host->ad_client,
+ FEDFS_GET_LIMITED_NSDB_PARAMS,
+ (xdrproc_t)xdr_FedFsNsdbName, (caddr_t)arg,
+ (xdrproc_t)xdr_FedFsGetLimitedNsdbParamsRes,
+ (caddr_t)result, host->ad_timeout);
+
+ xlog(D_CALL, "RPC GET_LIMITED_NSDB_PARAMS returned %d",
+ host->ad_rpc_status);
+
+ if (host->ad_rpc_status == RPC_AUTHERROR)
+ return EACCES;
+ if (host->ad_rpc_status != RPC_SUCCESS)
+ return EIO;
+
+ if (result->status != FEDFS_ERR_DELAY)
+ break;
+
+ clnt_freeres(host->ad_client,
+ (xdrproc_t)xdr_FedFsGetLimitedNsdbParamsRes,
+ (caddr_t)result);
+ (void)sleep(delay);
+ delay = fedfs_delay(delay);
+ } while (1);
+
+ host->ad_srv_status = result->status;
+ return 0;
+}
+
+/**
+ * FEDFS_GET_LIMITED_NSDB_PARAMS (5.10)
+ *
+ * @param host an initialized admin_t
+ * @param nsdb hostname and port of an NSDB service
+ * @param sectype OUT: connection security for specified NSDB
+ * @return zero or an errno
+ */
+int
+admin_get_limited_nsdb_params(admin_t host, struct admin_nsdb *nsdb,
+ FedFsConnectionSec *sectype)
+{
+ FedFsGetLimitedNsdbParamsRes result;
+ FedFsNsdbName arg;
+ int retval;
+
+ if (host == NULL)
+ return EINVAL;
+ admin_reset(host);
+
+ if (nsdb == NULL || sectype == NULL)
+ return EINVAL;
+
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ memset(&arg, 0, sizeof(arg));
+ admin_set_nsdb_arg(nsdb, &arg);
+
+ retval = admin_get_limited_nsdb_params_rpc(host, &arg, &result);
+
+ if (retval == 0 && result.status == FEDFS_OK)
+ *sectype = result.FedFsGetLimitedNsdbParamsRes_u.secType;
+
+ clnt_freeres(host->ad_client,
+ (xdrproc_t)xdr_FedFsGetLimitedNsdbParamsRes,
+ (caddr_t)&result);
+ return retval;
+}
new file mode 100644
@@ -0,0 +1,74 @@
+/**
+ * @file src/libadmin/null.c
+ * @brief Handle NULL ADMIN RPC operation
+ */
+
+/*
+ * Copyright 2013 Oracle. All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils. If not, see:
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <unistd.h>
+#include <errno.h>
+
+#include "fedfs_admin.h"
+#include "admin-internal.h"
+#include "xlog.h"
+
+/**
+ * FEDFS_NULL (5.1) - Send a NULL ADMIN request (ping) to a remote fileserver
+ *
+ * @param host an initialized admin_t
+ * @return zero or an errno
+ *
+ * The RPC procedure does not return a result. We fill in a
+ * status of FEDFS_OK if the RPC succeeds.
+ */
+int
+admin_null(admin_t host)
+{
+ char result;
+
+ if (host == NULL)
+ return EINVAL;
+ admin_reset(host);
+
+ if (!admin_is_connected(host))
+ return ENOTCONN;
+
+ xlog(D_CALL, "sending NULL to %s",
+ admin_hostname(host));
+
+ memset((char *)&result, 0, sizeof(result));
+ host->ad_rpc_status = clnt_call(host->ad_client,
+ FEDFS_NULL,
+ (xdrproc_t)xdr_void, (caddr_t)NULL,
+ (xdrproc_t)xdr_void, (caddr_t)&result,
+ host->ad_timeout);
+
+ xlog(D_CALL, "RPC NULL returned %d",
+ host->ad_rpc_status);
+
+ if (host->ad_rpc_status == RPC_AUTHERROR)
+ return EACCES;
+ if (host->ad_rpc_status != RPC_SUCCESS)
+ return EIO;
+
+ host->ad_srv_status = FEDFS_OK;
+ return 0;
+}
In order to communicate with NSDBs, we have nsdb_t. Let's add a similar object for communicating with remote ADMIN services. These objects are materialized via admin_new(), which takes a hostname and a nettype. They are released with admin_free(). The new API hides RPC- and GSS-related details inside libadmin. It should then be simple to add full ADMIN support directly into other tools, such as nsdbparams, without having to drag in a lot of redundant code. Note: one new sparse error appears: rpc/auth.h:218:16: error: undefined identifier '__sync_sub_and_fetch' Sparse does not recognize gcc built-ins that provide atomic manipulation of integers. This is a harmless error. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- configure.ac | 5 src/fedfsc/Makefile.am | 2 src/include/Makefile.am | 4 src/include/admin.h | 286 +++++++++++++++ src/include/fedfs.h | 5 src/libadmin/Makefile.am | 5 src/libadmin/admin-internal.h | 61 +++ src/libadmin/admin.c | 386 ++++++++++++++++++++ src/libadmin/gss.c | 281 ++++++++++++++ src/libadmin/junction.c | 801 +++++++++++++++++++++++++++++++++++++++++ src/libadmin/nsdb.c | 407 +++++++++++++++++++++ src/libadmin/null.c | 74 ++++ 12 files changed, 2313 insertions(+), 4 deletions(-) create mode 100644 src/include/admin.h create mode 100644 src/libadmin/admin-internal.h create mode 100644 src/libadmin/admin.c create mode 100644 src/libadmin/gss.c create mode 100644 src/libadmin/junction.c create mode 100644 src/libadmin/nsdb.c create mode 100644 src/libadmin/null.c