root/source4/lib/ldb/modules/asq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. asq_context_init
  2. asq_search_terminate
  3. asq_base_callback
  4. asq_reqs_callback
  5. asq_build_first_request
  6. asq_build_multiple_requests
  7. asq_search_continue
  8. asq_search
  9. asq_init

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Simo Sorce  2005-2008
   5 
   6      ** NOTE! The following LGPL license applies to the ldb
   7      ** library. This does NOT imply that all of Samba is released
   8      ** under the LGPL
   9    
  10    This library is free software; you can redistribute it and/or
  11    modify it under the terms of the GNU Lesser General Public
  12    License as published by the Free Software Foundation; either
  13    version 3 of the License, or (at your option) any later version.
  14 
  15    This library is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18    Lesser General Public License for more details.
  19 
  20    You should have received a copy of the GNU Lesser General Public
  21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 /*
  25  *  Name: ldb
  26  *
  27  *  Component: ldb attribute scoped query control module
  28  *
  29  *  Description: this module searches all the the objects pointed
  30  *               by the DNs contained in the references attribute
  31  *
  32  *  Author: Simo Sorce
  33  */
  34 
  35 #include "ldb_module.h"
  36 
  37 struct asq_context {
  38 
  39         enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
  40 
  41         struct ldb_module *module;
  42         struct ldb_request *req;
  43 
  44         struct ldb_asq_control *asq_ctrl;
  45 
  46         const char * const *req_attrs;
  47         char *req_attribute;
  48         enum {
  49                 ASQ_CTRL_SUCCESS                        = 0,
  50                 ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX       = 21,
  51                 ASQ_CTRL_UNWILLING_TO_PERFORM           = 53,
  52                 ASQ_CTRL_AFFECTS_MULTIPLE_DSA           = 71
  53         } asq_ret;
  54 
  55         struct ldb_reply *base_res;
  56 
  57         struct ldb_request **reqs;
  58         int num_reqs;
  59         int cur_req;
  60 
  61         struct ldb_control **controls;
  62 };
  63 
  64 static struct asq_context *asq_context_init(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
  65 {
  66         struct ldb_context *ldb;
  67         struct asq_context *ac;
  68 
  69         ldb = ldb_module_get_ctx(module);
  70 
  71         ac = talloc_zero(req, struct asq_context);
  72         if (ac == NULL) {
  73                 ldb_oom(ldb);
  74                 return NULL;
  75         }
  76 
  77         ac->module = module;
  78         ac->req = req;
  79 
  80         return ac;
  81 }
  82 
  83 static int asq_search_continue(struct asq_context *ac);
  84 
  85 static int asq_search_terminate(struct asq_context *ac)
     /* [<][>][^][v][top][bottom][index][help] */
  86 {
  87         struct ldb_asq_control *asq;
  88         int i;
  89 
  90         if (ac->controls) {
  91                 for (i = 0; ac->controls[i]; i++) /* count em */ ;
  92         } else {
  93                 i = 0;
  94         }
  95 
  96         ac->controls = talloc_realloc(ac, ac->controls, struct ldb_control *, i + 2);
  97 
  98         if (ac->controls == NULL) {
  99                 return LDB_ERR_OPERATIONS_ERROR;
 100         }
 101 
 102         ac->controls[i] = talloc(ac->controls, struct ldb_control);
 103         if (ac->controls[i] == NULL) {
 104                 return LDB_ERR_OPERATIONS_ERROR;
 105         }
 106 
 107         ac->controls[i]->oid = LDB_CONTROL_ASQ_OID;
 108         ac->controls[i]->critical = 0;
 109 
 110         asq = talloc_zero(ac->controls[i], struct ldb_asq_control);
 111         if (asq == NULL)
 112                 return LDB_ERR_OPERATIONS_ERROR;
 113 
 114         asq->result = ac->asq_ret;
 115 
 116         ac->controls[i]->data = asq;
 117 
 118         ac->controls[i + 1] = NULL;
 119 
 120         return ldb_module_done(ac->req, ac->controls, NULL, LDB_SUCCESS);
 121 }
 122 
 123 static int asq_base_callback(struct ldb_request *req, struct ldb_reply *ares)
     /* [<][>][^][v][top][bottom][index][help] */
 124 {
 125         struct asq_context *ac;
 126         int ret;
 127 
 128         ac = talloc_get_type(req->context, struct asq_context);
 129 
 130         if (!ares) {
 131                 return ldb_module_done(ac->req, NULL, NULL,
 132                                         LDB_ERR_OPERATIONS_ERROR);
 133         }
 134         if (ares->error != LDB_SUCCESS) {
 135                 return ldb_module_done(ac->req, ares->controls,
 136                                         ares->response, ares->error);
 137         }
 138 
 139         switch (ares->type) {
 140         case LDB_REPLY_ENTRY:
 141                 ac->base_res = talloc_move(ac, &ares);
 142                 break;
 143 
 144         case LDB_REPLY_REFERRAL:
 145                 /* ignore referrals */
 146                 talloc_free(ares);
 147                 break;
 148 
 149         case LDB_REPLY_DONE:
 150 
 151                 talloc_free(ares);
 152 
 153                 /* next step */
 154                 ret = asq_search_continue(ac);
 155                 if (ret != LDB_SUCCESS) {
 156                         return ldb_module_done(ac->req, NULL, NULL, ret);
 157                 }
 158                 break;
 159 
 160         }
 161         return LDB_SUCCESS;
 162 }
 163 
 164 static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares)
     /* [<][>][^][v][top][bottom][index][help] */
 165 {
 166         struct asq_context *ac;
 167         int ret;
 168 
 169         ac = talloc_get_type(req->context, struct asq_context);
 170 
 171         if (!ares) {
 172                 return ldb_module_done(ac->req, NULL, NULL,
 173                                         LDB_ERR_OPERATIONS_ERROR);
 174         }
 175         if (ares->error != LDB_SUCCESS) {
 176                 return ldb_module_done(ac->req, ares->controls,
 177                                         ares->response, ares->error);
 178         }
 179 
 180         switch (ares->type) {
 181         case LDB_REPLY_ENTRY:
 182                 /* pass the message up to the original callback as we
 183                  * do not have to elaborate on it any further */
 184                 ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
 185                 if (ret != LDB_SUCCESS) {
 186                         return ldb_module_done(ac->req, NULL, NULL, ret);
 187                 }
 188                 talloc_free(ares);
 189                 break;
 190 
 191         case LDB_REPLY_REFERRAL:
 192                 /* ignore referrals */
 193                 talloc_free(ares);
 194                 break;
 195 
 196         case LDB_REPLY_DONE:
 197 
 198                 talloc_free(ares);
 199 
 200                 ret = asq_search_continue(ac);
 201                 if (ret != LDB_SUCCESS) {
 202                         return ldb_module_done(ac->req, NULL, NULL, ret);
 203                 }
 204                 break;
 205         }
 206 
 207         return LDB_SUCCESS;
 208 }
 209 
 210 static int asq_build_first_request(struct asq_context *ac, struct ldb_request **base_req)
     /* [<][>][^][v][top][bottom][index][help] */
 211 {
 212         struct ldb_context *ldb;
 213         const char **base_attrs;
 214         int ret;
 215 
 216         ldb = ldb_module_get_ctx(ac->module);
 217 
 218         ac->req_attrs = ac->req->op.search.attrs;
 219         ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute);
 220         if (ac->req_attribute == NULL)
 221                 return LDB_ERR_OPERATIONS_ERROR;
 222 
 223         base_attrs = talloc_array(ac, const char *, 2);
 224         if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR;
 225 
 226         base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute);
 227         if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR;
 228 
 229         base_attrs[1] = NULL;
 230 
 231         ret = ldb_build_search_req(base_req, ldb, ac,
 232                                         ac->req->op.search.base,
 233                                         LDB_SCOPE_BASE,
 234                                         NULL,
 235                                         (const char * const *)base_attrs,
 236                                         NULL,
 237                                         ac, asq_base_callback,
 238                                         ac->req);
 239         if (ret != LDB_SUCCESS) {
 240                 return LDB_ERR_OPERATIONS_ERROR;
 241         }
 242 
 243         return LDB_SUCCESS;
 244 }
 245 
 246 static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated)
     /* [<][>][^][v][top][bottom][index][help] */
 247 {
 248         struct ldb_context *ldb;
 249         struct ldb_control **saved_controls;
 250         struct ldb_control *control;
 251         struct ldb_dn *dn;
 252         struct ldb_message_element *el;
 253         int ret, i;
 254 
 255         if (ac->base_res == NULL) {
 256                 return LDB_ERR_NO_SUCH_OBJECT;
 257         }
 258 
 259         ldb = ldb_module_get_ctx(ac->module);
 260 
 261         el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
 262         /* no values found */
 263         if (el == NULL) {
 264                 ac->asq_ret = ASQ_CTRL_SUCCESS;
 265                 *terminated = true;
 266                 return asq_search_terminate(ac);
 267         }
 268 
 269         ac->num_reqs = el->num_values;
 270         ac->cur_req = 0;
 271         ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
 272         if (ac->reqs == NULL) {
 273                 return LDB_ERR_OPERATIONS_ERROR;
 274         }
 275 
 276         for (i = 0; i < el->num_values; i++) {
 277 
 278                 dn = ldb_dn_new(ac, ldb,
 279                                 (const char *)el->values[i].data);
 280                 if ( ! ldb_dn_validate(dn)) {
 281                         ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
 282                         *terminated = true;
 283                         return asq_search_terminate(ac);
 284                 }
 285 
 286                 ret = ldb_build_search_req_ex(&ac->reqs[i],
 287                                                 ldb, ac,
 288                                                 dn, LDB_SCOPE_BASE,
 289                                                 ac->req->op.search.tree,
 290                                                 ac->req_attrs,
 291                                                 ac->req->controls,
 292                                                 ac, asq_reqs_callback,
 293                                                 ac->req);
 294                 if (ret != LDB_SUCCESS) {
 295                         return LDB_ERR_OPERATIONS_ERROR;
 296                 }
 297 
 298                 /* remove the ASQ control itself */
 299                 control = ldb_request_get_control(ac->req, LDB_CONTROL_ASQ_OID);
 300                 if (!save_controls(control, ac->reqs[i], &saved_controls)) {
 301                         return LDB_ERR_OPERATIONS_ERROR;
 302                 }
 303         }
 304 
 305         return LDB_SUCCESS;
 306 }
 307 
 308 static int asq_search_continue(struct asq_context *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 309 {
 310         struct ldb_context *ldb;
 311         bool terminated = false;
 312         int ret;
 313 
 314         ldb = ldb_module_get_ctx(ac->module);
 315 
 316         switch (ac->step) {
 317         case ASQ_SEARCH_BASE:
 318 
 319                 /* build up the requests call chain */
 320                 ret = asq_build_multiple_requests(ac, &terminated);
 321                 if (ret != LDB_SUCCESS || terminated) {
 322                         return ret;
 323                 }
 324 
 325                 ac->step = ASQ_SEARCH_MULTI;
 326 
 327                 return ldb_request(ldb, ac->reqs[ac->cur_req]);
 328 
 329         case ASQ_SEARCH_MULTI:
 330 
 331                 ac->cur_req++;
 332 
 333                 if (ac->cur_req == ac->num_reqs) {
 334                         /* done */
 335                         return asq_search_terminate(ac);
 336                 }
 337 
 338                 return ldb_request(ldb, ac->reqs[ac->cur_req]);
 339         }
 340 
 341         return LDB_ERR_OPERATIONS_ERROR;
 342 }
 343 
 344 static int asq_search(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 345 {
 346         struct ldb_context *ldb;
 347         struct ldb_request *base_req;
 348         struct ldb_control *control;
 349         struct asq_context *ac;
 350         int ret;
 351 
 352         ldb = ldb_module_get_ctx(module);
 353 
 354         /* check if there's a paged request control */
 355         control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
 356         if (control == NULL) {
 357                 /* not found go on */
 358                 return ldb_next_request(module, req);
 359         }
 360 
 361         ac = asq_context_init(module, req);
 362         if (!ac) {
 363                 return LDB_ERR_OPERATIONS_ERROR;
 364         }
 365 
 366         /* check the search is well formed */
 367         if (req->op.search.scope != LDB_SCOPE_BASE) {
 368                 ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
 369                 return asq_search_terminate(ac);
 370         }
 371 
 372         ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
 373         if (!ac->asq_ctrl) {
 374                 return LDB_ERR_PROTOCOL_ERROR;
 375         }
 376 
 377         ret = asq_build_first_request(ac, &base_req);
 378         if (ret != LDB_SUCCESS) {
 379                 return ret;
 380         }
 381 
 382         ac->step = ASQ_SEARCH_BASE;
 383 
 384         return ldb_request(ldb, base_req);
 385 }
 386 
 387 static int asq_init(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 388 {
 389         struct ldb_context *ldb;
 390         int ret;
 391 
 392         ldb = ldb_module_get_ctx(module);
 393 
 394         ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID);
 395         if (ret != LDB_SUCCESS) {
 396                 ldb_debug(ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n");
 397         }
 398 
 399         return ldb_next_init(module);
 400 }
 401 
 402 const struct ldb_module_ops ldb_asq_module_ops = {
 403         .name              = "asq",
 404         .search            = asq_search,
 405         .init_context      = asq_init
 406 };

/* [<][>][^][v][top][bottom][index][help] */