1
0
mirror of https://github.com/altlinux/gpupdate.git synced 2025-12-02 16:23:52 +03:00

Compare commits

..

153 Commits

Author SHA1 Message Date
527c4f8172 Fixed the definition of the module activation check
Reported-by: Sergey Sysoev <sysoevsa@surgut.gazprom.ru>
2024-06-27 14:08:27 +04:00
Valery Sinelnikov
c57d1bac9e 0.10.3-alt1
- Added autocompletion for gpoa, gpupdate, gpupdate-setup
- Added correct work with json data in keys for the Firefox browser
- Polkit_appliers changed to non-experimental
- Fixed bug of not clearing kde applier settings (closes: 50336)
- Fixed registry key reading (closes: 50553)
- Added waiting for data generation for scripts (closes: 50667)
2024-06-19 14:45:49 +04:00
b9b5239448 Changed macro processing method 2024-06-19 14:37:40 +04:00
aae2776790 Added dictionary with macros 2024-06-19 13:59:13 +04:00
Valery Sinelnikov
a20aa841d6 Add functions to find and wait for a Python process by script path 2024-06-19 13:57:53 +04:00
Valentin Sokolov
8c7819d96f Update autocompletion for gpupdate-setup 2024-06-13 16:54:24 +04:00
Valentin Sokolov
3d9473f979 Update autocompletion for gpoa and gpupdate 2024-06-13 16:52:34 +04:00
Valentin Sokolov
01f48be853 Update gpupdate.spec 2024-06-13 16:17:02 +04:00
Valentin Sokolov
1638098fd4 Added autocompletion for gpupdate-setup 2024-06-13 16:16:56 +04:00
Valentin Sokolov
047e5459af Added autocompletion for gpupdate 2024-06-13 16:16:37 +04:00
Valentin Sokolov
5baa4245e3 Added autocompletion for gpoa 2024-06-13 16:16:30 +04:00
ec6b9f7887 Changing the date in the license 2024-06-13 16:13:00 +04:00
22d0d23b89 Added functionality for clearing unconnected settings 2024-06-13 16:12:53 +04:00
fd3a32e8e1 Removing the old system settings cleanup 2024-06-13 16:12:37 +04:00
Valery Sinelnikov
9e849e8fe3 Added use try_dict_to_literal_eval 2024-06-13 16:09:02 +04:00
Valery Sinelnikov
d65f3ed942 Added forgotten return 2024-06-13 16:07:53 +04:00
Valery Sinelnikov
31298be840 Added new function try_dict_to_literal_eval 2024-06-13 16:06:27 +04:00
Valery Sinelnikov
5c889fd57e Added saving to dconf of type REG_MULTI_SZ 2024-06-11 16:02:17 +04:00
Valery Sinelnikov
4e2874c972 Fixed reading flagSync 2024-06-11 15:44:18 +04:00
Valery Sinelnikov
63e50ac2df Polkit_applier enabled by default 2024-06-11 15:42:29 +04:00
Valery Sinelnikov
ad2a87e20d 0.10.2-alt1
- Added some fixes to dconf_registry and scripts
- Fixed windows registry key reading for loopback
2024-06-07 14:59:14 +04:00
Valery Sinelnikov
e9c3a4262a Fixed windows registry key reading for loopback 2024-06-07 14:54:25 +04:00
Valery Sinelnikov
b5706ec6e1 Added support for the newline symbol in the environment file 2024-06-06 18:14:35 +04:00
Valery Sinelnikov
61e7350429 Replaced Popen with run for command execution 2024-06-06 16:39:39 +04:00
Valery Sinelnikov
c9a274fc79 Reducing typical data to two types 2024-06-06 16:33:01 +04:00
Valery Sinelnikov
127c9f7183 0.10.1-alt1
- Added handling of unexpected data types when writing to dconf
2024-06-04 17:45:48 +04:00
Valery Sinelnikov
a27f8ba5dd Added handling of unexpected data types 2024-06-04 17:40:23 +04:00
Valery Sinelnikov
fafe2c34b4 0.10.0-alt1
- A method for storing registry keys obtained from GPOs (Group Policy Objects)
  has undergone significant repairs. We have switched from using SQLite
  to using Dconf to improve data storage efficiency
2024-05-13 18:36:07 +04:00
Valery Sinelnikov
9c91ddc7ba Added processing the absence of GPO version 2024-05-13 18:34:12 +04:00
Valery Sinelnikov
1f02ed650b Added corrections of shortcuts 2024-05-07 13:51:03 +04:00
Valery Sinelnikov
fc47df4649 Added saving version 2024-04-26 10:30:58 +04:00
Valery Sinelnikov
42b8bdb82a Added usage version 2024-04-26 10:29:58 +04:00
Valery Sinelnikov
2a174edeef Added version argument 2024-04-26 10:29:02 +04:00
Valery Sinelnikov
9b8529b39b Fixed creation of shortcut attributes 2024-04-25 15:15:35 +04:00
Valery Sinelnikov
062ff742c3 Typo fixed 2024-04-24 13:19:27 +04:00
Valery Sinelnikov
1764560c49 Fixed the templates for a new registry 2024-04-10 17:10:20 +04:00
Valery Sinelnikov
b439e04a2f Corrected the interpretation of the terminal attribute for shortcuts 2024-04-09 18:20:35 +04:00
Valery Sinelnikov
e413f95633 Improved processing of registry keys 2024-04-05 16:40:31 +04:00
Valery Sinelnikov
675f37ab85 The incapable dictionary is removed 2024-04-04 16:01:34 +04:00
Valery Sinelnikov
9932c682ef Simplifying dconf profile selection 2024-03-15 13:31:41 +04:00
Valery Sinelnikov
018b30cdc4 Cleaning up code and removing unnecessary parts 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
249eb69ade Changed package_applier_user launch keys 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
1ab8c7aee0 Adapted check_enable_home_link to work with the new storage 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
400a5fab7d Typo corrected 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
e7851e88b3 Added use of profile forwarding in registry_factory 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
0761637666 Corrected variable name 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
dda4d987cb Added the ability to store envprofile status 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
609ec0e8b8 Improve code readability 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
c0b28a0655 In dconf_registry init was removed, the action performed in it was transferred to gpt 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
78aad11e06 Improved get_key_value and get_dconf_envprofile 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
59bebbc45e Added function to get profile for dconf 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
e92656add0 Adaptation to the new storage for pkcon_runner 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
5d24579d2f Added use of username when get storage 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
ce284b61be Added class field to store username 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
7a8118ac63 Added the ability to save username when get storage 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
18d8e73acd Unnecessary line removed 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
58235cb1a1 Fix check_enabled in package_applier 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
e0d88cc076 Adapted to work with the new storage 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
c8b0927090 Adding forwarding policy_name and username to load_preg_dconf 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
a4a79d8c99 Adding policy name to ReadQueue key values 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
408609fa58 Using a new argument when creating a gpt object 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
6efebfad89 Added username argument to gpt class constructor 2024-03-14 10:40:30 +04:00
12865b0b43 Correcting logs in class methods 2024-03-14 10:40:30 +04:00
9117dddcee Changing the log in the create_dconf_ini_file method 2024-03-14 10:40:30 +04:00
1e267f5cb6 Removing an empty key in a dictionary 2024-03-14 10:40:30 +04:00
62ed015ea9 Added logs for the create_dconf_ini_file 2024-03-14 10:40:30 +04:00
3e6b7cd040 Added logs for the get_entry 2024-03-14 10:40:30 +04:00
209eb84d6d Added logs for the get_dictionary_from_dconf 2024-03-14 10:40:30 +04:00
7f3b47a23c Added logs for the apply_template 2024-03-14 10:40:30 +04:00
08ba87c8d8 log correction 2024-03-14 10:40:30 +04:00
f2a45a2a6d Added logs for the dconf_update 2024-03-14 10:40:30 +04:00
9c544adc94 Added logs for the get_key_value method 2024-03-14 10:40:30 +04:00
a225c9aa7f Added logs for the get_matching_keys method 2024-03-14 10:40:30 +04:00
51c8711da6 Updated get_key_values ​​method 2024-03-14 10:40:30 +04:00
54eb4188a7 Fixed error message and added logging module 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
89d5e36d6c Added extension with unique values 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
6cd5ab4ee2 Removed duplicate additions of objects 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
0c913c68e3 Added search for a suitable .desktop file
and creation of a policy based on it
2024-03-14 10:40:30 +04:00
Valery Sinelnikov
12d746a1dc Added get_desktop_files_directory for .desktop path 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
0a25f3a1d6 Changed work with object_shortcut 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
1eaab893c8 Changed queries to the registry from systemd_applier 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
05ea872831 Fixed registry queries 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
d0506dba29 Changed interpretation method from new repository 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
dd28587b20 Added local path processing 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
1a288c84f5 Added check for empty value 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
cadc3eda52 Added processing of the key list request 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
8d3e6691d4 Added the ability to return registry keys with a list item value 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
cb54fa5d78 Changes in requests to get a list of packages 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
53ffc072f0 Added the ability to get a class 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
7a59bcb65b Added fun for correct processing of branch requests 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
b81a727cd4 Added class method to get the key 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
11b33dd148 Changed request method for ScrollSysvolDC 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
1ccc18a31f Changed request method for UserPolicyMode 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
9a3afeebdf Request method changed 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
0720471cca Fixed adding a list of scripts 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
dd43ddaad6 Typos corrected 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
6fc059aaac Processing module status changed 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
8cfb6f0bb3 Removed unnecessary arguments 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
ddcdc322f8 Moved save_dconf 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
4ee52f06d6 Added gpt status flags 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
603efc2deb Removed obsolete implementation 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
9fc5007590 Added registry saving to dconf in the backend 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
a6210f8b29 Removed obsolete implementation 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
175f244a5f Removed excess supply merge_polfile 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
0d4ce533bc Added flag for data status 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
8e22235df2 Adaptation of gsettings for new storage 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
0519d2703c Added handling of empty data 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
1ca9b006e1 Using the dconf registry 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
8cc5a8904b Added processing of various requests 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
70cdef2e71 Changed key request gsettings 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
3baffeb12d Changes to the data source in the registry 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
a0d9dc585f Removed erroneous addition of objects 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
388125415b Fixed directory functionality 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
14c7e5db21 Bugs fixed and return data wrapper added 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
582a85df88 Added explicit conversion to string 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
18ddc54626 Added processing of different types of keys 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
6bad9a331d Added the ability to query the Group Policy dictionary 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
16b5747620 Added checking the fullness of the global registry key dictionary 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
47015ec312 Added the ability to query a dictionary across multiple dconf paths 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
666c88bdf1 Added class method for getting dconf keys 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
bd5262353b Added semicolon handling when writing dconf 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
e1d5712b83 Added the ability to call methods through a class 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
bcb9108424 Refactor object initialization in init 2024-03-14 10:40:30 +04:00
Valery Sinelnikov
82bb88ca34 Added saving the preference to dconf 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
518685f361 Added to gpupdate.spec req_skip storage.dconf_registry 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
39e3d15fa8 Fixed formation of the general list of scripts 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
7a755bbb3e Added old storage functionality 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
41260df1a1 Added support for sqlite_registry API 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
0d1b60158a Added functions for verification and request in the dictionary 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
b244df8f2d Changed storage int 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
e48ca4fc8e Added staticmethod for update dconf 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
82d52d1c9f Added methods for mandatory_profile creation 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
e6a51d02fb Added functions get_uid_by_username 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
28e2d9c94b Added new fields to store preference 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
60137feed0 Added static methods to query dconf 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
a86c49e471 Added to the global_dict key ReadQueue and to able fill it 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
8c5d0bbb06 Use load_preg_dconf in merge_polfile 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
c26fbf8042 create_dconf_ini_file function moved 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
83e70d5e7a Added functions for filling the dictionary 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
c383b8df9b Added class to storing registry data for dconf 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
fc810c3362 Add create_ini_file function 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
7e225c837a Add touch_file function 2024-03-14 10:40:29 +04:00
Valery Sinelnikov
b053544512 0.9.13.9-alt1
- Fixed premature removal of double slash
2024-03-13 16:14:31 +04:00
Valery Sinelnikov
9b4527d334 Fixed premature removal of double slash 2024-03-13 16:13:26 +04:00
Valery Sinelnikov
3794ffa5be 0.9.13.8-alt1
- Added search for dc on the site
- Added compatibility support for the oldest versions of SQLAlchemy
2024-02-22 17:00:44 +04:00
Valery Sinelnikov
fe68f0cca8 Added use of new exception GetGPOListFail 2024-02-22 17:00:09 +04:00
Valery Sinelnikov
d83cf4d29d Added new exception GetGPOListFail 2024-02-21 14:57:22 +04:00
Valery Sinelnikov
47dc1df796 The way to find the desired DC is supplemented 2024-02-21 11:49:45 +04:00
Valery Sinelnikov
5d2fb3f719 Fixed search for the required domain 2024-02-20 15:31:32 +04:00
Evgeny Sinelnikov
3fded83c75 Support compatility for oldest versions of SQLAlchemy in storage 2024-02-20 13:00:36 +04:00
Valery Sinelnikov
aeab315c3d Improved search for the required domain 2024-02-20 12:59:49 +04:00
Valery Sinelnikov
446fa532db Added removal of extra slash 2024-02-19 11:51:34 +04:00
Valery Sinelnikov
ac2190809a Added a class for site domain search 2024-02-16 18:34:12 +04:00
45 changed files with 1188 additions and 157 deletions

