Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/libcli/ldap/ldap_client.c
Line
Count
Source
1
/* 
2
   Unix SMB/CIFS implementation.
3
   LDAP protocol helper functions for SAMBA
4
   
5
   Copyright (C) Andrew Tridgell  2004
6
   Copyright (C) Volker Lendecke 2004
7
   Copyright (C) Stefan Metzmacher 2004
8
   Copyright (C) Simo Sorce 2004
9
    
10
   This program is free software; you can redistribute it and/or modify
11
   it under the terms of the GNU General Public License as published by
12
   the Free Software Foundation; either version 3 of the License, or
13
   (at your option) any later version.
14
   
15
   This program is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
   GNU General Public License for more details.
19
   
20
   You should have received a copy of the GNU General Public License
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
   
23
*/
24
25
#include "includes.h"
26
#include <tevent.h>
27
#include "lib/socket/socket.h"
28
#include "lib/tsocket/tsocket.h"
29
#include "libcli/util/tstream.h"
30
#include "../lib/util/asn1.h"
31
#include "../lib/util/dlinklist.h"
32
#include "libcli/ldap/libcli_ldap.h"
33
#include "libcli/ldap/ldap_proto.h"
34
#include "libcli/ldap/ldap_client.h"
35
#include "libcli/composite/composite.h"
36
#include "lib/tls/tls.h"
37
#include "auth/gensec/gensec.h"
38
#include "system/time.h"
39
#include "param/param.h"
40
#include "libcli/resolve/resolve.h"
41
#include "librpc/gen_ndr/ads.h"
42
43
static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status);
44
45
static int ldap_connection_destructor(struct ldap_connection *conn)
46
0
{
47
  /*
48
   * NT_STATUS_OK means that callbacks of pending requests are not
49
   * triggered
50
   */
51
0
  ldap_connection_dead(conn, NT_STATUS_OK);
52
0
  return 0;
53
0
}
54
55
/**
56
  create a new ldap_connection structure. The event context is optional
57
*/
58
59
_PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx, 
60
               struct loadparm_context *lp_ctx,
61
               struct tevent_context *ev)
62
0
{
63
0
  struct ldap_connection *conn;
64
65
0
  if (ev == NULL) {
66
0
    return NULL;
67
0
  }
68
69
0
  if (lp_ctx == NULL) {
70
0
    return NULL;
71
0
  }
72
73
0
  conn = talloc_zero(mem_ctx, struct ldap_connection);
74
0
  if (conn == NULL) {
75
0
    return NULL;
76
0
  }
77
78
0
  conn->next_messageid  = 1;
79
0
  conn->event.event_ctx = ev;
80
81
0
  conn->sockets.send_queue = tevent_queue_create(conn,
82
0
          "ldap_connection send_queue");
83
0
  if (conn->sockets.send_queue == NULL) {
84
0
    TALLOC_FREE(conn);
85
0
    return NULL;
86
0
  }
87
88
0
  conn->lp_ctx = lp_ctx;
89
90
  /* set a reasonable request timeout */
91
0
  conn->timeout = 60;
92
93
  /* explicitly avoid reconnections by default */
94
0
  conn->reconnect.max_retries = 0;
95
96
0
  talloc_set_destructor(conn, ldap_connection_destructor);
97
0
  return conn;
98
0
}
99
100
/*
101
  the connection is dead
102
*/
103
static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status)
104
0
{
105
0
  struct ldap_request *req;
106
107
0
  tevent_queue_stop(conn->sockets.send_queue);
108
0
  TALLOC_FREE(conn->sockets.recv_subreq);
109
0
  conn->sockets.active = NULL;
110
0
  TALLOC_FREE(conn->sockets.sasl);
111
0
  TALLOC_FREE(conn->sockets.tls);
112
0
  TALLOC_FREE(conn->sockets.raw);
113
114
  /* return an error for any pending request ... */
115
0
  while (conn->pending) {
116
0
    req = conn->pending;
117
0
    DLIST_REMOVE(req->conn->pending, req);
118
0
    req->conn = NULL;
119
0
    req->state = LDAP_REQUEST_DONE;
120
0
    if (NT_STATUS_IS_OK(status)) {
121
0
      continue;
122
0
    }
123
0
    req->status = status;
124
0
    if (req->async.fn) {
125
0
      req->async.fn(req);
126
0
    }
127
0
  }
128
0
}
129
130
static void ldap_reconnect(struct ldap_connection *conn);
131
132
/*
133
  handle packet errors
134
*/
135
static void ldap_error_handler(struct ldap_connection *conn, NTSTATUS status)
136
0
{
137
0
  ldap_connection_dead(conn, status);
138
139
  /* but try to reconnect so that the ldb client can go on */
140
0
  ldap_reconnect(conn);
141
0
}
142
143
144
/*
145
  match up with a pending message, adding to the replies list
146
*/
147
static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg)
148
0
{
149
0
  struct ldap_request *req;
150
0
  int i;
151
152
0
  for (req=conn->pending; req; req=req->next) {
153
0
    if (req->messageid == msg->messageid) break;
154
0
  }
155
  /* match a zero message id to the last request sent.
156
     It seems that servers send 0 if unable to parse */
157
0
  if (req == NULL && msg->messageid == 0) {
158
0
    req = conn->pending;
159
0
  }
160
0
  if (req == NULL) {
161
0
    DEBUG(0,("ldap: no matching message id for %u\n",
162
0
       msg->messageid));
163
0
    TALLOC_FREE(msg);
164
0
    return;
165
0
  }
166
167
  /* Check for undecoded critical extensions */
168
0
  for (i=0; msg->controls && msg->controls[i]; i++) {
169
0
    if (!msg->controls_decoded[i] && 
170
0
        msg->controls[i]->critical) {
171
0
      TALLOC_FREE(msg);
172
0
      req->status = NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION);
173
0
      req->state = LDAP_REQUEST_DONE;
174
0
      DLIST_REMOVE(conn->pending, req);
175
0
      if (req->async.fn) {
176
0
        req->async.fn(req);
177
0
      }
178
0
      return;
179
0
    }
180
0
  }
