Whamcloud - gitweb
branch: HEAD
[fs/lustre-release.git] / lustre / ptlrpc / sec_config.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
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 #ifndef EXPORT_SYMTAB
38 #define EXPORT_SYMTAB
39 #endif
40 #define DEBUG_SUBSYSTEM S_SEC
41
42 #include <libcfs/libcfs.h>
43 #ifndef __KERNEL__
44 #include <liblustre.h>
45 #include <libcfs/list.h>
46 #else
47 #include <linux/crypto.h>
48 #include <linux/key.h>
49 #endif
50
51 #include <obd.h>
52 #include <obd_class.h>
53 #include <obd_support.h>
54 #include <lustre_net.h>
55 #include <lustre_import.h>
56 #include <lustre_log.h>
57 #include <lustre_disk.h>
58 #include <lustre_dlm.h>
59 #include <lustre_param.h>
60 #include <lustre_sec.h>
61
62 #include "ptlrpc_internal.h"
63
64 const char *sptlrpc_part2name(enum lustre_sec_part part)
65 {
66         switch (part) {
67         case LUSTRE_SP_CLI:
68                 return "cli";
69         case LUSTRE_SP_MDT:
70                 return "mdt";
71         case LUSTRE_SP_OST:
72                 return "ost";
73         case LUSTRE_SP_MGC:
74                 return "mgc";
75         case LUSTRE_SP_MGS:
76                 return "mgs";
77         case LUSTRE_SP_ANY:
78                 return "any";
79         default:
80                 return "err";
81         }
82 }
83 EXPORT_SYMBOL(sptlrpc_part2name);
84
85 enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd)
86 {
87         const char *type = obd->obd_type->typ_name;
88
89         if (!strcmp(type, LUSTRE_MDT_NAME))
90                 return LUSTRE_SP_MDT;
91         if (!strcmp(type, LUSTRE_OST_NAME))
92                 return LUSTRE_SP_OST;
93         if (!strcmp(type, LUSTRE_MGS_NAME))
94                 return LUSTRE_SP_MGS;
95
96         CERROR("unknown target %p(%s)\n", obd, type);
97         return LUSTRE_SP_ANY;
98 }
99 EXPORT_SYMBOL(sptlrpc_target_sec_part);
100
101 /****************************************
102  * user supplied flavor string parsing  *
103  ****************************************/
104
105 #ifdef HAVE_ADLER
106 #define BULK_HASH_ALG_DEFAULT   BULK_HASH_ALG_ADLER32
107 #else
108 #define BULK_HASH_ALG_DEFAULT   BULK_HASH_ALG_CRC32
109 #endif
110
111 typedef enum {
112         BULK_TYPE_N = 0,
113         BULK_TYPE_I = 1,
114         BULK_TYPE_P = 2
115 } bulk_type_t;
116
117 static void get_default_flavor(struct sptlrpc_flavor *sf)
118 {
119         sf->sf_rpc = SPTLRPC_FLVR_NULL;
120         sf->sf_bulk_ciph = BULK_CIPH_ALG_NULL;
121         sf->sf_bulk_hash = BULK_HASH_ALG_NULL;
122         sf->sf_flags = 0;
123 }
124
125 static void get_flavor_by_rpc(struct sptlrpc_flavor *flvr, __u16 rpc_flavor)
126 {
127         get_default_flavor(flvr);
128
129         flvr->sf_rpc = rpc_flavor;
130
131         switch (rpc_flavor) {
132         case SPTLRPC_FLVR_NULL:
133                 break;
134         case SPTLRPC_FLVR_PLAIN:
135         case SPTLRPC_FLVR_KRB5N:
136         case SPTLRPC_FLVR_KRB5A:
137                 flvr->sf_bulk_hash = BULK_HASH_ALG_DEFAULT;
138                 break;
139         case SPTLRPC_FLVR_KRB5P:
140                 flvr->sf_bulk_ciph = BULK_CIPH_ALG_AES128;
141                 /* fall through */
142         case SPTLRPC_FLVR_KRB5I:
143                 flvr->sf_bulk_hash = BULK_HASH_ALG_SHA1;
144                 break;
145         default:
146                 LBUG();
147         }
148 }
149
150 static void get_flavor_by_bulk(struct sptlrpc_flavor *flvr,
151                                __u16 rpc_flavor, bulk_type_t bulk_type)
152 {
153         switch (bulk_type) {
154         case BULK_TYPE_N:
155                 flvr->sf_bulk_hash = BULK_HASH_ALG_NULL;
156                 flvr->sf_bulk_ciph = BULK_CIPH_ALG_NULL;
157                 break;
158         case BULK_TYPE_I:
159                 switch (rpc_flavor) {
160                 case SPTLRPC_FLVR_PLAIN:
161                 case SPTLRPC_FLVR_KRB5N:
162                 case SPTLRPC_FLVR_KRB5A:
163                         flvr->sf_bulk_hash = BULK_HASH_ALG_DEFAULT;
164                         break;
165                 case SPTLRPC_FLVR_KRB5I:
166                 case SPTLRPC_FLVR_KRB5P:
167                         flvr->sf_bulk_hash = BULK_HASH_ALG_SHA1;
168                         break;
169                 default:
170                         LBUG();
171                 }
172                 flvr->sf_bulk_ciph = BULK_CIPH_ALG_NULL;
173                 break;
174         case BULK_TYPE_P:
175                 flvr->sf_bulk_hash = BULK_HASH_ALG_SHA1;
176                 flvr->sf_bulk_ciph = BULK_CIPH_ALG_AES128;
177                 break;
178         default:
179                 LBUG();
180         }
181 }
182
183 static __u16 __flavors[] = {
184         SPTLRPC_FLVR_NULL,
185         SPTLRPC_FLVR_PLAIN,
186         SPTLRPC_FLVR_KRB5N,
187         SPTLRPC_FLVR_KRB5A,
188         SPTLRPC_FLVR_KRB5I,
189         SPTLRPC_FLVR_KRB5P,
190 };
191
192 #define __nflavors      ARRAY_SIZE(__flavors)
193
194 /*
195  * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]]
196  * for examples:
197  *  null
198  *  plain-bulki
199  *  krb5p-bulkn
200  *  krb5i-bulkp
201  *  krb5i-bulkp:sha512/arc4
202  */
203 int sptlrpc_parse_flavor(const char *str, struct sptlrpc_flavor *flvr)
204 {
205         const char     *f;
206         char           *bulk, *alg, *enc;
207         char            buf[64];
208         bulk_type_t     bulk_type;
209         __u8            i;
210         ENTRY;
211
212         if (str == NULL || str[0] == '\0') {
213                 flvr->sf_rpc = SPTLRPC_FLVR_INVALID;
214                 goto out;
215         }
216
217         for (i = 0; i < __nflavors; i++) {
218                 f = sptlrpc_rpcflavor2name(__flavors[i]);
219                 if (strncmp(str, f, strlen(f)) == 0)
220                         break;
221         }
222
223         if (i >= __nflavors)
224                 GOTO(invalid, -EINVAL);
225
226         /* prepare local buffer thus we can modify it as we want */
227         strncpy(buf, str, 64);
228         buf[64 - 1] = '\0';
229
230         /* find bulk string */
231         bulk = strchr(buf, '-');
232         if (bulk)
233                 *bulk++ = '\0';
234
235         /* now the first part must equal to rpc flavor name */
236         if (strcmp(buf, f) != 0)
237                 GOTO(invalid, -EINVAL);
238
239         get_flavor_by_rpc(flvr, __flavors[i]);
240
241         if (bulk == NULL)
242                 goto out;
243
244         /* find bulk algorithm string */
245         alg = strchr(bulk, ':');
246         if (alg)
247                 *alg++ = '\0';
248
249         /* verify bulk section */
250         if (strcmp(bulk, "bulkn") == 0) {
251                 flvr->sf_bulk_hash = BULK_HASH_ALG_NULL;
252                 flvr->sf_bulk_ciph = BULK_CIPH_ALG_NULL;
253                 bulk_type = BULK_TYPE_N;
254         } else if (strcmp(bulk, "bulki") == 0)
255                 bulk_type = BULK_TYPE_I;
256         else if (strcmp(bulk, "bulkp") == 0)
257                 bulk_type = BULK_TYPE_P;
258         else
259                 GOTO(invalid, -EINVAL);
260
261         /* null flavor don't support bulk i/p */
262         if (__flavors[i] == SPTLRPC_FLVR_NULL && bulk_type != BULK_TYPE_N)
263                 GOTO(invalid, -EINVAL);
264
265         /* plain policy dosen't support bulk p */
266         if (__flavors[i] == SPTLRPC_FLVR_PLAIN && bulk_type == BULK_TYPE_P)
267                 GOTO(invalid, -EINVAL);
268
269         get_flavor_by_bulk(flvr, __flavors[i], bulk_type);
270
271         if (alg == NULL)
272                 goto out;
273
274         /* find encryption algorithm string */
275         enc = strchr(alg, '/');
276         if (enc)
277                 *enc++ = '\0';
278
279         /* checksum algorithm */
280         for (i = 0; i < BULK_HASH_ALG_MAX; i++) {
281                 if (strcmp(alg, sptlrpc_get_hash_name(i)) == 0) {
282                         flvr->sf_bulk_hash = i;
283                         break;
284                 }
285         }
286         if (i >= BULK_HASH_ALG_MAX)
287                 GOTO(invalid, -EINVAL);
288
289         /* privacy algorithm */
290         if (enc) {
291                 for (i = 0; i < BULK_CIPH_ALG_MAX; i++) {
292                         if (strcmp(enc, sptlrpc_get_ciph_name(i)) == 0) {
293                                 flvr->sf_bulk_ciph = i;
294                                 break;
295                         }
296                 }
297                 if (i >= BULK_CIPH_ALG_MAX)
298                         GOTO(invalid, -EINVAL);
299         }
300
301         /*
302          * bulk combination sanity checks
303          */
304         if (bulk_type == BULK_TYPE_P &&
305             flvr->sf_bulk_ciph == BULK_CIPH_ALG_NULL)
306                 GOTO(invalid, -EINVAL);
307
308         if (bulk_type == BULK_TYPE_I &&
309             (flvr->sf_bulk_hash == BULK_HASH_ALG_NULL ||
310              flvr->sf_bulk_ciph != BULK_CIPH_ALG_NULL))
311                 GOTO(invalid, -EINVAL);
312
313         if (bulk_type == BULK_TYPE_N &&
314             (flvr->sf_bulk_hash != BULK_HASH_ALG_NULL ||
315              flvr->sf_bulk_ciph != BULK_CIPH_ALG_NULL))
316                 GOTO(invalid, -EINVAL);
317
318 out:
319         return 0;
320 invalid:
321         CERROR("invalid flavor string: %s\n", str);
322         return -EINVAL;
323 }
324 EXPORT_SYMBOL(sptlrpc_parse_flavor);
325
326 /****************************************
327  * configure rules                      *
328  ****************************************/
329
330 static void sptlrpc_rule_init(struct sptlrpc_rule *rule)
331 {
332         rule->sr_netid = LNET_NIDNET(LNET_NID_ANY);
333         rule->sr_from = LUSTRE_SP_ANY;
334         rule->sr_to = LUSTRE_SP_ANY;
335         rule->sr_padding = 0;
336
337         get_default_flavor(&rule->sr_flvr);
338 }
339
340 /*
341  * format: network[.direction]=flavor
342  */
343 int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
344 {
345         char           *flavor, *dir;
346         int             rc;
347
348         sptlrpc_rule_init(rule);
349
350         flavor = strchr(param, '=');
351         if (flavor == NULL) {
352                 CERROR("invalid param, no '='\n");
353                 RETURN(-EINVAL);
354         }
355         *flavor++ = '\0';
356
357         dir = strchr(param, '.');
358         if (dir)
359                 *dir++ = '\0';
360
361         /* 1.1 network */
362         if (strcmp(param, "default")) {
363                 rule->sr_netid = libcfs_str2net(param);
364                 if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
365                         CERROR("invalid network name: %s\n", param);
366                         RETURN(-EINVAL);
367                 }
368         }
369
370         /* 1.2 direction */
371         if (dir) {
372                 if (!strcmp(dir, "mdt2ost")) {
373                         rule->sr_from = LUSTRE_SP_MDT;
374                         rule->sr_to = LUSTRE_SP_OST;
375                 } else if (!strcmp(dir, "mdt2mdt")) {
376                         rule->sr_from = LUSTRE_SP_MDT;
377                         rule->sr_to = LUSTRE_SP_MDT;
378                 } else if (!strcmp(dir, "cli2ost")) {
379                         rule->sr_from = LUSTRE_SP_CLI;
380                         rule->sr_to = LUSTRE_SP_OST;
381                 } else if (!strcmp(dir, "cli2mdt")) {
382                         rule->sr_from = LUSTRE_SP_CLI;
383                         rule->sr_to = LUSTRE_SP_MDT;
384                 } else {
385                         CERROR("invalid rule dir segment: %s\n", dir);
386                         RETURN(-EINVAL);
387                 }
388         }
389
390         /* 2.1 flavor */
391         rc = sptlrpc_parse_flavor(flavor, &rule->sr_flvr);
392         if (rc)
393                 RETURN(-EINVAL);
394
395         RETURN(0);
396 }
397 EXPORT_SYMBOL(sptlrpc_parse_rule);
398
399 void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
400 {
401         LASSERT(rset->srs_nslot ||
402                 (rset->srs_nrule == 0 && rset->srs_rules == NULL));
403
404         if (rset->srs_nslot) {
405                 OBD_FREE(rset->srs_rules,
406                          rset->srs_nslot * sizeof(*rset->srs_rules));
407                 sptlrpc_rule_set_init(rset);
408         }
409 }
410 EXPORT_SYMBOL(sptlrpc_rule_set_free);
411
412 /*
413  * return 0 if the rule set could accomodate one more rule.
414  * if @expand != 0, the rule set might be expanded.
415  */
416 int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset, int expand)
417 {
418         struct sptlrpc_rule *rules;
419         int nslot;
420
421         if (rset->srs_nrule < rset->srs_nslot)
422                 return 0; 
423
424         if (expand == 0)
425                 return -E2BIG;
426
427         nslot = rset->srs_nslot + 8;
428
429         /* better use realloc() if available */
430         OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules));
431         if (rules == NULL)
432                 return -ENOMEM;
433
434         if (rset->srs_nrule) {
435                 LASSERT(rset->srs_nslot && rset->srs_rules);
436                 memcpy(rules, rset->srs_rules,
437                        rset->srs_nrule * sizeof(*rset->srs_rules));
438
439                 OBD_FREE(rset->srs_rules,
440                          rset->srs_nslot * sizeof(*rset->srs_rules));
441         }
442
443         rset->srs_rules = rules;
444         rset->srs_nslot = nslot;
445         return 0;
446 }
447 EXPORT_SYMBOL(sptlrpc_rule_set_expand);
448
449 static inline int rule_spec_dir(struct sptlrpc_rule *rule)
450 {
451         return (rule->sr_from != LUSTRE_SP_ANY ||
452                 rule->sr_to != LUSTRE_SP_ANY);
453 }
454 static inline int rule_spec_net(struct sptlrpc_rule *rule)
455 {
456         return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
457 }
458 static inline int rule_match_dir(struct sptlrpc_rule *r1,
459                                  struct sptlrpc_rule *r2)
460 {
461         return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to);
462 }
463 static inline int rule_match_net(struct sptlrpc_rule *r1,
464                                  struct sptlrpc_rule *r2)
465 {
466         return (r1->sr_netid == r2->sr_netid);
467 }
468
469 /*
470  * merge @rule into @rset.
471  * if @expand != 0 then @rset slots might be expanded.
472  */
473 int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset, 
474                            struct sptlrpc_rule *rule,
475                            int expand)
476 {
477         struct sptlrpc_rule      *p = rset->srs_rules;
478         int                       spec_dir, spec_net;
479         int                       rc, n, match = 0;
480
481         spec_net = rule_spec_net(rule);
482         spec_dir = rule_spec_dir(rule);
483
484         for (n = 0; n < rset->srs_nrule; n++) {
485                 p = &rset->srs_rules[n]; 
486
487                 /* test network match, if failed:
488                  * - spec rule: skip rules which is also spec rule match, until
489                  *   we hit a wild rule, which means no more chance
490                  * - wild rule: skip until reach the one which is also wild
491                  *   and matches
492                  */
493                 if (!rule_match_net(p, rule)) {
494                         if (spec_net) {
495                                 if (rule_spec_net(p))
496                                         continue;
497                                 else
498                                         break;
499                         } else {
500                                 continue;
501                         }
502                 }
503
504                 /* test dir match, same logic as net matching */
505                 if (!rule_match_dir(p, rule)) {
506                         if (spec_dir) {
507                                 if (rule_spec_dir(p))
508                                         continue;
509                                 else
510                                         break;
511                         } else {
512                                 continue;
513                         }
514                 }
515
516                 /* find a match */
517                 match = 1;
518                 break;
519         }
520
521         if (match) {
522                 LASSERT(n >= 0 && n < rset->srs_nrule);
523
524                 if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
525                         /* remove this rule */
526                         if (n < rset->srs_nrule - 1)
527                                 memmove(&rset->srs_rules[n],
528                                         &rset->srs_rules[n + 1],
529                                         (rset->srs_nrule - n - 1) *
530                                         sizeof(*rule));
531                         rset->srs_nrule--;
532                 } else {
533                         /* override the rule */
534                         memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
535                 }
536         } else {
537                 LASSERT(n >= 0 && n <= rset->srs_nrule);
538
539                 if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
540                         rc = sptlrpc_rule_set_expand(rset, expand);
541                         if (rc)
542                                 return rc;
543
544                         if (n < rset->srs_nrule)
545                                 memmove(&rset->srs_rules[n + 1],
546                                         &rset->srs_rules[n],
547                                         (rset->srs_nrule - n) * sizeof(*rule));
548                         memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
549                         rset->srs_nrule++;
550                 } else {
551                         CDEBUG(D_CONFIG, "ignore the unmatched deletion\n");
552                 }
553         }
554
555         return 0;
556 }
557 EXPORT_SYMBOL(sptlrpc_rule_set_merge);
558
559 /**
560  * given from/to/nid, determine a matching flavor in ruleset.
561  * return 1 if a match found, otherwise return 0.
562  */
563 int sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
564                             enum lustre_sec_part from,
565                             enum lustre_sec_part to,
566                             lnet_nid_t nid,
567                             struct sptlrpc_flavor *sf)
568 {
569         struct sptlrpc_rule    *r;
570         int                     n;
571
572         for (n = 0; n < rset->srs_nrule; n++) {
573                 r = &rset->srs_rules[n];
574
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)
578                         continue;
579
580                 if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY &&
581                     from != r->sr_from)
582                         continue;
583
584                 if (to != LUSTRE_SP_ANY && r->sr_to != LUSTRE_SP_ANY &&
585                     to != r->sr_to)
586                         continue;
587
588                 *sf = r->sr_flvr;
589                 return 1;
590         }
591
592         return 0;
593 }
594 EXPORT_SYMBOL(sptlrpc_rule_set_choose);
595
596 void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset)
597 {
598         struct sptlrpc_rule *r;
599         int     n;
600
601         for (n = 0; n < rset->srs_nrule; n++) {
602                 r = &rset->srs_rules[n];
603                 CWARN("<%02d> from %x to %x, net %x, rpc %x\n", n,
604                       r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
605         }
606 }
607 EXPORT_SYMBOL(sptlrpc_rule_set_dump);
608
609 static int sptlrpc_rule_set_extract(struct sptlrpc_rule_set *gen,
610                                     struct sptlrpc_rule_set *tgt,
611                                     enum lustre_sec_part from,
612                                     enum lustre_sec_part to,
613                                     struct sptlrpc_rule_set *rset)
614 {
615         struct sptlrpc_rule_set *src[2] = { gen, tgt };
616         struct sptlrpc_rule     *rule;
617         int                      i, n, rc;
618
619         /* merge general rules firstly, then target-specific rules */
620         for (i = 0; i < 2; i++) {
621                 if (src[i] == NULL)
622                         continue;
623
624                 for (n = 0; n < src[i]->srs_nrule; n++) {
625                         rule = &src[i]->srs_rules[n];
626
627                         if (from != LUSTRE_SP_ANY &&
628                             rule->sr_from != LUSTRE_SP_ANY &&
629                             rule->sr_from != from)
630                                 continue;
631                         if (to != LUSTRE_SP_ANY &&
632                             rule->sr_to != LUSTRE_SP_ANY &&
633                             rule->sr_to != to)
634                                 continue;
635
636                         rc = sptlrpc_rule_set_merge(rset, rule, 1);
637                         if (rc) {
638                                 CERROR("can't merge: %d\n", rc);
639                                 return rc;
640                         }
641                 }
642         }
643
644         return 0;
645 }
646
647 /**********************************
648  * sptlrpc configuration support  *
649  **********************************/
650
651 struct sptlrpc_conf_tgt {
652         struct list_head        sct_list;
653         char                    sct_name[MAX_OBD_NAME];
654         struct sptlrpc_rule_set sct_rset;
655 };
656
657 struct sptlrpc_conf {
658         struct list_head        sc_list;
659         char                    sc_fsname[MTI_NAME_MAXLEN];
660         unsigned int            sc_modified;  /* modified during updating */
661         unsigned int            sc_updated:1, /* updated copy from MGS */
662                                 sc_local:1;   /* local copy from target */
663         struct sptlrpc_rule_set sc_rset;      /* fs general rules */
664         struct list_head        sc_tgts;      /* target-specific rules */
665 };
666
667 static struct mutex sptlrpc_conf_lock;
668 static CFS_LIST_HEAD(sptlrpc_confs);
669
670 static inline int is_hex(char c)
671 {
672         return ((c >= '0' && c <= '9') ||
673                 (c >= 'a' && c <= 'f'));
674 }
675
676 static void target2fsname(const char *tgt, char *fsname, int buflen)
677 {
678         const char     *ptr;
679         int             len;
680
681         ptr = strrchr(tgt, '-');
682         if (ptr) {
683                 if ((strncmp(ptr, "-MDT", 4) != 0 &&
684                      strncmp(ptr, "-OST", 4) != 0) ||
685                     !is_hex(ptr[4]) || !is_hex(ptr[5]) ||
686                     !is_hex(ptr[6]) || !is_hex(ptr[7]))
687                         ptr = NULL;
688         }
689
690         /* if we didn't find the pattern, treat the whole string as fsname */
691         if (ptr == NULL)
692                 len = strlen(tgt);
693         else
694                 len = ptr - tgt;
695
696         len = min(len, buflen - 1);
697         memcpy(fsname, tgt, len);
698         fsname[len] = '\0';
699 }
700
701 static void sptlrpc_conf_free_rsets(struct sptlrpc_conf *conf)
702 {
703         struct sptlrpc_conf_tgt *conf_tgt, *conf_tgt_next;
704
705         sptlrpc_rule_set_free(&conf->sc_rset);
706
707         list_for_each_entry_safe(conf_tgt, conf_tgt_next,
708                                  &conf->sc_tgts, sct_list) {
709                 sptlrpc_rule_set_free(&conf_tgt->sct_rset);
710                 list_del(&conf_tgt->sct_list);
711                 OBD_FREE_PTR(conf_tgt);
712         }
713         LASSERT(list_empty(&conf->sc_tgts));
714
715         conf->sc_updated = 0;
716         conf->sc_local = 0;
717 }
718
719 static void sptlrpc_conf_free(struct sptlrpc_conf *conf)
720 {
721         CDEBUG(D_SEC, "free sptlrpc conf %s\n", conf->sc_fsname);
722
723         sptlrpc_conf_free_rsets(conf);
724         list_del(&conf->sc_list);
725         OBD_FREE_PTR(conf);
726 }
727
728 static
729 struct sptlrpc_conf_tgt *sptlrpc_conf_get_tgt(struct sptlrpc_conf *conf,
730                                               const char *name,
731                                               int create)
732 {
733         struct sptlrpc_conf_tgt *conf_tgt;
734
735         list_for_each_entry(conf_tgt, &conf->sc_tgts, sct_list) {
736                 if (strcmp(conf_tgt->sct_name, name) == 0)
737                         return conf_tgt;
738         }
739
740         if (!create)
741                 return NULL;
742
743         OBD_ALLOC_PTR(conf_tgt);
744         if (conf_tgt) {
745                 strncpy(conf_tgt->sct_name, name, sizeof(conf_tgt->sct_name));
746                 sptlrpc_rule_set_init(&conf_tgt->sct_rset);
747                 list_add(&conf_tgt->sct_list, &conf->sc_tgts);
748         }
749
750         return conf_tgt;
751 }
752
753 static
754 struct sptlrpc_conf *sptlrpc_conf_get(const char *fsname,
755                                       int create)
756 {
757         struct sptlrpc_conf *conf;
758
759         list_for_each_entry(conf, &sptlrpc_confs, sc_list) {
760                 if (strcmp(conf->sc_fsname, fsname) == 0)
761                         return conf;
762         }
763
764         if (!create)
765                 return NULL;
766
767         OBD_ALLOC_PTR(conf);
768         if (conf == NULL)
769                 return NULL;
770
771         strcpy(conf->sc_fsname, fsname);
772         sptlrpc_rule_set_init(&conf->sc_rset);
773         CFS_INIT_LIST_HEAD(&conf->sc_tgts);
774         list_add(&conf->sc_list, &sptlrpc_confs);
775
776         CDEBUG(D_SEC, "create sptlrpc conf %s\n", conf->sc_fsname);
777         return conf;
778 }
779
780 /**
781  * caller must hold conf_lock already.
782  */
783 static int sptlrpc_conf_merge_rule(struct sptlrpc_conf *conf,
784                                    const char *target,
785                                    struct sptlrpc_rule *rule)
786 {
787         struct sptlrpc_conf_tgt  *conf_tgt;
788         struct sptlrpc_rule_set  *rule_set;
789
790         /* fsname == target means general rules for the whole fs */
791         if (strcmp(conf->sc_fsname, target) == 0) {
792                 rule_set = &conf->sc_rset;
793         } else {
794                 conf_tgt = sptlrpc_conf_get_tgt(conf, target, 1);
795                 if (conf_tgt) {
796                         rule_set = &conf_tgt->sct_rset;
797                 } else {
798                         CERROR("out of memory, can't merge rule!\n");
799                         return -ENOMEM;
800                 }
801         }
802
803         return sptlrpc_rule_set_merge(rule_set, rule, 1);
804 }
805
806 /**
807  * process one LCFG_SPTLRPC_CONF record. if \a conf is NULL, we
808  * find one through the target name in the record inside conf_lock;
809  * otherwise means caller already hold conf_lock.
810  */
811 static int __sptlrpc_process_config(struct lustre_cfg *lcfg,
812                                     struct sptlrpc_conf *conf)
813 {
814         char                   *target, *param;
815         char                    fsname[MTI_NAME_MAXLEN];
816         struct sptlrpc_rule     rule;
817         int                     rc;
818         ENTRY;
819
820         target = lustre_cfg_string(lcfg, 1);
821         if (target == NULL) {
822                 CERROR("missing target name\n");
823                 RETURN(-EINVAL);
824         }
825
826         param = lustre_cfg_string(lcfg, 2);
827         if (param == NULL) {
828                 CERROR("missing parameter\n");
829                 RETURN(-EINVAL);
830         }
831
832         CDEBUG(D_SEC, "got one rule: %s.%s\n", target, param);
833
834         /* parse rule to make sure the format is correct */
835         if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) {
836                 CERROR("Invalid sptlrpc parameter: %s\n", param);
837                 RETURN(-EINVAL);
838         }
839         param += sizeof(PARAM_SRPC_FLVR) - 1;
840
841         rc = sptlrpc_parse_rule(param, &rule);
842         if (rc)
843                 RETURN(-EINVAL);
844
845         if (conf == NULL) {
846                 target2fsname(target, fsname, sizeof(fsname));
847
848                 mutex_lock(&sptlrpc_conf_lock);
849                 conf = sptlrpc_conf_get(fsname, 0);
850                 if (conf == NULL) {
851                         CERROR("can't find conf\n");
852                         rc = -ENOMEM;
853                 } else {
854                         rc = sptlrpc_conf_merge_rule(conf, target, &rule);
855                 }
856                 mutex_unlock(&sptlrpc_conf_lock);
857         } else {
858                 LASSERT(mutex_is_locked(&sptlrpc_conf_lock));
859                 rc = sptlrpc_conf_merge_rule(conf, target, &rule);
860         }
861
862         if (rc == 0)
863                 conf->sc_modified++;
864
865         RETURN(rc);
866 }
867
868 int sptlrpc_process_config(struct lustre_cfg *lcfg)
869 {
870         return __sptlrpc_process_config(lcfg, NULL);
871 }
872 EXPORT_SYMBOL(sptlrpc_process_config);
873
874 static int logname2fsname(const char *logname, char *buf, int buflen)
875 {
876         char   *ptr;
877         int     len;
878
879         ptr = strrchr(logname, '-');
880         if (ptr == NULL || strcmp(ptr, "-sptlrpc")) {
881                 CERROR("%s is not a sptlrpc config log\n", logname);
882                 return -EINVAL;
883         }
884
885         len = min((int) (ptr - logname), buflen - 1);
886
887         memcpy(buf, logname, len);
888         buf[len] = '\0';
889         return 0;
890 }
891
892 void sptlrpc_conf_log_update_begin(const char *logname)
893 {
894         struct sptlrpc_conf *conf;
895         char                 fsname[16];
896
897         if (logname2fsname(logname, fsname, sizeof(fsname)))
898                 return;
899
900         mutex_lock(&sptlrpc_conf_lock);
901
902         conf = sptlrpc_conf_get(fsname, 0);
903         if (conf && conf->sc_local) {
904                 LASSERT(conf->sc_updated == 0);
905                 sptlrpc_conf_free_rsets(conf);
906         }
907         conf->sc_modified = 0;
908
909         mutex_unlock(&sptlrpc_conf_lock);
910 }
911 EXPORT_SYMBOL(sptlrpc_conf_log_update_begin);
912
913 /**
914  * mark a config log has been updated
915  */
916 void sptlrpc_conf_log_update_end(const char *logname)
917 {
918         struct sptlrpc_conf *conf;
919         char                 fsname[16];
920
921         if (logname2fsname(logname, fsname, sizeof(fsname)))
922                 return;
923
924         mutex_lock(&sptlrpc_conf_lock);
925
926         conf = sptlrpc_conf_get(fsname, 0);
927         if (conf) {
928                 /*
929                  * if original state is not updated, make sure the
930                  * modified counter > 0 to enforce updating local copy.
931                  */
932                 if (conf->sc_updated == 0)
933                         conf->sc_modified++;
934
935                 conf->sc_updated = 1;
936         }
937
938         mutex_unlock(&sptlrpc_conf_lock);
939 }
940 EXPORT_SYMBOL(sptlrpc_conf_log_update_end);
941
942 void sptlrpc_conf_log_start(const char *logname)
943 {
944         struct sptlrpc_conf *conf;
945         char                 fsname[16];
946
947         if (logname2fsname(logname, fsname, sizeof(fsname)))
948                 return;
949
950         mutex_lock(&sptlrpc_conf_lock);
951         conf = sptlrpc_conf_get(fsname, 1);
952         mutex_unlock(&sptlrpc_conf_lock);
953 }
954 EXPORT_SYMBOL(sptlrpc_conf_log_start);
955
956 void sptlrpc_conf_log_stop(const char *logname)
957 {
958         struct sptlrpc_conf *conf;
959         char                 fsname[16];
960
961         if (logname2fsname(logname, fsname, sizeof(fsname)))
962                 return;
963
964         mutex_lock(&sptlrpc_conf_lock);
965         conf = sptlrpc_conf_get(fsname, 0);
966         if (conf)
967                 sptlrpc_conf_free(conf);
968         mutex_unlock(&sptlrpc_conf_lock);
969 }
970 EXPORT_SYMBOL(sptlrpc_conf_log_stop);
971
972 static void inline flavor_set_flags(struct sptlrpc_flavor *sf,
973                                     enum lustre_sec_part from,
974                                     enum lustre_sec_part to,
975                                     unsigned int fl_udesc)
976 {
977         if (from == LUSTRE_SP_MDT) {
978                 /* MDT->MDT; MDT->OST */
979                 sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY;
980         } else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST) {
981                 /* CLI->OST */
982                 sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
983         } else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT) {
984                 /* CLI->MDT */
985                 if (fl_udesc && sf->sf_rpc != SPTLRPC_FLVR_NULL)
986                         sf->sf_flags |= PTLRPC_SEC_FL_UDESC;
987         }
988 }
989
990 void sptlrpc_conf_choose_flavor(enum lustre_sec_part from,
991                                 enum lustre_sec_part to,
992                                 struct obd_uuid *target,
993                                 lnet_nid_t nid,
994                                 struct sptlrpc_flavor *sf)
995 {
996         struct sptlrpc_conf     *conf;
997         struct sptlrpc_conf_tgt *conf_tgt;
998         char                     name[MTI_NAME_MAXLEN];
999         int                      len, rc = 0;
1000
1001         target2fsname(target->uuid, name, sizeof(name));
1002
1003         mutex_lock(&sptlrpc_conf_lock);
1004
1005         conf = sptlrpc_conf_get(name, 0);
1006         if (conf == NULL)
1007                 goto out;
1008
1009         /* convert uuid name (supposed end with _UUID) to target name */
1010         len = strlen(target->uuid);
1011         LASSERT(len > 5);
1012         memcpy(name, target->uuid, len - 5);
1013         name[len - 5] = '\0';
1014
1015         conf_tgt = sptlrpc_conf_get_tgt(conf, name, 0);
1016         if (conf_tgt) {
1017                 rc = sptlrpc_rule_set_choose(&conf_tgt->sct_rset,
1018                                              from, to, nid, sf);
1019                 if (rc)
1020                         goto out;
1021         }
1022
1023         rc = sptlrpc_rule_set_choose(&conf->sc_rset, from, to, nid, sf);
1024 out:
1025         mutex_unlock(&sptlrpc_conf_lock);
1026
1027         if (rc == 0)
1028                 get_default_flavor(sf);
1029
1030         flavor_set_flags(sf, from, to, 1);
1031 }
1032
1033 /**
1034  * called by target devices, determine the expected flavor from
1035  * certain peer (from, nid).
1036  */
1037 void sptlrpc_target_choose_flavor(struct sptlrpc_rule_set *rset,
1038                                   enum lustre_sec_part from,
1039                                   lnet_nid_t nid,
1040                                   struct sptlrpc_flavor *sf)
1041 {
1042         if (sptlrpc_rule_set_choose(rset, from, LUSTRE_SP_ANY, nid, sf) == 0)
1043                 get_default_flavor(sf);
1044 }
1045 EXPORT_SYMBOL(sptlrpc_target_choose_flavor);
1046
1047 #define SEC_ADAPT_DELAY         (10)
1048
1049 /**
1050  * called by client devices, notify the sptlrpc config has changed and
1051  * do import_sec_adapt later.
1052  */
1053 void sptlrpc_conf_client_adapt(struct obd_device *obd)
1054 {
1055         struct obd_import  *imp;
1056         ENTRY;
1057
1058         LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 ||
1059                 strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) ==0);
1060         CDEBUG(D_SEC, "obd %s\n", obd->u.cli.cl_target_uuid.uuid);
1061
1062         /* serialize with connect/disconnect import */
1063         down_read(&obd->u.cli.cl_sem);
1064
1065         imp = obd->u.cli.cl_import;
1066         if (imp) {
1067                 spin_lock(&imp->imp_lock);
1068                 if (imp->imp_sec)
1069                         imp->imp_sec_expire = cfs_time_current_sec() +
1070                                               SEC_ADAPT_DELAY;
1071                 spin_unlock(&imp->imp_lock);
1072         }
1073
1074         up_read(&obd->u.cli.cl_sem);
1075         EXIT;
1076 }
1077 EXPORT_SYMBOL(sptlrpc_conf_client_adapt);
1078
1079 #ifdef __KERNEL__
1080
1081 static void rule2string(struct sptlrpc_rule *r, char *buf, int buflen)
1082 {
1083         char    dirbuf[8];
1084         char   *net;
1085         char   *ptr = buf;
1086
1087         if (r->sr_netid == LNET_NIDNET(LNET_NID_ANY))
1088                 net = "default";
1089         else
1090                 net = libcfs_net2str(r->sr_netid);
1091
1092         if (r->sr_from == LUSTRE_SP_ANY && r->sr_to == LUSTRE_SP_ANY)
1093                 dirbuf[0] = '\0';
1094         else
1095                 snprintf(dirbuf, sizeof(dirbuf), ".%s2%s",
1096                          sptlrpc_part2name(r->sr_from),
1097                          sptlrpc_part2name(r->sr_to));
1098
1099         ptr += snprintf(buf, buflen, "srpc.flavor.%s%s=", net, dirbuf);
1100
1101         sptlrpc_flavor2name(&r->sr_flvr, ptr, buflen - (ptr - buf));
1102         buf[buflen - 1] = '\0';
1103 }
1104
1105 static int sptlrpc_record_rule_set(struct llog_handle *llh,
1106                                    char *target,
1107                                    struct sptlrpc_rule_set *rset)
1108 {
1109         struct lustre_cfg_bufs  bufs;
1110         struct lustre_cfg      *lcfg;
1111         struct llog_rec_hdr     rec;
1112         int                     buflen;
1113         char                    param[48];
1114         int                     i, rc;
1115
1116         for (i = 0; i < rset->srs_nrule; i++) {
1117                 rule2string(&rset->srs_rules[i], param, sizeof(param));
1118
1119                 lustre_cfg_bufs_reset(&bufs, NULL);
1120                 lustre_cfg_bufs_set_string(&bufs, 1, target);
1121                 lustre_cfg_bufs_set_string(&bufs, 2, param);
1122                 lcfg = lustre_cfg_new(LCFG_SPTLRPC_CONF, &bufs);
1123                 LASSERT(lcfg);
1124
1125                 buflen = lustre_cfg_len(lcfg->lcfg_bufcount,
1126                                         lcfg->lcfg_buflens);
1127                 rec.lrh_len = llog_data_len(buflen);
1128                 rec.lrh_type = OBD_CFG_REC;
1129                 rc = llog_write_rec(llh, &rec, NULL, 0, (void *)lcfg, -1);
1130                 if (rc)
1131                         CERROR("failed to write a rec: rc = %d\n", rc);
1132                 lustre_cfg_free(lcfg);
1133         }
1134         return 0;
1135 }
1136
1137 static int sptlrpc_record_rules(struct llog_handle *llh,
1138                                 struct sptlrpc_conf *conf)
1139 {
1140         struct sptlrpc_conf_tgt *conf_tgt;
1141
1142         sptlrpc_record_rule_set(llh, conf->sc_fsname, &conf->sc_rset);
1143
1144         list_for_each_entry(conf_tgt, &conf->sc_tgts, sct_list) {
1145                 sptlrpc_record_rule_set(llh, conf_tgt->sct_name,
1146                                         &conf_tgt->sct_rset);
1147         }
1148         return 0;
1149 }
1150
1151 #define LOG_SPTLRPC_TMP "sptlrpc.tmp"
1152 #define LOG_SPTLRPC     "sptlrpc"
1153
1154 static
1155 int sptlrpc_target_local_copy_conf(struct obd_device *obd,
1156                                    struct sptlrpc_conf *conf)
1157 {
1158         struct llog_handle   *llh = NULL;
1159         struct llog_ctxt     *ctxt;
1160         struct lvfs_run_ctxt  saved;
1161         struct dentry        *dentry;
1162         int                   rc;
1163         ENTRY;
1164
1165         ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
1166         if (ctxt == NULL) {
1167                 CERROR("missing llog context\n");
1168                 RETURN(-EINVAL);
1169         }
1170
1171         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
1172
1173         dentry = lookup_one_len(MOUNT_CONFIGS_DIR, current->fs->pwd,
1174                                 strlen(MOUNT_CONFIGS_DIR));
1175         if (IS_ERR(dentry)) {
1176                 rc = PTR_ERR(dentry);
1177                 CERROR("cannot lookup %s directory: rc = %d\n",
1178                        MOUNT_CONFIGS_DIR, rc);
1179                 GOTO(out_ctx, rc);
1180         }
1181
1182         /* erase the old tmp log */
1183         rc = llog_create(ctxt, &llh, NULL, LOG_SPTLRPC_TMP);
1184         if (rc == 0) {
1185                 rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL);
1186                 if (rc == 0) {
1187                         rc = llog_destroy(llh);
1188                         llog_free_handle(llh);
1189                 } else {
1190                         llog_close(llh);
1191                 }
1192         }
1193
1194         if (rc) {
1195                 CERROR("target %s: cannot erase temporary sptlrpc log: "
1196                        "rc = %d\n", obd->obd_name, rc);
1197                 GOTO(out_dput, rc);
1198         }
1199
1200         /* write temporary log */
1201         rc = llog_create(ctxt, &llh, NULL, LOG_SPTLRPC_TMP);
1202         if (rc)
1203                 GOTO(out_dput, rc);
1204         rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL);
1205         if (rc)
1206                 GOTO(out_close, rc);
1207
1208         rc = sptlrpc_record_rules(llh, conf);
1209
1210 out_close:
1211         llog_close(llh);
1212
1213         if (rc == 0) {
1214                 rc = lustre_rename(dentry, obd->obd_lvfs_ctxt.pwdmnt,
1215                                    LOG_SPTLRPC_TMP, LOG_SPTLRPC);
1216         }
1217
1218 out_dput:
1219         l_dput(dentry);
1220 out_ctx:
1221         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
1222         llog_ctxt_put(ctxt);
1223         CDEBUG(D_SEC, "target %s: write local sptlrpc conf: rc = %d\n",
1224                obd->obd_name, rc);
1225         RETURN(rc);
1226 }
1227
1228 static int local_read_handler(struct llog_handle *llh,
1229                               struct llog_rec_hdr *rec,
1230                               void *data)
1231 {
1232         struct sptlrpc_conf  *conf = (struct sptlrpc_conf *) data;
1233         struct lustre_cfg    *lcfg = (struct lustre_cfg *)(rec + 1);
1234         int                   cfg_len, rc;
1235         ENTRY;
1236
1237         if (rec->lrh_type != OBD_CFG_REC) {
1238                 CERROR("unhandled lrh_type: %#x\n", rec->lrh_type);
1239                 RETURN(-EINVAL);
1240         }
1241
1242         cfg_len = rec->lrh_len - sizeof(struct llog_rec_hdr) -
1243                   sizeof(struct llog_rec_tail);
1244
1245         rc = lustre_cfg_sanity_check(lcfg, cfg_len);
1246         if (rc) {
1247                 CERROR("Insane cfg\n");
1248                 RETURN(rc);
1249         }
1250
1251         if (lcfg->lcfg_command != LCFG_SPTLRPC_CONF) {
1252                 CERROR("invalid command (%x)\n", lcfg->lcfg_command);
1253                 RETURN(-EINVAL);
1254         }
1255
1256         RETURN(__sptlrpc_process_config(lcfg, conf));
1257 }
1258
1259 static
1260 int sptlrpc_target_local_read_conf(struct obd_device *obd,
1261                                    struct sptlrpc_conf *conf)
1262 {
1263         struct llog_handle    *llh = NULL;
1264         struct llog_ctxt      *ctxt;
1265         struct lvfs_run_ctxt   saved;
1266         int                    rc;
1267         ENTRY;
1268
1269         LASSERT(conf->sc_updated == 0 && conf->sc_local == 0);
1270
1271         ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
1272         if (ctxt == NULL) {
1273                 CERROR("missing llog context\n");
1274                 RETURN(-EINVAL);
1275         }
1276
1277         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
1278
1279         rc = llog_create(ctxt, &llh, NULL, LOG_SPTLRPC);
1280         if (rc)
1281                 GOTO(out_pop, rc);
1282
1283         rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL);
1284         if (rc)
1285                 GOTO(out_close, rc);
1286
1287         if (llog_get_size(llh) <= 1) {
1288                 CDEBUG(D_SEC, "no local sptlrpc copy found\n");
1289                 GOTO(out_close, rc = 0);
1290         }
1291
1292         rc = llog_process(llh, local_read_handler, (void *) conf, NULL);
1293
1294         if (rc == 0) {
1295                 conf->sc_local = 1;
1296         } else {
1297                 sptlrpc_conf_free_rsets(conf);
1298         }
1299
1300 out_close:
1301         llog_close(llh);
1302 out_pop:
1303         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
1304         llog_ctxt_put(ctxt);
1305         CDEBUG(D_SEC, "target %s: read local sptlrpc conf: rc = %d\n",
1306                obd->obd_name, rc);
1307         RETURN(rc);
1308 }
1309
1310 #endif /* __KRENEL__ */
1311
1312 /**
1313  * called by target devices, extract sptlrpc rules which applies to
1314  * this target, to be used for future rpc flavor checking.
1315  */
1316 int sptlrpc_conf_target_get_rules(struct obd_device *obd,
1317                                   struct sptlrpc_rule_set *rset,
1318                                   int initial)
1319 {
1320         struct sptlrpc_conf      *conf;
1321         struct sptlrpc_conf_tgt  *conf_tgt;
1322         enum lustre_sec_part      sp_dst;
1323         char                      fsname[MTI_NAME_MAXLEN];
1324         int                       rc = 0;
1325         ENTRY;
1326
1327         if (strcmp(obd->obd_type->typ_name, LUSTRE_MDT_NAME) == 0) {
1328                 sp_dst = LUSTRE_SP_MDT;
1329         } else if (strcmp(obd->obd_type->typ_name, LUSTRE_OST_NAME) == 0) {
1330                 sp_dst = LUSTRE_SP_OST;
1331         } else {
1332                 CERROR("unexpected obd type %s\n", obd->obd_type->typ_name);
1333                 RETURN(-EINVAL);
1334         }
1335         CDEBUG(D_SEC, "get rules for target %s\n", obd->obd_uuid.uuid);
1336
1337         target2fsname(obd->obd_uuid.uuid, fsname, sizeof(fsname));
1338
1339         mutex_lock(&sptlrpc_conf_lock);
1340
1341         conf = sptlrpc_conf_get(fsname, 0);
1342         if (conf == NULL) {
1343                 CERROR("missing sptlrpc config log\n");
1344                 GOTO(out, rc);
1345         }
1346
1347 #ifdef __KERNEL__
1348         if (conf->sc_updated  == 0) {
1349                 /*
1350                  * always read from local copy. here another option is
1351                  * if we already have a local copy (read from another
1352                  * target device hosted on the same node) we simply use that.
1353                  */
1354                 if (conf->sc_local)
1355                         sptlrpc_conf_free_rsets(conf);
1356
1357                 sptlrpc_target_local_read_conf(obd, conf);
1358         } else {
1359                 LASSERT(conf->sc_local == 0);
1360
1361                 /* write a local copy */
1362                 if (initial || conf->sc_modified)
1363                         sptlrpc_target_local_copy_conf(obd, conf);
1364                 else
1365                         CDEBUG(D_SEC, "unchanged, skip updating local copy\n");
1366         }
1367 #endif
1368
1369         /* extract rule set for this target */
1370         conf_tgt = sptlrpc_conf_get_tgt(conf, obd->obd_name, 0);
1371
1372         rc = sptlrpc_rule_set_extract(&conf->sc_rset,
1373                                       conf_tgt ? &conf_tgt->sct_rset: NULL,
1374                                       LUSTRE_SP_ANY, sp_dst, rset);
1375 out:
1376         mutex_unlock(&sptlrpc_conf_lock);
1377         RETURN(rc);
1378 }
1379 EXPORT_SYMBOL(sptlrpc_conf_target_get_rules);
1380
1381 int  sptlrpc_conf_init(void)
1382 {
1383         mutex_init(&sptlrpc_conf_lock);
1384         return 0;
1385 }
1386
1387 void sptlrpc_conf_fini(void)
1388 {
1389         struct sptlrpc_conf  *conf, *conf_next;
1390
1391         mutex_lock(&sptlrpc_conf_lock);
1392         list_for_each_entry_safe(conf, conf_next, &sptlrpc_confs, sc_list) {
1393                 sptlrpc_conf_free(conf);
1394         }
1395         LASSERT(list_empty(&sptlrpc_confs));
1396         mutex_unlock(&sptlrpc_conf_lock);
1397 }