Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Group Policy Update event for winbindd
4 : * Copyright (C) David Mulder 2017
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 : #include "includes.h"
20 : #include "param/param.h"
21 : #include "param/loadparm.h"
22 : #include "winbindd.h"
23 : #include "lib/global_contexts.h"
24 :
25 : /*
26 : * gpupdate_interval()
27 : * return Random integer between 5400 and 7200, the group policy update
28 : * interval in seconds
29 : *
30 : * Group Policy should be updated every 90 minutes in the background,
31 : * with a random offset between 0 and 30 minutes. This ensures multiple
32 : * clients will not update at the same time.
33 : */
34 : #define GPUPDATE_INTERVAL (90*60)
35 : #define GPUPDATE_RAND_OFFSET (30*60)
36 0 : static uint32_t gpupdate_interval(void)
37 : {
38 0 : int rand_int_offset = generate_random() % GPUPDATE_RAND_OFFSET;
39 0 : return GPUPDATE_INTERVAL+rand_int_offset;
40 : }
41 :
42 : struct gpupdate_state {
43 : TALLOC_CTX *ctx;
44 : struct loadparm_context *lp_ctx;
45 : };
46 :
47 : static void gpupdate_cmd_done(struct tevent_req *subreq);
48 :
49 0 : static void gpupdate_callback(struct tevent_context *ev,
50 : struct tevent_timer *tim,
51 : struct timeval current_time,
52 : void *private_data)
53 : {
54 0 : struct tevent_timer *time_event;
55 0 : struct timeval schedule;
56 0 : struct tevent_req *req = NULL;
57 0 : struct gpupdate_state *data =
58 0 : talloc_get_type_abort(private_data, struct gpupdate_state);
59 0 : const char *const *gpupdate_cmd =
60 0 : lpcfg_gpo_update_command(data->lp_ctx);
61 0 : const char *smbconf = lpcfg_configfile(data->lp_ctx);
62 0 : if (smbconf == NULL) {
63 0 : smbconf = lp_default_path();
64 : }
65 :
66 : /* Execute gpupdate */
67 0 : req = samba_runcmd_send(data->ctx, ev, timeval_zero(), 2, 0,
68 : gpupdate_cmd,
69 : "-s",
70 : smbconf,
71 : "--target=Computer",
72 : "--machine-pass",
73 : NULL);
74 0 : if (req == NULL) {
75 0 : DEBUG(0, ("Failed to execute the gpupdate command\n"));
76 0 : return;
77 : }
78 :
79 0 : tevent_req_set_callback(req, gpupdate_cmd_done, NULL);
80 :
81 : /* Schedule the next event */
82 0 : schedule = tevent_timeval_current_ofs(gpupdate_interval(), 0);
83 0 : time_event = tevent_add_timer(ev, data->ctx, schedule,
84 : gpupdate_callback, data);
85 0 : if (time_event == NULL) {
86 0 : DEBUG(0, ("Failed scheduling the next gpupdate event\n"));
87 : }
88 : }
89 :
90 45 : void gpupdate_init(void)
91 : {
92 0 : struct tevent_timer *time_event;
93 0 : struct timeval schedule;
94 45 : TALLOC_CTX * ctx = talloc_new(global_event_context());
95 45 : struct gpupdate_state *data = talloc(ctx, struct gpupdate_state);
96 0 : struct loadparm_context *lp_ctx =
97 45 : loadparm_init_s3(NULL, loadparm_s3_helpers());
98 :
99 : /*
100 : * Check if gpupdate is enabled for winbind, if not
101 : * return without scheduling any events.
102 : */
103 45 : if (!lpcfg_apply_group_policies(lp_ctx)) {
104 45 : return;
105 : }
106 :
107 : /*
108 : * Execute the first event immediately, future events
109 : * will execute on the gpupdate interval, which is every
110 : * 90 to 120 minutes (at random).
111 : */
112 0 : schedule = tevent_timeval_current_ofs(0, 0);
113 0 : data->ctx = ctx;
114 0 : data->lp_ctx = lp_ctx;
115 0 : if (data->lp_ctx == NULL) {
116 0 : smb_panic("Could not load smb.conf\n");
117 : }
118 0 : time_event = tevent_add_timer(global_event_context(), data->ctx,
119 : schedule, gpupdate_callback, data);
120 0 : if (time_event == NULL) {
121 0 : DEBUG(0, ("Failed scheduling the gpupdate event\n"));
122 : }
123 : }
124 :
125 0 : void gpupdate_user_init(const char *user)
126 : {
127 0 : struct tevent_req *req = NULL;
128 0 : TALLOC_CTX *ctx = talloc_new(global_event_context());
129 0 : struct loadparm_context *lp_ctx =
130 0 : loadparm_init_s3(NULL, loadparm_s3_helpers());
131 0 : const char *const *gpupdate_cmd = lpcfg_gpo_update_command(lp_ctx);
132 0 : const char *smbconf = lpcfg_configfile(lp_ctx);
133 0 : if (smbconf == NULL) {
134 0 : smbconf = lp_default_path();
135 : }
136 :
137 0 : if (ctx == NULL) {
138 0 : DBG_ERR("talloc_new failed\n");
139 0 : return;
140 : }
141 :
142 : /*
143 : * Check if gpupdate is enabled for winbind, if not
144 : * return without applying user policy.
145 : */
146 0 : if (!lpcfg_apply_group_policies(lp_ctx)) {
147 0 : return;
148 : }
149 :
150 : /*
151 : * Execute gpupdate for the user immediately.
152 : * TODO: This should be scheduled to reapply every 90 to 120 minutes.
153 : * Logoff will need to handle cancelling these events though, and
154 : * multiple timers cannot be run for the same user, even if there are
155 : * multiple active sessions.
156 : */
157 0 : req = samba_runcmd_send(ctx, global_event_context(),
158 : timeval_zero(), 2, 0,
159 : gpupdate_cmd,
160 : "-s",
161 : smbconf,
162 : "--target=User",
163 : "-U",
164 : user,
165 : NULL);
166 0 : if (req == NULL) {
167 0 : DBG_ERR("Failed to execute the gpupdate command\n");
168 0 : return;
169 : }
170 :
171 0 : tevent_req_set_callback(req, gpupdate_cmd_done, NULL);
172 : }
173 :
174 0 : static void gpupdate_cmd_done(struct tevent_req *subreq)
175 : {
176 0 : int sys_errno;
177 0 : int ret;
178 :
179 0 : ret = samba_runcmd_recv(subreq, &sys_errno);
180 0 : TALLOC_FREE(subreq);
181 0 : if (ret != 0) {
182 0 : DBG_ERR("gpupdate failed with exit status %d\n", sys_errno);
183 : }
184 0 : }
|