Whamcloud - gitweb
9a3b8139e2fae65845424ec27d5e08b1d890680b
[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         spin_lock(&filter->fo_capa_lock);
42         list_for_each_entry_safe(key, n, &filter->fo_capa_keys, k_list) {
43                 list_del_init(&key->k_list);
44                 OBD_FREE(key, sizeof(*key));
45         }
46         spin_unlock(&filter->fo_capa_lock);
47 }
48
49 int filter_update_capa_key(struct obd_device *obd, struct lustre_capa_key *key)
50 {
51         struct filter_obd *filter = &obd->u.filter;
52         struct filter_capa_key *tmp = NULL, *rkey = NULL, *bkey = NULL;
53         int rc = 0;
54         ENTRY;
55
56         spin_lock(&filter->fo_capa_lock);
57         list_for_each_entry(tmp, &filter->fo_capa_keys, k_list) {
58                 if (tmp->k_key.lk_mdsid != le32_to_cpu(key->lk_mdsid))
59                         continue;
60
61                 if (rkey == NULL)
62                         rkey = tmp;
63                 else
64                         bkey = tmp;
65         }
66         spin_unlock(&filter->fo_capa_lock);
67
68         if (rkey && bkey && capa_key_cmp(&rkey->k_key, &bkey->k_key) < 0) {
69                 tmp = rkey;
70                 rkey = bkey;
71                 bkey = tmp;
72         }
73
74         if (bkey) {
75                 tmp = bkey;
76
77                 DEBUG_CAPA_KEY(D_INFO, &tmp->k_key, "filter update");
78         } else {
79                 OBD_ALLOC(tmp, sizeof(*tmp));
80                 if (!tmp)
81                         GOTO(out, rc = -ENOMEM);
82
83                 DEBUG_CAPA_KEY(D_INFO, &tmp->k_key, "filter new");
84         }
85
86         /* fields in lustre_capa_key are in cpu order */
87         spin_lock(&filter->fo_capa_lock);
88         tmp->k_key.lk_mdsid = le32_to_cpu(key->lk_mdsid);
89         tmp->k_key.lk_keyid = le32_to_cpu(key->lk_keyid);
90         tmp->k_key.lk_expiry = le64_to_cpu(key->lk_expiry);
91         memcpy(&tmp->k_key.lk_key, key->lk_key, sizeof(key->lk_key));
92
93         if (!bkey)
94                 list_add_tail(&tmp->k_list, &filter->fo_capa_keys);
95         spin_unlock(&filter->fo_capa_lock);
96 out:
97         RETURN(rc);
98 }
99
100 int filter_verify_fid(struct obd_export *exp, struct inode *inode,
101                       struct lustre_capa *capa)
102 {
103         struct lustre_id fid;
104         int rc;
105
106         if (!capa)
107                 return 0;
108
109         ENTRY;
110         rc = fsfilt_get_md(exp->exp_obd, inode, &fid, sizeof(fid), EA_SID);
111         if (rc < 0) {
112                 CERROR("get fid from object failed! rc:%d\n", rc);
113                 RETURN(rc);
114         } else if (rc > 0) {
115                 if (capa->lc_mdsid != id_group(&fid) ||
116                     capa->lc_ino != id_ino(&fid))
117                         RETURN(-EINVAL);
118         }
119
120         RETURN(0);
121 }
122
123 int
124 filter_verify_capa(int cmd, struct obd_export *exp, struct lustre_capa *capa)
125 {
126         struct obd_device *obd = exp->exp_obd;
127         struct filter_obd *filter = &obd->u.filter;
128         struct obd_capa *ocapa;
129         struct lustre_capa tcapa;
130         struct filter_capa_key *rkey = NULL, *bkey = NULL, *tmp;
131         __u8 hmac_key[CAPA_KEY_LEN];
132         int rc = 0;
133
134         /* capability is disabled */
135         if (filter->fo_capa_stat == 0)
136                 RETURN(0);
137
138         ENTRY;
139         if (capa == NULL)
140                 RETURN(-EACCES);
141
142         if (cmd == OBD_BRW_WRITE && capa->lc_op != MAY_WRITE)
143                 RETURN(-EACCES);
144         if (cmd == OBD_BRW_READ && !(capa->lc_op & (MAY_WRITE | MAY_READ)))
145                 RETURN(-EACCES);
146
147         if (OBD_FAIL_CHECK(OBD_FAIL_FILTER_VERIFY_CAPA))
148                 RETURN(-EACCES);
149
150         if (capa_expired(capa))
151                 RETURN(-ESTALE);
152
153         ocapa = capa_get(capa->lc_uid, capa->lc_op, capa->lc_mdsid,
154                          capa->lc_ino, FILTER_CAPA, NULL, NULL, NULL);
155 verify:
156         if (ocapa) {
157                 /* fo_capa_lock protects capa too */
158                 spin_lock(&filter->fo_capa_lock);
159                 if (capa->lc_keyid == ocapa->c_capa.lc_keyid) {
160                         rc = memcmp(capa, &ocapa->c_capa, sizeof(*capa));
161                 } else if (ocapa->c_bvalid &&
162                            capa->lc_keyid == ocapa->c_bkeyid) {
163                         rc = memcmp(capa->lc_hmac, ocapa->c_bhmac,
164                                     sizeof(capa->lc_hmac));
165                 } else {
166                         /* ocapa is obsolete */
167                         capa_put(ocapa, FILTER_CAPA);
168                         spin_unlock(&filter->fo_capa_lock);
169                         goto new_capa;
170                 }
171                 spin_unlock(&filter->fo_capa_lock);
172
173                 capa_put(ocapa, FILTER_CAPA);
174                 RETURN(rc ? -EACCES : 0);
175         }
176
177 new_capa:
178         spin_lock(&filter->fo_capa_lock);
179         list_for_each_entry(tmp, &filter->fo_capa_keys, k_list) {
180                 if (tmp->k_key.lk_mdsid == capa->lc_mdsid) {
181                         if (rkey == NULL)
182                                 rkey = tmp;
183                         else
184                                 bkey = tmp;
185                 }
186         }
187
188         if (rkey && bkey && capa_key_cmp(&rkey->k_key, &bkey->k_key) < 0) {
189                 tmp = rkey;
190                 rkey = bkey;
191                 bkey = tmp;
192         }
193
194         if ((!rkey || rkey->k_key.lk_keyid != capa->lc_keyid) &&
195             (!bkey || bkey->k_key.lk_keyid != capa->lc_keyid)) {
196                 spin_unlock(&filter->fo_capa_lock);
197                 GOTO(out, rc = -ESTALE);
198         }
199
200         LASSERT(rkey);
201
202         memcpy(&tcapa, capa, sizeof(tcapa));
203         tcapa.lc_keyid = rkey->k_key.lk_keyid;
204         memcpy(hmac_key, rkey->k_key.lk_key, sizeof(hmac_key));
205         spin_unlock(&filter->fo_capa_lock);
206
207         capa_hmac(filter->fo_capa_hmac, hmac_key, &tcapa);
208
209         /* store in capa cache */
210         ocapa = capa_get(capa->lc_uid, capa->lc_op, capa->lc_mdsid,
211                          capa->lc_ino, FILTER_CAPA, capa, NULL, NULL);
212         if (!ocapa)
213                 GOTO(out, rc = -ENOMEM);
214
215         if (bkey) {
216                 spin_lock(&filter->fo_capa_lock);
217                 tcapa.lc_keyid = bkey->k_key.lk_keyid;
218                 memcpy(hmac_key, bkey->k_key.lk_key, sizeof(hmac_key));
219                 ocapa->c_bkeyid = bkey->k_key.lk_keyid;
220                 spin_unlock(&filter->fo_capa_lock);
221
222                 capa_hmac(filter->fo_capa_hmac, bkey->k_key.lk_key, &tcapa);
223
224                 spin_lock(&filter->fo_capa_lock);
225                 memcpy(ocapa->c_bhmac, tcapa.lc_hmac, sizeof(ocapa->c_bhmac));
226                 spin_unlock(&filter->fo_capa_lock);
227         }
228         goto verify;
229 out:
230         RETURN(rc);
231 }