Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2015 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <errno.h>
22 : #include <talloc.h>
23 : #include <tevent.h>
24 :
25 : #include "util/util.h"
26 : #include "providers/be_ptask.h"
27 : #include "providers/ipa/ipa_sudo.h"
28 : #include "providers/ldap/sdap_sudo_shared.h"
29 : #include "db/sysdb_sudo.h"
30 :
31 : struct ipa_sudo_full_refresh_state {
32 : struct ipa_sudo_ctx *sudo_ctx;
33 : struct sss_domain_info *domain;
34 : int dp_error;
35 : };
36 :
37 : static void ipa_sudo_full_refresh_done(struct tevent_req *subreq);
38 :
39 : struct tevent_req *
40 0 : ipa_sudo_full_refresh_send(TALLOC_CTX *mem_ctx,
41 : struct tevent_context *ev,
42 : struct ipa_sudo_ctx *sudo_ctx)
43 : {
44 : struct ipa_sudo_full_refresh_state *state;
45 : struct tevent_req *subreq;
46 : struct tevent_req *req;
47 : char *delete_filter;
48 : int ret;
49 :
50 0 : req = tevent_req_create(mem_ctx, &state,
51 : struct ipa_sudo_full_refresh_state);
52 0 : if (req == NULL) {
53 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
54 0 : return NULL;
55 : }
56 :
57 0 : state->domain = sudo_ctx->id_ctx->be->domain;
58 0 : state->sudo_ctx = sudo_ctx;
59 :
60 : /* Remove all rules from cache */
61 0 : delete_filter = talloc_asprintf(state, "(%s=%s)", SYSDB_OBJECTCLASS,
62 : SYSDB_SUDO_CACHE_OC);
63 0 : if (delete_filter == NULL) {
64 0 : ret = ENOMEM;
65 0 : goto immediately;
66 : }
67 :
68 0 : DEBUG(SSSDBG_TRACE_FUNC, "Issuing a full refresh of sudo rules\n");
69 :
70 0 : subreq = ipa_sudo_refresh_send(state, ev, sudo_ctx,
71 : NULL, NULL, delete_filter);
72 0 : if (subreq == NULL) {
73 0 : ret = ENOMEM;
74 0 : goto immediately;
75 : }
76 :
77 0 : tevent_req_set_callback(subreq, ipa_sudo_full_refresh_done, req);
78 :
79 0 : return req;
80 :
81 : immediately:
82 0 : if (ret == EOK) {
83 0 : tevent_req_done(req);
84 : } else {
85 0 : tevent_req_error(req, ret);
86 : }
87 0 : tevent_req_post(req, ev);
88 :
89 0 : return req;
90 : }
91 :
92 : static void
93 0 : ipa_sudo_full_refresh_done(struct tevent_req *subreq)
94 : {
95 : struct ipa_sudo_full_refresh_state *state;
96 : struct tevent_req *req;
97 : int ret;
98 :
99 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
100 0 : state = tevent_req_data(req, struct ipa_sudo_full_refresh_state);
101 :
102 0 : ret = ipa_sudo_refresh_recv(subreq, &state->dp_error, NULL);
103 0 : talloc_zfree(subreq);
104 0 : if (ret != EOK || state->dp_error != DP_ERR_OK) {
105 : goto done;
106 : }
107 :
108 0 : ret = sysdb_sudo_set_last_full_refresh(state->domain, time(NULL));
109 0 : if (ret != EOK) {
110 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unable to save time of "
111 : "a successful full refresh\n");
112 : }
113 :
114 0 : DEBUG(SSSDBG_TRACE_FUNC, "Successful full refresh of sudo rules\n");
115 :
116 : done:
117 0 : if (ret != EOK) {
118 0 : tevent_req_error(req, ret);
119 0 : return;
120 : }
121 :
122 0 : tevent_req_done(req);
123 : }
124 :
125 : int
126 0 : ipa_sudo_full_refresh_recv(struct tevent_req *req,
127 : int *dp_error)
128 : {
129 : struct ipa_sudo_full_refresh_state *state;
130 0 : state = tevent_req_data(req, struct ipa_sudo_full_refresh_state);
131 :
132 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
133 :
134 0 : *dp_error = state->dp_error;
135 :
136 0 : return EOK;
137 : }
138 :
139 : struct ipa_sudo_smart_refresh_state {
140 : int dp_error;
141 : };
142 :
143 : static void ipa_sudo_smart_refresh_done(struct tevent_req *subreq);
144 :
145 : static struct tevent_req *
146 0 : ipa_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx,
147 : struct tevent_context *ev,
148 : struct ipa_sudo_ctx *sudo_ctx)
149 : {
150 0 : struct sdap_server_opts *srv_opts = sudo_ctx->id_ctx->srv_opts;
151 : struct ipa_sudo_smart_refresh_state *state;
152 : struct tevent_req *subreq;
153 : struct tevent_req *req;
154 : char *cmdgroups_filter;
155 : char *search_filter;
156 : const char *usn;
157 : errno_t ret;
158 :
159 0 : req = tevent_req_create(mem_ctx, &state,
160 : struct ipa_sudo_smart_refresh_state);
161 0 : if (req == NULL) {
162 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
163 0 : return NULL;
164 : }
165 :
166 : /* Download all rules from LDAP that are newer than usn */
167 0 : if (srv_opts == NULL || srv_opts->max_sudo_value == 0) {
168 0 : DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, assuming zero.\n");
169 0 : usn = "0";
170 0 : search_filter = NULL;
171 : } else {
172 0 : usn = srv_opts->max_sudo_value;
173 0 : search_filter = talloc_asprintf(state, "(%s>=%s)",
174 0 : sudo_ctx->sudorule_map[IPA_AT_SUDORULE_ENTRYUSN].name, usn);
175 0 : if (search_filter == NULL) {
176 0 : ret = ENOMEM;
177 0 : goto immediately;
178 : }
179 : }
180 :
181 0 : cmdgroups_filter = talloc_asprintf(state, "(%s>=%s)",
182 0 : sudo_ctx->sudocmdgroup_map[IPA_AT_SUDOCMDGROUP_ENTRYUSN].name, usn);
183 0 : if (cmdgroups_filter == NULL) {
184 0 : ret = ENOMEM;
185 0 : goto immediately;
186 : }
187 :
188 : /* Do not remove any rules that are already in the sysdb. */
189 :
190 0 : DEBUG(SSSDBG_TRACE_FUNC, "Issuing a smart refresh of sudo rules "
191 : "(USN >= %s)\n", usn);
192 :
193 0 : subreq = ipa_sudo_refresh_send(state, ev, sudo_ctx, cmdgroups_filter,
194 : search_filter, NULL);
195 0 : if (subreq == NULL) {
196 0 : ret = ENOMEM;
197 0 : goto immediately;
198 : }
199 :
200 0 : tevent_req_set_callback(subreq, ipa_sudo_smart_refresh_done, req);
201 :
202 0 : return req;
203 :
204 : immediately:
205 0 : if (ret == EOK) {
206 0 : tevent_req_done(req);
207 : } else {
208 0 : tevent_req_error(req, ret);
209 : }
210 0 : tevent_req_post(req, ev);
211 :
212 0 : return req;
213 : }
214 :
215 0 : static void ipa_sudo_smart_refresh_done(struct tevent_req *subreq)
216 : {
217 0 : struct tevent_req *req = NULL;
218 0 : struct ipa_sudo_smart_refresh_state *state = NULL;
219 : int ret;
220 :
221 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
222 0 : state = tevent_req_data(req, struct ipa_sudo_smart_refresh_state);
223 :
224 0 : ret = ipa_sudo_refresh_recv(subreq, &state->dp_error, NULL);
225 0 : talloc_zfree(subreq);
226 0 : if (ret != EOK || state->dp_error != DP_ERR_OK) {
227 : goto done;
228 : }
229 :
230 0 : DEBUG(SSSDBG_TRACE_FUNC, "Successful smart refresh of sudo rules\n");
231 :
232 : done:
233 0 : if (ret != EOK) {
234 0 : tevent_req_error(req, ret);
235 0 : return;
236 : }
237 :
238 0 : tevent_req_done(req);
239 : }
240 :
241 0 : int ipa_sudo_smart_refresh_recv(struct tevent_req *req,
242 : int *dp_error)
243 : {
244 0 : struct ipa_sudo_smart_refresh_state *state = NULL;
245 0 : state = tevent_req_data(req, struct ipa_sudo_smart_refresh_state);
246 :
247 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
248 :
249 0 : *dp_error = state->dp_error;
250 :
251 0 : return EOK;
252 : }
253 :
254 : struct ipa_sudo_rules_refresh_state {
255 : size_t num_rules;
256 : int dp_error;
257 : bool deleted;
258 : };
259 :
260 : static void ipa_sudo_rules_refresh_done(struct tevent_req *subreq);
261 :
262 : struct tevent_req *
263 0 : ipa_sudo_rules_refresh_send(TALLOC_CTX *mem_ctx,
264 : struct tevent_context *ev,
265 : struct ipa_sudo_ctx *sudo_ctx,
266 : char **rules)
267 : {
268 : TALLOC_CTX *tmp_ctx;
269 : struct ipa_sudo_rules_refresh_state *state;
270 : struct tevent_req *subreq;
271 : struct tevent_req *req;
272 : char *search_filter;
273 : char *delete_filter;
274 : char *safe_rule;
275 : errno_t ret;
276 : int i;
277 :
278 0 : req = tevent_req_create(mem_ctx, &state, struct ipa_sudo_rules_refresh_state);
279 0 : if (req == NULL) {
280 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
281 0 : return NULL;
282 : }
283 :
284 0 : tmp_ctx = talloc_new(NULL);
285 0 : if (tmp_ctx == NULL) {
286 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
287 0 : ret = ENOMEM;
288 0 : goto immediately;
289 : }
290 :
291 0 : if (rules == NULL || rules[0] == NULL) {
292 0 : state->dp_error = DP_ERR_OK;
293 0 : state->num_rules = 0;
294 0 : state->deleted = false;
295 0 : ret = EOK;
296 0 : goto immediately;
297 : }
298 :
299 0 : search_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */
300 0 : delete_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */
301 :
302 : /* Download only selected rules from LDAP. */
303 : /* Remove all selected rules from cache. */
304 0 : for (i = 0; rules[i] != NULL; i++) {
305 0 : ret = sss_filter_sanitize(tmp_ctx, rules[i], &safe_rule);
306 0 : if (ret != EOK) {
307 0 : ret = ENOMEM;
308 0 : goto immediately;
309 : }
310 :
311 0 : search_filter = talloc_asprintf_append_buffer(search_filter, "(%s=%s)",
312 0 : sudo_ctx->sudorule_map[IPA_AT_SUDORULE_NAME].name,
313 : safe_rule);
314 0 : if (search_filter == NULL) {
315 0 : ret = ENOMEM;
316 0 : goto immediately;
317 : }
318 :
319 0 : delete_filter = talloc_asprintf_append_buffer(delete_filter, "(%s=%s)",
320 : SYSDB_NAME, safe_rule);
321 0 : if (delete_filter == NULL) {
322 0 : ret = ENOMEM;
323 0 : goto immediately;
324 : }
325 : }
326 :
327 0 : state->num_rules = i;
328 :
329 0 : search_filter = talloc_asprintf(tmp_ctx, "(|%s)", search_filter);
330 0 : if (search_filter == NULL) {
331 0 : ret = ENOMEM;
332 0 : goto immediately;
333 : }
334 :
335 0 : delete_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|%s))",
336 : SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC,
337 : delete_filter);
338 0 : if (delete_filter == NULL) {
339 0 : ret = ENOMEM;
340 0 : goto immediately;
341 : }
342 :
343 0 : subreq = ipa_sudo_refresh_send(req, ev, sudo_ctx, NULL, search_filter,
344 : delete_filter);
345 0 : if (subreq == NULL) {
346 0 : ret = ENOMEM;
347 0 : goto immediately;
348 : }
349 :
350 0 : tevent_req_set_callback(subreq, ipa_sudo_rules_refresh_done, req);
351 :
352 0 : ret = EOK;
353 :
354 : immediately:
355 0 : talloc_free(tmp_ctx);
356 :
357 0 : if (ret != EOK) {
358 0 : tevent_req_error(req, ret);
359 0 : tevent_req_post(req, ev);
360 : }
361 :
362 0 : return req;
363 : }
364 :
365 : static void
366 0 : ipa_sudo_rules_refresh_done(struct tevent_req *subreq)
367 : {
368 : struct ipa_sudo_rules_refresh_state *state;
369 0 : struct tevent_req *req = NULL;
370 : size_t downloaded_rules_num;
371 : int ret;
372 :
373 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
374 0 : state = tevent_req_data(req, struct ipa_sudo_rules_refresh_state);
375 :
376 0 : ret = ipa_sudo_refresh_recv(subreq, &state->dp_error, &downloaded_rules_num);
377 0 : talloc_zfree(subreq);
378 0 : if (ret != EOK || state->dp_error != DP_ERR_OK) {
379 : goto done;
380 : }
381 :
382 0 : state->deleted = downloaded_rules_num != state->num_rules ? true : false;
383 :
384 : done:
385 0 : if (ret != EOK) {
386 0 : tevent_req_error(req, ret);
387 0 : return;
388 : }
389 :
390 0 : tevent_req_done(req);
391 : }
392 :
393 : int
394 0 : ipa_sudo_rules_refresh_recv(struct tevent_req *req,
395 : int *dp_error,
396 : bool *deleted)
397 : {
398 : struct ipa_sudo_rules_refresh_state *state;
399 0 : state = tevent_req_data(req, struct ipa_sudo_rules_refresh_state);
400 :
401 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
402 :
403 0 : *dp_error = state->dp_error;
404 0 : *deleted = state->deleted;
405 :
406 0 : return EOK;
407 : }
408 :
409 : static struct tevent_req *
410 0 : ipa_sudo_ptask_full_refresh_send(TALLOC_CTX *mem_ctx,
411 : struct tevent_context *ev,
412 : struct be_ctx *be_ctx,
413 : struct be_ptask *be_ptask,
414 : void *pvt)
415 : {
416 : struct ipa_sudo_ctx *sudo_ctx;
417 0 : sudo_ctx = talloc_get_type(pvt, struct ipa_sudo_ctx);
418 :
419 0 : return ipa_sudo_full_refresh_send(mem_ctx, be_ctx->ev, sudo_ctx);
420 : }
421 :
422 : static errno_t
423 0 : ipa_sudo_ptask_full_refresh_recv(struct tevent_req *req)
424 : {
425 : int dp_error;
426 :
427 0 : return ipa_sudo_full_refresh_recv(req, &dp_error);
428 : }
429 :
430 : static struct tevent_req *
431 0 : ipa_sudo_ptask_smart_refresh_send(TALLOC_CTX *mem_ctx,
432 : struct tevent_context *ev,
433 : struct be_ctx *be_ctx,
434 : struct be_ptask *be_ptask,
435 : void *pvt)
436 : {
437 : struct ipa_sudo_ctx *sudo_ctx;
438 0 : sudo_ctx = talloc_get_type(pvt, struct ipa_sudo_ctx);
439 :
440 0 : return ipa_sudo_smart_refresh_send(mem_ctx, be_ctx->ev, sudo_ctx);
441 : }
442 :
443 : static errno_t
444 0 : ipa_sudo_ptask_smart_refresh_recv(struct tevent_req *req)
445 : {
446 : int dp_error;
447 :
448 0 : return ipa_sudo_smart_refresh_recv(req, &dp_error);
449 : }
450 :
451 : errno_t
452 0 : ipa_sudo_ptask_setup(struct be_ctx *be_ctx, struct ipa_sudo_ctx *sudo_ctx)
453 : {
454 0 : return sdap_sudo_ptask_setup_generic(be_ctx, sudo_ctx->id_ctx->opts->basic,
455 : ipa_sudo_ptask_full_refresh_send,
456 : ipa_sudo_ptask_full_refresh_recv,
457 : ipa_sudo_ptask_smart_refresh_send,
458 : ipa_sudo_ptask_smart_refresh_recv,
459 : sudo_ctx);
460 : }
|