diff options
author | J. Bruce Fields <bfields@redhat.com> | 2013-04-13 14:27:29 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2013-07-01 17:23:06 -0400 |
commit | 57266a6e916e2522ea61758a3ee5576b60156791 (patch) | |
tree | 04646f973fa306dd02396274a5f0723944f61008 /fs/nfsd | |
parent | 0dc1531aca7fd1440918bd55844a054e9c29acad (diff) |
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>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4state.c | 76 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 22 | ||||
-rw-r--r-- | fs/nfsd/state.h | 1 |
3 files changed, 87 insertions, 12 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 109b43402e82..2383d24e258f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1265,6 +1265,31 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | |||
1265 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); | 1265 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); |
1266 | } | 1266 | } |
1267 | 1267 | ||
1268 | static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) | ||
1269 | { | ||
1270 | struct svc_cred *cr = &rqstp->rq_cred; | ||
1271 | u32 service; | ||
1272 | |||
1273 | service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); | ||
1274 | return service == RPC_GSS_SVC_INTEGRITY || | ||
1275 | service == RPC_GSS_SVC_PRIVACY; | ||
1276 | } | ||
1277 | |||
1278 | static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) | ||
1279 | { | ||
1280 | struct svc_cred *cr = &rqstp->rq_cred; | ||
1281 | |||
1282 | if (!cl->cl_mach_cred) | ||
1283 | return true; | ||
1284 | if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) | ||
1285 | return false; | ||
1286 | if (!svc_rqst_integrity_protected(rqstp)) | ||
1287 | return false; | ||
1288 | if (!cr->cr_principal) | ||
1289 | return false; | ||
1290 | return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); | ||
1291 | } | ||
1292 | |||
1268 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) | 1293 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) |
1269 | { | 1294 | { |
1270 | static u32 current_clientid = 1; | 1295 | static u32 current_clientid = 1; |
@@ -1642,16 +1667,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1642 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) | 1667 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) |
1643 | return nfserr_inval; | 1668 | return nfserr_inval; |
1644 | 1669 | ||
1645 | /* Currently only support SP4_NONE */ | ||
1646 | switch (exid->spa_how) { | 1670 | switch (exid->spa_how) { |
1671 | case SP4_MACH_CRED: | ||
1672 | if (!svc_rqst_integrity_protected(rqstp)) | ||
1673 | return nfserr_inval; | ||
1647 | case SP4_NONE: | 1674 | case SP4_NONE: |
1648 | break; | 1675 | break; |
1649 | default: /* checked by xdr code */ | 1676 | default: /* checked by xdr code */ |
1650 | WARN_ON_ONCE(1); | 1677 | WARN_ON_ONCE(1); |
1651 | case SP4_SSV: | 1678 | case SP4_SSV: |
1652 | return nfserr_encr_alg_unsupp; | 1679 | return nfserr_encr_alg_unsupp; |
1653 | case SP4_MACH_CRED: | ||
1654 | return nfserr_serverfault; /* no excuse :-/ */ | ||
1655 | } | 1680 | } |
1656 | 1681 | ||
1657 | /* Cases below refer to rfc 5661 section 18.35.4: */ | 1682 | /* Cases below refer to rfc 5661 section 18.35.4: */ |
@@ -1666,6 +1691,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1666 | status = nfserr_inval; | 1691 | status = nfserr_inval; |
1667 | goto out; | 1692 | goto out; |
1668 | } | 1693 | } |
1694 | if (!mach_creds_match(conf, rqstp)) { | ||
1695 | status = nfserr_wrong_cred; | ||
1696 | goto out; | ||
1697 | } | ||
1669 | if (!creds_match) { /* case 9 */ | 1698 | if (!creds_match) { /* case 9 */ |
1670 | status = nfserr_perm; | 1699 | status = nfserr_perm; |
1671 | goto out; | 1700 | goto out; |
@@ -1713,6 +1742,7 @@ out_new: | |||
1713 | goto out; | 1742 | goto out; |
1714 | } | 1743 | } |
1715 | new->cl_minorversion = cstate->minorversion; | 1744 | new->cl_minorversion = cstate->minorversion; |
1745 | new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); | ||
1716 | 1746 | ||
1717 | gen_clid(new, nn); | 1747 | gen_clid(new, nn); |
1718 | add_to_unconfirmed(new); | 1748 | add_to_unconfirmed(new); |
@@ -1877,6 +1907,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1877 | WARN_ON_ONCE(conf && unconf); | 1907 | WARN_ON_ONCE(conf && unconf); |
1878 | 1908 | ||
1879 | if (conf) { | 1909 | if (conf) { |
1910 | status = nfserr_wrong_cred; | ||
1911 | if (!mach_creds_match(conf, rqstp)) | ||
1912 | goto out_free_conn; | ||
1880 | cs_slot = &conf->cl_cs_slot; | 1913 | cs_slot = &conf->cl_cs_slot; |
1881 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1914 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1882 | if (status == nfserr_replay_cache) { | 1915 | if (status == nfserr_replay_cache) { |
@@ -1893,6 +1926,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1893 | status = nfserr_clid_inuse; | 1926 | status = nfserr_clid_inuse; |
1894 | goto out_free_conn; | 1927 | goto out_free_conn; |
1895 | } | 1928 | } |
1929 | status = nfserr_wrong_cred; | ||
1930 | if (!mach_creds_match(unconf, rqstp)) | ||
1931 | goto out_free_conn; | ||
1896 | cs_slot = &unconf->cl_cs_slot; | 1932 | cs_slot = &unconf->cl_cs_slot; |
1897 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1933 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1898 | if (status) { | 1934 | if (status) { |
@@ -1989,6 +2025,9 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | |||
1989 | status = nfserr_badsession; | 2025 | status = nfserr_badsession; |
1990 | if (!session) | 2026 | if (!session) |
1991 | goto out; | 2027 | goto out; |
2028 | status = nfserr_wrong_cred; | ||
2029 | if (!mach_creds_match(session->se_client, rqstp)) | ||
2030 | goto out; | ||
1992 | status = nfsd4_map_bcts_dir(&bcts->dir); | 2031 | status = nfsd4_map_bcts_dir(&bcts->dir); |
1993 | if (status) | 2032 | if (status) |
1994 | goto out; | 2033 | goto out; |
@@ -2031,6 +2070,9 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2031 | status = nfserr_badsession; | 2070 | status = nfserr_badsession; |
2032 | if (!ses) | 2071 | if (!ses) |
2033 | goto out_client_lock; | 2072 | goto out_client_lock; |
2073 | status = nfserr_wrong_cred; | ||
2074 | if (!mach_creds_match(ses->se_client, r)) | ||
2075 | goto out_client_lock; | ||
2034 | status = mark_session_dead_locked(ses); | 2076 | status = mark_session_dead_locked(ses); |
2035 | if (status) | 2077 | if (status) |
2036 | goto out_client_lock; | 2078 | goto out_client_lock; |
@@ -2061,26 +2103,31 @@ static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_s | |||
2061 | return NULL; | 2103 | return NULL; |
2062 | } | 2104 | } |
2063 | 2105 | ||
2064 | static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) | 2106 | static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) |
2065 | { | 2107 | { |
2066 | struct nfs4_client *clp = ses->se_client; | 2108 | struct nfs4_client *clp = ses->se_client; |
2067 | struct nfsd4_conn *c; | 2109 | struct nfsd4_conn *c; |
2110 | __be32 status = nfs_ok; | ||
2068 | int ret; | 2111 | int ret; |
2069 | 2112 | ||
2070 | spin_lock(&clp->cl_lock); | 2113 | spin_lock(&clp->cl_lock); |
2071 | c = __nfsd4_find_conn(new->cn_xprt, ses); | 2114 | c = __nfsd4_find_conn(new->cn_xprt, ses); |
2072 | if (c) { | 2115 | if (c) |
2073 | spin_unlock(&clp->cl_lock); | 2116 | goto out_free; |
2074 | free_conn(new); | 2117 | status = nfserr_conn_not_bound_to_session; |
2075 | return; | 2118 | if (clp->cl_mach_cred) |
2076 | } | 2119 | goto out_free; |
2077 | __nfsd4_hash_conn(new, ses); | 2120 | __nfsd4_hash_conn(new, ses); |
2078 | spin_unlock(&clp->cl_lock); | 2121 | spin_unlock(&clp->cl_lock); |
2079 | ret = nfsd4_register_conn(new); | 2122 | ret = nfsd4_register_conn(new); |
2080 | if (ret) | 2123 | if (ret) |
2081 | /* oops; xprt is already down: */ | 2124 | /* oops; xprt is already down: */ |
2082 | nfsd4_conn_lost(&new->cn_xpt_user); | 2125 | nfsd4_conn_lost(&new->cn_xpt_user); |
2083 | return; | 2126 | return nfs_ok; |
2127 | out_free: | ||
2128 | spin_unlock(&clp->cl_lock); | ||
2129 | free_conn(new); | ||
2130 | return status; | ||
2084 | } | 2131 | } |
2085 | 2132 | ||
2086 | static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) | 2133 | 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, | |||
2172 | if (status) | 2219 | if (status) |
2173 | goto out_put_session; | 2220 | goto out_put_session; |
2174 | 2221 | ||
2175 | nfsd4_sequence_check_conn(conn, session); | 2222 | status = nfsd4_sequence_check_conn(conn, session); |
2176 | conn = NULL; | 2223 | conn = NULL; |
2224 | if (status) | ||
2225 | goto out_put_session; | ||
2177 | 2226 | ||
2178 | /* Success! bump slot seqid */ | 2227 | /* Success! bump slot seqid */ |
2179 | slot->sl_seqid = seq->seqid; | 2228 | slot->sl_seqid = seq->seqid; |
@@ -2235,7 +2284,10 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2235 | status = nfserr_stale_clientid; | 2284 | status = nfserr_stale_clientid; |
2236 | goto out; | 2285 | goto out; |
2237 | } | 2286 | } |
2238 | 2287 | if (!mach_creds_match(clp, rqstp)) { | |
2288 | status = nfserr_wrong_cred; | ||
2289 | goto out; | ||
2290 | } | ||
2239 | expire_client(clp); | 2291 | expire_client(clp); |
2240 | out: | 2292 | out: |
2241 | nfs4_unlock_state(); | 2293 | nfs4_unlock_state(); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 170ea7e1ae25..3126210383bd 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -3321,6 +3321,14 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w | |||
3321 | return nfserr; | 3321 | return nfserr; |
3322 | } | 3322 | } |
3323 | 3323 | ||
3324 | static const u32 nfs4_minimal_spo_must_enforce[2] = { | ||
3325 | [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) | | ||
3326 | 1 << (OP_EXCHANGE_ID - 32) | | ||
3327 | 1 << (OP_CREATE_SESSION - 32) | | ||
3328 | 1 << (OP_DESTROY_SESSION - 32) | | ||
3329 | 1 << (OP_DESTROY_CLIENTID - 32) | ||
3330 | }; | ||
3331 | |||
3324 | static __be32 | 3332 | static __be32 |
3325 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, | 3333 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, |
3326 | struct nfsd4_exchange_id *exid) | 3334 | struct nfsd4_exchange_id *exid) |
@@ -3359,6 +3367,20 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
3359 | /* state_protect4_r. Currently only support SP4_NONE */ | 3367 | /* state_protect4_r. Currently only support SP4_NONE */ |
3360 | BUG_ON(exid->spa_how != SP4_NONE); | 3368 | BUG_ON(exid->spa_how != SP4_NONE); |
3361 | WRITE32(exid->spa_how); | 3369 | WRITE32(exid->spa_how); |
3370 | switch (exid->spa_how) { | ||
3371 | case SP4_NONE: | ||
3372 | break; | ||
3373 | case SP4_MACH_CRED: | ||
3374 | /* spo_must_enforce bitmap: */ | ||
3375 | WRITE32(2); | ||
3376 | WRITE32(nfs4_minimal_spo_must_enforce[0]); | ||
3377 | WRITE32(nfs4_minimal_spo_must_enforce[1]); | ||
3378 | /* empty spo_must_allow bitmap: */ | ||
3379 | WRITE32(0); | ||
3380 | break; | ||
3381 | default: | ||
3382 | WARN_ON_ONCE(1); | ||
3383 | } | ||
3362 | 3384 | ||
3363 | /* The server_owner struct */ | 3385 | /* The server_owner struct */ |
3364 | WRITE64(minor_id); /* Minor id */ | 3386 | WRITE64(minor_id); /* Minor id */ |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 274e2a114e05..424d8f5f2317 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -246,6 +246,7 @@ struct nfs4_client { | |||
246 | nfs4_verifier cl_verifier; /* generated by client */ | 246 | nfs4_verifier cl_verifier; /* generated by client */ |
247 | time_t cl_time; /* time of last lease renewal */ | 247 | time_t cl_time; /* time of last lease renewal */ |
248 | struct sockaddr_storage cl_addr; /* client ipaddress */ | 248 | struct sockaddr_storage cl_addr; /* client ipaddress */ |
249 | bool cl_mach_cred; /* SP4_MACH_CRED in force */ | ||
249 | struct svc_cred cl_cred; /* setclientid principal */ | 250 | struct svc_cred cl_cred; /* setclientid principal */ |
250 | clientid_t cl_clientid; /* generated by server */ | 251 | clientid_t cl_clientid; /* generated by server */ |
251 | nfs4_verifier cl_confirm; /* generated by server */ | 252 | nfs4_verifier cl_confirm; /* generated by server */ |