mirror of
https://github.com/altlinux/gpupdate.git
synced 2025-10-15 07:33:26 +03:00
Compare commits
50 Commits
0.9.2-alt1
...
gsettings_
Author | SHA1 | Date | |
---|---|---|---|
|
285e646986 | ||
|
94d039653a | ||
|
e6f19a2116 | ||
|
86c240b9df | ||
|
dae3cf2c6c | ||
|
4fe7d0a73e | ||
|
54d0c7c2cb | ||
|
954a5598fb | ||
|
ba4eb4bf28 | ||
|
aa10d5bbf9 | ||
|
f3062668fa | ||
|
046079d4c9 | ||
|
414a827eb8 | ||
|
8ce322d552 | ||
|
84d5122319 | ||
|
436eeb3760 | ||
|
4b9ef4335a | ||
|
929f9678ad | ||
|
03cada30cf | ||
|
8199cac510 | ||
|
e050889a07 | ||
|
1bf2bd053d | ||
|
950e132e2a | ||
|
82e255efc9 | ||
|
011a3fbed3 | ||
|
8eda2fbedb | ||
|
3f3fa5f7d9 | ||
|
0210f97e0d | ||
|
7e6dec6b3d | ||
|
5e4ed2f655 | ||
|
721ba96559 | ||
|
c83568cc70 | ||
|
15f99e0171 | ||
|
f84af7e0e8 | ||
7bd1131d5d
|
|||
5fb8e6ff74
|
|||
ce2797e5f1
|
|||
6d9417fb94
|
|||
301a77e90a
|
|||
|
274d9d8555 | ||
|
04f5f98681 | ||
|
9638e5fabb | ||
|
393fd25cdb | ||
|
23f862f9a5 | ||
a85fed7cff
|
|||
bbcb98bb94
|
|||
|
57f4f0678a | ||
|
306b8db34a | ||
|
7c8f9892b5 | ||
|
4c6a099529 |
19
dist/gpupdate-group-users
vendored
Executable file
19
dist/gpupdate-group-users
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /etc/control.d/functions
|
||||
|
||||
CONFIG=/etc/pam.d/system-policy-gpupdate
|
||||
|
||||
new_subst disabled \
|
||||
'^[[:space:]]*session[[:space:]]+\[.*default=1.*\][[:space:]]+pam_succeed_if.so user ingroup users.*' \
|
||||
's,^\([[:space:]]*session[[:space:]]\+\[.*\)default=[[:alnum:]]\+\(.*pam_succeed_if.so user ingroup users.*\)$,\1default=1\2,'
|
||||
new_subst enabled \
|
||||
'^[[:space:]]*session[[:space:]]+\[.*default=ignore.*\][[:space:]]+pam_succeed_if.so user ingroup users.*' \
|
||||
's,^\([[:space:]]*session[[:space:]]\+\[.*\)default=[[:alnum:]]\+\(.*pam_succeed_if.so user ingroup users.*\)$,\1default=ignore\2,'
|
||||
|
||||
new_help disabled "Disable group policy applying for users in 'users' group only"
|
||||
new_help enabled "Enable group policy applying for users in 'users' group only"
|
||||
|
||||
new_summary "Group policy applying for users in 'users' group only"
|
||||
|
||||
control_subst "$CONFIG" "$*"
|
19
dist/gpupdate-localusers
vendored
Executable file
19
dist/gpupdate-localusers
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /etc/control.d/functions
|
||||
|
||||
CONFIG=/etc/pam.d/system-policy-gpupdate
|
||||
|
||||
new_subst disabled \
|
||||
'^[[:space:]]*session[[:space:]]+\[.*success=2.*\][[:space:]]+pam_localuser.so' \
|
||||
's,^\([[:space:]]*session[[:space:]]\+\[.*\)success=[[:alnum:]]\+\(.*pam_localuser.so.*\)$,\1success=2\2,'
|
||||
new_subst enabled \
|
||||
'^[[:space:]]*session[[:space:]]+\[.*success=1.*\][[:space:]]+pam_localuser.so' \
|
||||
's,^\([[:space:]]*session[[:space:]]\+\[.*\)success=[[:alnum:]]\+\(.*pam_localuser.so.*\)$,\1success=1\2,'
|
||||
|
||||
new_help disabled 'Disable group policy applying for local users'
|
||||
new_help enabled 'Enable group policy applying for local users'
|
||||
|
||||
new_summary 'Group policy applying for local users'
|
||||
|
||||
control_subst "$CONFIG" "$*"
|
19
dist/gpupdate-system-uids
vendored
Executable file
19
dist/gpupdate-system-uids
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /etc/control.d/functions
|
||||
|
||||
CONFIG=/etc/pam.d/system-policy-gpupdate
|
||||
|
||||
new_subst disabled \
|
||||
'^[[:space:]]*session[[:space:]]+\[.*default=1.*\][[:space:]]+pam_succeed_if.so uid >= 500.*' \
|
||||
's,^\([[:space:]]*session[[:space:]]\+\[.*\)default=[[:alnum:]]\+\(.*pam_succeed_if.so uid >= 500.*\)$,\1default=1\2,'
|
||||
new_subst enabled \
|
||||
'^[[:space:]]*session[[:space:]]+\[.*default=ignore.*\][[:space:]]+pam_succeed_if.so uid >= 500.*' \
|
||||
's,^\([[:space:]]*session[[:space:]]\+\[.*\)default=[[:alnum:]]\+\(.*pam_succeed_if.so uid >= 500.*\)$,\1default=ignore\2,'
|
||||
|
||||
new_help disabled "Disable group policy applying for users with not system uids only"
|
||||
new_help enabled "Enable group policy applying for users with not system uids only"
|
||||
|
||||
new_summary "Group policy applying for users with not system uids (greater or equal 500) only"
|
||||
|
||||
control_subst "$CONFIG" "$*"
|
4
dist/gpupdate.ini
vendored
4
dist/gpupdate.ini
vendored
@@ -1,4 +1,4 @@
|
||||
[gpoa]
|
||||
backend = samba
|
||||
local-policy = auto
|
||||
backend = local
|
||||
local-policy = default
|
||||
|
||||
|
2
dist/gpupdate.service
vendored
2
dist/gpupdate.service
vendored
@@ -1,6 +1,6 @@
|
||||
[Unit]
|
||||
Description=Group policy update for machine
|
||||
After=sssd.service
|
||||
After=syslog.target network-online.target sssd.service
|
||||
|
||||
[Service]
|
||||
Environment="PATH=/bin:/sbin:/usr/bin:/usr/sbin"
|
||||
|
8
dist/system-policy-gpupdate
vendored
8
dist/system-policy-gpupdate
vendored
@@ -1,4 +1,12 @@
|
||||
#%PAM-1.0
|
||||
session [success=2 perm_denied=ignore default=die] pam_localuser.so
|
||||
session required pam_mkhomedir.so silent
|
||||
session [default=1] pam_permit.so
|
||||
session [default=6] pam_permit.so
|
||||
session [success=1 default=ignore] pam_succeed_if.so user ingroup users quiet
|
||||
session [default=4] pam_permit.so
|
||||
session [success=1 default=ignore] pam_succeed_if.so uid >= 500 quiet
|
||||
session [default=2] pam_permit.so
|
||||
-session required pam_oddjob_gpupdate.so
|
||||
session optional pam_env.so user_readenv=1 conffile=/etc/gpupdate/environment user_envfile=.gpupdate_environment
|
||||
session required pam_permit.so
|
||||
|
@@ -41,7 +41,7 @@ def backend_factory(dc, username, is_machine, no_domain = False):
|
||||
log('D52', ld)
|
||||
sc = smbcreds(dc)
|
||||
domain = sc.get_domain()
|
||||
ldata = dict({'domain': domain})
|
||||
ldata = dict({'domain': domain, "username": username, 'is_machine': is_machine})
|
||||
log('D9', ldata)
|
||||
try:
|
||||
back = samba_backend(sc, username, domain, is_machine)
|
||||
|
@@ -126,7 +126,7 @@ class samba_backend(applier_backend):
|
||||
def _get_gpts(self, username, sid):
|
||||
gpts = list()
|
||||
|
||||
log('D45')
|
||||
log('D45', {'username': username, 'sid': sid})
|
||||
# util.windows.smbcreds
|
||||
gpos = self.sambacreds.update_gpos(username)
|
||||
log('D46')
|
||||
|
@@ -24,44 +24,89 @@ from gi.repository import Gio, GLib
|
||||
from util.logging import slogm
|
||||
|
||||
class system_gsetting:
|
||||
def __init__(self, schema, path, value, override_priority_file):
|
||||
def __init__(self, schema, path, value, lock, helper_function=None):
|
||||
self.schema = schema
|
||||
self.path = path
|
||||
self.value = value
|
||||
self.file_path = override_priority_file
|
||||
self.lock = lock
|
||||
self.helper_function = helper_function
|
||||
|
||||
def apply(self):
|
||||
config = configparser.ConfigParser()
|
||||
try:
|
||||
config.read(self.file_path)
|
||||
except Exception as exc:
|
||||
logging.error(slogm(exc))
|
||||
def apply(self, settings, config, locks):
|
||||
try:
|
||||
config.add_section(self.schema)
|
||||
except configparser.DuplicateSectionError:
|
||||
pass
|
||||
|
||||
value = glib_value(self.schema, self.path, self.value)
|
||||
config.set(self.schema, self.path, str(value))
|
||||
#logging.debug('Setting GSettings key {} (in {}) to {}'.format(self.path, self.schema, str(value)))
|
||||
value = self.value
|
||||
if self.helper_function:
|
||||
value = self.helper_function(self.schema, self.path, value)
|
||||
result = glib_value(self.schema, self.path, value, settings)
|
||||
config.set(self.schema, self.path, str(result))
|
||||
|
||||
with open(self.file_path, 'w') as f:
|
||||
if self.lock:
|
||||
lock_path = dconf_path(settings, self.path)
|
||||
locks.append(lock_path)
|
||||
|
||||
class system_gsettings:
|
||||
__path_local_dir = '/etc/dconf/db/local.d'
|
||||
__path_locks = '/etc/dconf/db/policy.d/locks/policy'
|
||||
__path_profile = '/etc/dconf/profile/user'
|
||||
__profile_data = 'user-db:user\nsystem-db:policy\nsystem-db:local\n'
|
||||
|
||||
def __init__(self, override_file_path):
|
||||
self.gsettings = list()
|
||||
self.locks = list()
|
||||
self.override_file_path = override_file_path
|
||||
|
||||
def append(self, schema, path, data, lock, helper):
|
||||
self.gsettings.append(system_gsetting(schema, path, data, lock, helper))
|
||||
|
||||
def apply(self):
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
for gsetting in self.gsettings:
|
||||
settings = Gio.Settings(schema=gsetting.schema)
|
||||
logging.debug(slogm('Applying machine setting {}.{} to {} {}'.format(gsetting.schema,
|
||||
gsetting.path,
|
||||
gsetting.value,
|
||||
gsetting.value,
|
||||
'locked' if gsetting.lock else 'unlocked')))
|
||||
gsetting.apply(settings, config, self.locks)
|
||||
|
||||
with open(self.override_file_path, 'w') as f:
|
||||
config.write(f)
|
||||
|
||||
os.makedirs(self.__path_local_dir, mode=0o755, exist_ok=True)
|
||||
os.makedirs(os.path.dirname(self.__path_locks), mode=0o755, exist_ok=True)
|
||||
os.makedirs(os.path.dirname(self.__path_profile), mode=0o755, exist_ok=True)
|
||||
try:
|
||||
os.remove(self.__path_locks)
|
||||
except OSError as error:
|
||||
pass
|
||||
|
||||
file_locks = open(self.__path_locks,'w')
|
||||
for lock in self.locks:
|
||||
file_locks.write(lock +'\n')
|
||||
file_locks.close()
|
||||
|
||||
profile = open(self.__path_profile ,'w')
|
||||
profile.write(self.__profile_data)
|
||||
profile.close()
|
||||
|
||||
def glib_map(value, glib_type):
|
||||
result_value = value
|
||||
|
||||
if glib_type == 'i' or glib_type == 'b':
|
||||
if glib_type == 'i' or glib_type == 'b' or glib_type == 'q':
|
||||
result_value = GLib.Variant(glib_type, int(value))
|
||||
else:
|
||||
result_value = GLib.Variant(glib_type, value)
|
||||
|
||||
return result_value
|
||||
|
||||
def glib_value(schema, path, value, settings=None):
|
||||
# Access the current schema if not initialized
|
||||
if not settings:
|
||||
settings = Gio.Settings(schema=schema)
|
||||
def dconf_path(settings, path):
|
||||
return settings.get_property("path") + path
|
||||
|
||||
def glib_value(schema, path, value, settings):
|
||||
# Get the key to modify
|
||||
key = settings.get_value(path)
|
||||
# Query the data type for the key
|
||||
@@ -71,27 +116,20 @@ def glib_value(schema, path, value, settings=None):
|
||||
|
||||
class user_gsetting:
|
||||
def __init__(self, schema, path, value, helper_function=None):
|
||||
#logging.debug('Creating User GSettings element {} (in {}) with value {}'.format(path, schema, value))
|
||||
self.schema = schema
|
||||
self.path = path
|
||||
self.value = value
|
||||
self.helper_function = helper_function
|
||||
|
||||
def apply(self):
|
||||
#logging.debug('Setting User GSettings key {} (in {}) to {}'.format(self.path, self.schema, self.value))
|
||||
if self.helper_function:
|
||||
self.helper_function(self.schema, self.path, self.value)
|
||||
# Access the current schema
|
||||
settings = Gio.Settings(schema=self.schema)
|
||||
# Update result with helper function
|
||||
value = self.value
|
||||
if self.helper_function:
|
||||
value = self.helper_function(self.schema, self.path, value)
|
||||
# Get typed value by schema
|
||||
val = glib_value(self.schema, self.path, self.value, settings)
|
||||
result = glib_value(self.schema, self.path, value, settings)
|
||||
# Set the value
|
||||
settings.set_value(self.path, val)
|
||||
settings.set_value(self.path, result)
|
||||
settings.sync()
|
||||
|
||||
#gso = Gio.Settings.new(self.schema)
|
||||
#variants = gso.get_property(self.path)
|
||||
#if (variants.has_key(self.path)):
|
||||
# key = variants.get_key(self.path)
|
||||
# print(key.get_range())
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from storage import registry_factory
|
||||
from storage.fs_file_cache import fs_file_cache
|
||||
|
||||
from .control_applier import control_applier
|
||||
from .polkit_applier import (
|
||||
@@ -107,6 +108,7 @@ class frontend_manager:
|
||||
self.is_machine = is_machine
|
||||
self.process_uname = get_process_user()
|
||||
self.sid = get_sid(self.storage.get_info('domain'), self.username, is_machine)
|
||||
self.file_cache = fs_file_cache('file_cache')
|
||||
|
||||
self.machine_appliers = dict()
|
||||
self.machine_appliers['control'] = control_applier(self.storage)
|
||||
@@ -115,7 +117,7 @@ class frontend_manager:
|
||||
self.machine_appliers['firefox'] = firefox_applier(self.storage, self.sid, self.username)
|
||||
self.machine_appliers['chromium'] = chromium_applier(self.storage, self.sid, self.username)
|
||||
self.machine_appliers['shortcuts'] = shortcut_applier(self.storage)
|
||||
self.machine_appliers['gsettings'] = gsettings_applier(self.storage)
|
||||
self.machine_appliers['gsettings'] = gsettings_applier(self.storage, self.file_cache)
|
||||
self.machine_appliers['cups'] = cups_applier(self.storage)
|
||||
self.machine_appliers['firewall'] = firewall_applier(self.storage)
|
||||
self.machine_appliers['folders'] = folder_applier(self.storage, self.sid)
|
||||
@@ -128,7 +130,7 @@ class frontend_manager:
|
||||
self.user_appliers = dict()
|
||||
self.user_appliers['shortcuts'] = shortcut_applier_user(self.storage, self.sid, self.username)
|
||||
self.user_appliers['folders'] = folder_applier_user(self.storage, self.sid, self.username)
|
||||
self.user_appliers['gsettings'] = gsettings_applier_user(self.storage, self.sid, self.username)
|
||||
self.user_appliers['gsettings'] = gsettings_applier_user(self.storage, self.file_cache, self.sid, self.username)
|
||||
try:
|
||||
self.user_appliers['cifs'] = cifs_applier_user(self.storage, self.sid, self.username)
|
||||
except Exception as exc:
|
||||
@@ -148,6 +150,7 @@ class frontend_manager:
|
||||
log('E13')
|
||||
return
|
||||
log('D16')
|
||||
|
||||
for applier_name, applier_object in self.machine_appliers.items():
|
||||
try:
|
||||
applier_object.apply()
|
||||
|
@@ -20,6 +20,7 @@ import logging
|
||||
import os
|
||||
import pwd
|
||||
import subprocess
|
||||
import urllib.parse
|
||||
|
||||
from gi.repository import (
|
||||
Gio
|
||||
@@ -32,34 +33,70 @@ from .applier_frontend import (
|
||||
, check_windows_mapping_enabled
|
||||
)
|
||||
from .appliers.gsettings import (
|
||||
system_gsetting,
|
||||
system_gsettings,
|
||||
user_gsetting
|
||||
)
|
||||
from util.logging import slogm
|
||||
|
||||
def uri_fetch(schema, path, value, cache):
|
||||
'''
|
||||
Function to fetch and cache uri
|
||||
'''
|
||||
retval = value
|
||||
logdata = dict()
|
||||
logdata['schema'] = schema
|
||||
logdata['path'] = path
|
||||
logdata['src'] = value
|
||||
try:
|
||||
retval = cache.get(value)
|
||||
logdata['dst'] = retval
|
||||
logging.debug(slogm('Getting cached file for URI: {}'.format(logdata)))
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
return retval
|
||||
|
||||
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'
|
||||
__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):
|
||||
def __init__(self, storage, file_cache):
|
||||
self.storage = storage
|
||||
self.file_cache = file_cache
|
||||
gsettings_filter = '{}%'.format(self.__registry_branch)
|
||||
gsettings_locks_filter = '{}%'.format(self.__registry_locks_branch)
|
||||
self.gsettings_keys = self.storage.filter_hklm_entries(gsettings_filter)
|
||||
self.gsettings = list()
|
||||
self.gsettings_locks = self.storage.filter_hklm_entries(gsettings_locks_filter)
|
||||
self.override_file = os.path.join(self.__global_schema, self.__override_priority_file)
|
||||
self.override_old_file = os.path.join(self.__global_schema, self.__override_old_file)
|
||||
self.gsettings = system_gsettings(self.override_file)
|
||||
self.locks = dict()
|
||||
self.__module_enabled = check_enabled(
|
||||
self.storage
|
||||
, self.__module_name
|
||||
, self.__module_experimental
|
||||
)
|
||||
|
||||
def update_file_cache(self, data):
|
||||
try:
|
||||
self.file_cache.store(data)
|
||||
except Exception as exc:
|
||||
logdata = dict()
|
||||
logdata['exception'] = str(exc)
|
||||
logging.debug(slogm('Unable to cache specified URI for machine: {}'.format(logdata)))
|
||||
|
||||
def uri_fetch_helper(self, schema, path, value):
|
||||
return uri_fetch(schema, path, value, self.file_cache)
|
||||
|
||||
def run(self):
|
||||
# Compatility cleanup of old settings
|
||||
if os.path.exists(self.override_old_file):
|
||||
@@ -70,18 +107,31 @@ class gsettings_applier(applier_frontend):
|
||||
logging.debug(slogm('Removing GSettings policy file from previous run'))
|
||||
os.remove(self.override_file)
|
||||
|
||||
# Get all configured gsettings locks
|
||||
for lock in self.gsettings_locks:
|
||||
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]
|
||||
rp = valuename.rpartition('.')
|
||||
schema = rp[0]
|
||||
path = rp[2]
|
||||
self.gsettings.append(system_gsetting(schema, path, setting.data, self.override_file))
|
||||
data = setting.data
|
||||
lock = bool(self.locks[valuename]) if valuename in self.locks else None
|
||||
if setting.hive_key.lower() == self.__wallpaper_entry.lower():
|
||||
check = urllib.parse.urlparse(setting.data)
|
||||
if check.scheme:
|
||||
self.update_file_cache(setting.data)
|
||||
helper = self.uri_fetch_helper
|
||||
elif setting.hive_key.lower() == self.__vino_authentication_methods_entry.lower():
|
||||
data = [setting.data]
|
||||
self.gsettings.append(schema, path, data, lock, helper)
|
||||
|
||||
# Create GSettings policy with highest available priority
|
||||
for gsetting in self.gsettings:
|
||||
logging.debug(slogm('Applying setting {}/{} to {}'.format(gsetting.schema, gsetting.path, gsetting.value)))
|
||||
gsetting.apply()
|
||||
self.gsettings.apply()
|
||||
|
||||
# Recompile GSettings schemas with overrides
|
||||
try:
|
||||
@@ -89,6 +139,12 @@ class gsettings_applier(applier_frontend):
|
||||
except Exception as exc:
|
||||
logging.debug(slogm('Error recompiling global GSettings schemas'))
|
||||
|
||||
# Update desktop configuration system backend
|
||||
try:
|
||||
proc = subprocess.run(args=['/usr/bin/dconf', "update"], capture_output=True, check=True)
|
||||
except Exception as exc:
|
||||
logging.debug(slogm('Error update desktop configuration system backend'))
|
||||
|
||||
def apply(self):
|
||||
if self.__module_enabled:
|
||||
logging.debug(slogm('Running GSettings applier for machine'))
|
||||
@@ -131,10 +187,13 @@ class gsettings_applier_user(applier_frontend):
|
||||
__module_name = 'GSettingsApplierUser'
|
||||
__module_experimental = False
|
||||
__module_enabled = True
|
||||
__registry_branch = 'Software\\BaseALT\\Policies\\gsettings'
|
||||
__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, sid, username):
|
||||
def __init__(self, storage, file_cache, sid, username):
|
||||
self.storage = storage
|
||||
self.file_cache = file_cache
|
||||
self.sid = sid
|
||||
self.username = username
|
||||
gsettings_filter = '{}%'.format(self.__registry_branch)
|
||||
@@ -179,14 +238,17 @@ class gsettings_applier_user(applier_frontend):
|
||||
|
||||
def windows_mapping_append(self):
|
||||
for setting_key in self.__windows_settings.keys():
|
||||
#logging.debug('Checking for GSettings mapping {}'.format(setting_key))
|
||||
value = self.storage.get_hkcu_entry(self.sid, setting_key)
|
||||
if value:
|
||||
logging.debug(slogm('Found GSettings windows mapping {} to {}'.format(setting_key, value.data)))
|
||||
mapping = self.__windows_settings[setting_key]
|
||||
self.gsettings.append(user_gsetting(mapping.gsettings_schema, mapping.gsettings_key, value.data))
|
||||
#else:
|
||||
# logging.debug('GSettings windows mapping for {} not found'.format(setting_key))
|
||||
try:
|
||||
self.gsettings.append(user_gsetting(mapping.gsettings_schema, mapping.gsettings_key, value.data))
|
||||
except Exception as exc:
|
||||
print(exc)
|
||||
|
||||
def uri_fetch_helper(self, schema, path, value):
|
||||
return uri_fetch(schema, path, value, self.file_cache)
|
||||
|
||||
def run(self):
|
||||
#for setting in self.gsettings_keys:
|
||||
@@ -210,11 +272,17 @@ class gsettings_applier_user(applier_frontend):
|
||||
rp = valuename.rpartition('.')
|
||||
schema = rp[0]
|
||||
path = rp[2]
|
||||
self.gsettings.append(user_gsetting(schema, path, setting.data))
|
||||
data = setting.data
|
||||
helper = self.uri_fetch_helper if setting.hive_key.lower() == self.__wallpaper_entry.lower() else None
|
||||
if setting.hive_key.lower() == self.__vino_authentication_methods_entry.lower():
|
||||
data = [setting.data]
|
||||
self.gsettings.append(user_gsetting(schema, path, data, helper))
|
||||
|
||||
# Create GSettings policy with highest available priority
|
||||
for gsetting in self.gsettings:
|
||||
logging.debug(slogm('Applying user setting {}/{} to {}'.format(gsetting.schema, gsetting.path, gsetting.value)))
|
||||
logging.debug(slogm('Applying user setting {}.{} to {}'.format(gsetting.schema,
|
||||
gsetting.path,
|
||||
gsetting.value)))
|
||||
gsetting.apply()
|
||||
|
||||
def user_context_apply(self):
|
||||
@@ -225,8 +293,14 @@ class gsettings_applier_user(applier_frontend):
|
||||
logging.debug(slogm('GSettings applier for user in user context will not be started'))
|
||||
|
||||
def admin_context_apply(self):
|
||||
'''
|
||||
Not implemented because there is no point of doing so.
|
||||
'''
|
||||
pass
|
||||
# Cache files on remote locations
|
||||
try:
|
||||
entry = self.__wallpaper_entry
|
||||
filter_result = self.storage.get_hkcu_entry(self.sid, entry)
|
||||
if filter_result:
|
||||
self.file_cache.store(filter_result.data)
|
||||
except Exception as exc:
|
||||
logdata = dict()
|
||||
logdata['exception'] = str(exc)
|
||||
logging.debug(slogm('Unable to cache specified URI for user: {}'.format(logdata)))
|
||||
|
||||
|
@@ -46,9 +46,9 @@ def storage_get_shortcuts(storage, sid, username=None):
|
||||
|
||||
return shortcuts
|
||||
|
||||
def write_shortcut(shortcut, username=None):
|
||||
def apply_shortcut(shortcut, username=None):
|
||||
'''
|
||||
Write the single shortcut file to the disk.
|
||||
Apply the single shortcut file to the disk.
|
||||
|
||||
:username: None means working with machine variables and paths
|
||||
'''
|
||||
@@ -66,22 +66,22 @@ def write_shortcut(shortcut, username=None):
|
||||
if dest_abspath.startswith(get_homedir(username)):
|
||||
# Don't try to operate on non-existent directory
|
||||
if not homedir_exists(username):
|
||||
logging.warning(slogm('No home directory exists for user {}: will not create link {}'.format(username, dest_abspath)))
|
||||
logging.warning(slogm('No home directory exists for user {}: will not apply link {}'.format(username, dest_abspath)))
|
||||
return None
|
||||
else:
|
||||
logging.warning(slogm('User\'s shortcut not placed to home directory for {}: bad path {}'.format(username, dest_abspath)))
|
||||
return None
|
||||
|
||||
if '%' in dest_abspath:
|
||||
logging.debug(slogm('Fail for writing shortcut to file with \'%\': {}'.format(dest_abspath)))
|
||||
logging.debug(slogm('Fail for applying shortcut to file with \'%\': {}'.format(dest_abspath)))
|
||||
return None
|
||||
|
||||
if not dest_abspath.startswith('/'):
|
||||
logging.debug(slogm('Fail for writing shortcut to not absolute path \'%\': {}'.format(dest_abspath)))
|
||||
logging.debug(slogm('Fail for applying shortcut to not absolute path \'%\': {}'.format(dest_abspath)))
|
||||
return None
|
||||
|
||||
logging.debug(slogm('Writing shortcut file to {}'.format(dest_abspath)))
|
||||
shortcut.write_desktop(dest_abspath)
|
||||
logging.debug(slogm('Applying shortcut file to {} with action {}'.format(dest_abspath, shortcut.action)))
|
||||
shortcut.apply_desktop(dest_abspath)
|
||||
|
||||
class shortcut_applier(applier_frontend):
|
||||
__module_name = 'ShortcutsApplier'
|
||||
@@ -100,7 +100,7 @@ class shortcut_applier(applier_frontend):
|
||||
shortcuts = storage_get_shortcuts(self.storage, self.storage.get_info('machine_sid'))
|
||||
if shortcuts:
|
||||
for sc in shortcuts:
|
||||
write_shortcut(sc)
|
||||
apply_shortcut(sc)
|
||||
if len(shortcuts) > 0:
|
||||
# According to ArchWiki - this thing is needed to rebuild MIME
|
||||
# type cache in order file bindings to work. This rebuilds
|
||||
@@ -133,9 +133,9 @@ class shortcut_applier_user(applier_frontend):
|
||||
if shortcuts:
|
||||
for sc in shortcuts:
|
||||
if in_usercontext and sc.is_usercontext():
|
||||
write_shortcut(sc, self.username)
|
||||
apply_shortcut(sc, self.username)
|
||||
if not in_usercontext and not sc.is_usercontext():
|
||||
write_shortcut(sc, self.username)
|
||||
apply_shortcut(sc, self.username)
|
||||
else:
|
||||
logging.debug(slogm('No shortcuts to process for {}'.format(self.sid)))
|
||||
|
||||
|
37
gpoa/gpoa
37
gpoa/gpoa
@@ -73,25 +73,44 @@ class gpoa_controller:
|
||||
def __init__(self):
|
||||
self.__args = parse_arguments()
|
||||
self.is_machine = False
|
||||
if not self.__args.user:
|
||||
user = get_machine_name()
|
||||
self.is_machine = True
|
||||
self.noupdate = self.__args.noupdate
|
||||
set_loglevel(self.__args.loglevel)
|
||||
|
||||
locale.bindtextdomain('gpoa', '/usr/lib/python3/site-packages/gpoa/locale')
|
||||
gettext.bindtextdomain('gpoa', '/usr/lib/python3/site-packages/gpoa/locale')
|
||||
gettext.textdomain('gpoa')
|
||||
|
||||
if not self.__args.user:
|
||||
self.username = get_machine_name()
|
||||
self.is_machine = True
|
||||
else:
|
||||
self.username = self.__args.user
|
||||
|
||||
uname = get_process_user()
|
||||
uid = os.getuid()
|
||||
logdata = dict()
|
||||
logdata['username'] = uname
|
||||
logdata['uid'] = uid
|
||||
log('D1', logdata)
|
||||
logdata['username'] = self.username
|
||||
logdata['is_machine'] = self.is_machine
|
||||
logdata['process_username'] = uname
|
||||
logdata['process_uid'] = uid
|
||||
|
||||
if self.is_machine:
|
||||
log('D61', logdata)
|
||||
else:
|
||||
log('D1', logdata)
|
||||
self.username = determine_username(self.username)
|
||||
|
||||
if not is_root():
|
||||
self.username = uname
|
||||
self.noupdate = True
|
||||
|
||||
if self.is_machine:
|
||||
msgtext = message_with_code('E34')
|
||||
log('E34', {'username': self.username})
|
||||
raise Exception(msgtext)
|
||||
|
||||
log('D59', {'username': self.username})
|
||||
else:
|
||||
self.username = determine_username(self.__args.user)
|
||||
log('D60', {'username': self.username})
|
||||
|
||||
def run(self):
|
||||
'''
|
||||
@@ -113,7 +132,7 @@ class gpoa_controller:
|
||||
if self.__args.nodomain:
|
||||
nodomain = True
|
||||
|
||||
if not self.__args.noupdate:
|
||||
if not self.noupdate:
|
||||
if is_root():
|
||||
back = None
|
||||
try:
|
||||
|
@@ -68,7 +68,7 @@ from .tasks import (
|
||||
import util
|
||||
import util.preg
|
||||
from util.paths import (
|
||||
default_policy_path,
|
||||
local_policy_path,
|
||||
cache_dir,
|
||||
local_policy_cache
|
||||
)
|
||||
@@ -326,7 +326,7 @@ def lp2gpt():
|
||||
'''
|
||||
Convert local-policy to full-featured GPT.
|
||||
'''
|
||||
lppath = os.path.join(default_policy_path(), 'Machine/Registry.pol.xml')
|
||||
lppath = os.path.join(local_policy_path(), 'Machine/Registry.pol.xml')
|
||||
|
||||
# Load settings from XML PolFile
|
||||
polparser = GPPolParser()
|
||||
|
@@ -79,7 +79,7 @@ def read_shortcuts(shortcuts_file):
|
||||
# URL or FILESYSTEM
|
||||
target_type = get_ttype(props.get('targetType'))
|
||||
|
||||
sc = shortcut(dest, path, arguments, link.get('name'), target_type)
|
||||
sc = shortcut(dest, path, arguments, link.get('name'), props.get('action'), target_type)
|
||||
sc.set_changed(link.get('changed'))
|
||||
sc.set_clsid(link.get('clsid'))
|
||||
sc.set_guid(link.get('uid'))
|
||||
@@ -100,7 +100,7 @@ def json2sc(json_str):
|
||||
json_obj = json.loads(json_str)
|
||||
link_type = get_ttype(json_obj['type'])
|
||||
|
||||
sc = shortcut(json_obj['dest'], json_obj['path'], json_obj['arguments'], json_obj['name'], link_type)
|
||||
sc = shortcut(json_obj['dest'], json_obj['path'], json_obj['arguments'], json_obj['name'], json_obj['action'], link_type)
|
||||
sc.set_changed(json_obj['changed'])
|
||||
sc.set_clsid(json_obj['clsid'])
|
||||
sc.set_guid(json_obj['guid'])
|
||||
@@ -111,7 +111,7 @@ def json2sc(json_str):
|
||||
return sc
|
||||
|
||||
class shortcut:
|
||||
def __init__(self, dest, path, arguments, name=None, ttype=TargetType.FILESYSTEM):
|
||||
def __init__(self, dest, path, arguments, name=None, action=None, ttype=TargetType.FILESYSTEM):
|
||||
'''
|
||||
:param dest: Path to resulting file on file system
|
||||
:param path: Path where the link should point to
|
||||
@@ -124,6 +124,7 @@ class shortcut:
|
||||
self.expanded_path = None
|
||||
self.arguments = arguments
|
||||
self.name = name
|
||||
self.action = action
|
||||
self.changed = ''
|
||||
self.icon = None
|
||||
self.is_in_user_context = self.set_usercontext()
|
||||
@@ -188,6 +189,7 @@ class shortcut:
|
||||
content['clsid'] = self.clsid
|
||||
content['guid'] = self.guid
|
||||
content['changed'] = self.changed
|
||||
content['action'] = self.action
|
||||
content['is_in_user_context'] = self.is_in_user_context
|
||||
content['type'] = ttype2str(self.type)
|
||||
if self.icon:
|
||||
@@ -197,19 +199,29 @@ class shortcut:
|
||||
|
||||
return json.dumps(result.content)
|
||||
|
||||
def desktop(self):
|
||||
def desktop(self, dest=None):
|
||||
'''
|
||||
Returns desktop file object which may be written to disk.
|
||||
'''
|
||||
self.desktop_file = DesktopEntry()
|
||||
self.desktop_file.addGroup('Desktop Entry')
|
||||
if dest:
|
||||
self.desktop_file = DesktopEntry(dest)
|
||||
else:
|
||||
self.desktop_file = DesktopEntry()
|
||||
self.desktop_file.addGroup('Desktop Entry')
|
||||
self.desktop_file.set('Version', '1.0')
|
||||
self._update_desktop()
|
||||
|
||||
return self.desktop_file
|
||||
|
||||
def _update_desktop(self):
|
||||
'''
|
||||
Update desktop file object from internal data.
|
||||
'''
|
||||
if self.type == TargetType.URL:
|
||||
self.desktop_file.set('Type', 'Link')
|
||||
else:
|
||||
self.desktop_file.set('Type', 'Application')
|
||||
|
||||
self.desktop_file.set('Version', '1.0')
|
||||
self.desktop_file.set('Name', self.name)
|
||||
|
||||
desktop_path = self.path
|
||||
@@ -224,15 +236,41 @@ class shortcut:
|
||||
if self.icon:
|
||||
self.desktop_file.set('Icon', self.icon)
|
||||
|
||||
return self.desktop_file
|
||||
|
||||
def write_desktop(self, dest):
|
||||
def _write_desktop(self, dest, create_only=False, read_firstly=False):
|
||||
'''
|
||||
Write .desktop file to disk using path 'dest'. Please note that
|
||||
.desktop files must have executable bit set in order to work in
|
||||
GUI.
|
||||
'''
|
||||
self.desktop().write(dest)
|
||||
sc = Path(dest)
|
||||
if sc.exists() and create_only:
|
||||
return
|
||||
|
||||
if sc.exists() and read_firstly:
|
||||
self.desktop(dest).write(dest)
|
||||
else:
|
||||
self.desktop().write(dest)
|
||||
|
||||
sc.chmod(sc.stat().st_mode | stat.S_IEXEC)
|
||||
|
||||
def _remove_desktop(self, dest):
|
||||
'''
|
||||
Remove .desktop file fromo disk using path 'dest'.
|
||||
'''
|
||||
sc = Path(dest)
|
||||
if sc.exists():
|
||||
sc.unlink()
|
||||
|
||||
def apply_desktop(self, dest):
|
||||
'''
|
||||
Apply .desktop file by action.
|
||||
'''
|
||||
if self.action == 'U':
|
||||
self._write_desktop(dest, read_firstly=True)
|
||||
elif self.action == 'D':
|
||||
self._remove_desktop(dest)
|
||||
elif self.action == 'R':
|
||||
self._remove_desktop(dest)
|
||||
self._write_desktop(dest)
|
||||
elif self.action == 'C':
|
||||
self._write_desktop(dest, create_only=True)
|
||||
|
@@ -23,8 +23,6 @@ import sys
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
import re
|
||||
|
||||
from util.util import (
|
||||
runcmd
|
||||
, get_backends
|
||||
@@ -33,17 +31,14 @@ from util.util import (
|
||||
, get_policy_variants
|
||||
)
|
||||
from util.config import GPConfig
|
||||
from util.paths import get_custom_policy_dir
|
||||
|
||||
|
||||
class Runner:
|
||||
__control_path = '/usr/sbin/control'
|
||||
__systemctl_path = '/bin/systemctl'
|
||||
__etc_policy_dir = '/etc/local-policy'
|
||||
__usr_policy_dir = '/usr/share/local-policy'
|
||||
|
||||
def __init__(self):
|
||||
self.etc_policies = get_policy_entries(self.__etc_policy_dir)
|
||||
self.usr_policies = get_policy_entries(self.__usr_policy_dir)
|
||||
self.arguments = parse_arguments()
|
||||
|
||||
def parse_arguments():
|
||||
@@ -194,13 +189,13 @@ def disable_gp():
|
||||
runcmd(cmd_set_local_policy)
|
||||
runcmd(cmd_disable_gpupdate_service)
|
||||
runcmd(cmd_disable_gpupdate_user_service)
|
||||
config.set_local_policy_template()
|
||||
config.set_backend()
|
||||
|
||||
def enable_gp(policy_name, backend_type):
|
||||
'''
|
||||
Consistently enable group policy services
|
||||
'''
|
||||
policy_dir = '/usr/share/local-policy'
|
||||
etc_policy_dir = '/etc/local-policy'
|
||||
cmd_set_gpupdate_policy = ['/usr/sbin/control', 'system-policy', 'gpupdate']
|
||||
cmd_gpoa_nodomain = ['/usr/sbin/gpoa', '--nodomain', '--loglevel', '5']
|
||||
cmd_enable_gpupdate_service = ['/bin/systemctl', 'enable', 'gpupdate.service']
|
||||
@@ -208,18 +203,17 @@ def enable_gp(policy_name, backend_type):
|
||||
|
||||
config = GPConfig()
|
||||
|
||||
custom_policy_dir = get_custom_policy_dir()
|
||||
if not os.path.isdir(custom_policy_dir):
|
||||
os.makedirs(custom_policy_dir)
|
||||
|
||||
target_policy_name = get_default_policy_name()
|
||||
if policy_name:
|
||||
if validate_policy_name(policy_name):
|
||||
target_policy_name = policy_name
|
||||
|
||||
print (target_policy_name)
|
||||
default_policy_name = os.path.join(policy_dir, target_policy_name)
|
||||
|
||||
if not os.path.isdir(etc_policy_dir):
|
||||
os.makedirs(etc_policy_dir)
|
||||
|
||||
config.set_local_policy_template(default_policy_name)
|
||||
config.set_local_policy_template(target_policy_name)
|
||||
config.set_backend(backend_type)
|
||||
|
||||
# Enable oddjobd_gpupdate in PAM config
|
||||
|
@@ -61,6 +61,11 @@ def error_code(code):
|
||||
error_ids[31] = 'Error connecting to DBus Session daemon'
|
||||
error_ids[32] = 'No reply from DBus Session'
|
||||
error_ids[33] = 'Error occured while running forked process with dropped privileges'
|
||||
error_ids[34] = 'Error running GPOA directly for computer'
|
||||
error_ids[35] = 'Error caching URI to file'
|
||||
error_ids[36] = 'Error getting cached file for URI'
|
||||
error_ids[37] = 'Error caching file URIs'
|
||||
error_ids[38] = 'Unable to cache specified URI'
|
||||
|
||||
return error_ids.get(code, 'Unknown error code')
|
||||
|
||||
@@ -124,6 +129,14 @@ def debug_code(code):
|
||||
debug_ids[56] = 'Kill dbus-daemon and dconf-service in user context'
|
||||
debug_ids[57] = 'Found connection by org.freedesktop.DBus.GetConnectionUnixProcessID'
|
||||
debug_ids[58] = 'Connection search return org.freedesktop.DBus.Error.NameHasNoOwner'
|
||||
debug_ids[59] = 'Running GPOA without GPT update directly for user'
|
||||
debug_ids[60] = 'Running GPOA by root for user'
|
||||
debug_ids[61] = 'The GPOA process was started for computer'
|
||||
debug_ids[62] = 'Path not resolved as UNC URI'
|
||||
debug_ids[63] = 'Delete HKLM branch key'
|
||||
debug_ids[64] = 'Delete HKCU branch key'
|
||||
debug_ids[65] = 'Delete HKLM branch key error'
|
||||
debug_ids[66] = 'Delete HKCU branch key error'
|
||||
|
||||
return debug_ids.get(code, 'Unknown debug code')
|
||||
|
||||
|
97
gpoa/storage/fs_file_cache.py
Normal file
97
gpoa/storage/fs_file_cache.py
Normal file
@@ -0,0 +1,97 @@
|
||||
#
|
||||
# GPOA - GPO Applier for Linux
|
||||
#
|
||||
# Copyright (C) 2021 BaseALT Ltd. <org@basealt.ru>
|
||||
# Copyright (C) 2021 Igor Chudov <nir@nir.org.ru>
|
||||
#
|
||||
# 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 os
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
import smbc
|
||||
|
||||
|
||||
from util.logging import log
|
||||
from util.paths import file_cache_dir, UNCPath
|
||||
from util.exceptions import NotUNCPathError
|
||||
|
||||
|
||||
class fs_file_cache:
|
||||
__read_blocksize = 4096
|
||||
|
||||
def __init__(self, cache_name):
|
||||
self.cache_name = cache_name
|
||||
self.storage_uri = file_cache_dir()
|
||||
logdata = dict({'cache_file': self.storage_uri})
|
||||
log('D20', logdata)
|
||||
self.samba_context = smbc.Context(use_kerberos=1)
|
||||
#, debug=10)
|
||||
|
||||
def store(self, uri):
|
||||
destdir = uri
|
||||
try:
|
||||
uri_path = UNCPath(uri)
|
||||
file_name = os.path.basename(uri_path.get_path())
|
||||
file_path = os.path.dirname(uri_path.get_path())
|
||||
destdir = Path('{}/{}/{}'.format(self.storage_uri,
|
||||
uri_path.get_domain(),
|
||||
file_path))
|
||||
except Exception as exc:
|
||||
logdata = dict({'exception': str(exc)})
|
||||
log('E38', logdata)
|
||||
raise exc
|
||||
|
||||
if not destdir.exists():
|
||||
destdir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
destfile = Path('{}/{}/{}'.format(self.storage_uri,
|
||||
uri_path.get_domain(),
|
||||
uri_path.get_path()))
|
||||
|
||||
with open(destfile, 'wb') as df:
|
||||
df.truncate()
|
||||
df.flush()
|
||||
try:
|
||||
file_handler = self.samba_context.open(str(uri_path), os.O_RDONLY)
|
||||
while True:
|
||||
data = file_handler.read(self.__read_blocksize)
|
||||
if not data:
|
||||
break
|
||||
df.write(data)
|
||||
df.flush()
|
||||
except Exception as exc:
|
||||
logdata = dict({'exception': str(exc)})
|
||||
log('E35', logdata)
|
||||
raise exc
|
||||
|
||||
def get(self, uri):
|
||||
destfile = uri
|
||||
try:
|
||||
uri_path = UNCPath(uri)
|
||||
file_name = os.path.basename(uri_path.get_path())
|
||||
file_path = os.path.dirname(uri_path.get_path())
|
||||
destfile = Path('{}/{}/{}'.format(self.storage_uri,
|
||||
uri_path.get_domain(),
|
||||
uri_path.get_path()))
|
||||
except NotUNCPathError as exc:
|
||||
logdata = dict({'path': str(exc)})
|
||||
log('D62', logdata)
|
||||
except Exception as exc:
|
||||
logdata = dict({'exception': str(exc)})
|
||||
log('E36', logdata)
|
||||
raise exc
|
||||
|
||||
return str(destfile)
|
||||
|
@@ -22,7 +22,9 @@ class samba_preg(object):
|
||||
'''
|
||||
def __init__(self, preg_obj, policy_name):
|
||||
self.policy_name = policy_name
|
||||
self.hive_key = '{}\\{}'.format(preg_obj.keyname, preg_obj.valuename)
|
||||
self.keyname = preg_obj.keyname
|
||||
self.valuename = preg_obj.valuename
|
||||
self.hive_key = '{}\\{}'.format(self.keyname, self.valuename)
|
||||
self.type = preg_obj.type
|
||||
self.data = preg_obj.data
|
||||
|
||||
@@ -41,7 +43,9 @@ class samba_hkcu_preg(object):
|
||||
def __init__(self, sid, preg_obj, policy_name):
|
||||
self.sid = sid
|
||||
self.policy_name = policy_name
|
||||
self.hive_key = '{}\\{}'.format(preg_obj.keyname, preg_obj.valuename)
|
||||
self.keyname = preg_obj.keyname
|
||||
self.valuename = preg_obj.valuename
|
||||
self.hive_key = '{}\\{}'.format(self.keyname, self.valuename)
|
||||
self.type = preg_obj.type
|
||||
self.data = preg_obj.data
|
||||
|
||||
|
@@ -68,6 +68,8 @@ class sqlite_registry(registry):
|
||||
, Column('id', Integer, primary_key=True)
|
||||
, Column('hive_key', String(65536, collation='NOCASE'),
|
||||
unique=True)
|
||||
, Column('keyname', String(collation='NOCASE'))
|
||||
, Column('valuename', String(collation='NOCASE'))
|
||||
, Column('policy_name', String)
|
||||
, Column('type', Integer)
|
||||
, Column('data', String)
|
||||
@@ -78,6 +80,8 @@ class sqlite_registry(registry):
|
||||
, Column('id', Integer, primary_key=True)
|
||||
, Column('sid', String)
|
||||
, Column('hive_key', String(65536, collation='NOCASE'))
|
||||
, Column('keyname', String(collation='NOCASE'))
|
||||
, Column('valuename', String(collation='NOCASE'))
|
||||
, Column('policy_name', String)
|
||||
, Column('type', Integer)
|
||||
, Column('data', String)
|
||||
@@ -240,16 +244,52 @@ class sqlite_registry(registry):
|
||||
log('D19', logdata)
|
||||
self._info_upsert(ientry)
|
||||
|
||||
def _delete_hklm_keyname(self, keyname):
|
||||
'''
|
||||
Delete PReg hive_key from HKEY_LOCAL_MACHINE
|
||||
'''
|
||||
logdata = dict({'keyname': keyname})
|
||||
try:
|
||||
(self
|
||||
.db_session
|
||||
.query(samba_preg)
|
||||
.filter(samba_preg.keyname == keyname)
|
||||
.delete(synchronize_session=False))
|
||||
self.db_session.commit()
|
||||
log('D65', logdata)
|
||||
except Exception as exc:
|
||||
log('D63', logdata)
|
||||
|
||||
def add_hklm_entry(self, preg_entry, policy_name):
|
||||
'''
|
||||
Write PReg entry to HKEY_LOCAL_MACHINE
|
||||
'''
|
||||
pentry = samba_preg(preg_entry, policy_name)
|
||||
if not pentry.hive_key.rpartition('\\')[2].startswith('**'):
|
||||
if not pentry.valuename.startswith('**'):
|
||||
self._hklm_upsert(pentry)
|
||||
else:
|
||||
logdata = dict({'key': pentry.hive_key})
|
||||
log('D27', logdata)
|
||||
if pentry.valuename.lower() == '**delvals.':
|
||||
self._delete_hklm_keyname(pentry.keyname)
|
||||
else:
|
||||
log('D27', logdata)
|
||||
|
||||
def _delete_hkcu_keyname(self, keyname, sid):
|
||||
'''
|
||||
Delete PReg hive_key from HKEY_CURRENT_USER
|
||||
'''
|
||||
logdata = dict({'sid': sid, 'keyname': keyname})
|
||||
try:
|
||||
(self
|
||||
.db_session
|
||||
.query(samba_hkcu_preg)
|
||||
.filter(samba_hkcu_preg.sid == sid)
|
||||
.filter(samba_hkcu_preg.keyname == keyname)
|
||||
.delete(synchronize_session=False))
|
||||
self.db_session.commit()
|
||||
log('D66', logdata)
|
||||
except:
|
||||
log('D64', logdata)
|
||||
|
||||
def add_hkcu_entry(self, preg_entry, sid, policy_name):
|
||||
'''
|
||||
@@ -257,11 +297,14 @@ class sqlite_registry(registry):
|
||||
'''
|
||||
hkcu_pentry = samba_hkcu_preg(sid, preg_entry, policy_name)
|
||||
logdata = dict({'sid': sid, 'policy': policy_name, 'key': hkcu_pentry.hive_key})
|
||||
if not hkcu_pentry.hive_key.rpartition('\\')[2].startswith('**'):
|
||||
if not hkcu_pentry.valuename.startswith('**'):
|
||||
log('D26', logdata)
|
||||
self._hkcu_upsert(hkcu_pentry)
|
||||
else:
|
||||
log('D51', logdata)
|
||||
if hkcu_pentry.valuename.lower() == '**delvals.':
|
||||
self._delete_hkcu_keyname(hkcu_pentry.keyname, sid)
|
||||
else:
|
||||
log('D51', logdata)
|
||||
|
||||
def add_shortcut(self, sid, sc_obj, policy_name):
|
||||
'''
|
||||
@@ -335,6 +378,7 @@ class sqlite_registry(registry):
|
||||
.db_session
|
||||
.query(row_object)
|
||||
.filter(row_object.sid == sid)
|
||||
.order_by(row_object.id)
|
||||
.all())
|
||||
return res
|
||||
|
||||
|
@@ -45,7 +45,7 @@ class GPConfig:
|
||||
|
||||
return 'samba'
|
||||
|
||||
def set_backend(self, backend_name):
|
||||
def set_backend(self, backend_name='local'):
|
||||
self.full_config['gpoa']['backend'] = backend_name
|
||||
self.write_config()
|
||||
|
||||
@@ -71,7 +71,7 @@ class GPConfig:
|
||||
|
||||
return get_default_policy_name()
|
||||
|
||||
def set_local_policy_template(self, template_name):
|
||||
def set_local_policy_template(self, template_name='default'):
|
||||
self.full_config['gpoa']['local-policy'] = template_name
|
||||
self.write_config()
|
||||
|
||||
|
@@ -39,3 +39,10 @@ def geterr():
|
||||
|
||||
return traceinfo
|
||||
|
||||
class NotUNCPathError(Exception):
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
|
||||
def __str__(self):
|
||||
return self.path
|
||||
|
||||
|
@@ -21,15 +21,19 @@ import subprocess
|
||||
|
||||
from .util import get_machine_name
|
||||
from .logging import log
|
||||
from .samba import smbopts
|
||||
|
||||
|
||||
def machine_kinit(cache_name=None):
|
||||
'''
|
||||
Perform kinit with machine credentials
|
||||
'''
|
||||
opts = smbopts()
|
||||
host = get_machine_name()
|
||||
realm = opts.get_realm()
|
||||
with_realm = '{}@{}'.format(host, realm)
|
||||
os.environ['KRB5CCNAME'] = 'FILE:{}'.format(cache_name)
|
||||
kinit_cmd = ['kinit', '-k', host]
|
||||
kinit_cmd = ['kinit', '-k', with_realm]
|
||||
if cache_name:
|
||||
kinit_cmd.extend(['-c', cache_name])
|
||||
proc = subprocess.Popen(kinit_cmd)
|
||||
@@ -55,8 +59,9 @@ def machine_kdestroy(cache_name=None):
|
||||
if cache_name:
|
||||
kdestroy_cmd.extend(['-c', cache_name])
|
||||
|
||||
proc = subprocess.Popen(kdestroy_cmd, stderr=subprocess.DEVNULL)
|
||||
proc.wait()
|
||||
if cache_name or 'KRB5CCNAME' in os.environ:
|
||||
proc = subprocess.Popen(kdestroy_cmd, stderr=subprocess.DEVNULL)
|
||||
proc.wait()
|
||||
|
||||
if cache_name and os.path.exists(cache_name):
|
||||
os.unlink(cache_name)
|
||||
|
@@ -1,7 +1,8 @@
|
||||
#
|
||||
# GPOA - GPO Applier for Linux
|
||||
#
|
||||
# Copyright (C) 2019-2020 BaseALT Ltd.
|
||||
# Copyright (C) 2019-2021 BaseALT Ltd. <org@basealt.ru>
|
||||
# Copyright (C) 2019-2021 Igor Chudov <nir@nir.org.ru>
|
||||
#
|
||||
# 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
|
||||
@@ -18,26 +19,38 @@
|
||||
|
||||
import pathlib
|
||||
import os
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from .config import GPConfig
|
||||
from .util import get_default_policy_name
|
||||
from .exceptions import NotUNCPathError
|
||||
|
||||
|
||||
def default_policy_path():
|
||||
def get_custom_policy_dir():
|
||||
'''
|
||||
Returns path pointing to Default Policy directory.
|
||||
Returns path pointing to Custom Policy directory.
|
||||
'''
|
||||
local_policy_default = '/usr/share/local-policy/{}'.format(get_default_policy_name())
|
||||
return '/etc/local-policy'
|
||||
|
||||
def local_policy_path(default_template_name="default"):
|
||||
'''
|
||||
Returns path pointing to Local Policy template directory.
|
||||
'''
|
||||
local_policy_dir = '/usr/share/local-policy'
|
||||
|
||||
config = GPConfig()
|
||||
local_policy_template = config.get_local_policy_template()
|
||||
local_policy_template_path = os.path.join(local_policy_dir, local_policy_template)
|
||||
local_policy_default = os.path.join(local_policy_dir, default_template_name)
|
||||
|
||||
result_path = pathlib.Path(local_policy_default)
|
||||
|
||||
if os.path.exists(config.get_local_policy_template()):
|
||||
result_path = pathlib.Path(config.get_local_policy_template())
|
||||
if os.path.exists(local_policy_template):
|
||||
result_path = pathlib.Path(local_policy_template)
|
||||
elif os.path.exists(local_policy_template_path):
|
||||
result_path = pathlib.Path(local_policy_template_path)
|
||||
|
||||
return pathlib.Path(result_path)
|
||||
|
||||
|
||||
def cache_dir():
|
||||
'''
|
||||
Returns path pointing to gpupdate's cache directory
|
||||
@@ -49,6 +62,16 @@ def cache_dir():
|
||||
|
||||
return cachedir
|
||||
|
||||
def file_cache_dir():
|
||||
'''
|
||||
Returns path pointing to gpupdate's cache directory
|
||||
'''
|
||||
cachedir = pathlib.Path('/var/cache/gpupdate_file_cache')
|
||||
|
||||
if not cachedir.exists():
|
||||
cachedir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
return cachedir
|
||||
|
||||
def local_policy_cache():
|
||||
'''
|
||||
@@ -62,3 +85,46 @@ def local_policy_cache():
|
||||
|
||||
return lpcache
|
||||
|
||||
class UNCPath:
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
self.type = None
|
||||
if self.path.startswith(r'smb://'):
|
||||
self.type = 'uri'
|
||||
if self.path.startswith(r'\\'):
|
||||
self.type = 'unc'
|
||||
if not self.type:
|
||||
raise NotUNCPathError(path)
|
||||
|
||||
def get_uri(self):
|
||||
path = self.path
|
||||
if self.type == 'unc':
|
||||
path = self.path.replace('\\', '/')
|
||||
path = path.replace('//', 'smb://')
|
||||
else:
|
||||
pass
|
||||
|
||||
return path
|
||||
|
||||
def get_unc(self):
|
||||
path = self.path
|
||||
if self.type == 'uri':
|
||||
path = self.path.replace('//', '\\\\')
|
||||
path = path.replace('smb:\\\\', '\\\\')
|
||||
path = path.replace('/', '\\')
|
||||
else:
|
||||
pass
|
||||
|
||||
return path
|
||||
|
||||
def get_domain(self):
|
||||
schema_struct = urlparse(self.get_uri())
|
||||
return schema_struct.netloc
|
||||
|
||||
def get_path(self):
|
||||
schema_struct = urlparse(self.get_uri())
|
||||
return schema_struct.path
|
||||
|
||||
def __str__(self):
|
||||
return self.get_uri()
|
||||
|
||||
|
@@ -18,6 +18,7 @@
|
||||
|
||||
|
||||
import optparse
|
||||
import socket
|
||||
from samba import getopt as options
|
||||
|
||||
|
||||
@@ -28,11 +29,32 @@ class smbopts:
|
||||
self.sambaopts = options.SambaOptions(self.parser)
|
||||
self.lp = self.sambaopts.get_loadparm()
|
||||
|
||||
def get_realm(self):
|
||||
'''
|
||||
Get the default realm specified in smb.conf file.
|
||||
'''
|
||||
return self._get_prop('realm')
|
||||
|
||||
def get_cache_dir(self):
|
||||
return self._get_prop('cache directory')
|
||||
|
||||
def get_server_role(self):
|
||||
return self._get_prop('server role')
|
||||
|
||||
def get_machine_name(self):
|
||||
'''
|
||||
Get localhost name looking like DC0$
|
||||
'''
|
||||
nb_name = self.get_netbios_name()
|
||||
result = nb_name + "$"
|
||||
|
||||
if result == '':
|
||||
result = socket.gethostname().split('.', 1)[0].upper() + "$"
|
||||
|
||||
return result
|
||||
|
||||
def get_netbios_name(self):
|
||||
return self._get_prop('netbios name')
|
||||
|
||||
def _get_prop(self, property_name):
|
||||
return self.lp.get(property_name)
|
||||
|
@@ -17,10 +17,10 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import socket
|
||||
import os
|
||||
import pwd
|
||||
import subprocess
|
||||
import re
|
||||
from pathlib import Path
|
||||
from .samba import smbopts
|
||||
|
||||
@@ -29,7 +29,10 @@ def get_machine_name():
|
||||
'''
|
||||
Get localhost name looking like DC0$
|
||||
'''
|
||||
return socket.gethostname().split('.', 1)[0].upper() + "$"
|
||||
loadparm = smbopts()
|
||||
result = loadparm.get_machine_name()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def is_machine_name(name):
|
||||
|
@@ -105,7 +105,7 @@ class smbcreds (smbopts):
|
||||
for gpo in gpos:
|
||||
# These setters are taken from libgpo/pygpo.c
|
||||
# print(gpo.ds_path) # LDAP entry
|
||||
ldata = dict({'gpo_name': gpo.display_name, 'gpo_uuid': gpo.name})
|
||||
ldata = dict({'gpo_name': gpo.display_name, 'gpo_uuid': gpo.name, 'file_sys_path': gpo.file_sys_path})
|
||||
log('I2', ldata)
|
||||
|
||||
except Exception as exc:
|
||||
|
@@ -1,8 +1,8 @@
|
||||
%define _unpackaged_files_terminate_build 1
|
||||
|
||||
Name: gpupdate
|
||||
Version: 0.9.2
|
||||
Release: alt1
|
||||
Version: 0.9.8
|
||||
Release: alt0.dev1
|
||||
|
||||
Summary: GPT applier
|
||||
License: GPLv3+
|
||||
@@ -18,11 +18,13 @@ Requires: python3-module-rpm
|
||||
Requires: python3-module-dbus
|
||||
Requires: oddjob-%name >= 0.2.0
|
||||
Requires: libnss-role >= 0.5.0
|
||||
Requires: local-policy >= 0.4.0
|
||||
Requires: local-policy >= 0.4.9
|
||||
Requires: pam-config >= 1.9.0
|
||||
Requires: autofs
|
||||
# This is needed by shortcuts_applier
|
||||
Requires: desktop-file-utils
|
||||
# This is needed for smb file cache support
|
||||
Requires: python3-module-smbc >= 1.0.23-alt3
|
||||
|
||||
Source0: %name-%version.tar
|
||||
|
||||
@@ -48,6 +50,7 @@ mkdir -p \
|
||||
%buildroot%_bindir/ \
|
||||
%buildroot%_sbindir/ \
|
||||
%buildroot%_cachedir/%name/ \
|
||||
%buildroot%_cachedir/%{name}_file_cache/ \
|
||||
%buildroot%_cachedir/%name/creds
|
||||
|
||||
ln -s %python3_sitelibdir/gpoa/gpoa \
|
||||
@@ -65,12 +68,20 @@ mkdir -p %buildroot%_sysconfdir/%name
|
||||
touch %buildroot%_sysconfdir/%name/environment
|
||||
|
||||
install -Dm0644 dist/%name.service %buildroot%_unitdir/%name.service
|
||||
install -Dm0644 dist/%name.service %buildroot/usr/lib/systemd/user/%name-user.service
|
||||
install -Dm0644 dist/%name-user.service %buildroot/usr/lib/systemd/user/%name-user.service
|
||||
install -Dm0644 dist/system-policy-%name %buildroot%_sysconfdir/pam.d/system-policy-%name
|
||||
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
|
||||
|
||||
for i in gpupdate-localusers \
|
||||
gpupdate-group-users \
|
||||
gpupdate-system-uids
|
||||
do
|
||||
install -pD -m755 "dist/$i" \
|
||||
"%buildroot%_sysconfdir/control.d/facilities/$i"
|
||||
done
|
||||
|
||||
%preun
|
||||
%preun_service gpupdate
|
||||
|
||||
@@ -80,7 +91,7 @@ install -Dm0644 doc/gpupdate.1 %buildroot/%_man1dir/gpupdate.1
|
||||
# Remove storage in case we've lost compatibility between versions.
|
||||
# The storage will be regenerated on GPOA start.
|
||||
%define active_policy %_sysconfdir/local-policy/active
|
||||
%triggerpostun -- %name < 0.8.0
|
||||
%triggerpostun -- %name < 0.9.6
|
||||
rm -f %_cachedir/%name/registry.sqlite
|
||||
if test -L %active_policy; then
|
||||
sed -i "s|^\s*local-policy\s*=.*|local-policy = $(readlink -f %active_policy)|" \
|
||||
@@ -101,10 +112,12 @@ fi
|
||||
%_man1dir/gpupdate.1.*
|
||||
/usr/lib/systemd/user/%name-user.service
|
||||
%dir %_sysconfdir/%name
|
||||
%_sysconfdir/control.d/facilities/*
|
||||
%config(noreplace) %_sysconfdir/%name/environment
|
||||
%config(noreplace) %_sysconfdir/%name/%name.ini
|
||||
%config(noreplace) %_sysconfdir/pam.d/system-policy-%name
|
||||
%dir %attr(0700, root, root) %_cachedir/%name
|
||||
%dir %attr(0755, root, root) %_cachedir/%{name}_file_cache
|
||||
%dir %attr(0700, root, root) %_cachedir/%name/creds
|
||||
%exclude %python3_sitelibdir/gpoa/.pylintrc
|
||||
%exclude %python3_sitelibdir/gpoa/.prospector.yaml
|
||||
@@ -112,6 +125,36 @@ fi
|
||||
%exclude %python3_sitelibdir/gpoa/test
|
||||
|
||||
%changelog
|
||||
* Wed Sep 29 2021 Evgeny Sinelnikov <sin@altlinux.org> 0.9.7-alt1
|
||||
- Fix regression with kestroy for user credential cache
|
||||
- Update system-policy-gpupdate PAM-rules to ignore applying group policies
|
||||
for local users and system users with uid less than 500
|
||||
- Add control facilities to rule system-policy-gpupdate rules:
|
||||
+ gpupdate-group-users
|
||||
+ gpupdate-localusers
|
||||
+ gpupdate-system-uids
|
||||
|
||||
* Mon Sep 20 2021 Evgeny Sinelnikov <sin@altlinux.org> 0.9.6-alt1
|
||||
- Add support changed GPO List Processing for '**DelVals.' value name
|
||||
|
||||
* Tue Sep 14 2021 Evgeny Sinelnikov <sin@altlinux.org> 0.9.5-alt1
|
||||
- Refix local policy path detection
|
||||
- gpupdate-setup: revert settings to default when disabled
|
||||
|
||||
* Tue Sep 14 2021 Evgeny Sinelnikov <sin@altlinux.org> 0.9.4-alt1
|
||||
- Add improvement with new local-policy system-policy control
|
||||
- Fix gpupdate-setup and user service installation regressions
|
||||
- Set empty local policy and local backend by default
|
||||
- Fix local policy path detection
|
||||
|
||||
* Mon Sep 06 2021 Evgeny Sinelnikov <sin@altlinux.org> 0.9.3-alt1
|
||||
- Use NetBIOS name for Kerberos authentification
|
||||
- Add support actions (create, update, delete, replace) for Shortcuts
|
||||
- Add support GSettings with locks feature
|
||||
- Add support file cache for special GSettings policy:
|
||||
Software\BaseALT\Policies\GSettings\org.mate.background.picture-filename
|
||||
(requires python smbc module with use_kerberos option support)
|
||||
|
||||
* Wed Jul 28 2021 Evgeny Sinelnikov <sin@altlinux.org> 0.9.2-alt1
|
||||
- Fix Shortcuts applier double running in user context
|
||||
- Add LogonUser variable to expand_windows_var() function
|
||||
|
Reference in New Issue
Block a user