4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2012, 2014 Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * lustre/ofd/ofd_capa.c
34 * This file provides helper functions for Lustre capability key management and
35 * capability authentication. A capability is a token of authority, which is
36 * distributed by MDT to client upon open/lookup/getattr/setattr and unlink
37 * (this is not needed for new servers because destroying objects on OST is
38 * originated from MDT, which doesn't need capability), and will be packed
39 * into subsequent requests to MDT and OST. Capability key is shared by MDT and
40 * OST, which is used to sign and authenticate capability (HMAC algorithm).
42 * Author: Lai Siyao <lai.siyao@intel.com>
45 #define DEBUG_SUBSYSTEM S_FILTER
47 #include "ofd_internal.h"
49 static inline __u32 ofd_ck_keyid(struct filter_capa_key *key)
51 return key->k_key.lk_keyid;
55 * Update capability key
57 * A new capability key is received from MDT, because MDT only uses the
58 * latest key to sign capability, OFD caches the latest two keys in case client
59 * still helds capability signed with old key.
61 * \param[in] ofd OFD device
62 * \param[in] new new capability key
63 * \retval 0 on success
64 * \retval negative number on error
66 int ofd_update_capa_key(struct ofd_device *ofd, struct lustre_capa_key *new)
68 struct obd_device *obd = ofd_obd(ofd);
69 struct filter_capa_key *k, *keys[2] = { NULL, NULL };
72 spin_lock(&capa_lock);
73 list_for_each_entry(k, &obd->u.filter.fo_capa_keys, k_list) {
74 if (k->k_key.lk_seq != new->lk_seq)
79 if (ofd_ck_keyid(keys[1]) > ofd_ck_keyid(keys[0]))
80 keys[1] = keys[0], keys[0] = k;
85 spin_unlock(&capa_lock);
87 for (i = 0; i < 2; i++) {
90 if (ofd_ck_keyid(keys[i]) != new->lk_keyid)
92 /* maybe because of recovery or other reasons, MDS sent the
93 * the old capability key again.
95 spin_lock(&capa_lock);
96 keys[i]->k_key = *new;
97 spin_unlock(&capa_lock);
103 /* if OSS already have two keys, update the old one */
109 INIT_LIST_HEAD(&k->k_list);
112 spin_lock(&capa_lock);
114 if (list_empty(&k->k_list))
115 list_add(&k->k_list, &obd->u.filter.fo_capa_keys);
116 spin_unlock(&capa_lock);
118 DEBUG_CAPA_KEY(D_SEC, new, "new");
123 * Authenticate capability
125 * OFD authenticate the capability packed in client request. Firstly, it will
126 * lookup from local cache, if found, compare with it, otherwise sign it with
127 * capability key to validate it. If the capability is valid, it will be added
128 * into local cache for later use.
130 * \param[in] exp export for the client
131 * \param[in] fid master fid (on MDT) of the file
132 * \param[in] seq OST sequence extracted from master fid
133 * \param[in] capa capability extracted from client request
134 * \param[in] opc opcode the caller requested
135 * \retval 0 on success
136 * \retval negative number on error
138 int ofd_auth_capa(struct obd_export *exp, const struct lu_fid *fid,
139 u64 seq, struct lustre_capa *capa, __u64 opc)
141 struct filter_obd *filter = &exp->exp_obd->u.filter;
142 struct filter_capa_key *k;
143 struct lustre_capa_key key;
146 int keys_ready = 0, key_found = 0, rc = 0;
150 /* skip capa check for llog and obdecho */
151 if (!fid_seq_is_mdt(seq))
154 /* capability is disabled */
155 if (!filter->fo_fl_oss_capa)
158 if (!(exp_connect_flags(exp) & OBD_CONNECT_OSS_CAPA))
163 CERROR("seq/fid/opc "LPU64"/"DFID"/"LPX64
164 ": no capability has been passed\n",
165 seq, PFID(fid), opc);
167 CERROR("seq/opc "LPU64"/"LPX64
168 ": no capability has been passed\n",
173 if (opc == CAPA_OPC_OSS_READ) {
174 if (!(capa->lc_opc & CAPA_OPC_OSS_RW))
176 } else if (!capa_opc_supported(capa, opc)) {
181 DEBUG_CAPA(D_ERROR, capa, "opc "LPX64" not supported by", opc);
185 oc = capa_lookup(filter->fo_capa_hash, capa, 0);
187 spin_lock(&oc->c_lock);
188 if (capa_is_expired(oc)) {
189 DEBUG_CAPA(D_ERROR, capa, "expired");
192 spin_unlock(&oc->c_lock);
198 if (capa_is_expired_sec(capa)) {
199 DEBUG_CAPA(D_ERROR, capa, "expired");
203 spin_lock(&capa_lock);
204 list_for_each_entry(k, &filter->fo_capa_keys, k_list) {
205 if (k->k_key.lk_seq == seq) {
207 if (k->k_key.lk_keyid == capa_keyid(capa)) {
214 spin_unlock(&capa_lock);
217 CDEBUG(D_SEC, "MDS hasn't propagated capability keys yet, "
223 DEBUG_CAPA(D_ERROR, capa, "no matched capability key for");
227 OBD_ALLOC(hmac, CAPA_HMAC_MAX_LEN);
231 rc = capa_hmac(hmac, capa, key.lk_key);
233 DEBUG_CAPA(D_ERROR, capa, "HMAC failed: rc %d", rc);
234 OBD_FREE(hmac, CAPA_HMAC_MAX_LEN);
238 rc = memcmp(hmac, capa->lc_hmac, CAPA_HMAC_MAX_LEN);
239 OBD_FREE(hmac, CAPA_HMAC_MAX_LEN);
241 DEBUG_CAPA_KEY(D_ERROR, &key, "calculate HMAC with ");
242 DEBUG_CAPA(D_ERROR, capa, "HMAC mismatch");
246 /* store in capa hash */
247 oc = capa_add(filter->fo_capa_hash, capa);
253 * Free capability keys
255 * OFD free cached capability keys when OFD device is destroyed.
257 * \param[in] ofd OFD device
259 void ofd_free_capa_keys(struct ofd_device *ofd)
261 struct obd_device *obd = ofd_obd(ofd);
262 struct filter_capa_key *key, *n;
264 spin_lock(&capa_lock);
265 list_for_each_entry_safe(key, n, &obd->u.filter.fo_capa_keys, k_list) {
266 list_del_init(&key->k_list);
269 spin_unlock(&capa_lock);