Add support for AUTH_UNIX and RPCSEC_GSS security.  The tool now
exits with a typical Unix exit status code.

Signed-off-by: Chuck Lever <[email protected]>
---
 doc/man/fedfs-create-junction.8    |  112 ++++++------------
 src/fedfsc/fedfs-create-junction.c |  223 +++++++++++++++++++-----------------
 2 files changed, 156 insertions(+), 179 deletions(-)

diff --git a/doc/man/fedfs-create-junction.8 b/doc/man/fedfs-create-junction.8
index 743d3bd..c7360a9 100644
--- a/doc/man/fedfs-create-junction.8
+++ b/doc/man/fedfs-create-junction.8
@@ -5,7 +5,7 @@
 .\"
 
 .\"
-.\" Copyright 2011 Oracle.  All rights reserved.
+.\" Copyright 2011, 2013 Oracle.  All rights reserved.
 .\"
 .\" This file is part of fedfs-utils.
 .\"
@@ -37,6 +37,8 @@ fedfs-create-junction \- send a FEDFS_CREATE_JUNCTION ADMIN 
protocol request
 .IR nsdbname ]
 .RB [ \-r
 .IR nsdbport ]
+.RB [ \-s
+.IR security ]
 .I path
 .I fsn-uuid
 .SH INTRODUCTION
@@ -122,77 +124,21 @@ Specifies the IP port of the NSDB to insert into the new 
FedFS junction.
 If this option is not specified,
 the value of the FEDFS_NSDB_PORT environment variable is consulted.
 The default value if the variable is not set is 389.
-.SH EXIT CODES
-The remote administration service returns a value that reflects the
-success of the requested operation.
-.TP
-.B FEDFS_OK
-The operation succeeded.
-.TP
-.B FEDFS_ERR_ACCESS
-The caller does not have permission to perform the requested operation
-on the remote server.
-.TP
-.B FEDFS_ERR_BADCHAR
-The pathname contains a character which is not
-supported by the remote server.
-.TP
-.B FEDFS_ERR_BADNAME
-A component of the pathname consisted of valid UTF-8 characters
-supported by the remote server,
-but the name is not supported by the remote server
-as a valid name for the current operation.
-.TP
-.B FEDFS_ERR_NAMETOOLONG
-The length of the pathname exceeds the remote server’s implementation limit.
-.TP
-.B FEDFS_ERR_LOOP
-Too many symbolic links were encountered in resolving the pathname.
-.TP
-.B FEDFS_ERR_BADXDR
-The remote server encountered an XDR decoding error while
-processing the request.
-.TP
-.B FEDFS_ERR_EXIST
-The specified junction already exists.
-.TP
-.B FEDFS_ERR_INVAL
-One of the arguments was not valid.
-.TP
-.B FEDFS_ERR_IO
-A hard error occurred on the remote server.
-.TP
-.B FEDFS_ERR_NOSPC
-The requested operation would have caused the remote
-server’s filesystem to exceed some limit (for example, if there is
-a fixed number of junctions per fileset or per server).
-.TP
-.B FEDFS_ERR_NOTJUNCT
-The pathname does not end in a junction.
-.TP
-.B FEDFS_ERR_NOTLOCAL
-The pathname contains a junction in any position other than the last component.
-.TP
-.B FEDFS_ERR_PERM
-The operation was not allowed because the caller is
-either not a privileged user or not the owner of an object that
-would be modified by the operation.
-.TP
-.B FEDFS_ERR_ROFS
-A modifying operation was attempted on a read-only filesystem.
-.TP
-.B FEDFS_ERR_SVRFAULT
-An unanticipated non-protocol error occurred on the remote server.
-.TP
-.B FEDFS_ERR_NSDB_PARAMS
-The remote server does not have any connection
-parameters on record for the specified NSDB.
-.TP
-.B FEDFS_ERR_PATH_TYPE_UNSUPP
-The remote server does not support the specified FedFsPathType value.
-.TP
-.B FEDFS_ERR_NOTSUPP
-The remote server does not support the specified procedure.
+.IP "\fB\-s, \-\-security=\fIflavor\fP"
+Specifies the security flavor to use
+when contacting the remote FedFS ADMIN service.
+Valid flavors are
+.BR sys ,
+.BR unix ,
+.BR krb5 ,
+.BR krb5i ", and"
+.BR krb5p .
+If this option is not specified, the
+.B unix
+flavor is used.
+See the
+.B SECURITY
+section of this man page for details.
 .SH EXAMPLES
 Suppose you are the FedFS administrator of the
 .I example.net
@@ -214,12 +160,32 @@ command, and added to the NSDB using the
 .BR nsdb-create-fsn (8)
 command.
 .SH SECURITY
