mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-03-01 12:22:01 +07:00
Merge branch 'nfs-for-next' of git://linux-nfs.org/~trondmy/nfs-2.6 into for-3.10
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.
This commit is contained in:
commit
b1df763723
@ -201,7 +201,9 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
|
|||||||
if (clp->cl_minorversion != 0)
|
if (clp->cl_minorversion != 0)
|
||||||
__set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
|
__set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
|
||||||
__set_bit(NFS_CS_DISCRTRY, &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)
|
if (error < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -302,7 +304,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
|
|||||||
struct rpc_cred *cred)
|
struct rpc_cred *cred)
|
||||||
{
|
{
|
||||||
struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
|
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 = {
|
struct nfs4_setclientid_res clid = {
|
||||||
.clientid = new->cl_clientid,
|
.clientid = new->cl_clientid,
|
||||||
.confirm = new->cl_confirm,
|
.confirm = new->cl_confirm,
|
||||||
@ -310,10 +312,23 @@ int nfs40_walk_client_list(struct nfs_client *new,
|
|||||||
int status = -NFS4ERR_STALE_CLIENTID;
|
int status = -NFS4ERR_STALE_CLIENTID;
|
||||||
|
|
||||||
spin_lock(&nn->nfs_client_lock);
|
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
|
/* If "pos" isn't marked ready, we can't trust the
|
||||||
* remaining fields in "pos" */
|
* 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;
|
continue;
|
||||||
|
|
||||||
if (pos->rpc_ops != new->rpc_ops)
|
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 rpc_cred *cred)
|
||||||
{
|
{
|
||||||
struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
|
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;
|
int status = -NFS4ERR_STALE_CLIENTID;
|
||||||
|
|
||||||
spin_lock(&nn->nfs_client_lock);
|
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
|
/* If "pos" isn't marked ready, we can't trust the
|
||||||
* remaining fields in "pos", especially the client
|
* remaining fields in "pos", especially the client
|
||||||
* ID and serverowner fields. Wait for CREATE_SESSION
|
* ID and serverowner fields. Wait for CREATE_SESSION
|
||||||
* to finish. */
|
* to finish. */
|
||||||
if (pos->cl_cons_state < NFS_CS_READY) {
|
if (pos->cl_cons_state > NFS_CS_READY) {
|
||||||
atomic_inc(&pos->cl_count);
|
atomic_inc(&pos->cl_count);
|
||||||
spin_unlock(&nn->nfs_client_lock);
|
spin_unlock(&nn->nfs_client_lock);
|
||||||
|
|
||||||
@ -442,18 +457,17 @@ int nfs41_walk_client_list(struct nfs_client *new,
|
|||||||
nfs_put_client(prev);
|
nfs_put_client(prev);
|
||||||
prev = pos;
|
prev = pos;
|
||||||
|
|
||||||
nfs4_schedule_lease_recovery(pos);
|
|
||||||
status = nfs_wait_client_init_complete(pos);
|
status = nfs_wait_client_init_complete(pos);
|
||||||
if (status < 0) {
|
if (status == 0) {
|
||||||
nfs_put_client(pos);
|
nfs4_schedule_lease_recovery(pos);
|
||||||
spin_lock(&nn->nfs_client_lock);
|
status = nfs4_wait_clnt_recover(pos);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
status = pos->cl_cons_state;
|
|
||||||
spin_lock(&nn->nfs_client_lock);
|
spin_lock(&nn->nfs_client_lock);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (pos->cl_cons_state != NFS_CS_READY)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (pos->rpc_ops != new->rpc_ops)
|
if (pos->rpc_ops != new->rpc_ops)
|
||||||
continue;
|
continue;
|
||||||
@ -471,17 +485,18 @@ int nfs41_walk_client_list(struct nfs_client *new,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
atomic_inc(&pos->cl_count);
|
atomic_inc(&pos->cl_count);
|
||||||
spin_unlock(&nn->nfs_client_lock);
|
*result = pos;
|
||||||
|
status = 0;
|
||||||
dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
|
dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
|
||||||
__func__, pos, atomic_read(&pos->cl_count));
|
__func__, pos, atomic_read(&pos->cl_count));
|
||||||
|
break;
|
||||||
*result = pos;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No matching nfs_client found. */
|
/* No matching nfs_client found. */
|
||||||
spin_unlock(&nn->nfs_client_lock);
|
spin_unlock(&nn->nfs_client_lock);
|
||||||
dprintk("NFS: <-- %s status = %d\n", __func__, status);
|
dprintk("NFS: <-- %s status = %d\n", __func__, status);
|
||||||
|
if (prev)
|
||||||
|
nfs_put_client(prev);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NFS_V4_1 */
|
#endif /* CONFIG_NFS_V4_1 */
|
||||||
|
@ -134,33 +134,38 @@ static size_t nfs_parse_server_name(char *string, size_t len,
|
|||||||
return ret;
|
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)
|
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
|
||||||
{
|
{
|
||||||
struct gss_api_mech *mech;
|
rpc_authflavor_t pseudoflavor;
|
||||||
struct xdr_netobj oid;
|
struct nfs4_secinfo4 *secinfo;
|
||||||
int i;
|
unsigned int i;
|
||||||
rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
|
|
||||||
|
|
||||||
for (i = 0; i < flavors->num_flavors; i++) {
|
for (i = 0; i < flavors->num_flavors; i++) {
|
||||||
struct nfs4_secinfo_flavor *flavor;
|
secinfo = &flavors->flavors[i];
|
||||||
flavor = &flavors->flavors[i];
|
|
||||||
|
|
||||||
if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
|
switch (secinfo->flavor) {
|
||||||
pseudoflavor = flavor->flavor;
|
case RPC_AUTH_NULL:
|
||||||
break;
|
case RPC_AUTH_UNIX:
|
||||||
} else if (flavor->flavor == RPC_AUTH_GSS) {
|
case RPC_AUTH_GSS:
|
||||||
oid.len = flavor->gss.sec_oid4.len;
|
pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
|
||||||
oid.data = flavor->gss.sec_oid4.data;
|
&secinfo->flavor_info);
|
||||||
mech = gss_mech_get_by_OID(&oid);
|
if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
|
||||||
if (!mech)
|
return pseudoflavor;
|
||||||
continue;
|
|
||||||
pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service);
|
|
||||||
gss_mech_put(mech);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pseudoflavor;
|
return RPC_AUTH_UNIX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
|
static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
|
||||||
|
@ -769,6 +769,7 @@ struct nfs4_opendata {
|
|||||||
struct iattr attrs;
|
struct iattr attrs;
|
||||||
unsigned long timestamp;
|
unsigned long timestamp;
|
||||||
unsigned int rpc_done : 1;
|
unsigned int rpc_done : 1;
|
||||||
|
unsigned int is_recover : 1;
|
||||||
int rpc_status;
|
int rpc_status;
|
||||||
int cancelled;
|
int cancelled;
|
||||||
};
|
};
|
||||||
@ -1101,9 +1102,12 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
|
|||||||
/* Save the delegation */
|
/* Save the delegation */
|
||||||
nfs4_stateid_copy(&stateid, &delegation->stateid);
|
nfs4_stateid_copy(&stateid, &delegation->stateid);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
|
nfs_release_seqid(opendata->o_arg.seqid);
|
||||||
if (ret != 0)
|
if (!opendata->is_recover) {
|
||||||
goto out;
|
ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
|
||||||
|
if (ret != 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
|
|
||||||
/* Try to update the stateid using the delegation */
|
/* 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();
|
rcu_read_lock();
|
||||||
delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
|
delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
|
||||||
if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR &&
|
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))
|
can_open_delegated(delegation, data->o_arg.fmode))
|
||||||
goto unlock_no_action;
|
goto unlock_no_action;
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
/* Update client id. */
|
/* Update client id. */
|
||||||
data->o_arg.clientid = clp->cl_clientid;
|
data->o_arg.clientid = clp->cl_clientid;
|
||||||
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
|
switch (data->o_arg.claim) {
|
||||||
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
|
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];
|
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);
|
nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
|
||||||
}
|
}
|
||||||
data->timestamp = jiffies;
|
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_done = 0;
|
||||||
data->rpc_status = 0;
|
data->rpc_status = 0;
|
||||||
data->cancelled = 0;
|
data->cancelled = 0;
|
||||||
if (isrecover)
|
data->is_recover = 0;
|
||||||
|
if (isrecover) {
|
||||||
nfs4_set_sequence_privileged(&o_arg->seq_args);
|
nfs4_set_sequence_privileged(&o_arg->seq_args);
|
||||||
|
data->is_recover = 1;
|
||||||
|
}
|
||||||
task = rpc_run_task(&task_setup_data);
|
task = rpc_run_task(&task_setup_data);
|
||||||
if (IS_ERR(task))
|
if (IS_ERR(task))
|
||||||
return PTR_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,
|
.rpc_cred = cred,
|
||||||
};
|
};
|
||||||
unsigned long timestamp = jiffies;
|
unsigned long timestamp = jiffies;
|
||||||
|
fmode_t fmode;
|
||||||
|
bool truncate;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
nfs_fattr_init(fattr);
|
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 = {
|
struct nfs_lockowner lockowner = {
|
||||||
.l_owner = current->files,
|
.l_owner = current->files,
|
||||||
.l_pid = current->tgid,
|
.l_pid = current->tgid,
|
||||||
};
|
};
|
||||||
nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
|
nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
|
||||||
&lockowner);
|
&lockowner);
|
||||||
} else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
|
|
||||||
FMODE_WRITE)) {
|
|
||||||
/* Use that stateid */
|
|
||||||
} else
|
} else
|
||||||
nfs4_stateid_copy(&arg.stateid, &zero_stateid);
|
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);
|
err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case -NFS4ERR_OPENMODE:
|
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)) {
|
if (state && !(state->state & FMODE_WRITE)) {
|
||||||
err = -EBADF;
|
err = -EBADF;
|
||||||
if (sattr->ia_valid & ATTR_OPEN)
|
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);
|
auth = rpcauth_create(flavor, server->client);
|
||||||
if (IS_ERR(auth)) {
|
if (IS_ERR(auth)) {
|
||||||
ret = -EIO;
|
ret = -EACCES;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
ret = nfs4_lookup_root(server, fhandle, info);
|
ret = nfs4_lookup_root(server, fhandle, info);
|
||||||
@ -2544,27 +2568,36 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
|
|||||||
return ret;
|
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,
|
static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
struct nfs_fsinfo *info)
|
struct nfs_fsinfo *info)
|
||||||
{
|
{
|
||||||
int i, len, status = 0;
|
/* Per 3530bis 15.33.5 */
|
||||||
rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
|
static const rpc_authflavor_t flav_array[] = {
|
||||||
|
RPC_AUTH_GSS_KRB5P,
|
||||||
len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array));
|
RPC_AUTH_GSS_KRB5I,
|
||||||
if (len < 0)
|
RPC_AUTH_GSS_KRB5,
|
||||||
return len;
|
RPC_AUTH_UNIX, /* courtesy */
|
||||||
|
RPC_AUTH_NULL,
|
||||||
for (i = 0; i < len; i++) {
|
};
|
||||||
/* AUTH_UNIX is the default flavor if none was specified,
|
int status = -EPERM;
|
||||||
* thus has already been tried. */
|
size_t i;
|
||||||
if (flav_array[i] == RPC_AUTH_UNIX)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
|
||||||
status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
|
status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
|
||||||
if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
|
if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* -EACCESS could mean that the user doesn't have correct permissions
|
* -EACCESS could mean that the user doesn't have correct permissions
|
||||||
* to access the mount. It could also mean that we tried to mount
|
* 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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int nfs4_do_find_root_sec(struct nfs_server *server,
|
||||||
* get the file handle for the "/" directory on the 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,
|
int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
struct nfs_fsinfo *info)
|
struct nfs_fsinfo *info)
|
||||||
{
|
{
|
||||||
int minor_version = server->nfs_client->cl_minorversion;
|
int status;
|
||||||
int status = nfs4_lookup_root(server, fhandle, info);
|
|
||||||
if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
|
status = nfs4_lookup_root(server, fhandle, info);
|
||||||
/*
|
if ((status == -NFS4ERR_WRONGSEC) &&
|
||||||
* A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
|
!(server->flags & NFS_MOUNT_SECFLAVOUR))
|
||||||
* by nfs4_map_errors() as this function exits.
|
status = nfs4_do_find_root_sec(server, fhandle, info);
|
||||||
*/
|
|
||||||
status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
|
|
||||||
if (status == 0)
|
if (status == 0)
|
||||||
status = nfs4_server_capabilities(server, fhandle);
|
status = nfs4_server_capabilities(server, fhandle);
|
||||||
if (status == 0)
|
if (status == 0)
|
||||||
status = nfs4_do_fsinfo(server, fhandle, info);
|
status = nfs4_do_fsinfo(server, fhandle, info);
|
||||||
|
|
||||||
return nfs4_map_errors(status);
|
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)
|
static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
|
||||||
{
|
{
|
||||||
struct nfs4_exception exception = { };
|
struct nfs4_exception exception = { };
|
||||||
|
unsigned long now = jiffies;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
err = nfs4_handle_exception(server,
|
err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
|
||||||
_nfs4_do_fsinfo(server, fhandle, fsinfo),
|
if (err == 0) {
|
||||||
&exception);
|
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);
|
} while (exception.retry);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -4319,27 +4373,17 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
|
|||||||
struct nfs4_setclientid_res *arg,
|
struct nfs4_setclientid_res *arg,
|
||||||
struct rpc_cred *cred)
|
struct rpc_cred *cred)
|
||||||
{
|
{
|
||||||
struct nfs_fsinfo fsinfo;
|
|
||||||
struct rpc_message msg = {
|
struct rpc_message msg = {
|
||||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
|
||||||
.rpc_argp = arg,
|
.rpc_argp = arg,
|
||||||
.rpc_resp = &fsinfo,
|
|
||||||
.rpc_cred = cred,
|
.rpc_cred = cred,
|
||||||
};
|
};
|
||||||
unsigned long now;
|
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n",
|
dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n",
|
||||||
clp->cl_rpcclient->cl_auth->au_ops->au_name,
|
clp->cl_rpcclient->cl_auth->au_ops->au_name,
|
||||||
clp->cl_clientid);
|
clp->cl_clientid);
|
||||||
now = jiffies;
|
|
||||||
status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
|
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);
|
dprintk("NFS reply setclientid_confirm: %d\n", status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -154,18 +154,6 @@ struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
|
|||||||
return cred;
|
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 *
|
static struct rpc_cred *
|
||||||
nfs4_get_renew_cred_server_locked(struct nfs_server *server)
|
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);
|
clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
case -EACCES:
|
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 -NFS4ERR_DELAY:
|
||||||
case -ETIMEDOUT:
|
case -ETIMEDOUT:
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
@ -1874,31 +1858,18 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
|
|||||||
{
|
{
|
||||||
const struct nfs4_state_recovery_ops *ops =
|
const struct nfs4_state_recovery_ops *ops =
|
||||||
clp->cl_mvops->reboot_recovery_ops;
|
clp->cl_mvops->reboot_recovery_ops;
|
||||||
rpc_authflavor_t *flavors, flav, save;
|
|
||||||
struct rpc_clnt *clnt;
|
struct rpc_clnt *clnt;
|
||||||
struct rpc_cred *cred;
|
struct rpc_cred *cred;
|
||||||
int i, len, status;
|
int i, status;
|
||||||
|
|
||||||
dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname);
|
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;
|
clnt = clp->cl_rpcclient;
|
||||||
save = clnt->cl_auth->au_flavor;
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
mutex_lock(&nfs_clid_init_mutex);
|
mutex_lock(&nfs_clid_init_mutex);
|
||||||
status = -ENOENT;
|
|
||||||
again:
|
again:
|
||||||
|
status = -ENOENT;
|
||||||
cred = ops->get_clid_cred(clp);
|
cred = ops->get_clid_cred(clp);
|
||||||
if (cred == NULL)
|
if (cred == NULL)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
@ -1908,12 +1879,6 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
|
|||||||
switch (status) {
|
switch (status) {
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
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 -NFS4ERR_DELAY:
|
||||||
case -ETIMEDOUT:
|
case -ETIMEDOUT:
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
@ -1922,22 +1887,23 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
|
|||||||
dprintk("NFS: %s after status %d, retrying\n",
|
dprintk("NFS: %s after status %d, retrying\n",
|
||||||
__func__, status);
|
__func__, status);
|
||||||
goto again;
|
goto again;
|
||||||
|
case -EACCES:
|
||||||
|
if (i++)
|
||||||
|
break;
|
||||||
case -NFS4ERR_CLID_INUSE:
|
case -NFS4ERR_CLID_INUSE:
|
||||||
case -NFS4ERR_WRONGSEC:
|
case -NFS4ERR_WRONGSEC:
|
||||||
status = -EPERM;
|
clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX);
|
||||||
if (i >= len)
|
|
||||||
break;
|
|
||||||
|
|
||||||
flav = flavors[i++];
|
|
||||||
if (flav == save)
|
|
||||||
flav = flavors[i++];
|
|
||||||
clnt = rpc_clone_client_set_auth(clnt, flav);
|
|
||||||
if (IS_ERR(clnt)) {
|
if (IS_ERR(clnt)) {
|
||||||
status = PTR_ERR(clnt);
|
status = PTR_ERR(clnt);
|
||||||
break;
|
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;
|
goto again;
|
||||||
|
|
||||||
case -NFS4ERR_MINOR_VERS_MISMATCH:
|
case -NFS4ERR_MINOR_VERS_MISMATCH:
|
||||||
@ -1948,13 +1914,15 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
|
|||||||
case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
|
case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
|
||||||
* in nfs4_exchange_id */
|
* in nfs4_exchange_id */
|
||||||
status = -EKEYEXPIRED;
|
status = -EKEYEXPIRED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_warn("NFS: %s unhandled error %d. Exiting with error EIO\n",
|
||||||
|
__func__, status);
|
||||||
|
status = -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&nfs_clid_init_mutex);
|
mutex_unlock(&nfs_clid_init_mutex);
|
||||||
out_free:
|
|
||||||
kfree(flavors);
|
|
||||||
out:
|
|
||||||
dprintk("NFS: %s: status = %d\n", __func__, status);
|
dprintk("NFS: %s: status = %d\n", __func__, status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -252,6 +252,8 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
|
|||||||
|
|
||||||
dfprintk(MOUNT, "--> nfs4_try_mount()\n");
|
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;
|
export_path = data->nfs_server.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,
|
root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
|
||||||
|
@ -530,14 +530,10 @@ static int nfs4_stat_to_errno(int);
|
|||||||
decode_setclientid_maxsz)
|
decode_setclientid_maxsz)
|
||||||
#define NFS4_enc_setclientid_confirm_sz \
|
#define NFS4_enc_setclientid_confirm_sz \
|
||||||
(compound_encode_hdr_maxsz + \
|
(compound_encode_hdr_maxsz + \
|
||||||
encode_setclientid_confirm_maxsz + \
|
encode_setclientid_confirm_maxsz)
|
||||||
encode_putrootfh_maxsz + \
|
|
||||||
encode_fsinfo_maxsz)
|
|
||||||
#define NFS4_dec_setclientid_confirm_sz \
|
#define NFS4_dec_setclientid_confirm_sz \
|
||||||
(compound_decode_hdr_maxsz + \
|
(compound_decode_hdr_maxsz + \
|
||||||
decode_setclientid_confirm_maxsz + \
|
decode_setclientid_confirm_maxsz)
|
||||||
decode_putrootfh_maxsz + \
|
|
||||||
decode_fsinfo_maxsz)
|
|
||||||
#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \
|
#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \
|
||||||
encode_sequence_maxsz + \
|
encode_sequence_maxsz + \
|
||||||
encode_putfh_maxsz + \
|
encode_putfh_maxsz + \
|
||||||
@ -2601,12 +2597,9 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
|
|||||||
struct compound_hdr hdr = {
|
struct compound_hdr hdr = {
|
||||||
.nops = 0,
|
.nops = 0,
|
||||||
};
|
};
|
||||||
const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
|
|
||||||
|
|
||||||
encode_compound_hdr(xdr, req, &hdr);
|
encode_compound_hdr(xdr, req, &hdr);
|
||||||
encode_setclientid_confirm(xdr, arg, &hdr);
|
encode_setclientid_confirm(xdr, arg, &hdr);
|
||||||
encode_putrootfh(xdr, &hdr);
|
|
||||||
encode_fsinfo(xdr, lease_bitmap, &hdr);
|
|
||||||
encode_nops(&hdr);
|
encode_nops(&hdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5198,27 +5191,30 @@ static int decode_delegreturn(struct xdr_stream *xdr)
|
|||||||
return decode_op_hdr(xdr, OP_DELEGRETURN);
|
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;
|
__be32 *p;
|
||||||
|
|
||||||
p = xdr_inline_decode(xdr, 4);
|
p = xdr_inline_decode(xdr, 4);
|
||||||
if (unlikely(!p))
|
if (unlikely(!p))
|
||||||
goto out_overflow;
|
goto out_overflow;
|
||||||
flavor->gss.sec_oid4.len = be32_to_cpup(p);
|
oid_len = be32_to_cpup(p);
|
||||||
if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN)
|
if (oid_len > GSS_OID_MAX_LEN)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len);
|
p = xdr_inline_decode(xdr, oid_len);
|
||||||
if (unlikely(!p))
|
if (unlikely(!p))
|
||||||
goto out_overflow;
|
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);
|
p = xdr_inline_decode(xdr, 8);
|
||||||
if (unlikely(!p))
|
if (unlikely(!p))
|
||||||
goto out_overflow;
|
goto out_overflow;
|
||||||
flavor->gss.qop4 = be32_to_cpup(p++);
|
flavor->flavor_info.qop = be32_to_cpup(p++);
|
||||||
flavor->gss.service = be32_to_cpup(p);
|
flavor->flavor_info.service = be32_to_cpup(p);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -5231,10 +5227,10 @@ static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor
|
|||||||
|
|
||||||
static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
|
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;
|
int status;
|
||||||
__be32 *p;
|
__be32 *p;
|
||||||
int i, num_flavors;
|
|
||||||
|
|
||||||
p = xdr_inline_decode(xdr, 4);
|
p = xdr_inline_decode(xdr, 4);
|
||||||
if (unlikely(!p))
|
if (unlikely(!p))
|
||||||
@ -6637,8 +6633,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
|
|||||||
* Decode SETCLIENTID_CONFIRM response
|
* Decode SETCLIENTID_CONFIRM response
|
||||||
*/
|
*/
|
||||||
static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
|
static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
|
||||||
struct xdr_stream *xdr,
|
struct xdr_stream *xdr)
|
||||||
struct nfs_fsinfo *fsinfo)
|
|
||||||
{
|
{
|
||||||
struct compound_hdr hdr;
|
struct compound_hdr hdr;
|
||||||
int status;
|
int status;
|
||||||
@ -6646,10 +6641,6 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
|
|||||||
status = decode_compound_hdr(xdr, &hdr);
|
status = decode_compound_hdr(xdr, &hdr);
|
||||||
if (!status)
|
if (!status)
|
||||||
status = decode_setclientid_confirm(xdr);
|
status = decode_setclientid_confirm(xdr);
|
||||||
if (!status)
|
|
||||||
status = decode_putrootfh(xdr);
|
|
||||||
if (!status)
|
|
||||||
status = decode_fsinfo(xdr, fsinfo);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,7 +920,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
|
|||||||
data->mount_server.port = NFS_UNSPEC_PORT;
|
data->mount_server.port = NFS_UNSPEC_PORT;
|
||||||
data->nfs_server.port = NFS_UNSPEC_PORT;
|
data->nfs_server.port = NFS_UNSPEC_PORT;
|
||||||
data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
|
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->auth_flavor_len = 1;
|
||||||
data->minorversion = 0;
|
data->minorversion = 0;
|
||||||
data->need_mount = true;
|
data->need_mount = true;
|
||||||
@ -1608,49 +1608,57 @@ static int nfs_parse_mount_options(char *raw,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Match the requested auth flavors with the list returned by
|
* Select a security flavor for this mount. The selected flavor
|
||||||
* the server. Returns zero and sets the mount's authentication
|
* is planted in args->auth_flavors[0].
|
||||||
* flavor on success; returns -EACCES if server does not support
|
|
||||||
* the requested flavor.
|
|
||||||
*/
|
*/
|
||||||
static int nfs_walk_authlist(struct nfs_parsed_mount_data *args,
|
static void nfs_select_flavor(struct nfs_parsed_mount_data *args,
|
||||||
struct nfs_mount_request *request)
|
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
|
* Certain releases of Linux's mountd return an empty
|
||||||
* flavor list. To prevent behavioral regression with
|
* flavor list in some cases.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
if (server_authlist_len == 0)
|
if (count == 0)
|
||||||
return 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
|
* RFC 2623, section 2.7 suggests we SHOULD prefer the
|
||||||
* flavor listed first. However, some servers list
|
* flavor listed first. However, some servers list
|
||||||
* AUTH_NULL first. Our caller plants AUTH_SYS, the
|
* AUTH_NULL first. Avoid ever choosing AUTH_NULL.
|
||||||
* preferred default, in args->auth_flavors[0] if user
|
|
||||||
* didn't specify sec= mount option.
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < args->auth_flavor_len; i++)
|
for (i = 0; i < count; i++) {
|
||||||
for (j = 0; j < server_authlist_len; j++)
|
struct rpcsec_gss_info info;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n");
|
flavor = request->auth_flavs[i];
|
||||||
nfs_umount(request);
|
switch (flavor) {
|
||||||
return -EACCES;
|
case RPC_AUTH_UNIX:
|
||||||
|
goto out_set;
|
||||||
|
case RPC_AUTH_NULL:
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
if (rpcauth_get_gssinfo(flavor, &info) == 0)
|
||||||
|
goto out_set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
nfs_select_flavor(args, &request);
|
||||||
* MNTv1 (NFSv2) does not support auth flavor negotiation.
|
return 0;
|
||||||
*/
|
|
||||||
if (args->mount_server.version != NFS_MNT3_VERSION)
|
|
||||||
return 0;
|
|
||||||
return nfs_walk_authlist(args, &request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dentry *nfs_try_mount(int flags, const char *dev_name,
|
struct dentry *nfs_try_mount(int flags, const char *dev_name,
|
||||||
|
@ -3083,10 +3083,9 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
|
|||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
|
nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
|
||||||
__be32 nfserr,struct svc_export *exp)
|
__be32 nfserr, struct svc_export *exp)
|
||||||
{
|
{
|
||||||
int i = 0;
|
u32 i, nflavs;
|
||||||
u32 nflavs;
|
|
||||||
struct exp_flavor_info *flavs;
|
struct exp_flavor_info *flavs;
|
||||||
struct exp_flavor_info def_flavs[2];
|
struct exp_flavor_info def_flavs[2];
|
||||||
__be32 *p;
|
__be32 *p;
|
||||||
@ -3117,30 +3116,29 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
|
|||||||
WRITE32(nflavs);
|
WRITE32(nflavs);
|
||||||
ADJUST_ARGS();
|
ADJUST_ARGS();
|
||||||
for (i = 0; i < nflavs; i++) {
|
for (i = 0; i < nflavs; i++) {
|
||||||
u32 flav = flavs[i].pseudoflavor;
|
struct rpcsec_gss_info info;
|
||||||
struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
|
|
||||||
|
|
||||||
if (gm) {
|
if (rpcauth_get_gssinfo(flavs[i].pseudoflavor, &info) == 0) {
|
||||||
RESERVE_SPACE(4);
|
RESERVE_SPACE(4);
|
||||||
WRITE32(RPC_AUTH_GSS);
|
WRITE32(RPC_AUTH_GSS);
|
||||||
ADJUST_ARGS();
|
ADJUST_ARGS();
|
||||||
RESERVE_SPACE(4 + gm->gm_oid.len);
|
RESERVE_SPACE(4 + info.oid.len);
|
||||||
WRITE32(gm->gm_oid.len);
|
WRITE32(info.oid.len);
|
||||||
WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
|
WRITEMEM(info.oid.data, info.oid.len);
|
||||||
ADJUST_ARGS();
|
ADJUST_ARGS();
|
||||||
RESERVE_SPACE(4);
|
RESERVE_SPACE(4);
|
||||||
WRITE32(0); /* qop */
|
WRITE32(info.qop);
|
||||||
ADJUST_ARGS();
|
ADJUST_ARGS();
|
||||||
RESERVE_SPACE(4);
|
RESERVE_SPACE(4);
|
||||||
WRITE32(gss_pseudoflavor_to_service(gm, flav));
|
WRITE32(info.service);
|
||||||
ADJUST_ARGS();
|
ADJUST_ARGS();
|
||||||
gss_mech_put(gm);
|
|
||||||
} else {
|
} else {
|
||||||
RESERVE_SPACE(4);
|
RESERVE_SPACE(4);
|
||||||
WRITE32(flav);
|
WRITE32(flavs[i].pseudoflavor);
|
||||||
ADJUST_ARGS();
|
ADJUST_ARGS();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (exp)
|
if (exp)
|
||||||
exp_put(exp);
|
exp_put(exp);
|
||||||
|
@ -14,9 +14,6 @@
|
|||||||
#define NFS_DEF_FILE_IO_SIZE (4096U)
|
#define NFS_DEF_FILE_IO_SIZE (4096U)
|
||||||
#define NFS_MIN_FILE_IO_SIZE (1024U)
|
#define NFS_MIN_FILE_IO_SIZE (1024U)
|
||||||
|
|
||||||
/* Forward declaration for NFS v3 */
|
|
||||||
struct nfs4_secinfo_flavors;
|
|
||||||
|
|
||||||
struct nfs4_string {
|
struct nfs4_string {
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
char *data;
|
char *data;
|
||||||
@ -1053,25 +1050,14 @@ struct nfs4_fs_locations_res {
|
|||||||
struct nfs4_fs_locations *fs_locations;
|
struct nfs4_fs_locations *fs_locations;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nfs4_secinfo_oid {
|
struct nfs4_secinfo4 {
|
||||||
unsigned int len;
|
u32 flavor;
|
||||||
char data[GSS_OID_MAX_LEN];
|
struct rpcsec_gss_info flavor_info;
|
||||||
};
|
|
||||||
|
|
||||||
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_secinfo_flavors {
|
struct nfs4_secinfo_flavors {
|
||||||
unsigned int num_flavors;
|
unsigned int num_flavors;
|
||||||
struct nfs4_secinfo_flavor flavors[0];
|
struct nfs4_secinfo4 flavors[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nfs4_secinfo_arg {
|
struct nfs4_secinfo_arg {
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
/* size of the nodename buffer */
|
/* size of the nodename buffer */
|
||||||
#define UNX_MAXNODENAME 32
|
#define UNX_MAXNODENAME 32
|
||||||
|
|
||||||
|
struct rpcsec_gss_info;
|
||||||
|
|
||||||
/* Work around the lack of a VFS credential */
|
/* Work around the lack of a VFS credential */
|
||||||
struct auth_cred {
|
struct auth_cred {
|
||||||
kuid_t uid;
|
kuid_t uid;
|
||||||
@ -103,6 +105,9 @@ struct rpc_authops {
|
|||||||
int (*pipes_create)(struct rpc_auth *);
|
int (*pipes_create)(struct rpc_auth *);
|
||||||
void (*pipes_destroy)(struct rpc_auth *);
|
void (*pipes_destroy)(struct rpc_auth *);
|
||||||
int (*list_pseudoflavors)(rpc_authflavor_t *, int);
|
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 {
|
struct rpc_credops {
|
||||||
@ -137,6 +142,10 @@ int rpcauth_register(const struct rpc_authops *);
|
|||||||
int rpcauth_unregister(const struct rpc_authops *);
|
int rpcauth_unregister(const struct rpc_authops *);
|
||||||
struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
|
struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
|
||||||
void rpcauth_release(struct rpc_auth *);
|
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);
|
int rpcauth_list_flavors(rpc_authflavor_t *, int);
|
||||||
struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, 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 *);
|
void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
|
||||||
|
@ -25,10 +25,21 @@ struct gss_ctx {
|
|||||||
|
|
||||||
#define GSS_C_NO_BUFFER ((struct xdr_netobj) 0)
|
#define GSS_C_NO_BUFFER ((struct xdr_netobj) 0)
|
||||||
#define GSS_C_NO_CONTEXT ((struct gss_ctx *) 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? */
|
/*XXX arbitrary length - is this set somewhere? */
|
||||||
#define GSS_OID_MAX_LEN 32
|
#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
|
/* gss-api prototypes; note that these are somewhat simplified versions of
|
||||||
* the prototypes specified in RFC 2744. */
|
* the prototypes specified in RFC 2744. */
|
||||||
@ -59,12 +70,14 @@ u32 gss_unwrap(
|
|||||||
u32 gss_delete_sec_context(
|
u32 gss_delete_sec_context(
|
||||||
struct gss_ctx **ctx_id);
|
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);
|
u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor);
|
||||||
char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service);
|
char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service);
|
||||||
|
|
||||||
struct pf_desc {
|
struct pf_desc {
|
||||||
u32 pseudoflavor;
|
u32 pseudoflavor;
|
||||||
|
u32 qop;
|
||||||
u32 service;
|
u32 service;
|
||||||
char *name;
|
char *name;
|
||||||
char *auth_domain_name;
|
char *auth_domain_name;
|
||||||
@ -77,7 +90,7 @@ struct pf_desc {
|
|||||||
struct gss_api_mech {
|
struct gss_api_mech {
|
||||||
struct list_head gm_list;
|
struct list_head gm_list;
|
||||||
struct module *gm_owner;
|
struct module *gm_owner;
|
||||||
struct xdr_netobj gm_oid;
|
struct rpcsec_gss_oid gm_oid;
|
||||||
char *gm_name;
|
char *gm_name;
|
||||||
const struct gss_api_ops *gm_ops;
|
const struct gss_api_ops *gm_ops;
|
||||||
/* pseudoflavors supported by this mechanism: */
|
/* 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
|
/* returns a mechanism descriptor given an OID, and increments the mechanism's
|
||||||
* reference count. */
|
* 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. */
|
/* Returns a reference to a mechanism, given a name like "krb5" etc. */
|
||||||
struct gss_api_mech *gss_mech_get_by_name(const char *);
|
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 */
|
/* Fill in an array with a list of supported pseudoflavors */
|
||||||
int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int);
|
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
|
/* For every successful gss_mech_get or gss_mech_get_by_* call there must be a
|
||||||
* corresponding call to gss_mech_put. */
|
* corresponding call to gss_mech_put. */
|
||||||
void gss_mech_put(struct gss_api_mech *);
|
void gss_mech_put(struct gss_api_mech *);
|
||||||
|
@ -3,6 +3,7 @@ config SUNRPC
|
|||||||
|
|
||||||
config SUNRPC_GSS
|
config SUNRPC_GSS
|
||||||
tristate
|
tristate
|
||||||
|
select OID_REGISTRY
|
||||||
|
|
||||||
config SUNRPC_BACKCHANNEL
|
config SUNRPC_BACKCHANNEL
|
||||||
bool
|
bool
|
||||||
|
@ -82,7 +82,7 @@ MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
|
|||||||
|
|
||||||
static u32
|
static u32
|
||||||
pseudoflavor_to_flavor(u32 flavor) {
|
pseudoflavor_to_flavor(u32 flavor) {
|
||||||
if (flavor >= RPC_AUTH_MAXFLAVOR)
|
if (flavor > RPC_AUTH_MAXFLAVOR)
|
||||||
return RPC_AUTH_GSS;
|
return RPC_AUTH_GSS;
|
||||||
return flavor;
|
return flavor;
|
||||||
}
|
}
|
||||||
@ -123,6 +123,79 @@ rpcauth_unregister(const struct rpc_authops *ops)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rpcauth_unregister);
|
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
|
* rpcauth_list_flavors - discover registered flavors and pseudoflavors
|
||||||
* @array: array to fill in
|
* @array: array to fill in
|
||||||
|
@ -1641,6 +1641,8 @@ static const struct rpc_authops authgss_ops = {
|
|||||||
.pipes_create = gss_pipes_dentries_create,
|
.pipes_create = gss_pipes_dentries_create,
|
||||||
.pipes_destroy = gss_pipes_dentries_destroy,
|
.pipes_destroy = gss_pipes_dentries_destroy,
|
||||||
.list_pseudoflavors = gss_mech_list_pseudoflavors,
|
.list_pseudoflavors = gss_mech_list_pseudoflavors,
|
||||||
|
.info2flavor = gss_mech_info2flavor,
|
||||||
|
.flavor2info = gss_mech_flavor2info,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct rpc_credops gss_credops = {
|
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 */
|
rcu_barrier(); /* Wait for completion of call_rcu()'s */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MODULE_ALIAS("rpc-auth-6");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
module_param_named(expired_cred_retry_delay,
|
module_param_named(expired_cred_retry_delay,
|
||||||
gss_expired_cred_retry_delay,
|
gss_expired_cred_retry_delay,
|
||||||
|
@ -732,16 +732,19 @@ static const struct gss_api_ops gss_kerberos_ops = {
|
|||||||
static struct pf_desc gss_kerberos_pfs[] = {
|
static struct pf_desc gss_kerberos_pfs[] = {
|
||||||
[0] = {
|
[0] = {
|
||||||
.pseudoflavor = RPC_AUTH_GSS_KRB5,
|
.pseudoflavor = RPC_AUTH_GSS_KRB5,
|
||||||
|
.qop = GSS_C_QOP_DEFAULT,
|
||||||
.service = RPC_GSS_SVC_NONE,
|
.service = RPC_GSS_SVC_NONE,
|
||||||
.name = "krb5",
|
.name = "krb5",
|
||||||
},
|
},
|
||||||
[1] = {
|
[1] = {
|
||||||
.pseudoflavor = RPC_AUTH_GSS_KRB5I,
|
.pseudoflavor = RPC_AUTH_GSS_KRB5I,
|
||||||
|
.qop = GSS_C_QOP_DEFAULT,
|
||||||
.service = RPC_GSS_SVC_INTEGRITY,
|
.service = RPC_GSS_SVC_INTEGRITY,
|
||||||
.name = "krb5i",
|
.name = "krb5i",
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
.pseudoflavor = RPC_AUTH_GSS_KRB5P,
|
.pseudoflavor = RPC_AUTH_GSS_KRB5P,
|
||||||
|
.qop = GSS_C_QOP_DEFAULT,
|
||||||
.service = RPC_GSS_SVC_PRIVACY,
|
.service = RPC_GSS_SVC_PRIVACY,
|
||||||
.name = "krb5p",
|
.name = "krb5p",
|
||||||
},
|
},
|
||||||
@ -753,11 +756,12 @@ MODULE_ALIAS("rpc-auth-gss-krb5p");
|
|||||||
MODULE_ALIAS("rpc-auth-gss-390003");
|
MODULE_ALIAS("rpc-auth-gss-390003");
|
||||||
MODULE_ALIAS("rpc-auth-gss-390004");
|
MODULE_ALIAS("rpc-auth-gss-390004");
|
||||||
MODULE_ALIAS("rpc-auth-gss-390005");
|
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 = {
|
static struct gss_api_mech gss_kerberos_mech = {
|
||||||
.gm_name = "krb5",
|
.gm_name = "krb5",
|
||||||
.gm_owner = THIS_MODULE,
|
.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_ops = &gss_kerberos_ops,
|
||||||
.gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs),
|
.gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs),
|
||||||
.gm_pfs = gss_kerberos_pfs,
|
.gm_pfs = gss_kerberos_pfs,
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/oid_registry.h>
|
||||||
#include <linux/sunrpc/msg_prot.h>
|
#include <linux/sunrpc/msg_prot.h>
|
||||||
#include <linux/sunrpc/gss_asn1.h>
|
#include <linux/sunrpc/gss_asn1.h>
|
||||||
#include <linux/sunrpc/auth_gss.h>
|
#include <linux/sunrpc/auth_gss.h>
|
||||||
@ -102,8 +103,13 @@ gss_mech_svc_setup(struct gss_api_mech *gm)
|
|||||||
return status;
|
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;
|
int status;
|
||||||
|
|
||||||
@ -116,11 +122,14 @@ gss_mech_register(struct gss_api_mech *gm)
|
|||||||
dprintk("RPC: registered gss mechanism %s\n", gm->gm_name);
|
dprintk("RPC: registered gss mechanism %s\n", gm->gm_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(gss_mech_register);
|
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(®istered_mechs_lock);
|
spin_lock(®istered_mechs_lock);
|
||||||
list_del(&gm->gm_list);
|
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);
|
dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name);
|
||||||
gss_mech_free(gm);
|
gss_mech_free(gm);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(gss_mech_unregister);
|
EXPORT_SYMBOL_GPL(gss_mech_unregister);
|
||||||
|
|
||||||
struct gss_api_mech *
|
static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm)
|
||||||
gss_mech_get(struct gss_api_mech *gm)
|
|
||||||
{
|
{
|
||||||
__module_get(gm->gm_owner);
|
__module_get(gm->gm_owner);
|
||||||
return gm;
|
return gm;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(gss_mech_get);
|
|
||||||
|
|
||||||
static struct gss_api_mech *
|
static struct gss_api_mech *
|
||||||
_gss_mech_get_by_name(const char *name)
|
_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;
|
return gm;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
|
|
||||||
|
|
||||||
struct gss_api_mech *
|
struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
|
||||||
gss_mech_get_by_OID(struct xdr_netobj *obj)
|
|
||||||
{
|
{
|
||||||
struct gss_api_mech *pos, *gm = NULL;
|
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(®istered_mechs_lock);
|
spin_lock(®istered_mechs_lock);
|
||||||
list_for_each_entry(pos, ®istered_mechs, gm_list) {
|
list_for_each_entry(pos, ®istered_mechs, gm_list) {
|
||||||
@ -188,11 +197,8 @@ gss_mech_get_by_OID(struct xdr_netobj *obj)
|
|||||||
}
|
}
|
||||||
spin_unlock(®istered_mechs_lock);
|
spin_unlock(®istered_mechs_lock);
|
||||||
return gm;
|
return gm;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(gss_mech_get_by_OID);
|
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
|
mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
|
||||||
{
|
{
|
||||||
@ -237,8 +243,6 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
|
|||||||
return gm;
|
return gm;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors
|
* gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors
|
||||||
* @array: array to fill in
|
* @array: array to fill in
|
||||||
@ -268,19 +272,82 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size)
|
|||||||
return i;
|
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;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < gm->gm_pf_num; 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 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
|
u32
|
||||||
gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service);
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
gss_mech_put(struct gss_api_mech * gm)
|
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);
|
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
|
/* The mech could probably be determined from the token instead, but it's just
|
||||||
* as easy for now to pass it in. */
|
* as easy for now to pass it in. */
|
||||||
int
|
int
|
||||||
|
@ -220,7 +220,6 @@ static int gssp_call(struct net *net, struct rpc_message *msg)
|
|||||||
|
|
||||||
/* numbers somewhat arbitrary but large enough for current needs */
|
/* numbers somewhat arbitrary but large enough for current needs */
|
||||||
#define GSSX_MAX_OUT_HANDLE 128
|
#define GSSX_MAX_OUT_HANDLE 128
|
||||||
#define GSSX_MAX_MECH_OID 16
|
|
||||||
#define GSSX_MAX_SRC_PRINC 256
|
#define GSSX_MAX_SRC_PRINC 256
|
||||||
#define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \
|
#define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \
|
||||||
GSSX_max_oid_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:
|
* buffers but let the xdr code kmalloc them:
|
||||||
*/
|
*/
|
||||||
.exported_context_token.len = GSSX_max_output_handle_sz,
|
.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
|
.src_name.display_name.len = GSSX_max_princ_sz
|
||||||
};
|
};
|
||||||
struct gssx_res_accept_sec_context res = {
|
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;
|
data->minor_status = res.status.minor_status;
|
||||||
if (res.context_handle) {
|
if (res.context_handle) {
|
||||||
data->out_handle = rctxh.exported_context_token;
|
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;
|
client_name = rctxh.src_name.display_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#ifndef _GSS_RPC_UPCALL_H
|
#ifndef _GSS_RPC_UPCALL_H
|
||||||
#define _GSS_RPC_UPCALL_H
|
#define _GSS_RPC_UPCALL_H
|
||||||
|
|
||||||
|
#include <linux/sunrpc/gss_api.h>
|
||||||
#include <linux/sunrpc/auth_gss.h>
|
#include <linux/sunrpc/auth_gss.h>
|
||||||
#include "gss_rpc_xdr.h"
|
#include "gss_rpc_xdr.h"
|
||||||
#include "../netns.h"
|
#include "../netns.h"
|
||||||
@ -30,7 +31,7 @@ struct gssp_upcall_data {
|
|||||||
struct gssp_in_token in_token;
|
struct gssp_in_token in_token;
|
||||||
struct xdr_netobj out_handle;
|
struct xdr_netobj out_handle;
|
||||||
struct xdr_netobj out_token;
|
struct xdr_netobj out_token;
|
||||||
struct xdr_netobj mech_oid;
|
struct rpcsec_gss_oid mech_oid;
|
||||||
struct svc_cred creds;
|
struct svc_cred creds;
|
||||||
int found_creds;
|
int found_creds;
|
||||||
int major_status;
|
int major_status;
|
||||||
|
@ -1544,7 +1544,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
|
|||||||
svcdata->rsci = rsci;
|
svcdata->rsci = rsci;
|
||||||
cache_get(&rsci->h);
|
cache_get(&rsci->h);
|
||||||
rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor(
|
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;
|
ret = SVC_OK;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -304,10 +304,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
|
|||||||
err = rpciod_up();
|
err = rpciod_up();
|
||||||
if (err)
|
if (err)
|
||||||
goto out_no_rpciod;
|
goto out_no_rpciod;
|
||||||
err = -EINVAL;
|
|
||||||
if (!xprt)
|
|
||||||
goto out_no_xprt;
|
|
||||||
|
|
||||||
|
err = -EINVAL;
|
||||||
if (args->version >= program->nrvers)
|
if (args->version >= program->nrvers)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
version = program->version[args->version];
|
version = program->version[args->version];
|
||||||
@ -382,10 +380,9 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
|
|||||||
out_no_stats:
|
out_no_stats:
|
||||||
kfree(clnt);
|
kfree(clnt);
|
||||||
out_err:
|
out_err:
|
||||||
xprt_put(xprt);
|
|
||||||
out_no_xprt:
|
|
||||||
rpciod_down();
|
rpciod_down();
|
||||||
out_no_rpciod:
|
out_no_rpciod:
|
||||||
|
xprt_put(xprt);
|
||||||
return ERR_PTR(err);
|
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);
|
new = rpc_new_client(args, xprt);
|
||||||
if (IS_ERR(new)) {
|
if (IS_ERR(new)) {
|
||||||
err = PTR_ERR(new);
|
err = PTR_ERR(new);
|
||||||
goto out_put;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_inc(&clnt->cl_count);
|
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;
|
new->cl_chatty = clnt->cl_chatty;
|
||||||
return new;
|
return new;
|
||||||
|
|
||||||
out_put:
|
|
||||||
xprt_put(xprt);
|
|
||||||
out_err:
|
out_err:
|
||||||
dprintk("RPC: %s: returned error %d\n", __func__, err);
|
dprintk("RPC: %s: returned error %d\n", __func__, err);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
Loading…
Reference in New Issue
Block a user