]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'nfs-for-next' of git://linux-nfs.org/~trondmy/nfs-2.6 into for-3.10
authorJ. Bruce Fields <bfields@redhat.com>
Mon, 29 Apr 2013 18:03:30 +0000 (14:03 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Mon, 29 Apr 2013 20:23:34 +0000 (16:23 -0400)
Note conflict: Chuck's patches modified (and made static)
gss_mech_get_by_OID, which is still needed by gss-proxy patches.

The conflict resolution is a bit minimal; we may want some more cleanup.

20 files changed:
fs/nfs/nfs4client.c
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4super.c
fs/nfs/nfs4xdr.c
fs/nfs/super.c
fs/nfsd/nfs4xdr.c
include/linux/nfs_xdr.h
include/linux/sunrpc/auth.h
include/linux/sunrpc/gss_api.h
net/sunrpc/Kconfig
net/sunrpc/auth.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/gss_krb5_mech.c
net/sunrpc/auth_gss/gss_mech_switch.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/gss_rpc_upcall.h
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/clnt.c

index f4d4d4ec6bf76e83ff0708279cd7f420de4091d9..947b0c908aa908c643140dd7087b0927753c6d49 100644 (file)
@@ -201,7 +201,9 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
        if (clp->cl_minorversion != 0)
                __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
        __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
-       error = nfs_create_rpc_client(clp, timeparms, authflavour);
+       error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
+       if (error == -EINVAL)
+               error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_NULL);
        if (error < 0)
                goto error;
 
@@ -302,7 +304,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
                           struct rpc_cred *cred)
 {
        struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
-       struct nfs_client *pos, *n, *prev = NULL;
+       struct nfs_client *pos, *prev = NULL;
        struct nfs4_setclientid_res clid = {
                .clientid       = new->cl_clientid,
                .confirm        = new->cl_confirm,
@@ -310,10 +312,23 @@ int nfs40_walk_client_list(struct nfs_client *new,
        int status = -NFS4ERR_STALE_CLIENTID;
 
        spin_lock(&nn->nfs_client_lock);
-       list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
+       list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
                /* If "pos" isn't marked ready, we can't trust the
                 * remaining fields in "pos" */
-               if (pos->cl_cons_state < NFS_CS_READY)
+               if (pos->cl_cons_state > NFS_CS_READY) {
+                       atomic_inc(&pos->cl_count);
+                       spin_unlock(&nn->nfs_client_lock);
+
+                       if (prev)
+                               nfs_put_client(prev);
+                       prev = pos;
+
+                       status = nfs_wait_client_init_complete(pos);
+                       spin_lock(&nn->nfs_client_lock);
+                       if (status < 0)
+                               continue;
+               }
+               if (pos->cl_cons_state != NFS_CS_READY)
                        continue;
 
                if (pos->rpc_ops != new->rpc_ops)
@@ -425,16 +440,16 @@ int nfs41_walk_client_list(struct nfs_client *new,
                           struct rpc_cred *cred)
 {
        struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
-       struct nfs_client *pos, *n, *prev = NULL;
+       struct nfs_client *pos, *prev = NULL;
        int status = -NFS4ERR_STALE_CLIENTID;
 
        spin_lock(&nn->nfs_client_lock);
-       list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
+       list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
                /* If "pos" isn't marked ready, we can't trust the
                 * remaining fields in "pos", especially the client
                 * ID and serverowner fields.  Wait for CREATE_SESSION
                 * to finish. */
-               if (pos->cl_cons_state < NFS_CS_READY) {
+               if (pos->cl_cons_state > NFS_CS_READY) {
                        atomic_inc(&pos->cl_count);
                        spin_unlock(&nn->nfs_client_lock);
 
@@ -442,18 +457,17 @@ int nfs41_walk_client_list(struct nfs_client *new,
                                nfs_put_client(prev);
                        prev = pos;
 
-                       nfs4_schedule_lease_recovery(pos);
                        status = nfs_wait_client_init_complete(pos);
-                       if (status < 0) {
-                               nfs_put_client(pos);
-                               spin_lock(&nn->nfs_client_lock);
-                               continue;
+                       if (status == 0) {
+                               nfs4_schedule_lease_recovery(pos);
+                               status = nfs4_wait_clnt_recover(pos);
                        }
-                       status = pos->cl_cons_state;
                        spin_lock(&nn->nfs_client_lock);
                        if (status < 0)
                                continue;
                }
+               if (pos->cl_cons_state != NFS_CS_READY)
+                       continue;
 
                if (pos->rpc_ops != new->rpc_ops)
                        continue;
@@ -471,17 +485,18 @@ int nfs41_walk_client_list(struct nfs_client *new,
                        continue;
 
                atomic_inc(&pos->cl_count);
-               spin_unlock(&nn->nfs_client_lock);
+               *result = pos;
+               status = 0;
                dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
                        __func__, pos, atomic_read(&pos->cl_count));
-
-               *result = pos;
-               return 0;
+               break;
        }
 
        /* No matching nfs_client found. */
        spin_unlock(&nn->nfs_client_lock);
        dprintk("NFS: <-- %s status = %d\n", __func__, status);
+       if (prev)
+               nfs_put_client(prev);
        return status;
 }
 #endif /* CONFIG_NFS_V4_1 */
index 0dd766079e1ca34feb26ba2da2dafafeb1e24060..cdb0b41a48109e274364e4e69150c5b222114953 100644 (file)
@@ -134,33 +134,38 @@ static size_t nfs_parse_server_name(char *string, size_t len,
        return ret;
 }
 
+/**
+ * nfs_find_best_sec - Find a security mechanism supported locally
+ * @flavors: List of security tuples returned by SECINFO procedure
+ *
+ * Return the pseudoflavor of the first security mechanism in
+ * "flavors" that is locally supported.  Return RPC_AUTH_UNIX if
+ * no matching flavor is found in the array.  The "flavors" array
+ * is searched in the order returned from the server, per RFC 3530
+ * recommendation.
+ */
 rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
 {
-       struct gss_api_mech *mech;
-       struct xdr_netobj oid;
-       int i;
-       rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
+       rpc_authflavor_t pseudoflavor;
+       struct nfs4_secinfo4 *secinfo;
+       unsigned int i;
 
        for (i = 0; i < flavors->num_flavors; i++) {
-               struct nfs4_secinfo_flavor *flavor;
-               flavor = &flavors->flavors[i];
-
-               if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
-                       pseudoflavor = flavor->flavor;
-                       break;
-               } else if (flavor->flavor == RPC_AUTH_GSS) {
-                       oid.len  = flavor->gss.sec_oid4.len;
-                       oid.data = flavor->gss.sec_oid4.data;
-                       mech = gss_mech_get_by_OID(&oid);
-                       if (!mech)
-                               continue;
-                       pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service);
-                       gss_mech_put(mech);
+               secinfo = &flavors->flavors[i];
+
+               switch (secinfo->flavor) {
+               case RPC_AUTH_NULL:
+               case RPC_AUTH_UNIX:
+               case RPC_AUTH_GSS:
+                       pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
+                                                       &secinfo->flavor_info);
+                       if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
+                               return pseudoflavor;
                        break;
                }
        }
 
-       return pseudoflavor;
+       return RPC_AUTH_UNIX;
 }
 
 static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
index c13144911d2017be38a10276098b0f83e9b1a96a..9da4bd55eb3019a964f8a7a7b0f89e2bab4c8b42 100644 (file)
@@ -769,6 +769,7 @@ struct nfs4_opendata {
        struct iattr attrs;
        unsigned long timestamp;
        unsigned int rpc_done : 1;
+       unsigned int is_recover : 1;
        int rpc_status;
        int cancelled;
 };
@@ -1101,9 +1102,12 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
                /* Save the delegation */
                nfs4_stateid_copy(&stateid, &delegation->stateid);
                rcu_read_unlock();
-               ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
-               if (ret != 0)
-                       goto out;
+               nfs_release_seqid(opendata->o_arg.seqid);
+               if (!opendata->is_recover) {
+                       ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
+                       if (ret != 0)
+                               goto out;
+               }
                ret = -EAGAIN;
 
                /* Try to update the stateid using the delegation */
@@ -1543,15 +1547,20 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
                rcu_read_lock();
                delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
                if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR &&
+                   data->o_arg.claim != NFS4_OPEN_CLAIM_DELEG_CUR_FH &&
                    can_open_delegated(delegation, data->o_arg.fmode))
                        goto unlock_no_action;
                rcu_read_unlock();
        }
        /* Update client id. */
        data->o_arg.clientid = clp->cl_clientid;
-       if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
-               task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
+       switch (data->o_arg.claim) {
+       case NFS4_OPEN_CLAIM_PREVIOUS:
+       case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
+       case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
                data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
+       case NFS4_OPEN_CLAIM_FH:
+               task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
                nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
        }
        data->timestamp = jiffies;
@@ -1665,8 +1674,11 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
        data->rpc_done = 0;
        data->rpc_status = 0;
        data->cancelled = 0;
-       if (isrecover)
+       data->is_recover = 0;
+       if (isrecover) {
                nfs4_set_sequence_privileged(&o_arg->seq_args);
+               data->is_recover = 1;
+       }
        task = rpc_run_task(&task_setup_data);
         if (IS_ERR(task))
                 return PTR_ERR(task);
@@ -2130,20 +2142,25 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
                .rpc_cred       = cred,
         };
        unsigned long timestamp = jiffies;
