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

Generated by: LCOV version 1.13