1#!/usr/bin/env python3
2#
3# Copyright (C) 2012-2019 Red Hat, Inc.
4#
5# This library is free software; you can redistribute it and/or
6# modify it under the terms of the GNU Lesser General Public
7# License as published by the Free Software Foundation; either
8# version 2.1 of the License, or (at your option) any later version.
9#
10# This library is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13# Lesser General Public License for more details.
14#
15# You should have received a copy of the GNU Lesser General Public
16# License along with this library.  If not, see
17# <http://www.gnu.org/licenses/>.
18#
19
20import re
21import sys
22
23objects = [
24    "CONNECT", "DOMAIN", "INTERFACE", "NETWORK_PORT",
25    "NETWORK", "NODE_DEVICE", "NWFILTER_BINDING",
26    "NWFILTER", "SECRET", "STORAGE_POOL", "STORAGE_VOL",
27]
28
29objectstr = "|".join(objects)
30
31# Data we're going to be generating looks like this
32#
33# <policyconfig>
34#   <action id="org.libvirt.unix.monitor">
35#     <description>Monitor local virtualized systems</description>
36#     <message>System policy prevents monitoring of
37#              local virtualized systems</message>
38#     <defaults>
39#       <allow_any>yes</allow_any>
40#       <allow_inactive>yes</allow_inactive>
41#       <allow_active>yes</allow_active>
42#     </defaults>
43#   </action>
44#   ...more <action> rules...
45# </policyconfig>
46
47opts = {}
48in_opts = False
49
50perms = {}
51
52aclfile = sys.argv[1]
53with open(aclfile, "r") as fh:
54    for line in fh:
55        if in_opts:
56            if "*/" in line:
57                in_opts = False
58            else:
59                m = re.search(r'''\*\s*\@(\w+):\s*(.*?)\s*$''', line)
60                if m is not None:
61                    opts[m.group(1)] = m.group(2)
62        elif "**" in line:
63            in_opts = True
64        else:
65            m = re.search(r'''VIR_ACCESS_PERM_(%s)_((?:\w|_)+),''' %
66                          objectstr, line)
67            if m is not None:
68                obj = m.group(1).lower()
69                perm = m.group(2).lower()
70                if perm == "last":
71                    continue
72
73                obj = obj.replace("_", "-")
74                perm = perm.replace("_", "-")
75
76                if obj not in perms:
77                    perms[obj] = {}
78                perms[obj][perm] = {
79                    "desc": opts.get("desc", None),
80                    "message": opts.get("message", None),
81                    "anonymous": opts.get("anonymous", None),
82                }
83                opts = {}
84
85print('<?xml version="1.0" encoding="UTF-8"?>')
86print('<!DOCTYPE policyconfig PUBLIC ' +
87      '"-//freedesktop//DTD polkit Policy Configuration 1.0//EN"')
88print('    "http://www.freedesktop.org/software/polkit/policyconfig-1.dtd">')
89print('<policyconfig>')
90print('  <vendor>Libvirt Project</vendor>')
91print('  <vendor_url>https://libvirt.org</vendor_url>')
92
93for obj in sorted(perms.keys()):
94    for perm in sorted(perms[obj].keys()):
95        description = perms[obj][perm]["desc"]
96        message = perms[obj][perm]["message"]
97        anonymous = perms[obj][perm]["anonymous"]
98
99        if description is None:
100            raise Exception("missing description for %s.%s" % (obj, perm))
101        if message is None:
102            raise Exception("missing message for %s.%s" % (obj, perm))
103
104        allow_any = "no"
105        if anonymous:
106            allow_any = "yes"
107        allow_inactive = allow_any
108        allow_active = allow_any
109
110        print('  <action id="org.libvirt.api.%s.%s">' % (obj, perm))
111        print('    <description>%s</description>' % description)
112        print('    <message>%s</message>' % message)
113        print('    <defaults>')
114        print('      <allow_any>%s</allow_any>' % allow_any)
115        print('      <allow_inactive>%s</allow_inactive>' % allow_inactive)
116        print('      <allow_active>%s</allow_active>' % allow_active)
117        print('    </defaults>')
118        print('  </action>')
119
120print('</policyconfig>')
121