+       fmode_t fmode;
+       bool truncate;
        int status;
 
        nfs_fattr_init(fattr);
 
-       if (state != NULL && nfs4_valid_open_stateid(state)) {
+       /* Servers should only apply open mode checks for file size changes */
+       truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false;
+       fmode = truncate ? FMODE_WRITE : FMODE_READ;
+
+       if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
+               /* Use that stateid */
+       } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
                struct nfs_lockowner lockowner = {
                        .l_owner = current->files,
                        .l_pid = current->tgid,
                };
                nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
                                &lockowner);
-       } else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
-                               FMODE_WRITE)) {
-               /* Use that stateid */
        } else
                nfs4_stateid_copy(&arg.stateid, &zero_stateid);
 
@@ -2167,6 +2184,13 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
                err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
                switch (err) {
                case -NFS4ERR_OPENMODE:
+                       if (!(sattr->ia_valid & ATTR_SIZE)) {
+                               pr_warn_once("NFSv4: server %s is incorrectly "
+                                               "applying open mode checks to "
+                                               "a SETATTR that is not "
+                                               "changing file size.\n",
+                                               server->nfs_client->cl_hostname);
+                       }
                        if (state && !(state->state & FMODE_WRITE)) {
                                err = -EBADF;
                                if (sattr->ia_valid & ATTR_OPEN)
@@ -2536,7 +2560,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
 
        auth = rpcauth_create(flavor, server->client);
        if (IS_ERR(auth)) {
-               ret = -EIO;
+               ret = -EACCES;
                goto out;
        }
        ret = nfs4_lookup_root(server, fhandle, info);
@@ -2544,27 +2568,36 @@ out:
        return ret;
 }
 
+/*
+ * Retry pseudoroot lookup with various security flavors.  We do this when:
+ *
+ *   NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
+ *   NFSv4.1: the server does not support the SECINFO_NO_NAME operation
+ *
+ * Returns zero on success, or a negative NFS4ERR value, or a
+ * negative errno value.
+ */
 static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
                              struct nfs_fsinfo *info)
 {
-       int i, len, status = 0;
-       rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
-
-       len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array));
-       if (len < 0)
-               return len;
-
-       for (i = 0; i < len; i++) {
-               /* AUTH_UNIX is the default flavor if none was specified,
-                * thus has already been tried. */
-               if (flav_array[i] == RPC_AUTH_UNIX)
-                       continue;
+       /* Per 3530bis 15.33.5 */
+       static const rpc_authflavor_t flav_array[] = {
+               RPC_AUTH_GSS_KRB5P,
+               RPC_AUTH_GSS_KRB5I,
+               RPC_AUTH_GSS_KRB5,
+               RPC_AUTH_UNIX,                  /* courtesy */
+               RPC_AUTH_NULL,
+       };
+       int status = -EPERM;
+       size_t i;
 
+       for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
                status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
                if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
                        continue;
                break;
        }
+
        /*
         * -EACCESS could mean that the user doesn't have correct permissions
         * to access the mount.  It could also mean that we tried to mount
@@ -2577,24 +2610,36 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        return status;
 }
 
-/*
- * get the file handle for the "/" directory on the server
+static int nfs4_do_find_root_sec(struct nfs_server *server,
+               struct nfs_fh *fhandle, struct nfs_fsinfo *info)
+{
+       int mv = server->nfs_client->cl_minorversion;
+       return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info);
+}
+
+/**
+ * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
+ * @server: initialized nfs_server handle
+ * @fhandle: we fill in the pseudo-fs root file handle
+ * @info: we fill in an FSINFO struct
+ *
+ * Returns zero on success, or a negative errno.
  */
 int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
                         struct nfs_fsinfo *info)
 {
-       int minor_version = server->nfs_client->cl_minorversion;
-       int status = nfs4_lookup_root(server, fhandle, info);
-       if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
-               /*
-                * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
-                * by nfs4_map_errors() as this function exits.
-                */
-               status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
+       int status;
+
+       status = nfs4_lookup_root(server, fhandle, info);
+       if ((status == -NFS4ERR_WRONGSEC) &&
+           !(server->flags & NFS_MOUNT_SECFLAVOUR))
+               status = nfs4_do_find_root_sec(server, fhandle, info);
+
        if (status == 0)
                status = nfs4_server_capabilities(server, fhandle);
        if (status == 0)
                status = nfs4_do_fsinfo(server, fhandle, info);
+
        return nfs4_map_errors(status);
 }
 
