From 4d1517c57fee366acc349fa164921231f3918cd2 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Tue, 10 Apr 2018 15:04:53 -0600 Subject: [PATCH 01/11] 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 bb778588b28af3fa6814b3dedc546cab4786e571 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 8 Jan 2018 07:17:29 -0700 Subject: [PATCH 02/11] 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 9191942e4a330393652cad8d0da715823d7f2920 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 4 May 2018 14:09:30 -0600 Subject: [PATCH 03/11] 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 | 2 ++ source4/scripting/bin/samba_gpoupdate | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index bbd385f73c6..2637f72590f 100644 --- a/python/samba/gp_sec_ext.py +++ b/python/samba/gp_sec_ext.py @@ -127,6 +127,8 @@ def listuserpol(self, rootpath): return os.path.join(rootpath, "User/Registry.pol") def apply_map(self): + if not self.ldb: + return {} return {"System Access": {"MinimumPasswordAge": ("minPwdAge", inf_to_ldb), "MaximumPasswordAge": ("maxPwdAge", diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate index 89b3ed77616..a7fe641973d 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/samba_gpoupdate @@ -86,8 +86,7 @@ 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 From 07d668d334d2e4824c89e04e3b93edf11248e6db Mon Sep 17 00:00:00 2001 From: David Mulder Date: Thu, 12 Apr 2018 14:31:54 -0600 Subject: [PATCH 04/11] libgpo: add py_register_gp_extension for registering gp extensions Signed-off-by: David Mulder --- libgpo/pygpo.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c index 1c05d071608..17a55604a1f 100644 --- a/libgpo/pygpo.c +++ b/libgpo/pygpo.c @@ -28,6 +28,11 @@ #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" /* A Python C API module to use LIBGPO */ @@ -383,6 +388,65 @@ static PyObject *py_check_refresh_gpo_list(PyObject * self, return ret; } +static void get_gp_registry_context(TALLOC_CTX *ctx, + uint32_t desired_access, + struct gp_registry_context **reg_ctx) +{ + struct security_token *token; + WERROR werr; + + lp_load_initial_only(get_dyn_CONFIGFILE()); + + token = registry_create_system_token(ctx); + if (!token) { + PyErr_SetString(PyExc_MemoryError, + "Failed to create system token"); + return; + } + werr = gp_init_reg_ctx(ctx, KEY_WINLOGON_GPEXT_PATH, desired_access, + token, reg_ctx); + if (!W_ERROR_IS_OK(werr)) { + PyErr_SetNTSTATUS(werror_to_ntstatus(werr)); + return; + } +} + +static PyObject *py_register_gp_extension(PyObject * self, PyObject * args) +{ + TALLOC_CTX *frame = talloc_stackframe(); + const char *module_path = NULL; + const char *guid_name = NULL; + WERROR werr; + struct gp_registry_context *reg_ctx = NULL; + struct registry_key *key = NULL; + struct registry_value module_val; + PyObject *ret = NULL; + + if (!PyArg_ParseTuple(args, "ss", &guid_name, &module_path)) { + return NULL; + } + + get_gp_registry_context(frame, REG_KEY_WRITE, ®_ctx); + 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; + } + + 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) @@ -587,6 +651,8 @@ static PyTypeObject ads_ADSType = { }; static PyMethodDef py_gpo_methods[] = { + {"register_gp_extension", (PyCFunction)py_register_gp_extension, + METH_VARARGS, NULL}, {"gpo_get_sysvol_gpt_version", (PyCFunction)py_gpo_get_sysvol_gpt_version, METH_VARARGS, NULL}, From 4a55638c66f63ba884944e61f8bc38ae4db51bd6 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 13 Apr 2018 15:14:06 -0600 Subject: [PATCH 05/11] libgpo: add py_unregister_gp_extension for unregistering gp extensions Signed-off-by: David Mulder --- libgpo/pygpo.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c index 17a55604a1f..6903190e1cf 100644 --- a/libgpo/pygpo.c +++ b/libgpo/pygpo.c @@ -411,6 +411,34 @@ static void get_gp_registry_context(TALLOC_CTX *ctx, } } +static PyObject *py_unregister_gp_extension(PyObject * self, PyObject * args) +{ + TALLOC_CTX *frame = talloc_stackframe(); + const char *guid_name = NULL; + struct gp_registry_context *reg_ctx = NULL; + WERROR werr; + PyObject *ret = Py_False; + + if (!PyArg_ParseTuple(args, "s", &guid_name)) { + return NULL; + } + + get_gp_registry_context(frame, REG_KEY_WRITE, ®_ctx); + if (!reg_ctx) { + goto out; + } + + werr = reg_deletekey_recursive(reg_ctx->curr_key, guid_name); + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + + ret = Py_True; +out: + TALLOC_FREE(frame); + return ret; +} + static PyObject *py_register_gp_extension(PyObject * self, PyObject * args) { TALLOC_CTX *frame = talloc_stackframe(); @@ -653,6 +681,8 @@ static PyTypeObject ads_ADSType = { static PyMethodDef py_gpo_methods[] = { {"register_gp_extension", (PyCFunction)py_register_gp_extension, METH_VARARGS, 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}, From 18f2745380a82ee99446866fa7d4b15fb06cdf9a Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 4 May 2018 10:41:16 -0600 Subject: [PATCH 06/11] libgpo: add py_list_gp_extensions for listing registered gp extensions Signed-off-by: David Mulder --- libgpo/pygpo.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c index 6903190e1cf..365e3c7766c 100644 --- a/libgpo/pygpo.c +++ b/libgpo/pygpo.c @@ -33,6 +33,7 @@ #include "registry/reg_api.h" #include "../libcli/registry/util_reg.h" #include "../libgpo/gpext/gpext.h" +#include "registry/reg_objects.h" /* A Python C API module to use LIBGPO */ @@ -411,6 +412,55 @@ static void get_gp_registry_context(TALLOC_CTX *ctx, } } +static PyObject *py_list_gp_extensions(PyObject * self, PyObject * args) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct gp_registry_context *reg_ctx = NULL; + WERROR werr; + PyObject *ret = NULL; + struct registry_key *parent; + int i; + + get_gp_registry_context(frame, REG_KEY_READ, ®_ctx); + if (!reg_ctx) { + goto out; + } + + parent = reg_ctx->curr_key; + + ret = PyDict_New(); + if (ret == NULL) { + goto out; + } + + for (i = regsubkey_ctr_numkeys(parent->subkeys); i > 0; i--) { + struct registry_key *subkey; + char *subkey_name = NULL; + const char *subkey_val = NULL; + struct registry_value *reg_val; + PyObject *val = NULL; + + subkey_name = regsubkey_ctr_specific_key(parent->subkeys, i-1); + werr = gp_read_reg_subkey(frame, reg_ctx, + subkey_name, &subkey); + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + werr = gp_read_reg_val_sz(frame, subkey, + "DllName", &subkey_val); + if (!W_ERROR_IS_OK(werr)) { + ret = NULL; + goto out; + } + val = PyStr_FromString(subkey_val); + PyDict_SetItemString(ret, subkey_name, val); + } + +out: + TALLOC_FREE(frame); + return ret; +} + static PyObject *py_unregister_gp_extension(PyObject * self, PyObject * args) { TALLOC_CTX *frame = talloc_stackframe(); @@ -683,6 +733,8 @@ static PyMethodDef py_gpo_methods[] = { METH_VARARGS, NULL}, {"unregister_gp_extension", (PyCFunction)py_unregister_gp_extension, METH_VARARGS, NULL}, + {"list_gp_extensions", (PyCFunction)py_list_gp_extensions, + METH_NOARGS, NULL}, {"gpo_get_sysvol_gpt_version", (PyCFunction)py_gpo_get_sysvol_gpt_version, METH_VARARGS, NULL}, From 12f2e91a0f6d8cd88d212fff907b040c3e0a5075 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 4 May 2018 13:38:44 -0600 Subject: [PATCH 07/11] 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 | 68 +++++++++++++++++++++++++++++++++++ python/samba/gp_sec_ext.py | 2 +- source4/scripting/bin/samba_gpoupdate | 6 ++-- 3 files changed, 73 insertions(+), 3 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..1a849b0118b --- /dev/null +++ b/python/samba/gp_ext_loader.py @@ -0,0 +1,68 @@ +# 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 check_base(cls, base_names=['gp_ext']): + bases = cls.__bases__ + for base in bases: + if base.__name__ in base_names: + return base.__name__ + else: + return check_base(base, base_names) + return None + +def get_gp_exts_from_module(mod): + import inspect + machine_exts = [] + clses = inspect.getmembers(mod, inspect.isclass) + for cls in clses: + base = check_base(cls[-1]) + if base == 'gp_ext' and cls[-1].__module__ == mod.__name__: + machine_exts.append(cls[-1]) + return {'machine_exts': machine_exts} + +def get_gp_client_side_extensions(logger): + machine_exts = [] + gp_exts = gpo.list_gp_extensions() + for gp_ext_file in gp_exts.values(): + gp_ext_name = os.path.splitext(os.path.basename(gp_ext_file))[0] + module = import_file(gp_ext_name, gp_ext_file) + exts = get_gp_exts_from_module(module) + machine_exts.extend(exts['machine_exts']) + if len(exts['machine_exts']) > 0: + logger.info('Loaded machine extensions from %s: %s' + % (gp_ext_file, + ' '.join([cls.__name__ for cls in exts['machine_exts']]))) + return machine_exts + diff --git a/python/samba/gp_sec_ext.py b/python/samba/gp_sec_ext.py index 2637f72590f..8df95440ba3 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 class inf_to_kdc_tdb(gp_ext_setter): def mins_to_hours(self): diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate index a7fe641973d..73d2786d129 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/samba_gpoupdate @@ -35,7 +35,7 @@ try: except: SamDB = None 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__": @@ -84,9 +84,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) 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 0e97615d3a172eadca67307c2b75c4772956719e Mon Sep 17 00:00:00 2001 From: David Mulder Date: Fri, 4 May 2018 13:25:25 -0600 Subject: [PATCH 08/11] gpo: Add user policy extensions Signed-off-by: David Mulder --- python/samba/gp_ext_loader.py | 15 ++++++++++++--- python/samba/gpclass.py | 5 +++++ source4/scripting/bin/samba_gpoupdate | 5 +++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/python/samba/gp_ext_loader.py b/python/samba/gp_ext_loader.py index 1a849b0118b..f2123f14067 100644 --- a/python/samba/gp_ext_loader.py +++ b/python/samba/gp_ext_loader.py @@ -33,7 +33,7 @@ def import_file(name, location): def import_file(name, location): return imp.load_source(name, location) -def check_base(cls, base_names=['gp_ext']): +def check_base(cls, base_names=['gp_ext', 'gp_user_ext']): bases = cls.__bases__ for base in bases: if base.__name__ in base_names: @@ -44,15 +44,19 @@ def check_base(cls, base_names=['gp_ext']): def get_gp_exts_from_module(mod): import inspect + user_exts = [] machine_exts = [] clses = inspect.getmembers(mod, inspect.isclass) for cls in clses: base = check_base(cls[-1]) if base == 'gp_ext' and cls[-1].__module__ == mod.__name__: machine_exts.append(cls[-1]) - return {'machine_exts': machine_exts} + elif base == 'gp_user_ext' and cls[-1].__module__ == mod.__name__: + user_exts.append(cls[-1]) + return {'machine_exts': machine_exts, 'user_exts': user_exts} def get_gp_client_side_extensions(logger): + user_exts = [] machine_exts = [] gp_exts = gpo.list_gp_extensions() for gp_ext_file in gp_exts.values(): @@ -64,5 +68,10 @@ def get_gp_client_side_extensions(logger): logger.info('Loaded machine extensions from %s: %s' % (gp_ext_file, ' '.join([cls.__name__ for cls in exts['machine_exts']]))) - return machine_exts + user_exts.extend(exts['user_exts']) + if len(exts['user_exts']) > 0: + logger.info('Loaded user extensions from %s: %s' + % (gp_ext_file, + ' '.join([cls.__name__ for cls in exts['user_exts']]))) + return (machine_exts, user_exts) diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index b9c376bf75a..fbad3bee109 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -336,6 +336,11 @@ def parse(self, afile, ldb, conn, gp_db, lp): def __str__(self): pass +class gp_user_ext(gp_ext): + def __init__(self, logger, creds): + super(gp_user_ext, self).__init__(logger) + self.creds = creds + class gp_ext_setter(): __metaclass__ = ABCMeta diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate index 73d2786d129..d78fdf48775 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/samba_gpoupdate @@ -84,13 +84,14 @@ 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) + machine_exts, user_exts = get_gp_client_side_extensions(logger) gp_extensions = [] if opts.machine: for ext in machine_exts: gp_extensions.append(ext(logger)) else: - pass # User extensions + for ext in user_exts: + gp_extensions.append(ext(logger, creds)) # Get a live instance of Samba if SamDB: From 3cc0038d8d600824695ca792920f37fe43e92b9a Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 7 May 2018 09:45:32 -0600 Subject: [PATCH 09/11] 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 0c1b28babbc..d6524ab859f 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2734,7 +2734,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 51a175b25e8..2d4edb6ee9e 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 520d0660ccf..f2e8e29e3c0 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 d78fdf48775..0602ced446e 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/gpupdate @@ -39,7 +39,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 @@ -68,7 +68,7 @@ if __name__ == "__main__": session = system_session() # 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 15d17c440fee758fb8a2658768f3ba512d2bcaaa Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 7 May 2018 09:48:32 -0600 Subject: [PATCH 10/11] 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 2d4edb6ee9e..e01bf4ec1e0 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 0602ced446e..bbf0c93e1de 100755 --- a/source4/scripting/bin/gpupdate +++ b/source4/scripting/bin/gpupdate @@ -49,8 +49,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 @@ -86,10 +86,10 @@ if __name__ == "__main__": machine_exts, user_exts = get_gp_client_side_extensions(logger) gp_extensions = [] - if opts.machine: + if opts.target == 'Computer': for ext in machine_exts: gp_extensions.append(ext(logger)) - else: + elif opts.target == 'User': for ext in user_exts: gp_extensions.append(ext(logger, creds)) 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 94113736db7f5723befcbaf49954af5e9d7439c4 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 7 May 2018 10:18:00 -0600 Subject: [PATCH 11/11] 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 --- source4/scripting/bin/gpupdate | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source4/scripting/bin/gpupdate b/source4/scripting/bin/gpupdate index bbf0c93e1de..dc2338b3c78 100755 --- a/source4/scripting/bin/gpupdate +++ b/source4/scripting/bin/gpupdate @@ -94,10 +94,15 @@ if __name__ == "__main__": gp_extensions.append(ext(logger, creds)) # Get a live instance of Samba + test_ldb = None if SamDB: - test_ldb = SamDB(url, session_info=session, credentials=creds, lp=lp) - else: - test_ldb = None + try: + test_ldb = SamDB(url, + session_info=session, + credentials=creds, + lp=lp) + except: + test_ldb = None if not opts.unapply: apply_gp(lp, creds, test_ldb, logger, store, gp_extensions)