181
182
  /* add to the list of replies received */
183
0
  req->replies = talloc_realloc(req, req->replies, 
184
0
              struct ldap_message *, req->num_replies+1);
185
0
  if (req->replies == NULL) {
186
0
    TALLOC_FREE(msg);
187
0
    req->status = NT_STATUS_NO_MEMORY;
188
0
    req->state = LDAP_REQUEST_DONE;
189
0
    DLIST_REMOVE(conn->pending, req);
190
0
    if (req->async.fn) {
191
0
      req->async.fn(req);
192
0
    }
193
0
    return;
194
0
  }
195
196
0
  req->replies[req->num_replies] = talloc_steal(req->replies, msg);
197
0
  req->num_replies++;
198
199
0
  if (msg->type != LDAP_TAG_SearchResultEntry &&
200
0
      msg->type != LDAP_TAG_SearchResultReference) {
201
    /* currently only search results expect multiple
202
       replies */
203
0
    req->state = LDAP_REQUEST_DONE;
204
0
    DLIST_REMOVE(conn->pending, req);
205
0
  }
206
207
0
  if (req->async.fn) {
208
0
    req->async.fn(req);
209
0
  }
210
0
}
211
212
static void ldap_connection_recv_done(struct tevent_req *subreq);
213
214
static void ldap_connection_recv_next(struct ldap_connection *conn)
215
0
{
216
0
  struct tevent_req *subreq = NULL;
217
218
0
  if (conn->sockets.recv_subreq != NULL) {
219
0
    return;
220
0
  }
221
222
0
  if (conn->sockets.active == NULL) {
223
0
    return;
224
0
  }
225
226
0
  if (conn->pending == NULL) {
227
0
    return;
228
0
  }
229
230
  /*
231
   * The minimum size of a LDAP pdu is 7 bytes
232
   *
233
   * dumpasn1 -hh ldap-unbind-min.dat
234
   *
235
   *     <30 05 02 01 09 42 00>
236
   *    0    5: SEQUENCE {
237
   *     <02 01 09>
238
   *    2    1:   INTEGER 9
239
   *     <42 00>
240
   *    5    0:   [APPLICATION 2]
241
   *          :     Error: Object has zero length.
242
   *          :   }
243
   *
244
   * dumpasn1 -hh ldap-unbind-windows.dat
245
   *
246
   *     <30 84 00 00 00 05 02 01 09 42 00>
247
   *    0    5: SEQUENCE {
248
   *     <02 01 09>
249
   *    6    1:   INTEGER 9
250
   *     <42 00>
251
   *    9    0:   [APPLICATION 2]
252
   *          :     Error: Object has zero length.
253
   *          :   }
254
   *
255
   * This means using an initial read size
256
   * of 7 is ok.
257
   */
258
0
  subreq = tstream_read_pdu_blob_send(conn,
259
0
              conn->event.event_ctx,
260
0
              conn->sockets.active,
261
0
              7, /* initial_read_size */
262
0
              ldap_full_packet,
263
0
              conn);
264
0
  if (subreq == NULL) {
265
0
    ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
266
0
    return;
267
0
  }
268
0
  tevent_req_set_callback(subreq, ldap_connection_recv_done, conn);
269
0
  conn->sockets.recv_subreq = subreq;
270
0
  return;
271
0
}
272
273
/*
274
  decode/process LDAP data
275
*/
276
static void ldap_connection_recv_done(struct tevent_req *subreq)
277
0
{
278
0
  NTSTATUS status;
279
0
  struct ldap_connection *conn =
280
0
    tevent_req_callback_data(subreq,
281
0
    struct ldap_connection);
282
0
  struct ldap_message *msg;
283
0
  struct asn1_data *asn1;
284
0
  DATA_BLOB blob;
285
0
  struct ldap_request_limits limits = {0};
286
287
0
  msg = talloc_zero(conn, struct ldap_message);
288
0
  if (msg == NULL) {
289
0
    ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
290
0
    return;
291
0
  }
292
293
0
  asn1 = asn1_init(conn, ASN1_MAX_TREE_DEPTH);
294
0
  if (asn1 == NULL) {
295
0
    TALLOC_FREE(msg);
296
0
    ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
297
0
    return;
298
0
  }
299
300
0
  conn->sockets.recv_subreq = NULL;
301
302
0
  status = tstream_read_pdu_blob_recv(subreq,
303
0
              asn1,
304
0
              &blob);
305
0
  TALLOC_FREE(subreq);
306
0
  if (!NT_STATUS_IS_OK(status)) {
307
0
    TALLOC_FREE(msg);
308
0
    asn1_free(asn1);
309
0
    ldap_error_handler(conn, status);
310
0
    return;
311
0
  }
312
313
0
  asn1_load_nocopy(asn1, blob.data, blob.length);
314
315
0
  status = ldap_decode(asn1, &limits, samba_ldap_control_handlers(), msg);
316
0
  asn1_free(asn1);
317
0
  if (!NT_STATUS_IS_OK(status)) {
318
0
    TALLOC_FREE(msg);
319
0
    ldap_error_handler(conn, status);
320
0
    return;
321
0
  }
322
323
0
  ldap_match_message(conn, msg);
324
0
  ldap_connection_recv_next(conn);
325
326
0
  return;
327
0
}
328
329
enum ldap_proto {
330
  LDAP_PROTO_NONE,
331
  LDAP_PROTO_LDAP,
332
  LDAP_PROTO_LDAPS,
333
  LDAP_PROTO_LDAPI
334
};
335
336
static int ldap_parse_basic_url(
337
  const char *url,
338
  enum ldap_proto *pproto,
339
  TALLOC_CTX *mem_ctx,
340
  char **pdest,   /* path for ldapi, host for ldap[s] */
341
  uint16_t *pport)  /* Not set for ldapi */