@@ -3473,12 +3518,21 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
 static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
 {
        struct nfs4_exception exception = { };
+       unsigned long now = jiffies;
        int err;
 
        do {
-               err = nfs4_handle_exception(server,
-                               _nfs4_do_fsinfo(server, fhandle, fsinfo),
-                               &exception);
+               err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
+               if (err == 0) {
+                       struct nfs_client *clp = server->nfs_client;
+
+                       spin_lock(&clp->cl_lock);
+                       clp->cl_lease_time = fsinfo->lease_time * HZ;
+                       clp->cl_last_renewal = now;
+                       spin_unlock(&clp->cl_lock);
+                       break;
+               }
+               err = nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
        return err;
 }
@@ -4319,27 +4373,17 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
                struct nfs4_setclientid_res *arg,
                struct rpc_cred *cred)
 {
-       struct nfs_fsinfo fsinfo;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
                .rpc_argp = arg,
-               .rpc_resp = &fsinfo,
                .rpc_cred = cred,
        };
-       unsigned long now;
        int status;
 
        dprintk("NFS call  setclientid_confirm auth=%s, (client ID %llx)\n",
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                clp->cl_clientid);
-       now = jiffies;
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
-       if (status == 0) {
-               spin_lock(&clp->cl_lock);
-               clp->cl_lease_time = fsinfo.lease_time * HZ;
-               clp->cl_last_renewal = now;
-               spin_unlock(&clp->cl_lock);
-       }
        dprintk("NFS reply setclientid_confirm: %d\n", status);
        return status;
 }
index b7796950eceb214e3d0d399d2bfae7379b05256c..0b32f9483b7afb07d993fb92568bec662b3dd9a4 100644 (file)
@@ -154,18 +154,6 @@ struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
        return cred;
 }
 
-static void nfs4_clear_machine_cred(struct nfs_client *clp)
-{
-       struct rpc_cred *cred;
-
-       spin_lock(&clp->cl_lock);
-       cred = clp->cl_machine_cred;
-       clp->cl_machine_cred = NULL;
-       spin_unlock(&clp->cl_lock);
-       if (cred != NULL)
-               put_rpccred(cred);
-}
-
 static struct rpc_cred *
 nfs4_get_renew_cred_server_locked(struct nfs_server *server)
 {
@@ -1776,10 +1764,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
                clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
                return -EPERM;
        case -EACCES:
-               if (clp->cl_machine_cred == NULL)
-                       return -EACCES;
-               /* Handle case where the user hasn't set up machine creds */
-               nfs4_clear_machine_cred(clp);
        case -NFS4ERR_DELAY:
        case -ETIMEDOUT:
        case -EAGAIN:
@@ -1874,31 +1858,18 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
 {
        const struct nfs4_state_recovery_ops *ops =
                                clp->cl_mvops->reboot_recovery_ops;
-       rpc_authflavor_t *flavors, flav, save;
        struct rpc_clnt *clnt;
        struct rpc_cred *cred;
-       int i, len, status;
+       int i, status;
 
        dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname);
 
-       len = NFS_MAX_SECFLAVORS;
-       flavors = kcalloc(len, sizeof(*flavors), GFP_KERNEL);
-       if (flavors == NULL) {
-               status = -ENOMEM;
-               goto out;
-       }
-       len = rpcauth_list_flavors(flavors, len);
-       if (len < 0) {
-               status = len;
-               goto out_free;
-       }
        clnt = clp->cl_rpcclient;
-       save = clnt->cl_auth->au_flavor;
        i = 0;
 
        mutex_lock(&nfs_clid_init_mutex);
-       status  = -ENOENT;
 again:
+       status  = -ENOENT;
        cred = ops->get_clid_cred(clp);
        if (cred == NULL)
                goto out_unlock;
@@ -1908,12 +1879,6 @@ again:
        switch (status) {
        case 0:
                break;
-
-       case -EACCES:
-               if (clp->cl_machine_cred == NULL)
-                       break;
-               /* Handle case where the user hasn't set up machine creds */
-               nfs4_clear_machine_cred(clp);
        case -NFS4ERR_DELAY:
        case -ETIMEDOUT:
        case -EAGAIN:
@@ -1922,22 +1887,23 @@ again:
                dprintk("NFS: %s after status %d, retrying\n",
                        __func__, status);
                goto again;
-
+       case -EACCES:
+               if (i++)
+                       break;
        case -NFS4ERR_CLID_INUSE:
        case -NFS4ERR_WRONGSEC:
-               status = -EPERM;
-               if (i >= len)
-                       break;
-
-               flav = flavors[i++];
-               if (flav == save)
-                       flav = flavors[i++];
-               clnt = rpc_clone_client_set_auth(clnt, flav);
+               clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX);
                if (IS_ERR(clnt)) {
                        status = PTR_ERR(clnt);
                        break;
                }
-               clp->cl_rpcclient = clnt;
+               /* Note: this is safe because we haven't yet marked the
+                * client as ready, so we are the only user of
+                * clp->cl_rpcclient
+                */
+               clnt = xchg(&clp->cl_rpcclient, clnt);
+               rpc_shutdown_client(clnt);
+               clnt = clp->cl_rpcclient;
                goto again;
 
        case -NFS4ERR_MINOR_VERS_MISMATCH:
@@ -1948,13 +1914,15 @@ again:
        case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
                                 * in nfs4_exchange_id */
                status = -EKEYEXPIRED;
+               break;
+       default:
+               pr_warn("NFS: %s unhandled error %d. Exiting with error EIO\n",
+                               __func__, status);
+               status = -EIO;
        }
 
 out_unlock:
        mutex_unlock(&nfs_clid_init_mutex);
-out_free:
-       kfree(flavors);
-out:
        dprintk("NFS: %s: status = %d\n", __func__, status);
        return status;
 }
index 569b166cc050143c8d2cfa7ec506b479e8517240..a5e1a3026d489240cb7a44ae87eec07df019ce3a 100644 (file)
@@ -252,6 +252,8 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 
        dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
