Skip to content

Commit

Permalink
Merge branch 'rpcsec_gss-from_cel' into linux-next
Browse files Browse the repository at this point in the history
* rpcsec_gss-from_cel: (21 commits)
  NFS: Retry SETCLIENTID with AUTH_SYS instead of AUTH_NONE
  NFSv4: Don't clear the machine cred when client establish returns EACCES
  NFSv4: Fix issues in nfs4_discover_server_trunking
  NFSv4: Fix the fallback to AUTH_NULL if krb5i is not available
  NFS: Use server-recommended security flavor by default (NFSv3)
  SUNRPC: Don't recognize RPC_AUTH_MAXFLAVOR
  NFS: Use "krb5i" to establish NFSv4 state whenever possible
  NFS: Try AUTH_UNIX when PUTROOTFH gets NFS4ERR_WRONGSEC
  NFS: Use static list of security flavors during root FH lookup recovery
  NFS: Avoid PUTROOTFH when managing leases
  NFS: Clean up nfs4_proc_get_rootfh
  NFS: Handle missing rpc.gssd when looking up root FH
  SUNRPC: Remove EXPORT_SYMBOL_GPL() from GSS mech switch
  SUNRPC: Make gss_mech_get() static
  SUNRPC: Refactor nfsd4_do_encode_secinfo()
  SUNRPC: Consider qop when looking up pseudoflavors
  SUNRPC: Load GSS kernel module by OID
  SUNRPC: Introduce rpcauth_get_pseudoflavor()
  SUNRPC: Define rpcsec_gss_info structure
  NFS: Remove unneeded forward declaration
  ...
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Apr 23, 2013
2 parents bdeca1b + 79d852b commit bd1d421
Show file tree
Hide file tree
Showing 17 changed files with 375 additions and 240 deletions.
4 changes: 3 additions & 1 deletion fs/nfs/nfs4client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
43 changes: 24 additions & 19 deletions fs/nfs/nfs4namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
92 changes: 56 additions & 36 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2547,35 +2547,44 @@ 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);
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
Expand All @@ -2588,24 +2597,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);
}

Expand Down Expand Up @@ -3484,12 +3505,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;
}
Expand Down Expand Up @@ -4330,27 +4360,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;
}
Expand Down
60 changes: 11 additions & 49 deletions fs/nfs/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand All @@ -1908,12 +1879,6 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
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:
Expand All @@ -1922,17 +1887,12 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
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;
Expand All @@ -1948,13 +1908,15 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
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;
}
Expand Down
2 changes: 2 additions & 0 deletions fs/nfs/nfs4super.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit bd1d421

Please sign in to comment.