342
0
{
343
0
  enum ldap_proto proto = LDAP_PROTO_NONE;
344
0
  char *host = NULL;
345
0
  int ret, port;
346
347
0
  if (url == NULL) {
348
0
    return EINVAL;
349
0
  }
350
351
0
  if (strncasecmp_m(url, "ldapi://", strlen("ldapi://")) == 0) {
352
0
    char *path = NULL, *end = NULL;
353
354
0
    path = talloc_strdup(mem_ctx, url+8);
355
0
    if (path == NULL) {
356
0
      return ENOMEM;
357
0
    }
358
0
    end = rfc1738_unescape(path);
359
0
    if (end == NULL) {
360
0
      TALLOC_FREE(path);
361
0
      return EINVAL;
362
0
    }
363
364
0
    *pproto = LDAP_PROTO_LDAPI;
365
0
    *pdest = path;
366
0
    return 0;
367
0
  }
368
369
0
  if (strncasecmp_m(url, "ldap://", strlen("ldap://")) == 0) {
370
0
    url += 7;
371
0
    proto = LDAP_PROTO_LDAP;
372
0
    port = 389;
373
0
  }
374
0
  if (strncasecmp_m(url, "ldaps://", strlen("ldaps://")) == 0) {
375
0
    url += 8;
376
0
    port = 636;
377
0
    proto = LDAP_PROTO_LDAPS;
378
0
  }
379
380
0
  if (proto == LDAP_PROTO_NONE) {
381
0
    return EPROTONOSUPPORT;
382
0
  }
383
384
0
  if (url[0] == '[') {
385
    /*
386
     * IPv6 with [aa:bb:cc..]:port
387
     */
388
0
    const char *end = NULL;
389
390
0
    url +=1;
391
392
0
    end = strchr(url, ']');
393
0
    if (end == NULL) {
394
0
      return EINVAL;
395
0
    }
396
397
0
    ret = sscanf(end+1, ":%d", &port);
398
0
    if (ret < 0) {
399
0
      return EINVAL;
400
0
    }
401
402
0
    *pdest = talloc_strndup(mem_ctx, url, end-url);
403
0
    if (*pdest == NULL) {
404
0
      return ENOMEM;
405
0
    }
406
0
    *pproto = proto;
407
0
    *pport = port;
408
0
    return 0;
409
0
  }
410
411
0
  ret = sscanf(url, "%m[^:/]:%d", &host, &port);
412
0
  if (ret < 1) {
413
0
    return EINVAL;
414
0
  }
415
416
0
  *pdest = talloc_strdup(mem_ctx, host);
417
0
  SAFE_FREE(host);
418
0
  if (*pdest == NULL) {
419
0
    return ENOMEM;
420
0
  }
421
0
  *pproto = proto;
422
0
  *pport = port;
423
424
0
  return 0;
425
0
}
426
427
/*
428
  connect to a ldap server
429
*/
430
431
struct ldap_connect_state {
432
  struct composite_context *ctx;
433
  struct ldap_connection *conn;
434
  struct socket_context *sock;
435
  struct tstream_context *raw;
436
  struct tstream_tls_params *tls_params;
437
  struct tstream_context *tls;
438
};
439
440
static void ldap_connect_recv_unix_conn(struct composite_context *ctx);
441
static void ldap_connect_recv_tcp_conn(struct composite_context *ctx);
442
443
_PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
444
              const char *url)