-RPCSEC GSSAPI authentication has not yet been implemented for this command.
+By default, or if the
+.B sys
+and
+.B unix
+flavors are specified with the
+.BI \-\-security= flavor
+option, the
+.BR fedfs-create-junction (8)
+command uses AUTH_SYS security for the Remote Procedure Call.
+AUTH_SYS has known weaknesses and should be avoided on untrusted networks.
+.P
+The RPC client uses the Kerberos v5 GSS mechanism
+if a Kerberos security flavor is specified.
+When specifying a Kerberos security flavor,
+the user must first obtain a valid Kerberos ticket using
+.BR kinit (1)
+before running
+.BR fedfs-create-junction (8).
+.P
+The AUTH_NONE security flavor is no longer supported by this implementation.
 .SH "SEE ALSO"
 .BR fedfs (7),
 .BR rpc.fedfsd (8),
 .BR fedfs-lookup-junction (8),
 .BR nsdb-create-fsn (8),
+.BR kinit (1),
 .BR rpc (3t)
 .sp
 RFC 5716 for FedFS requirements and overview
diff --git a/src/fedfsc/fedfs-create-junction.c 
b/src/fedfsc/fedfs-create-junction.c
index 0d6ce2d..987c02a 100644
--- a/src/fedfsc/fedfs-create-junction.c
+++ b/src/fedfsc/fedfs-create-junction.c
@@ -1,13 +1,10 @@
 /**
  * @file src/fedfsc/fedfs-create-junction.c
  * @brief Send a FEDFS_CREATE_JUNCTION RPC to a FedFS ADMIN server
- *
- * @todo
- *     Implement RPCGSS authentication
  */
 
 /*
- * Copyright 2010 Oracle.  All rights reserved.
+ * Copyright 2010, 2013 Oracle.  All rights reserved.
  *
  * This file is part of fedfs-utils.
  *
@@ -30,31 +27,25 @@
 #include <sys/stat.h>
 
 #include <stdbool.h>
+#include <stdlib.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
 #include <getopt.h>
 #include <locale.h>
 
-#include <rpc/clnt.h>
-#include <uuid/uuid.h>
-
 #include "fedfs.h"
 #include "fedfs_admin.h"
+#include "admin.h"
 #include "nsdb.h"
 #include "junction.h"
 #include "xlog.h"
 #include "gpl-boiler.h"
 
 /**
- * Default RPC request timeout
- */
-static struct timeval fedfs_create_junction_timeout = { 25, 0 };
-
-/**
  * Short form command line options
  */
-static const char fedfs_create_junction_opts[] = "?dh:l:n:r:";
+static const char fedfs_create_junction_opts[] = "?dh:l:n:r:s:";
 
 /**
  * Long form command line options
@@ -63,9 +54,10 @@ static const struct option fedfs_create_junction_longopts[] 
= {
        { "debug", 0, NULL, 'd', },
        { "help", 0, NULL, '?', },
        { "hostname", 1, NULL, 'h', },
-       { "nettype", 1, NULL, 'n', },
        { "nsdbname", 1, NULL, 'l', },
+       { "nettype", 1, NULL, 'n', },
        { "nsdbport", 1, NULL, 'r', },
+       { "security", 1, NULL, 's', },
        { NULL, 0, NULL, 0, },
 };
 
@@ -73,8 +65,9 @@ static const struct option fedfs_create_junction_longopts[] = 
{
  * Display program synopsis
  *
  * @param progname NUL-terminated C string containing name of program
+ * @return program exit status
  */
-static void
+static int
 fedfs_create_junction_usage(const char *progname)
 {
        fprintf(stderr, "\n%s version " VERSION "\n", progname);
@@ -89,89 +82,101 @@ fedfs_create_junction_usage(const char *progname)
        fprintf(stderr, "\t-h, --hostname       ADMIN server hostname (default: 
'localhost')\n");
        fprintf(stderr, "\t-l, --nsdbname       NSDB hostname to set\n");
        fprintf(stderr, "\t-r, --nsdbport       NSDB port to set\n");
+       fprintf(stderr, "\t-s, --security       RPC security level\n");
 
        fprintf(stderr, "%s", fedfs_gpl_boilerplate);
 
-       exit((int)FEDFS_ERR_INVAL);
+       return EXIT_FAILURE;
 }
 
 /**
  * Create a junction on a remote fileserver
  *
- * @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 path NUL-terminated C string containing remote pathname of new 
junction
- * @param uuid NUL-terminated C string containing FSN UUID for new junction
- * @param nsdbname NUL-terminated UTF-8 string containing name of NSDB node 
for this junction
- * @param nsdbport port number of NSDB node for this junction
- * @return a FedFsStatus code
+ * @param host an initialized and opened admin_t
+ * @param path_array an array of NUL-terminated C strings containing pathname 
components
+ * @param fsn FileSet Name to plant in new junction
+ * @return program exit status
  */
