1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2007 Cluster File Systems, Inc.
6 * This file is part of Lustre, http://www.lustre.org.
8 * Lustre is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
12 * Lustre is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Lustre; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define DEBUG_SUBSYSTEM S_SEC
27 #include <libcfs/libcfs.h>
29 #include <liblustre.h>
30 #include <libcfs/list.h>
32 #include <linux/crypto.h>
33 #include <linux/key.h>
37 #include <obd_class.h>
38 #include <obd_support.h>
39 #include <lustre_net.h>
40 #include <lustre_import.h>
41 #include <lustre_dlm.h>
42 #include <lustre_sec.h>
44 #include "ptlrpc_internal.h"
46 const char *sptlrpc_part2name(enum lustre_sec_part part)
63 EXPORT_SYMBOL(sptlrpc_part2name);
65 enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd)
67 const char *type = obd->obd_type->typ_name;
69 if (!strcmp(type, LUSTRE_MDT_NAME))
71 if (!strcmp(type, LUSTRE_OST_NAME))
73 if (!strcmp(type, LUSTRE_MGS_NAME))
76 CERROR("unknown target %p(%s)\n", obd, type);
79 EXPORT_SYMBOL(sptlrpc_target_sec_part);
81 /****************************************
82 * user supplied flavor string parsing *
83 ****************************************/
91 static void get_default_flavor(struct sptlrpc_flavor *sf)
93 sf->sf_rpc = SPTLRPC_FLVR_NULL;
94 sf->sf_bulk_priv = BULK_PRIV_ALG_NULL;
95 sf->sf_bulk_csum = BULK_CSUM_ALG_NULL;
99 static void get_flavor_by_rpc(struct sptlrpc_rule *rule, __u16 rpc_flavor)
101 get_default_flavor(&rule->sr_flvr);
103 rule->sr_flvr.sf_rpc = rpc_flavor;
105 switch (rpc_flavor) {
106 case SPTLRPC_FLVR_NULL:
107 case SPTLRPC_FLVR_PLAIN:
108 case SPTLRPC_FLVR_KRB5N:
109 case SPTLRPC_FLVR_KRB5A:
111 case SPTLRPC_FLVR_KRB5P:
112 rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_ARC4;
114 case SPTLRPC_FLVR_KRB5I:
115 rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_SHA1;
122 static void get_flavor_by_bulk(struct sptlrpc_rule *rule, bulk_type_t bulk_type)
126 rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_NULL;
127 rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL;
130 rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_SHA1;
131 rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL;
134 rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_SHA1;
135 rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_ARC4;
142 static __u16 __flavors[] = {
151 #define __nflavors ARRAY_SIZE(__flavors)
154 * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]]
160 * krb5i-bulkp:sha512/arc4
162 static int parse_flavor(char *str, struct sptlrpc_rule *rule)
165 char *bulk, *alg, *enc;
167 bulk_type_t bulk_type;
171 if (str == NULL || str[0] == '\0') {
172 rule->sr_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
176 for (i = 0; i < __nflavors; i++) {
177 f = sptlrpc_rpcflavor2name(__flavors[i]);
178 if (strncmp(str, f, strlen(f)) == 0)
183 GOTO(invalid, -EINVAL);
185 /* prepare local buffer thus we can modify it as we want */
186 strncpy(buf, str, 64);
189 /* find bulk string */
190 bulk = strchr(buf, '-');
194 /* now the first part must equal to rpc flavor name */
195 if (strcmp(buf, f) != 0)
196 GOTO(invalid, -EINVAL);
198 get_flavor_by_rpc(rule, __flavors[i]);
203 /* find bulk algorithm string */
204 alg = strchr(bulk, ':');
208 /* verify bulk section */
209 if (strcmp(bulk, "bulkn") == 0) {
210 rule->sr_flvr.sf_bulk_csum = BULK_CSUM_ALG_NULL;
211 rule->sr_flvr.sf_bulk_priv = BULK_PRIV_ALG_NULL;
212 bulk_type = BULK_TYPE_N;
213 } else if (strcmp(bulk, "bulki") == 0)
214 bulk_type = BULK_TYPE_I;
215 else if (strcmp(bulk, "bulkp") == 0)
216 bulk_type = BULK_TYPE_P;
218 GOTO(invalid, -EINVAL);
220 /* null flavor don't support bulk i/p */
221 if (__flavors[i] == SPTLRPC_FLVR_NULL && bulk_type != BULK_TYPE_N)
222 GOTO(invalid, -EINVAL);
224 /* plain policy dosen't support bulk p */
225 if (__flavors[i] == SPTLRPC_FLVR_PLAIN && bulk_type == BULK_TYPE_P)
226 GOTO(invalid, -EINVAL);
228 get_flavor_by_bulk(rule, bulk_type);
233 /* find encryption algorithm string */
234 enc = strchr(alg, '/');
238 /* checksum algorithm */
239 for (i = 0; i < BULK_CSUM_ALG_MAX; i++) {
240 if (strcmp(alg, sptlrpc_bulk_csum_alg2name(i)) == 0) {
241 rule->sr_flvr.sf_bulk_csum = i;
245 if (i >= BULK_CSUM_ALG_MAX)
246 GOTO(invalid, -EINVAL);
248 /* privacy algorithm */
250 for (i = 0; i < BULK_PRIV_ALG_MAX; i++) {
251 if (strcmp(enc, sptlrpc_bulk_priv_alg2name(i)) == 0) {
252 rule->sr_flvr.sf_bulk_priv = i;
256 if (i >= BULK_PRIV_ALG_MAX)
257 GOTO(invalid, -EINVAL);
261 * bulk combination sanity checks
263 if (bulk_type == BULK_TYPE_P &&
264 rule->sr_flvr.sf_bulk_priv == BULK_PRIV_ALG_NULL)
265 GOTO(invalid, -EINVAL);
267 if (bulk_type == BULK_TYPE_I &&
268 (rule->sr_flvr.sf_bulk_csum == BULK_CSUM_ALG_NULL ||
269 rule->sr_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL))
270 GOTO(invalid, -EINVAL);
272 if (bulk_type == BULK_TYPE_N &&
273 (rule->sr_flvr.sf_bulk_csum != BULK_CSUM_ALG_NULL ||
274 rule->sr_flvr.sf_bulk_priv != BULK_PRIV_ALG_NULL))
275 GOTO(invalid, -EINVAL);
280 CERROR("invalid flavor string: %s\n", str);
284 /****************************************
286 ****************************************/
288 static void sptlrpc_rule_init(struct sptlrpc_rule *rule)
290 rule->sr_netid = LNET_NIDNET(LNET_NID_ANY);
291 rule->sr_from = LUSTRE_SP_ANY;
292 rule->sr_to = LUSTRE_SP_ANY;
293 rule->sr_padding = 0;
295 get_default_flavor(&rule->sr_flvr);
299 * format: network[.direction]=flavor
301 int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
306 sptlrpc_rule_init(rule);
308 flavor = strchr(param, '=');
309 if (flavor == NULL) {
310 CERROR("invalid param, no '='\n");
315 dir = strchr(param, '.');
320 if (strcmp(param, "default")) {
321 rule->sr_netid = libcfs_str2net(param);
322 if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
323 CERROR("invalid network name: %s\n", param);
330 if (!strcmp(dir, "mdt2ost")) {
331 rule->sr_from = LUSTRE_SP_MDT;
332 rule->sr_to = LUSTRE_SP_OST;
333 } else if (!strcmp(dir, "mdt2mdt")) {
334 rule->sr_from = LUSTRE_SP_MDT;
335 rule->sr_to = LUSTRE_SP_MDT;
336 } else if (!strcmp(dir, "cli2ost")) {
337 rule->sr_from = LUSTRE_SP_CLI;
338 rule->sr_to = LUSTRE_SP_OST;
339 } else if (!strcmp(dir, "cli2mdt")) {
340 rule->sr_from = LUSTRE_SP_CLI;
341 rule->sr_to = LUSTRE_SP_MDT;
343 CERROR("invalid rule dir segment: %s\n", dir);
349 rc = parse_flavor(flavor, rule);
355 EXPORT_SYMBOL(sptlrpc_parse_rule);
357 void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
359 LASSERT(rset->srs_nslot ||
360 (rset->srs_nrule == 0 && rset->srs_rules == NULL));
362 if (rset->srs_nslot) {
363 OBD_FREE(rset->srs_rules,
364 rset->srs_nslot * sizeof(*rset->srs_rules));
365 sptlrpc_rule_set_init(rset);
368 EXPORT_SYMBOL(sptlrpc_rule_set_free);
371 * return 0 if the rule set could accomodate one more rule.
372 * if @expand != 0, the rule set might be expanded.
374 int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset, int expand)
376 struct sptlrpc_rule *rules;
379 if (rset->srs_nrule < rset->srs_nslot)
385 if (rset->srs_nslot == 0)
388 nslot = rset->srs_nslot + 8;
390 /* better use realloc() if available */
391 OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules));
395 memcpy(rules, rset->srs_rules,
396 rset->srs_nrule * sizeof(*rset->srs_rules));
399 OBD_FREE(rset->srs_rules,
400 rset->srs_nslot * sizeof(*rset->srs_rules));
402 rset->srs_rules = rules;
403 rset->srs_nslot = nslot;
406 EXPORT_SYMBOL(sptlrpc_rule_set_expand);
408 static inline int rule_spec_dir(struct sptlrpc_rule *rule)
410 return (rule->sr_from != LUSTRE_SP_ANY ||
411 rule->sr_to != LUSTRE_SP_ANY);
413 static inline int rule_spec_net(struct sptlrpc_rule *rule)
415 return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
417 static inline int rule_match_dir(struct sptlrpc_rule *r1,
418 struct sptlrpc_rule *r2)
420 return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to);
422 static inline int rule_match_net(struct sptlrpc_rule *r1,
423 struct sptlrpc_rule *r2)
425 return (r1->sr_netid == r2->sr_netid);
429 * merge @rule into @rset.
430 * if @expand != 0 then @rset slots might be expanded.
432 int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset,
433 struct sptlrpc_rule *rule,
436 struct sptlrpc_rule *p = rset->srs_rules;
437 int spec_dir, spec_net;
438 int rc, n, match = 0;
440 spec_net = rule_spec_net(rule);
441 spec_dir = rule_spec_dir(rule);
443 for (n = 0; n < rset->srs_nrule; n++) {
444 p = &rset->srs_rules[n];
446 /* test network match, if failed:
447 * - spec rule: skip rules which is also spec rule match, until
448 * we hit a wild rule, which means no more chance
449 * - wild rule: skip until reach the one which is also wild
452 if (!rule_match_net(p, rule)) {
454 if (rule_spec_net(p))
463 /* test dir match, same logic as net matching */
464 if (!rule_match_dir(p, rule)) {
466 if (rule_spec_dir(p))
481 LASSERT(n >= 0 && n < rset->srs_nrule);
483 if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
484 /* remove this rule */
485 if (n < rset->srs_nrule - 1)
486 memmove(&rset->srs_rules[n],
487 &rset->srs_rules[n + 1],
488 (rset->srs_nrule - n - 1) *
492 /* override the rule */
493 memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
496 LASSERT(n >= 0 && n <= rset->srs_nrule);
498 if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
499 rc = sptlrpc_rule_set_expand(rset, expand);
503 if (n < rset->srs_nrule)
504 memmove(&rset->srs_rules[n + 1],
506 (rset->srs_nrule - n) * sizeof(*rule));
507 memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
510 CWARN("ignore the unmatched deletion\n");
516 EXPORT_SYMBOL(sptlrpc_rule_set_merge);
518 int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset,
519 struct sptlrpc_conf_log *log)
524 sptlrpc_rule_set_free(rset);
526 if (log->scl_nrule == 0)
529 OBD_ALLOC(rset->srs_rules, log->scl_nrule * sizeof(*log->scl_rules));
530 if (!rset->srs_rules)
533 memcpy(rset->srs_rules, log->scl_rules,
534 log->scl_nrule * sizeof(*log->scl_rules));
535 rset->srs_nslot = rset->srs_nrule = log->scl_nrule;
538 EXPORT_SYMBOL(sptlrpc_rule_set_from_log);
541 * according to NID/from choose a flavor from rule set.
543 void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
544 enum lustre_sec_part from,
546 struct sptlrpc_flavor *sf)
548 struct sptlrpc_rule *r;
551 for (n = 0; n < rset->srs_nrule; n++) {
552 r = &rset->srs_rules[n];
554 if (LNET_NIDNET(nid) != LNET_NIDNET(LNET_NID_ANY) &&
555 r->sr_netid != LNET_NIDNET(LNET_NID_ANY) &&
556 LNET_NIDNET(nid) != r->sr_netid)
559 if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY &&
567 /* no match found, set as default flavor */
568 get_default_flavor(sf);
570 EXPORT_SYMBOL(sptlrpc_rule_set_choose);
572 void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset)
574 struct sptlrpc_rule *r;
577 for (n = 0; n < rset->srs_nrule; n++) {
578 r = &rset->srs_rules[n];
579 CWARN("<%02d> from %x to %x, net %x, rpc %x\n", n,
580 r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
583 EXPORT_SYMBOL(sptlrpc_rule_set_dump);
585 /****************************************
586 * sptlrpc config log *
587 ****************************************/
589 struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void)
591 struct sptlrpc_conf_log *log;
595 return ERR_PTR(-ENOMEM);
597 log->scl_max = SPTLRPC_CONF_LOG_MAX;
600 EXPORT_SYMBOL(sptlrpc_conf_log_alloc);
602 void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log)
604 LASSERT(log->scl_max == SPTLRPC_CONF_LOG_MAX);
607 EXPORT_SYMBOL(sptlrpc_conf_log_free);
609 static __u32 get_log_rule_flags(enum lustre_sec_part from,
610 enum lustre_sec_part to,
611 unsigned int fl_udesc)
613 /* MDT->MDT; MDT->OST */
614 if (from == LUSTRE_SP_MDT)
615 return PTLRPC_SEC_FL_ROOTONLY;
617 if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST)
618 return PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
620 if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT)
622 return PTLRPC_SEC_FL_UDESC;
628 * generate config log: merge general and target rules, which
631 int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen,
632 struct sptlrpc_rule_set *tgt,
633 enum lustre_sec_part from,
634 enum lustre_sec_part to,
635 unsigned int fl_udesc,
636 struct sptlrpc_conf_log *log)
638 struct sptlrpc_rule_set *src[2] = { gen, tgt };
639 struct sptlrpc_rule_set dst;
640 struct sptlrpc_rule *rule;
646 dst.srs_nslot = log->scl_max;
648 dst.srs_rules = log->scl_rules;
650 /* merge general rules firstly, then target-specific rules */
651 for (i = 0; i < 2; i++) {
655 for (n = 0; n < src[i]->srs_nrule; n++) {
656 rule = &src[i]->srs_rules[n];
658 if (from != LUSTRE_SP_ANY &&
659 rule->sr_from != LUSTRE_SP_ANY &&
660 rule->sr_from != from)
662 if (to != LUSTRE_SP_ANY &&
663 rule->sr_to != LUSTRE_SP_ANY &&
667 rc = sptlrpc_rule_set_merge(&dst, rule, 0);
669 CERROR("can't merge: %d\n", rc);
675 log->scl_nrule = dst.srs_nrule;
677 /* set flags for each rule */
678 flags = get_log_rule_flags(from, to, fl_udesc);
680 for (i = 0; i < log->scl_nrule; i++) {
681 log->scl_rules[i].sr_flvr.sf_flags = flags;
683 /* also clear the from/to fields which don't need to be known
684 * accordingly. @from == ANY means this log is for target,
685 * otherwise for client. */
686 if (from != LUSTRE_SP_ANY)
687 log->scl_rules[i].sr_from = LUSTRE_SP_ANY;
688 log->scl_rules[i].sr_to = LUSTRE_SP_ANY;
693 EXPORT_SYMBOL(sptlrpc_conf_log_populate);
696 * extract config log from @lcfg
698 struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg)
700 struct sptlrpc_conf_log *log;
701 struct sptlrpc_rule *r;
705 log = lustre_cfg_buf(lcfg, 1);
707 CERROR("no sptlrpc config data\n");
708 RETURN(ERR_PTR(-EINVAL));
711 if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
712 __swab32s(&log->scl_max);
713 __swab32s(&log->scl_nrule);
716 if (LUSTRE_CFG_BUFLEN(lcfg, 1) <
717 log->scl_max * sizeof(log->scl_rules[0])) {
718 CERROR("mal-formed config log\n");
719 RETURN(ERR_PTR(-EINVAL));
722 if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
723 for (i = 0; i < log->scl_nrule; i++) {
724 r = &log->scl_rules[i];
725 __swab32s(&r->sr_netid);
726 __swab16s(&r->sr_flvr.sf_rpc);
727 __swab32s(&r->sr_flvr.sf_flags);
733 EXPORT_SYMBOL(sptlrpc_conf_log_extract);
735 void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log)
738 memset(log->scl_rules, 0, sizeof(log->scl_rules));
740 EXPORT_SYMBOL(sptlrpc_conf_log_cleanup);
742 void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log)
744 struct sptlrpc_rule *r;
747 CWARN("max %u, rule# %u part %u\n",
748 log->scl_max, log->scl_nrule, log->scl_part);
750 for (n = 0; n < log->scl_nrule; n++) {
751 r = &log->scl_rules[n];
752 CWARN("<%02d> %x -> %x, net %x, rpc %x\n", n,
753 r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
756 EXPORT_SYMBOL(sptlrpc_conf_log_dump);
759 * caller should guarantee that no concurrent calls to this function
761 #define SEC_ADAPT_DELAY (10)
763 int sptlrpc_cliobd_process_config(struct obd_device *obd,
764 struct lustre_cfg *lcfg)
766 struct sptlrpc_conf_log *log;
767 struct obd_import *imp;
770 log = sptlrpc_conf_log_extract(lcfg);
772 CERROR("extract log error: %ld\n", PTR_ERR(log));
776 obd->u.cli.cl_sec_part = log->scl_part;
778 rc = sptlrpc_rule_set_from_log(&obd->u.cli.cl_sptlrpc_rset, log);
780 CERROR("failed create rule set: %d\n", rc);
784 imp = obd->u.cli.cl_import;
788 /* even if imp_sec_expire is already set, we'll override it to a
789 * newer (later) time */
790 spin_lock(&imp->imp_lock);
792 imp->imp_sec_expire = cfs_time_current_sec() + SEC_ADAPT_DELAY;
793 spin_unlock(&imp->imp_lock);
796 EXPORT_SYMBOL(sptlrpc_cliobd_process_config);