Merge tag 'clk-for-linus-3.12' of git://git.linaro.org/people/mturquette/linux
[cascardo/linux.git] / net / sunrpc / auth_generic.c
index b6badaf..f6d84be 100644 (file)
@@ -89,6 +89,7 @@ generic_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
        gcred->acred.uid = acred->uid;
        gcred->acred.gid = acred->gid;
        gcred->acred.group_info = acred->group_info;
+       gcred->acred.ac_flags = 0;
        if (gcred->acred.group_info != NULL)
                get_group_info(gcred->acred.group_info);
        gcred->acred.machine_cred = acred->machine_cred;
@@ -182,11 +183,78 @@ void rpc_destroy_generic_auth(void)
        rpcauth_destroy_credcache(&generic_auth);
 }
 
+/*
+ * Test the the current time (now) against the underlying credential key expiry
+ * minus a timeout and setup notification.
+ *
+ * The normal case:
+ * If 'now' is before the key expiry minus RPC_KEY_EXPIRE_TIMEO, set
+ * the RPC_CRED_NOTIFY_TIMEOUT flag to setup the underlying credential
+ * rpc_credops crmatch routine to notify this generic cred when it's key
+ * expiration is within RPC_KEY_EXPIRE_TIMEO, and return 0.
+ *
+ * The error case:
+ * If the underlying cred lookup fails, return -EACCES.
+ *
+ * The 'almost' error case:
+ * If 'now' is within key expiry minus RPC_KEY_EXPIRE_TIMEO, but not within
+ * key expiry minus RPC_KEY_EXPIRE_FAIL, set the RPC_CRED_EXPIRE_SOON bit
+ * on the acred ac_flags and return 0.
+ */
+static int
+generic_key_timeout(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+       struct auth_cred *acred = &container_of(cred, struct generic_cred,
+                                               gc_base)->acred;
+       struct rpc_cred *tcred;
+       int ret = 0;
+
+
+       /* Fast track for non crkey_timeout (no key) underlying credentials */
+       if (test_bit(RPC_CRED_NO_CRKEY_TIMEOUT, &acred->ac_flags))
+               return 0;
+
+       /* Fast track for the normal case */
+       if (test_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags))
+               return 0;
+
+       /* lookup_cred either returns a valid referenced rpc_cred, or PTR_ERR */
+       tcred = auth->au_ops->lookup_cred(auth, acred, 0);
+       if (IS_ERR(tcred))
+               return -EACCES;
+
+       if (!tcred->cr_ops->crkey_timeout) {
+               set_bit(RPC_CRED_NO_CRKEY_TIMEOUT, &acred->ac_flags);
+               ret = 0;
+               goto out_put;
+       }
+
+       /* Test for the almost error case */
+       ret = tcred->cr_ops->crkey_timeout(tcred);
+       if (ret != 0) {
+               set_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
+               ret = 0;
+       } else {
+               /* In case underlying cred key has been reset */
+               if (test_and_clear_bit(RPC_CRED_KEY_EXPIRE_SOON,
+                                       &acred->ac_flags))
+                       dprintk("RPC:        UID %d Credential key reset\n",
+                               tcred->cr_uid);
+               /* set up fasttrack for the normal case */
+               set_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags);
+       }
+
+out_put:
+       put_rpccred(tcred);
+       return ret;
+}
+
 static const struct rpc_authops generic_auth_ops = {
        .owner = THIS_MODULE,
        .au_name = "Generic",
        .lookup_cred = generic_lookup_cred,
        .crcreate = generic_create_cred,
+       .key_timeout = generic_key_timeout,
 };
 
 static struct rpc_auth generic_auth = {
@@ -194,9 +262,23 @@ static struct rpc_auth generic_auth = {
        .au_count = ATOMIC_INIT(0),
 };
 
+static bool generic_key_to_expire(struct rpc_cred *cred)
+{
+       struct auth_cred *acred = &container_of(cred, struct generic_cred,
+                                               gc_base)->acred;
+       bool ret;
+
+       get_rpccred(cred);
+       ret = test_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
+       put_rpccred(cred);
+
+       return ret;
+}
+
 static const struct rpc_credops generic_credops = {
        .cr_name = "Generic cred",
        .crdestroy = generic_destroy_cred,
        .crbind = generic_bind_cred,
        .crmatch = generic_match,
+       .crkey_to_expire = generic_key_to_expire,
 };