LCOV - code coverage report
Current view: top level - ldb_modules - memberof.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 813 1259 64.6 %
Date: 2012-11-29 Functions: 44 56 78.6 %
Branches: 401 879 45.6 %

           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 : }

Generated by: LCOV version 1.9