summaryrefslogtreecommitdiffstats
path: root/source3/winbindd/winbindd_gpupdate.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/winbindd/winbindd_gpupdate.c')
-rw-r--r--source3/winbindd/winbindd_gpupdate.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/source3/winbindd/winbindd_gpupdate.c b/source3/winbindd/winbindd_gpupdate.c
new file mode 100644
index 0000000..1ab20fb
--- /dev/null
+++ b/source3/winbindd/winbindd_gpupdate.c
@@ -0,0 +1,184 @@
+/*
+ * 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"
+#include "lib/global_contexts.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 multiple
+ * 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 = generate_random() % GPUPDATE_RAND_OFFSET;
+ return GPUPDATE_INTERVAL+rand_int_offset;
+}
+
+struct gpupdate_state {
+ TALLOC_CTX *ctx;
+ struct loadparm_context *lp_ctx;
+};
+
+static void gpupdate_cmd_done(struct tevent_req *subreq);
+
+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 = lpcfg_configfile(data->lp_ctx);
+ if (smbconf == NULL) {
+ smbconf = lp_default_path();
+ }
+
+ /* Execute gpupdate */
+ req = samba_runcmd_send(data->ctx, ev, timeval_zero(), 2, 0,
+ gpupdate_cmd,
+ "-s",
+ smbconf,
+ "--target=Computer",
+ "--machine-pass",
+ NULL);
+ if (req == NULL) {
+ DEBUG(0, ("Failed to execute the gpupdate command\n"));
+ return;
+ }
+
+ tevent_req_set_callback(req, gpupdate_cmd_done, NULL);
+
+ /* 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(global_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(global_event_context(), data->ctx,
+ schedule, gpupdate_callback, data);
+ if (time_event == NULL) {
+ DEBUG(0, ("Failed scheduling the gpupdate event\n"));
+ }
+}
+
+void gpupdate_user_init(const char *user)
+{
+ struct tevent_req *req = NULL;
+ TALLOC_CTX *ctx = talloc_new(global_event_context());
+ struct loadparm_context *lp_ctx =
+ loadparm_init_s3(NULL, loadparm_s3_helpers());
+ const char *const *gpupdate_cmd = lpcfg_gpo_update_command(lp_ctx);
+ const char *smbconf = lpcfg_configfile(lp_ctx);
+ if (smbconf == NULL) {
+ smbconf = lp_default_path();
+ }
+
+ if (ctx == NULL) {
+ DBG_ERR("talloc_new failed\n");
+ return;
+ }
+
+ /*
+ * Check if gpupdate is enabled for winbind, if not
+ * return without applying user policy.
+ */
+ if (!lpcfg_apply_group_policies(lp_ctx)) {
+ return;
+ }
+
+ /*
+ * Execute gpupdate for the user immediately.
+ * TODO: This should be scheduled to reapply every 90 to 120 minutes.
+ * Logoff will need to handle cancelling these events though, and
+ * multiple timers cannot be run for the same user, even if there are
+ * multiple active sessions.
+ */
+ req = samba_runcmd_send(ctx, global_event_context(),
+ timeval_zero(), 2, 0,
+ gpupdate_cmd,
+ "-s",
+ smbconf,
+ "--target=User",
+ "-U",
+ user,
+ NULL);
+ if (req == NULL) {
+ DBG_ERR("Failed to execute the gpupdate command\n");
+ return;
+ }
+
+ tevent_req_set_callback(req, gpupdate_cmd_done, NULL);
+}
+
+static void gpupdate_cmd_done(struct tevent_req *subreq)
+{
+ int sys_errno;
+ int ret;
+
+ ret = samba_runcmd_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ DBG_ERR("gpupdate failed with exit status %d\n", sys_errno);
+ }
+}