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