aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2013-04-13 14:27:29 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-07-01 17:23:06 -0400
commit57266a6e916e2522ea61758a3ee5576b60156791 (patch)
tree04646f973fa306dd02396274a5f0723944f61008 /fs/nfsd
parent0dc1531aca7fd1440918bd55844a054e9c29acad (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.c76
-rw-r--r--fs/nfsd/nfs4xdr.c22
-rw-r--r--fs/nfsd/state.h1
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
1268static 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
1278static 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
1268static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 1293static 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
2064static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 2106static __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;
2127out_free:
2128 spin_unlock(&clp->cl_lock);
2129 free_conn(new);
2130 return status;
2084} 2131}
2085 2132
2086static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 2133static 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);
2240out: 2292out:
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
3324static 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
3324static __be32 3332static __be32
3325nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, 3333nfsd4_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 */