/* * 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" #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); } }