-static FedFsStatus
-fedfs_create_junction_call(const char *hostname, const char *nettype,
-               const char *path, const char *uuid, char *nsdbname,
-               const uint16_t nsdbport)
+static int
+fedfs_create_junction_try(admin_t host, char * const *path_array,
+               struct admin_fsn *fsn)
 {
-       enum clnt_stat status;
-       FedFsCreateArgs arg;
-       FedFsStatus result;
-       char **path_array;
-       CLIENT *client;
-       uuid_t uu;
-       int res;
+       int status, err;
 
-       memset(&arg, 0, sizeof(arg));
+       status = EXIT_FAILURE;
+       err = admin_create_junction(host, path_array, fsn);
+       switch (err) {
+       case 0:
+               break;
+       case EACCES:
+               xlog(L_ERROR, "%s: access denied", admin_hostname(host));
+               xlog(D_GENERAL, "%s",
+                       admin_perror(host, admin_hostname(host)));
+               goto out;
+       case EIO:
+               xlog(L_ERROR, "%s",
+                       admin_perror(host, admin_hostname(host)));
+               goto out;
+       default:
+               xlog(L_ERROR, "ADMIN client: %s", strerror(err));
+               goto out;
+       }
 
-       res = uuid_parse(uuid, uu);
-       if (res != 0) {
-               fprintf(stderr, "Failed to parse UUID %s\n", uuid);
-               return FEDFS_ERR_INVAL;
+       switch (admin_status(host)) {
+       case FEDFS_OK:
+               printf("Junction created successfully\n");
+               status = EXIT_SUCCESS;
+               break;
+       case FEDFS_ERR_NSDB_PARAMS:
+               printf("No connection parameters found\n");
+               break;
+       default:
+               nsdb_print_fedfsstatus(admin_status(host));
        }
-       memcpy(arg.fsn.fsnUuid, uu, sizeof(FedFsUuid));
 
-       arg.fsn.nsdbName.hostname.utf8string_val = nsdbname;
-       arg.fsn.nsdbName.hostname.utf8string_len = strlen(nsdbname);
-       arg.fsn.nsdbName.port = nsdbport;
+out:
+       return status;
+}
 
-       arg.path.type = FEDFS_PATH_SYS;
-       result = nsdb_posix_to_path_array(path, &path_array);
-       if (result != FEDFS_OK) {
-               fprintf(stderr, "Failed to encode pathname: %s",
-                       nsdb_display_fedfsstatus(result));
-               return result;
-       }
-       result = nsdb_path_array_to_fedfspathname(path_array,
-                               &arg.path.FedFsPath_u.adminPath);
-       if (result != FEDFS_OK) {
-               fprintf(stderr, "Failed to encode pathname: %s",
-                       nsdb_display_fedfsstatus(result));
-               nsdb_free_string_array(path_array);
-               return result;
-       }
+/**
+ * Create a junction on a remote fileserver
+ *
+ * @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 RPC security mode
+ * @param path_array an array of NUL-terminated C strings containing pathname 
components
+ * @param fsn FileSet Name to plant in new junction
+ * @return program exit status
+ */
+static int
+fedfs_create_junction_host(const char *hostname, const char *nettype,
+               const char *security, char * const *path_array,
+               struct admin_fsn *fsn)
+{
+       admin_t host;
+       int status;
 
-       client = clnt_create(hostname, FEDFS_PROG, FEDFS_V1, nettype);
-       if (client == NULL) {
-               clnt_pcreateerror("Failed to create FEDFS client");
-               result = FEDFS_ERR_SVRFAULT;
-               goto out;
+       status = EXIT_FAILURE;
+       switch (admin_create(hostname, nettype, security, &host)) {
+       case 0:
+               status = fedfs_create_junction_try(host, path_array, fsn);
+               admin_release(host);
+               break;
+       case EINVAL:
+               xlog(L_ERROR, "Invalid command line parameter");
+               break;
+       case EACCES:
+               xlog(L_ERROR, "Failed to authenticate server");
+               break;
+       case EKEYEXPIRED:
+               xlog(L_ERROR, "User credentials not found");
+               break;
+       default:
+               xlog(L_ERROR, "%s",
+                       admin_open_perror(admin_hostname(host)));
        }
 
-       memset((char *)&result, 0, sizeof(result));
-       status = clnt_call(client, FEDFS_CREATE_JUNCTION,
-                               (xdrproc_t)xdr_FedFsCreateArgs,
-                               (caddr_t)&arg,
-                               (xdrproc_t)xdr_FedFsStatus, (caddr_t)&result,
-                               fedfs_create_junction_timeout);
-       if (status != RPC_SUCCESS) {
-               clnt_perror(client, "FEDFS_CREATE_JUNCTION call failed");
-               result = FEDFS_ERR_SVRFAULT;
-       } else
-               nsdb_print_fedfsstatus(result);
-       (void)clnt_destroy(client);
-
-out:
-       nsdb_free_fedfspathname(&arg.path.FedFsPath_u.adminPath);
-       nsdb_free_string_array(path_array);
-       return result;
+       return status;
 }
 
 /**
@@ -184,12 +189,12 @@ out:
 int
 main(int argc, char **argv)
 {
-       char *progname, *hostname, *nettype;
-       char *fsn_uuid, *path, *nsdbname;
-       unsigned short nsdbport;
-       unsigned int seconds;
-       FedFsStatus status;
-       int arg;
+       char *progname, *hostname, *nettype, *security, *path;
+       struct admin_nsdb *nsdb;
+       struct admin_fsn fsn;
+       FedFsStatus retval;
+       char **path_array;
+       int arg, status;
 
        (void)setlocale(LC_ALL, "");
        (void)umask(S_IRWXO);
@@ -205,10 +210,12 @@ main(int argc, char **argv)
        xlog_syslog(0);
        xlog_open(progname);
 
-       nsdb_env(&nsdbname, &nsdbport, NULL, NULL);
+       nsdb = &fsn.af_nsdb;
+       nsdb_env((char **)&nsdb->an_hostname, &nsdb->an_port, NULL, NULL);
 
        hostname = "localhost";
        nettype = "netpath";
+       security = "unix";
        while ((arg = getopt_long(argc, argv, fedfs_create_junction_opts,
                        fedfs_create_junction_longopts, NULL)) != -1) {
                switch (arg) {
@@ -222,48 +229,52 @@ main(int argc, char **argv)
                        if (!nsdb_is_hostname_utf8(optarg)) {
                                fprintf(stderr, "NSDB name %s is "
                                        "not a UTF-8 hostname\n", optarg);
-                               fedfs_create_junction_usage(progname);
+                               return fedfs_create_junction_usage(progname);
                        }
-                       nsdbname = optarg;
+                       nsdb->an_hostname = optarg;
                        break;
                case 'n':
                        nettype = optarg;
                        break;
                case 'r':
-                       if (!nsdb_parse_port_string(optarg, &nsdbport)) {
+                       if (!nsdb_parse_port_string(optarg, &nsdb->an_port)) {
                                fprintf(stderr, "Bad port number: '%s'\n",
                                        optarg);
-                               fedfs_create_junction_usage(progname);
+                               return fedfs_create_junction_usage(progname);
                        }
                        break;
+               case 's':
+                       security = optarg;
+                       break;
                default:
                        fprintf(stderr, "Invalid command line "
                                "argument: %c\n", (char)arg);
                case '?':
-                       fedfs_create_junction_usage(progname);
+                       return fedfs_create_junction_usage(progname);
                }
        }
        if (argc == optind + 2) {
                path = argv[optind];
-               fsn_uuid = argv[optind + 1];
+               fsn.af_uuid = argv[optind + 1];
        } else {
                fprintf(stderr, "Ambiguous positional parameters\n");
-               fedfs_create_junction_usage(progname);
+               return fedfs_create_junction_usage(progname);
        }
-       if (nsdbname == NULL) {
+       if (nsdb->an_hostname == NULL) {
                fprintf(stderr, "No NSDB hostname was specified\n");
-               fedfs_create_junction_usage(progname);
+               return fedfs_create_junction_usage(progname);
        }
 
-       for (seconds = FEDFS_DELAY_MIN_SECS;; seconds = fedfs_delay(seconds)) {
-               status = fedfs_create_junction_call(hostname, nettype, path,
-                                               fsn_uuid, nsdbname, nsdbport);
-               if (status != FEDFS_ERR_DELAY)
-                       break;
-
-               xlog(D_GENERAL, "Delaying %u seconds...", seconds);
-               if (sleep(seconds) != 0)
-                       break;
+       retval = nsdb_posix_to_path_array(path, &path_array);
+       if (retval != FEDFS_OK) {
+               fprintf(stderr, "Failed to encode pathname: %s",
+                       nsdb_display_fedfsstatus(retval));
+               return EXIT_FAILURE;
        }
-       return (int)status;
+
+       status = fedfs_create_junction_host(hostname, nettype, security,
+                                               path_array, &fsn);
+
+       nsdb_free_string_array(path_array);
+       return status;
 }


_______________________________________________
fedfs-utils-devel mailing list
[email protected]
https://oss.oracle.com/mailman/listinfo/fedfs-utils-devel

Reply via email to