Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / obdfilter / filter_capa.c
index 9a3b813..c7d3ea2 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- * Copyright (C) 2004, 2005 Cluster File Systems, Inc.
+ * Copyright (C) 2005 Cluster File Systems, Inc.
  *
  * Author: Lai Siyao <lsy@clusterfs.com>
  *
 #include <linux/file.h>
 #include <linux/kmod.h>
 
-#include <linux/lustre_fsfilt.h>
-#include <linux/lustre_sec.h>
+#include <lustre_fsfilt.h>
+#include <lustre_capa.h>
 
 #include "filter_internal.h"
 
-void filter_free_capa_keys(struct filter_obd *filter)
+static inline __u32 filter_ck_keyid(struct filter_capa_key *key)
 {
-        struct filter_capa_key *key, *n;
-
-        spin_lock(&filter->fo_capa_lock);
-        list_for_each_entry_safe(key, n, &filter->fo_capa_keys, k_list) {
-                list_del_init(&key->k_list);
-                OBD_FREE(key, sizeof(*key));
-        }
-        spin_unlock(&filter->fo_capa_lock);
+        return key->k_key.lk_keyid;
 }
 
-int filter_update_capa_key(struct obd_device *obd, struct lustre_capa_key *key)
+int filter_update_capa_key(struct obd_device *obd, struct lustre_capa_key *new)
 {
         struct filter_obd *filter = &obd->u.filter;
-        struct filter_capa_key *tmp = NULL, *rkey = NULL, *bkey = NULL;
-        int rc = 0;
-        ENTRY;
+        struct filter_capa_key *k, *keys[2] = { NULL, NULL };
+        int i;
 
-        spin_lock(&filter->fo_capa_lock);
-        list_for_each_entry(tmp, &filter->fo_capa_keys, k_list) {
-                if (tmp->k_key.lk_mdsid != le32_to_cpu(key->lk_mdsid))
+        spin_lock(&capa_lock);
+        list_for_each_entry(k, &filter->fo_capa_keys, k_list) {
+                if (k->k_key.lk_mdsid != new->lk_mdsid)
                         continue;
 
-                if (rkey == NULL)
-                        rkey = tmp;
-                else
-                        bkey = tmp;
+                if (keys[0]) {
+                        keys[1] = k;
+                        if (filter_ck_keyid(keys[1]) > filter_ck_keyid(keys[0]))
+                                keys[1] = keys[0], keys[0] = k;
+                } else {
+                        keys[0] = k;
+                }
         }
-        spin_unlock(&filter->fo_capa_lock);
+        spin_unlock(&capa_lock);
 
-        if (rkey && bkey && capa_key_cmp(&rkey->k_key, &bkey->k_key) < 0) {
-                tmp = rkey;
-                rkey = bkey;
-                bkey = tmp;
-        }
+        for (i = 0; i < 2; i++) {
+                if (!keys[i])
+                        continue;
+                if (filter_ck_keyid(keys[i]) != new->lk_keyid)
+                        continue;
+                /* maybe because of recovery or other reasons, MDS sent the
+                 * the old capability key again.
+                 */
+                spin_lock(&capa_lock);
+                keys[i]->k_key = *new;
+                spin_unlock(&capa_lock);
 
-        if (bkey) {
-                tmp = bkey;
+                RETURN(0);
+        }
 
-                DEBUG_CAPA_KEY(D_INFO, &tmp->k_key, "filter update");
+        if (keys[1]) {
+                /* if OSS already have two keys, update the old one */
+                k = keys[1];
         } else {
-                OBD_ALLOC(tmp, sizeof(*tmp));
-                if (!tmp)
-                        GOTO(out, rc = -ENOMEM);
-
-                DEBUG_CAPA_KEY(D_INFO, &tmp->k_key, "filter new");
+                OBD_ALLOC_PTR(k);
+                if (!k)
+                        RETURN(-ENOMEM);
+                INIT_LIST_HEAD(&k->k_list);
         }
 
-        /* fields in lustre_capa_key are in cpu order */
-        spin_lock(&filter->fo_capa_lock);
-        tmp->k_key.lk_mdsid = le32_to_cpu(key->lk_mdsid);
-        tmp->k_key.lk_keyid = le32_to_cpu(key->lk_keyid);
-        tmp->k_key.lk_expiry = le64_to_cpu(key->lk_expiry);
-        memcpy(&tmp->k_key.lk_key, key->lk_key, sizeof(key->lk_key));
-
-        if (!bkey)
-                list_add_tail(&tmp->k_list, &filter->fo_capa_keys);
-        spin_unlock(&filter->fo_capa_lock);
-out:
-        RETURN(rc);
-}
-
-int filter_verify_fid(struct obd_export *exp, struct inode *inode,
-                      struct lustre_capa *capa)
-{
-        struct lustre_id fid;
-        int rc;
-
-        if (!capa)
-                return 0;
-
-        ENTRY;
-        rc = fsfilt_get_md(exp->exp_obd, inode, &fid, sizeof(fid), EA_SID);
-        if (rc < 0) {
-                CERROR("get fid from object failed! rc:%d\n", rc);
-                RETURN(rc);
-        } else if (rc > 0) {
-                if (capa->lc_mdsid != id_group(&fid) ||
-                    capa->lc_ino != id_ino(&fid))
-                        RETURN(-EINVAL);
-        }
+        spin_lock(&capa_lock);
+        k->k_key = *new;
+        if (list_empty(&k->k_list))
+                list_add(&k->k_list, &filter->fo_capa_keys);
+        spin_unlock(&capa_lock);
 
+        DEBUG_CAPA_KEY(D_SEC, new, "new");
         RETURN(0);
 }
 
-int
-filter_verify_capa(int cmd, struct obd_export *exp, struct lustre_capa *capa)
+int filter_auth_capa(struct obd_export *exp, struct lu_fid *fid, __u64 mdsid,
+                     struct lustre_capa *capa, __u64 opc)
 {
         struct obd_device *obd = exp->exp_obd;
         struct filter_obd *filter = &obd->u.filter;
-        struct obd_capa *ocapa;
-        struct lustre_capa tcapa;
-        struct filter_capa_key *rkey = NULL, *bkey = NULL, *tmp;
-        __u8 hmac_key[CAPA_KEY_LEN];
-        int rc = 0;
+        struct filter_capa_key *k;
+        struct lustre_capa_key key;
+        struct obd_capa *oc;
+        __u8 *hmac;
+        int keys_ready = 0, key_found = 0, rc = 0;
+        ENTRY;
 
         /* capability is disabled */
-        if (filter->fo_capa_stat == 0)
+        if (!filter->fo_fl_oss_capa)
                 RETURN(0);
 
-        ENTRY;
-        if (capa == NULL)
-                RETURN(-EACCES);
-
-        if (cmd == OBD_BRW_WRITE && capa->lc_op != MAY_WRITE)
-                RETURN(-EACCES);
-        if (cmd == OBD_BRW_READ && !(capa->lc_op & (MAY_WRITE | MAY_READ)))
+        if (capa == NULL) {
+                if (fid)
+                        CERROR("mdsno/fid/opc "LPU64"/"DFID"/"LPX64
+                               ": no capability has been passed\n",
+                               mdsid, PFID(fid), opc);
+                else
+                        CERROR("mdsno/opc "LPU64"/"LPX64
+                               ": no capability has been passed\n",
+                               mdsid, opc);
                 RETURN(-EACCES);
+        }
 
-        if (OBD_FAIL_CHECK(OBD_FAIL_FILTER_VERIFY_CAPA))
-                RETURN(-EACCES);
+#warning "enable fid check in filter_auth_capa() when fid stored in OSS object"
 
-        if (capa_expired(capa))
-                RETURN(-ESTALE);
+        if (opc == CAPA_OPC_OSS_READ) {
+                if (!(capa->lc_opc & CAPA_OPC_OSS_RW))
+                        rc = -EACCES;
+        } else if (!capa_opc_supported(capa, opc)) {
+                rc = -EACCES;
+        }
+        if (rc) {
+                DEBUG_CAPA(D_ERROR, capa, "opc "LPX64" not supported by", opc);
+                RETURN(rc);
+        }
 
-        ocapa = capa_get(capa->lc_uid, capa->lc_op, capa->lc_mdsid,
-                         capa->lc_ino, FILTER_CAPA, NULL, NULL, NULL);
-verify:
-        if (ocapa) {
-                /* fo_capa_lock protects capa too */
-                spin_lock(&filter->fo_capa_lock);
-                if (capa->lc_keyid == ocapa->c_capa.lc_keyid) {
-                        rc = memcmp(capa, &ocapa->c_capa, sizeof(*capa));
-                } else if (ocapa->c_bvalid &&
-                           capa->lc_keyid == ocapa->c_bkeyid) {
-                        rc = memcmp(capa->lc_hmac, ocapa->c_bhmac,
-                                    sizeof(capa->lc_hmac));
-                } else {
-                        /* ocapa is obsolete */
-                        capa_put(ocapa, FILTER_CAPA);
-                        spin_unlock(&filter->fo_capa_lock);
-                        goto new_capa;
+        oc = capa_lookup(filter->fo_capa_hash, capa, 0);
+        if (oc) {
+                spin_lock(&oc->c_lock);
+                if (capa_is_expired(oc)) {
+                        DEBUG_CAPA(D_ERROR, capa, "expired");
+                        rc = -ESTALE;
                 }
-                spin_unlock(&filter->fo_capa_lock);
+                spin_unlock(&oc->c_lock);
 
-                capa_put(ocapa, FILTER_CAPA);
-                RETURN(rc ? -EACCES : 0);
+                capa_put(oc);
+                RETURN(rc);
         }
 
-new_capa:
-        spin_lock(&filter->fo_capa_lock);
-        list_for_each_entry(tmp, &filter->fo_capa_keys, k_list) {
-                if (tmp->k_key.lk_mdsid == capa->lc_mdsid) {
-                        if (rkey == NULL)
-                                rkey = tmp;
-                        else
-                                bkey = tmp;
+        spin_lock(&capa_lock);
+        list_for_each_entry(k, &filter->fo_capa_keys, k_list)
+                if (k->k_key.lk_mdsid == mdsid) {
+                        keys_ready = 1;
+                        if (k->k_key.lk_keyid == capa_keyid(capa)) {
+                                key = k->k_key;
+                                key_found = 1;
+                                break;
+                        }
                 }
-        }
+        spin_unlock(&capa_lock);
 
-        if (rkey && bkey && capa_key_cmp(&rkey->k_key, &bkey->k_key) < 0) {
-                tmp = rkey;
-                rkey = bkey;
-                bkey = tmp;
+        if (!keys_ready) {
+                CDEBUG(D_SEC, "MDS hasn't propagated capability keys yet, "
+                       "ignore check!\n");
+                RETURN(0);
         }
 
-        if ((!rkey || rkey->k_key.lk_keyid != capa->lc_keyid) &&
-            (!bkey || bkey->k_key.lk_keyid != capa->lc_keyid)) {
-                spin_unlock(&filter->fo_capa_lock);
-                GOTO(out, rc = -ESTALE);
+       if (!key_found) {
+                DEBUG_CAPA(D_ERROR, capa, "no matched capability key for");
+                RETURN(-ESTALE);
         }
 
-        LASSERT(rkey);
+        OBD_ALLOC(hmac, CAPA_HMAC_MAX_LEN);
+        if (hmac == NULL)
+                RETURN(-ENOMEM);
 
-        memcpy(&tcapa, capa, sizeof(tcapa));
-        tcapa.lc_keyid = rkey->k_key.lk_keyid;
-        memcpy(hmac_key, rkey->k_key.lk_key, sizeof(hmac_key));
-        spin_unlock(&filter->fo_capa_lock);
-
-        capa_hmac(filter->fo_capa_hmac, hmac_key, &tcapa);
+        rc = capa_hmac(hmac, capa, key.lk_key);
+        if (rc) {
+                DEBUG_CAPA(D_ERROR, capa, "HMAC failed: rc %d", rc);
+                OBD_FREE(hmac, CAPA_HMAC_MAX_LEN);
+                RETURN(rc);
+        }
 
-        /* store in capa cache */
-        ocapa = capa_get(capa->lc_uid, capa->lc_op, capa->lc_mdsid,
-                         capa->lc_ino, FILTER_CAPA, capa, NULL, NULL);
-        if (!ocapa)
-                GOTO(out, rc = -ENOMEM);
+        rc = memcmp(hmac, capa->lc_hmac, CAPA_HMAC_MAX_LEN);
+        OBD_FREE(hmac, CAPA_HMAC_MAX_LEN);
+        if (rc) {
+                DEBUG_CAPA_KEY(D_ERROR, &key, "calculate HMAC with ");
+                DEBUG_CAPA(D_ERROR, capa, "HMAC mismatch");
+                RETURN(-EACCES);
+        }
 
-        if (bkey) {
-                spin_lock(&filter->fo_capa_lock);
-                tcapa.lc_keyid = bkey->k_key.lk_keyid;
-                memcpy(hmac_key, bkey->k_key.lk_key, sizeof(hmac_key));
-                ocapa->c_bkeyid = bkey->k_key.lk_keyid;
-                spin_unlock(&filter->fo_capa_lock);
+        /* store in capa hash */
+        oc = capa_add(filter->fo_capa_hash, capa);
+        capa_put(oc);
+        RETURN(0);
+}
 
-                capa_hmac(filter->fo_capa_hmac, bkey->k_key.lk_key, &tcapa);
+void filter_free_capa_keys(struct filter_obd *filter)
+{
+        struct filter_capa_key *key, *n;
 
-                spin_lock(&filter->fo_capa_lock);
-                memcpy(ocapa->c_bhmac, tcapa.lc_hmac, sizeof(ocapa->c_bhmac));
-                spin_unlock(&filter->fo_capa_lock);
+        spin_lock(&capa_lock);
+        list_for_each_entry_safe(key, n, &filter->fo_capa_keys, k_list) {
+                list_del_init(&key->k_list);
+                OBD_FREE(key, sizeof(*key));
         }
-        goto verify;
-out:
-        RETURN(rc);
+        spin_unlock(&capa_lock);
 }