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) 2008, 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 
37 #define DEBUG_SUBSYSTEM S_SEC
38 
39 #include "../../include/linux/libcfs/libcfs.h"
40 #include <linux/crypto.h>
41 #include <linux/key.h>
42 
43 #include "../include/obd.h"
44 #include "../include/obd_support.h"
45 #include "../include/lustre_import.h"
46 #include "../include/lustre_param.h"
47 #include "../include/lustre_sec.h"
48 
49 #include "ptlrpc_internal.h"
50 
sptlrpc_part2name(enum lustre_sec_part part)51 const char *sptlrpc_part2name(enum lustre_sec_part part)
52 {
53 	switch (part) {
54 	case LUSTRE_SP_CLI:
55 		return "cli";
56 	case LUSTRE_SP_MDT:
57 		return "mdt";
58 	case LUSTRE_SP_OST:
59 		return "ost";
60 	case LUSTRE_SP_MGC:
61 		return "mgc";
62 	case LUSTRE_SP_MGS:
63 		return "mgs";
64 	case LUSTRE_SP_ANY:
65 		return "any";
66 	default:
67 		return "err";
68 	}
69 }
70 EXPORT_SYMBOL(sptlrpc_part2name);
71 
sptlrpc_target_sec_part(struct obd_device * obd)72 enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd)
73 {
74 	const char *type = obd->obd_type->typ_name;
75 
76 	if (!strcmp(type, LUSTRE_MDT_NAME))
77 		return LUSTRE_SP_MDT;
78 	if (!strcmp(type, LUSTRE_OST_NAME))
79 		return LUSTRE_SP_OST;
80 	if (!strcmp(type, LUSTRE_MGS_NAME))
81 		return LUSTRE_SP_MGS;
82 
83 	CERROR("unknown target %p(%s)\n", obd, type);
84 	return LUSTRE_SP_ANY;
85 }
86 EXPORT_SYMBOL(sptlrpc_target_sec_part);
87 
88 /****************************************
89  * user supplied flavor string parsing  *
90  ****************************************/
91 
92 /*
93  * format: <base_flavor>[-<bulk_type:alg_spec>]
94  */
sptlrpc_parse_flavor(const char * str,struct sptlrpc_flavor * flvr)95 int sptlrpc_parse_flavor(const char *str, struct sptlrpc_flavor *flvr)
96 {
97 	char	    buf[32];
98 	char	   *bulk, *alg;
99 
100 	memset(flvr, 0, sizeof(*flvr));
101 
102 	if (str == NULL || str[0] == '\0') {
103 		flvr->sf_rpc = SPTLRPC_FLVR_INVALID;
104 		return 0;
105 	}
106 
107 	strncpy(buf, str, sizeof(buf));
108 	buf[sizeof(buf) - 1] = '\0';
109 
110 	bulk = strchr(buf, '-');
111 	if (bulk)
112 		*bulk++ = '\0';
113 
114 	flvr->sf_rpc = sptlrpc_name2flavor_base(buf);
115 	if (flvr->sf_rpc == SPTLRPC_FLVR_INVALID)
116 		goto err_out;
117 
118 	/*
119 	 * currently only base flavor "plain" can have bulk specification.
120 	 */
121 	if (flvr->sf_rpc == SPTLRPC_FLVR_PLAIN) {
122 		flvr->u_bulk.hash.hash_alg = BULK_HASH_ALG_ADLER32;
123 		if (bulk) {
124 			/*
125 			 * format: plain-hash:<hash_alg>
126 			 */
127 			alg = strchr(bulk, ':');
128 			if (alg == NULL)
129 				goto err_out;
130 			*alg++ = '\0';
131 
132 			if (strcmp(bulk, "hash"))
133 				goto err_out;
134 
135 			flvr->u_bulk.hash.hash_alg = sptlrpc_get_hash_alg(alg);
136 			if (flvr->u_bulk.hash.hash_alg >= BULK_HASH_ALG_MAX)
137 				goto err_out;
138 		}
139 
140 		if (flvr->u_bulk.hash.hash_alg == BULK_HASH_ALG_NULL)
141 			flvr_set_bulk_svc(&flvr->sf_rpc, SPTLRPC_BULK_SVC_NULL);
142 		else
143 			flvr_set_bulk_svc(&flvr->sf_rpc, SPTLRPC_BULK_SVC_INTG);
144 	} else {
145 		if (bulk)
146 			goto err_out;
147 	}
148 
149 	flvr->sf_flags = 0;
150 	return 0;
151 
152 err_out:
153 	CERROR("invalid flavor string: %s\n", str);
154 	return -EINVAL;
155 }
156 EXPORT_SYMBOL(sptlrpc_parse_flavor);
157 
158 /****************************************
159  * configure rules		      *
160  ****************************************/
161 
get_default_flavor(struct sptlrpc_flavor * sf)162 static void get_default_flavor(struct sptlrpc_flavor *sf)
163 {
164 	memset(sf, 0, sizeof(*sf));
165 
166 	sf->sf_rpc = SPTLRPC_FLVR_NULL;
167 	sf->sf_flags = 0;
168 }
169 
sptlrpc_rule_init(struct sptlrpc_rule * rule)170 static void sptlrpc_rule_init(struct sptlrpc_rule *rule)
171 {
172 	rule->sr_netid = LNET_NIDNET(LNET_NID_ANY);
173 	rule->sr_from = LUSTRE_SP_ANY;
174 	rule->sr_to = LUSTRE_SP_ANY;
175 	rule->sr_padding = 0;
176 
177 	get_default_flavor(&rule->sr_flvr);
178 }
179 
180 /*
181  * format: network[.direction]=flavor
182  */
sptlrpc_parse_rule(char * param,struct sptlrpc_rule * rule)183 int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
184 {
185 	char	   *flavor, *dir;
186 	int	     rc;
187 
188 	sptlrpc_rule_init(rule);
189 
190 	flavor = strchr(param, '=');
191 	if (flavor == NULL) {
192 		CERROR("invalid param, no '='\n");
193 		return -EINVAL;
194 	}
195 	*flavor++ = '\0';
196 
197 	dir = strchr(param, '.');
198 	if (dir)
199 		*dir++ = '\0';
200 
201 	/* 1.1 network */
202 	if (strcmp(param, "default")) {
203 		rule->sr_netid = libcfs_str2net(param);
204 		if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
205 			CERROR("invalid network name: %s\n", param);
206 			return -EINVAL;
207 		}
208 	}
209 
210 	/* 1.2 direction */
211 	if (dir) {
212 		if (!strcmp(dir, "mdt2ost")) {
213 			rule->sr_from = LUSTRE_SP_MDT;
214 			rule->sr_to = LUSTRE_SP_OST;
215 		} else if (!strcmp(dir, "mdt2mdt")) {
216 			rule->sr_from = LUSTRE_SP_MDT;
217 			rule->sr_to = LUSTRE_SP_MDT;
218 		} else if (!strcmp(dir, "cli2ost")) {
219 			rule->sr_from = LUSTRE_SP_CLI;
220 			rule->sr_to = LUSTRE_SP_OST;
221 		} else if (!strcmp(dir, "cli2mdt")) {
222 			rule->sr_from = LUSTRE_SP_CLI;
223 			rule->sr_to = LUSTRE_SP_MDT;
224 		} else {
225 			CERROR("invalid rule dir segment: %s\n", dir);
226 			return -EINVAL;
227 		}
228 	}
229 
230 	/* 2.1 flavor */
231 	rc = sptlrpc_parse_flavor(flavor, &rule->sr_flvr);
232 	if (rc)
233 		return -EINVAL;
234 
235 	return 0;
236 }
237 EXPORT_SYMBOL(sptlrpc_parse_rule);
238 
sptlrpc_rule_set_free(struct sptlrpc_rule_set * rset)239 void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
240 {
241 	LASSERT(rset->srs_nslot ||
242 		(rset->srs_nrule == 0 && rset->srs_rules == NULL));
243 
244 	if (rset->srs_nslot) {
245 		OBD_FREE(rset->srs_rules,
246 			 rset->srs_nslot * sizeof(*rset->srs_rules));
247 		sptlrpc_rule_set_init(rset);
248 	}
249 }
250 EXPORT_SYMBOL(sptlrpc_rule_set_free);
251 
252 /*
253  * return 0 if the rule set could accommodate one more rule.
254  */
sptlrpc_rule_set_expand(struct sptlrpc_rule_set * rset)255 int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset)
256 {
257 	struct sptlrpc_rule *rules;
258 	int nslot;
259 
260 	might_sleep();
261 
262 	if (rset->srs_nrule < rset->srs_nslot)
263 		return 0;
264 
265 	nslot = rset->srs_nslot + 8;
266 
267 	/* better use realloc() if available */
268 	OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules));
269 	if (rules == NULL)
270 		return -ENOMEM;
271 
272 	if (rset->srs_nrule) {
273 		LASSERT(rset->srs_nslot && rset->srs_rules);
274 		memcpy(rules, rset->srs_rules,
275 		       rset->srs_nrule * sizeof(*rset->srs_rules));
276 
277 		OBD_FREE(rset->srs_rules,
278 			 rset->srs_nslot * sizeof(*rset->srs_rules));
279 	}
280 
281 	rset->srs_rules = rules;
282 	rset->srs_nslot = nslot;
283 	return 0;
284 }
285 EXPORT_SYMBOL(sptlrpc_rule_set_expand);
286 
rule_spec_dir(struct sptlrpc_rule * rule)287 static inline int rule_spec_dir(struct sptlrpc_rule *rule)
288 {
289 	return (rule->sr_from != LUSTRE_SP_ANY ||
290 		rule->sr_to != LUSTRE_SP_ANY);
291 }
rule_spec_net(struct sptlrpc_rule * rule)292 static inline int rule_spec_net(struct sptlrpc_rule *rule)
293 {
294 	return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
295 }
rule_match_dir(struct sptlrpc_rule * r1,struct sptlrpc_rule * r2)296 static inline int rule_match_dir(struct sptlrpc_rule *r1,
297 				 struct sptlrpc_rule *r2)
298 {
299 	return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to);
300 }
rule_match_net(struct sptlrpc_rule * r1,struct sptlrpc_rule * r2)301 static inline int rule_match_net(struct sptlrpc_rule *r1,
302 				 struct sptlrpc_rule *r2)
303 {
304 	return (r1->sr_netid == r2->sr_netid);
305 }
306 
307 /*
308  * merge @rule into @rset.
309  * the @rset slots might be expanded.
310  */
sptlrpc_rule_set_merge(struct sptlrpc_rule_set * rset,struct sptlrpc_rule * rule)311 int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset,
312 			   struct sptlrpc_rule *rule)
313 {
314 	struct sptlrpc_rule      *p = rset->srs_rules;
315 	int		       spec_dir, spec_net;
316 	int		       rc, n, match = 0;
317 
318 	might_sleep();
319 
320 	spec_net = rule_spec_net(rule);
321 	spec_dir = rule_spec_dir(rule);
322 
323 	for (n = 0; n < rset->srs_nrule; n++) {
324 		p = &rset->srs_rules[n];
325 
326 		/* test network match, if failed:
327 		 * - spec rule: skip rules which is also spec rule match, until
328 		 *   we hit a wild rule, which means no more chance
329 		 * - wild rule: skip until reach the one which is also wild
330 		 *   and matches
331 		 */
332 		if (!rule_match_net(p, rule)) {
333 			if (spec_net) {
334 				if (rule_spec_net(p))
335 					continue;
336 				else
337 					break;
338 			} else {
339 				continue;
340 			}
341 		}
342 
343 		/* test dir match, same logic as net matching */
344 		if (!rule_match_dir(p, rule)) {
345 			if (spec_dir) {
346 				if (rule_spec_dir(p))
347 					continue;
348 				else
349 					break;
350 			} else {
351 				continue;
352 			}
353 		}
354 
355 		/* find a match */
356 		match = 1;
357 		break;
358 	}
359 
360 	if (match) {
361 		LASSERT(n >= 0 && n < rset->srs_nrule);
362 
363 		if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
364 			/* remove this rule */
365 			if (n < rset->srs_nrule - 1)
366 				memmove(&rset->srs_rules[n],
367 					&rset->srs_rules[n + 1],
368 					(rset->srs_nrule - n - 1) *
369 					sizeof(*rule));
370 			rset->srs_nrule--;
371 		} else {
372 			/* override the rule */
373 			memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
374 		}
375 	} else {
376 		LASSERT(n >= 0 && n <= rset->srs_nrule);
377 
378 		if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
379 			rc = sptlrpc_rule_set_expand(rset);
380 			if (rc)
381 				return rc;
382 
383 			if (n < rset->srs_nrule)
384 				memmove(&rset->srs_rules[n + 1],
385 					&rset->srs_rules[n],
386 					(rset->srs_nrule - n) * sizeof(*rule));
387 			memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
388 			rset->srs_nrule++;
389 		} else {
390 			CDEBUG(D_CONFIG, "ignore the unmatched deletion\n");
391 		}
392 	}
393 
394 	return 0;
395 }
396 EXPORT_SYMBOL(sptlrpc_rule_set_merge);
397 
398 /**
399  * given from/to/nid, determine a matching flavor in ruleset.
400  * return 1 if a match found, otherwise return 0.
401  */
sptlrpc_rule_set_choose(struct sptlrpc_rule_set * rset,enum lustre_sec_part from,enum lustre_sec_part to,lnet_nid_t nid,struct sptlrpc_flavor * sf)402 int sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
403 			    enum lustre_sec_part from,
404 			    enum lustre_sec_part to,
405 			    lnet_nid_t nid,
406 			    struct sptlrpc_flavor *sf)
407 {
408 	struct sptlrpc_rule    *r;
409 	int		     n;
410 
411 	for (n = 0; n < rset->srs_nrule; n++) {
412 		r = &rset->srs_rules[n];
413 
414 		if (LNET_NIDNET(nid) != LNET_NIDNET(LNET_NID_ANY) &&
415 		    r->sr_netid != LNET_NIDNET(LNET_NID_ANY) &&
416 		    LNET_NIDNET(nid) != r->sr_netid)
417 			continue;
418 
419 		if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY &&
420 		    from != r->sr_from)
421 			continue;
422 
423 		if (to != LUSTRE_SP_ANY && r->sr_to != LUSTRE_SP_ANY &&
424 		    to != r->sr_to)
425 			continue;
426 
427 		*sf = r->sr_flvr;
428 		return 1;
429 	}
430 
431 	return 0;
432 }
433 EXPORT_SYMBOL(sptlrpc_rule_set_choose);
434 
sptlrpc_rule_set_dump(struct sptlrpc_rule_set * rset)435 void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset)
436 {
437 	struct sptlrpc_rule *r;
438 	int     n;
439 
440 	for (n = 0; n < rset->srs_nrule; n++) {
441 		r = &rset->srs_rules[n];
442 		CDEBUG(D_SEC, "<%02d> from %x to %x, net %x, rpc %x\n", n,
443 		       r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
444 	}
445 }
446 EXPORT_SYMBOL(sptlrpc_rule_set_dump);
447 
448 /**********************************
449  * sptlrpc configuration support  *
450  **********************************/
451 
452 struct sptlrpc_conf_tgt {
453 	struct list_head	      sct_list;
454 	char		    sct_name[MAX_OBD_NAME];
455 	struct sptlrpc_rule_set sct_rset;
456 };
457 
458 struct sptlrpc_conf {
459 	struct list_head	      sc_list;
460 	char		    sc_fsname[MTI_NAME_MAXLEN];
461 	unsigned int	    sc_modified;  /* modified during updating */
462 	unsigned int	    sc_updated:1, /* updated copy from MGS */
463 				sc_local:1;   /* local copy from target */
464 	struct sptlrpc_rule_set sc_rset;      /* fs general rules */
465 	struct list_head	      sc_tgts;      /* target-specific rules */
466 };
467 
468 static struct mutex sptlrpc_conf_lock;
469 static LIST_HEAD(sptlrpc_confs);
470 
is_hex(char c)471 static inline int is_hex(char c)
472 {
473 	return ((c >= '0' && c <= '9') ||
474 		(c >= 'a' && c <= 'f'));
475 }
476 
target2fsname(const char * tgt,char * fsname,int buflen)477 static void target2fsname(const char *tgt, char *fsname, int buflen)
478 {
479 	const char     *ptr;
480 	int	     len;
481 
482 	ptr = strrchr(tgt, '-');
483 	if (ptr) {
484 		if ((strncmp(ptr, "-MDT", 4) != 0 &&
485 		     strncmp(ptr, "-OST", 4) != 0) ||
486 		    !is_hex(ptr[4]) || !is_hex(ptr[5]) ||
487 		    !is_hex(ptr[6]) || !is_hex(ptr[7]))
488 			ptr = NULL;
489 	}
490 
491 	/* if we didn't find the pattern, treat the whole string as fsname */
492 	if (ptr == NULL)
493 		len = strlen(tgt);
494 	else
495 		len = ptr - tgt;
496 
497 	len = min(len, buflen - 1);
498 	memcpy(fsname, tgt, len);
499 	fsname[len] = '\0';
500 }
501 
sptlrpc_conf_free_rsets(struct sptlrpc_conf * conf)502 static void sptlrpc_conf_free_rsets(struct sptlrpc_conf *conf)
503 {
504 	struct sptlrpc_conf_tgt *conf_tgt, *conf_tgt_next;
505 
506 	sptlrpc_rule_set_free(&conf->sc_rset);
507 
508 	list_for_each_entry_safe(conf_tgt, conf_tgt_next,
509 				     &conf->sc_tgts, sct_list) {
510 		sptlrpc_rule_set_free(&conf_tgt->sct_rset);
511 		list_del(&conf_tgt->sct_list);
512 		OBD_FREE_PTR(conf_tgt);
513 	}
514 	LASSERT(list_empty(&conf->sc_tgts));
515 
516 	conf->sc_updated = 0;
517 	conf->sc_local = 0;
518 }
519 
sptlrpc_conf_free(struct sptlrpc_conf * conf)520 static void sptlrpc_conf_free(struct sptlrpc_conf *conf)
521 {
522 	CDEBUG(D_SEC, "free sptlrpc conf %s\n", conf->sc_fsname);
523 
524 	sptlrpc_conf_free_rsets(conf);
525 	list_del(&conf->sc_list);
526 	OBD_FREE_PTR(conf);
527 }
528 
529 static
sptlrpc_conf_get_tgt(struct sptlrpc_conf * conf,const char * name,int create)530 struct sptlrpc_conf_tgt *sptlrpc_conf_get_tgt(struct sptlrpc_conf *conf,
531 					      const char *name,
532 					      int create)
533 {
534 	struct sptlrpc_conf_tgt *conf_tgt;
535 
536 	list_for_each_entry(conf_tgt, &conf->sc_tgts, sct_list) {
537 		if (strcmp(conf_tgt->sct_name, name) == 0)
538 			return conf_tgt;
539 	}
540 
541 	if (!create)
542 		return NULL;
543 
544 	OBD_ALLOC_PTR(conf_tgt);
545 	if (conf_tgt) {
546 		strlcpy(conf_tgt->sct_name, name, sizeof(conf_tgt->sct_name));
547 		sptlrpc_rule_set_init(&conf_tgt->sct_rset);
548 		list_add(&conf_tgt->sct_list, &conf->sc_tgts);
549 	}
550 
551 	return conf_tgt;
552 }
553 
554 static
sptlrpc_conf_get(const char * fsname,int create)555 struct sptlrpc_conf *sptlrpc_conf_get(const char *fsname,
556 				      int create)
557 {
558 	struct sptlrpc_conf *conf;
559 
560 	list_for_each_entry(conf, &sptlrpc_confs, sc_list) {
561 		if (strcmp(conf->sc_fsname, fsname) == 0)
562 			return conf;
563 	}
564 
565 	if (!create)
566 		return NULL;
567 
568 	OBD_ALLOC_PTR(conf);
569 	if (conf == NULL)
570 		return NULL;
571 
572 	strcpy(conf->sc_fsname, fsname);
573 	sptlrpc_rule_set_init(&conf->sc_rset);
574 	INIT_LIST_HEAD(&conf->sc_tgts);
575 	list_add(&conf->sc_list, &sptlrpc_confs);
576 
577 	CDEBUG(D_SEC, "create sptlrpc conf %s\n", conf->sc_fsname);
578 	return conf;
579 }
580 
581 /**
582  * caller must hold conf_lock already.
583  */
sptlrpc_conf_merge_rule(struct sptlrpc_conf * conf,const char * target,struct sptlrpc_rule * rule)584 static int sptlrpc_conf_merge_rule(struct sptlrpc_conf *conf,
585 				   const char *target,
586 				   struct sptlrpc_rule *rule)
587 {
588 	struct sptlrpc_conf_tgt  *conf_tgt;
589 	struct sptlrpc_rule_set  *rule_set;
590 
591 	/* fsname == target means general rules for the whole fs */
592 	if (strcmp(conf->sc_fsname, target) == 0) {
593 		rule_set = &conf->sc_rset;
594 	} else {
595 		conf_tgt = sptlrpc_conf_get_tgt(conf, target, 1);
596 		if (conf_tgt) {
597 			rule_set = &conf_tgt->sct_rset;
598 		} else {
599 			CERROR("out of memory, can't merge rule!\n");
600 			return -ENOMEM;
601 		}
602 	}
603 
604 	return sptlrpc_rule_set_merge(rule_set, rule);
605 }
606 
607 /**
608  * process one LCFG_SPTLRPC_CONF record. if \a conf is NULL, we
609  * find one through the target name in the record inside conf_lock;
610  * otherwise means caller already hold conf_lock.
611  */
__sptlrpc_process_config(struct lustre_cfg * lcfg,struct sptlrpc_conf * conf)612 static int __sptlrpc_process_config(struct lustre_cfg *lcfg,
613 				    struct sptlrpc_conf *conf)
614 {
615 	char		   *target, *param;
616 	char		    fsname[MTI_NAME_MAXLEN];
617 	struct sptlrpc_rule     rule;
618 	int		     rc;
619 
620 	target = lustre_cfg_string(lcfg, 1);
621 	if (target == NULL) {
622 		CERROR("missing target name\n");
623 		return -EINVAL;
624 	}
625 
626 	param = lustre_cfg_string(lcfg, 2);
627 	if (param == NULL) {
628 		CERROR("missing parameter\n");
629 		return -EINVAL;
630 	}
631 
632 	CDEBUG(D_SEC, "processing rule: %s.%s\n", target, param);
633 
634 	/* parse rule to make sure the format is correct */
635 	if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) {
636 		CERROR("Invalid sptlrpc parameter: %s\n", param);
637 		return -EINVAL;
638 	}
639 	param += sizeof(PARAM_SRPC_FLVR) - 1;
640 
641 	rc = sptlrpc_parse_rule(param, &rule);
642 	if (rc)
643 		return -EINVAL;
644 
645 	if (conf == NULL) {
646 		target2fsname(target, fsname, sizeof(fsname));
647 
648 		mutex_lock(&sptlrpc_conf_lock);
649 		conf = sptlrpc_conf_get(fsname, 0);
650 		if (conf == NULL) {
651 			CERROR("can't find conf\n");
652 			rc = -ENOMEM;
653 		} else {
654 			rc = sptlrpc_conf_merge_rule(conf, target, &rule);
655 		}
656 		mutex_unlock(&sptlrpc_conf_lock);
657 	} else {
658 		LASSERT(mutex_is_locked(&sptlrpc_conf_lock));
659 		rc = sptlrpc_conf_merge_rule(conf, target, &rule);
660 	}
661 
662 	if (rc == 0)
663 		conf->sc_modified++;
664 
665 	return rc;
666 }
667 
sptlrpc_process_config(struct lustre_cfg * lcfg)668 int sptlrpc_process_config(struct lustre_cfg *lcfg)
669 {
670 	return __sptlrpc_process_config(lcfg, NULL);
671 }
672 EXPORT_SYMBOL(sptlrpc_process_config);
673 
logname2fsname(const char * logname,char * buf,int buflen)674 static int logname2fsname(const char *logname, char *buf, int buflen)
675 {
676 	char   *ptr;
677 	int     len;
678 
679 	ptr = strrchr(logname, '-');
680 	if (ptr == NULL || strcmp(ptr, "-sptlrpc")) {
681 		CERROR("%s is not a sptlrpc config log\n", logname);
682 		return -EINVAL;
683 	}
684 
685 	len = min((int) (ptr - logname), buflen - 1);
686 
687 	memcpy(buf, logname, len);
688 	buf[len] = '\0';
689 	return 0;
690 }
691 
sptlrpc_conf_log_update_begin(const char * logname)692 void sptlrpc_conf_log_update_begin(const char *logname)
693 {
694 	struct sptlrpc_conf *conf;
695 	char		 fsname[16];
696 
697 	if (logname2fsname(logname, fsname, sizeof(fsname)))
698 		return;
699 
700 	mutex_lock(&sptlrpc_conf_lock);
701 
702 	conf = sptlrpc_conf_get(fsname, 0);
703 	if (conf) {
704 		if (conf->sc_local) {
705 			LASSERT(conf->sc_updated == 0);
706 			sptlrpc_conf_free_rsets(conf);
707 		}
708 		conf->sc_modified = 0;
709 	}
710 
711 	mutex_unlock(&sptlrpc_conf_lock);
712 }
713 EXPORT_SYMBOL(sptlrpc_conf_log_update_begin);
714 
715 /**
716  * mark a config log has been updated
717  */
sptlrpc_conf_log_update_end(const char * logname)718 void sptlrpc_conf_log_update_end(const char *logname)
719 {
720 	struct sptlrpc_conf *conf;
721 	char		 fsname[16];
722 
723 	if (logname2fsname(logname, fsname, sizeof(fsname)))
724 		return;
725 
726 	mutex_lock(&sptlrpc_conf_lock);
727 
728 	conf = sptlrpc_conf_get(fsname, 0);
729 	if (conf) {
730 		/*
731 		 * if original state is not updated, make sure the
732 		 * modified counter > 0 to enforce updating local copy.
733 		 */
734 		if (conf->sc_updated == 0)
735 			conf->sc_modified++;
736 
737 		conf->sc_updated = 1;
738 	}
739 
740 	mutex_unlock(&sptlrpc_conf_lock);
741 }
742 EXPORT_SYMBOL(sptlrpc_conf_log_update_end);
743 
sptlrpc_conf_log_start(const char * logname)744 void sptlrpc_conf_log_start(const char *logname)
745 {
746 	char		 fsname[16];
747 
748 	if (logname2fsname(logname, fsname, sizeof(fsname)))
749 		return;
750 
751 	mutex_lock(&sptlrpc_conf_lock);
752 	sptlrpc_conf_get(fsname, 1);
753 	mutex_unlock(&sptlrpc_conf_lock);
754 }
755 EXPORT_SYMBOL(sptlrpc_conf_log_start);
756 
sptlrpc_conf_log_stop(const char * logname)757 void sptlrpc_conf_log_stop(const char *logname)
758 {
759 	struct sptlrpc_conf *conf;
760 	char		 fsname[16];
761 
762 	if (logname2fsname(logname, fsname, sizeof(fsname)))
763 		return;
764 
765 	mutex_lock(&sptlrpc_conf_lock);
766 	conf = sptlrpc_conf_get(fsname, 0);
767 	if (conf)
768 		sptlrpc_conf_free(conf);
769 	mutex_unlock(&sptlrpc_conf_lock);
770 }
771 EXPORT_SYMBOL(sptlrpc_conf_log_stop);
772 
flavor_set_flags(struct sptlrpc_flavor * sf,enum lustre_sec_part from,enum lustre_sec_part to,unsigned int fl_udesc)773 static inline void flavor_set_flags(struct sptlrpc_flavor *sf,
774 				    enum lustre_sec_part from,
775 				    enum lustre_sec_part to,
776 				    unsigned int fl_udesc)
777 {
778 	/*
779 	 * null flavor doesn't need to set any flavor, and in fact
780 	 * we'd better not do that because everybody share a single sec.
781 	 */
782 	if (sf->sf_rpc == SPTLRPC_FLVR_NULL)
783 		return;
784 
785 	if (from == LUSTRE_SP_MDT) {
786 		/* MDT->MDT; MDT->OST */
787 		sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY;
788 	} else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST) {
789 		/* CLI->OST */
790 		sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
791 	} else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT) {
792 		/* CLI->MDT */
793 		if (fl_udesc && sf->sf_rpc != SPTLRPC_FLVR_NULL)
794 			sf->sf_flags |= PTLRPC_SEC_FL_UDESC;
795 	}
796 }
797 
sptlrpc_conf_choose_flavor(enum lustre_sec_part from,enum lustre_sec_part to,struct obd_uuid * target,lnet_nid_t nid,struct sptlrpc_flavor * sf)798 void sptlrpc_conf_choose_flavor(enum lustre_sec_part from,
799 				enum lustre_sec_part to,
800 				struct obd_uuid *target,
801 				lnet_nid_t nid,
802 				struct sptlrpc_flavor *sf)
803 {
804 	struct sptlrpc_conf     *conf;
805 	struct sptlrpc_conf_tgt *conf_tgt;
806 	char		     name[MTI_NAME_MAXLEN];
807 	int		      len, rc = 0;
808 
809 	target2fsname(target->uuid, name, sizeof(name));
810 
811 	mutex_lock(&sptlrpc_conf_lock);
812 
813 	conf = sptlrpc_conf_get(name, 0);
814 	if (conf == NULL)
815 		goto out;
816 
817 	/* convert uuid name (supposed end with _UUID) to target name */
818 	len = strlen(target->uuid);
819 	LASSERT(len > 5);
820 	memcpy(name, target->uuid, len - 5);
821 	name[len - 5] = '\0';
822 
823 	conf_tgt = sptlrpc_conf_get_tgt(conf, name, 0);
824 	if (conf_tgt) {
825 		rc = sptlrpc_rule_set_choose(&conf_tgt->sct_rset,
826 					     from, to, nid, sf);
827 		if (rc)
828 			goto out;
829 	}
830 
831 	rc = sptlrpc_rule_set_choose(&conf->sc_rset, from, to, nid, sf);
832 out:
833 	mutex_unlock(&sptlrpc_conf_lock);
834 
835 	if (rc == 0)
836 		get_default_flavor(sf);
837 
838 	flavor_set_flags(sf, from, to, 1);
839 }
840 
841 /**
842  * called by target devices, determine the expected flavor from
843  * certain peer (from, nid).
844  */
sptlrpc_target_choose_flavor(struct sptlrpc_rule_set * rset,enum lustre_sec_part from,lnet_nid_t nid,struct sptlrpc_flavor * sf)845 void sptlrpc_target_choose_flavor(struct sptlrpc_rule_set *rset,
846 				  enum lustre_sec_part from,
847 				  lnet_nid_t nid,
848 				  struct sptlrpc_flavor *sf)
849 {
850 	if (sptlrpc_rule_set_choose(rset, from, LUSTRE_SP_ANY, nid, sf) == 0)
851 		get_default_flavor(sf);
852 }
853 EXPORT_SYMBOL(sptlrpc_target_choose_flavor);
854 
855 #define SEC_ADAPT_DELAY	 (10)
856 
857 /**
858  * called by client devices, notify the sptlrpc config has changed and
859  * do import_sec_adapt later.
860  */
sptlrpc_conf_client_adapt(struct obd_device * obd)861 void sptlrpc_conf_client_adapt(struct obd_device *obd)
862 {
863 	struct obd_import  *imp;
864 
865 	LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 ||
866 		strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) == 0);
867 	CDEBUG(D_SEC, "obd %s\n", obd->u.cli.cl_target_uuid.uuid);
868 
869 	/* serialize with connect/disconnect import */
870 	down_read(&obd->u.cli.cl_sem);
871 
872 	imp = obd->u.cli.cl_import;
873 	if (imp) {
874 		spin_lock(&imp->imp_lock);
875 		if (imp->imp_sec)
876 			imp->imp_sec_expire = get_seconds() +
877 				SEC_ADAPT_DELAY;
878 		spin_unlock(&imp->imp_lock);
879 	}
880 
881 	up_read(&obd->u.cli.cl_sem);
882 }
883 EXPORT_SYMBOL(sptlrpc_conf_client_adapt);
884 
sptlrpc_conf_init(void)885 int  sptlrpc_conf_init(void)
886 {
887 	mutex_init(&sptlrpc_conf_lock);
888 	return 0;
889 }
890 
sptlrpc_conf_fini(void)891 void sptlrpc_conf_fini(void)
892 {
893 	struct sptlrpc_conf  *conf, *conf_next;
894 
895 	mutex_lock(&sptlrpc_conf_lock);
896 	list_for_each_entry_safe(conf, conf_next, &sptlrpc_confs, sc_list) {
897 		sptlrpc_conf_free(conf);
898 	}
899 	LASSERT(list_empty(&sptlrpc_confs));
900 	mutex_unlock(&sptlrpc_conf_lock);
901 }
902