LCOV - code coverage report
Current view: top level - lib/ldb/ldb_ldap - ldb_ldap.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 24 518 4.6 %
Date: 2024-04-21 15:09:00 Functions: 2 23 8.7 %

          Line data    Source code
       1             : /* 
       2             :    ldb database library
       3             : 
       4             :    Copyright (C) Andrew Tridgell  2004
       5             :    Copyright (C) Simo Sorce       2006
       6             : 
       7             :      ** NOTE! The following LGPL license applies to the ldb
       8             :      ** library. This does NOT imply that all of Samba is released
       9             :      ** under the LGPL
      10             :    
      11             :    This library is free software; you can redistribute it and/or
      12             :    modify it under the terms of the GNU Lesser General Public
      13             :    License as published by the Free Software Foundation; either
      14             :    version 3 of the License, or (at your option) any later version.
      15             : 
      16             :    This library is distributed in the hope that it will be useful,
      17             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      19             :    Lesser General Public License for more details.
      20             : 
      21             :    You should have received a copy of the GNU Lesser General Public
      22             :    License along with this library; if not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : /*
      26             :  *  Name: ldb_ldap
      27             :  *
      28             :  *  Component: ldb ldap backend
      29             :  *
      30             :  *  Description: core files for LDAP backend
      31             :  *
      32             :  *  Author: Andrew Tridgell
      33             :  *
      34             :  *  Modifications:
      35             :  *
      36             :  *  - description: make the module use asynchronous calls
      37             :  *    date: Feb 2006
      38             :  *    author: Simo Sorce
      39             :  */
      40             : 
      41             : #include "replace.h"
      42             : #include "system/filesys.h"
      43             : #include "system/time.h"
      44             : #include "ldb_module.h"
      45             : #include "ldb_private.h"
      46             : 
      47             : #define LDAP_DEPRECATED 1
      48             : #include <ldap.h>
      49             : 
      50             : struct lldb_private {
      51             :         LDAP *ldap;
      52             : };
      53             : 
      54             : struct lldb_context {
      55             :         struct ldb_module *module;
      56             :         struct ldb_request *req;
      57             : 
      58             :         struct lldb_private *lldb;
      59             : 
      60             :         struct ldb_control **controls;
      61             :         int msgid;
      62             : };
      63             : 
      64           0 : static int lldb_ldap_to_ldb(int err) {
      65             :         /* Ldap errors and ldb errors are defined to the same values */
      66           0 :         return err;
      67             : }
      68             : 
      69             : /*
      70             :   convert a ldb_message structure to a list of LDAPMod structures
      71             :   ready for ldap_add() or ldap_modify()
      72             : */
      73           0 : static LDAPMod **lldb_msg_to_mods(void *mem_ctx, const struct ldb_message *msg, int use_flags)
      74             : {
      75           0 :         LDAPMod **mods;
      76           0 :         unsigned int i, j;
      77           0 :         int num_mods = 0;
      78             : 
      79             :         /* allocate maximum number of elements needed */
      80           0 :         mods = talloc_array(mem_ctx, LDAPMod *, msg->num_elements+1);
      81           0 :         if (!mods) {
      82           0 :                 errno = ENOMEM;
      83           0 :                 return NULL;
      84             :         }
      85           0 :         mods[0] = NULL;
      86             : 
      87           0 :         for (i=0;i<msg->num_elements;i++) {
      88           0 :                 const struct ldb_message_element *el = &msg->elements[i];
      89             : 
      90           0 :                 mods[num_mods] = talloc(mods, LDAPMod);
      91           0 :                 if (!mods[num_mods]) {
      92           0 :                         goto failed;
      93             :                 }
      94           0 :                 mods[num_mods+1] = NULL;
      95           0 :                 mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
      96           0 :                 if (use_flags) {
      97           0 :                         switch (el->flags & LDB_FLAG_MOD_MASK) {
      98           0 :                         case LDB_FLAG_MOD_ADD:
      99           0 :                                 mods[num_mods]->mod_op |= LDAP_MOD_ADD;
     100           0 :                                 break;
     101           0 :                         case LDB_FLAG_MOD_DELETE:
     102           0 :                                 mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
     103           0 :                                 break;
     104           0 :                         case LDB_FLAG_MOD_REPLACE:
     105           0 :                                 mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
     106           0 :                                 break;
     107             :                         }
     108             :                 }
     109           0 :                 mods[num_mods]->mod_type = discard_const_p(char, el->name);
     110           0 :                 mods[num_mods]->mod_vals.modv_bvals = talloc_array(mods[num_mods], 
     111             :                                                                    struct berval *,
     112             :                                                                    1+el->num_values);
     113           0 :                 if (!mods[num_mods]->mod_vals.modv_bvals) {
     114           0 :                         goto failed;
     115             :                 }
     116             : 
     117           0 :                 for (j=0;j<el->num_values;j++) {
     118           0 :                         mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals,
     119             :                                                                         struct berval);
     120           0 :                         if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
     121           0 :                                 goto failed;
     122             :                         }
     123           0 :                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = (char *)el->values[j].data;
     124           0 :                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
     125             :                 }
     126           0 :                 mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
     127           0 :                 num_mods++;
     128             :         }
     129             : 
     130           0 :         return mods;
     131             : 
     132           0 : failed:
     133           0 :         talloc_free(mods);
     134           0 :         return NULL;
     135             : }
     136             : 
     137             : /*
     138             :   add a single set of ldap message values to a ldb_message
     139             : */
     140           1 : static int lldb_add_msg_attr(struct ldb_context *ldb,
     141             :                              struct ldb_message *msg, 
     142             :                              const char *attr, struct berval **bval)
     143             : {
     144           1 :         int count, i, ret;
     145           1 :         struct ldb_message_element *el;
     146             : 
     147           1 :         count = ldap_count_values_len(bval);
     148             : 
     149           1 :         if (count <= 0) {
     150           0 :                 return -1;
     151             :         }
     152             : 
     153           1 :         ret = ldb_msg_add_empty(msg, attr, 0, &el);
     154           1 :         if (ret != LDB_SUCCESS) {
     155           0 :                 errno = ENOMEM;
     156           0 :                 return -1;
     157             :         }
     158             : 
     159           1 :         el->values = talloc_array(msg->elements, struct ldb_val, count);
     160           1 :         if (!el->values) {
     161           0 :                 errno = ENOMEM;
     162           0 :                 return -1;
     163             :         }
     164             : 
     165           2 :         for (i=0;i<count;i++) {
     166             :                 /* we have to ensure this is null terminated so that
     167             :                    ldb_msg_find_attr_as_string() can work */
     168           1 :                 el->values[i].data = talloc_size(el->values, bval[i]->bv_len+1);
     169           1 :                 if (!el->values[i].data) {
     170           0 :                         errno = ENOMEM;
     171           0 :                         return -1;
     172             :                 }
     173           1 :                 memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
     174           1 :                 el->values[i].data[bval[i]->bv_len] = 0;
     175           1 :                 el->values[i].length = bval[i]->bv_len;
     176           1 :                 el->num_values++;
     177             :         }
     178             : 
     179           0 :         return 0;
     180             : }
     181             : 
     182             : /*
     183             :   search for matching records
     184             : */
     185           0 : static int lldb_search(struct lldb_context *lldb_ac)
     186             : {
     187           0 :         struct ldb_context *ldb;
     188           0 :         struct lldb_private *lldb = lldb_ac->lldb;
     189           0 :         struct ldb_module *module = lldb_ac->module;
     190           0 :         struct ldb_request *req = lldb_ac->req;
     191           0 :         struct timeval tv;
     192           0 :         int ldap_scope;
     193           0 :         char *search_base;
     194           0 :         char *expression;
     195           0 :         int ret;
     196             : 
     197           0 :         ldb = ldb_module_get_ctx(module);
     198             : 
     199           0 :         if (!req->callback || !req->context) {
     200           0 :                 ldb_set_errstring(ldb, "Async interface called with NULL callback function or NULL context");
     201           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     202             :         }
     203             : 
     204           0 :         if (req->op.search.tree == NULL) {
     205           0 :                 ldb_set_errstring(ldb, "Invalid expression parse tree");
     206           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     207             :         }
     208             : 
     209           0 :         if (req->controls != NULL) {
     210           0 :                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!");
     211             :         }
     212             : 
     213           0 :         ldb_request_set_state(req, LDB_ASYNC_PENDING);
     214             : 
     215           0 :         search_base = ldb_dn_alloc_linearized(lldb_ac, req->op.search.base);
     216           0 :         if (req->op.search.base == NULL) {
     217           0 :                 search_base = talloc_strdup(lldb_ac, "");
     218             :         }
     219           0 :         if (search_base == NULL) {
     220           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     221             :         }
     222             : 
     223           0 :         expression = ldb_filter_from_tree(lldb_ac, req->op.search.tree);
     224           0 :         if (expression == NULL) {
     225           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     226             :         }
     227             : 
     228           0 :         switch (req->op.search.scope) {
     229           0 :         case LDB_SCOPE_BASE:
     230           0 :                 ldap_scope = LDAP_SCOPE_BASE;
     231           0 :                 break;
     232           0 :         case LDB_SCOPE_ONELEVEL:
     233           0 :                 ldap_scope = LDAP_SCOPE_ONELEVEL;
     234           0 :                 break;
     235           0 :         default:
     236           0 :                 ldap_scope = LDAP_SCOPE_SUBTREE;
     237           0 :                 break;
     238             :         }
     239             : 
     240           0 :         tv.tv_sec = 0;
     241           0 :         tv.tv_usec = 0;
     242           0 :         if (req->timeout > 0) {
     243           0 :                 tv.tv_sec = req->timeout;
     244             :         }
     245             : 
     246           0 :         ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope, 
     247             :                               expression, 
     248           0 :                               discard_const_p(char *, req->op.search.attrs),
     249             :                               0,
     250             :                               NULL,
     251             :                               NULL,
     252             :                               &tv,
     253             :                               LDAP_NO_LIMIT,
     254             :                               &lldb_ac->msgid);
     255             : 
     256           0 :         if (ret != LDAP_SUCCESS) {
     257           0 :                 ldb_set_errstring(ldb, ldap_err2string(ret));
     258             :         }
     259             : 
     260           0 :         return lldb_ldap_to_ldb(ret);
     261             : }
     262             : 
     263             : /*
     264             :   add a record
     265             : */
     266           0 : static int lldb_add(struct lldb_context *lldb_ac)
     267             : {
     268           0 :         struct ldb_context *ldb;
     269           0 :         struct lldb_private *lldb = lldb_ac->lldb;
     270           0 :         struct ldb_module *module = lldb_ac->module;
     271           0 :         struct ldb_request *req = lldb_ac->req;
     272           0 :         LDAPMod **mods;
     273           0 :         char *dn;
     274           0 :         int ret;
     275             : 
     276           0 :         ldb = ldb_module_get_ctx(module);
     277             : 
     278           0 :         ldb_request_set_state(req, LDB_ASYNC_PENDING);
     279             : 
     280           0 :         mods = lldb_msg_to_mods(lldb_ac, req->op.add.message, 0);
     281           0 :         if (mods == NULL) {
     282           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     283             :         }
     284             : 
     285           0 :         dn = ldb_dn_alloc_linearized(lldb_ac, req->op.add.message->dn);
     286           0 :         if (dn == NULL) {
     287           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     288             :         }
     289             : 
     290           0 :         ret = ldap_add_ext(lldb->ldap, dn, mods,
     291             :                            NULL,
     292             :                            NULL,
     293             :                            &lldb_ac->msgid);
     294             : 
     295           0 :         if (ret != LDAP_SUCCESS) {
     296           0 :                 ldb_set_errstring(ldb, ldap_err2string(ret));
     297             :         }
     298             : 
     299           0 :         return lldb_ldap_to_ldb(ret);
     300             : }
     301             : 
     302             : /*
     303             :   modify a record
     304             : */
     305           0 : static int lldb_modify(struct lldb_context *lldb_ac)
     306             : {
     307           0 :         struct ldb_context *ldb;
     308           0 :         struct lldb_private *lldb = lldb_ac->lldb;
     309           0 :         struct ldb_module *module = lldb_ac->module;
     310           0 :         struct ldb_request *req = lldb_ac->req;
     311           0 :         LDAPMod **mods;
     312           0 :         char *dn;
     313           0 :         int ret;
     314             : 
     315           0 :         ldb = ldb_module_get_ctx(module);
     316             : 
     317           0 :         ldb_request_set_state(req, LDB_ASYNC_PENDING);
     318             : 
     319           0 :         mods = lldb_msg_to_mods(lldb_ac, req->op.mod.message, 1);
     320           0 :         if (mods == NULL) {
     321           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     322             :         }
     323             : 
     324           0 :         dn = ldb_dn_alloc_linearized(lldb_ac, req->op.mod.message->dn);
     325           0 :         if (dn == NULL) {
     326           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     327             :         }
     328             : 
     329           0 :         ret = ldap_modify_ext(lldb->ldap, dn, mods,
     330             :                               NULL,
     331             :                               NULL,
     332             :                               &lldb_ac->msgid);
     333             : 
     334           0 :         if (ret != LDAP_SUCCESS) {
     335           0 :                 ldb_set_errstring(ldb, ldap_err2string(ret));
     336             :         }
     337             : 
     338           0 :         return lldb_ldap_to_ldb(ret);
     339             : }
     340             : 
     341             : /*
     342             :   delete a record
     343             : */
     344           0 : static int lldb_delete(struct lldb_context *lldb_ac)
     345             : {
     346           0 :         struct ldb_context *ldb;
     347           0 :         struct lldb_private *lldb = lldb_ac->lldb;
     348           0 :         struct ldb_module *module = lldb_ac->module;
     349           0 :         struct ldb_request *req = lldb_ac->req;
     350           0 :         char *dnstr;
     351           0 :         int ret;
     352             : 
     353           0 :         ldb = ldb_module_get_ctx(module);
     354             : 
     355           0 :         ldb_request_set_state(req, LDB_ASYNC_PENDING);
     356             : 
     357           0 :         dnstr = ldb_dn_alloc_linearized(lldb_ac, req->op.del.dn);
     358             : 
     359           0 :         ret = ldap_delete_ext(lldb->ldap, dnstr,
     360             :                               NULL,
     361             :                               NULL,
     362             :                               &lldb_ac->msgid);
     363             : 
     364           0 :         if (ret != LDAP_SUCCESS) {
     365           0 :                 ldb_set_errstring(ldb, ldap_err2string(ret));
     366             :         }
     367             : 
     368           0 :         return lldb_ldap_to_ldb(ret);
     369             : }
     370             : 
     371             : /*
     372             :   rename a record
     373             : */
     374           0 : static int lldb_rename(struct lldb_context *lldb_ac)
     375             : {
     376           0 :         struct ldb_context *ldb;
     377           0 :         struct lldb_private *lldb = lldb_ac->lldb;
     378           0 :         struct ldb_module *module = lldb_ac->module;
     379           0 :         struct ldb_request *req = lldb_ac->req;
     380           0 :         const char *rdn_name;
     381           0 :         const struct ldb_val *rdn_val;
     382           0 :         char *old_dn;
     383           0 :         char *newrdn;
     384           0 :         char *parentdn;
     385           0 :         int ret;
     386             : 
     387           0 :         ldb = ldb_module_get_ctx(module);
     388             : 
     389           0 :         ldb_request_set_state(req, LDB_ASYNC_PENDING);
     390             : 
     391           0 :         old_dn = ldb_dn_alloc_linearized(lldb_ac, req->op.rename.olddn);
     392           0 :         if (old_dn == NULL) {
     393           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     394             :         }
     395             : 
     396           0 :         rdn_name = ldb_dn_get_rdn_name(req->op.rename.newdn);
     397           0 :         rdn_val = ldb_dn_get_rdn_val(req->op.rename.newdn);
     398             : 
     399           0 :         if ((rdn_name != NULL) && (rdn_val != NULL)) {
     400           0 :                 newrdn = talloc_asprintf(lldb_ac, "%s=%s", rdn_name,
     401           0 :                                          rdn_val->length > 0 ? ldb_dn_escape_value(lldb_ac, *rdn_val) : "");
     402             :         } else {
     403           0 :                 newrdn = talloc_strdup(lldb_ac, "");
     404             :         }
     405           0 :         if (!newrdn) {
     406           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     407             :         }
     408             : 
     409           0 :         parentdn = ldb_dn_alloc_linearized(lldb_ac, ldb_dn_get_parent(lldb_ac, req->op.rename.newdn));
     410           0 :         if (!parentdn) {
     411           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     412             :         }
     413             : 
     414           0 :         ret = ldap_rename(lldb->ldap, old_dn, newrdn, parentdn,
     415             :                           1, NULL, NULL,
     416             :                           &lldb_ac->msgid);
     417             : 
     418           0 :         if (ret != LDAP_SUCCESS) {
     419           0 :                 ldb_set_errstring(ldb, ldap_err2string(ret));
     420             :         }
     421             : 
     422           0 :         return lldb_ldap_to_ldb(ret);
     423             : }
     424             : 
     425           0 : static int lldb_start_trans(struct ldb_module *module)
     426             : {
     427             :         /* TODO implement a local transaction mechanism here */
     428             : 
     429           0 :         return LDB_SUCCESS;
     430             : }
     431             : 
     432           0 : static int lldb_end_trans(struct ldb_module *module)
     433             : {
     434             :         /* TODO implement a local transaction mechanism here */
     435             : 
     436           0 :         return LDB_SUCCESS;
     437             : }
     438             : 
     439           0 : static int lldb_del_trans(struct ldb_module *module)
     440             : {
     441             :         /* TODO implement a local transaction mechanism here */
     442             : 
     443           0 :         return LDB_SUCCESS;
     444             : }
     445             : 
     446           0 : static void lldb_request_done(struct lldb_context *ac,
     447             :                         struct ldb_control **ctrls, int error)
     448             : {
     449           0 :         struct ldb_request *req;
     450           0 :         struct ldb_reply *ares;
     451             : 
     452           0 :         req = ac->req;
     453             : 
     454           0 :         ares = talloc_zero(req, struct ldb_reply);
     455           0 :         if (!ares) {
     456           0 :                 ldb_oom(ldb_module_get_ctx(ac->module));
     457           0 :                 req->callback(req, NULL);
     458           0 :                 return;
     459             :         }
     460           0 :         ares->type = LDB_REPLY_DONE;
     461           0 :         ares->controls = talloc_steal(ares, ctrls);
     462           0 :         ares->error = error;
     463             : 
     464           0 :         req->callback(req, ares);
     465             : }
     466             : 
     467             : /* return false if the request is still in progress
     468             :  * return true if the request is completed
     469             :  */
     470           0 : static bool lldb_parse_result(struct lldb_context *ac, LDAPMessage *result)
     471             : {
     472           0 :         struct ldb_context *ldb;
     473           0 :         struct lldb_private *lldb = ac->lldb;
     474           0 :         LDAPControl **serverctrlsp = NULL;
     475           0 :         char **referralsp = NULL;
     476           0 :         char *matcheddnp = NULL;
     477           0 :         char *errmsgp = NULL;
     478           0 :         LDAPMessage *msg;
     479           0 :         int type;
     480           0 :         struct ldb_message *ldbmsg = NULL;
     481           0 :         char *referral;
     482           0 :         bool callback_failed;
     483           0 :         bool request_done;
     484           0 :         bool lret;
     485           0 :         unsigned int i;
     486           0 :         int ret;
     487             : 
     488           0 :         ldb = ldb_module_get_ctx(ac->module);
     489             : 
     490           0 :         type = ldap_msgtype(result);
     491           0 :         callback_failed = false;
     492           0 :         request_done = false;
     493             : 
     494           0 :         switch (type) {
     495           0 :         case LDAP_RES_SEARCH_ENTRY:
     496             : 
     497           0 :                 msg = ldap_first_entry(lldb->ldap, result);
     498           0 :                 if (msg != NULL) {
     499           0 :                         BerElement *berptr = NULL;
     500           0 :                         char *attr, *dn;
     501             : 
     502           0 :                         ldbmsg = ldb_msg_new(ac);
     503           0 :                         if (!ldbmsg) {
     504           0 :                                 ldb_oom(ldb);
     505           0 :                                 ret = LDB_ERR_OPERATIONS_ERROR;
     506           0 :                                 break;
     507             :                         }
     508             : 
     509           0 :                         dn = ldap_get_dn(lldb->ldap, msg);
     510           0 :                         if (!dn) {
     511           0 :                                 ldb_oom(ldb);
     512           0 :                                 talloc_free(ldbmsg);
     513           0 :                                 ret = LDB_ERR_OPERATIONS_ERROR;
     514           0 :                                 break;
     515             :                         }
     516           0 :                         ldbmsg->dn = ldb_dn_new(ldbmsg, ldb, dn);
     517           0 :                         if ( ! ldb_dn_validate(ldbmsg->dn)) {
     518           0 :                                 ldb_asprintf_errstring(ldb, "Invalid DN '%s' in reply", dn);
     519           0 :                                 talloc_free(ldbmsg);
     520           0 :                                 ret = LDB_ERR_OPERATIONS_ERROR;
     521           0 :                                 ldap_memfree(dn);
     522           0 :                                 break;
     523             :                         }
     524           0 :                         ldap_memfree(dn);
     525             :                         /* loop over all attributes */
     526           0 :                         for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
     527           0 :                              attr;
     528           0 :                              attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
     529           0 :                                 struct berval **bval;
     530           0 :                                 bval = ldap_get_values_len(lldb->ldap, msg, attr);
     531             : 
     532           0 :                                 if (bval) {
     533           0 :                                         lldb_add_msg_attr(ldb, ldbmsg, attr, bval);
     534           0 :                                         ldap_value_free_len(bval);
     535             :                                 }
     536             :                         }
     537           0 :                         if (berptr) ber_free(berptr, 0);
     538             : 
     539           0 :                         ret = ldb_module_send_entry(ac->req, ldbmsg, NULL /* controls not yet supported */);
     540           0 :                         if (ret != LDB_SUCCESS) {
     541           0 :                                 ldb_asprintf_errstring(ldb, "entry send failed: %s",
     542             :                                                        ldb_errstring(ldb));
     543           0 :                                 callback_failed = true;
     544             :                         }
     545             :                 } else {
     546           0 :                         ret = LDB_ERR_OPERATIONS_ERROR;
     547             :                 }
     548           0 :                 break;
     549             : 
     550           0 :         case LDAP_RES_SEARCH_REFERENCE:
     551             : 
     552           0 :                 ret = ldap_parse_reference(lldb->ldap, result,
     553             :                                            &referralsp, &serverctrlsp, 0);
     554           0 :                 if (ret != LDAP_SUCCESS) {
     555           0 :                         ldb_asprintf_errstring(ldb, "ldap reference parse error: %s : %s",
     556             :                                                ldap_err2string(ret), errmsgp);
     557           0 :                         ret = LDB_ERR_OPERATIONS_ERROR;
     558           0 :                         break;
     559             :                 }
     560           0 :                 if (referralsp == NULL) {
     561           0 :                         ldb_asprintf_errstring(ldb, "empty ldap referrals list");
     562           0 :                         ret = LDB_ERR_PROTOCOL_ERROR;
     563           0 :                         break;
     564             :                 }
     565             : 
     566           0 :                 for (i = 0; referralsp[i]; i++) {
     567           0 :                         referral = talloc_strdup(ac, referralsp[i]);
     568             : 
     569           0 :                         ret = ldb_module_send_referral(ac->req, referral);
     570           0 :                         if (ret != LDB_SUCCESS) {
     571           0 :                                 ldb_asprintf_errstring(ldb, "referral send failed: %s",
     572             :                                                        ldb_errstring(ldb));
     573           0 :                                 callback_failed = true;
     574           0 :                                 break;
     575             :                         }
     576             :                 }
     577           0 :                 break;
     578             : 
     579           0 :         case LDAP_RES_SEARCH_RESULT:
     580             :         case LDAP_RES_MODIFY:
     581             :         case LDAP_RES_ADD:
     582             :         case LDAP_RES_DELETE:
     583             :         case LDAP_RES_MODDN:
     584             : 
     585           0 :                 if (ldap_parse_result(lldb->ldap, result, &ret,
     586             :                                         &matcheddnp, &errmsgp,
     587             :                                         &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
     588           0 :                         ret = LDB_ERR_OPERATIONS_ERROR;
     589             :                 }
     590           0 :                 if (ret != LDB_SUCCESS) {
     591           0 :                         ldb_asprintf_errstring(ldb, "ldap parse error for type %d: %s : %s",
     592             :                                                type, ldap_err2string(ret), errmsgp);
     593           0 :                         break;
     594             :                 }
     595             : 
     596           0 :                 if (serverctrlsp != NULL) {
     597             :                         /* FIXME: transform the LDAPControl list into an ldb_control one */
     598           0 :                         ac->controls = NULL;
     599             :                 }
     600             : 
     601           0 :                 request_done = true;
     602           0 :                 break;
     603             : 
     604           0 :         default:
     605           0 :                 ldb_asprintf_errstring(ldb, "unknown ldap return type: %d", type);
     606           0 :                 ret = LDB_ERR_PROTOCOL_ERROR;
     607           0 :                 break;
     608             :         }
     609             : 
     610           0 :         if (ret != LDB_SUCCESS) {
     611             : 
     612             :                 /* if the callback failed the caller will have freed the
     613             :                  * request. Just return and don't try to use it */
     614           0 :                 if (callback_failed) {
     615             : 
     616             :                         /* tell lldb_wait to remove the request from the
     617             :                          *  queue */
     618           0 :                         lret = true;
     619           0 :                         goto free_and_return;
     620             :                 }
     621             : 
     622           0 :                 request_done = true;
     623             :         }
     624             : 
     625           0 :         if (request_done) {
     626           0 :                 lldb_request_done(ac, ac->controls, ret);
     627           0 :                 lret = true;
     628           0 :                 goto free_and_return;
     629             :         }
     630             : 
     631           0 :         lret = false;
     632             : 
     633           0 : free_and_return:
     634             : 
     635           0 :         if (matcheddnp) ldap_memfree(matcheddnp);
     636           0 :         if (errmsgp && *errmsgp) {
     637           0 :                 ldb_set_errstring(ldb, errmsgp);
     638             :         }
     639           0 :         if (errmsgp) {
     640           0 :                 ldap_memfree(errmsgp);
     641             :         }
     642           0 :         if (referralsp) ldap_value_free(referralsp);
     643           0 :         if (serverctrlsp) ldap_controls_free(serverctrlsp);
     644             : 
     645           0 :         ldap_msgfree(result);
     646             : 
     647           0 :         return lret;
     648             : }
     649             : 
     650           0 : static void lldb_timeout(struct tevent_context *ev,
     651             :                          struct tevent_timer *te,
     652             :                          struct timeval t,
     653             :                          void *private_data)
     654             : {
     655           0 :         struct lldb_context *ac;
     656           0 :         ac = talloc_get_type(private_data, struct lldb_context);
     657             : 
     658           0 :         lldb_request_done(ac, NULL, LDB_ERR_TIME_LIMIT_EXCEEDED);
     659           0 : }
     660             : 
     661           0 : static void lldb_callback(struct tevent_context *ev,
     662             :                           struct tevent_timer *te,
     663             :                           struct timeval t,
     664             :                           void *private_data)
     665             : {
     666           0 :         struct lldb_context *ac;
     667           0 :         struct tevent_timer *lte;
     668           0 :         struct timeval tv;
     669           0 :         LDAPMessage *result;
     670           0 :         int lret;
     671             : 
     672           0 :         ac = talloc_get_type(private_data, struct lldb_context);
     673             : 
     674           0 :         if (!ac->msgid) {
     675           0 :                 lldb_request_done(ac, NULL, LDB_ERR_OPERATIONS_ERROR);
     676           0 :                 return;
     677             :         }
     678             : 
     679           0 :         tv.tv_sec = 0;
     680           0 :         tv.tv_usec = 0;
     681           0 :         lret = ldap_result(ac->lldb->ldap, ac->msgid, 0, &tv, &result);
     682           0 :         if (lret == 0) {
     683           0 :                 goto respin;
     684             :         }
     685           0 :         if (lret == -1) {
     686           0 :                 lldb_request_done(ac, NULL, LDB_ERR_OPERATIONS_ERROR);
     687           0 :                 return;
     688             :         }
     689             : 
     690           0 :         if ( ! lldb_parse_result(ac, result)) {
     691           0 :                 goto respin;
     692             :         }
     693             : 
     694           0 :         return;
     695             : 
     696           0 : respin:
     697           0 :         tv.tv_sec = 0;
     698           0 :         tv.tv_usec = 100;
     699           0 :         lte = tevent_add_timer(ev, ac, tv, lldb_callback, ac);
     700           0 :         if (NULL == lte) {
     701           0 :                 lldb_request_done(ac, NULL, LDB_ERR_OPERATIONS_ERROR);
     702             :         }
     703             : }
     704             : 
     705           0 : static bool lldb_dn_is_special(struct ldb_request *req)
     706             : {
     707           0 :         struct ldb_dn *dn = NULL;
     708             : 
     709           0 :         switch (req->operation) {
     710           0 :         case LDB_ADD:
     711           0 :                 dn = req->op.add.message->dn;
     712           0 :                 break;
     713           0 :         case LDB_MODIFY:
     714           0 :                 dn = req->op.mod.message->dn;
     715           0 :                 break;
     716           0 :         case LDB_DELETE:
     717           0 :                 dn = req->op.del.dn;
     718           0 :                 break;
     719           0 :         case LDB_RENAME:
     720           0 :                 dn = req->op.rename.olddn;
     721           0 :                 break;
     722           0 :         default:
     723           0 :                 break;
     724             :         }
     725             : 
     726           0 :         if (dn && ldb_dn_is_special(dn)) {
     727           0 :                 return true;
     728             :         }
     729           0 :         return false;
     730             : }
     731             : 
     732           0 : static void lldb_auto_done_callback(struct tevent_context *ev,
     733             :                                     struct tevent_timer *te,
     734             :                                     struct timeval t,
     735             :                                     void *private_data)
     736             : {
     737           0 :         struct lldb_context *ac;
     738             : 
     739           0 :         ac = talloc_get_type(private_data, struct lldb_context);
     740           0 :         lldb_request_done(ac, NULL, LDB_SUCCESS);
     741           0 : }
     742             : 
     743           0 : static int lldb_handle_request(struct ldb_module *module, struct ldb_request *req)
     744             : {
     745           0 :         struct ldb_context *ldb;
     746           0 :         struct lldb_private *lldb;
     747           0 :         struct lldb_context *ac;
     748           0 :         struct tevent_context *ev;
     749           0 :         struct tevent_timer *te;
     750           0 :         struct timeval tv;
     751           0 :         int ret;
     752             : 
     753           0 :         lldb = talloc_get_type(ldb_module_get_private(module), struct lldb_private);
     754           0 :         ldb = ldb_module_get_ctx(module);
     755             : 
     756           0 :         if (req->starttime == 0 || req->timeout == 0) {
     757           0 :                 ldb_set_errstring(ldb, "Invalid timeout settings");
     758           0 :                 return LDB_ERR_TIME_LIMIT_EXCEEDED;
     759             :         }
     760             : 
     761           0 :         ev = ldb_get_event_context(ldb);
     762           0 :         if (NULL == ev) {
     763           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     764             :         }
     765             : 
     766           0 :         ac = talloc_zero(ldb, struct lldb_context);
     767           0 :         if (ac == NULL) {
     768           0 :                 ldb_set_errstring(ldb, "Out of Memory");
     769           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     770             :         }
     771             : 
     772           0 :         ac->module = module;
     773           0 :         ac->req = req;
     774           0 :         ac->lldb = lldb;
     775           0 :         ac->msgid = 0;
     776             : 
     777           0 :         if (lldb_dn_is_special(req)) {
     778           0 :                 tv.tv_sec = 0;
     779           0 :                 tv.tv_usec = 0;
     780           0 :                 te = tevent_add_timer(ev, ac, tv,
     781             :                                      lldb_auto_done_callback, ac);
     782           0 :                 if (NULL == te) {
     783           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     784             :                 }
     785             : 
     786           0 :                 return LDB_SUCCESS;
     787             :         }
     788             : 
     789           0 :         switch (ac->req->operation) {
     790           0 :         case LDB_SEARCH:
     791           0 :                 ret = lldb_search(ac);
     792           0 :                 break;
     793           0 :         case LDB_ADD:
     794           0 :                 ret = lldb_add(ac);
     795           0 :                 break;
     796           0 :         case LDB_MODIFY:
     797           0 :                 ret = lldb_modify(ac);
     798           0 :                 break;
     799           0 :         case LDB_DELETE:
     800           0 :                 ret = lldb_delete(ac);
     801           0 :                 break;
     802           0 :         case LDB_RENAME:
     803           0 :                 ret = lldb_rename(ac);
     804           0 :                 break;
     805           0 :         default:
     806             :                 /* no other op supported */
     807           0 :                 ret = LDB_ERR_PROTOCOL_ERROR;
     808           0 :                 break;
     809             :         }
     810             : 
     811           0 :         if (ret != LDB_SUCCESS) {
     812           0 :                 lldb_request_done(ac, NULL, ret);
     813           0 :                 return ret;
     814             :         }
     815             : 
     816           0 :         tv.tv_sec = 0;
     817           0 :         tv.tv_usec = 0;
     818           0 :         te = tevent_add_timer(ev, ac, tv, lldb_callback, ac);
     819           0 :         if (NULL == te) {
     820           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     821             :         }
     822             : 
     823           0 :         if (req->timeout > 0) {
     824           0 :                 tv.tv_sec = req->starttime + req->timeout;
     825           0 :                 tv.tv_usec = 0;
     826           0 :                 te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
     827           0 :                 if (NULL == te) {
     828           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     829             :                 }
     830             :         }
     831             : 
     832           0 :         return LDB_SUCCESS;
     833             : }
     834             : 
     835             : static const struct ldb_module_ops lldb_ops = {
     836             :         .name              = "ldap",
     837             :         .search            = lldb_handle_request,
     838             :         .add               = lldb_handle_request,
     839             :         .modify            = lldb_handle_request,
     840             :         .del               = lldb_handle_request,
     841             :         .rename            = lldb_handle_request,
     842             :         .request           = lldb_handle_request,
     843             :         .start_transaction = lldb_start_trans,
     844             :         .end_transaction   = lldb_end_trans,
     845             :         .del_transaction   = lldb_del_trans,
     846             : };
     847             : 
     848             : 
     849           0 : static int lldb_destructor(struct lldb_private *lldb)
     850             : {
     851           0 :         ldap_unbind(lldb->ldap);
     852           0 :         return 0;
     853             : }
     854             : 
     855             : 
     856             : /*
     857             :   optionally perform a bind
     858             :  */
     859           0 : static int lldb_bind(struct ldb_module *module,
     860             :                      const char *options[])
     861             : {
     862           0 :         const char *bind_mechanism;
     863           0 :         struct lldb_private *lldb;
     864           0 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     865           0 :         int ret;
     866             : 
     867           0 :         bind_mechanism = ldb_options_find(ldb, options, "bindMech");
     868           0 :         if (bind_mechanism == NULL) {
     869             :                 /* no bind wanted */
     870           0 :                 return LDB_SUCCESS;
     871             :         }
     872             : 
     873           0 :         lldb = talloc_get_type(ldb_module_get_private(module), struct lldb_private);
     874             : 
     875           0 :         if (strcmp(bind_mechanism, "simple") == 0) {
     876           0 :                 const char *bind_id, *bind_secret;
     877             : 
     878           0 :                 bind_id = ldb_options_find(ldb, options, "bindID");
     879           0 :                 bind_secret = ldb_options_find(ldb, options, "bindSecret");
     880           0 :                 if (bind_id == NULL || bind_secret == NULL) {
     881           0 :                         ldb_asprintf_errstring(ldb, "simple bind requires bindID and bindSecret");
     882           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     883             :                 }
     884             : 
     885           0 :                 ret = ldap_simple_bind_s(lldb->ldap, bind_id, bind_secret);
     886           0 :                 if (ret != LDAP_SUCCESS) {
     887           0 :                         ldb_asprintf_errstring(ldb, "bind failed: %s", ldap_err2string(ret));
     888           0 :                         return ret;
     889             :                 }
     890           0 :                 return LDB_SUCCESS;
     891             :         }
     892             : 
     893           0 :         ldb_asprintf_errstring(ldb, "bind failed: unknown mechanism %s", bind_mechanism);
     894           0 :         return LDB_ERR_INAPPROPRIATE_AUTHENTICATION;
     895             : }
     896             : 
     897             : /*
     898             :   connect to the database
     899             : */
     900           0 : static int lldb_connect(struct ldb_context *ldb,
     901             :                         const char *url,
     902             :                         unsigned int flags,
     903             :                         const char *options[],
     904             :                         struct ldb_module **_module)
     905             : {
     906           0 :         struct ldb_module *module;
     907           0 :         struct lldb_private *lldb;
     908           0 :         int version = 3;
     909           0 :         int ret;
     910             : 
     911           0 :         module = ldb_module_new(ldb, ldb, "ldb_ldap backend", &lldb_ops);
     912           0 :         if (!module) return LDB_ERR_OPERATIONS_ERROR;
     913             : 
     914           0 :         lldb = talloc_zero(module, struct lldb_private);
     915           0 :         if (!lldb) {
     916           0 :                 ldb_oom(ldb);
     917           0 :                 goto failed;
     918             :         }
     919           0 :         ldb_module_set_private(module, lldb);
     920             : 
     921           0 :         ret = ldap_initialize(&lldb->ldap, url);
     922           0 :         if (ret != LDAP_SUCCESS) {
     923           0 :                 ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_initialize failed for URL '%s' - %s",
     924             :                           url, ldap_err2string(ret));
     925           0 :                 goto failed;
     926             :         }
     927             : 
     928           0 :         talloc_set_destructor(lldb, lldb_destructor);
     929             : 
     930           0 :         ret = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
     931           0 :         if (ret != LDAP_SUCCESS) {
     932           0 :                 ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_set_option failed - %s",
     933             :                           ldap_err2string(ret));
     934           0 :                 goto failed;
     935             :         }
     936             : 
     937           0 :         *_module = module;
     938             : 
     939           0 :         ret = lldb_bind(module, options);
     940           0 :         if (ret != LDB_SUCCESS) {
     941           0 :                 goto failed;
     942             :         }
     943             : 
     944             : 
     945           0 :         return LDB_SUCCESS;
     946             : 
     947           0 : failed:
     948           0 :         talloc_free(module);
     949           0 :         return LDB_ERR_OPERATIONS_ERROR;
     950             : }
     951             : 
     952             : /*
     953             :   initialise the module
     954             :  */
     955        6067 : int ldb_ldap_init(const char *version)
     956             : {
     957         444 :         int ret, i;
     958        6067 :         const char *names[] = { "ldap", "ldaps", "ldapi", NULL };
     959        6067 :         LDB_MODULE_CHECK_VERSION(version);
     960       24268 :         for (i=0; names[i]; i++) {
     961       18201 :                 ret = ldb_register_backend(names[i], lldb_connect, false);
     962       18201 :                 if (ret != LDB_SUCCESS) {
     963           0 :                         return ret;
     964             :                 }
     965             :         }
     966        5623 :         return LDB_SUCCESS;
     967             : }

Generated by: LCOV version 1.14