445
0
{
446
0
  struct composite_context *result, *ctx;
447
0
  struct ldap_connect_state *state;
448
0
  enum ldap_proto proto;
449
0
  char *dest = NULL;
450
0
  uint16_t port;
451
0
  int ret;
452
453
0
  result = talloc_zero(conn, struct composite_context);
454
0
  if (result == NULL) goto failed;
455
0
  result->state = COMPOSITE_STATE_IN_PROGRESS;
456
0
  result->async.fn = NULL;
457
0
  result->event_ctx = conn->event.event_ctx;
458
459
0
  state = talloc(result, struct ldap_connect_state);
460
0
  if (state == NULL) goto failed;
461
0
  state->ctx = result;
462
0
  result->private_data = state;
463
464
0
  state->conn = conn;
465
466
0
  if (conn->reconnect.url == NULL) {
467
0
    conn->reconnect.url = talloc_strdup(conn, url);
468
0
    if (conn->reconnect.url == NULL) goto failed;
469
0
  }
470
471
0
  ret = ldap_parse_basic_url(url, &proto, conn, &dest, &port);
472
0
  if (ret != 0) {
473
0
    composite_error(result, map_nt_error_from_unix_common(ret));
474
0
    return result;
475
0
  }
476
477
0
  if (proto == LDAP_PROTO_LDAPI) {
478
0
    struct socket_address *unix_addr;
479
0
    NTSTATUS status = socket_create(state, "unix",
480
0
            SOCKET_TYPE_STREAM,
481
0
            &state->sock, 0);
482
0
    if (!NT_STATUS_IS_OK(status)) {
483
0
      return NULL;
484
0
    }
485
486
0
    conn->host = talloc_asprintf(conn, "%s.%s",
487
0
               lpcfg_netbios_name(conn->lp_ctx),
488
0
               lpcfg_dnsdomain(conn->lp_ctx));
489
0
    if (composite_nomem(conn->host, state->ctx)) {
490
0
      return result;
491
0
    }
492
493
0
    unix_addr = socket_address_from_strings(state, state->sock->backend_name,
494
0
              dest, 0);
495
0
    if (composite_nomem(unix_addr, result)) {
496
0
      return result;
497
0
    }
498
499
0
    ctx = socket_connect_send(state->sock, NULL, unix_addr,
500
0
            0, result->event_ctx);
501
0
    ctx->async.fn = ldap_connect_recv_unix_conn;
502
0
    ctx->async.private_data = state;
503
0
    return result;
504
0
  }
505
506
0
  if ((proto == LDAP_PROTO_LDAP) || (proto == LDAP_PROTO_LDAPS)) {
507
0
    int wrap_flags = lpcfg_client_ldap_sasl_wrapping(conn->lp_ctx);
508
509
0
    conn->ldaps = (proto == LDAP_PROTO_LDAPS);
510
511
0
    if (wrap_flags & ADS_AUTH_SASL_LDAPS) {
512
0
      if (proto == LDAP_PROTO_LDAP) {
513
0
        if (port == 389) {
514
0
          port = 636;
515
0
          proto = LDAP_PROTO_LDAPS;
516
0
        } else if (port == 3268) {
517
0
          port = 3269;
518
0
          proto = LDAP_PROTO_LDAPS;
519
0
        } else {
520
0
          conn->starttls = true;
521
0
        }
522
0
      }
523
0
      conn->ldaps = true;
524
0
    } else if (wrap_flags & ADS_AUTH_SASL_STARTTLS) {
525
0
      if (proto == LDAP_PROTO_LDAP) {
526
0
        conn->starttls = true;
527
0
      }
528
0
      conn->ldaps = true;
529
0
    }
530
531
0
    conn->host = talloc_move(conn, &dest);
532
0
    conn->port = port;
533
534
0
    if (conn->ldaps) {
535
0
      NTSTATUS status;
536
537
0
      status = tstream_tls_params_client_lpcfg(state,
538
0
                 conn->lp_ctx,
539
0
                 conn->host,
540
0
                 &state->tls_params);
541
0
      if (!NT_STATUS_IS_OK(status)) {
542
0
        composite_error(result, status);
543
0
        return result;
544
0
      }
545
0
    }
546
547
0
    ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
548
0
            lpcfg_resolve_context(conn->lp_ctx),
549
0
            result->event_ctx);
550
0
    if (composite_nomem(ctx, result)) {
551
0
      return result;
552
0
    }
553
554
0
    ctx->async.fn = ldap_connect_recv_tcp_conn;
555
0
    ctx->async.private_data = state;
556
0
    return result;
557
0
  }
558
0
 failed:
559
0
  talloc_free(result);
560
0
  return NULL;
561
0
}
562
563
static void ldap_connect_starttls_done(struct ldap_request *ldap_req);
564
static void ldap_connect_got_tls(struct tevent_req *subreq);
565
566
static void ldap_connect_got_sock(struct composite_context *ctx, 
567
          struct ldap_connection *conn)
568
0
{
569
0
  struct ldap_connect_state *state =
570
0
    talloc_get_type_abort(ctx->private_data,
571
0
    struct ldap_connect_state);
572
0
  struct tevent_req *subreq = NULL;
573
0
  int fd;
574
0
  int ret;
575
576
0
  socket_set_flags(state->sock, SOCKET_FLAG_NOCLOSE);
577
0
  fd = socket_get_fd(state->sock);
578
0
  TALLOC_FREE(state->sock);
579
580
0
  smb_set_close_on_exec(fd);
581
582
0
  ret = set_blocking(fd, false);
583
0
  if (ret == -1) {
584
0
    NTSTATUS status = map_nt_error_from_unix_common(errno);
585
0
    composite_error(state->ctx, status);
586
0
    return;
587
0
  }
588
589
0
  ret = tstream_bsd_existing_socket(state, fd, &state->raw);
590
0
  if (ret == -1) {
591
0
    NTSTATUS status = map_nt_error_from_unix_common(errno);
592
0
    composite_error(state->ctx, status);
593
0
    return;
594
0
  }
595
596
0
  conn->sockets.raw = talloc_move(conn, &state->raw);
597
0
  conn->sockets.active = conn->sockets.raw;
598
599
0
  if (!conn->ldaps) {
600
0
    composite_done(state->ctx);
601
0
    return;
602
0
  }
603
604
0
  if (conn->starttls) {
605
0
    struct ldap_message msg = {
606
0
      .type = LDAP_TAG_ExtendedRequest,
607
0
      .r.ExtendedRequest.oid = LDB_EXTENDED_START_TLS_OID,
608
0
    };
609
0
    struct ldap_request *ldap_req = NULL;
610
611
0
    ldap_req = ldap_request_send(conn, &msg);
612
0
    if (composite_nomem(ldap_req, state->ctx)) {
613
0
      return;
614
0
    }
615
0
    ldap_req->async.fn = ldap_connect_starttls_done;
616
0
    ldap_req->async.private_data = state;
617
0
    return;
618
0
  }
619
620
0
  subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
621
0
            conn->sockets.raw, state->tls_params);