22
completions/gpoa Normal file
View File

@@ -0,0 +1,22 @@
_gpoa()
{
local cur prev words cword split
_init_completion -s || return
case $prev in
--dc)
_filedir
return
;;
--loglevel)
COMPREPLY=($(compgen -W '0 1 2 3 4 5' -- "$cur"))
return
;;
*)
COMPREPLY=($(compgen -W '--dc --nodomain --noupdate --noplugins --list-backends --loglevel --help' -- "$cur"))
return
;;
esac
}
complete -F _gpoa gpoa

27
completions/gpupdate Normal file
View File

@@ -0,0 +1,27 @@
_gpupdate()
{
local cur prev words cword split
_init_completion -s || return
case $prev in
-u|--user)
_filedir
return
;;
-t|--target)
COMPREPLY=($(compgen -W 'ALL USER COMPUTER' -- "$cur"))
return
;;
-l|--loglevel)
COMPREPLY=($(compgen -W '0 1 2 3 4 5' -- "$cur"))
return
;;
*)
COMPREPLY=($(compgen -W '--user --target --loglevel --system --help' -- "$cur"))
return
;;
esac
}
complete -F _gpupdate gpupdate

View File

@@ -0,0 +1,18 @@
_gpupdate-setup()
{
local cur prev words cword split
_init_completion -s || return
case $prev in
set-backend)
COMPREPLY=($(compgen -W 'local samba' -- "$cur"))
return
;;
*)
COMPREPLY=($(compgen -W 'list list-backends status enable disable update write set-backend default-policy active-policy active-backend' -- "$cur"))
return
;;
esac
}
complete -F _gpupdate-setup gpupdate-setup

View File

@@ -22,6 +22,9 @@ from .samba_backend import samba_backend
from .nodomain_backend import nodomain_backend
from util.logging import log
from util.config import GPConfig
from util.util import get_uid_by_username, touch_file
from util.paths import get_dconf_config_path
from storage.dconf_registry import Dconf_registry, create_dconf_ini_file
def backend_factory(dc, username, is_machine, no_domain = False):
'''
@@ -59,3 +62,12 @@ def backend_factory(dc, username, is_machine, no_domain = False):
return back
def save_dconf(username, is_machine):
if is_machine:
uid = None
else:
uid = get_uid_by_username(username) if not is_machine else None
target_file = get_dconf_config_path(uid)
touch_file(target_file)
Dconf_registry.apply_template(uid)
create_dconf_ini_file(target_file,Dconf_registry.global_registry_dict)

View File

@@ -35,7 +35,7 @@ class nodomain_backend(applier_backend):
domain = None
machine_name = get_machine_name()
machine_sid = get_sid(domain, machine_name, True)
self.storage = registry_factory('registry')
self.storage = registry_factory()
self.storage.set_info('domain', domain)
self.storage.set_info('machine_name', machine_name)
self.storage.set_info('machine_sid', machine_sid)

View File

@@ -24,7 +24,7 @@ except ImportError:
from samba.gp.gpclass import check_safe_path
from .applier_backend import applier_backend
from storage import cache_factory, registry_factory
from storage import registry_factory
from gpt.gpt import gpt, get_local_gpt
from util.util import (
get_machine_name,
@@ -39,14 +39,15 @@ import util.preg
from util.logging import log
class samba_backend(applier_backend):
__user_policy_mode_key = 'Software\\Policies\\Microsoft\\Windows\\System\\UserPolicyMode'
__user_policy_mode_key = '/SOFTWARE/Policies/Microsoft/Windows/System/UserPolicyMode'
__user_policy_mode_key_win = '/Software/Policies/Microsoft/Windows/System/UserPolicyMode'
def __init__(self, sambacreds, username, domain, is_machine):
self.cache_path = '/var/cache/gpupdate/creds/krb5cc_{}'.format(os.getpid())
self.__kinit_successful = machine_kinit(self.cache_path)
if not self.__kinit_successful:
raise Exception('kinit is not successful')
self.storage = registry_factory('registry')
self.storage = registry_factory()
self.storage.set_info('domain', domain)
machine_name = get_machine_name()
machine_sid = get_sid(domain, machine_name, is_machine)
@@ -61,9 +62,6 @@ class samba_backend(applier_backend):
else:
self.sid = get_sid(self.storage.get_info('domain'), self.username)
self.cache = cache_factory('regpol_cache')
self.gpo_names = cache_factory('gpo_names')
# Samba objects - LoadParm() and CredentialsOptions()
self.sambacreds = sambacreds
@@ -81,9 +79,11 @@ class samba_backend(applier_backend):
is possible to work with user's part of GPT. This value is
checked only if working for user's SID.
'''
upm = self.storage.get_hklm_entry(self.__user_policy_mode_key)
if upm and upm.data:
upm = int(upm.data)
upm_key = self.storage.get_key_value(self.__user_policy_mode_key)
upm_win_key = self.storage.get_key_value(self.__user_policy_mode_key_win)
upm = upm_key if upm_key else upm_win_key
if upm:
upm = int(upm)
if upm < 0 or upm > 2:
upm = 0
else:
@@ -176,7 +176,16 @@ class samba_backend(applier_backend):
slogdata = dict({'sysvol_path': gpo.file_sys_path, 'gpo_name': gpo.display_name, 'gpo_path': path})
log('D30', slogdata)
gpt_abspath = os.path.join(self.cache_dir, 'gpo_cache', path)
obj = gpt(gpt_abspath, sid)
gpo_version=None
try:
gpo_version=gpo.version
except:
log('D210')
if self._is_machine_username:
obj = gpt(gpt_abspath, sid, None, version=gpo_version)
else:
obj = gpt(gpt_abspath, sid, self.username, version=gpo_version)
obj.set_name(gpo.display_name)
gpts.append(obj)
else:

View File

@@ -18,43 +18,42 @@
from abc import ABC
import logging
from util.logging import slogm
from util.logging import log
def check_experimental_enabled(storage):
experimental_enable_flag = 'Software\\BaseALT\\Policies\\GPUpdate\\GlobalExperimental'
flag = storage.get_hklm_entry(experimental_enable_flag)
experimental_enable_flag = '/Software/BaseALT/Policies/GPUpdate/GlobalExperimental'
flag = storage.get_key_value(experimental_enable_flag)
result = False
if flag and '1' == flag.data:
if flag and '1' == str(flag):
result = True
return result
def check_windows_mapping_enabled(storage):
windows_mapping_enable_flag = 'Software\\BaseALT\\Policies\\GPUpdate\\WindowsPoliciesMapping'
flag = storage.get_hklm_entry(windows_mapping_enable_flag)
windows_mapping_enable_flag = '/Software/BaseALT/Policies/GPUpdate/WindowsPoliciesMapping'
flag = storage.get_key_value(windows_mapping_enable_flag)
result = True
if flag and '0' == flag.data:
flag = str(flag)
if flag and '0' == flag:
result = False
return result
def check_module_enabled(storage, module_name):
gpupdate_module_enable_branch = 'Software\\BaseALT\\Policies\\GPUpdate'
gpupdate_module_flag = '{}\\{}'.format(gpupdate_module_enable_branch, module_name)
flag = storage.get_hklm_entry(gpupdate_module_flag)
gpupdate_module_enable_branch = '/Software/BaseALT/Policies/GPUpdate'
gpupdate_module_flag = '{}/{}'.format(gpupdate_module_enable_branch, module_name)
flag = storage.get_key_value(gpupdate_module_flag)
result = None
flag = str(flag)
if flag:
if '1' == flag.data:
if '1' == flag:
result = True
if '0' == flag.data:
result = False
else:
result = False
return result

View File

@@ -92,6 +92,8 @@ class Envvar:
value = value.replace('\\', '/')
exist_line = None
for line in lines:
if line == '\n':
continue
if line.split()[0] == name:
exist_line = line
break

View File