+       if (data->auth_flavors[0] == RPC_AUTH_MAXFLAVOR)
+               data->auth_flavors[0] = RPC_AUTH_UNIX;
        export_path = data->nfs_server.export_path;
        data->nfs_server.export_path = "/";
        root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
index c2cbf0d90a318c60cce574b9998bf2b7f697486f..3c79c5878c6da6689df58f4b0990a777798fdf9e 100644 (file)
@@ -530,14 +530,10 @@ static int nfs4_stat_to_errno(int);
                                decode_setclientid_maxsz)
 #define NFS4_enc_setclientid_confirm_sz \
                                (compound_encode_hdr_maxsz + \
-                               encode_setclientid_confirm_maxsz + \
-                               encode_putrootfh_maxsz + \
-                               encode_fsinfo_maxsz)
+                               encode_setclientid_confirm_maxsz)
 #define NFS4_dec_setclientid_confirm_sz \
                                (compound_decode_hdr_maxsz + \
-                               decode_setclientid_confirm_maxsz + \
-                               decode_putrootfh_maxsz + \
-                               decode_fsinfo_maxsz)
+                               decode_setclientid_confirm_maxsz)
 #define NFS4_enc_lock_sz        (compound_encode_hdr_maxsz + \
                                encode_sequence_maxsz + \
                                encode_putfh_maxsz + \
@@ -2601,12 +2597,9 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
        struct compound_hdr hdr = {
                .nops   = 0,
        };
-       const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
 
        encode_compound_hdr(xdr, req, &hdr);
        encode_setclientid_confirm(xdr, arg, &hdr);
-       encode_putrootfh(xdr, &hdr);
-       encode_fsinfo(xdr, lease_bitmap, &hdr);
        encode_nops(&hdr);
 }
 
@@ -5198,27 +5191,30 @@ static int decode_delegreturn(struct xdr_stream *xdr)
        return decode_op_hdr(xdr, OP_DELEGRETURN);
 }
 
-static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor)
+static int decode_secinfo_gss(struct xdr_stream *xdr,
+                             struct nfs4_secinfo4 *flavor)
 {
+       u32 oid_len;
        __be32 *p;
 
        p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
                goto out_overflow;
-       flavor->gss.sec_oid4.len = be32_to_cpup(p);
-       if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN)
+       oid_len = be32_to_cpup(p);
+       if (oid_len > GSS_OID_MAX_LEN)
                goto out_err;
 
-       p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len);
+       p = xdr_inline_decode(xdr, oid_len);
        if (unlikely(!p))
                goto out_overflow;
-       memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len);
+       memcpy(flavor->flavor_info.oid.data, p, oid_len);
+       flavor->flavor_info.oid.len = oid_len;
 
        p = xdr_inline_decode(xdr, 8);
        if (unlikely(!p))
                goto out_overflow;
-       flavor->gss.qop4 = be32_to_cpup(p++);
-       flavor->gss.service = be32_to_cpup(p);
+       flavor->flavor_info.qop = be32_to_cpup(p++);
+       flavor->flavor_info.service = be32_to_cpup(p);
 
        return 0;
 
@@ -5231,10 +5227,10 @@ out_err:
 
 static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
 {
-       struct nfs4_secinfo_flavor *sec_flavor;
+       struct nfs4_secinfo4 *sec_flavor;
+       unsigned int i, num_flavors;
        int status;
        __be32 *p;
-       int i, num_flavors;
 
        p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
@@ -6637,8 +6633,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
  * Decode SETCLIENTID_CONFIRM response
  */
 static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
-                                           struct xdr_stream *xdr,
-                                           struct nfs_fsinfo *fsinfo)
+                                           struct xdr_stream *xdr)
 {
        struct compound_hdr hdr;
        int status;
@@ -6646,10 +6641,6 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
        status = decode_compound_hdr(xdr, &hdr);
        if (!status)
                status = decode_setclientid_confirm(xdr);
-       if (!status)
-               status = decode_putrootfh(xdr);
-       if (!status)
-               status = decode_fsinfo(xdr, fsinfo);
        return status;
 }
 
index 2f8a29db0f1bed59a8300d64038ebe4404d611a6..eb494f6a4c6bcf3671cbd87df52c68776a94b2ab 100644 (file)
@@ -920,7 +920,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
                data->mount_server.port = NFS_UNSPEC_PORT;
                data->nfs_server.port   = NFS_UNSPEC_PORT;
                data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-               data->auth_flavors[0]   = RPC_AUTH_UNIX;
+               data->auth_flavors[0]   = RPC_AUTH_MAXFLAVOR;
                data->auth_flavor_len   = 1;
                data->minorversion      = 0;
                data->need_mount        = true;
@@ -1608,49 +1608,57 @@ out_security_failure:
 }
 
 /*
- * Match the requested auth flavors with the list returned by
- * the server.  Returns zero and sets the mount's authentication
- * flavor on success; returns -EACCES if server does not support
- * the requested flavor.
+ * Select a security flavor for this mount.  The selected flavor
+ * is planted in args->auth_flavors[0].
  */
-static int nfs_walk_authlist(struct nfs_parsed_mount_data *args,
-                            struct nfs_mount_request *request)
+static void nfs_select_flavor(struct nfs_parsed_mount_data *args,
+                             struct nfs_mount_request *request)
 {
-       unsigned int i, j, server_authlist_len = *(request->auth_flav_len);
+       unsigned int i, count = *(request->auth_flav_len);
+       rpc_authflavor_t flavor;
+
+       if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR)
+               goto out;
+
+       /*
+        * The NFSv2 MNT operation does not return a flavor list.
+        */
+       if (args->mount_server.version != NFS_MNT3_VERSION)
+               goto out_default;
 
        /*
         * Certain releases of Linux's mountd return an empty
-        * flavor list.  To prevent behavioral regression with
-        * these servers (ie. rejecting mounts that used to
-        * succeed), revert to pre-2.6.32 behavior (no checking)
-        * if the returned flavor list is empty.
+        * flavor list in some cases.
         */
-       if (server_authlist_len == 0)
-               return 0;
+       if (count == 0)
+               goto out_default;
 
        /*
-        * We avoid sophisticated negotiating here, as there are
-        * plenty of cases where we can get it wrong, providing
-        * either too little or too much security.
-        *
         * RFC 2623, section 2.7 suggests we SHOULD prefer the
         * flavor listed first.  However, some servers list
-        * AUTH_NULL first.  Our caller plants AUTH_SYS, the
-        * preferred default, in args->auth_flavors[0] if user
-        * didn't specify sec= mount option.
+        * AUTH_NULL first.  Avoid ever choosing AUTH_NULL.
         */
