Whamcloud - gitweb
- make noise if capa hasn't been passed even
[fs/lustre-release.git] / lustre / obdfilter / filter_capa.c
index 3f52db0..09208b9 100644 (file)
 
 #include "filter_internal.h"
 
+/*
+ * FIXME
+ * keep this as simple as possible. we suppose the blacklist usually
+ * be empry or very short (<5), since long term blacklist should be
+ * done on MDS side. A more sophisticated blacklist will be implemented
+ * later.
+ *
+ * note blacklist didn't take effect when OSS capability disabled. this
+ * looks reasonable to me.
+ */
+#define BLACKLIST_MAX   (32)
+static int nblacklist = 0;
+static uid_t blacklist[BLACKLIST_MAX];
+static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
+
+int blacklist_display(char *buf, int bufsize)
+{
+        char one[16];
+        int i;
+        LASSERT(buf);
+
+        buf[0] = '\0';
+        spin_lock(&blacklist_lock);
+        for (i = 0; i < nblacklist; i++) {
+                snprintf(one, 16, "%u\n", blacklist[i]);
+                strncat(buf, one, bufsize);
+        }
+        spin_unlock(&blacklist_lock);
+        return strnlen(buf, bufsize);
+}
+
+void blacklist_add(uid_t uid)
+{
+        int i;
+
+        spin_lock(&blacklist_lock);
+        if (nblacklist == BLACKLIST_MAX) {
+                CERROR("can't add more in blacklist\n");
+                spin_unlock(&blacklist_lock);
+                return;
+        }
+
+        for (i = 0; i < nblacklist; i++) {
+                if (blacklist[i] == uid) {
+                        spin_unlock(&blacklist_lock);
+                        return;
+                }
+        }
+
+        blacklist[nblacklist++] = uid;
+        spin_unlock(&blacklist_lock);
+}
+
+void blacklist_del(uid_t uid)
+{
+        int i;
+
+        spin_lock(&blacklist_lock);
+        for (i = 0; i < nblacklist; i++) {
+                if (blacklist[i] == uid) {
+                        nblacklist--;
+                        while (i < nblacklist) {
+                                blacklist[i] = blacklist[i+1];
+                                i++;
+                        }
+                        spin_unlock(&blacklist_lock);
+                        return;
+                }
+        }
+        spin_unlock(&blacklist_lock);
+}
+
+int blacklist_check(uid_t uid)
+{
+        int i, rc = 0;
+
+        spin_lock(&blacklist_lock);
+        for (i = 0; i < nblacklist; i++) {
+                if (blacklist[i] == uid) {
+                        rc = 1;
+                        break;
+                }
+        }
+        spin_unlock(&blacklist_lock);
+        return rc;
+}
+
+
 void filter_free_capa_keys(struct filter_obd *filter)
 {
         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(&key->k_list);
+                list_del_init(&key->k_list);
                 OBD_FREE(key, sizeof(*key));
         }
+        spin_unlock(&filter->fo_capa_lock);
 }
 
 int filter_update_capa_key(struct obd_device *obd, struct lustre_capa_key *key)
@@ -53,12 +143,13 @@ int filter_update_capa_key(struct obd_device *obd, struct lustre_capa_key *key)
 
         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)) {
-                        if (rkey == NULL)
-                                rkey = tmp;
-                        else
-                                bkey = tmp;
-                }
+                if (tmp->k_key.lk_mdsid != le32_to_cpu(key->lk_mdsid))
+                        continue;
+
+                if (rkey == NULL)
+                        rkey = tmp;
+                else
+                        bkey = tmp;
         }
         spin_unlock(&filter->fo_capa_lock);
 
@@ -68,28 +159,57 @@ int filter_update_capa_key(struct obd_device *obd, struct lustre_capa_key *key)
                 bkey = tmp;
         }
 
