diff options
-rw-r--r-- | fs/nfs/inode.c | 2 | ||||
-rw-r--r-- | fs/nfs/write.c | 24 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 1 | ||||
-rw-r--r-- | include/linux/sunrpc/auth.h | 12 | ||||
-rw-r--r-- | net/sunrpc/auth.c | 23 | ||||
-rw-r--r-- | net/sunrpc/auth_generic.c | 69 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 21 |
7 files changed, 28 insertions, 124 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 5b1eee4952b7..aea015743172 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -962,6 +962,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, | |||
962 | nfs_sb_active(dentry->d_sb); | 962 | nfs_sb_active(dentry->d_sb); |
963 | ctx->dentry = dget(dentry); | 963 | ctx->dentry = dget(dentry); |
964 | ctx->cred = cred; | 964 | ctx->cred = cred; |
965 | ctx->ll_cred = NULL; | ||
965 | ctx->state = NULL; | 966 | ctx->state = NULL; |
966 | ctx->mode = f_mode; | 967 | ctx->mode = f_mode; |
967 | ctx->flags = 0; | 968 | ctx->flags = 0; |
@@ -1001,6 +1002,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) | |||
1001 | put_rpccred(ctx->cred); | 1002 | put_rpccred(ctx->cred); |
1002 | dput(ctx->dentry); | 1003 | dput(ctx->dentry); |
1003 | nfs_sb_deactive(sb); | 1004 | nfs_sb_deactive(sb); |
1005 | put_rpccred(ctx->ll_cred); | ||
1004 | kfree(ctx->mdsthreshold); | 1006 | kfree(ctx->mdsthreshold); |
1005 | kfree_rcu(ctx, rcu_head); | 1007 | kfree_rcu(ctx, rcu_head); |
1006 | } | 1008 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 586726a590d8..c1452f838131 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1233,9 +1233,12 @@ int | |||
1233 | nfs_key_timeout_notify(struct file *filp, struct inode *inode) | 1233 | nfs_key_timeout_notify(struct file *filp, struct inode *inode) |
1234 | { | 1234 | { |
1235 | struct nfs_open_context *ctx = nfs_file_open_context(filp); | 1235 | struct nfs_open_context *ctx = nfs_file_open_context(filp); |
1236 | struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth; | ||
1237 | 1236 | ||
1238 | return rpcauth_key_timeout_notify(auth, ctx->cred); | 1237 | if (nfs_ctx_key_to_expire(ctx, inode) && |
1238 | !ctx->ll_cred) | ||
1239 | /* Already expired! */ | ||
1240 | return -EACCES; | ||
1241 | return 0; | ||
1239 | } | 1242 | } |
1240 | 1243 | ||
1241 | /* | 1244 | /* |
@@ -1244,8 +1247,23 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode) | |||
1244 | bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx, struct inode *inode) | 1247 | bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx, struct inode *inode) |
1245 | { | 1248 | { |
1246 | struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth; | 1249 | struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth; |
1250 | struct rpc_cred *cred = ctx->ll_cred; | ||
1251 | struct auth_cred acred = { | ||
1252 | .cred = ctx->cred->cr_cred, | ||
1253 | }; | ||
1247 | 1254 | ||
1248 | return rpcauth_cred_key_to_expire(auth, ctx->cred); | 1255 | if (cred && !cred->cr_ops->crmatch(&acred, cred, 0)) { |
1256 | put_rpccred(cred); | ||
1257 | ctx->ll_cred = NULL; | ||
1258 | cred = NULL; | ||
1259 | } | ||
1260 | if (!cred) | ||
1261 | cred = auth->au_ops->lookup_cred(auth, &acred, 0); | ||
1262 | if (!cred || IS_ERR(cred)) | ||
1263 | return true; | ||
1264 | ctx->ll_cred = cred; | ||
1265 | return !!(cred->cr_ops->crkey_timeout && | ||
1266 | cred->cr_ops->crkey_timeout(cred)); | ||
1249 | } | 1267 | } |
1250 | 1268 | ||
1251 | /* | 1269 | /* |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 6e0417c02279..ecf22c0034d5 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -71,6 +71,7 @@ struct nfs_open_context { | |||
71 | fl_owner_t flock_owner; | 71 | fl_owner_t flock_owner; |
72 | struct dentry *dentry; | 72 | struct dentry *dentry; |
73 | struct rpc_cred *cred; | 73 | struct rpc_cred *cred; |
74 | struct rpc_cred *ll_cred; /* low-level cred - use to check for expiry */ | ||
74 | struct nfs4_state *state; | 75 | struct nfs4_state *state; |
75 | fmode_t mode; | 76 | fmode_t mode; |
76 | 77 | ||
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 28b34c740c43..0bdc2f4957ff 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
@@ -37,17 +37,9 @@ | |||
37 | 37 | ||
38 | struct rpcsec_gss_info; | 38 | struct rpcsec_gss_info; |
39 | 39 | ||
40 | /* auth_cred ac_flags bits */ | ||
41 | enum { | ||
42 | RPC_CRED_KEY_EXPIRE_SOON = 1, /* underlying cred key will expire soon */ | ||
43 | RPC_CRED_NOTIFY_TIMEOUT = 2, /* nofity generic cred when underlying | ||
44 | key will expire soon */ | ||
45 | }; | ||
46 | |||
47 | struct auth_cred { | 40 | struct auth_cred { |
48 | const struct cred *cred; | 41 | const struct cred *cred; |
49 | const char *principal; /* If present, this is a machine credential */ | 42 | const char *principal; /* If present, this is a machine credential */ |
50 | unsigned long ac_flags; | ||
51 | }; | 43 | }; |
52 | 44 | ||
53 | /* | 45 | /* |
@@ -154,7 +146,6 @@ struct rpc_credops { | |||
154 | int (*crunwrap_resp)(struct rpc_task *, kxdrdproc_t, | 146 | int (*crunwrap_resp)(struct rpc_task *, kxdrdproc_t, |
155 | void *, __be32 *, void *); | 147 | void *, __be32 *, void *); |
156 | int (*crkey_timeout)(struct rpc_cred *); | 148 | int (*crkey_timeout)(struct rpc_cred *); |
157 | bool (*crkey_to_expire)(struct rpc_cred *); | ||
158 | char * (*crstringify_acceptor)(struct rpc_cred *); | 149 | char * (*crstringify_acceptor)(struct rpc_cred *); |
159 | bool (*crneed_reencode)(struct rpc_task *); | 150 | bool (*crneed_reencode)(struct rpc_task *); |
160 | }; | 151 | }; |
@@ -198,9 +189,6 @@ int rpcauth_uptodatecred(struct rpc_task *); | |||
198 | int rpcauth_init_credcache(struct rpc_auth *); | 189 | int rpcauth_init_credcache(struct rpc_auth *); |
199 | void rpcauth_destroy_credcache(struct rpc_auth *); | 190 | void rpcauth_destroy_credcache(struct rpc_auth *); |
200 | void rpcauth_clear_credcache(struct rpc_cred_cache *); | 191 | void rpcauth_clear_credcache(struct rpc_cred_cache *); |
201 | int rpcauth_key_timeout_notify(struct rpc_auth *, | ||
202 | struct rpc_cred *); | ||
203 | bool rpcauth_cred_key_to_expire(struct rpc_auth *, struct rpc_cred *); | ||
204 | char * rpcauth_stringify_acceptor(struct rpc_cred *); | 192 | char * rpcauth_stringify_acceptor(struct rpc_cred *); |
205 | 193 | ||
206 | static inline | 194 | static inline |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 27d90578e7a0..cf23eed01b1c 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -360,29 +360,6 @@ out_nocache: | |||
360 | } | 360 | } |
361 | EXPORT_SYMBOL_GPL(rpcauth_init_credcache); | 361 | EXPORT_SYMBOL_GPL(rpcauth_init_credcache); |
362 | 362 | ||
363 | /* | ||
364 | * Setup a credential key lifetime timeout notification | ||
365 | */ | ||
366 | int | ||
367 | rpcauth_key_timeout_notify(struct rpc_auth *auth, struct rpc_cred *cred) | ||
368 | { | ||
369 | if (!cred->cr_auth->au_ops->key_timeout) | ||
370 | return 0; | ||
371 | return cred->cr_auth->au_ops->key_timeout(auth, cred); | ||
372 | } | ||
373 | EXPORT_SYMBOL_GPL(rpcauth_key_timeout_notify); | ||
374 | |||
375 | bool | ||
376 | rpcauth_cred_key_to_expire(struct rpc_auth *auth, struct rpc_cred *cred) | ||
377 | { | ||
378 | if (auth->au_flags & RPCAUTH_AUTH_NO_CRKEY_TIMEOUT) | ||
379 | return false; | ||
380 | if (!cred->cr_ops->crkey_to_expire) | ||
381 | return false; | ||
382 | return cred->cr_ops->crkey_to_expire(cred); | ||
383 | } | ||
384 | EXPORT_SYMBOL_GPL(rpcauth_cred_key_to_expire); | ||
385 | |||
386 | char * | 363 | char * |
387 | rpcauth_stringify_acceptor(struct rpc_cred *cred) | 364 | rpcauth_stringify_acceptor(struct rpc_cred *cred) |
388 | { | 365 | { |
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c index 5f7aa6324b78..c57e83184d3c 100644 --- a/net/sunrpc/auth_generic.c +++ b/net/sunrpc/auth_generic.c | |||
@@ -87,7 +87,6 @@ generic_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, g | |||
87 | gcred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; | 87 | gcred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; |
88 | 88 | ||
89 | gcred->acred.cred = gcred->gc_base.cr_cred; | 89 | gcred->acred.cred = gcred->gc_base.cr_cred; |
90 | gcred->acred.ac_flags = 0; | ||
91 | gcred->acred.principal = acred->principal; | 90 | gcred->acred.principal = acred->principal; |
92 | 91 | ||
93 | dprintk("RPC: allocated %s cred %p for uid %d gid %d\n", | 92 | dprintk("RPC: allocated %s cred %p for uid %d gid %d\n", |
@@ -179,72 +178,12 @@ void rpc_destroy_generic_auth(void) | |||
179 | rpcauth_destroy_credcache(&generic_auth); | 178 | rpcauth_destroy_credcache(&generic_auth); |
180 | } | 179 | } |
181 | 180 | ||
182 | /* | ||
183 | * Test the the current time (now) against the underlying credential key expiry | ||
184 | * minus a timeout and setup notification. | ||
185 | * | ||
186 | * The normal case: | ||
187 | * If 'now' is before the key expiry minus RPC_KEY_EXPIRE_TIMEO, set | ||
188 | * the RPC_CRED_NOTIFY_TIMEOUT flag to setup the underlying credential | ||
189 | * rpc_credops crmatch routine to notify this generic cred when it's key | ||
190 | * expiration is within RPC_KEY_EXPIRE_TIMEO, and return 0. | ||
191 | * | ||
192 | * The error case: | ||
193 | * If the underlying cred lookup fails, return -EACCES. | ||
194 | * | ||
195 | * The 'almost' error case: | ||
196 | * If 'now' is within key expiry minus RPC_KEY_EXPIRE_TIMEO, but not within | ||
197 | * key expiry minus RPC_KEY_EXPIRE_FAIL, set the RPC_CRED_EXPIRE_SOON bit | ||
198 | * on the acred ac_flags and return 0. | ||
199 | */ | ||
200 | static int | ||
201 | generic_key_timeout(struct rpc_auth *auth, struct rpc_cred *cred) | ||
202 | { | ||
203 | struct auth_cred *acred = &container_of(cred, struct generic_cred, | ||
204 | gc_base)->acred; | ||
205 | struct rpc_cred *tcred; | ||
206 | int ret = 0; | ||
207 | |||
208 | |||
209 | /* Fast track for non crkey_timeout (no key) underlying credentials */ | ||
210 | if (auth->au_flags & RPCAUTH_AUTH_NO_CRKEY_TIMEOUT) | ||
211 | return 0; | ||
212 | |||
213 | /* Fast track for the normal case */ | ||
214 | if (test_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags)) | ||
215 | return 0; | ||
216 | |||
217 | /* lookup_cred either returns a valid referenced rpc_cred, or PTR_ERR */ | ||
218 | tcred = auth->au_ops->lookup_cred(auth, acred, 0); | ||
219 | if (IS_ERR(tcred)) | ||
220 | return -EACCES; | ||
221 | |||
222 | /* Test for the almost error case */ | ||
223 | ret = tcred->cr_ops->crkey_timeout(tcred); | ||
224 | if (ret != 0) { | ||
225 | set_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags); | ||
226 | ret = 0; | ||
227 | } else { | ||
228 | /* In case underlying cred key has been reset */ | ||
229 | if (test_and_clear_bit(RPC_CRED_KEY_EXPIRE_SOON, | ||
230 | &acred->ac_flags)) | ||
231 | dprintk("RPC: UID %d Credential key reset\n", | ||
232 | from_kuid(&init_user_ns, tcred->cr_uid)); | ||
233 | /* set up fasttrack for the normal case */ | ||
234 | set_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags); | ||
235 | } | ||
236 | |||
237 | put_rpccred(tcred); | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | static const struct rpc_authops generic_auth_ops = { | 181 | static const struct rpc_authops generic_auth_ops = { |
242 | .owner = THIS_MODULE, | 182 | .owner = THIS_MODULE, |
243 | .au_name = "Generic", | 183 | .au_name = "Generic", |
244 | .hash_cred = generic_hash_cred, | 184 | .hash_cred = generic_hash_cred, |
245 | .lookup_cred = generic_lookup_cred, | 185 | .lookup_cred = generic_lookup_cred, |
246 | .crcreate = generic_create_cred, | 186 | .crcreate = generic_create_cred, |
247 | .key_timeout = generic_key_timeout, | ||
248 | }; | 187 | }; |
249 | 188 | ||
250 | static struct rpc_auth generic_auth = { | 189 | static struct rpc_auth generic_auth = { |
@@ -252,17 +191,9 @@ static struct rpc_auth generic_auth = { | |||
252 | .au_count = REFCOUNT_INIT(1), | 191 | .au_count = REFCOUNT_INIT(1), |
253 | }; | 192 | }; |
254 | 193 | ||
255 | static bool generic_key_to_expire(struct rpc_cred *cred) | ||
256 | { | ||
257 | struct auth_cred *acred = &container_of(cred, struct generic_cred, | ||
258 | gc_base)->acred; | ||
259 | return test_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags); | ||
260 | } | ||
261 | |||
262 | static const struct rpc_credops generic_credops = { | 194 | static const struct rpc_credops generic_credops = { |
263 | .cr_name = "Generic cred", | 195 | .cr_name = "Generic cred", |
264 | .crdestroy = generic_destroy_cred, | 196 | .crdestroy = generic_destroy_cred, |
265 | .crbind = generic_bind_cred, | 197 | .crbind = generic_bind_cred, |
266 | .crmatch = generic_match, | 198 | .crmatch = generic_match, |
267 | .crkey_to_expire = generic_key_to_expire, | ||
268 | }; | 199 | }; |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index b218e15b61cb..03a1cd5bfb43 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1517,23 +1517,10 @@ out: | |||
1517 | if (gss_cred->gc_principal == NULL) | 1517 | if (gss_cred->gc_principal == NULL) |
1518 | return 0; | 1518 | return 0; |
1519 | ret = strcmp(acred->principal, gss_cred->gc_principal) == 0; | 1519 | ret = strcmp(acred->principal, gss_cred->gc_principal) == 0; |
1520 | goto check_expire; | 1520 | } else { |
1521 | } | 1521 | if (gss_cred->gc_principal != NULL) |
1522 | if (gss_cred->gc_principal != NULL) | 1522 | return 0; |
1523 | return 0; | 1523 | ret = uid_eq(rc->cr_uid, acred->cred->fsuid); |
1524 | ret = uid_eq(rc->cr_uid, acred->cred->fsuid); | ||
1525 | |||
1526 | check_expire: | ||
1527 | if (ret == 0) | ||
1528 | return ret; | ||
1529 | |||
1530 | /* Notify acred users of GSS context expiration timeout */ | ||
1531 | if (test_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags) && | ||
1532 | (gss_key_timeout(rc) != 0)) { | ||
1533 | /* test will now be done from generic cred */ | ||
1534 | test_and_clear_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags); | ||
1535 | /* tell NFS layer that key will expire soon */ | ||
1536 | set_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags); | ||
1537 | } | 1524 | } |
1538 | return ret; | 1525 | return ret; |
1539 | } | 1526 | } |