1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
40 #define DEBUG_SUBSYSTEM S_SEC
42 #include <libcfs/libcfs.h>
44 #include <liblustre.h>
45 #include <libcfs/list.h>
47 #include <linux/crypto.h>
48 #include <linux/key.h>
52 #include <obd_class.h>
53 #include <obd_support.h>
54 #include <lustre_net.h>
55 #include <lustre_import.h>
56 #include <lustre_dlm.h>
57 #include <lustre_sec.h>
59 #include "ptlrpc_internal.h"
61 const char *sptlrpc_part2name(enum lustre_sec_part part)
78 EXPORT_SYMBOL(sptlrpc_part2name);
80 enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd)
82 const char *type = obd->obd_type->typ_name;
84 if (!strcmp(type, LUSTRE_MDT_NAME))
86 if (!strcmp(type, LUSTRE_OST_NAME))
88 if (!strcmp(type, LUSTRE_MGS_NAME))
91 CERROR("unknown target %p(%s)\n", obd, type);
94 EXPORT_SYMBOL(sptlrpc_target_sec_part);
96 /****************************************
97 * user supplied flavor string parsing *
98 ****************************************/
101 #define BULK_HASH_ALG_DEFAULT BULK_HASH_ALG_ADLER32
103 #define BULK_HASH_ALG_DEFAULT BULK_HASH_ALG_CRC32
112 static void get_default_flavor(struct sptlrpc_flavor *sf)
114 sf->sf_rpc = SPTLRPC_FLVR_NULL;
115 sf->sf_bulk_ciph = BULK_CIPH_ALG_NULL;
116 sf->sf_bulk_hash = BULK_HASH_ALG_NULL;
120 static void get_flavor_by_rpc(struct sptlrpc_rule *rule, __u16 rpc_flavor)
122 get_default_flavor(&rule->sr_flvr);
124 rule->sr_flvr.sf_rpc = rpc_flavor;
126 switch (rpc_flavor) {
127 case SPTLRPC_FLVR_NULL:
129 case SPTLRPC_FLVR_PLAIN:
130 case SPTLRPC_FLVR_KRB5N:
131 case SPTLRPC_FLVR_KRB5A:
132 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_DEFAULT;
134 case SPTLRPC_FLVR_KRB5P:
135 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128;
137 case SPTLRPC_FLVR_KRB5I:
138 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
145 static void get_flavor_by_bulk(struct sptlrpc_rule *rule,
146 __u16 rpc_flavor, bulk_type_t bulk_type)
150 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL;
151 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
154 switch (rpc_flavor) {
155 case SPTLRPC_FLVR_PLAIN:
156 case SPTLRPC_FLVR_KRB5N:
157 case SPTLRPC_FLVR_KRB5A:
158 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_DEFAULT;
160 case SPTLRPC_FLVR_KRB5I:
161 case SPTLRPC_FLVR_KRB5P:
162 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
167 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
170 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
171 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128;
178 static __u16 __flavors[] = {
187 #define __nflavors ARRAY_SIZE(__flavors)
190 * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]]
196 * krb5i-bulkp:sha512/arc4
198 static int parse_flavor(char *str, struct sptlrpc_rule *rule)
201 char *bulk, *alg, *enc;
203 bulk_type_t bulk_type;
207 if (str == NULL || str[0] == '\0') {
208 rule->sr_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
212 for (i = 0; i < __nflavors; i++) {
213 f = sptlrpc_rpcflavor2name(__flavors[i]);
214 if (strncmp(str, f, strlen(f)) == 0)
219 GOTO(invalid, -EINVAL);
221 /* prepare local buffer thus we can modify it as we want */
222 strncpy(buf, str, 64);
225 /* find bulk string */
226 bulk = strchr(buf, '-');
230 /* now the first part must equal to rpc flavor name */
231 if (strcmp(buf, f) != 0)
232 GOTO(invalid, -EINVAL);
234 get_flavor_by_rpc(rule, __flavors[i]);
239 /* find bulk algorithm string */
240 alg = strchr(bulk, ':');
244 /* verify bulk section */
245 if (strcmp(bulk, "bulkn") == 0) {
246 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL;
247 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
248 bulk_type = BULK_TYPE_N;
249 } else if (strcmp(bulk, "bulki") == 0)
250 bulk_type = BULK_TYPE_I;
251 else if (strcmp(bulk, "bulkp") == 0)
252 bulk_type = BULK_TYPE_P;
254 GOTO(invalid, -EINVAL);
256 /* null flavor don't support bulk i/p */
257 if (__flavors[i] == SPTLRPC_FLVR_NULL && bulk_type != BULK_TYPE_N)
258 GOTO(invalid, -EINVAL);
260 /* plain policy dosen't support bulk p */
261 if (__flavors[i] == SPTLRPC_FLVR_PLAIN && bulk_type == BULK_TYPE_P)
262 GOTO(invalid, -EINVAL);
264 get_flavor_by_bulk(rule, __flavors[i], bulk_type);
269 /* find encryption algorithm string */
270 enc = strchr(alg, '/');
274 /* checksum algorithm */
275 for (i = 0; i < BULK_HASH_ALG_MAX; i++) {
276 if (strcmp(alg, sptlrpc_get_hash_name(i)) == 0) {
277 rule->sr_flvr.sf_bulk_hash = i;
281 if (i >= BULK_HASH_ALG_MAX)
282 GOTO(invalid, -EINVAL);
284 /* privacy algorithm */
286 for (i = 0; i < BULK_CIPH_ALG_MAX; i++) {
287 if (strcmp(enc, sptlrpc_get_ciph_name(i)) == 0) {
288 rule->sr_flvr.sf_bulk_ciph = i;
292 if (i >= BULK_CIPH_ALG_MAX)
293 GOTO(invalid, -EINVAL);
297 * bulk combination sanity checks
299 if (bulk_type == BULK_TYPE_P &&
300 rule->sr_flvr.sf_bulk_ciph == BULK_CIPH_ALG_NULL)
301 GOTO(invalid, -EINVAL);
303 if (bulk_type == BULK_TYPE_I &&
304 (rule->sr_flvr.sf_bulk_hash == BULK_HASH_ALG_NULL ||
305 rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL))
306 GOTO(invalid, -EINVAL);
308 if (bulk_type == BULK_TYPE_N &&
309 (rule->sr_flvr.sf_bulk_hash != BULK_HASH_ALG_NULL ||
310 rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL))
311 GOTO(invalid, -EINVAL);
316 CERROR("invalid flavor string: %s\n", str);
320 /****************************************
322 ****************************************/
324 static void sptlrpc_rule_init(struct sptlrpc_rule *rule)
326 rule->sr_netid = LNET_NIDNET(LNET_NID_ANY);
327 rule->sr_from = LUSTRE_SP_ANY;
328 rule->sr_to = LUSTRE_SP_ANY;
329 rule->sr_padding = 0;
331 get_default_flavor(&rule->sr_flvr);
335 * format: network[.direction]=flavor
337 int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
342 sptlrpc_rule_init(rule);
344 flavor = strchr(param, '=');
345 if (flavor == NULL) {
346 CERROR("invalid param, no '='\n");
351 dir = strchr(param, '.');
356 if (strcmp(param, "default")) {
357 rule->sr_netid = libcfs_str2net(param);
358 if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
359 CERROR("invalid network name: %s\n", param);
366 if (!strcmp(dir, "mdt2ost")) {
367 rule->sr_from = LUSTRE_SP_MDT;
368 rule->sr_to = LUSTRE_SP_OST;
369 } else if (!strcmp(dir, "mdt2mdt")) {
370 rule->sr_from = LUSTRE_SP_MDT;
371 rule->sr_to = LUSTRE_SP_MDT;
372 } else if (!strcmp(dir, "cli2ost")) {
373 rule->sr_from = LUSTRE_SP_CLI;
374 rule->sr_to = LUSTRE_SP_OST;
375 } else if (!strcmp(dir, "cli2mdt")) {
376 rule->sr_from = LUSTRE_SP_CLI;
377 rule->sr_to = LUSTRE_SP_MDT;
379 CERROR("invalid rule dir segment: %s\n", dir);
385 rc = parse_flavor(flavor, rule);
391 EXPORT_SYMBOL(sptlrpc_parse_rule);
393 void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
395 LASSERT(rset->srs_nslot ||
396 (rset->srs_nrule == 0 && rset->srs_rules == NULL));
398 if (rset->srs_nslot) {
399 OBD_FREE(rset->srs_rules,
400 rset->srs_nslot * sizeof(*rset->srs_rules));
401 sptlrpc_rule_set_init(rset);
404 EXPORT_SYMBOL(sptlrpc_rule_set_free);
407 * return 0 if the rule set could accomodate one more rule.
408 * if @expand != 0, the rule set might be expanded.
410 int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset, int expand)
412 struct sptlrpc_rule *rules;
415 if (rset->srs_nrule < rset->srs_nslot)
421 if (rset->srs_nslot == 0)
424 nslot = rset->srs_nslot + 8;
426 /* better use realloc() if available */
427 OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules));
431 memcpy(rules, rset->srs_rules,
432 rset->srs_nrule * sizeof(*rset->srs_rules));
435 OBD_FREE(rset->srs_rules,
436 rset->srs_nslot * sizeof(*rset->srs_rules));
438 rset->srs_rules = rules;
439 rset->srs_nslot = nslot;
442 EXPORT_SYMBOL(sptlrpc_rule_set_expand);
444 static inline int rule_spec_dir(struct sptlrpc_rule *rule)
446 return (rule->sr_from != LUSTRE_SP_ANY ||
447 rule->sr_to != LUSTRE_SP_ANY);
449 static inline int rule_spec_net(struct sptlrpc_rule *rule)
451 return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
453 static inline int rule_match_dir(struct sptlrpc_rule *r1,
454 struct sptlrpc_rule *r2)
456 return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to);
458 static inline int rule_match_net(struct sptlrpc_rule *r1,
459 struct sptlrpc_rule *r2)
461 return (r1->sr_netid == r2->sr_netid);
465 * merge @rule into @rset.
466 * if @expand != 0 then @rset slots might be expanded.
468 int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset,
469 struct sptlrpc_rule *rule,
472 struct sptlrpc_rule *p = rset->srs_rules;
473 int spec_dir, spec_net;
474 int rc, n, match = 0;
476 spec_net = rule_spec_net(rule);
477 spec_dir = rule_spec_dir(rule);
479 for (n = 0; n < rset->srs_nrule; n++) {
480 p = &rset->srs_rules[n];
482 /* test network match, if failed:
483 * - spec rule: skip rules which is also spec rule match, until
484 * we hit a wild rule, which means no more chance
485 * - wild rule: skip until reach the one which is also wild
488 if (!rule_match_net(p, rule)) {
490 if (rule_spec_net(p))
499 /* test dir match, same logic as net matching */
500 if (!rule_match_dir(p, rule)) {
502 if (rule_spec_dir(p))
517 LASSERT(n >= 0 && n < rset->srs_nrule);
519 if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
520 /* remove this rule */
521 if (n < rset->srs_nrule - 1)
522 memmove(&rset->srs_rules[n],
523 &rset->srs_rules[n + 1],
524 (rset->srs_nrule - n - 1) *
528 /* override the rule */
529 memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
532 LASSERT(n >= 0 && n <= rset->srs_nrule);
534 if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
535 rc = sptlrpc_rule_set_expand(rset, expand);
539 if (n < rset->srs_nrule)
540 memmove(&rset->srs_rules[n + 1],
542 (rset->srs_nrule - n) * sizeof(*rule));
543 memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
546 CWARN("ignore the unmatched deletion\n");
552 EXPORT_SYMBOL(sptlrpc_rule_set_merge);
554 int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset,
555 struct sptlrpc_conf_log *log)
560 sptlrpc_rule_set_free(rset);
562 if (log->scl_nrule == 0)
565 OBD_ALLOC(rset->srs_rules, log->scl_nrule * sizeof(*log->scl_rules));
566 if (!rset->srs_rules)
569 memcpy(rset->srs_rules, log->scl_rules,
570 log->scl_nrule * sizeof(*log->scl_rules));
571 rset->srs_nslot = rset->srs_nrule = log->scl_nrule;
574 EXPORT_SYMBOL(sptlrpc_rule_set_from_log);
577 * according to NID/from choose a flavor from rule set.
579 void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
580 enum lustre_sec_part from,
582 struct sptlrpc_flavor *sf)
584 struct sptlrpc_rule *r;
587 for (n = 0; n < rset->srs_nrule; n++) {
588 r = &rset->srs_rules[n];
590 if (LNET_NIDNET(nid) != LNET_NIDNET(LNET_NID_ANY) &&
591 r->sr_netid != LNET_NIDNET(LNET_NID_ANY) &&
592 LNET_NIDNET(nid) != r->sr_netid)
595 if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY &&
603 /* no match found, set as default flavor */
604 get_default_flavor(sf);
606 EXPORT_SYMBOL(sptlrpc_rule_set_choose);
608 void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset)
610 struct sptlrpc_rule *r;
613 for (n = 0; n < rset->srs_nrule; n++) {
614 r = &rset->srs_rules[n];
615 CWARN("<%02d> from %x to %x, net %x, rpc %x\n", n,
616 r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
619 EXPORT_SYMBOL(sptlrpc_rule_set_dump);
621 /****************************************
622 * sptlrpc config log *
623 ****************************************/
625 struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void)
627 struct sptlrpc_conf_log *log;
631 return ERR_PTR(-ENOMEM);
633 log->scl_max = SPTLRPC_CONF_LOG_MAX;
636 EXPORT_SYMBOL(sptlrpc_conf_log_alloc);
638 void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log)
640 LASSERT(log->scl_max == SPTLRPC_CONF_LOG_MAX);
643 EXPORT_SYMBOL(sptlrpc_conf_log_free);
645 static __u32 get_log_rule_flags(enum lustre_sec_part from,
646 enum lustre_sec_part to,
647 unsigned int fl_udesc)
649 /* MDT->MDT; MDT->OST */
650 if (from == LUSTRE_SP_MDT)
651 return PTLRPC_SEC_FL_ROOTONLY;
653 if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST)
654 return PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
656 if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT)
658 return PTLRPC_SEC_FL_UDESC;
664 * generate config log: merge general and target rules, which
667 int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen,
668 struct sptlrpc_rule_set *tgt,
669 enum lustre_sec_part from,
670 enum lustre_sec_part to,
671 unsigned int fl_udesc,
672 struct sptlrpc_conf_log *log)
674 struct sptlrpc_rule_set *src[2] = { gen, tgt };
675 struct sptlrpc_rule_set dst;
676 struct sptlrpc_rule *rule;
682 dst.srs_nslot = log->scl_max;
684 dst.srs_rules = log->scl_rules;
686 /* merge general rules firstly, then target-specific rules */
687 for (i = 0; i < 2; i++) {
691 for (n = 0; n < src[i]->srs_nrule; n++) {
692 rule = &src[i]->srs_rules[n];
694 if (from != LUSTRE_SP_ANY &&
695 rule->sr_from != LUSTRE_SP_ANY &&
696 rule->sr_from != from)
698 if (to != LUSTRE_SP_ANY &&
699 rule->sr_to != LUSTRE_SP_ANY &&
703 rc = sptlrpc_rule_set_merge(&dst, rule, 0);
705 CERROR("can't merge: %d\n", rc);
711 log->scl_nrule = dst.srs_nrule;
713 /* set flags for each rule */
714 flags = get_log_rule_flags(from, to, fl_udesc);
716 for (i = 0; i < log->scl_nrule; i++) {
717 log->scl_rules[i].sr_flvr.sf_flags = flags;
719 /* also clear the from/to fields which don't need to be known
720 * accordingly. @from == ANY means this log is for target,
721 * otherwise for client. */
722 if (from != LUSTRE_SP_ANY)
723 log->scl_rules[i].sr_from = LUSTRE_SP_ANY;
724 log->scl_rules[i].sr_to = LUSTRE_SP_ANY;
729 EXPORT_SYMBOL(sptlrpc_conf_log_populate);
732 * extract config log from @lcfg
734 struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg)
736 struct sptlrpc_conf_log *log;
737 struct sptlrpc_rule *r;
741 log = lustre_cfg_buf(lcfg, 1);
743 CERROR("no sptlrpc config data\n");
744 RETURN(ERR_PTR(-EINVAL));
747 if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
748 __swab32s(&log->scl_max);
749 __swab32s(&log->scl_nrule);
752 if (LUSTRE_CFG_BUFLEN(lcfg, 1) <
753 log->scl_max * sizeof(log->scl_rules[0])) {
754 CERROR("mal-formed config log\n");
755 RETURN(ERR_PTR(-EINVAL));
758 if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
759 for (i = 0; i < log->scl_nrule; i++) {
760 r = &log->scl_rules[i];
761 __swab32s(&r->sr_netid);
762 __swab16s(&r->sr_flvr.sf_rpc);
763 __swab32s(&r->sr_flvr.sf_flags);
769 EXPORT_SYMBOL(sptlrpc_conf_log_extract);
771 void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log)
774 memset(log->scl_rules, 0, sizeof(log->scl_rules));
776 EXPORT_SYMBOL(sptlrpc_conf_log_cleanup);
778 void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log)
780 struct sptlrpc_rule *r;
783 CWARN("max %u, rule# %u part %u\n",
784 log->scl_max, log->scl_nrule, log->scl_part);
786 for (n = 0; n < log->scl_nrule; n++) {
787 r = &log->scl_rules[n];
788 CWARN("<%02d> %x -> %x, net %x, rpc %x\n", n,
789 r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
792 EXPORT_SYMBOL(sptlrpc_conf_log_dump);
795 * caller should guarantee that no concurrent calls to this function
797 #define SEC_ADAPT_DELAY (10)
799 int sptlrpc_cliobd_process_config(struct obd_device *obd,
800 struct lustre_cfg *lcfg)
802 struct sptlrpc_conf_log *log;
803 struct obd_import *imp;
806 log = sptlrpc_conf_log_extract(lcfg);
808 CERROR("extract log error: %ld\n", PTR_ERR(log));
812 obd->u.cli.cl_sec_part = log->scl_part;
814 rc = sptlrpc_rule_set_from_log(&obd->u.cli.cl_sptlrpc_rset, log);
816 CERROR("failed create rule set: %d\n", rc);
820 imp = obd->u.cli.cl_import;
824 /* even if imp_sec_expire is already set, we'll override it to a
825 * newer (later) time */
826 spin_lock(&imp->imp_lock);
828 imp->imp_sec_expire = cfs_time_current_sec() + SEC_ADAPT_DELAY;
829 spin_unlock(&imp->imp_lock);
832 EXPORT_SYMBOL(sptlrpc_cliobd_process_config);