1    	/*
2    	    SSSD
3    	
4    	    Async LDAP Helper routines
5    	
6    	    Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
7    	
8    	    This program is free software; you can redistribute it and/or modify
9    	    it under the terms of the GNU General Public License as published by
10   	    the Free Software Foundation; either version 3 of the License, or
11   	    (at your option) any later version.
12   	
13   	    This program is distributed in the hope that it will be useful,
14   	    but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   	    GNU General Public License for more details.
17   	
18   	    You should have received a copy of the GNU General Public License
19   	    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20   	*/
21   	
22   	#include "util/util.h"
23   	#include "db/sysdb.h"
24   	#include "providers/ldap/sdap_async_private.h"
25   	
26   	/* ==Save-User-Entry====================================================== */
27   	
28   	struct sdap_save_user_state {
29   	    struct tevent_context *ev;
30   	    struct sysdb_handle *handle;
31   	    struct sdap_options *opts;
32   	
33   	    struct sss_domain_info *dom;
34   	
35   	    const char *name;
36   	    struct sysdb_attrs *attrs;
37   	    char *timestamp;
38   	};
39   	
40   	static void sdap_save_user_done(struct tevent_req *subreq);
41   	
42   	    /* FIXME: support storing additional attributes */
43   	
44   	static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
45   	                                              struct tevent_context *ev,
46   	                                              struct sysdb_handle *handle,
47   	                                              struct sdap_options *opts,
48   	                                              struct sss_domain_info *dom,
49   	                                              struct sysdb_attrs *attrs,
50   	                                              bool is_initgr)
51   	{
52   	    struct tevent_req *req, *subreq;
53   	    struct sdap_save_user_state *state;
54   	    struct ldb_message_element *el;
55   	    int ret;
56   	    const char *pwd;
57   	    const char *gecos;
58   	    const char *homedir;
59   	    const char *shell;
60   	    long int l;
61   	    uid_t uid;
62   	    gid_t gid;
63   	    struct sysdb_attrs *user_attrs;
64   	    char *upn = NULL;
65   	    int i;
66   	    char *val = NULL;
67   	    int cache_timeout;
68   	
69   	    DEBUG(9, ("Save user\n"));
70   	
71   	    req = tevent_req_create(memctx, &state, struct sdap_save_user_state);
72   	    if (!req) return NULL;
73   	
74   	    state->ev = ev;
75   	    state->handle = handle;
76   	    state->dom = dom;
77   	    state->opts = opts;
78   	    state->attrs = attrs;
79   	    state->timestamp = NULL;
80   	
81   	    ret = sysdb_attrs_get_el(state->attrs,
82   	                             opts->user_map[SDAP_AT_USER_NAME].sys_name, &el);
83   	    if (ret) goto fail;
84   	    if (el->num_values == 0) {
85   	        ret = EINVAL;
86   	        goto fail;
87   	    }
88   	    state->name = (const char *)el->values[0].data;
89   	
90   	    ret = sysdb_attrs_get_el(state->attrs,
91   	                             opts->user_map[SDAP_AT_USER_PWD].sys_name, &el);
92   	    if (ret) goto fail;
93   	    if (el->num_values == 0) pwd = NULL;
94   	    else pwd = (const char *)el->values[0].data;
95   	
96   	    ret = sysdb_attrs_get_el(state->attrs,
97   	                             opts->user_map[SDAP_AT_USER_GECOS].sys_name, &el);
98   	    if (ret) goto fail;
99   	    if (el->num_values == 0) gecos = NULL;
100  	    else gecos = (const char *)el->values[0].data;
101  	
102  	    ret = sysdb_attrs_get_el(state->attrs,
103  	                             opts->user_map[SDAP_AT_USER_HOME].sys_name, &el);
104  	    if (ret) goto fail;
105  	    if (el->num_values == 0) homedir = NULL;
106  	    else homedir = (const char *)el->values[0].data;
107  	
108  	    ret = sysdb_attrs_get_el(state->attrs,
109  	                             opts->user_map[SDAP_AT_USER_SHELL].sys_name, &el);
110  	    if (ret) goto fail;
111  	    if (el->num_values == 0) shell = NULL;
112  	    else shell = (const char *)el->values[0].data;
113  	
114  	    ret = sysdb_attrs_get_el(state->attrs,
115  	                             opts->user_map[SDAP_AT_USER_UID].sys_name, &el);
116  	    if (ret) goto fail;
117  	    if (el->num_values == 0) {
118  	        DEBUG(1, ("no uid provided for [%s] in domain [%s].\n",
119  	                  state->name, dom->name));
120  	        ret = EINVAL;
121  	        goto fail;
122  	    }
123  	    errno = 0;
124  	    l = strtol((const char *)el->values[0].data, NULL, 0);
125  	    if (errno) {
126  	        ret = EINVAL;
127  	        goto fail;
128  	    }
129  	    uid = l;
130  	
131  	    /* check that the uid is valid for this domain */
132  	    if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) {
133  	            DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
134  	                      state->name));
135  	        ret = EINVAL;
136  	        goto fail;
137  	    }
138  	
139  	    ret = sysdb_attrs_get_el(state->attrs,
140  	                             opts->user_map[SDAP_AT_USER_GID].sys_name, &el);
141  	    if (ret) goto fail;
142  	    if (el->num_values == 0) {
143  	        DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
144  	                  state->name, dom->name));
145  	        ret = EINVAL;
146  	        goto fail;
147  	    }
148  	    errno = 0;
149  	    l = strtol((const char *)el->values[0].data, NULL, 0);
150  	    if (errno) {
151  	        ret = EINVAL;
152  	        goto fail;
153  	    }
154  	    gid = l;
155  	
156  	    /* check that the gid is valid for this domain */
157  	    if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
158  	            DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
159  	                      state->name));
160  	        ret = EINVAL;
161  	        goto fail;
162  	    }
163  	
164  	    user_attrs = sysdb_new_attrs(state);
165  	    if (user_attrs == NULL) {
166  	        ret = ENOMEM;
167  	        goto fail;
168  	    }
169  	
170  	    ret = sysdb_attrs_get_el(state->attrs, SYSDB_ORIG_DN, &el);
171  	    if (ret) {
172  	        goto fail;
173  	    }
174  	    if (el->num_values == 0) {
175  	        DEBUG(7, ("Original DN is not available for [%s].\n", state->name));
176  	    } else {
177  	        DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
178  	                  el->values[0].data, state->name));
179  	        ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_DN,
180  	                                     (const char *) el->values[0].data);
181  	        if (ret) {
182  	            goto fail;
183  	        }
184  	    }
185  	
186  	    ret = sysdb_attrs_get_el(state->attrs, SYSDB_MEMBEROF, &el);
187  	    if (ret) {
188  	        goto fail;
189  	    }
190  	    if (el->num_values == 0) {
191  	        DEBUG(7, ("Original memberOf is not available for [%s].\n",
192  	                  state->name));
193  	    } else {
194  	        DEBUG(7, ("Adding original memberOf attributes to [%s].\n",
195  	                  state->name));
196  	        for (i = 0; i < el->num_values; i++) {
197  	            ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF,
198  	                                         (const char *) el->values[i].data);
199  	            if (ret) {
200  	                goto fail;
201  	            }
202  	        }
203  	    }
204  	
205  	    ret = sysdb_attrs_get_el(state->attrs,
206  	                      opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name, &el);
207  	    if (ret) {
208  	        goto fail;
209  	    }
210  	    if (el->num_values == 0) {
211  	        DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
212  	                  state->name));
213  	    } else {
214  	        ret = sysdb_attrs_add_string(user_attrs,
215  	                          opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name,
216  	                          (const char*)el->values[0].data);
217  	        if (ret) {
218  	            goto fail;
219  	        }
220  	        state->timestamp = talloc_strdup(state,
221  	                                         (const char*)el->values[0].data);
222  	        if (!state->timestamp) {
223  	            ret = ENOMEM;
224  	            goto fail;
225  	        }
226  	    }
227  	
228  	    ret = sysdb_attrs_get_el(state->attrs,
229  	                             opts->user_map[SDAP_AT_USER_PRINC].sys_name, &el);
230  	    if (ret) {
231  	        goto fail;
232  	    }
233  	    if (el->num_values == 0) {
234  	        DEBUG(7, ("User principle is not available for [%s].\n", state->name));
235  	    } else {
236  	        upn = talloc_strdup(user_attrs, (const char*) el->values[0].data);
237  	        if (!upn) {
238  	            ret = ENOMEM;
239  	            goto fail;
240  	        }
241  	        if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {
242  	            make_realm_upper_case(upn);
243  	        }
244  	        DEBUG(7, ("Adding user principle [%s] to attributes of [%s].\n",
245  	                  upn, state->name));
246  	        ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn);
247  	        if (ret) {
248  	            goto fail;
249  	        }
250  	    }
251  	
252  	    for (i = SDAP_FIRST_EXTRA_USER_AT; i < SDAP_OPTS_USER; i++) {
253  	        ret = sysdb_attrs_get_el(state->attrs, opts->user_map[i].sys_name, &el);
254  	        if (ret) {
255  	            goto fail;
256  	        }
257  	        if (el->num_values > 0) {
258  	            DEBUG(9, ("Adding [%s]=[%s] to user attributes.\n",
259  	                      opts->user_map[i].sys_name,
260  	                      (const char*) el->values[0].data));
261  	            val = talloc_strdup(user_attrs, (const char*) el->values[0].data);
262  	            if (val == NULL) {
263  	                ret = ENOMEM;
264  	                goto fail;
265  	            }
266  	            ret = sysdb_attrs_add_string(user_attrs,
267  	                                         opts->user_map[i].sys_name, val);
268  	            if (ret) {
269  	                goto fail;
270  	            }
271  	        }
272  	    }
273  	
274  	    cache_timeout = dp_opt_get_int(opts->basic, SDAP_ENTRY_CACHE_TIMEOUT);
275  	
276  	    if (is_initgr) {
277  	        ret = sysdb_attrs_add_time_t(user_attrs, SYSDB_INITGR_EXPIRE,
278  	                                     (cache_timeout ?
279  	                                      (time(NULL) + cache_timeout) : 0));
280  	        if (ret) {
281  	            goto fail;
282  	        }
283  	    }
284  	
285  	    DEBUG(6, ("Storing info for user %s\n", state->name));
286  	
287  	    subreq = sysdb_store_user_send(state, state->ev, state->handle,
288  	                                   state->dom, state->name, pwd,
289  	                                   uid, gid, gecos, homedir, shell,
290  	                                   user_attrs, cache_timeout);
291  	    if (!subreq) {
292  	        ret = ENOMEM;
293  	        goto fail;
294  	    }
295  	    tevent_req_set_callback(subreq, sdap_save_user_done, req);
296  	
297  	    return req;
298  	
299  	fail:
300  	    tevent_req_error(req, ret);
301  	    tevent_req_post(req, ev);
302  	    return req;
303  	}
304  	
305  	static void sdap_save_user_done(struct tevent_req *subreq)
306  	{
307  	    struct tevent_req *req = tevent_req_callback_data(subreq,
308  	                                                      struct tevent_req);
309  	    struct sdap_save_user_state *state = tevent_req_data(req,
310  	                                            struct sdap_save_user_state);
311  	    int ret;
312  	
313  	    ret = sysdb_store_user_recv(subreq);
314  	    talloc_zfree(subreq);
315  	    if (ret) {
316  	        DEBUG(2, ("Failed to save user %s\n", state->name));
317  	        tevent_req_error(req, ret);
318  	        return;
319  	    }
320  	
321  	    tevent_req_done(req);
322  	}
323  	
324  	static int sdap_save_user_recv(struct tevent_req *req,
325  	                               TALLOC_CTX *mem_ctx, char **timestamp)
326  	{
327  	    struct sdap_save_user_state *state = tevent_req_data(req,
328  	                                            struct sdap_save_user_state);
329  	
330  	    TEVENT_REQ_RETURN_ON_ERROR(req);
331  	
332  	    if (timestamp) {
333  	        *timestamp = talloc_steal(mem_ctx, state->timestamp);
334  	    }
335  	
336  	    return EOK;
337  	}
338  	
339  	
340  	/* ==Generic-Function-to-save-multiple-users============================= */
341  	
342  	struct sdap_save_users_state {
343  	    struct tevent_context *ev;
344  	    struct sysdb_ctx *sysdb;
345  	    struct sdap_options *opts;
346  	    struct sss_domain_info *dom;
347  	
348  	    struct sysdb_attrs **users;
349  	    int count;
350  	    int cur;
351  	
352  	    struct sysdb_handle *handle;
353  	
354  	    char *higher_timestamp;
355  	};
356  	
357  	static void sdap_save_users_trans(struct tevent_req *subreq);
358  	static void sdap_save_users_store(struct tevent_req *req);
359  	static void sdap_save_users_process(struct tevent_req *subreq);
360  	struct tevent_req *sdap_save_users_send(TALLOC_CTX *memctx,
361  	                                         struct tevent_context *ev,
362  	                                         struct sss_domain_info *dom,
363  	                                         struct sysdb_ctx *sysdb,
364  	                                         struct sdap_options *opts,
365  	                                         struct sysdb_attrs **users,
366  	                                         int num_users)
367  	{
368  	    struct tevent_req *req, *subreq;
369  	    struct sdap_save_users_state *state;
370  	
371  	    req = tevent_req_create(memctx, &state, struct sdap_save_users_state);
372  	    if (!req) return NULL;
373  	
374  	    state->ev = ev;
375  	    state->opts = opts;
376  	    state->sysdb = sysdb;
377  	    state->dom = dom;
378  	    state->users = users;
379  	    state->count = num_users;
380  	    state->cur = 0;
381  	    state->handle = NULL;
382  	    state->higher_timestamp = NULL;
383  	
384  	    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
385  	    if (!subreq) {
386  	        tevent_req_error(req, ENOMEM);
387  	        tevent_req_post(req, ev);
388  	        return req;
389  	    }
390  	    tevent_req_set_callback(subreq, sdap_save_users_trans, req);
391  	
392  	    return req;
393  	}
394  	
395  	static void sdap_save_users_trans(struct tevent_req *subreq)
396  	{
397  	    struct tevent_req *req;
398  	    struct sdap_save_users_state *state;
399  	    int ret;
400  	
401  	    req = tevent_req_callback_data(subreq, struct tevent_req);
402  	    state = tevent_req_data(req, struct sdap_save_users_state);
403  	
404  	    ret = sysdb_transaction_recv(subreq, state, &state->handle);
405  	    talloc_zfree(subreq);
406  	    if (ret) {
407  	        tevent_req_error(req, ret);
408  	        return;
409  	    }
410  	
411  	    sdap_save_users_store(req);
412  	}
413  	
414  	static void sdap_save_users_store(struct tevent_req *req)
415  	{
416  	    struct tevent_req *subreq;
417  	    struct sdap_save_users_state *state;
418  	
419  	    state = tevent_req_data(req, struct sdap_save_users_state);
420  	
421  	    subreq = sdap_save_user_send(state, state->ev, state->handle,
422  	                                  state->opts, state->dom,
423  	                                  state->users[state->cur], false);
424  	    if (!subreq) {
425  	        tevent_req_error(req, ENOMEM);
426  	        return;
427  	    }
428  	    tevent_req_set_callback(subreq, sdap_save_users_process, req);
429  	}
430  	
431  	static void sdap_save_users_process(struct tevent_req *subreq)
432  	{
433  	    struct tevent_req *req;
434  	    struct sdap_save_users_state *state;
435  	    char *timestamp = NULL;
436  	    int ret;
437  	
438  	    req = tevent_req_callback_data(subreq, struct tevent_req);
439  	    state = tevent_req_data(req, struct sdap_save_users_state);
440  	
441  	    ret = sdap_save_user_recv(subreq, state, &timestamp);
442  	    talloc_zfree(subreq);
443  	
444  	    /* Do not fail completely on errors.
445  	     * Just report the failure to save and go on */
446  	    if (ret) {
447  	        DEBUG(2, ("Failed to store user %d. Ignoring.\n", state->cur));
448  	    } else {
449  	        DEBUG(9, ("User %d processed!\n", state->cur));
450  	    }
451  	
452  	    if (timestamp) {
453  	        if (state->higher_timestamp) {
454  	            if (strcmp(timestamp, state->higher_timestamp) > 0) {
455  	                talloc_zfree(state->higher_timestamp);
456  	                state->higher_timestamp = timestamp;
457  	            } else {
458  	                talloc_zfree(timestamp);
459  	            }
460  	        } else {
461  	            state->higher_timestamp = timestamp;
462  	        }
463  	    }
464  	
465  	    state->cur++;
466  	    if (state->cur < state->count) {
467  	        sdap_save_users_store(req);
468  	    } else {
469  	        subreq = sysdb_transaction_commit_send(state, state->ev,
470  	                                               state->handle);
471  	        if (!subreq) {
472  	            tevent_req_error(req, ENOMEM);
473  	            return;
474  	        }
475  	        /* sysdb_transaction_complete will call tevent_req_done(req) */
476  	        tevent_req_set_callback(subreq, sysdb_transaction_complete, req);
477  	    }
478  	}
479  	
480  	static int sdap_save_users_recv(struct tevent_req *req,
481  	                                TALLOC_CTX *mem_ctx, char **timestamp)
482  	{
483  	    struct sdap_save_users_state *state  = tevent_req_data(req,
484  	                                               struct sdap_save_users_state);
485  	
486  	    TEVENT_REQ_RETURN_ON_ERROR(req);
487  	
488  	    if (timestamp) {
489  	        *timestamp = talloc_steal(mem_ctx, state->higher_timestamp);
490  	    }
491  	
492  	    return EOK;
493  	}
494  	
495  	
496  	/* ==Search-Users-with-filter============================================= */
497  	
498  	struct sdap_get_users_state {
499  	    struct tevent_context *ev;
500  	    struct sdap_options *opts;
501  	    struct sdap_handle *sh;
502  	    struct sss_domain_info *dom;
503  	    struct sysdb_ctx *sysdb;
504  	    const char **attrs;
505  	    const char *filter;
506  	
507  	    char *higher_timestamp;
508  	    struct sysdb_attrs **users;
509  	    size_t count;
510  	};
511  	
512  	static void sdap_get_users_process(struct tevent_req *subreq);
513  	static void sdap_get_users_done(struct tevent_req *subreq);
514  	
515  	struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
516  	                                       struct tevent_context *ev,
517  	                                       struct sss_domain_info *dom,
518  	                                       struct sysdb_ctx *sysdb,
519  	                                       struct sdap_options *opts,
520  	                                       struct sdap_handle *sh,
521  	                                       const char **attrs,
522  	                                       const char *filter)
523  	{
524  	    struct tevent_req *req, *subreq;
525  	    struct sdap_get_users_state *state;
526  	
527  	    req = tevent_req_create(memctx, &state, struct sdap_get_users_state);
528  	    if (!req) return NULL;
529  	
530  	    state->ev = ev;
531  	    state->opts = opts;
532  	    state->dom = dom;
533  	    state->sh = sh;
534  	    state->sysdb = sysdb;
535  	    state->filter = filter;
536  	    state->attrs = attrs;
537  	    state->higher_timestamp = NULL;
538  	    state->users =  NULL;
539  	    state->count = 0;
540  	
541  	    subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
542  	                                   dp_opt_get_string(state->opts->basic,
543  	                                                     SDAP_USER_SEARCH_BASE),
544  	                                   LDAP_SCOPE_SUBTREE,
545  	                                   state->filter, state->attrs,
546  	                                   state->opts->user_map, SDAP_OPTS_USER);
547  	    if (!subreq) {
548  	        talloc_zfree(req);
549  	        return NULL;
550  	    }
551  	    tevent_req_set_callback(subreq, sdap_get_users_process, req);
552  	
553  	    return req;
554  	}
555  	
556  	static void sdap_get_users_process(struct tevent_req *subreq)
557  	{
558  	    struct tevent_req *req = tevent_req_callback_data(subreq,
559  	                                                      struct tevent_req);
560  	    struct sdap_get_users_state *state = tevent_req_data(req,
561  	                                            struct sdap_get_users_state);
562  	    int ret;
563  	
564  	    ret = sdap_get_generic_recv(subreq, state,
565  	                                &state->count, &state->users);
566  	    talloc_zfree(subreq);
567  	    if (ret) {
568  	        tevent_req_error(req, ret);
569  	        return;
570  	    }
571  	
572  	    DEBUG(6, ("Search for users, returned %d results.\n", state->count));
573  	
574  	    if (state->count == 0) {
575  	        tevent_req_error(req, ENOENT);
576  	        return;
577  	    }
578  	
579  	    subreq = sdap_save_users_send(state, state->ev, state->dom,
580  	                                  state->sysdb, state->opts,
581  	                                  state->users, state->count);
582  	    if (!subreq) {
583  	        tevent_req_error(req, ENOMEM);
584  	        return;
585  	    }
586  	    tevent_req_set_callback(subreq, sdap_get_users_done, req);
587  	}
588  	
589  	static void sdap_get_users_done(struct tevent_req *subreq)
590  	{
591  	    struct tevent_req *req = tevent_req_callback_data(subreq,
592  	                                                      struct tevent_req);
593  	    struct sdap_get_users_state *state = tevent_req_data(req,
594  	                                            struct sdap_get_users_state);
595  	    int ret;
596  	
597  	    DEBUG(9, ("Saving %d Users - Done\n", state->count));
598  	
599  	    ret = sdap_save_users_recv(subreq, state, &state->higher_timestamp);
600  	    talloc_zfree(subreq);
601  	    if (ret) {
602  	        DEBUG(2, ("Failed to store users.\n"));
603  	        tevent_req_error(req, ret);
604  	        return;
605  	    }
606  	
607  	    tevent_req_done(req);
608  	}
609  	
610  	int sdap_get_users_recv(struct tevent_req *req,
611  	                        TALLOC_CTX *mem_ctx, char **timestamp)
612  	{
613  	    struct sdap_get_users_state *state = tevent_req_data(req,
614  	                                            struct sdap_get_users_state);
615  	
616  	    TEVENT_REQ_RETURN_ON_ERROR(req);
617  	
618  	    if (timestamp) {
619  	        *timestamp = talloc_steal(mem_ctx, state->higher_timestamp);
620  	    }
621  	
622  	    return EOK;
623  	}
624  	
625  	/* ==Group-Parsing Routines=============================================== */
626  	
627  	struct sdap_orig_entry_state {
628  	    int done;
629  	};
630  	
631  	static void sdap_find_entry_by_origDN_done(struct tevent_req *req)
632  	{
633  	    struct sdap_orig_entry_state *state = tevent_req_callback_data(req,
634  	                                               struct sdap_orig_entry_state);
635  	    state->done = 1;
636  	}
637  	
638  	/* WARNING: this is a sync routine for now */
639  	static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx,
640  	                                     struct tevent_context *ev,
641  	                                     struct sysdb_handle *handle,
642  	                                     struct sss_domain_info *domain,
643  	                                     const char *orig_dn,
644  	                                     char **localdn)
645  	{
646  	    struct tevent_req *req;
647  	    struct sdap_orig_entry_state *state;
648  	    static const char *attrs[] = { NULL };
649  	    struct ldb_dn *base_dn;
650  	    char *filter;
651  	    struct ldb_message **msgs;
652  	    size_t num_msgs;
653  	    int ret;
654  	
655  	    state = talloc_zero(memctx, struct sdap_orig_entry_state);
656  	    if (!state) {
657  	        ret = ENOMEM;
658  	        goto done;
659  	    }
660  	
661  	    filter = talloc_asprintf(state, "%s=%s", SYSDB_ORIG_DN, orig_dn);
662  	    if (!filter) {
663  	        ret = ENOMEM;
664  	        goto done;
665  	    }
666  	
667  	    base_dn = sysdb_domain_dn(sysdb_handle_get_ctx(handle),
668  	                              state, domain->name);
669  	    if (!base_dn) {
670  	        ret = ENOMEM;
671  	        goto done;
672  	    }
673  	
674  	    req = sysdb_search_entry_send(state, ev, handle, base_dn,
675  	                                  LDB_SCOPE_SUBTREE, filter, attrs);
676  	    if (!req) {
677  	        ret = ENOMEM;
678  	        goto done;
679  	    }
680  	    tevent_req_set_callback(req, sdap_find_entry_by_origDN_done, state);
681  	
682  	    /* WARNING: SYNC LOOP HERE */
683  	    tevent_loop_allow_nesting(ev);
684  	    while (state->done == 0) {
685  	        tevent_loop_once(ev);
686  	    }
687  	
688  	    ret = sysdb_search_entry_recv(req, state, &num_msgs, &msgs);
689  	    if (ret) {
690  	        goto done;
691  	    }
692  	    if (num_msgs != 1) {
693  	        ret = ENOENT;
694  	        goto done;
695  	    }
696  	
697  	    *localdn = talloc_strdup(memctx, ldb_dn_get_linearized(msgs[0]->dn));
698  	    if (!*localdn) {
699  	        ret = ENOENT;
700  	        goto done;
701  	    }
702  	
703  	    ret = EOK;
704  	
705  	done:
706  	    talloc_zfree(state);
707  	    return ret;
708  	}
709  	
710  	static int sdap_fill_memberships(struct sysdb_attrs *group_attrs,
711  	                                 struct tevent_context *ev,
712  	                                 struct sysdb_handle *handle,
713  	                                 struct sdap_options *opts,
714  	                                 struct sss_domain_info *domain,
715  	                                 struct ldb_val *values,
716  	                                 int num_values)
717  	{
718  	    struct ldb_message_element *el;
719  	    int i, j;
720  	    int ret;
721  	
722  	    switch (opts->schema_type) {
723  	    case SDAP_SCHEMA_RFC2307:
724  	        DEBUG(9, ("[RFC2307 Schema]\n"));
725  	
726  	        ret = sysdb_attrs_users_from_ldb_vals(group_attrs, SYSDB_MEMBER,
727  	                                              domain->name,
728  	                                              values, num_values);
729  	        if (ret) {
730  	            goto done;
731  	        }
732  	
733  	        break;
734  	
735  	    case SDAP_SCHEMA_RFC2307BIS:
736  	    case SDAP_SCHEMA_IPA_V1:
737  	    case SDAP_SCHEMA_AD:
738  	        DEBUG(9, ("[IPA or AD Schema]\n"));
739  	
740  	        ret = sysdb_attrs_get_el(group_attrs, SYSDB_MEMBER, &el);
741  	        if (ret) {
742  	            goto done;
743  	        }
744  	
745  	        /* Just allocate both big enough to contain all members for now */
746  	        el->values = talloc_realloc(el, el->values, struct ldb_val,
747  	                                    el->num_values + num_values);
748  	        if (!el->values) {
749  	            ret = ENOMEM;
750  	            goto done;
751  	        }
752  	
753  	        for (i = 0, j = el->num_values; i < num_values; i++) {
754  	
755  	            /* sync search entry with this as origDN */
756  	            ret = sdap_find_entry_by_origDN(el->values, ev,
757  	                                            handle, domain,
758  	                                            (char *)values[i].data,
759  	                                            (char **)&el->values[j].data);
760  	            if (ret != EOK) {
761  	                if (ret != ENOENT) {
762  	                    goto done;
763  	                }
764  	
765  	                DEBUG(7, ("    member #%d (%s): not found!\n",
766  	                          i, (char *)values[i].data));
767  	            } else {
768  	                DEBUG(7, ("    member #%d (%s): [%s]\n",
769  	                          i, (char *)values[i].data,
770  	                          (char *)el->values[j].data));
771  	
772  	                el->values[j].length = strlen((char *)el->values[j].data);
773  	                j++;
774  	            }
775  	        }
776  	        el->num_values = j;
777  	
778  	        break;
779  	
780  	    default:
781  	        DEBUG(0, ("FATAL ERROR: Unhandled schema type! (%d)\n",
782  	                  opts->schema_type));
783  	        ret = EFAULT;
784  	        goto done;
785  	    }
786  	
787  	    ret = EOK;
788  	
789  	done:
790  	    return ret;
791  	}
792  	
793  	/* ==Save-Group-Entry===================================================== */
794  	
795  	struct sdap_save_group_state {
796  	    struct tevent_context *ev;
797  	    struct sysdb_handle *handle;
798  	    struct sdap_options *opts;
799  	
800  	    struct sss_domain_info *dom;
801  	
802  	    const char *name;
803  	    char *timestamp;
804  	};
805  	
806  	static void sdap_save_group_done(struct tevent_req *subreq);
807  	
808  	    /* FIXME: support non legacy */
809  	    /* FIXME: support storing additional attributes */
810  	
811  	static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx,
812  	                                               struct tevent_context *ev,
813  	                                               struct sysdb_handle *handle,
814  	                                               struct sdap_options *opts,
815  	                                               struct sss_domain_info *dom,
816  	                                               struct sysdb_attrs *attrs,
817  	                                               bool store_members)
818  	{
819  	    struct tevent_req *req, *subreq;
820  	    struct sdap_save_group_state *state;
821  	    struct ldb_message_element *el;
822  	    struct sysdb_attrs *group_attrs;
823  	    long int l;
824  	    gid_t gid;
825  	    int ret;
826  	
827  	    req = tevent_req_create(memctx, &state, struct sdap_save_group_state);
828  	    if (!req) return NULL;
829  	
830  	    state->ev = ev;
831  	    state->handle = handle;
832  	    state->dom = dom;
833  	    state->opts = opts;
834  	    state->timestamp = NULL;
835  	
836  	    ret = sysdb_attrs_get_el(attrs,
837  	                          opts->group_map[SDAP_AT_GROUP_NAME].sys_name, &el);
838  	    if (ret) goto fail;
839  	    if (el->num_values == 0) {
840  	        ret = EINVAL;
841  	        goto fail;
842  	    }
843  	    state->name = (const char *)el->values[0].data;
844  	
845  	    ret = sysdb_attrs_get_el(attrs,
846  	                          opts->group_map[SDAP_AT_GROUP_GID].sys_name, &el);
847  	    if (ret) goto fail;
848  	    if (el->num_values == 0) {
849  	        DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
850  	                  state->name, dom->name));
851  	        ret = EINVAL;
852  	        goto fail;
853  	    }
854  	    errno = 0;
855  	    l = strtol((const char *)el->values[0].data, NULL, 0);
856  	    if (errno) {
857  	        ret = EINVAL;
858  	        goto fail;
859  	    }
860  	    gid = l;
861  	
862  	    /* check that the gid is valid for this domain */
863  	    if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
864  	            DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
865  	                      state->name));
866  	        ret = EINVAL;
867  	        goto fail;
868  	    }
869  	
870  	    group_attrs = sysdb_new_attrs(state);
871  	    if (!group_attrs) {
872  	        ret = ENOMEM;
873  	        goto fail;
874  	    }
875  	
876  	    ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
877  	    if (ret) {
878  	        goto fail;
879  	    }
880  	    if (el->num_values == 0) {
881  	        DEBUG(7, ("Original DN is not available for [%s].\n", state->name));
882  	    } else {
883  	        DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
884  	                  el->values[0].data, state->name));
885  	        ret = sysdb_attrs_add_string(group_attrs, SYSDB_ORIG_DN,
886  	                                     (const char *)el->values[0].data);
887  	        if (ret) {
888  	            goto fail;
889  	        }
890  	    }
891  	
892  	    ret = sysdb_attrs_get_el(attrs,
893  	                      opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name, &el);
894  	    if (ret) {
895  	        goto fail;
896  	    }
897  	    if (el->num_values == 0) {
898  	        DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
899  	                  state->name));
900  	    } else {
901  	        ret = sysdb_attrs_add_string(group_attrs,
902  	                          opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name,
903  	                          (const char*)el->values[0].data);
904  	        if (ret) {
905  	            goto fail;
906  	        }
907  	        state->timestamp = talloc_strdup(state,
908  	                                         (const char*)el->values[0].data);
909  	        if (!state->timestamp) {
910  	            ret = ENOMEM;
911  	            goto fail;
912  	        }
913  	    }
914  	
915  	    if (store_members) {
916  	        ret = sysdb_attrs_get_el(attrs,
917  	                        opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el);
918  	        if (ret != EOK) {
919  	            goto fail;
920  	        }
921  	        if (el->num_values == 0) {
922  	            DEBUG(7, ("No members for group [%s]\n", state->name));
923  	
924  	        } else {
925  	            DEBUG(7, ("Adding member users to group [%s]\n", state->name));
926  	
927  	            ret = sdap_fill_memberships(group_attrs, ev, handle, opts, dom,
928  	                                        el->values, el->num_values);
929  	            if (ret) {
930  	                goto fail;
931  	            }
932  	        }
933  	    }
934  	
935  	    DEBUG(6, ("Storing info for group %s\n", state->name));
936  	
937  	    subreq = sysdb_store_group_send(state, state->ev,
938  	                                    state->handle, state->dom,
939  	                                    state->name, gid,
940  	                                    group_attrs,
941  	                                    dp_opt_get_int(opts->basic,
942  	                                                   SDAP_ENTRY_CACHE_TIMEOUT));
943  	    if (!subreq) {
944  	        ret = ENOMEM;
945  	        goto fail;
946  	    }
947  	    tevent_req_set_callback(subreq, sdap_save_group_done, req);
948  	
949  	    return req;
950  	
951  	fail:
952  	    tevent_req_error(req, ret);
953  	    tevent_req_post(req, ev);
954  	    return req;
955  	}
956  	
957  	static void sdap_save_group_done(struct tevent_req *subreq)
958  	{
959  	    struct tevent_req *req = tevent_req_callback_data(subreq,
960  	                                                      struct tevent_req);
961  	    struct sdap_save_group_state *state = tevent_req_data(req,
962  	                                            struct sdap_save_group_state);
963  	    int ret;
964  	
965  	    ret = sysdb_store_group_recv(subreq);
966  	    talloc_zfree(subreq);
967  	    if (ret) {
968  	        DEBUG(2, ("Failed to save group %s [%d]\n", state->name, ret));
969  	        tevent_req_error(req, ret);
970  	        return;
971  	    }
972  	
973  	    tevent_req_done(req);
974  	}
975  	
976  	static int sdap_save_group_recv(struct tevent_req *req,
977  	                                TALLOC_CTX *mem_ctx, char **timestamp)
978  	{
979  	    struct sdap_save_group_state *state = tevent_req_data(req,
980  	                                            struct sdap_save_group_state);
981  	
982  	    TEVENT_REQ_RETURN_ON_ERROR(req);
983  	
984  	    if ( timestamp ) {
985  	        *timestamp = talloc_steal(mem_ctx, state->timestamp);
986  	    }
987  	
988  	    return EOK;
989  	}
990  	
991  	
992  	/* ==Save-Group-Memebrs=================================================== */
993  	
994  	struct sdap_save_grpmem_state {
995  	    struct tevent_context *ev;
996  	    struct sysdb_handle *handle;
997  	    struct sdap_options *opts;
998  	
999  	    struct sss_domain_info *dom;
1000 	
1001 	    const char *name;
1002 	};
1003 	
1004 	static void sdap_save_grpmem_done(struct tevent_req *subreq);
1005 	
1006 	    /* FIXME: support non legacy */
1007 	    /* FIXME: support storing additional attributes */
1008 	
1009 	static struct tevent_req *sdap_save_grpmem_send(TALLOC_CTX *memctx,
1010 	                                                struct tevent_context *ev,
1011 	                                                struct sysdb_handle *handle,
1012 	                                                struct sdap_options *opts,
1013 	                                                struct sss_domain_info *dom,
1014 	                                                struct sysdb_attrs *attrs)
1015 	{
1016 	    struct tevent_req *req, *subreq;
1017 	    struct sdap_save_grpmem_state *state;
1018 	    struct ldb_message_element *el;
1019 	    struct sysdb_attrs *group_attrs = NULL;
1020 	    int ret;
1021 	
1022 	    req = tevent_req_create(memctx, &state, struct sdap_save_grpmem_state);
1023 	    if (!req) return NULL;
1024 	
1025 	    state->ev = ev;
1026 	    state->handle = handle;
1027 	    state->dom = dom;
1028 	    state->opts = opts;
1029 	
1030 	    ret = sysdb_attrs_get_string(attrs,
1031 	                                opts->group_map[SDAP_AT_GROUP_NAME].sys_name,
1032 	                                &state->name);
1033 	    if (ret != EOK) {
1034 	        goto fail;
1035 	    }
1036 	
1037 	    ret = sysdb_attrs_get_el(attrs,
1038 	                    opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el);
1039 	    if (ret != EOK) {
1040 	        goto fail;
1041 	    }
1042 	    if (el->num_values == 0) {
1043 	        DEBUG(7, ("No members for group [%s]\n", state->name));
1044 	
1045 	    } else {
1046 	        DEBUG(7, ("Adding member users to group [%s]\n", state->name));
1047 	
1048 	        group_attrs = sysdb_new_attrs(state);
1049 	        if (!group_attrs) {
1050 	            ret = ENOMEM;
1051 	            goto fail;
1052 	        }
1053 	
1054 	        ret = sdap_fill_memberships(group_attrs, ev, handle, opts, dom,
1055 	                                    el->values, el->num_values);
1056 	        if (ret) {
1057 	            goto fail;
1058 	        }
1059 	    }
1060 	
1061 	    DEBUG(6, ("Storing members for group %s\n", state->name));
1062 	
1063 	    subreq = sysdb_store_group_send(state, state->ev,
1064 	                                    state->handle, state->dom,
1065 	                                    state->name, 0,
1066 	                                    group_attrs,
1067 	                                    dp_opt_get_int(opts->basic,
1068 	                                               SDAP_ENTRY_CACHE_TIMEOUT));
1069 	    if (!subreq) {
1070 	        ret = ENOMEM;
1071 	        goto fail;
1072 	    }
1073 	    tevent_req_set_callback(subreq, sdap_save_grpmem_done, req);
1074 	
1075 	    return req;
1076 	
1077 	fail:
1078 	    tevent_req_error(req, ret);
1079 	    tevent_req_post(req, ev);
1080 	    return req;
1081 	}
1082 	
1083 	static void sdap_save_grpmem_done(struct tevent_req *subreq)
1084 	{
1085 	    struct tevent_req *req = tevent_req_callback_data(subreq,
1086 	                                                      struct tevent_req);
1087 	    struct sdap_save_grpmem_state *state = tevent_req_data(req,
1088 	                                              struct sdap_save_grpmem_state);
1089 	    int ret;
1090 	
1091 	    ret = sysdb_store_group_recv(subreq);
1092 	    talloc_zfree(subreq);
1093 	    if (ret) {
1094 	        DEBUG(2, ("Failed to save group members for %s [%d]\n",
1095 	                  state->name, ret));
1096 	        tevent_req_error(req, ret);
1097 	        return;
1098 	    }
1099 	
1100 	    tevent_req_done(req);
1101 	}
1102 	
1103 	static int sdap_save_grpmem_recv(struct tevent_req *req)
1104 	{
1105 	    TEVENT_REQ_RETURN_ON_ERROR(req);
1106 	
1107 	    return EOK;
1108 	}
1109 	
1110 	
1111 	/* ==Generic-Function-to-save-multiple-groups============================= */
1112 	
1113 	struct sdap_save_groups_state {
1114 	    struct tevent_context *ev;
1115 	    struct sysdb_ctx *sysdb;
1116 	    struct sdap_options *opts;
1117 	    struct sss_domain_info *dom;
1118 	
1119 	    struct sysdb_attrs **groups;
1120 	    int count;
1121 	    int cur;
1122 	    bool twopass;
1123 	
1124 	    struct sysdb_handle *handle;
1125 	
1126 	    char *higher_timestamp;
1127 	};
1128 	
1129 	static void sdap_save_groups_trans(struct tevent_req *subreq);
1130 	static void sdap_save_groups_save(struct tevent_req *req);
1131 	static void sdap_save_groups_loop(struct tevent_req *subreq);
1132 	static void sdap_save_groups_mem_save(struct tevent_req *req);
1133 	static void sdap_save_groups_mem_loop(struct tevent_req *subreq);
1134 	struct tevent_req *sdap_save_groups_send(TALLOC_CTX *memctx,
1135 	                                         struct tevent_context *ev,
1136 	                                         struct sss_domain_info *dom,
1137 	                                         struct sysdb_ctx *sysdb,
1138 	                                         struct sdap_options *opts,
1139 	                                         struct sysdb_attrs **groups,
1140 	                                         int num_groups)
1141 	{
1142 	    struct tevent_req *req, *subreq;
1143 	    struct sdap_save_groups_state *state;
1144 	
1145 	    req = tevent_req_create(memctx, &state, struct sdap_save_groups_state);
1146 	    if (!req) return NULL;
1147 	
1148 	    state->ev = ev;
1149 	    state->opts = opts;
1150 	    state->sysdb = sysdb;
1151 	    state->dom = dom;
1152 	    state->groups = groups;
1153 	    state->count = num_groups;
1154 	    state->cur = 0;
1155 	    state->handle = NULL;
1156 	    state->higher_timestamp = NULL;
1157 	
1158 	    switch (opts->schema_type) {
1159 	    case SDAP_SCHEMA_RFC2307:
1160 	        state->twopass = false;
1161 	        break;
1162 	
1163 	    case SDAP_SCHEMA_RFC2307BIS:
1164 	    case SDAP_SCHEMA_IPA_V1:
1165 	    case SDAP_SCHEMA_AD:
1166 	        state->twopass = true;
1167 	        break;
1168 	
1169 	    default:
1170 	        tevent_req_error(req, EINVAL);
1171 	        tevent_req_post(req, ev);
1172 	        return req;
1173 	    }
1174 	
1175 	    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1176 	    if (!subreq) {
1177 	        tevent_req_error(req, ENOMEM);
1178 	        tevent_req_post(req, ev);
1179 	        return req;
1180 	    }
1181 	    tevent_req_set_callback(subreq, sdap_save_groups_trans, req);
1182 	
1183 	    return req;
1184 	}
1185 	
1186 	static void sdap_save_groups_trans(struct tevent_req *subreq)
1187 	{
1188 	    struct tevent_req *req;
1189 	    struct sdap_save_groups_state *state;
1190 	    int ret;
1191 	
1192 	    req = tevent_req_callback_data(subreq, struct tevent_req);
1193 	    state = tevent_req_data(req, struct sdap_save_groups_state);
1194 	
1195 	    ret = sysdb_transaction_recv(subreq, state, &state->handle);
1196 	    talloc_zfree(subreq);
1197 	    if (ret) {
1198 	        tevent_req_error(req, ret);
1199 	        return;
1200 	    }
1201 	
1202 	    sdap_save_groups_save(req);
1203 	}
1204 	
1205 	static void sdap_save_groups_save(struct tevent_req *req)
1206 	{
1207 	    struct tevent_req *subreq;
1208 	    struct sdap_save_groups_state *state;
1209 	
1210 	    state = tevent_req_data(req, struct sdap_save_groups_state);
1211 	
1212 	    /* if 2 pass savemembers = false */
1213 	    subreq = sdap_save_group_send(state, state->ev, state->handle,
1214 	                                  state->opts, state->dom,
1215 	                                  state->groups[state->cur],
1216 	                                  (!state->twopass));
1217 	    if (!subreq) {
1218 	        tevent_req_error(req, ENOMEM);
1219 	        return;
1220 	    }
1221 	    tevent_req_set_callback(subreq, sdap_save_groups_loop, req);
1222 	}
1223 	
1224 	static void sdap_save_groups_loop(struct tevent_req *subreq)
1225 	{
1226 	    struct tevent_req *req;
1227 	    struct sdap_save_groups_state *state;
1228 	    char *timestamp = NULL;
1229 	    int ret;
1230 	
1231 	    req = tevent_req_callback_data(subreq, struct tevent_req);
1232 	    state = tevent_req_data(req, struct sdap_save_groups_state);
1233 	
1234 	    ret = sdap_save_group_recv(subreq, state, &timestamp);
1235 	    talloc_zfree(subreq);
1236 	
1237 	    /* Do not fail completely on errors.
1238 	     * Just report the failure to save and go on */
1239 	    if (ret) {
1240 	        DEBUG(2, ("Failed to store group %d. Ignoring.\n", state->cur));
1241 	    } else {
1242 	        DEBUG(9, ("Group %d processed!\n", state->cur));
1243 	    }
1244 	
1245 	    if (timestamp) {
1246 	        if (state->higher_timestamp) {
1247 	            if (strcmp(timestamp, state->higher_timestamp) > 0) {
1248 	                talloc_zfree(state->higher_timestamp);
1249 	                state->higher_timestamp = timestamp;
1250 	            } else {
1251 	                talloc_zfree(timestamp);
1252 	            }
1253 	        } else {
1254 	            state->higher_timestamp = timestamp;
1255 	        }
1256 	    }
1257 	
1258 	    state->cur++;
1259 	    if (state->cur < state->count) {
1260 	
1261 	        sdap_save_groups_save(req);
1262 	
1263 	    } else if (state->twopass) {
1264 	
1265 	        state->cur = 0;
1266 	        sdap_save_groups_mem_save(req);
1267 	
1268 	    } else {
1269 	
1270 	        subreq = sysdb_transaction_commit_send(state, state->ev,
1271 	                                               state->handle);
1272 	        if (!subreq) {
1273 	            tevent_req_error(req, ENOMEM);
1274 	            return;
1275 	        }
1276 	        /* sysdb_transaction_complete will call tevent_req_done(req) */
1277 	        tevent_req_set_callback(subreq, sysdb_transaction_complete, req);
1278 	    }
1279 	}
1280 	
1281 	static void sdap_save_groups_mem_save(struct tevent_req *req)
1282 	{
1283 	    struct tevent_req *subreq;
1284 	    struct sdap_save_groups_state *state;
1285 	
1286 	    state = tevent_req_data(req, struct sdap_save_groups_state);
1287 	
1288 	    subreq = sdap_save_grpmem_send(state, state->ev, state->handle,
1289 	                                  state->opts, state->dom,
1290 	                                  state->groups[state->cur]);
1291 	    if (!subreq) {
1292 	        tevent_req_error(req, ENOMEM);
1293 	        return;
1294 	    }
1295 	    tevent_req_set_callback(subreq, sdap_save_groups_mem_loop, req);
1296 	}
1297 	
1298 	static void sdap_save_groups_mem_loop(struct tevent_req *subreq)
1299 	{
1300 	    struct tevent_req *req;
1301 	    struct sdap_save_groups_state *state;
1302 	    int ret;
1303 	
1304 	    req = tevent_req_callback_data(subreq, struct tevent_req);
1305 	    state = tevent_req_data(req, struct sdap_save_groups_state);
1306 	
1307 	    ret = sdap_save_grpmem_recv(subreq);
1308 	    talloc_zfree(subreq);
1309 	
1310 	    /* Do not fail completely on errors.
1311 	     * Just report the failure to save and go on */
1312 	    if (ret) {
1313 	        DEBUG(2, ("Failed to store group %d. Ignoring.\n", state->cur));
1314 	    }
1315 	
1316 	    state->cur++;
1317 	    if (state->cur < state->count) {
1318 	
1319 	        sdap_save_groups_mem_save(req);
1320 	
1321 	    } else {
1322 	
1323 	        subreq = sysdb_transaction_commit_send(state, state->ev,
1324 	                                               state->handle);
1325 	        if (!subreq) {
1326 	            tevent_req_error(req, ENOMEM);
1327 	            return;
1328 	        }
1329 	        /* sysdb_transaction_complete will call tevent_req_done(req) */
1330 	        tevent_req_set_callback(subreq, sysdb_transaction_complete, req);
1331 	    }
1332 	}
1333 	
1334 	static int sdap_save_groups_recv(struct tevent_req *req,
1335 	                                 TALLOC_CTX *mem_ctx, char **timestamp)
1336 	{
1337 	    struct sdap_save_groups_state *state = tevent_req_data(req,
1338 	                                              struct sdap_save_groups_state);
1339 	
1340 	    TEVENT_REQ_RETURN_ON_ERROR(req);
1341 	
1342 	    if (timestamp) {
1343 	        *timestamp = talloc_steal(mem_ctx, state->higher_timestamp);
1344 	    }
1345 	
1346 	    return EOK;
1347 	}
1348 	
1349 	
1350 	/* ==Search-Groups-with-filter============================================ */
1351 	
1352 	struct sdap_get_groups_state {
1353 	    struct tevent_context *ev;
1354 	    struct sdap_options *opts;
1355 	    struct sdap_handle *sh;
1356 	    struct sss_domain_info *dom;
1357 	    struct sysdb_ctx *sysdb;
1358 	    const char **attrs;
1359 	    const char *filter;
1360 	
1361 	    char *higher_timestamp;
1362 	    struct sysdb_attrs **groups;
1363 	    size_t count;
1364 	};
1365 	
1366 	static void sdap_get_groups_process(struct tevent_req *subreq);
1367 	static void sdap_get_groups_done(struct tevent_req *subreq);
1368 	
1369 	struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
1370 	                                       struct tevent_context *ev,
1371 	                                       struct sss_domain_info *dom,
1372 	                                       struct sysdb_ctx *sysdb,
1373 	                                       struct sdap_options *opts,
1374 	                                       struct sdap_handle *sh,
1375 	                                       const char **attrs,
1376 	                                       const char *filter)
1377 	{
1378 	    struct tevent_req *req, *subreq;
1379 	    struct sdap_get_groups_state *state;
1380 	
1381 	    req = tevent_req_create(memctx, &state, struct sdap_get_groups_state);
1382 	    if (!req) return NULL;
1383 	
1384 	    state->ev = ev;
1385 	    state->opts = opts;
1386 	    state->dom = dom;
1387 	    state->sh = sh;
1388 	    state->sysdb = sysdb;
1389 	    state->filter = filter;
1390 	    state->attrs = attrs;
1391 	    state->higher_timestamp = NULL;
1392 	    state->groups =  NULL;
1393 	    state->count = 0;
1394 	
1395 	    subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
1396 	                                   dp_opt_get_string(state->opts->basic,
1397 	                                                     SDAP_GROUP_SEARCH_BASE),
1398 	                                   LDAP_SCOPE_SUBTREE,
1399 	                                   state->filter, state->attrs,
1400 	                                   state->opts->group_map, SDAP_OPTS_GROUP);
1401 	    if (!subreq) {
1402 	        talloc_zfree(req);
1403 	        return NULL;
1404 	    }
1405 	    tevent_req_set_callback(subreq, sdap_get_groups_process, req);
1406 	
1407 	    return req;
1408 	}
1409 	
1410 	static void sdap_get_groups_process(struct tevent_req *subreq)
1411 	{
1412 	    struct tevent_req *req = tevent_req_callback_data(subreq,
1413 	                                                      struct tevent_req);
1414 	    struct sdap_get_groups_state *state = tevent_req_data(req,
1415 	                                            struct sdap_get_groups_state);
1416 	    int ret;
1417 	
1418 	    ret = sdap_get_generic_recv(subreq, state,
1419 	                                &state->count, &state->groups);
1420 	    talloc_zfree(subreq);
1421 	    if (ret) {
1422 	        tevent_req_error(req, ret);
1423 	        return;
1424 	    }
1425 	
1426 	    DEBUG(6, ("Search for groups, returned %d results.\n", state->count));
1427 	
1428 	    if (state->count == 0) {
1429 	        tevent_req_error(req, ENOENT);
1430 	        return;
1431 	    }
1432 	
1433 	    subreq = sdap_save_groups_send(state, state->ev, state->dom,
1434 	                                   state->sysdb, state->opts,
1435 	                                   state->groups, state->count);
1436 	    if (!subreq) {
1437 	        tevent_req_error(req, ENOMEM);
1438 	        return;
1439 	    }
1440 	    tevent_req_set_callback(subreq, sdap_get_groups_done, req);
1441 	}
1442 	
1443 	static void sdap_get_groups_done(struct tevent_req *subreq)
1444 	{
1445 	    struct tevent_req *req = tevent_req_callback_data(subreq,
1446 	                                                      struct tevent_req);
1447 	    struct sdap_get_groups_state *state = tevent_req_data(req,
1448 	                                            struct sdap_get_groups_state);
1449 	    int ret;
1450 	
1451 	    DEBUG(9, ("Saving %d Groups - Done\n", state->count));
1452 	
1453 	    ret = sdap_save_groups_recv(subreq, state, &state->higher_timestamp);
1454 	    talloc_zfree(subreq);
1455 	    if (ret) {
1456 	        DEBUG(2, ("Failed to store groups.\n"));
1457 	        tevent_req_error(req, ret);
1458 	        return;
1459 	    }
1460 	
1461 	    tevent_req_done(req);
1462 	}
1463 	
1464 	int sdap_get_groups_recv(struct tevent_req *req,
1465 	                         TALLOC_CTX *mem_ctx, char **timestamp)
1466 	{
1467 	    struct sdap_get_groups_state *state = tevent_req_data(req,
1468 	                                            struct sdap_get_groups_state);
1469 	
1470 	    TEVENT_REQ_RETURN_ON_ERROR(req);
1471 	
1472 	    if (timestamp) {
1473 	        *timestamp = talloc_steal(mem_ctx, state->higher_timestamp);
1474 	    }
1475 	
1476 	    return EOK;
1477 	}
1478 	
1479 	
1480 	/* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-Classic/BIS========= */
1481 	
1482 	struct sdap_initgr_rfc2307_state {
1483 	    struct tevent_context *ev;
1484 	    struct sysdb_ctx *sysdb;
1485 	    struct sdap_options *opts;
1486 	    struct sss_domain_info *dom;
1487 	    struct sdap_handle *sh;
1488 	
1489 	    struct sdap_op *op;
1490 	};
1491 	
1492 	static void sdap_initgr_rfc2307_process(struct tevent_req *subreq);
1493 	static void sdap_initgr_rfc2307_done(struct tevent_req *subreq);
1494 	struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
1495 	                                            struct tevent_context *ev,
1496 	                                            struct sdap_options *opts,
1497 	                                            struct sysdb_ctx *sysdb,
1498 	                                            struct sss_domain_info *dom,
1499 	                                            struct sdap_handle *sh,
1500 	                                            const char *base_dn,
1501 	                                            const char *name,
1502 	                                            const char **grp_attrs)
1503 	{
1504 	    struct tevent_req *req, *subreq;
1505 	    struct sdap_initgr_rfc2307_state *state;
1506 	    const char *filter;
1507 	
1508 	    req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
1509 	    if (!req) return NULL;
1510 	
1511 	    state->ev = ev;
1512 	    state->opts = opts;
1513 	    state->sysdb = sysdb;
1514 	    state->dom = dom;
1515 	    state->sh = sh;
1516 	    state->op = NULL;
1517 	
1518 	    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
1519 	                             opts->group_map[SDAP_AT_GROUP_MEMBER].name,
1520 	                             name, opts->group_map[SDAP_OC_GROUP].name);
1521 	    if (!filter) {
1522 	        talloc_zfree(req);
1523 	        return NULL;
1524 	    }
1525 	
1526 	    subreq = sdap_get_generic_send(state, state->ev, state->opts,
1527 	                                   state->sh, base_dn, LDAP_SCOPE_SUBTREE,
1528 	                                   filter, grp_attrs,
1529 	                                   state->opts->group_map, SDAP_OPTS_GROUP);
1530 	    if (!subreq) {
1531 	        talloc_zfree(req);
1532 	        return NULL;
1533 	    }
1534 	    tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req);
1535 	
1536 	    return req;
1537 	}
1538 	
1539 	static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
1540 	{
1541 	    struct tevent_req *req;
1542 	    struct sdap_initgr_rfc2307_state *state;
1543 	    struct sysdb_attrs **groups;
1544 	    size_t count;
1545 	    int ret;
1546 	
1547 	    req = tevent_req_callback_data(subreq, struct tevent_req);
1548 	    state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
1549 	
1550 	    ret = sdap_get_generic_recv(subreq, state, &count, &groups);
1551 	    talloc_zfree(subreq);
1552 	    if (ret) {
1553 	        tevent_req_error(req, ret);
1554 	        return;
1555 	    }
1556 	
1557 	    if (count == 0) {
1558 	        tevent_req_done(req);
1559 	        return;
1560 	    }
1561 	
1562 	    subreq = sdap_save_groups_send(state, state->ev, state->dom,
1563 	                                   state->sysdb, state->opts,
1564 	                                   groups, count);
1565 	    if (!subreq) {
1566 	        tevent_req_error(req, ENOMEM);
1567 	        return;
1568 	    }
1569 	    tevent_req_set_callback(subreq, sdap_initgr_rfc2307_done, req);
1570 	}
1571 	
1572 	static void sdap_initgr_rfc2307_done(struct tevent_req *subreq)
1573 	{
1574 	    struct tevent_req *req;
1575 	    int ret;
1576 	
1577 	    req = tevent_req_callback_data(subreq, struct tevent_req);
1578 	
1579 	    ret = sdap_save_groups_recv(subreq, NULL, NULL);
1580 	    talloc_zfree(subreq);
1581 	    if (ret) {
1582 	        tevent_req_error(req, ret);
1583 	        return;
1584 	    }
1585 	
1586 	    tevent_req_done(req);
1587 	}
1588 	
1589 	static int sdap_initgr_rfc2307_recv(struct tevent_req *req)
1590 	{
1591 	    TEVENT_REQ_RETURN_ON_ERROR(req);
1592 	
1593 	    return EOK;
1594 	}
1595 	
1596 	
1597 	/* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */
1598 	
1599 	struct sdap_initgr_nested_state {
1600 	    struct tevent_context *ev;
1601 	    struct sysdb_ctx *sysdb;
1602 	    struct sdap_options *opts;
1603 	    struct sss_domain_info *dom;
1604 	    struct sdap_handle *sh;
1605 	
1606 	    const char **grp_attrs;
1607 	
1608 	    char *filter;
1609 	    char **group_dns;
1610 	    int count;
1611 	    int cur;
1612 	
1613 	    struct sdap_op *op;
1614 	
1615 	    struct sysdb_attrs **groups;
1616 	    int groups_cur;
1617 	};
1618 	
1619 	static void sdap_initgr_nested_search(struct tevent_req *subreq);
1620 	static void sdap_initgr_nested_store(struct tevent_req *req);
1621 	static void sdap_initgr_nested_done(struct tevent_req *subreq);
1622 	static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,
1623 	                                                  struct tevent_context *ev,
1624 	                                                  struct sdap_options *opts,
1625 	                                                  struct sysdb_ctx *sysdb,
1626 	                                                  struct sss_domain_info *dom,
1627 	                                                  struct sdap_handle *sh,
1628 	                                                  struct sysdb_attrs *user,
1629 	                                                  const char **grp_attrs)
1630 	{
1631 	    struct tevent_req *req, *subreq;
1632 	    struct sdap_initgr_nested_state *state;
1633 	    struct ldb_message_element *el;
1634 	    int i, ret;
1635 	
1636 	    req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state);
1637 	    if (!req) return NULL;
1638 	
1639 	    state->ev = ev;
1640 	    state->opts = opts;
1641 	    state->sysdb = sysdb;
1642 	    state->dom = dom;
1643 	    state->sh = sh;
1644 	    state->grp_attrs = grp_attrs;
1645 	    state->op = NULL;
1646 	
1647 	    state->filter = talloc_asprintf(state, "(objectclass=%s)",
1648 	                                    opts->group_map[SDAP_OC_GROUP].name);
1649 	    if (!state->filter) {
1650 	        talloc_zfree(req);
1651 	        return NULL;
1652 	    }
1653 	
1654 	    /* TODO: test rootDSE for deref support and use it if available */
1655 	    /* TODO: or test rootDSE for ASQ support and use it if available */
1656 	
1657 	    ret = sysdb_attrs_get_el(user, SYSDB_MEMBEROF, &el);
Event var_compare_op: Comparing "el" to null implies that "el" might be null.
Also see events: [var_deref_op]
At conditional (1): "!el": Taking true branch.
1658 	    if (ret || !el || el->num_values == 0) {
At conditional (2): "4 <= debug_level": Taking true branch.
At conditional (3): "debug_timestamps": Taking true branch.
1659 	        DEBUG(4, ("User entry lacks original memberof ?\n"));
1660 	        /* user with no groups ? */
1661 	        tevent_req_error(req, ENOENT);
1662 	        tevent_req_post(req, ev);
1663 	    }
Event var_deref_op: Dereferencing null variable "el".
Also see events: [var_compare_op]
1664 	    state->count = el->num_values;
1665 	
1666 	    state->groups = talloc_zero_array(state, struct sysdb_attrs *,
1667 	                                      state->count + 1);;
1668 	    if (!state->groups) {
1669 	        talloc_zfree(req);
1670 	        return NULL;
1671 	    }
1672 	    state->groups_cur = 0;
1673 	
1674 	    state->group_dns = talloc_array(state, char *, state->count + 1);
1675 	    if (!state->group_dns) {
1676 	        talloc_zfree(req);
1677 	        return NULL;
1678 	    }
1679 	    for (i = 0; i < state->count; i++) {
1680 	        state->group_dns[i] = talloc_strdup(state->group_dns,
1681 	                                            (char *)el->values[i].data);
1682 	        if (!state->group_dns[i]) {
1683 	            talloc_zfree(req);
1684 	            return NULL;
1685 	        }
1686 	    }
1687 	    state->group_dns[i] = NULL; /* terminate */
1688 	    state->cur = 0;
1689 	
1690 	    subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
1691 	                                   state->group_dns[state->cur],
1692 	                                   LDAP_SCOPE_BASE,
1693 	                                   state->filter, state->grp_attrs,
1694 	                                   state->opts->group_map, SDAP_OPTS_GROUP);
1695 	    if (!subreq) {
1696 	        talloc_zfree(req);
1697 	        return NULL;
1698 	    }
1699 	    tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
1700 	
1701 	    return req;
1702 	}
1703 	
1704 	static void sdap_initgr_nested_search(struct tevent_req *subreq)
1705 	{
1706 	    struct tevent_req *req;
1707 	    struct sdap_initgr_nested_state *state;
1708 	    struct sysdb_attrs **groups;
1709 	    size_t count;
1710 	    int ret;
1711 	
1712 	    req = tevent_req_callback_data(subreq, struct tevent_req);
1713 	    state = tevent_req_data(req, struct sdap_initgr_nested_state);
1714 	
1715 	    ret = sdap_get_generic_recv(subreq, state, &count, &groups);
1716 	    talloc_zfree(subreq);
1717 	    if (ret) {
1718 	        tevent_req_error(req, ret);
1719 	        return;
1720 	    }
1721 	
1722 	    if (count == 1) {
1723 	        state->groups[state->groups_cur] = groups[0];
1724 	        state->groups_cur++;
1725 	    } else {
1726 	        DEBUG(2, ("Search for group %s, returned %d results. Skipping\n",
1727 	                  state->group_dns[state->cur], count));
1728 	    }
1729 	
1730 	    state->cur++;
1731 	    if (state->cur < state->count) {
1732 	        subreq = sdap_get_generic_send(state, state->ev,
1733 	                                       state->opts, state->sh,
1734 	                                       state->group_dns[state->cur],
1735 	                                       LDAP_SCOPE_BASE,
1736 	                                       state->filter, state->grp_attrs,
1737 	                                       state->opts->group_map,
1738 	                                       SDAP_OPTS_GROUP);
1739 	        if (!subreq) {
1740 	            tevent_req_error(req, ENOMEM);
1741 	            return;
1742 	        }
1743 	        tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
1744 	    } else {
1745 	        sdap_initgr_nested_store(req);
1746 	    }
1747 	}
1748 	
1749 	static void sdap_initgr_nested_store(struct tevent_req *req)
1750 	{
1751 	    struct tevent_req *subreq;
1752 	    struct sdap_initgr_nested_state *state;
1753 	
1754 	    state = tevent_req_data(req, struct sdap_initgr_nested_state);
1755 	
1756 	    subreq = sdap_save_groups_send(state, state->ev, state->dom,
1757 	                                   state->sysdb, state->opts,
1758 	                                   state->groups, state->groups_cur);
1759 	    if (!subreq) {
1760 	        tevent_req_error(req, ENOMEM);
1761 	        return;
1762 	    }
1763 	    tevent_req_set_callback(subreq, sdap_initgr_nested_done, req);
1764 	}
1765 	
1766 	static void sdap_initgr_nested_done(struct tevent_req *subreq)
1767 	{
1768 	    struct tevent_req *req;
1769 	    int ret;
1770 	
1771 	    req = tevent_req_callback_data(subreq, struct tevent_req);
1772 	
1773 	    ret = sdap_save_groups_recv(subreq, NULL, NULL);
1774 	    talloc_zfree(subreq);
1775 	    if (ret) {
1776 	        tevent_req_error(req, ret);
1777 	        return;
1778 	    }
1779 	
1780 	    tevent_req_done(req);
1781 	}
1782 	
1783 	static int sdap_initgr_nested_recv(struct tevent_req *req)
1784 	{
1785 	    TEVENT_REQ_RETURN_ON_ERROR(req);
1786 	
1787 	    return EOK;
1788 	}
1789 	
1790 	
1791 	/* ==Initgr-call-(groups-a-user-is-member-of)============================= */
1792 	
1793 	struct sdap_get_initgr_state {
1794 	    struct tevent_context *ev;
1795 	    struct sysdb_ctx *sysdb;
1796 	    struct sdap_options *opts;
1797 	    struct sss_domain_info *dom;
1798 	    struct sdap_handle *sh;
1799 	    const char *name;
1800 	    const char **grp_attrs;
1801 	
1802 	    struct sysdb_attrs *orig_user;
1803 	
1804 	    struct sysdb_handle *handle;
1805 	};
1806 	
1807 	static void sdap_get_initgr_user(struct tevent_req *subreq);
1808 	static void sdap_get_initgr_store(struct tevent_req *subreq);
1809 	static void sdap_get_initgr_commit(struct tevent_req *subreq);
1810 	static void sdap_get_initgr_process(struct tevent_req *subreq);
1811 	static void sdap_get_initgr_done(struct tevent_req *subreq);
1812 	
1813 	struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
1814 	                                        struct tevent_context *ev,
1815 	                                        struct sss_domain_info *dom,
1816 	                                        struct sysdb_ctx *sysdb,
1817 	                                        struct sdap_options *opts,
1818 	                                        struct sdap_handle *sh,
1819 	                                        const char *name,
1820 	                                        const char **grp_attrs)
1821 	{
1822 	    struct tevent_req *req, *subreq;
1823 	    struct sdap_get_initgr_state *state;
1824 	    const char *base_dn;
1825 	    char *filter;
1826 	    const char **attrs;
1827 	    int ret;
1828 	
1829 	    DEBUG(9, ("Retrieving info for initgroups call\n"));
1830 	
1831 	    req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state);
1832 	    if (!req) return NULL;
1833 	
1834 	    state->ev = ev;
1835 	    state->opts = opts;
1836 	    state->sysdb = sysdb;
1837 	    state->dom = dom;
1838 	    state->sh = sh;
1839 	    state->name = name;
1840 	    state->grp_attrs = grp_attrs;
1841 	    state->orig_user = NULL;
1842 	
1843 	    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
1844 	                        state->opts->user_map[SDAP_AT_USER_NAME].name,
1845 	                        state->name,
1846 	                        state->opts->user_map[SDAP_OC_USER].name);
1847 	    if (!filter) {
1848 	        talloc_zfree(req);
1849 	        return NULL;
1850 	    }
1851 	
1852 	    base_dn = dp_opt_get_string(state->opts->basic,
1853 	                                SDAP_USER_SEARCH_BASE);
1854 	    if (!base_dn) {
1855 	        talloc_zfree(req);
1856 	        return NULL;
1857 	    }
1858 	
1859 	    ret = build_attrs_from_map(state, state->opts->user_map,
1860 	                               SDAP_OPTS_USER, &attrs);
1861 	    if (ret) {
1862 	        talloc_zfree(req);
1863 	        return NULL;
1864 	    }
1865 	
1866 	    subreq = sdap_get_generic_send(state, state->ev,
1867 	                                   state->opts, state->sh,
1868 	                                   base_dn, LDAP_SCOPE_SUBTREE,
1869 	                                   filter, attrs,
1870 	                                   state->opts->user_map, SDAP_OPTS_USER);
1871 	    if (!subreq) {
1872 	        talloc_zfree(req);
1873 	        return NULL;
1874 	    }
1875 	    tevent_req_set_callback(subreq, sdap_get_initgr_user, req);
1876 	
1877 	    return req;
1878 	}
1879 	
1880 	static void sdap_get_initgr_user(struct tevent_req *subreq)
1881 	{
1882 	    struct tevent_req *req = tevent_req_callback_data(subreq,
1883 	                                                      struct tevent_req);
1884 	    struct sdap_get_initgr_state *state = tevent_req_data(req,
1885 	                                               struct sdap_get_initgr_state);
1886 	    struct sysdb_attrs **usr_attrs;
1887 	    size_t count;
1888 	    int ret;
1889 	
1890 	    DEBUG(9, ("Receiving info for the user\n"));
1891 	
1892 	    ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);
1893 	    talloc_zfree(subreq);
1894 	    if (ret) {
1895 	        tevent_req_error(req, ret);
1896 	        return;
1897 	    }
1898 	
1899 	    if (count != 1) {
1900 	        DEBUG(2, ("Expected one user entry and got %d\n", count));
1901 	        tevent_req_error(req, ENOENT);
1902 	        return;
1903 	    }
1904 	
1905 	    state->orig_user = usr_attrs[0];
1906 	
1907 	    subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1908 	    if (!subreq) {
1909 	        tevent_req_error(req, ENOMEM);
1910 	        return;
1911 	    }
1912 	    tevent_req_set_callback(subreq, sdap_get_initgr_store, req);
1913 	}
1914 	
1915 	static void sdap_get_initgr_store(struct tevent_req *subreq)
1916 	{
1917 	    struct tevent_req *req = tevent_req_callback_data(subreq,
1918 	                                                      struct tevent_req);
1919 	    struct sdap_get_initgr_state *state = tevent_req_data(req,
1920 	                                               struct sdap_get_initgr_state);
1921 	    int ret;
1922 	
1923 	    DEBUG(9, ("Storing the user\n"));
1924 	
1925 	    ret = sysdb_transaction_recv(subreq, state, &state->handle);
1926 	    talloc_zfree(subreq);
1927 	    if (ret) {
1928 	        tevent_req_error(req, ret);
1929 	        return;
1930 	    }
1931 	
1932 	    subreq = sdap_save_user_send(state, state->ev, state->handle,
1933 	                                 state->opts, state->dom,
1934 	                                 state->orig_user, true);
1935 	    if (!subreq) {
1936 	        tevent_req_error(req, ENOMEM);
1937 	        return;
1938 	    }
1939 	    tevent_req_set_callback(subreq, sdap_get_initgr_commit, req);
1940 	}
1941 	
1942 	static void sdap_get_initgr_commit(struct tevent_req *subreq)
1943 	{
1944 	    struct tevent_req *req = tevent_req_callback_data(subreq,
1945 	                                                      struct tevent_req);
1946 	    struct sdap_get_initgr_state *state = tevent_req_data(req,
1947 	                                               struct sdap_get_initgr_state);
1948 	    int ret;
1949 	
1950 	    DEBUG(9, ("Commit change\n"));
1951 	
1952 	    ret = sdap_save_user_recv(subreq, NULL, NULL);
1953 	    talloc_zfree(subreq);
1954 	    if (ret) {
1955 	        tevent_req_error(req, ret);
1956 	        return;
1957 	    }
1958 	
1959 	    subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1960 	    if (!subreq) {
1961 	        tevent_req_error(req, ENOMEM);
1962 	        return;
1963 	    }
1964 	    tevent_req_set_callback(subreq, sdap_get_initgr_process, req);
1965 	}
1966 	
1967 	static void sdap_get_initgr_process(struct tevent_req *subreq)
1968 	{
1969 	    struct tevent_req *req = tevent_req_callback_data(subreq,
1970 	                                                      struct tevent_req);
1971 	    struct sdap_get_initgr_state *state = tevent_req_data(req,
1972 	                                               struct sdap_get_initgr_state);
1973 	    int ret;
1974 	
1975 	    DEBUG(9, ("Process user's groups\n"));
1976 	
1977 	    ret = sysdb_transaction_commit_recv(subreq);
1978 	    talloc_zfree(subreq);
1979 	    if (ret) {
1980 	        tevent_req_error(req, ret);
1981 	        return;
1982 	    }
1983 	
1984 	    switch (state->opts->schema_type) {
1985 	    case SDAP_SCHEMA_RFC2307:
1986 	        subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,
1987 	                                    state->sysdb, state->dom, state->sh,
1988 	                                    dp_opt_get_string(state->opts->basic,
1989 	                                                  SDAP_GROUP_SEARCH_BASE),
1990 	                                    state->name, state->grp_attrs);
1991 	        if (!subreq) {
1992 	            tevent_req_error(req, ENOMEM);
1993 	            return;
1994 	        }
1995 	        tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
1996 	        break;
1997 	
1998 	    case SDAP_SCHEMA_RFC2307BIS:
1999 	    case SDAP_SCHEMA_IPA_V1:
2000 	    case SDAP_SCHEMA_AD:
2001 	        /* TODO: AD uses a different member/memberof schema
2002 	         *       We need an AD specific call that is able to unroll
2003 	         *       nested groups by doing extensive recursive searches */
2004 	
2005 	        subreq = sdap_initgr_nested_send(state, state->ev, state->opts,
2006 	                                         state->sysdb, state->dom, state->sh,
2007 	                                         state->orig_user, state->grp_attrs);
2008 	        if (!subreq) {
2009 	            tevent_req_error(req, ENOMEM);
2010 	            return;
2011 	        }
2012 	        tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
2013 	        return;
2014 	
2015 	    default:
2016 	        tevent_req_error(req, EINVAL);
2017 	        return;
2018 	    }
2019 	}
2020 	
2021 	static void sdap_get_initgr_done(struct tevent_req *subreq)
2022 	{
2023 	    struct tevent_req *req = tevent_req_callback_data(subreq,
2024 	                                                      struct tevent_req);
2025 	    struct sdap_get_initgr_state *state = tevent_req_data(req,
2026 	                                               struct sdap_get_initgr_state);
2027 	    int ret;
2028 	
2029 	    DEBUG(9, ("Initgroups done\n"));
2030 	
2031 	    switch (state->opts->schema_type) {
2032 	    case SDAP_SCHEMA_RFC2307:
2033 	
2034 	        ret = sdap_initgr_rfc2307_recv(subreq);
2035 	        break;
2036 	
2037 	    case SDAP_SCHEMA_RFC2307BIS:
2038 	    case SDAP_SCHEMA_IPA_V1:
2039 	    case SDAP_SCHEMA_AD:
2040 	
2041 	        ret = sdap_initgr_nested_recv(subreq);
2042 	        break;
2043 	
2044 	    default:
2045 	
2046 	        ret = EINVAL;
2047 	        break;
2048 	    }
2049 	
2050 	    talloc_zfree(subreq);
2051 	    if (ret) {
2052 	        tevent_req_error(req, ret);
2053 	        return;
2054 	    }
2055 	
2056 	    tevent_req_done(req);
2057 	}
2058 	
2059 	int sdap_get_initgr_recv(struct tevent_req *req)
2060 	{
2061 	    TEVENT_REQ_RETURN_ON_ERROR(req);
2062 	
2063 	    return EOK;
2064 	}
2065