622
0
  if (composite_nomem(subreq, state->ctx)) {
623
0
    return;
624
0
  }
625
0
  tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
626
0
}
627
628
static void ldap_connect_starttls_done(struct ldap_request *ldap_req)
629
0
{
630
0
  struct ldap_connect_state *state =
631
0
    talloc_get_type_abort(ldap_req->async.private_data,
632
0
    struct ldap_connect_state);
633
0
  struct ldap_connection *conn = state->conn;
634
0
  NTSTATUS status = ldap_req->status;
635
0
  struct tevent_req *subreq = NULL;
636
637
0
  if (!NT_STATUS_IS_OK(status)) {
638
0
    TALLOC_FREE(ldap_req);
639
0
    composite_error(state->ctx, status);
640
0
    return;
641
0
  }
642
643
0
  if (ldap_req->num_replies != 1) {
644
0
    TALLOC_FREE(ldap_req);
645
0
    status = NT_STATUS_INVALID_NETWORK_RESPONSE;
646
0
    composite_error(state->ctx, status);
647
0
    return;
648
0
  }
649
650
0
  if (ldap_req->replies[0]->type != LDAP_TAG_ExtendedResponse) {
651
0
    TALLOC_FREE(ldap_req);
652
0
    status = NT_STATUS_INVALID_NETWORK_RESPONSE;
653
0
    composite_error(state->ctx, status);
654
0
    return;
655
0
  }
656
657
0
  status = ldap_check_response(conn,
658
0
             &ldap_req->replies[0]->r.GeneralResult);
659
0
  if (!NT_STATUS_IS_OK(status)) {
660
0
    TALLOC_FREE(ldap_req);
661
0
    composite_error(state->ctx, status);
662
0
    return;
663
0
  }
664
665
0
  subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
666
0
            conn->sockets.raw, state->tls_params);
667
0
  if (composite_nomem(subreq, state->ctx)) {
668
0
    return;
669
0
  }
670
0
  tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
