mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
nfsd4: implement minimal SP4_MACH_CRED
Do a minimal SP4_MACH_CRED implementation suggested by Trond, ignoring the client-provided spo_must_* arrays and just enforcing credential checks for the minimum required operations. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
0dc1531aca
commit
57266a6e91
3 changed files with 87 additions and 12 deletions
|
@ -1265,6 +1265,31 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
|
||||||
return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
|
return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
|
||||||
|
{
|
||||||
|
struct svc_cred *cr = &rqstp->rq_cred;
|
||||||
|
u32 service;
|
||||||
|
|
||||||
|
service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
|
||||||
|
return service == RPC_GSS_SVC_INTEGRITY ||
|
||||||
|
service == RPC_GSS_SVC_PRIVACY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
|
||||||
|
{
|
||||||
|
struct svc_cred *cr = &rqstp->rq_cred;
|
||||||
|
|
||||||
|
if (!cl->cl_mach_cred)
|
||||||
|
return true;
|
||||||
|
if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
|
||||||
|
return false;
|
||||||
|
if (!svc_rqst_integrity_protected(rqstp))
|
||||||
|
return false;
|
||||||
|
if (!cr->cr_principal)
|
||||||
|
return false;
|
||||||
|
return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
|
||||||
|
}
|
||||||
|
|
||||||
static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
|
static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
|
||||||
{
|
{
|
||||||
static u32 current_clientid = 1;
|
static u32 current_clientid = 1;
|
||||||
|
@ -1642,16 +1667,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||||
if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
|
if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
|
||||||
return nfserr_inval;
|
return nfserr_inval;
|
||||||
|
|
||||||
/* Currently only support SP4_NONE */
|
|
||||||
switch (exid->spa_how) {
|
switch (exid->spa_how) {
|
||||||
|
case SP4_MACH_CRED:
|
||||||
|
if (!svc_rqst_integrity_protected(rqstp))
|
||||||
|
return nfserr_inval;
|
||||||
case SP4_NONE:
|
case SP4_NONE:
|
||||||
break;
|
break;
|
||||||
default: /* checked by xdr code */
|
default: /* checked by xdr code */
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
case SP4_SSV:
|
case SP4_SSV:
|
||||||
return nfserr_encr_alg_unsupp;
|
return nfserr_encr_alg_unsupp;
|
||||||
case SP4_MACH_CRED:
|
|
||||||
return nfserr_serverfault; /* no excuse :-/ */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cases below refer to rfc 5661 section 18.35.4: */
|
/* Cases below refer to rfc 5661 section 18.35.4: */
|
||||||
|
@ -1666,6 +1691,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||||
status = nfserr_inval;
|
status = nfserr_inval;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (!mach_creds_match(conf, rqstp)) {
|
||||||
|
status = nfserr_wrong_cred;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (!creds_match) { /* case 9 */
|
if (!creds_match) { /* case 9 */
|
||||||
status = nfserr_perm;
|
status = nfserr_perm;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1713,6 +1742,7 @@ out_new:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
new->cl_minorversion = cstate->minorversion;
|
new->cl_minorversion = cstate->minorversion;
|
||||||
|
new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
|
||||||
|
|
||||||
gen_clid(new, nn);
|
gen_clid(new, nn);
|
||||||
add_to_unconfirmed(new);
|
add_to_unconfirmed(new);
|
||||||
|
@ -1877,6 +1907,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||||
WARN_ON_ONCE(conf && unconf);
|
WARN_ON_ONCE(conf && unconf);
|
||||||
|
|
||||||
if (conf) {
|
if (conf) {
|
||||||
|
status = nfserr_wrong_cred;
|
||||||
|
if (!mach_creds_match(conf, rqstp))
|
||||||
|
goto out_free_conn;
|
||||||
cs_slot = &conf->cl_cs_slot;
|
cs_slot = &conf->cl_cs_slot;
|
||||||
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
||||||
if (status == nfserr_replay_cache) {
|
if (status == nfserr_replay_cache) {
|
||||||
|
@ -1893,6 +1926,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||||
status = nfserr_clid_inuse;
|
status = nfserr_clid_inuse;
|
||||||
goto out_free_conn;
|
goto out_free_conn;
|
||||||
}
|
}
|
||||||
|
status = nfserr_wrong_cred;
|
||||||
|
if (!mach_creds_match(unconf, rqstp))
|
||||||
|
goto out_free_conn;
|
||||||
cs_slot = &unconf->cl_cs_slot;
|
cs_slot = &unconf->cl_cs_slot;
|
||||||
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
||||||
if (status) {
|
if (status) {
|
||||||
|
@ -1989,6 +2025,9 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
|
||||||
status = nfserr_badsession;
|
status = nfserr_badsession;
|
||||||
if (!session)
|
if (!session)
|
||||||
goto out;
|
goto out;
|
||||||
|
status = nfserr_wrong_cred;
|
||||||
|
if (!mach_creds_match(session->se_client, rqstp))
|
||||||
|
goto out;
|
||||||
status = nfsd4_map_bcts_dir(&bcts->dir);
|
status = nfsd4_map_bcts_dir(&bcts->dir);
|
||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -2031,6 +2070,9 @@ nfsd4_destroy_session(struct svc_rqst *r,
|
||||||
status = nfserr_badsession;
|
status = nfserr_badsession;
|
||||||
if (!ses)
|
if (!ses)
|
||||||
goto out_client_lock;
|
goto out_client_lock;
|
||||||
|
status = nfserr_wrong_cred;
|
||||||
|
if (!mach_creds_match(ses->se_client, r))
|
||||||
|
goto out_client_lock;
|
||||||
status = mark_session_dead_locked(ses);
|
status = mark_session_dead_locked(ses);
|
||||||
if (status)
|
if (status)
|
||||||
goto out_client_lock;
|
goto out_client_lock;
|
||||||
|
@ -2061,26 +2103,31 @@ static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_s
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
|
static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
|
||||||
{
|
{
|
||||||
struct nfs4_client *clp = ses->se_client;
|
struct nfs4_client *clp = ses->se_client;
|
||||||
struct nfsd4_conn *c;
|
struct nfsd4_conn *c;
|
||||||
|
__be32 status = nfs_ok;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
spin_lock(&clp->cl_lock);
|
spin_lock(&clp->cl_lock);
|
||||||
c = __nfsd4_find_conn(new->cn_xprt, ses);
|
c = __nfsd4_find_conn(new->cn_xprt, ses);
|
||||||
if (c) {
|
if (c)
|
||||||
spin_unlock(&clp->cl_lock);
|
goto out_free;
|
||||||
free_conn(new);
|
status = nfserr_conn_not_bound_to_session;
|
||||||
return;
|
if (clp->cl_mach_cred)
|
||||||
}
|
goto out_free;
|
||||||
__nfsd4_hash_conn(new, ses);
|
__nfsd4_hash_conn(new, ses);
|
||||||
spin_unlock(&clp->cl_lock);
|
spin_unlock(&clp->cl_lock);
|
||||||
ret = nfsd4_register_conn(new);
|
ret = nfsd4_register_conn(new);
|
||||||
if (ret)
|
if (ret)
|
||||||
/* oops; xprt is already down: */
|
/* oops; xprt is already down: */
|
||||||
nfsd4_conn_lost(&new->cn_xpt_user);
|
nfsd4_conn_lost(&new->cn_xpt_user);
|
||||||
return;
|
return nfs_ok;
|
||||||
|
out_free:
|
||||||
|
spin_unlock(&clp->cl_lock);
|
||||||
|
free_conn(new);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
|
static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
|
||||||
|
@ -2172,8 +2219,10 @@ nfsd4_sequence(struct svc_rqst *rqstp,
|
||||||
if (status)
|
if (status)
|
||||||
goto out_put_session;
|
goto out_put_session;
|
||||||
|
|
||||||
nfsd4_sequence_check_conn(conn, session);
|
status = nfsd4_sequence_check_conn(conn, session);
|
||||||
conn = NULL;
|
conn = NULL;
|
||||||
|
if (status)
|
||||||
|
goto out_put_session;
|
||||||
|
|
||||||
/* Success! bump slot seqid */
|
/* Success! bump slot seqid */
|
||||||
slot->sl_seqid = seq->seqid;
|
slot->sl_seqid = seq->seqid;
|
||||||
|
@ -2235,7 +2284,10 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
|
||||||
status = nfserr_stale_clientid;
|
status = nfserr_stale_clientid;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (!mach_creds_match(clp, rqstp)) {
|
||||||
|
status = nfserr_wrong_cred;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
expire_client(clp);
|
expire_client(clp);
|
||||||
out:
|
out:
|
||||||
nfs4_unlock_state();
|
nfs4_unlock_state();
|
||||||
|
|
|
@ -3321,6 +3321,14 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w
|
||||||
return nfserr;
|
return nfserr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const u32 nfs4_minimal_spo_must_enforce[2] = {
|
||||||
|
[1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
|
||||||
|
1 << (OP_EXCHANGE_ID - 32) |
|
||||||
|
1 << (OP_CREATE_SESSION - 32) |
|
||||||
|
1 << (OP_DESTROY_SESSION - 32) |
|
||||||
|
1 << (OP_DESTROY_CLIENTID - 32)
|
||||||
|
};
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||||
struct nfsd4_exchange_id *exid)
|
struct nfsd4_exchange_id *exid)
|
||||||
|
@ -3359,6 +3367,20 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||||
/* state_protect4_r. Currently only support SP4_NONE */
|
/* state_protect4_r. Currently only support SP4_NONE */
|
||||||
BUG_ON(exid->spa_how != SP4_NONE);
|
BUG_ON(exid->spa_how != SP4_NONE);
|
||||||
WRITE32(exid->spa_how);
|
WRITE32(exid->spa_how);
|
||||||
|
switch (exid->spa_how) {
|
||||||
|
case SP4_NONE:
|
||||||
|
break;
|
||||||
|
case SP4_MACH_CRED:
|
||||||
|
/* spo_must_enforce bitmap: */
|
||||||
|
WRITE32(2);
|
||||||
|
WRITE32(nfs4_minimal_spo_must_enforce[0]);
|
||||||
|
WRITE32(nfs4_minimal_spo_must_enforce[1]);
|
||||||
|
/* empty spo_must_allow bitmap: */
|
||||||
|
WRITE32(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
}
|
||||||
|
|
||||||
/* The server_owner struct */
|
/* The server_owner struct */
|
||||||
WRITE64(minor_id); /* Minor id */
|
WRITE64(minor_id); /* Minor id */
|
||||||
|
|
|
@ -246,6 +246,7 @@ struct nfs4_client {
|
||||||
nfs4_verifier cl_verifier; /* generated by client */
|
nfs4_verifier cl_verifier; /* generated by client */
|
||||||
time_t cl_time; /* time of last lease renewal */
|
time_t cl_time; /* time of last lease renewal */
|
||||||
struct sockaddr_storage cl_addr; /* client ipaddress */
|
struct sockaddr_storage cl_addr; /* client ipaddress */
|
||||||
|
bool cl_mach_cred; /* SP4_MACH_CRED in force */
|
||||||
struct svc_cred cl_cred; /* setclientid principal */
|
struct svc_cred cl_cred; /* setclientid principal */
|
||||||
clientid_t cl_clientid; /* generated by server */
|
clientid_t cl_clientid; /* generated by server */
|
||||||
nfs4_verifier cl_confirm; /* generated by server */
|
nfs4_verifier cl_confirm; /* generated by server */
|
||||||
|
|
Loading…
Add table
Reference in a new issue