-       for (i = 0; i < args->auth_flavor_len; i++)
-               for (j = 0; j < server_authlist_len; j++)
-                       if (args->auth_flavors[i] == request->auth_flavs[j]) {
-                               dfprintk(MOUNT, "NFS: using auth flavor %d\n",
-                                       request->auth_flavs[j]);
-                               args->auth_flavors[0] = request->auth_flavs[j];
-                               return 0;
-                       }
+       for (i = 0; i < count; i++) {
+               struct rpcsec_gss_info info;
+
+               flavor = request->auth_flavs[i];
+               switch (flavor) {
+               case RPC_AUTH_UNIX:
+                       goto out_set;
+               case RPC_AUTH_NULL:
+                       continue;
+               default:
+                       if (rpcauth_get_gssinfo(flavor, &info) == 0)
+                               goto out_set;
+               }
+       }
 
-       dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n");
-       nfs_umount(request);
-       return -EACCES;
+out_default:
+       flavor = RPC_AUTH_UNIX;
+out_set:
+       args->auth_flavors[0] = flavor;
+out:
+       dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]);
 }
 
 /*
@@ -1713,12 +1721,8 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args,
                return status;
        }
 
-       /*
-        * MNTv1 (NFSv2) does not support auth flavor negotiation.
-        */
-       if (args->mount_server.version != NFS_MNT3_VERSION)
-               return 0;
-       return nfs_walk_authlist(args, &request);
+       nfs_select_flavor(args, &request);
+       return 0;
 }
 
 struct dentry *nfs_try_mount(int flags, const char *dev_name,
index 888a600dad8c6df5829ee57e49e05a23658948e6..78272185a13d6846225002a0694068e61fe2dc03 100644 (file)
@@ -3083,10 +3083,9 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
 
 static __be32
 nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
-                        __be32 nfserr,struct svc_export *exp)
+                        __be32 nfserr, struct svc_export *exp)
 {
-       int i = 0;
-       u32 nflavs;
+       u32 i, nflavs;
        struct exp_flavor_info *flavs;
        struct exp_flavor_info def_flavs[2];
        __be32 *p;
@@ -3117,30 +3116,29 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
        WRITE32(nflavs);
        ADJUST_ARGS();
        for (i = 0; i < nflavs; i++) {
-               u32 flav = flavs[i].pseudoflavor;
-               struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
+               struct rpcsec_gss_info info;
 
-               if (gm) {
+               if (rpcauth_get_gssinfo(flavs[i].pseudoflavor, &info) == 0) {
                        RESERVE_SPACE(4);
                        WRITE32(RPC_AUTH_GSS);
                        ADJUST_ARGS();
-                       RESERVE_SPACE(4 + gm->gm_oid.len);
-                       WRITE32(gm->gm_oid.len);
-                       WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
+                       RESERVE_SPACE(4 + info.oid.len);
+                       WRITE32(info.oid.len);
+                       WRITEMEM(info.oid.data, info.oid.len);
                        ADJUST_ARGS();
                        RESERVE_SPACE(4);
-                       WRITE32(0); /* qop */
+                       WRITE32(info.qop);
                        ADJUST_ARGS();
                        RESERVE_SPACE(4);
-                       WRITE32(gss_pseudoflavor_to_service(gm, flav));
+                       WRITE32(info.service);
                        ADJUST_ARGS();
-                       gss_mech_put(gm);
                } else {
                        RESERVE_SPACE(4);
-                       WRITE32(flav);
+                       WRITE32(flavs[i].pseudoflavor);
                        ADJUST_ARGS();
                }
        }
+
 out:
        if (exp)
                exp_put(exp);
index bdc100f66dfbe38311506d5d3ce5e6364b06db29..766c5bc9d441ccf440341dab53e06616e3262363 100644 (file)
@@ -14,9 +14,6 @@
 #define NFS_DEF_FILE_IO_SIZE   (4096U)
 #define NFS_MIN_FILE_IO_SIZE   (1024U)
 
-/* Forward declaration for NFS v3 */
-struct nfs4_secinfo_flavors;
-
 struct nfs4_string {
        unsigned int len;
        char *data;
@@ -1053,25 +1050,14 @@ struct nfs4_fs_locations_res {
        struct nfs4_fs_locations       *fs_locations;
 };
 
-struct nfs4_secinfo_oid {
-       unsigned int len;
-       char data[GSS_OID_MAX_LEN];
-};
-
-struct nfs4_secinfo_gss {
-       struct nfs4_secinfo_oid sec_oid4;
-       unsigned int qop4;
-       unsigned int service;
-};
-
-struct nfs4_secinfo_flavor {
-       unsigned int            flavor;
-       struct nfs4_secinfo_gss gss;
+struct nfs4_secinfo4 {
+       u32                     flavor;
+       struct rpcsec_gss_info  flavor_info;
 };
 
 struct nfs4_secinfo_flavors {
-       unsigned int num_flavors;
-       struct nfs4_secinfo_flavor flavors[0];
+       unsigned int            num_flavors;
+       struct nfs4_secinfo4    flavors[0];
 };
 
 struct nfs4_secinfo_arg {
index 58fda1c3c783948f4627361eba9bc93a51bde796..0dd00f4f681046018f25292cc288632dc2593caa 100644 (file)
@@ -22,6 +22,8 @@
 /* size of the nodename buffer */
 #define UNX_MAXNODENAME        32
 
+struct rpcsec_gss_info;
+
 /* Work around the lack of a VFS credential */
 struct auth_cred {
        kuid_t  uid;
@@ -103,6 +105,9 @@ struct rpc_authops {
        int                     (*pipes_create)(struct rpc_auth *);
        void                    (*pipes_destroy)(struct rpc_auth *);
        int                     (*list_pseudoflavors)(rpc_authflavor_t *, int);
+       rpc_authflavor_t        (*info2flavor)(struct rpcsec_gss_info *);
+       int                     (*flavor2info)(rpc_authflavor_t,
+                                               struct rpcsec_gss_info *);
 };
 
 struct rpc_credops {
@@ -137,6 +142,10 @@ int                        rpcauth_register(const struct rpc_authops *);
 int                    rpcauth_unregister(const struct rpc_authops *);
 struct rpc_auth *      rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
 void                   rpcauth_release(struct rpc_auth *);
+rpc_authflavor_t       rpcauth_get_pseudoflavor(rpc_authflavor_t,
+                               struct rpcsec_gss_info *);
+int                    rpcauth_get_gssinfo(rpc_authflavor_t,
+                               struct rpcsec_gss_info *);
 int                    rpcauth_list_flavors(rpc_authflavor_t *, int);
 struct rpc_cred *      rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
 void                   rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
index 04d03bb2de5d01fb67053be55c4545fc3b9c1f98..161463e596247824f774df256580d08e9dde895f 100644 (file)
@@ -25,10 +25,21 @@ struct gss_ctx {
 
 #define GSS_C_NO_BUFFER                ((struct xdr_netobj) 0)
 #define GSS_C_NO_CONTEXT       ((struct gss_ctx *) 0)
-#define GSS_C_NULL_OID         ((struct xdr_netobj) 0)
+#define GSS_C_QOP_DEFAULT      (0)
 
 /*XXX  arbitrary length - is this set somewhere? */
 #define GSS_OID_MAX_LEN 32
+struct rpcsec_gss_oid {
+       unsigned int    len;
+       u8              data[GSS_OID_MAX_LEN];
+};
+
+/* From RFC 3530 */
+struct rpcsec_gss_info {
+       struct rpcsec_gss_oid   oid;
+       u32                     qop;
+       u32                     service;
+};
 
 /* gss-api prototypes; note that these are somewhat simplified versions of
  * the prototypes specified in RFC 2744. */
@@ -59,12 +70,14 @@ u32 gss_unwrap(
 u32 gss_delete_sec_context(
                struct gss_ctx          **ctx_id);
 
-u32 gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 service);
+rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 qop,
+                                       u32 service);
 u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor);
 char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service);
 
 struct pf_desc {
        u32     pseudoflavor;
+       u32     qop;
        u32     service;
        char    *name;
        char    *auth_domain_name;
@@ -77,7 +90,7 @@ struct pf_desc {
 struct gss_api_mech {
        struct list_head        gm_list;
        struct module           *gm_owner;
-       struct xdr_netobj       gm_oid;
+       struct rpcsec_gss_oid   gm_oid;
        char                    *gm_name;
        const struct gss_api_ops *gm_ops;
        /* pseudoflavors supported by this mechanism: */
@@ -121,7 +134,13 @@ void gss_mech_unregister(struct gss_api_mech *);
 
 /* returns a mechanism descriptor given an OID, and increments the mechanism's
  * reference count. */
-struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *);
+struct gss_api_mech * gss_mech_get_by_OID(struct rpcsec_gss_oid *);
+
+/* Given a GSS security tuple, look up a pseudoflavor */
+rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);
+
+/* Given a pseudoflavor, look up a GSS security tuple */
+int gss_mech_flavor2info(rpc_authflavor_t, struct rpcsec_gss_info *);
 
 /* Returns a reference to a mechanism, given a name like "krb5" etc. */
 struct gss_api_mech *gss_mech_get_by_name(const char *);
@@ -132,9 +151,6 @@ struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32);
 /* Fill in an array with a list of supported pseudoflavors */
 int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int);
 
-/* Just increments the mechanism's reference count and returns its input: */
-struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
-
 /* For every successful gss_mech_get or gss_mech_get_by_* call there must be a
  * corresponding call to gss_mech_put. */
 void gss_mech_put(struct gss_api_mech *);
index 262caf03bd5f8b6b6e17bd2cdc362b2f9bcb7c79..241b54f30204a63ec4a63372910a8c1fe714dbad 100644 (file)
@@ -3,6 +3,7 @@ config SUNRPC
 
 config SUNRPC_GSS
        tristate
+       select OID_REGISTRY
 
 config SUNRPC_BACKCHANNEL
        bool
index f5294047df77b03b0feae953405bfd5b41252b76..ed2fdd210c0bac4f5569acbe5da9daa025012cdd 100644 (file)
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
 
 static u32
 pseudoflavor_to_flavor(u32 flavor) {
-       if (flavor >= RPC_AUTH_MAXFLAVOR)
+       if (flavor > RPC_AUTH_MAXFLAVOR)
                return RPC_AUTH_GSS;
        return flavor;
 }
@@ -123,6 +123,79 @@ rpcauth_unregister(const struct rpc_authops *ops)
 }
 EXPORT_SYMBOL_GPL(rpcauth_unregister);
 
+/**
+ * rpcauth_get_pseudoflavor - check if security flavor is supported
+ * @flavor: a security flavor
+ * @info: a GSS mech OID, quality of protection, and service value
+ *
+ * Verifies that an appropriate kernel module is available or already loaded.
+ * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is
+ * not supported locally.
+ */
+rpc_authflavor_t
+rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info)
+{
+       const struct rpc_authops *ops;
+       rpc_authflavor_t pseudoflavor;
+
+       ops = auth_flavors[flavor];
+       if (ops == NULL)
+               request_module("rpc-auth-%u", flavor);
+       spin_lock(&rpc_authflavor_lock);
+       ops = auth_flavors[flavor];
+       if (ops == NULL || !try_module_get(ops->owner)) {
+               spin_unlock(&rpc_authflavor_lock);
+               return RPC_AUTH_MAXFLAVOR;
+       }
+       spin_unlock(&rpc_authflavor_lock);
+
+       pseudoflavor = flavor;
+       if (ops->info2flavor != NULL)
+               pseudoflavor = ops->info2flavor(info);
+
+       module_put(ops->owner);
+       return pseudoflavor;
+}
+EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor);
+
+/**
+ * rpcauth_get_gssinfo - find GSS tuple matching a GSS pseudoflavor
+ * @pseudoflavor: GSS pseudoflavor to match
+ * @info: rpcsec_gss_info structure to fill in
+ *
+ * Returns zero and fills in "info" if pseudoflavor matches a
+ * supported mechanism.
+ */
+int
+rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info)
+{
+       rpc_authflavor_t flavor = pseudoflavor_to_flavor(pseudoflavor);
+       const struct rpc_authops *ops;
+       int result;
+
+       if (flavor >= RPC_AUTH_MAXFLAVOR)
+               return -EINVAL;
+
+       ops = auth_flavors[flavor];
+       if (ops == NULL)
+               request_module("rpc-auth-%u", flavor);
+       spin_lock(&rpc_authflavor_lock);
+       ops = auth_flavors[flavor];
+       if (ops == NULL || !try_module_get(ops->owner)) {
+               spin_unlock(&rpc_authflavor_lock);
+               return -ENOENT;
+       }
+       spin_unlock(&rpc_authflavor_lock);
+
+       result = -ENOENT;
+       if (ops->flavor2info != NULL)
+               result = ops->flavor2info(pseudoflavor, info);
+
+       module_put(ops->owner);
+       return result;
+}
+EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo);
+
 /**
  * rpcauth_list_flavors - discover registered flavors and pseudoflavors
  * @array: array to fill in
index 23563e783ec287243af09589c2fe0b6e9d2bb832..a764e227fddeb06955226e7a7d622282e168b481 100644 (file)
@@ -1641,6 +1641,8 @@ static const struct rpc_authops authgss_ops = {
        .pipes_create   = gss_pipes_dentries_create,
        .pipes_destroy  = gss_pipes_dentries_destroy,
        .list_pseudoflavors = gss_mech_list_pseudoflavors,
+       .info2flavor    = gss_mech_info2flavor,
+       .flavor2info    = gss_mech_flavor2info,
 };
 
 static const struct rpc_credops gss_credops = {
@@ -1733,6 +1735,7 @@ static void __exit exit_rpcsec_gss(void)
        rcu_barrier(); /* Wait for completion of call_rcu()'s */
 }
 