671
0
}
672
673
static void ldap_connect_got_tls(struct tevent_req *subreq)
674
0
{
675
0
  struct ldap_connect_state *state =
676
0
    tevent_req_callback_data(subreq,
677
0
    struct ldap_connect_state);
678
0
  int err;
679
0
  int ret;
680
681
0
  ret = tstream_tls_connect_recv(subreq, &err, state, &state->tls);
682
0
  TALLOC_FREE(subreq);
683
0
  if (ret == -1) {
684
0
    NTSTATUS status = map_nt_error_from_unix_common(err);
685
0
    composite_error(state->ctx, status);
686
0
    return;
687
0
  }
688
689
0
  talloc_steal(state->tls, state->tls_params);
690
691
0
  state->conn->sockets.tls = talloc_move(state->conn->sockets.raw,
692
0
                 &state->tls);
693
0
  state->conn->sockets.active = state->conn->sockets.tls;
694
0
  composite_done(state->ctx);
695
0
}
696
697
static void ldap_connect_recv_tcp_conn(struct composite_context *ctx)
698
0
{
699
0
  struct ldap_connect_state *state =
700
0
    talloc_get_type_abort(ctx->async.private_data,
701
0
    struct ldap_connect_state);
702
0
  struct ldap_connection *conn = state->conn;
703
0
  uint16_t port;
704
0
  NTSTATUS status = socket_connect_multi_recv(ctx, state, &state->sock,
705
0
                   &port);
706
0
  if (!NT_STATUS_IS_OK(status)) {
707
0
    composite_error(state->ctx, status);
708
0
    return;
709
0
  }
710
711
0
  ldap_connect_got_sock(state->ctx, conn);
712
0
}
713
714
static void ldap_connect_recv_unix_conn(struct composite_context *ctx)
715
0
{
716
0
  struct ldap_connect_state *state =
717
0
    talloc_get_type_abort(ctx->async.private_data,
718
0
    struct ldap_connect_state);
719
0
  struct ldap_connection *conn = state->conn;
720
721
0
  NTSTATUS status = socket_connect_recv(ctx);
722
723
0
  if (!NT_STATUS_IS_OK(state->ctx->status)) {
724
0
    composite_error(state->ctx, status);
725
0
    return;
726
0
  }
727
728
0
  ldap_connect_got_sock(state->ctx, conn);
729
0
}
730
731
_PUBLIC_ NTSTATUS ldap_connect_recv(struct composite_context *ctx)
732
0
{
733
0
  NTSTATUS status = composite_wait(ctx);
734
0
  talloc_free(ctx);
735
0
  return status;
736
0
}
737
738
_PUBLIC_ NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
739
0
{
740
0
  struct composite_context *ctx = ldap_connect_send(conn, url);
741
0
  return ldap_connect_recv(ctx);
742
0
}
743
744
/* set reconnect parameters */
745
746
_PUBLIC_ void ldap_set_reconn_params(struct ldap_connection *conn, int max_retries)
747
0
{
748
0
  if (conn) {
749
0
    conn->reconnect.max_retries = max_retries;
750
0
    conn->reconnect.retries = 0;
751
0
    conn->reconnect.previous = time_mono(NULL);
752
0
  }
753
0
}
754
755
/* Actually this function is NOT ASYNC safe, FIXME? */
756
static void ldap_reconnect(struct ldap_connection *conn)
757
0
{
758
0
  NTSTATUS status;
759
0
  time_t now = time_mono(NULL);
760
761
  /* do we have set up reconnect ? */
762
0
  if (conn->reconnect.max_retries == 0) return;
763
764
  /* is the retry time expired ? */
765
0
  if (now > conn->reconnect.previous + 30) {
766
0
    conn->reconnect.retries = 0;
767
0
    conn->reconnect.previous = now;
768
0
  }
769
770
  /* are we reconnectind too often and too fast? */
771
0
  if (conn->reconnect.retries > conn->reconnect.max_retries) return;
772
773
  /* keep track of the number of reconnections */
774
0
  conn->reconnect.retries++;
775
776
  /* reconnect */
777
0
  status = ldap_connect(conn, conn->reconnect.url);
778
0
  if ( ! NT_STATUS_IS_OK(status)) {
779
0
    return;
780
0
  }
781
782
  /* rebind */
783
0
  status = ldap_rebind(conn);
784
0
  if ( ! NT_STATUS_IS_OK(status)) {
785
0
    ldap_connection_dead(conn, status);
786
0
  }
787
0
}
788
789
static void ldap_request_destructor_abandon(struct ldap_request *abandon)
790
0
{
791
0
  TALLOC_FREE(abandon);
792
0
}
793
794
/* destroy an open ldap request */
795
static int ldap_request_destructor(struct ldap_request *req)
796
0
{
797
0
  if (req->state == LDAP_REQUEST_PENDING) {
798
0
    struct ldap_message msg = {
799
0
      .type = LDAP_TAG_AbandonRequest,
800
0
      .r.AbandonRequest.messageid = req->messageid,
801
0
    };
802
0
    struct ldap_request *abandon = NULL;
803
804
0
    DLIST_REMOVE(req->conn->pending, req);
805
806
0
    abandon = ldap_request_send(req->conn, &msg);
807
0
    if (abandon == NULL) {
808
0
      ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
809
0
      return 0;
810
0
    }
811
0
    abandon->async.fn = ldap_request_destructor_abandon;
812
0
    abandon->async.private_data = NULL;
813
0
  }
814
815
0
  return 0;
816
0
}
817
818
static void ldap_request_timeout_abandon(struct ldap_request *abandon)
819
0
{
820
0
  struct ldap_request *req =
821
0
    talloc_get_type_abort(abandon->async.private_data,
822
0
    struct ldap_request);
823
824
0
  if (req->state == LDAP_REQUEST_PENDING) {
825
0
    DLIST_REMOVE(req->conn->pending, req);
826
0
  }
827
0
  req->state = LDAP_REQUEST_DONE;
828
0
  if (req->async.fn) {
829
0
    req->async.fn(req);
830
0
  }
831
0
}
832
833
/*
834
  called on timeout of a ldap request
835
*/
836
static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer *te, 
837
              struct timeval t, void *private_data)
838
0
{
839
0
  struct ldap_request *req =
840
0
    talloc_get_type_abort(private_data,
841
0
    struct ldap_request);
842
843
0
  req->status = NT_STATUS_IO_TIMEOUT;
844
0
  if (req->state == LDAP_REQUEST_PENDING) {
845
0
    struct ldap_message msg = {
846
0
      .type = LDAP_TAG_AbandonRequest,
847
0
      .r.AbandonRequest.messageid = req->messageid,
848
0
    };
849
0
    struct ldap_request *abandon = NULL;
850
851
0
    abandon = ldap_request_send(req->conn, &msg);
852
0
    if (abandon == NULL) {
853
0
      ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
854
0
      return;
855
0
    }
856
0
    talloc_reparent(req->conn, req, abandon);
857
0
    abandon->async.fn = ldap_request_timeout_abandon;
858
0
    abandon->async.private_data = req;
859
0
    DLIST_REMOVE(req->conn->pending, req);
860
0
    return;
861
0
  }
862
0
  req->state = LDAP_REQUEST_DONE;
863
0
  if (req->async.fn) {
864
0
    req->async.fn(req);
865
0
  }
866
0
}
867
868
869
/*
870
  called on completion of a failed ldap request
871
*/
872
static void ldap_request_failed_complete(struct tevent_context *ev, struct tevent_timer *te,
873
              struct timeval t, void *private_data)
874
0
{
875
0
  struct ldap_request *req =
876
0
    talloc_get_type_abort(private_data,
877
0
    struct ldap_request);
878
879
0
  if (req->async.fn) {
880
0
    req->async.fn(req);
881
0
  }
882
0
}
883
884
static void ldap_request_written(struct tevent_req *subreq);
885
886
/*
887
  send a ldap message - async interface
888
*/
889
_PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
890
               struct ldap_message *msg)
