gpo: Add the winbind call to gpupdate
authorDavid Mulder <dmulder@suse.com>
Tue, 21 Nov 2017 10:44:12 +0000 (03:44 -0700)
committerStefan Metzmacher <metze@samba.org>
Sat, 13 Jan 2018 21:38:05 +0000 (22:38 +0100)
Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
13 files changed:
docs-xml/smbdotconf/domain/gpoupdatecommand.xml
docs-xml/smbdotconf/winbind/applygrouppolicies.xml [new file with mode: 0644]
lib/param/loadparm.c
python/samba/gpclass.py
selftest/target/Samba4.pm
source3/param/loadparm.c
source3/winbindd/winbindd.c
source3/winbindd/winbindd_gpupdate.c [new file with mode: 0644]
source3/winbindd/winbindd_proto.h
source3/winbindd/wscript_build
source4/scripting/bin/samba_gpoupdate
source4/scripting/bin/wscript_build
source4/scripting/wscript_build

index 22a42163f276191dd768365e60e13b79f7a87e77..77b596051b75cf4fda486d290217cbfd9decb9e9 100644 (file)
@@ -5,10 +5,13 @@
                  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>
 
diff --git a/docs-xml/smbdotconf/winbind/applygrouppolicies.xml b/docs-xml/smbdotconf/winbind/applygrouppolicies.xml
new file mode 100644 (file)
index 0000000..67baa0d
--- /dev/null
@@ -0,0 +1,19 @@
+<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>
index f26545963d664c9b7b316f1e379d2cbf9529a5a4..7854f57a158243c1244e73235636110ed80407b8 100644 (file)
@@ -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",
index ca34120d513a2dd02b60b5972d56ea1f5510e3e6..33c9001cb6d0e86778507d64ea34069cb9a57da0 100644 (file)
@@ -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
index 628f4f19f9e1c972e0275f7cadebc9e90de4fdd0..c161ee082a05b32c05f67da206cad04c6c5855cf 100755 (executable)
@@ -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
 
index f1f453e7ef15b5cd55cd068970421122c2af345b..096c23f4fb3976cbf4bbb8730ab5967cca56e8ec 100644 (file)
@@ -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");
index 53267374be044ed1b0e70c838de8f730ccc6fd45..0a8d146dfdc76ecf26c3c6d850a853a3abf84b1e 100644 (file)
@@ -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 (file)
index 0000000..48ebb55
--- /dev/null
@@ -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 <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"));
+       }
+}
+
index 39cdef54531005d5c859b9ec55e6eedd704d6aed..9a52f6a4edb1a15fed938a9c45cce90166f2e9bf 100644 (file)
@@ -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_  */
index 51264e9e365b829ecb1f828f80b49e464eeb290c..48250ea565e3b4ff1906d4e49344b4f3bb354a79 100644 (file)
@@ -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
index e74b2c896a17686dd0e9e9c138014ef3879eaf78..26e0984413ed7543a4445a65e9e18c3e59aecd24 100755 (executable)
@@ -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)
index 737f1bce411bcab1928bac7005982ba26cb633ea..043442b34070a5841778b71ed407556feffec821 100644 (file)
@@ -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='.')
index eb11c4202fefad85e816778e0391c03a50919b51..2f53cce12b7861b8f157f8ea7caa416a20f040d6 100644 (file)
@@ -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}',