-        if (!bkey || !tmp) {
+        if (bkey) {
+                tmp = bkey;
+
+                DEBUG_CAPA_KEY(D_INFO, &tmp->k_key, "filter update");
+        } else {
                 OBD_ALLOC(tmp, sizeof(*tmp));
                 if (!tmp)
                         GOTO(out, rc = -ENOMEM);
 
-                spin_lock(&filter->fo_capa_lock);
-                list_add_tail(&tmp->k_list, &filter->fo_capa_keys);
-                spin_unlock(&filter->fo_capa_lock);
+                DEBUG_CAPA_KEY(D_INFO, &tmp->k_key, "filter new");
         }
 
         /* 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_capa(int cmd, struct obd_export *exp,
-                       struct lustre_capa *capa)
+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);
+        }
+
+        RETURN(0);
+}
+
+int
+filter_verify_capa(int cmd, struct obd_export *exp, struct lustre_capa *capa)
 {
         struct obd_device *obd = exp->exp_obd;
         struct filter_obd *filter = &obd->u.filter;
@@ -98,30 +218,41 @@ int filter_verify_capa(int cmd, struct obd_export *exp,
         struct filter_capa_key *rkey = NULL, *bkey = NULL, *tmp;
         __u8 hmac_key[CAPA_KEY_LEN];
         int rc = 0;
-        ENTRY;
 
         /* capability is disabled */
         if (filter->fo_capa_stat == 0)
                 RETURN(0);
 
-        if (capa == NULL)
+        ENTRY;
+        if (capa == NULL) {
+                CDEBUG(D_ERROR, "no capa has been passed\n");
                 RETURN(-EACCES);
+        }
 
-        if (cmd == OBD_BRW_WRITE && !(capa->lc_op & MAY_WRITE))
+        if (blacklist_check(capa->lc_uid)) {
+                DEBUG_CAPA(D_ERROR, capa, "found in blacklist\n");
                 RETURN(-EACCES);
-        if (cmd == OBD_BRW_READ && !(capa->lc_op & (MAY_WRITE | MAY_READ)))
+        }
+
+        if (cmd == OBD_BRW_WRITE && !(capa->lc_op & (CAPA_WRITE | CAPA_TRUNC))) {
+                DEBUG_CAPA(D_ERROR, capa, "have no write access\n");
+                RETURN(-EACCES);
+        }
+        if (cmd == OBD_BRW_READ && !(capa->lc_op & (CAPA_WRITE | CAPA_READ))) {
+                DEBUG_CAPA(D_ERROR, capa, "have no read access\n");
                 RETURN(-EACCES);
+        }
 
         if (OBD_FAIL_CHECK(OBD_FAIL_FILTER_VERIFY_CAPA))
                 RETURN(-EACCES);
 
-        /* TODO: get fid from EA, and verify that against capa */
-
-        if (capa_expired(capa))
+        if (capa_expired(capa)) {
+                DEBUG_CAPA(D_INFO | D_ERROR, capa, "expired");
                 RETURN(-ESTALE);
+        }
 
         ocapa = capa_get(capa->lc_uid, capa->lc_op, capa->lc_mdsid,
-                         capa->lc_ino, FILTER_CAPA, NULL, NULL, NULL);
+                         capa->lc_ino, FILTER_CAPA);
 verify:
         if (ocapa) {
                 /* fo_capa_lock protects capa too */
@@ -133,19 +264,24 @@ verify:
                         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);
+                        /* ocapa is obsolete too */
+                        ocapa->c_bvalid = 0;
+                        goto new_capa;
+                }
+
+                if (rc && __capa_is_to_expire(ocapa)) {
+                        /* client should use new expiry now */
+                        ocapa->c_bvalid = 0;
                         goto new_capa;
                 }
                 spin_unlock(&filter->fo_capa_lock);
 
-                capa_put(ocapa, FILTER_CAPA);
+                capa_put(ocapa);
                 RETURN(rc ? -EACCES : 0);
         }
 
-new_capa:
         spin_lock(&filter->fo_capa_lock);
+new_capa:
         list_for_each_entry(tmp, &filter->fo_capa_keys, k_list) {
                 if (tmp->k_key.lk_mdsid == capa->lc_mdsid) {
                         if (rkey == NULL)
@@ -177,8 +313,7 @@ new_capa:
         capa_hmac(filter->fo_capa_hmac, hmac_key, &tcapa);
 
         /* store in capa cache */
-        ocapa = capa_get(capa->lc_uid, capa->lc_op, capa->lc_mdsid,
-                         capa->lc_ino, FILTER_CAPA, capa, NULL, NULL);
+        ocapa = capa_renew(capa, FILTER_CAPA);
         if (!ocapa)
                 GOTO(out, rc = -ENOMEM);
 
@@ -193,6 +328,7 @@ new_capa:
 
                 spin_lock(&filter->fo_capa_lock);
                 memcpy(ocapa->c_bhmac, tcapa.lc_hmac, sizeof(ocapa->c_bhmac));
+                ocapa->c_bvalid = 1;
                 spin_unlock(&filter->fo_capa_lock);
         }
         goto verify;