LCOV - code coverage report
Current view: top level - source4/ldap_server - ldap_backend.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 723 870 83.1 %
Date: 2024-06-13 04:01:37 Functions: 20 21 95.2 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    LDAP server
       4             :    Copyright (C) Stefan Metzmacher 2004
       5             :    Copyright (C) Matthias Dieter Wallnöfer 2009
       6             :    
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             :    
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             :    
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "ldap_server/ldap_server.h"
      23             : #include "../lib/util/dlinklist.h"
      24             : #include "auth/credentials/credentials.h"
      25             : #include "auth/gensec/gensec.h"
      26             : #include "auth/gensec/gensec_internal.h" /* TODO: remove this */
      27             : #include "auth/common_auth.h"
      28             : #include "param/param.h"
      29             : #include "samba/service_stream.h"
      30             : #include "dsdb/samdb/samdb.h"
      31             : #include <ldb_errors.h>
      32             : #include <ldb_module.h>
      33             : #include "ldb_wrap.h"
      34             : #include "lib/tsocket/tsocket.h"
      35             : #include "libcli/ldap/ldap_proto.h"
      36             : #include "source4/auth/auth.h"
      37             : 
      38      166991 : static int map_ldb_error(TALLOC_CTX *mem_ctx, int ldb_err,
      39             :         const char *add_err_string, const char **errstring)
      40             : {
      41             :         WERROR err;
      42             : 
      43             :         /* Certain LDB modules need to return very special WERROR codes. Proof
      44             :          * for them here and if they exist skip the rest of the mapping. */
      45      166991 :         if (add_err_string != NULL) {
      46             :                 char *endptr;
      47       38007 :                 strtol(add_err_string, &endptr, 16);
      48       38007 :                 if (endptr != add_err_string) {
      49       10076 :                         *errstring = add_err_string;
      50       10076 :                         return ldb_err;
      51             :                 }
      52             :         }
      53             : 
      54             :         /* Otherwise we calculate here a generic, but appropriate WERROR. */
      55             : 
      56      156915 :         switch (ldb_err) {
      57      128973 :         case LDB_SUCCESS:
      58      128973 :                 err = WERR_OK;
      59      128973 :         break;
      60          80 :         case LDB_ERR_OPERATIONS_ERROR:
      61          80 :                 err = WERR_DS_OPERATIONS_ERROR;
      62          80 :         break;
      63           1 :         case LDB_ERR_PROTOCOL_ERROR:
      64           1 :                 err = WERR_DS_PROTOCOL_ERROR;
      65           1 :         break;
      66           5 :         case LDB_ERR_TIME_LIMIT_EXCEEDED:
      67           5 :                 err = WERR_DS_TIMELIMIT_EXCEEDED;
      68           5 :         break;
      69          10 :         case LDB_ERR_SIZE_LIMIT_EXCEEDED:
      70          10 :                 err = WERR_DS_SIZELIMIT_EXCEEDED;
      71          10 :         break;
      72           0 :         case LDB_ERR_COMPARE_FALSE:
      73           0 :                 err = WERR_DS_COMPARE_FALSE;
      74           0 :         break;
      75           0 :         case LDB_ERR_COMPARE_TRUE:
      76           0 :                 err = WERR_DS_COMPARE_TRUE;
      77           0 :         break;
      78           0 :         case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
      79           0 :                 err = WERR_DS_AUTH_METHOD_NOT_SUPPORTED;
      80           0 :         break;
      81           0 :         case LDB_ERR_STRONG_AUTH_REQUIRED:
      82           0 :                 err = WERR_DS_STRONG_AUTH_REQUIRED;
      83           0 :         break;
      84           8 :         case LDB_ERR_REFERRAL:
      85           8 :                 err = WERR_DS_REFERRAL;
      86           8 :         break;
      87           1 :         case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
      88           1 :                 err = WERR_DS_ADMIN_LIMIT_EXCEEDED;
      89           1 :         break;
      90           0 :         case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
      91           0 :                 err = WERR_DS_UNAVAILABLE_CRIT_EXTENSION;
      92           0 :         break;
      93           0 :         case LDB_ERR_CONFIDENTIALITY_REQUIRED:
      94           0 :                 err = WERR_DS_CONFIDENTIALITY_REQUIRED;
      95           0 :         break;
      96           0 :         case LDB_ERR_SASL_BIND_IN_PROGRESS:
      97           0 :                 err = WERR_DS_BUSY;
      98           0 :         break;
      99           5 :         case LDB_ERR_NO_SUCH_ATTRIBUTE:
     100           5 :                 err = WERR_DS_NO_ATTRIBUTE_OR_VALUE;
     101           5 :         break;
     102           3 :         case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
     103           3 :                 err = WERR_DS_ATTRIBUTE_TYPE_UNDEFINED;
     104           3 :         break;
     105           0 :         case LDB_ERR_INAPPROPRIATE_MATCHING:
     106           0 :                 err = WERR_DS_INAPPROPRIATE_MATCHING;
     107           0 :         break;
     108         397 :         case LDB_ERR_CONSTRAINT_VIOLATION:
     109         397 :                 err = WERR_DS_CONSTRAINT_VIOLATION;
     110         397 :         break;
     111         137 :         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
     112         137 :                 err = WERR_DS_ATTRIBUTE_OR_VALUE_EXISTS;
     113         137 :         break;
     114          15 :         case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
     115          15 :                 err = WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
     116          15 :         break;
     117       25582 :         case LDB_ERR_NO_SUCH_OBJECT:
     118       25582 :                 err = WERR_DS_NO_SUCH_OBJECT;
     119       25582 :         break;
     120           0 :         case LDB_ERR_ALIAS_PROBLEM:
     121           0 :                 err = WERR_DS_ALIAS_PROBLEM;
     122           0 :         break;
     123          98 :         case LDB_ERR_INVALID_DN_SYNTAX:
     124          98 :                 err = WERR_DS_INVALID_DN_SYNTAX;
     125          98 :         break;
     126           0 :         case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
     127           0 :                 err = WERR_DS_ALIAS_DEREF_PROBLEM;
     128           0 :         break;
     129           0 :         case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
     130           0 :                 err = WERR_DS_INAPPROPRIATE_AUTH;
     131           0 :         break;
     132           0 :         case LDB_ERR_INVALID_CREDENTIALS:
     133           0 :                 err = WERR_ACCESS_DENIED;
     134           0 :         break;
     135         914 :         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
     136         914 :                 err = WERR_DS_INSUFF_ACCESS_RIGHTS;
     137         914 :         break;
     138           0 :         case LDB_ERR_BUSY:
     139           0 :                 err = WERR_DS_BUSY;
     140           0 :         break;
     141           0 :         case LDB_ERR_UNAVAILABLE:
     142           0 :                 err = WERR_DS_UNAVAILABLE;
     143           0 :         break;
     144         396 :         case LDB_ERR_UNWILLING_TO_PERFORM:
     145         396 :                 err = WERR_DS_UNWILLING_TO_PERFORM;
     146         396 :         break;
     147           0 :         case LDB_ERR_LOOP_DETECT:
     148           0 :                 err = WERR_DS_LOOP_DETECT;
     149           0 :         break;
     150           8 :         case LDB_ERR_NAMING_VIOLATION:
     151           8 :                 err = WERR_DS_NAMING_VIOLATION;
     152           8 :         break;
     153         241 :         case LDB_ERR_OBJECT_CLASS_VIOLATION:
     154         241 :                 err = WERR_DS_OBJ_CLASS_VIOLATION;
     155         241 :         break;
     156          11 :         case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
     157          11 :                 err = WERR_DS_CANT_ON_NON_LEAF;
     158          11 :         break;
     159           2 :         case LDB_ERR_NOT_ALLOWED_ON_RDN:
     160           2 :                 err = WERR_DS_CANT_ON_RDN;
     161           2 :         break;
     162          24 :         case LDB_ERR_ENTRY_ALREADY_EXISTS:
     163          24 :                 err = WERR_DS_OBJ_STRING_NAME_EXISTS;
     164          24 :         break;
     165           0 :         case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
     166           0 :                 err = WERR_DS_CANT_MOD_OBJ_CLASS;
     167           0 :         break;
     168           0 :         case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
     169           0 :                 err = WERR_DS_AFFECTS_MULTIPLE_DSAS;
     170           0 :         break;
     171           4 :         default:
     172           4 :                 err = WERR_DS_GENERIC_ERROR;
     173           4 :         break;
     174             :         }
     175             : 
     176      193110 :         *errstring = talloc_asprintf(mem_ctx, "%08X: %s", W_ERROR_V(err),
     177       36195 :                 add_err_string != NULL ? add_err_string : ldb_strerror(ldb_err));
     178             : 
     179             :         /* result is 1:1 for now */
     180      156915 :         return ldb_err;
     181             : }
     182             : 
     183             : /*
     184             :   connect to the sam database
     185             : */
     186       38920 : int ldapsrv_backend_Init(struct ldapsrv_connection *conn,
     187             :                               char **errstring)
     188             : {
     189       98294 :         int ret = samdb_connect_url(conn,
     190       38920 :                                     conn->connection->event.ctx,
     191             :                                     conn->lp_ctx,
     192             :                                     conn->session_info,
     193       38920 :                                     conn->global_catalog ? LDB_FLG_RDONLY : 0,
     194             :                                     "sam.ldb",
     195       38920 :                                     conn->connection->remote_address,
     196             :                                     &conn->ldb,
     197             :                                     errstring);
     198       38920 :         if (ret != LDB_SUCCESS) {
     199           0 :                 return ret;
     200             :         }
     201             : 
     202       38920 :         if (conn->server_credentials) {
     203       38920 :                 struct gensec_security *gensec_security = NULL;
     204       38920 :                 const char **sasl_mechs = NULL;
     205             :                 NTSTATUS status;
     206             : 
     207       98294 :                 status = samba_server_gensec_start(conn,
     208       38920 :                                                    conn->connection->event.ctx,
     209       38920 :                                                    conn->connection->msg_ctx,
     210             :                                                    conn->lp_ctx,
     211             :                                                    conn->server_credentials,
     212             :                                                    "ldap",
     213             :                                                    &gensec_security);
     214       38920 :                 if (!NT_STATUS_IS_OK(status)) {
     215           0 :                         DBG_ERR("samba_server_gensec_start failed: %s\n",
     216             :                                 nt_errstr(status));
     217           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     218             :                 }
     219             : 
     220             :                 /* ldb can have a different lifetime to conn, so we
     221             :                    need to ensure that sasl_mechs lives as long as the
     222             :                    ldb does */
     223       38920 :                 sasl_mechs = gensec_security_sasl_names(gensec_security,
     224       38920 :                                                         conn->ldb);
     225       38920 :                 TALLOC_FREE(gensec_security);
     226       38920 :                 if (sasl_mechs == NULL) {
     227           0 :                         DBG_ERR("Failed to get sasl mechs!\n");
     228           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     229             :                 }
     230             : 
     231       38920 :                 ldb_set_opaque(conn->ldb, "supportedSASLMechanisms", sasl_mechs);
     232             :         }
     233             : 
     234       38920 :         return LDB_SUCCESS;
     235             : }
     236             : 
     237     1109277 : struct ldapsrv_reply *ldapsrv_init_reply(struct ldapsrv_call *call, uint8_t type)
     238             : {
     239             :         struct ldapsrv_reply *reply;
     240             : 
     241     1109277 :         reply = talloc_zero(call, struct ldapsrv_reply);
     242     1109277 :         if (!reply) {
     243           0 :                 return NULL;
     244             :         }
     245     1109277 :         reply->msg = talloc_zero(reply, struct ldap_message);
     246     1109277 :         if (reply->msg == NULL) {
     247           0 :                 talloc_free(reply);
     248           0 :                 return NULL;
     249             :         }
     250             : 
     251     1109277 :         reply->msg->messageid = call->request->messageid;
     252     1109277 :         reply->msg->type = type;
     253     1109277 :         reply->msg->controls = NULL;
     254             : 
     255     1109277 :         return reply;
     256             : }
     257             : 
     258             : /*
     259             :  * Encode a reply to an LDAP client as ASN.1, free the original memory
     260             :  */
     261     1109277 : static NTSTATUS ldapsrv_encode(TALLOC_CTX *mem_ctx,
     262             :                                struct ldapsrv_reply *reply)
     263             : {
     264     1109277 :         bool bret = ldap_encode(reply->msg,
     265             :                                 samba_ldap_control_handlers(),
     266             :                                 &reply->blob,
     267             :                                 mem_ctx);
     268     1109277 :         TALLOC_FREE(reply->msg);
     269     1109277 :         if (!bret) {
     270           0 :                 DEBUG(0,("Failed to encode ldap reply of type %d: "
     271             :                          "ldap_encode() failed\n",
     272             :                          reply->msg->type));
     273           0 :                 return NT_STATUS_NO_MEMORY;
     274             :         }
     275             : 
     276     1109277 :         talloc_set_name_const(reply->blob.data,
     277             :                               "Outgoing, encoded single LDAP reply");
     278             : 
     279     1109277 :         return NT_STATUS_OK;
     280             : }
     281             : 
     282             : /*
     283             :  * Queue a reply (encoding it also), even if it would exceed the
     284             :  * limit.  This allows the error packet with LDAP_SIZE_LIMIT_EXCEEDED
     285             :  * to be sent
     286             :  */
     287      288178 : static NTSTATUS ldapsrv_queue_reply_forced(struct ldapsrv_call *call,
     288             :                                            struct ldapsrv_reply *reply)
     289             : {
     290      288178 :         NTSTATUS status = ldapsrv_encode(call, reply);
     291             : 
     292      288178 :         if (NT_STATUS_IS_OK(status)) {
     293      288178 :                 DLIST_ADD_END(call->replies, reply);
     294             :         }
     295      288178 :         return status;
     296             : }
     297             : 
     298             : /*
     299             :  * Queue a reply (encoding it also) but check we do not send more than
     300             :  * LDAP_SERVER_MAX_REPLY_SIZE of responses as a way to limit the
     301             :  * amount of data a client can make us allocate.
     302             :  */
     303      821099 : NTSTATUS ldapsrv_queue_reply(struct ldapsrv_call *call, struct ldapsrv_reply *reply)
     304             : {
     305      821099 :         NTSTATUS status = ldapsrv_encode(call, reply);
     306             : 
     307      821099 :         if (!NT_STATUS_IS_OK(status)) {
     308           0 :                 return status;
     309             :         }
     310             : 
     311      821099 :         if (call->reply_size > call->reply_size + reply->blob.length
     312      821099 :             || call->reply_size + reply->blob.length > LDAP_SERVER_MAX_REPLY_SIZE) {
     313          10 :                 DBG_WARNING("Refusing to queue LDAP search response size "
     314             :                             "of more than %zu bytes\n",
     315             :                             LDAP_SERVER_MAX_REPLY_SIZE);
     316          10 :                 TALLOC_FREE(reply->blob.data);
     317          10 :                 return NT_STATUS_FILE_TOO_LARGE;
     318             :         }
     319             : 
     320      821089 :         call->reply_size += reply->blob.length;
     321             : 
     322      821089 :         DLIST_ADD_END(call->replies, reply);
     323             : 
     324      821089 :         return status;
     325             : }
     326             : 
     327           0 : static NTSTATUS ldapsrv_unwilling(struct ldapsrv_call *call, int error)
     328             : {
     329             :         struct ldapsrv_reply *reply;
     330             :         struct ldap_ExtendedResponse *r;
     331             : 
     332           0 :         DEBUG(10,("Unwilling type[%d] id[%d]\n", call->request->type, call->request->messageid));
     333             : 
     334           0 :         reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
     335           0 :         if (!reply) {
     336           0 :                 return NT_STATUS_NO_MEMORY;
     337             :         }
     338             : 
     339           0 :         r = &reply->msg->r.ExtendedResponse;
     340           0 :         r->response.resultcode = error;
     341           0 :         r->response.dn = NULL;
     342           0 :         r->response.errormessage = NULL;
     343           0 :         r->response.referral = NULL;
     344           0 :         r->oid = NULL;
     345           0 :         r->value = NULL;
     346             : 
     347           0 :         ldapsrv_queue_reply(call, reply);
     348           0 :         return NT_STATUS_OK;
     349             : }
     350             : 
     351       43573 : static int ldapsrv_add_with_controls(struct ldapsrv_call *call,
     352             :                                      const struct ldb_message *message,
     353             :                                      struct ldb_control **controls,
     354             :                                      struct ldb_result *res)
     355             : {
     356       43573 :         struct ldb_context *ldb = call->conn->ldb;
     357             :         struct ldb_request *req;
     358             :         int ret;
     359             : 
     360       43573 :         ret = ldb_msg_sanity_check(ldb, message);
     361       43573 :         if (ret != LDB_SUCCESS) {
     362           0 :                 return ret;
     363             :         }
     364             : 
     365       43573 :         ret = ldb_build_add_req(&req, ldb, ldb,
     366             :                                         message,
     367             :                                         controls,
     368             :                                         res,
     369             :                                         ldb_modify_default_callback,
     370             :                                         NULL);
     371             : 
     372       43573 :         if (ret != LDB_SUCCESS) return ret;
     373             : 
     374       43573 :         if (call->conn->global_catalog) {
     375           0 :                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM, "modify forbidden on global catalog port");
     376             :         }
     377       43573 :         ldb_request_add_control(req, DSDB_CONTROL_NO_GLOBAL_CATALOG, false, NULL);
     378             : 
     379       43573 :         ret = ldb_transaction_start(ldb);
     380       43573 :         if (ret != LDB_SUCCESS) {
     381           0 :                 return ret;
     382             :         }
     383             : 
     384       43573 :         if (!call->conn->is_privileged) {
     385       43573 :                 ldb_req_mark_untrusted(req);
     386             :         }
     387             : 
     388       43573 :         LDB_REQ_SET_LOCATION(req);
     389             : 
     390       43573 :         ret = ldb_request(ldb, req);
     391       43573 :         if (ret == LDB_SUCCESS) {
     392       43563 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     393             :         }
     394             : 
     395       43573 :         if (ret == LDB_SUCCESS) {
     396       42925 :                 ret = ldb_transaction_commit(ldb);
     397             :         }
     398             :         else {
     399         648 :                 ldb_transaction_cancel(ldb);
     400             :         }
     401             : 
     402       43573 :         talloc_free(req);
     403       43573 :         return ret;
     404             : }
     405             : 
     406             : /* create and execute a modify request */
     407       63869 : static int ldapsrv_mod_with_controls(struct ldapsrv_call *call,
     408             :                                      const struct ldb_message *message,
     409             :                                      struct ldb_control **controls,
     410             :                                      struct ldb_result *res)
     411             : {
     412       63869 :         struct ldb_context *ldb = call->conn->ldb;
     413             :         struct ldb_request *req;
     414             :         int ret;
     415             : 
     416       63869 :         ret = ldb_msg_sanity_check(ldb, message);
     417       63869 :         if (ret != LDB_SUCCESS) {
     418           0 :                 return ret;
     419             :         }
     420             : 
     421       63869 :         ret = ldb_build_mod_req(&req, ldb, ldb,
     422             :                                         message,
     423             :                                         controls,
     424             :                                         res,
     425             :                                         ldb_modify_default_callback,
     426             :                                         NULL);
     427             : 
     428       63869 :         if (ret != LDB_SUCCESS) {
     429           0 :                 return ret;
     430             :         }
     431             : 
     432       63869 :         if (call->conn->global_catalog) {
     433           0 :                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM, "modify forbidden on global catalog port");
     434             :         }
     435       63869 :         ldb_request_add_control(req, DSDB_CONTROL_NO_GLOBAL_CATALOG, false, NULL);
     436             : 
     437       63869 :         ret = ldb_transaction_start(ldb);
     438       63869 :         if (ret != LDB_SUCCESS) {
     439           0 :                 return ret;
     440             :         }
     441             : 
     442       63869 :         if (!call->conn->is_privileged) {
     443       63869 :                 ldb_req_mark_untrusted(req);
     444             :         }
     445             : 
     446       63869 :         LDB_REQ_SET_LOCATION(req);
     447             : 
     448       63869 :         ret = ldb_request(ldb, req);
     449       63869 :         if (ret == LDB_SUCCESS) {
     450       61590 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     451             :         }
     452             : 
     453       63869 :         if (ret == LDB_SUCCESS) {
     454       60173 :                 ret = ldb_transaction_commit(ldb);
     455             :         }
     456             :         else {
     457        3696 :                 ldb_transaction_cancel(ldb);
     458             :         }
     459             : 
     460       63869 :         talloc_free(req);
     461       63869 :         return ret;
     462             : }
     463             : 
     464             : /* create and execute a delete request */
     465       51169 : static int ldapsrv_del_with_controls(struct ldapsrv_call *call,
     466             :                                      struct ldb_dn *dn,
     467             :                                      struct ldb_control **controls,
     468             :                                      struct ldb_result *res)
     469             : {
     470       51169 :         struct ldb_context *ldb = call->conn->ldb;
     471             :         struct ldb_request *req;
     472             :         int ret;
     473             : 
     474       51169 :         ret = ldb_build_del_req(&req, ldb, ldb,
     475             :                                         dn,
     476             :                                         controls,
     477             :                                         res,
     478             :                                         ldb_modify_default_callback,
     479             :                                         NULL);
     480             : 
     481       51169 :         if (ret != LDB_SUCCESS) return ret;
     482             : 
     483       51169 :         if (call->conn->global_catalog) {
     484           0 :                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM, "modify forbidden on global catalog port");
     485             :         }
     486       51169 :         ldb_request_add_control(req, DSDB_CONTROL_NO_GLOBAL_CATALOG, false, NULL);
     487             : 
     488       51169 :         ret = ldb_transaction_start(ldb);
     489       51169 :         if (ret != LDB_SUCCESS) {
     490           0 :                 return ret;
     491             :         }
     492             : 
     493       51169 :         if (!call->conn->is_privileged) {
     494       51169 :                 ldb_req_mark_untrusted(req);
     495             :         }
     496             : 
     497       51169 :         LDB_REQ_SET_LOCATION(req);
     498             : 
     499       51169 :         ret = ldb_request(ldb, req);
     500       51169 :         if (ret == LDB_SUCCESS) {
     501       51158 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     502             :         }
     503             : 
     504       51169 :         if (ret == LDB_SUCCESS) {
     505       25567 :                 ret = ldb_transaction_commit(ldb);
     506             :         }
     507             :         else {
     508       25602 :                 ldb_transaction_cancel(ldb);
     509             :         }
     510             : 
     511       51169 :         talloc_free(req);
     512       51169 :         return ret;
     513             : }
     514             : 
     515         360 : static int ldapsrv_rename_with_controls(struct ldapsrv_call *call,
     516             :                                         struct ldb_dn *olddn,
     517             :                                         struct ldb_dn *newdn,
     518             :                                         struct ldb_control **controls,
     519             :                                         struct ldb_result *res)
     520             : {
     521         360 :         struct ldb_context *ldb = call->conn->ldb;
     522             :         struct ldb_request *req;
     523             :         int ret;
     524             : 
     525         360 :         ret = ldb_build_rename_req(&req, ldb, ldb,
     526             :                                         olddn,
     527             :                                         newdn,
     528             :                                         controls,
     529             :                                         res,
     530             :                                         ldb_modify_default_callback,
     531             :                                         NULL);
     532             : 
     533         360 :         if (ret != LDB_SUCCESS) return ret;
     534             : 
     535         360 :         if (call->conn->global_catalog) {
     536           0 :                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM, "modify forbidden on global catalog port");
     537             :         }
     538         360 :         ldb_request_add_control(req, DSDB_CONTROL_NO_GLOBAL_CATALOG, false, NULL);
     539             : 
     540         360 :         ret = ldb_transaction_start(ldb);
     541         360 :         if (ret != LDB_SUCCESS) {
     542           0 :                 return ret;
     543             :         }
     544             : 
     545         360 :         if (!call->conn->is_privileged) {
     546         360 :                 ldb_req_mark_untrusted(req);
     547             :         }
     548             : 
     549         360 :         LDB_REQ_SET_LOCATION(req);
     550             : 
     551         360 :         ret = ldb_request(ldb, req);
     552         360 :         if (ret == LDB_SUCCESS) {
     553         360 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     554             :         }
     555             : 
     556         360 :         if (ret == LDB_SUCCESS) {
     557         308 :                 ret = ldb_transaction_commit(ldb);
     558             :         }
     559             :         else {
     560          52 :                 ldb_transaction_cancel(ldb);
     561             :         }
     562             : 
     563         360 :         talloc_free(req);
     564         360 :         return ret;
     565             : }
     566             : 
     567             : 
     568             : 
     569             : struct ldapsrv_context {
     570             :         struct ldapsrv_call *call;
     571             :         int extended_type;
     572             :         bool attributesonly;
     573             :         struct ldb_control **controls;
     574             :         size_t count; /* For notificaiton only */
     575             : };
     576             : 
     577      923873 : static int ldap_server_search_callback(struct ldb_request *req, struct ldb_reply *ares)
     578             : {
     579      923873 :         struct ldapsrv_context *ctx = talloc_get_type(req->context, struct ldapsrv_context);
     580      923873 :         struct ldapsrv_call *call = ctx->call;
     581      923873 :         struct ldb_context *ldb = call->conn->ldb;
     582             :         unsigned int j;
     583      923873 :         struct ldapsrv_reply *ent_r = NULL;
     584             :         struct ldap_SearchResEntry *ent;
     585             :         int ret;
     586             :         NTSTATUS status;
     587             : 
     588      923873 :         if (!ares) {
     589           0 :                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
     590             :         }
     591      923873 :         if (ares->error != LDB_SUCCESS) {
     592        7998 :                 return ldb_request_done(req, ares->error);
     593             :         }
     594             : 
     595      915875 :         switch (ares->type) {
     596      546200 :         case LDB_REPLY_ENTRY:
     597             :         {
     598      546200 :                 struct ldb_message *msg = ares->message;
     599      546200 :                 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
     600      546200 :                 if (ent_r == NULL) {
     601           0 :                         return ldb_oom(ldb);
     602             :                 }
     603             : 
     604      546200 :                 ctx->count++;
     605             : 
     606             :                 /*
     607             :                  * Put the LDAP search response data under ent_r->msg
     608             :                  * so we can free that later once encoded
     609             :                  */
     610      546200 :                 talloc_steal(ent_r->msg, msg);
     611             : 
     612      546200 :                 ent = &ent_r->msg->r.SearchResultEntry;
     613      546200 :                 ent->dn = ldb_dn_get_extended_linearized(ent_r, msg->dn,
     614             :                                                          ctx->extended_type);
     615      546200 :                 ent->num_attributes = 0;
     616      546200 :                 ent->attributes = NULL;
     617      546200 :                 if (msg->num_elements == 0) {
     618       58816 :                         goto queue_reply;
     619             :                 }
     620      487384 :                 ent->num_attributes = msg->num_elements;
     621      487384 :                 ent->attributes = talloc_array(ent_r, struct ldb_message_element, ent->num_attributes);
     622      487384 :                 if (ent->attributes == NULL) {
     623           0 :                         return ldb_oom(ldb);
     624             :                 }
     625             : 
     626     2870626 :                 for (j=0; j < ent->num_attributes; j++) {
     627     2383242 :                         ent->attributes[j].name = msg->elements[j].name;
     628     2383242 :                         ent->attributes[j].num_values = 0;
     629     2383242 :                         ent->attributes[j].values = NULL;
     630     2383242 :                         if (ctx->attributesonly && (msg->elements[j].num_values == 0)) {
     631           0 :                                 continue;
     632             :                         }
     633     2383242 :                         ent->attributes[j].num_values = msg->elements[j].num_values;
     634     2383242 :                         ent->attributes[j].values = msg->elements[j].values;
     635             :                 }
     636      487384 : queue_reply:
     637      546200 :                 status = ldapsrv_queue_reply(call, ent_r);
     638      546200 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_TOO_LARGE)) {
     639          10 :                         ret = ldb_request_done(req,
     640             :                                                LDB_ERR_SIZE_LIMIT_EXCEEDED);
     641          10 :                         ldb_asprintf_errstring(ldb,
     642             :                                                "LDAP search response size "
     643             :                                                "limited to %zu bytes\n",
     644             :                                                LDAP_SERVER_MAX_REPLY_SIZE);
     645      546190 :                 } else if (!NT_STATUS_IS_OK(status)) {
     646           0 :                         ret = ldb_request_done(req,
     647             :                                                ldb_operr(ldb));
     648             :                 } else {
     649      546190 :                         ret = LDB_SUCCESS;
     650             :                 }
     651      546200 :                 break;
     652             :         }
     653       89477 :         case LDB_REPLY_REFERRAL:
     654             :         {
     655             :                 struct ldap_SearchResRef *ent_ref;
     656             : 
     657             :                 /*
     658             :                  * TODO: This should be handled by the notification
     659             :                  * module not here
     660             :                  */
     661       89477 :                 if (call->notification.busy) {
     662           6 :                         ret = LDB_SUCCESS;
     663           6 :                         break;
     664             :                 }
     665             : 
     666       89471 :                 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultReference);
     667       89471 :                 if (ent_r == NULL) {
     668           0 :                         return ldb_oom(ldb);
     669             :                 }
     670             : 
     671             :                 /*
     672             :                  * Put the LDAP referral data under ent_r->msg
     673             :                  * so we can free that later once encoded
     674             :                  */
     675       89471 :                 talloc_steal(ent_r->msg, ares->referral);
     676             : 
     677       89471 :                 ent_ref = &ent_r->msg->r.SearchResultReference;
     678       89471 :                 ent_ref->referral = ares->referral;
     679             : 
     680       89471 :                 status = ldapsrv_queue_reply(call, ent_r);
     681       89471 :                 if (!NT_STATUS_IS_OK(status)) {
     682           0 :                         ret = LDB_ERR_OPERATIONS_ERROR;
     683             :                 } else {
     684       89471 :                         ret = LDB_SUCCESS;
     685             :                 }
     686       89471 :                 break;
     687             :         }
     688      280198 :         case LDB_REPLY_DONE:
     689             :         {
     690             :                 /*
     691             :                  * We don't queue the reply for this one, we let that
     692             :                  * happen outside
     693             :                  */
     694      280198 :                 ctx->controls = talloc_move(ctx, &ares->controls);
     695             : 
     696      280198 :                 TALLOC_FREE(ares);
     697      280198 :                 return ldb_request_done(req, LDB_SUCCESS);
     698             :         }
     699           0 :         default:
     700             :                 /* Doesn't happen */
     701           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     702             :         }
     703      635677 :         TALLOC_FREE(ares);
     704             : 
     705      635677 :         return ret;
     706             : }
     707             : 
     708             : 
     709      288207 : static NTSTATUS ldapsrv_SearchRequest(struct ldapsrv_call *call)
     710             : {
     711      288207 :         struct ldap_SearchRequest *req = &call->request->r.SearchRequest;
     712             :         struct ldap_Result *done;
     713             :         struct ldapsrv_reply *done_r;
     714             :         TALLOC_CTX *local_ctx;
     715      288207 :         struct ldapsrv_context *callback_ctx = NULL;
     716      288207 :         struct ldb_context *samdb = talloc_get_type(call->conn->ldb, struct ldb_context);
     717             :         struct ldb_dn *basedn;
     718             :         struct ldb_request *lreq;
     719             :         struct ldb_control *search_control;
     720             :         struct ldb_search_options_control *search_options;
     721             :         struct ldb_control *extended_dn_control;
     722      288207 :         struct ldb_extended_dn_control *extended_dn_decoded = NULL;
     723      288207 :         struct ldb_control *notification_control = NULL;
     724      288207 :         enum ldb_scope scope = LDB_SCOPE_DEFAULT;
     725      288207 :         const char **attrs = NULL;
     726      288207 :         const char *scope_str, *errstr = NULL;
     727      288207 :         int result = -1;
     728      288207 :         int ldb_ret = -1;
     729             :         unsigned int i;
     730      288207 :         int extended_type = 1;
     731             : 
     732             :         /*
     733             :          * Warn for searches that are longer than 1/4 of the
     734             :          * search_timeout, being 30sec by default
     735             :          */
     736      288207 :         struct timeval start_time = timeval_current();
     737      231136 :         struct timeval warning_time
     738      288207 :                 = timeval_add(&start_time,
     739      288207 :                               call->conn->limits.search_timeout / 4,
     740             :                               0);
     741             : 
     742      288207 :         local_ctx = talloc_new(call);
     743      288207 :         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
     744             : 
     745      288207 :         basedn = ldb_dn_new(local_ctx, samdb, req->basedn);
     746      288207 :         NT_STATUS_HAVE_NO_MEMORY(basedn);
     747             : 
     748      288207 :         switch (req->scope) {
     749      143119 :         case LDAP_SEARCH_SCOPE_BASE:
     750      143119 :                 scope_str = "BASE";
     751      143119 :                 scope = LDB_SCOPE_BASE;
     752      143119 :                 break;
     753       73674 :         case LDAP_SEARCH_SCOPE_SINGLE:
     754       73674 :                 scope_str = "ONE";
     755       73674 :                 scope = LDB_SCOPE_ONELEVEL;
     756       73674 :                 break;
     757       71414 :         case LDAP_SEARCH_SCOPE_SUB:
     758       71414 :                 scope_str = "SUB";
     759       71414 :                 scope = LDB_SCOPE_SUBTREE;
     760       71414 :                 break;
     761           0 :         default:
     762           0 :                 result = LDAP_PROTOCOL_ERROR;
     763           0 :                 map_ldb_error(local_ctx, LDB_ERR_PROTOCOL_ERROR, NULL,
     764             :                               &errstr);
     765           0 :                 scope_str = "<Invalid scope>";
     766           0 :                 errstr = talloc_asprintf(local_ctx,
     767             :                                          "%s. Invalid scope", errstr);
     768           0 :                 goto reply;
     769             :         }
     770      288207 :         DEBUG(10,("SearchRequest: scope: [%s]\n", scope_str));
     771             : 
     772      288207 :         if (req->num_attributes >= 1) {
     773      246194 :                 attrs = talloc_array(local_ctx, const char *, req->num_attributes+1);
     774      246194 :                 NT_STATUS_HAVE_NO_MEMORY(attrs);
     775             : 
     776      758551 :                 for (i=0; i < req->num_attributes; i++) {
     777      512357 :                         DEBUG(10,("SearchRequest: attrs: [%s]\n",req->attributes[i]));
     778      512357 :                         attrs[i] = req->attributes[i];
     779             :                 }
     780      246194 :                 attrs[i] = NULL;
     781             :         }
     782             : 
     783      288207 :         DEBUG(5,("ldb_request %s dn=%s filter=%s\n", 
     784             :                  scope_str, req->basedn, ldb_filter_from_tree(call, req->tree)));
     785             : 
     786      288207 :         callback_ctx = talloc_zero(local_ctx, struct ldapsrv_context);
     787      288207 :         NT_STATUS_HAVE_NO_MEMORY(callback_ctx);
     788      288207 :         callback_ctx->call = call;
     789      288207 :         callback_ctx->extended_type = extended_type;
     790      288207 :         callback_ctx->attributesonly = req->attributesonly;
     791             : 
     792      288207 :         ldb_ret = ldb_build_search_req_ex(&lreq, samdb, local_ctx,
     793             :                                           basedn, scope,
     794             :                                           req->tree, attrs,
     795      288207 :                                           call->request->controls,
     796             :                                           callback_ctx,
     797             :                                           ldap_server_search_callback,
     798             :                                           NULL);
     799             : 
     800      288207 :         if (ldb_ret != LDB_SUCCESS) {
     801           0 :                 goto reply;
     802             :         }
     803             : 
     804      288207 :         if (call->conn->global_catalog) {
     805          23 :                 search_control = ldb_request_get_control(lreq, LDB_CONTROL_SEARCH_OPTIONS_OID);
     806             : 
     807          23 :                 search_options = NULL;
     808          23 :                 if (search_control) {
     809           2 :                         search_options = talloc_get_type(search_control->data, struct ldb_search_options_control);
     810           2 :                         search_options->search_options |= LDB_SEARCH_OPTION_PHANTOM_ROOT;
     811             :                 } else {
     812          21 :                         search_options = talloc(lreq, struct ldb_search_options_control);
     813          21 :                         NT_STATUS_HAVE_NO_MEMORY(search_options);
     814          21 :                         search_options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
     815          21 :                         ldb_request_add_control(lreq, LDB_CONTROL_SEARCH_OPTIONS_OID, false, search_options);
     816             :                 }
     817             :         } else {
     818      288184 :                 ldb_request_add_control(lreq, DSDB_CONTROL_NO_GLOBAL_CATALOG, false, NULL);
     819             :         }
     820             : 
     821      288207 :         extended_dn_control = ldb_request_get_control(lreq, LDB_CONTROL_EXTENDED_DN_OID);
     822             : 
     823      288207 :         if (extended_dn_control) {
     824       13117 :                 if (extended_dn_control->data) {
     825       13003 :                         extended_dn_decoded = talloc_get_type(extended_dn_control->data, struct ldb_extended_dn_control);
     826       13003 :                         extended_type = extended_dn_decoded->type;
     827             :                 } else {
     828         114 :                         extended_type = 0;
     829             :                 }
     830       13117 :                 callback_ctx->extended_type = extended_type;
     831             :         }
     832             : 
     833      288207 :         notification_control = ldb_request_get_control(lreq, LDB_CONTROL_NOTIFICATION_OID);
     834      288207 :         if (notification_control != NULL) {
     835        1531 :                 const struct ldapsrv_call *pc = NULL;
     836        1531 :                 size_t count = 0;
     837             : 
     838        1548 :                 for (pc = call->conn->pending_calls; pc != NULL; pc = pc->next) {
     839          17 :                         count += 1;
     840             :                 }
     841             : 
     842        1531 :                 if (count >= call->conn->limits.max_notifications) {
     843           1 :                         DEBUG(10,("SearchRequest: error MaxNotificationPerConn\n"));
     844           1 :                         result = map_ldb_error(local_ctx,
     845             :                                                LDB_ERR_ADMIN_LIMIT_EXCEEDED,
     846             :                                                "MaxNotificationPerConn reached",
     847             :                                                &errstr);
     848           1 :                         goto reply;
     849             :                 }
     850             : 
     851             :                 /*
     852             :                  * For now we need to do periodic retries on our own.
     853             :                  * As the dsdb_notification module will return after each run.
     854             :                  */
     855        1530 :                 call->notification.busy = true;
     856             :         }
     857             : 
     858             :         {
     859      288206 :                 const char *scheme = NULL;
     860      288206 :                 switch (call->conn->referral_scheme) {
     861         707 :                 case LDAP_REFERRAL_SCHEME_LDAPS:
     862         707 :                         scheme = "ldaps";
     863         707 :                         break;
     864      287499 :                 default:
     865      287499 :                         scheme = "ldap";
     866             :                 }
     867      288206 :                 ldb_ret = ldb_set_opaque(
     868             :                         samdb,
     869             :                         LDAP_REFERRAL_SCHEME_OPAQUE,
     870             :                         discard_const_p(char *, scheme));
     871      288206 :                 if (ldb_ret != LDB_SUCCESS) {
     872           0 :                         goto reply;
     873             :                 }
     874             :         }
     875             : 
     876             :         {
     877      288206 :                 time_t timeout = call->conn->limits.search_timeout;
     878             : 
     879      288206 :                 if (timeout == 0
     880      288206 :                     || (req->timelimit != 0
     881         546 :                         && req->timelimit < timeout))
     882             :                 {
     883         546 :                         timeout = req->timelimit;
     884             :                 }
     885      288206 :                 ldb_set_timeout(samdb, lreq, timeout);
     886             :         }
     887             : 
     888      288206 :         if (!call->conn->is_privileged) {
     889      287636 :                 ldb_req_mark_untrusted(lreq);
     890             :         }
     891             : 
     892      288206 :         LDB_REQ_SET_LOCATION(lreq);
     893             : 
     894      288206 :         ldb_ret = ldb_request(samdb, lreq);
     895             : 
     896      288206 :         if (ldb_ret != LDB_SUCCESS) {
     897        4678 :                 goto reply;
     898             :         }
     899             : 
     900      283528 :         ldb_ret = ldb_wait(lreq->handle, LDB_WAIT_ALL);
     901             : 
     902      283528 :         if (ldb_ret == LDB_SUCCESS) {
     903      280198 :                 if (call->notification.busy) {
     904             :                         /* Move/Add it to the end */
     905          29 :                         DLIST_DEMOTE(call->conn->pending_calls, call);
     906          29 :                         call->notification.generation =
     907          29 :                                 call->conn->service->notification.generation;
     908             : 
     909          29 :                         if (callback_ctx->count != 0) {
     910           1 :                                 call->notification.generation += 1;
     911           1 :                                 ldapsrv_notification_retry_setup(call->conn->service,
     912             :                                                                  true);
     913             :                         }
     914             : 
     915          29 :                         talloc_free(local_ctx);
     916          29 :                         return NT_STATUS_OK;
     917             :                 }
     918             :         }
     919             : 
     920      514606 : reply:
     921             : 
     922             :         /*
     923             :          * This looks like duplicated code - because it is - but
     924             :          * otherwise the work in the parameters will be done
     925             :          * regardless, this way the functions only execute when the
     926             :          * log level is set.
     927             :          *
     928             :          * The basedn is re-obtained as a string to escape it
     929             :          */
     930      288178 :         if ((req->timelimit == 0 || call->conn->limits.search_timeout < req->timelimit)
     931      287637 :             && ldb_ret == LDB_ERR_TIME_LIMIT_EXCEEDED) {
     932             :                 struct dom_sid_buf sid_buf;
     933           5 :                 DBG_WARNING("MaxQueryDuration(%d) timeout exceeded "
     934             :                             "in SearchRequest by %s from %s filter: [%s] "
     935             :                             "basedn: [%s] "
     936             :                             "scope: [%s]\n",
     937             :                             call->conn->limits.search_timeout,
     938             :                             dom_sid_str_buf(&call->conn->session_info->security_token->sids[0],
     939             :                                             &sid_buf),
     940             :                             tsocket_address_string(call->conn->connection->remote_address,
     941             :                                                    call),
     942             :                             ldb_filter_from_tree(call, req->tree),
     943             :                             ldb_dn_get_extended_linearized(call, basedn, 1),
     944             :                             scope_str);
     945          10 :                 for (i=0; i < req->num_attributes; i++) {
     946           5 :                         DBG_WARNING("MaxQueryDuration timeout exceeded attrs: [%s]\n",
     947             :                                     req->attributes[i]);
     948             :                 }
     949             : 
     950      288173 :         } else if (timeval_expired(&warning_time)) {
     951             :                 struct dom_sid_buf sid_buf;
     952           0 :                 DBG_NOTICE("Long LDAP Query: Duration was %.2fs, "
     953             :                            "MaxQueryDuration(%d)/4 == %d "
     954             :                            "in SearchRequest by %s from %s filter: [%s] "
     955             :                            "basedn: [%s] "
     956             :                            "scope: [%s] "
     957             :                            "result: %s\n",
     958             :                            timeval_elapsed(&start_time),
     959             :                            call->conn->limits.search_timeout,
     960             :                            call->conn->limits.search_timeout / 4,
     961             :                            dom_sid_str_buf(&call->conn->session_info->security_token->sids[0],
     962             :                                            &sid_buf),
     963             :                            tsocket_address_string(call->conn->connection->remote_address,
     964             :                                                   call),
     965             :                            ldb_filter_from_tree(call, req->tree),
     966             :                            ldb_dn_get_extended_linearized(call, basedn, 1),
     967             :                            scope_str,
     968             :                            ldb_strerror(ldb_ret));
     969           0 :                 for (i=0; i < req->num_attributes; i++) {
     970           0 :                         DBG_NOTICE("Long LDAP Query attrs: [%s]\n",
     971             :                                    req->attributes[i]);
     972             :                 }
     973             :         } else {
     974             :                 struct dom_sid_buf sid_buf;
     975      288173 :                 DBG_INFO("LDAP Query: Duration was %.2fs, "
     976             :                          "SearchRequest by %s from %s filter: [%s] "
     977             :                          "basedn: [%s] "
     978             :                          "scope: [%s] "
     979             :                          "result: %s\n",
     980             :                          timeval_elapsed(&start_time),
     981             :                          dom_sid_str_buf(&call->conn->session_info->security_token->sids[0],
     982             :                                          &sid_buf),
     983             :                          tsocket_address_string(call->conn->connection->remote_address,
     984             :                                                 call),
     985             :                          ldb_filter_from_tree(call, req->tree),
     986             :                          ldb_dn_get_extended_linearized(call, basedn, 1),
     987             :                          scope_str,
     988             :                          ldb_strerror(ldb_ret));
     989             :         }
     990             : 
     991      288178 :         DLIST_REMOVE(call->conn->pending_calls, call);
     992      288178 :         call->notification.busy = false;
     993             : 
     994      288178 :         done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
     995      288178 :         NT_STATUS_HAVE_NO_MEMORY(done_r);
     996             : 
     997      288178 :         done = &done_r->msg->r.SearchResultDone;
     998      288178 :         done->dn = NULL;
     999      288178 :         done->referral = NULL;
    1000             : 
    1001      288178 :         if (result != -1) {
    1002      288177 :         } else if (ldb_ret == LDB_SUCCESS) {
    1003      280169 :                 if (callback_ctx->controls) {
    1004      115167 :                         done_r->msg->controls = callback_ctx->controls;
    1005      115167 :                         talloc_steal(done_r->msg, callback_ctx->controls);
    1006             :                 }
    1007      280169 :                 result = LDB_SUCCESS;
    1008             :         } else {
    1009        8008 :                 DEBUG(10,("SearchRequest: error\n"));
    1010        8008 :                 result = map_ldb_error(local_ctx, ldb_ret, ldb_errstring(samdb),
    1011             :                                        &errstr);
    1012             :         }
    1013             : 
    1014      288178 :         done->resultcode = result;
    1015      288178 :         done->errormessage = (errstr?talloc_strdup(done_r, errstr):NULL);
    1016             : 
    1017      288178 :         talloc_free(local_ctx);
    1018             : 
    1019      288178 :         return ldapsrv_queue_reply_forced(call, done_r);
    1020             : }
    1021             : 
    1022       63869 : static NTSTATUS ldapsrv_ModifyRequest(struct ldapsrv_call *call)
    1023             : {
    1024       63869 :         struct ldap_ModifyRequest *req = &call->request->r.ModifyRequest;
    1025             :         struct ldap_Result *modify_result;
    1026             :         struct ldapsrv_reply *modify_reply;
    1027             :         TALLOC_CTX *local_ctx;
    1028       63869 :         struct ldb_context *samdb = call->conn->ldb;
    1029       63869 :         struct ldb_message *msg = NULL;
    1030             :         struct ldb_dn *dn;
    1031       63869 :         const char *errstr = NULL;
    1032       63869 :         int result = LDAP_SUCCESS;
    1033             :         int ldb_ret;
    1034             :         unsigned int i,j;
    1035       63869 :         struct ldb_result *res = NULL;
    1036             : 
    1037       63869 :         DEBUG(10, ("ModifyRequest"));
    1038       63869 :         DEBUGADD(10, (" dn: %s\n", req->dn));
    1039             : 
    1040       63869 :         local_ctx = talloc_named(call, 0, "ModifyRequest local memory context");
    1041       63869 :         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
    1042             : 
    1043       63869 :         dn = ldb_dn_new(local_ctx, samdb, req->dn);
    1044       63869 :         NT_STATUS_HAVE_NO_MEMORY(dn);
    1045             : 
    1046       63869 :         DEBUG(10, ("ModifyRequest: dn: [%s]\n", req->dn));
    1047             : 
    1048       63869 :         msg = ldb_msg_new(local_ctx);
    1049       63869 :         NT_STATUS_HAVE_NO_MEMORY(msg);
    1050             : 
    1051       63869 :         msg->dn = dn;
    1052             : 
    1053       63869 :         if (req->num_mods > 0) {
    1054       63862 :                 msg->num_elements = req->num_mods;
    1055       63862 :                 msg->elements = talloc_array(msg, struct ldb_message_element, req->num_mods);
    1056       63862 :                 NT_STATUS_HAVE_NO_MEMORY(msg->elements);
    1057             : 
    1058      147116 :                 for (i=0; i < msg->num_elements; i++) {
    1059       83254 :                         msg->elements[i].name = discard_const_p(char, req->mods[i].attrib.name);
    1060       83254 :                         msg->elements[i].num_values = 0;
    1061       83254 :                         msg->elements[i].values = NULL;
    1062             : 
    1063       83254 :                         switch (req->mods[i].type) {
    1064           0 :                         default:
    1065           0 :                                 result = LDAP_PROTOCOL_ERROR;
    1066           0 :                                 map_ldb_error(local_ctx,
    1067             :                                         LDB_ERR_PROTOCOL_ERROR, NULL, &errstr);
    1068           0 :                                 errstr = talloc_asprintf(local_ctx,
    1069             :                                         "%s. Invalid LDAP_MODIFY_* type", errstr);
    1070           0 :                                 goto reply;
    1071       24919 :                         case LDAP_MODIFY_ADD:
    1072       24919 :                                 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
    1073       24919 :                                 break;
    1074       16076 :                         case LDAP_MODIFY_DELETE:
    1075       16076 :                                 msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
    1076       16076 :                                 break;
    1077       42259 :                         case LDAP_MODIFY_REPLACE:
    1078       42259 :                                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
    1079       42259 :                                 break;
    1080             :                         }
    1081             : 
    1082       83254 :                         msg->elements[i].num_values = req->mods[i].attrib.num_values;
    1083       83254 :                         if (msg->elements[i].num_values > 0) {
    1084       78983 :                                 msg->elements[i].values = talloc_array(msg->elements, struct ldb_val,
    1085             :                                                                        msg->elements[i].num_values);
    1086       78983 :                                 NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values);
    1087             : 
    1088      164744 :                                 for (j=0; j < msg->elements[i].num_values; j++) {
    1089       85761 :                                         msg->elements[i].values[j].length = req->mods[i].attrib.values[j].length;
    1090       85761 :                                         msg->elements[i].values[j].data = req->mods[i].attrib.values[j].data;                     
    1091             :                                 }
    1092             :                         }
    1093             :                 }
    1094             :         }
    1095             : 
    1096       63869 : reply:
    1097       63869 :         modify_reply = ldapsrv_init_reply(call, LDAP_TAG_ModifyResponse);
    1098       63869 :         NT_STATUS_HAVE_NO_MEMORY(modify_reply);
    1099             : 
    1100       63869 :         if (result == LDAP_SUCCESS) {
    1101       63869 :                 res = talloc_zero(local_ctx, struct ldb_result);
    1102       63869 :                 NT_STATUS_HAVE_NO_MEMORY(res);
    1103       63869 :                 ldb_ret = ldapsrv_mod_with_controls(call, msg, call->request->controls, res);
    1104       63869 :                 result = map_ldb_error(local_ctx, ldb_ret, ldb_errstring(samdb),
    1105             :                                        &errstr);
    1106             :         }
    1107             : 
    1108       63869 :         modify_result = &modify_reply->msg->r.ModifyResponse;
    1109       63869 :         modify_result->dn = NULL;
    1110       63869 :         if ((res != NULL) && (res->refs != NULL)) {
    1111           2 :                 modify_result->resultcode = map_ldb_error(local_ctx,
    1112             :                                                           LDB_ERR_REFERRAL,
    1113             :                                                           NULL, &errstr);
    1114           2 :                 modify_result->errormessage = (errstr?talloc_strdup(modify_reply, errstr):NULL);
    1115           2 :                 modify_result->referral = talloc_strdup(call, *res->refs);
    1116             :         } else {
    1117       63867 :                 modify_result->resultcode = result;
    1118       63867 :                 modify_result->errormessage = (errstr?talloc_strdup(modify_reply, errstr):NULL);
    1119       63867 :                 modify_result->referral = NULL;
    1120             :         }
    1121       63869 :         talloc_free(local_ctx);
    1122             : 
    1123       63869 :         return ldapsrv_queue_reply(call, modify_reply);
    1124             : 
    1125             : }
    1126             : 
    1127       43573 : static NTSTATUS ldapsrv_AddRequest(struct ldapsrv_call *call)
    1128             : {
    1129       43573 :         struct ldap_AddRequest *req = &call->request->r.AddRequest;
    1130             :         struct ldap_Result *add_result;
    1131             :         struct ldapsrv_reply *add_reply;
    1132             :         TALLOC_CTX *local_ctx;
    1133       43573 :         struct ldb_context *samdb = call->conn->ldb;
    1134       43573 :         struct ldb_message *msg = NULL;
    1135             :         struct ldb_dn *dn;
    1136       43573 :         const char *errstr = NULL;
    1137       43573 :         int result = LDAP_SUCCESS;
    1138             :         int ldb_ret;
    1139             :         unsigned int i,j;
    1140       43573 :         struct ldb_result *res = NULL;
    1141             : 
    1142       43573 :         DEBUG(10, ("AddRequest"));
    1143       43573 :         DEBUGADD(10, (" dn: %s\n", req->dn));
    1144             : 
    1145       43573 :         local_ctx = talloc_named(call, 0, "AddRequest local memory context");
    1146       43573 :         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
    1147             : 
    1148       43573 :         dn = ldb_dn_new(local_ctx, samdb, req->dn);
    1149       43573 :         NT_STATUS_HAVE_NO_MEMORY(dn);
    1150             : 
    1151       43573 :         DEBUG(10, ("AddRequest: dn: [%s]\n", req->dn));
    1152             : 
    1153       43573 :         msg = talloc(local_ctx, struct ldb_message);
    1154       43573 :         NT_STATUS_HAVE_NO_MEMORY(msg);
    1155             : 
    1156       43573 :         msg->dn = dn;
    1157       43573 :         msg->num_elements = 0;
    1158       43573 :         msg->elements = NULL;
    1159             : 
    1160       43573 :         if (req->num_attributes > 0) {
    1161       43570 :                 msg->num_elements = req->num_attributes;
    1162       43570 :                 msg->elements = talloc_array(msg, struct ldb_message_element, msg->num_elements);
    1163       43570 :                 NT_STATUS_HAVE_NO_MEMORY(msg->elements);
    1164             : 
    1165      154745 :                 for (i=0; i < msg->num_elements; i++) {
    1166      111175 :                         msg->elements[i].name = discard_const_p(char, req->attributes[i].name);
    1167      111175 :                         msg->elements[i].flags = 0;
    1168      111175 :                         msg->elements[i].num_values = 0;
    1169      111175 :                         msg->elements[i].values = NULL;
    1170             :                         
    1171      111175 :                         if (req->attributes[i].num_values > 0) {
    1172      111138 :                                 msg->elements[i].num_values = req->attributes[i].num_values;
    1173      111138 :                                 msg->elements[i].values = talloc_array(msg->elements, struct ldb_val,
    1174             :                                                                        msg->elements[i].num_values);
    1175      111138 :                                 NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values);
    1176             : 
    1177      227075 :                                 for (j=0; j < msg->elements[i].num_values; j++) {
    1178      115937 :                                         msg->elements[i].values[j].length = req->attributes[i].values[j].length;
    1179      115937 :                                         msg->elements[i].values[j].data = req->attributes[i].values[j].data;                      
    1180             :                                 }
    1181             :                         }
    1182             :                 }
    1183             :         }
    1184             : 
    1185       43573 :         add_reply = ldapsrv_init_reply(call, LDAP_TAG_AddResponse);
    1186       43573 :         NT_STATUS_HAVE_NO_MEMORY(add_reply);
    1187             : 
    1188       43573 :         if (result == LDAP_SUCCESS) {
    1189       43573 :                 res = talloc_zero(local_ctx, struct ldb_result);
    1190       43573 :                 NT_STATUS_HAVE_NO_MEMORY(res);
    1191       43573 :                 ldb_ret = ldapsrv_add_with_controls(call, msg, call->request->controls, res);
    1192       43573 :                 result = map_ldb_error(local_ctx, ldb_ret, ldb_errstring(samdb),
    1193             :                                        &errstr);
    1194             :         }
    1195             : 
    1196       43573 :         add_result = &add_reply->msg->r.AddResponse;
    1197       43573 :         add_result->dn = NULL;
    1198       43573 :         if ((res != NULL) && (res->refs != NULL)) {
    1199           5 :                 add_result->resultcode =  map_ldb_error(local_ctx,
    1200             :                                                         LDB_ERR_REFERRAL, NULL,
    1201             :                                                         &errstr);
    1202           5 :                 add_result->errormessage = (errstr?talloc_strdup(add_reply,errstr):NULL);
    1203           5 :                 add_result->referral = talloc_strdup(call, *res->refs);
    1204             :         } else {
    1205       43568 :                 add_result->resultcode = result;
    1206       43568 :                 add_result->errormessage = (errstr?talloc_strdup(add_reply,errstr):NULL);
    1207       43568 :                 add_result->referral = NULL;
    1208             :         }
    1209       43573 :         talloc_free(local_ctx);
    1210             : 
    1211       43573 :         return ldapsrv_queue_reply(call, add_reply);
    1212             : 
    1213             : }
    1214             : 
    1215       51169 : static NTSTATUS ldapsrv_DelRequest(struct ldapsrv_call *call)
    1216             : {
    1217       51169 :         struct ldap_DelRequest *req = &call->request->r.DelRequest;
    1218             :         struct ldap_Result *del_result;
    1219             :         struct ldapsrv_reply *del_reply;
    1220             :         TALLOC_CTX *local_ctx;
    1221       51169 :         struct ldb_context *samdb = call->conn->ldb;
    1222             :         struct ldb_dn *dn;
    1223       51169 :         const char *errstr = NULL;
    1224       51169 :         int result = LDAP_SUCCESS;
    1225             :         int ldb_ret;
    1226       51169 :         struct ldb_result *res = NULL;
    1227             : 
    1228       51169 :         DEBUG(10, ("DelRequest"));
    1229       51169 :         DEBUGADD(10, (" dn: %s\n", req->dn));
    1230             : 
    1231       51169 :         local_ctx = talloc_named(call, 0, "DelRequest local memory context");
    1232       51169 :         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
    1233             : 
    1234       51169 :         dn = ldb_dn_new(local_ctx, samdb, req->dn);
    1235       51169 :         NT_STATUS_HAVE_NO_MEMORY(dn);
    1236             : 
    1237       51169 :         DEBUG(10, ("DelRequest: dn: [%s]\n", req->dn));
    1238             : 
    1239       51169 :         del_reply = ldapsrv_init_reply(call, LDAP_TAG_DelResponse);
    1240       51169 :         NT_STATUS_HAVE_NO_MEMORY(del_reply);
    1241             : 
    1242       51169 :         if (result == LDAP_SUCCESS) {
    1243       51169 :                 res = talloc_zero(local_ctx, struct ldb_result);
    1244       51169 :                 NT_STATUS_HAVE_NO_MEMORY(res);
    1245       51169 :                 ldb_ret = ldapsrv_del_with_controls(call, dn, call->request->controls, res);
    1246       51169 :                 result = map_ldb_error(local_ctx, ldb_ret, ldb_errstring(samdb),
    1247             :                                        &errstr);
    1248             :         }
    1249             : 
    1250       51169 :         del_result = &del_reply->msg->r.DelResponse;
    1251       51169 :         del_result->dn = NULL;
    1252       51169 :         if ((res != NULL) && (res->refs != NULL)) {
    1253           1 :                 del_result->resultcode = map_ldb_error(local_ctx,
    1254             :                                                        LDB_ERR_REFERRAL, NULL,
    1255             :                                                        &errstr);
    1256           1 :                 del_result->errormessage = (errstr?talloc_strdup(del_reply,errstr):NULL);
    1257           1 :                 del_result->referral = talloc_strdup(call, *res->refs);
    1258             :         } else {
    1259       51168 :                 del_result->resultcode = result;
    1260       51168 :                 del_result->errormessage = (errstr?talloc_strdup(del_reply,errstr):NULL);
    1261       51168 :                 del_result->referral = NULL;
    1262             :         }
    1263             : 
    1264       51169 :         talloc_free(local_ctx);
    1265             : 
    1266       51169 :         return ldapsrv_queue_reply(call, del_reply);
    1267             : }
    1268             : 
    1269         363 : static NTSTATUS ldapsrv_ModifyDNRequest(struct ldapsrv_call *call)
    1270             : {
    1271         363 :         struct ldap_ModifyDNRequest *req = &call->request->r.ModifyDNRequest;
    1272             :         struct ldap_Result *modifydn;
    1273             :         struct ldapsrv_reply *modifydn_r;
    1274             :         TALLOC_CTX *local_ctx;
    1275         363 :         struct ldb_context *samdb = call->conn->ldb;
    1276         363 :         struct ldb_dn *olddn, *newdn=NULL, *newrdn;
    1277         363 :         struct ldb_dn *parentdn = NULL;
    1278         363 :         const char *errstr = NULL;
    1279         363 :         int result = LDAP_SUCCESS;
    1280             :         int ldb_ret;
    1281         363 :         struct ldb_result *res = NULL;
    1282             : 
    1283         363 :         DEBUG(10, ("ModifyDNRequest"));
    1284         363 :         DEBUGADD(10, (" dn: %s", req->dn));
    1285         363 :         DEBUGADD(10, (" newrdn: %s\n", req->newrdn));
    1286             : 
    1287         363 :         local_ctx = talloc_named(call, 0, "ModifyDNRequest local memory context");
    1288         363 :         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
    1289             : 
    1290         363 :         olddn = ldb_dn_new(local_ctx, samdb, req->dn);
    1291         363 :         NT_STATUS_HAVE_NO_MEMORY(olddn);
    1292             : 
    1293         363 :         newrdn = ldb_dn_new(local_ctx, samdb, req->newrdn);
    1294         363 :         NT_STATUS_HAVE_NO_MEMORY(newrdn);
    1295             : 
    1296         363 :         DEBUG(10, ("ModifyDNRequest: olddn: [%s]\n", req->dn));
    1297         363 :         DEBUG(10, ("ModifyDNRequest: newrdn: [%s]\n", req->newrdn));
    1298             : 
    1299         363 :         if (ldb_dn_get_comp_num(newrdn) == 0) {
    1300           1 :                 result = LDAP_PROTOCOL_ERROR;
    1301           1 :                 map_ldb_error(local_ctx, LDB_ERR_PROTOCOL_ERROR, NULL,
    1302             :                               &errstr);
    1303           1 :                 goto reply;
    1304             :         }
    1305             : 
    1306         362 :         if (ldb_dn_get_comp_num(newrdn) > 1) {
    1307           1 :                 result = LDAP_NAMING_VIOLATION;
    1308           1 :                 map_ldb_error(local_ctx, LDB_ERR_NAMING_VIOLATION, NULL,
    1309             :                               &errstr);
    1310           1 :                 goto reply;
    1311             :         }
    1312             : 
    1313             :         /* we can't handle the rename if we should not remove the old dn */
    1314         361 :         if (!req->deleteolddn) {
    1315           0 :                 result = LDAP_UNWILLING_TO_PERFORM;
    1316           0 :                 map_ldb_error(local_ctx, LDB_ERR_UNWILLING_TO_PERFORM, NULL,
    1317             :                               &errstr);
    1318           0 :                 errstr = talloc_asprintf(local_ctx,
    1319             :                         "%s. Old RDN must be deleted", errstr);
    1320           0 :                 goto reply;
    1321             :         }
    1322             : 
    1323         361 :         if (req->newsuperior) {
    1324         359 :                 DEBUG(10, ("ModifyDNRequest: newsuperior: [%s]\n", req->newsuperior));
    1325         359 :                 parentdn = ldb_dn_new(local_ctx, samdb, req->newsuperior);
    1326             :         }
    1327             : 
    1328         361 :         if (!parentdn) {
    1329           2 :                 parentdn = ldb_dn_get_parent(local_ctx, olddn);
    1330             :         }
    1331         361 :         if (!parentdn) {
    1332           1 :                 result = LDAP_NO_SUCH_OBJECT;
    1333           1 :                 map_ldb_error(local_ctx, LDB_ERR_NO_SUCH_OBJECT, NULL, &errstr);
    1334           1 :                 goto reply;
    1335             :         }
    1336             : 
    1337         360 :         if ( ! ldb_dn_add_child(parentdn, newrdn)) {
    1338           0 :                 result = LDAP_OTHER;
    1339           0 :                 map_ldb_error(local_ctx, LDB_ERR_OTHER, NULL, &errstr);
    1340           0 :                 goto reply;
    1341             :         }
    1342         360 :         newdn = parentdn;
    1343             : 
    1344         363 : reply:
    1345         363 :         modifydn_r = ldapsrv_init_reply(call, LDAP_TAG_ModifyDNResponse);
    1346         363 :         NT_STATUS_HAVE_NO_MEMORY(modifydn_r);
    1347             : 
    1348         363 :         if (result == LDAP_SUCCESS) {
    1349         360 :                 res = talloc_zero(local_ctx, struct ldb_result);
    1350         360 :                 NT_STATUS_HAVE_NO_MEMORY(res);
    1351         360 :                 ldb_ret = ldapsrv_rename_with_controls(call, olddn, newdn, call->request->controls, res);
    1352         360 :                 result = map_ldb_error(local_ctx, ldb_ret, ldb_errstring(samdb),
    1353             :                                        &errstr);
    1354             :         }
    1355             : 
    1356         363 :         modifydn = &modifydn_r->msg->r.ModifyDNResponse;
    1357         363 :         modifydn->dn = NULL;
    1358         363 :         if ((res != NULL) && (res->refs != NULL)) {
    1359           0 :                 modifydn->resultcode = map_ldb_error(local_ctx,
    1360             :                                                      LDB_ERR_REFERRAL, NULL,
    1361             :                                                      &errstr);;
    1362           0 :                 modifydn->errormessage = (errstr?talloc_strdup(modifydn_r,errstr):NULL);
    1363           0 :                 modifydn->referral = talloc_strdup(call, *res->refs);
    1364             :         } else {
    1365         363 :                 modifydn->resultcode = result;
    1366         363 :                 modifydn->errormessage = (errstr?talloc_strdup(modifydn_r,errstr):NULL);
    1367         363 :                 modifydn->referral = NULL;
    1368             :         }
    1369             : 
    1370         363 :         talloc_free(local_ctx);
    1371             : 
    1372         363 :         return ldapsrv_queue_reply(call, modifydn_r);
    1373             : }
    1374             : 
    1375           1 : static NTSTATUS ldapsrv_CompareRequest(struct ldapsrv_call *call)
    1376             : {
    1377           1 :         struct ldap_CompareRequest *req = &call->request->r.CompareRequest;
    1378             :         struct ldap_Result *compare;
    1379             :         struct ldapsrv_reply *compare_r;
    1380             :         TALLOC_CTX *local_ctx;
    1381           1 :         struct ldb_context *samdb = call->conn->ldb;
    1382           1 :         struct ldb_result *res = NULL;
    1383             :         struct ldb_dn *dn;
    1384             :         const char *attrs[1];
    1385           1 :         const char *errstr = NULL;
    1386           1 :         const char *filter = NULL;
    1387           1 :         int result = LDAP_SUCCESS;
    1388             :         int ldb_ret;
    1389             : 
    1390           1 :         DEBUG(10, ("CompareRequest"));
    1391           1 :         DEBUGADD(10, (" dn: %s\n", req->dn));
    1392             : 
    1393           1 :         local_ctx = talloc_named(call, 0, "CompareRequest local_memory_context");
    1394           1 :         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
    1395             : 
    1396           1 :         dn = ldb_dn_new(local_ctx, samdb, req->dn);
    1397           1 :         NT_STATUS_HAVE_NO_MEMORY(dn);
    1398             : 
    1399           1 :         DEBUG(10, ("CompareRequest: dn: [%s]\n", req->dn));
    1400           2 :         filter = talloc_asprintf(local_ctx, "(%s=%*s)", req->attribute, 
    1401           1 :                                  (int)req->value.length, req->value.data);
    1402           1 :         NT_STATUS_HAVE_NO_MEMORY(filter);
    1403             : 
    1404           1 :         DEBUGADD(10, ("CompareRequest: attribute: [%s]\n", filter));
    1405             : 
    1406           1 :         attrs[0] = NULL;
    1407             : 
    1408           1 :         compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
    1409           1 :         NT_STATUS_HAVE_NO_MEMORY(compare_r);
    1410             : 
    1411           1 :         if (result == LDAP_SUCCESS) {
    1412           1 :                 ldb_ret = ldb_search(samdb, local_ctx, &res,
    1413             :                                      dn, LDB_SCOPE_BASE, attrs, "%s", filter);
    1414           1 :                 if (ldb_ret != LDB_SUCCESS) {
    1415           0 :                         result = map_ldb_error(local_ctx, ldb_ret,
    1416             :                                                ldb_errstring(samdb), &errstr);
    1417           0 :                         DEBUG(10,("CompareRequest: error: %s\n", errstr));
    1418           1 :                 } else if (res->count == 0) {
    1419           0 :                         DEBUG(10,("CompareRequest: doesn't matched\n"));
    1420           0 :                         result = LDAP_COMPARE_FALSE;
    1421           0 :                         errstr = NULL;
    1422           1 :                 } else if (res->count == 1) {
    1423           1 :                         DEBUG(10,("CompareRequest: matched\n"));
    1424           1 :                         result = LDAP_COMPARE_TRUE;
    1425           1 :                         errstr = NULL;
    1426           0 :                 } else if (res->count > 1) {
    1427           0 :                         result = LDAP_OTHER;
    1428           0 :                         map_ldb_error(local_ctx, LDB_ERR_OTHER, NULL, &errstr);
    1429           0 :                         errstr = talloc_asprintf(local_ctx,
    1430             :                                 "%s. Too many objects match!", errstr);
    1431           0 :                         DEBUG(10,("CompareRequest: %d results: %s\n", res->count, errstr));
    1432             :                 }
    1433             :         }
    1434             : 
    1435           1 :         compare = &compare_r->msg->r.CompareResponse;
    1436           1 :         compare->dn = NULL;
    1437           1 :         compare->resultcode = result;
    1438           1 :         compare->errormessage = (errstr?talloc_strdup(compare_r,errstr):NULL);
    1439           1 :         compare->referral = NULL;
    1440             : 
    1441           1 :         talloc_free(local_ctx);
    1442             : 
    1443           1 :         return ldapsrv_queue_reply(call, compare_r);
    1444             : }
    1445             : 
    1446          28 : static NTSTATUS ldapsrv_AbandonRequest(struct ldapsrv_call *call)
    1447             : {
    1448          28 :         struct ldap_AbandonRequest *req = &call->request->r.AbandonRequest;
    1449          28 :         struct ldapsrv_call *c = NULL;
    1450          28 :         struct ldapsrv_call *n = NULL;
    1451             : 
    1452          28 :         DEBUG(10, ("AbandonRequest\n"));
    1453             : 
    1454          65 :         for (c = call->conn->pending_calls; c != NULL; c = n) {
    1455          37 :                 n = c->next;
    1456             : 
    1457          37 :                 if (c->request->messageid != req->messageid) {
    1458          10 :                         continue;
    1459             :                 }
    1460             : 
    1461          27 :                 DLIST_REMOVE(call->conn->pending_calls, c);
    1462          27 :                 TALLOC_FREE(c);
    1463             :         }
    1464             : 
    1465          28 :         return NT_STATUS_OK;
    1466             : }
    1467             : 
    1468           3 : static NTSTATUS ldapsrv_expired(struct ldapsrv_call *call)
    1469             : {
    1470           3 :         struct ldapsrv_reply *reply = NULL;
    1471           3 :         struct ldap_ExtendedResponse *r = NULL;
    1472             : 
    1473           3 :         DBG_DEBUG("Sending connection expired message\n");
    1474             : 
    1475           3 :         reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
    1476           3 :         if (reply == NULL) {
    1477           0 :                 return NT_STATUS_NO_MEMORY;
    1478             :         }
    1479             : 
    1480             :         /*
    1481             :          * According to RFC4511 section 4.4.1 this has a msgid of 0
    1482             :          */
    1483           3 :         reply->msg->messageid = 0;
    1484             : 
    1485           3 :         r = &reply->msg->r.ExtendedResponse;
    1486           3 :         r->response.resultcode = LDB_ERR_UNAVAILABLE;
    1487           3 :         r->response.errormessage = "The server has timed out this connection";
    1488           3 :         r->oid = "1.3.6.1.4.1.1466.20036"; /* see rfc4511 section 4.4.1 */
    1489             : 
    1490           3 :         ldapsrv_queue_reply(call, reply);
    1491           3 :         return NT_STATUS_OK;
    1492             : }
    1493             : 
    1494      473753 : NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call)
    1495             : {
    1496             :         unsigned int i;
    1497      473753 :         struct ldap_message *msg = call->request;
    1498      473753 :         struct ldapsrv_connection *conn = call->conn;
    1499             :         NTSTATUS status;
    1500             :         bool expired;
    1501             : 
    1502      473753 :         expired = timeval_expired(&conn->limits.expire_time);
    1503      473753 :         if (expired) {
    1504           3 :                 status = ldapsrv_expired(call);
    1505           3 :                 if (!NT_STATUS_IS_OK(status)) {
    1506           0 :                         return status;
    1507             :                 }
    1508           3 :                 return NT_STATUS_NETWORK_SESSION_EXPIRED;
    1509             :         }
    1510             : 
    1511             :         /* Check for undecoded critical extensions */
    1512      703502 :         for (i=0; msg->controls && msg->controls[i]; i++) {
    1513      229752 :                 if (!msg->controls_decoded[i] && 
    1514           0 :                     msg->controls[i]->critical) {
    1515           0 :                         DEBUG(3, ("ldapsrv_do_call: Critical extension %s is not known to this server\n",
    1516             :                                   msg->controls[i]->oid));
    1517           0 :                         return ldapsrv_unwilling(call, LDAP_UNAVAILABLE_CRITICAL_EXTENSION);
    1518             :                 }
    1519             :         }
    1520             : 
    1521      473750 :         if (call->conn->authz_logged == false) {
    1522       46286 :                 bool log = true;
    1523             : 
    1524             :                 /*
    1525             :                  * We do not want to log anonymous access if the query
    1526             :                  * is just for the rootDSE, or it is a startTLS or a
    1527             :                  * Bind.
    1528             :                  *
    1529             :                  * A rootDSE search could also be done over
    1530             :                  * CLDAP anonymously for example, so these don't
    1531             :                  * really count.
    1532             :                  * Essentially we want to know about
    1533             :                  * access beyond that normally done prior to a
    1534             :                  * bind.
    1535             :                  */
    1536             : 
    1537       46286 :                 switch(call->request->type) {
    1538       26450 :                 case LDAP_TAG_BindRequest:
    1539             :                 case LDAP_TAG_UnbindRequest:
    1540             :                 case LDAP_TAG_AbandonRequest:
    1541       26450 :                         log = false;
    1542       26450 :                         break;
    1543           0 :                 case LDAP_TAG_ExtendedResponse: {
    1544           0 :                         struct ldap_ExtendedRequest *req = &call->request->r.ExtendedRequest;
    1545           0 :                         if (strcmp(req->oid, LDB_EXTENDED_START_TLS_OID) == 0) {
    1546           0 :                                 log = false;
    1547             :                         }
    1548           0 :                         break;
    1549             :                 }
    1550       19809 :                 case LDAP_TAG_SearchRequest: {
    1551       19809 :                         struct ldap_SearchRequest *req = &call->request->r.SearchRequest;
    1552       19809 :                         if (req->scope == LDAP_SEARCH_SCOPE_BASE) {
    1553       19777 :                                 if (req->basedn[0] == '\0') {
    1554       19766 :                                         log = false;
    1555             :                                 }
    1556             :                         }
    1557       19809 :                         break;
    1558             :                 }
    1559          27 :                 default:
    1560          27 :                         break;
    1561             :                 }
    1562             : 
    1563       46286 :                 if (log) {
    1564          70 :                         const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
    1565          70 :                         if (call->conn->sockets.active == call->conn->sockets.tls) {
    1566           1 :                                 transport_protection = AUTHZ_TRANSPORT_PROTECTION_TLS;
    1567             :                         }
    1568             : 
    1569         115 :                         log_successful_authz_event(call->conn->connection->msg_ctx,
    1570          70 :                                                    call->conn->connection->lp_ctx,
    1571          70 :                                                    call->conn->connection->remote_address,
    1572          70 :                                                    call->conn->connection->local_address,
    1573             :                                                    "LDAP",
    1574             :                                                    "no bind",
    1575             :                                                    transport_protection,
    1576          70 :                                                    call->conn->session_info);
    1577             : 
    1578          70 :                         call->conn->authz_logged = true;
    1579             :                 }
    1580             :         }
    1581             : 
    1582      473750 :         switch(call->request->type) {
    1583       26450 :         case LDAP_TAG_BindRequest:
    1584       26450 :                 return ldapsrv_BindRequest(call);
    1585          90 :         case LDAP_TAG_UnbindRequest:
    1586          90 :                 return ldapsrv_UnbindRequest(call);
    1587      288207 :         case LDAP_TAG_SearchRequest:
    1588      288207 :                 return ldapsrv_SearchRequest(call);
    1589       63869 :         case LDAP_TAG_ModifyRequest:
    1590       63869 :                 status = ldapsrv_ModifyRequest(call);
    1591       63869 :                 break;
    1592       43573 :         case LDAP_TAG_AddRequest:
    1593       43573 :                 status = ldapsrv_AddRequest(call);
    1594       43573 :                 break;
    1595       51169 :         case LDAP_TAG_DelRequest:
    1596       51169 :                 status = ldapsrv_DelRequest(call);
    1597       51169 :                 break;
    1598         363 :         case LDAP_TAG_ModifyDNRequest:
    1599         363 :                 status = ldapsrv_ModifyDNRequest(call);
    1600         363 :                 break;
    1601           1 :         case LDAP_TAG_CompareRequest:
    1602           1 :                 return ldapsrv_CompareRequest(call);
    1603          28 :         case LDAP_TAG_AbandonRequest:
    1604          28 :                 return ldapsrv_AbandonRequest(call);
    1605           0 :         case LDAP_TAG_ExtendedRequest:
    1606           0 :                 status = ldapsrv_ExtendedRequest(call);
    1607           0 :                 break;
    1608           0 :         default:
    1609           0 :                 return ldapsrv_unwilling(call, LDAP_PROTOCOL_ERROR);
    1610             :         }
    1611             : 
    1612      158974 :         if (NT_STATUS_IS_OK(status)) {
    1613      158974 :                 ldapsrv_notification_retry_setup(call->conn->service, true);
    1614             :         }
    1615             : 
    1616      158974 :         return status;
    1617             : }

Generated by: LCOV version 1.13