diff options
author | Weston Andros Adamson <dros@netapp.com> | 2013-08-13 16:37:32 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-09-05 10:40:45 -0400 |
commit | 2031cd1af143f47dacacbb35efbef22f2fd079e6 (patch) | |
tree | d5737cb0679b190fcfd583bb74768edfa032203e /fs/nfs/nfs4proc.c | |
parent | 92cb6c5be8134db6f7c38f25f6afd13e444cebaf (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/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 133 |
1 files changed, 126 insertions, 7 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 | */ | ||
6122 | static 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 | */ | ||
6139 | static 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 | */ |
6129 | int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | 6199 | static 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 | */ | ||
6329 | int 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 | |||
6227 | static int _nfs4_proc_destroy_clientid(struct nfs_client *clp, | 6346 | static int _nfs4_proc_destroy_clientid(struct nfs_client *clp, |
6228 | struct rpc_cred *cred) | 6347 | struct rpc_cred *cred) |
6229 | { | 6348 | { |