#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)
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);
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;
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 */
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)
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);
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;