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 ****************************************/
86 #define BULK_HASH_ALG_DEFAULT BULK_HASH_ALG_ADLER32
88 #define BULK_HASH_ALG_DEFAULT BULK_HASH_ALG_CRC32
97 static void get_default_flavor(struct sptlrpc_flavor *sf)
99 sf->sf_rpc = SPTLRPC_FLVR_NULL;
100 sf->sf_bulk_ciph = BULK_CIPH_ALG_NULL;
101 sf->sf_bulk_hash = BULK_HASH_ALG_NULL;
105 static void get_flavor_by_rpc(struct sptlrpc_rule *rule, __u16 rpc_flavor)
107 get_default_flavor(&rule->sr_flvr);
109 rule->sr_flvr.sf_rpc = rpc_flavor;
111 switch (rpc_flavor) {
112 case SPTLRPC_FLVR_NULL:
114 case SPTLRPC_FLVR_PLAIN:
115 case SPTLRPC_FLVR_KRB5N:
116 case SPTLRPC_FLVR_KRB5A:
117 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_DEFAULT;
119 case SPTLRPC_FLVR_KRB5P:
120 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128;
122 case SPTLRPC_FLVR_KRB5I:
123 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
130 static void get_flavor_by_bulk(struct sptlrpc_rule *rule,
131 __u16 rpc_flavor, bulk_type_t bulk_type)
135 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL;
136 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
139 switch (rpc_flavor) {
140 case SPTLRPC_FLVR_PLAIN:
141 case SPTLRPC_FLVR_KRB5N:
142 case SPTLRPC_FLVR_KRB5A:
143 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_DEFAULT;
145 case SPTLRPC_FLVR_KRB5I:
146 case SPTLRPC_FLVR_KRB5P:
147 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
152 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
155 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
156 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128;
163 static __u16 __flavors[] = {
172 #define __nflavors ARRAY_SIZE(__flavors)
175 * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]]
181 * krb5i-bulkp:sha512/arc4
183 static int parse_flavor(char *str, struct sptlrpc_rule *rule)
186 char *bulk, *alg, *enc;
188 bulk_type_t bulk_type;
192 if (str == NULL || str[0] == '\0') {
193 rule->sr_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
197 for (i = 0; i < __nflavors; i++) {
198 f = sptlrpc_rpcflavor2name(__flavors[i]);
199 if (strncmp(str, f, strlen(f)) == 0)
204 GOTO(invalid, -EINVAL);
206 /* prepare local buffer thus we can modify it as we want */
207 strncpy(buf, str, 64);
210 /* find bulk string */
211 bulk = strchr(buf, '-');
215 /* now the first part must equal to rpc flavor name */
216 if (strcmp(buf, f) != 0)
217 GOTO(invalid, -EINVAL);
219 get_flavor_by_rpc(rule, __flavors[i]);
224 /* find bulk algorithm string */
225 alg = strchr(bulk, ':');
229 /* verify bulk section */
230 if (strcmp(bulk, "bulkn") == 0) {
231 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL;
232 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
233 bulk_type = BULK_TYPE_N;
234 } else if (strcmp(bulk, "bulki") == 0)
235 bulk_type = BULK_TYPE_I;
236 else if (strcmp(bulk, "bulkp") == 0)
237 bulk_type = BULK_TYPE_P;
239 GOTO(invalid, -EINVAL);
241 /* null flavor don't support bulk i/p */
242 if (__flavors[i] == SPTLRPC_FLVR_NULL && bulk_type != BULK_TYPE_N)
243 GOTO(invalid, -EINVAL);
245 /* plain policy dosen't support bulk p */
246 if (__flavors[i] == SPTLRPC_FLVR_PLAIN && bulk_type == BULK_TYPE_P)
247 GOTO(invalid, -EINVAL);
249 get_flavor_by_bulk(rule, __flavors[i], bulk_type);
254 /* find encryption algorithm string */
255 enc = strchr(alg, '/');
259 /* checksum algorithm */
260 for (i = 0; i < BULK_HASH_ALG_MAX; i++) {
261 if (strcmp(alg, sptlrpc_get_hash_name(i)) == 0) {
262 rule->sr_flvr.sf_bulk_hash = i;
266 if (i >= BULK_HASH_ALG_MAX)
267 GOTO(invalid, -EINVAL);
269 /* privacy algorithm */
271 for (i = 0; i < BULK_CIPH_ALG_MAX; i++) {
272 if (strcmp(enc, sptlrpc_get_ciph_name(i)) == 0) {
273 rule->sr_flvr.sf_bulk_ciph = i;
277 if (i >= BULK_CIPH_ALG_MAX)
278 GOTO(invalid, -EINVAL);
282 * bulk combination sanity checks
284 if (bulk_type == BULK_TYPE_P &&
285 rule->sr_flvr.sf_bulk_ciph == BULK_CIPH_ALG_NULL)
286 GOTO(invalid, -EINVAL);
288 if (bulk_type == BULK_TYPE_I &&
289 (rule->sr_flvr.sf_bulk_hash == BULK_HASH_ALG_NULL ||
290 rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL))
291 GOTO(invalid, -EINVAL);
293 if (bulk_type == BULK_TYPE_N &&
294 (rule->sr_flvr.sf_bulk_hash != BULK_HASH_ALG_NULL ||
295 rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL))
296 GOTO(invalid, -EINVAL);
301 CERROR("invalid flavor string: %s\n", str);
305 /****************************************
307 ****************************************/
309 static void sptlrpc_rule_init(struct sptlrpc_rule *rule)
311 rule->sr_netid = LNET_NIDNET(LNET_NID_ANY);
312 rule->sr_from = LUSTRE_SP_ANY;
313 rule->sr_to = LUSTRE_SP_ANY;
314 rule->sr_padding = 0;
316 get_default_flavor(&rule->sr_flvr);
320 * format: network[.direction]=flavor
322 int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
327 sptlrpc_rule_init(rule);
329 flavor = strchr(param, '=');
330 if (flavor == NULL) {
331 CERROR("invalid param, no '='\n");
336 dir = strchr(param, '.');
341 if (strcmp(param, "default")) {
342 rule->sr_netid = libcfs_str2net(param);
343 if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
344 CERROR("invalid network name: %s\n", param);
351 if (!strcmp(dir, "mdt2ost")) {
352 rule->sr_from = LUSTRE_SP_MDT;
353 rule->sr_to = LUSTRE_SP_OST;
354 } else if (!strcmp(dir, "mdt2mdt")) {
355 rule->sr_from = LUSTRE_SP_MDT;
356 rule->sr_to = LUSTRE_SP_MDT;
357 } else if (!strcmp(dir, "cli2ost")) {
358 rule->sr_from = LUSTRE_SP_CLI;
359 rule->sr_to = LUSTRE_SP_OST;
360 } else if (!strcmp(dir, "cli2mdt")) {
361 rule->sr_from = LUSTRE_SP_CLI;
362 rule->sr_to = LUSTRE_SP_MDT;
364 CERROR("invalid rule dir segment: %s\n", dir);
370 rc = parse_flavor(flavor, rule);
376 EXPORT_SYMBOL(sptlrpc_parse_rule);
378 void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
380 LASSERT(rset->srs_nslot ||
381 (rset->srs_nrule == 0 && rset->srs_rules == NULL));
383 if (rset->srs_nslot) {
384 OBD_FREE(rset->srs_rules,
385 rset->srs_nslot * sizeof(*rset->srs_rules));
386 sptlrpc_rule_set_init(rset);
389 EXPORT_SYMBOL(sptlrpc_rule_set_free);
392 * return 0 if the rule set could accomodate one more rule.
393 * if @expand != 0, the rule set might be expanded.
395 int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset, int expand)
397 struct sptlrpc_rule *rules;
400 if (rset->srs_nrule < rset->srs_nslot)
406 if (rset->srs_nslot == 0)
409 nslot = rset->srs_nslot + 8;
411 /* better use realloc() if available */
412 OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules));
416 memcpy(rules, rset->srs_rules,
417 rset->srs_nrule * sizeof(*rset->srs_rules));
420 OBD_FREE(rset->srs_rules,
421 rset->srs_nslot * sizeof(*rset->srs_rules));
423 rset->srs_rules = rules;
424 rset->srs_nslot = nslot;
427 EXPORT_SYMBOL(sptlrpc_rule_set_expand);
429 static inline int rule_spec_dir(struct sptlrpc_rule *rule)
431 return (rule->sr_from != LUSTRE_SP_ANY ||
432 rule->sr_to != LUSTRE_SP_ANY);
434 static inline int rule_spec_net(struct sptlrpc_rule *rule)
436 return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
438 static inline int rule_match_dir(struct sptlrpc_rule *r1,
439 struct sptlrpc_rule *r2)
441 return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to);
443 static inline int rule_match_net(struct sptlrpc_rule *r1,
444 struct sptlrpc_rule *r2)
446 return (r1->sr_netid == r2->sr_netid);
450 * merge @rule into @rset.
451 * if @expand != 0 then @rset slots might be expanded.
453 int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset,
454 struct sptlrpc_rule *rule,
457 struct sptlrpc_rule *p = rset->srs_rules;
458 int spec_dir, spec_net;
459 int rc, n, match = 0;
461 spec_net = rule_spec_net(rule);
462 spec_dir = rule_spec_dir(rule);
464 for (n = 0; n < rset->srs_nrule; n++) {
465 p = &rset->srs_rules[n];
467 /* test network match, if failed:
468 * - spec rule: skip rules which is also spec rule match, until
469 * we hit a wild rule, which means no more chance
470 * - wild rule: skip until reach the one which is also wild
473 if (!rule_match_net(p, rule)) {
475 if (rule_spec_net(p))
484 /* test dir match, same logic as net matching */
485 if (!rule_match_dir(p, rule)) {
487 if (rule_spec_dir(p))
502 LASSERT(n >= 0 && n < rset->srs_nrule);
504 if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
505 /* remove this rule */
506 if (n < rset->srs_nrule - 1)
507 memmove(&rset->srs_rules[n],
508 &rset->srs_rules[n + 1],
509 (rset->srs_nrule - n - 1) *
513 /* override the rule */
514 memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
517 LASSERT(n >= 0 && n <= rset->srs_nrule);
519 if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
520 rc = sptlrpc_rule_set_expand(rset, expand);
524 if (n < rset->srs_nrule)
525 memmove(&rset->srs_rules[n + 1],
527 (rset->srs_nrule - n) * sizeof(*rule));
528 memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
531 CWARN("ignore the unmatched deletion\n");
537 EXPORT_SYMBOL(sptlrpc_rule_set_merge);
539 int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset,
540 struct sptlrpc_conf_log *log)
545 sptlrpc_rule_set_free(rset);
547 if (log->scl_nrule == 0)
550 OBD_ALLOC(rset->srs_rules, log->scl_nrule * sizeof(*log->scl_rules));
551 if (!rset->srs_rules)
554 memcpy(rset->srs_rules, log->scl_rules,
555 log->scl_nrule * sizeof(*log->scl_rules));
556 rset->srs_nslot = rset->srs_nrule = log->scl_nrule;
559 EXPORT_SYMBOL(sptlrpc_rule_set_from_log);
562 * according to NID/from choose a flavor from rule set.
564 void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
565 enum lustre_sec_part from,
567 struct sptlrpc_flavor *sf)
569 struct sptlrpc_rule *r;
572 for (n = 0; n < rset->srs_nrule; n++) {
573 r = &rset->srs_rules[n];
575 if (LNET_NIDNET(nid) != LNET_NIDNET(LNET_NID_ANY) &&
576 r->sr_netid != LNET_NIDNET(LNET_NID_ANY) &&
577 LNET_NIDNET(nid) != r->sr_netid)
580 if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY &&
588 /* no match found, set as default flavor */
589 get_default_flavor(sf);
591 EXPORT_SYMBOL(sptlrpc_rule_set_choose);
593 void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset)
595 struct sptlrpc_rule *r;
598 for (n = 0; n < rset->srs_nrule; n++) {
599 r = &rset->srs_rules[n];
600 CWARN("<%02d> from %x to %x, net %x, rpc %x\n", n,
601 r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
604 EXPORT_SYMBOL(sptlrpc_rule_set_dump);
606 /****************************************
607 * sptlrpc config log *
608 ****************************************/
610 struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void)
612 struct sptlrpc_conf_log *log;
616 return ERR_PTR(-ENOMEM);
618 log->scl_max = SPTLRPC_CONF_LOG_MAX;
621 EXPORT_SYMBOL(sptlrpc_conf_log_alloc);
623 void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log)
625 LASSERT(log->scl_max == SPTLRPC_CONF_LOG_MAX);
628 EXPORT_SYMBOL(sptlrpc_conf_log_free);
630 static __u32 get_log_rule_flags(enum lustre_sec_part from,
631 enum lustre_sec_part to,
632 unsigned int fl_udesc)
634 /* MDT->MDT; MDT->OST */
635 if (from == LUSTRE_SP_MDT)
636 return PTLRPC_SEC_FL_ROOTONLY;
638 if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST)
639 return PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
641 if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT)
643 return PTLRPC_SEC_FL_UDESC;
649 * generate config log: merge general and target rules, which
652 int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen,
653 struct sptlrpc_rule_set *tgt,
654 enum lustre_sec_part from,
655 enum lustre_sec_part to,
656 unsigned int fl_udesc,
657 struct sptlrpc_conf_log *log)
659 struct sptlrpc_rule_set *src[2] = { gen, tgt };
660 struct sptlrpc_rule_set dst;
661 struct sptlrpc_rule *rule;
667 dst.srs_nslot = log->scl_max;
669 dst.srs_rules = log->scl_rules;
671 /* merge general rules firstly, then target-specific rules */
672 for (i = 0; i < 2; i++) {
676 for (n = 0; n < src[i]->srs_nrule; n++) {
677 rule = &src[i]->srs_rules[n];
679 if (from != LUSTRE_SP_ANY &&
680 rule->sr_from != LUSTRE_SP_ANY &&
681 rule->sr_from != from)
683 if (to != LUSTRE_SP_ANY &&
684 rule->sr_to != LUSTRE_SP_ANY &&
688 rc = sptlrpc_rule_set_merge(&dst, rule, 0);
690 CERROR("can't merge: %d\n", rc);
696 log->scl_nrule = dst.srs_nrule;
698 /* set flags for each rule */
699 flags = get_log_rule_flags(from, to, fl_udesc);
701 for (i = 0; i < log->scl_nrule; i++) {
702 log->scl_rules[i].sr_flvr.sf_flags = flags;
704 /* also clear the from/to fields which don't need to be known
705 * accordingly. @from == ANY means this log is for target,
706 * otherwise for client. */
707 if (from != LUSTRE_SP_ANY)
708 log->scl_rules[i].sr_from = LUSTRE_SP_ANY;
709 log->scl_rules[i].sr_to = LUSTRE_SP_ANY;
714 EXPORT_SYMBOL(sptlrpc_conf_log_populate);
717 * extract config log from @lcfg
719 struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg)
721 struct sptlrpc_conf_log *log;
722 struct sptlrpc_rule *r;
726 log = lustre_cfg_buf(lcfg, 1);
728 CERROR("no sptlrpc config data\n");
729 RETURN(ERR_PTR(-EINVAL));
732 if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
733 __swab32s(&log->scl_max);
734 __swab32s(&log->scl_nrule);
737 if (LUSTRE_CFG_BUFLEN(lcfg, 1) <
738 log->scl_max * sizeof(log->scl_rules[0])) {
739 CERROR("mal-formed config log\n");
740 RETURN(ERR_PTR(-EINVAL));
743 if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
744 for (i = 0; i < log->scl_nrule; i++) {
745 r = &log->scl_rules[i];
746 __swab32s(&r->sr_netid);
747 __swab16s(&r->sr_flvr.sf_rpc);
748 __swab32s(&r->sr_flvr.sf_flags);
754 EXPORT_SYMBOL(sptlrpc_conf_log_extract);
756 void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log)
759 memset(log->scl_rules, 0, sizeof(log->scl_rules));
761 EXPORT_SYMBOL(sptlrpc_conf_log_cleanup);
763 void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log)
765 struct sptlrpc_rule *r;
768 CWARN("max %u, rule# %u part %u\n",
769 log->scl_max, log->scl_nrule, log->scl_part);
771 for (n = 0; n < log->scl_nrule; n++) {
772 r = &log->scl_rules[n];
773 CWARN("<%02d> %x -> %x, net %x, rpc %x\n", n,
774 r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
777 EXPORT_SYMBOL(sptlrpc_conf_log_dump);
780 * caller should guarantee that no concurrent calls to this function
782 #define SEC_ADAPT_DELAY (10)
784 int sptlrpc_cliobd_process_config(struct obd_device *obd,
785 struct lustre_cfg *lcfg)
787 struct sptlrpc_conf_log *log;
788 struct obd_import *imp;
791 log = sptlrpc_conf_log_extract(lcfg);
793 CERROR("extract log error: %ld\n", PTR_ERR(log));
797 obd->u.cli.cl_sec_part = log->scl_part;
799 rc = sptlrpc_rule_set_from_log(&obd->u.cli.cl_sptlrpc_rset, log);
801 CERROR("failed create rule set: %d\n", rc);
805 imp = obd->u.cli.cl_import;
809 /* even if imp_sec_expire is already set, we'll override it to a
810 * newer (later) time */
811 spin_lock(&imp->imp_lock);
813 imp->imp_sec_expire = cfs_time_current_sec() + SEC_ADAPT_DELAY;
814 spin_unlock(&imp->imp_lock);
817 EXPORT_SYMBOL(sptlrpc_cliobd_process_config);