Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
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. | |
9 | * | |
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). | |
15 | * | |
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.sun.com/software/products/lustre/docs/GPLv2.pdf | |
19 | * | |
20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
21 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
22 | * have any questions. | |
23 | * | |
24 | * GPL HEADER END | |
25 | */ | |
26 | /* | |
27 | * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
30 | * Copyright (c) 2011, 2012, Intel Corporation. | |
31 | */ | |
32 | /* | |
33 | * This file is part of Lustre, http://www.lustre.org/ | |
34 | * Lustre is a trademark of Sun Microsystems, Inc. | |
35 | * | |
36 | * lustre/ptlrpc/sec_null.c | |
37 | * | |
38 | * Author: Eric Mei <ericm@clusterfs.com> | |
39 | */ | |
40 | ||
41 | #define DEBUG_SUBSYSTEM S_SEC | |
42 | ||
43 | ||
e27db149 GKH |
44 | #include "../include/obd_support.h" |
45 | #include "../include/obd_cksum.h" | |
46 | #include "../include/obd_class.h" | |
47 | #include "../include/lustre_net.h" | |
48 | #include "../include/lustre_sec.h" | |
d7e09d03 PT |
49 | |
50 | static struct ptlrpc_sec_policy null_policy; | |
51 | static struct ptlrpc_sec null_sec; | |
52 | static struct ptlrpc_cli_ctx null_cli_ctx; | |
53 | static struct ptlrpc_svc_ctx null_svc_ctx; | |
54 | ||
55 | /* | |
56 | * we can temporarily use the topmost 8-bits of lm_secflvr to identify | |
57 | * the source sec part. | |
58 | */ | |
59 | static inline | |
60 | void null_encode_sec_part(struct lustre_msg *msg, enum lustre_sec_part sp) | |
61 | { | |
62 | msg->lm_secflvr |= (((__u32) sp) & 0xFF) << 24; | |
63 | } | |
64 | ||
65 | static inline | |
66 | enum lustre_sec_part null_decode_sec_part(struct lustre_msg *msg) | |
67 | { | |
68 | return (msg->lm_secflvr >> 24) & 0xFF; | |
69 | } | |
70 | ||
71 | static int null_ctx_refresh(struct ptlrpc_cli_ctx *ctx) | |
72 | { | |
73 | /* should never reach here */ | |
74 | LBUG(); | |
75 | return 0; | |
76 | } | |
77 | ||
78 | static | |
79 | int null_ctx_sign(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req) | |
80 | { | |
81 | req->rq_reqbuf->lm_secflvr = SPTLRPC_FLVR_NULL; | |
82 | ||
83 | if (!req->rq_import->imp_dlm_fake) { | |
84 | struct obd_device *obd = req->rq_import->imp_obd; | |
85 | null_encode_sec_part(req->rq_reqbuf, | |
86 | obd->u.cli.cl_sp_me); | |
87 | } | |
88 | req->rq_reqdata_len = req->rq_reqlen; | |
89 | return 0; | |
90 | } | |
91 | ||
92 | static | |
93 | int null_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req) | |
94 | { | |
d0bfef31 | 95 | __u32 cksums, cksumc; |
d7e09d03 PT |
96 | |
97 | LASSERT(req->rq_repdata); | |
98 | ||
99 | req->rq_repmsg = req->rq_repdata; | |
100 | req->rq_replen = req->rq_repdata_len; | |
101 | ||
102 | if (req->rq_early) { | |
103 | cksums = lustre_msg_get_cksum(req->rq_repdata); | |
d7e09d03 | 104 | cksumc = lustre_msg_calc_cksum(req->rq_repmsg); |
d7e09d03 PT |
105 | if (cksumc != cksums) { |
106 | CDEBUG(D_SEC, | |
107 | "early reply checksum mismatch: %08x != %08x\n", | |
108 | cksumc, cksums); | |
109 | return -EINVAL; | |
110 | } | |
111 | } | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
116 | static | |
117 | struct ptlrpc_sec *null_create_sec(struct obd_import *imp, | |
118 | struct ptlrpc_svc_ctx *svc_ctx, | |
119 | struct sptlrpc_flavor *sf) | |
120 | { | |
121 | LASSERT(SPTLRPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_NULL); | |
122 | ||
123 | /* general layer has take a module reference for us, because we never | |
124 | * really destroy the sec, simply release the reference here. | |
125 | */ | |
126 | sptlrpc_policy_put(&null_policy); | |
127 | return &null_sec; | |
128 | } | |
129 | ||
130 | static | |
131 | void null_destroy_sec(struct ptlrpc_sec *sec) | |
132 | { | |
133 | LASSERT(sec == &null_sec); | |
134 | } | |
135 | ||
136 | static | |
137 | struct ptlrpc_cli_ctx *null_lookup_ctx(struct ptlrpc_sec *sec, | |
138 | struct vfs_cred *vcred, | |
139 | int create, int remove_dead) | |
140 | { | |
141 | atomic_inc(&null_cli_ctx.cc_refcount); | |
142 | return &null_cli_ctx; | |
143 | } | |
144 | ||
145 | static | |
146 | int null_flush_ctx_cache(struct ptlrpc_sec *sec, | |
147 | uid_t uid, | |
148 | int grace, int force) | |
149 | { | |
150 | return 0; | |
151 | } | |
152 | ||
153 | static | |
154 | int null_alloc_reqbuf(struct ptlrpc_sec *sec, | |
155 | struct ptlrpc_request *req, | |
156 | int msgsize) | |
157 | { | |
158 | if (!req->rq_reqbuf) { | |
159 | int alloc_size = size_roundup_power2(msgsize); | |
160 | ||
161 | LASSERT(!req->rq_pool); | |
ee0ec194 | 162 | req->rq_reqbuf = libcfs_kvzalloc(alloc_size, GFP_NOFS); |
d7e09d03 PT |
163 | if (!req->rq_reqbuf) |
164 | return -ENOMEM; | |
165 | ||
166 | req->rq_reqbuf_len = alloc_size; | |
167 | } else { | |
168 | LASSERT(req->rq_pool); | |
169 | LASSERT(req->rq_reqbuf_len >= msgsize); | |
170 | memset(req->rq_reqbuf, 0, msgsize); | |
171 | } | |
172 | ||
173 | req->rq_reqmsg = req->rq_reqbuf; | |
174 | return 0; | |
175 | } | |
176 | ||
177 | static | |
178 | void null_free_reqbuf(struct ptlrpc_sec *sec, | |
179 | struct ptlrpc_request *req) | |
180 | { | |
181 | if (!req->rq_pool) { | |
182 | LASSERTF(req->rq_reqmsg == req->rq_reqbuf, | |
183 | "req %p: reqmsg %p is not reqbuf %p in null sec\n", | |
184 | req, req->rq_reqmsg, req->rq_reqbuf); | |
185 | LASSERTF(req->rq_reqbuf_len >= req->rq_reqlen, | |
186 | "req %p: reqlen %d should smaller than buflen %d\n", | |
187 | req, req->rq_reqlen, req->rq_reqbuf_len); | |
188 | ||
ee0ec194 | 189 | kvfree(req->rq_reqbuf); |
d7e09d03 PT |
190 | req->rq_reqbuf = NULL; |
191 | req->rq_reqbuf_len = 0; | |
192 | } | |
193 | } | |
194 | ||
195 | static | |
196 | int null_alloc_repbuf(struct ptlrpc_sec *sec, | |
197 | struct ptlrpc_request *req, | |
198 | int msgsize) | |
199 | { | |
200 | /* add space for early replied */ | |
201 | msgsize += lustre_msg_early_size(); | |
202 | ||
203 | msgsize = size_roundup_power2(msgsize); | |
204 | ||
ee0ec194 | 205 | req->rq_repbuf = libcfs_kvzalloc(msgsize, GFP_NOFS); |
d7e09d03 PT |
206 | if (!req->rq_repbuf) |
207 | return -ENOMEM; | |
208 | ||
209 | req->rq_repbuf_len = msgsize; | |
210 | return 0; | |
211 | } | |
212 | ||
213 | static | |
214 | void null_free_repbuf(struct ptlrpc_sec *sec, | |
215 | struct ptlrpc_request *req) | |
216 | { | |
217 | LASSERT(req->rq_repbuf); | |
218 | ||
ee0ec194 | 219 | kvfree(req->rq_repbuf); |
d7e09d03 PT |
220 | req->rq_repbuf = NULL; |
221 | req->rq_repbuf_len = 0; | |
222 | } | |
223 | ||
224 | static | |
225 | int null_enlarge_reqbuf(struct ptlrpc_sec *sec, | |
226 | struct ptlrpc_request *req, | |
227 | int segment, int newsize) | |
228 | { | |
d0bfef31 CH |
229 | struct lustre_msg *newbuf; |
230 | struct lustre_msg *oldbuf = req->rq_reqmsg; | |
231 | int oldsize, newmsg_size, alloc_size; | |
d7e09d03 PT |
232 | |
233 | LASSERT(req->rq_reqbuf); | |
234 | LASSERT(req->rq_reqbuf == req->rq_reqmsg); | |
235 | LASSERT(req->rq_reqbuf_len >= req->rq_reqlen); | |
236 | LASSERT(req->rq_reqlen == lustre_packed_msg_size(oldbuf)); | |
237 | ||
238 | /* compute new message size */ | |
239 | oldsize = req->rq_reqbuf->lm_buflens[segment]; | |
240 | req->rq_reqbuf->lm_buflens[segment] = newsize; | |
241 | newmsg_size = lustre_packed_msg_size(oldbuf); | |
242 | req->rq_reqbuf->lm_buflens[segment] = oldsize; | |
243 | ||
244 | /* request from pool should always have enough buffer */ | |
245 | LASSERT(!req->rq_pool || req->rq_reqbuf_len >= newmsg_size); | |
246 | ||
247 | if (req->rq_reqbuf_len < newmsg_size) { | |
248 | alloc_size = size_roundup_power2(newmsg_size); | |
249 | ||
ee0ec194 | 250 | newbuf = libcfs_kvzalloc(alloc_size, GFP_NOFS); |
d7e09d03 PT |
251 | if (newbuf == NULL) |
252 | return -ENOMEM; | |
253 | ||
61d7258b OD |
254 | /* Must lock this, so that otherwise unprotected change of |
255 | * rq_reqmsg is not racing with parallel processing of | |
256 | * imp_replay_list traversing threads. See LU-3333 | |
257 | * This is a bandaid at best, we really need to deal with this | |
258 | * in request enlarging code before unpacking that's already | |
259 | * there */ | |
260 | if (req->rq_import) | |
261 | spin_lock(&req->rq_import->imp_lock); | |
d7e09d03 PT |
262 | memcpy(newbuf, req->rq_reqbuf, req->rq_reqlen); |
263 | ||
ee0ec194 | 264 | kvfree(req->rq_reqbuf); |
d7e09d03 PT |
265 | req->rq_reqbuf = req->rq_reqmsg = newbuf; |
266 | req->rq_reqbuf_len = alloc_size; | |
61d7258b OD |
267 | |
268 | if (req->rq_import) | |
269 | spin_unlock(&req->rq_import->imp_lock); | |
d7e09d03 PT |
270 | } |
271 | ||
272 | _sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize); | |
273 | req->rq_reqlen = newmsg_size; | |
274 | ||
275 | return 0; | |
276 | } | |
277 | ||
278 | static struct ptlrpc_svc_ctx null_svc_ctx = { | |
279 | .sc_refcount = ATOMIC_INIT(1), | |
280 | .sc_policy = &null_policy, | |
281 | }; | |
282 | ||
283 | static | |
284 | int null_accept(struct ptlrpc_request *req) | |
285 | { | |
286 | LASSERT(SPTLRPC_FLVR_POLICY(req->rq_flvr.sf_rpc) == | |
287 | SPTLRPC_POLICY_NULL); | |
288 | ||
289 | if (req->rq_flvr.sf_rpc != SPTLRPC_FLVR_NULL) { | |
290 | CERROR("Invalid rpc flavor 0x%x\n", req->rq_flvr.sf_rpc); | |
291 | return SECSVC_DROP; | |
292 | } | |
293 | ||
294 | req->rq_sp_from = null_decode_sec_part(req->rq_reqbuf); | |
295 | ||
296 | req->rq_reqmsg = req->rq_reqbuf; | |
297 | req->rq_reqlen = req->rq_reqdata_len; | |
298 | ||
299 | req->rq_svc_ctx = &null_svc_ctx; | |
300 | atomic_inc(&req->rq_svc_ctx->sc_refcount); | |
301 | ||
302 | return SECSVC_OK; | |
303 | } | |
304 | ||
305 | static | |
306 | int null_alloc_rs(struct ptlrpc_request *req, int msgsize) | |
307 | { | |
308 | struct ptlrpc_reply_state *rs; | |
309 | int rs_size = sizeof(*rs) + msgsize; | |
310 | ||
311 | LASSERT(msgsize % 8 == 0); | |
312 | ||
313 | rs = req->rq_reply_state; | |
314 | ||
315 | if (rs) { | |
316 | /* pre-allocated */ | |
317 | LASSERT(rs->rs_size >= rs_size); | |
318 | } else { | |
ee0ec194 | 319 | rs = libcfs_kvzalloc(rs_size, GFP_NOFS); |
d7e09d03 PT |
320 | if (rs == NULL) |
321 | return -ENOMEM; | |
322 | ||
323 | rs->rs_size = rs_size; | |
324 | } | |
325 | ||
326 | rs->rs_svc_ctx = req->rq_svc_ctx; | |
327 | atomic_inc(&req->rq_svc_ctx->sc_refcount); | |
328 | ||
329 | rs->rs_repbuf = (struct lustre_msg *) (rs + 1); | |
330 | rs->rs_repbuf_len = rs_size - sizeof(*rs); | |
331 | rs->rs_msg = rs->rs_repbuf; | |
332 | ||
333 | req->rq_reply_state = rs; | |
334 | return 0; | |
335 | } | |
336 | ||
337 | static | |
338 | void null_free_rs(struct ptlrpc_reply_state *rs) | |
339 | { | |
340 | LASSERT_ATOMIC_GT(&rs->rs_svc_ctx->sc_refcount, 1); | |
341 | atomic_dec(&rs->rs_svc_ctx->sc_refcount); | |
342 | ||
343 | if (!rs->rs_prealloc) | |
ee0ec194 | 344 | kvfree(rs); |
d7e09d03 PT |
345 | } |
346 | ||
347 | static | |
348 | int null_authorize(struct ptlrpc_request *req) | |
349 | { | |
350 | struct ptlrpc_reply_state *rs = req->rq_reply_state; | |
351 | ||
352 | LASSERT(rs); | |
353 | ||
354 | rs->rs_repbuf->lm_secflvr = SPTLRPC_FLVR_NULL; | |
355 | rs->rs_repdata_len = req->rq_replen; | |
356 | ||
357 | if (likely(req->rq_packed_final)) { | |
358 | if (lustre_msghdr_get_flags(req->rq_reqmsg) & MSGHDR_AT_SUPPORT) | |
359 | req->rq_reply_off = lustre_msg_early_size(); | |
360 | else | |
361 | req->rq_reply_off = 0; | |
362 | } else { | |
363 | __u32 cksum; | |
364 | ||
d7e09d03 | 365 | cksum = lustre_msg_calc_cksum(rs->rs_repbuf); |
d7e09d03 PT |
366 | lustre_msg_set_cksum(rs->rs_repbuf, cksum); |
367 | req->rq_reply_off = 0; | |
368 | } | |
369 | ||
370 | return 0; | |
371 | } | |
372 | ||
373 | static struct ptlrpc_ctx_ops null_ctx_ops = { | |
374 | .refresh = null_ctx_refresh, | |
375 | .sign = null_ctx_sign, | |
376 | .verify = null_ctx_verify, | |
377 | }; | |
378 | ||
379 | static struct ptlrpc_sec_cops null_sec_cops = { | |
380 | .create_sec = null_create_sec, | |
381 | .destroy_sec = null_destroy_sec, | |
382 | .lookup_ctx = null_lookup_ctx, | |
383 | .flush_ctx_cache = null_flush_ctx_cache, | |
384 | .alloc_reqbuf = null_alloc_reqbuf, | |
385 | .alloc_repbuf = null_alloc_repbuf, | |
386 | .free_reqbuf = null_free_reqbuf, | |
387 | .free_repbuf = null_free_repbuf, | |
388 | .enlarge_reqbuf = null_enlarge_reqbuf, | |
389 | }; | |
390 | ||
391 | static struct ptlrpc_sec_sops null_sec_sops = { | |
392 | .accept = null_accept, | |
393 | .alloc_rs = null_alloc_rs, | |
394 | .authorize = null_authorize, | |
395 | .free_rs = null_free_rs, | |
396 | }; | |
397 | ||
398 | static struct ptlrpc_sec_policy null_policy = { | |
399 | .sp_owner = THIS_MODULE, | |
400 | .sp_name = "sec.null", | |
401 | .sp_policy = SPTLRPC_POLICY_NULL, | |
402 | .sp_cops = &null_sec_cops, | |
403 | .sp_sops = &null_sec_sops, | |
404 | }; | |
405 | ||
406 | static void null_init_internal(void) | |
407 | { | |
408 | static HLIST_HEAD(__list); | |
409 | ||
410 | null_sec.ps_policy = &null_policy; | |
411 | atomic_set(&null_sec.ps_refcount, 1); /* always busy */ | |
412 | null_sec.ps_id = -1; | |
413 | null_sec.ps_import = NULL; | |
414 | null_sec.ps_flvr.sf_rpc = SPTLRPC_FLVR_NULL; | |
415 | null_sec.ps_flvr.sf_flags = 0; | |
416 | null_sec.ps_part = LUSTRE_SP_ANY; | |
417 | null_sec.ps_dying = 0; | |
418 | spin_lock_init(&null_sec.ps_lock); | |
419 | atomic_set(&null_sec.ps_nctx, 1); /* for "null_cli_ctx" */ | |
420 | INIT_LIST_HEAD(&null_sec.ps_gc_list); | |
421 | null_sec.ps_gc_interval = 0; | |
422 | null_sec.ps_gc_next = 0; | |
423 | ||
424 | hlist_add_head(&null_cli_ctx.cc_cache, &__list); | |
425 | atomic_set(&null_cli_ctx.cc_refcount, 1); /* for hash */ | |
426 | null_cli_ctx.cc_sec = &null_sec; | |
427 | null_cli_ctx.cc_ops = &null_ctx_ops; | |
428 | null_cli_ctx.cc_expire = 0; | |
429 | null_cli_ctx.cc_flags = PTLRPC_CTX_CACHED | PTLRPC_CTX_ETERNAL | | |
430 | PTLRPC_CTX_UPTODATE; | |
431 | null_cli_ctx.cc_vcred.vc_uid = 0; | |
432 | spin_lock_init(&null_cli_ctx.cc_lock); | |
433 | INIT_LIST_HEAD(&null_cli_ctx.cc_req_list); | |
434 | INIT_LIST_HEAD(&null_cli_ctx.cc_gc_chain); | |
435 | } | |
436 | ||
437 | int sptlrpc_null_init(void) | |
438 | { | |
439 | int rc; | |
440 | ||
441 | null_init_internal(); | |
442 | ||
443 | rc = sptlrpc_register_policy(&null_policy); | |
444 | if (rc) | |
445 | CERROR("failed to register %s: %d\n", null_policy.sp_name, rc); | |
446 | ||
447 | return rc; | |
448 | } | |
449 | ||
450 | void sptlrpc_null_fini(void) | |
451 | { | |
452 | int rc; | |
453 | ||
454 | rc = sptlrpc_unregister_policy(&null_policy); | |
455 | if (rc) | |
1d8cb70c GD |
456 | CERROR("failed to unregister %s: %d\n", |
457 | null_policy.sp_name, rc); | |
d7e09d03 | 458 | } |