1    	/*
2    	   SSSD memberof module
3    	
4    	   Copyright (C) Simo Sorce <idra@samba.org> 2008
5    	
6    	   This program is free software; you can redistribute it and/or modify
7    	   it under the terms of the GNU General Public License as published by
8    	   the Free Software Foundation; either version 3 of the License, or
9    	   (at your option) any later version.
10   	
11   	   This program is distributed in the hope that it will be useful,
12   	   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   	   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   	   GNU General Public License for more details.
15   	
16   	   You should have received a copy of the GNU General Public License
17   	   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   	*/
19   	
20   	#include <string.h>
21   	#include "ldb_module.h"
22   	#include "util/util.h"
23   	#include "dhash.h"
24   	
25   	#define DB_MEMBER "member"
26   	#define DB_MEMBEROF "memberof"
27   	#define DB_MEMBERUID "memberuid"
28   	#define DB_NAME "name"
29   	#define DB_USER_CLASS "user"
30   	#define DB_OC "objectClass"
31   	
32   	#ifndef talloc_zfree
33   	#define talloc_zfree(ptr) do { talloc_free(ptr); ptr = NULL; } while(0)
34   	#endif
35   	
36   	#ifndef MAX
37   	#define MAX(a,b) (((a) > (b)) ? (a) : (b))
38   	#endif
39   	
40   	struct mbof_dn_array {
41   	    struct ldb_dn **dns;
42   	    int num;
43   	};
44   	
45   	struct mbof_dn {
46   	    struct mbof_dn *next;
47   	    struct ldb_dn *dn;
48   	};
49   	
50   	struct mbof_ctx {
51   	    struct ldb_module *module;
52   	    struct ldb_request *req;
53   	
54   	    struct ldb_control **ret_ctrls;
55   	    struct ldb_extended *ret_resp;
56   	};
57   	
58   	struct mbof_add_operation {
59   	    struct mbof_add_ctx *add_ctx;
60   	    struct mbof_add_operation *next;
61   	
62   	    struct mbof_dn_array *parents;
63   	    struct ldb_dn *entry_dn;
64   	
65   	    struct ldb_message *entry;
66   	};
67   	
68   	struct mbof_memberuid_op {
69   	    struct ldb_dn *dn;
70   	    struct ldb_message_element *el;
71   	};
72   	
73   	struct mbof_add_ctx {
74   	    struct mbof_ctx *ctx;
75   	
76   	    struct mbof_add_operation *add_list;
77   	    struct mbof_add_operation *current_op;
78   	
79   	    struct ldb_message *msg;
80   	    struct ldb_dn *msg_dn;
81   	    bool terminate;
82   	
83   	    struct mbof_dn *missing;
84   	
85   	    struct mbof_memberuid_op *muops;
86   	    int num_muops;
87   	    int cur_muop;
88   	};
89   	
90   	struct mbof_del_ancestors_ctx {
91   	    struct mbof_dn_array *new_list;
92   	    int num_direct;
93   	    int cur;
94   	
95   	    struct ldb_message *entry;
96   	};
97   	
98   	struct mbof_del_operation {
99   	    struct mbof_del_ctx *del_ctx;
100  	    struct mbof_del_operation *parent;
101  	    struct mbof_del_operation **children;
102  	    int num_children;
103  	    int next_child;
104  	
105  	    struct ldb_dn *entry_dn;
106  	
107  	    struct ldb_message *entry;
108  	    struct ldb_message **parents;
109  	    int num_parents;
110  	    int cur_parent;
111  	
112  	    struct mbof_del_ancestors_ctx *anc_ctx;
113  	};
114  	
115  	struct mbof_mod_ctx;
116  	
117  	struct mbof_del_ctx {
118  	    struct mbof_ctx *ctx;
119  	
120  	    struct mbof_del_operation *first;
121  	    struct mbof_dn *history;
122  	
123  	    struct ldb_message **mus;
124  	    int num_mus;
125  	
126  	    struct mbof_memberuid_op *muops;
127  	    int num_muops;
128  	    int cur_muop;
129  	
130  	    struct mbof_mod_ctx *follow_mod;
131  	    bool is_mod;
132  	};
133  	
134  	struct mbof_mod_ctx {
135  	    struct mbof_ctx *ctx;
136  	
137  	    const struct ldb_message_element *membel;
138  	    struct ldb_message *entry;
139  	
140  	    struct mbof_dn_array *to_add;
141  	
142  	    struct ldb_message *msg;
143  	    bool terminate;
144  	};
145  	
146  	static struct mbof_ctx *mbof_init(struct ldb_module *module,
147  	                                  struct ldb_request *req)
148  	{
149  	    struct mbof_ctx *ctx;
150  	
151  	    ctx = talloc_zero(req, struct mbof_ctx);
152  	    if (!ctx) {
153  	        return NULL;
154  	    }
155  	
156  	    ctx->module = module;
157  	    ctx->req = req;
158  	
159  	    return ctx;
160  	}
161  	
162  	static int entry_is_user_object(struct ldb_message *entry)
163  	{
164  	    struct ldb_message_element *el;
165  	    struct ldb_val *val;
166  	    int i;
167  	
168  	    el = ldb_msg_find_element(entry, DB_OC);
169  	    if (!el) {
170  	        return LDB_ERR_OPERATIONS_ERROR;
171  	    }
172  	
173  	    /* see if this is a user */
174  	    for (i = 0; i < el->num_values; i++) {
175  	        val = &(el->values[i]);
176  	        if (strncasecmp(DB_USER_CLASS, (char *)val->data, val->length) == 0) {
177  	            return LDB_SUCCESS;
178  	        }
179  	    }
180  	
181  	    return LDB_ERR_NO_SUCH_ATTRIBUTE;
182  	}
183  	
184  	static int mbof_append_muop(TALLOC_CTX *memctx,
185  	                            struct mbof_memberuid_op **_muops,
186  	                            int *_num_muops,
187  	                            int flags,
188  	                            struct ldb_dn *parent,
189  	                            const char *name)
190  	{
191  	    struct mbof_memberuid_op *muops = *_muops;
192  	    int num_muops = *_num_muops;
193  	    struct mbof_memberuid_op *op;
194  	    struct ldb_val *val;
195  	    int i;
196  	
197  	    op = NULL;
198  	    if (muops) {
199  	        for (i = 0; i < num_muops; i++) {
200  	            if (ldb_dn_compare(parent, muops[i].dn) == 0) {
201  	                op = &muops[i];
202  	                break;
203  	            }
204  	        }
205  	    }
206  	    if (!op) {
207  	        muops = talloc_realloc(memctx, muops,
208  	                               struct mbof_memberuid_op,
209  	                               num_muops + 1);
210  	        if (!muops) {
211  	            return LDB_ERR_OPERATIONS_ERROR;
212  	        }
213  	        op = &muops[num_muops];
214  	        num_muops++;
215  	        *_muops = muops;
216  	        *_num_muops = num_muops;
217  	
218  	        op->dn = parent;
219  	        op->el = NULL;
220  	    }
221  	
222  	    if (!op->el) {
223  	        op->el = talloc_zero(muops, struct ldb_message_element);
224  	        if (!op->el) {
225  	            return LDB_ERR_OPERATIONS_ERROR;
226  	        }
227  	        op->el->name = talloc_strdup(op->el, DB_MEMBERUID);
228  	        if (!op->el->name) {
229  	            return LDB_ERR_OPERATIONS_ERROR;
230  	        }
231  	        op->el->flags = flags;
232  	    }
233  	
234  	    for (i = 0; i < op->el->num_values; i++) {
235  	        if (strcmp((char *)op->el->values[i].data, name) == 0) {
236  	            /* we already have this value, get out*/
237  	            return LDB_SUCCESS;
238  	        }
239  	    }
240  	
241  	    val = talloc_realloc(op->el, op->el->values,
242  	                         struct ldb_val, op->el->num_values + 1);
243  	    if (!val) {
244  	        return LDB_ERR_OPERATIONS_ERROR;
245  	    }
246  	    val[op->el->num_values].data = (uint8_t *)talloc_strdup(val, name);
247  	    if (!val[op->el->num_values].data) {
248  	        return LDB_ERR_OPERATIONS_ERROR;
249  	    }
250  	    val[op->el->num_values].length = strlen(name);
251  	
252  	    op->el->values = val;
253  	    op->el->num_values++;
254  	
255  	    return LDB_SUCCESS;
256  	}
257  	
258  	
259  	/* add operation */
260  	
261  	/* An add operation is quite simple.
262  	 * First of all a new object cannot yet have parents, so the only memberof
263  	 * attribute that can be added to any member contains just one object DN.
264  	 *
265  	 * The real add operation is done first, to assure nothing else fails.
266  	 * Then we list all members of the object just created, and for each member
267  	 * we create an "add operation" and we pass it a parent list of one member
268  	 * (the object we just added again).
269  	 *
270  	 * For each add operation we lookup the object we want to operate on.
271  	 * We take the list of memberof attributes and sort out which parents are
272  	 * still missing from the parent list we have provided.
273  	 * We modify the object memberof attributes to reflect the new memberships.
274  	 * Then we list all members of this object, and for each once again we create
275  	 * an "add operation" as we did in the initial object.
276  	 *
277  	 * Processing stops when the target object does not have members or when it
278  	 * already has all the parents (can happen if nested groups create loops).
279  	 *
280  	 * Group cache unrolling:
281  	 * Every time we add a memberof attribute to an actual user object,
282  	 * we proceed to store the user name.
283  	 *
284  	 * At the end we will add a memberuid attribute to our new object that
285  	 * includes all direct and indeirect user members names.
286  	 */
287  	
288  	static int mbof_append_addop(struct mbof_add_ctx *add_ctx,
289  	                             struct mbof_dn_array *parents,
290  	                             struct ldb_dn *entry_dn)
291  	{
292  	    struct mbof_add_operation *lastop = NULL;
293  	    struct mbof_add_operation *addop;
294  	
295  	    /* test if this is a duplicate */
296  	    /* FIXME: this is not efficient */
297  	    if (add_ctx->add_list) {
298  	        do {
299  	            if (lastop) {
300  	                lastop = lastop->next;
301  	            } else {
302  	                lastop = add_ctx->add_list;
303  	            }
304  	
305  	            /* FIXME: check if this is right, might have to compare parents */
306  	            if (ldb_dn_compare(lastop->entry_dn, entry_dn) == 0) {
307  	                /* duplicate found */
308  	                return LDB_SUCCESS;
309  	            }
310  	        } while (lastop->next);
311  	    }
312  	
313  	    addop = talloc_zero(add_ctx, struct mbof_add_operation);
314  	    if (!addop) {
315  	        return LDB_ERR_OPERATIONS_ERROR;
316  	    }
317  	
318  	    addop->add_ctx = add_ctx;
319  	    addop->parents = parents;
320  	    addop->entry_dn = entry_dn;
321  	
322  	    if (add_ctx->add_list) {
323  	        lastop->next = addop;
324  	    } else {
325  	        add_ctx->add_list = addop;
326  	    }
327  	
328  	    return LDB_SUCCESS;
329  	}
330  	
331  	static int memberof_recompute_task(struct ldb_module *module,
332  	                                   struct ldb_request *req);
333  	
334  	static int mbof_add_callback(struct ldb_request *req,
335  	                             struct ldb_reply *ares);
336  	static int mbof_next_add(struct mbof_add_operation *addop);
337  	static int mbof_next_add_callback(struct ldb_request *req,
338  	                                  struct ldb_reply *ares);
339  	static int mbof_add_operation(struct mbof_add_operation *addop);
340  	static int mbof_add_missing(struct mbof_add_ctx *add_ctx, struct ldb_dn *dn);
341  	static int mbof_add_cleanup(struct mbof_add_ctx *add_ctx);
342  	static int mbof_add_cleanup_callback(struct ldb_request *req,
343  	                                     struct ldb_reply *ares);
344  	static int mbof_add_muop(struct mbof_add_ctx *add_ctx);
345  	static int mbof_add_muop_callback(struct ldb_request *req,
346  	                                  struct ldb_reply *ares);
347  	
348  	static int memberof_add(struct ldb_module *module, struct ldb_request *req)
349  	{
350  	    struct ldb_context *ldb = ldb_module_get_ctx(module);
351  	    struct mbof_add_ctx *add_ctx;
352  	    struct mbof_ctx *ctx;
353  	    struct ldb_request *add_req;
354  	    struct ldb_message_element *el;
355  	    struct mbof_dn_array *parents;
356  	    struct ldb_dn *valdn;
357  	    int i, ret;
358  	
359  	    if (ldb_dn_is_special(req->op.add.message->dn)) {
360  	
361  	        if (strcmp("@MEMBEROF-REBUILD",
362  	                   ldb_dn_get_linearized(req->op.add.message->dn)) == 0) {
363  	            return memberof_recompute_task(module, req);
364  	        }
365  	
366  	        /* do not manipulate other control entries */
367  	        return ldb_next_request(module, req);
368  	    }
369  	
370  	    /* check if memberof is specified */
371  	    el = ldb_msg_find_element(req->op.add.message, DB_MEMBEROF);
372  	    if (el) {
373  	        ldb_debug(ldb, LDB_DEBUG_ERROR,
374  	                  "Error: the memberof attribute is readonly.");
375  	        return LDB_ERR_UNWILLING_TO_PERFORM;
376  	    }
377  	
378  	    /* check if memberuid is specified */
379  	    el = ldb_msg_find_element(req->op.add.message, DB_MEMBERUID);
380  	    if (el) {
381  	        ldb_debug(ldb, LDB_DEBUG_ERROR,
382  	                  "Error: the memberuid attribute is readonly.");
383  	        return LDB_ERR_UNWILLING_TO_PERFORM;
384  	    }
385  	
386  	    ctx = mbof_init(module, req);
387  	    if (!ctx) {
388  	        return LDB_ERR_OPERATIONS_ERROR;
389  	    }
390  	
391  	    add_ctx = talloc_zero(ctx, struct mbof_add_ctx);
392  	    if (!add_ctx) {
393  	        return LDB_ERR_OPERATIONS_ERROR;
394  	    }
395  	    add_ctx->ctx = ctx;
396  	
397  	    add_ctx->msg = ldb_msg_copy(add_ctx, req->op.add.message);
398  	    if (!add_ctx->msg) {
399  	        return LDB_ERR_OPERATIONS_ERROR;
400  	    }
401  	    add_ctx->msg_dn = add_ctx->msg->dn;
402  	
403  	    /* continue with normal ops if there are no members */
404  	    el = ldb_msg_find_element(add_ctx->msg, DB_MEMBER);
405  	    if (!el) {
406  	        add_ctx->terminate = true;
407  	        goto done;
408  	    }
409  	
410  	    parents = talloc_zero(add_ctx, struct mbof_dn_array);
411  	    if (!parents) {
412  	        return LDB_ERR_OPERATIONS_ERROR;
413  	    }
414  	    parents->dns = talloc_array(parents, struct ldb_dn *, 1);
415  	    if (!parents->dns) {
416  	        return LDB_ERR_OPERATIONS_ERROR;
417  	    }
418  	    parents->dns[0] = add_ctx->msg_dn;
419  	    parents->num = 1;
420  	
421  	    /* process new members */
422  	    /* check we are not adding ourselves as member as well */
423  	    for (i = 0; i < el->num_values; i++) {
424  	        valdn = ldb_dn_from_ldb_val(add_ctx, ldb, &el->values[i]);
425  	        if (!valdn || !ldb_dn_validate(valdn)) {
426  	            ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid dn value: [%s]",
427  	                                            (const char *)el->values[i].data);
428  	            return LDB_ERR_INVALID_DN_SYNTAX;
429  	        }
430  	        if (ldb_dn_compare(valdn, req->op.add.message->dn) == 0) {
431  	            ldb_debug(ldb, LDB_DEBUG_ERROR,
432  	                      "Adding self as member is not permitted! Skipping");
433  	            continue;
434  	        }
435  	        ret = mbof_append_addop(add_ctx, parents, valdn);
436  	        if (ret != LDB_SUCCESS) {
437  	            return ret;
438  	        }
439  	    }
440  	
441  	done:
442  	    /* add original object */
443  	    ret = ldb_build_add_req(&add_req, ldb, add_ctx,
444  	                            add_ctx->msg, req->controls,
445  	                            add_ctx, mbof_add_callback,
446  	                            req);
447  	    if (ret != LDB_SUCCESS) {
448  	        return ret;
449  	    }
450  	
451  	    return ldb_next_request(module, add_req);
452  	}
453  	
454  	static int mbof_add_callback(struct ldb_request *req,
455  	                             struct ldb_reply *ares)
456  	{
457  	    struct mbof_add_ctx *add_ctx;
458  	    struct mbof_ctx *ctx;
459  	    int ret;
460  	
461  	    add_ctx = talloc_get_type(req->context, struct mbof_add_ctx);
462  	    ctx = add_ctx->ctx;
463  	
464  	    if (!ares) {
465  	        return ldb_module_done(ctx->req, NULL, NULL,
466  	                               LDB_ERR_OPERATIONS_ERROR);
467  	    }
468  	    if (ares->error != LDB_SUCCESS) {
469  	        return ldb_module_done(ctx->req,
470  	                               ares->controls,
471  	                               ares->response,
472  	                               ares->error);
473  	    }
474  	
475  	    switch (ares->type) {
476  	    case LDB_REPLY_ENTRY:
477  	        /* shouldn't happen */
478  	        talloc_zfree(ares);
479  	        return ldb_module_done(ctx->req, NULL, NULL,
480  	                               LDB_ERR_OPERATIONS_ERROR);
481  	    case LDB_REPLY_REFERRAL:
482  	        /* ignore */
483  	        break;
484  	
485  	    case LDB_REPLY_DONE:
486  	        if (add_ctx->terminate) {
487  	            return ldb_module_done(ctx->req,
488  	                                   ctx->ret_ctrls,
489  	                                   ctx->ret_resp,
490  	                                   LDB_SUCCESS);
491  	        }
492  	
493  	        if (add_ctx->current_op == NULL) {
494  	            /* first operation */
495  	            ctx->ret_ctrls = talloc_steal(ctx, ares->controls);
496  	            ctx->ret_resp = talloc_steal(ctx, ares->response);
497  	            ret = mbof_next_add(add_ctx->add_list);
498  	        }
499  	        else if (add_ctx->current_op->next) {
500  	            /* next operation */
501  	            ret = mbof_next_add(add_ctx->current_op->next);
502  	        }
503  	        else {
504  	            /* no more operations */
505  	            if (add_ctx->missing) {
506  	                ret = mbof_add_cleanup(add_ctx);
507  	            }
508  	            else if (add_ctx->muops) {
509  	                ret = mbof_add_muop(add_ctx);
510  	            }
511  	            else {
512  	                return ldb_module_done(ctx->req,
513  	                                       ctx->ret_ctrls,
514  	                                       ctx->ret_resp,
515  	                                       LDB_SUCCESS);
516  	            }
517  	        }
518  	
519  	        if (ret != LDB_SUCCESS) {
520  	            talloc_zfree(ares);
521  	            return ldb_module_done(ctx->req, NULL, NULL, ret);
522  	        }
523  	    }
524  	
525  	    talloc_zfree(ares);
526  	    return LDB_SUCCESS;
527  	}
528  	
529  	static int mbof_next_add(struct mbof_add_operation *addop)
530  	{
531  	    static const char *attrs[] = { DB_OC, DB_NAME,
532  	                                   DB_MEMBER, DB_MEMBEROF, NULL };
533  	    struct ldb_context *ldb;
534  	    struct ldb_request *req;
535  	    struct mbof_add_ctx *add_ctx;
536  	    struct mbof_ctx *ctx;
537  	    int ret;
538  	
539  	    add_ctx = addop->add_ctx;
540  	    ctx = add_ctx->ctx;
541  	    ldb = ldb_module_get_ctx(ctx->module);
542  	
543  	    /* mark the operation as being handled */
544  	    add_ctx->current_op = addop;
545  	
546  	    ret = ldb_build_search_req(&req, ldb, ctx,
547  	                               addop->entry_dn, LDB_SCOPE_BASE,
548  	                               NULL, attrs, NULL,
549  	                               addop, mbof_next_add_callback,
550  	                               ctx->req);
551  	    if (ret != LDB_SUCCESS) {
552  	        return ret;
553  	    }
554  	
555  	    return ldb_request(ldb, req);
556  	}
557  	
558  	static int mbof_next_add_callback(struct ldb_request *req,
559  	                                  struct ldb_reply *ares)
560  	{
561  	    struct mbof_add_operation *addop;
562  	    struct mbof_add_ctx *add_ctx;
563  	    struct ldb_context *ldb;
564  	    struct mbof_ctx *ctx;
565  	    int ret;
566  	
567  	    addop = talloc_get_type(req->context, struct mbof_add_operation);
568  	    add_ctx = addop->add_ctx;
569  	    ctx = add_ctx->ctx;
570  	    ldb = ldb_module_get_ctx(ctx->module);
571  	
572  	    if (!ares) {
573  	        return ldb_module_done(ctx->req, NULL, NULL,
574  	                               LDB_ERR_OPERATIONS_ERROR);
575  	    }
576  	    if (ares->error != LDB_SUCCESS) {
577  	        return ldb_module_done(ctx->req,
578  	                               ares->controls,
579  	                               ares->response,
580  	                               ares->error);
581  	    }
582  	
583  	    switch (ares->type) {
584  	    case LDB_REPLY_ENTRY:
585  	        if (addop->entry != NULL) {
586  	            ldb_debug(ldb, LDB_DEBUG_TRACE,
587  	                           "Found multiple entries for (%s)",
588  	                           ldb_dn_get_linearized(addop->entry_dn));
589  	            /* more than one entry per dn ?? db corrupted ? */
590  	            return ldb_module_done(ctx->req, NULL, NULL,
591  	                                   LDB_ERR_OPERATIONS_ERROR);
592  	        }
593  	
594  	        addop->entry = talloc_steal(addop, ares->message);
595  	        if (addop->entry == NULL) {
596  	            return ldb_module_done(ctx->req, NULL, NULL,
597  	                                   LDB_ERR_OPERATIONS_ERROR);
598  	        }
599  	
600  	        break;
601  	    case LDB_REPLY_REFERRAL:
602  	        /* ignore */
603  	        break;
604  	
605  	    case LDB_REPLY_DONE:
606  	        talloc_zfree(ares);
607  	        if (addop->entry == NULL) {
608  	            ldb_debug(ldb, LDB_DEBUG_TRACE, "Entry not found (%s)",
609  	                           ldb_dn_get_linearized(addop->entry_dn));
610  	
611  	            /* this target does not exists, save as missing */
612  	            ret = mbof_add_missing(add_ctx, addop->entry_dn);
613  	            if (ret != LDB_SUCCESS) {
614  	                return ldb_module_done(ctx->req, NULL, NULL, ret);
615  	            }
616  	            /* now try the next operation */
617  	            if (add_ctx->current_op->next) {
618  	                ret = mbof_next_add(add_ctx->current_op->next);
619  	            }
620  	            else {
621  	                /* no more operations */
622  	                if (add_ctx->missing) {
623  	                    ret = mbof_add_cleanup(add_ctx);
624  	                }
625  	                else if (add_ctx->muops) {
626  	                    ret = mbof_add_muop(add_ctx);
627  	                }
628  	                else {
629  	                    return ldb_module_done(ctx->req,
630  	                                           ctx->ret_ctrls,
631  	                                           ctx->ret_resp,
632  	                                           LDB_SUCCESS);
633  	                }
634  	            }
635  	            if (ret != LDB_SUCCESS) {
636  	                return ldb_module_done(ctx->req, NULL, NULL, ret);
637  	            }
638  	        }
639  	        else {
640  	            ret = mbof_add_operation(addop);
641  	            if (ret != LDB_SUCCESS) {
642  	                return ldb_module_done(ctx->req, NULL, NULL, ret);
643  	            }
644  	        }
645  	        return LDB_SUCCESS;
646  	    }
647  	
648  	    talloc_zfree(ares);
649  	    return LDB_SUCCESS;
650  	}
651  	
652  	/* if it is a group, add all members for cascade effect
653  	 * add memberof attribute to this entry
654  	 */
655  	static int mbof_add_operation(struct mbof_add_operation *addop)
656  	{
657  	
658  	    TALLOC_CTX *tmp_ctx;
659  	    struct mbof_ctx *ctx;
660  	    struct mbof_add_ctx *add_ctx;
661  	    struct ldb_context *ldb;
662  	    struct ldb_message_element *el;
663  	    struct ldb_request *mod_req;
664  	    struct ldb_message *msg;
665  	    struct ldb_dn *elval_dn;
666  	    struct ldb_dn *valdn;
667  	    struct mbof_dn_array *parents;
668  	    int i, j, ret;
669  	    const char *val;
670  	    const char *name;
671  	
672  	    add_ctx = addop->add_ctx;
673  	    ctx = add_ctx->ctx;
674  	    ldb = ldb_module_get_ctx(ctx->module);
675  	
676  	    parents = talloc_zero(add_ctx, struct mbof_dn_array);
677  	    if (!parents) {
678  	        return LDB_ERR_OPERATIONS_ERROR;
679  	    }
680  	    /* can't be more than the immediate parent */
681  	    parents->dns = talloc_array(parents, struct ldb_dn *,
682  	                                addop->parents->num);
683  	    if (!parents->dns) {
684  	        return LDB_ERR_OPERATIONS_ERROR;
685  	    }
686  	
687  	    /* create new parent set for this entry */
688  	    for (i = 0; i < addop->parents->num; i++) {
689  	        /* never add yourself as memberof */
690  	        if (ldb_dn_compare(addop->parents->dns[i], addop->entry_dn) == 0) {
691  	            continue;
692  	        }
693  	        parents->dns[parents->num] = addop->parents->dns[i];
694  	        parents->num++;
695  	    }
696  	
697  	    /* remove entries that are already there */
698  	    el = ldb_msg_find_element(addop->entry, DB_MEMBEROF);
699  	    if (el) {
700  	
701  	        tmp_ctx = talloc_new(addop);
702  	        if (!tmp_ctx) return LDB_ERR_OPERATIONS_ERROR;
703  	
704  	        for (i = 0; i < el->num_values; i++) {
705  	            elval_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
706  	            if (!elval_dn) {
707  	                ldb_debug(ldb, LDB_DEBUG_TRACE, "Invalid DN in memberof [%s]",
708  	                                            (const char *)el->values[i].data);
709  	                talloc_free(tmp_ctx);
710  	                return LDB_ERR_OPERATIONS_ERROR;
711  	            }
712  	            for (j = 0; j < parents->num; j++) {
713  	                if (ldb_dn_compare(parents->dns[j], elval_dn) == 0) {
714  	                    /* duplicate found */
715  	                    break;
716  	                }
717  	            }
718  	            if (j < parents->num) {
719  	                /* remove duplicate */
720  	                for (;j+1 < parents->num; j++) {
721  	                    parents->dns[j] = parents->dns[j+1];
722  	                }
723  	                parents->num--;
724  	            }
725  	        }
726  	
727  	        if (parents->num == 0) {
728  	            /* already contains all parents as memberof, skip to next */
729  	            talloc_free(tmp_ctx);
730  	            talloc_free(addop->entry);
731  	            addop->entry = NULL;
732  	
733  	            if (addop->next) {
734  	                return mbof_next_add(addop->next);
735  	            }
736  	            else if (add_ctx->muops) {
737  	                return mbof_add_muop(add_ctx);
738  	            }
739  	            else {
740  	                /* that was the last entry, get out */
741  	                return ldb_module_done(ctx->req,
742  	                                       ctx->ret_ctrls,
743  	                                       ctx->ret_resp,
744  	                                       LDB_SUCCESS);
745  	            }
746  	        }
747  	        talloc_free(tmp_ctx);
748  	    }
749  	
750  	    /* if it is a group add all members */
751  	    el = ldb_msg_find_element(addop->entry, DB_MEMBER);
752  	    if (el) {
753  	        for (i = 0; i < el->num_values; i++) {
754  	            valdn = ldb_dn_from_ldb_val(add_ctx, ldb, &el->values[i]);
755  	            if (!valdn) {
756  	                ldb_debug(ldb, LDB_DEBUG_TRACE, "Invalid DN in member [%s]",
757  	                                            (const char *)el->values[i].data);
758  	                return LDB_ERR_OPERATIONS_ERROR;
759  	            }
760  	            if (!ldb_dn_validate(valdn)) {
761  	                ldb_debug(ldb, LDB_DEBUG_TRACE,
762  	                               "Invalid DN syntax for member [%s]",
763  	                                            (const char *)el->values[i].data);
764  	                return LDB_ERR_INVALID_DN_SYNTAX;
765  	            }
766  	            ret = mbof_append_addop(add_ctx, parents, valdn);
767  	            if (ret != LDB_SUCCESS) {
768  	                return ret;
769  	            }
770  	        }
771  	    }
772  	
773  	    /* check if we need to store memberuid ops for this entry */
774  	    ret = entry_is_user_object(addop->entry);
775  	    switch (ret) {
776  	    case LDB_SUCCESS:
777  	        /* it's a user object  */
778  	        name = ldb_msg_find_attr_as_string(addop->entry, DB_NAME, NULL);
779  	        if (!name) {
780  	            return LDB_ERR_OPERATIONS_ERROR;
781  	        }
782  	
783  	        for (i = 0; i < parents->num; i++) {
784  	            ret = mbof_append_muop(add_ctx, &add_ctx->muops,
785  	                                   &add_ctx->num_muops,
786  	                                   LDB_FLAG_MOD_ADD,
787  	                                   parents->dns[i], name);
788  	            if (ret != LDB_SUCCESS) {
789  	                return ret;
790  	            }
791  	        }
792  	
793  	        break;
794  	
795  	    case LDB_ERR_NO_SUCH_ATTRIBUTE:
796  	        /* it is not a user object, continue */
797  	        break;
798  	
799  	    default:
800  	        /* an error occured, return */
801  	        return ret;
802  	    }
803  	
804  	    /* we are done with the entry now */
805  	    talloc_free(addop->entry);
806  	    addop->entry = NULL;
807  	
808  	    /* add memberof to entry */
809  	    msg = ldb_msg_new(addop);
810  	    if (!msg) return LDB_ERR_OPERATIONS_ERROR;
811  	
812  	    msg->dn = addop->entry_dn;
813  	
814  	    ret = ldb_msg_add_empty(msg, DB_MEMBEROF, LDB_FLAG_MOD_ADD, &el);
815  	    if (ret != LDB_SUCCESS) {
816  	        return ret;
817  	    }
818  	    el->values = talloc_array(msg, struct ldb_val, parents->num);
819  	    if (!el->values) {
820  	        return LDB_ERR_OPERATIONS_ERROR;
821  	    }
822  	    for (i = 0, j = 0; i < parents->num; i++) {
823  	        if (ldb_dn_compare(parents->dns[i], msg->dn) == 0) continue;
824  	        val = ldb_dn_get_linearized(parents->dns[i]);
825  	        el->values[j].length = strlen(val);
826  	        el->values[j].data = (uint8_t *)talloc_strdup(el->values, val);
827  	        if (!el->values[j].data) {
828  	            return LDB_ERR_OPERATIONS_ERROR;
829  	        }
830  	        j++;
831  	    }
832  	    el->num_values = j;
833  	
834  	    ret = ldb_build_mod_req(&mod_req, ldb, add_ctx,
835  	                            msg, NULL,
836  	                            add_ctx, mbof_add_callback,
837  	                            ctx->req);
838  	    if (ret != LDB_SUCCESS) {
839  	        return ret;
840  	    }
841  	    talloc_steal(mod_req, msg);
842  	
843  	    return ldb_next_request(ctx->module, mod_req);
844  	}
845  	
846  	static int mbof_add_missing(struct mbof_add_ctx *add_ctx, struct ldb_dn *dn)
847  	{
848  	    struct mbof_dn *mdn;
849  	
850  	    mdn = talloc(add_ctx, struct mbof_dn);
851  	    if (!mdn) {
852  	        return LDB_ERR_OPERATIONS_ERROR;
853  	    }
854  	    mdn->dn = talloc_steal(mdn, dn);
855  	
856  	    /* add to the list */
857  	    mdn->next = add_ctx->missing;
858  	    add_ctx->missing = mdn;
859  	
860  	    return LDB_SUCCESS;
861  	}
862  	
863  	/* remove unexisting members and add memberuid attribute */
864  	static int mbof_add_cleanup(struct mbof_add_ctx *add_ctx)
865  	{
866  	    struct ldb_context *ldb;
867  	    struct ldb_message *msg;
868  	    struct ldb_request *mod_req;
869  	    struct ldb_message_element *el;
870  	    struct mbof_ctx *ctx;
871  	    struct mbof_dn *iter;
872  	    const char *val;
873  	    int ret, i, num;
874  	
875  	    ctx = add_ctx->ctx;
876  	    ldb = ldb_module_get_ctx(ctx->module);
877  	
878  	    num = 0;
879  	    for (iter = add_ctx->missing; iter; iter = iter->next) {
880  	        num++;
881  	    }
882  	    if (num == 0) {
883  	        return LDB_ERR_OPERATIONS_ERROR;
884  	    }
885  	
886  	    msg = ldb_msg_new(add_ctx);
887  	    if (!msg) return LDB_ERR_OPERATIONS_ERROR;
888  	
889  	    msg->dn = add_ctx->msg_dn;
890  	
891  	    ret = ldb_msg_add_empty(msg, DB_MEMBER, LDB_FLAG_MOD_DELETE, &el);
892  	    if (ret != LDB_SUCCESS) {
893  	        return ret;
894  	    }
895  	    el->values = talloc_array(msg, struct ldb_val, num);
896  	    if (!el->values) {
897  	        return LDB_ERR_OPERATIONS_ERROR;
898  	    }
899  	    el->num_values = num;
900  	    for (i = 0, iter = add_ctx->missing; iter; iter = iter->next, i++) {
901  	        val = ldb_dn_get_linearized(iter->dn);
902  	        el->values[i].length = strlen(val);
903  	        el->values[i].data = (uint8_t *)talloc_strdup(el->values, val);
904  	        if (!el->values[i].data) {
905  	            return LDB_ERR_OPERATIONS_ERROR;
906  	        }
907  	    }
908  	
909  	    ret = ldb_build_mod_req(&mod_req, ldb, add_ctx,
910  	                            msg, NULL,
911  	                            add_ctx, mbof_add_cleanup_callback,
912  	                            ctx->req);
913  	    if (ret != LDB_SUCCESS) {
914  	        return ret;
915  	    }
916  	
917  	    return ldb_next_request(ctx->module, mod_req);
918  	}
919  	
920  	static int mbof_add_cleanup_callback(struct ldb_request *req,
921  	                                     struct ldb_reply *ares)
922  	{
923  	    struct mbof_add_ctx *add_ctx;
924  	    struct mbof_ctx *ctx;
925  	    int ret;
926  	
927  	    add_ctx = talloc_get_type(req->context, struct mbof_add_ctx);
928  	    ctx = add_ctx->ctx;
929  	
930  	    if (!ares) {
931  	        return ldb_module_done(ctx->req, NULL, NULL,
932  	                               LDB_ERR_OPERATIONS_ERROR);
933  	    }
934  	    if (ares->error != LDB_SUCCESS) {
935  	        return ldb_module_done(ctx->req,
936  	                               ares->controls,
937  	                               ares->response,
938  	                               ares->error);
939  	    }
940  	
941  	    switch (ares->type) {
942  	    case LDB_REPLY_ENTRY:
943  	        /* shouldn't happen */
944  	        talloc_zfree(ares);
945  	        return ldb_module_done(ctx->req, NULL, NULL,
946  	                               LDB_ERR_OPERATIONS_ERROR);
947  	    case LDB_REPLY_REFERRAL:
948  	        /* ignore */
949  	        break;
950  	
951  	    case LDB_REPLY_DONE:
952  	        if (add_ctx->muops) {
953  	            ret = mbof_add_muop(add_ctx);
954  	        }
955  	        else {
956  	            return ldb_module_done(ctx->req,
957  	                                   ctx->ret_ctrls,
958  	                                   ctx->ret_resp,
959  	                                   LDB_SUCCESS);
960  	        }
961  	
962  	        if (ret != LDB_SUCCESS) {
963  	            talloc_zfree(ares);
964  	            return ldb_module_done(ctx->req, NULL, NULL, ret);
965  	        }
966  	    }
967  	
968  	    talloc_zfree(ares);
969  	    return LDB_SUCCESS;
970  	}
971  	
972  	/* add memberuid attributes to parent groups */
973  	static int mbof_add_muop(struct mbof_add_ctx *add_ctx)
974  	{
975  	    struct ldb_context *ldb;
976  	    struct ldb_message *msg;
977  	    struct ldb_request *mod_req;
978  	    struct mbof_ctx *ctx;
979  	    int ret;
980  	
981  	    ctx = add_ctx->ctx;
982  	    ldb = ldb_module_get_ctx(ctx->module);
983  	
984  	    msg = ldb_msg_new(add_ctx);
985  	    if (!msg) return LDB_ERR_OPERATIONS_ERROR;
986  	
987  	    msg->dn = add_ctx->muops[add_ctx->cur_muop].dn;
988  	    msg->elements = add_ctx->muops[add_ctx->cur_muop].el;
989  	    msg->num_elements = 1;
990  	
991  	    ret = ldb_build_mod_req(&mod_req, ldb, add_ctx,
992  	                            msg, NULL,
993  	                            add_ctx, mbof_add_muop_callback,
994  	                            ctx->req);
995  	    if (ret != LDB_SUCCESS) {
996  	        return ret;
997  	    }
998  	
999  	    return ldb_next_request(ctx->module, mod_req);
1000 	}
1001 	
1002 	static int mbof_add_muop_callback(struct ldb_request *req,
1003 	                                  struct ldb_reply *ares)
1004 	{
1005 	    struct mbof_add_ctx *add_ctx;
1006 	    struct mbof_ctx *ctx;
1007 	    int ret;
1008 	
1009 	    add_ctx = talloc_get_type(req->context, struct mbof_add_ctx);
1010 	    ctx = add_ctx->ctx;
1011 	
1012 	    if (!ares) {
1013 	        return ldb_module_done(ctx->req, NULL, NULL,
1014 	                               LDB_ERR_OPERATIONS_ERROR);
1015 	    }
1016 	    if (ares->error != LDB_SUCCESS) {
1017 	        return ldb_module_done(ctx->req,
1018 	                               ares->controls,
1019 	                               ares->response,
1020 	                               ares->error);
1021 	    }
1022 	
1023 	    switch (ares->type) {
1024 	    case LDB_REPLY_ENTRY:
1025 	        /* shouldn't happen */
1026 	        talloc_zfree(ares);
1027 	        return ldb_module_done(ctx->req, NULL, NULL,
1028 	                               LDB_ERR_OPERATIONS_ERROR);
1029 	    case LDB_REPLY_REFERRAL:
1030 	        /* ignore */
1031 	        break;
1032 	
1033 	    case LDB_REPLY_DONE:
1034 	        add_ctx->cur_muop++;
1035 	        if (add_ctx->cur_muop < add_ctx->num_muops) {
1036 	            ret = mbof_add_muop(add_ctx);
1037 	        }
1038 	        else {
1039 	            return ldb_module_done(ctx->req,
1040 	                                   ctx->ret_ctrls,
1041 	                                   ctx->ret_resp,
1042 	                                   LDB_SUCCESS);
1043 	        }
1044 	
1045 	        if (ret != LDB_SUCCESS) {
1046 	            talloc_zfree(ares);
1047 	            return ldb_module_done(ctx->req, NULL, NULL, ret);
1048 	        }
1049 	    }
1050 	
1051 	    talloc_zfree(ares);
1052 	    return LDB_SUCCESS;
1053 	}
1054 	
1055 	
1056 	
1057 	
1058 	/* delete operations */
1059 	
1060 	/* The implementation of delete operations is a bit more complex than an add
1061 	 * operation. This is because we need to recompute memberships of potentially
1062 	 * quite far descendants and we also have to account for loops and how to
1063 	 * break them without ending in an endless loop ourselves.
1064 	 * The difficulty is in the fact that while the member -> memberof link is
1065 	 * direct, memberof -> member is not as membership is transitive.
1066 	 *
1067 	 * Ok, first of all, contrary to the add operation, a delete operation
1068 	 * involves an existing object that may have existing parents. So, first, we
1069 	 * search  the object itself to get the original membership lists (member and
1070 	 * memberof) for this object, and we also search for any object that has it as
1071 	 * one of its members.
1072 	 * Once we have the results, we store object and parents and proceed with the
1073 	 * original operation to make sure it is valid.
1074 	 *
1075 	 * Once the original op returns we proceed fixing parents (parents being each
1076 	 * object that has the delete operation target object as member), if any.
1077 	 *
1078 	 * For each parent we retrieved we proceed to delete the member attribute that
1079 	 * points to the object we just deleted. Once done for all parents (or if no
1080 	 * parents exists), we proceed with the children and descendants.
1081 	 *
1082 	 * To handle the children we create a first ancestor operation that reflects
1083 	 * the delete we just made. We set as parents of this object the parents just
1084 	 * retrieved with the first search. Then we create a remove list.
1085 	 *
1086 	 * The remove list contains all objects in the original memberof list and the
1087 	 * object dn itself of the original delete operation target object (the first
1088 	 * ancestor).
1089 	 *
1090 	 * An operation is identified by an object that contains a tree of
1091 	 * descendants:
1092 	 * The remove list for the children, the immediate parent, and the dn and
1093 	 * entry of the object this operation is about.
1094 	 *
1095 	 * We now proceed with adding a new operation for each original member of the
1096 	 * first ancestor.
1097 	 *
1098 	 * In each operation we must first lookup the target object and each immediate
1099 	 * parent (all the objects in the tree that have target as a "member").
1100 	 *
1101 	 * Then we proceed to calculate the new memberof list that we are going to set
1102 	 * on the target object.
1103 	 * The new memberof list starts with including all the objects that have the
1104 	 * target as their direct member.
1105 	 * Finally for each entry in this provisional new memberof list we add all its
1106 	 * memberof elements to the new memberof list (taking care of excluding
1107 	 * duplicates). This way we are certain all direct and indirect membership are
1108 	 * accounted for.
1109 	 *
1110 	 * At this point we have the final new memberof list for this operation and we
1111 	 * can proceed to modify the entry.
1112 	 *
1113 	 * Once the entry has been modified we proceed again to check if there are any
1114 	 * children of this entry (the entry has "member"s).
1115 	 * We create a new remove list that is the difference between the original
1116 	 * entry memberof list and the new memberof list we just stored back in the
1117 	 * object.
1118 	 * Then for each member we create a new operation.
1119 	 *
1120 	 * We continue to process operations until no new operations need to be
1121 	 * performed.
1122 	 *
1123 	 * Ordering is important here, se the mbof_del_get_next() function to
1124 	 * understand how we proceed to select which new operation to process.
1125 	 *
1126 	 * As a final operation remove any memberuid corresponding to a removal of
1127 	 * a memberof field from a user entry
1128 	 */
1129 	
1130 	static int mbof_del_search_callback(struct ldb_request *req,
1131 	                                    struct ldb_reply *ares);
1132 	static int mbof_orig_del(struct mbof_del_ctx *ctx);
1133 	static int mbof_orig_del_callback(struct ldb_request *req,
1134 	                                  struct ldb_reply *ares);
1135 	static int mbof_del_cleanup_parents(struct mbof_del_ctx *del_ctx);
1136 	static int mbof_del_clean_par_callback(struct ldb_request *req,
1137 	                                       struct ldb_reply *ares);
1138 	static int mbof_del_cleanup_children(struct mbof_del_ctx *del_ctx);
1139 	static int mbof_append_delop(struct mbof_del_operation *parent,
1140 	                             struct ldb_dn *entry_dn);
1141 	static int mbof_del_execute_op(struct mbof_del_operation *delop);
1142 	static int mbof_del_exop_search_callback(struct ldb_request *req,
1143 	                                         struct ldb_reply *ares);
1144 	static int mbof_del_execute_cont(struct mbof_del_operation *delop);
1145 	static int mbof_del_ancestors(struct mbof_del_operation *delop);
1146 	static int mbof_del_anc_callback(struct ldb_request *req,
1147 	                                 struct ldb_reply *ares);
1148 	static int mbof_del_mod_entry(struct mbof_del_operation *delop);
1149 	static int mbof_del_mod_callback(struct ldb_request *req,
1150 	                                 struct ldb_reply *ares);
1151 	static int mbof_del_progeny(struct mbof_del_operation *delop);
1152 	static int mbof_del_get_next(struct mbof_del_operation *delop,
1153 	                             struct mbof_del_operation **nextop);
1154 	static int mbof_del_fill_muop(struct mbof_del_ctx *del_ctx,
1155 	                              struct ldb_message *entry);
1156 	static int mbof_del_muop(struct mbof_del_ctx *ctx);
1157 	static int mbof_del_muop_callback(struct ldb_request *req,
1158 	                                  struct ldb_reply *ares);
1159 	
1160 	
1161 	static int memberof_del(struct ldb_module *module, struct ldb_request *req)
1162 	{
1163 	    static const char *attrs[] = { DB_OC, DB_NAME,
1164 	                                   DB_MEMBER, DB_MEMBEROF, NULL };
1165 	    struct ldb_context *ldb = ldb_module_get_ctx(module);
1166 	    struct mbof_del_operation *first;
1167 	    struct ldb_request *search;
1168 	    char *expression;
1169 	    const char *dn;
1170 	    struct mbof_del_ctx *del_ctx;
1171 	    struct mbof_ctx *ctx;
1172 	    int ret;
1173 	
1174 	    if (ldb_dn_is_special(req->op.del.dn)) {
1175 	        /* do not manipulate our control entries */
1176 	        return ldb_next_request(module, req);
1177 	    }
1178 	
1179 	    ctx = mbof_init(module, req);
1180 	    if (!ctx) {
1181 	        return LDB_ERR_OPERATIONS_ERROR;
1182 	    }
1183 	
1184 	    del_ctx = talloc_zero(ctx, struct mbof_del_ctx);
1185 	    if (!del_ctx) {
1186 	        talloc_free(ctx);
1187 	        return LDB_ERR_OPERATIONS_ERROR;
1188 	    }
1189 	    del_ctx->ctx = ctx;
1190 	
1191 	    /* create first entry */
1192 	    /* the first entry is the parent of all entries and the one where we remove
1193 	     * member from, it does not get the same treatment as others */
1194 	    first = talloc_zero(del_ctx, struct mbof_del_operation);
1195 	    if (!first) {
1196 	        talloc_free(ctx);
1197 	        return LDB_ERR_OPERATIONS_ERROR;
1198 	    }
1199 	    del_ctx->first = first;
1200 	
1201 	    first->del_ctx = del_ctx;
1202 	    first->entry_dn = req->op.del.dn;
1203 	
1204 	    dn = ldb_dn_get_linearized(req->op.del.dn);
1205 	    if (!dn) {
1206 	        talloc_free(ctx);
1207 	        return LDB_ERR_OPERATIONS_ERROR;
1208 	    }
1209 	    expression = talloc_asprintf(del_ctx,
1210 	                                 "(|(distinguishedName=%s)(%s=%s))",
1211 	                                 dn, DB_MEMBER, dn);
1212 	    if (!expression) {
1213 	        talloc_free(ctx);
1214 	        return LDB_ERR_OPERATIONS_ERROR;
1215 	    }
1216 	
1217 	    ret = ldb_build_search_req(&search, ldb, del_ctx,
1218 	                               NULL, LDB_SCOPE_SUBTREE,
1219 	                               expression, attrs, NULL,
1220 	                               first, mbof_del_search_callback,
1221 	                               req);
1222 	    if (ret != LDB_SUCCESS) {
1223 	        talloc_free(ctx);
1224 	        return ret;
1225 	    }
1226 	
1227 	    return ldb_request(ldb, search);
1228 	}
1229 	
1230 	static int mbof_del_search_callback(struct ldb_request *req,
1231 	                                    struct ldb_reply *ares)
1232 	{
1233 	    struct mbof_del_operation *first;
1234 	    struct ldb_context *ldb;
1235 	    struct ldb_message *msg;
1236 	    struct mbof_del_ctx *del_ctx;
1237 	    struct mbof_ctx *ctx;
1238 	    int ret;
1239 	
1240 	    first = talloc_get_type(req->context, struct mbof_del_operation);
1241 	    del_ctx = first->del_ctx;
1242 	    ctx = del_ctx->ctx;
1243 	    ldb = ldb_module_get_ctx(ctx->module);
1244 	
1245 	    if (!ares) {
1246 	        return ldb_module_done(ctx->req, NULL, NULL,
1247 	                               LDB_ERR_OPERATIONS_ERROR);
1248 	    }
1249 	    if (ares->error != LDB_SUCCESS) {
1250 	        return ldb_module_done(ctx->req,
1251 	                               ares->controls,
1252 	                               ares->response,
1253 	                               ares->error);
1254 	    }
1255 	
1256 	    switch (ares->type) {
1257 	    case LDB_REPLY_ENTRY:
1258 	        msg = ares->message;
1259 	
1260 	        if (ldb_dn_compare(msg->dn, ctx->req->op.del.dn) == 0) {
1261 	
1262 	            if (first->entry != NULL) {
1263 	                /* more than one entry per dn ?? db corrupted ? */
1264 	                return ldb_module_done(ctx->req, NULL, NULL,
1265 	                                       LDB_ERR_OPERATIONS_ERROR);
1266 	            }
1267 	
1268 	            first->entry = talloc_steal(first, msg);
1269 	            if (first->entry == NULL) {
1270 	                return ldb_module_done(ctx->req, NULL, NULL,
1271 	                                       LDB_ERR_OPERATIONS_ERROR);
1272 	            }
1273 	        } else {
1274 	            first->parents = talloc_realloc(first, first->parents,
1275 	                                             struct ldb_message *,
1276 	                                             first->num_parents + 1);
1277 	            if (!first->parents) {
1278 	                return ldb_module_done(ctx->req, NULL, NULL,
1279 	                                       LDB_ERR_OPERATIONS_ERROR);
1280 	            }
1281 	            msg = talloc_steal(first->parents, ares->message);
1282 	            if (!msg) {
1283 	                return ldb_module_done(ctx->req, NULL, NULL,
1284 	                                       LDB_ERR_OPERATIONS_ERROR);
1285 	            }
1286 	            first->parents[first->num_parents] = msg;
1287 	            first->num_parents++;
1288 	        }
1289 	        break;
1290 	    case LDB_REPLY_REFERRAL:
1291 	        /* ignore */
1292 	        break;
1293 	
1294 	    case LDB_REPLY_DONE:
1295 	        if (first->entry == NULL) {
1296 	            /* this target does not exists, too bad! */
1297 	            ldb_debug(ldb, LDB_DEBUG_TRACE,
1298 	                           "Target entry (%s) not found",
1299 	                           ldb_dn_get_linearized(first->entry_dn));
1300 	            return ldb_module_done(ctx->req, NULL, NULL,
1301 	                                   LDB_ERR_NO_SUCH_OBJECT);
1302 	        }
1303 	
1304 	        /* now perform the requested delete, before proceeding further */
1305 	        ret =  mbof_orig_del(del_ctx);
1306 	        if (ret != LDB_SUCCESS) {
1307 	            talloc_zfree(ares);
1308 	            return ldb_module_done(ctx->req, NULL, NULL, ret);
1309 	        }
1310 	    }
1311 	
1312 	    talloc_zfree(ares);
1313 	    return LDB_SUCCESS;
1314 	}
1315 	
1316 	static int mbof_orig_del(struct mbof_del_ctx *del_ctx)
1317 	{
1318 	    struct ldb_request *del_req;
1319 	    struct mbof_ctx *ctx;
1320 	    int ret;
1321 	
1322 	    ctx = del_ctx->ctx;
1323 	
1324 	    ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ctx->module),
1325 	                            ctx->req, ctx->req->op.del.dn, NULL,
1326 	                            del_ctx, mbof_orig_del_callback,
1327 	                            ctx->req);
1328 	    if (ret != LDB_SUCCESS) {
1329 	        return ret;
1330 	    }
1331 	
1332 	    return ldb_next_request(ctx->module, del_req);
1333 	}
1334 	
1335 	static int mbof_orig_del_callback(struct ldb_request *req,
1336 	                                  struct ldb_reply *ares)
1337 	{
1338 	    struct ldb_context *ldb;
1339 	    struct mbof_del_ctx *del_ctx;
1340 	    struct mbof_ctx *ctx;
1341 	    int ret;
1342 	
1343 	    del_ctx = talloc_get_type(req->context, struct mbof_del_ctx);
1344 	    ctx = del_ctx->ctx;
1345 	    ldb = ldb_module_get_ctx(ctx->module);
1346 	
1347 	    if (!ares) {
1348 	        return ldb_module_done(ctx->req, NULL, NULL,
1349 	                               LDB_ERR_OPERATIONS_ERROR);
1350 	    }
1351 	    if (ares->error != LDB_SUCCESS) {
1352 	        return ldb_module_done(ctx->req,
1353 	                               ares->controls,
1354 	                               ares->response,
1355 	                               ares->error);
1356 	    }
1357 	
1358 	    if (ares->type != LDB_REPLY_DONE) {
1359 	        talloc_zfree(ares);
1360 	        ldb_set_errstring(ldb, "Invalid reply type!");
1361 	        return ldb_module_done(ctx->req, NULL, NULL,
1362 	                               LDB_ERR_OPERATIONS_ERROR);
1363 	    }
1364 	
1365 	    /* save real call stuff */
1366 	    ctx->ret_ctrls = talloc_steal(ctx, ares->controls);
1367 	    ctx->ret_resp = talloc_steal(ctx, ares->response);
1368 	
1369 	    /* prep following clean ops */
1370 	    if (del_ctx->first->num_parents) {
1371 	
1372 	        /* if there are parents there may be memberuids to remove */
1373 	        ret = mbof_del_fill_muop(del_ctx, del_ctx->first->entry);
1374 	        if (ret != LDB_SUCCESS) {
1375 	            talloc_zfree(ares);
1376 	            return ldb_module_done(ctx->req, NULL, NULL, ret);
1377 	        }
1378 	
1379 	        /* if there are any parents, fire a removal sequence */
1380 	        ret = mbof_del_cleanup_parents(del_ctx);
1381 	    }
1382 	    else if (ldb_msg_find_element(del_ctx->first->entry, DB_MEMBER)) {
1383 	        /* if there are any children, fire a removal sequence */
1384 	        ret = mbof_del_cleanup_children(del_ctx);
1385 	    }
1386 	    /* see if there are memberuid operations to perform */
1387 	    else if (del_ctx->muops) {
1388 	        return mbof_del_muop(del_ctx);
1389 	    }
1390 	    else {
1391 	        /* no parents nor children, end ops */
1392 	        return ldb_module_done(ctx->req,
1393 	                               ares->controls,
1394 	                               ares->response,
1395 	                               LDB_SUCCESS);
1396 	    }
1397 	    if (ret != LDB_SUCCESS) {
1398 	        talloc_zfree(ares);
1399 	        return ldb_module_done(ctx->req, NULL, NULL, ret);
1400 	    }
1401 	
1402 	    talloc_zfree(ares);
1403 	    return LDB_SUCCESS;
1404 	}
1405 	
1406 	static int mbof_del_cleanup_parents(struct mbof_del_ctx *del_ctx)
1407 	{
1408 	    struct mbof_del_operation *first;
1409 	    struct mbof_ctx *ctx;
1410 	    struct ldb_context *ldb;
1411 	    struct ldb_request *mod_req;
1412 	    struct ldb_message *msg;
1413 	    struct ldb_message_element *el;
1414 	    const char *val;
1415 	    int ret;
1416 	
1417 	    first = del_ctx->first;
1418 	    ctx = del_ctx->ctx;
1419 	    ldb = ldb_module_get_ctx(ctx->module);
1420 	
1421 	    msg = ldb_msg_new(first->parents);
1422 	    if (!msg) return LDB_ERR_OPERATIONS_ERROR;
1423 	
1424 	    msg->dn = first->parents[first->cur_parent]->dn;
1425 	    first->cur_parent++;
1426 	
1427 	    ret = ldb_msg_add_empty(msg, DB_MEMBER, LDB_FLAG_MOD_DELETE, &el);
1428 	    if (ret != LDB_SUCCESS) {
1429 	        return ret;
1430 	    }
1431 	    el->values = talloc_array(msg, struct ldb_val, 1);
1432 	    if (!el->values) {
1433 	        return LDB_ERR_OPERATIONS_ERROR;
1434 	    }
1435 	    val = ldb_dn_get_linearized(first->entry_dn);
1436 	    el->values[0].length = strlen(val);
1437 	    el->values[0].data = (uint8_t *)talloc_strdup(el->values, val);
1438 	    if (!el->values[0].data) {
1439 	        return LDB_ERR_OPERATIONS_ERROR;
1440 	    }
1441 	    el->num_values = 1;
1442 	
1443 	    ret = ldb_build_mod_req(&mod_req, ldb, first->parents,
1444 	                            msg, NULL,
1445 	                            del_ctx, mbof_del_clean_par_callback,
1446 	                            ctx->req);
1447 	    if (ret != LDB_SUCCESS) {
1448 	        return ret;
1449 	    }
1450 	
1451 	    return ldb_next_request(ctx->module, mod_req);
1452 	}
1453 	
1454 	static int mbof_del_clean_par_callback(struct ldb_request *req,
1455 	                                       struct ldb_reply *ares)
1456 	{
1457 	    struct mbof_del_operation *first;
1458 	    struct ldb_context *ldb;
1459 	    struct mbof_del_ctx *del_ctx;
1460 	    struct mbof_ctx *ctx;
1461 	    int ret;
1462 	
1463 	    del_ctx = talloc_get_type(req->context, struct mbof_del_ctx);
1464 	    first = del_ctx->first;
1465 	    ctx = del_ctx->ctx;
1466 	    ldb = ldb_module_get_ctx(ctx->module);
1467 	
1468 	    if (!ares) {
1469 	        return ldb_module_done(ctx->req, NULL, NULL,
1470 	                               LDB_ERR_OPERATIONS_ERROR);
1471 	    }
1472 	
1473 	    if (ares->error != LDB_SUCCESS) {
1474 	        return ldb_module_done(ctx->req,
1475 	                               ares->controls,
1476 	                               ares->response,
1477 	                               ares->error);
1478 	    }
1479 	
1480 	    if (ares->type != LDB_REPLY_DONE) {
1481 	        talloc_zfree(ares);
1482 	        ldb_set_errstring(ldb, "Invalid reply type!");
1483 	        return ldb_module_done(ctx->req, NULL, NULL,
1484 	                               LDB_ERR_OPERATIONS_ERROR);
1485 	    }
1486 	
1487 	    if (first->num_parents > first->cur_parent) {
1488 	        /* still parents to cleanup, go on */
1489 	        ret = mbof_del_cleanup_parents(del_ctx);
1490 	    }
1491 	    else {
1492 	        /* continue */
1493 	        if (ldb_msg_find_element(first->entry, DB_MEMBER)) {
1494 	            /* if there are any children, fire a removal sequence */
1495 	            ret = mbof_del_cleanup_children(del_ctx);
1496 	        }
1497 	        /* see if there are memberuid operations to perform */
1498 	        else if (del_ctx->muops) {
1499 	            return mbof_del_muop(del_ctx);
1500 	        }
1501 	        else {
1502 	            /* no children, end ops */
1503 	            return ldb_module_done(ctx->req,
1504 	                                   ctx->ret_ctrls,
1505 	                                   ctx->ret_resp,
1506 	                                   LDB_SUCCESS);
1507 	        }
1508 	    }
1509 	
1510 	    if (ret != LDB_SUCCESS) {
1511 	        talloc_zfree(ares);
1512 	        return ldb_module_done(ctx->req, NULL, NULL, ret);
1513 	    }
1514 	
1515 	    talloc_zfree(ares);
1516 	    return LDB_SUCCESS;
1517 	}
1518 	
1519 	static int mbof_del_cleanup_children(struct mbof_del_ctx *del_ctx)
1520 	{
1521 	    struct mbof_del_operation *first;
1522 	    struct mbof_ctx *ctx;
1523 	    struct ldb_context *ldb;
1524 	    const struct ldb_message_element *el;
1525 	    struct ldb_dn *valdn;
1526 	    int i, ret;
1527 	
1528 	    first = del_ctx->first;
1529 	    ctx = del_ctx->ctx;
1530 	    ldb = ldb_module_get_ctx(ctx->module);
1531 	
1532 	    el = ldb_msg_find_element(first->entry, DB_MEMBER);
1533 	
1534 	    /* prepare del sets */
1535 	    for (i = 0; i < el->num_values; i++) {
1536 	        valdn = ldb_dn_from_ldb_val(first, ldb, &el->values[i]);
1537 	        if (!valdn || !ldb_dn_validate(valdn)) {
1538 	            ldb_debug(ldb, LDB_DEBUG_TRACE,
1539 	                           "Invalid dn syntax for member [%s]",
1540 	                                        (const char *)el->values[i].data);
1541 	            return LDB_ERR_INVALID_DN_SYNTAX;
1542 	        }
1543 	        ret = mbof_append_delop(first, valdn);
1544 	        if (ret != LDB_SUCCESS) {
1545 	            return ret;
1546 	        }
1547 	    }
1548 	
1549 	    /* now that sets are built, start processing */
1550 	    return mbof_del_execute_op(first->children[0]);
1551 	}
1552 	
1553 	static int mbof_append_delop(struct mbof_del_operation *parent,
1554 	                             struct ldb_dn *entry_dn)
1555 	{
1556 	    struct mbof_del_operation *delop;
1557 	
1558 	    delop = talloc_zero(parent, struct mbof_del_operation);
1559 	    if (!delop) {
1560 	        return LDB_ERR_OPERATIONS_ERROR;
1561 	    }
1562 	
1563 	    delop->del_ctx = parent->del_ctx;
1564 	    delop->parent = parent;
1565 	    delop->entry_dn = entry_dn;
1566 	
1567 	    parent->children = talloc_realloc(parent, parent->children,
1568 	                                      struct mbof_del_operation *,
1569 	                                      parent->num_children +1);
1570 	    if (!parent->children) {
1571 	        talloc_free(delop);
1572 	        return LDB_ERR_OPERATIONS_ERROR;
1573 	    }
1574 	
1575 	    parent->children[parent->num_children] = delop;
1576 	    parent->num_children++;
1577 	
1578 	    return LDB_SUCCESS;
1579 	}
1580 	
1581 	static int mbof_del_execute_op(struct mbof_del_operation *delop)
1582 	{
1583 	    struct mbof_del_ctx *del_ctx;
1584 	    struct mbof_ctx *ctx;
1585 	    struct ldb_context *ldb;
1586 	    struct ldb_request *search;
1587 	    char *expression;
1588 	    const char *dn;
1589 	    static const char *attrs[] = { DB_OC, DB_NAME,
1590 	                                   DB_MEMBER, DB_MEMBEROF, NULL };
1591 	    int ret;
1592 	
1593 	    del_ctx = delop->del_ctx;
1594 	    ctx = del_ctx->ctx;
1595 	    ldb = ldb_module_get_ctx(ctx->module);
1596 	
1597 	    /* load entry */
1598 	    dn = ldb_dn_get_linearized(delop->entry_dn);
1599 	    if (!dn) {
1600 	        return LDB_ERR_OPERATIONS_ERROR;
1601 	    }
1602 	    expression = talloc_asprintf(del_ctx,
1603 	                                 "(|(distinguishedName=%s)(%s=%s))",
1604 	                                 dn, DB_MEMBER, dn);
1605 	    if (!expression) {
1606 	        return LDB_ERR_OPERATIONS_ERROR;
1607 	    }
1608 	
1609 	    ret = ldb_build_search_req(&search, ldb, delop,
1610 	                               NULL, LDB_SCOPE_SUBTREE,
1611 	                               expression, attrs, NULL,
1612 	                               delop, mbof_del_exop_search_callback,
1613 	                               ctx->req);
1614 	    if (ret != LDB_SUCCESS) {
1615 	        talloc_free(ctx);
1616 	        return ret;
1617 	    }
1618 	
1619 	    return ldb_request(ldb, search);
1620 	}
1621 	
1622 	static int mbof_del_exop_search_callback(struct ldb_request *req,
1623 	                                         struct ldb_reply *ares)
1624 	{
1625 	    struct mbof_del_operation *delop;
1626 	    struct mbof_del_ctx *del_ctx;
1627 	    struct ldb_context *ldb;
1628 	    struct mbof_ctx *ctx;
1629 	    struct ldb_message *msg;
1630 	    int ret;
1631 	
1632 	    delop = talloc_get_type(req->context, struct mbof_del_operation);
1633 	    del_ctx = delop->del_ctx;
1634 	    ctx = del_ctx->ctx;
1635 	    ldb = ldb_module_get_ctx(ctx->module);
1636 	
1637 	    if (!ares) {
1638 	        return ldb_module_done(ctx->req, NULL, NULL,
1639 	                               LDB_ERR_OPERATIONS_ERROR);
1640 	    }
1641 	    if (ares->error != LDB_SUCCESS) {
1642 	        return ldb_module_done(ctx->req,
1643 	                               ares->controls,
1644 	                               ares->response,
1645 	                               ares->error);
1646 	    }
1647 	
1648 	    switch (ares->type) {
1649 	    case LDB_REPLY_ENTRY:
1650 	        msg = ares->message;
1651 	
1652 	        if (ldb_dn_compare(msg->dn, delop->entry_dn) == 0) {
1653 	
1654 	            if (delop->entry != NULL) {
1655 	                ldb_debug(ldb, LDB_DEBUG_TRACE,
1656 	                               "Found multiple entries for (%s)",
1657 	                               ldb_dn_get_linearized(delop->entry_dn));
1658 	                /* more than one entry per dn ?? db corrupted ? */
1659 	                return ldb_module_done(ctx->req, NULL, NULL,
1660 	                                       LDB_ERR_OPERATIONS_ERROR);
1661 	            }
1662 	
1663 	            delop->entry = talloc_steal(delop, msg);
1664 	            if (delop->entry == NULL) {
1665 	                return ldb_module_done(ctx->req, NULL, NULL,
1666 	                                       LDB_ERR_OPERATIONS_ERROR);
1667 	            }
1668 	        } else {
1669 	            delop->parents = talloc_realloc(delop, delop->parents,
1670 	                                            struct ldb_message *,
1671 	                                            delop->num_parents + 1);
1672 	            if (!delop->parents) {
1673 	                return ldb_module_done(ctx->req, NULL, NULL,
1674 	                                       LDB_ERR_OPERATIONS_ERROR);
1675 	            }
1676 	            msg = talloc_steal(delop->parents, msg);
1677 	            if (!msg) {
1678 	                return ldb_module_done(ctx->req, NULL, NULL,
1679 	                                       LDB_ERR_OPERATIONS_ERROR);
1680 	            }
1681 	            delop->parents[delop->num_parents] = msg;
1682 	            delop->num_parents++;
1683 	        }
1684 	        break;
1685 	    case LDB_REPLY_REFERRAL:
1686 	        /* ignore */
1687 	        break;
1688 	
1689 	    case LDB_REPLY_DONE:
1690 	        if (delop->entry == NULL) {
1691 	            /* no target, no party! */
1692 	            return ldb_module_done(ctx->req, NULL, NULL,
1693 	                                   LDB_ERR_OPERATIONS_ERROR);
1694 	        }
1695 	
1696 	        /* ok process the entry */
1697 	        ret = mbof_del_execute_cont(delop);
1698 	
1699 	        if (ret != LDB_SUCCESS) {
1700 	            return ldb_module_done(ctx->req, NULL, NULL,
1701 	                                   LDB_ERR_OPERATIONS_ERROR);
1702 	        }
1703 	    }
1704 	
1705 	    talloc_zfree(ares);
1706 	    return LDB_SUCCESS;
1707 	}
1708 	
1709 	static int mbof_del_execute_cont(struct mbof_del_operation *delop)
1710 	{
1711 	    struct mbof_del_ancestors_ctx *anc_ctx;
1712 	    struct mbof_del_operation *parent;
1713 	    struct mbof_del_ctx *del_ctx;
1714 	    struct mbof_ctx *ctx;
1715 	    struct ldb_context *ldb;
1716 	    struct mbof_dn_array *new_list;
1717 	    int i;
1718 	
1719 	    del_ctx = delop->del_ctx;
1720 	    parent = delop->parent;
1721 	    ctx = del_ctx->ctx;
1722 	    ldb = ldb_module_get_ctx(ctx->module);
1723 	
1724 	    anc_ctx = talloc_zero(delop, struct mbof_del_ancestors_ctx);
1725 	    if (!anc_ctx) {
1726 	        return LDB_ERR_OPERATIONS_ERROR;
1727 	    }
1728 	    delop->anc_ctx = anc_ctx;
1729 	
1730 	    new_list = talloc_zero(anc_ctx, struct mbof_dn_array);
1731 	    if (!new_list) {
1732 	        return LDB_ERR_OPERATIONS_ERROR;
1733 	    }
1734 	
1735 	    /* at the very least we have a number of memberof elements
1736 	     * equal to the number of objects that have this entry as
1737 	     * direct member */
1738 	    new_list->num = delop->num_parents;
1739 	
1740 	    /* attach the list to the operation */
1741 	    delop->anc_ctx->new_list = new_list;
1742 	    delop->anc_ctx->num_direct = new_list->num;
1743 	
1744 	    /* do we have any direct parent at all ? */
1745 	    if (new_list->num == 0) {
1746 	        /* no entries at all, entry ended up being orphaned */
1747 	        /* skip to directly set the new memberof list for this entry */
1748 	
1749 	        return mbof_del_mod_entry(delop);
1750 	    }
1751 	
1752 	    /* fill in the list if we have parents */
1753 	    new_list->dns = talloc_zero_array(new_list,
1754 	                                      struct ldb_dn *,
1755 	                                      new_list->num);
1756 	    if (!new_list->dns) {
1757 	        return LDB_ERR_OPERATIONS_ERROR;
1758 	    }
1759 	    for (i = 0; i < delop->num_parents; i++) {
1760 	        new_list->dns[i] = delop->parents[i]->dn;
1761 	    }
1762 	
1763 	    /* before proceeding we also need to fetch the ancestors (anew as some may
1764 	     * have changed by preceeding operations) */
1765 	    return mbof_del_ancestors(delop);
1766 	}
1767 	
1768 	static int mbof_del_ancestors(struct mbof_del_operation *delop)
1769 	{
1770 	    struct mbof_del_ancestors_ctx *anc_ctx;
1771 	    struct mbof_del_ctx *del_ctx;
1772 	    struct mbof_ctx *ctx;
1773 	    struct ldb_context *ldb;
1774 	    struct mbof_dn_array *new_list;
1775 	    static const char *attrs[] = { DB_MEMBEROF, NULL };
1776 	    struct ldb_request *search;
1777 	    int ret;
1778 	
1779 	    del_ctx = delop->del_ctx;
1780 	    ctx = del_ctx->ctx;
1781 	    ldb = ldb_module_get_ctx(ctx->module);
1782 	    anc_ctx = delop->anc_ctx;
1783 	    new_list = anc_ctx->new_list;
1784 	
1785 	    ret = ldb_build_search_req(&search, ldb, anc_ctx,
1786 	                               new_list->dns[anc_ctx->cur],
1787 	                               LDB_SCOPE_BASE, NULL, attrs, NULL,
1788 	                               delop, mbof_del_anc_callback,
1789 	                               ctx->req);
1790 	    if (ret != LDB_SUCCESS) {
1791 	        return ret;
1792 	    }
1793 	
1794 	    return ldb_request(ldb, search);
1795 	}
1796 	
1797 	static int mbof_del_anc_callback(struct ldb_request *req,
1798 	                                 struct ldb_reply *ares)
1799 	{
1800 	    struct mbof_del_ancestors_ctx *anc_ctx;
1801 	    struct mbof_del_operation *delop;
1802 	    struct mbof_del_ctx *del_ctx;
1803 	    struct mbof_ctx *ctx;
1804 	    struct ldb_context *ldb;
1805 	    struct ldb_message *msg;
1806 	    const struct ldb_message_element *el;
1807 	    struct mbof_dn_array *new_list;
1808 	    struct ldb_dn *valdn;
1809 	    int i, j, ret;
1810 	
1811 	    delop = talloc_get_type(req->context, struct mbof_del_operation);
1812 	    del_ctx = delop->del_ctx;
1813 	    ctx = del_ctx->ctx;
1814 	    ldb = ldb_module_get_ctx(ctx->module);
1815 	    anc_ctx = delop->anc_ctx;
1816 	    new_list = anc_ctx->new_list;
1817 	
1818 	    if (!ares) {
1819 	        return ldb_module_done(ctx->req, NULL, NULL,
1820 	                               LDB_ERR_OPERATIONS_ERROR);
1821 	    }
1822 	    if (ares->error != LDB_SUCCESS) {
1823 	        return ldb_module_done(ctx->req,
1824 	                               ares->controls,
1825 	                               ares->response,
1826 	                               ares->error);
1827 	    }
1828 	
1829 	    switch (ares->type) {
1830 	    case LDB_REPLY_ENTRY:
1831 	        msg = ares->message;
1832 	
1833 	        if (anc_ctx->entry != NULL) {
1834 	            ldb_debug(ldb, LDB_DEBUG_TRACE,
1835 	                           "Found multiple entries for (%s)",
1836 	                           ldb_dn_get_linearized(anc_ctx->entry->dn));
1837 	            /* more than one entry per dn ?? db corrupted ? */
1838 	            return ldb_module_done(ctx->req, NULL, NULL,
1839 	                                   LDB_ERR_OPERATIONS_ERROR);
1840 	        }
1841 	
1842 	        anc_ctx->entry = talloc_steal(anc_ctx, msg);
1843 	        if (anc_ctx->entry == NULL) {
1844 	            return ldb_module_done(ctx->req, NULL, NULL,
1845 	                                   LDB_ERR_OPERATIONS_ERROR);
1846 	        }
1847 	        break;
1848 	    case LDB_REPLY_REFERRAL:
1849 	        /* ignore */
1850 	        break;
1851 	
1852 	    case LDB_REPLY_DONE:
1853 	        if (anc_ctx->entry == NULL) {
1854 	            /* no target, no party! */
1855 	            return ldb_module_done(ctx->req, NULL, NULL,
1856 	                                   LDB_ERR_OPERATIONS_ERROR);
1857 	        }
1858 	
1859 	        /* check entry */
1860 	        el = ldb_msg_find_element(anc_ctx->entry, DB_MEMBEROF);
1861 	        if (el) {
1862 	            for (i = 0; i < el->num_values; i++) {
1863 	                valdn = ldb_dn_from_ldb_val(new_list, ldb, &el->values[i]);
1864 	                if (!valdn) {
1865 	                    ldb_debug(ldb, LDB_DEBUG_TRACE,
1866 	                                   "Invalid dn for memberof: (%s)",
1867 	                                   (const char *)el->values[i].data);
1868 	                    return ldb_module_done(ctx->req, NULL, NULL,
1869 	                                           LDB_ERR_OPERATIONS_ERROR);
1870 	                }
1871 	                for (j = 0; j < new_list->num; j++) {
1872 	                    if (ldb_dn_compare(valdn, new_list->dns[j]) == 0)
1873 	                        break;
1874 	                }
1875 	                if (j < new_list->num) {
1876 	                    talloc_free(valdn);
1877 	                    continue;
1878 	                }
1879 	                /* do not re-add the original deleted entry by mistake */
1880 	                if (ldb_dn_compare(valdn, del_ctx->first->entry_dn) == 0) {
1881 	                    talloc_free(valdn);
1882 	                    continue;
1883 	                }
1884 	                new_list->dns = talloc_realloc(new_list,
1885 	                                               new_list->dns,
1886 	                                               struct ldb_dn *,
1887 	                                               new_list->num + 1);
1888 	                if (!new_list->dns) {
1889 	                    return ldb_module_done(ctx->req, NULL, NULL,
1890 	                                           LDB_ERR_OPERATIONS_ERROR);
1891 	                }
1892 	                new_list->dns[new_list->num] = valdn;
1893 	                new_list->num++;
1894 	            }
1895 	        }
1896 	
1897 	        /* done with this one */
1898 	        talloc_free(anc_ctx->entry);
1899 	        anc_ctx->entry = NULL;
1900 	        anc_ctx->cur++;
1901 	
1902 	        /* check if we need to process any more */
1903 	        if (anc_ctx->cur < anc_ctx->num_direct) {
1904 	            /* ok process the next one */
1905 	            ret = mbof_del_ancestors(delop);
1906 	        } else {
1907 	            /* ok, end of the story, proceed to modify the entry */
1908 	            ret = mbof_del_mod_entry(delop);
1909 	        }
1910 	
1911 	        if (ret != LDB_SUCCESS) {
1912 	            return ldb_module_done(ctx->req, NULL, NULL,
1913 	                                   LDB_ERR_OPERATIONS_ERROR);
1914 	        }
1915 	    }
1916 	
1917 	    talloc_zfree(ares);
1918 	    return LDB_SUCCESS;
1919 	}
1920 	
1921 	static int mbof_del_mod_entry(struct mbof_del_operation *delop)
1922 	{
1923 	    struct mbof_del_ctx *del_ctx;
1924 	    struct mbof_ctx *ctx;
1925 	    struct ldb_context *ldb;
1926 	    struct mbof_dn_array *new_list;
1927 	    struct ldb_request *mod_req;
1928 	    struct ldb_message *msg;
1929 	    struct ldb_message_element *el;
1930 	    struct ldb_dn **diff = NULL;
1931 	    const char *name;
1932 	    const char *val;
1933 	    int i, j, k;
1934 	    bool is_user;
1935 	    int ret;
1936 	
1937 	    del_ctx = delop->del_ctx;
1938 	    ctx = del_ctx->ctx;
1939 	    ldb = ldb_module_get_ctx(ctx->module);
1940 	    new_list = delop->anc_ctx->new_list;
1941 	
1942 	    /* if this is a user we need to find out which entries have been
1943 	     * removed so that we can later schedule removal of memberuid
1944 	     * attributes from these entries */
1945 	    ret = entry_is_user_object(delop->entry);
1946 	    switch (ret) {
1947 	    case LDB_SUCCESS:
1948 	        /* it's a user object  */
1949 	        is_user = true;
1950 	        break;
1951 	    case LDB_ERR_NO_SUCH_ATTRIBUTE:
1952 	        /* it is not a user object, continue */
1953 	        is_user = false;
1954 	        break;
1955 	    default:
1956 	        /* an error occured, return */
1957 	        return ret;
1958 	    }
1959 	
1960 	    if (is_user) {
1961 	        /* prepare memberuid delete list */
1962 	        /* copy all original memberof entries, and then later remove
1963 	         * the ones that will survive in the entry */
1964 	        el = ldb_msg_find_element(delop->entry, DB_MEMBEROF);
1965 	        if (!el || !el->num_values) {
1966 	            return LDB_ERR_OPERATIONS_ERROR;
1967 	        }
1968 	        diff = talloc_array(del_ctx->muops, struct ldb_dn *,
1969 	                            el->num_values + 1);
1970 	        if (!diff) {
1971 	            return LDB_ERR_OPERATIONS_ERROR;
1972 	        }
1973 	        for (i = 0, j = 0; i < el->num_values; i++) {
1974 	            diff[j] = ldb_dn_from_ldb_val(diff, ldb, &el->values[i]);
1975 	            if (!diff[j]) {
1976 	                return LDB_ERR_OPERATIONS_ERROR;
1977 	            }
1978 	            /* skip the deleted entry if this is a delete op */
1979 	            if (!del_ctx->is_mod) {
1980 	                if (ldb_dn_compare(del_ctx->first->entry_dn, diff[j]) == 0) {
1981 	                    continue;
1982 	                }
1983 	            }
1984 	            j++;
1985 	        }
1986 	        /* zero terminate array */
1987 	        diff[j] = NULL;
1988 	    }
1989 	
1990 	    /* change memberof on entry */
1991 	    msg = ldb_msg_new(delop);
1992 	    if (!msg) return LDB_ERR_OPERATIONS_ERROR;
1993 	
1994 	    msg->dn = delop->entry_dn;
1995 	
1996 	    if (new_list->num) {
1997 	        ret = ldb_msg_add_empty(msg, DB_MEMBEROF, LDB_FLAG_MOD_REPLACE, &el);
1998 	        if (ret != LDB_SUCCESS) {
1999 	            return ret;
2000 	        }
2001 	
2002 	        el->values = talloc_array(el, struct ldb_val, new_list->num);
2003 	        if (!el->values) {
2004 	            return LDB_ERR_OPERATIONS_ERROR;
2005 	        }
2006 	        for (i = 0, j = 0; i < new_list->num; i++) {
2007 	            if (ldb_dn_compare(new_list->dns[i], msg->dn) == 0)
2008 	                continue;
2009 	            val = ldb_dn_get_linearized(new_list->dns[i]);
2010 	            if (!val) {
2011 	                return LDB_ERR_OPERATIONS_ERROR;
2012 	            }
2013 	            el->values[j].length = strlen(val);
2014 	            el->values[j].data = (uint8_t *)talloc_strdup(el->values, val);
2015 	            if (!el->values[j].data) {
2016 	                return LDB_ERR_OPERATIONS_ERROR;
2017 	            }
2018 	            j++;
2019 	
2020 	            if (is_user) {
2021 	                /* compare the entry's original memberof list with the new
2022 	                 * one and for each missing entry add a memberuid removal
2023 	                 * operation */
2024 	                for (k = 0; diff[k]; k++) {
2025 	                    if (ldb_dn_compare(new_list->dns[i], diff[k]) == 0) {
2026 	                        break;
2027 	                    }
2028 	                }
2029 	                if (diff[k]) {
2030 	                    talloc_zfree(diff[k]);
2031 	                    for (; diff[k + 1]; k++) {
2032 	                        diff[k] = diff[k + 1];
2033 	                    }
2034 	                    diff[k] = NULL;
2035 	                }
2036 	            }
2037 	        }
2038 	        el->num_values = j;
2039 	
2040 	    }
2041 	    else {
2042 	        ret = ldb_msg_add_empty(msg, DB_MEMBEROF, LDB_FLAG_MOD_DELETE, &el);
2043 	        if (ret != LDB_SUCCESS) {
2044 	            return ret;
2045 	        }
2046 	    }
2047 	
2048 	    if (is_user && diff[0]) {
2049 	        /* file memberuid removal operations */
2050 	        name = ldb_msg_find_attr_as_string(delop->entry, DB_NAME, NULL);
2051 	        if (!name) {
2052 	            return LDB_ERR_OPERATIONS_ERROR;
2053 	        }
2054 	
2055 	        for (i = 0; diff[i]; i++) {
2056 	            ret = mbof_append_muop(del_ctx, &del_ctx->muops,
2057 	                                   &del_ctx->num_muops,
2058 	                                   LDB_FLAG_MOD_DELETE,
2059 	                                   diff[i], name);
2060 	            if (ret != LDB_SUCCESS) {
2061 	                return ret;
2062 	            }
2063 	        }
2064 	    }
2065 	
2066 	    ret = ldb_build_mod_req(&mod_req, ldb, delop,
2067 	                            msg, NULL,
2068 	                            delop, mbof_del_mod_callback,
2069 	                            ctx->req);
2070 	    if (ret != LDB_SUCCESS) {
2071 	        return ret;
2072 	    }
2073 	    talloc_steal(mod_req, msg);
2074 	
2075 	    return ldb_next_request(ctx->module, mod_req);
2076 	}
2077 	
2078 	static int mbof_del_mod_callback(struct ldb_request *req,
2079 	                                 struct ldb_reply *ares)
2080 	{
2081 	    struct mbof_del_operation *delop;
2082 	    struct mbof_del_ctx *del_ctx;
2083 	    struct ldb_context *ldb;
2084 	    struct mbof_ctx *ctx;
2085 	    int ret;
2086 	
2087 	    delop = talloc_get_type(req->context, struct mbof_del_operation);
2088 	    del_ctx = delop->del_ctx;
2089 	    ctx = del_ctx->ctx;
2090 	    ldb = ldb_module_get_ctx(ctx->module);
2091 	
2092 	    if (!ares) {
2093 	        return ldb_module_done(ctx->req, NULL, NULL,
2094 	                               LDB_ERR_OPERATIONS_ERROR);
2095 	    }
2096 	    if (ares->error != LDB_SUCCESS) {
2097 	        return ldb_module_done(ctx->req,
2098 	                               ares->controls,
2099 	                               ares->response,
2100 	                               ares->error);
2101 	    }
2102 	
2103 	    switch (ares->type) {
2104 	    case LDB_REPLY_ENTRY:
2105 	        ldb_debug(ldb, LDB_DEBUG_TRACE, "Got an entry on a non search op ?!");
2106 	        /* shouldn't happen */
2107 	        talloc_zfree(ares);
2108 	        return ldb_module_done(ctx->req, NULL, NULL,
2109 	                               LDB_ERR_OPERATIONS_ERROR);
2110 	    case LDB_REPLY_REFERRAL:
2111 	        /* ignore */
2112 	        talloc_zfree(ares);
2113 	        break;
2114 	
2115 	    case LDB_REPLY_DONE:
2116 	
2117 	        ret = mbof_del_progeny(delop);
2118 	
2119 	        if (ret != LDB_SUCCESS) {
2120 	            talloc_zfree(ares);
2121 	            return ldb_module_done(ctx->req, NULL, NULL, ret);
2122 	        }
2123 	    }
2124 	
2125 	    return LDB_SUCCESS;
2126 	}
2127 	
2128 	static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
2129 	                        struct mbof_dn_array *ael);
2130 	
2131 	static int mbof_del_progeny(struct mbof_del_operation *delop)
2132 	{
2133 	    struct mbof_ctx *ctx;
2134 	    struct mbof_del_ctx *del_ctx;
2135 	    struct mbof_del_operation *nextop;
2136 	    const struct ldb_message_element *el;
2137 	    struct ldb_context *ldb;
2138 	    struct ldb_dn *valdn;
2139 	    int i, ret;
2140 	
2141 	    del_ctx = delop->del_ctx;
2142 	    ctx = del_ctx->ctx;
2143 	    ldb = ldb_module_get_ctx(ctx->module);
2144 	
2145 	    /* now verify if this entry is a group and members need to be processed as
2146 	     * well */
2147 	
2148 	    el = ldb_msg_find_element(delop->entry, DB_MEMBER);
2149 	    if (el) {
2150 	        for (i = 0; i < el->num_values; i++) {
2151 	            valdn = ldb_dn_from_ldb_val(delop, ldb, &el->values[i]);
2152 	            if (!valdn || !ldb_dn_validate(valdn)) {
2153 	                ldb_debug(ldb, LDB_DEBUG_TRACE,
2154 	                               "Invalid DN for member: (%s)",
2155 	                               (const char *)el->values[i].data);
2156 	                return LDB_ERR_INVALID_DN_SYNTAX;
2157 	            }
2158 	            ret = mbof_append_delop(delop, valdn);
2159 	            if (ret != LDB_SUCCESS) {
2160 	                return ret;
2161 	            }
2162 	        }
2163 	    }
2164 	
2165 	    /* finally find the next entry to handle */
2166 	    ret = mbof_del_get_next(delop, &nextop);
2167 	    if (ret != LDB_SUCCESS) {
2168 	        return ret;
2169 	    }
2170 	
2171 	    if (nextop) {
2172 	        return mbof_del_execute_op(nextop);
2173 	    }
2174 	
2175 	    /* see if there are memberuid operations to perform */
2176 	    if (del_ctx->muops) {
2177 	        return mbof_del_muop(del_ctx);
2178 	    }
2179 	    /* see if there are follow functions to run */
2180 	    if (del_ctx->follow_mod) {
2181 	        return mbof_mod_add(del_ctx->follow_mod,
2182 	                            del_ctx->follow_mod->to_add);
2183 	    }
2184 	
2185 	    /* ok, no more ops, this means our job is done */
2186 	    return ldb_module_done(ctx->req,
2187 	                           ctx->ret_ctrls,
2188 	                           ctx->ret_resp,
2189 	                           LDB_SUCCESS);
2190 	}
2191 	
2192 	static int mbof_del_get_next(struct mbof_del_operation *delop,
2193 	                             struct mbof_del_operation **nextop)
2194 	{
2195 	    struct mbof_del_operation *top, *cop;
2196 	    struct mbof_del_ctx *del_ctx;
2197 	    struct mbof_ctx *ctx;
2198 	    struct mbof_dn *save, *tmp;
2199 	
2200 	    del_ctx = delop->del_ctx;
2201 	    ctx = del_ctx->ctx;
2202 	
2203 	    /* first of all, save the current delop in the history */
2204 	    save = talloc_zero(del_ctx, struct mbof_dn);
2205 	    if (!save) {
2206 	        return LDB_ERR_OPERATIONS_ERROR;
2207 	    }
2208 	    save->dn = delop->entry_dn;
2209 	
2210 	    if (del_ctx->history) {
2211 	        tmp = del_ctx->history;
2212 	        while (tmp->next) tmp = tmp->next;
2213 	        tmp->next = save;
2214 	    } else {
2215 	        del_ctx->history = save;
2216 	    }
2217 	
2218 	    /* Find next one */
2219 	    for (top = delop; top; top = top->parent) {
2220 	        if (top->num_children == 0 || top->next_child >= top->num_children) {
2221 	            /* no children, go for next one */
2222 	            continue;
2223 	        }
2224 	
2225 	        while (top->next_child < top->num_children) {
2226 	            cop = top->children[top->next_child];
2227 	            top->next_child++;
2228 	
2229 	            /* verify this operation has not already been performed */
2230 	            for (tmp = del_ctx->history; tmp; tmp = tmp->next) {
2231 	                if (ldb_dn_compare(tmp->dn, cop->entry_dn) == 0) {
2232 	                    break;
2233 	                }
2234 	            }
2235 	            if (tmp == NULL) {
2236 	                /* and return the current one */
2237 	                *nextop = cop;
2238 	                return LDB_SUCCESS;
2239 	            }
2240 	        }
2241 	    }
2242 	
2243 	    /* we have no more ops */
2244 	    *nextop = NULL;
2245 	    return LDB_SUCCESS;
2246 	}
2247 	
2248 	static int mbof_del_fill_muop(struct mbof_del_ctx *del_ctx,
2249 	                              struct ldb_message *entry)
2250 	{
2251 	    struct ldb_message_element *el;
2252 	    char *name;
2253 	    int ret;
2254 	    int i;
2255 	
2256 	    el = ldb_msg_find_element(entry, DB_MEMBEROF);
2257 	    if (!el || el->num_values == 0) {
2258 	        /* no memberof attributes ... */
2259 	        return LDB_SUCCESS;
2260 	    }
2261 	
2262 	    ret = entry_is_user_object(entry);
2263 	    switch (ret) {
2264 	    case LDB_SUCCESS:
2265 	        /* it's a user object, continue */
2266 	        break;
2267 	
2268 	    case LDB_ERR_NO_SUCH_ATTRIBUTE:
2269 	        /* it is not a user object, just return */
2270 	        return LDB_SUCCESS;
2271 	
2272 	    default:
2273 	        /* an error occured, return */
2274 	        return ret;
2275 	    }
2276 	
2277 	    name = talloc_strdup(del_ctx,
2278 	                         ldb_msg_find_attr_as_string(entry, DB_NAME, NULL));
2279 	    if (!name) {
2280 	        return LDB_ERR_OPERATIONS_ERROR;
2281 	    }
2282 	
2283 	    for (i = 0; i < el->num_values; i++) {
2284 	        struct ldb_dn *valdn;
2285 	
2286 	        valdn = ldb_dn_from_ldb_val(del_ctx->muops,
2287 	                                    ldb_module_get_ctx(del_ctx->ctx->module),
2288 	                                    &el->values[i]);
2289 	        if (!valdn || !ldb_dn_validate(valdn)) {
2290 	            ldb_debug(ldb_module_get_ctx(del_ctx->ctx->module),
2291 	                      LDB_DEBUG_ERROR,
2292 	                      "Invalid dn value: [%s]",
2293 	                      (const char *)el->values[i].data);
2294 	        }
2295 	
2296 	        ret = mbof_append_muop(del_ctx, &del_ctx->muops,
2297 	                               &del_ctx->num_muops,
2298 	                               LDB_FLAG_MOD_DELETE,
2299 	                               valdn, name);
2300 	        if (ret != LDB_SUCCESS) {
2301 	            return ret;
2302 	        }
2303 	    }
2304 	
2305 	    return LDB_SUCCESS;
2306 	}
2307 	
2308 	/* del memberuid attributes to parent groups */
2309 	static int mbof_del_muop(struct mbof_del_ctx *del_ctx)
2310 	{
2311 	    struct ldb_context *ldb;
2312 	    struct ldb_message *msg;
2313 	    struct ldb_request *mod_req;
2314 	    struct mbof_ctx *ctx;
2315 	    int ret;
2316 	
2317 	    ctx = del_ctx->ctx;
2318 	    ldb = ldb_module_get_ctx(ctx->module);
2319 	
2320 	    msg = ldb_msg_new(del_ctx);
2321 	    if (!msg) return LDB_ERR_OPERATIONS_ERROR;
2322 	
2323 	    msg->dn = del_ctx->muops[del_ctx->cur_muop].dn;
2324 	    msg->elements = del_ctx->muops[del_ctx->cur_muop].el;
2325 	    msg->num_elements = 1;
2326 	
2327 	    ret = ldb_build_mod_req(&mod_req, ldb, del_ctx,
2328 	                            msg, NULL,
2329 	                            del_ctx, mbof_del_muop_callback,
2330 	                            ctx->req);
2331 	    if (ret != LDB_SUCCESS) {
2332 	        return ret;
2333 	    }
2334 	
2335 	    return ldb_next_request(ctx->module, mod_req);
2336 	}
2337 	
2338 	static int mbof_del_muop_callback(struct ldb_request *req,
2339 	                                  struct ldb_reply *ares)
2340 	{
2341 	    struct mbof_del_ctx *del_ctx;
2342 	    struct mbof_ctx *ctx;
2343 	    int ret;
2344 	
2345 	    del_ctx = talloc_get_type(req->context, struct mbof_del_ctx);
2346 	    ctx = del_ctx->ctx;
2347 	
2348 	    if (!ares) {
2349 	        return ldb_module_done(ctx->req, NULL, NULL,
2350 	                               LDB_ERR_OPERATIONS_ERROR);
2351 	    }
2352 	    if (ares->error != LDB_SUCCESS) {
2353 	        return ldb_module_done(ctx->req,
2354 	                               ares->controls,
2355 	                               ares->response,
2356 	                               ares->error);
2357 	    }
2358 	
2359 	    switch (ares->type) {
2360 	    case LDB_REPLY_ENTRY:
2361 	        /* shouldn't happen */
2362 	        talloc_zfree(ares);
2363 	        return ldb_module_done(ctx->req, NULL, NULL,
2364 	                               LDB_ERR_OPERATIONS_ERROR);
2365 	    case LDB_REPLY_REFERRAL:
2366 	        /* ignore */
2367 	        break;
2368 	
2369 	    case LDB_REPLY_DONE:
2370 	        del_ctx->cur_muop++;
2371 	        if (del_ctx->cur_muop < del_ctx->num_muops) {
2372 	            ret = mbof_del_muop(del_ctx);
2373 	        }
2374 	        /* see if there are follow functions to run */
2375 	        else if (del_ctx->follow_mod) {
2376 	            return mbof_mod_add(del_ctx->follow_mod,
2377 	                                del_ctx->follow_mod->to_add);
2378 	        }
2379 	        else {
2380 	            return ldb_module_done(ctx->req,
2381 	                                   ctx->ret_ctrls,
2382 	                                   ctx->ret_resp,
2383 	                                   LDB_SUCCESS);
2384 	        }
2385 	
2386 	        if (ret != LDB_SUCCESS) {
2387 	            talloc_zfree(ares);
2388 	            return ldb_module_done(ctx->req, NULL, NULL, ret);
2389 	        }
2390 	    }
2391 	
2392 	    talloc_zfree(ares);
2393 	    return LDB_SUCCESS;
2394 	}
2395 	
2396 	
2397 	
2398 	/* mod operation */
2399 	
2400 	/* A modify operation just implements either an add operation, or a delete
2401 	 * operation or both (replace) in turn.
2402 	 * The only difference between a modify and a pure add or a pure delete is that
2403 	 * the object is not created a new or not completely removed, but the setup just
2404 	 * treats it in the same way children objects are treated in a pure add or delete
2405 	 * operation. A list of appropriate parents and objects to modify is built, then
2406 	 * we jump directly in the add or delete code.
2407 	 * If both add and delete are necessary, delete operations are performed first
2408 	 * and then a followup add operation is concatenated */
2409 	
2410 	static int mbof_mod_callback(struct ldb_request *req,
2411 	                             struct ldb_reply *ares);
2412 	static int mbof_orig_mod(struct mbof_mod_ctx *mod_ctx);
2413 	static int mbof_orig_mod_callback(struct ldb_request *req,
2414 	                                  struct ldb_reply *ares);
2415 	static int mbof_mod_process(struct mbof_mod_ctx *mod_ctx, bool *done);
2416 	static int mbof_mod_delete(struct mbof_mod_ctx *mod_ctx,
2417 	                           struct mbof_dn_array *del);
2418 	static int mbof_fill_dn_array(TALLOC_CTX *memctx,
2419 	                              struct ldb_context *ldb,
2420 	                              const struct ldb_message_element *el,
2421 	                              struct mbof_dn_array **dn_array);
2422 	
2423 	static int memberof_mod(struct ldb_module *module, struct ldb_request *req)
2424 	{
2425 	    struct ldb_message_element *el;
2426 	    struct mbof_mod_ctx *mod_ctx;
2427 	    struct mbof_ctx *ctx;
2428 	    static const char *attrs[] = {DB_MEMBER, DB_MEMBEROF, NULL};
2429 	    struct ldb_context *ldb = ldb_module_get_ctx(module);
2430 	    struct ldb_request *search;
2431 	    int ret;
2432 	
2433 	    if (ldb_dn_is_special(req->op.mod.message->dn)) {
2434 	        /* do not manipulate our control entries */
2435 	        return ldb_next_request(module, req);
2436 	    }
2437 	
2438 	    /* check if memberof is specified */
2439 	    el = ldb_msg_find_element(req->op.mod.message, DB_MEMBEROF);
2440 	    if (el) {
2441 	        ldb_debug(ldb, LDB_DEBUG_ERROR,
2442 	                  "Error: the memberof attribute is readonly.");
2443 	        return LDB_ERR_UNWILLING_TO_PERFORM;
2444 	    }
2445 	
2446 	    /* check if memberuid is specified */
2447 	    el = ldb_msg_find_element(req->op.mod.message, DB_MEMBERUID);
2448 	    if (el) {
2449 	        ldb_debug(ldb, LDB_DEBUG_ERROR,
2450 	                  "Error: the memberuid attribute is readonly.");
2451 	        return LDB_ERR_UNWILLING_TO_PERFORM;
2452 	    }
2453 	
2454 	    ctx = mbof_init(module, req);
2455 	    if (!ctx) {
2456 	        return LDB_ERR_OPERATIONS_ERROR;
2457 	    }
2458 	
2459 	    mod_ctx = talloc_zero(ctx, struct mbof_mod_ctx);
2460 	    if (!mod_ctx) {
2461 	        talloc_free(ctx);
2462 	        return LDB_ERR_OPERATIONS_ERROR;
2463 	    }
2464 	    mod_ctx->ctx = ctx;
2465 	
2466 	    mod_ctx->msg = ldb_msg_copy(mod_ctx, req->op.mod.message);
2467 	    if (!mod_ctx->msg) {
2468 	        return LDB_ERR_OPERATIONS_ERROR;
2469 	    }
2470 	
2471 	    /* continue with normal ops if there are no members */
2472 	    el = ldb_msg_find_element(mod_ctx->msg, DB_MEMBER);
2473 	    if (!el) {
2474 	        mod_ctx->terminate = true;
2475 	        return mbof_orig_mod(mod_ctx);
2476 	    }
2477 	
2478 	    mod_ctx->membel = el;
2479 	
2480 	    /* can't do anything,
2481 	     * must check first what's on the entry */
2482 	    ret = ldb_build_search_req(&search, ldb, mod_ctx,
2483 	                               mod_ctx->msg->dn, LDB_SCOPE_BASE,
2484 	                               NULL, attrs, NULL,
2485 	                               mod_ctx, mbof_mod_callback,
2486 	                               req);
2487 	    if (ret != LDB_SUCCESS) {
2488 	        talloc_free(ctx);
2489 	        return ret;
2490 	    }
2491 	
2492 	    return ldb_request(ldb, search);
2493 	}
2494 	
2495 	
2496 	static int mbof_mod_callback(struct ldb_request *req,
2497 	                             struct ldb_reply *ares)
2498 	{
2499 	    struct mbof_mod_ctx *mod_ctx;
2500 	    struct ldb_context *ldb;
2501 	    struct mbof_ctx *ctx;
2502 	    int ret;
2503 	
2504 	    mod_ctx = talloc_get_type(req->context, struct mbof_mod_ctx);
2505 	    ctx = mod_ctx->ctx;
2506 	    ldb = ldb_module_get_ctx(ctx->module);
2507 	
2508 	    if (!ares) {
2509 	        return ldb_module_done(ctx->req, NULL, NULL,
2510 	                               LDB_ERR_OPERATIONS_ERROR);
2511 	    }
2512 	    if (ares->error != LDB_SUCCESS) {
2513 	        return ldb_module_done(ctx->req,
2514 	                               ares->controls,
2515 	                               ares->response,
2516 	                               ares->error);
2517 	    }
2518 	
2519 	    switch (ares->type) {
2520 	    case LDB_REPLY_ENTRY:
2521 	        if (mod_ctx->entry != NULL) {
2522 	            ldb_debug(ldb, LDB_DEBUG_TRACE,
2523 	                           "Found multiple entries for (%s)",
2524 	                           ldb_dn_get_linearized(mod_ctx->msg->dn));
2525 	            /* more than one entry per dn ?? db corrupted ? */
2526 	            return ldb_module_done(ctx->req, NULL, NULL,
2527 	                                   LDB_ERR_OPERATIONS_ERROR);
2528 	        }
2529 	
2530 	        mod_ctx->entry = talloc_steal(mod_ctx, ares->message);
2531 	        if (mod_ctx->entry == NULL) {
2532 	            return ldb_module_done(ctx->req, NULL, NULL,
2533 	                                   LDB_ERR_OPERATIONS_ERROR);
2534 	        }
2535 	        break;
2536 	    case LDB_REPLY_REFERRAL:
2537 	        /* ignore */
2538 	        break;
2539 	
2540 	    case LDB_REPLY_DONE:
2541 	        if (mod_ctx->entry == NULL) {
2542 	            ldb_debug(ldb, LDB_DEBUG_TRACE, "Entry not found (%s)",
2543 	                           ldb_dn_get_linearized(mod_ctx->msg->dn));
2544 	            /* this target does not exists, too bad! */
2545 	            return ldb_module_done(ctx->req, NULL, NULL,
2546 	                                   LDB_ERR_NO_SUCH_OBJECT);
2547 	        }
2548 	
2549 	        ret = mbof_orig_mod(mod_ctx);
2550 	        if (ret != LDB_SUCCESS) {
2551 	            talloc_zfree(ares);
2552 	            return ldb_module_done(ctx->req, NULL, NULL, ret);
2553 	        }
2554 	    }
2555 	
2556 	    talloc_zfree(ares);
2557 	    return LDB_SUCCESS;
2558 	}
2559 	
2560 	static int mbof_orig_mod(struct mbof_mod_ctx *mod_ctx)
2561 	{
2562 	    struct ldb_request *mod_req;
2563 	    struct ldb_context *ldb;
2564 	    struct mbof_ctx *ctx;
2565 	    int ret;
2566 	
2567 	    ctx = mod_ctx->ctx;
2568 	    ldb = ldb_module_get_ctx(ctx->module);
2569 	
2570 	    ret = ldb_build_mod_req(&mod_req, ldb, ctx->req,
2571 	                            mod_ctx->msg, ctx->req->controls,
2572 	                            mod_ctx, mbof_orig_mod_callback,
2573 	                            ctx->req);
2574 	    if (ret != LDB_SUCCESS) {
2575 	        return ret;
2576 	    }
2577 	
2578 	    return ldb_next_request(ctx->module, mod_req);
2579 	}
2580 	
2581 	static int mbof_orig_mod_callback(struct ldb_request *req,
2582 	                                  struct ldb_reply *ares)
2583 	{
2584 	    struct ldb_context *ldb;
2585 	    struct mbof_mod_ctx *mod_ctx;
2586 	    struct mbof_ctx *ctx;
2587 	    int ret;
2588 	
2589 	    mod_ctx = talloc_get_type(req->context, struct mbof_mod_ctx);
2590 	    ctx = mod_ctx->ctx;
2591 	    ldb = ldb_module_get_ctx(ctx->module);
2592 	
2593 	    if (!ares) {
2594 	        return ldb_module_done(ctx->req, NULL, NULL,
2595 	                               LDB_ERR_OPERATIONS_ERROR);
2596 	    }
2597 	    if (ares->error != LDB_SUCCESS) {
2598 	        return ldb_module_done(ctx->req,
2599 	                               ares->controls,
2600 	                               ares->response,
2601 	                               ares->error);
2602 	    }
2603 	
2604 	    if (ares->type != LDB_REPLY_DONE) {
2605 	        talloc_zfree(ares);
2606 	        ldb_debug(ldb, LDB_DEBUG_TRACE, "Invalid reply type!");
2607 	        ldb_set_errstring(ldb, "Invalid reply type!");
2608 	        return ldb_module_done(ctx->req, NULL, NULL,
2609 	                               LDB_ERR_OPERATIONS_ERROR);
2610 	    }
2611 	
2612 	    /* save real call stuff */
2613 	    ctx->ret_ctrls = talloc_steal(ctx, ares->controls);
2614 	    ctx->ret_resp = talloc_steal(ctx, ares->response);
2615 	
2616 	    if (!mod_ctx->terminate) {
2617 	        /* next step */
2618 	        ret = mbof_mod_process(mod_ctx, &mod_ctx->terminate);
2619 	        if (ret != LDB_SUCCESS) {
2620 	            talloc_zfree(ares);
2621 	            return ldb_module_done(ctx->req, NULL, NULL, ret);
2622 	        }
2623 	    }
2624 	
2625 	    if (mod_ctx->terminate) {
2626 	        talloc_zfree(ares);
2627 	        return ldb_module_done(ctx->req,
2628 	                               ctx->ret_ctrls,
2629 	                               ctx->ret_resp,
2630 	                               LDB_SUCCESS);
2631 	    }
2632 	
2633 	    talloc_zfree(ares);
2634 	    return LDB_SUCCESS;
2635 	}
2636 	
2637 	static int mbof_mod_process(struct mbof_mod_ctx *mod_ctx, bool *done)
2638 	{
2639 	    const struct ldb_message_element *el;
2640 	    struct ldb_context *ldb;
2641 	    struct mbof_ctx *ctx;
2642 	    struct mbof_dn_array *removed;
2643 	    struct mbof_dn_array *added;
2644 	    int i, j, ret;
2645 	
2646 	    ctx = mod_ctx->ctx;
2647 	    ldb = ldb_module_get_ctx(ctx->module);
2648 	
2649 	    switch (mod_ctx->membel->flags) {
2650 	    case LDB_FLAG_MOD_ADD:
2651 	
2652 	        ret = mbof_fill_dn_array(mod_ctx, ldb, mod_ctx->membel, &added);
2653 	        if (ret != LDB_SUCCESS) {
2654 	            return ret;
2655 	        }
2656 	
2657 	        return mbof_mod_add(mod_ctx, added);
2658 	
2659 	    case LDB_FLAG_MOD_DELETE:
2660 	
2661 	        if (mod_ctx->membel->num_values == 0) {
2662 	            el = ldb_msg_find_element(mod_ctx->entry, DB_MEMBER);
2663 	        } else {
2664 	            el = mod_ctx->membel;
2665 	        }
2666 	
2667 	        if (!el) {
2668 	            /* nothing to do really */
2669 	            *done = true;
2670 	            return LDB_SUCCESS;
2671 	        }
2672 	
2673 	        ret = mbof_fill_dn_array(mod_ctx, ldb, el, &removed);
2674 	        if (ret != LDB_SUCCESS) {
2675 	            return ret;
2676 	        }
2677 	
2678 	        return mbof_mod_delete(mod_ctx, removed);
2679 	
2680 	    case LDB_FLAG_MOD_REPLACE:
2681 	
2682 	        removed = NULL;
2683 	        el = ldb_msg_find_element(mod_ctx->entry, DB_MEMBER);
2684 	        if (el) {
2685 	            ret = mbof_fill_dn_array(mod_ctx, ldb, el, &removed);
2686 	            if (ret != LDB_SUCCESS) {
2687 	                return ret;
2688 	            }
2689 	        }
2690 	
2691 	        added = NULL;
2692 	        el = mod_ctx->membel;
2693 	        if (el) {
2694 	            ret = mbof_fill_dn_array(mod_ctx, ldb, el, &added);
2695 	            if (ret != LDB_SUCCESS) {
2696 	                return ret;
2697 	            }
2698 	        }
2699 	
2700 	        /* remove from arrays values that ended up unchanged */
2701 	        if (removed && removed->num && added && added->num) {
2702 	            for (i = 0; i < added->num; i++) {
2703 	                for (j = 0; j < removed->num; j++) {
2704 	                    if (ldb_dn_compare(added->dns[i], removed->dns[j]) == 0) {
2705 	                        break;
2706 	                    }
2707 	                }
2708 	                if (j < removed->num) {
2709 	                    /* preexisting one, not removed, nor added */
2710 	                    for (; j+1 < removed->num; j++) {
2711 	                        removed->dns[j] = removed->dns[j+1];
2712 	                    }
2713 	                    removed->num--;
2714 	                    for (j = i; j+1 < added->num; j++) {
2715 	                        added->dns[j] = added->dns[j+1];
2716 	                    }
2717 	                    added->num--;
2718 	                }
2719 	            }
2720 	        }
2721 	
2722 	        /* if we need to add something put it away so that it
2723 	         * can be done after all delete operations are over */
2724 	        if (added && added->num) {
2725 	            mod_ctx->to_add = added;
2726 	        }
2727 	
2728 	        /* if we have something to remove do it first */
2729 	        if (removed && removed->num) {
2730 	            return mbof_mod_delete(mod_ctx, removed);
2731 	        }
2732 	
2733 	        /* if there is nothing to remove and we have stuff to add
2734 	         * do it right away */
2735 	        if (mod_ctx->to_add) {
2736 	            return mbof_mod_add(mod_ctx, added);
2737 	        }
2738 	
2739 	        /* the replacement function resulted in a null op,
2740 	         * nothing to do, return happily */
2741 	        *done = true;
2742 	        return LDB_SUCCESS;
2743 	    }
2744 	
2745 	    return LDB_ERR_OPERATIONS_ERROR;
2746 	}
2747 	
2748 	static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
2749 	                        struct mbof_dn_array *ael)
2750 	{
2751 	    const struct ldb_message_element *el;
2752 	    struct mbof_dn_array *parents;
2753 	    struct mbof_add_ctx *add_ctx;
2754 	    struct ldb_context *ldb;
2755 	    struct mbof_ctx *ctx;
2756 	    int i, ret;
2757 	
2758 	    ctx = mod_ctx->ctx;
2759 	    ldb = ldb_module_get_ctx(ctx->module);
2760 	
2761 	    el = ldb_msg_find_element(mod_ctx->entry, DB_MEMBEROF);
2762 	
2763 	    /* all the parents + itself */
2764 	    ret = mbof_fill_dn_array(mod_ctx, ldb, el, &parents);
2765 	    if (ret != LDB_SUCCESS) {
2766 	        return ret;
2767 	    }
2768 	
2769 	    parents->dns = talloc_realloc(parents, parents->dns,
2770 	                                  struct ldb_dn *, parents->num + 1);
2771 	    if (!parents->dns) {
2772 	        return LDB_ERR_OPERATIONS_ERROR;
2773 	    }
2774 	    parents->dns[parents->num] = mod_ctx->entry->dn;
2775 	    parents->num++;
2776 	
2777 	    add_ctx = talloc_zero(mod_ctx, struct mbof_add_ctx);
2778 	    if (!add_ctx) {
2779 	        return LDB_ERR_OPERATIONS_ERROR;
2780 	    }
2781 	    add_ctx->ctx = ctx;
2782 	    add_ctx->msg_dn = mod_ctx->msg->dn;
2783 	
2784 	    for (i = 0; i < ael->num; i++) {
2785 	        ret = mbof_append_addop(add_ctx, parents, ael->dns[i]);
2786 	        if (ret != LDB_SUCCESS) {
2787 	            return ret;
2788 	        }
2789 	    }
2790 	
2791 	    return mbof_next_add(add_ctx->add_list);
2792 	}
2793 	
2794 	static int mbof_mod_delete(struct mbof_mod_ctx *mod_ctx,
2795 	                           struct mbof_dn_array *del)
2796 	{
2797 	    struct mbof_del_operation *first;
2798 	    struct mbof_del_ctx *del_ctx;
2799 	    struct ldb_context *ldb;
2800 	    struct mbof_ctx *ctx;
2801 	    int i, ret;
2802 	
2803 	    ctx = mod_ctx->ctx;
Event returned_pointer: Pointer "ldb" returned by "ldb_module_get_ctx(ctx->module)" is never used.
2804 	    ldb = ldb_module_get_ctx(ctx->module);
2805 	
2806 	    del_ctx = talloc_zero(mod_ctx, struct mbof_del_ctx);
2807 	    if (!del_ctx) {
2808 	        return LDB_ERR_OPERATIONS_ERROR;
2809 	    }
2810 	    del_ctx->ctx = ctx;
2811 	    del_ctx->is_mod = true;
2812 	
2813 	    /* create first entry */
2814 	    /* the first entry is the parent of all entries and the one where we
2815 	     * remove member from, it does not get the same treatment as others */
2816 	    first = talloc_zero(del_ctx, struct mbof_del_operation);
2817 	    if (!first) {
2818 	        return LDB_ERR_OPERATIONS_ERROR;
2819 	    }
2820 	    del_ctx->first = first;
2821 	
2822 	    first->del_ctx = del_ctx;
2823 	    first->entry = mod_ctx->entry;
2824 	    first->entry_dn = mod_ctx->entry->dn;
2825 	
2826 	    /* prepare del sets */
2827 	    for (i = 0; i < del->num; i++) {
2828 	        ret = mbof_append_delop(first, del->dns[i]);
2829 	        if (ret != LDB_SUCCESS) {
2830 	            return ret;
2831 	        }
2832 	    }
2833 	
2834 	    /* add followup function if we also have stuff to add */
2835 	    if (mod_ctx->to_add) {
2836 	        del_ctx->follow_mod = mod_ctx;
2837 	    }
2838 	
2839 	    /* now that sets are built, start processing */
2840 	    return mbof_del_execute_op(first->children[0]);
2841 	}
2842 	
2843 	static int mbof_fill_dn_array(TALLOC_CTX *memctx,
2844 	                              struct ldb_context *ldb,
2845 	                              const struct ldb_message_element *el,
2846 	                              struct mbof_dn_array **dn_array)
2847 	{
2848 	    struct mbof_dn_array *ar;
2849 	    struct ldb_dn *valdn;
2850 	    int i;
2851 	
2852 	    ar = talloc_zero(memctx, struct mbof_dn_array);
2853 	    if (!ar) {
2854 	        return LDB_ERR_OPERATIONS_ERROR;
2855 	    }
2856 	    *dn_array = ar;
2857 	
2858 	    if (!el || el->num_values == 0) {
2859 	        return LDB_SUCCESS;
2860 	    }
2861 	
2862 	    ar->dns = talloc_array(ar, struct ldb_dn *, el->num_values);
2863 	    if (!ar->dns) {
2864 	        return LDB_ERR_OPERATIONS_ERROR;
2865 	    }
2866 	    ar->num = el->num_values;
2867 	
2868 	    for (i = 0; i < ar->num; i++) {
2869 	        valdn = ldb_dn_from_ldb_val(ar, ldb, &el->values[i]);
2870 	        if (!valdn || !ldb_dn_validate(valdn)) {
2871 	            ldb_debug(ldb, LDB_DEBUG_TRACE, "Invalid dn value: [%s]",
2872 	                                            (const char *)el->values[i].data);
2873 	            return LDB_ERR_INVALID_DN_SYNTAX;
2874 	        }
2875 	        ar->dns[i] = valdn;
2876 	    }
2877 	
2878 	    return LDB_SUCCESS;
2879 	}
2880 	
2881 	
2882 	/*************************
2883 	 * Cleanup task routines *
2884 	 *************************/
2885 	
2886 	struct mbof_member {
2887 	    struct mbof_member *prev;
2888 	    struct mbof_member *next;
2889 	
2890 	    struct ldb_dn *dn;
2891 	    const char *name;
2892 	    bool orig_has_memberof;
2893 	    bool orig_has_memberuid;
2894 	    struct ldb_message_element *orig_members;
2895 	
2896 	    struct mbof_member **members;
2897 	
2898 	    hash_table_t *memberofs;
2899 	
2900 	    struct ldb_message_element *memuids;
2901 	
2902 	    enum { MBOF_GROUP_TO_DO = 0,
2903 	           MBOF_GROUP_DONE,
2904 	           MBOF_USER,
2905 	           MBOF_ITER_ERROR } status;
2906 	};
2907 	
2908 	struct mbof_rcmp_context {
2909 	    struct ldb_module *module;
2910 	    struct ldb_request *req;
2911 	
2912 	    struct mbof_member *user_list;
2913 	    hash_table_t *user_table;
2914 	
2915 	    struct mbof_member *group_list;
2916 	    hash_table_t *group_table;
2917 	};
2918 	
2919 	static void *hash_alloc(const size_t size, void *pvt)
2920 	{
2921 	    return talloc_size(pvt, size);
2922 	}
2923 	
2924 	static void hash_free(void *ptr, void *pvt)
2925 	{
2926 	    talloc_free(ptr);
2927 	}
2928 	
2929 	static int mbof_steal_msg_el(TALLOC_CTX *memctx,
2930 	                             const char *name,
2931 	                             struct ldb_message *msg,
2932 	                             struct ldb_message_element **_dest)
2933 	{
2934 	    struct ldb_message_element *src;
2935 	    struct ldb_message_element *dest;
2936 	
2937 	    src = ldb_msg_find_element(msg, name);
2938 	    if (!src) {
2939 	        return LDB_ERR_NO_SUCH_ATTRIBUTE;
2940 	    }
2941 	
2942 	    dest = talloc_zero(memctx, struct ldb_message_element);
2943 	    if (!dest) {
2944 	        return LDB_ERR_OPERATIONS_ERROR;
2945 	    }
2946 	
2947 	    *dest = *src;
2948 	    talloc_steal(dest, dest->name);
2949 	    talloc_steal(dest, dest->values);
2950 	
2951 	    *_dest = dest;
2952 	    return LDB_SUCCESS;
2953 	}
2954 	
2955 	static int mbof_rcmp_usr_callback(struct ldb_request *req,
2956 	                                  struct ldb_reply *ares);
2957 	static int mbof_rcmp_search_groups(struct mbof_rcmp_context *ctx);
2958 	static int mbof_rcmp_grp_callback(struct ldb_request *req,
2959 	                                  struct ldb_reply *ares);
2960 	static int mbof_member_update(struct mbof_rcmp_context *ctx,
2961 	                              struct mbof_member *parent,
2962 	                              struct mbof_member *mem);
2963 	static bool mbof_member_iter(hash_entry_t *item, void *user_data);
2964 	static int mbof_add_memuid(struct mbof_member *grp, const char *user);
2965 	static int mbof_rcmp_update(struct mbof_rcmp_context *ctx);
2966 	static int mbof_rcmp_mod_callback(struct ldb_request *req,
2967 	                                  struct ldb_reply *ares);
2968 	
2969 	static int memberof_recompute_task(struct ldb_module *module,
2970 	                                   struct ldb_request *req)
2971 	{
2972 	    struct ldb_context *ldb = ldb_module_get_ctx(module);
2973 	    static const char *attrs[] = { DB_NAME, DB_MEMBEROF, NULL };
2974 	    static const char *filter = "(objectclass=user)";
2975 	    struct mbof_rcmp_context *ctx;
2976 	    struct ldb_request *src_req;
2977 	    int ret;
2978 	
2979 	    ctx = talloc_zero(req, struct mbof_rcmp_context);
2980 	    if (!ctx) {
2981 	        return LDB_ERR_OPERATIONS_ERROR;
2982 	    }
2983 	    ctx->module = module;
2984 	    ctx->req = req;
2985 	
2986 	    ret = hash_create_ex(1024, &ctx->user_table, 0, 0, 0, 0,
2987 	                         hash_alloc, hash_free, ctx, NULL, NULL);
2988 	    if (ret != HASH_SUCCESS) {
2989 	        return LDB_ERR_OPERATIONS_ERROR;
2990 	    }
2991 	
2992 	    ret = ldb_build_search_req(&src_req, ldb, ctx,
2993 	                               NULL, LDB_SCOPE_SUBTREE,
2994 	                               filter, attrs, NULL,
2995 	                               ctx, mbof_rcmp_usr_callback, ctx->req);
2996 	    if (ret != LDB_SUCCESS) {
2997 	        return ret;
2998 	    }
2999 	
3000 	    return ldb_request(ldb, src_req);
3001 	}
3002 	
3003 	static int mbof_rcmp_usr_callback(struct ldb_request *req,
3004 	                                  struct ldb_reply *ares)
3005 	{
3006 	    struct mbof_rcmp_context *ctx;
3007 	    struct mbof_member *usr;
3008 	    hash_value_t value;
3009 	    hash_key_t key;
3010 	    const char *name;
3011 	    int ret;
3012 	
3013 	    ctx = talloc_get_type(req->context, struct mbof_rcmp_context);
3014 	
3015 	    if (!ares) {
3016 	        return ldb_module_done(ctx->req, NULL, NULL,
3017 	                               LDB_ERR_OPERATIONS_ERROR);
3018 	    }
3019 	    if (ares->error != LDB_SUCCESS) {
3020 	        return ldb_module_done(ctx->req,
3021 	                               ares->controls,
3022 	                               ares->response,
3023 	                               ares->error);
3024 	    }
3025 	
3026 	    switch (ares->type) {
3027 	    case LDB_REPLY_ENTRY:
3028 	
3029 	        usr = talloc_zero(ctx, struct mbof_member);
3030 	        if (!usr) {
3031 	            return ldb_module_done(ctx->req, NULL, NULL,
3032 	                                   LDB_ERR_OPERATIONS_ERROR);
3033 	        }
3034 	
3035 	        usr->status = MBOF_USER;
3036 	        usr->dn = talloc_steal(usr, ares->message->dn);
3037 	        name = ldb_msg_find_attr_as_string(ares->message, DB_NAME, NULL);
3038 	        if (name) {
3039 	            usr->name = talloc_steal(usr, name);
3040 	        }
3041 	
3042 	        if (ldb_msg_find_element(ares->message, DB_MEMBEROF)) {
3043 	            usr->orig_has_memberof = true;
3044 	        }
3045 	
3046 	        DLIST_ADD(ctx->user_list, usr);
3047 	
3048 	        key.type = HASH_KEY_STRING;
3049 	        key.str = discard_const(ldb_dn_get_linearized(usr->dn));
3050 	        value.type = HASH_VALUE_PTR;
3051 	        value.ptr = usr;
3052 	
3053 	        ret = hash_enter(ctx->user_table, &key, &value);
3054 	        if (ret != HASH_SUCCESS) {
3055 	            return ldb_module_done(ctx->req, NULL, NULL,
3056 	                                   LDB_ERR_OPERATIONS_ERROR);
3057 	        }
3058 	
3059 	        break;
3060 	
3061 	    case LDB_REPLY_REFERRAL:
3062 	        /* ignore */
3063 	        break;
3064 	
3065 	    case LDB_REPLY_DONE:
3066 	        talloc_zfree(ares);
3067 	
3068 	        /* and now search groups */
3069 	        return mbof_rcmp_search_groups(ctx);
3070 	    }
3071 	
3072 	    talloc_zfree(ares);
3073 	    return LDB_SUCCESS;
3074 	}
3075 	
3076 	static int mbof_rcmp_search_groups(struct mbof_rcmp_context *ctx)
3077 	{
3078 	    struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
3079 	    static const char *attrs[] = { DB_MEMBEROF, DB_MEMBERUID,
3080 	                                   DB_NAME, DB_MEMBER, NULL };
3081 	    static const char *filter = "(objectclass=group)";
3082 	    struct ldb_request *req;
3083 	    int ret;
3084 	
3085 	    ret = hash_create_ex(1024, &ctx->group_table, 0, 0, 0, 0,
3086 	                         hash_alloc, hash_free, ctx, NULL, NULL);
3087 	    if (ret != HASH_SUCCESS) {
3088 	        return ldb_module_done(ctx->req, NULL, NULL,
3089 	                               LDB_ERR_OPERATIONS_ERROR);
3090 	    }
3091 	
3092 	    ret = ldb_build_search_req(&req, ldb, ctx,
3093 	                               NULL, LDB_SCOPE_SUBTREE,
3094 	                               filter, attrs, NULL,
3095 	                               ctx, mbof_rcmp_grp_callback, ctx->req);
3096 	    if (ret != LDB_SUCCESS) {
3097 	        return ret;
3098 	    }
3099 	
3100 	    return ldb_request(ldb, req);
3101 	}
3102 	
3103 	static int mbof_rcmp_grp_callback(struct ldb_request *req,
3104 	                                  struct ldb_reply *ares)
3105 	{
3106 	    struct ldb_context *ldb;
3107 	    struct mbof_rcmp_context *ctx;
3108 	    struct ldb_message_element *el;
3109 	    struct mbof_member *iter;
3110 	    struct mbof_member *grp;
3111 	    hash_value_t value;
3112 	    hash_key_t key;
3113 	    const char *name;
3114 	    int i, j;
3115 	    int ret;
3116 	
3117 	    ctx = talloc_get_type(req->context, struct mbof_rcmp_context);
3118 	    ldb = ldb_module_get_ctx(ctx->module);
3119 	
3120 	    if (!ares) {
3121 	        return ldb_module_done(ctx->req, NULL, NULL,
3122 	                               LDB_ERR_OPERATIONS_ERROR);
3123 	    }
3124 	    if (ares->error != LDB_SUCCESS) {
3125 	        return ldb_module_done(ctx->req,
3126 	                               ares->controls,
3127 	                               ares->response,
3128 	                               ares->error);
3129 	    }
3130 	
3131 	    switch (ares->type) {
3132 	    case LDB_REPLY_ENTRY:
3133 	
3134 	        grp = talloc_zero(ctx, struct mbof_member);
3135 	        if (!grp) {
3136 	            return ldb_module_done(ctx->req, NULL, NULL,
3137 	                                   LDB_ERR_OPERATIONS_ERROR);
3138 	        }
3139 	
3140 	        grp->status = MBOF_GROUP_TO_DO;
3141 	        grp->dn = talloc_steal(grp, ares->message->dn);
3142 	        grp->name = ldb_msg_find_attr_as_string(ares->message, DB_NAME, NULL);
3143 	        name = ldb_msg_find_attr_as_string(ares->message, DB_NAME, NULL);
3144 	        if (name) {
3145 	            grp->name = talloc_steal(grp, name);
3146 	        }
3147 	
3148 	        if (ldb_msg_find_element(ares->message, DB_MEMBEROF)) {
3149 	            grp->orig_has_memberof = true;
3150 	        }
3151 	
3152 	        if (ldb_msg_find_element(ares->message, DB_MEMBERUID)) {
3153 	            grp->orig_has_memberuid = true;
3154 	        }
3155 	
3156 	        ret = mbof_steal_msg_el(grp, DB_MEMBER,
3157 	                                ares->message, &grp->orig_members);
3158 	        if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
3159 	            return ldb_module_done(ctx->req, NULL, NULL,
3160 	                                   LDB_ERR_OPERATIONS_ERROR);
3161 	        }
3162 	
3163 	        DLIST_ADD(ctx->group_list, grp);
3164 	
3165 	        key.type = HASH_KEY_STRING;
3166 	        key.str = discard_const(ldb_dn_get_linearized(grp->dn));
3167 	        value.type = HASH_VALUE_PTR;
3168 	        value.ptr = grp;
3169 	
3170 	        ret = hash_enter(ctx->group_table, &key, &value);
3171 	        if (ret != HASH_SUCCESS) {
3172 	            return ldb_module_done(ctx->req, NULL, NULL,
3173 	                                   LDB_ERR_OPERATIONS_ERROR);
3174 	        }
3175 	
3176 	        break;
3177 	
3178 	    case LDB_REPLY_REFERRAL:
3179 	        /* ignore */
3180 	        break;
3181 	
3182 	    case LDB_REPLY_DONE:
3183 	        talloc_zfree(ares);
3184 	
3185 	        if (!ctx->group_list) {
3186 	            /* no groups ? */
3187 	            return ldb_module_done(ctx->req, NULL, NULL, LDB_SUCCESS);
3188 	        }
3189 	
3190 	        /* for each group compute the members list */
3191 	        for (iter = ctx->group_list; iter; iter = iter->next) {
3192 	
3193 	            el = iter->orig_members;
3194 	            if (!el || el->num_values == 0) {
3195 	                /* no members */
3196 	                continue;
3197 	            }
3198 	
3199 	            /* we have at most num_values group members */
3200 	            iter->members = talloc_array(iter, struct mbof_member *,
3201 	                                         el->num_values +1);
3202 	            if (!iter->members) {
3203 	                return ldb_module_done(ctx->req, NULL, NULL,
3204 	                                       LDB_ERR_OPERATIONS_ERROR);
3205 	            }
3206 	
3207 	            for (i = 0, j = 0; i < el->num_values; i++) {
3208 	                key.type = HASH_KEY_STRING;
3209 	                key.str = (char *)el->values[i].data;
3210 	
3211 	                ret = hash_lookup(ctx->user_table, &key, &value);
3212 	                switch (ret) {
3213 	                case HASH_SUCCESS:
3214 	                    iter->members[j] = (struct mbof_member *)value.ptr;
3215 	                    j++;
3216 	                    break;
3217 	
3218 	                case HASH_ERROR_KEY_NOT_FOUND:
3219 	                    /* not a user, see if it is a group */
3220 	
3221 	                    ret = hash_lookup(ctx->group_table, &key, &value);
3222 	                    if (ret != HASH_SUCCESS) {
3223 	                        if (ret != HASH_ERROR_KEY_NOT_FOUND) {
3224 	                            return ldb_module_done(ctx->req, NULL, NULL,
3225 	                                                   LDB_ERR_OPERATIONS_ERROR);
3226 	                        }
3227 	                    }
3228 	                    if (ret == HASH_ERROR_KEY_NOT_FOUND) {
3229 	                        /* not a known user, nor a known group ?
3230 	                           give a warning an continue */
3231 	                        ldb_debug(ldb, LDB_DEBUG_ERROR,
3232 	                                  "member attribute [%s] has no corresponding"
3233 	                                  " entry!", key.str);
3234 	                        break;
3235 	                    }
3236 	
3237 	                    iter->members[j] = (struct mbof_member *)value.ptr;
3238 	                    j++;
3239 	                    break;
3240 	
3241 	                default:
3242 	                    return ldb_module_done(ctx->req, NULL, NULL,
3243 	                                           LDB_ERR_OPERATIONS_ERROR);
3244 	                }
3245 	            }
3246 	            /* terminate */
3247 	            iter->members[j] = NULL;
3248 	
3249 	            talloc_zfree(iter->orig_members);
3250 	        }
3251 	
3252 	        /* now generate correct memberof tables */
3253 	        while (ctx->group_list->status == MBOF_GROUP_TO_DO) {
3254 	
3255 	            grp = ctx->group_list;
3256 	
3257 	            /* move to end of list and mark as done.
3258 	             * NOTE: this is not efficient, but will do for now */
3259 	            DLIST_DEMOTE(ctx->group_list, grp, struct mbof_member *);
3260 	            grp->status = MBOF_GROUP_DONE;
3261 	
3262 	            /* verify if members need updating */
3263 	            if (!grp->members) {
3264 	                continue;
3265 	            }
3266 	            for (i = 0; grp->members[i]; i++) {
3267 	                ret = mbof_member_update(ctx, grp, grp->members[i]);
3268 	                if (ret != LDB_SUCCESS) {
3269 	                    return ldb_module_done(ctx->req, NULL, NULL,
3270 	                                           LDB_ERR_OPERATIONS_ERROR);
3271 	                }
3272 	            }
3273 	        }
3274 	
3275 	        /* ok all done, now go on and modify the tree */
3276 	        return mbof_rcmp_update(ctx);
3277 	    }
3278 	
3279 	    talloc_zfree(ares);
3280 	    return LDB_SUCCESS;
3281 	}
3282 	
3283 	static int mbof_member_update(struct mbof_rcmp_context *ctx,
3284 	                              struct mbof_member *parent,
3285 	                              struct mbof_member *mem)
3286 	{
3287 	    hash_value_t value;
3288 	    hash_key_t key;
3289 	    int ret;
3290 	
3291 	    /* ignore loops */
3292 	    if (parent == mem) return LDB_SUCCESS;
3293 	
3294 	    key.type = HASH_KEY_STRING;
3295 	    key.str = discard_const(ldb_dn_get_linearized(parent->dn));
3296 	
3297 	    if (!mem->memberofs) {
3298 	        ret = hash_create_ex(32, &mem->memberofs, 0, 0, 0, 0,
3299 	                             hash_alloc, hash_free, mem, NULL, NULL);
3300 	        if (ret != HASH_SUCCESS) {
3301 	            return LDB_ERR_OPERATIONS_ERROR;
3302 	        }
3303 	
3304 	        ret = HASH_ERROR_KEY_NOT_FOUND;
3305 	
3306 	    } else {
3307 	
3308 	        ret = hash_lookup(mem->memberofs, &key, &value);
3309 	        if (ret != HASH_SUCCESS) {
3310 	            if (ret != HASH_ERROR_KEY_NOT_FOUND) {
3311 	                /* fatal error */
3312 	                return LDB_ERR_OPERATIONS_ERROR;
3313 	            }
3314 	        }
3315 	    }
3316 	
3317 	    if (ret == HASH_ERROR_KEY_NOT_FOUND) {
3318 	
3319 	        /* it's missing, update member */
3320 	        value.type = HASH_VALUE_PTR;
3321 	        value.ptr = parent;
3322 	
3323 	        ret = hash_enter(mem->memberofs, &key, &value);
3324 	        if (ret != HASH_SUCCESS) {
3325 	            return LDB_ERR_OPERATIONS_ERROR;
3326 	        }
3327 	
3328 	        if (mem->status == MBOF_USER) {
3329 	            /* add corresponding memuid to the group */
3330 	            ret = mbof_add_memuid(parent, mem->name);
3331 	            if (ret != LDB_SUCCESS) {
3332 	                return ret;
3333 	            }
3334 	        }
3335 	
3336 	        /* if we updated a group, mark it as TO DO again */
3337 	        if (mem->status == MBOF_GROUP_DONE) {
3338 	            mem->status = MBOF_GROUP_TO_DO;
3339 	        }
3340 	    }
3341 	
3342 	    /* now see if the parent has memberofs to pass down */
3343 	    if (parent->memberofs) {
3344 	        ret = hash_iterate(parent->memberofs, mbof_member_iter, mem);
3345 	        if (ret != HASH_SUCCESS) {
3346 	            return LDB_ERR_OPERATIONS_ERROR;
3347 	        }
3348 	        if (mem->status == MBOF_ITER_ERROR) {
3349 	            return LDB_ERR_OPERATIONS_ERROR;
3350 	        }
3351 	    }
3352 	
3353 	    /* finally, if it was made TO DO move it to the head */
3354 	    if (mem->status == MBOF_GROUP_TO_DO) {
3355 	        DLIST_PROMOTE(ctx->group_list, mem);
3356 	    }
3357 	
3358 	    return LDB_SUCCESS;
3359 	}
3360 	
3361 	static bool mbof_member_iter(hash_entry_t *item, void *user_data)
3362 	{
3363 	    struct mbof_member *parent;
3364 	    struct mbof_member *mem;
3365 	    hash_value_t value;
3366 	    int ret;
3367 	
3368 	    mem = talloc_get_type(user_data, struct mbof_member);
3369 	
3370 	    /* exclude self */
3371 	    if (strcmp(item->key.str, ldb_dn_get_linearized(mem->dn)) == 0) {
3372 	        return true;
3373 	    }
3374 	
3375 	    /* check if we already have it */
3376 	    ret = hash_lookup(mem->memberofs, &item->key, &value);
3377 	    if (ret != HASH_SUCCESS) {
3378 	        if (ret != HASH_ERROR_KEY_NOT_FOUND) {
3379 	            /* fatal error */
3380 	            mem->status = MBOF_ITER_ERROR;
3381 	            return false;
3382 	        }
3383 	
3384 	        /* was not already here, add it and mark group as TO DO */
3385 	        ret = hash_enter(mem->memberofs, &item->key, &item->value);
3386 	        if (ret != HASH_SUCCESS) {
3387 	            return LDB_ERR_OPERATIONS_ERROR;
3388 	        }
3389 	
3390 	        if (mem->status == MBOF_GROUP_DONE) {
3391 	            mem->status = MBOF_GROUP_TO_DO;
3392 	        }
3393 	
3394 	        if (mem->status == MBOF_USER) {
3395 	            /* add corresponding memuid to the group */
3396 	            parent = (struct mbof_member *)item->value.ptr;
3397 	            ret = mbof_add_memuid(parent, mem->name);
3398 	            if (ret != LDB_SUCCESS) {
3399 	                mem->status = MBOF_ITER_ERROR;
3400 	                return false;
3401 	            }
3402 	        }
3403 	    }
3404 	
3405 	    return true;
3406 	}
3407 	
3408 	static int mbof_add_memuid(struct mbof_member *grp, const char *user)
3409 	{
3410 	    struct ldb_val *vals;
3411 	    int n;
3412 	
3413 	    if (!grp->memuids) {
3414 	        grp->memuids = talloc_zero(grp, struct ldb_message_element);
3415 	        if (!grp->memuids) {
3416 	            return LDB_ERR_OPERATIONS_ERROR;
3417 	        }
3418 	
3419 	        grp->memuids->name = talloc_strdup(grp->memuids, DB_MEMBERUID);
3420 	        if (!grp->memuids->name) {
3421 	            return LDB_ERR_OPERATIONS_ERROR;
3422 	        }
3423 	    }
3424 	
3425 	    n = grp->memuids->num_values;
3426 	    vals = talloc_realloc(grp->memuids,
3427 	                          grp->memuids->values,
3428 	                          struct ldb_val, n + 1);
3429 	    if (!vals) {
3430 	        return LDB_ERR_OPERATIONS_ERROR;
3431 	    }
3432 	
3433 	    vals[n].data = (uint8_t *)talloc_strdup(vals, user);
3434 	    vals[n].length = strlen(user);
3435 	
3436 	    grp->memuids->values = vals;
3437 	    grp->memuids->num_values = n + 1;
3438 	
3439 	    return LDB_SUCCESS;
3440 	}
3441 	
3442 	static int mbof_rcmp_update(struct mbof_rcmp_context *ctx)
3443 	{
3444 	    struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
3445 	    struct ldb_message_element *el;
3446 	    struct ldb_message *msg = NULL;
3447 	    struct ldb_request *req;
3448 	    struct mbof_member *x = NULL;
3449 	    hash_key_t *keys;
3450 	    unsigned long count;
3451 	    int flags;
3452 	    int ret, i;
3453 	
3454 	    /* we process all users first and then all groups */
3455 	    if (ctx->user_list) {
3456 	        /* take the next entry and remove it from the list */
3457 	        x = ctx->user_list;
3458 	        DLIST_REMOVE(ctx->user_list, x);
3459 	    }
3460 	    else if (ctx->group_list) {
3461 	        /* take the next entry and remove it from the list */
3462 	        x = ctx->group_list;
3463 	        DLIST_REMOVE(ctx->group_list, x);
3464 	    }
3465 	    else {
3466 	        /* processing terminated, return */
3467 	        ret = LDB_SUCCESS;
3468 	        goto done;
3469 	    }
3470 	
3471 	    msg = ldb_msg_new(ctx);
3472 	    if (!msg) {
3473 	        ret = LDB_ERR_OPERATIONS_ERROR;
3474 	        goto done;
3475 	    }
3476 	
3477 	    msg->dn = x->dn;
3478 	
3479 	    /* process memberof */
3480 	    if (x->memberofs) {
3481 	        ret = hash_keys(x->memberofs, &count, &keys);
3482 	        if (ret != HASH_SUCCESS) {
3483 	            ret = LDB_ERR_OPERATIONS_ERROR;
3484 	            goto done;
3485 	        }
3486 	
3487 	        if (x->orig_has_memberof) {
3488 	            flags = LDB_FLAG_MOD_REPLACE;
3489 	        } else {
3490 	            flags = LDB_FLAG_MOD_ADD;
3491 	        }
3492 	
3493 	        ret = ldb_msg_add_empty(msg, DB_MEMBEROF, flags, &el);
3494 	        if (ret != LDB_SUCCESS) {
3495 	            goto done;
3496 	        }
3497 	
3498 	        el->values = talloc_array(el, struct ldb_val, count);
3499 	        if (!el->values) {
3500 	            ret = LDB_ERR_OPERATIONS_ERROR;
3501 	            goto done;
3502 	        }
3503 	        el->num_values = count;
3504 	
3505 	        for (i = 0; i < count; i++) {
3506 	            el->values[i].data = (uint8_t *)keys[i].str;
3507 	            el->values[i].length = strlen(keys[i].str);
3508 	        }
3509 	    } else if (x->orig_has_memberof) {
3510 	        ret = ldb_msg_add_empty(msg, DB_MEMBEROF, LDB_FLAG_MOD_DELETE, NULL);
3511 	        if (ret != LDB_SUCCESS) {
3512 	            goto done;
3513 	        }
3514 	    }
3515 	
3516 	    /* process memberuid */
3517 	    if (x->memuids) {
3518 	        if (x->orig_has_memberuid) {
3519 	            flags = LDB_FLAG_MOD_REPLACE;
3520 	        } else {
3521 	            flags = LDB_FLAG_MOD_ADD;
3522 	        }
3523 	
3524 	        ret = ldb_msg_add(msg, x->memuids, flags);
3525 	        if (ret != LDB_SUCCESS) {
3526 	            goto done;
3527 	        }
3528 	    }
3529 	    else if (x->orig_has_memberuid) {
3530 	        ret = ldb_msg_add_empty(msg, DB_MEMBERUID, LDB_FLAG_MOD_DELETE, NULL);
3531 	        if (ret != LDB_SUCCESS) {
3532 	            goto done;
3533 	        }
3534 	    }
3535 	
3536 	    ret = ldb_build_mod_req(&req, ldb, ctx, msg, NULL,
3537 	                            ctx, mbof_rcmp_mod_callback,
3538 	                            ctx->req);
3539 	    if (ret != LDB_SUCCESS) {
3540 	        goto done;
3541 	    }
3542 	    talloc_steal(req, msg);
3543 	
3544 	    /* fire next call */
3545 	    return ldb_next_request(ctx->module, req);
3546 	
3547 	done:
3548 	    /* all users and groups have been processed */
3549 	    return ldb_module_done(ctx->req, NULL, NULL, ret);
3550 	}
3551 	
3552 	static int mbof_rcmp_mod_callback(struct ldb_request *req,
3553 	                                  struct ldb_reply *ares)
3554 	{
3555 	    struct ldb_context *ldb;
3556 	    struct mbof_rcmp_context *ctx;
3557 	
3558 	    ctx = talloc_get_type(req->context, struct mbof_rcmp_context);
3559 	    ldb = ldb_module_get_ctx(ctx->module);
3560 	
3561 	    if (!ares) {
3562 	        return ldb_module_done(ctx->req, NULL, NULL,
3563 	                               LDB_ERR_OPERATIONS_ERROR);
3564 	    }
3565 	    if (ares->error != LDB_SUCCESS) {
3566 	        return ldb_module_done(ctx->req,
3567 	                               ares->controls,
3568 	                               ares->response,
3569 	                               ares->error);
3570 	    }
3571 	
3572 	    switch (ares->type) {
3573 	    case LDB_REPLY_ENTRY:
3574 	        ldb_debug(ldb, LDB_DEBUG_TRACE, "Got an entry on a non search op ?!");
3575 	        /* shouldn't happen */
3576 	        talloc_zfree(ares);
3577 	        return ldb_module_done(ctx->req, NULL, NULL,
3578 	                               LDB_ERR_OPERATIONS_ERROR);
3579 	    case LDB_REPLY_REFERRAL:
3580 	        /* ignore */
3581 	        talloc_zfree(ares);
3582 	        break;
3583 	
3584 	    case LDB_REPLY_DONE:
3585 	        talloc_zfree(ares);
3586 	
3587 	        /* update the next one */
3588 	        return mbof_rcmp_update(ctx);
3589 	    }
3590 	
3591 	    return LDB_SUCCESS;
3592 	}
3593 	
3594 	
3595 	
3596 	/* module init code */
3597 	
3598 	static int memberof_init(struct ldb_module *module)
3599 	{
3600 	    struct ldb_context *ldb = ldb_module_get_ctx(module);
3601 	    int ret;
3602 	
3603 	    /* set syntaxes for member and memberof so that comparisons in filters and
3604 	     * such are done right */
3605 	    ret = ldb_schema_attribute_add(ldb, DB_MEMBER, 0, LDB_SYNTAX_DN);
3606 	    ret = ldb_schema_attribute_add(ldb, DB_MEMBEROF, 0, LDB_SYNTAX_DN);
3607 	
3608 	    return ldb_next_init(module);
3609 	}
3610 	
3611 	const struct ldb_module_ops ldb_memberof_module_ops = {
3612 	    .name = "memberof",
3613 	    .init_context = memberof_init,
3614 	    .add = memberof_add,
3615 	    .modify = memberof_mod,
3616 	    .del = memberof_del,
3617 	};