LCOV - code coverage report
Current view: top level - lib/ldb/modules - asq.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 120 160 75.0 %
Date: 2021-09-23 10:06:22 Functions: 10 10 100.0 %

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

Generated by: LCOV version 1.13