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