@@ -44,14 +44,16 @@ def remove_dir_tree(path, delete_files=False, delete_folder=False, delete_sub_fo
return content
def str2bool(boolstr):
if boolstr and boolstr.lower() in ['true', 'yes', '1']:
if isinstance(boolstr, bool):
return boolstr
elif boolstr and boolstr.lower() in ['true', 'yes', '1']:
return True
return False
class Folder:
def __init__(self, folder_object, username=None):
folder_path = expand_windows_var(folder_object.path, username).replace('\\', '/')
folder_path = expand_windows_var(folder_object.path, username).replace('\\', '/').replace('//', '/')
if username:
folder_path = folder_path.replace(get_homedir(username), '')
self.folder_path = Path(get_homedir(username)).joinpath(folder_path if folder_path [0] != '/' else folder_path [1:])

View File

@@ -30,7 +30,7 @@ class chromium_applier(applier_frontend):
__module_name = 'ChromiumApplier'
__module_enabled = True
__module_experimental = False
__registry_branch = 'Software\\Policies\\Google\\Chrome'
__registry_branch = 'Software/Policies/Google/Chrome'
__managed_policies_path = '/etc/chromium/policies/managed'
__recommended_policies_path = '/etc/chromium/policies/recommended'
@@ -168,7 +168,7 @@ class chromium_applier(applier_frontend):
'''
Parse registry path string and leave key parameters
'''
parts = hivekeyname.replace(self.__registry_branch, '').split('\\')
parts = hivekeyname.replace(self.__registry_branch, '').split('/')
return parts

View File

@@ -222,7 +222,7 @@ class cifs_applier_user(applier_frontend):
def check_enable_home_link(self, enable_home_link):
if self.storage.get_hkcu_entry(self.sid, enable_home_link):
data = self.storage.get_hkcu_entry(self.sid, enable_home_link).data
return bool(int(data))
return bool(int(data)) if data else None
else:
return False

View File

@@ -29,11 +29,11 @@ class control_applier(applier_frontend):
__module_name = 'ControlApplier'
__module_experimental = False
__module_enabled = True
_registry_branch = 'Software\\BaseALT\\Policies\\Control'
_registry_branch = 'Software/BaseALT/Policies/Control'
def __init__(self, storage):
self.storage = storage
self.control_settings = self.storage.filter_hklm_entries('Software\\BaseALT\\Policies\\Control%')
self.control_settings = self.storage.filter_hklm_entries(self._registry_branch)
self.controls = list()
self.__module_enabled = check_enabled(
self.storage
@@ -43,7 +43,7 @@ class control_applier(applier_frontend):
def run(self):
for setting in self.control_settings:
valuename = setting.hive_key.rpartition('\\')[2]
valuename = setting.hive_key.rpartition('/')[2]
try:
self.controls.append(control(valuename, int(setting.data)))
logdata = dict()

View File

@@ -33,13 +33,13 @@ from .applier_frontend import (
, check_enabled
)
from util.logging import log
from util.util import is_machine_name
from util.util import is_machine_name, try_dict_to_literal_eval
class firefox_applier(applier_frontend):
__module_name = 'FirefoxApplier'
__module_experimental = False
__module_enabled = True
__registry_branch = 'Software\\Policies\\Mozilla\\Firefox\\'
__registry_branch = 'Software/Policies/Mozilla/Firefox'
__firefox_installdir1 = '/usr/lib64/firefox/distribution'
__firefox_installdir2 = '/etc/firefox/policies'
@@ -69,7 +69,7 @@ class firefox_applier(applier_frontend):
'''
Parse registry path string and leave key parameters
'''
parts = hivekeyname.replace(self.__registry_branch, '').split('\\')
parts = hivekeyname.replace(self.__registry_branch, '').split('/')
return parts
def create_dict(self, firefox_keys):
@@ -83,6 +83,10 @@ class firefox_applier(applier_frontend):
try:
if type(it_data.data) is bytes:
it_data.data = it_data.data.decode(encoding='utf-16').replace('\x00','')
json_data = try_dict_to_literal_eval(it_data.data)
if json_data:
it_data.data = json_data
it_data.type = 7
#Cases when it is necessary to create nested dictionaries
if it_data.valuename != it_data.data:
parts = self.get_parts(it_data.hive_key)
@@ -95,6 +99,8 @@ class firefox_applier(applier_frontend):
branch[parts[-1]] = int(it_data.data)
else:
branch[parts[-1]] = self.get_boolean(it_data.data)
elif it_data.type == 7:
branch[parts[-1]] = it_data.data
else:
branch[parts[-1]] = str(it_data.data).replace('\\', '/')
#Cases when it is necessary to create lists in a dictionary
@@ -164,6 +170,9 @@ def dict_item_to_list(dictionary:dict) -> dict:
'''
Replacing dictionaries with numeric keys with a List
'''
if '' in dictionary:
dictionary = dictionary.pop('')
for key,val in dictionary.items():
if type(val) == dict:
if key_dict_is_digit(val):

View File

@@ -128,8 +128,8 @@ class frontend_manager:
'''
def __init__(self, username, is_machine):
self.storage = registry_factory('registry')
self.username = determine_username(username)
self.storage = registry_factory('dconf', username=self.username)
self.is_machine = is_machine
self.process_uname = get_process_user()
self.sid = get_sid(self.storage.get_info('domain'), self.username, is_machine)

View File

@@ -59,14 +59,14 @@ class gsettings_applier(applier_frontend):
__module_name = 'GSettingsApplier'
__module_experimental = False
__module_enabled = True
__registry_branch = 'Software\\BaseALT\\Policies\\GSettings\\'
__registry_branch = 'Software\\BaseALT\\Policies\\gsettings\\'
__registry_locks_branch = 'Software\\BaseALT\\Policies\\GSettingsLocks\\'
__wallpaper_entry = 'Software\\BaseALT\\Policies\\GSettings\\org.mate.background.picture-filename'
__vino_authentication_methods_entry = 'Software\\BaseALT\\Policies\\GSettings\\org.gnome.Vino.authentication-methods'
__wallpaper_entry = 'Software/BaseALT/Policies/gsettings/org.mate.background.picture-filename'
__vino_authentication_methods_entry = 'Software/BaseALT/Policies/gsettings/org.gnome.Vino.authentication-methods'
__global_schema = '/usr/share/glib-2.0/schemas'
__override_priority_file = 'zzz_policy.gschema.override'
__override_old_file = '0_policy.gschema.override'
__windows_settings = dict()
def __init__(self, storage, file_cache):
self.storage = storage
@@ -108,13 +108,13 @@ class gsettings_applier(applier_frontend):
# Get all configured gsettings locks
for lock in self.gsettings_locks:
valuename = lock.hive_key.rpartition('\\')[2]
valuename = lock.hive_key.rpartition('/')[2]
self.locks[valuename] = int(lock.data)
# Calculate all configured gsettings
for setting in self.gsettings_keys:
helper = None
valuename = setting.hive_key.rpartition('\\')[2]
valuename = setting.hive_key.rpartition('/')[2]
rp = valuename.rpartition('.')
schema = rp[0]
path = rp[2]
@@ -184,9 +184,9 @@ class gsettings_applier_user(applier_frontend):
__module_name = 'GSettingsApplierUser'
__module_experimental = False
__module_enabled = True
__registry_branch = 'Software\\BaseALT\\Policies\\GSettings\\'
__wallpaper_entry = 'Software\\BaseALT\\Policies\\GSettings\\org.mate.background.picture-filename'
__vino_authentication_methods_entry = 'Software\\BaseALT\\Policies\\GSettings\\org.gnome.Vino.authentication-methods'
__registry_branch = 'Software\\BaseALT\\Policies\\gsettings\\'
__wallpaper_entry = 'Software/BaseALT/Policies/gsettings/org.mate.background.picture-filename'
__vino_authentication_methods_entry = 'Software/BaseALT/Policies/gsettings/org.gnome.Vino.authentication-methods'
def __init__(self, storage, file_cache, sid, username):
self.storage = storage
@@ -204,25 +204,25 @@ class gsettings_applier_user(applier_frontend):
mapping = [
# Disable or enable screen saver
GSettingsMapping(
'Software\\Policies\\Microsoft\\Windows\\Control Panel\\Desktop\\ScreenSaveActive'
'Software/Policies/Microsoft/Windows/Control Panel/Desktop/ScreenSaveActive'
, 'org.mate.screensaver'
, 'idle-activation-enabled'
)
# Timeout in seconds for screen saver activation. The value of zero effectively disables screensaver start
, GSettingsMapping(
'Software\\Policies\\Microsoft\\Windows\\Control Panel\\Desktop\\ScreenSaveTimeOut'
'Software/Policies/Microsoft/Windows/Control Panel/Desktop/ScreenSaveTimeOut'
, 'org.mate.session'
, 'idle-delay'
)
# Enable or disable password protection for screen saver
, GSettingsMapping(
'Software\\Policies\\Microsoft\\Windows\\Control Panel\\Desktop\\ScreenSaverIsSecure'
'Software/Policies/Microsoft/Windows/Control Panel/Desktop/ScreenSaverIsSecure'
, 'org.mate.screensaver'
, 'lock-enabled'
)
# Specify image which will be used as a wallpaper
, GSettingsMapping(
'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\Wallpaper'
'Software/Microsoft/Windows/CurrentVersion/Policies/System/Wallpaper'
, 'org.mate.background'
, 'picture-filename'
)
@@ -251,15 +251,6 @@ class gsettings_applier_user(applier_frontend):
return uri_fetch(schema, path, value, self.file_cache)
def run(self):
#for setting in self.gsettings_keys:
# valuename = setting.hive_key.rpartition('\\')[2]
# rp = valuename.rpartition('.')
# schema = rp[0]
# path = rp[2]
# self.gsettings.append(user_gsetting(schema, path, setting.data))
# Calculate all mapped gsettings if mapping enabled
if self.__windows_mapping_enabled:
log('D83')
self.windows_mapping_append()
@@ -268,7 +259,7 @@ class gsettings_applier_user(applier_frontend):
# Calculate all configured gsettings
for setting in self.gsettings_keys:
valuename = setting.hive_key.rpartition('\\')[2]
valuename = setting.hive_key.rpartition('/')[2]
rp = valuename.rpartition('.')
schema = rp[0]
path = rp[2]
@@ -293,7 +284,7 @@ class gsettings_applier_user(applier_frontend):
try:
entry = self.__wallpaper_entry
filter_result = self.storage.get_hkcu_entry(self.sid, entry)
if filter_result:
if filter_result and filter_result.data:
self.file_cache.store(filter_result.data)
except NotUNCPathError:
...

View File

@@ -1,7 +1,7 @@
#
# GPOA - GPO Applier for Linux
#
# Copyright (C) 2019-2023 BaseALT Ltd.
# Copyright (C) 2019-2024 BaseALT Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -101,7 +101,7 @@ def create_dict(kde_settings, all_kde_settings, locks_settings, locks_dict, file
locks_dict[locks.valuename] = locks.data
for setting in kde_settings:
try:
file_name, section, value = setting.keyname.split("\\")[-2], setting.keyname.split("\\")[-1], setting.valuename
file_name, section, value = setting.keyname.split("/")[-2], setting.keyname.split("/")[-1], setting.valuename
data = setting.data
if file_name == 'wallpaper':
apply_for_wallpaper(data, file_cache, username)
@@ -124,17 +124,31 @@ def create_dict(kde_settings, all_kde_settings, locks_settings, locks_dict, file
def apply(all_kde_settings, locks_dict, username = None):
logdata = dict()
if username is None:
system_path_settings = '/etc/xdg/'
system_files = [
"baloofilerc",
"kcminputrc",
"kded_device_automounterrc",
"kdeglobals",
"ksplashrc",
"kwinrc",
"plasma-localerc",
"plasmarc",
"powermanagementprofilesrc"
]
for file in system_files:
file_to_remove = f'{system_path_settings}{file}'
if os.path.exists(file_to_remove):
os.remove(file_to_remove)
for file_name, sections in all_kde_settings.items():
file_path = f'/etc/xdg/{file_name}'
if os.path.exists(file_path):
os.remove(file_path)
file_path = f'{system_path_settings}{file_name}'
with open(file_path, 'w') as file:
for section, keys in sections.items():
section = section.replace(')(', '][')
file.write(f'[{section}]\n')
for key, value in keys.items():
lock = f"{file_name}.{section}.{key}".replace('][', ')(')
if lock in locks_dict and locks_dict[lock] == '1':
if lock in locks_dict and locks_dict[lock] == 1:
file.write(f'{key}[$i]={value}\n')
else:
file.write(f'{key}={value}\n')
@@ -149,7 +163,7 @@ def apply(all_kde_settings, locks_dict, username = None):
for section, keys in sections.items():
for key, value in keys.items():
lock = f"{file_name}.{section}.{key}"
if lock in locks_dict and locks_dict[lock] == '1':
if lock in locks_dict and locks_dict[lock] == 1:
command = [
'kwriteconfig5',
'--file', file_name,
@@ -275,4 +289,4 @@ def get_id_desktop(path_to_wallpaper):
else:
return None
except:
return None
return None

View File

@@ -62,8 +62,7 @@ class package_applier(applier_frontend):
)
def run(self):
for flag in self.sync_packages_setting:
if flag.data:
self.flagSync = bool(int(flag.data))
self.flagSync = bool(flag.data)
if 0 < self.install_packages_setting.count() or 0 < self.remove_packages_setting.count():
if self.flagSync:
@@ -104,8 +103,8 @@ class package_applier_user(applier_frontend):
self.username = username
self.fulcmd = list()
self.fulcmd.append('/usr/libexec/gpupdate/pkcon_runner')
self.fulcmd.append('--sid')
self.fulcmd.append(self.sid)
self.fulcmd.append('--user')
self.fulcmd.append(self.username)
self.fulcmd.append('--loglevel')
logger = logging.getLogger()
self.fulcmd.append(str(logger.level))
@@ -119,7 +118,7 @@ class package_applier_user(applier_frontend):
self.sync_packages_setting = self.storage.filter_hkcu_entries(self.sid, sync_branch)
self.flagSync = False
self.__module_enabled = check_enabled(self.storage, self.__module_name, self.__module_enabled)
self.__module_enabled = check_enabled(self.storage, self.__module_name, self.__module_experimental)
def user_context_apply(self):
'''

View File

@@ -26,8 +26,8 @@ from util.logging import log
class polkit_applier(applier_frontend):
__module_name = 'PolkitApplier'
__module_experimental = True
__module_enabled = False
__module_experimental = False
__module_enabled = True
__deny_all_win = 'Software\\Policies\\Microsoft\\Windows\\RemovableStorageDevices\\Deny_All'
__registry_branch = 'Software\\BaseALT\\Policies\\Polkit\\'
__registry_locks_branch = 'Software\\BaseALT\\Policies\\PolkitLocks\\'
@@ -106,8 +106,8 @@ class polkit_applier(applier_frontend):
class polkit_applier_user(applier_frontend):
__module_name = 'PolkitApplierUser'
__module_experimental = True
__module_enabled = False
__module_experimental = False
__module_enabled = True
__deny_all_win = 'Software\\Policies\\Microsoft\\Windows\\RemovableStorageDevices\\Deny_All'
__registry_branch = 'Software\\BaseALT\\Policies\\Polkit\\'
__polkit_map = {

View File

@@ -148,10 +148,10 @@ def install_script(storage_script_entry, script_dir, access_permissions):
shutil.copyfile(storage_script_entry.path, script_file)
os.chmod(script_file, int(access_permissions, base = 8))
if storage_script_entry.arg:
if storage_script_entry.args:
dir_path = script_dir + '/' + script_name + '.arg'
dir_arg = Path(dir_path)
dir_arg.mkdir(parents=True, exist_ok=True)
file_arg = open(dir_path + '/arg', 'w')
file_arg.write(storage_script_entry.arg)
file_arg.write(storage_script_entry.args)
file_arg.close()

View File

@@ -38,8 +38,7 @@ def storage_get_shortcuts(storage, sid, username=None):
shortcut_objs = storage.get_shortcuts(sid)
shortcuts = list()
for sc_obj in shortcut_objs:
sc = json2sc(sc_obj.shortcut)
for sc in shortcut_objs:
if username:
sc.set_expanded_path(expand_windows_var(sc.path, username))
shortcuts.append(sc)

View File

@@ -29,11 +29,11 @@ class systemd_applier(applier_frontend):
__module_name = 'SystemdApplier'
__module_experimental = False
__module_enabled = True
__registry_branch = 'Software\\BaseALT\\Policies\\SystemdUnits'
__registry_branch = 'Software/BaseALT/Policies/SystemdUnits'
def __init__(self, storage):
self.storage = storage
self.systemd_unit_settings = self.storage.filter_hklm_entries('Software\\BaseALT\\Policies\\SystemdUnits%')
self.systemd_unit_settings = self.storage.filter_hklm_entries(self.__registry_branch)
self.units = []
self.__module_enabled = check_enabled(
self.storage
@@ -43,7 +43,7 @@ class systemd_applier(applier_frontend):
def run(self):
for setting in self.systemd_unit_settings:
valuename = setting.hive_key.rpartition('\\')[2]
valuename = setting.hive_key.rpartition('/')[2]
try:
self.units.append(systemd_unit(valuename, int(setting.data)))
logdata = dict()
@@ -76,7 +76,7 @@ class systemd_applier_user(applier_frontend):
__module_name = 'SystemdApplierUser'
__module_experimental = False
__module_enabled = True
__registry_branch = 'Software\\BaseALT\\Policies\\SystemdUnits'
__registry_branch = 'Software/BaseALT/Policies/SystemdUnits'
def __init__(self, storage, sid, username):
self.storage = storage

View File

@@ -30,7 +30,7 @@ class yandex_browser_applier(applier_frontend):
__module_name = 'YandexBrowserApplier'
__module_enabled = True
__module_experimental = False
__registry_branch = 'Software\\Policies\\YandexBrowser'
__registry_branch = 'Software/Policies/YandexBrowser'
__managed_policies_path = '/etc/opt/yandex/browser/policies/managed'
__recommended_policies_path = '/etc/opt/yandex/browser/policies/recommended'
@@ -152,7 +152,7 @@ class yandex_browser_applier(applier_frontend):
'''
Parse registry path string and leave key parameters
'''
parts = hivekeyname.replace(self.__registry_branch, '').split('\\')
parts = hivekeyname.replace(self.__registry_branch, '').split('/')
return parts

View File

@@ -23,7 +23,7 @@ import signal
import gettext
import locale
from backend import backend_factory
from backend import backend_factory, save_dconf
from frontend.frontend_manager import frontend_manager, determine_username
from plugin import plugin_manager
from messages import message_with_code
@@ -159,6 +159,7 @@ class gpoa_controller:
einfo = geterr()
logdata.update(einfo)
log('E3', logdata)
save_dconf(self.username, self.is_machine)
def start_frontend(self):
'''

View File

@@ -70,6 +70,7 @@ def read_folders(folders_file):
folders.append(fld_obj)
return folders
def merge_folders(storage, sid, folder_objects, policy_name):

View File

@@ -153,10 +153,13 @@ def get_merger(preference_type):
return mergers[preference_type]
class gpt:
def __init__(self, gpt_path, sid):
def __init__(self, gpt_path, sid, username='Machine', version=None):
self.path = gpt_path
self.username = username
self.sid = sid
self.storage = registry_factory('registry')
self.storage = registry_factory()
self.storage._gpt_read_flag = True
self.version = version
self.name = ''
self.guid = self.path.rpartition('/')[2]
if 'default' == self.guid:
@@ -214,7 +217,7 @@ class gpt:
if self.settings['machine']['regpol']:
mlogdata = dict({'polfile': self.settings['machine']['regpol']})
log('D34', mlogdata)
util.preg.merge_polfile(self.settings['machine']['regpol'], policy_name=self.name)
util.preg.merge_polfile(self.settings['machine']['regpol'], policy_name=self.name, version=self.version)
# Merge machine preferences to registry if possible
for preference_name, preference_path in self.settings['machine'].items():
if preference_path:
@@ -240,7 +243,11 @@ class gpt:
if self.settings['user']['regpol']:
mulogdata = dict({'polfile': self.settings['user']['regpol']})
log('D35', mulogdata)
util.preg.merge_polfile(self.settings['user']['regpol'], sid=self.sid, policy_name=self.name)
util.preg.merge_polfile(self.settings['user']['regpol'],
sid=self.sid,
policy_name=self.name,
username=self.username,
version=self.version)
# Merge user preferences to registry if possible
for preference_name, preference_path in self.settings['user'].items():
if preference_path:

View File

@@ -17,6 +17,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from util.xml import get_xml_root
from storage.dconf_registry import Dconf_registry
def read_networkshares(networksharesxml):
networkshares = list()

View File

@@ -24,9 +24,10 @@ def read_polfile(filename):
return load_preg(filename).entries
def merge_polfile(storage, sid, policy_objects, policy_name):
for entry in policy_objects:
if not sid:
storage.add_hklm_entry(entry, policy_name)
else:
storage.add_hkcu_entry(entry, sid, policy_name)
pass
# for entry in policy_objects:
# if not sid:
# storage.add_hklm_entry(entry, policy_name)
# else:
# storage.add_hkcu_entry(entry, sid, policy_name)

View File

@@ -61,19 +61,19 @@ def read_scripts(scripts_file):
section_scripts[key_index].set_args(config[act][key])
if logon_scripts:
for i in sorted(logon_scripts.keys()):
scripts.add_script(act_upper, logon_scripts[i])
scripts.add_script('LOGON', logon_scripts[i])
if logoff_scripts:
for i in sorted(logoff_scripts.keys()):
scripts.add_script(act_upper, logoff_scripts[i])
scripts.add_script('LOGOFF', logoff_scripts[i])
if startup_scripts:
for i in sorted(startup_scripts.keys()):
scripts.add_script(act_upper, startup_scripts[i])
scripts.add_script('STARTUP', startup_scripts[i])
if shutdown_scripts:
for i in sorted(shutdown_scripts.keys()):
scripts.add_script(act_upper, shutdown_scripts[i])
scripts.add_script('SHUTDOWN', shutdown_scripts[i])
return scripts

View File

@@ -27,6 +27,7 @@ import json
from util.windows import transform_windows_path
from util.xml import get_xml_root
from util.paths import get_desktop_files_directory
class TargetType(Enum):
FILESYSTEM = 'FILESYSTEM'
@@ -115,6 +116,19 @@ def json2sc(json_str):
return sc
def find_desktop_entry(binary_path):
desktop_dir = get_desktop_files_directory()
binary_name = ''.join(binary_path.split('/')[-1])
desktop_file_path = Path(f"{desktop_dir}/{binary_name}.desktop")
if desktop_file_path.exists():
desktop_entry = DesktopEntry()
desktop_entry.parse(desktop_file_path)
return desktop_entry
return None
class shortcut:
def __init__(self, dest, path, arguments, name=None, action=None, ttype=TargetType.FILESYSTEM):
'''
@@ -135,6 +149,7 @@ class shortcut:
self.comment = ''
self.is_in_user_context = self.set_usercontext()
self.type = ttype
self.desktop_file_template = None
def replace_slashes(self, input_path):
if input_path.startswith('%'):
@@ -233,6 +248,7 @@ class shortcut:
if dest:
self.desktop_file = DesktopEntry(dest)
else:
self.desktop_file_template = find_desktop_entry(self.path)
self.desktop_file = DesktopEntry()
self.desktop_file.addGroup('Desktop Entry')
self.desktop_file.set('Version', '1.0')
@@ -257,12 +273,18 @@ class shortcut:
if self.type == TargetType.URL:
self.desktop_file.set('URL', desktop_path)
else:
self.desktop_file.set('Terminal', 'false')
str2bool_lambda = (lambda boolstr: boolstr if isinstance(boolstr, bool)
else boolstr and boolstr.lower() in ['True', 'true', 'yes', '1'])
if self.desktop_file_template:
terminal_state = str2bool_lambda(self.desktop_file_template.get('Terminal'))
self.desktop_file.set('Terminal', 'true' if terminal_state else 'false')
self.desktop_file.set('Exec', '{} {}'.format(desktop_path, self.arguments))
self.desktop_file.set('Comment', self.comment)
if self.icon:
self.desktop_file.set('Icon', self.icon)
elif self.desktop_file_template and self.desktop_file_template.get('Icon', False):
self.desktop_file.set('Icon', self.desktop_file_template.get('Icon'))
def _write_desktop(self, dest, create_only=False, read_firstly=False):
'''

View File

@@ -240,6 +240,18 @@ msgstr "Ошибка создания переменных среды"
msgid "Error running kwriteconfig5 command"
msgstr "Ошибка выполнения команды kwriteconfig5"
msgid "Error getting list of keys"
msgstr "Ошибка получения списка ключей"
msgid "Error getting key value"
msgstr "Ошибка при получении значения ключей"
msgid "Failed to update dconf database"
msgstr "Не удалось обновить базу данных dconf"
msgid "Exception occurred while updating dconf database"
msgstr "Возникло исключение при обновлении базы данных dconf"
# Error_end
# Debug
@@ -837,6 +849,27 @@ msgstr "Изменение конфигурационного файла"
msgid "Widget command completed successfully"
msgstr "Команда для виджетов выполнена успешно"
msgid "Getting a list of keys"
msgstr "Получение списка ключей"
msgid "Getting the key value"
msgstr "Получение значения ключа"
msgid "Successfully updated dconf database"
msgstr "База данных dconf успешно обновлена"
msgid "Creating a dictionary with keys and values from the dconf database"
msgstr "Формирование словаря с ключами и значениями из базы dconf"
msgid "No entry found for the specified path"
msgstr "Не найдено записей по указанному пути"
msgid "Creating an ini file with policies for dconf"
msgstr "Создание ini-файла с политиками для dconf"
msgid "GPO version was not found"
msgstr "Версия GPO не найдена"
# Debug_end
# Warning
@@ -904,12 +937,15 @@ msgstr "Ошибка при подключении к серверу"
msgid "Wallpaper configuration file not found"
msgstr "Конфигурационный файл для обоев не найден"
msgid "The user setting was not installed, conflict with computer setting."
msgstr "Пользовательская настройка не была установлена, конфликт с настройкой компьютера."
msgid "The user setting was not installed, conflict with computer setting"
msgstr "Пользовательская настройка не была установлена, конфликт с настройкой компьютера"
msgid "Action for ini file failed"
msgstr "Не удалось выполнить действие для INI-файла"
msgid "Couldn't get the uid"
msgstr "Не удалось получить uid"
# Fatal
msgid "Unable to refresh GPO list"
msgstr "Невозможно обновить список объектов групповых политик"

View File

@@ -103,6 +103,10 @@ def error_code(code):
error_ids[66] = 'Error while executing command for widgets'
error_ids[67] = 'Error creating environment variables'
error_ids[68] = 'Error running kwriteconfig5 command'
error_ids[69] = 'Error getting list of keys'
error_ids[70] = 'Error getting key value'
error_ids[71] = 'Failed to update dconf database'
error_ids[72] = 'Exception occurred while updating dconf database'
return error_ids.get(code, 'Unknown error code')
def debug_code(code):
@@ -310,6 +314,14 @@ def debug_code(code):
debug_ids[201] = 'KDE applier for user in user context will not be started'
debug_ids[202] = 'Changing the configuration file'
debug_ids[203] = 'Widget command completed successfully'
debug_ids[204] = 'Getting a list of keys'
debug_ids[205] = 'Getting the key value'
debug_ids[206] = 'Successfully updated dconf database'
debug_ids[207] = 'Creating a dictionary with keys and values from the dconf database'
debug_ids[208] = 'No entry found for the specified path'
debug_ids[209] = 'Creating an ini file with policies for dconf'
debug_ids[210] = 'GPO version was not found'
return debug_ids.get(code, 'Unknown debug code')
def warning_code(code):
@@ -341,8 +353,9 @@ def warning_code(code):
warning_ids[19] = 'Failed to change KDE configuration file'
warning_ids[20] = 'Error connecting to server'
warning_ids[21] = 'Wallpaper configuration file not found'
warning_ids[22] = 'The user setting was not installed, conflict with computer setting.'
warning_ids[22] = 'The user setting was not installed, conflict with computer setting'
warning_ids[23] = 'Action for ini file failed'
warning_ids[24] = 'Couldn\'t get the uid'
return warning_ids.get(code, 'Unknown warning code')

View File

@@ -44,27 +44,21 @@ def is_rpm_installed(rpm_name):
class Pkcon_applier:
def __init__(self, sid = None):
def __init__(self, user = None):
self.__install_key_name = 'Install'
self.__remove_key_name = 'Remove'
self.__hkcu_branch = 'Software\\BaseALT\\Policies\\Packages'
self.__hklm_branch = 'Software\\BaseALT\\Policies\\Packages'
self.__hklm_branch = '/Software/BaseALT/Policies/Packages'
self.__install_command = ['/usr/bin/pkcon', '-y', 'install']
self.__remove_command = ['/usr/bin/pkcon', '-y', 'remove']
self.__reinstall_command = ['/usr/bin/pkcon', '-y', 'reinstall']
self.install_packages = set()
self.remove_packages = set()
self.storage = registry_factory('registry')
if sid:
install_branch_user = '{}\\{}%'.format(self.__hkcu_branch, self.__install_key_name)
remove_branch_user = '{}\\{}%'.format(self.__hkcu_branch, self.__remove_key_name)
self.install_packages_setting = self.storage.filter_hkcu_entries(sid, install_branch_user)
self.remove_packages_setting = self.storage.filter_hkcu_entries(sid, remove_branch_user)
else:
install_branch = '{}\\{}%'.format(self.__hklm_branch, self.__install_key_name)
remove_branch = '{}\\{}%'.format(self.__hklm_branch, self.__remove_key_name)
self.install_packages_setting = self.storage.filter_hklm_entries(install_branch)
self.remove_packages_setting = self.storage.filter_hklm_entries(remove_branch)
self.storage = registry_factory(username=user)
self.storage.filling_storage_from_dconf()
install_branch = '{}/{}'.format(self.__hklm_branch, self.__install_key_name)
remove_branch = '{}/{}'.format(self.__hklm_branch, self.__remove_key_name)
self.install_packages_setting = self.storage.filter_hklm_entries(install_branch)
self.remove_packages_setting = self.storage.filter_hklm_entries(remove_branch)
for package in self.install_packages_setting:
if not is_rpm_installed(package.data):
self.install_packages.add(package.data)
@@ -137,13 +131,13 @@ if __name__ == '__main__':
gettext.textdomain('gpoa')
logger = logging.getLogger()
parser = argparse.ArgumentParser(description='Package applier')
parser.add_argument('--sid', type = str, help = 'sid', nargs = '?', default = None)
parser.add_argument('--user', type = str, help = 'user', nargs = '?', default = None)
parser.add_argument('--loglevel', type = int, help = 'loglevel', nargs = '?', default = 30)
args = parser.parse_args()
logger.setLevel(args.loglevel)
if args.sid:
applier = Pkcon_applier(args.sid)
if args.user:
applier = Pkcon_applier(args.user)
else:
applier = Pkcon_applier()
applier.apply()

View File

@@ -21,6 +21,8 @@ import subprocess
import argparse
import os
from pathlib import Path
import psutil
import time
class Scripts_runner:
'''
@@ -104,12 +106,39 @@ class Scripts_runner:
def run_cmd_subprocess(self, cmd):
try:
subprocess.Popen(cmd)
subprocess.run(cmd)
return 'Script run: {}'.format(cmd)
except Exception as exc:
return exc
def find_process_by_name_and_script(name, script_path):
for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
try:
# Check if the process name matches and the script path is in the command line arguments
if proc.info['name'] == name and script_path in proc.info['cmdline']:
return proc
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
continue
return None
def wait_for_process(name, script_path, check_interval=1):
process = find_process_by_name_and_script(name, script_path)
if not process:
print(f"Process with name {name} and script path {script_path} not found.")
return
try:
# Loop to wait for the process to finish
while process.is_running():
print(f"Waiting for process {name} with PID {process.pid} to finish...")
time.sleep(check_interval)
print(f"Process {name} with PID {process.pid} has finished.")
return
except (psutil.NoSuchProcess, psutil.AccessDenied):
print(f"Process {name} with PID {process.pid} is no longer accessible.")
return
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Scripts runner')
@@ -117,6 +146,9 @@ if __name__ == '__main__':
parser.add_argument('--user', type = str, help = 'User name ', nargs = '?', default = None)
parser.add_argument('--action', type = str, help = 'MACHINE : [STARTUP or SHUTDOWN], USER : [LOGON or LOGOFF]', nargs = '?', default = None)
process_name = "python3"
script_path = "/usr/sbin/gpoa"
wait_for_process(process_name, script_path)
args = parser.parse_args()
try:
Scripts_runner(args.mode, args.user, args.action)

View File

@@ -1,7 +1,7 @@
#
# GPOA - GPO Applier for Linux
#
# Copyright (C) 2019-2020 BaseALT Ltd.
# Copyright (C) 2019-2023 BaseALT Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,12 +16,19 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .sqlite_registry import sqlite_registry
from .sqlite_cache import sqlite_cache
def cache_factory(cache_name):
return sqlite_cache(cache_name)
from storage.dconf_registry import Dconf_registry
def registry_factory(registry_name='registry', registry_dir=None):
return sqlite_registry(registry_name, registry_dir)
def registry_factory(registry_name='', envprofile=None , username=None):
if username:
Dconf_registry._username = username
else:
Dconf_registry._envprofile = 'system'
if envprofile:
Dconf_registry._envprofile = envprofile
if registry_name == 'dconf':
return Dconf_registry()
else:
return Dconf_registry

View File

@@ -0,0 +1,591 @@
#
# GPOA - GPO Applier for Linux
#
# Copyright (C) 2019-2023 BaseALT Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import subprocess
from pathlib import Path
from util.util import string_to_literal_eval, touch_file, get_uid_by_username
from util.logging import log
import re
class PregDconf():
def __init__(self, keyname, valuename, type_preg, data):
self.keyname = keyname
self.valuename = valuename
self.hive_key = '{}/{}'.format(self.keyname, self.valuename)
self.type = type_preg
self.data = data
class gplist(list):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def first(self):
if self:
return self[0]
else:
return None
def count(self):
return len(self)
class Dconf_registry():
'''
A class variable that represents a global registry dictionary shared among instances of the class
'''
_ReadQueue = 'Software/BaseALT/Policies/ReadQueue'
global_registry_dict = dict({_ReadQueue:{}})
__template_file = '/usr/share/dconf/user_mandatory.template'
_policies_path = 'Software/'
_policies_win_path = 'SOFTWARE/'
_gpt_read_flag = False
__dconf_dict_flag = False
__dconf_dict = dict()
_username = None
_envprofile = None
list_keys = list()
_info = dict()
shortcuts = list()
folders = list()
files = list()
drives = list()
scheduledtasks = list()
environmentvariables = list()
inifiles = list()
services = list()
printers = list()
scripts = list()
networkshares = list()
@classmethod
def set_info(cls, key , data):
cls._info[key] = data
@classmethod
def get_info(cls, key):
return cls._info.setdefault(key, None)
@staticmethod
def get_matching_keys(path):
if path[0] != '/':
path = '/' + path
logdata = dict()
envprofile = get_dconf_envprofile()
try:
process = subprocess.Popen(['dconf', 'list', path],
env=envprofile, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
logdata['path'] = path
log('D204', logdata)
output, error = process.communicate()
if not output and not error:
return
if not error:
keys = output.strip().split('\n')
for key in keys:
Dconf_registry.get_matching_keys(f'{path}{key}')
else:
Dconf_registry.list_keys.append(path)
return Dconf_registry.list_keys
except Exception as exc:
logdata['exc'] = exc
log('E69', logdata)
return None
@staticmethod
def get_key_values(keys):
key_values = {}
for key in keys:
key_values[key] = Dconf_registry.get_key_value(key)
return key_values
@staticmethod
def get_key_value(key):
logdata = dict()
envprofile = get_dconf_envprofile()
try:
process = subprocess.Popen(['dconf', 'read', key],
env=envprofile, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
logdata['key'] = key
output, error = process.communicate()
if not error:
return string_to_literal_eval(string_to_literal_eval(output))
else:
return None
except Exception as exc:
logdata['exc'] = exc
log('E70', logdata)
return None
@staticmethod
def dconf_update():
logdata = dict()
try:
process = subprocess.Popen(['dconf', 'update'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
output, error = process.communicate()
if error:
logdata['error'] = error
log('E71', logdata)
else:
logdata['outpupt'] = output
log('D206', logdata)
except Exception as exc:
logdata['exc'] = exc
log('E72', logdata)
@classmethod
def check_profile_template(cls):
if Path(cls.__template_file).exists():
return True
else:
return None
@classmethod
def apply_template(cls, uid):
logdata = dict()
if uid and cls.check_profile_template():
with open(cls.__template_file, "r") as f:
template = f.read()
# Replace the "{uid}" placeholder with the actual UID value
content = template.replace("{{uid}}", str(uid))
elif uid:
content = f"user-db:user\n" \
f"system-db:policy\n" \
f"system-db:policy{uid}\n" \
f"system-db:local\n" \
f"system-db:default\n" \
f"system-db:local\n" \
f"system-db:policy{uid}\n" \
f"system-db:policy\n"
else:
logdata['uid'] = uid
log('W24', logdata)
return
user_mandatory = f'/run/dconf/user/{uid}'
touch_file(user_mandatory)
with open(user_mandatory, "w") as f:
f.write(content)
@classmethod
def get_policies_from_dconf(cls):
return cls.get_dictionary_from_dconf(cls._policies_path, cls._policies_win_path)
@classmethod
def get_dictionary_from_dconf(self, *startswith_list):
output_dict = {}
for startswith in startswith_list:
dconf_dict = self.get_key_values(self.get_matching_keys(startswith))
for key, value in dconf_dict.items():
keys_tmp = key.split('/')
update_dict(output_dict.setdefault('/'.join(keys_tmp[:-1])[1:], {}), {keys_tmp[-1]: value})
log('D207')
return output_dict
@classmethod
def filter_entries(cls, startswith):
if startswith[-1] == '%':
startswith = startswith[:-1]
if startswith[-1] == '/' or startswith[-1] == '\\':
startswith = startswith[:-1]
return filter_dict_keys(startswith, flatten_dictionary(cls.global_registry_dict))
return filter_dict_keys(startswith, flatten_dictionary(cls.global_registry_dict))
@classmethod
def filter_hklm_entries(cls, startswith):
pregs = cls.filter_entries(startswith)
list_entiers = list()
for keyname, value in pregs.items():
if isinstance(value, dict):
for valuename, data in value.items():
list_entiers.append(PregDconf(
keyname, convert_string_dconf(valuename), find_preg_type(data), data))
elif isinstance(value, list):
for data in value:
list_entiers.append(PregDconf(
keyname, convert_string_dconf(data), find_preg_type(data), data))
else:
list_entiers.append(PregDconf(
'/'.join(keyname.split('/')[:-1]), convert_string_dconf(keyname.split('/')[-1]), find_preg_type(value), value))
return gplist(list_entiers)
@classmethod
def filter_hkcu_entries(cls, sid, startswith):
return cls.filter_hklm_entries(startswith)
@classmethod
def get_storage(cls,dictionary = None):
if dictionary:
result = dictionary
elif Dconf_registry._gpt_read_flag:
result = Dconf_registry.global_registry_dict
else:
if Dconf_registry.__dconf_dict_flag:
result = Dconf_registry.__dconf_dict
else:
Dconf_registry.__dconf_dict = Dconf_registry.get_policies_from_dconf()
result = Dconf_registry.__dconf_dict
Dconf_registry.__dconf_dict_flag = True
return result
@classmethod
def filling_storage_from_dconf(cls):
Dconf_registry.global_registry_dict = Dconf_registry.get_storage()
@classmethod
def get_entry(cls, path, dictionary = None):
logdata = dict()
result = Dconf_registry.get_storage(dictionary)
keys = path.split("\\") if "\\" in path else path.split("/")
key = '/'.join(keys[:-1]) if keys[0] else '/'.join(keys[:-1])[1:]
if isinstance(result, dict) and key in result.keys():
data = result.get(key).get(keys[-1])
return PregDconf(
key, convert_string_dconf(keys[-1]), find_preg_type(data), data)
else:
logdata['path'] = path
log('D208', logdata)
return None
@classmethod
def get_hkcu_entry(cls, sid, hive_key, dictionary = None):
return cls.get_hklm_entry(hive_key, dictionary)
@classmethod
def get_hklm_entry(cls, hive_key, dictionary = None):
return cls.get_entry(hive_key, dictionary)
@classmethod
def add_shortcut(cls, sid, sc_obj, policy_name):
cls.shortcuts.append(sc_obj)
@classmethod
def add_printer(cls, sid, pobj, policy_name):
cls.printers.append(pobj)
@classmethod
def add_drive(cls, sid, dobj, policy_name):
cls.drives.append(dobj)
@classmethod
def add_folder(cls, sid, fobj, policy_name):
cls.folders.append(fobj)
@classmethod
def add_envvar(self, sid, evobj, policy_name):
self.environmentvariables.append(evobj)
@classmethod
def add_script(cls, sid, scrobj, policy_name):
cls.scripts.append(scrobj)
@classmethod
def add_file(cls, sid, fileobj, policy_name):
cls.files.append(fileobj)
@classmethod
def add_ini(cls, sid, iniobj, policy_name):
cls.inifiles.append(iniobj)
@classmethod
def add_networkshare(cls, sid, networkshareobj, policy_name):
cls.networkshares.append(networkshareobj)
@classmethod
def get_shortcuts(cls, sid):
return cls.shortcuts
@classmethod
def get_printers(cls, sid):
return cls.printers
@classmethod
def get_drives(cls, sid):
return cls.drives
@classmethod
def get_folders(cls, sid):
return cls.folders
@classmethod
def get_envvars(cls, sid):
return cls.environmentvariables
@classmethod
def get_scripts(cls, sid, action):
action_scripts = list()
for part in cls.scripts:
if action == 'LOGON':
action_scripts.append(part)
elif action == 'LOGOFF':
action_scripts.append(part)
elif action == 'STARTUP':
action_scripts.append(part)
elif action == 'SHUTDOWN':
action_scripts.append(part)
return action_scripts
@classmethod
def get_files(cls, sid):
return cls.files
@classmethod
def get_networkshare(cls, sid):
return cls.networkshares
@classmethod
def get_ini(cls, sid):
return cls.inifiles
@classmethod
def wipe_user(cls, sid):
cls.wipe_hklm()
@classmethod
def wipe_hklm(cls):
cls.global_registry_dict = dict({cls._ReadQueue:{}})
def filter_dict_keys(starting_string, input_dict):
result = dict()
for key in input_dict:
key_list = remove_empty_values(re.split(r'\\|/', key))
start_list = remove_empty_values(re.split(r'\\|/', starting_string))
if key_list[:len(start_list)] == start_list:
result[key] = input_dict.get(key)
return result
def find_preg_type(argument):
if isinstance(argument, int):
return 4
else:
return 1
def update_dict(dict1, dict2):
'''
Updates dict1 with the key-value pairs from dict2
'''
for key, value in dict2.items():
if key in dict1:
# If both values are dictionaries, recursively call the update_dict function
if isinstance(dict1[key], dict) and isinstance(value, dict):
update_dict(dict1[key], value)
# If the value in dict1 is a list, extend it with unique values from value
elif isinstance(dict1[key], list):
dict1[key].extend(set(value) - set(dict1[key]))
else:
# If the value in dict1 is not a dictionary or the value in dict2 is not a dictionary,
# replace the value in dict1 with the value from dict2
dict1[key] = value
else:
# If the key does not exist in dict1, add the key-value pair from dict2 to dict1
dict1[key] = value
def add_to_dict(string, policy_name, username, version):
if username is None:
correct_path = '/'.join(string.split('/')[:-2])
machine= '{}/Machine'.format(Dconf_registry._ReadQueue)
dictionary = Dconf_registry.global_registry_dict.setdefault(machine, dict())
else:
correct_path = '/'.join(string.split('/')[:-2])
user = '{}/User'.format(Dconf_registry._ReadQueue)
dictionary = Dconf_registry.global_registry_dict.setdefault(user, dict())
dictionary[len(dictionary)] = (policy_name, correct_path, version)
def load_preg_dconf(pregfile, pathfile, policy_name, username, version=None):
'''
Loads the configuration from preg registry into a dictionary
'''
dd = dict()
for i in pregfile.entries:
# Skip this entry if the valuename starts with '**del'
if i.valuename.startswith('**del'):
continue
valuename = convert_string_dconf(i.valuename)
data = check_data(i.data, i.type)
if i.valuename != i.data and i.valuename:
if i.keyname.replace('\\', '/') in dd:
# If the key exists in dd, update its value with the new key-value pair
dd[i.keyname.replace('\\', '/')].update({valuename.replace('\\', '/'):data})
else:
# If the key does not exist in dd, create a new key-value pair
dd[i.keyname.replace('\\', '/')] = {valuename.replace('\\', '/'):data}
elif not i.valuename:
keyname_tmp = i.keyname.replace('\\', '/').split('/')
keyname = '/'.join(keyname_tmp[:-1])
if keyname in dd:
# If the key exists in dd, update its value with the new key-value pair
dd[keyname].update({keyname_tmp[-1]:data})
else:
# If the key does not exist in dd, create a new key-value pair
dd[keyname] = {keyname_tmp[-1]:data}
else:
# If the value name is the same as the data,
# split the keyname and add the data to the appropriate location in dd.
all_list_key = i.keyname.split('\\')
dd_target = dd.setdefault('/'.join(all_list_key[:-1]),{})
dd_target.setdefault(all_list_key[-1], []).append(data)
# Update the global registry dictionary with the contents of dd
add_to_dict(pathfile, policy_name, username, version)
update_dict(Dconf_registry.global_registry_dict, dd)
def create_dconf_ini_file(filename, data):
'''
Create an ini-file based on a dictionary of dictionaries.
Args:
data (dict): The dictionary of dictionaries containing the data for the ini-file.
filename (str): The filename to save the ini-file.
Returns:
None
Raises:
None
'''
with open(filename, 'w') as file:
for section, section_data in data.items():
file.write(f'[{section}]\n')
for key, value in section_data.items():
if isinstance(value, int):
file.write(f'{key} = {value}\n')
else:
file.write(f'{key} = "{value}"\n')
file.write('\n')
logdata = dict()
logdata['path'] = filename
log('D209', logdata)
Dconf_registry.dconf_update()
def clean_data(data):
try:
cleaned_string = data.replace('\n', '').replace('\r', '')
cleaned_string = cleaned_string.replace('"', "'")
return cleaned_string
except:
return None
def check_data(data, t_data):
if isinstance(data, bytes):
if t_data == 7:
return clean_data(data.decode('utf-16').replace('\x00',''))
else:
return None
elif t_data == 4:
return data
return clean_data(data)
def convert_string_dconf(input_string):
macros = {
'#': '%sharp%',
';': '%semicolon%',
'//': '%doubleslash%'
}
output_string = input_string
for key, value in macros.items():
if key in input_string:
output_string = input_string.replace(key, value)
elif value in input_string:
output_string = input_string.replace(value, key)
return output_string
def remove_empty_values(input_list):
return list(filter(None, input_list))
def flatten_dictionary(input_dict, result=None, current_key=''):
if result is None:
result = {}
for key, value in input_dict.items():
new_key = f"{current_key}/{key}" if current_key else key
if isinstance(value, dict):
flatten_dictionary(value, result, new_key)
else:
result[new_key] = value
return result
def get_dconf_envprofile():
dconf_envprofile = {'default': {'DCONF_PROFILE': 'default'},
'local': {'DCONF_PROFILE': 'local'},
'system': {'DCONF_PROFILE': 'system'}
}
if Dconf_registry._envprofile:
return dconf_envprofile.get(Dconf_registry._envprofile, dconf_envprofile['system'])
if not Dconf_registry._username:
return dconf_envprofile['system']
profile = '/run/dconf/user/{}'.format(get_uid_by_username(Dconf_registry._username))
return {'DCONF_PROFILE': profile}

View File

@@ -57,6 +57,9 @@ class fs_file_cache:
file_path))
else:
destdir = destfile.parent
except NotUNCPathError:
return None
except Exception as exc:
logdata = dict({'exception': str(exc)})
log('D144', logdata)

View File

@@ -17,7 +17,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% if Deny_All == '1' %}
{% if Deny_All == 1 %}
polkit.addRule(function (action, subject) {
if ((action.id == "org.freedesktop.udisks2.filesystem-mount" ||
action.id == "org.freedesktop.udisks2.filesystem-mount-system" ||

View File

@@ -17,7 +17,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% if Deny_All == '1' %}
{% if Deny_All == 1 %}
polkit.addRule(function (action, subject) {
if (action.id == "org.freedesktop.udisks2.filesystem-mount" ||
action.id == "org.freedesktop.udisks2.filesystem-mount-system" ||

View File

@@ -46,3 +46,10 @@ class NotUNCPathError(Exception):
def __str__(self):
return self.path
class GetGPOListFail(Exception):
def __init__(self, exc):
self.exc = exc
def __str__(self):
return self.exc

View File

@@ -93,6 +93,15 @@ def local_policy_cache():
return lpcache
def get_dconf_config_path(uid = None):
if uid:
return f'/etc/dconf/db/policy{uid}.d/policy{uid}.ini'
else:
return '/etc/dconf/db/policy.d/policy.ini'
def get_desktop_files_directory():
return '/usr/share/applications'
class UNCPath:
def __init__(self, path):
self.path = path

View File

@@ -19,6 +19,7 @@
from xml.etree import ElementTree
from storage import registry_factory
from storage.dconf_registry import load_preg_dconf
from samba.gp_parse.gp_pol import GPPolParser
@@ -80,10 +81,16 @@ def preg_keymap(preg):
return keymap
def merge_polfile(preg, sid=None, reg_name='registry', reg_path=None, policy_name='Unknown'):
def merge_polfile(preg, sid=None, reg_name='registry', reg_path=None, policy_name='Unknown', username='Machine', version=None):
pregfile = load_preg(preg)
if sid is None and username == 'Machine':
load_preg_dconf(pregfile, preg, policy_name, None, version)
else:
load_preg_dconf(pregfile, preg, policy_name, username, version)
logdata = dict({'pregfile': preg})
log('D32', logdata)
#log dconf
return
storage = registry_factory(reg_name, reg_path)
for entry in pregfile.entries:
if not sid:

View File

@@ -47,7 +47,6 @@ def username_match_uid(username):
'''
Check the passed username matches current process UID.
'''
uid = os.getuid()
process_username = get_process_user()
if process_username == username:

View File

@@ -174,3 +174,25 @@ def string_to_literal_eval(string):
except:
literaleval = string
return literaleval
def try_dict_to_literal_eval(string):
try:
literaleval = ast.literal_eval(string)
if isinstance(literaleval ,dict):
return literaleval
else:
return None
except:
return None
def touch_file(filename):
path = Path(filename)
path.parent.mkdir(parents=True, exist_ok=True)
path.touch()
def get_uid_by_username(username):
try:
user_info = pwd.getpwnam(username)
return user_info.pw_uid
except KeyError:
return None

View File

@@ -30,16 +30,21 @@ except ImportError:
from samba.netcmd.common import netcmd_get_domain_infos_via_cldap
import samba.gpo
from storage import cache_factory
from messages import message_with_code
from .xdg import (
xdg_get_desktop
)
from .util import get_homedir
from .exceptions import GetGPOListFail
from .logging import log
from .samba import smbopts
from gpoa.storage import registry_factory
from samba.samdb import SamDB
from samba.auth import system_session
import optparse
import ldb
import ipaddress
import netifaces
import random
class smbcreds (smbopts):
@@ -48,6 +53,13 @@ class smbcreds (smbopts):
self.credopts = options.CredentialsOptions(self.parser)
self.creds = self.credopts.get_credentials(self.lp, fallback_machine=True)
self.set_dc(dc_fqdn)
self.sDomain = SiteDomainScanner(self.creds, self.lp, self.selected_dc)
self.dc_site_servers = self.sDomain.select_site_servers()
self.all_servers = self.sDomain.select_all_servers()
[self.all_servers.remove(element)
for element in self.dc_site_servers
if element in self.all_servers]
self.pdc_emulator_server = self.sDomain.select_pdc_emulator_server()
def get_dc(self):
return self.selected_dc
@@ -113,17 +125,32 @@ class smbcreds (smbopts):
log('I2', ldata)
except Exception as exc:
if self.selected_dc != self.pdc_emulator_server:
raise GetGPOListFail(exc)
logdata = dict({'username': username, 'dc': self.selected_dc})
log('E17', logdata)
return gpos
def update_gpos(self, username):
gpos = self.get_gpos(username)
list_selected_dc = set()
if self.dc_site_servers:
self.selected_dc = self.dc_site_servers.pop()
self.all_servers = [dc for dc in self.all_servers if dc != self.selected_dc]
list_selected_dc.add(self.selected_dc)
try:
gpos = self.get_gpos(username)
except GetGPOListFail:
self.selected_dc = self.pdc_emulator_server
gpos = self.get_gpos(username)
while list_selected_dc:
logdata = dict()
logdata['username'] = username
@@ -136,22 +163,135 @@ class smbcreds (smbopts):
except NTSTATUSError as smb_exc:
logdata['smb_exc'] = str(smb_exc)
if not check_scroll_enabled():
log('F1', logdata)
raise smb_exc
self.selected_dc = get_dc_hostname(self.creds, self.lp)
if self.selected_dc not in list_selected_dc:
logdata['action'] = 'Search another dc'
log('W11', logdata)
list_selected_dc.add(self.selected_dc)
if self.pdc_emulator_server and self.selected_dc != self.pdc_emulator_server:
self.selected_dc = self.pdc_emulator_server
logdata['action'] = 'Selected pdc'
logdata['pdc'] = self.selected_dc
log('W11', logdata)
else:
log('F1', logdata)
raise smb_exc
else:
log('F1', logdata)
raise smb_exc
if self.dc_site_servers:
self.selected_dc = self.dc_site_servers.pop()
elif self.all_servers:
self.selected_dc = self.all_servers.pop()
else:
self.selected_dc = self.pdc_emulator_server
if self.selected_dc not in list_selected_dc:
logdata['action'] = 'Search another dc'
logdata['another_dc'] = self.selected_dc
log('W11', logdata)
list_selected_dc.add(self.selected_dc)
else:
log('F1', logdata)
raise smb_exc
except Exception as exc:
logdata['exc'] = str(exc)
log('F1', logdata)
raise exc
return gpos
class SiteDomainScanner:
def __init__(self, smbcreds, lp, dc):
self.samdb = SamDB(url='ldap://{}'.format(dc), session_info=system_session(), credentials=smbcreds, lp=lp)
self.pdc_emulator = self._search_pdc_emulator()
@staticmethod
def _get_ldb_single_message_attr(ldb_message, attr_name, encoding='utf8'):
if attr_name in ldb_message:
return ldb_message[attr_name][0].decode(encoding)
else:
return None
@staticmethod
def _get_ldb_single_result_attr(ldb_result, attr_name, encoding='utf8'):
if len(ldb_result) == 1 and attr_name in ldb_result[0]:
return ldb_result[0][attr_name][0].decode(encoding)
else:
return None
def _get_server_hostname(self, ds_service_name):
ds_service_name_dn = ldb.Dn(self.samdb, ds_service_name)
server_dn = ds_service_name_dn.parent()
res = self.samdb.search(server_dn, scope=ldb.SCOPE_BASE)
return self._get_ldb_single_result_attr(res, 'dNSHostName')
def _search_pdc_emulator(self):
res = self.samdb.search(self.samdb.domain_dn(), scope=ldb.SCOPE_BASE)
pdc_settings_object = self._get_ldb_single_result_attr(res, 'fSMORoleOwner')
return self._get_server_hostname(pdc_settings_object)
def get_ip_addresses(self):
interface_list = netifaces.interfaces()
addresses = []
for iface in interface_list:
address_entry = netifaces.ifaddresses(iface)
if netifaces.AF_INET in address_entry:
addresses.extend(ipaddress.ip_address(ipv4_address_entry['addr']) for ipv4_address_entry in address_entry[netifaces.AF_INET])
if netifaces.AF_INET6 in address_entry:
addresses.extend(ipaddress.ip_address(ipv6_address_entry['addr']) for ipv6_address_entry in address_entry[netifaces.AF_INET6])
return addresses
def get_ad_subnets_sites(self):
subnet_dn = ldb.Dn(self.samdb, "CN=Subnets,CN=Sites")
config_dn = self.samdb.get_config_basedn()
subnet_dn.add_base(config_dn)
res = self.samdb.search(subnet_dn, ldb.SCOPE_ONELEVEL, expression='objectClass=subnet', attrs=['cn', 'siteObject'])
subnets = {ipaddress.ip_network(self._get_ldb_single_message_attr(msg, 'cn')): self._get_ldb_single_message_attr(msg, 'siteObject') for msg in res}
return subnets
def get_ad_site_servers(self, site):
servers_dn = ldb.Dn(self.samdb, "CN=Servers")
site_dn = ldb.Dn(self.samdb, site)
servers_dn.add_base(site_dn)
res = self.samdb.search(servers_dn, ldb.SCOPE_ONELEVEL, expression='objectClass=server', attrs=['dNSHostName'])
servers = [self._get_ldb_single_message_attr(msg, 'dNSHostName') for msg in res]
random.shuffle(servers)
return servers
def get_ad_all_servers(self):
sites_dn = ldb.Dn(self.samdb, "CN=Sites")
config_dn = self.samdb.get_config_basedn()
sites_dn.add_base(config_dn)
res = self.samdb.search(sites_dn, ldb.SCOPE_SUBTREE, expression='objectClass=server', attrs=['dNSHostName'])
servers = [self._get_ldb_single_message_attr(msg, 'dNSHostName') for msg in res]
random.shuffle(servers)
return servers
def check_ip_in_subnets(self, ip_addresses, subnets_sites):
return next((subnets_sites[subnet] for subnet in subnets_sites.keys()
if any(ip_address in subnet for ip_address in ip_addresses)), None)
def select_site_servers(self):
try:
ip_addresses = self.get_ip_addresses()
subnets_sites = self.get_ad_subnets_sites()
our_site = self.check_ip_in_subnets(ip_addresses, subnets_sites)
servers = []
if our_site:
servers = self.get_ad_site_servers(our_site)
random.shuffle(servers)
return servers
except Exception as e:
return []
def select_all_servers(self):
try:
servers = self.get_ad_all_servers()
random.shuffle(servers)
return servers
except Exception as e:
return []
def select_pdc_emulator_server(self):
return self.pdc_emulator
def expand_windows_var(text, username=None):
'''
Scan the line for percent-encoded variables and expand them.
@@ -194,9 +334,9 @@ def transform_windows_path(text):
return result
def check_scroll_enabled():
storage = registry_factory('registry')
enable_scroll = 'Software\\BaseALT\\Policies\\GPUpdate\\ScrollSysvolDC'
if storage.get_hklm_entry(enable_scroll):
storage = registry_factory()
enable_scroll = '/Software/BaseALT/Policies/GPUpdate/ScrollSysvolDC'
if storage.get_key_value(enable_scroll):
data = storage.get_hklm_entry(enable_scroll).data
return bool(int(data))
else:

View File

@@ -11,6 +11,7 @@
%add_python3_req_skip messages
%add_python3_req_skip storage
%add_python3_req_skip storage.fs_file_cache
%add_python3_req_skip storage.dconf_registry
%add_python3_req_skip util
%add_python3_req_skip util.arguments
%add_python3_req_skip util.config
@@ -32,7 +33,7 @@
%add_python3_req_skip util.gpoa_ini_parsing
Name: gpupdate
Version: 0.9.13.7
Version: 0.10.3
Release: alt1
Summary: GPT applier
@@ -53,6 +54,7 @@ Requires: libnss-role >= 0.5.0
Requires: local-policy >= 0.4.9
Requires: pam-config >= 1.9.0
Requires: autofs
Requires: dconf-profile
# This is needed by shortcuts_applier
Requires: desktop-file-utils
# This is needed for smb file cache support
@@ -119,6 +121,9 @@ install -Dm0644 dist/%name-remote-policy %buildroot%_sysconfdir/pam.d/%name-remo
install -Dm0644 dist/%name.ini %buildroot%_sysconfdir/%name/%name.ini
install -Dm0644 doc/gpoa.1 %buildroot/%_man1dir/gpoa.1
install -Dm0644 doc/gpupdate.1 %buildroot/%_man1dir/gpupdate.1
install -Dm0644 completions/gpoa %buildroot/%_datadir/bash-completion/completions/gpoa
install -Dm0644 completions/gpupdate %buildroot/%_datadir/bash-completion/completions/gpupdate
install -Dm0644 completions/gpupdate-setup %buildroot/%_datadir/bash-completion/completions/gpupdate-setup
for i in gpupdate-localusers \
gpupdate-group-users \
@@ -165,9 +170,12 @@ fi
%_unitdir/%name.timer
%_man1dir/gpoa.1.*
%_man1dir/gpupdate.1.*
/usr/lib/systemd/user/%name-user.service
/usr/lib/systemd/user/%name-user.timer
/usr/lib/systemd/user/%name-scripts-run-user.service
%_datadir/bash-completion/completions/gpoa
%_datadir/bash-completion/completions/gpupdate
%_datadir/bash-completion/completions/gpupdate-setup
%_user_unitdir/%name-user.service
%_user_unitdir/%name-user.timer
%_user_unitdir/%name-scripts-run-user.service
%dir %_sysconfdir/%name
%_sysconfdir/control.d/facilities/*
%config(noreplace) %_sysconfdir/%name/environment
@@ -183,6 +191,33 @@ fi
%exclude %python3_sitelibdir/gpoa/test
%changelog
* Wed Jun 19 2024 Valery Sinelnikov <greh@altlinux.org> 0.10.3-alt1
- Added autocompletion for gpoa, gpupdate, gpupdate-setup
- Added correct work with json data in keys for the Firefox browser
- Polkit_appliers changed to non-experimental
- Fixed bug of not clearing kde applier settings (closes: 50336)
- Fixed registry key reading (closes: 50553)
- Added waiting for data generation for scripts (closes: 50667)
* Fri Jun 07 2024 Valery Sinelnikov <greh@altlinux.org> 0.10.2-alt1
- Added some fixes to dconf_registry and scripts
- Fixed windows registry key reading for loopback
* Tue Jun 04 2024 Valery Sinelnikov <greh@altlinux.org> 0.10.1-alt1
- Added handling of unexpected data types when writing to dconf
* Mon May 13 2024 Valery Sinelnikov <greh@altlinux.org> 0.10.0-alt1
- A method for storing registry keys obtained from GPOs (Group Policy Objects)
has undergone significant repairs. We have switched from using SQLite
to using Dconf to improve data storage efficiency
* Wed Mar 13 2024 Valery Sinelnikov <greh@altlinux.org> 0.9.13.9-alt1
- Fixed premature removal of double slash
* Thu Feb 22 2024 Valery Sinelnikov <greh@altlinux.org> 0.9.13.8-alt1
- Added search for dc on the site
- Added compatibility support for the oldest versions of SQLAlchemy
* Mon Feb 05 2024 Valery Sinelnikov <greh@altlinux.org> 0.9.13.7-alt1
- Editing the cache size in the Yandex browser has returned (closes: 44621)
- Removed unnecessary calls to subprocess