xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
<description>
<para>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.
</para>
</description>
--- /dev/null
+<samba:parameter name="apply group policies"
+ context="G"
+ type="boolean"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+
+ <para>This option controls whether winbind will execute the gpupdate
+ command defined in <smbconfoption name="gpo update command"/> 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.
+ </para>
+
+</description>
+
+<value type="default">no</value>
+<value type="example">yes</value>
+</samba:parameter>
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",
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
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
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");
daemon_ready("winbindd");
}
+ gpupdate_init();
+
/* Loop waiting for requests */
while (1) {
frame = talloc_stackframe();
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#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"));
+ }
+}
+
/* 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_ */
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
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):
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
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)
'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='.')
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}',