891
0
{
892
0
  struct ldap_request *req;
893
0
  NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
894
0
  struct tevent_req *subreq = NULL;
895
896
0
  req = talloc_zero(conn, struct ldap_request);
897
0
  if (req == NULL) return NULL;
898
899
0
  if (conn->sockets.active == NULL) {
900
0
    status = NT_STATUS_INVALID_CONNECTION;
901
0
    goto failed;
902
0
  }
903
904
0
  req->state       = LDAP_REQUEST_SEND;
905
0
  req->conn        = conn;
906
0
  req->messageid   = conn->next_messageid++;
907
0
  if (conn->next_messageid == 0) {
908
0
    conn->next_messageid = 1;
909
0
  }
910
0
  req->type        = msg->type;
911
0
  if (req->messageid == -1) {
912
0
    goto failed;
913
0
  }
914
915
0
  talloc_set_destructor(req, ldap_request_destructor);
916
917
0
  msg->messageid = req->messageid;
918
919
0
  if (!ldap_encode(msg, samba_ldap_control_handlers(), &req->data, req)) {
920
0
    status = NT_STATUS_INTERNAL_ERROR;
921
0
    goto failed;    
922
0
  }
923
924
  /* put a timeout on the request */
925
0
  req->time_event = tevent_add_timer(conn->event.event_ctx, req,
926
0
             timeval_current_ofs(conn->timeout, 0),
927
0
             ldap_request_timeout, req);
928
0
  if (req->time_event == NULL) {
929
0
    status = NT_STATUS_NO_MEMORY;
930
0
    goto failed;
931
0
  }
932
933
0
  req->write_iov.iov_base = req->data.data;
934
0
  req->write_iov.iov_len = req->data.length;
935
936
0
  subreq = tstream_writev_queue_send(req, conn->event.event_ctx,
937
0
             conn->sockets.active,
938
0
             conn->sockets.send_queue,
939
0
             &req->write_iov, 1);
940
0
  if (subreq == NULL) {
941
0
    status = NT_STATUS_NO_MEMORY;
942
0
    goto failed;
943
0
  }
944
0
  tevent_req_set_callback(subreq, ldap_request_written, req);
945
946
0
  req->state = LDAP_REQUEST_PENDING;
947
0
  DLIST_ADD(conn->pending, req);
948
949
0
  return req;
950
951
0
failed:
952
0
  req->status = status;
953
0
  req->state = LDAP_REQUEST_ERROR;
954
0
  tevent_add_timer(conn->event.event_ctx, req, timeval_zero(),
955
0
       ldap_request_failed_complete, req);
956
957
0
  return req;
958
0
}
959
960
static void ldap_request_written(struct tevent_req *subreq)
961
0
{
962
0
  struct ldap_request *req =
963
0
    tevent_req_callback_data(subreq,
964
0
    struct ldap_request);
965
0
  int err;
966
0
  ssize_t ret;
967
968
0
  ret = tstream_writev_queue_recv(subreq, &err);
969
0
  TALLOC_FREE(subreq);
970
0
  if (ret == -1) {
971
0
    NTSTATUS error = map_nt_error_from_unix_common(err);
972
0
    ldap_error_handler(req->conn, error);
973
0
    return;
974
0
  }
975
976
0
  if (req->type == LDAP_TAG_AbandonRequest ||
977
0
      req->type == LDAP_TAG_UnbindRequest)
978
0
  {
979
0
    if (req->state == LDAP_REQUEST_PENDING) {
980
0
      DLIST_REMOVE(req->conn->pending, req);
981
0
    }
982
0
    req->state = LDAP_REQUEST_DONE;
983
0
    if (req->async.fn) {
984
0
      req->async.fn(req);
985
0
    }
986
0
    return;
987
0
  }
988
989
0
  ldap_connection_recv_next(req->conn);
990
0
}
991
992
993
/*
994
  wait for a request to complete
995
  note that this does not destroy the request
996
*/
997
_PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req)
998
0
{
999
0
  while (req->state < LDAP_REQUEST_DONE) {
1000
0
    if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
1001
0
      req->state = LDAP_REQUEST_ERROR;
1002
0
      req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1003
0
      break;
1004
0
    }
1005
0
  }
1006
0
  return req->status;
1007
0
}
1008
1009
1010
/*
1011
  a mapping of ldap response code to strings
1012
*/
1013
static const struct {
1014
  enum ldap_result_code code;
1015
  const char *str;
1016
} ldap_code_map[] = {
1017
#define _LDAP_MAP_CODE(c) { c, #c }
1018
  _LDAP_MAP_CODE(LDAP_SUCCESS),
1019
  _LDAP_MAP_CODE(LDAP_OPERATIONS_ERROR),
1020
  _LDAP_MAP_CODE(LDAP_PROTOCOL_ERROR),
1021
  _LDAP_MAP_CODE(LDAP_TIME_LIMIT_EXCEEDED),
1022
  _LDAP_MAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED),
1023
  _LDAP_MAP_CODE(LDAP_COMPARE_FALSE),
1024
  _LDAP_MAP_CODE(LDAP_COMPARE_TRUE),
1025
  _LDAP_MAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED),
