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