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