chiark / gitweb /
eed542d8f89ff425a782e8a2310d8bb745120efb
[elogind.git] / src / bus-proxyd / bus-policy.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "xml.h"
23 #include "fileio.h"
24 #include "strv.h"
25 #include "conf-files.h"
26 #include "bus-internal.h"
27 #include "bus-policy.h"
28
29 static void policy_item_free(PolicyItem *i) {
30         assert(i);
31
32         free(i->interface);
33         free(i->member);
34         free(i->error);
35         free(i->name);
36         free(i->path);
37         free(i);
38 }
39
40 DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
41
42 static void item_append(PolicyItem *i, PolicyItem **list) {
43
44         PolicyItem *tail;
45
46         LIST_FIND_TAIL(items, *list, tail);
47         LIST_INSERT_AFTER(items, *list, tail, i);
48 }
49
50 static int file_load(Policy *p, const char *path) {
51
52         _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
53         _cleanup_(policy_item_freep) PolicyItem *i = NULL;
54         void *xml_state = NULL;
55         unsigned n_other = 0;
56         const char *q;
57         int r;
58
59         enum {
60                 STATE_OUTSIDE,
61                 STATE_BUSCONFIG,
62                 STATE_POLICY,
63                 STATE_POLICY_CONTEXT,
64                 STATE_POLICY_USER,
65                 STATE_POLICY_GROUP,
66                 STATE_POLICY_OTHER_ATTRIBUTE,
67                 STATE_ALLOW_DENY,
68                 STATE_ALLOW_DENY_INTERFACE,
69                 STATE_ALLOW_DENY_MEMBER,
70                 STATE_ALLOW_DENY_ERROR,
71                 STATE_ALLOW_DENY_PATH,
72                 STATE_ALLOW_DENY_MESSAGE_TYPE,
73                 STATE_ALLOW_DENY_NAME,
74                 STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
75                 STATE_OTHER,
76         } state = STATE_OUTSIDE;
77
78         enum {
79                 POLICY_CATEGORY_NONE,
80                 POLICY_CATEGORY_DEFAULT,
81                 POLICY_CATEGORY_MANDATORY,
82                 POLICY_CATEGORY_USER,
83                 POLICY_CATEGORY_GROUP
84         } policy_category = POLICY_CATEGORY_NONE;
85
86         unsigned line = 0;
87
88         assert(p);
89
90         r = read_full_file(path, &c, NULL);
91         if (r < 0) {
92                 if (r == -ENOENT)
93                         return 0;
94                 if (r == -EISDIR)
95                         return r;
96
97                 log_error("Failed to load %s: %s", path, strerror(-r));
98                 return r;
99         }
100
101         q = c;
102         for (;;) {
103                 _cleanup_free_ char *name = NULL;
104                 int t;
105
106                 t = xml_tokenize(&q, &name, &xml_state, &line);
107                 if (t < 0) {
108                         log_error("XML parse failure in %s: %s", path, strerror(-t));
109                         return t;
110                 }
111
112                 switch (state) {
113
114                 case STATE_OUTSIDE:
115
116                         if (t == XML_TAG_OPEN) {
117                                 if (streq(name, "busconfig"))
118                                         state = STATE_BUSCONFIG;
119                                 else {
120                                         log_error("Unexpected tag %s at %s:%u.", name, path, line);
121                                         return -EINVAL;
122                                 }
123
124                         } else if (t == XML_END)
125                                 return 0;
126                         else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
127                                 log_error("Unexpected token (1) at %s:%u.", path, line);
128                                 return -EINVAL;
129                         }
130
131                         break;
132
133                 case STATE_BUSCONFIG:
134
135                         if (t == XML_TAG_OPEN) {
136                                 if (streq(name, "policy")) {
137                                         state = STATE_POLICY;
138                                         policy_category = POLICY_CATEGORY_NONE;
139                                         free(policy_user);
140                                         free(policy_group);
141                                         policy_user = policy_group = NULL;
142                                 } else {
143                                         state = STATE_OTHER;
144                                         n_other = 0;
145                                 }
146                         } else if (t == XML_TAG_CLOSE_EMPTY ||
147                                    (t == XML_TAG_CLOSE && streq(name, "busconfig")))
148                                 state = STATE_OUTSIDE;
149                         else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
150                                 log_error("Unexpected token (2) at %s:%u.", path, line);
151                                 return -EINVAL;
152                         }
153
154                         break;
155
156                 case STATE_POLICY:
157
158                         if (t == XML_ATTRIBUTE_NAME) {
159                                 if (streq(name, "context"))
160                                         state = STATE_POLICY_CONTEXT;
161                                 else if (streq(name, "user"))
162                                         state = STATE_POLICY_USER;
163                                 else if (streq(name, "group"))
164                                         state = STATE_POLICY_GROUP;
165                                 else {
166                                         if (streq(name, "at_console"))
167                                                 log_debug("Attribute %s of <policy> tag unsupported at %s:%u, ignoring.", name, path, line);
168                                         else
169                                                 log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
170                                         state = STATE_POLICY_OTHER_ATTRIBUTE;
171                                 }
172                         } else if (t == XML_TAG_CLOSE_EMPTY ||
173                                    (t == XML_TAG_CLOSE && streq(name, "policy")))
174                                 state = STATE_BUSCONFIG;
175                         else if (t == XML_TAG_OPEN) {
176                                 PolicyItemType it;
177
178                                 if (streq(name, "allow"))
179                                         it = POLICY_ITEM_ALLOW;
180                                 else if (streq(name, "deny"))
181                                         it = POLICY_ITEM_DENY;
182                                 else {
183                                         log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
184                                         return -EINVAL;
185                                 }
186
187                                 assert(!i);
188                                 i = new0(PolicyItem, 1);
189                                 if (!i)
190                                         return log_oom();
191
192                                 i->type = it;
193                                 state = STATE_ALLOW_DENY;
194
195                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
196                                 log_error("Unexpected token (3) at %s:%u.", path, line);
197                                 return -EINVAL;
198                         }
199
200                         break;
201
202                 case STATE_POLICY_CONTEXT:
203
204                         if (t == XML_ATTRIBUTE_VALUE) {
205                                 if (streq(name, "default")) {
206                                         policy_category = POLICY_CATEGORY_DEFAULT;
207                                         state = STATE_POLICY;
208                                 } else if (streq(name, "mandatory")) {
209                                         policy_category = POLICY_CATEGORY_MANDATORY;
210                                         state = STATE_POLICY;
211                                 } else {
212                                         log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
213                                         return -EINVAL;
214                                 }
215                         } else {
216                                 log_error("Unexpected token (4) at %s:%u.", path, line);
217                                 return -EINVAL;
218                         }
219
220                         break;
221
222                 case STATE_POLICY_USER:
223
224                         if (t == XML_ATTRIBUTE_VALUE) {
225                                 free(policy_user);
226                                 policy_user = name;
227                                 name = NULL;
228                                 policy_category = POLICY_CATEGORY_USER;
229                                 state = STATE_POLICY;
230                         } else {
231                                 log_error("Unexpected token (5) in %s:%u.", path, line);
232                                 return -EINVAL;
233                         }
234
235                         break;
236
237                 case STATE_POLICY_GROUP:
238
239                         if (t == XML_ATTRIBUTE_VALUE) {
240                                 free(policy_group);
241                                 policy_group = name;
242                                 name = NULL;
243                                 policy_category = POLICY_CATEGORY_GROUP;
244                                 state = STATE_POLICY;
245                         } else {
246                                 log_error("Unexpected token (6) at %s:%u.", path, line);
247                                 return -EINVAL;
248                         }
249
250                         break;
251
252                 case STATE_POLICY_OTHER_ATTRIBUTE:
253
254                         if (t == XML_ATTRIBUTE_VALUE)
255                                 state = STATE_POLICY;
256                         else {
257                                 log_error("Unexpected token (7) in %s:%u.", path, line);
258                                 return -EINVAL;
259                         }
260
261                         break;
262
263                 case STATE_ALLOW_DENY:
264
265                         assert(i);
266
267                         if (t == XML_ATTRIBUTE_NAME) {
268                                 PolicyItemClass ic;
269
270                                 if (startswith(name, "send_"))
271                                         ic = POLICY_ITEM_SEND;
272                                 else if (startswith(name, "receive_"))
273                                         ic = POLICY_ITEM_RECV;
274                                 else if (streq(name, "own"))
275                                         ic = POLICY_ITEM_OWN;
276                                 else if (streq(name, "own_prefix"))
277                                         ic = POLICY_ITEM_OWN_PREFIX;
278                                 else if (streq(name, "user"))
279                                         ic = POLICY_ITEM_USER;
280                                 else if (streq(name, "group"))
281                                         ic = POLICY_ITEM_GROUP;
282                                 else if (streq(name, "eavesdrop")) {
283                                         log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
284                                         i->class = POLICY_ITEM_IGNORE;
285                                         state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
286                                         break;
287                                 } else {
288                                         log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
289                                         state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
290                                         break;
291                                 }
292
293                                 if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
294                                         log_error("send_ and receive_ fields mixed on same tag at %s:%u.", path, line);
295                                         return -EINVAL;
296                                 }
297
298                                 i->class = ic;
299
300                                 if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
301                                         const char *u;
302
303                                         u = strchr(name, '_');
304                                         assert(u);
305
306                                         u++;
307
308                                         if (streq(u, "interface"))
309                                                 state = STATE_ALLOW_DENY_INTERFACE;
310                                         else if (streq(u, "member"))
311                                                 state = STATE_ALLOW_DENY_MEMBER;
312                                         else if (streq(u, "error"))
313                                                 state = STATE_ALLOW_DENY_ERROR;
314                                         else if (streq(u, "path"))
315                                                 state = STATE_ALLOW_DENY_PATH;
316                                         else if (streq(u, "type"))
317                                                 state = STATE_ALLOW_DENY_MESSAGE_TYPE;
318                                         else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
319                                                  (streq(u, "sender") && ic == POLICY_ITEM_RECV))
320                                                 state = STATE_ALLOW_DENY_NAME;
321                                         else {
322                                                 if (streq(u, "requested_reply"))
323                                                         log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
324                                                 else
325                                                         log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
326                                                 state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
327                                                 break;
328                                         }
329                                 } else
330                                         state = STATE_ALLOW_DENY_NAME;
331
332                         } else if (t == XML_TAG_CLOSE_EMPTY ||
333                                    (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
334
335                                 if (i->class == _POLICY_ITEM_CLASS_UNSET) {
336                                         log_error("Policy not set at %s:%u.", path, line);
337                                         return -EINVAL;
338                                 }
339
340                                 if (policy_category == POLICY_CATEGORY_DEFAULT)
341                                         item_append(i, &p->default_items);
342                                 else if (policy_category == POLICY_CATEGORY_MANDATORY)
343                                         item_append(i, &p->mandatory_items);
344                                 else if (policy_category == POLICY_CATEGORY_USER) {
345                                         const char *u = policy_user;
346
347                                         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
348
349                                         r = hashmap_ensure_allocated(&p->user_items, NULL);
350                                         if (r < 0)
351                                                 return log_oom();
352
353                                         if (!u) {
354                                                 log_error("User policy without name");
355                                                 return -EINVAL;
356                                         }
357
358                                         r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
359                                         if (r < 0) {
360                                                 log_error("Failed to resolve user %s, ignoring policy: %s", u, strerror(-r));
361                                                 free(i);
362                                         } else {
363                                                 PolicyItem *first;
364
365                                                 first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
366                                                 item_append(i, &first);
367
368                                                 r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
369                                                 if (r < 0) {
370                                                         LIST_REMOVE(items, first, i);
371                                                         return log_oom();
372                                                 }
373                                         }
374
375                                 } else if (policy_category == POLICY_CATEGORY_GROUP) {
376                                         const char *g = policy_group;
377
378                                         assert_cc(sizeof(gid_t) == sizeof(uint32_t));
379
380                                         r = hashmap_ensure_allocated(&p->group_items, NULL);
381                                         if (r < 0)
382                                                 return log_oom();
383
384                                         if (!g) {
385                                                 log_error("Group policy without name");
386                                                 return -EINVAL;
387                                         }
388
389                                         r = get_group_creds(&g, &i->gid);
390                                         if (r < 0) {
391                                                 log_error("Failed to resolve group %s, ignoring policy: %s", g, strerror(-r));
392                                                 free(i);
393                                         } else {
394                                                 PolicyItem *first;
395
396                                                 first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
397                                                 item_append(i, &first);
398
399                                                 r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
400                                                 if (r < 0) {
401                                                         LIST_REMOVE(items, first, i);
402                                                         return log_oom();
403                                                 }
404                                         }
405                                 }
406
407                                 state = STATE_POLICY;
408                                 i = NULL;
409
410                         } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
411                                 log_error("Unexpected token (8) at %s:%u.", path, line);
412                                 return -EINVAL;
413                         }
414
415                         break;
416
417                 case STATE_ALLOW_DENY_INTERFACE:
418
419                         if (t == XML_ATTRIBUTE_VALUE) {
420                                 assert(i);
421                                 if (i->interface) {
422                                         log_error("Duplicate interface at %s:%u.", path, line);
423                                         return -EINVAL;
424                                 }
425
426                                 i->interface = name;
427                                 name = NULL;
428                                 state = STATE_ALLOW_DENY;
429                         } else {
430                                 log_error("Unexpected token (9) at %s:%u.", path, line);
431                                 return -EINVAL;
432                         }
433
434                         break;
435
436                 case STATE_ALLOW_DENY_MEMBER:
437
438                         if (t == XML_ATTRIBUTE_VALUE) {
439                                 assert(i);
440                                 if (i->member) {
441                                         log_error("Duplicate member in %s:%u.", path, line);
442                                         return -EINVAL;
443                                 }
444
445                                 i->member = name;
446                                 name = NULL;
447                                 state = STATE_ALLOW_DENY;
448                         } else {
449                                 log_error("Unexpected token (10) in %s:%u.", path, line);
450                                 return -EINVAL;
451                         }
452
453                         break;
454
455                 case STATE_ALLOW_DENY_ERROR:
456
457                         if (t == XML_ATTRIBUTE_VALUE) {
458                                 assert(i);
459                                 if (i->error) {
460                                         log_error("Duplicate error in %s:%u.", path, line);
461                                         return -EINVAL;
462                                 }
463
464                                 i->error = name;
465                                 name = NULL;
466                                 state = STATE_ALLOW_DENY;
467                         } else {
468                                 log_error("Unexpected token (11) in %s:%u.", path, line);
469                                 return -EINVAL;
470                         }
471
472                         break;
473
474                 case STATE_ALLOW_DENY_PATH:
475
476                         if (t == XML_ATTRIBUTE_VALUE) {
477                                 assert(i);
478                                 if (i->path) {
479                                         log_error("Duplicate path in %s:%u.", path, line);
480                                         return -EINVAL;
481                                 }
482
483                                 i->path = name;
484                                 name = NULL;
485                                 state = STATE_ALLOW_DENY;
486                         } else {
487                                 log_error("Unexpected token (12) in %s:%u.", path, line);
488                                 return -EINVAL;
489                         }
490
491                         break;
492
493                 case STATE_ALLOW_DENY_MESSAGE_TYPE:
494
495                         if (t == XML_ATTRIBUTE_VALUE) {
496                                 assert(i);
497
498                                 if (i->message_type != 0) {
499                                         log_error("Duplicate message type in %s:%u.", path, line);
500                                         return -EINVAL;
501                                 }
502
503                                 r = bus_message_type_from_string(name, &i->message_type);
504                                 if (r < 0) {
505                                         log_error("Invalid message type in %s:%u.", path, line);
506                                         return -EINVAL;
507                                 }
508
509                                 state = STATE_ALLOW_DENY;
510                         } else {
511                                 log_error("Unexpected token (13) in %s:%u.", path, line);
512                                 return -EINVAL;
513                         }
514
515                         break;
516
517                 case STATE_ALLOW_DENY_NAME:
518
519                         if (t == XML_ATTRIBUTE_VALUE) {
520                                 assert(i);
521                                 if (i->name) {
522                                         log_error("Duplicate name in %s:%u.", path, line);
523                                         return -EINVAL;
524                                 }
525
526                                 i->name = name;
527                                 name = NULL;
528                                 state = STATE_ALLOW_DENY;
529                         } else {
530                                 log_error("Unexpected token (14) in %s:%u.", path, line);
531                                 return -EINVAL;
532                         }
533
534                         break;
535
536                 case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
537
538                         if (t == XML_ATTRIBUTE_VALUE)
539                                 state = STATE_ALLOW_DENY;
540                         else {
541                                 log_error("Unexpected token (15) in %s:%u.", path, line);
542                                 return -EINVAL;
543                         }
544
545                         break;
546
547                 case STATE_OTHER:
548
549                         if (t == XML_TAG_OPEN)
550                                 n_other++;
551                         else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
552
553                                 if (n_other == 0)
554                                         state = STATE_BUSCONFIG;
555                                 else
556                                         n_other--;
557                         }
558
559                         break;
560                 }
561         }
562 }
563
564 int policy_load(Policy *p, char **files) {
565         char **i;
566         int r;
567
568         assert(p);
569
570         STRV_FOREACH(i, files) {
571
572                 r = file_load(p, *i);
573                 if (r == -EISDIR) {
574                         _cleanup_strv_free_ char **l = NULL;
575                         char **j;
576
577                         r = conf_files_list(&l, ".conf", NULL, *i, NULL);
578                         if (r < 0) {
579                                 log_error("Failed to get configuration file list: %s", strerror(-r));
580                                 return r;
581                         }
582
583                         STRV_FOREACH(j, l)
584                                 file_load(p, *j);
585                 }
586
587                 /* We ignore all errors but EISDIR, and just proceed. */
588         }
589
590         return 0;
591 }
592
593 void policy_free(Policy *p) {
594         PolicyItem *i, *first;
595
596         if (!p)
597                 return;
598
599         while ((i = p->default_items)) {
600                 LIST_REMOVE(items, p->default_items, i);
601                 policy_item_free(i);
602         }
603
604         while ((i = p->mandatory_items)) {
605                 LIST_REMOVE(items, p->mandatory_items, i);
606                 policy_item_free(i);
607         }
608
609         while ((first = hashmap_steal_first(p->user_items))) {
610
611                 while ((i = first)) {
612                         LIST_REMOVE(items, first, i);
613                         policy_item_free(i);
614                 }
615         }
616
617         while ((first = hashmap_steal_first(p->group_items))) {
618
619                 while ((i = first)) {
620                         LIST_REMOVE(items, first, i);
621                         policy_item_free(i);
622                 }
623         }
624
625         hashmap_free(p->user_items);
626         hashmap_free(p->group_items);
627
628         p->user_items = p->group_items = NULL;
629 }
630
631 static void dump_items(PolicyItem *i, const char *prefix) {
632
633         if (!i)
634                 return;
635
636         if (!prefix)
637                 prefix = "";
638
639         printf("%sType: %s\n"
640                "%sClass: %s\n",
641                prefix, policy_item_type_to_string(i->type),
642                prefix, policy_item_class_to_string(i->class));
643
644         if (i->interface)
645                 printf("%sInterface: %s\n",
646                        prefix, i->interface);
647
648         if (i->member)
649                 printf("%sMember: %s\n",
650                        prefix, i->member);
651
652         if (i->error)
653                 printf("%sError: %s\n",
654                        prefix, i->error);
655
656         if (i->path)
657                 printf("%sPath: %s\n",
658                        prefix, i->path);
659
660         if (i->name)
661                 printf("%sName: %s\n",
662                        prefix, i->name);
663
664         if (i->message_type != 0)
665                 printf("%sMessage Type: %s\n",
666                        prefix, bus_message_type_to_string(i->message_type));
667
668         if (i->uid_valid) {
669                 _cleanup_free_ char *user;
670
671                 user = uid_to_name(i->uid);
672
673                 printf("%sUser: %s\n",
674                        prefix, strna(user));
675         }
676
677         if (i->gid_valid) {
678                 _cleanup_free_ char *group;
679
680                 group = gid_to_name(i->gid);
681
682                 printf("%sGroup: %s\n",
683                        prefix, strna(group));
684         }
685
686         if (i->items_next) {
687                 printf("%s%s\n", prefix, draw_special_char(DRAW_DASH));
688                 dump_items(i->items_next, prefix);
689         }
690 }
691
692 static void dump_hashmap_items(Hashmap *h) {
693         PolicyItem *i;
694         Iterator j;
695         void *k;
696
697         HASHMAP_FOREACH_KEY(i, k, h, j) {
698                 printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
699                 dump_items(i, "\t\t");
700         }
701 }
702
703 noreturn void policy_dump(Policy *p) {
704
705         printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
706         dump_items(p->default_items, "\t");
707
708         printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
709         dump_hashmap_items(p->group_items);
710
711         printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
712         dump_hashmap_items(p->user_items);
713
714         printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
715         dump_items(p->mandatory_items, "\t");
716
717         exit(0);
718 }
719
720 static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
721         [_POLICY_ITEM_TYPE_UNSET] = "unset",
722         [POLICY_ITEM_ALLOW] = "allow",
723         [POLICY_ITEM_DENY] = "deny",
724 };
725 DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
726
727 static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
728         [_POLICY_ITEM_CLASS_UNSET] = "unset",
729         [POLICY_ITEM_SEND] = "send",
730         [POLICY_ITEM_RECV] = "recv",
731         [POLICY_ITEM_OWN] = "own",
732         [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
733         [POLICY_ITEM_USER] = "user",
734         [POLICY_ITEM_GROUP] = "group",
735         [POLICY_ITEM_IGNORE] = "ignore",
736 };
737 DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);