forked from openSUSE/rpmlint-checks
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCheckPolkitPrivs.py
177 lines (144 loc) · 7.06 KB
/
CheckPolkitPrivs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# vim:sw=4:et
#############################################################################
# File : CheckPolkitPrivs.py
# Package : rpmlint
# Author : Ludwig Nussel
# Purpose : Check for /etc/polkit-default-privs violations
#############################################################################
from Filter import *
import AbstractCheck
import Config
import re
import os
from xml.dom.minidom import parse
POLKIT_PRIVS_WHITELIST = Config.getOption('PolkitPrivsWhiteList', ()) # set of file names
POLKIT_PRIVS_FILES = Config.getOption('PolkitPrivsFiles', ["/etc/polkit-default-privs.standard"])
class PolkitCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckPolkitPrivs")
self.privs = {}
for filename in POLKIT_PRIVS_FILES:
if os.path.exists(filename):
self._parsefile(filename)
def _parsefile(self, filename):
with open(filename) as inputfile:
for line in inputfile:
line = line.split('#')[0].split('\n')[0]
if len(line):
line = re.split(r'\s+', line)
priv = line[0]
value = line[1]
self.privs[priv] = value
def check(self, pkg):
if pkg.isSource():
return
files = pkg.files()
permfiles = {}
# first pass, find additional files
for f in files:
if f in pkg.ghostFiles():
continue
if f.startswith("/etc/polkit-default-privs.d/"):
bn = f[28:]
if bn not in POLKIT_PRIVS_WHITELIST:
printError(pkg, "polkit-unauthorized-file", f)
if bn.endswith(".restrictive") or bn.endswith(".standard") or bn.endswith(".relaxed"):
bn = bn.split('.')[0]
if bn not in permfiles:
permfiles[bn] = 1
for f in permfiles:
f = pkg.dirName() + "/etc/polkit-default-privs.d/" + f
if os.path.exists(f + ".restrictive"):
self._parsefile(f + ".restrictive")
elif os.path.exists(f + ".standard"):
self._parsefile(f + ".standard")
elif os.path.exists(f + ".relaxed"):
self._parsefile(f + ".relaxed")
else:
self._parsefile(f)
for f in files:
if f in pkg.ghostFiles():
continue
# catch xml exceptions
try:
if f.startswith("/usr/share/PolicyKit/policy/")\
or f.startswith("/usr/share/polkit-1/actions/"):
xml = parse(pkg.dirName() + f)
for a in xml.getElementsByTagName("action"):
action = a.getAttribute('id')
if action not in self.privs:
iserr = 0
foundno = 0
foundundef = 0
settings = {}
try:
defaults = a.getElementsByTagName("defaults")[0]
for i in defaults.childNodes:
if not i.nodeType == i.ELEMENT_NODE:
continue
if i.nodeName in ('allow_any', 'allow_inactive', 'allow_active'):
settings[i.nodeName] = i.firstChild.data
except KeyError:
iserr = 1
for i in ('allow_any', 'allow_inactive', 'allow_active'):
if i not in settings:
foundundef = 1
settings[i] = '??'
elif settings[i].find("auth_admin") != 0:
if settings[i] == 'no':
foundno = 1
else:
iserr = 1
if iserr:
printError(
pkg, 'polkit-unauthorized-privilege',
'%s (%s:%s:%s)' % (
action,
settings['allow_any'],
settings['allow_inactive'],
settings['allow_active']))
else:
printError(
pkg, 'polkit-untracked-privilege',
'%s (%s:%s:%s)' % (
action,
settings['allow_any'],
settings['allow_inactive'],
settings['allow_active']))
if foundno or foundundef:
printInfo(
pkg, 'polkit-cant-acquire-privilege',
'%s (%s:%s:%s)' % (
action,
settings['allow_any'],
settings['allow_inactive'],
settings['allow_active']))
except Exception as x:
printError(pkg, 'rpmlint-exception', "%(file)s raised an exception: %(x)s" % {'file': f, 'x': x})
continue
check = PolkitCheck()
AUDIT_BUG_URL = "https://en.opensuse.org/openSUSE:Package_security_guidelines#audit_bugs"
addDetails(
'polkit-unauthorized-file',
"""If the package is intended for inclusion in any SUSE product
please open a bug report to request review of the package by the
security team. Please refer to {} for more information""".format(AUDIT_BUG_URL),
'polkit-unauthorized-privilege',
"""The package allows unprivileged users to carry out privileged
operations without authentication. This could cause security
problems if not done carefully. If the package is intended for
inclusion in any SUSE product please open a bug report to request
review of the package by the security team. Please refer to {}
for more information.""".format(AUDIT_BUG_URL),
'polkit-untracked-privilege',
"""The privilege is not listed in /etc/polkit-default-privs.*
which makes it harder for admins to find. Furthermore polkit
authorization checks can easily introduce security issues. If the
package is intended for inclusion in any SUSE product please open
a bug report to request review of the package by the security team.
Please refer to {} for more information.""".format(AUDIT_BUG_URL),
'polkit-cant-acquire-privilege',
"""Usability can be improved by allowing users to acquire privileges
via authentication. Use e.g. 'auth_admin' instead of 'no' and make
sure to define 'allow_any'. This is an issue only if the privilege
is not listed in /etc/polkit-default-privs.*""")