1    	/*
2    	    SSSD
3    	
4    	    LDAP Identity Enumeration
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 "db/sysdb.h"
31   	#include "providers/ldap/ldap_common.h"
32   	#include "providers/ldap/sdap_async.h"
33   	
34   	extern struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
35   	                                               struct tevent_context *ev,
36   	                                               struct sdap_id_ctx *ctx);
37   	
38   	/* ==Enumeration-Task===================================================== */
39   	
40   	static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
41   	                                                 struct sdap_id_ctx *ctx);
42   	
43   	static void ldap_id_enumerate_reschedule(struct tevent_req *req);
44   	
45   	static void ldap_id_enumerate_timeout(struct tevent_context *ev,
46   	                                      struct tevent_timer *te,
47   	                                      struct timeval tv, void *pvt);
48   	
49   	static void ldap_id_enumerate_timer(struct tevent_context *ev,
50   	                                    struct tevent_timer *tt,
51   	                                    struct timeval tv, void *pvt)
52   	{
53   	    struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
54   	    struct tevent_timer *timeout;
55   	    struct tevent_req *req;
56   	    int delay;
57   	
58   	    if (be_is_offline(ctx->be)) {
59   	        DEBUG(4, ("Backend is marked offline, retry later!\n"));
60   	        /* schedule starting from now, not the last run */
61   	        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
62   	        tv = tevent_timeval_current_ofs(delay, 0);
63   	        ldap_id_enumerate_set_timer(ctx, tv);
64   	        return;
65   	    }
66   	
67   	    req = ldap_id_enumerate_send(ev, ctx);
68   	    if (!req) {
69   	        DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
70   	        /* schedule starting from now, not the last run */
71   	        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
72   	        tv = tevent_timeval_current_ofs(delay, 0);
73   	        ldap_id_enumerate_set_timer(ctx, tv);
74   	        return;
75   	    }
76   	    tevent_req_set_callback(req, ldap_id_enumerate_reschedule, ctx);
77   	
78   	    /* if enumeration takes so long, either we try to enumerate too
79   	     * frequently, or something went seriously wrong */
80   	    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
81   	    tv = tevent_timeval_current_ofs(delay, 0);
Event returned_pointer: Pointer "timeout" returned by "_tevent_add_timer(ctx->be->ev, req, tv, ldap_id_enumerate_timeout, req, &"ldap_id_enumerate_timeout", &"providers/ldap/ldap_id_enum.c:82")" is never used.
82   	    timeout = tevent_add_timer(ctx->be->ev, req, tv,
83   	                               ldap_id_enumerate_timeout, req);
84   	    return;
85   	}
86   	
87   	static void ldap_id_enumerate_timeout(struct tevent_context *ev,
88   	                                      struct tevent_timer *te,
89   	                                      struct timeval tv, void *pvt)
90   	{
91   	    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
92   	    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
93   	                                                       struct sdap_id_ctx);
94   	    int delay;
95   	
96   	    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
97   	    DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", delay));
98   	
99   	    tv = tevent_timeval_current_ofs(delay, 0);
100  	    ldap_id_enumerate_set_timer(ctx, tv);
101  	
102  	    talloc_zfree(req);
103  	}
104  	
105  	static void ldap_id_enumerate_reschedule(struct tevent_req *req)
106  	{
107  	    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
108  	                                                       struct sdap_id_ctx);
109  	    enum tevent_req_state tstate;
110  	    uint64_t err;
111  	    struct timeval tv;
112  	    int delay;
113  	
114  	    if (tevent_req_is_error(req, &tstate, &err)) {
115  	        /* On error schedule starting from now, not the last run */
116  	        tv = tevent_timeval_current();
117  	    } else {
118  	        tv = ctx->last_enum;
119  	    }
120  	    talloc_zfree(req);
121  	
122  	    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
123  	    tv = tevent_timeval_add(&tv, delay, 0);
124  	    ldap_id_enumerate_set_timer(ctx, tv);
125  	}
126  	
127  	
128  	
129  	int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
130  	{
131  	    struct tevent_timer *enum_task;
132  	
133  	    DEBUG(6, ("Scheduling next enumeration at %ld.%ld\n",
134  	              (long)tv.tv_sec, (long)tv.tv_usec));
135  	
136  	    enum_task = tevent_add_timer(ctx->be->ev, ctx,
137  	                                 tv, ldap_id_enumerate_timer, ctx);
138  	    if (!enum_task) {
139  	        DEBUG(0, ("FATAL: failed to setup enumeration task!\n"));
140  	        return EFAULT;
141  	    }
142  	
143  	    return EOK;
144  	}
145  	
146  	#define MAX_ENUM_RESTARTS 3
147  	
148  	struct global_enum_state {
149  	    struct tevent_context *ev;
150  	    struct sdap_id_ctx *ctx;
151  	
152  	    bool purge;
153  	    int restarts;
154  	};
155  	
156  	static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
157  	                                          struct tevent_context *ev,
158  	                                          struct sdap_id_ctx *ctx,
159  	                                          bool purge);
160  	static void ldap_id_enum_users_done(struct tevent_req *subreq);
161  	static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
162  	                                          struct tevent_context *ev,
163  	                                          struct sdap_id_ctx *ctx,
164  	                                          bool purge);
165  	static void ldap_id_enum_groups_done(struct tevent_req *subreq);
166  	static void ldap_id_enum_cleanup_done(struct tevent_req *subreq);
167  	static int ldap_id_enum_users_restart(struct tevent_req *req);
168  	static int ldap_id_enum_groups_restart(struct tevent_req *req);
169  	
170  	static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
171  	                                                 struct sdap_id_ctx *ctx)
172  	{
173  	    struct global_enum_state *state;
174  	    struct tevent_req *req, *subreq;
175  	    int t;
176  	
177  	    req = tevent_req_create(ctx, &state, struct global_enum_state);
178  	    if (!req) return NULL;
179  	
180  	    state->ev = ev;
181  	    state->ctx = ctx;
182  	    state->restarts = 0;
183  	
184  	    ctx->last_enum = tevent_timeval_current();
185  	
186  	    t = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
187  	    if ((ctx->last_purge.tv_sec + t) < ctx->last_enum.tv_sec) {
188  	        state->purge = true;
189  	    } else {
190  	        state->purge = false;
191  	    }
192  	
193  	    subreq = enum_users_send(state, ev, ctx, state->purge);
194  	    if (!subreq) {
195  	        talloc_zfree(req);
196  	        return NULL;
197  	    }
198  	    tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);
199  	
200  	    return req;
201  	}
202  	
203  	static void ldap_id_enum_users_done(struct tevent_req *subreq)
204  	{
205  	    struct tevent_req *req = tevent_req_callback_data(subreq,
206  	                                                      struct tevent_req);
207  	    struct global_enum_state *state = tevent_req_data(req,
208  	                                                 struct global_enum_state);
209  	    enum tevent_req_state tstate;
210  	    uint64_t err = 0;
211  	    int ret;
212  	
213  	    if (tevent_req_is_error(subreq, &tstate, &err)) {
214  	        if (tstate != TEVENT_REQ_USER_ERROR) {
215  	            err = EIO;
216  	        }
217  	        if (err != ENOENT) {
218  	            goto fail;
219  	        }
220  	    }
221  	    talloc_zfree(subreq);
222  	
223  	    subreq = enum_groups_send(state, state->ev, state->ctx, state->purge);
224  	    if (!subreq) {
225  	        goto fail;
226  	    }
227  	    tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
228  	
229  	    return;
230  	
231  	fail:
232  	    if (err) {
233  	        DEBUG(9, ("User enumeration failed with: (%d)[%s]\n",
234  	                  (int)err, strerror(err)));
235  	
236  	        if (sdap_check_gssapi_reconnect(state->ctx)) {
237  	            if (state->ctx->gsh) {
238  	                state->ctx->gsh->connected = false;
239  	            }
240  	            ret = ldap_id_enum_users_restart(req);
241  	            if (ret == EOK) return;
242  	        }
243  	        sdap_mark_offline(state->ctx);
244  	    }
245  	
246  	    DEBUG(1, ("Failed to enumerate users, retrying later!\n"));
247  	    tevent_req_done(req);
248  	}
249  	
250  	static void ldap_id_enum_groups_done(struct tevent_req *subreq)
251  	{
252  	    struct tevent_req *req = tevent_req_callback_data(subreq,
253  	                                                      struct tevent_req);
254  	    struct global_enum_state *state = tevent_req_data(req,
255  	                                                 struct global_enum_state);
256  	    enum tevent_req_state tstate;
257  	    uint64_t err = 0;
258  	    int ret;
259  	
260  	    if (tevent_req_is_error(subreq, &tstate, &err)) {
261  	        if (tstate != TEVENT_REQ_USER_ERROR) {
262  	            err = EIO;
263  	        }
264  	        if (err != ENOENT) {
265  	            goto fail;
266  	        }
267  	    }
268  	    talloc_zfree(subreq);
269  	
270  	    if (state->purge) {
271  	
272  	        subreq = ldap_id_cleanup_send(state, state->ev, state->ctx);
273  	        if (!subreq) {
274  	            goto fail;
275  	        }
276  	        tevent_req_set_callback(subreq, ldap_id_enum_cleanup_done, req);
277  	
278  	        return;
279  	    }
280  	
281  	    tevent_req_done(req);
282  	    return;
283  	
284  	fail:
285  	    /* check if credentials are expired otherwise go offline on failures */
286  	    if (sdap_check_gssapi_reconnect(state->ctx)) {
287  	        if (state->ctx->gsh) {
288  	            state->ctx->gsh->connected = false;
289  	        }
290  	        ret = ldap_id_enum_groups_restart(req);
291  	        if (ret == EOK) return;
292  	    }
293  	    sdap_mark_offline(state->ctx);
294  	    DEBUG(1, ("Failed to enumerate groups (%d [%s]), retrying later!\n",
295  	              (int)err, strerror(err)));
296  	    tevent_req_done(req);
297  	}
298  	
299  	static void ldap_id_enum_cleanup_done(struct tevent_req *subreq)
300  	{
301  	    struct tevent_req *req = tevent_req_callback_data(subreq,
302  	                                                      struct tevent_req);
303  	    talloc_zfree(subreq);
304  	    tevent_req_done(req);
305  	}
306  	
307  	static void ldap_id_enum_users_immediate(struct tevent_context *ctx,
308  	                                         struct tevent_immediate *im,
309  	                                         void *private_data)
310  	{
311  	    struct tevent_req *req = talloc_get_type(private_data,
312  	                                             struct tevent_req);
313  	    struct global_enum_state *state = tevent_req_data(req,
314  	                                                 struct global_enum_state);
315  	    struct tevent_req *subreq;
316  	
317  	    subreq = enum_users_send(state, state->ev, state->ctx, state->purge);
318  	    if (subreq == NULL) {
319  	        tevent_req_error(req, ENOMEM);
320  	        return;
321  	    }
322  	    tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);
323  	}
324  	
325  	static int ldap_id_enum_users_restart(struct tevent_req *req)
326  	{
327  	    struct global_enum_state *state = tevent_req_data(req,
328  	                                                 struct global_enum_state);
329  	    struct tevent_immediate *im;
330  	
331  	    state->restarts++;
332  	    if (state->restarts < MAX_ENUM_RESTARTS) {
333  	        return ELOOP;
334  	    }
335  	
336  	    im = tevent_create_immediate(req);
337  	    if (!im) {
338  	        return ENOMEM;
339  	    }
340  	
341  	    /* schedule a completely new event to avoid deep recursions */
342  	    tevent_schedule_immediate(im, state->ev,
343  	                              ldap_id_enum_users_immediate, req);
344  	
345  	    return EOK;
346  	}
347  	
348  	static void ldap_id_enum_groups_immediate(struct tevent_context *ctx,
349  	                                          struct tevent_immediate *im,
350  	                                          void *private_data)
351  	{
352  	    struct tevent_req *req = talloc_get_type(private_data,
353  	                                             struct tevent_req);
354  	    struct global_enum_state *state = tevent_req_data(req,
355  	                                                 struct global_enum_state);
356  	    struct tevent_req *subreq;
357  	
358  	    subreq = enum_groups_send(state, state->ev, state->ctx, state->purge);
359  	    if (subreq == NULL) {
360  	        tevent_req_error(req, ENOMEM);
361  	        return;
362  	    }
363  	    tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
364  	}
365  	
366  	static int ldap_id_enum_groups_restart(struct tevent_req *req)
367  	{
368  	    struct global_enum_state *state = tevent_req_data(req,
369  	                                                 struct global_enum_state);
370  	    struct tevent_immediate *im;
371  	
372  	    state->restarts++;
373  	    if (state->restarts < MAX_ENUM_RESTARTS) {
374  	        return ELOOP;
375  	    }
376  	
377  	    im = tevent_create_immediate(req);
378  	    if (!im) {
379  	        return ENOMEM;
380  	    }
381  	
382  	    /* schedule a completely new event to avoid deep recursions */
383  	    tevent_schedule_immediate(im, state->ev,
384  	                              ldap_id_enum_groups_immediate, req);
385  	
386  	    return EOK;
387  	}
388  	
389  	
390  	/* ==User-Enumeration===================================================== */
391  	
392  	struct enum_users_state {
393  	    struct tevent_context *ev;
394  	    struct sdap_id_ctx *ctx;
395  	
396  	    char *filter;
397  	    const char **attrs;
398  	};
399  	
400  	static void enum_users_connect_done(struct tevent_req *subreq);
401  	static void enum_users_op_done(struct tevent_req *subreq);
402  	
403  	static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
404  	                                          struct tevent_context *ev,
405  	                                          struct sdap_id_ctx *ctx,
406  	                                          bool purge)
407  	{
408  	    struct tevent_req *req, *subreq;
409  	    struct enum_users_state *state;
410  	    int ret;
411  	
412  	    req = tevent_req_create(memctx, &state, struct enum_users_state);
413  	    if (!req) return NULL;
414  	
415  	    state->ev = ev;
416  	    state->ctx = ctx;
417  	
418  	    if (ctx->max_user_timestamp && !purge) {
419  	
420  	        state->filter = talloc_asprintf(state,
421  	                               "(&(%s=*)(objectclass=%s)(%s>=%s)(!(%s=%s)))",
422  	                               ctx->opts->user_map[SDAP_AT_USER_NAME].name,
423  	                               ctx->opts->user_map[SDAP_OC_USER].name,
424  	                               ctx->opts->user_map[SDAP_AT_USER_MODSTAMP].name,
425  	                               ctx->max_user_timestamp,
426  	                               ctx->opts->user_map[SDAP_AT_USER_MODSTAMP].name,
427  	                               ctx->max_user_timestamp);
428  	    } else {
429  	        state->filter = talloc_asprintf(state,
430  	                               "(&(%s=*)(objectclass=%s))",
431  	                               ctx->opts->user_map[SDAP_AT_USER_NAME].name,
432  	                               ctx->opts->user_map[SDAP_OC_USER].name);
433  	    }
434  	    if (!state->filter) {
435  	        DEBUG(2, ("Failed to build filter\n"));
436  	        ret = ENOMEM;
437  	        goto fail;
438  	    }
439  	
440  	    /* TODO: handle attrs_type */
441  	    ret = build_attrs_from_map(state, ctx->opts->user_map,
442  	                               SDAP_OPTS_USER, &state->attrs);
443  	    if (ret != EOK) goto fail;
444  	
445  	    if (!sdap_connected(ctx)) {
446  	
447  	        /* FIXME: add option to decide if tls should be used
448  	         * or SASL/GSSAPI, etc ... */
449  	        subreq = sdap_cli_connect_send(state, ev, ctx->opts,
450  	                                       ctx->be, ctx->service,
451  	                                       &ctx->rootDSE);
452  	        if (!subreq) {
453  	            ret = ENOMEM;
454  	            goto fail;
455  	        }
456  	
457  	        tevent_req_set_callback(subreq, enum_users_connect_done, req);
458  	
459  	        return req;
460  	    }
461  	
462  	    subreq = sdap_get_users_send(state, state->ev,
463  	                                 state->ctx->be->domain,
464  	                                 state->ctx->be->sysdb,
465  	                                 state->ctx->opts,
466  	                                 state->ctx->gsh,
467  	                                 state->attrs, state->filter);
468  	    if (!subreq) {
469  	        ret = ENOMEM;
470  	        goto fail;
471  	    }
472  	    tevent_req_set_callback(subreq, enum_users_op_done, req);
473  	
474  	    return req;
475  	
476  	fail:
477  	    tevent_req_error(req, ret);
478  	    tevent_req_post(req, ev);
479  	    return req;
480  	}
481  	
482  	static void enum_users_connect_done(struct tevent_req *subreq)
483  	{
484  	    struct tevent_req *req = tevent_req_callback_data(subreq,
485  	                                                      struct tevent_req);
486  	    struct enum_users_state *state = tevent_req_data(req,
487  	                                                     struct enum_users_state);
488  	    int ret;
489  	
490  	    ret = sdap_cli_connect_recv(subreq, state->ctx,
491  	                                &state->ctx->gsh, &state->ctx->rootDSE);
492  	    talloc_zfree(subreq);
493  	    if (ret) {
494  	        if (ret == ENOTSUP) {
495  	            DEBUG(0, ("Authentication mechanism not Supported by server"));
496  	        }
497  	        tevent_req_error(req, ret);
498  	        return;
499  	    }
500  	
501  	    subreq = sdap_get_users_send(state, state->ev,
502  	                                 state->ctx->be->domain,
503  	                                 state->ctx->be->sysdb,
504  	                                 state->ctx->opts, state->ctx->gsh,
505  	                                 state->attrs, state->filter);
506  	    if (!subreq) {
507  	        tevent_req_error(req, ENOMEM);
508  	        return;
509  	    }
510  	    tevent_req_set_callback(subreq, enum_users_op_done, req);
511  	}
512  	
513  	static void enum_users_op_done(struct tevent_req *subreq)
514  	{
515  	    struct tevent_req *req = tevent_req_callback_data(subreq,
516  	                                                      struct tevent_req);
517  	    struct enum_users_state *state = tevent_req_data(req,
518  	                                                     struct enum_users_state);
519  	    char *timestamp;
520  	    int ret;
521  	
522  	    ret = sdap_get_users_recv(subreq, state, &timestamp);
523  	    talloc_zfree(subreq);
524  	    if (ret) {
525  	        tevent_req_error(req, ret);
526  	        return;
527  	    }
528  	
529  	    if (timestamp) {
530  	        talloc_zfree(state->ctx->max_user_timestamp);
531  	        state->ctx->max_user_timestamp = talloc_steal(state->ctx, timestamp);
532  	    }
533  	
534  	    DEBUG(4, ("Users higher timestamp: [%s]\n",
535  	              state->ctx->max_user_timestamp));
536  	
537  	    tevent_req_done(req);
538  	}
539  	
540  	/* =Group-Enumeration===================================================== */
541  	
542  	struct enum_groups_state {
543  	    struct tevent_context *ev;
544  	    struct sdap_id_ctx *ctx;
545  	
546  	    char *filter;
547  	    const char **attrs;
548  	};
549  	
550  	static void enum_groups_connect_done(struct tevent_req *subreq);
551  	static void enum_groups_op_done(struct tevent_req *subreq);
552  	
553  	static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
554  	                                          struct tevent_context *ev,
555  	                                          struct sdap_id_ctx *ctx,
556  	                                          bool purge)
557  	{
558  	    struct tevent_req *req, *subreq;
559  	    struct enum_groups_state *state;
560  	    const char *attr_name;
561  	    int ret;
562  	
563  	    req = tevent_req_create(memctx, &state, struct enum_groups_state);
564  	    if (!req) return NULL;
565  	
566  	    state->ev = ev;
567  	    state->ctx = ctx;
568  	
569  	    attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name;
570  	
571  	    if (ctx->max_group_timestamp && !purge) {
572  	
573  	        state->filter = talloc_asprintf(state,
574  	                              "(&(%s=*)(objectclass=%s)(%s>=%s)(!(%s=%s)))",
575  	                              ctx->opts->group_map[SDAP_AT_GROUP_NAME].name,
576  	                              ctx->opts->group_map[SDAP_OC_GROUP].name,
577  	                              ctx->opts->group_map[SDAP_AT_GROUP_MODSTAMP].name,
578  	                              ctx->max_group_timestamp,
579  	                              ctx->opts->group_map[SDAP_AT_GROUP_MODSTAMP].name,
580  	                              ctx->max_group_timestamp);
581  	    } else {
582  	        state->filter = talloc_asprintf(state,
583  	                              "(&(%s=*)(objectclass=%s))",
584  	                              ctx->opts->group_map[SDAP_AT_GROUP_NAME].name,
585  	                              ctx->opts->group_map[SDAP_OC_GROUP].name);
586  	    }
587  	    if (!state->filter) {
588  	        DEBUG(2, ("Failed to build filter\n"));
589  	        ret = ENOMEM;
590  	        goto fail;
591  	    }
592  	
593  	    /* TODO: handle attrs_type */
594  	    ret = build_attrs_from_map(state, ctx->opts->group_map,
595  	                               SDAP_OPTS_GROUP, &state->attrs);
596  	    if (ret != EOK) goto fail;
597  	
598  	    if (!sdap_connected(ctx)) {
599  	
600  	        /* FIXME: add option to decide if tls should be used
601  	         * or SASL/GSSAPI, etc ... */
602  	        subreq = sdap_cli_connect_send(state, ev, ctx->opts,
603  	                                       ctx->be, ctx->service,
604  	                                       &ctx->rootDSE);
605  	        if (!subreq) {
606  	            ret = ENOMEM;
607  	            goto fail;
608  	        }
609  	
610  	        tevent_req_set_callback(subreq, enum_groups_connect_done, req);
611  	
612  	        return req;
613  	    }
614  	
615  	    subreq = sdap_get_groups_send(state, state->ev,
616  	                                 state->ctx->be->domain,
617  	                                 state->ctx->be->sysdb,
618  	                                 state->ctx->opts, state->ctx->gsh,
619  	                                 state->attrs, state->filter);
620  	    if (!subreq) {
621  	        ret = ENOMEM;
622  	        goto fail;
623  	    }
624  	    tevent_req_set_callback(subreq, enum_groups_op_done, req);
625  	
626  	    return req;
627  	
628  	fail:
629  	    tevent_req_error(req, ret);
630  	    tevent_req_post(req, ev);
631  	    return req;
632  	}
633  	
634  	static void enum_groups_connect_done(struct tevent_req *subreq)
635  	{
636  	    struct tevent_req *req = tevent_req_callback_data(subreq,
637  	                                                      struct tevent_req);
638  	    struct enum_groups_state *state = tevent_req_data(req,
639  	                                                 struct enum_groups_state);
640  	    int ret;
641  	
642  	    ret = sdap_cli_connect_recv(subreq, state->ctx,
643  	                                &state->ctx->gsh, &state->ctx->rootDSE);
644  	    talloc_zfree(subreq);
645  	    if (ret) {
646  	        if (ret == ENOTSUP) {
647  	            DEBUG(0, ("Authentication mechanism not Supported by server"));
648  	        }
649  	        tevent_req_error(req, ret);
650  	        return;
651  	    }
652  	
653  	    subreq = sdap_get_groups_send(state, state->ev,
654  	                                  state->ctx->be->domain,
655  	                                  state->ctx->be->sysdb,
656  	                                  state->ctx->opts, state->ctx->gsh,
657  	                                  state->attrs, state->filter);
658  	    if (!subreq) {
659  	        tevent_req_error(req, ENOMEM);
660  	        return;
661  	    }
662  	    tevent_req_set_callback(subreq, enum_groups_op_done, req);
663  	}
664  	
665  	static void enum_groups_op_done(struct tevent_req *subreq)
666  	{
667  	    struct tevent_req *req = tevent_req_callback_data(subreq,
668  	                                                      struct tevent_req);
669  	    struct enum_groups_state *state = tevent_req_data(req,
670  	                                                 struct enum_groups_state);
671  	    char *timestamp;
672  	    int ret;
673  	
674  	    ret = sdap_get_groups_recv(subreq, state, &timestamp);
675  	    talloc_zfree(subreq);
676  	    if (ret) {
677  	        tevent_req_error(req, ret);
678  	        return;
679  	    }
680  	
681  	    if (timestamp) {
682  	        talloc_zfree(state->ctx->max_group_timestamp);
683  	        state->ctx->max_group_timestamp = talloc_steal(state->ctx, timestamp);
684  	    }
685  	
686  	    DEBUG(4, ("Groups higher timestamp: [%s]\n",
687  	              state->ctx->max_group_timestamp));
688  	
689  	    tevent_req_done(req);
690  	}
691