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  * Copyright (C) 2007 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #ifndef EXPORT_SYMTAB
23 #define EXPORT_SYMTAB
24 #endif
25 #define DEBUG_SUBSYSTEM S_SEC
26
27 #include <libcfs/libcfs.h>
28 #ifndef __KERNEL__
29 #include <liblustre.h>
30 #include <libcfs/list.h>
31 #else
32 #include <linux/crypto.h>
33 #include <linux/key.h>
34 #endif
35
36 #include <obd.h>
37 #include <obd_class.h>
38 #include <obd_support.h>
39 #include <lustre_net.h>
40 #include <lustre_import.h>
41 #include <lustre_dlm.h>
42 #include <lustre_sec.h>
43
44 #include "ptlrpc_internal.h"
45
46 const char *sptlrpc_part2name(enum lustre_sec_part part)
47 {
48         switch (part) {
49         case LUSTRE_SP_CLI:
50                 return "cli";
51         case LUSTRE_SP_MDT:
52                 return "mdt";
53         case LUSTRE_SP_OST:
54                 return "ost";
55         case LUSTRE_SP_MGS:
56                 return "mgs";
57         case LUSTRE_SP_ANY:
58                 return "any";
59         default:
60                 return "err";
61         }
62 }
63 EXPORT_SYMBOL(sptlrpc_part2name);
64
65 enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd)
66 {
67         const char *type = obd->obd_type->typ_name;
68
69         if (!strcmp(type, LUSTRE_MDT_NAME))
70                 return LUSTRE_SP_MDT;
71         if (!strcmp(type, LUSTRE_OST_NAME))
72                 return LUSTRE_SP_OST;
73         if (!strcmp(type, LUSTRE_MGS_NAME))
74                 return LUSTRE_SP_MGS;
75
76         CERROR("unknown target %p(%s)\n", obd, type);
77         return LUSTRE_SP_ANY;
78 }
79 EXPORT_SYMBOL(sptlrpc_target_sec_part);
80
81 /****************************************
82  * user supplied flavor string parsing  *
83  ****************************************/
84
85 typedef enum {
86         BULK_TYPE_N = 0,
87         BULK_TYPE_I = 1,
88         BULK_TYPE_P = 2
89 } bulk_type_t;
90
91 static void get_default_flavor(struct sptlrpc_flavor *sf)
92 {
93         sf->sf_rpc = SPTLRPC_FLVR_NULL;
94         sf->sf_bulk_ciph = BULK_CIPH_ALG_NULL;
95         sf->sf_bulk_hash = BULK_HASH_ALG_NULL;
96         sf->sf_flags = 0;
97 }
98
99 static void get_flavor_by_rpc(struct sptlrpc_rule *rule, __u16 rpc_flavor)
100 {
101         get_default_flavor(&rule->sr_flvr);
102
103         rule->sr_flvr.sf_rpc = rpc_flavor;
104
105         switch (rpc_flavor) {
106         case SPTLRPC_FLVR_NULL:
107                 break;
108         case SPTLRPC_FLVR_PLAIN:
109         case SPTLRPC_FLVR_KRB5N:
110         case SPTLRPC_FLVR_KRB5A:
111                 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_ADLER32;
112                 break;
113         case SPTLRPC_FLVR_KRB5P:
114                 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128;
115                 /* fall through */
116         case SPTLRPC_FLVR_KRB5I:
117                 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
118                 break;
119         default:
120                 LBUG();
121         }
122 }
123
124 static void get_flavor_by_bulk(struct sptlrpc_rule *rule,
125                                __u16 rpc_flavor, bulk_type_t bulk_type)
126 {
127         switch (bulk_type) {
128         case BULK_TYPE_N:
129                 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL;
130                 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
131                 break;
132         case BULK_TYPE_I:
133                 switch (rpc_flavor) {
134                 case SPTLRPC_FLVR_PLAIN:
135                 case SPTLRPC_FLVR_KRB5N:
136                 case SPTLRPC_FLVR_KRB5A:
137                         rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_ADLER32;
138                         break;
139                 case SPTLRPC_FLVR_KRB5I:
140                 case SPTLRPC_FLVR_KRB5P:
141                         rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
142                         break;
143                 default:
144                         LBUG();
145                 }
146                 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
147                 break;
148         case BULK_TYPE_P:
149                 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_SHA1;
150                 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_AES128;
151                 break;
152         default:
153                 LBUG();
154         }
155 }
156
157 static __u16 __flavors[] = {
158         SPTLRPC_FLVR_NULL,
159         SPTLRPC_FLVR_PLAIN,
160         SPTLRPC_FLVR_KRB5N,
161         SPTLRPC_FLVR_KRB5A,
162         SPTLRPC_FLVR_KRB5I,
163         SPTLRPC_FLVR_KRB5P,
164 };
165
166 #define __nflavors      ARRAY_SIZE(__flavors)
167
168 /*
169  * flavor string format: rpc[-bulk{n|i|p}[:cksum/enc]]
170  * for examples:
171  *  null
172  *  plain-bulki
173  *  krb5p-bulkn
174  *  krb5i-bulkp
175  *  krb5i-bulkp:sha512/arc4
176  */
177 static int parse_flavor(char *str, struct sptlrpc_rule *rule)
178 {
179         const char     *f;
180         char           *bulk, *alg, *enc;
181         char            buf[64];
182         bulk_type_t     bulk_type;
183         __u8            i;
184         ENTRY;
185
186         if (str == NULL || str[0] == '\0') {
187                 rule->sr_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
188                 goto out;
189         }
190
191         for (i = 0; i < __nflavors; i++) {
192                 f = sptlrpc_rpcflavor2name(__flavors[i]);
193                 if (strncmp(str, f, strlen(f)) == 0)
194                         break;
195         }
196
197         if (i >= __nflavors)
198                 GOTO(invalid, -EINVAL);
199
200         /* prepare local buffer thus we can modify it as we want */
201         strncpy(buf, str, 64);
202         buf[64 - 1] = '\0';
203
204         /* find bulk string */
205         bulk = strchr(buf, '-');
206         if (bulk)
207                 *bulk++ = '\0';
208
209         /* now the first part must equal to rpc flavor name */
210         if (strcmp(buf, f) != 0)
211                 GOTO(invalid, -EINVAL);
212
213         get_flavor_by_rpc(rule, __flavors[i]);
214
215         if (bulk == NULL)
216                 goto out;
217
218         /* find bulk algorithm string */
219         alg = strchr(bulk, ':');
220         if (alg)
221                 *alg++ = '\0';
222
223         /* verify bulk section */
224         if (strcmp(bulk, "bulkn") == 0) {
225                 rule->sr_flvr.sf_bulk_hash = BULK_HASH_ALG_NULL;
226                 rule->sr_flvr.sf_bulk_ciph = BULK_CIPH_ALG_NULL;
227                 bulk_type = BULK_TYPE_N;
228         } else if (strcmp(bulk, "bulki") == 0)
229                 bulk_type = BULK_TYPE_I;
230         else if (strcmp(bulk, "bulkp") == 0)
231                 bulk_type = BULK_TYPE_P;
232         else
233                 GOTO(invalid, -EINVAL);
234
235         /* null flavor don't support bulk i/p */
236         if (__flavors[i] == SPTLRPC_FLVR_NULL && bulk_type != BULK_TYPE_N)
237                 GOTO(invalid, -EINVAL);
238
239         /* plain policy dosen't support bulk p */
240         if (__flavors[i] == SPTLRPC_FLVR_PLAIN && bulk_type == BULK_TYPE_P)
241                 GOTO(invalid, -EINVAL);
242
243         get_flavor_by_bulk(rule, __flavors[i], bulk_type);
244
245         if (alg == NULL)
246                 goto out;
247
248         /* find encryption algorithm string */
249         enc = strchr(alg, '/');
250         if (enc)
251                 *enc++ = '\0';
252
253         /* checksum algorithm */
254         for (i = 0; i < BULK_HASH_ALG_MAX; i++) {
255                 if (strcmp(alg, sptlrpc_get_hash_name(i)) == 0) {
256                         rule->sr_flvr.sf_bulk_hash = i;
257                         break;
258                 }
259         }
260         if (i >= BULK_HASH_ALG_MAX)
261                 GOTO(invalid, -EINVAL);
262
263         /* privacy algorithm */
264         if (enc) {
265                 for (i = 0; i < BULK_CIPH_ALG_MAX; i++) {
266                         if (strcmp(enc, sptlrpc_get_ciph_name(i)) == 0) {
267                                 rule->sr_flvr.sf_bulk_ciph = i;
268                                 break;
269                         }
270                 }
271                 if (i >= BULK_CIPH_ALG_MAX)
272                         GOTO(invalid, -EINVAL);
273         }
274
275         /*
276          * bulk combination sanity checks
277          */
278         if (bulk_type == BULK_TYPE_P &&
279             rule->sr_flvr.sf_bulk_ciph == BULK_CIPH_ALG_NULL)
280                 GOTO(invalid, -EINVAL);
281
282         if (bulk_type == BULK_TYPE_I &&
283             (rule->sr_flvr.sf_bulk_hash == BULK_HASH_ALG_NULL ||
284              rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL))
285                 GOTO(invalid, -EINVAL);
286
287         if (bulk_type == BULK_TYPE_N &&
288             (rule->sr_flvr.sf_bulk_hash != BULK_HASH_ALG_NULL ||
289              rule->sr_flvr.sf_bulk_ciph != BULK_CIPH_ALG_NULL))
290                 GOTO(invalid, -EINVAL);
291
292 out:
293         return 0;
294 invalid:
295         CERROR("invalid flavor string: %s\n", str);
296         return -EINVAL;
297 }
298
299 /****************************************
300  * configure rules                      *
301  ****************************************/
302
303 static void sptlrpc_rule_init(struct sptlrpc_rule *rule)
304 {
305         rule->sr_netid = LNET_NIDNET(LNET_NID_ANY);
306         rule->sr_from = LUSTRE_SP_ANY;
307         rule->sr_to = LUSTRE_SP_ANY;
308         rule->sr_padding = 0;
309
310         get_default_flavor(&rule->sr_flvr);
311 }
312
313 /*
314  * format: network[.direction]=flavor
315  */
316 int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
317 {
318         char           *flavor, *dir;
319         int             rc;
320
321         sptlrpc_rule_init(rule);
322
323         flavor = strchr(param, '=');
324         if (flavor == NULL) {
325                 CERROR("invalid param, no '='\n");
326                 RETURN(-EINVAL);
327         }
328         *flavor++ = '\0';
329
330         dir = strchr(param, '.');
331         if (dir)
332                 *dir++ = '\0';
333
334         /* 1.1 network */
335         if (strcmp(param, "default")) {
336                 rule->sr_netid = libcfs_str2net(param);
337                 if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
338                         CERROR("invalid network name: %s\n", param);
339                         RETURN(-EINVAL);
340                 }
341         }
342
343         /* 1.2 direction */
344         if (dir) {
345                 if (!strcmp(dir, "mdt2ost")) {
346                         rule->sr_from = LUSTRE_SP_MDT;
347                         rule->sr_to = LUSTRE_SP_OST;
348                 } else if (!strcmp(dir, "mdt2mdt")) {
349                         rule->sr_from = LUSTRE_SP_MDT;
350                         rule->sr_to = LUSTRE_SP_MDT;
351                 } else if (!strcmp(dir, "cli2ost")) {
352                         rule->sr_from = LUSTRE_SP_CLI;
353                         rule->sr_to = LUSTRE_SP_OST;
354                 } else if (!strcmp(dir, "cli2mdt")) {
355                         rule->sr_from = LUSTRE_SP_CLI;
356                         rule->sr_to = LUSTRE_SP_MDT;
357                 } else {
358                         CERROR("invalid rule dir segment: %s\n", dir);
359                         RETURN(-EINVAL);
360                 }
361         }
362
363         /* 2.1 flavor */
364         rc = parse_flavor(flavor, rule);
365         if (rc)
366                 RETURN(-EINVAL);
367
368         RETURN(0);
369 }
370 EXPORT_SYMBOL(sptlrpc_parse_rule);
371
372 void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
373 {
374         LASSERT(rset->srs_nslot ||
375                 (rset->srs_nrule == 0 && rset->srs_rules == NULL));
376
377         if (rset->srs_nslot) {
378                 OBD_FREE(rset->srs_rules,
379                          rset->srs_nslot * sizeof(*rset->srs_rules));
380                 sptlrpc_rule_set_init(rset);
381         }
382 }
383 EXPORT_SYMBOL(sptlrpc_rule_set_free);
384
385 /*
386  * return 0 if the rule set could accomodate one more rule.
387  * if @expand != 0, the rule set might be expanded.
388  */
389 int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset, int expand)
390 {
391         struct sptlrpc_rule *rules;
392         int nslot;
393
394         if (rset->srs_nrule < rset->srs_nslot)
395                 return 0; 
396
397         if (expand == 0)
398                 return -E2BIG;
399
400         if (rset->srs_nslot == 0)
401                 nslot = 8;
402         else
403                 nslot = rset->srs_nslot + 8;
404
405         /* better use realloc() if available */
406         OBD_ALLOC(rules, nslot * sizeof(*rset->srs_rules));
407         if (rules == NULL)
408                 return -ENOMEM;
409
410         memcpy(rules, rset->srs_rules,
411                rset->srs_nrule * sizeof(*rset->srs_rules));
412
413         if (rset->srs_rules)
414                 OBD_FREE(rset->srs_rules,
415                          rset->srs_nslot * sizeof(*rset->srs_rules));
416
417         rset->srs_rules = rules;
418         rset->srs_nslot = nslot;
419         return 0;
420 }
421 EXPORT_SYMBOL(sptlrpc_rule_set_expand);
422
423 static inline int rule_spec_dir(struct sptlrpc_rule *rule)
424 {
425         return (rule->sr_from != LUSTRE_SP_ANY ||
426                 rule->sr_to != LUSTRE_SP_ANY);
427 }
428 static inline int rule_spec_net(struct sptlrpc_rule *rule)
429 {
430         return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
431 }
432 static inline int rule_match_dir(struct sptlrpc_rule *r1,
433                                  struct sptlrpc_rule *r2)
434 {
435         return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to);
436 }
437 static inline int rule_match_net(struct sptlrpc_rule *r1,
438                                  struct sptlrpc_rule *r2)
439 {
440         return (r1->sr_netid == r2->sr_netid);
441 }
442
443 /*
444  * merge @rule into @rset.
445  * if @expand != 0 then @rset slots might be expanded.
446  */
447 int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset, 
448                            struct sptlrpc_rule *rule,
449                            int expand)
450 {
451         struct sptlrpc_rule      *p = rset->srs_rules;
452         int                       spec_dir, spec_net;
453         int                       rc, n, match = 0;
454
455         spec_net = rule_spec_net(rule);
456         spec_dir = rule_spec_dir(rule);
457
458         for (n = 0; n < rset->srs_nrule; n++) {
459                 p = &rset->srs_rules[n]; 
460
461                 /* test network match, if failed:
462                  * - spec rule: skip rules which is also spec rule match, until
463                  *   we hit a wild rule, which means no more chance
464                  * - wild rule: skip until reach the one which is also wild
465                  *   and matches
466                  */
467                 if (!rule_match_net(p, rule)) {
468                         if (spec_net) {
469                                 if (rule_spec_net(p))
470                                         continue;
471                                 else
472                                         break;
473                         } else {
474                                 continue;
475                         }
476                 }
477
478                 /* test dir match, same logic as net matching */
479                 if (!rule_match_dir(p, rule)) {
480                         if (spec_dir) {
481                                 if (rule_spec_dir(p))
482                                         continue;
483                                 else
484                                         break;
485                         } else {
486                                 continue;
487                         }
488                 }
489
490                 /* find a match */
491                 match = 1;
492                 break;
493         }
494
495         if (match) {
496                 LASSERT(n >= 0 && n < rset->srs_nrule);
497
498                 if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
499                         /* remove this rule */
500                         if (n < rset->srs_nrule - 1)
501                                 memmove(&rset->srs_rules[n],
502                                         &rset->srs_rules[n + 1],
503                                         (rset->srs_nrule - n - 1) *
504                                         sizeof(*rule));
505                         rset->srs_nrule--;
506                 } else {
507                         /* override the rule */
508                         memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
509                 }
510         } else {
511                 LASSERT(n >= 0 && n <= rset->srs_nrule);
512
513                 if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
514                         rc = sptlrpc_rule_set_expand(rset, expand);
515                         if (rc)
516                                 return rc;
517
518                         if (n < rset->srs_nrule)
519                                 memmove(&rset->srs_rules[n + 1],
520                                         &rset->srs_rules[n],
521                                         (rset->srs_nrule - n) * sizeof(*rule));
522                         memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
523                         rset->srs_nrule++;
524                 } else {
525                         CWARN("ignore the unmatched deletion\n");
526                 }
527         }
528
529         return 0;
530 }
531 EXPORT_SYMBOL(sptlrpc_rule_set_merge);
532
533 int sptlrpc_rule_set_from_log(struct sptlrpc_rule_set *rset,
534                               struct sptlrpc_conf_log *log)
535 {
536         LASSERT(rset);
537         LASSERT(log);
538
539         sptlrpc_rule_set_free(rset);
540
541         if (log->scl_nrule == 0)
542                 return 0;
543
544         OBD_ALLOC(rset->srs_rules, log->scl_nrule * sizeof(*log->scl_rules));
545         if (!rset->srs_rules)
546                 return -ENOMEM;
547
548         memcpy(rset->srs_rules, log->scl_rules,
549                log->scl_nrule * sizeof(*log->scl_rules));
550         rset->srs_nslot = rset->srs_nrule = log->scl_nrule;
551         return 0;
552 }
553 EXPORT_SYMBOL(sptlrpc_rule_set_from_log);
554
555 /*
556  * according to NID/from choose a flavor from rule set.
557  */
558 void sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
559                              enum lustre_sec_part from,
560                              lnet_nid_t nid,
561                              struct sptlrpc_flavor *sf)
562 {
563         struct sptlrpc_rule    *r;
564         int                     n;
565
566         for (n = 0; n < rset->srs_nrule; n++) {
567                 r = &rset->srs_rules[n];
568
569                 if (LNET_NIDNET(nid) != LNET_NIDNET(LNET_NID_ANY) &&
570                     r->sr_netid != LNET_NIDNET(LNET_NID_ANY) &&
571                     LNET_NIDNET(nid) != r->sr_netid)
572                         continue;
573
574                 if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY &&
575                     from != r->sr_from)
576                         continue;
577
578                 *sf = r->sr_flvr;
579                 return;
580         }
581
582         /* no match found, set as default flavor */
583         get_default_flavor(sf);
584 }
585 EXPORT_SYMBOL(sptlrpc_rule_set_choose);
586
587 void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset)
588 {
589         struct sptlrpc_rule *r;
590         int     n;
591
592         for (n = 0; n < rset->srs_nrule; n++) {
593                 r = &rset->srs_rules[n];
594                 CWARN("<%02d> from %x to %x, net %x, rpc %x\n", n,
595                       r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
596         }
597 }
598 EXPORT_SYMBOL(sptlrpc_rule_set_dump);
599
600 /****************************************
601  * sptlrpc config log                   *
602  ****************************************/
603
604 struct sptlrpc_conf_log *sptlrpc_conf_log_alloc(void)
605 {
606         struct sptlrpc_conf_log *log;
607
608         OBD_ALLOC_PTR(log);
609         if (log == NULL)
610                 return ERR_PTR(-ENOMEM);
611
612         log->scl_max = SPTLRPC_CONF_LOG_MAX;
613         return log;
614 }
615 EXPORT_SYMBOL(sptlrpc_conf_log_alloc);
616
617 void sptlrpc_conf_log_free(struct sptlrpc_conf_log *log)
618 {
619         LASSERT(log->scl_max == SPTLRPC_CONF_LOG_MAX);
620         OBD_FREE_PTR(log);
621 }
622 EXPORT_SYMBOL(sptlrpc_conf_log_free);
623
624 static __u32 get_log_rule_flags(enum lustre_sec_part from,
625                                 enum lustre_sec_part to,
626                                 unsigned int fl_udesc)
627 {
628         /* MDT->MDT; MDT->OST */
629         if (from == LUSTRE_SP_MDT)
630                 return PTLRPC_SEC_FL_ROOTONLY;
631         /* CLI->OST */
632         if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST)
633                 return PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
634         /* CLI->MDT */
635         if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT)
636                 if (fl_udesc)
637                         return PTLRPC_SEC_FL_UDESC;
638
639         return 0;
640 }
641
642 /*
643  * generate config log: merge general and target rules, which
644  * match @from @to
645  */
646 int sptlrpc_conf_log_populate(struct sptlrpc_rule_set *gen,
647                               struct sptlrpc_rule_set *tgt,
648                               enum lustre_sec_part from,
649                               enum lustre_sec_part to,
650                               unsigned int fl_udesc,
651                               struct sptlrpc_conf_log *log)
652 {
653         struct sptlrpc_rule_set *src[2] = { gen, tgt };
654         struct sptlrpc_rule_set  dst;
655         struct sptlrpc_rule     *rule;
656         __u32                    flags;
657         int                      i, n, rc;
658
659         LASSERT(log);
660
661         dst.srs_nslot = log->scl_max;
662         dst.srs_nrule = 0;
663         dst.srs_rules = log->scl_rules;
664
665         /* merge general rules firstly, then target-specific rules */
666         for (i = 0; i < 2; i++) {
667                 if (src[i] == NULL)
668                         continue;
669
670                 for (n = 0; n < src[i]->srs_nrule; n++) {
671                         rule = &src[i]->srs_rules[n];
672
673                         if (from != LUSTRE_SP_ANY &&
674                             rule->sr_from != LUSTRE_SP_ANY &&
675                             rule->sr_from != from)
676                                 continue;
677                         if (to != LUSTRE_SP_ANY &&
678                             rule->sr_to != LUSTRE_SP_ANY &&
679                             rule->sr_to != to)
680                                 continue;
681
682                         rc = sptlrpc_rule_set_merge(&dst, rule, 0);
683                         if (rc) {
684                                 CERROR("can't merge: %d\n", rc);
685                                 return rc;
686                         }
687                 }
688         }
689
690         log->scl_nrule = dst.srs_nrule;
691
692         /* set flags for each rule */
693         flags = get_log_rule_flags(from, to, fl_udesc);
694
695         for (i = 0; i < log->scl_nrule; i++) {
696                 log->scl_rules[i].sr_flvr.sf_flags = flags;
697
698                 /* also clear the from/to fields which don't need to be known
699                  * accordingly. @from == ANY means this log is for target,
700                  * otherwise for client. */
701                 if (from != LUSTRE_SP_ANY)
702                         log->scl_rules[i].sr_from = LUSTRE_SP_ANY;
703                 log->scl_rules[i].sr_to = LUSTRE_SP_ANY;
704         }
705
706         return 0;
707 }
708 EXPORT_SYMBOL(sptlrpc_conf_log_populate);
709
710 /*
711  * extract config log from @lcfg
712  */
713 struct sptlrpc_conf_log *sptlrpc_conf_log_extract(struct lustre_cfg *lcfg)
714 {
715         struct sptlrpc_conf_log *log;
716         struct sptlrpc_rule     *r;
717         int                      i;
718         ENTRY;
719
720         log = lustre_cfg_buf(lcfg, 1);
721         if (log == NULL) {
722                 CERROR("no sptlrpc config data\n");
723                 RETURN(ERR_PTR(-EINVAL));
724         }
725
726         if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
727                 __swab32s(&log->scl_max);
728                 __swab32s(&log->scl_nrule);
729         }
730
731         if (LUSTRE_CFG_BUFLEN(lcfg, 1) <
732             log->scl_max * sizeof(log->scl_rules[0])) {
733                 CERROR("mal-formed config log\n");
734                 RETURN(ERR_PTR(-EINVAL));
735         }
736
737         if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
738                 for (i = 0; i < log->scl_nrule; i++) {
739                         r = &log->scl_rules[i];
740                         __swab32s(&r->sr_netid);
741                         __swab16s(&r->sr_flvr.sf_rpc);
742                         __swab32s(&r->sr_flvr.sf_flags);
743                 }
744         }
745
746         RETURN(log);
747 }
748 EXPORT_SYMBOL(sptlrpc_conf_log_extract);
749
750 void sptlrpc_conf_log_cleanup(struct sptlrpc_conf_log *log)
751 {
752         log->scl_nrule = 0;
753         memset(log->scl_rules, 0, sizeof(log->scl_rules));
754 }
755 EXPORT_SYMBOL(sptlrpc_conf_log_cleanup);
756
757 void sptlrpc_conf_log_dump(struct sptlrpc_conf_log *log)
758 {
759         struct sptlrpc_rule    *r;
760         int                     n;
761
762         CWARN("max %u, rule# %u part %u\n",
763               log->scl_max, log->scl_nrule, log->scl_part);
764
765         for (n = 0; n < log->scl_nrule; n++) {
766                 r = &log->scl_rules[n];
767                 CWARN("<%02d> %x -> %x, net %x, rpc %x\n", n,
768                       r->sr_from, r->sr_to, r->sr_netid, r->sr_flvr.sf_rpc);
769         }
770 }
771 EXPORT_SYMBOL(sptlrpc_conf_log_dump);
772
773 /*
774  * caller should guarantee that no concurrent calls to this function
775  */
776 #define SEC_ADAPT_DELAY         (10)
777
778 int sptlrpc_cliobd_process_config(struct obd_device *obd,
779                                   struct lustre_cfg *lcfg)
780 {
781         struct sptlrpc_conf_log *log;
782         struct obd_import       *imp;
783         int                      rc;
784
785         log = sptlrpc_conf_log_extract(lcfg);
786         if (IS_ERR(log)) {
787                 CERROR("extract log error: %ld\n", PTR_ERR(log));
788                 return PTR_ERR(log);
789         }
790
791         obd->u.cli.cl_sec_part = log->scl_part;
792
793         rc = sptlrpc_rule_set_from_log(&obd->u.cli.cl_sptlrpc_rset, log);
794         if (rc) {
795                 CERROR("failed create rule set: %d\n", rc);
796                 return rc;
797         }
798
799         imp = obd->u.cli.cl_import;
800         if (imp == NULL)
801                 return 0;
802
803         /* even if imp_sec_expire is already set, we'll override it to a
804          * newer (later) time */
805         spin_lock(&imp->imp_lock);
806         if (imp->imp_sec)
807                 imp->imp_sec_expire = cfs_time_current_sec() + SEC_ADAPT_DELAY;
808         spin_unlock(&imp->imp_lock);
809         return 0;
810 }
811 EXPORT_SYMBOL(sptlrpc_cliobd_process_config);