From fd38fc55ac7d703e99401913c992369c122c9b9b Mon Sep 17 00:00:00 2001 From: David Mulder Date: Tue, 10 Apr 2018 15:04:53 -0600 Subject: [PATCH 01/30] libgpo: Add python bindings for check_refresh_gpo_list Signed-off-by: David Mulder --- libgpo/pygpo.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c index 60220a6bc2a..1c05d071608 100644 --- a/libgpo/pygpo.c +++ b/libgpo/pygpo.c @@ -296,6 +296,93 @@ static PyObject* py_ads_connect(ADS *self) /* Parameter mapping and functions for the GP_EXT struct */ void initgpo(void); +static PyTypeObject ads_ADSType; + +static PyObject *py_check_refresh_gpo_list(PyObject * self, + PyObject * args) +{ + TALLOC_CTX *frame = talloc_stackframe(); + ADS *ads = NULL; + const char *cache_dir = NULL; + struct GROUP_POLICY_OBJECT *gpo_front = NULL; + struct GROUP_POLICY_OBJECT *gpo_ptr = NULL; + PyObject *gpo_list = NULL; + PyObject *gpo_obj = NULL; + NTSTATUS status; + PyObject *ret = NULL; + Py_ssize_t gp_list_len = 0; + int success = 0; + int i; + + if (!PyArg_ParseTuple(args, "OO|s", &ads, &gpo_list, &cache_dir)) { + goto out; + } + success = PyObject_TypeCheck(gpo_list, &PyList_Type); + if (!success) { + PyErr_SetString(PyExc_TypeError, "A gpo list was expected"); + goto out; + } + gp_list_len = PyList_Size(gpo_list); + if (gp_list_len == 0) { + ret = Py_True; + goto out; + } + for (i = 0; i < gp_list_len; i++) { + struct GROUP_POLICY_OBJECT *gpo = NULL; + + gpo_obj = PyList_GetItem(gpo_list, i); + if (!gpo_obj) { + goto out; + } + + success = PyObject_TypeCheck(gpo_obj, &GPOType); + if (!success) { + PyErr_SetString(PyExc_TypeError, + "A gpo type was expected"); + goto out; + } + gpo = (struct GROUP_POLICY_OBJECT *)pytalloc_get_ptr(gpo_obj); + if (gpo_ptr) { + gpo_ptr->next = talloc_memdup(frame, gpo, + sizeof(struct GROUP_POLICY_OBJECT)); + gpo_ptr->next->prev = gpo_ptr; + gpo_ptr = gpo_ptr->next; + } else { + gpo_ptr = talloc_memdup(frame, gpo, + sizeof(struct GROUP_POLICY_OBJECT)); + gpo_front = gpo_ptr; + } + } + gpo_ptr->next = NULL; + + success = PyObject_TypeCheck(ads, &ads_ADSType); + if (!success) { + PyErr_SetString(PyExc_TypeError, "An ADS type was expected"); + goto out; + } + + if (!cache_dir) { + cache_dir = cache_path(GPO_CACHE_DIR); + if (!cache_dir) { + PyErr_SetString(PyExc_MemoryError, + "Failed to determine gpo cache dir"); + goto out; + } + } + + status = check_refresh_gpo_list(ads->ads_ptr, frame, cache_dir, 0, + gpo_front); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + goto out; + } + + ret = Py_True; +out: + TALLOC_FREE(frame); + return ret; +} + /* Global methods aka do not need a special pyobject type */ static PyObject *py_gpo_get_sysvol_gpt_version(PyObject * self, PyObject * args) @@ -503,6 +590,9 @@ static PyMethodDef py_gpo_methods[] = { {"gpo_get_sysvol_gpt_version", (PyCFunction)py_gpo_get_sysvol_gpt_version, METH_VARARGS, NULL}, + {"check_refresh_gpo_list", + (PyCFunction)py_check_refresh_gpo_list, + METH_VARARGS, NULL}, {NULL} }; From f8e34509b82a754322c1c704644d754ac9531cfe Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 8 Jan 2018 07:17:29 -0700 Subject: [PATCH 02/30] gpo: Read GPO versions locally, not from sysvol This patch does not change current functionality for the kdc. Non-kdc clients cannot read directly from the sysvol, so we need to store the GPT.INI file locally to read each gpo version. Signed-off-by: David Mulder --- python/samba/gpclass.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 0966611b686..b9c376bf75a 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -421,7 +421,18 @@ def get_gpo_list(dc_hostname, creds, lp): ads = gpo.ADS_STRUCT(dc_hostname, lp, creds) if ads.connect(): gpos = ads.get_gpo_list(creds.get_username()) - return gpos + return (ads, gpos) + +def gpo_version(lp, path, sysvol): + # gpo.gpo_get_sysvol_gpt_version() reads the GPT.INI from a local file. + # If we don't have a sysvol path locally (if we're not a kdc), then + # read from the gpo client cache. + if sysvol: + local_path = os.path.join(sysvol, path, 'GPT.INI') + else: + gpt_path = lp.cache_path(os.path.join('gpo_cache', path)) + local_path = os.path.join(gpt_path, 'GPT.INI') + return int(gpo.gpo_get_sysvol_gpt_version(os.path.dirname(local_path))[1]) def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions): gp_db = store.get_gplog(creds.get_username()) @@ -431,15 +442,17 @@ def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions): except: logger.error('Error connecting to \'%s\' using SMB' % dc_hostname) raise - gpos = get_gpo_list(dc_hostname, creds, lp) + ads, gpos = get_gpo_list(dc_hostname, creds, lp) + sysvol = lp.get("path", "sysvol") + if not sysvol: + gpo.check_refresh_gpo_list(ads, gpos) for gpo_obj in gpos: guid = gpo_obj.name if guid == 'Local Policy': continue path = os.path.join(lp.get('realm').lower(), 'Policies', guid) - local_path = os.path.join(lp.get("path", "sysvol"), path) - version = int(gpo.gpo_get_sysvol_gpt_version(local_path)[1]) + version = gpo_version(lp, path, sysvol) if version != store.get_int(guid): logger.info('GPO %s has changed' % guid) gp_db.state(GPOSTATE.APPLY) From 8b3af323b05921befb7e7eae021ab77e2f5ef834 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 4 May 2018 14:09:30 -0600 Subject: [PATCH 03/30] gpo: gp_sec_ext should check whether to apply Whether an extension should apply should be determined by the extension, not by the calling script. Signed-off-by: David Mulder --- python/samba/gp_sec_ext.py | 20 ++++++++++++++++++++ python/samba/gpclass.py | 14 ++++++-------- source4/scripting/bin/samba_gpoupdate | 20 +++----------------- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index bbd385f73c6..9e1764b7fb9 100644 --- a/python/samba/gp_sec_ext.py +++ b/python/samba/gp_sec_ext.py @@ -17,8 +17,17 @@ import os.path from gpclass import gp_ext_setter, gp_inf_ext +from samba.auth import system_session +try: + from samba.samdb import SamDB +except: + SamDB = None class inf_to_kdc_tdb(gp_ext_setter): + def __init__(self, logger, gp_db, lp, attribute, val, ldb): + super(inf_to_kdc_tdb, self).__init__(logger, gp_db, lp, attribute, val) + self.ldb = ldb + def mins_to_hours(self): return '%d' % (int(self.val)/60) @@ -53,6 +62,10 @@ class inf_to_ldb(gp_ext_setter): object to update the parameter to Samba4. Not registry oriented whatsoever. ''' + def __init__(self, logger, gp_db, lp, attribute, val, ldb): + super(inf_to_ldb, self).__init__(logger, gp_db, lp, attribute, val) + self.ldb = ldb + def ch_minPwdAge(self, val): old_val = self.ldb.get_minPwdAge() self.logger.info('KDC Minimum Password age was changed from %s to %s' \ @@ -127,6 +140,13 @@ def listuserpol(self, rootpath): return os.path.join(rootpath, "User/Registry.pol") def apply_map(self): + if SamDB: + self.ldb = SamDB(self.lp.samdb_url(), + session_info=system_session(), + credentials=self.creds, + lp=self.lp) + else: + return {} return {"System Access": {"MinimumPasswordAge": ("minPwdAge", inf_to_ldb), "MaximumPasswordAge": ("maxPwdAge", diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index b9c376bf75a..da21fa1da0e 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -305,8 +305,7 @@ def apply_map(self): def read(self, policy): pass - def parse(self, afile, ldb, conn, gp_db, lp): - self.ldb = ldb + def parse(self, afile, conn, gp_db, lp): self.gp_db = gp_db self.lp = lp @@ -339,9 +338,8 @@ def __str__(self): class gp_ext_setter(): __metaclass__ = ABCMeta - def __init__(self, logger, ldb, gp_db, lp, attribute, val): + def __init__(self, logger, gp_db, lp, attribute, val): self.logger = logger - self.ldb = ldb self.attribute = attribute self.val = val self.lp = lp @@ -434,7 +432,7 @@ def gpo_version(lp, path, sysvol): local_path = os.path.join(gpt_path, 'GPT.INI') return int(gpo.gpo_get_sysvol_gpt_version(os.path.dirname(local_path))[1]) -def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions): +def apply_gp(lp, creds, logger, store, gp_extensions): gp_db = store.get_gplog(creds.get_username()) dc_hostname = get_dc_hostname(creds, lp) try: @@ -462,7 +460,7 @@ def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions): store.start() for ext in gp_extensions: try: - ext.parse(ext.list(path), test_ldb, conn, gp_db, lp) + ext.parse(ext.list(path), conn, gp_db, lp) except Exception as e: logger.error('Failed to parse gpo %s for extension %s' % \ (guid, str(ext))) @@ -480,14 +478,14 @@ def unapply_log(gp_db): else: break -def unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions): +def unapply_gp(lp, creds, logger, store, gp_extensions): gp_db = store.get_gplog(creds.get_username()) gp_db.state(GPOSTATE.UNAPPLY) for gpo_guid in unapply_log(gp_db): gp_db.set_guid(gpo_guid) unapply_attributes = gp_db.list(gp_extensions) for attr in unapply_attributes: - attr_obj = attr[-1](logger, test_ldb, gp_db, lp, attr[0], attr[1]) + attr_obj = attr[-1](logger, gp_db, lp, attr[0], attr[1]) attr_obj.mapper()[attr[0]][0](attr[1]) # Set the old value gp_db.delete(str(attr_obj), attr[0]) gp_db.commit() diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate index 89b3ed77616..e2c8c625aea 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/samba_gpoupdate @@ -29,11 +29,6 @@ sys.path.insert(0, "bin/python") import optparse from samba import getopt as options -from samba.auth import system_session -try: - from samba.samdb import SamDB -except: - SamDB = None from samba.gpclass import apply_gp, unapply_gp, GPOStorage from samba.gp_sec_ext import gp_sec_ext import logging @@ -63,9 +58,7 @@ if __name__ == "__main__": else: url = opts.url - # Initialize the session creds = credopts.get_credentials(lp, fallback_machine=True) - session = system_session() # Set up logging logger = logging.getLogger('samba_gpoupdate') @@ -86,19 +79,12 @@ if __name__ == "__main__": gp_extensions = [] if opts.machine: - if lp.get('server role') == 'active directory domain controller': - gp_extensions.append(gp_sec_ext(logger)) + gp_extensions.append(gp_sec_ext(logger)) else: pass # User extensions - # Get a live instance of Samba - if SamDB: - test_ldb = SamDB(url, session_info=session, credentials=creds, lp=lp) - else: - test_ldb = None - if not opts.unapply: - apply_gp(lp, creds, test_ldb, logger, store, gp_extensions) + apply_gp(lp, creds, logger, store, gp_extensions) else: - unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions) + unapply_gp(lp, creds, logger, store, gp_extensions) From eb4197fda7f0a37b3e0d5d62be3e22bb7e0f1859 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Thu, 12 Apr 2018 14:31:54 -0600 Subject: [PATCH 04/30] libgpo: add py_register_gp_extension for registering gp extensions Signed-off-by: David Mulder --- libgpo/gpo_proto.h | 8 +++++ libgpo/gpo_reg.c | 16 ++++----- libgpo/pygpo.c | 39 +++++++++++++++++++++ libgpo/register.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ libgpo/register.h | 24 +++++++++++++ libgpo/wscript_build | 2 +- 6 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 libgpo/register.c create mode 100644 libgpo/register.h diff --git a/libgpo/gpo_proto.h b/libgpo/gpo_proto.h index 32a61eab214..b80e7589891 100644 --- a/libgpo/gpo_proto.h +++ b/libgpo/gpo_proto.h @@ -53,6 +53,14 @@ WERROR gp_store_reg_val_sz(TALLOC_CTX *mem_ctx, struct registry_key *key, const char *val_name, const char *val); +WERROR gp_store_reg_val_dword(TALLOC_CTX *mem_ctx, + struct registry_key *key, + const char *val_name, + uint32_t val); +WERROR gp_read_reg_val_dword(TALLOC_CTX *mem_ctx, + struct registry_key *key, + const char *val_name, + uint32_t *val); WERROR gp_read_reg_val_sz(TALLOC_CTX *mem_ctx, struct registry_key *key, const char *val_name, diff --git a/libgpo/gpo_reg.c b/libgpo/gpo_reg.c index 18d0498c7e9..64ea8d744b2 100644 --- a/libgpo/gpo_reg.c +++ b/libgpo/gpo_reg.c @@ -182,10 +182,10 @@ WERROR gp_store_reg_val_sz(TALLOC_CTX *mem_ctx, /**************************************************************** ****************************************************************/ -static WERROR gp_store_reg_val_dword(TALLOC_CTX *mem_ctx, - struct registry_key *key, - const char *val_name, - uint32_t val) +WERROR gp_store_reg_val_dword(TALLOC_CTX *mem_ctx, + struct registry_key *key, + const char *val_name, + uint32_t val) { struct registry_value reg_val; @@ -224,10 +224,10 @@ WERROR gp_read_reg_val_sz(TALLOC_CTX *mem_ctx, /**************************************************************** ****************************************************************/ -static WERROR gp_read_reg_val_dword(TALLOC_CTX *mem_ctx, - struct registry_key *key, - const char *val_name, - uint32_t *val) +WERROR gp_read_reg_val_dword(TALLOC_CTX *mem_ctx, + struct registry_key *key, + const char *val_name, + uint32_t *val) { WERROR werr; struct registry_value *reg_val = NULL; diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c index 1c05d071608..52bd068650b 100644 --- a/libgpo/pygpo.c +++ b/libgpo/pygpo.c @@ -28,6 +28,12 @@ #include "auth/credentials/pycredentials.h" #include "libcli/util/pyerrors.h" #include "python/py3compat.h" +#include "libgpo/gpo_proto.h" +#include "registry.h" +#include "registry/reg_api.h" +#include "../libcli/registry/util_reg.h" +#include "../libgpo/gpext/gpext.h" +#include "register.h" /* A Python C API module to use LIBGPO */ @@ -383,6 +389,37 @@ static PyObject *py_check_refresh_gpo_list(PyObject * self, return ret; } +static PyObject *py_register_gp_extension(PyObject * self, PyObject *args, + PyObject *kwds) +{ + const char *module_path = NULL; + const char *guid_name = NULL; + PyObject *ret = NULL; + int cret = 0; + const char *smb_conf = NULL; + const char *gp_ext_cls = NULL; + int machine = 1, user = 1; + static const char *kwlist[] = {"guid", "gp_ext_cls", "path", + "smb_conf", "machine", "user"}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sss|sii", + discard_const_p(char *, kwlist), + &guid_name, &gp_ext_cls, &module_path, + &smb_conf, &machine, &user)) { + return NULL; + } + + cret = register_gp_extension(guid_name, gp_ext_cls, module_path, + smb_conf, machine, user); + if (cret == 0) { + goto out; + } + + ret = Py_True; +out: + return ret; +} + /* Global methods aka do not need a special pyobject type */ static PyObject *py_gpo_get_sysvol_gpt_version(PyObject * self, PyObject * args) @@ -587,6 +624,8 @@ static PyTypeObject ads_ADSType = { }; static PyMethodDef py_gpo_methods[] = { + {"register_gp_extension", (PyCFunction)py_register_gp_extension, + METH_VARARGS | METH_KEYWORDS, NULL}, {"gpo_get_sysvol_gpt_version", (PyCFunction)py_gpo_get_sysvol_gpt_version, METH_VARARGS, NULL}, diff --git a/libgpo/register.c b/libgpo/register.c new file mode 100644 index 00000000000..e10b4c270ac --- /dev/null +++ b/libgpo/register.c @@ -0,0 +1,98 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) David Mulder 2018 + + 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 . +*/ +#include "includes.h" +#include "version.h" +#include "gpo.h" +#include "ads.h" +#include "secrets.h" +#include "../libds/common/flags.h" +#include "libgpo/gpo_proto.h" +#include "registry.h" +#include "registry/reg_api.h" +#include "../libcli/registry/util_reg.h" +#include "../libgpo/gpext/gpext.h" +#include "registry/reg_objects.h" +#include "libgpo/register.h" + +static void get_gp_registry_context(TALLOC_CTX *ctx, + uint32_t desired_access, + struct gp_registry_context **reg_ctx, + const char *smb_conf) +{ + struct security_token *token; + WERROR werr; + + lp_load_initial_only(smb_conf ? smb_conf : get_dyn_CONFIGFILE()); + + token = registry_create_system_token(ctx); + if (!token) { + return; + } + werr = gp_init_reg_ctx(ctx, KEY_WINLOGON_GPEXT_PATH, desired_access, + token, reg_ctx); + if (!W_ERROR_IS_OK(werr)) { + return; + } +} + +int register_gp_extension(const char *guid_name, + const char *gp_ext_cls, + const char *module_path, + const char *smb_conf, + int machine, + int user) +{ + TALLOC_CTX *frame = talloc_stackframe(); + WERROR werr; + struct gp_registry_context *reg_ctx = NULL; + struct registry_key *key = NULL; + int ret = 0; + + get_gp_registry_context(frame, REG_KEY_WRITE, ®_ctx, smb_conf); + if (!reg_ctx) { + goto out; + } + + werr = gp_store_reg_subkey(frame, guid_name, + reg_ctx->curr_key, &key); + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + werr = gp_store_reg_val_sz(frame, key, "DllName", module_path); + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + werr = gp_store_reg_val_sz(frame, key, "ProcessGroupPolicy", + gp_ext_cls); + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + werr = gp_store_reg_val_dword(frame, key, "NoMachinePolicy", !machine); + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + werr = gp_store_reg_val_dword(frame, key, "NoUserPolicy", !user); + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + + ret = 1; +out: + TALLOC_FREE(frame); + return ret; +} diff --git a/libgpo/register.h b/libgpo/register.h new file mode 100644 index 00000000000..7d1d2bb6ced --- /dev/null +++ b/libgpo/register.h @@ -0,0 +1,24 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) David Mulder 2018 + + 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 . +*/ + +int register_gp_extension(const char *guid_name, + const char *gp_ext_cls, + const char *module_path, + const char *smb_conf, + int machine, + int user); diff --git a/libgpo/wscript_build b/libgpo/wscript_build index 9fbff9d0974..7b20859728b 100644 --- a/libgpo/wscript_build +++ b/libgpo/wscript_build @@ -3,7 +3,7 @@ bld.SAMBA3_LIBRARY('gpext', source='''gpext/gpext.c gpo_util.c gpo_ldap.c gpo_ini.c gpo_fetch.c gpo_filesync.c - gpo_sec.c gpo_reg.c''', + gpo_sec.c gpo_reg.c register.c''', deps='talloc ads TOKEN_UTIL auth', private_library=True) From 7cc9f67cf09af39ea6c4b17936a588d396afd305 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 13 Apr 2018 15:14:06 -0600 Subject: [PATCH 05/30] libgpo: add py_unregister_gp_extension for unregistering gp extensions Signed-off-by: David Mulder --- libgpo/pygpo.c | 23 +++++++++++++++++++++++ libgpo/register.c | 24 ++++++++++++++++++++++++ libgpo/register.h | 2 ++ 3 files changed, 49 insertions(+) diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c index 52bd068650b..48734438fe5 100644 --- a/libgpo/pygpo.c +++ b/libgpo/pygpo.c @@ -389,6 +389,27 @@ static PyObject *py_check_refresh_gpo_list(PyObject * self, return ret; } +static PyObject *py_unregister_gp_extension(PyObject * self, PyObject * args) +{ + const char *guid_name = NULL; + PyObject *ret = Py_False; + int cret = 0; + const char *smb_conf = NULL; + + if (!PyArg_ParseTuple(args, "s|s", &guid_name, &smb_conf)) { + return NULL; + } + + cret = unregister_gp_extension(guid_name, smb_conf); + if (cret == 0) { + goto out; + } + + ret = Py_True; +out: + return ret; +} + static PyObject *py_register_gp_extension(PyObject * self, PyObject *args, PyObject *kwds) { @@ -626,6 +647,8 @@ static PyTypeObject ads_ADSType = { static PyMethodDef py_gpo_methods[] = { {"register_gp_extension", (PyCFunction)py_register_gp_extension, METH_VARARGS | METH_KEYWORDS, NULL}, + {"unregister_gp_extension", (PyCFunction)py_unregister_gp_extension, + METH_VARARGS, NULL}, {"gpo_get_sysvol_gpt_version", (PyCFunction)py_gpo_get_sysvol_gpt_version, METH_VARARGS, NULL}, diff --git a/libgpo/register.c b/libgpo/register.c index e10b4c270ac..29a35ae5ace 100644 --- a/libgpo/register.c +++ b/libgpo/register.c @@ -50,6 +50,30 @@ static void get_gp_registry_context(TALLOC_CTX *ctx, } } +int unregister_gp_extension(const char *guid_name, + const char *smb_conf) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct gp_registry_context *reg_ctx = NULL; + WERROR werr; + int ret = 0; + + get_gp_registry_context(frame, REG_KEY_WRITE, ®_ctx, smb_conf); + if (!reg_ctx) { + goto out; + } + + werr = reg_deletekey_recursive(reg_ctx->curr_key, guid_name); + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + + ret = 1; +out: + TALLOC_FREE(frame); + return ret; +} + int register_gp_extension(const char *guid_name, const char *gp_ext_cls, const char *module_path, diff --git a/libgpo/register.h b/libgpo/register.h index 7d1d2bb6ced..2ea6d00d4f4 100644 --- a/libgpo/register.h +++ b/libgpo/register.h @@ -16,6 +16,8 @@ along with this program. If not, see . */ +int unregister_gp_extension(const char *guid_name, + const char *smb_conf); int register_gp_extension(const char *guid_name, const char *gp_ext_cls, const char *module_path, From c69fb5277ee465b520c14d543aeac85f0792c4c3 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 4 May 2018 10:41:16 -0600 Subject: [PATCH 06/30] libgpo: add py_list_gp_extensions for listing registered gp extensions Signed-off-by: David Mulder --- libgpo/pygpo.c | 52 +++++++++++++++++++++++++++++++++++++++++- libgpo/register.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ libgpo/register.h | 12 ++++++++++ 3 files changed, 131 insertions(+), 1 deletion(-) diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c index 48734438fe5..d75c08eeb9c 100644 --- a/libgpo/pygpo.c +++ b/libgpo/pygpo.c @@ -389,6 +389,54 @@ static PyObject *py_check_refresh_gpo_list(PyObject * self, return ret; } +static PyObject *py_list_gp_extensions(PyObject * self, PyObject * args) +{ + TALLOC_CTX *frame = talloc_stackframe(); + PyObject *ret = NULL; + const char *smb_conf = NULL; + struct gplist_dict *list = NULL; + + if (!PyArg_ParseTuple(args, "|s", &smb_conf)) { + return NULL; + } + + if (!list_gp_extensions(frame, smb_conf, &list)) { + goto out; + } + + ret = PyDict_New(); + if (ret == NULL) { + goto out; + } + + for (; list != NULL; list = list->next) { + PyObject *val; + PyObject *subitem = PyDict_New(); + if (subitem == NULL) { + goto out; + } + + if (list->module_path) { + val = PyStr_FromString(list->module_path); + PyDict_SetItemString(subitem, "DllName", val); + } + if (list->gp_ext_cls) { + val = PyStr_FromString(list->gp_ext_cls); + PyDict_SetItemString(subitem, "ProcessGroupPolicy", val); + } + PyDict_SetItemString(subitem, "MachinePolicy", + list->machine ? Py_True : Py_False); + PyDict_SetItemString(subitem, "UserPolicy", + list->user ? Py_True : Py_False); + + PyDict_SetItemString(ret, list->guid, subitem); + } + +out: + TALLOC_FREE(frame); + return ret; +} + static PyObject *py_unregister_gp_extension(PyObject * self, PyObject * args) { const char *guid_name = NULL; @@ -421,7 +469,7 @@ static PyObject *py_register_gp_extension(PyObject * self, PyObject *args, const char *gp_ext_cls = NULL; int machine = 1, user = 1; static const char *kwlist[] = {"guid", "gp_ext_cls", "path", - "smb_conf", "machine", "user"}; + "smb_conf", "machine", "user", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "sss|sii", discard_const_p(char *, kwlist), @@ -649,6 +697,8 @@ static PyMethodDef py_gpo_methods[] = { METH_VARARGS | METH_KEYWORDS, NULL}, {"unregister_gp_extension", (PyCFunction)py_unregister_gp_extension, METH_VARARGS, NULL}, + {"list_gp_extensions", (PyCFunction)py_list_gp_extensions, + METH_VARARGS, NULL}, {"gpo_get_sysvol_gpt_version", (PyCFunction)py_gpo_get_sysvol_gpt_version, METH_VARARGS, NULL}, diff --git a/libgpo/register.c b/libgpo/register.c index 29a35ae5ace..86a372c5aa3 100644 --- a/libgpo/register.c +++ b/libgpo/register.c @@ -50,6 +50,74 @@ static void get_gp_registry_context(TALLOC_CTX *ctx, } } +int list_gp_extensions(TALLOC_CTX *ctx, + const char *smb_conf, + struct gplist_dict **list) +{ + struct gp_registry_context *reg_ctx = NULL; + WERROR werr; + struct registry_key *parent; + int i, count = 0; + struct gplist_dict *itr = NULL; + int ret = 0; + + get_gp_registry_context(ctx, REG_KEY_READ, ®_ctx, smb_conf); + if (!reg_ctx) { + goto out; + } + + parent = reg_ctx->curr_key; + count = regsubkey_ctr_numkeys(parent->subkeys); + + if (count > 0) { + *list = talloc_zero(ctx, struct gplist_dict); + itr = *list; + } + + for (i = count-1; i >= 0; i--) { + struct registry_key *subkey; + char *subkey_name = NULL; + const char *subkey_val = NULL; + uint32_t subkey_dword; + + subkey_name = regsubkey_ctr_specific_key(parent->subkeys, i); + werr = gp_read_reg_subkey(ctx, reg_ctx, + subkey_name, &subkey); + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + itr->guid = talloc_strdup(*list, subkey_name); + werr = gp_read_reg_val_sz(ctx, subkey, + "DllName", &subkey_val); + if (W_ERROR_IS_OK(werr)) { + itr->module_path = talloc_strdup(*list, subkey_val); + } + werr = gp_read_reg_val_sz(ctx, subkey, + "ProcessGroupPolicy", &subkey_val); + if (W_ERROR_IS_OK(werr)) { + itr->gp_ext_cls = talloc_strdup(*list, subkey_val); + } + werr = gp_read_reg_val_dword(ctx, subkey, + "NoMachinePolicy", &subkey_dword); + if (W_ERROR_IS_OK(werr)) { + itr->machine = !subkey_dword; + } + werr = gp_read_reg_val_dword(ctx, subkey, + "NoUserPolicy", &subkey_dword); + if (W_ERROR_IS_OK(werr)) { + itr->user = !subkey_dword; + } + if (i > 0) { + itr->next = talloc_zero(*list, struct gplist_dict); + itr = itr->next; + } + } + + ret = 1; +out: + return ret; +} + int unregister_gp_extension(const char *guid_name, const char *smb_conf) { diff --git a/libgpo/register.h b/libgpo/register.h index 2ea6d00d4f4..a4db8574f3d 100644 --- a/libgpo/register.h +++ b/libgpo/register.h @@ -16,6 +16,18 @@ along with this program. If not, see . */ +struct gplist_dict { + struct gplist_dict *next; + char *guid; + char *module_path; + char *gp_ext_cls; + int machine; + int user; +}; + +int list_gp_extensions(TALLOC_CTX *ctx, + const char *smb_conf, + struct gplist_dict **list); int unregister_gp_extension(const char *guid_name, const char *smb_conf); int register_gp_extension(const char *guid_name, From 7f701eee0ec5ec393158ece92d6df8c03f3f5eb6 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Wed, 9 May 2018 09:24:37 -0600 Subject: [PATCH 07/30] libgpo: Tests for gp_ext register/unregister Adds testing for the gp_ext register and unregister functions, as well as testing the list function. Signed-off-by: David Mulder --- python/samba/tests/gpo.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py index 796a5cb06cb..fda25d44a09 100644 --- a/python/samba/tests/gpo.py +++ b/python/samba/tests/gpo.py @@ -75,3 +75,20 @@ def test_gpt_version(self): assert gpo.gpo_get_sysvol_gpt_version(gpo_path)[1] == old_vers, \ 'gpo_get_sysvol_gpt_version() did not return the expected version' + def test_gpt_ext_register(self): + ext_path = '/home/dmulder/code/samba/bin/python/samba/gp_sec_ext.py' + ext_guid = '{827D319E-6EAC-11D2-A4EA-00C04F79F83A}' + gpo.register_gp_extension(ext_guid, 'gp_sec_ext', ext_path, + smb_conf=self.lp.configfile, + machine=True, user=False) + gp_exts = gpo.list_gp_extensions(self.lp.configfile) + assert ext_guid in gp_exts.keys(), \ + 'Failed to list gp exts from registry' + assert gp_exts[ext_guid]['DllName'] == ext_path, \ + 'Failed to list gp exts from registry' + + gpo.unregister_gp_extension(ext_guid) + gp_exts = gpo.list_gp_extensions(self.lp.configfile) + assert ext_guid not in gp_exts.keys(), \ + 'Failed to unregister gp exts from registry' + From e2e906e6e25f24efacaefb4e64a5536ff1ad2af7 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Wed, 16 May 2018 09:03:32 -0600 Subject: [PATCH 08/30] gpo: Specify samba module when importing from gpclass Signed-off-by: David Mulder --- python/samba/gp_sec_ext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index 9e1764b7fb9..4f2092ba403 100644 --- a/python/samba/gp_sec_ext.py +++ b/python/samba/gp_sec_ext.py @@ -16,7 +16,7 @@ # along with this program. If not, see . import os.path -from gpclass import gp_ext_setter, gp_inf_ext +from samba.gpclass import gp_ext_setter, gp_inf_ext from samba.auth import system_session try: from samba.samdb import SamDB From d5576fa0d65fef5c48a0739b5c5f09336010d93b Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 4 May 2018 13:38:44 -0600 Subject: [PATCH 09/30] gpo: Dynamically load gp_exts from registry This loads Group Policy Client Side Extensions in the same way that they are loaded on a Windows client. Extensions are installed via the registry at HKLM/Software/Microsoft/Windows NT/ CurrentVersion/Winlogon/GPExtensions where they receive a unique GUID matched with the path to the python gp_ext file. Classes which inherit from the gp_ext class (as defined in gpclass.py) will be dynamically loaded. Signed-off-by: David Mulder --- python/samba/gp_ext_loader.py | 56 +++++++++++++++++++++++++++++++++++ source4/scripting/bin/samba_gpoupdate | 6 ++-- 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 python/samba/gp_ext_loader.py diff --git a/python/samba/gp_ext_loader.py b/python/samba/gp_ext_loader.py new file mode 100644 index 00000000000..7dcdc23df18 --- /dev/null +++ b/python/samba/gp_ext_loader.py @@ -0,0 +1,56 @@ +# Group Policy Client Side Extension Loader +# Copyright (C) David Mulder 2018 +# +# 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 . + +import os +from samba import gpo + +try: + import importlib.util + def import_file(name, location): + try: + spec = importlib.util.spec_from_file_location(name, location) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + except AttributeError: + from importlib.machinery import SourceFileLoader + module = SourceFileLoader(name, location).load_module() + return module +except ImportError: + import imp + def import_file(name, location): + return imp.load_source(name, location) + +def get_gp_ext_from_module(name, mod): + import inspect + if mod: + clses = inspect.getmembers(mod, inspect.isclass) + for cls in clses: + if cls[-1].__name__ == name: + return cls[-1] + return None + +def get_gp_client_side_extensions(logger, smb_conf): + machine_exts = [] + gp_exts = gpo.list_gp_extensions(smb_conf) + for gp_ext in gp_exts.values(): + module = import_file(gp_ext['ProcessGroupPolicy'], gp_ext['DllName']) + ext = get_gp_ext_from_module(gp_ext['ProcessGroupPolicy'], module) + if ext and gp_ext['MachinePolicy']: + machine_exts.append(ext) + logger.info('Loaded machine extension from %s: %s' + % (gp_ext['DllName'], ext.__name__)) + return machine_exts + diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate index e2c8c625aea..c319797cda6 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/samba_gpoupdate @@ -30,7 +30,7 @@ sys.path.insert(0, "bin/python") import optparse from samba import getopt as options from samba.gpclass import apply_gp, unapply_gp, GPOStorage -from samba.gp_sec_ext import gp_sec_ext +from samba.gp_ext_loader import get_gp_client_side_extensions import logging if __name__ == "__main__": @@ -77,9 +77,11 @@ if __name__ == "__main__": cache_dir = lp.get('cache directory') store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb')) + machine_exts = get_gp_client_side_extensions(logger, lp.configfile) gp_extensions = [] if opts.machine: - gp_extensions.append(gp_sec_ext(logger)) + for ext in machine_exts: + gp_extensions.append(ext(logger)) else: pass # User extensions From b05068fafad78be5b64b25f727e4ec1126819be8 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Wed, 16 May 2018 10:58:29 -0600 Subject: [PATCH 10/30] gpo: Initialize gp_ext variables in constructor Initialize variables for the gp_ext in the constructor instead of passing them via the parse function. Signed-off-by: David Mulder --- python/samba/gpclass.py | 12 ++++++------ source4/scripting/bin/samba_gpoupdate | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index da21fa1da0e..c580d7e7643 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -290,8 +290,11 @@ def __del__(self): class gp_ext(object): __metaclass__ = ABCMeta - def __init__(self, logger): + def __init__(self, logger, lp, creds, store): self.logger = logger + self.lp = lp + self.creds = creds + self.gp_db = store.get_gplog(creds.get_username()) @abstractmethod def list(self, rootpath): @@ -305,10 +308,7 @@ def apply_map(self): def read(self, policy): pass - def parse(self, afile, conn, gp_db, lp): - self.gp_db = gp_db - self.lp = lp - + def parse(self, afile, conn): # Fixing the bug where only some Linux Boxes capitalize MACHINE try: blist = afile.split('/') @@ -460,7 +460,7 @@ def apply_gp(lp, creds, logger, store, gp_extensions): store.start() for ext in gp_extensions: try: - ext.parse(ext.list(path), conn, gp_db, lp) + ext.parse(ext.list(path), conn) except Exception as e: logger.error('Failed to parse gpo %s for extension %s' % \ (guid, str(ext))) diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate index c319797cda6..23c48d4ab3b 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/samba_gpoupdate @@ -81,7 +81,7 @@ if __name__ == "__main__": gp_extensions = [] if opts.machine: for ext in machine_exts: - gp_extensions.append(ext(logger)) + gp_extensions.append(ext(logger, lp, creds, store)) else: pass # User extensions From 3c792c95335e27e3226489ea75e820a4f97cab02 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 4 May 2018 13:25:25 -0600 Subject: [PATCH 11/30] gpo: Add user policy extensions Signed-off-by: David Mulder --- python/samba/gp_ext_loader.py | 7 ++++++- python/samba/gpclass.py | 7 ++++++- source4/scripting/bin/samba_gpoupdate | 6 ++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/python/samba/gp_ext_loader.py b/python/samba/gp_ext_loader.py index 7dcdc23df18..a1a60323012 100644 --- a/python/samba/gp_ext_loader.py +++ b/python/samba/gp_ext_loader.py @@ -43,6 +43,7 @@ def get_gp_ext_from_module(name, mod): return None def get_gp_client_side_extensions(logger, smb_conf): + user_exts = [] machine_exts = [] gp_exts = gpo.list_gp_extensions(smb_conf) for gp_ext in gp_exts.values(): @@ -52,5 +53,9 @@ def get_gp_client_side_extensions(logger, smb_conf): machine_exts.append(ext) logger.info('Loaded machine extension from %s: %s' % (gp_ext['DllName'], ext.__name__)) - return machine_exts + if ext and gp_ext['UserPolicy']: + user_exts.append(ext) + logger.info('Loaded user extension from %s: %s' + % (gp_ext['DllName'], ext.__name__)) + return (machine_exts, user_exts) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index c580d7e7643..4e5a4ef929c 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -312,7 +312,12 @@ def parse(self, afile, conn): # Fixing the bug where only some Linux Boxes capitalize MACHINE try: blist = afile.split('/') - idx = afile.lower().split('/').index('machine') + index = None + if 'machine' in afile.lower(): + index = 'machine' + elif 'user' in afile.lower(): + index = 'user' + idx = afile.lower().split('/').index(index) for case in [ blist[idx].upper(), blist[idx].capitalize(), diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate index 23c48d4ab3b..d0f1d73278b 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/samba_gpoupdate @@ -77,13 +77,15 @@ if __name__ == "__main__": cache_dir = lp.get('cache directory') store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb')) - machine_exts = get_gp_client_side_extensions(logger, lp.configfile) + machine_exts, user_exts = get_gp_client_side_extensions(logger, + lp.configfile) gp_extensions = [] if opts.machine: for ext in machine_exts: gp_extensions.append(ext(logger, lp, creds, store)) else: - pass # User extensions + for ext in user_exts: + gp_extensions.append(ext(logger, lp, creds, store)) if not opts.unapply: apply_gp(lp, creds, logger, store, gp_extensions) From a200cb8762dcca81a3f0c553b8924a881ff0e684 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 7 May 2018 09:45:32 -0600 Subject: [PATCH 12/30] samba_gpoupdate: Rename the command to gpupdate On a Windows client, this command is called 'gpupdate' Signed-off-by: David Mulder --- docs-xml/smbdotconf/domain/gpoupdatecommand.xml | 4 ++-- lib/param/loadparm.c | 2 +- selftest/target/Samba4.pm | 2 +- source3/param/loadparm.c | 2 +- source4/scripting/bin/{samba_gpoupdate => gpupdate} | 4 ++-- source4/scripting/bin/wscript_build | 2 +- .../scripting/man/{samba_gpoupdate.8.xml => gpupdate.8.xml} | 10 +++++----- source4/scripting/wscript_build | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) rename source4/scripting/bin/{samba_gpoupdate => gpupdate} (96%) rename source4/scripting/man/{samba_gpoupdate.8.xml => gpupdate.8.xml} (94%) diff --git a/docs-xml/smbdotconf/domain/gpoupdatecommand.xml b/docs-xml/smbdotconf/domain/gpoupdatecommand.xml index 3ce26d78287..6832201c288 100644 --- a/docs-xml/smbdotconf/domain/gpoupdatecommand.xml +++ b/docs-xml/smbdotconf/domain/gpoupdatecommand.xml @@ -5,7 +5,7 @@ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> This option sets the command that is called to apply GPO policies. - The samba_gpoupdate script applies System Access and Kerberos Policies + The gpupdate script applies System Access and Kerberos Policies to the KDC. System Access policies set minPwdAge, maxPwdAge, minPwdLength, and pwdProperties in the samdb. Kerberos Policies set kdc:service ticket lifetime, kdc:user ticket lifetime, and kdc:renewal @@ -13,6 +13,6 @@ -&pathconfig.SCRIPTSBINDIR;/samba_gpoupdate +&pathconfig.SCRIPTSBINDIR;/gpupdate /usr/local/sbin/gpoupdate diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index 3b7f8053e4a..1f95f073f74 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2733,7 +2733,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "require strong key", "True"); lpcfg_do_global_parameter(lp_ctx, "winbindd socket directory", dyn_WINBINDD_SOCKET_DIR); lpcfg_do_global_parameter(lp_ctx, "ntp signd socket directory", dyn_NTP_SIGND_SOCKET_DIR); - lpcfg_do_global_parameter_var(lp_ctx, "gpo update command", "%s/samba_gpoupdate", dyn_SCRIPTSBINDIR); + lpcfg_do_global_parameter_var(lp_ctx, "gpo update command", "%s/gpupdate", dyn_SCRIPTSBINDIR); lpcfg_do_global_parameter_var(lp_ctx, "apply group policies", "False"); lpcfg_do_global_parameter_var(lp_ctx, "dns update command", "%s/samba_dnsupdate", dyn_SCRIPTSBINDIR); lpcfg_do_global_parameter_var(lp_ctx, "spn update command", "%s/samba_spnupdate", dyn_SCRIPTSBINDIR); diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 5353779292e..cf8c0acc4e9 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -641,7 +641,7 @@ sub provision_raw_step1($$) rndc command = true dns update command = $ctx->{samba_dnsupdate} spn update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_spnupdate -s $ctx->{smb_conf} - gpo update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_gpoupdate -s $ctx->{smb_conf} -H $ctx->{privatedir}/sam.ldb --machine + gpo update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/gpupdate -s $ctx->{smb_conf} -H $ctx->{privatedir}/sam.ldb --machine dreplsrv:periodic_startup_interval = 0 dsdb:schema update allowed = yes diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index ecff22eb638..d7c43b78701 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -917,7 +917,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.dns_update_command = str_list_make_v3_const(NULL, s, NULL); TALLOC_FREE(s); - s = talloc_asprintf(talloc_tos(), "%s/samba_gpoupdate", get_dyn_SCRIPTSBINDIR()); + s = talloc_asprintf(talloc_tos(), "%s/gpupdate", get_dyn_SCRIPTSBINDIR()); if (s == NULL) { smb_panic("init_globals: ENOMEM"); } diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/gpupdate similarity index 96% rename from source4/scripting/bin/samba_gpoupdate rename to source4/scripting/bin/gpupdate index d0f1d73278b..0ade8d470f3 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/gpupdate @@ -34,7 +34,7 @@ from samba.gp_ext_loader import get_gp_client_side_extensions import logging if __name__ == "__main__": - parser = optparse.OptionParser('samba_gpoupdate [options]') + parser = optparse.OptionParser('gpupdate [options]') sambaopts = options.SambaOptions(parser) # Get the command line options @@ -61,7 +61,7 @@ if __name__ == "__main__": creds = credopts.get_credentials(lp, fallback_machine=True) # Set up logging - logger = logging.getLogger('samba_gpoupdate') + logger = logging.getLogger('gpupdate') logger.addHandler(logging.StreamHandler(sys.stdout)) logger.setLevel(logging.CRITICAL) log_level = lp.log_level() diff --git a/source4/scripting/bin/wscript_build b/source4/scripting/bin/wscript_build index 043442b3407..a1dbd558703 100644 --- a/source4/scripting/bin/wscript_build +++ b/source4/scripting/bin/wscript_build @@ -9,4 +9,4 @@ if bld.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'): 'samba_upgradedns', 'gen_output.py']: bld.SAMBA_SCRIPT(script, pattern=script, installdir='.') -bld.SAMBA_SCRIPT('samba_gpoupdate', pattern='samba_gpoupdate', installdir='.') +bld.SAMBA_SCRIPT('gpupdate', pattern='gpupdate', installdir='.') diff --git a/source4/scripting/man/samba_gpoupdate.8.xml b/source4/scripting/man/gpupdate.8.xml similarity index 94% rename from source4/scripting/man/samba_gpoupdate.8.xml rename to source4/scripting/man/gpupdate.8.xml index 0c3a0a812a1..5ac93f469fd 100644 --- a/source4/scripting/man/samba_gpoupdate.8.xml +++ b/source4/scripting/man/gpupdate.8.xml @@ -1,6 +1,6 @@ - + 2017-07-11 @@ -12,17 +12,17 @@ - samba_gpoupdate + gpupdate apply group policy - samba_gpoupdate + gpupdate - samba_gpoupdate + gpupdate options @@ -37,7 +37,7 @@ samba 1 suite. - samba_gpoupdate a script for + gpupdate a script for applying and unapplying Group Policy. Group Policy application is experimental. Currently this applies password policies (minimum/maximum password age, diff --git a/source4/scripting/wscript_build b/source4/scripting/wscript_build index 2f53cce12b7..b20ff9bc103 100644 --- a/source4/scripting/wscript_build +++ b/source4/scripting/wscript_build @@ -5,8 +5,8 @@ from samba_utils import MODE_755 sbin_files = '' if bld.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'): sbin_files = 'bin/samba_dnsupdate bin/samba_spnupdate bin/samba_upgradedns bin/samba_kcc ' -sbin_files += 'bin/samba_gpoupdate' -man_files = 'man/samba_gpoupdate.8' +sbin_files += 'bin/gpupdate' +man_files = 'man/gpupdate.8' if sbin_files: bld.INSTALL_FILES('${SBINDIR}', From a31a2667719cbf1a92d58abf9aaf7e20d2a5a6bb Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 7 May 2018 09:48:32 -0600 Subject: [PATCH 13/30] gpupdate: Change machine option to target On a Windows client, you designate machine/user apply with a 'target' parameter. This change makes gpupdate work more like that command. Signed-off-by: David Mulder --- selftest/target/Samba4.pm | 2 +- source3/winbindd/winbindd_gpupdate.c | 2 +- source4/scripting/bin/gpupdate | 8 ++++---- source4/scripting/man/gpupdate.8.xml | 3 +++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index cf8c0acc4e9..9da08d86d5b 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -641,7 +641,7 @@ sub provision_raw_step1($$) rndc command = true dns update command = $ctx->{samba_dnsupdate} spn update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_spnupdate -s $ctx->{smb_conf} - gpo update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/gpupdate -s $ctx->{smb_conf} -H $ctx->{privatedir}/sam.ldb --machine + gpo update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/gpupdate -s $ctx->{smb_conf} -H $ctx->{privatedir}/sam.ldb --target=Computer dreplsrv:periodic_startup_interval = 0 dsdb:schema update allowed = yes diff --git a/source3/winbindd/winbindd_gpupdate.c b/source3/winbindd/winbindd_gpupdate.c index c86c007be12..75772ea4feb 100644 --- a/source3/winbindd/winbindd_gpupdate.c +++ b/source3/winbindd/winbindd_gpupdate.c @@ -62,7 +62,7 @@ static void gpupdate_callback(struct tevent_context *ev, gpupdate_cmd, "-s", smbconf, - "--machine", + "--target=Computer", "--machine-pass", NULL); if (req == NULL) { diff --git a/source4/scripting/bin/gpupdate b/source4/scripting/bin/gpupdate index 0ade8d470f3..ecbf8e02069 100755 --- a/source4/scripting/bin/gpupdate +++ b/source4/scripting/bin/gpupdate @@ -44,8 +44,8 @@ if __name__ == "__main__": parser.add_option('-H', '--url', dest='url', help='URL for the samdb') parser.add_option('-X', '--unapply', help='Unapply Group Policy', action='store_true') - parser.add_option('-M', '--machine', help='Apply machine policy', - action='store_true', default=False) + parser.add_option('--target', default='Computer', help='{Computer | User}', + choices=['Computer', 'User']) parser.add_option_group(credopts) # Set the options and the arguments @@ -80,10 +80,10 @@ if __name__ == "__main__": machine_exts, user_exts = get_gp_client_side_extensions(logger, lp.configfile) gp_extensions = [] - if opts.machine: + if opts.target == 'Computer': for ext in machine_exts: gp_extensions.append(ext(logger, lp, creds, store)) - else: + elif opts.target == 'User': for ext in user_exts: gp_extensions.append(ext(logger, lp, creds, store)) diff --git a/source4/scripting/man/gpupdate.8.xml b/source4/scripting/man/gpupdate.8.xml index 5ac93f469fd..be70a70ca7f 100644 --- a/source4/scripting/man/gpupdate.8.xml +++ b/source4/scripting/man/gpupdate.8.xml @@ -59,6 +59,9 @@ , Unapply Group Policy + + {Computer | User} + Samba Common Options: FILE, =FILE From c5f7ea29c69ed778eaf5c8dae351cea6980cb892 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 7 May 2018 10:18:00 -0600 Subject: [PATCH 14/30] gpupdate: Don't fail with dc installed Don't fail if the dc is installed, but we're joined as a client. Signed-off-by: David Mulder --- python/samba/gp_sec_ext.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index 4f2092ba403..58f6fb66ecd 100644 --- a/python/samba/gp_sec_ext.py +++ b/python/samba/gp_sec_ext.py @@ -141,10 +141,13 @@ def listuserpol(self, rootpath): def apply_map(self): if SamDB: - self.ldb = SamDB(self.lp.samdb_url(), - session_info=system_session(), - credentials=self.creds, - lp=self.lp) + try: + self.ldb = SamDB(self.lp.samdb_url(), + session_info=system_session(), + credentials=self.creds, + lp=self.lp) + except: + return {} else: return {} return {"System Access": {"MinimumPasswordAge": ("minPwdAge", From 46af1bfa3ef082524b9f4dc9012c81e5f040a252 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Wed, 9 May 2018 10:39:06 -0600 Subject: [PATCH 15/30] gpo: Remove old gp_ext and net ads gpo code Signed-off-by: David Mulder --- source3/libgpo/gpext/registry.c | 428 -------------------------------- source3/libgpo/gpext/scripts.c | 487 ------------------------------------- source3/libgpo/gpext/security.c | 297 ---------------------- source3/libgpo/gpext/wscript_build | 23 -- source3/utils/net_ads_gpo.c | 94 ------- source3/wscript_build | 1 - 6 files changed, 1330 deletions(-) delete mode 100644 source3/libgpo/gpext/registry.c delete mode 100644 source3/libgpo/gpext/scripts.c delete mode 100644 source3/libgpo/gpext/security.c delete mode 100644 source3/libgpo/gpext/wscript_build diff --git a/source3/libgpo/gpext/registry.c b/source3/libgpo/gpext/registry.c deleted file mode 100644 index ceb05f030b6..00000000000 --- a/source3/libgpo/gpext/registry.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Group Policy Support - * Copyright (C) Guenther Deschner 2007-2008,2010 - * - * 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 . - */ - -#include "includes.h" -#include "../libgpo/gpo_ini.h" -#include "../libgpo/gpo.h" -#include "libgpo/gpo_proto.h" -#include "registry.h" -#include "../librpc/gen_ndr/ndr_preg.h" -#include "libgpo/gpext/gpext.h" - -#define GP_EXT_NAME "registry" - -/* more info can be found at: - * http://msdn2.microsoft.com/en-us/library/aa374407.aspx */ - -#define GP_REGPOL_FILE "Registry.pol" - -#define GP_REGPOL_FILE_SIGNATURE 0x67655250 /* 'PReg' */ -#define GP_REGPOL_FILE_VERSION 1 - -static TALLOC_CTX *ctx = NULL; - -NTSTATUS gpext_registry_init(TALLOC_CTX *mem_ctx); - -/**************************************************************** -****************************************************************/ - -static bool reg_parse_value(TALLOC_CTX *mem_ctx, - const char **value, - enum gp_reg_action *action) -{ - if (!*value) { - *action = GP_REG_ACTION_ADD_KEY; - return true; - } - - if (strncmp(*value, "**", 2) != 0) { - *action = GP_REG_ACTION_ADD_VALUE; - return true; - } - - if (strnequal(*value, "**DelVals.", 10)) { - *action = GP_REG_ACTION_DEL_ALL_VALUES; - return true; - } - - if (strnequal(*value, "**Del.", 6)) { - *value = talloc_strdup(mem_ctx, *value + 6); - *action = GP_REG_ACTION_DEL_VALUE; - return true; - } - - if (strnequal(*value, "**SecureKey", 11)) { - if (strnequal(*value, "**SecureKey=1", 13)) { - *action = GP_REG_ACTION_SEC_KEY_SET; - return true; - } - - /*************** not tested from here on ***************/ - if (strnequal(*value, "**SecureKey=0", 13)) { - smb_panic("not supported: **SecureKey=0"); - *action = GP_REG_ACTION_SEC_KEY_RESET; - return true; - } - DEBUG(0,("unknown: SecureKey: %s\n", *value)); - smb_panic("not supported SecureKey method"); - return false; - } - - if (strnequal(*value, "**DeleteValues", strlen("**DeleteValues"))) { - smb_panic("not supported: **DeleteValues"); - *action = GP_REG_ACTION_DEL_VALUES; - return false; - } - - if (strnequal(*value, "**DeleteKeys", strlen("**DeleteKeys"))) { - smb_panic("not supported: **DeleteKeys"); - *action = GP_REG_ACTION_DEL_KEYS; - return false; - } - - DEBUG(0,("unknown value: %s\n", *value)); - smb_panic(*value); - return false; -} - -/**************************************************************** -****************************************************************/ - -static bool gp_reg_entry_from_file_entry(TALLOC_CTX *mem_ctx, - struct preg_entry *r, - struct gp_registry_entry **reg_entry) -{ - struct registry_value *data = NULL; - struct gp_registry_entry *entry = NULL; - enum gp_reg_action action = GP_REG_ACTION_NONE; - - ZERO_STRUCTP(*reg_entry); - - data = talloc_zero(mem_ctx, struct registry_value); - if (!data) - return false; - - data->type = r->type; - data->data = data_blob_talloc(data, r->data, r->size); - - entry = talloc_zero(mem_ctx, struct gp_registry_entry); - if (!entry) - return false; - - if (!reg_parse_value(mem_ctx, &r->valuename, &action)) - return false; - - entry->key = talloc_strdup(entry, r->keyname); - entry->value = talloc_strdup(entry, r->valuename); - entry->data = data; - entry->action = action; - - *reg_entry = entry; - - return true; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS reg_parse_registry(TALLOC_CTX *mem_ctx, - uint32_t flags, - const char *filename, - struct gp_registry_entry **entries_p, - size_t *num_entries_p) -{ - DATA_BLOB blob; - NTSTATUS status; - enum ndr_err_code ndr_err; - const char *real_filename = NULL; - struct preg_file r; - struct gp_registry_entry *entries = NULL; - size_t num_entries = 0; - int i; - - status = gp_find_file(mem_ctx, - flags, - filename, - GP_REGPOL_FILE, - &real_filename); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - blob.data = (uint8_t *)file_load(real_filename, &blob.length, 0, NULL); - if (!blob.data) { - return NT_STATUS_CANNOT_LOAD_REGISTRY_FILE; - } - - ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r, - (ndr_pull_flags_fn_t)ndr_pull_preg_file); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - status = ndr_map_error2ntstatus(ndr_err); - goto out; - } - - if (flags & GPO_INFO_FLAG_VERBOSE) { - NDR_PRINT_DEBUG(preg_file, &r); - } - - if (!strequal(r.header.signature, "PReg")) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; - } - - if (r.header.version != GP_REGPOL_FILE_VERSION) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; - } - - for (i=0; i < r.num_entries; i++) { - - struct gp_registry_entry *r_entry = NULL; - - if (!gp_reg_entry_from_file_entry(mem_ctx, - &r.entries[i], - &r_entry)) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - - if (!add_gp_registry_entry_to_array(mem_ctx, - r_entry, - &entries, - &num_entries)) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - } - - *entries_p = entries; - *num_entries_p = num_entries; - - status = NT_STATUS_OK; - - out: - data_blob_free(&blob); - return status; -} - -/**************************************************************** -****************************************************************/ - -static WERROR reg_apply_registry(TALLOC_CTX *mem_ctx, - const struct security_token *token, - struct registry_key *root_key, - uint32_t flags, - struct gp_registry_entry *entries, - size_t num_entries) -{ - struct gp_registry_context *reg_ctx = NULL; - WERROR werr; - size_t i; - - if (num_entries == 0) { - return WERR_OK; - } - -#if 0 - if (flags & GPO_LIST_FLAG_MACHINE) { - werr = gp_init_reg_ctx(mem_ctx, KEY_HKLM, REG_KEY_WRITE, - get_system_token(), - ®_ctx); - } else { - werr = gp_init_reg_ctx(mem_ctx, KEY_HKCU, REG_KEY_WRITE, - token, - ®_ctx); - } - W_ERROR_NOT_OK_RETURN(werr); -#endif - for (i=0; inext) { - } - - */ - - for (gpo = changed_gpo_list; gpo; gpo = gpo->next) { - - gpext_debug_header(0, "registry_process_group_policy", flags, - gpo, GP_EXT_GUID_REGISTRY, NULL); - - status = gpo_get_unix_path(mem_ctx, gpo_cache_path, - gpo, &unix_path); - if (!NT_STATUS_IS_OK(status)) { - goto err_cache_path_free; - } - - status = reg_parse_registry(mem_ctx, - flags, - unix_path, - &entries, - &num_entries); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("failed to parse registry: %s\n", - nt_errstr(status))); - goto err_cache_path_free; - } - - dump_reg_entries(flags, "READ", entries, num_entries); - - werr = reg_apply_registry(mem_ctx, token, root_key, flags, - entries, num_entries); - if (!W_ERROR_IS_OK(werr)) { - DEBUG(0,("failed to apply registry: %s\n", - win_errstr(werr))); - status = werror_to_ntstatus(werr); - goto err_cache_path_free; - } - } - status = NT_STATUS_OK; - -err_cache_path_free: - talloc_free(gpo_cache_path); - talloc_free(entries); - return status; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS registry_get_reg_config(TALLOC_CTX *mem_ctx, - struct gp_extension_reg_info **reg_info) -{ - NTSTATUS status; - struct gp_extension_reg_info *info = NULL; - struct gp_extension_reg_table table[] = { - { "ProcessGroupPolicy", REG_SZ, "registry_process_group_policy" }, - { NULL, REG_NONE, NULL } - }; - - info = talloc_zero(mem_ctx, struct gp_extension_reg_info); - NT_STATUS_HAVE_NO_MEMORY(info); - - status = gpext_info_add_entry(mem_ctx, GP_EXT_NAME, - GP_EXT_GUID_REGISTRY, - table, info); - NT_STATUS_NOT_OK_RETURN(status); - - *reg_info = info; - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS registry_initialize(TALLOC_CTX *mem_ctx) -{ - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS registry_shutdown(void) -{ - NTSTATUS status; - - status = gpext_unregister_gp_extension(GP_EXT_NAME); - if (NT_STATUS_IS_OK(status)) { - return status; - } - - TALLOC_FREE(ctx); - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static struct gp_extension_methods registry_methods = { - .initialize = registry_initialize, - .process_group_policy = registry_process_group_policy, - .get_reg_config = registry_get_reg_config, - .shutdown = registry_shutdown -}; - -/**************************************************************** -****************************************************************/ - -NTSTATUS gpext_registry_init(TALLOC_CTX *mem_ctx) -{ - NTSTATUS status; - - ctx = talloc_init("gpext_registry_init"); - NT_STATUS_HAVE_NO_MEMORY(ctx); - - status = gpext_register_gp_extension(ctx, SMB_GPEXT_INTERFACE_VERSION, - GP_EXT_NAME, GP_EXT_GUID_REGISTRY, - ®istry_methods); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(ctx); - } - - return status; -} diff --git a/source3/libgpo/gpext/scripts.c b/source3/libgpo/gpext/scripts.c deleted file mode 100644 index de664133b87..00000000000 --- a/source3/libgpo/gpext/scripts.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Group Policy Support - * Copyright (C) Guenther Deschner 2007 - * - * 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 . - */ - -#include "includes.h" -#include "../libgpo/gpo_ini.h" -#include "../libgpo/gpo.h" -#include "libgpo/gpo_proto.h" -#include "registry.h" -#include "registry/reg_api.h" -#include "../libcli/registry/util_reg.h" -#include "libgpo/gpext/gpext.h" - -#define GP_EXT_NAME "scripts" - -#define KEY_GP_SCRIPTS "Software\\Policies\\Microsoft\\Windows\\System\\Scripts" - -#define GP_SCRIPTS_INI "Scripts/scripts.ini" - -#define GP_SCRIPTS_INI_STARTUP "Startup" -#define GP_SCRIPTS_INI_SHUTDOWN "Shutdown" -#define GP_SCRIPTS_INI_LOGON "Logon" -#define GP_SCRIPTS_INI_LOGOFF "Logoff" - -#define GP_SCRIPTS_SECTION_CMDLINE "cmdline" -#define GP_SCRIPTS_SECTION_PARAMETERS "parameters" - -#define GP_SCRIPTS_REG_VAL_SCRIPT "Script" -#define GP_SCRIPTS_REG_VAL_PARAMETERS "Parameters" -#define GP_SCRIPTS_REG_VAL_EXECTIME "ExecTime" - -NTSTATUS gpext_scripts_init(TALLOC_CTX *mem_ctx); - -static TALLOC_CTX *ctx = NULL; - -/**************************************************************** -****************************************************************/ - -static NTSTATUS scripts_get_reg_config(TALLOC_CTX *mem_ctx, - struct gp_extension_reg_info **reg_info) -{ - NTSTATUS status; - struct gp_extension_reg_info *info = NULL; - - struct gp_extension_reg_table table[] = { - { "ProcessGroupPolicy", REG_SZ, "scripts_process_group_policy" }, - { "NoGPOListChanges", REG_DWORD, "1" }, - { "NoSlowLink", REG_DWORD, "1" }, - { "NotifyLinkTransition", REG_DWORD, "1" }, - { NULL, REG_NONE, NULL }, - }; - - info = talloc_zero(mem_ctx, struct gp_extension_reg_info); - NT_STATUS_HAVE_NO_MEMORY(info); - - status = gpext_info_add_entry(mem_ctx, GP_EXT_NAME, - GP_EXT_GUID_SCRIPTS, - table, info); - NT_STATUS_NOT_OK_RETURN(status); - - *reg_info = info; - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS generate_gp_registry_entry(TALLOC_CTX *mem_ctx, - const char *key, - const char *value, - uint32_t data_type, - DATA_BLOB *blob, - enum gp_reg_action action, - struct gp_registry_entry **entry_out) -{ - struct gp_registry_entry *entry = NULL; - struct registry_value *data = NULL; - - entry = talloc_zero(mem_ctx, struct gp_registry_entry); - NT_STATUS_HAVE_NO_MEMORY(entry); - - data = talloc_zero(mem_ctx, struct registry_value); - NT_STATUS_HAVE_NO_MEMORY(data); - - data->type = data_type; - data->data = *blob; - - entry->key = key; - entry->data = data; - entry->action = action; - entry->value = talloc_strdup(mem_ctx, value); - NT_STATUS_HAVE_NO_MEMORY(entry->value); - - *entry_out = entry; - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS scripts_parse_ini_section(struct gp_inifile_context *ini_ctx, - uint32_t flags, - const char *section, - struct gp_registry_entry **entries, - size_t *num_entries) -{ - NTSTATUS status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - NTSTATUS result; - int i = 0; - - while (1) { - - const char *key = NULL; - const char *script = NULL; - const char *count = NULL; - const char *parameters = NULL; - DATA_BLOB blob; - bool ok; - - count = talloc_asprintf(ini_ctx->mem_ctx, "%d", i); - NT_STATUS_HAVE_NO_MEMORY(count); - - key = talloc_asprintf(ini_ctx->mem_ctx, "%s:%s%s", - section, count, - GP_SCRIPTS_SECTION_CMDLINE); - NT_STATUS_HAVE_NO_MEMORY(key); - - result = gp_inifile_getstring(ini_ctx, key, &script); - if (!NT_STATUS_IS_OK(result)) { - break; - } - - key = talloc_asprintf(ini_ctx->mem_ctx, "%s:%s%s", - section, count, - GP_SCRIPTS_SECTION_PARAMETERS); - NT_STATUS_HAVE_NO_MEMORY(key); - - result = gp_inifile_getstring(ini_ctx, key, ¶meters); - if (!NT_STATUS_IS_OK(result)) { - break; - } - - { - struct gp_registry_entry *entry = NULL; - - ok = push_reg_sz(ini_ctx->mem_ctx, &blob, script); - if (!ok) { - return NT_STATUS_NO_MEMORY; - } - - status = generate_gp_registry_entry(ini_ctx->mem_ctx, - count, - GP_SCRIPTS_REG_VAL_SCRIPT, - REG_SZ, - &blob, - GP_REG_ACTION_ADD_VALUE, - &entry); - NT_STATUS_NOT_OK_RETURN(status); - if (!add_gp_registry_entry_to_array(ini_ctx->mem_ctx, - entry, - entries, - num_entries)) { - return NT_STATUS_NO_MEMORY; - } - } - { - struct gp_registry_entry *entry = NULL; - - ok = push_reg_sz(ini_ctx->mem_ctx, &blob, parameters); - if (!ok) { - return NT_STATUS_NO_MEMORY; - } - - status = generate_gp_registry_entry(ini_ctx->mem_ctx, - count, - GP_SCRIPTS_REG_VAL_PARAMETERS, - REG_SZ, - &blob, - GP_REG_ACTION_ADD_VALUE, - &entry); - NT_STATUS_NOT_OK_RETURN(status); - if (!add_gp_registry_entry_to_array(ini_ctx->mem_ctx, - entry, - entries, - num_entries)) { - return NT_STATUS_NO_MEMORY; - } - } - { - struct gp_registry_entry *entry = NULL; - - blob = data_blob_talloc_zero(ini_ctx->mem_ctx, 8); - - status = generate_gp_registry_entry(ini_ctx->mem_ctx, - count, - GP_SCRIPTS_REG_VAL_EXECTIME, - REG_QWORD, - &blob, - GP_REG_ACTION_ADD_VALUE, - &entry); - NT_STATUS_NOT_OK_RETURN(status); - if (!add_gp_registry_entry_to_array(ini_ctx->mem_ctx, - entry, - entries, - num_entries)) { - return NT_STATUS_NO_MEMORY; - } - } - status = NT_STATUS_OK; - i++; - } - - return status; -} - -/**************************************************************** -****************************************************************/ - -static WERROR scripts_store_reg_gpovals(TALLOC_CTX *mem_ctx, - struct registry_key *key, - const struct GROUP_POLICY_OBJECT *gpo) -{ - WERROR werr; - - if (!key || !gpo) { - return WERR_INVALID_PARAMETER; - } - - werr = gp_store_reg_val_sz(mem_ctx, key, "DisplayName", - gpo->display_name); - W_ERROR_NOT_OK_RETURN(werr); - - werr = gp_store_reg_val_sz(mem_ctx, key, "FileSysPath", - gpo->file_sys_path); - W_ERROR_NOT_OK_RETURN(werr); - - werr = gp_store_reg_val_sz(mem_ctx, key, "GPO-ID", - gpo->ds_path); - W_ERROR_NOT_OK_RETURN(werr); - - werr = gp_store_reg_val_sz(mem_ctx, key, "GPOName", - gpo->name); - W_ERROR_NOT_OK_RETURN(werr); - - werr = gp_store_reg_val_sz(mem_ctx, key, "SOM-ID", - gpo->link); - W_ERROR_NOT_OK_RETURN(werr); - - return werr; -} - -/**************************************************************** -****************************************************************/ - -static WERROR scripts_apply(TALLOC_CTX *mem_ctx, - const struct security_token *token, - struct registry_key *root_key, - uint32_t flags, - const char *section, - const struct GROUP_POLICY_OBJECT *gpo, - struct gp_registry_entry *entries, - size_t num_entries) -{ - struct gp_registry_context *reg_ctx = NULL; - WERROR werr; - size_t i; - const char *keystr = NULL; - int count = 0; - - if (num_entries == 0) { - return WERR_OK; - } - -#if 0 - if (flags & GPO_INFO_FLAG_MACHINE) { - struct security_token *tmp_token; - - tmp_token = registry_create_system_token(mem_ctx); - W_ERROR_HAVE_NO_MEMORY(tmp_token); - - werr = gp_init_reg_ctx(mem_ctx, KEY_HKLM, REG_KEY_WRITE, - tmp_token, - ®_ctx); - } else { - werr = gp_init_reg_ctx(mem_ctx, KEY_HKCU, REG_KEY_WRITE, - token, - ®_ctx); - } - W_ERROR_NOT_OK_RETURN(werr); -#endif - - keystr = talloc_asprintf(mem_ctx, "%s\\%s\\%d", KEY_GP_SCRIPTS, - section, count++); - W_ERROR_HAVE_NO_MEMORY(keystr); - - reg_deletekey_recursive(root_key, keystr); - - werr = gp_store_reg_subkey(mem_ctx, keystr, - root_key, &root_key); - if (!W_ERROR_IS_OK(werr)) { - goto done; - } - - werr = scripts_store_reg_gpovals(mem_ctx, root_key, gpo); - if (!W_ERROR_IS_OK(werr)) { - goto done; - } - - for (i=0; inext) { - } - - */ - - for (gpo = changed_gpo_list; gpo; gpo = gpo->next) { - - gpext_debug_header(0, "scripts_process_group_policy", flags, - gpo, GP_EXT_GUID_SCRIPTS, NULL); - - status = gpo_get_unix_path(mem_ctx, gpo_cache_path, - gpo, &unix_path); - if (!NT_STATUS_IS_OK(status)) { - goto err_cache_path_free; - } - - status = gp_inifile_init_context(mem_ctx, flags, unix_path, - GP_SCRIPTS_INI, &ini_ctx); - if (!NT_STATUS_IS_OK(status)) { - goto err_cache_path_free; - } - - for (i = 0; i < ARRAY_SIZE(list); i++) { - - TALLOC_FREE(entries); - num_entries = 0; - - status = scripts_parse_ini_section(ini_ctx, flags, list[i], - &entries, &num_entries); - if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { - continue; - } - - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(ini_ctx); - goto err_cache_path_free; - } - - dump_reg_entries(flags, "READ", entries, num_entries); - - werr = scripts_apply(ini_ctx->mem_ctx, token, root_key, - flags, list[i], gpo, entries, num_entries); - if (!W_ERROR_IS_OK(werr)) { - continue; /* FIXME: finally fix storing emtpy strings and REG_QWORD! */ - } - } - - TALLOC_FREE(ini_ctx); - } - status = NT_STATUS_OK; - -err_cache_path_free: - talloc_free(gpo_cache_path); - return status; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS scripts_initialize(TALLOC_CTX *mem_ctx) -{ - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS scripts_shutdown(void) -{ - NTSTATUS status; - - status = gpext_unregister_gp_extension(GP_EXT_NAME); - if (NT_STATUS_IS_OK(status)) { - return status; - } - - TALLOC_FREE(ctx); - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static struct gp_extension_methods scripts_methods = { - .initialize = scripts_initialize, - .process_group_policy = scripts_process_group_policy, - .get_reg_config = scripts_get_reg_config, - .shutdown = scripts_shutdown -}; - -/**************************************************************** -****************************************************************/ - -NTSTATUS gpext_scripts_init(TALLOC_CTX *mem_ctx) -{ - NTSTATUS status; - - ctx = talloc_init("gpext_scripts_init"); - NT_STATUS_HAVE_NO_MEMORY(ctx); - - status = gpext_register_gp_extension(ctx, SMB_GPEXT_INTERFACE_VERSION, - GP_EXT_NAME, GP_EXT_GUID_SCRIPTS, - &scripts_methods); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(ctx); - } - - return status; -} diff --git a/source3/libgpo/gpext/security.c b/source3/libgpo/gpext/security.c deleted file mode 100644 index b6b7ca08e62..00000000000 --- a/source3/libgpo/gpext/security.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Group Policy Support - * Copyright (C) Guenther Deschner 2005-2008 - * - * 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 . - */ - -#include "includes.h" -#include "../libgpo/gpo_ini.h" -#include "../libgpo/gpo.h" -#include "libgpo/gpo_proto.h" -#include "libgpo/gpext/gpext.h" - -#define GP_EXT_NAME "security" - -#define GPTTMPL_UNIX_PATH "Microsoft/Windows NT/SecEdit/GptTmpl.inf" - -#define GPTTMPL_SECTION_UNICODE "Unicode" -#define GPTTMPL_SECTION_VERSION "Version" - -#define GPTTMPL_SECTION_REGISTRY_VALUES "Registry Values" -#define GPTTMPL_SECTION_SYSTEM_ACCESS "System Access" -#define GPTTMPL_SECTION_KERBEROS_POLICY "Kerberos Policy" -#define GPTTMPL_SECTION_EVENT_AUDIT "Event Audit" -#define GPTTMPL_SECTION_PRIVILEGE_RIGHTS "Privilege Rights" -#define GPTTMPL_SECTION_APPLICATION_LOG "Application Log" -#define GPTTMPL_SECTION_SECURITY_LOG "Security Log" -#define GPTTMPL_SECTION_SYSTEM_LOG "System Log" -#define GPTTMPL_SECTION_GROUP_MEMBERSHIP "Group Membership" -#define GPTTMPL_SECTION_FILE_SECURITY "File Security" -#define GPTTMPL_SECTION_SERVICE_GENERAL_SETTING "Service General Setting" - -NTSTATUS gpext_security_init(TALLOC_CTX *mem_ctx); - -static TALLOC_CTX *ctx = NULL; - -struct gpttmpl_table { - const char *section; - const char *parameter; - enum winreg_Type type; -}; - -/**************************************************************** - parse the Version section from gpttmpl file -****************************************************************/ - -#define GPTTMPL_PARAMETER_REVISION "Revision" -#define GPTTMPL_PARAMETER_SIGNATURE "signature" -#define GPTTMPL_VALUE_CHICAGO "\"$CHICAGO$\"" /* whatever this is good for... */ -#define GPTTMPL_PARAMETER_UNICODE "Unicode" - -static NTSTATUS gpttmpl_parse_header(struct gp_inifile_context *ini_ctx, - uint32_t *version_out) -{ - const char *signature = NULL; - NTSTATUS result; - int version; - bool is_unicode = false; - - if (!ini_ctx) { - return NT_STATUS_INVALID_PARAMETER; - } - - result = gp_inifile_getstring(ini_ctx, GPTTMPL_SECTION_VERSION - ":"GPTTMPL_PARAMETER_SIGNATURE, &signature); - if (!NT_STATUS_IS_OK(result)) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (!strequal(signature, GPTTMPL_VALUE_CHICAGO)) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - result = gp_inifile_getint(ini_ctx, GPTTMPL_SECTION_VERSION - ":"GPTTMPL_PARAMETER_REVISION, &version); - if (!NT_STATUS_IS_OK(result)) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (version_out) { - *version_out = version; - } - - result = gp_inifile_getbool(ini_ctx, GPTTMPL_SECTION_UNICODE - ":"GPTTMPL_PARAMETER_UNICODE, &is_unicode); - if (!NT_STATUS_IS_OK(result) || !is_unicode) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS gpttmpl_init_context(TALLOC_CTX *mem_ctx, - uint32_t flags, - const char *unix_path, - struct gp_inifile_context **ini_ctx) -{ - NTSTATUS status; - uint32_t version; - struct gp_inifile_context *tmp_ctx = NULL; - - status = gp_inifile_init_context(mem_ctx, flags, unix_path, - GPTTMPL_UNIX_PATH, &tmp_ctx); - NT_STATUS_NOT_OK_RETURN(status); - - status = gpttmpl_parse_header(tmp_ctx, &version); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1,("gpttmpl_init_context: failed: %s\n", - nt_errstr(status))); - TALLOC_FREE(tmp_ctx); - return status; - } - - *ini_ctx = tmp_ctx; - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS gpttmpl_process(struct gp_inifile_context *ini_ctx, - struct registry_key *root_key, - uint32_t flags) -{ - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS security_process_group_policy(TALLOC_CTX *mem_ctx, - uint32_t flags, - struct registry_key *root_key, - const struct security_token *token, - const struct GROUP_POLICY_OBJECT *deleted_gpo_list, - const struct GROUP_POLICY_OBJECT *changed_gpo_list) -{ - NTSTATUS status = NT_STATUS_OK; - char *unix_path = NULL; - struct gp_inifile_context *ini_ctx = NULL; - const struct GROUP_POLICY_OBJECT *gpo; - char *gpo_cache_path = cache_path(GPO_CACHE_DIR); - if (gpo_cache_path == NULL) { - return NT_STATUS_NO_MEMORY; - } - - /* implementation of the policy callback function, see - * http://msdn.microsoft.com/en-us/library/aa373494%28v=vs.85%29.aspx - * for details - gd */ - - /* for now do not process the list of deleted group policies - - for (gpo = deleted_gpo_list; gpo; gpo = gpo->next) { - } - - */ - - for (gpo = changed_gpo_list; gpo; gpo = gpo->next) { - - gpext_debug_header(0, "security_process_group_policy", flags, - gpo, GP_EXT_GUID_SECURITY, NULL); - - /* this handler processes the gpttmpl files and merge output to the - * registry */ - - status = gpo_get_unix_path(mem_ctx, gpo_cache_path, - gpo, &unix_path); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = gpttmpl_init_context(mem_ctx, flags, unix_path, - &ini_ctx); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = gpttmpl_process(ini_ctx, root_key, flags); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - TALLOC_FREE(ini_ctx); - } - - out: - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("security_process_group_policy: %s\n", - nt_errstr(status))); - } - TALLOC_FREE(ini_ctx); - talloc_free(gpo_cache_path); - - return status; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS security_get_reg_config(TALLOC_CTX *mem_ctx, - struct gp_extension_reg_info **reg_info) -{ - NTSTATUS status; - struct gp_extension_reg_info *info = NULL; - - struct gp_extension_reg_table table[] = { - /* FIXME: how can we store the "(Default)" value ??? */ - /* { "", REG_SZ, "Security" }, */ - { "ProcessGroupPolicy", REG_SZ, "security_process_group_policy" }, - { "NoUserPolicy", REG_DWORD, "1" }, - { "ExtensionDebugLevel", REG_DWORD, "1" }, - { NULL, REG_NONE, NULL } - }; - - info = talloc_zero(mem_ctx, struct gp_extension_reg_info); - NT_STATUS_HAVE_NO_MEMORY(info); - - status = gpext_info_add_entry(mem_ctx, GP_EXT_NAME, - GP_EXT_GUID_SECURITY, - table, info); - NT_STATUS_NOT_OK_RETURN(status); - - *reg_info = info; - - return NT_STATUS_OK; -} - - -/**************************************************************** -****************************************************************/ - -static NTSTATUS security_initialize(TALLOC_CTX *mem_ctx) -{ - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static NTSTATUS security_shutdown(void) -{ - NTSTATUS status; - - status = gpext_unregister_gp_extension(GP_EXT_NAME); - if (NT_STATUS_IS_OK(status)) { - return status; - } - - TALLOC_FREE(ctx); - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static struct gp_extension_methods security_methods = { - .initialize = security_initialize, - .process_group_policy = security_process_group_policy, - .get_reg_config = security_get_reg_config, - .shutdown = security_shutdown -}; - -/**************************************************************** -****************************************************************/ - -NTSTATUS gpext_security_init(TALLOC_CTX *mem_ctx) -{ - NTSTATUS status; - - ctx = talloc_init("gpext_security_init"); - NT_STATUS_HAVE_NO_MEMORY(ctx); - - status = gpext_register_gp_extension(ctx, SMB_GPEXT_INTERFACE_VERSION, - GP_EXT_NAME, GP_EXT_GUID_SECURITY, - &security_methods); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(ctx); - } - - return status; -} diff --git a/source3/libgpo/gpext/wscript_build b/source3/libgpo/gpext/wscript_build deleted file mode 100644 index 365b4203f91..00000000000 --- a/source3/libgpo/gpext/wscript_build +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -bld.SAMBA3_MODULE('gpext_registry', - subsystem='gpext', - source='registry.c', - deps='NDR_PREG', - init_function='', - internal_module=bld.SAMBA3_IS_STATIC_MODULE('gpext_registry'), - enabled=bld.SAMBA3_IS_ENABLED_MODULE('gpext_registry')) - -bld.SAMBA3_MODULE('gpext_scripts', - subsystem='gpext', - source='scripts.c', - init_function='', - internal_module=bld.SAMBA3_IS_STATIC_MODULE('gpext_scripts'), - enabled=bld.SAMBA3_IS_ENABLED_MODULE('gpext_scripts')) - -bld.SAMBA3_MODULE('gpext_security', - subsystem='gpext', - source='security.c', - init_function='', - internal_module=bld.SAMBA3_IS_STATIC_MODULE('gpext_security'), - enabled=bld.SAMBA3_IS_ENABLED_MODULE('gpext_security')) diff --git a/source3/utils/net_ads_gpo.c b/source3/utils/net_ads_gpo.c index f2f65c8790e..b56b44252c7 100644 --- a/source3/utils/net_ads_gpo.c +++ b/source3/utils/net_ads_gpo.c @@ -369,92 +369,6 @@ static int net_ads_gpo_list(struct net_context *c, int argc, const char **argv) return 0; } -static int net_ads_gpo_apply(struct net_context *c, int argc, const char **argv) -{ - TALLOC_CTX *mem_ctx; - ADS_STRUCT *ads; - ADS_STATUS status; - const char *dn = NULL; - struct GROUP_POLICY_OBJECT *gpo_list; - uint32_t uac = 0; - uint32_t flags = 0; - struct security_token *token = NULL; - const char *filter = NULL; - - if (argc < 1 || c->display_usage) { - d_printf("Usage:\n" - "net ads gpo apply \n" - " Apply GPOs for machine/user\n" - " username\tUsername to apply GPOs for\n" - " machinename\tMachine to apply GPOs for\n"); - return -1; - } - - mem_ctx = talloc_init("net_ads_gpo_apply"); - if (mem_ctx == NULL) { - goto out; - } - - if (argc >= 2) { - filter = cse_gpo_name_to_guid_string(argv[1]); - } - - status = ads_startup(c, false, &ads); - /* filter = cse_gpo_name_to_guid_string("Security"); */ - - if (!ADS_ERR_OK(status)) { - d_printf("got: %s\n", ads_errstr(status)); - goto out; - } - - status = ads_find_samaccount(ads, mem_ctx, argv[0], &uac, &dn); - if (!ADS_ERR_OK(status)) { - d_printf("failed to find samaccount for %s: %s\n", - argv[0], ads_errstr(status)); - goto out; - } - - if (uac & UF_WORKSTATION_TRUST_ACCOUNT) { - flags |= GPO_LIST_FLAG_MACHINE; - } - - if (c->opt_verbose) { - flags |= GPO_INFO_FLAG_VERBOSE; - } - - d_printf("%s: '%s' has dn: '%s'\n", - (uac & UF_WORKSTATION_TRUST_ACCOUNT) ? "machine" : "user", - argv[0], dn); - - if (uac & UF_WORKSTATION_TRUST_ACCOUNT) { - status = gp_get_machine_token(ads, mem_ctx, dn, &token); - } else { - status = ads_get_sid_token(ads, mem_ctx, dn, &token); - } - - if (!ADS_ERR_OK(status)) { - goto out; - } - - status = ads_get_gpo_list(ads, mem_ctx, dn, flags, token, &gpo_list); - if (!ADS_ERR_OK(status)) { - goto out; - } - - status = ADS_ERROR_NT(gpo_process_gpo_list(mem_ctx, token, NULL, gpo_list, - filter, flags)); - if (!ADS_ERR_OK(status)) { - d_printf("failed to process gpo list: %s\n", - ads_errstr(status)); - goto out; - } - -out: - ads_destroy(&ads); - talloc_destroy(mem_ctx); - return 0; -} - static int net_ads_gpo_link_get(struct net_context *c, int argc, const char **argv) { ADS_STRUCT *ads; @@ -635,14 +549,6 @@ static int net_ads_gpo_get_gpo(struct net_context *c, int argc, const char **arg int net_ads_gpo(struct net_context *c, int argc, const char **argv) { struct functable func[] = { - { - "apply", - net_ads_gpo_apply, - NET_TRANSPORT_ADS, - "Apply GPO to container", - "net ads gpo apply\n" - " Apply GPO to container" - }, { "getgpo", net_ads_gpo_get_gpo, diff --git a/source3/wscript_build b/source3/wscript_build index 03d5724ee11..3dcf438b70a 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -1328,7 +1328,6 @@ bld.SAMBA3_BINARY('spotlight2sparql', ########################## INCLUDES ################################# bld.RECURSE('auth') -bld.RECURSE('libgpo/gpext') bld.RECURSE('librpc') bld.RECURSE('librpc/idl') bld.RECURSE('libsmb') From c4c91e081c24b72eab5f2891aa3e7d8aa01786ed Mon Sep 17 00:00:00 2001 From: David Mulder Date: Wed, 16 May 2018 08:04:20 -0600 Subject: [PATCH 16/30] gpupdate: Remove the unnecessary url parameter This option isn't necessary, since specifying the smb.conf ensures we pick up the correct samdb. Also, applying policy to a remote samdb doesn't make sense. Signed-off-by: David Mulder --- selftest/target/Samba4.pm | 2 +- source4/scripting/bin/gpupdate | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 9da08d86d5b..1095e5a09f9 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -641,7 +641,7 @@ sub provision_raw_step1($$) rndc command = true dns update command = $ctx->{samba_dnsupdate} spn update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_spnupdate -s $ctx->{smb_conf} - gpo update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/gpupdate -s $ctx->{smb_conf} -H $ctx->{privatedir}/sam.ldb --target=Computer + gpo update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/gpupdate -s $ctx->{smb_conf} --target=Computer dreplsrv:periodic_startup_interval = 0 dsdb:schema update allowed = yes diff --git a/source4/scripting/bin/gpupdate b/source4/scripting/bin/gpupdate index ecbf8e02069..e5fbb47139a 100755 --- a/source4/scripting/bin/gpupdate +++ b/source4/scripting/bin/gpupdate @@ -41,7 +41,6 @@ if __name__ == "__main__": parser.add_option_group(sambaopts) parser.add_option_group(options.VersionOptions(parser)) credopts = options.CredentialsOptions(parser) - parser.add_option('-H', '--url', dest='url', help='URL for the samdb') parser.add_option('-X', '--unapply', help='Unapply Group Policy', action='store_true') parser.add_option('--target', default='Computer', help='{Computer | User}', @@ -53,10 +52,6 @@ if __name__ == "__main__": # Set the loadparm context lp = sambaopts.get_loadparm() - if not opts.url: - url = lp.samdb_url() - else: - url = opts.url creds = credopts.get_credentials(lp, fallback_machine=True) From fc214f287f050e70cbe778e507b115307b195486 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Wed, 16 May 2018 11:08:13 -0600 Subject: [PATCH 17/30] gpo: Remove unused methods from gp_sec_ext Signed-off-by: David Mulder --- python/samba/gp_sec_ext.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index 58f6fb66ecd..2a118a1d909 100644 --- a/python/samba/gp_sec_ext.py +++ b/python/samba/gp_sec_ext.py @@ -133,12 +133,6 @@ def list(self, rootpath): return os.path.join(rootpath, "MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf") - def listmachpol(self, rootpath): - return os.path.join(rootpath, "Machine/Registry.pol") - - def listuserpol(self, rootpath): - return os.path.join(rootpath, "User/Registry.pol") - def apply_map(self): if SamDB: try: From 39709ea0e76fd37d1736163cd79f00e85299a119 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Wed, 16 May 2018 10:37:09 -0600 Subject: [PATCH 18/30] gpo: Offline policy application via cache Read policy files from the cache, rather than the sysvol (unless on a dc, then read from the local sysvol). This enables offline policy apply. Signed-off-by: David Mulder --- python/samba/gpclass.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 4e5a4ef929c..2dc60775032 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -308,8 +308,13 @@ def apply_map(self): def read(self, policy): pass - def parse(self, afile, conn): + def parse(self, afile): # Fixing the bug where only some Linux Boxes capitalize MACHINE + sysvol = self.lp.get("path", "sysvol") + if sysvol: + local_path = sysvol + else: + local_path = self.lp.cache_path('gpo_cache') try: blist = afile.split('/') index = None @@ -323,18 +328,18 @@ def parse(self, afile, conn): blist[idx].capitalize(), blist[idx].lower() ]: - bfile = '/'.join(blist[:idx]) + '/' + case + '/' + \ - '/'.join(blist[idx+1:]) - try: - return self.read(conn.loadfile(bfile.replace('/', '\\'))) - except NTSTATUSError: + bfile = ('/'.join(blist[:idx]) + '/' + case + '/' + \ + '/'.join(blist[idx+1:])).replace('\\', '/') + data_file = os.path.join(local_path, bfile) + if os.path.exists(data_file): + return self.read(open(data_file, 'r').read()) + else: continue except ValueError: - try: - return self.read(conn.loadfile(afile.replace('/', '\\'))) - except Exception as e: - self.logger.error(str(e)) - return None + data_file = os.path.join(local_path, afile).replace('\\', '/') + if os.path.exists(data_file): + return self.read(open(data_file, 'r').read()) + return None @abstractmethod def __str__(self): @@ -440,11 +445,6 @@ def gpo_version(lp, path, sysvol): def apply_gp(lp, creds, logger, store, gp_extensions): gp_db = store.get_gplog(creds.get_username()) dc_hostname = get_dc_hostname(creds, lp) - try: - conn = smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds) - except: - logger.error('Error connecting to \'%s\' using SMB' % dc_hostname) - raise ads, gpos = get_gpo_list(dc_hostname, creds, lp) sysvol = lp.get("path", "sysvol") if not sysvol: @@ -465,7 +465,7 @@ def apply_gp(lp, creds, logger, store, gp_extensions): store.start() for ext in gp_extensions: try: - ext.parse(ext.list(path), conn) + ext.parse(ext.list(path)) except Exception as e: logger.error('Failed to parse gpo %s for extension %s' % \ (guid, str(ext))) From 3e5413f8f1bbe73ac4ae5cc56cfc6366123ffdd3 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Thu, 17 May 2018 15:56:15 -0600 Subject: [PATCH 19/30] gpo: Create a function for returning applied settings This returns a list of guids for gpos applied plus settings applied and their previous values. Signed-off-by: David Mulder --- python/samba/gpclass.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 2dc60775032..fe6bc8b4ff3 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -229,6 +229,34 @@ def list(self, gp_extensions): ret.append((attr.attrib['name'], attr.text, func)) return ret + def get_applied(self): + ''' Return a list of applied ext guids + return - List of tuples containing the guid of a gpo, then + a dictionary of policies and their values prior + policy application. These are sorted so that the + most recently applied settings are removed first. + ''' + guids = [] + user_obj = self.gpdb.find('user[@name="%s"]' % self.user) + if user_obj is not None: + apply_log = user_obj.find('applylog') + if apply_log is None: + return guids + for i in reversed(range(0, len(apply_log))): + guid_obj = apply_log.find('guid[@count="%d"]' % i) + guid = guid_obj.attrib['value'] + guid_settings = user_obj.find('guid[@value="%s"]' % guid) + exts = guid_settings.findall('gp_ext') + settings = {} + for ext in exts: + attr_dict = {} + attrs = ext.findall('attribute') + for attr in attrs: + attr_dict[attr.attrib['name']] = attr.text + settings[ext.attrib['name']] = attr_dict + guids.append((guid, settings)) + return guids + def delete(self, gp_ext_name, attribute): ''' Remove an attribute from the gp_log param gp_ext_name - name of extension from which to remove the From 34b3a92d55325a0509a6da3574fa1c6d7538483a Mon Sep 17 00:00:00 2001 From: David Mulder Date: Wed, 9 May 2018 13:16:38 -0600 Subject: [PATCH 20/30] gpo: Implement process_group_policy() gp_ext func MS spec describes the policy callback as a function called ProcessGroupPolicy which accepts a pDeletedGPOList and a pChangedGPOList param. The Group Policy Client Side Extension then iterates over the deleted, then the changed gpo lists and applies/unapplies policy. We should do this also. Signed-off-by: David Mulder --- python/samba/gp_sec_ext.py | 35 +++++++++++++++++++++-------------- python/samba/gpclass.py | 45 +++++++++++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index 2a118a1d909..6edfbbf5943 100644 --- a/python/samba/gp_sec_ext.py +++ b/python/samba/gp_sec_ext.py @@ -129,21 +129,7 @@ class gp_sec_ext(gp_inf_ext): def __str__(self): return "Security GPO extension" - def list(self, rootpath): - return os.path.join(rootpath, - "MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf") - def apply_map(self): - if SamDB: - try: - self.ldb = SamDB(self.lp.samdb_url(), - session_info=system_session(), - credentials=self.creds, - lp=self.lp) - except: - return {} - else: - return {} return {"System Access": {"MinimumPasswordAge": ("minPwdAge", inf_to_ldb), "MaximumPasswordAge": ("maxPwdAge", @@ -168,3 +154,24 @@ def apply_map(self): } } + def process_group_policy(self, deleted_gpo_list, changed_gpo_list): + if SamDB: + try: + ldb = SamDB(self.lp.samdb_url(), + session_info=system_session(), + credentials=self.creds, + lp=self.lp) + except: + return + else: + return + inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf' + for gpo in deleted_gpo_list: + pass + + for gpo in changed_gpo_list: + if gpo.file_sys_path: + self.gp_db.set_guid(gpo.name) + path = gpo.file_sys_path.split('\\sysvol\\')[-1] + self.parse(os.path.join(path, inf_file)) + diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index fe6bc8b4ff3..57f7f61b4e4 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -325,7 +325,7 @@ def __init__(self, logger, lp, creds, store): self.gp_db = store.get_gplog(creds.get_username()) @abstractmethod - def list(self, rootpath): + def process_group_policy(self, deleted_gpo_list, changed_gpo_list): pass @abstractmethod @@ -400,7 +400,7 @@ def __str__(self): class gp_inf_ext(gp_ext): @abstractmethod - def list(self, rootpath): + def process_group_policy(self, deleted_gpo_list, changed_gpo_list): pass @abstractmethod @@ -478,30 +478,35 @@ def apply_gp(lp, creds, logger, store, gp_extensions): if not sysvol: gpo.check_refresh_gpo_list(ads, gpos) + changed_gpos = [] for gpo_obj in gpos: - guid = gpo_obj.name - if guid == 'Local Policy': + if not gpo_obj.file_sys_path: continue - path = os.path.join(lp.get('realm').lower(), 'Policies', guid) + guid = gpo_obj.name + path = gpo_obj.file_sys_path.split('\\sysvol\\')[-1] + path = path.replace('\\', '/') version = gpo_version(lp, path, sysvol) if version != store.get_int(guid): logger.info('GPO %s has changed' % guid) - gp_db.state(GPOSTATE.APPLY) - else: - gp_db.state(GPOSTATE.ENFORCE) - gp_db.set_guid(guid) - store.start() - for ext in gp_extensions: - try: - ext.parse(ext.list(path)) - except Exception as e: - logger.error('Failed to parse gpo %s for extension %s' % \ - (guid, str(ext))) - logger.error('Message was: ' + str(e)) - store.cancel() - continue + changed_gpos.append(gpo_obj) + + store.start() + for ext in gp_extensions: + try: + ext.process_group_policy([], changed_gpos) + except Exception as e: + logger.error('Failed to apply extension %s' % str(ext)) + logger.error('Message was: ' + str(e)) + continue + for gpo_obj in gpos: + if not gpo_obj.file_sys_path: + continue + guid = gpo_obj.name + path = gpo_obj.file_sys_path.split('\\sysvol\\')[-1] + path = path.replace('\\', '/') + version = gpo_version(lp, path, sysvol) store.store(guid, '%i' % version) - store.commit() + store.commit() def unapply_log(gp_db): while True: From 6096ef4f79fc0929ebad281855a0226d2f9abc21 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Thu, 17 May 2018 16:23:51 -0600 Subject: [PATCH 21/30] gpo: Move policy application to the gp_ext Policy specific setting application should be handled by the group policy extension, not the read/parse handler. Signed-off-by: David Mulder --- python/samba/gp_sec_ext.py | 41 ++++++++++++++++++++++++++--------------- python/samba/gpclass.py | 34 +--------------------------------- 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index 6edfbbf5943..51983347049 100644 --- a/python/samba/gp_sec_ext.py +++ b/python/samba/gp_sec_ext.py @@ -129,8 +129,18 @@ class gp_sec_ext(gp_inf_ext): def __str__(self): return "Security GPO extension" - def apply_map(self): - return {"System Access": {"MinimumPasswordAge": ("minPwdAge", + def process_group_policy(self, deleted_gpo_list, changed_gpo_list): + if SamDB: + try: + ldb = SamDB(self.lp.samdb_url(), + session_info=system_session(), + credentials=self.creds, + lp=self.lp) + except: + return + else: + return + apmp = {"System Access": {"MinimumPasswordAge": ("minPwdAge", inf_to_ldb), "MaximumPasswordAge": ("maxPwdAge", inf_to_ldb), @@ -153,18 +163,6 @@ def apply_map(self): ), } } - - def process_group_policy(self, deleted_gpo_list, changed_gpo_list): - if SamDB: - try: - ldb = SamDB(self.lp.samdb_url(), - session_info=system_session(), - credentials=self.creds, - lp=self.lp) - except: - return - else: - return inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf' for gpo in deleted_gpo_list: pass @@ -173,5 +171,18 @@ def process_group_policy(self, deleted_gpo_list, changed_gpo_list): if gpo.file_sys_path: self.gp_db.set_guid(gpo.name) path = gpo.file_sys_path.split('\\sysvol\\')[-1] - self.parse(os.path.join(path, inf_file)) + inf_conf = self.parse(os.path.join(path, inf_file)) + if not inf_conf: + continue + for section in inf_conf.sections(): + current_section = apmp.get(section) + if not current_section: + continue + for key, value in inf_conf.items(section): + if current_section.get(key): + (att, setter) = current_section.get(key) + value = value.encode('ascii', 'ignore') + setter(self.logger, self.gp_db, self.lp, att, + value, ldb).update_samba() + self.gp_db.commit() diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 57f7f61b4e4..20f95d45546 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -328,10 +328,6 @@ def __init__(self, logger, lp, creds, store): def process_group_policy(self, deleted_gpo_list, changed_gpo_list): pass - @abstractmethod - def apply_map(self): - pass - @abstractmethod def read(self, policy): pass @@ -403,42 +399,14 @@ class gp_inf_ext(gp_ext): def process_group_policy(self, deleted_gpo_list, changed_gpo_list): pass - @abstractmethod - def apply_map(self): - pass - def read(self, policy): - ret = False - inftable = self.apply_map() - - current_section = None - - # So here we would declare a boolean, - # that would get changed to TRUE. - # - # If at any point in time a GPO was applied, - # then we return that boolean at the end. - inf_conf = ConfigParser() inf_conf.optionxform=str try: inf_conf.readfp(StringIO(policy)) except: inf_conf.readfp(StringIO(policy.decode('utf-16'))) - - for section in inf_conf.sections(): - current_section = inftable.get(section) - if not current_section: - continue - for key, value in inf_conf.items(section): - if current_section.get(key): - (att, setter) = current_section.get(key) - value = value.encode('ascii', 'ignore') - ret = True - setter(self.logger, self.ldb, self.gp_db, self.lp, att, - value).update_samba() - self.gp_db.commit() - return ret + return inf_conf @abstractmethod def __str__(self): From 4c654e405be875b55bf0491586e80dac7fac2a6b Mon Sep 17 00:00:00 2001 From: David Mulder Date: Thu, 17 May 2018 16:48:47 -0600 Subject: [PATCH 22/30] gpo: Use the new process_group_policy() for unapply Signed-off-by: David Mulder --- python/samba/gp_sec_ext.py | 17 ++++++++++++++++- python/samba/gpclass.py | 30 ++++++++++++++---------------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index 51983347049..9ee1398a8f9 100644 --- a/python/samba/gp_sec_ext.py +++ b/python/samba/gp_sec_ext.py @@ -165,7 +165,22 @@ def process_group_policy(self, deleted_gpo_list, changed_gpo_list): } inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf' for gpo in deleted_gpo_list: - pass + self.gp_db.set_guid(gpo[0]) + for section in gpo[1].keys(): + current_section = apmp.get(section) + if not current_section: + continue + for key, value in gpo[1][section].items(): + setter = None + for _, tup in current_section.items(): + if tup[0] == key: + setter = tup[1] + if setter: + value = value.encode('ascii', 'ignore') + setter(self.logger, self.gp_db, self.lp, key, + value, ldb).delete() + self.gp_db.delete(section, key) + self.gp_db.commit() for gpo in changed_gpo_list: if gpo.file_sys_path: diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 20f95d45546..1305b491146 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -390,6 +390,10 @@ def update_samba(self): def mapper(self): pass + def delete(self): + upd_sam, _ = self.mapper().get(self.attribute) + upd_sam(self.val) + @abstractmethod def __str__(self): pass @@ -476,23 +480,17 @@ def apply_gp(lp, creds, logger, store, gp_extensions): store.store(guid, '%i' % version) store.commit() -def unapply_log(gp_db): - while True: - item = gp_db.apply_log_pop() - if item: - yield item - else: - break - def unapply_gp(lp, creds, logger, store, gp_extensions): gp_db = store.get_gplog(creds.get_username()) gp_db.state(GPOSTATE.UNAPPLY) - for gpo_guid in unapply_log(gp_db): - gp_db.set_guid(gpo_guid) - unapply_attributes = gp_db.list(gp_extensions) - for attr in unapply_attributes: - attr_obj = attr[-1](logger, gp_db, lp, attr[0], attr[1]) - attr_obj.mapper()[attr[0]][0](attr[1]) # Set the old value - gp_db.delete(str(attr_obj), attr[0]) - gp_db.commit() + del_gpos = gp_db.get_applied() # Treat all applied gpos as deleted + store.start() + for ext in gp_extensions: + try: + ext.process_group_policy(del_gpos, []) + except Exception as e: + logger.error('Failed to unapply extension %s' % str(ext)) + logger.error('Message was: ' + str(e)) + continue + store.commit() From 2a56fc805c7e8bebbcca595cedec2844bbaa9cdc Mon Sep 17 00:00:00 2001 From: David Mulder Date: Tue, 15 May 2018 14:00:07 -0600 Subject: [PATCH 23/30] gpo: Calculate deleted gpos and unapply them Signed-off-by: David Mulder --- python/samba/gpclass.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 1305b491146..4fff5e72ade 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -431,6 +431,15 @@ def get_gpo_list(dc_hostname, creds, lp): gpos = ads.get_gpo_list(creds.get_username()) return (ads, gpos) +def get_deleted_gpos_list(gp_db, gpos): + ret = [] + applied_gpos = gp_db.get_applied() + current_guids = [p.name for p in gpos] + for g in applied_gpos: + if g[0] not in current_guids: + ret.append(g) + return ret + def gpo_version(lp, path, sysvol): # gpo.gpo_get_sysvol_gpt_version() reads the GPT.INI from a local file. # If we don't have a sysvol path locally (if we're not a kdc), then @@ -446,6 +455,7 @@ def apply_gp(lp, creds, logger, store, gp_extensions): gp_db = store.get_gplog(creds.get_username()) dc_hostname = get_dc_hostname(creds, lp) ads, gpos = get_gpo_list(dc_hostname, creds, lp) + del_gpos = get_deleted_gpos_list(gp_db, gpos) sysvol = lp.get("path", "sysvol") if not sysvol: gpo.check_refresh_gpo_list(ads, gpos) @@ -465,7 +475,7 @@ def apply_gp(lp, creds, logger, store, gp_extensions): store.start() for ext in gp_extensions: try: - ext.process_group_policy([], changed_gpos) + ext.process_group_policy(del_gpos, changed_gpos) except Exception as e: logger.error('Failed to apply extension %s' % str(ext)) logger.error('Message was: ' + str(e)) From d98300b4a367ff6f6aed9195a61cbd38bbd1f764 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Thu, 17 May 2018 16:49:39 -0600 Subject: [PATCH 24/30] gpo: Remove unused apply_log_pop() and list() funcs Signed-off-by: David Mulder --- python/samba/gpclass.py | 51 ------------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 4fff5e72ade..6855afbadee 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -139,24 +139,6 @@ def set_guid(self, guid): item.attrib['count'] = '%d' % (len(apply_log)-1) item.attrib['value'] = guid - def apply_log_pop(self): - ''' Pop a GPO guid from the applylog - return - last applied GPO guid - - Removes the GPO guid last added to the list, which is the most recently - applied GPO. - ''' - user_obj = self.gpdb.find('user[@name="%s"]' % self.user) - apply_log = user_obj.find('applylog') - if apply_log is not None: - ret = apply_log.find('guid[@count="%d"]' % (len(apply_log)-1)) - if ret is not None: - apply_log.remove(ret) - return ret.attrib['value'] - if len(apply_log) == 0 and apply_log in user_obj: - user_obj.remove(apply_log) - return None - def store(self, gp_ext_name, attribute, old_val): ''' Store an attribute in the gp_log param gp_ext_name - Name of the extension applying policy @@ -196,39 +178,6 @@ def retrieve(self, gp_ext_name, attribute): return attr.text return None - def list(self, gp_extensions): - ''' Return a list of attributes, their previous values, and functions - to set them - param gp_extensions - list of extension objects, for retrieving attr to - func mappings - return - list of (attr, value, apply_func) tuples for - unapplying policy - ''' - user_obj = self.gpdb.find('user[@name="%s"]' % self.user) - guid_obj = user_obj.find('guid[@value="%s"]' % self.guid) - assert guid_obj is not None, "gpo guid was not set" - ret = [] - data_maps = {} - for gp_ext in gp_extensions: - data_maps.update(gp_ext.apply_map()) - exts = guid_obj.findall('gp_ext') - if exts is not None: - for ext in exts: - attrs = ext.findall('attribute') - for attr in attrs: - func = None - if attr.attrib['name'] in data_maps[ext.attrib['name']]: - func = data_maps[ext.attrib['name']]\ - [attr.attrib['name']][-1] - else: - for dmap in data_maps[ext.attrib['name']].keys(): - if data_maps[ext.attrib['name']][dmap][0] == \ - attr.attrib['name']: - func = data_maps[ext.attrib['name']][dmap][-1] - break - ret.append((attr.attrib['name'], attr.text, func)) - return ret - def get_applied(self): ''' Return a list of applied ext guids return - List of tuples containing the guid of a gpo, then From e81fd04eefc54171492c230db9bd56b42638b404 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Wed, 16 May 2018 09:54:38 -0600 Subject: [PATCH 25/30] gpupdate: Add the --force option This option forces the reapplication of policy, and works the same as MS 'gpupdate /force' Signed-off-by: David Mulder --- python/samba/gpclass.py | 29 +++++++++++++++++------------ source4/scripting/bin/gpupdate | 4 +++- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 6855afbadee..6815300506c 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -400,7 +400,7 @@ def gpo_version(lp, path, sysvol): local_path = os.path.join(gpt_path, 'GPT.INI') return int(gpo.gpo_get_sysvol_gpt_version(os.path.dirname(local_path))[1]) -def apply_gp(lp, creds, logger, store, gp_extensions): +def apply_gp(lp, creds, logger, store, gp_extensions, force=False): gp_db = store.get_gplog(creds.get_username()) dc_hostname = get_dc_hostname(creds, lp) ads, gpos = get_gpo_list(dc_hostname, creds, lp) @@ -409,17 +409,22 @@ def apply_gp(lp, creds, logger, store, gp_extensions): if not sysvol: gpo.check_refresh_gpo_list(ads, gpos) - changed_gpos = [] - for gpo_obj in gpos: - if not gpo_obj.file_sys_path: - continue - guid = gpo_obj.name - path = gpo_obj.file_sys_path.split('\\sysvol\\')[-1] - path = path.replace('\\', '/') - version = gpo_version(lp, path, sysvol) - if version != store.get_int(guid): - logger.info('GPO %s has changed' % guid) - changed_gpos.append(gpo_obj) + if force: + changed_gpos = gpos + gp_db.state(GPOSTATE.ENFORCE) + else: + changed_gpos = [] + for gpo_obj in gpos: + if not gpo_obj.file_sys_path: + continue + guid = gpo_obj.name + path = gpo_obj.file_sys_path.split('\\sysvol\\')[-1] + path = path.replace('\\', '/') + version = gpo_version(lp, path, sysvol) + if version != store.get_int(guid): + logger.info('GPO %s has changed' % guid) + changed_gpos.append(gpo_obj) + gp_db.state(GPOSTATE.APPLY) store.start() for ext in gp_extensions: diff --git a/source4/scripting/bin/gpupdate b/source4/scripting/bin/gpupdate index e5fbb47139a..3cf0a31ee8d 100755 --- a/source4/scripting/bin/gpupdate +++ b/source4/scripting/bin/gpupdate @@ -45,6 +45,8 @@ if __name__ == "__main__": action='store_true') parser.add_option('--target', default='Computer', help='{Computer | User}', choices=['Computer', 'User']) + parser.add_option('--force', help='Reapplies all policy settings', + action='store_true') parser.add_option_group(credopts) # Set the options and the arguments @@ -83,7 +85,7 @@ if __name__ == "__main__": gp_extensions.append(ext(logger, lp, creds, store)) if not opts.unapply: - apply_gp(lp, creds, logger, store, gp_extensions) + apply_gp(lp, creds, logger, store, gp_extensions, opts.force) else: unapply_gp(lp, creds, logger, store, gp_extensions) From ff22b8d17fedfbdb54b7095eabcc3ec69c6fe3e6 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 11 May 2018 15:47:35 -0600 Subject: [PATCH 26/30] gpo: Don't fail reading utf-16-le GPT.INI is a ini file stored on the sysvol, but is written with UTF16LE, using a byte order mark at the beginning of the text. Detect the byte order mark and read UTF16LE if found. Signed-off-by: David Mulder --- ctdb/common/conf.c | 1 + lib/util/params.c | 39 ++++++++++++++++++++++++++--- lib/util/tini.c | 68 +++++++++++++++++++++++++++++++++++++-------------- lib/util/tini.h | 6 +++++ lib/util/tiniparser.c | 1 + 5 files changed, 93 insertions(+), 22 deletions(-) diff --git a/ctdb/common/conf.c b/ctdb/common/conf.c index dccf6613f48..c87063a1f0e 100644 --- a/ctdb/common/conf.c +++ b/ctdb/common/conf.c @@ -936,6 +936,7 @@ static int conf_load_internal(struct conf_context *conf) false, conf_load_section, conf_load_option, + ASCII, &state); fclose(fp); if (!ok) { diff --git a/lib/util/params.c b/lib/util/params.c index c5c252613d3..a049b4dfe7b 100644 --- a/lib/util/params.c +++ b/lib/util/params.c @@ -81,6 +81,34 @@ #include "replace.h" #include "lib/util/samba_util.h" #include "tini.h" +#include + +static FILE* open_encoding(const char *filename, enum tini_encoding *encoding) +{ + FILE *f = NULL, *o; + int c[2] = { 0 }; + + o = fopen(filename, "r"); + if (o == NULL) { + return NULL; + } + c[0] = fgetc(o); + c[1] = fgetc(o); + fclose(o); + + if (c[0] == 0xFF && c[1] == 0xFE) { + f = fopen(filename, "r,ccs=UTF16LE"); + if (f != NULL) { + fgetwc(f); + } + *encoding = UTF16LE; + } else { + f = fopen(filename, "r"); + *encoding = ASCII; + } + + return f; +} bool pm_process(const char *filename, bool (*sfunc)(const char *section, void *private_data), @@ -90,13 +118,14 @@ bool pm_process(const char *filename, { FILE *f; bool ret; + enum tini_encoding encoding; - f = fopen(filename, "r"); + f = open_encoding(filename, &encoding); if (f == NULL) { return false; } - ret = tini_parse(f, false, sfunc, pfunc, private_data); + ret = tini_parse(f, false, sfunc, pfunc, encoding, private_data); fclose(f); @@ -113,13 +142,15 @@ bool pm_process_with_flags(const char *filename, { FILE *f; bool ret; + enum tini_encoding encoding; - f = fopen(filename, "r"); + f = open_encoding(filename, &encoding); if (f == NULL) { return false; } - ret = tini_parse(f, allow_empty_values, sfunc, pfunc, private_data); + ret = tini_parse(f, allow_empty_values, sfunc, pfunc, encoding, + private_data); fclose(f); diff --git a/lib/util/tini.c b/lib/util/tini.c index 36d7a4522ce..4feac497fa0 100644 --- a/lib/util/tini.c +++ b/lib/util/tini.c @@ -42,6 +42,7 @@ #include #include #include "tini.h" +#include static bool c_isspace(char c) { @@ -52,31 +53,51 @@ static bool c_isspace(char c) return isspace(uc); } -static int next_content(FILE *f) +static wint_t next_content(FILE *f, enum tini_encoding encoding) { - int c; + wint_t c; - for (c = fgetc(f); c != EOF; c = fgetc(f)) { - if (!c_isspace(c)) { - break; + if (encoding == UTF16LE) { + for (c = fgetwc(f); c != EOF; c = fgetwc(f)) { + if (!c_isspace(c)) { + break; + } + if (c == '\n') { + break; + } } - if (c == '\n') { - break; + } else { + for (c = fgetc(f); c != EOF; c = fgetc(f)) { + if (!c_isspace(c)) { + break; + } + if (c == '\n') { + break; + } } } return c; } -static int next_end_of_line(FILE *f) +static wint_t next_end_of_line(FILE *f, enum tini_encoding encoding) { - int c; + wint_t c; - for (c = fgetc(f); c != EOF; c = fgetc(f)) { - if (c == '\n') { - break; + if (encoding == UTF16LE) { + for (c = fgetwc(f); c != EOF; c = fgetwc(f)) { + if (c == '\n') { + break; + } + } + } else { + for (c = fgetc(f); c != EOF; c = fgetc(f)) { + if (c == '\n') { + break; + } } } + return c; } @@ -96,6 +117,15 @@ static bool make_space(char **buf, size_t *buflen, size_t position) return true; } +static wint_t fgetc_func(FILE *stream, enum tini_encoding encoding) +{ + if (encoding == UTF16LE) { + return fgetwc(stream); + } else { + return fgetc(stream); + } +} + /* * Get a conf line into *pbuf (which must be a malloc'ed buffer already). * @@ -106,9 +136,10 @@ static bool make_space(char **buf, size_t *buflen, size_t position) * Zaps multiple spaces into one */ -static int get_line(FILE *f, char **pbuf, size_t *pbuflen) +static int get_line(FILE *f, char **pbuf, size_t *pbuflen, + enum tini_encoding encoding) { - int c; + wint_t c; char *buf; size_t buflen, pos; @@ -118,7 +149,7 @@ static int get_line(FILE *f, char **pbuf, size_t *pbuflen) next_line: - c = next_content(f); + c = next_content(f, encoding); if (c == EOF) { return ENOENT; } @@ -127,7 +158,7 @@ static int get_line(FILE *f, char **pbuf, size_t *pbuflen) /* * Line starting with a comment, skip */ - c = next_end_of_line(f); + c = next_end_of_line(f, encoding); if (c == EOF) { return ENOENT; } @@ -141,7 +172,7 @@ static int get_line(FILE *f, char **pbuf, size_t *pbuflen) goto next_line; } - for ( ; c != EOF ; c = fgetc(f)) { + for ( ; c != EOF ; c = fgetc_func(f, encoding)) { if (c == '\n') { @@ -269,6 +300,7 @@ bool tini_parse(FILE *f, bool (*sfunc)(const char *section, void *private_data), bool (*pfunc)(const char *name, const char *value, void *private_data), + enum tini_encoding encoding, void *private_data) { char *buf; @@ -285,7 +317,7 @@ bool tini_parse(FILE *f, int ret; bool ok; - ret = get_line(f, &buf, &buflen); + ret = get_line(f, &buf, &buflen, encoding); if (ret == ENOENT) { /* No lines anymore */ diff --git a/lib/util/tini.h b/lib/util/tini.h index 36fc08082a1..f207b1c716f 100644 --- a/lib/util/tini.h +++ b/lib/util/tini.h @@ -37,9 +37,15 @@ #include +enum tini_encoding { + UTF16LE, + ASCII, +}; + bool tini_parse(FILE *f, bool allow_empty_value, bool (*sfunc)(const char *section, void *private_data), bool (*pfunc)(const char *name, const char *value, void *private_data), + enum tini_encoding encoding, void *private_data); diff --git a/lib/util/tiniparser.c b/lib/util/tiniparser.c index c3ab4e7f806..cab482e81d0 100644 --- a/lib/util/tiniparser.c +++ b/lib/util/tiniparser.c @@ -342,6 +342,7 @@ struct tiniparser_dictionary *tiniparser_load(const char *filename) false, section_parser, value_parser, + ASCII, d); fclose(fp); if (ret == false) { From 56de170ed8c3a0448ec8f52084d5bd5571aeb747 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 14 May 2018 13:56:58 -0600 Subject: [PATCH 27/30] gpo: Register gp_sec_ext for gpo.apply tests Signed-off-by: David Mulder --- source4/torture/gpo/apply.c | 8 ++++++++ source4/torture/gpo/wscript_build | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/source4/torture/gpo/apply.c b/source4/torture/gpo/apply.c index 248ddbbc139..0a0441e0ccf 100644 --- a/source4/torture/gpo/apply.c +++ b/source4/torture/gpo/apply.c @@ -27,6 +27,7 @@ #include "lib/ldb/include/ldb.h" #include "torture/gpo/proto.h" #include +#include "libgpo/register.h" struct torture_suite *gpo_apply_suite(TALLOC_CTX *ctx) { @@ -77,6 +78,9 @@ PasswordComplexity = %d\n\ " #define GPTINI "addom.samba.example.com/Policies/"\ "{31B2F340-016D-11D2-945F-00C04FB984F9}/GPT.INI" +#define GP_SEC_GUID "{827D319E-6EAC-11D2-A4EA-00C04F79F83A}" +#define GP_SEC_GP_EXT "./bin/python/samba/gp_sec_ext.py" +#define GP_SEC_CLS "gp_sec_ext" bool torture_gpo_system_access_policies(struct torture_context *tctx) { @@ -118,6 +122,10 @@ bool torture_gpo_system_access_policies(struct torture_context *tctx) torture_assert(tctx, gpo_update_cmd && gpo_update_cmd[0], "Failed to fetch the gpo update command"); + /* Enable the gp_ext */ + register_gp_extension(GP_SEC_GUID, GP_SEC_CLS, GP_SEC_GP_EXT, + tctx->lp_ctx->szConfigFile, 1, 0); + /* Open and read the samba db and store the initial password settings */ samdb = samdb_connect(ctx, tctx->ev, diff --git a/source4/torture/gpo/wscript_build b/source4/torture/gpo/wscript_build index d7b131f8095..4456fb6186c 100644 --- a/source4/torture/gpo/wscript_build +++ b/source4/torture/gpo/wscript_build @@ -6,7 +6,7 @@ bld.SAMBA_MODULE('TORTURE_GPO', apply.c ''', subsystem='smbtorture', - deps='torture samba-util-core ldb', + deps='torture samba-util-core ldb gpext', internal_module=True, autoproto='proto.h', init_function='torture_gpo_init' From 2f7d0de512232f9c7d80d89ab42e055e61d5894d Mon Sep 17 00:00:00 2001 From: David Mulder Date: Tue, 15 May 2018 08:37:08 -0600 Subject: [PATCH 28/30] gpo: Don't duplicate guids in the apply log Signed-off-by: David Mulder --- python/samba/gpclass.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 6815300506c..951138cc8e7 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -135,9 +135,11 @@ def set_guid(self, guid): apply_log = user_obj.find('applylog') if apply_log is None: apply_log = etree.SubElement(user_obj, 'applylog') - item = etree.SubElement(apply_log, 'guid') - item.attrib['count'] = '%d' % (len(apply_log)-1) - item.attrib['value'] = guid + prev = apply_log.find('guid[@value="%s"]' % guid) + if prev is None: + item = etree.SubElement(apply_log, 'guid') + item.attrib['count'] = '%d' % (len(apply_log)-1) + item.attrib['value'] = guid def store(self, gp_ext_name, attribute, old_val): ''' Store an attribute in the gp_log From 30ae994e40f7ba529851b80a9de0bbad538cf308 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Tue, 15 May 2018 12:21:50 -0600 Subject: [PATCH 29/30] gpo: Switch to using lxml.etree, where possible Signed-off-by: David Mulder --- python/samba/gpclass.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index 951138cc8e7..b0426433377 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -23,7 +23,10 @@ from ConfigParser import ConfigParser from StringIO import StringIO from abc import ABCMeta, abstractmethod -import xml.etree.ElementTree as etree +try: + import lxml.etree as etree +except ImportError: + import xml.etree.ElementTree as etree import re from samba.net import Net from samba.dcerpc import nbt @@ -227,7 +230,7 @@ def delete(self, gp_ext_name, attribute): def commit(self): ''' Write gp_log changes to disk ''' - self.gpostore.store(self.username, etree.tostring(self.gpdb, 'utf-8')) + self.gpostore.store(self.username, etree.tostring(self.gpdb)) class GPOStorage: def __init__(self, log_file): From 9146dfe709858a913c0e8ed38e85a1123a10717f Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 21 May 2018 13:26:06 -0600 Subject: [PATCH 30/30] gpo: gp_sec_ext cse register Signed-off-by: David Mulder --- python/samba/gp_sec_ext.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index 9ee1398a8f9..7cef02f37b7 100644 --- a/python/samba/gp_sec_ext.py +++ b/python/samba/gp_sec_ext.py @@ -201,3 +201,21 @@ def process_group_policy(self, deleted_gpo_list, changed_gpo_list): value, ldb).update_samba() self.gp_db.commit() +if __name__ == "__main__": + from samba import gpo + import optparse + from samba import getopt as options + guid = '{827D319E-6EAC-11D2-A4EA-00C04F79F83A}' + name = 'gp_sec_ext' + path = os.path.abspath(__file__) + + parser = optparse.OptionParser('%s [options]' % name) + sambaopts = options.SambaOptions(parser) + parser.add_option_group(sambaopts) + + (opts, args) = parser.parse_args() + lp = sambaopts.get_loadparm() + + gpo.register_gp_extension(guid, name, path, smb_conf=lp.configfile, + machine=True, user=False) +