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 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" 49 50static struct ptlrpc_sec_policy null_policy; 51static struct ptlrpc_sec null_sec; 52static struct ptlrpc_cli_ctx null_cli_ctx; 53static 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 */ 59static inline 60void null_encode_sec_part(struct lustre_msg *msg, enum lustre_sec_part sp) 61{ 62 msg->lm_secflvr |= (((__u32) sp) & 0xFF) << 24; 63} 64 65static inline 66enum lustre_sec_part null_decode_sec_part(struct lustre_msg *msg) 67{ 68 return (msg->lm_secflvr >> 24) & 0xFF; 69} 70 71static int null_ctx_refresh(struct ptlrpc_cli_ctx *ctx) 72{ 73 /* should never reach here */ 74 LBUG(); 75 return 0; 76} 77 78static 79int 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 92static 93int null_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req) 94{ 95 __u32 cksums, cksumc; 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); 104#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 7, 50, 0) 105 if (lustre_msghdr_get_flags(req->rq_reqmsg) & 106 MSGHDR_CKSUM_INCOMPAT18) 107 cksumc = lustre_msg_calc_cksum(req->rq_repmsg, 0); 108 else 109 cksumc = lustre_msg_calc_cksum(req->rq_repmsg, 1); 110#else 111# warning "remove checksum compatibility support for b1_8" 112 cksumc = lustre_msg_calc_cksum(req->rq_repmsg); 113#endif 114 if (cksumc != cksums) { 115 CDEBUG(D_SEC, 116 "early reply checksum mismatch: %08x != %08x\n", 117 cksumc, cksums); 118 return -EINVAL; 119 } 120 } 121 122 return 0; 123} 124 125static 126struct ptlrpc_sec *null_create_sec(struct obd_import *imp, 127 struct ptlrpc_svc_ctx *svc_ctx, 128 struct sptlrpc_flavor *sf) 129{ 130 LASSERT(SPTLRPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_NULL); 131 132 /* general layer has take a module reference for us, because we never 133 * really destroy the sec, simply release the reference here. 134 */ 135 sptlrpc_policy_put(&null_policy); 136 return &null_sec; 137} 138 139static 140void null_destroy_sec(struct ptlrpc_sec *sec) 141{ 142 LASSERT(sec == &null_sec); 143} 144 145static 146struct ptlrpc_cli_ctx *null_lookup_ctx(struct ptlrpc_sec *sec, 147 struct vfs_cred *vcred, 148 int create, int remove_dead) 149{ 150 atomic_inc(&null_cli_ctx.cc_refcount); 151 return &null_cli_ctx; 152} 153 154static 155int null_flush_ctx_cache(struct ptlrpc_sec *sec, 156 uid_t uid, 157 int grace, int force) 158{ 159 return 0; 160} 161 162static 163int null_alloc_reqbuf(struct ptlrpc_sec *sec, 164 struct ptlrpc_request *req, 165 int msgsize) 166{ 167 if (!req->rq_reqbuf) { 168 int alloc_size = size_roundup_power2(msgsize); 169 170 LASSERT(!req->rq_pool); 171 OBD_ALLOC_LARGE(req->rq_reqbuf, alloc_size); 172 if (!req->rq_reqbuf) 173 return -ENOMEM; 174 175 req->rq_reqbuf_len = alloc_size; 176 } else { 177 LASSERT(req->rq_pool); 178 LASSERT(req->rq_reqbuf_len >= msgsize); 179 memset(req->rq_reqbuf, 0, msgsize); 180 } 181 182 req->rq_reqmsg = req->rq_reqbuf; 183 return 0; 184} 185 186static 187void null_free_reqbuf(struct ptlrpc_sec *sec, 188 struct ptlrpc_request *req) 189{ 190 if (!req->rq_pool) { 191 LASSERTF(req->rq_reqmsg == req->rq_reqbuf, 192 "req %p: reqmsg %p is not reqbuf %p in null sec\n", 193 req, req->rq_reqmsg, req->rq_reqbuf); 194 LASSERTF(req->rq_reqbuf_len >= req->rq_reqlen, 195 "req %p: reqlen %d should smaller than buflen %d\n", 196 req, req->rq_reqlen, req->rq_reqbuf_len); 197 198 OBD_FREE_LARGE(req->rq_reqbuf, req->rq_reqbuf_len); 199 req->rq_reqbuf = NULL; 200 req->rq_reqbuf_len = 0; 201 } 202} 203 204static 205int null_alloc_repbuf(struct ptlrpc_sec *sec, 206 struct ptlrpc_request *req, 207 int msgsize) 208{ 209 /* add space for early replied */ 210 msgsize += lustre_msg_early_size(); 211 212 msgsize = size_roundup_power2(msgsize); 213 214 OBD_ALLOC_LARGE(req->rq_repbuf, msgsize); 215 if (!req->rq_repbuf) 216 return -ENOMEM; 217 218 req->rq_repbuf_len = msgsize; 219 return 0; 220} 221 222static 223void null_free_repbuf(struct ptlrpc_sec *sec, 224 struct ptlrpc_request *req) 225{ 226 LASSERT(req->rq_repbuf); 227 228 OBD_FREE_LARGE(req->rq_repbuf, req->rq_repbuf_len); 229 req->rq_repbuf = NULL; 230 req->rq_repbuf_len = 0; 231} 232 233static 234int null_enlarge_reqbuf(struct ptlrpc_sec *sec, 235 struct ptlrpc_request *req, 236 int segment, int newsize) 237{ 238 struct lustre_msg *newbuf; 239 struct lustre_msg *oldbuf = req->rq_reqmsg; 240 int oldsize, newmsg_size, alloc_size; 241 242 LASSERT(req->rq_reqbuf); 243 LASSERT(req->rq_reqbuf == req->rq_reqmsg); 244 LASSERT(req->rq_reqbuf_len >= req->rq_reqlen); 245 LASSERT(req->rq_reqlen == lustre_packed_msg_size(oldbuf)); 246 247 /* compute new message size */ 248 oldsize = req->rq_reqbuf->lm_buflens[segment]; 249 req->rq_reqbuf->lm_buflens[segment] = newsize; 250 newmsg_size = lustre_packed_msg_size(oldbuf); 251 req->rq_reqbuf->lm_buflens[segment] = oldsize; 252 253 /* request from pool should always have enough buffer */ 254 LASSERT(!req->rq_pool || req->rq_reqbuf_len >= newmsg_size); 255 256 if (req->rq_reqbuf_len < newmsg_size) { 257 alloc_size = size_roundup_power2(newmsg_size); 258 259 OBD_ALLOC_LARGE(newbuf, alloc_size); 260 if (newbuf == NULL) 261 return -ENOMEM; 262 263 /* Must lock this, so that otherwise unprotected change of 264 * rq_reqmsg is not racing with parallel processing of 265 * imp_replay_list traversing threads. See LU-3333 266 * This is a bandaid at best, we really need to deal with this 267 * in request enlarging code before unpacking that's already 268 * there */ 269 if (req->rq_import) 270 spin_lock(&req->rq_import->imp_lock); 271 memcpy(newbuf, req->rq_reqbuf, req->rq_reqlen); 272 273 OBD_FREE_LARGE(req->rq_reqbuf, req->rq_reqbuf_len); 274 req->rq_reqbuf = req->rq_reqmsg = newbuf; 275 req->rq_reqbuf_len = alloc_size; 276 277 if (req->rq_import) 278 spin_unlock(&req->rq_import->imp_lock); 279 } 280 281 _sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize); 282 req->rq_reqlen = newmsg_size; 283 284 return 0; 285} 286 287static struct ptlrpc_svc_ctx null_svc_ctx = { 288 .sc_refcount = ATOMIC_INIT(1), 289 .sc_policy = &null_policy, 290}; 291 292static 293int null_accept(struct ptlrpc_request *req) 294{ 295 LASSERT(SPTLRPC_FLVR_POLICY(req->rq_flvr.sf_rpc) == 296 SPTLRPC_POLICY_NULL); 297 298 if (req->rq_flvr.sf_rpc != SPTLRPC_FLVR_NULL) { 299 CERROR("Invalid rpc flavor 0x%x\n", req->rq_flvr.sf_rpc); 300 return SECSVC_DROP; 301 } 302 303 req->rq_sp_from = null_decode_sec_part(req->rq_reqbuf); 304 305 req->rq_reqmsg = req->rq_reqbuf; 306 req->rq_reqlen = req->rq_reqdata_len; 307 308 req->rq_svc_ctx = &null_svc_ctx; 309 atomic_inc(&req->rq_svc_ctx->sc_refcount); 310 311 return SECSVC_OK; 312} 313 314static 315int null_alloc_rs(struct ptlrpc_request *req, int msgsize) 316{ 317 struct ptlrpc_reply_state *rs; 318 int rs_size = sizeof(*rs) + msgsize; 319 320 LASSERT(msgsize % 8 == 0); 321 322 rs = req->rq_reply_state; 323 324 if (rs) { 325 /* pre-allocated */ 326 LASSERT(rs->rs_size >= rs_size); 327 } else { 328 OBD_ALLOC_LARGE(rs, rs_size); 329 if (rs == NULL) 330 return -ENOMEM; 331 332 rs->rs_size = rs_size; 333 } 334 335 rs->rs_svc_ctx = req->rq_svc_ctx; 336 atomic_inc(&req->rq_svc_ctx->sc_refcount); 337 338 rs->rs_repbuf = (struct lustre_msg *) (rs + 1); 339 rs->rs_repbuf_len = rs_size - sizeof(*rs); 340 rs->rs_msg = rs->rs_repbuf; 341 342 req->rq_reply_state = rs; 343 return 0; 344} 345 346static 347void null_free_rs(struct ptlrpc_reply_state *rs) 348{ 349 LASSERT_ATOMIC_GT(&rs->rs_svc_ctx->sc_refcount, 1); 350 atomic_dec(&rs->rs_svc_ctx->sc_refcount); 351 352 if (!rs->rs_prealloc) 353 OBD_FREE_LARGE(rs, rs->rs_size); 354} 355 356static 357int null_authorize(struct ptlrpc_request *req) 358{ 359 struct ptlrpc_reply_state *rs = req->rq_reply_state; 360 361 LASSERT(rs); 362 363 rs->rs_repbuf->lm_secflvr = SPTLRPC_FLVR_NULL; 364 rs->rs_repdata_len = req->rq_replen; 365 366 if (likely(req->rq_packed_final)) { 367 if (lustre_msghdr_get_flags(req->rq_reqmsg) & MSGHDR_AT_SUPPORT) 368 req->rq_reply_off = lustre_msg_early_size(); 369 else 370 req->rq_reply_off = 0; 371 } else { 372 __u32 cksum; 373 374#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 7, 50, 0) 375 if (lustre_msghdr_get_flags(req->rq_reqmsg) & 376 MSGHDR_CKSUM_INCOMPAT18) 377 cksum = lustre_msg_calc_cksum(rs->rs_repbuf, 0); 378 else 379 cksum = lustre_msg_calc_cksum(rs->rs_repbuf, 1); 380#else 381# warning "remove checksum compatibility support for b1_8" 382 cksum = lustre_msg_calc_cksum(rs->rs_repbuf); 383#endif 384 lustre_msg_set_cksum(rs->rs_repbuf, cksum); 385 req->rq_reply_off = 0; 386 } 387 388 return 0; 389} 390 391static struct ptlrpc_ctx_ops null_ctx_ops = { 392 .refresh = null_ctx_refresh, 393 .sign = null_ctx_sign, 394 .verify = null_ctx_verify, 395}; 396 397static struct ptlrpc_sec_cops null_sec_cops = { 398 .create_sec = null_create_sec, 399 .destroy_sec = null_destroy_sec, 400 .lookup_ctx = null_lookup_ctx, 401 .flush_ctx_cache = null_flush_ctx_cache, 402 .alloc_reqbuf = null_alloc_reqbuf, 403 .alloc_repbuf = null_alloc_repbuf, 404 .free_reqbuf = null_free_reqbuf, 405 .free_repbuf = null_free_repbuf, 406 .enlarge_reqbuf = null_enlarge_reqbuf, 407}; 408 409static struct ptlrpc_sec_sops null_sec_sops = { 410 .accept = null_accept, 411 .alloc_rs = null_alloc_rs, 412 .authorize = null_authorize, 413 .free_rs = null_free_rs, 414}; 415 416static struct ptlrpc_sec_policy null_policy = { 417 .sp_owner = THIS_MODULE, 418 .sp_name = "sec.null", 419 .sp_policy = SPTLRPC_POLICY_NULL, 420 .sp_cops = &null_sec_cops, 421 .sp_sops = &null_sec_sops, 422}; 423 424static void null_init_internal(void) 425{ 426 static HLIST_HEAD(__list); 427 428 null_sec.ps_policy = &null_policy; 429 atomic_set(&null_sec.ps_refcount, 1); /* always busy */ 430 null_sec.ps_id = -1; 431 null_sec.ps_import = NULL; 432 null_sec.ps_flvr.sf_rpc = SPTLRPC_FLVR_NULL; 433 null_sec.ps_flvr.sf_flags = 0; 434 null_sec.ps_part = LUSTRE_SP_ANY; 435 null_sec.ps_dying = 0; 436 spin_lock_init(&null_sec.ps_lock); 437 atomic_set(&null_sec.ps_nctx, 1); /* for "null_cli_ctx" */ 438 INIT_LIST_HEAD(&null_sec.ps_gc_list); 439 null_sec.ps_gc_interval = 0; 440 null_sec.ps_gc_next = 0; 441 442 hlist_add_head(&null_cli_ctx.cc_cache, &__list); 443 atomic_set(&null_cli_ctx.cc_refcount, 1); /* for hash */ 444 null_cli_ctx.cc_sec = &null_sec; 445 null_cli_ctx.cc_ops = &null_ctx_ops; 446 null_cli_ctx.cc_expire = 0; 447 null_cli_ctx.cc_flags = PTLRPC_CTX_CACHED | PTLRPC_CTX_ETERNAL | 448 PTLRPC_CTX_UPTODATE; 449 null_cli_ctx.cc_vcred.vc_uid = 0; 450 spin_lock_init(&null_cli_ctx.cc_lock); 451 INIT_LIST_HEAD(&null_cli_ctx.cc_req_list); 452 INIT_LIST_HEAD(&null_cli_ctx.cc_gc_chain); 453} 454 455int sptlrpc_null_init(void) 456{ 457 int rc; 458 459 null_init_internal(); 460 461 rc = sptlrpc_register_policy(&null_policy); 462 if (rc) 463 CERROR("failed to register %s: %d\n", null_policy.sp_name, rc); 464 465 return rc; 466} 467 468void sptlrpc_null_fini(void) 469{ 470 int rc; 471 472 rc = sptlrpc_unregister_policy(&null_policy); 473 if (rc) 474 CERROR("failed to unregister %s: %d\n", 475 null_policy.sp_name, rc); 476} 477