Hello community,

here is the log from the commit of package polkit-default-privs for 
openSUSE:Factory checked in at 2020-03-14 09:53:47
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/polkit-default-privs (Old)
 and      /work/SRC/openSUSE:Factory/.polkit-default-privs.new.3160 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "polkit-default-privs"

Sat Mar 14 09:53:47 2020 rev:181 rq:783415 version:1550+20200310.cdde967

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/polkit-default-privs/polkit-default-privs.changes    
    2020-03-01 21:26:30.192372336 +0100
+++ 
/work/SRC/openSUSE:Factory/.polkit-default-privs.new.3160/polkit-default-privs.changes
      2020-03-14 09:53:48.503042662 +0100
@@ -1,0 +2,7 @@
+Tue Mar 10 13:37:13 UTC 2020 - [email protected]
+
+- Update to version 1550+20200310.cdde967:
+  * profiles: whitelist new timeshift pkexec actions (bsc#1165436)
+  * polkit profile: remove trailing '###' lines
+
+-------------------------------------------------------------------

Old:
----
  polkit-default-privs-1550+20200213.f716f0a.tar.xz

New:
----
  polkit-default-privs-1550+20200310.cdde967.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ polkit-default-privs.spec ++++++
--- /var/tmp/diff_new_pack.qLldGz/_old  2020-03-14 09:53:49.075043082 +0100
+++ /var/tmp/diff_new_pack.qLldGz/_new  2020-03-14 09:53:49.075043082 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package polkit-default-privs
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -23,7 +23,7 @@
 %endif
 
 Name:           polkit-default-privs
-Version:        1550+20200213.f716f0a
+Version:        1550+20200310.cdde967
 Release:        0
 Summary:        SUSE PolicyKit default permissions
 License:        GPL-2.0-or-later

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.qLldGz/_old  2020-03-14 09:53:49.099043099 +0100
+++ /var/tmp/diff_new_pack.qLldGz/_new  2020-03-14 09:53:49.103043103 +0100
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/openSUSE/polkit-default-privs.git</param>
-              <param 
name="changesrevision">f716f0a6a93490b9230f8d76647767fc100879b8</param></service></servicedata>
\ No newline at end of file
+              <param 
name="changesrevision">cdde967ac428c1be56a32f4c83fb99877b11a57e</param></service></servicedata>
\ No newline at end of file

++++++ polkit-default-privs-1550+20200213.f716f0a.tar.xz -> 
polkit-default-privs-1550+20200310.cdde967.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/polkit-default-privs-1550+20200213.f716f0a/profiles/polkit-default-privs.easy
 
new/polkit-default-privs-1550+20200310.cdde967/profiles/polkit-default-privs.easy
--- 
old/polkit-default-privs-1550+20200213.f716f0a/profiles/polkit-default-privs.easy
   2020-02-13 13:15:26.000000000 +0100
+++ 
new/polkit-default-privs-1550+20200310.cdde967/profiles/polkit-default-privs.easy
   2020-03-10 14:13:36.000000000 +0100
@@ -1051,4 +1051,6 @@
 # calamares run as root in X11 (bsc#1143147)
 com.github.calamares.calamares.pkexec.run no:no:auth_admin
 
-###
+# backup tool that needs root privilege escalation via pkexec (bsc#1165436)
+in.teejeetech.pkexec.timeshift-gtk auth_admin:auth_admin:auth_admin
+in.teejeetech.pkexec.timeshift auth_admin:auth_admin:auth_admin
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/polkit-default-privs-1550+20200213.f716f0a/profiles/polkit-default-privs.restrictive
 
new/polkit-default-privs-1550+20200310.cdde967/profiles/polkit-default-privs.restrictive
--- 
old/polkit-default-privs-1550+20200213.f716f0a/profiles/polkit-default-privs.restrictive
    2020-02-13 13:15:26.000000000 +0100
+++ 
new/polkit-default-privs-1550+20200310.cdde967/profiles/polkit-default-privs.restrictive
    2020-03-10 14:13:36.000000000 +0100
@@ -989,4 +989,6 @@
 # calamares run as root in X11 (bsc#1143147)
 com.github.calamares.calamares.pkexec.run no:no:auth_admin
 
-###
+# backup tool that needs root privilege escalation via pkexec (bsc#1165436)
+in.teejeetech.pkexec.timeshift-gtk auth_admin:auth_admin:auth_admin
+in.teejeetech.pkexec.timeshift auth_admin:auth_admin:auth_admin
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/polkit-default-privs-1550+20200213.f716f0a/profiles/polkit-default-privs.standard
 
new/polkit-default-privs-1550+20200310.cdde967/profiles/polkit-default-privs.standard
--- 
old/polkit-default-privs-1550+20200213.f716f0a/profiles/polkit-default-privs.standard
       2020-02-13 13:15:26.000000000 +0100
+++ 
new/polkit-default-privs-1550+20200310.cdde967/profiles/polkit-default-privs.standard
       2020-03-10 14:13:36.000000000 +0100
@@ -1052,4 +1052,6 @@
 # calamares run as root in X11 (bsc#1143147)
 com.github.calamares.calamares.pkexec.run no:no:auth_admin
 
-###
+# backup tool that needs root privilege escalation via pkexec (bsc#1165436)
+in.teejeetech.pkexec.timeshift-gtk auth_admin:auth_admin:auth_admin
+in.teejeetech.pkexec.timeshift auth_admin:auth_admin:auth_admin
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/polkit-default-privs-1550+20200213.f716f0a/tools/add_polkit_action.py 
new/polkit-default-privs-1550+20200310.cdde967/tools/add_polkit_action.py
--- old/polkit-default-privs-1550+20200213.f716f0a/tools/add_polkit_action.py   
1970-01-01 01:00:00.000000000 +0100
+++ new/polkit-default-privs-1550+20200310.cdde967/tools/add_polkit_action.py   
2020-03-10 14:13:36.000000000 +0100
@@ -0,0 +1,265 @@
+#!/usr/bin/python3
+
+# vim: ts=4 et sw=4 sts=4 :
+
+import os, sys
+import argparse
+from pathlib import Path
+
+def printerr(*args, **kwargs):
+    kwargs["file"] = sys.stderr
+    print(*args, **kwargs)
+
+epilog = """Example invocation:
+
+# add a single new rule introducing a new group of actions
+{} \\
+    --new-group "bsc#1165436:backup tool that performs privilege escalation to 
root" \\
+    --action in.teejeetech.pkexec.timeshift \\
+    --easy auth_admin:auth_admin:auth_admin_keep \\
+    --standard auth_admin \\
+    --restrictive auth_admin
+""".format(__file__)
+
+class PolkitActionHandler:
+
+    # existing default profiles in increasing order of security
+    PROFILES = ("easy", "standard", "restrictive")
+    # existing authentication type settings in increasing order of security
+    AUTH_TYPES = ("yes", "auth_self_keep", "auth_self", "auth_admin_keep", 
"auth_admin", "no")
+    AUTH_CATEGORIES = ("any-user", "inactive-session", "active-session")
+
+    def __init__(self):
+
+        self.m_profile_dir = Path(__file__).parent.with_name("profiles")
+
+        self.m_parser = argparse.ArgumentParser(
+            description = "Adds a new action with associated authentication 
settings to the polkit profiles managed by polkit-default-privs",
+            formatter_class = argparse.RawTextHelpFormatter,
+            epilog = epilog
+        )
+
+        self.m_parser.add_argument(
+            "--new-group",
+            metavar = "bsc#<bug>:<comment>",
+            type = self.parseGroupArg,
+            help = "Introduces a new group block of related polkit actions. 
Requires a bug reference and comment string"
+        )
+
+        self.m_parser.add_argument(
+            "--action",
+            help = "the canonical action name to add like 
'in.teejeetech.pkexec.timeshift'",
+            required = True,
+            type = self.parseAction
+        )
+
+        for profile in self.PROFILES:
+
+            self.m_parser.add_argument(
+                "--" + profile,
+                metavar = ':'.join(self.AUTH_CATEGORIES),
+                type = self.parseAuthTuple,
+                help = "Specifies the settings for the --action in this 
profile. If all three fields are equal you may also specify only a single field 
without colons.",
+                required = True
+            )
+
+    def parseAuthTuple(self, s):
+        s = s.lower()
+        if s in self.AUTH_TYPES:
+            # the same auth type for all three fields
+            # expand to three full fields for easier usage later on
+            return [s] * 3
+
+        parts = s.split(':')
+
+        if len(parts) != 3:
+            raise argparse.ArgumentTypeError("invalid number of ':' separated 
fields")
+
+        ret = []
+
+        for part in parts:
+            part = part.lower()
+            if part not in self.AUTH_TYPES:
+                raise argparse.ArgumentTypeError("bad authentication type 
'{}'".format(part))
+
+            ret.append(part)
+
+        return ret
+
+    def parseGroupArg(self, s):
+
+        parts = s.split(':', 1)
+
+        if len(parts) != 2:
+            raise argparse.ArgumentTypeError("missing ':' separator")
+
+        bug, comment = parts
+
+        parts = bug.split('#')
+
+        if len(parts) != 2:
+            raise argparse.ArgumentTypeError("missing '#' separator in bug 
reference")
+
+        prefix, nr = parts
+        prefix = prefix.lower()
+
+        allowed_prefixes = ("bsc", "boo")
+
+        if prefix not in allowed_prefixes:
+            raise argparse.ArgumentTypeError("invalid bug prefix, expected any 
of {}".format(allowed_prefixes))
+
+        try:
+            nr = int(nr)
+        except ValueError:
+            raise argparse.ArgumentTypeError("invalid bug number 
{}".format(nr))
+
+        if len(comment.split("\n")) != 1:
+            raise argparse.ArgumentTypeError("newline in comment encountered")
+
+        return (prefix, nr), comment
+
+    def parseAction(self, s):
+
+        # make sure there's no whitespace
+        if len(s.split()) != 1:
+            raise argparse.ArgumentTypeError("whitespace in action name")
+
+        # should have at least one separator
+        if len(s.split('.')) < 2:
+            raise argparse.ArgumentTypeError("too few elements in action name")
+
+        return s
+
+    def getProfilePath(self, which):
+        base = "polkit-default-privs.{}".format(which)
+        return self.m_profile_dir / base
+
+    def run(self):
+
+        self.m_args = self.m_parser.parse_args()
+        # tuple of auth types matching the profiles
+        self.m_auth_types = tuple( getattr(self.m_args, profile) for profile 
in self.PROFILES )
+
+        if not self.sanityCheck():
+            printerr("Not adding new action since sanity check(s) failed")
+            sys.exit(2)
+
+        self.addAction()
+
+    def sanityCheck(self):
+        """Perform a couple of sanity checks for the newly added actions. This
+        is somewhat redundant to the linter in the security-tools repository
+        but these checks can this way be applied right away and they're not
+        too complex to make."""
+
+        ret = self.findDuplicateActions()
+        ret &= self.checkProfileAuthTypeOrder()
+        ret &= self.checkBugNr()
+
+        return ret
+
+    def findDuplicateActions(self):
+
+        ret = True
+
+        for profile in self.PROFILES:
+
+            path = self.getProfilePath(profile)
+
+            with open(path) as fd:
+
+                nr = 0
+                for line in fd.readlines():
+                    nr += 1
+                    line = line.strip()
+                    if not line or line.startswith('#'):
+                        continue
+
+                    action = line.split()[0]
+                    if action == self.m_args.action:
+                        printerr("ERROR: action to be added already exists in 
{}:{}".format(
+                            path, nr
+                        ))
+                        ret = False
+
+
+        return ret
+
+    def checkProfileAuthTypeOrder(self):
+        """Checks that authentication types are not getting weaker in stronger
+        profiles."""
+
+        ret = True
+        strongest = [ self.AUTH_TYPES[0] ] * 3
+
+        for profile, auth_types in zip( self.PROFILES, self.m_auth_types ):
+            for nr, old, new in zip( range(len(strongest)), strongest, 
auth_types ):
+
+                if self.AUTH_TYPES.index(old) > self.AUTH_TYPES.index(new):
+                    printerr("ERROR: Auth type for {} in profile {} is weaker 
than in profile {}".format(
+                        self.AUTH_CATEGORIES[nr],
+                        profile,
+                        self.PROFILES[ self.PROFILES.index(profile) - 1]
+                    ))
+                    ret = False
+
+            strongest = auth_types
+
+        return ret
+
+    def checkBugNr(self):
+        """Attempts to verify that a specified bug number really exists."""
+
+        import subprocess
+        import shutil
+
+        if not self.m_args.new_group:
+            return True
+
+        bug = self.m_args.new_group[0]
+        nr = bug[1]
+
+        insect = shutil.which("insect")
+
+        if not insect:
+            # cannot check bug validity without some bugzilla CLI, assume it's
+            # fine
+            return True
+
+        try:
+            # don't suppress output, might be a helpful pointer to see the
+            # actual bug summary once more on success
+            subprocess.check_call(
+                [insect, "info", "-1", str(nr)],
+                shell = False,
+                close_fds = True
+            )
+        except subprocess.CalledProcessError:
+            printerr("ERROR: bug {}#{} doesn't seem to exist".format(*bug))
+            return False
+
+        return True
+
+    def addAction(self):
+
+        for profile, auth_settings in zip(self.PROFILES, self.m_auth_types):
+
+            path = self.getProfilePath(profile)
+
+            with open(path, 'a') as fd:
+
+                if self.m_args.new_group:
+                    bug, comment = self.m_args.new_group
+                    fd.write("\n")
+                    fd.write("# {} ({}#{})\n".format(
+                        comment, *bug
+                    ))
+
+                fd.write("{} {}\n".format(
+                    self.m_args.action,
+                    ':'.join(auth_settings)
+                ))
+
+
+main = PolkitActionHandler()
+main.run()


Reply via email to