class PPA(dbus.service.Object): def __init__(self, conn=None, object_path=None, bus_name=None): dbus.service.Object.__init__(self, conn, object_path, bus_name) # These are used by PolKit to check privileges self.dbus_info = None self.polkit = None self.enforce_polkit = True try: self.system_repo = repolib.SystemSource() except: self.system_repo = None self.sp = SoftwareProperties() self.cache = apt.Cache() @dbus.service.method( "org.pop_os.repoman.Interface", in_signature='', out_signature='', sender_keyword='sender', connection_keyword='conn' ) def exit(self, sender=None, conn=None): mainloop.quit() @dbus.service.method( "org.pop_os.repoman.Interface", in_signature='b', out_signature='b', sender_keyword='sender', connection_keyword='conn' ) def set_system_source_code_enabled(self, enabled, sender=None, conn=None): """ Enable or disable source code in the system source. Arguments: enabled (bool): The new state to set, True = Enabled. """ self._check_polkit_privilege( sender, conn, 'org.pop_os.repoman.modifysources' ) if self.system_repo: self.system_repo.load_from_file() new_types = [repolib.util.AptSourceType.BINARY] if enabled: new_types.append(repolib.util.AptSourceType.SOURCE) self.system_repo.types = new_types self.system_repo.save_to_disk() return enabled return False @dbus.service.method( "org.pop_os.repoman.Interface", in_signature='sb', out_signature='b', sender_keyword='sender', connection_keyword='conn' ) def set_system_comp_enabled(self, comp, enable, sender=None, conn=None): """ Enable or disable a component in the system source. Arguments: comp (str): the component to set enable (bool): The new state to set, True = Enabled. """ self._check_polkit_privilege( sender, conn, 'org.pop_os.repoman.modifysources' ) if self.system_repo: self.system_repo.load_from_file() self.system_repo.set_component_enabled(component=comp, enabled=enable) self.system_repo.save_to_disk() return True return False @dbus.service.method( "org.pop_os.repoman.Interface", in_signature='sb', out_signature='b', sender_keyword='sender', connection_keyword='conn' ) def set_system_suite_enabled(self, suite, enable, sender=None, conn=None): """ Enable or disable a suite in the system source. Arguments: suite (str): the suite to set enable (bool): The new state to set, True = Enabled. """ self._check_polkit_privilege( sender, conn, 'org.pop_os.repoman.modifysources' ) if self.system_repo: self.system_repo.load_from_file() self.system_repo.set_suite_enabled(suite=suite, enabled=enable) self.system_repo.save_to_disk() return True return False ## TODO: These are old SoftwareProperties Methods, and need to be replaced. @dbus.service.method( 'org.pop_os.repoman.Interface', in_signature='s', out_signature='bs', sender_keyword='sender', connection_keyword='conn' ) def add_repo(self, line, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'org.pop_os.repoman.modifysources' ) try: self.sp.add_source_from_line(line) self.sp.sourceslist.save() self.cache.open() self.cache.update() self.cache.open(None) self.sp.reload_sourceslist() return [True, ''] except Exception as e: print(str(e)) return [False, str(e)] @dbus.service.method( 'org.pop_os.repoman.Interface', in_signature='s', out_signature='bs', sender_keyword='sender', connection_keyword='conn' ) def delete_repo(self, repo, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'org.pop_os.repoman.modifysources' ) try: self.sp.remove_source(repo, remove_source_code=True) self.sp.sourceslist.save() self.cache.open() self.cache.update() self.cache.open(None) self.sp.reload_sourceslist() return [True, ''] except Exception as e: print(str(e)) return [False, str(e)] @dbus.service.method( 'org.pop_os.repoman.Interface', in_signature='ss', out_signature='bs', sender_keyword='sender', connection_keyword='conn' ) def modify_repo(self, old_repo, new_repo, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'org.pop_os.repoman.modifysources' ) try: old_source = self._find_source_from_string(old_repo) index = self.sp.sourceslist.list.index(old_source) file = self.sp.sourceslist.list[index].file new_source_entry = SourceEntry(new_repo, file) self.sp.sourceslist.list[index] = new_source_entry self.sp.sourceslist.save() self.cache.open() self.cache.update() self.cache.open(None) self.sp.reload_sourceslist() return [True, ''] except Exception as e: print(str(e)) return [False, str(e)] @dbus.service.method( 'org.pop_os.repoman.Interface', in_signature='b', out_signature='i', sender_keyword='sender', connection_keyword='conn' ) def set_source_code_enabled(self, enabled, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'org.pop_os.repoman.modifysources' ) if enabled: self.sp.enable_source_code_sources() else: self.sp.disable_source_code_sources() return 0 @dbus.service.method( 'org.pop_os.repoman.Interface', in_signature='sb', out_signature='i', sender_keyword='sender', connection_keyword='conn' ) def set_child_enabled(self, child, enabled, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'org.pop_os.repoman.modifysources' ) if enabled: self.sp.enable_child_source(child) else: self.sp.disable_child_source(child) return 0 @dbus.service.method( 'org.pop_os.repoman.Interface', in_signature='sb', out_signature='i', sender_keyword='sender', connection_keyword='conn' ) def set_comp_enabled(self, comp, enabled, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'org.pop_os.repoman.modifysources' ) if enabled: self.sp.enable_component(comp) else: self.sp.disable_component(comp) return 0 def _find_source_from_string(self, line): # ensure that we have a current list, it might have been changed underneath # us self.sp.reload_sourceslist() for source in self.sp.sourceslist.list: if str(source) == line: return source return None @classmethod def _log_in_file(klass, filename, string): date = time.asctime(time.localtime()) ff = open(filename, "a") ff.write("%s : %s\n" %(date,str(string))) ff.close() @classmethod def _strip_source_line(self, source): source = source.replace("#", "# ") source = source.replace("[", "") source = source.replace("]", "") source = source.replace("'", "") source = source.replace(" ", " ") return source def _check_polkit_privilege(self, sender, conn, privilege): # from jockey '''Verify that sender has a given PolicyKit privilege. sender is the sender's (private) D-BUS name, such as ":1:42" (sender_keyword in @dbus.service.methods). conn is the dbus.Connection object (connection_keyword in @dbus.service.methods). privilege is the PolicyKit privilege string. This method returns if the caller is privileged, and otherwise throws a PermissionDeniedByPolicy exception. ''' if sender is None and conn is None: # called locally, not through D-BUS return if not self.enforce_polkit: # that happens for testing purposes when running on the session # bus, and it does not make sense to restrict operations here return # get peer PID if self.dbus_info is None: self.dbus_info = dbus.Interface(conn.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus/Bus', False), 'org.freedesktop.DBus') pid = self.dbus_info.GetConnectionUnixProcessID(sender) # query PolicyKit if self.polkit is None: self.polkit = dbus.Interface(dbus.SystemBus().get_object( 'org.freedesktop.PolicyKit1', '/org/freedesktop/PolicyKit1/Authority', False), 'org.freedesktop.PolicyKit1.Authority') try: # we don't need is_challenge return here, since we call with AllowUserInteraction (is_auth, _, details) = self.polkit.CheckAuthorization( ('unix-process', {'pid': dbus.UInt32(pid, variant_level=1), 'start-time': dbus.UInt64(0, variant_level=1)}), privilege, {'': ''}, dbus.UInt32(1), '', timeout=600) except dbus.DBusException as e: if e._dbus_error_name == 'org.freedesktop.DBus.Error.ServiceUnknown': # polkitd timed out, connect again self.polkit = None return self._check_polkit_privilege(sender, conn, privilege) else: raise if not is_auth: PPA._log_in_file('/tmp/repoman.log','_check_polkit_privilege: sender %s on connection %s pid %i is not authorized for %s: %s' % (sender, conn, pid, privilege, str(details))) raise PermissionDeniedByPolicy(privilege)
class PPAObject(dbus.service.Object): cache = apt.Cache() def __init__(self, conn=None, object_path=None, bus_name=None): dbus.service.Object.__init__(self, conn, object_path, bus_name) # The following variables are used bu _check_polkit_privilege self.dbus_info = None self.polkit = None self.enforce_polkit = True self.sp = SoftwareProperties() @dbus.service.method( "ro.santopiet.repoman.Interface", in_signature='s', out_signature='i', sender_keyword='sender', connection_keyword='conn' ) def DelPPA(self, ppa, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'ro.santopiet.repoman.delppa' ) # PPA Remove code here try: self.sp.reload_sourceslist() self.sp.remove_source(ppa, remove_source_code=True) self.sp.sourceslist.save() self.sp.reload_sourceslist() return 0 except: raise AptException("Could not remove the APT Source") @dbus.service.method( "ro.santopiet.repoman.Interface", in_signature='s', out_signature='i', sender_keyword='sender', connection_keyword='conn' ) def AddPPA(self, ppa, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'ro.santopiet.repoman.addppa' ) # PPA Add code here try: self.sp.reload_sourceslist() self.sp.add_source_from_line(ppa) self.sp.sourceslist.save() self.sp.reload_sourceslist() return 0 except: raise AptException("Could not remove the APT Source") @dbus.service.method( "ro.santopiet.repoman.Interface", in_signature='ss', out_signature='i', sender_keyword='sender', connection_keyword='conn' ) def ModifyPPA(self, old_source, new_source, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'ro.santopiet.repoman.modppa' ) # PPA Modify code here try: self.sp.reload_sourceslist() old_source = self._strip_source_line(old_source) isvs = self.sp.get_isv_sources() for i in isvs: if str(i) == old_source: source = i index = self.sp.sourceslist.list.index(source) file = self.sp.sourceslist.list[index].file new_source_entry = SourceEntry(new_source,file) self.sp.sourceslist.list[index] = new_source_entry self.sp.sourceslist.save() self.cache.open() self.cache.update() self.cache.open(None) self.cache.close() self.sp.reload_sourceslist() return 0 except: raise AptException("Could not modify the APT Source") @dbus.service.method( "ro.santopiet.repoman.Interface", in_signature='sb', out_signature='i', sender_keyword='sender', connection_keyword='conn' ) def SetCompEnabled(self, comp_name, is_enabled, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'ro.santopiet.repoman.modppa' ) # PPA Modify code here if is_enabled: self.sp.enable_component(comp_name) else: self.sp.disable_component(comp_name) return 0 @dbus.service.method( "ro.santopiet.repoman.Interface", in_signature='sb', out_signature='i', sender_keyword='sender', connection_keyword='conn' ) def SetChildEnabled(self, child_name, is_enabled, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'ro.santopiet.repoman.modppa' ) # PPA Modify code here repos = self.sp.distro.source_template.children for repo in repos: if repo.name == child_name: child = repo if is_enabled: self.sp.enable_child_source(child) else: self.sp.disable_child_source(child) return 0 @dbus.service.method( "ro.santopiet.repoman.Interface", in_signature='b', out_signature='i', sender_keyword='sender', connection_keyword='conn' ) def SetSourceCodeEnabled(self, is_enabled, sender=None, conn=None): self._check_polkit_privilege( sender, conn, 'ro.santopiet.repoman.modppa' ) # PPA Modify code here if is_enabled: self.sp.enable_source_code_sources() else: self.sp.disable_source_code_sources() return 0 @dbus.service.method( "ro.santopiet.repoman.Interface", in_signature='', out_signature='', sender_keyword='sender', connection_keyword='conn' ) def RaiseException(self, sender=None, conn=None): raise RepomanException('Error managing software sources!') @dbus.service.method( "ro.santopiet.repoman.Interface", in_signature='', out_signature='', sender_keyword='sender', connection_keyword='conn' ) def Exit(self, sender=None, conn=None): mainloop.quit() @classmethod def _log_in_file(klass, filename, string): date = time.asctime(time.localtime()) ff = open(filename, "a") ff.write("%s : %s\n" %(date,str(string))) ff.close() @classmethod def _strip_source_line(self, source): source = source.replace("#", "# ") source = source.replace("[", "") source = source.replace("]", "") source = source.replace("'", "") source = source.replace(" ", " ") return source def _check_polkit_privilege(self, sender, conn, privilege): # from jockey '''Verify that sender has a given PolicyKit privilege. sender is the sender's (private) D-BUS name, such as ":1:42" (sender_keyword in @dbus.service.methods). conn is the dbus.Connection object (connection_keyword in @dbus.service.methods). privilege is the PolicyKit privilege string. This method returns if the caller is privileged, and otherwise throws a PermissionDeniedByPolicy exception. ''' if sender is None and conn is None: # called locally, not through D-BUS return if not self.enforce_polkit: # that happens for testing purposes when running on the session # bus, and it does not make sense to restrict operations here return # get peer PID if self.dbus_info is None: self.dbus_info = dbus.Interface(conn.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus/Bus', False), 'org.freedesktop.DBus') pid = self.dbus_info.GetConnectionUnixProcessID(sender) # query PolicyKit if self.polkit is None: self.polkit = dbus.Interface(dbus.SystemBus().get_object( 'org.freedesktop.PolicyKit1', '/org/freedesktop/PolicyKit1/Authority', False), 'org.freedesktop.PolicyKit1.Authority') try: # we don't need is_challenge return here, since we call with AllowUserInteraction (is_auth, _, details) = self.polkit.CheckAuthorization( ('unix-process', {'pid': dbus.UInt32(pid, variant_level=1), 'start-time': dbus.UInt64(0, variant_level=1)}), privilege, {'': ''}, dbus.UInt32(1), '', timeout=600) except dbus.DBusException as e: if e._dbus_error_name == 'org.freedesktop.DBus.Error.ServiceUnknown': # polkitd timed out, connect again self.polkit = None return self._check_polkit_privilege(sender, conn, privilege) else: raise if not is_auth: PPAObject._log_in_file('/tmp/repoman.log','_check_polkit_privilege: sender %s on connection %s pid %i is not authorized for %s: %s' % (sender, conn, pid, privilege, str(details))) raise PermissionDeniedByPolicy(privilege)