From 2ca73cba53621c6db79f769f625316535fbfdbc9 Mon Sep 17 00:00:00 2001 From: David Mulder Date: Tue, 21 Nov 2017 03:44:12 -0700 Subject: [PATCH] gpo: Add the winbind call to gpupdate Signed-off-by: David Mulder Reviewed-by: Garming Sam Reviewed-by: Andrew Bartlett --- docs-xml/smbdotconf/domain/gpoupdatecommand.xml | 11 +- docs-xml/smbdotconf/winbind/applygrouppolicies.xml | 19 ++++ lib/param/loadparm.c | 1 + python/samba/gpclass.py | 9 +- selftest/target/Samba4.pm | 2 +- source3/param/loadparm.c | 2 + source3/winbindd/winbindd.c | 2 + source3/winbindd/winbindd_gpupdate.c | 116 +++++++++++++++++++++ source3/winbindd/winbindd_proto.h | 3 + source3/winbindd/wscript_build | 3 +- source4/scripting/bin/samba_gpoupdate | 21 +++- source4/scripting/bin/wscript_build | 2 +- source4/scripting/wscript_build | 7 +- 13 files changed, 178 insertions(+), 20 deletions(-) create mode 100644 docs-xml/smbdotconf/winbind/applygrouppolicies.xml create mode 100644 source3/winbindd/winbindd_gpupdate.c diff --git a/docs-xml/smbdotconf/domain/gpoupdatecommand.xml b/docs-xml/smbdotconf/domain/gpoupdatecommand.xml index 22a42163f27..77b596051b7 100644 --- a/docs-xml/smbdotconf/domain/gpoupdatecommand.xml +++ b/docs-xml/smbdotconf/domain/gpoupdatecommand.xml @@ -5,10 +5,13 @@ 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. - 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 lifetime in smb.conf. + The samba_gpoupdate script applies System Access and Kerberos Policies + to the KDC, or Environment Variable policies to client machines. 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 lifetime in + smb.conf. Environment Variable policies apply environment variables, + such as PATH, to /etc/profile. diff --git a/docs-xml/smbdotconf/winbind/applygrouppolicies.xml b/docs-xml/smbdotconf/winbind/applygrouppolicies.xml new file mode 100644 index 00000000000..67baa0d1426 --- /dev/null +++ b/docs-xml/smbdotconf/winbind/applygrouppolicies.xml @@ -0,0 +1,19 @@ + + + + This option controls whether winbind will execute the gpupdate + command defined in on the + Group Policy update interval. The Group Policy update interval is + defined as every 90 minutes, plus a random offset between 0 and 30 + minutes. This applies Group Policy Machine polices to the client or + KDC and machine policies to a server. + + + + +no +yes + diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index f26545963d6..7854f57a158 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2734,6 +2734,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) 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, "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); lpcfg_do_global_parameter_var(lp_ctx, "samba kcc command", diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py index ca34120d513..33c9001cb6d 100644 --- a/python/samba/gpclass.py +++ b/python/samba/gpclass.py @@ -19,19 +19,12 @@ import sys import os import tdb sys.path.insert(0, "bin/python") -import samba.gpo as gpo -import optparse -import ldb -from samba.auth import system_session -import samba.getopt as options -from samba.samdb import SamDB -from samba.netcmd import gpo as gpo_user -import codecs from samba import NTSTATUSError from ConfigParser import ConfigParser from StringIO import StringIO from abc import ABCMeta, abstractmethod import xml.etree.ElementTree as etree +import re try: from enum import Enum diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 628f4f19f9e..c161ee082a0 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -616,7 +616,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 + gpo update command = $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_gpoupdate -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 f1f453e7ef1..096c23f4fb3 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -923,6 +923,8 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.gpo_update_command = str_list_make_v3_const(NULL, s, NULL); TALLOC_FREE(s); + Globals.apply_group_policies = false; + s = talloc_asprintf(talloc_tos(), "%s/samba_spnupdate", get_dyn_SCRIPTSBINDIR()); if (s == NULL) { smb_panic("init_globals: ENOMEM"); diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index 53267374be0..0a8d146dfdc 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -1790,6 +1790,8 @@ int main(int argc, const char **argv) daemon_ready("winbindd"); } + gpupdate_init(); + /* Loop waiting for requests */ while (1) { frame = talloc_stackframe(); diff --git a/source3/winbindd/winbindd_gpupdate.c b/source3/winbindd/winbindd_gpupdate.c new file mode 100644 index 00000000000..48ebb5501aa --- /dev/null +++ b/source3/winbindd/winbindd_gpupdate.c @@ -0,0 +1,116 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Update event for winbindd + * Copyright (C) David Mulder 2017 + * + * 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 "param/param.h" +#include "param/loadparm.h" +#include "winbindd.h" + +/* + * gpupdate_interval() + * return Random integer between 5400 and 7200, the group policy update + * interval in seconds + * + * Group Policy should be updated every 90 minutes in the background, + * with a random offset between 0 and 30 minutes. This ensures mutiple + * clients will not update at the same time. + */ +#define GPUPDATE_INTERVAL (90*60) +#define GPUPDATE_RAND_OFFSET (30*60) +static uint32_t gpupdate_interval(void) +{ + int rand_int_offset = rand() % GPUPDATE_RAND_OFFSET; + return GPUPDATE_INTERVAL+rand_int_offset; +} + +struct gpupdate_state { + TALLOC_CTX *ctx; + struct loadparm_context *lp_ctx; +}; + +static void gpupdate_callback(struct tevent_context *ev, + struct tevent_timer *tim, + struct timeval current_time, + void *private_data) +{ + struct tevent_timer *time_event; + struct timeval schedule; + struct tevent_req *req = NULL; + struct gpupdate_state *data = + talloc_get_type_abort(private_data, struct gpupdate_state); + const char *const *gpupdate_cmd = + lpcfg_gpo_update_command(data->lp_ctx); + const char *smbconf = lp_default_path(); + + /* Execute gpupdate */ + req = samba_runcmd_send(data->ctx, ev, timeval_zero(), 2, 0, + gpupdate_cmd, + "-s", + smbconf, + "--machine", + "--machine-pass", + NULL); + if (req == NULL) { + DEBUG(0, ("Failed to execute the gpupdate command\n")); + return; + } + + /* Schedule the next event */ + schedule = tevent_timeval_current_ofs(gpupdate_interval(), 0); + time_event = tevent_add_timer(ev, data->ctx, schedule, + gpupdate_callback, data); + if (time_event == NULL) { + DEBUG(0, ("Failed scheduling the next gpupdate event\n")); + } +} + +void gpupdate_init(void) +{ + struct tevent_timer *time_event; + struct timeval schedule; + TALLOC_CTX * ctx = talloc_new(server_event_context()); + struct gpupdate_state *data = talloc(ctx, struct gpupdate_state); + struct loadparm_context *lp_ctx = + loadparm_init_s3(NULL, loadparm_s3_helpers()); + + /* + * Check if gpupdate is enabled for winbind, if not + * return without scheduling any events. + */ + if (!lpcfg_apply_group_policies(lp_ctx)) { + return; + } + + /* + * Execute the first event immediately, future events + * will execute on the gpupdate interval, which is every + * 90 to 120 minutes (at random). + */ + schedule = tevent_timeval_current_ofs(0, 0); + data->ctx = ctx; + data->lp_ctx = lp_ctx; + if (data->lp_ctx == NULL) { + smb_panic("Could not load smb.conf\n"); + } + time_event = tevent_add_timer(server_event_context(), data->ctx, + schedule, gpupdate_callback, data); + if (time_event == NULL) { + DEBUG(0, ("Failed scheduling the gpupdate event\n")); + } +} + diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 39cdef54531..9a52f6a4edb 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -942,4 +942,7 @@ NTSTATUS wb_irpc_register(void); /* The following definitions come from winbindd/winbindd_reconnect.c */ bool reconnect_need_retry(NTSTATUS status, struct winbindd_domain *domain); +/* The following definitions come from winbindd/winbindd_gpupdate.c */ +void gpupdate_init(void); + #endif /* _WINBINDD_PROTO_H_ */ diff --git a/source3/winbindd/wscript_build b/source3/winbindd/wscript_build index 51264e9e365..48250ea565e 100644 --- a/source3/winbindd/wscript_build +++ b/source3/winbindd/wscript_build @@ -254,7 +254,8 @@ bld.SAMBA3_BINARY('winbindd', winbindd_pam_logoff.c winbindd_pam_chauthtok.c winbindd_pam_auth_crap.c - winbindd_pam_chng_pswd_auth_crap.c''', + winbindd_pam_chng_pswd_auth_crap.c + winbindd_gpupdate.c''', deps=''' talloc tevent diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate index e74b2c896a1..26e0984413e 100755 --- a/source4/scripting/bin/samba_gpoupdate +++ b/source4/scripting/bin/samba_gpoupdate @@ -29,11 +29,18 @@ 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 * from samba.net import Net from samba.dcerpc import nbt from samba import smb +import samba.gpo as gpo import logging +import chardet ''' Fetch the hostname of a writable DC ''' def get_dc_hostname(creds, lp): @@ -117,6 +124,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_group(credopts) # Set the options and the arguments @@ -150,10 +159,18 @@ if __name__ == "__main__": cache_dir = lp.get('cache directory') store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb')) - gp_extensions = [gp_sec_ext(logger)] + gp_extensions = [] + if opts.machine: + if lp.get('server role') == 'active directory domain controller': + gp_extensions.append(gp_sec_ext(logger)) + else: + pass # User extensions # Get a live instance of Samba - test_ldb = SamDB(url, session_info=session, credentials=creds, lp=lp) + 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) diff --git a/source4/scripting/bin/wscript_build b/source4/scripting/bin/wscript_build index 737f1bce411..043442b3407 100644 --- a/source4/scripting/bin/wscript_build +++ b/source4/scripting/bin/wscript_build @@ -7,6 +7,6 @@ if bld.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'): 'samba_kcc', 'samba_upgradeprovision', 'samba_upgradedns', - 'samba_gpoupdate', 'gen_output.py']: bld.SAMBA_SCRIPT(script, pattern=script, installdir='.') +bld.SAMBA_SCRIPT('samba_gpoupdate', pattern='samba_gpoupdate', installdir='.') diff --git a/source4/scripting/wscript_build b/source4/scripting/wscript_build index eb11c4202fe..2f53cce12b7 100644 --- a/source4/scripting/wscript_build +++ b/source4/scripting/wscript_build @@ -2,10 +2,11 @@ from samba_utils import MODE_755 -sbin_files = None +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 bin/samba_gpoupdate' - man_files = 'man/samba_gpoupdate.8' + 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' if sbin_files: bld.INSTALL_FILES('${SBINDIR}', -- 2.11.4.GIT