1026
  _LDAP_MAP_CODE(LDAP_STRONG_AUTH_REQUIRED),
1027
  _LDAP_MAP_CODE(LDAP_REFERRAL),
1028
  _LDAP_MAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED),
1029
  _LDAP_MAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION),
1030
  _LDAP_MAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED),
1031
  _LDAP_MAP_CODE(LDAP_SASL_BIND_IN_PROGRESS),
1032
  _LDAP_MAP_CODE(LDAP_NO_SUCH_ATTRIBUTE),
1033
  _LDAP_MAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE),
1034
  _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_MATCHING),
1035
  _LDAP_MAP_CODE(LDAP_CONSTRAINT_VIOLATION),
1036
  _LDAP_MAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS),
1037
  _LDAP_MAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX),
1038
  _LDAP_MAP_CODE(LDAP_NO_SUCH_OBJECT),
1039
  _LDAP_MAP_CODE(LDAP_ALIAS_PROBLEM),
1040
  _LDAP_MAP_CODE(LDAP_INVALID_DN_SYNTAX),
1041
  _LDAP_MAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM),
1042
  _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION),
1043
  _LDAP_MAP_CODE(LDAP_INVALID_CREDENTIALS),
1044
  _LDAP_MAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTS),
1045
  _LDAP_MAP_CODE(LDAP_BUSY),
1046
  _LDAP_MAP_CODE(LDAP_UNAVAILABLE),
1047
  _LDAP_MAP_CODE(LDAP_UNWILLING_TO_PERFORM),
1048
  _LDAP_MAP_CODE(LDAP_LOOP_DETECT),
1049
  _LDAP_MAP_CODE(LDAP_NAMING_VIOLATION),
1050
  _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_VIOLATION),
1051
  _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF),
1052
  _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_RDN),
1053
  _LDAP_MAP_CODE(LDAP_ENTRY_ALREADY_EXISTS),
1054
  _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED),
1055
  _LDAP_MAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS),
1056
  _LDAP_MAP_CODE(LDAP_OTHER)
1057
};
1058
1059
/*
1060
  used to setup the status code from a ldap response
1061
*/
1062
_PUBLIC_ NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
1063
0
{
1064
0
  size_t i;
1065
0
  const char *codename = "unknown";
1066
1067
0
  if (r->resultcode == LDAP_SUCCESS) {
1068
0
    return NT_STATUS_OK;
1069
0
  }
1070
1071
0
  if (conn->last_error) {
1072
0
    talloc_free(conn->last_error);
1073
0
  }
1074
1075
0
  for (i=0;i<ARRAY_SIZE(ldap_code_map);i++) {
1076
0
    if ((enum ldap_result_code)r->resultcode == ldap_code_map[i].code) {
1077
0
      codename = ldap_code_map[i].str;
1078
0
      break;
1079
0
    }
1080
0
  }
1081
1082
0
  conn->last_error = talloc_asprintf(conn, "LDAP error %u %s - %s <%s> <%s>", 
1083
0
             r->resultcode,
1084
0
             codename,
1085
0
             r->dn?r->dn:"(NULL)", 
1086
0
             r->errormessage?r->errormessage:"", 
1087
0
             r->referral?r->referral:"");
1088
  
1089
0
  return NT_STATUS_LDAP(r->resultcode);
1090
0
}
1091
1092
/*
1093
  return error string representing the last error
1094
*/
1095
_PUBLIC_ const char *ldap_errstr(struct ldap_connection *conn, 
1096
      TALLOC_CTX *mem_ctx, 
1097
      NTSTATUS status)
1098
0
{
1099
0
  if (NT_STATUS_IS_LDAP(status) && conn->last_error != NULL) {
1100
0
    return talloc_strdup(mem_ctx, conn->last_error);
1101
0
  }
1102
0
  return talloc_asprintf(mem_ctx, "LDAP client internal error: %s", nt_errstr(status));
1103
0
}
1104
1105
1106
/*
1107
  return the Nth result message, waiting if necessary
1108
*/
1109
_PUBLIC_ NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
1110
0
{
1111
0
  *msg = NULL;
1112
1113
0
  NT_STATUS_HAVE_NO_MEMORY(req);
1114
1115
0
  while (req->state < LDAP_REQUEST_DONE && n >= req->num_replies) {
1116
0
    if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
1117
0
      return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1118
0
    }
1119
0
  }
1120
1121
0
  if (n < req->num_replies) {
1122
0
    *msg = req->replies[n];
1123
0
    return NT_STATUS_OK;
1124
0
  }
1125
1126
0
  if (!NT_STATUS_IS_OK(req->status)) {
1127
0
    return req->status;
1128
0
  }
1129
1130
0
  return NT_STATUS_NO_MORE_ENTRIES;
1131
0
}
1132
1133
1134
/*
1135
  return a single result message, checking if it is of the expected LDAP type
1136
*/
1137
_PUBLIC_ NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
1138
0
{
1139
0
  NTSTATUS status;
1140
0
  status = ldap_result_n(req, 0, msg);
1141
0
  if (!NT_STATUS_IS_OK(status)) {
1142
0
    return status;
1143
0
  }
1144
0
  if ((*msg) != NULL && (*msg)->type != (enum ldap_request_tag)type) {
1145
0
    *msg = NULL;
1146
0
    return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1147
0
  }
1148
0
  return status;
1149
0
}