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