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_ciph = BULK_CIPH_ALG_NULL;
95 sf->sf_bulk_hash = BULK_HASH_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:
108 case SPTLRPC_FLVR_PLAIN:
109 case SPTLRPC_FLVR_KRB5N:
110 case SPTLRPC_FLVR_KRB5A:
111 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_ADLER32;
113 case SPTLRPC_FLVR_KRB5P:
114 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128;
116 case SPTLRPC_FLVR_KRB5I:
117 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
124 static void get_flavor_by_bulk(struct sptlrpc_rule *rule,
125 __u16 rpc_flavor, bulk_type_t bulk_type)
129 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL;
130 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
133 switch (rpc_flavor) {
134 case SPTLRPC_FLVR_PLAIN:
135 case SPTLRPC_FLVR_KRB5N:
136 case SPTLRPC_FLVR_KRB5A:
137 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_ADLER32;
139 case SPTLRPC_FLVR_KRB5I:
140 case SPTLRPC_FLVR_KRB5P:
141 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
146 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
149 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
150 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128;
157 static __u16 __flavors[] = {
166 #define __nflavors ARRAY_SIZE(__flavors)
169 * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]]
175 * krb5i-bulkp:sha512/arc4
177 static int parse_flavor(char *str, struct sptlrpc_rule *rule)
180 char *bulk, *alg, *enc;
182 bulk_type_t bulk_type;
186 if (str == NULL || str[0] == '\0') {
187 rule->sr_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
191 for (i = 0; i < __nflavors; i++) {
192 f = sptlrpc_rpcflavor2name(__flavors[i]);
193 if (strncmp(str, f, strlen(f)) == 0)
198 GOTO(invalid, -EINVAL);
200 /* prepare local buffer thus we can modify it as we want */
201 strncpy(buf, str, 64);
204 /* find bulk string */
205 bulk = strchr(buf, '-');
209 /* now the first part must equal to rpc flavor name */
210 if (strcmp(buf, f) != 0)
211 GOTO(invalid, -EINVAL);
213 get_flavor_by_rpc(rule, __flavors[i]);
218 /* find bulk algorithm string */
219 alg = strchr(bulk, ':');
223 /* verify bulk section */
224 if (strcmp(bulk, "bulkn") == 0) {
225 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL;
226 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
227 bulk_type = BULK_TYPE_N;
228 } else if (strcmp(bulk, "bulki") == 0)
229 bulk_type = BULK_TYPE_I;
230 else if (strcmp(bulk, "bulkp") == 0)
231 bulk_type = BULK_TYPE_P;
233 GOTO(invalid, -EINVAL);
235 /* null flavor don't support bulk i/p */
236 if (__flavors[i] == SPTLRPC_FLVR_NULL && bulk_type != BULK_TYPE_N)
237 GOTO(invalid, -EINVAL);
239 /* plain policy dosen't support bulk p */
240 if (__flavors[i] == SPTLRPC_FLVR_PLAIN && bulk_type == BULK_TYPE_P)
241 GOTO(invalid, -EINVAL);
243 get_flavor_by_bulk(rule, __flavors[i], bulk_type);
248 /* find encryption algorithm string */
249 enc = strchr(alg, '/');
253 /* checksum algorithm */
254 for (i = 0; i < BULK_HASH_ALG_MAX; i++) {
255 if (strcmp(alg, sptlrpc_get_hash_name(i)) == 0) {
256 rule->sr_flvr.sf_bulk_hash = i;
260 if (i >= BULK_HASH_ALG_MAX)
261 GOTO(invalid, -EINVAL);
263 /* privacy algorithm */
265 for (i = 0; i < BULK_CIPH_ALG_MAX; i++) {
266 if (strcmp(enc, sptlrpc_get_ciph_name(i)) == 0) {
267 rule->sr_flvr.sf_bulk_ciph = i;
271 if (i >= BULK_CIPH_ALG_MAX)
272 GOTO(invalid, -EINVAL);
276 * bulk combination sanity checks
278 if (bulk_type == BULK_TYPE_P &&
279 rule->sr_flvr.sf_bulk_ciph == BULK_CIPH_ALG_NULL)
280 GOTO(invalid, -EINVAL);
282 if (bulk_type == BULK_TYPE_I &&
283 (rule->sr_flvr.sf_bulk_hash == BULK_HASH_ALG_NULL ||
284 rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL))
285 GOTO(invalid, -EINVAL);
287 if (bulk_type == BULK_TYPE_N &&
288 (rule->sr_flvr.sf_bulk_hash != BULK_HASH_ALG_NULL ||
289 rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL))
290 GOTO(invalid, -EINVAL);
295 CERROR("invalid flavor string: %s\n", str);
299 /****************************************
301 ****************************************/
303 static void sptlrpc_rule_init(struct sptlrpc_rule *rule)
305 rule->sr_netid = LNET_NIDNET(LNET_NID_ANY);
306 rule->sr_from = LUSTRE_SP_ANY;
307 rule->sr_to = LUSTRE_SP_ANY;
308 rule->sr_padding = 0;
310 get_default_flavor(&rule->sr_flvr);
314 * format: network[.direction]=flavor
316 int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
321 sptlrpc_rule_init(rule);
323 flavor = strchr(param, '=');
324 if (flavor == NULL) {
325 CERROR("invalid param, no '='\n");
330 dir = strchr(param, '.');
335 if (strcmp(param, "default")) {
336 rule->sr_netid = libcfs_str2net(param);
337 if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
338 CERROR("invalid network name: %s\n", param);
345 if (!strcmp(dir, "mdt2ost")) {
346 rule->sr_from = LUSTRE_SP_MDT;
347 rule->sr_to = LUSTRE_SP_OST;
348 } else if (!strcmp(dir, "mdt2mdt")) {
349 rule->sr_from = LUSTRE_SP_MDT;
350 rule->sr_to = LUSTRE_SP_MDT;
351 } else if (!strcmp(dir, "cli2ost")) {
352 rule->sr_from = LUSTRE_SP_CLI;
353 rule->sr_to = LUSTRE_SP_OST;
354 } else if (!strcmp(dir, "cli2mdt")) {
355 rule->sr_from = LUSTRE_SP_CLI;
356 rule->sr_to = LUSTRE_SP_MDT;
358 CERROR("invalid rule dir segment: %s\n", dir);
364 rc = parse_flavor(flavor, rule);
370 EXPORT_SYMBOL(sptlrpc_parse_rule);
372 void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
374 LASSERT(rset->srs_nslot ||
375 (rset->srs_nrule == 0 && rset->srs_rules == NULL));
377 if (rset->srs_nslot) {
378 OBD_FREE(rset->srs_rules,
379 rset->srs_nslot * sizeof(*rset->srs_rules));
380 sptlrpc_rule_set_init(rset);
383 EXPORT_SYMBOL(sptlrpc_rule_set_free);
386 * return 0 if the rule set could accomodate one more rule.
387 * if @expand != 0, the rule set might be expanded.
389 int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset, int expand)
391 struct sptlrpc_rule *rules;
394 if (rset->srs_nrule < rset->srs_nslot)
400 if (rset->srs_nslot == 0)
403 nslot = rset->srs_nslot + 8;
405 /* better use realloc() if available */
406 OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules));
410 memcpy(rules, rset->srs_rules,
411 rset->srs_nrule * sizeof(*rset->srs_rules));
414 OBD_FREE(rset->srs_rules,
415 rset->srs_nslot * sizeof(*rset->srs_rules));
417 rset->srs_rules = rules;
418 rset->srs_nslot = nslot;
421 EXPORT_SYMBOL(sptlrpc_rule_set_expand);
423 static inline int rule_spec_dir(struct sptlrpc_rule *rule)
425 return (rule->sr_from != LUSTRE_SP_ANY ||
426 rule->sr_to != LUSTRE_SP_ANY);
428 static inline int rule_spec_net(struct sptlrpc_rule *rule)
430 return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
432 static inline int rule_match_dir(struct sptlrpc_rule *r1,
433 struct sptlrpc_rule *r2)
435 return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to);
437 static inline int rule_match_net(struct sptlrpc_rule *r1,
438 struct sptlrpc_rule *r2)
440 return (r1->sr_netid == r2->sr_netid);
444 * merge @rule into @rset.
445 * if @expand != 0 then @rset slots might be expanded.
447 int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset,
448 struct sptlrpc_rule *rule,
451 struct sptlrpc_rule *p = rset->srs_rules;
452 int spec_dir, spec_net;
453 int rc, n, match = 0;
455 spec_net = rule_spec_net(rule);
456 spec_dir = rule_spec_dir(rule);
458 for (n = 0; n < rset->srs_nrule; n++) {
459 p = &rset->srs_rules[n];
461 /* test network match, if failed:
462 * - spec rule: skip rules which is also spec rule match, until
463 * we hit a wild rule, which means no more chance
464 * - wild rule: skip until reach the one which is also wild
467 if (!rule_match_net(p, rule)) {
469 if (rule_spec_net(p))
478 /* test dir match, same logic as net matching */
479 if (!rule_match_dir(p, rule)) {
481 if (rule_spec_dir(p))
496 LASSERT(n >= 0 && n < rset->srs_nrule);
498 if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
499 /* remove this rule */
500 if (n < rset->srs_nrule - 1)
501 memmove(&rset->srs_rules[n],
502 &rset->srs_rules[n + 1],
503 (rset->srs_nrule - n - 1) *
507 /* override the rule */
508 memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
511 LASSERT(n >= 0 && n <= rset->srs_nrule);
513 if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
514 rc = sptlrpc_rule_set_expand(rset, expand);
518 if (n < rset->srs_nrule)
519 memmove(&rset->srs_rules[n + 1],
521 (rset->srs_nrule - n) * sizeof(*rule));
522 memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
525 CWARN("ignore the unmatched deletion\n");
531 EXPORT_SYMBOL(sptlrpc_rule_set_merge);
533 int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset,
534 struct sptlrpc_conf_log *log)
539 sptlrpc_rule_set_free(rset);
541 if (log->scl_nrule == 0)
544 OBD_ALLOC(rset->srs_rules, log->scl_nrule * sizeof(*log->scl_rules));
545 if (!rset->srs_rules)
548 memcpy(rset->srs_rules, log->scl_rules,
549 log->scl_nrule * sizeof(*log->scl_rules));
550 rset->srs_nslot = rset->srs_nrule = log->scl_nrule;
553 EXPORT_SYMBOL(sptlrpc_rule_set_from_log);
556 * according to NID/from choose a flavor from rule set.
558 void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
559 enum lustre_sec_part from,
561 struct sptlrpc_flavor *sf)
563 struct sptlrpc_rule *r;
566 for (n = 0; n < rset->srs_nrule; n++) {
567 r = &rset->srs_rules[n];
569 if (LNET_NIDNET(nid) != LNET_NIDNET(LNET_NID_ANY) &&
570 r->sr_netid != LNET_NIDNET(LNET_NID_ANY) &&
571 LNET_NIDNET(nid) != r->sr_netid)
574 if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY &&
582 /* no match found, set as default flavor */
583 get_default_flavor(sf);
585 EXPORT_SYMBOL(sptlrpc_rule_set_choose);
587 void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset)
589 struct sptlrpc_rule *r;
592 for (n = 0; n < rset->srs_nrule; n++) {
593 r = &rset->srs_rules[n];
594 CWARN("<%02d> from %x to %x, net %x, rpc %x\n", n,
595 r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
598 EXPORT_SYMBOL(sptlrpc_rule_set_dump);
600 /****************************************
601 * sptlrpc config log *
602 ****************************************/
604 struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void)
606 struct sptlrpc_conf_log *log;
610 return ERR_PTR(-ENOMEM);
612 log->scl_max = SPTLRPC_CONF_LOG_MAX;
615 EXPORT_SYMBOL(sptlrpc_conf_log_alloc);
617 void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log)
619 LASSERT(log->scl_max == SPTLRPC_CONF_LOG_MAX);
622 EXPORT_SYMBOL(sptlrpc_conf_log_free);
624 static __u32 get_log_rule_flags(enum lustre_sec_part from,
625 enum lustre_sec_part to,
626 unsigned int fl_udesc)
628 /* MDT->MDT; MDT->OST */
629 if (from == LUSTRE_SP_MDT)
630 return PTLRPC_SEC_FL_ROOTONLY;
632 if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST)
633 return PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
635 if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT)
637 return PTLRPC_SEC_FL_UDESC;
643 * generate config log: merge general and target rules, which
646 int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen,
647 struct sptlrpc_rule_set *tgt,
648 enum lustre_sec_part from,
649 enum lustre_sec_part to,
650 unsigned int fl_udesc,
651 struct sptlrpc_conf_log *log)
653 struct sptlrpc_rule_set *src[2] = { gen, tgt };
654 struct sptlrpc_rule_set dst;
655 struct sptlrpc_rule *rule;
661 dst.srs_nslot = log->scl_max;
663 dst.srs_rules = log->scl_rules;
665 /* merge general rules firstly, then target-specific rules */
666 for (i = 0; i < 2; i++) {
670 for (n = 0; n < src[i]->srs_nrule; n++) {
671 rule = &src[i]->srs_rules[n];
673 if (from != LUSTRE_SP_ANY &&
674 rule->sr_from != LUSTRE_SP_ANY &&
675 rule->sr_from != from)
677 if (to != LUSTRE_SP_ANY &&
678 rule->sr_to != LUSTRE_SP_ANY &&
682 rc = sptlrpc_rule_set_merge(&dst, rule, 0);
684 CERROR("can't merge: %d\n", rc);
690 log->scl_nrule = dst.srs_nrule;
692 /* set flags for each rule */
693 flags = get_log_rule_flags(from, to, fl_udesc);
695 for (i = 0; i < log->scl_nrule; i++) {
696 log->scl_rules[i].sr_flvr.sf_flags = flags;
698 /* also clear the from/to fields which don't need to be known
699 * accordingly. @from == ANY means this log is for target,
700 * otherwise for client. */
701 if (from != LUSTRE_SP_ANY)
702 log->scl_rules[i].sr_from = LUSTRE_SP_ANY;
703 log->scl_rules[i].sr_to = LUSTRE_SP_ANY;
708 EXPORT_SYMBOL(sptlrpc_conf_log_populate);
711 * extract config log from @lcfg
713 struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg)
715 struct sptlrpc_conf_log *log;
716 struct sptlrpc_rule *r;
720 log = lustre_cfg_buf(lcfg, 1);
722 CERROR("no sptlrpc config data\n");
723 RETURN(ERR_PTR(-EINVAL));
726 if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
727 __swab32s(&log->scl_max);
728 __swab32s(&log->scl_nrule);
731 if (LUSTRE_CFG_BUFLEN(lcfg, 1) <
732 log->scl_max * sizeof(log->scl_rules[0])) {
733 CERROR("mal-formed config log\n");
734 RETURN(ERR_PTR(-EINVAL));
737 if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
738 for (i = 0; i < log->scl_nrule; i++) {
739 r = &log->scl_rules[i];
740 __swab32s(&r->sr_netid);
741 __swab16s(&r->sr_flvr.sf_rpc);
742 __swab32s(&r->sr_flvr.sf_flags);
748 EXPORT_SYMBOL(sptlrpc_conf_log_extract);
750 void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log)
753 memset(log->scl_rules, 0, sizeof(log->scl_rules));
755 EXPORT_SYMBOL(sptlrpc_conf_log_cleanup);
757 void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log)
759 struct sptlrpc_rule *r;
762 CWARN("max %u, rule# %u part %u\n",
763 log->scl_max, log->scl_nrule, log->scl_part);
765 for (n = 0; n < log->scl_nrule; n++) {
766 r = &log->scl_rules[n];
767 CWARN("<%02d> %x -> %x, net %x, rpc %x\n", n,
768 r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
771 EXPORT_SYMBOL(sptlrpc_conf_log_dump);
774 * caller should guarantee that no concurrent calls to this function
776 #define SEC_ADAPT_DELAY (10)
778 int sptlrpc_cliobd_process_config(struct obd_device *obd,
779 struct lustre_cfg *lcfg)
781 struct sptlrpc_conf_log *log;
782 struct obd_import *imp;
785 log = sptlrpc_conf_log_extract(lcfg);
787 CERROR("extract log error: %ld\n", PTR_ERR(log));
791 obd->u.cli.cl_sec_part = log->scl_part;
793 rc = sptlrpc_rule_set_from_log(&obd->u.cli.cl_sptlrpc_rset, log);
795 CERROR("failed create rule set: %d\n", rc);
799 imp = obd->u.cli.cl_import;
803 /* even if imp_sec_expire is already set, we'll override it to a
804 * newer (later) time */
805 spin_lock(&imp->imp_lock);
807 imp->imp_sec_expire = cfs_time_current_sec() + SEC_ADAPT_DELAY;
808 spin_unlock(&imp->imp_lock);
811 EXPORT_SYMBOL(sptlrpc_cliobd_process_config);