mirror of
https://github.com/altlinux/gpupdate.git
synced 2025-01-18 02:04:48 +03:00
Initial release
This commit is contained in:
commit
66f5b751b6
2
.gear/rules
Normal file
2
.gear/rules
Normal file
@ -0,0 +1,2 @@
|
||||
tar: .
|
||||
|
0
gpoa/__init__.py
Normal file
0
gpoa/__init__.py
Normal file
27
gpoa/control/__init__.py
Normal file
27
gpoa/control/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
class control:
|
||||
def __init__(self, name, value):
|
||||
self.control_name = name
|
||||
self.control_value = value
|
||||
self.possible_values = self._query_control_values()
|
||||
|
||||
def _query_control_values(self):
|
||||
proc = subprocess.Popen(['sudo', 'control', self.control_name, 'list'], stdout=subprocess.PIPE)
|
||||
for line in proc.stdout:
|
||||
values = line.split()
|
||||
return values
|
||||
|
||||
def get_control_name(self):
|
||||
return self.control_name
|
||||
|
||||
def get_control_status(self):
|
||||
proc = subprocess.Popen(['sudo', 'control', self.control_name], stdout=subprocess.PIPE)
|
||||
for line in proc.stdout:
|
||||
return line.rstrip('\n\r')
|
||||
|
||||
def set_control_status(self):
|
||||
print('Setting control {} to {}'.format(self.control_name, self.control_value))
|
||||
#proc = subprocess.Popen(['sudo', 'control', self.control_name, status], stdout=subprocess.PIPE)
|
||||
|
2
gpoa/generator/gen.py
Normal file
2
gpoa/generator/gen.py
Normal file
@ -0,0 +1,2 @@
|
||||
if __name__ == "__main__":
|
||||
print("main here!")
|
1
gpoa/generator/requirements.txt
Normal file
1
gpoa/generator/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
Jinja2
|
339
gpoa/main.py
Executable file
339
gpoa/main.py
Executable file
@ -0,0 +1,339 @@
|
||||
#! /usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
# Facility to determine GPTs for user
|
||||
import optparse
|
||||
from samba import getopt as options
|
||||
from samba.gpclass import get_dc_hostname, gpo_version, check_safe_path
|
||||
import samba.gpo
|
||||
|
||||
# Primitives to work with libregistry
|
||||
# samba.registry.str_regtype(2) -> 'REG_EXPAND_SZ'
|
||||
# Taken from python/samba/tests/registry.py
|
||||
from samba import registry
|
||||
|
||||
# PReg object generator
|
||||
from samba.dcerpc import preg
|
||||
from samba.dcerpc import misc
|
||||
import samba.ndr
|
||||
|
||||
from samba.gp_parse.gp_pol import GPPolParser
|
||||
|
||||
# This is needed by Registry.pol file search
|
||||
import os
|
||||
import re
|
||||
# This is needed for merging lists of PReg files.
|
||||
import itertools
|
||||
|
||||
# Our native control facility
|
||||
import control
|
||||
|
||||
class applier_backend:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
class hreg_filesystem_backend(applier_backend):
|
||||
_gpupdate_cache = '/var/cache/gpupdate'
|
||||
_base_path = '/tmp/gpoa_scripts'
|
||||
|
||||
def __init__(self, sid):
|
||||
self._sid = sid
|
||||
self._root_path = '{base}/root'.format(base=self._base_path)
|
||||
self._user_path = '{base}/user'.format(base=self._base_path)
|
||||
|
||||
def _get_files(self, dir_path):
|
||||
'''
|
||||
List all files located in hreg cache
|
||||
'''
|
||||
files = list()
|
||||
for entry in os.listdir(dir_path):
|
||||
abspath = os.path.join(dir_path, entry)
|
||||
try:
|
||||
if os.path.isdir(abspath):
|
||||
files.append(self._get_files(abspath))
|
||||
else:
|
||||
files.append(abspath)
|
||||
except:
|
||||
pass
|
||||
return files
|
||||
|
||||
def _read_value(self, path):
|
||||
'''
|
||||
Read hreg-cached value from file and return object representing it.
|
||||
'''
|
||||
pass
|
||||
|
||||
def get_values(self):
|
||||
cpath = os.path.join(self._gpupdate_cache, self._sid)
|
||||
|
||||
entry_list = self._get_files(cpath)
|
||||
for entry in entry_list:
|
||||
val = self._read_value(entry)
|
||||
|
||||
|
||||
class samba_backend(applier_backend):
|
||||
_samba_registry_file = '/var/cache/samba/registry.ldb'
|
||||
_mahine_hive = 'HKEY_LOCAL_MACHINE'
|
||||
_user_hive = 'HKEY_CURRENT_USER'
|
||||
_machine_pol_path_pattern = '[Mm][Aa][Cc][Hh][Ii][Nn][Ee]'
|
||||
_user_pol_path_pattern = '[Uu][Ss][Ee][Rr]'
|
||||
|
||||
def _check_sysvol_present(self, gpo):
|
||||
'''
|
||||
Check if there is SYSVOL path for GPO assigned
|
||||
'''
|
||||
if not gpo.file_sys_path:
|
||||
print('No SYSVOL entry assigned to GPO {}'.format(gpo.name))
|
||||
return False
|
||||
return True
|
||||
|
||||
def _gpo_get_gpt_polfiles(self, gpo_obj):
|
||||
'''
|
||||
Find absolute path to cached GPT directory and return
|
||||
dict of lists with PReg file paths.
|
||||
'''
|
||||
if self._check_sysvol_present(gpo_obj):
|
||||
print('Found SYSVOL entry {} for GPO {}'.format(gpo_obj.file_sys_path, gpo_obj.name))
|
||||
path = check_safe_path(gpo_obj.file_sys_path).upper()
|
||||
gpt_abspath = os.path.join(self.cache_dir, 'gpo_cache', path)
|
||||
print('Path: {}'.format(path))
|
||||
policy_files = self._find_regpol_files(gpt_abspath)
|
||||
|
||||
return policy_files
|
||||
return dict({ 'machine_regpols': [], 'user_regpols': [] })
|
||||
|
||||
def __init__(self, loadparm, creds, sid, dc):
|
||||
# Regular expressions to split PReg files into user and machine parts
|
||||
self._machine_pol_path_regex = re.compile(self._machine_pol_path_pattern)
|
||||
self._user_pol_path_regex = re.compile(self._user_pol_path_pattern)
|
||||
|
||||
# User SID to work with HKCU hive
|
||||
self.sid = sid
|
||||
|
||||
# Look at python-samba tests for code examples
|
||||
self.registry = registry.Registry()
|
||||
self.machine_hive = registry.open_ldb('/tmp/machine_hive.ldb')
|
||||
self.user_hive = registry.open_ldb('/tmp/HKCU-{}.ldb'.format(self.sid))
|
||||
self.registry.mount_hive(self.machine_hive, samba.registry.HKEY_LOCAL_MACHINE)
|
||||
self.registry.mount_hive(self.user_hive, samba.registry.HKEY_CURRENT_USER)
|
||||
|
||||
# Samba objects - LoadParm() and CredentialsOptions()
|
||||
self.loadparm = loadparm
|
||||
self.creds = creds
|
||||
|
||||
self.cache_dir = self.loadparm.get('cache directory')
|
||||
print('Cache directory is: {}'.format(self.cache_dir))
|
||||
|
||||
gpos = get_gpo_list(dc, self.creds, self.loadparm, 'administrator')
|
||||
self.policy_files = dict({ 'machine_regpols': [], 'user_regpols': [] })
|
||||
for gpo in gpos:
|
||||
polfiles = self._gpo_get_gpt_polfiles(gpo)
|
||||
self.policy_files['machine_regpols'] += polfiles['machine_regpols']
|
||||
self.policy_files['user_regpols'] += polfiles['user_regpols']
|
||||
print('Policy files: {}'.format(self.policy_files))
|
||||
|
||||
def _parse_pol_file(self, polfile):
|
||||
'''
|
||||
Parse PReg file and return its preg object
|
||||
'''
|
||||
gpparser = GPPolParser()
|
||||
data = None
|
||||
|
||||
with open(polfile, 'rb') as f:
|
||||
data = f.read()
|
||||
gpparser.parse(data)
|
||||
|
||||
#print(gpparser.pol_file.__ndr_print__())
|
||||
return gpparser.pol_file
|
||||
|
||||
def _merge_entry(self, hive, entry):
|
||||
'''
|
||||
Write preg.entry to hive
|
||||
'''
|
||||
# Build hive key path from PReg's key name and value name.
|
||||
hive_key = '{}\\{}'.format(entry.keyname, entry.valuename)
|
||||
print('Merging {}'.format(hive_key))
|
||||
|
||||
hive.set_value(hive_key, entry.type, entry.data.to_bytes(4, byteorder='big'))
|
||||
|
||||
# Dump data to disk
|
||||
hive.flush()
|
||||
|
||||
def get_values(self):
|
||||
'''
|
||||
Read data from PReg file and return list of NDR objects (samba.preg)
|
||||
'''
|
||||
# FIXME: Return registry and hives instead of samba.preg objects.
|
||||
preg_objs = []
|
||||
print('Parsing machine regpols')
|
||||
for regpol in self.policy_files['machine_regpols']:
|
||||
print('Processing {}'.format(regpol))
|
||||
pregfile = self._parse_pol_file(regpol)
|
||||
preg_objs.append(pregfile)
|
||||
for entry in pregfile.entries:
|
||||
self._merge_entry(self.machine_hive, entry)
|
||||
|
||||
return preg_objs
|
||||
|
||||
def _find_regpol_files(self, gpt_path):
|
||||
'''
|
||||
Seek through given GPT directory absolute path and return the dictionary
|
||||
of user's and machine's Registry.pol files.
|
||||
'''
|
||||
print('Finding regpols in: {}'.format(gpt_path))
|
||||
polfiles = dict({ 'machine_regpols': [], 'user_regpols': [] })
|
||||
for root, dirs, files in os.walk(gpt_path):
|
||||
for gpt_file in files:
|
||||
if gpt_file.endswith('.pol'):
|
||||
regpol_abspath = os.path.join(root, gpt_file)
|
||||
if self._machine_pol_path_regex.search(regpol_abspath):
|
||||
polfiles['machine_regpols'].append(regpol_abspath)
|
||||
else:
|
||||
polfiles['user_regpols'].append(regpol_abspath)
|
||||
print('Polfiles: {}'.format(polfiles))
|
||||
return polfiles
|
||||
|
||||
|
||||
|
||||
class applier_frontend:
|
||||
def __init__(self, regobj):
|
||||
pass
|
||||
|
||||
def apply(self):
|
||||
pass
|
||||
|
||||
class control_applier(applier_frontend):
|
||||
_registry_branch = 'Software\\BaseALT\\Policies\\Control'
|
||||
|
||||
def __init__(self, polfiles):
|
||||
self.polparsers = polfiles
|
||||
self.control_settings = self._get_controls(self.polparsers)
|
||||
self.controls = []
|
||||
for setting in self.control_settings:
|
||||
self.controls.append(control.control(setting.valuename, setting.data))
|
||||
#for e in polfile.pol_file.entries:
|
||||
# print('{}:{}:{}:{}:{}'.format(e.type, e.data, e.valuename, e.keyname))
|
||||
|
||||
def _get_controls(self, polfiles):
|
||||
'''
|
||||
Extract control entries from PReg file
|
||||
'''
|
||||
controls = []
|
||||
for parser in polfiles:
|
||||
for entry in parser.entries:
|
||||
if entry.keyname == self._registry_branch:
|
||||
controls.append(entry)
|
||||
print('Found control setting: {}'.format(entry.valuename))
|
||||
else:
|
||||
# Property names are taken from python/samba/gp_parse/gp_pol.py
|
||||
print('Dropped control setting: {}\\{}'.format(entry.keyname, entry.valuename))
|
||||
return controls
|
||||
|
||||
def apply(self):
|
||||
'''
|
||||
Trigger control facility invocation.
|
||||
'''
|
||||
for control in self.controls:
|
||||
control.set_control_status()
|
||||
|
||||
def dump_settings(self):
|
||||
'''
|
||||
Write actual controls as XML and PReg files
|
||||
'''
|
||||
print('Dumping...')
|
||||
polfile = preg.file()
|
||||
polfile.header.signature = 'PReg'
|
||||
polfile.header.version = 1
|
||||
polfile.num_entries = len(self.control_settings)
|
||||
polfile.entries = self.control_settings
|
||||
print(polfile.__ndr_print__())
|
||||
|
||||
policy_writer = GPPolParser()
|
||||
policy_writer.pol_file = polfile
|
||||
policy_writer.write_xml('test_reg.xml')
|
||||
policy_writer.write_binary('test_reg.pol')
|
||||
|
||||
class applier:
|
||||
def __init__(self, backend):
|
||||
self.backend = backend
|
||||
self.gpvalues = self.load_values()
|
||||
print('Values: {}'.format(self.gpvalues))
|
||||
capplier = control_applier(self.gpvalues)
|
||||
self.appliers = dict({ 'control': capplier })
|
||||
|
||||
def load_values(self):
|
||||
'''
|
||||
This thing returns the list of samba.preg objects for
|
||||
now but it must be transformed to return registry and
|
||||
its hives to read values from.
|
||||
'''
|
||||
print('Get values from backend')
|
||||
return self.backend.get_values()
|
||||
|
||||
def apply_parameters(self):
|
||||
print('Applying')
|
||||
self.appliers['control'].apply()
|
||||
# This thing dumps Registry.pol files to disk from data structures
|
||||
#print('Writing settings to file')
|
||||
#self.appliers['control'].dump_settings()
|
||||
|
||||
def parse_arguments():
|
||||
arguments = argparse.ArgumentParser(description='Generate configuration out of parsed policies')
|
||||
arguments.add_argument('sid',
|
||||
type=str,
|
||||
help='SID to parse policies from')
|
||||
arguments.add_argument('--dc',
|
||||
type=str,
|
||||
help='FQDN of the domain to replicate SYSVOL from')
|
||||
return arguments.parse_args()
|
||||
|
||||
def get_gpo_list(dc_hostname, creds, lp, user):
|
||||
gpos = []
|
||||
ads = samba.gpo.ADS_STRUCT(dc_hostname, lp, creds)
|
||||
if ads.connect():
|
||||
#gpos = ads.get_gpo_list(creds.get_username())
|
||||
gpos = ads.get_gpo_list(user)
|
||||
print('Got GPO list:')
|
||||
for gpo in gpos:
|
||||
# These setters are taken from libgpo/pygpo.c
|
||||
# print(gpo.ds_path) # LDAP entry
|
||||
print('{} ({})'.format(gpo.display_name, gpo.name))
|
||||
print('------')
|
||||
return gpos
|
||||
|
||||
def get_machine_domain():
|
||||
pass
|
||||
|
||||
def select_dc(lp, creds, dc):
|
||||
samba_dc = get_dc_hostname(creds, lp)
|
||||
|
||||
if samba_dc != dc and dc != None:
|
||||
print('Samba DC setting is {} and is overwritten by user setting {}'.format(samba_dc, dc))
|
||||
return dc
|
||||
|
||||
return samba_dc
|
||||
|
||||
def main():
|
||||
args = parse_arguments()
|
||||
|
||||
#back = hreg_filesystem_backend(args.sid)
|
||||
parser = optparse.OptionParser('GPO Applier')
|
||||
sambaopts = options.SambaOptions(parser)
|
||||
credopts = options.CredentialsOptions(parser)
|
||||
# Initialize loadparm context
|
||||
lp = sambaopts.get_loadparm()
|
||||
creds = credopts.get_credentials(lp, fallback_machine=True)
|
||||
|
||||
# Determine the default Samba DC for replication and try
|
||||
# to overwrite it with user setting.
|
||||
dc = select_dc(lp, creds, args.dc)
|
||||
|
||||
back = samba_backend(lp, creds, args.sid, dc)
|
||||
|
||||
appl = applier(back)
|
||||
appl.apply_parameters()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
13
gpoa/policy/__init__.py
Normal file
13
gpoa/policy/__init__.py
Normal file
@ -0,0 +1,13 @@
|
||||
import policy.firewall
|
||||
import policy.removable_devices_perms
|
||||
import policy.printers
|
||||
import policy.shortcuts
|
||||
import policy.applications
|
||||
from policy.common import Perms
|
||||
|
||||
data_roots = {}
|
||||
data_roots.update(policy.firewall.data_roots)
|
||||
data_roots.update(policy.removable_devices_perms.data_roots)
|
||||
data_roots.update(policy.printers.data_roots)
|
||||
data_roots.update(policy.shortcuts.data_roots)
|
||||
data_roots.update(policy.applications.data_roots)
|
24
gpoa/policy/applications.py
Normal file
24
gpoa/policy/applications.py
Normal file
@ -0,0 +1,24 @@
|
||||
from policy.common import Policy, Perms
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
class Applications (Policy):
|
||||
def __init__(self):
|
||||
self._Policy__name = "Applications"
|
||||
self._Policy__script_name = "applications.sh"
|
||||
self._Policy__template = "applications.bash.j2"
|
||||
self._Policy__perms = Perms.ROOT
|
||||
|
||||
def process(self, scope, path):
|
||||
applications = []
|
||||
print("{name} processing {path} ({scope})".format(name=self.name,path=path,scope=scope))
|
||||
for p in os.listdir(path):
|
||||
package_name = Path('{}/{}/packageName'.format(path, p)).read_text()
|
||||
product_name = Path('{}/{}/productName'.format(path, p)).read_text()
|
||||
applications.append({'uuid': p, 'package': package_name, 'name': product_name})
|
||||
|
||||
return ({'applications': applications})
|
||||
|
||||
data_roots = {
|
||||
"Applications": Applications
|
||||
}
|
44
gpoa/policy/common.py
Normal file
44
gpoa/policy/common.py
Normal file
@ -0,0 +1,44 @@
|
||||
from enum import Enum
|
||||
|
||||
class Perms (Enum):
|
||||
USER = 1
|
||||
ROOT = 2
|
||||
|
||||
class Policy (object):
|
||||
@property
|
||||
def name(self):
|
||||
try:
|
||||
return self.__name
|
||||
except AttributeError as e:
|
||||
raise e
|
||||
|
||||
@property
|
||||
def script_name(self):
|
||||
try:
|
||||
return self.__script_name
|
||||
except AttributeError as e:
|
||||
raise e
|
||||
|
||||
@property
|
||||
def template(self):
|
||||
try:
|
||||
return self.__template
|
||||
except AttributeError as e:
|
||||
raise e
|
||||
|
||||
@property
|
||||
def data_roots(self):
|
||||
try:
|
||||
return self.__data_roots
|
||||
except AttributeError as e:
|
||||
raise e
|
||||
|
||||
@property
|
||||
def perms(self):
|
||||
try:
|
||||
return self.__perms
|
||||
except AttributeError as e:
|
||||
raise e
|
||||
|
||||
def process(self, scope, path):
|
||||
raise "process must be implemented in child class"
|
46
gpoa/policy/firewall.py
Normal file
46
gpoa/policy/firewall.py
Normal file
@ -0,0 +1,46 @@
|
||||
from policy.common import Policy, Perms
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
class Firewall (Policy):
|
||||
def __init__(self):
|
||||
self._Policy__name = "Firewall"
|
||||
self._Policy__script_name = "firewall.sh"
|
||||
self._Policy__template = "firewall.bash.j2"
|
||||
self._Policy__perms = Perms.ROOT
|
||||
|
||||
def process(self, scope, path):
|
||||
print("{name} processing {path} ({scope})".format(name=self.name,path=path,scope=scope))
|
||||
zoneRules = {}
|
||||
for p in os.listdir(path):
|
||||
if path.split('/')[-1:] == ["WindowsFirewall"]:
|
||||
for zone in os.listdir(path):
|
||||
print("processing {} prifile".format(zone))
|
||||
zoneRules[zone] = self.__process_firewall_rules(zone, path)
|
||||
|
||||
return ({'zoneRules': zoneRules})
|
||||
|
||||
def __process_firewall_rules(self, zone, path):
|
||||
print("processing rules in {} zone".format(zone))
|
||||
base = "{}/{}".format(path, zone)
|
||||
openPortsPath = "GloballyOpenPorts"
|
||||
rules = {}
|
||||
if os.path.exists("{}/{}".format(base, openPortsPath)):
|
||||
listPath = "{}/{}/List".format(base, openPortsPath)
|
||||
openPorts = []
|
||||
for r in os.listdir(listPath):
|
||||
rule = Path('{}/{}'.format(listPath, r)).read_text()
|
||||
[port, proto, srcs, enabled, name] = rule.split(':')
|
||||
sources = srcs.split(',')
|
||||
openPorts.append({'proto': proto, 'port': port, 'sources': sources})
|
||||
rules['openPorts'] = openPorts
|
||||
|
||||
return(rules)
|
||||
|
||||
# for r in os.listdir("{}/{}".format(path,zone)):
|
||||
# print(r)
|
||||
|
||||
data_roots = {
|
||||
"Software/Microsoft/Windows/CurrentVersion/Policies/NetworkAccessProtection/ClientConfig": Firewall,
|
||||
"Software/Microsoft/Windows/CurrentVersion/Policies/WindowsFirewall": Firewall
|
||||
}
|
40
gpoa/policy/printers.py
Normal file
40
gpoa/policy/printers.py
Normal file
@ -0,0 +1,40 @@
|
||||
from policy.common import Policy, Perms
|
||||
import os
|
||||
|
||||
class Printers (Policy):
|
||||
def __init__(self):
|
||||
self._Policy__name = "Printers"
|
||||
self._Policy__script_name = "printers.sh"
|
||||
self._Policy__template = "printers.bash.j2"
|
||||
self._Policy__perms = Perms.ROOT
|
||||
|
||||
def process(self, scope, path):
|
||||
print("{name} processing {path} ({scope})".format(name=self.name,path=path,scope=scope))
|
||||
shared_path = "{}/SharedPrinter".format(path)
|
||||
port_path = "{}/PortPrinter".format(path)
|
||||
local_path = "{}/LocalPrinter".format(path)
|
||||
printers = []
|
||||
if os.path.exists(shared_path):
|
||||
print("SharedPrinters")
|
||||
if os.path.exists(port_path):
|
||||
print("PortPrinters")
|
||||
for p in os.listdir(port_path):
|
||||
with open("{}/{}/ipAddress".format(port_path,p)) as f:
|
||||
addr = f.read()
|
||||
with open("{}/{}/localName".format(port_path,p)) as f:
|
||||
name = f.read()
|
||||
prns = {'name': name, 'addr': addr}
|
||||
printers.append(prns)
|
||||
|
||||
if os.path.exists(local_path):
|
||||
print("LocalPrinters")
|
||||
|
||||
return ({'printers': printers})
|
||||
|
||||
@property
|
||||
def data_roots(self):
|
||||
return data_roots
|
||||
|
||||
data_roots = {
|
||||
"Preferences/Printers": Printers
|
||||
}
|
51
gpoa/policy/removable_devices_perms.py
Normal file
51
gpoa/policy/removable_devices_perms.py
Normal file
@ -0,0 +1,51 @@
|
||||
from policy.common import Policy, Perms
|
||||
from enum import Enum
|
||||
import os
|
||||
|
||||
class DevType (Enum):
|
||||
CDDVD = "{53f56308-b6bf-11d0-94f2-00a0c91efb8b}"
|
||||
FLOPPY = "{53f56311-b6bf-11d0-94f2-00a0c91efb8b}"
|
||||
REMDISKS = "{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}"
|
||||
TAPEDRIVE = "{53f5630b-b6bf-11d0-94f2-00a0c91efb8b}"
|
||||
WPDDEV1 = "{6AC27878-A6FA-4155-BA85-F98F491D4F33}"
|
||||
WPDDEV2 = "{F33FDC04-D1AC-4E8E-9A30-19BBD4B108AE}"
|
||||
|
||||
class RemovableDevices (Policy):
|
||||
def __init__(self):
|
||||
self._Policy__name = "RemovebleDivicesPerms"
|
||||
self._Policy__script_name = "removable_devices_perms.sh"
|
||||
self._Policy__template = "removable_devices_perms.bash.j2"
|
||||
self._Policy__perms = Perms.ROOT
|
||||
|
||||
def process(self, scope, path):
|
||||
print("{name} processing {path} ({scope})".format(name=self.name,path=path,scope=scope))
|
||||
perms = {}
|
||||
for p in os.listdir(path):
|
||||
if DevType(p) == DevType.REMDISKS:
|
||||
perms['Removable'] = self.__parse_perms('{}/{}'.format(path,p))
|
||||
# elif DevType(p) == DevType.CDDVD:
|
||||
|
||||
perms['CDDVD'] = {'deny_exec': True, 'deny_read': False, 'deny_write': True}
|
||||
return (perms)
|
||||
|
||||
def __parse_perms(self, path):
|
||||
deny_exec = self.__read_perm('{}/Deny_Execute.dword'.format(path))
|
||||
deny_read = self.__read_perm('{}/Deny_Read.dword'.format(path))
|
||||
deny_write = self.__read_perm('{}/Deny_Write.dword'.format(path))
|
||||
return ({'deny_exec': deny_exec, 'deny_read': deny_read, 'deny_write': deny_write})
|
||||
|
||||
def __read_perm(self, path):
|
||||
try:
|
||||
f = open(path, 'r')
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
|
||||
p = f.read()
|
||||
if p == "0x00000001":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
data_roots = {
|
||||
"Software/Microsoft/Windows/CurrentVersion/Policies/RemovableStorageDevices": RemovableDevices
|
||||
}
|
24
gpoa/policy/shortcuts.py
Normal file
24
gpoa/policy/shortcuts.py
Normal file
@ -0,0 +1,24 @@
|
||||
from policy.common import Policy, Perms
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
class Shortcuts (Policy):
|
||||
def __init__(self):
|
||||
self._Policy__name = "Shortcuts"
|
||||
self._Policy__script_name = "shortcuts.sh"
|
||||
self._Policy__template = "shortcuts.bash.j2"
|
||||
self._Policy__perms = Perms.USER
|
||||
|
||||
def process(self, scope, path):
|
||||
shortcuts = []
|
||||
print("{name} processing {path} ({scope})".format(name=self.name,path=path,scope=scope))
|
||||
for p in os.listdir(path):
|
||||
target_path = Path('{}/{}/targetPath'.format(path, p)).read_text()
|
||||
arguments = Path('{}/{}/arguments'.format(path, p)).read_text()
|
||||
shortcuts.append({'name': p, 'target': target_path, 'args': arguments})
|
||||
|
||||
return ({'shortcuts': shortcuts})
|
||||
|
||||
data_roots = {
|
||||
"Preferences/Shortcuts": Shortcuts
|
||||
}
|
7
gpoa/templ.py
Normal file
7
gpoa/templ.py
Normal file
@ -0,0 +1,7 @@
|
||||
from jinja2 import Environment, PackageLoader, FileSystemLoader, StrictUndefined, select_autoescape
|
||||
|
||||
templateLoader = FileSystemLoader(searchpath="./templates")
|
||||
env = Environment(loader=templateLoader, undefined=StrictUndefined)
|
||||
template = env.get_template('printers.bash.j2')
|
||||
|
||||
print(template.render(printer_name="HP_via_script", printer_address="10.64.128.250", DEBUG=False))
|
9
gpoa/templates/applications.bash.j2
Normal file
9
gpoa/templates/applications.bash.j2
Normal file
@ -0,0 +1,9 @@
|
||||
{% include "header.bash.j2" %}
|
||||
MODULE_NAME="Applications"
|
||||
|
||||
{% for a in applications %}
|
||||
{%set app_name = a.name %}
|
||||
{%set pkg_name = a.package %}
|
||||
logI "Install {{ pkg_name }} via apt-get"
|
||||
apt-get install -y "${pkg_name}"
|
||||
{% endfor %}
|
22
gpoa/templates/firewall.bash.j2
Normal file
22
gpoa/templates/firewall.bash.j2
Normal file
@ -0,0 +1,22 @@
|
||||
{% include 'header.bash.j2' %}
|
||||
MODULE_NAME="Firewall"
|
||||
|
||||
on_exit() {
|
||||
logI "on_exit in ${MODULE_NAME}"
|
||||
}
|
||||
|
||||
{% for z,rs in zoneRules.items() %}
|
||||
logI "Processing rules in zone {{z}}"
|
||||
if ! firewall-cmd --permanent --list-all-zones | grep -ve '\(^[[:space:]]*$\|\ .*\)' | grep -q "{{z}}"; then
|
||||
firewall-cmd --permanent --new-zone="{{z}}"
|
||||
fi
|
||||
{% if "openPorts" in rs %}
|
||||
logI "Define opened ports"
|
||||
{% for p in rs['openPorts'] %}
|
||||
{% for s in p.sources %}
|
||||
firewall-cmd --permanent --zone="{{z}}" --add-source="{{s}}"
|
||||
{% endfor %}
|
||||
firewall-cmd --permanent --zone={{z}} --add-port={{p.port}}/{{p.proto | lower }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
63
gpoa/templates/header.bash.j2
Normal file
63
gpoa/templates/header.bash.j2
Normal file
@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
{% if DEBUG %}
|
||||
set -x
|
||||
{% endif %}
|
||||
|
||||
BASE_DIR="${TMP}/gpoA"
|
||||
LOG_DIR="${BASE_DIR}/log"
|
||||
#STDERR_TO="${LOG_DIR}/stderr.log"
|
||||
|
||||
__log () {
|
||||
local level="$1"
|
||||
local msg="$2"
|
||||
local mod_name="${MODULE_NAME}"
|
||||
echo "${mod_name} [${level}] ${msg}"
|
||||
}
|
||||
|
||||
logD () {
|
||||
__log "DEBUG" "$1"
|
||||
}
|
||||
|
||||
logI () {
|
||||
__log "INFO" "$1"
|
||||
}
|
||||
|
||||
logW () {
|
||||
__log "WARNING" "$1"
|
||||
}
|
||||
|
||||
logE () {
|
||||
__log "ERROR" "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
__if_func_exists() {
|
||||
declare -f -F "$1" >/dev/null
|
||||
return $?
|
||||
}
|
||||
__on_exit() {
|
||||
__if_func_exists "on_exit" && on_exit
|
||||
logI "Finalizyng..."
|
||||
}
|
||||
|
||||
__on_error() {
|
||||
__if_func_exists "on_error" && on_exit
|
||||
logE "Error..."
|
||||
}
|
||||
|
||||
__init() {
|
||||
[[ -d "${BASE_DIR}" ]] || mkdir "${BASE_DIR}"
|
||||
[[ -d "${LOG_DIR}" ]] || mkdir "${LOG_DIR}"
|
||||
# exec 2> ${STDERR_TO}
|
||||
}
|
||||
|
||||
for sig in SIGINT SIGTERM SIGHUP SIGQUIT EXIT RETURN; do
|
||||
trap __on_exit $sig
|
||||
done
|
||||
|
||||
#for sig in ERR; do
|
||||
# trap __on_error $sig
|
||||
#done
|
||||
|
||||
__init
|
16
gpoa/templates/printers.bash.j2
Normal file
16
gpoa/templates/printers.bash.j2
Normal file
@ -0,0 +1,16 @@
|
||||
{% include "header.bash.j2" %}
|
||||
MODULE_NAME="Printers"
|
||||
|
||||
{% for p in printers %}
|
||||
{%set printer_name = p.name | replace(" ", "_") %}
|
||||
{%set printer_address = p.addr %}
|
||||
logI "Search if {{ printer_name }} is already defined"
|
||||
URI=$(LC_ALL="C" lpstat -v | awk '$3 ~ /{{ printer_name }}:/ { print $4;}')
|
||||
if [[ -z "$URI" ]]; then
|
||||
logI "Register {{ printer_name }} on {{ printer_address }}"
|
||||
lpadmin -p "{{ printer_name }}" -E -v "ipp://{{ printer_address }}/ipp/print" -m everywhere
|
||||
logI "Done"
|
||||
else
|
||||
logI "{{ printer_name }} is already defined as ${URI}. Nothing to do."
|
||||
fi
|
||||
{% endfor %}
|
25
gpoa/templates/removable_devices_perms.bash.j2
Normal file
25
gpoa/templates/removable_devices_perms.bash.j2
Normal file
@ -0,0 +1,25 @@
|
||||
{% include "header.bash.j2" %}
|
||||
MODULE_NAME="Removable Devices Perms"
|
||||
|
||||
mk_udisk2_rules() {
|
||||
local allow="$1"
|
||||
cat <<EOF >/etc/polkit-1/rules.d/60-udisks2.rules
|
||||
polkit.addRule(function(action, subject) {
|
||||
var YES = polkit.Result.YES;
|
||||
var NO = polkit.Result.NO;
|
||||
var perms = {
|
||||
"org.freedesktop.udisks2.filesystem-mount": ${allow},
|
||||
"org.freedesktop.udisks2.filesystem-mount-system": ${allow},
|
||||
"org.freedesktop.udisks2.filesystem-mount-other-seat": ${allow},
|
||||
|
||||
};
|
||||
// if (!subject.isInGroup("wheel")) {
|
||||
return permission[action.id];
|
||||
// }
|
||||
});
|
||||
EOF
|
||||
}
|
||||
|
||||
{% if Removable is defined and (Removable.deny_exec or Removable.deny_read or Removable.deny_write) %}
|
||||
mk_udisk2_rules "NO"
|
||||
{% endif %}
|
11
gpoa/templates/shortcuts.bash.j2
Normal file
11
gpoa/templates/shortcuts.bash.j2
Normal file
@ -0,0 +1,11 @@
|
||||
{% include "header.bash.j2" %}
|
||||
MODULE_NAME="Shortcuts"
|
||||
DESKTOP_DIR=$(xdg-user-dir DESKTOP)
|
||||
|
||||
{% for s in shortcuts %}
|
||||
cat <<EOF >"${DESKTOP_DIR}/{{s.name}}.desktop"
|
||||
[Desktop Entry]
|
||||
Name={{s.name}}
|
||||
Exec={{s.target}} {{s.args}}
|
||||
EOF
|
||||
{% endfor %}
|
BIN
gpoa/test/Registry.pol
Normal file
BIN
gpoa/test/Registry.pol
Normal file
Binary file not shown.
BIN
gpoa/test/test.pol
Normal file
BIN
gpoa/test/test.pol
Normal file
Binary file not shown.
23
gpoa/test/test.xml
Normal file
23
gpoa/test/test.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PolFile num_entries="4" signature="PReg" version="1">
|
||||
<Entry type="4" type_name="REG_DWORD">
|
||||
<Key>Software\BaseALT\Policies\Control</Key>
|
||||
<ValueName>sshd-gssapi-auth</ValueName>
|
||||
<Value>1</Value>
|
||||
</Entry>
|
||||
<Entry type="4" type_name="REG_DWORD">
|
||||
<Key>Software\BaseALT\Policies\Control</Key>
|
||||
<ValueName>ssh-gssapi-auth</ValueName>
|
||||
<Value>1</Value>
|
||||
</Entry>
|
||||
<Entry type="4" type_name="REG_DWORD">
|
||||
<Key>Software\BaseALT\Policies\Control</Key>
|
||||
<ValueName>sudo</ValueName>
|
||||
<Value>0</Value>
|
||||
</Entry>
|
||||
<Entry type="4" type_name="REG_DWORD">
|
||||
<Key>Software\Policies\Microsoft\Windows\System</Key>
|
||||
<ValueName>UserPolicyMode</ValueName>
|
||||
<Value>1</Value>
|
||||
</Entry>
|
||||
</PolFile>
|
BIN
gpoa/test/test_reg.pol
Normal file
BIN
gpoa/test/test_reg.pol
Normal file
Binary file not shown.
18
gpoa/test/test_reg.xml
Normal file
18
gpoa/test/test_reg.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PolFile num_entries="3" signature="PReg" version="1">
|
||||
<Entry type="4" type_name="REG_DWORD">
|
||||
<Key>Software\BaseALT\Policies\Control</Key>
|
||||
<ValueName>sshd-gssapi-auth</ValueName>
|
||||
<Value>1</Value>
|
||||
</Entry>
|
||||
<Entry type="4" type_name="REG_DWORD">
|
||||
<Key>Software\BaseALT\Policies\Control</Key>
|
||||
<ValueName>ssh-gssapi-auth</ValueName>
|
||||
<Value>1</Value>
|
||||
</Entry>
|
||||
<Entry type="4" type_name="REG_DWORD">
|
||||
<Key>Software\BaseALT\Policies\Control</Key>
|
||||
<ValueName>sudo</ValueName>
|
||||
<Value>0</Value>
|
||||
</Entry>
|
||||
</PolFile>
|
306
gpupdate
Executable file
306
gpupdate
Executable file
@ -0,0 +1,306 @@
|
||||
#! /usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
import os
|
||||
import errno
|
||||
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
import socket
|
||||
import sys
|
||||
import re
|
||||
|
||||
class gpupdate:
|
||||
_smb_cache = '/var/cache/samba/gpo_cache'
|
||||
_tmp_root = '/tmp/gpupdate'
|
||||
|
||||
def __init__(self, user, domain, controller):
|
||||
self._gpos = []
|
||||
self._user = user
|
||||
self._domain = domain
|
||||
self._controller = controller
|
||||
try:
|
||||
os.makedirs(self._tmp_root)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.EEXIST:
|
||||
raise
|
||||
pass
|
||||
self._temp_dir = self._mktmp('/tmp/gpupdate')
|
||||
|
||||
def update(self):
|
||||
'''
|
||||
Update GPO cache.
|
||||
'''
|
||||
proc = subprocess.Popen(['net', 'ads', 'gpo', 'list', self._user], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
#output = subprocess.check_output(['net', 'ads', 'gpo', 'list', self.user])
|
||||
#print(output)
|
||||
thr = threading.Thread(target=self._parse_netads, args=(proc,))
|
||||
thr.start()
|
||||
thr.join()
|
||||
|
||||
return self._fetch_gpos()
|
||||
|
||||
def _parse_netads(self, proc):
|
||||
'''
|
||||
Parse output of `net ads gpo list Administrator` command.
|
||||
'''
|
||||
for line in iter(proc.stdout.readline, b''):
|
||||
decoded_line = line.decode('utf-8')
|
||||
if decoded_line.startswith('filesyspath') and line != b'filesyspath:\t\t(null)\n':
|
||||
self._gpos.append(self._strip_paths(decoded_line))
|
||||
|
||||
|
||||
def _fetch_gpos(self):
|
||||
'''
|
||||
Download GPO directories specified by their GUIDs using smbclient with Kerberos 5 authentication.
|
||||
'''
|
||||
retrieved_gpos = []
|
||||
for pol in self._gpos:
|
||||
policy_tmp_dir = os.path.join(self._temp_dir, pol)
|
||||
os.makedirs(policy_tmp_dir)
|
||||
smbclient_cmd = 'prompt OFF;recurse ON;cd {}/Policies/{};lcd {};mget *'.format(self._domain.lower(), pol, policy_tmp_dir)
|
||||
print('Executing: {}'.format(smbclient_cmd))
|
||||
retcode = subprocess.call('smbclient -k \'\\\\{}\\sysvol\' -N -c \'{}\''.format(self._controller, smbclient_cmd), shell=True)
|
||||
if retcode == 0:
|
||||
print('Successfully retrieved GPO: {}'.format(pol))
|
||||
self._2gpo_cache(policy_tmp_dir, pol)
|
||||
retrieved_gpos.append(pol)
|
||||
else:
|
||||
print('Unable to retrieve GPO: {}'.format(pol))
|
||||
return retrieved_gpos
|
||||
|
||||
def _mktmp(self, tmp):
|
||||
'''
|
||||
Create temporary directory to download GPO
|
||||
'''
|
||||
try:
|
||||
os.makedirs(tmp)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.EEXIST:
|
||||
raise
|
||||
pass
|
||||
return tempfile.mkdtemp(dir=tmp)
|
||||
|
||||
def _strip_paths(self, policy_path):
|
||||
'''
|
||||
Strip newlines and extra symbols from paths.
|
||||
'''
|
||||
return policy_path[len('filesyspath:\t\t\\\\{}\\SysVol\\{}\\Policies\\'.format(self._domain, self._domain)):].strip()
|
||||
|
||||
def _2gpo_cache(self, obj, pol):
|
||||
'''
|
||||
Move downloaded GPOs to /var/cache/samba/gpo_cache
|
||||
'''
|
||||
gpo_dest = os.path.join(self._smb_cache, self._domain.upper(), 'POLICIES', pol)
|
||||
shutil.rmtree(gpo_dest) # Remove destination GPO if exists
|
||||
shutil.move(obj, gpo_dest)
|
||||
|
||||
class hreg:
|
||||
_hreg_exe = '/usr/bin/hreg'
|
||||
_hreg_cache = '/var/cache/gpupdate'
|
||||
|
||||
def __init__(self, cache_dir, domain, gpos, sid):
|
||||
self._cache_dir = cache_dir
|
||||
self._domain = domain
|
||||
self._gpos = gpos
|
||||
self._sid = sid
|
||||
self._temp_dir = os.path.join(self._hreg_cache, 'tmp')
|
||||
try:
|
||||
os.makedirs(self._temp_dir)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.EEXIST:
|
||||
raise
|
||||
pass
|
||||
|
||||
def to_fs(self):
|
||||
'''
|
||||
Transform policy files to file system representation for given domain
|
||||
'''
|
||||
dest = self._mktmp(self._temp_dir)
|
||||
for gpo in self._gpos:
|
||||
policy_file = os.path.join(self._cache_dir,
|
||||
self._domain.upper(),
|
||||
'POLICIES',
|
||||
gpo,
|
||||
'User',
|
||||
'Registry.pol')
|
||||
hreg_cmd = '{} apply {} {} -u {}'.format(self._hreg_exe, dest, policy_file, self._sid)
|
||||
subprocess.call(hreg_cmd, shell=True)
|
||||
# Move data to permanent cache
|
||||
permanent_cache = os.path.join(self._hreg_cache, self._sid)
|
||||
try:
|
||||
shutil.rmtree(permanent_cache)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.ENOENT:
|
||||
raise
|
||||
pass
|
||||
try:
|
||||
os.makedirs(permanent_cache)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.EEXIST:
|
||||
raise
|
||||
pass
|
||||
for i in os.listdir(dest):
|
||||
shutil.move(os.path.join(dest, i), permanent_cache)
|
||||
shutil.rmtree(dest)
|
||||
|
||||
def _mktmp(self, tmp):
|
||||
'''
|
||||
Create temporary directory for GPO VFS
|
||||
'''
|
||||
try:
|
||||
os.makedirs(tmp)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.EEXIST:
|
||||
raise
|
||||
pass
|
||||
return tempfile.mkdtemp(dir=tmp)
|
||||
|
||||
class gpoa:
|
||||
_gpoa_dir = '/usr/libexec/gpoa'
|
||||
_gpoa_exe = 'main.py'
|
||||
|
||||
def __init__(self, sid):
|
||||
self._sid = sid
|
||||
|
||||
def generate_scripts(self):
|
||||
'''
|
||||
Call gpoa utility to generate scripts
|
||||
'''
|
||||
gpoa_cmd = ['./{}'.format(self._gpoa_exe), self._sid]
|
||||
cwd = os.getcwd()
|
||||
|
||||
os.chdir(self._gpoa_dir)
|
||||
print('Running gpoa')
|
||||
output = subprocess.call(gpoa_cmd)
|
||||
print(output)
|
||||
os.chdir(cwd)
|
||||
|
||||
def wbinfo_getsid(domain, user):
|
||||
'''
|
||||
Get SID using wbinfo
|
||||
'''
|
||||
wbinfo_cmd = ['wbinfo', '-n', '{}\\{}'.format(domain.upper(), user)]
|
||||
output = subprocess.check_output(wbinfo_cmd)
|
||||
sid = output.split()[0].decode('utf-8')
|
||||
return sid
|
||||
|
||||
def machine_kinit():
|
||||
'''
|
||||
Perform kinit with machine credentials
|
||||
'''
|
||||
host = socket.gethostname().split('.', 1)[0].upper() + "$"
|
||||
subprocess.call(['kinit', '-k', host])
|
||||
print('kinit succeed')
|
||||
|
||||
def check_krb_ticket():
|
||||
'''
|
||||
Check if Kerberos 5 ticket present
|
||||
'''
|
||||
try:
|
||||
subprocess.check_call([ 'klist', '-s' ])
|
||||
output = subprocess.check_output('klist', stderr=subprocess.STDOUT).decode()
|
||||
print(output)
|
||||
except:
|
||||
sys.exit( 1 )
|
||||
print('Ticket check succeed')
|
||||
|
||||
def get_domain_name():
|
||||
'''
|
||||
Get current Active Directory domain name
|
||||
'''
|
||||
lookup_cmd = ['net', 'ads', 'lookup']
|
||||
output = subprocess.check_output(lookup_cmd, stderr=subprocess.STDOUT).decode()
|
||||
d = re.search( "Domain:\s*(\S+)\n", output, re.MULTILINE )
|
||||
if d:
|
||||
domain_name = d.group(1)
|
||||
print(domain_name)
|
||||
return domain_name
|
||||
return
|
||||
|
||||
def get_domain_controller():
|
||||
'''
|
||||
Get current Active Directory domain name
|
||||
'''
|
||||
lookup_cmd = ['net', 'ads', 'lookup']
|
||||
output = subprocess.check_output(lookup_cmd, stderr=subprocess.STDOUT).decode()
|
||||
d = re.search( "^Domain Controller:\s*(\S+)\n", output, re.MULTILINE )
|
||||
if d:
|
||||
domain_controller = d.group(1)
|
||||
print(domain_controller)
|
||||
return domain_controller
|
||||
return
|
||||
|
||||
def parse_cli_arguments():
|
||||
'''
|
||||
Command line argument parser
|
||||
'''
|
||||
argparser = argparse.ArgumentParser(description='Update group policies for the specified user')
|
||||
argparser.add_argument('-u',
|
||||
'--user',
|
||||
default='Administrator',
|
||||
help='Name of the user for GPO update')
|
||||
argparser.add_argument('-d',
|
||||
'--domain',
|
||||
help='Name of the AD domain for replication')
|
||||
argparser.add_argument('-c',
|
||||
'--controller',
|
||||
help='AD controller to connect to')
|
||||
argparser.add_argument('-p',
|
||||
'--password',
|
||||
help='Kerberos 5 password for the specified user')
|
||||
argparser.add_argument('-i',
|
||||
'--sid',
|
||||
help='Specify SID for User target')
|
||||
argparser.add_argument('-t',
|
||||
'--target',
|
||||
default='User',
|
||||
help='Computer or User')
|
||||
argparser.add_argument('-f',
|
||||
'--force',
|
||||
help='Reapply all policy settings')
|
||||
argparser.add_argument('-w',
|
||||
'--wait',
|
||||
default=600,
|
||||
help='Wait for specified number of seconds')
|
||||
argparser.add_argument('-l',
|
||||
'--logoff',
|
||||
help='Force logoff after settings are applied')
|
||||
argparser.add_argument('-b',
|
||||
'--boot',
|
||||
help='Force reboot after settings are applied')
|
||||
argparser.add_argument('-s',
|
||||
'--sync',
|
||||
help='Perform next GPO application synchronously')
|
||||
|
||||
return argparser.parse_args()
|
||||
|
||||
def main():
|
||||
args = parse_cli_arguments()
|
||||
|
||||
machine_kinit()
|
||||
check_krb_ticket()
|
||||
|
||||
domain = get_domain_name()
|
||||
print('Domain: {}'.format(domain))
|
||||
controller = get_domain_controller()
|
||||
print('Controller: {}'.format(controller))
|
||||
|
||||
updater = gpupdate(args.user, domain, controller)
|
||||
retrieved_gpos = updater.update()
|
||||
|
||||
sid = wbinfo_getsid(domain, args.user)
|
||||
hreg_util = hreg('/var/cache/samba/gpo_cache', domain, retrieved_gpos, sid)
|
||||
hreg_util.to_fs()
|
||||
|
||||
gpo_applier = gpoa(sid)
|
||||
gpo_applier.generate_scripts()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
40
gpupdate.spec
Normal file
40
gpupdate.spec
Normal file
@ -0,0 +1,40 @@
|
||||
%define _unpackaged_files_terminate_build 1
|
||||
|
||||
Name: gpupdate
|
||||
Version: 0.0.1
|
||||
Release: alt1
|
||||
|
||||
Summary: GPT applier
|
||||
License: MIT
|
||||
Group: Other
|
||||
Url: http://git.altlinux.org/
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: hreg
|
||||
Requires: control
|
||||
Requires: samba-dc
|
||||
|
||||
Source0: %name-%version.tar
|
||||
|
||||
%description
|
||||
GPT applier
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%install
|
||||
install -pD -m755 gpupdate \
|
||||
%buildroot%_bindir/gpupdate
|
||||
mkdir -p \
|
||||
%buildroot%prefix/libexec
|
||||
cp -r gpoa \
|
||||
%buildroot%prefix/libexec
|
||||
|
||||
%files
|
||||
%prefix/bin/gpupdate
|
||||
%prefix/libexec/gpoa
|
||||
|
||||
%changelog
|
||||
* Thu Nov 14 2019 Igor Chudov <nir@altlinux.org> 0.0.1-alt1
|
||||
- Initial release
|
||||
|
Loading…
x
Reference in New Issue
Block a user