aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorWeston Andros Adamson <dros@netapp.com>2013-08-13 16:37:32 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-09-05 10:40:45 -0400
commit2031cd1af143f47dacacbb35efbef22f2fd079e6 (patch)
treed5737cb0679b190fcfd583bb74768edfa032203e /fs/nfs
parent92cb6c5be8134db6f7c38f25f6afd13e444cebaf (diff)
nfs4.1: Minimal SP4_MACH_CRED implementation
This is a minimal client side implementation of SP4_MACH_CRED. It will attempt to negotiate SP4_MACH_CRED iff the EXCHANGE_ID is using krb5i or krb5p auth. SP4_MACH_CRED will be used if the server supports the minimal operations: BIND_CONN_TO_SESSION EXCHANGE_ID CREATE_SESSION DESTROY_SESSION DESTROY_CLIENTID This patch only includes the EXCHANGE_ID negotiation code because the client will already use the machine cred for these operations. If the server doesn't support SP4_MACH_CRED or doesn't support the minimal operations, the exchange id will be resent with SP4_NONE. Signed-off-by: Weston Andros Adamson <dros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c133
-rw-r--r--fs/nfs/nfs4xdr.c72
2 files changed, 188 insertions, 17 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 535011a27415..ab6ee1dffd7b 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -6117,16 +6117,87 @@ out:
6117} 6117}
6118 6118
6119/* 6119/*
6120 * nfs4_proc_exchange_id() 6120 * Minimum set of SP4_MACH_CRED operations from RFC 5661
6121 */
6122static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = {
6123 .how = SP4_MACH_CRED,
6124 .enforce.u.words = {
6125 [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
6126 1 << (OP_EXCHANGE_ID - 32) |
6127 1 << (OP_CREATE_SESSION - 32) |
6128 1 << (OP_DESTROY_SESSION - 32) |
6129 1 << (OP_DESTROY_CLIENTID - 32)
6130 }
6131};
6132
6133/*
6134 * Select the state protection mode for client `clp' given the server results
6135 * from exchange_id in `sp'.
6121 * 6136 *
6122 * Returns zero, a negative errno, or a negative NFS4ERR status code. 6137 * Returns 0 on success, negative errno otherwise.
6138 */
6139static int nfs4_sp4_select_mode(struct nfs_client *clp,
6140 struct nfs41_state_protection *sp)
6141{
6142 static const u32 supported_enforce[NFS4_OP_MAP_NUM_WORDS] = {
6143 [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
6144 1 << (OP_EXCHANGE_ID - 32) |
6145 1 << (OP_CREATE_SESSION - 32) |
6146 1 << (OP_DESTROY_SESSION - 32) |
6147 1 << (OP_DESTROY_CLIENTID - 32)
6148 };
6149 unsigned int i;
6150
6151 if (sp->how == SP4_MACH_CRED) {
6152 /* Print state protect result */
6153 dfprintk(MOUNT, "Server SP4_MACH_CRED support:\n");
6154 for (i = 0; i <= LAST_NFS4_OP; i++) {
6155 if (test_bit(i, sp->enforce.u.longs))
6156 dfprintk(MOUNT, " enforce op %d\n", i);
6157 if (test_bit(i, sp->allow.u.longs))
6158 dfprintk(MOUNT, " allow op %d\n", i);
6159 }
6160
6161 /* make sure nothing is on enforce list that isn't supported */
6162 for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++) {
6163 if (sp->enforce.u.words[i] & ~supported_enforce[i]) {
6164 dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
6165 return -EINVAL;
6166 }
6167 }
6168
6169 /*
6170 * Minimal mode - state operations are allowed to use machine
6171 * credential. Note this already happens by default, so the
6172 * client doesn't have to do anything more than the negotiation.
6173 *
6174 * NOTE: we don't care if EXCHANGE_ID is in the list -
6175 * we're already using the machine cred for exchange_id
6176 * and will never use a different cred.
6177 */
6178 if (test_bit(OP_BIND_CONN_TO_SESSION, sp->enforce.u.longs) &&
6179 test_bit(OP_CREATE_SESSION, sp->enforce.u.longs) &&
6180 test_bit(OP_DESTROY_SESSION, sp->enforce.u.longs) &&
6181 test_bit(OP_DESTROY_CLIENTID, sp->enforce.u.longs)) {
6182 dfprintk(MOUNT, "sp4_mach_cred:\n");
6183 dfprintk(MOUNT, " minimal mode enabled\n");
6184 set_bit(NFS_SP4_MACH_CRED_MINIMAL, &clp->cl_sp4_flags);
6185 } else {
6186 dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
6187 return -EINVAL;
6188 }
6189 }
6190
6191 return 0;
6192}
6193
6194/*
6195 * _nfs4_proc_exchange_id()
6123 * 6196 *
6124 * Since the clientid has expired, all compounds using sessions 6197 * Wrapper for EXCHANGE_ID operation.
6125 * associated with the stale clientid will be returning
6126 * NFS4ERR_BADSESSION in the sequence operation, and will therefore
6127 * be in some phase of session reset.
6128 */ 6198 */
6129int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) 6199static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
6200 u32 sp4_how)
6130{ 6201{
6131 nfs4_verifier verifier; 6202 nfs4_verifier verifier;
6132 struct nfs41_exchange_id_args args = { 6203 struct nfs41_exchange_id_args args = {
@@ -6173,11 +6244,30 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
6173 goto out_server_scope; 6244 goto out_server_scope;
6174 } 6245 }
6175 6246
6247 switch (sp4_how) {
6248 case SP4_NONE:
6249 args.state_protect.how = SP4_NONE;
6250 break;
6251
6252 case SP4_MACH_CRED:
6253 args.state_protect = nfs4_sp4_mach_cred_request;
6254 break;
6255
6256 default:
6257 /* unsupported! */
6258 WARN_ON_ONCE(1);
6259 status = -EINVAL;
6260 goto out_server_scope;
6261 }
6262
6176 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); 6263 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
6177 trace_nfs4_exchange_id(clp, status); 6264 trace_nfs4_exchange_id(clp, status);
6178 if (status == 0) 6265 if (status == 0)
6179 status = nfs4_check_cl_exchange_flags(res.flags); 6266 status = nfs4_check_cl_exchange_flags(res.flags);
6180 6267
6268 if (status == 0)
6269 status = nfs4_sp4_select_mode(clp, &res.state_protect);
6270
6181 if (status == 0) { 6271 if (status == 0) {
6182 clp->cl_clientid = res.clientid; 6272 clp->cl_clientid = res.clientid;
6183 clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R); 6273 clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
@@ -6224,6 +6314,35 @@ out:
6224 return status; 6314 return status;
6225} 6315}
6226 6316
6317/*
6318 * nfs4_proc_exchange_id()
6319 *
6320 * Returns zero, a negative errno, or a negative NFS4ERR status code.
6321 *
6322 * Since the clientid has expired, all compounds using sessions
6323 * associated with the stale clientid will be returning
6324 * NFS4ERR_BADSESSION in the sequence operation, and will therefore
6325 * be in some phase of session reset.
6326 *
6327 * Will attempt to negotiate SP4_MACH_CRED if krb5i / krb5p auth is used.
6328 */
6329int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
6330{
6331 rpc_authflavor_t authflavor = clp->cl_rpcclient->cl_auth->au_flavor;
6332 int status;
6333
6334 /* try SP4_MACH_CRED if krb5i/p */
6335 if (authflavor == RPC_AUTH_GSS_KRB5I ||
6336 authflavor == RPC_AUTH_GSS_KRB5P) {
6337 status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED);
6338 if (!status)
6339 return 0;
6340 }
6341
6342 /* try SP4_NONE */
6343 return _nfs4_proc_exchange_id(clp, cred, SP4_NONE);
6344}
6345
6227static int _nfs4_proc_destroy_clientid(struct nfs_client *clp, 6346static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
6228 struct rpc_cred *cred) 6347 struct rpc_cred *cred)
6229{ 6348{
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index cb5f94640be6..fbdad9e1719f 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -294,7 +294,9 @@ static int nfs4_stat_to_errno(int);
294 XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \ 294 XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \
295 1 /* flags */ + \ 295 1 /* flags */ + \
296 1 /* spa_how */ + \ 296 1 /* spa_how */ + \
297 0 /* SP4_NONE (for now) */ + \ 297 /* max is SP4_MACH_CRED (for now) */ + \
298 1 + NFS4_OP_MAP_NUM_WORDS + \
299 1 + NFS4_OP_MAP_NUM_WORDS + \
298 1 /* implementation id array of size 1 */ + \ 300 1 /* implementation id array of size 1 */ + \
299 1 /* nii_domain */ + \ 301 1 /* nii_domain */ + \
300 XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \ 302 XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
@@ -306,7 +308,9 @@ static int nfs4_stat_to_errno(int);
306 1 /* eir_sequenceid */ + \ 308 1 /* eir_sequenceid */ + \
307 1 /* eir_flags */ + \ 309 1 /* eir_flags */ + \
308 1 /* spr_how */ + \ 310 1 /* spr_how */ + \
309 0 /* SP4_NONE (for now) */ + \ 311 /* max is SP4_MACH_CRED (for now) */ + \
312 1 + NFS4_OP_MAP_NUM_WORDS + \
313 1 + NFS4_OP_MAP_NUM_WORDS + \
310 2 /* eir_server_owner.so_minor_id */ + \ 314 2 /* eir_server_owner.so_minor_id */ + \
311 /* eir_server_owner.so_major_id<> */ \ 315 /* eir_server_owner.so_major_id<> */ \
312 XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ 316 XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
@@ -1726,6 +1730,14 @@ static void encode_bind_conn_to_session(struct xdr_stream *xdr,
1726 *p = 0; /* use_conn_in_rdma_mode = False */ 1730 *p = 0; /* use_conn_in_rdma_mode = False */
1727} 1731}
1728 1732
1733static void encode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map)
1734{
1735 unsigned int i;
1736 encode_uint32(xdr, NFS4_OP_MAP_NUM_WORDS);
1737 for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++)
1738 encode_uint32(xdr, op_map->u.words[i]);
1739}
1740
1729static void encode_exchange_id(struct xdr_stream *xdr, 1741static void encode_exchange_id(struct xdr_stream *xdr,
1730 struct nfs41_exchange_id_args *args, 1742 struct nfs41_exchange_id_args *args,
1731 struct compound_hdr *hdr) 1743 struct compound_hdr *hdr)
@@ -1739,9 +1751,20 @@ static void encode_exchange_id(struct xdr_stream *xdr,
1739 1751
1740 encode_string(xdr, args->id_len, args->id); 1752 encode_string(xdr, args->id_len, args->id);
1741 1753
1742 p = reserve_space(xdr, 12); 1754 encode_uint32(xdr, args->flags);
1743 *p++ = cpu_to_be32(args->flags); 1755 encode_uint32(xdr, args->state_protect.how);
1744 *p++ = cpu_to_be32(0); /* zero length state_protect4_a */ 1756
1757 switch (args->state_protect.how) {
1758 case SP4_NONE:
1759 break;
1760 case SP4_MACH_CRED:
1761 encode_op_map(xdr, &args->state_protect.enforce);
1762 encode_op_map(xdr, &args->state_protect.allow);
1763 break;
1764 default:
1765 WARN_ON_ONCE(1);
1766 break;
1767 }
1745 1768
1746 if (send_implementation_id && 1769 if (send_implementation_id &&
1747 sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 && 1770 sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 &&
@@ -1752,7 +1775,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
1752 utsname()->version, utsname()->machine); 1775 utsname()->version, utsname()->machine);
1753 1776
1754 if (len > 0) { 1777 if (len > 0) {
1755 *p = cpu_to_be32(1); /* implementation id array length=1 */ 1778 encode_uint32(xdr, 1); /* implementation id array length=1 */
1756 1779
1757 encode_string(xdr, 1780 encode_string(xdr,
1758 sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) - 1, 1781 sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) - 1,
@@ -1763,7 +1786,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
1763 p = xdr_encode_hyper(p, 0); 1786 p = xdr_encode_hyper(p, 0);
1764 *p = cpu_to_be32(0); 1787 *p = cpu_to_be32(0);
1765 } else 1788 } else
1766 *p = cpu_to_be32(0); /* implementation id array length=0 */ 1789 encode_uint32(xdr, 0); /* implementation id array length=0 */
1767} 1790}
1768 1791
1769static void encode_create_session(struct xdr_stream *xdr, 1792static void encode_create_session(struct xdr_stream *xdr,
@@ -5374,6 +5397,23 @@ static int decode_secinfo_no_name(struct xdr_stream *xdr, struct nfs4_secinfo_re
5374 return decode_secinfo_common(xdr, res); 5397 return decode_secinfo_common(xdr, res);
5375} 5398}
5376 5399
5400static int decode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map)
5401{
5402 __be32 *p;
5403 uint32_t bitmap_words;
5404 unsigned int i;
5405
5406 p = xdr_inline_decode(xdr, 4);
5407 bitmap_words = be32_to_cpup(p++);
5408 if (bitmap_words > NFS4_OP_MAP_NUM_WORDS)
5409 return -EIO;
5410 p = xdr_inline_decode(xdr, 4 * bitmap_words);
5411 for (i = 0; i < bitmap_words; i++)
5412 op_map->u.words[i] = be32_to_cpup(p++);
5413
5414 return 0;
5415}
5416
5377static int decode_exchange_id(struct xdr_stream *xdr, 5417static int decode_exchange_id(struct xdr_stream *xdr,
5378 struct nfs41_exchange_id_res *res) 5418 struct nfs41_exchange_id_res *res)
5379{ 5419{
@@ -5397,10 +5437,22 @@ static int decode_exchange_id(struct xdr_stream *xdr,
5397 res->seqid = be32_to_cpup(p++); 5437 res->seqid = be32_to_cpup(p++);
5398 res->flags = be32_to_cpup(p++); 5438 res->flags = be32_to_cpup(p++);
5399 5439
5400 /* We ask for SP4_NONE */ 5440 res->state_protect.how = be32_to_cpup(p);
5401 dummy = be32_to_cpup(p); 5441 switch (res->state_protect.how) {
5402 if (dummy != SP4_NONE) 5442 case SP4_NONE:
5443 break;
5444 case SP4_MACH_CRED:
5445 status = decode_op_map(xdr, &res->state_protect.enforce);
5446 if (status)
5447 return status;
5448 status = decode_op_map(xdr, &res->state_protect.allow);
5449 if (status)
5450 return status;
5451 break;
5452 default:
5453 WARN_ON_ONCE(1);
5403 return -EIO; 5454 return -EIO;
5455 }
5404 5456
5405 /* server_owner4.so_minor_id */ 5457 /* server_owner4.so_minor_id */
5406 p = xdr_inline_decode(xdr, 8); 5458 p = xdr_inline_decode(xdr, 8);