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