+MODULE_ALIAS("rpc-auth-6");
 MODULE_LICENSE("GPL");
 module_param_named(expired_cred_retry_delay,
                   gss_expired_cred_retry_delay,
index 3bc4a23938ea72116deb071fae82f800ccc478d1..0d3c158ef8fa9e332eea86e72cc9c2b127619bd3 100644 (file)
@@ -732,16 +732,19 @@ static const struct gss_api_ops gss_kerberos_ops = {
 static struct pf_desc gss_kerberos_pfs[] = {
        [0] = {
                .pseudoflavor = RPC_AUTH_GSS_KRB5,
+               .qop = GSS_C_QOP_DEFAULT,
                .service = RPC_GSS_SVC_NONE,
                .name = "krb5",
        },
        [1] = {
                .pseudoflavor = RPC_AUTH_GSS_KRB5I,
+               .qop = GSS_C_QOP_DEFAULT,
                .service = RPC_GSS_SVC_INTEGRITY,
                .name = "krb5i",
        },
        [2] = {
                .pseudoflavor = RPC_AUTH_GSS_KRB5P,
+               .qop = GSS_C_QOP_DEFAULT,
                .service = RPC_GSS_SVC_PRIVACY,
                .name = "krb5p",
        },
@@ -753,11 +756,12 @@ MODULE_ALIAS("rpc-auth-gss-krb5p");
 MODULE_ALIAS("rpc-auth-gss-390003");
 MODULE_ALIAS("rpc-auth-gss-390004");
 MODULE_ALIAS("rpc-auth-gss-390005");
+MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2");
 
 static struct gss_api_mech gss_kerberos_mech = {
        .gm_name        = "krb5",
        .gm_owner       = THIS_MODULE,
-       .gm_oid         = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"},
+       .gm_oid         = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" },
        .gm_ops         = &gss_kerberos_ops,
        .gm_pf_num      = ARRAY_SIZE(gss_kerberos_pfs),
        .gm_pfs         = gss_kerberos_pfs,
index 43fd5bbf92c61002a3b727ac69ee66fdd93c1fc7..defa9d33925c382264b104ff43fc70ec3f1fcc32 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/oid_registry.h>
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/gss_asn1.h>
 #include <linux/sunrpc/auth_gss.h>
@@ -102,8 +103,13 @@ out:
        return status;
 }
 
-int
-gss_mech_register(struct gss_api_mech *gm)
+/**
+ * gss_mech_register - register a GSS mechanism
+ * @gm: GSS mechanism handle
+ *
+ * Returns zero if successful, or a negative errno.
+ */
+int gss_mech_register(struct gss_api_mech *gm)
 {
        int status;
 
@@ -116,11 +122,14 @@ gss_mech_register(struct gss_api_mech *gm)
        dprintk("RPC:       registered gss mechanism %s\n", gm->gm_name);
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(gss_mech_register);
 
-void
-gss_mech_unregister(struct gss_api_mech *gm)
+/**
+ * gss_mech_unregister - release a GSS mechanism
+ * @gm: GSS mechanism handle
+ *
+ */
+void gss_mech_unregister(struct gss_api_mech *gm)
 {
        spin_lock(&registered_mechs_lock);
        list_del(&gm->gm_list);
@@ -128,18 +137,14 @@ gss_mech_unregister(struct gss_api_mech *gm)
        dprintk("RPC:       unregistered gss mechanism %s\n", gm->gm_name);
        gss_mech_free(gm);
 }
-
 EXPORT_SYMBOL_GPL(gss_mech_unregister);
 
-struct gss_api_mech *
-gss_mech_get(struct gss_api_mech *gm)
+static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm)
 {
        __module_get(gm->gm_owner);
        return gm;
 }
 
-EXPORT_SYMBOL_GPL(gss_mech_get);
-
 static struct gss_api_mech *
 _gss_mech_get_by_name(const char *name)
 {
@@ -169,12 +174,16 @@ struct gss_api_mech * gss_mech_get_by_name(const char *name)
        }
        return gm;
 }
-EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
 
-struct gss_api_mech *
-gss_mech_get_by_OID(struct xdr_netobj *obj)
+struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
 {
        struct gss_api_mech     *pos, *gm = NULL;
+       char buf[32];
+
+       if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0)
+               return NULL;
+       dprintk("RPC:       %s(%s)\n", __func__, buf);
+       request_module("rpc-auth-gss-%s", buf);
 
        spin_lock(&registered_mechs_lock);
        list_for_each_entry(pos, &registered_mechs, gm_list) {
@@ -188,11 +197,8 @@ gss_mech_get_by_OID(struct xdr_netobj *obj)
        }
        spin_unlock(&registered_mechs_lock);
        return gm;
-
 }
 
-EXPORT_SYMBOL_GPL(gss_mech_get_by_OID);
-
 static inline int
 mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
 {
@@ -237,8 +243,6 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
        return gm;
 }
 
-EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);
-
 /**
  * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors
  * @array: array to fill in
@@ -268,19 +272,82 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size)
        return i;
 }
 
-u32
-gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
+/**
+ * gss_svc_to_pseudoflavor - map a GSS service number to a pseudoflavor
+ * @gm: GSS mechanism handle
+ * @qop: GSS quality-of-protection value
+ * @service: GSS service value
+ *
+ * Returns a matching security flavor, or RPC_AUTH_MAXFLAVOR if none is found.
+ */
+rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 qop,
+                                        u32 service)
 {
        int i;
 
        for (i = 0; i < gm->gm_pf_num; i++) {
-               if (gm->gm_pfs[i].service == service) {
+               if (gm->gm_pfs[i].qop == qop &&
+                   gm->gm_pfs[i].service == service) {
                        return gm->gm_pfs[i].pseudoflavor;
                }
        }
-       return RPC_AUTH_MAXFLAVOR; /* illegal value */
+       return RPC_AUTH_MAXFLAVOR;
+}
+
+/**
+ * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple
+ * @info: a GSS mech OID, quality of protection, and service value
+ *
+ * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is
+ * not supported.
+ */
+rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info)
+{
+       rpc_authflavor_t pseudoflavor;
+       struct gss_api_mech *gm;
+
+       gm = gss_mech_get_by_OID(&info->oid);
+       if (gm == NULL)
+               return RPC_AUTH_MAXFLAVOR;
+
+       pseudoflavor = gss_svc_to_pseudoflavor(gm, info->qop, info->service);
+
+       gss_mech_put(gm);
+       return pseudoflavor;
+}
+
+/**
+ * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor
+ * @pseudoflavor: GSS pseudoflavor to match
+ * @info: rpcsec_gss_info structure to fill in
+ *
+ * Returns zero and fills in "info" if pseudoflavor matches a
+ * supported mechanism.  Otherwise a negative errno is returned.
+ */
+int gss_mech_flavor2info(rpc_authflavor_t pseudoflavor,
+                        struct rpcsec_gss_info *info)
+{
+       struct gss_api_mech *gm;
+       int i;
+
+       gm = gss_mech_get_by_pseudoflavor(pseudoflavor);
+       if (gm == NULL)
+               return -ENOENT;
+
+       for (i = 0; i < gm->gm_pf_num; i++) {
+               if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) {
+                       memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len);
+                       info->oid.len = gm->gm_oid.len;
+                       info->qop = gm->gm_pfs[i].qop;
+                       info->service = gm->gm_pfs[i].service;
+                       gss_mech_put(gm);
+                       return 0;
+               }
+       }
+
+       gss_mech_put(gm);
+       return -ENOENT;
 }
-EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor);
 
 u32
 gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
@@ -294,8 +361,6 @@ gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
        return 0;
 }
 
-EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service);
-
 char *
 gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
 {
@@ -308,8 +373,6 @@ gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
        return NULL;
 }
 
-EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name);
-
 void
 gss_mech_put(struct gss_api_mech * gm)
 {
@@ -317,8 +380,6 @@ gss_mech_put(struct gss_api_mech * gm)
                module_put(gm->gm_owner);
 }
 
-EXPORT_SYMBOL_GPL(gss_mech_put);
-
 /* The mech could probably be determined from the token instead, but it's just
  * as easy for now to pass it in. */
 int
index 3f874d7048596013b36b42b68bb1652d541a4a48..c63273604ddc18ff53374e5cd13d970cf1bac46d 100644 (file)
@@ -220,7 +220,6 @@ static int gssp_call(struct net *net, struct rpc_message *msg)
 
 /* numbers somewhat arbitrary but large enough for current needs */
 #define GSSX_MAX_OUT_HANDLE    128
-#define GSSX_MAX_MECH_OID      16
 #define GSSX_MAX_SRC_PRINC     256
 #define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \
                        GSSX_max_oid_sz + \
@@ -242,7 +241,7 @@ int gssp_accept_sec_context_upcall(struct net *net,
                 * buffers but let the xdr code kmalloc them:
                 */
                .exported_context_token.len = GSSX_max_output_handle_sz,
-               .mech.len = GSSX_max_oid_sz,
+               .mech.len = GSS_OID_MAX_LEN,
                .src_name.display_name.len = GSSX_max_princ_sz
        };
        struct gssx_res_accept_sec_context res = {
@@ -272,7 +271,9 @@ int gssp_accept_sec_context_upcall(struct net *net,
        data->minor_status = res.status.minor_status;
        if (res.context_handle) {
                data->out_handle = rctxh.exported_context_token;
-               data->mech_oid = rctxh.mech;
+               data->mech_oid.len = rctxh.mech.len;
+               memcpy(data->mech_oid.data, rctxh.mech.data,
+                                               data->mech_oid.len);
                client_name = rctxh.src_name.display_name;
        }
 
index 4c2caaa7e84e1b1f4e03ff5fe0f365d3e7027399..1e542aded90a10cb20d78a23b4327a92a0806ae9 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef _GSS_RPC_UPCALL_H
 #define _GSS_RPC_UPCALL_H
 
+#include <linux/sunrpc/gss_api.h>
 #include <linux/sunrpc/auth_gss.h>
 #include "gss_rpc_xdr.h"
 #include "../netns.h"
@@ -30,7 +31,7 @@ struct gssp_upcall_data {
        struct gssp_in_token in_token;
        struct xdr_netobj out_handle;
        struct xdr_netobj out_token;
-       struct xdr_netobj mech_oid;
+       struct rpcsec_gss_oid mech_oid;
        struct svc_cred creds;
        int found_creds;
        int major_status;
index 58f5bc32940899c5166e39b915b6058cfab4f012..1c66a3b78329d940bbadc244abc1b0a83effd5a5 100644 (file)
@@ -1544,7 +1544,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
                svcdata->rsci = rsci;
                cache_get(&rsci->h);
                rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor(
-                                       rsci->mechctx->mech_type, gc->gc_svc);
+                                       rsci->mechctx->mech_type,
+                                       GSS_C_QOP_DEFAULT,
+                                       gc->gc_svc);
                ret = SVC_OK;
                goto out;
        }
index ac74399e8899cd9fcd7cc78a6427279c7d320bf9..3f7930f938cc295c79cdec097c1db4a9109a6086 100644 (file)
@@ -304,10 +304,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
        err = rpciod_up();
        if (err)
                goto out_no_rpciod;
-       err = -EINVAL;
-       if (!xprt)
-               goto out_no_xprt;
 
+       err = -EINVAL;
        if (args->version >= program->nrvers)
                goto out_err;
        version = program->version[args->version];
@@ -382,10 +380,9 @@ out_no_principal:
 out_no_stats:
        kfree(clnt);
 out_err:
-       xprt_put(xprt);
-out_no_xprt:
        rpciod_down();
 out_no_rpciod:
+       xprt_put(xprt);
        return ERR_PTR(err);
 }
 
@@ -516,7 +513,7 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
        new = rpc_new_client(args, xprt);
        if (IS_ERR(new)) {
                err = PTR_ERR(new);
-               goto out_put;
+               goto out_err;
        }
 
        atomic_inc(&clnt->cl_count);
@@ -529,8 +526,6 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
        new->cl_chatty = clnt->cl_chatty;
        return new;
 
-out_put:
-       xprt_put(xprt);
 out_err:
        dprintk("RPC:       %s: returned error %d\n", __func__, err);
        return ERR_PTR(err);