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