Whamcloud - gitweb
Land b_hd_capa onto HEAD (20050809_1942)
[fs/lustre-release.git] / lustre / obdfilter / filter_capa.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2004, 2005 Cluster File Systems, Inc.
5  *
6  * Author: Lai Siyao <lsy@clusterfs.com>
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #define DEBUG_SUBSYSTEM S_FILTER
25
26 #include <linux/fs.h>
27 #include <linux/version.h>
28 #include <asm/uaccess.h>
29 #include <linux/file.h>
30 #include <linux/kmod.h>
31
32 #include <linux/lustre_fsfilt.h>
33 #include <linux/lustre_sec.h>
34
35 #include "filter_internal.h"
36
37 void filter_free_capa_keys(struct filter_obd *filter)
38 {
39         struct filter_capa_key *key, *n;
40
41         list_for_each_entry_safe(key, n, &filter->fo_capa_keys, k_list) {
42                 list_del(&key->k_list);
43                 OBD_FREE(key, sizeof(*key));
44         }
45 }
46
47 int filter_update_capa_key(struct obd_device *obd, struct lustre_capa_key *key)
48 {
49         struct filter_obd *filter = &obd->u.filter;
50         struct filter_capa_key *tmp = NULL, *rkey = NULL, *bkey = NULL;
51         int rc = 0;
52         ENTRY;
53
54         spin_lock(&filter->fo_capa_lock);
55         list_for_each_entry(tmp, &filter->fo_capa_keys, k_list) {
56                 if (tmp->k_key.lk_mdsid == le32_to_cpu(key->lk_mdsid)) {
57                         if (rkey == NULL)
58                                 rkey = tmp;
59                         else
60                                 bkey = tmp;
61                 }
62         }
63         spin_unlock(&filter->fo_capa_lock);
64
65         if (rkey && bkey && capa_key_cmp(&rkey->k_key, &bkey->k_key) < 0) {
66                 tmp = rkey;
67                 rkey = bkey;
68                 bkey = tmp;
69         }
70
71         if (!bkey || !tmp) {
72                 OBD_ALLOC(tmp, sizeof(*tmp));
73                 if (!tmp)
74                         GOTO(out, rc = -ENOMEM);
75
76                 spin_lock(&filter->fo_capa_lock);
77                 list_add_tail(&tmp->k_list, &filter->fo_capa_keys);
78                 spin_unlock(&filter->fo_capa_lock);
79         }
80
81         /* fields in lustre_capa_key are in cpu order */
82         tmp->k_key.lk_mdsid = le32_to_cpu(key->lk_mdsid);
83         tmp->k_key.lk_keyid = le32_to_cpu(key->lk_keyid);
84         tmp->k_key.lk_expiry = le64_to_cpu(key->lk_expiry);
85         memcpy(&tmp->k_key.lk_key, key->lk_key, sizeof(key->lk_key));
86
87 out:
88         RETURN(rc);
89 }
90
91 int filter_verify_capa(int cmd, struct obd_export *exp,
92                        struct lustre_capa *capa)
93 {
94         struct obd_device *obd = exp->exp_obd;
95         struct filter_obd *filter = &obd->u.filter;
96         struct obd_capa *ocapa;
97         struct lustre_capa tcapa;
98         struct filter_capa_key *rkey = NULL, *bkey = NULL, *tmp;
99         __u8 hmac_key[CAPA_KEY_LEN];
100         int rc = 0;
101         ENTRY;
102
103         /* capability is disabled */
104         if (filter->fo_capa_stat == 0)
105                 RETURN(0);
106
107         if (capa == NULL)
108                 RETURN(-EACCES);
109
110         if (cmd == OBD_BRW_WRITE && !(capa->lc_op & MAY_WRITE))
111                 RETURN(-EACCES);
112         if (cmd == OBD_BRW_READ && !(capa->lc_op & (MAY_WRITE | MAY_READ)))
113                 RETURN(-EACCES);
114
115         if (OBD_FAIL_CHECK(OBD_FAIL_FILTER_VERIFY_CAPA))
116                 RETURN(-EACCES);
117
118         /* TODO: get fid from EA, and verify that against capa */
119
120         if (capa_expired(capa))
121                 RETURN(-ESTALE);
122
123         ocapa = capa_get(capa->lc_uid, capa->lc_op, capa->lc_mdsid,
124                          capa->lc_ino, FILTER_CAPA, NULL, NULL, NULL);
125 verify:
126         if (ocapa) {
127                 /* fo_capa_lock protects capa too */
128                 spin_lock(&filter->fo_capa_lock);
129                 if (capa->lc_keyid == ocapa->c_capa.lc_keyid) {
130                         rc = memcmp(capa, &ocapa->c_capa, sizeof(*capa));
131                 } else if (ocapa->c_bvalid &&
132                            capa->lc_keyid == ocapa->c_bkeyid) {
133                         rc = memcmp(capa->lc_hmac, ocapa->c_bhmac,
134                                     sizeof(capa->lc_hmac));
135                 } else {
136                         /* ocapa is obsolete */
137                         capa_put(ocapa, FILTER_CAPA);
138                         spin_unlock(&filter->fo_capa_lock);
139                         goto new_capa;
140                 }
141                 spin_unlock(&filter->fo_capa_lock);
142
143                 capa_put(ocapa, FILTER_CAPA);
144                 RETURN(rc ? -EACCES : 0);
145         }
146
147 new_capa:
148         spin_lock(&filter->fo_capa_lock);
149         list_for_each_entry(tmp, &filter->fo_capa_keys, k_list) {
150                 if (tmp->k_key.lk_mdsid == capa->lc_mdsid) {
151                         if (rkey == NULL)
152                                 rkey = tmp;
153                         else
154                                 bkey = tmp;
155                 }
156         }
157
158         if (rkey && bkey && capa_key_cmp(&rkey->k_key, &bkey->k_key) < 0) {
159                 tmp = rkey;
160                 rkey = bkey;
161                 bkey = tmp;
162         }
163
164         if ((!rkey || rkey->k_key.lk_keyid != capa->lc_keyid) &&
165             (!bkey || bkey->k_key.lk_keyid != capa->lc_keyid)) {
166                 spin_unlock(&filter->fo_capa_lock);
167                 GOTO(out, rc = -ESTALE);
168         }
169
170         LASSERT(rkey);
171
172         memcpy(&tcapa, capa, sizeof(tcapa));
173         tcapa.lc_keyid = rkey->k_key.lk_keyid;
174         memcpy(hmac_key, rkey->k_key.lk_key, sizeof(hmac_key));
175         spin_unlock(&filter->fo_capa_lock);
176
177         capa_hmac(filter->fo_capa_hmac, hmac_key, &tcapa);
178
179         /* store in capa cache */
180         ocapa = capa_get(capa->lc_uid, capa->lc_op, capa->lc_mdsid,
181                          capa->lc_ino, FILTER_CAPA, capa, NULL, NULL);
182         if (!ocapa)
183                 GOTO(out, rc = -ENOMEM);
184
185         if (bkey) {
186                 spin_lock(&filter->fo_capa_lock);
187                 tcapa.lc_keyid = bkey->k_key.lk_keyid;
188                 memcpy(hmac_key, bkey->k_key.lk_key, sizeof(hmac_key));
189                 ocapa->c_bkeyid = bkey->k_key.lk_keyid;
190                 spin_unlock(&filter->fo_capa_lock);
191
192                 capa_hmac(filter->fo_capa_hmac, bkey->k_key.lk_key, &tcapa);
193
194                 spin_lock(&filter->fo_capa_lock);
195                 memcpy(ocapa->c_bhmac, tcapa.lc_hmac, sizeof(ocapa->c_bhmac));
196                 spin_unlock(&filter->fo_capa_lock);
197         }
198         goto verify;
199 out:
200         RETURN(rc);
201 }