s4:torture: Skip test_membership_user for users that get incorrectly assigned group sid
[samba.git] / source3 / winbindd / winbindd_gpupdate.c
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 mutiple
32  * clients will not update at the same time.
33  */
34 #define GPUPDATE_INTERVAL       (90*60)
35 #define GPUPDATE_RAND_OFFSET    (30*60)
36 static uint32_t gpupdate_interval(void)
37 {
38         int rand_int_offset = generate_random() % GPUPDATE_RAND_OFFSET;
39         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 static void gpupdate_callback(struct tevent_context *ev,
50                               struct tevent_timer *tim,
51                               struct timeval current_time,
52                               void *private_data)
53 {
54         struct tevent_timer *time_event;
55         struct timeval schedule;
56         struct tevent_req *req = NULL;
57         struct gpupdate_state *data =
58                 talloc_get_type_abort(private_data, struct gpupdate_state);
59         const char *const *gpupdate_cmd =
60                 lpcfg_gpo_update_command(data->lp_ctx);
61         const char *smbconf = lpcfg_configfile(data->lp_ctx);
62         if (smbconf == NULL) {
63                 smbconf = lp_default_path();
64         }
65
66         /* Execute gpupdate */
67         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         if (req == NULL) {
75                 DEBUG(0, ("Failed to execute the gpupdate command\n"));
76                 return;
77         }
78
79         tevent_req_set_callback(req, gpupdate_cmd_done, NULL);
80
81         /* Schedule the next event */
82         schedule = tevent_timeval_current_ofs(gpupdate_interval(), 0);
83         time_event = tevent_add_timer(ev, data->ctx, schedule,
84                                       gpupdate_callback, data);
85         if (time_event == NULL) {
86                 DEBUG(0, ("Failed scheduling the next gpupdate event\n"));
87         }
88 }
89
90 void gpupdate_init(void)
91 {
92         struct tevent_timer *time_event;
93         struct timeval schedule;
94         TALLOC_CTX * ctx = talloc_new(global_event_context());
95         struct gpupdate_state *data = talloc(ctx, struct gpupdate_state);
96         struct loadparm_context *lp_ctx =
97                 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         if (!lpcfg_apply_group_policies(lp_ctx)) {
104                 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         schedule = tevent_timeval_current_ofs(0, 0);
113         data->ctx = ctx;
114         data->lp_ctx = lp_ctx;
115         if (data->lp_ctx == NULL) {
116                 smb_panic("Could not load smb.conf\n");
117         }
118         time_event = tevent_add_timer(global_event_context(), data->ctx,
119                                       schedule, gpupdate_callback, data);
120         if (time_event == NULL) {
121                 DEBUG(0, ("Failed scheduling the gpupdate event\n"));
122         }
123 }
124
125 void gpupdate_user_init(const char *user)
126 {
127         struct tevent_req *req = NULL;
128         TALLOC_CTX *ctx = talloc_new(global_event_context());
129         struct loadparm_context *lp_ctx =
130                 loadparm_init_s3(NULL, loadparm_s3_helpers());
131         const char *const *gpupdate_cmd = lpcfg_gpo_update_command(lp_ctx);
132         const char *smbconf = lpcfg_configfile(lp_ctx);
133         if (smbconf == NULL) {
134                 smbconf = lp_default_path();
135         }
136
137         if (ctx == NULL) {
138                 DBG_ERR("talloc_new failed\n");
139                 return;
140         }
141
142         /*
143          * Check if gpupdate is enabled for winbind, if not
144          * return without applying user policy.
145          */
146         if (!lpcfg_apply_group_policies(lp_ctx)) {
147                 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         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         if (req == NULL) {
167                 DBG_ERR("Failed to execute the gpupdate command\n");
168                 return;
169         }
170
171         tevent_req_set_callback(req, gpupdate_cmd_done, NULL);
172 }
173
174 static void gpupdate_cmd_done(struct tevent_req *subreq)
175 {
176         int sys_errno;
177         int ret;
178
179         ret = samba_runcmd_recv(subreq, &sys_errno);
180         TALLOC_FREE(subreq);
181         if (ret != 0) {
182                 DBG_ERR("gpupdate failed with exit status %d\n", sys_errno);
183         }
184 }