1 /*
2 SSSD
3
4 LDAP Identity Cleanup Functions
5
6 Authors:
7 Simo Sorce <ssorce@redhat.com>
8
9 Copyright (C) 2009 Red Hat
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include <errno.h>
26 #include <time.h>
27 #include <sys/time.h>
28
29 #include "util/util.h"
30 #include "util/find_uid.h"
31 #include "db/sysdb.h"
32 #include "providers/ldap/ldap_common.h"
33 #include "providers/ldap/sdap_async.h"
34
35 /* ==Cleanup-Task========================================================= */
36
37 struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
38 struct tevent_context *ev,
39 struct sdap_id_ctx *ctx);
40 static void ldap_id_cleanup_reschedule(struct tevent_req *req);
41
42 static void ldap_id_cleanup_timeout(struct tevent_context *ev,
43 struct tevent_timer *te,
44 struct timeval tv, void *pvt);
45
46 static void ldap_id_cleanup_timer(struct tevent_context *ev,
47 struct tevent_timer *tt,
48 struct timeval tv, void *pvt)
49 {
50 struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
51 struct tevent_timer *timeout;
52 struct tevent_req *req;
53 int delay;
54
55 if (be_is_offline(ctx->be)) {
56 DEBUG(4, ("Backend is marked offline, retry later!\n"));
57 /* schedule starting from now, not the last run */
58 delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
59 tv = tevent_timeval_current_ofs(delay, 0);
60 ldap_id_cleanup_set_timer(ctx, tv);
61 return;
62 }
63
64 req = ldap_id_cleanup_send(ctx, ev, ctx);
65 if (!req) {
66 DEBUG(1, ("Failed to schedule cleanup, retrying later!\n"));
67 /* schedule starting from now, not the last run */
68 delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
69 tv = tevent_timeval_current_ofs(delay, 0);
70 ldap_id_cleanup_set_timer(ctx, tv);
71 return;
72 }
73 tevent_req_set_callback(req, ldap_id_cleanup_reschedule, ctx);
74
75 /* if cleanup takes so long, either we try to cleanup too
76 * frequently, or something went seriously wrong */
77 delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
78 tv = tevent_timeval_current_ofs(delay, 0);
Event returned_pointer: Pointer "timeout" returned by "_tevent_add_timer(ctx->be->ev, req, tv, ldap_id_cleanup_timeout, req, &"ldap_id_cleanup_timeout", &"providers/ldap/ldap_id_cleanup.c:79")" is never used.
|
79 timeout = tevent_add_timer(ctx->be->ev, req, tv,
80 ldap_id_cleanup_timeout, req);
81 return;
82 }
83
84 static void ldap_id_cleanup_timeout(struct tevent_context *ev,
85 struct tevent_timer *te,
86 struct timeval tv, void *pvt)
87 {
88 struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
89 struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
90 struct sdap_id_ctx);
91 int delay;
92
93 delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
94 DEBUG(1, ("Cleanup timed out! Timeout too small? (%ds)!\n", delay));
95
96 tv = tevent_timeval_current_ofs(delay, 0);
97 ldap_id_cleanup_set_timer(ctx, tv);
98
99 talloc_zfree(req);
100 }
101
102 static void ldap_id_cleanup_reschedule(struct tevent_req *req)
103 {
104 struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
105 struct sdap_id_ctx);
106 enum tevent_req_state tstate;
107 uint64_t err;
108 struct timeval tv;
109 int delay;
110
111 if (tevent_req_is_error(req, &tstate, &err)) {
112 /* On error schedule starting from now, not the last run */
113 tv = tevent_timeval_current();
114 } else {
115 tv = ctx->last_purge;
116 }
117 talloc_zfree(req);
118
119 delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
120 tv = tevent_timeval_add(&tv, delay, 0);
121 ldap_id_cleanup_set_timer(ctx, tv);
122 }
123
124
125
126 int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
127 {
128 struct tevent_timer *cleanup_task;
129
130 DEBUG(6, ("Scheduling next cleanup at %ld.%ld\n",
131 (long)tv.tv_sec, (long)tv.tv_usec));
132
133 cleanup_task = tevent_add_timer(ctx->be->ev, ctx,
134 tv, ldap_id_cleanup_timer, ctx);
135 if (!cleanup_task) {
136 DEBUG(0, ("FATAL: failed to setup cleanup task!\n"));
137 return EFAULT;
138 }
139
140 return EOK;
141 }
142
143
144
145 struct global_cleanup_state {
146 struct tevent_context *ev;
147 struct sdap_id_ctx *ctx;
148 };
149
150 static struct tevent_req *cleanup_users_send(TALLOC_CTX *memctx,
151 struct tevent_context *ev,
152 struct sdap_id_ctx *ctx);
153 static void ldap_id_cleanup_users_done(struct tevent_req *subreq);
154 static struct tevent_req *cleanup_groups_send(TALLOC_CTX *memctx,
155 struct tevent_context *ev,
156 struct sysdb_ctx *sysdb,
157 struct sss_domain_info *domain);
158 static void ldap_id_cleanup_groups_done(struct tevent_req *subreq);
159
160 struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
161 struct tevent_context *ev,
162 struct sdap_id_ctx *ctx)
163 {
164 struct global_cleanup_state *state;
165 struct tevent_req *req, *subreq;
166
167 req = tevent_req_create(memctx, &state, struct global_cleanup_state);
168 if (!req) return NULL;
169
170 state->ev = ev;
171 state->ctx = ctx;
172
173 subreq = cleanup_users_send(state, ev, state->ctx);
174 if (!subreq) {
175 talloc_zfree(req);
176 return NULL;
177 }
178 tevent_req_set_callback(subreq, ldap_id_cleanup_users_done, req);
179
180 ctx->last_purge = tevent_timeval_current();
181
182 return req;
183 }
184
185 static void ldap_id_cleanup_users_done(struct tevent_req *subreq)
186 {
187 struct tevent_req *req = tevent_req_callback_data(subreq,
188 struct tevent_req);
189 struct global_cleanup_state *state = tevent_req_data(req,
190 struct global_cleanup_state);
191 enum tevent_req_state tstate;
192 uint64_t err = 0;
193
194 if (tevent_req_is_error(subreq, &tstate, &err)) {
195 if (tstate != TEVENT_REQ_USER_ERROR) {
196 err = EIO;
197 }
198 if (err != ENOENT) {
199 goto fail;
200 }
201 }
202 talloc_zfree(subreq);
203
204 subreq = cleanup_groups_send(state, state->ev,
205 state->ctx->be->sysdb,
206 state->ctx->be->domain);
207 if (!subreq) {
208 err = ENOMEM;
209 goto fail;
210 }
211 tevent_req_set_callback(subreq, ldap_id_cleanup_groups_done, req);
212
213 return;
214
215 fail:
216 DEBUG(1, ("Failed to cleanup users (%d [%s]), retrying later!\n",
217 (int)err, strerror(err)));
218 tevent_req_done(req);
219 }
220
221 static void ldap_id_cleanup_groups_done(struct tevent_req *subreq)
222 {
223 struct tevent_req *req = tevent_req_callback_data(subreq,
224 struct tevent_req);
225 enum tevent_req_state tstate;
226 uint64_t err;
227
228 if (tevent_req_is_error(subreq, &tstate, &err)) {
229 if (tstate != TEVENT_REQ_USER_ERROR) {
230 err = EIO;
231 }
232 if (err != ENOENT) {
233 goto fail;
234 }
235 }
236 talloc_zfree(subreq);
237
238 tevent_req_done(req);
239 return;
240
241 fail:
242 DEBUG(1, ("Failed to cleanup groups (%d [%s]), retrying later!\n",
243 (int)err, strerror(err)));
244 tevent_req_done(req);
245 }
246
247
248 /* ==User-Cleanup-Process================================================= */
249
250 struct cleanup_users_state {
251 struct tevent_context *ev;
252 struct sysdb_ctx *sysdb;
253 struct sss_domain_info *domain;
254 struct sdap_id_ctx *ctx;
255
256 struct sysdb_handle *handle;
257
258 hash_table_t *uid_table;
259
260 struct ldb_message **msgs;
261 size_t count;
262 int cur;
263 };
264
265 static void cleanup_users_process(struct tevent_req *subreq);
266 static int cleanup_users_logged_in(hash_table_t *table,
267 const struct ldb_message *msg);
268 static void cleanup_users_delete(struct tevent_req *req);
269 static void cleanup_users_next(struct tevent_req *req);
270 static void cleanup_users_delete_done(struct tevent_req *subreq);
271
272 static struct tevent_req *cleanup_users_send(TALLOC_CTX *memctx,
273 struct tevent_context *ev,
274 struct sdap_id_ctx *ctx)
275 {
276 struct tevent_req *req, *subreq;
277 struct cleanup_users_state *state;
278 static const char *attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL };
279 time_t now = time(NULL);
280 char *subfilter = NULL;
281 int account_cache_expiration;
282
283 req = tevent_req_create(memctx, &state, struct cleanup_users_state);
284 if (!req) {
285 return NULL;
286 }
287
288 state->ev = ev;
289 state->sysdb = ctx->be->sysdb;
290 state->domain = ctx->be->domain;
291 state->ctx = ctx;
292 state->msgs = NULL;
293 state->count = 0;
294 state->cur = 0;
295
296 account_cache_expiration = dp_opt_get_int(state->ctx->opts->basic,
297 SDAP_ACCOUNT_CACHE_EXPIRATION);
298 DEBUG(9, ("Cache expiration is set to %d days\n",
299 account_cache_expiration));
300
301 if (account_cache_expiration > 0) {
302 subfilter = talloc_asprintf(state,
303 "(&(!(%s=0))(%s<=%ld)(|(!(%s=*))(%s<=%ld)))",
304 SYSDB_CACHE_EXPIRE,
305 SYSDB_CACHE_EXPIRE,
306 (long) now,
307 SYSDB_LAST_LOGIN,
308 SYSDB_LAST_LOGIN,
309 (long) (now - (account_cache_expiration * 86400)));
310 } else {
311 subfilter = talloc_asprintf(state,
312 "(&(!(%s=0))(%s<=%ld)(!(%s=*)))",
313 SYSDB_CACHE_EXPIRE,
314 SYSDB_CACHE_EXPIRE,
315 (long) now,
316 SYSDB_LAST_LOGIN);
317 }
318 if (!subfilter) {
319 DEBUG(2, ("Failed to build filter\n"));
320 talloc_zfree(req);
321 return NULL;
322 }
323
324 subreq = sysdb_search_users_send(state, state->ev,
325 state->sysdb, NULL,
326 state->domain, subfilter, attrs);
327 if (!subreq) {
328 DEBUG(2, ("Failed to send entry search\n"));
329 talloc_zfree(req);
330 return NULL;
331 }
332 tevent_req_set_callback(subreq, cleanup_users_process, req);
333 return req;
334 }
335
336 static void cleanup_users_process(struct tevent_req *subreq)
337 {
338 struct tevent_req *req = tevent_req_callback_data(subreq,
339 struct tevent_req);
340 struct cleanup_users_state *state = tevent_req_data(req,
341 struct cleanup_users_state);
342 int ret;
343
344 ret = sysdb_search_users_recv(subreq, state, &state->count, &state->msgs);
345 talloc_zfree(subreq);
346 if (ret) {
347 if (ret == ENOENT) {
348 tevent_req_done(req);
349 return;
350 }
351 tevent_req_error(req, ret);
352 return;
353 }
354
355 DEBUG(4, ("Found %d expired user entries!\n", state->count));
356
357 if (state->count == 0) {
358 tevent_req_done(req);
359 }
360
361 ret = get_uid_table(state, &state->uid_table);
362 /* get_uid_table returns ENOSYS on non-Linux platforms. We proceed with
363 * the cleanup in that case
364 */
365 if (ret != EOK && ret != ENOSYS) {
366 tevent_req_error(req, ret);
367 return;
368 }
369
370 cleanup_users_delete(req);
371 }
372
373 static void cleanup_users_delete(struct tevent_req *req)
374 {
375 struct tevent_req *subreq;
376 struct cleanup_users_state *state = tevent_req_data(req,
377 struct cleanup_users_state);
378 const char *name;
379 int ret;
380
381 name = ldb_msg_find_attr_as_string(state->msgs[state->cur],
382 SYSDB_NAME, NULL);
383 if (!name) {
384 DEBUG(2, ("Entry %s has no Name Attribute ?!?\n",
385 ldb_dn_get_linearized(state->msgs[state->cur]->dn)));
386 tevent_req_error(req, EFAULT);
387 return;
388 }
389
390 if (state->uid_table) {
391 ret = cleanup_users_logged_in(state->uid_table, state->msgs[state->cur]);
392 if (ret == EOK) {
393 /* If the user is logged in, proceed to the next one */
394 DEBUG(5, ("User %s is still logged in, keeping his data\n", name));
395 cleanup_users_next(req);
396 return;
397 } else if (ret != ENOENT) {
398 tevent_req_error(req, ret);
399 return;
400 }
401 }
402
403 /* If not logged in or cannot check the table, delete him */
404 DEBUG(9, ("About to delete user %s\n", name));
405 subreq = sysdb_delete_user_send(state, state->ev,
406 state->sysdb, NULL,
407 state->domain, name, 0);
408 if (!subreq) {
409 tevent_req_error(req, ENOMEM);
410 return;
411 }
412 tevent_req_set_callback(subreq, cleanup_users_delete_done, req);
413 return;
414 }
415
416 static int cleanup_users_logged_in(hash_table_t *table,
417 const struct ldb_message *msg)
418 {
419 uid_t uid;
420 hash_key_t key;
421 hash_value_t value;
422 int ret;
423
424 uid = ldb_msg_find_attr_as_uint64(msg,
425 SYSDB_UIDNUM, 0);
426 if (!uid) {
427 DEBUG(2, ("Entry %s has no UID Attribute ?!?\n",
428 ldb_dn_get_linearized(msg->dn)));
429 return EFAULT;
430 }
431
432 key.type = HASH_KEY_ULONG;
433 key.ul = (unsigned long) uid;
434
435 ret = hash_lookup(table, &key, &value);
436 if (ret == HASH_SUCCESS) {
437 return EOK;
438 } else if (ret == HASH_ERROR_KEY_NOT_FOUND) {
439 return ENOENT;
440 }
441
442 return EIO;
443 }
444
445 static void cleanup_users_next(struct tevent_req *req)
446 {
447 struct cleanup_users_state *state = tevent_req_data(req,
448 struct cleanup_users_state);
449
450 state->cur++;
451 if (state->cur < state->count) {
452 cleanup_users_delete(req);
453 return;
454 }
455
456 tevent_req_done(req);
457 }
458
459 static void cleanup_users_delete_done(struct tevent_req *subreq)
460 {
461 struct tevent_req *req = tevent_req_callback_data(subreq,
462 struct tevent_req);
463 int ret;
464
465 ret = sysdb_delete_user_recv(subreq);
466 talloc_zfree(subreq);
467 if (ret) {
468 DEBUG(2, ("User delete returned %d (%s)\n",
469 ret, strerror(ret)));
470 tevent_req_error(req, ret);
471 return;
472 }
473
474 cleanup_users_next(req);
475 }
476
477 /* ==Group-Cleanup-Process================================================ */
478
479 struct cleanup_groups_state {
480 struct tevent_context *ev;
481 struct sysdb_ctx *sysdb;
482 struct sss_domain_info *domain;
483
484 struct sysdb_handle *handle;
485
486 struct ldb_message **msgs;
487 size_t count;
488 int cur;
489 };
490
491 static void cleanup_groups_process(struct tevent_req *subreq);
492 static void cleanup_groups_check_users(struct tevent_req *req);
493 static void cleanup_groups_check_users_done(struct tevent_req *subreq);
494 static void cleanup_groups_next(struct tevent_req *req);
495 static void cleanup_groups_delete(struct tevent_req *req);
496 static void cleanup_groups_delete_done(struct tevent_req *subreq);
497
498 static struct tevent_req *cleanup_groups_send(TALLOC_CTX *memctx,
499 struct tevent_context *ev,
500 struct sysdb_ctx *sysdb,
501 struct sss_domain_info *domain)
502 {
503 struct tevent_req *req, *subreq;
504 struct cleanup_groups_state *state;
505 static const char *attrs[] = { SYSDB_NAME, NULL };
506 time_t now = time(NULL);
507 char *subfilter;
508
509 req = tevent_req_create(memctx, &state, struct cleanup_groups_state);
510 if (!req) {
511 return NULL;
512 }
513
514 state->ev = ev;
515 state->sysdb = sysdb;
516 state->domain = domain;
517 state->msgs = NULL;
518 state->count = 0;
519 state->cur = 0;
520
521 subfilter = talloc_asprintf(state, "(&(!(%s=0))(%s<=%ld))",
522 SYSDB_CACHE_EXPIRE,
523 SYSDB_CACHE_EXPIRE, (long)now);
524 if (!subfilter) {
525 DEBUG(2, ("Failed to build filter\n"));
526 talloc_zfree(req);
527 return NULL;
528 }
529
530 subreq = sysdb_search_groups_send(state, state->ev,
531 state->sysdb, NULL,
532 state->domain, subfilter, attrs);
533 if (!subreq) {
534 DEBUG(2, ("Failed to send entry search\n"));
535 talloc_zfree(req);
536 return NULL;
537 }
538 tevent_req_set_callback(subreq, cleanup_groups_process, req);
539
540 return req;
541 }
542
543 static void cleanup_groups_process(struct tevent_req *subreq)
544 {
545 struct tevent_req *req = tevent_req_callback_data(subreq,
546 struct tevent_req);
547 struct cleanup_groups_state *state = tevent_req_data(req,
548 struct cleanup_groups_state);
549 int ret;
550
551 ret = sysdb_search_groups_recv(subreq, state, &state->count, &state->msgs);
552 talloc_zfree(subreq);
553 if (ret) {
554 if (ret == ENOENT) {
555 tevent_req_done(req);
556 return;
557 }
558 tevent_req_error(req, ret);
559 return;
560 }
561
562 DEBUG(4, ("Found %d expired group entries!\n", state->count));
563
564 if (state->count == 0) {
565 tevent_req_done(req);
566 }
567
568 cleanup_groups_check_users(req);
569 }
570
571 static void cleanup_groups_check_users(struct tevent_req *req)
572 {
573 struct cleanup_groups_state *state = tevent_req_data(req,
574 struct cleanup_groups_state);
575 struct tevent_req *subreq;
576 const char *subfilter;
577 const char *dn;
578
579 dn = ldb_dn_get_linearized(state->msgs[state->cur]->dn);
580 if (!dn) {
581 tevent_req_error(req, EINVAL);
582 return;
583 }
584
585 subfilter = talloc_asprintf(state, "(%s=%s)",
586 SYSDB_MEMBEROF, dn);
587 if (!subfilter) {
588 DEBUG(2, ("Failed to build filter\n"));
589 tevent_req_error(req, ENOMEM);
590 }
591
592 subreq = sysdb_search_users_send(state, state->ev,
593 state->sysdb, NULL,
594 state->domain, subfilter, NULL);
595 if (!subreq) {
596 DEBUG(2, ("Failed to send entry search\n"));
597 tevent_req_error(req, ENOMEM);
598 }
599 tevent_req_set_callback(subreq, cleanup_groups_check_users_done, req);
600 }
601
602 static void cleanup_groups_check_users_done(struct tevent_req *subreq)
603 {
604 struct tevent_req *req = tevent_req_callback_data(subreq,
605 struct tevent_req);
606 struct cleanup_groups_state *state = tevent_req_data(req,
607 struct cleanup_groups_state);
608 int ret;
609 struct ldb_message **msgs;
610 size_t count;
611
612 ret = sysdb_search_users_recv(subreq, state, &count, &msgs);
613 talloc_zfree(subreq);
614 if (ret != EOK) {
615 if (ret == ENOENT) {
616 cleanup_groups_delete(req);
617 return;
618 }
619 tevent_req_error(req, ret);
620 return;
621 }
622
623 cleanup_groups_next(req);
624 }
625
626 static void cleanup_groups_next(struct tevent_req *req)
627 {
628 struct cleanup_groups_state *state = tevent_req_data(req,
629 struct cleanup_groups_state);
630
631 state->cur++;
632 if (state->cur < state->count) {
633 cleanup_groups_check_users(req);
634 return;
635 }
636
637 tevent_req_done(req);
638 }
639
640 static void cleanup_groups_delete(struct tevent_req *req)
641 {
642 struct tevent_req *subreq;
643 struct cleanup_groups_state *state = tevent_req_data(req,
644 struct cleanup_groups_state);
645 const char *name;
646
647 name = ldb_msg_find_attr_as_string(state->msgs[state->cur],
648 SYSDB_NAME, NULL);
649 if (!name) {
650 DEBUG(2, ("Entry %s has no Name Attribute ?!?\n",
651 ldb_dn_get_linearized(state->msgs[state->cur]->dn)));
652 tevent_req_error(req, EFAULT);
653 return;
654 }
655
656 DEBUG(8, ("About to delete group %s\n", name));
657 subreq = sysdb_delete_group_send(state, state->ev,
658 state->sysdb, NULL,
659 state->domain, name, 0);
660 if (!subreq) {
661 tevent_req_error(req, ENOMEM);
662 return;
663 }
664 tevent_req_set_callback(subreq, cleanup_groups_delete_done, req);
665 }
666
667 static void cleanup_groups_delete_done(struct tevent_req *subreq)
668 {
669 struct tevent_req *req = tevent_req_callback_data(subreq,
670 struct tevent_req);
671 int ret;
672
673 ret = sysdb_delete_group_recv(subreq);
674 talloc_zfree(subreq);
675 if (ret) {
676 DEBUG(2, ("Group delete returned %d (%s)\n", ret, strerror(ret)));
677 tevent_req_error(req, ret);
678 return;
679 }
680
681 cleanup_groups_next(req);
682 }
683