Coverage Report

Created: 2025-08-29 06:10

/src/curl/lib/openldap.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                      _   _ ____  _
3
 *  Project         ___| | | |  _ \| |
4
 *                 / __| | | | |_) | |
5
 *                | (__| |_| |  _ <| |___
6
 *                 \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 * Copyright (C) Howard Chu, <hyc@openldap.org>
10
 *
11
 * This software is licensed as described in the file COPYING, which
12
 * you should have received as part of this distribution. The terms
13
 * are also available at https://curl.se/docs/copyright.html.
14
 *
15
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16
 * copies of the Software, and permit persons to whom the Software is
17
 * furnished to do so, under the terms of the COPYING file.
18
 *
19
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20
 * KIND, either express or implied.
21
 *
22
 * SPDX-License-Identifier: curl
23
 *
24
 ***************************************************************************/
25
26
#include "curl_setup.h"
27
28
#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
29
30
/*
31
 * Notice that USE_OPENLDAP is only a source code selection switch. When
32
 * libcurl is built with USE_OPENLDAP defined the libcurl source code that
33
 * gets compiled is the code from openldap.c, otherwise the code that gets
34
 * compiled is the code from ldap.c.
35
 *
36
 * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
37
 * might be required for compilation and runtime. In order to use ancient
38
 * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
39
 */
40
41
#include <ldap.h>
42
43
#include "urldata.h"
44
#include "url.h"
45
#include <curl/curl.h>
46
#include "sendf.h"
47
#include "vtls/vtls.h"
48
#include "transfer.h"
49
#include "curl_ldap.h"
50
#include "curlx/base64.h"
51
#include "cfilters.h"
52
#include "connect.h"
53
#include "curl_sasl.h"
54
#include "strcase.h"
55
/* The last 3 #include files should be in this order */
56
#include "curl_printf.h"
57
#include "curl_memory.h"
58
#include "memdebug.h"
59
60
/*
61
 * Uncommenting this will enable the built-in debug logging of the openldap
62
 * library. The debug log level can be set using the CURL_OPENLDAP_TRACE
63
 * environment variable. The debug output is written to stderr.
64
 *
65
 * The library supports the following debug flags:
66
 * LDAP_DEBUG_NONE         0x0000
67
 * LDAP_DEBUG_TRACE        0x0001
68
 * LDAP_DEBUG_CONSTRUCT    0x0002
69
 * LDAP_DEBUG_DESTROY      0x0004
70
 * LDAP_DEBUG_PARAMETER    0x0008
71
 * LDAP_DEBUG_ANY          0xffff
72
 *
73
 * For example, use CURL_OPENLDAP_TRACE=0 for no debug,
74
 * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only,
75
 * CURL_OPENLDAP_TRACE=65535 for all debug message levels.
76
 */
77
/* #define CURL_OPENLDAP_DEBUG */
78
79
/* Machine states. */
80
typedef enum {
81
  OLDAP_STOP,           /* Do nothing state, stops the state machine */
82
  OLDAP_SSL,            /* Performing SSL handshake. */
83
  OLDAP_STARTTLS,       /* STARTTLS request sent. */
84
  OLDAP_TLS,            /* Performing TLS handshake. */
85
  OLDAP_MECHS,          /* Get SASL authentication mechanisms. */
86
  OLDAP_SASL,           /* SASL binding reply. */
87
  OLDAP_BIND,           /* Simple bind reply. */
88
  OLDAP_BINDV2,         /* Simple bind reply in protocol version 2. */
89
  OLDAP_LAST            /* Never used */
90
} ldapstate;
91
92
#ifndef _LDAP_PVT_H
93
extern int ldap_pvt_url_scheme2proto(const char *);
94
extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
95
                        LDAP **ld);
96
#endif
97
98
static CURLcode oldap_setup_connection(struct Curl_easy *data,
99
                                       struct connectdata *conn);
100
static CURLcode oldap_do(struct Curl_easy *data, bool *done);
101
static CURLcode oldap_done(struct Curl_easy *data, CURLcode, bool);
102
static CURLcode oldap_connect(struct Curl_easy *data, bool *done);
103
static CURLcode oldap_connecting(struct Curl_easy *data, bool *done);
104
static CURLcode oldap_disconnect(struct Curl_easy *data,
105
                                 struct connectdata *conn, bool dead);
106
107
static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
108
                                   const struct bufref *initresp);
109
static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
110
                                    const struct bufref *resp);
111
static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech);
112
static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out);
113
114
static Curl_recv oldap_recv;
115
116
/*
117
 * LDAP protocol handler.
118
 */
119
120
const struct Curl_handler Curl_handler_ldap = {
121
  "ldap",                               /* scheme */
122
  oldap_setup_connection,               /* setup_connection */
123
  oldap_do,                             /* do_it */
124
  oldap_done,                           /* done */
125
  ZERO_NULL,                            /* do_more */
126
  oldap_connect,                        /* connect_it */
127
  oldap_connecting,                     /* connecting */
128
  ZERO_NULL,                            /* doing */
129
  ZERO_NULL,                            /* proto_pollset */
130
  ZERO_NULL,                            /* doing_pollset */
131
  ZERO_NULL,                            /* domore_pollset */
132
  ZERO_NULL,                            /* perform_pollset */
133
  oldap_disconnect,                     /* disconnect */
134
  ZERO_NULL,                            /* write_resp */
135
  ZERO_NULL,                            /* write_resp_hd */
136
  ZERO_NULL,                            /* connection_check */
137
  ZERO_NULL,                            /* attach connection */
138
  ZERO_NULL,                            /* follow */
139
  PORT_LDAP,                            /* defport */
140
  CURLPROTO_LDAP,                       /* protocol */
141
  CURLPROTO_LDAP,                       /* family */
142
  PROTOPT_NONE                          /* flags */
143
};
144
145
#ifdef USE_SSL
146
/*
147
 * LDAPS protocol handler.
148
 */
149
150
const struct Curl_handler Curl_handler_ldaps = {
151
  "ldaps",                              /* scheme */
152
  oldap_setup_connection,               /* setup_connection */
153
  oldap_do,                             /* do_it */
154
  oldap_done,                           /* done */
155
  ZERO_NULL,                            /* do_more */
156
  oldap_connect,                        /* connect_it */
157
  oldap_connecting,                     /* connecting */
158
  ZERO_NULL,                            /* doing */
159
  ZERO_NULL,                            /* proto_pollset */
160
  ZERO_NULL,                            /* doing_pollset */
161
  ZERO_NULL,                            /* domore_pollset */
162
  ZERO_NULL,                            /* perform_pollset */
163
  oldap_disconnect,                     /* disconnect */
164
  ZERO_NULL,                            /* write_resp */
165
  ZERO_NULL,                            /* write_resp_hd */
166
  ZERO_NULL,                            /* connection_check */
167
  ZERO_NULL,                            /* attach connection */
168
  ZERO_NULL,                            /* follow */
169
  PORT_LDAPS,                           /* defport */
170
  CURLPROTO_LDAPS,                      /* protocol */
171
  CURLPROTO_LDAP,                       /* family */
172
  PROTOPT_SSL                           /* flags */
173
};
174
#endif
175
176
/* SASL parameters for the ldap protocol */
177
static const struct SASLproto saslldap = {
178
  "ldap",                     /* The service name */
179
  oldap_perform_auth,         /* Send authentication command */
180
  oldap_continue_auth,        /* Send authentication continuation */
181
  oldap_cancel_auth,          /* Send authentication cancellation */
182
  oldap_get_message,          /* Get SASL response message */
183
  0,                          /* Maximum initial response length (no max) */
184
  LDAP_SASL_BIND_IN_PROGRESS, /* Code received when continuation is expected */
185
  LDAP_SUCCESS,               /* Code to receive upon authentication success */
186
  SASL_AUTH_NONE,             /* Default mechanisms */
187
  0                           /* Configuration flags */
188
};
189
190
struct ldapconninfo {
191
  struct SASL sasl;          /* SASL-related parameters */
192
  LDAP *ld;                  /* Openldap connection handle. */
193
  Curl_recv *recv;           /* For stacking SSL handler */
194
  Curl_send *send;
195
  struct berval *servercred; /* SASL data from server. */
196
  ldapstate state;           /* Current machine state. */
197
  int proto;                 /* LDAP_PROTO_TCP/LDAP_PROTO_UDP/LDAP_PROTO_IPC */
198
  int msgid;                 /* Current message id. */
199
};
200
201
struct ldapreqinfo {
202
  int msgid;
203
  int nument;
204
};
205
206
/* meta key for storing ldapconninfo at easy handle */
207
6.65k
#define CURL_META_LDAP_EASY   "meta:proto:ldap:easy"
208
/* meta key for storing ldapconninfo at connection */
209
31.2k
#define CURL_META_LDAP_CONN   "meta:proto:ldap:conn"
210
211
212
/*
213
 * oldap_state()
214
 *
215
 * This is the ONLY way to change LDAP state!
216
 */
217
static void oldap_state(struct Curl_easy *data, struct ldapconninfo *li,
218
                        ldapstate newstate)
219
4.19k
{
220
4.19k
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
221
  /* for debug purposes */
222
4.19k
  static const char * const names[] = {
223
4.19k
    "STOP",
224
4.19k
    "SSL",
225
4.19k
    "STARTTLS",
226
4.19k
    "TLS",
227
4.19k
    "MECHS",
228
4.19k
    "SASL",
229
4.19k
    "BIND",
230
4.19k
    "BINDV2",
231
    /* LAST */
232
4.19k
  };
233
234
4.19k
  if(li->state != newstate)
235
4.19k
    infof(data, "LDAP %p state change from %s to %s",
236
4.19k
          (void *)li, names[li->state], names[newstate]);
237
4.19k
#endif
238
4.19k
  (void)data;
239
4.19k
  li->state = newstate;
240
4.19k
}
241
242
/* Map some particular LDAP error codes to CURLcode values. */
243
static CURLcode oldap_map_error(int rc, CURLcode result)
244
1.83k
{
245
1.83k
  switch(rc) {
246
3
  case LDAP_NO_MEMORY:
247
3
    return CURLE_OUT_OF_MEMORY;
248
2
  case LDAP_INVALID_CREDENTIALS:
249
2
    return CURLE_LOGIN_DENIED;
250
2
  case LDAP_PROTOCOL_ERROR:
251
2
    return CURLE_UNSUPPORTED_PROTOCOL;
252
2
  case LDAP_INSUFFICIENT_ACCESS:
253
2
    return CURLE_REMOTE_ACCESS_DENIED;
254
1.83k
  }
255
1.82k
  return result;
256
1.83k
}
257
258
static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
259
7.15k
{
260
7.15k
  CURLcode result = CURLE_OK;
261
7.15k
  int rc = LDAP_URL_ERR_BADURL;
262
7.15k
  static const char * const url_errs[] = {
263
7.15k
    "success",
264
7.15k
    "out of memory",
265
7.15k
    "bad parameter",
266
7.15k
    "unrecognized scheme",
267
7.15k
    "unbalanced delimiter",
268
7.15k
    "bad URL",
269
7.15k
    "bad host or port",
270
7.15k
    "bad or missing attributes",
271
7.15k
    "bad or missing scope",
272
7.15k
    "bad or missing filter",
273
7.15k
    "bad or missing extensions"
274
7.15k
  };
275
276
7.15k
  *ludp = NULL;
277
7.15k
  if(!data->state.up.user && !data->state.up.password &&
278
7.15k
     !data->state.up.options)
279
7.06k
    rc = ldap_url_parse(data->state.url, ludp);
280
7.15k
  if(rc != LDAP_URL_SUCCESS) {
281
165
    const char *msg = "url parsing problem";
282
283
165
    result = rc == LDAP_URL_ERR_MEM ? CURLE_OUT_OF_MEMORY :
284
165
      CURLE_URL_MALFORMAT;
285
165
    rc -= LDAP_URL_SUCCESS;
286
165
    if((size_t) rc < CURL_ARRAYSIZE(url_errs))
287
165
      msg = url_errs[rc];
288
165
    failf(data, "LDAP local: %s", msg);
289
165
  }
290
7.15k
  return result;
291
7.15k
}
292
293
/* Parse the login options. */
294
static CURLcode oldap_parse_login_options(struct connectdata *conn)
295
3.03k
{
296
3.03k
  CURLcode result = CURLE_OK;
297
3.03k
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
298
3.03k
  const char *ptr = conn->options;
299
300
3.03k
  DEBUGASSERT(li);
301
3.03k
  if(!li)
302
0
    return CURLE_FAILED_INIT;
303
304
3.05k
  while(!result && ptr && *ptr) {
305
19
    const char *key = ptr;
306
19
    const char *value;
307
308
242
    while(*ptr && *ptr != '=')
309
223
      ptr++;
310
311
19
    value = ptr + 1;
312
313
226
    while(*ptr && *ptr != ';')
314
207
      ptr++;
315
316
19
    if(checkprefix("AUTH=", key))
317
0
      result = Curl_sasl_parse_url_auth_option(&li->sasl, value, ptr - value);
318
19
    else
319
19
      result = CURLE_SETOPT_OPTION_SYNTAX;
320
321
19
    if(*ptr == ';')
322
2
      ptr++;
323
19
  }
324
325
3.03k
  return result == CURLE_URL_MALFORMAT ? CURLE_SETOPT_OPTION_SYNTAX : result;
326
3.03k
}
327
328
static CURLcode oldap_setup_connection(struct Curl_easy *data,
329
                                       struct connectdata *conn)
330
5.99k
{
331
5.99k
  CURLcode result;
332
5.99k
  LDAPURLDesc *lud;
333
5.99k
  (void)conn;
334
335
  /* Early URL syntax check. */
336
5.99k
  result = oldap_url_parse(data, &lud);
337
5.99k
  ldap_free_urldesc(lud);
338
339
5.99k
  return result;
340
5.99k
}
341
342
/*
343
 * Get the SASL authentication challenge from the server credential buffer.
344
 */
345
static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out)
346
0
{
347
0
  struct ldapconninfo *li =
348
0
    Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
349
0
  struct berval *servercred = li ? li->servercred : NULL;
350
0
  DEBUGASSERT(li);
351
0
  if(!li)
352
0
    return CURLE_FAILED_INIT;
353
354
0
  if(!servercred || !servercred->bv_val)
355
0
    return CURLE_WEIRD_SERVER_REPLY;
356
0
  Curl_bufref_set(out, servercred->bv_val, servercred->bv_len, NULL);
357
0
  return CURLE_OK;
358
0
}
359
360
/*
361
 * Sends an initial SASL bind request to the server.
362
 */
363
static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
364
                                   const struct bufref *initresp)
365
0
{
366
0
  struct connectdata *conn = data->conn;
367
0
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
368
0
  struct berval cred;
369
0
  struct berval *pcred = &cred;
370
0
  int rc;
371
372
0
  DEBUGASSERT(li);
373
0
  if(!li)
374
0
    return CURLE_FAILED_INIT;
375
0
  cred.bv_val = (char *)CURL_UNCONST(Curl_bufref_ptr(initresp));
376
0
  cred.bv_len = Curl_bufref_len(initresp);
377
0
  if(!cred.bv_val)
378
0
    pcred = NULL;
379
0
  rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
380
0
  if(rc != LDAP_SUCCESS)
381
0
    return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
382
0
  return CURLE_OK;
383
0
}
384
385
/*
386
 * Sends SASL continuation.
387
 */
388
static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
389
                                    const struct bufref *resp)
390
0
{
391
0
  struct connectdata *conn = data->conn;
392
0
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
393
0
  struct berval cred;
394
0
  struct berval *pcred = &cred;
395
0
  int rc;
396
397
0
  if(!li)
398
0
    return CURLE_FAILED_INIT;
399
0
  cred.bv_val = (char *)CURL_UNCONST(Curl_bufref_ptr(resp));
400
0
  cred.bv_len = Curl_bufref_len(resp);
401
0
  if(!cred.bv_val)
402
0
    pcred = NULL;
403
0
  rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
404
0
  if(rc != LDAP_SUCCESS)
405
0
    return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
406
0
  return CURLE_OK;
407
0
}
408
409
/*
410
 * Sends SASL bind cancellation.
411
 */
412
static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech)
413
0
{
414
0
  struct ldapconninfo *li =
415
0
    Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
416
0
  int rc;
417
418
0
  (void)mech;
419
0
  if(!li)
420
0
    return CURLE_FAILED_INIT;
421
0
  rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL,
422
0
                      &li->msgid);
423
0
  if(rc != LDAP_SUCCESS)
424
0
    return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
425
0
  return CURLE_OK;
426
0
}
427
428
/* Starts LDAP simple bind. */
429
static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
430
2.85k
{
431
2.85k
  struct connectdata *conn = data->conn;
432
2.85k
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
433
2.85k
  char *binddn = NULL;
434
2.85k
  struct berval passwd;
435
2.85k
  int rc;
436
437
2.85k
  if(!li)
438
0
    return CURLE_FAILED_INIT;
439
2.85k
  passwd.bv_val = NULL;
440
2.85k
  passwd.bv_len = 0;
441
442
2.85k
  if(data->state.aptr.user) {
443
117
    binddn = conn->user;
444
117
    passwd.bv_val = conn->passwd;
445
117
    passwd.bv_len = strlen(passwd.bv_val);
446
117
  }
447
448
2.85k
  rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
449
2.85k
                      NULL, NULL, &li->msgid);
450
2.85k
  if(rc != LDAP_SUCCESS)
451
0
    return oldap_map_error(rc,
452
0
                           data->state.aptr.user ?
453
0
                           CURLE_LOGIN_DENIED : CURLE_LDAP_CANNOT_BIND);
454
2.85k
  oldap_state(data, li, newstate);
455
2.85k
  return CURLE_OK;
456
2.85k
}
457
458
/* Query the supported SASL authentication mechanisms. */
459
static CURLcode oldap_perform_mechs(struct Curl_easy *data)
460
163
{
461
163
  struct ldapconninfo *li =
462
163
    Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
463
163
  int rc;
464
163
  static const char * const supportedSASLMechanisms[] = {
465
163
    "supportedSASLMechanisms",
466
163
    NULL
467
163
  };
468
469
163
  if(!li)
470
0
    return CURLE_FAILED_INIT;
471
163
  rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
472
163
                       (char **)CURL_UNCONST(supportedSASLMechanisms), 0,
473
163
                       NULL, NULL, NULL, 0, &li->msgid);
474
163
  if(rc != LDAP_SUCCESS)
475
0
    return oldap_map_error(rc, CURLE_LOGIN_DENIED);
476
163
  oldap_state(data, li, OLDAP_MECHS);
477
163
  return CURLE_OK;
478
163
}
479
480
/* Starts SASL bind. */
481
static CURLcode oldap_perform_sasl(struct Curl_easy *data)
482
1
{
483
1
  struct ldapconninfo *li =
484
1
    Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
485
1
  saslprogress progress = SASL_IDLE;
486
1
  CURLcode result;
487
488
1
  if(!li)
489
0
    return CURLE_FAILED_INIT;
490
1
  result = Curl_sasl_start(&li->sasl, data, TRUE, &progress);
491
492
1
  oldap_state(data, li, OLDAP_SASL);
493
1
  if(!result && progress != SASL_INPROGRESS)
494
1
    result = Curl_sasl_is_blocked(&li->sasl, data);
495
1
  return result;
496
1
}
497
498
#ifdef USE_SSL
499
static Sockbuf_IO ldapsb_tls;
500
501
static bool ssl_installed(struct connectdata *conn)
502
4.19k
{
503
4.19k
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
504
4.19k
  return li && li->recv != NULL;
505
4.19k
}
506
507
static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
508
1
{
509
1
  struct connectdata *conn = data->conn;
510
1
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
511
1
  bool ssldone = FALSE;
512
1
  CURLcode result;
513
514
1
  if(!li)
515
0
    return CURLE_FAILED_INIT;
516
1
  result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
517
1
  if(!result) {
518
0
    oldap_state(data, li, newstate);
519
520
0
    if(ssldone) {
521
0
      Sockbuf *sb;
522
523
      /* Install the libcurl SSL handlers into the sockbuf. */
524
0
      ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
525
0
      ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
526
0
      li->recv = conn->recv[FIRSTSOCKET];
527
0
      li->send = conn->send[FIRSTSOCKET];
528
0
    }
529
0
  }
530
531
1
  return result;
532
1
}
533
534
/* Send the STARTTLS request */
535
static CURLcode oldap_perform_starttls(struct Curl_easy *data)
536
8
{
537
8
  struct ldapconninfo *li =
538
8
    Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
539
8
  int rc;
540
541
8
  if(!li)
542
0
    return CURLE_FAILED_INIT;
543
8
  rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid);
544
8
  if(rc != LDAP_SUCCESS)
545
0
    return oldap_map_error(rc, CURLE_USE_SSL_FAILED);
546
8
  oldap_state(data, li, OLDAP_STARTTLS);
547
8
  return CURLE_OK;
548
8
}
549
#endif
550
551
static void oldap_easy_dtor(void *key, size_t klen, void *entry)
552
839
{
553
839
  struct ldapreqinfo *lr = entry;
554
839
  (void)key;
555
839
  (void)klen;
556
839
  free(lr);
557
839
}
558
559
static void oldap_conn_dtor(void *key, size_t klen, void *entry)
560
3.03k
{
561
3.03k
  struct ldapconninfo *li = entry;
562
3.03k
  (void)key;
563
3.03k
  (void)klen;
564
3.03k
  if(li->ld) {
565
0
    ldap_unbind_ext(li->ld, NULL, NULL);
566
0
    li->ld = NULL;
567
0
  }
568
3.03k
  free(li);
569
3.03k
}
570
571
static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
572
3.03k
{
573
3.03k
  struct connectdata *conn = data->conn;
574
3.03k
  struct ldapconninfo *li;
575
3.03k
  static const int version = LDAP_VERSION3;
576
3.03k
  char *hosturl = NULL;
577
3.03k
  CURLcode result;
578
3.03k
  int rc;
579
#ifdef CURL_OPENLDAP_DEBUG
580
  static int do_trace = -1;
581
#endif
582
583
3.03k
  (void)done;
584
585
3.03k
  li = calloc(1, sizeof(struct ldapconninfo));
586
3.03k
  if(!li) {
587
0
    result = CURLE_OUT_OF_MEMORY;
588
0
    goto out;
589
0
  }
590
591
3.03k
  result = Curl_conn_meta_set(conn, CURL_META_LDAP_CONN, li, oldap_conn_dtor);
592
3.03k
  if(result)
593
0
    goto out;
594
595
3.03k
  li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
596
597
  /* Initialize the SASL storage */
598
3.03k
  Curl_sasl_init(&li->sasl, data, &saslldap);
599
600
3.03k
  result = oldap_parse_login_options(conn);
601
3.03k
  if(result)
602
19
    goto out;
603
604
3.01k
  hosturl = aprintf("%s://%s%s%s:%d",
605
3.01k
                    conn->handler->scheme,
606
3.01k
                    conn->bits.ipv6_ip ? "[" : "",
607
3.01k
                    conn->host.name,
608
3.01k
                    conn->bits.ipv6_ip ? "]" : "",
609
3.01k
                    conn->remote_port);
610
3.01k
  if(!hosturl) {
611
0
    result = CURLE_OUT_OF_MEMORY;
612
0
    goto out;
613
0
  }
614
615
3.01k
  rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
616
3.01k
  if(rc) {
617
0
    failf(data, "LDAP local: Cannot connect to %s, %s",
618
0
          hosturl, ldap_err2string(rc));
619
0
    result = CURLE_COULDNT_CONNECT;
620
0
    goto out;
621
0
  }
622
623
#ifdef CURL_OPENLDAP_DEBUG
624
  if(do_trace < 0) {
625
    const char *env = getenv("CURL_OPENLDAP_TRACE");
626
    curl_off_t e = 0;
627
    if(!curlx_str_number(&env, &e, INT_MAX))
628
      do_trace = e > 0;
629
  }
630
  if(do_trace)
631
    ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
632
#endif
633
634
  /* Try version 3 first. */
635
3.01k
  ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
636
637
  /* Do not chase referrals. */
638
3.01k
  ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
639
640
3.01k
#ifdef USE_SSL
641
3.01k
  if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
642
0
    result = oldap_ssl_connect(data, OLDAP_SSL);
643
0
    goto out;
644
0
  }
645
646
3.01k
  if(data->set.use_ssl) {
647
8
    result = oldap_perform_starttls(data);
648
8
    if(!result || data->set.use_ssl != CURLUSESSL_TRY)
649
8
      goto out;
650
8
  }
651
3.00k
#endif
652
653
3.00k
  if(li->sasl.prefmech != SASL_AUTH_NONE) {
654
163
    result = oldap_perform_mechs(data);
655
163
    goto out;
656
163
  }
657
658
  /* Force bind even if anonymous bind is not needed in protocol version 3
659
     to detect missing version 3 support. */
660
2.84k
  result = oldap_perform_bind(data, OLDAP_BIND);
661
662
3.03k
out:
663
3.03k
  free(hosturl);
664
3.03k
  return result;
665
2.84k
}
666
667
/* Handle the supported SASL mechanisms query response */
668
static CURLcode oldap_state_mechs_resp(struct Curl_easy *data,
669
                                       LDAPMessage *msg, int code)
670
192
{
671
192
  struct connectdata *conn = data->conn;
672
192
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
673
192
  int rc;
674
192
  BerElement *ber = NULL;
675
192
  CURLcode result = CURLE_OK;
676
192
  struct berval bv, *bvals;
677
678
192
  if(!li)
679
0
    return CURLE_FAILED_INIT;
680
192
  switch(ldap_msgtype(msg)) {
681
79
  case LDAP_RES_SEARCH_ENTRY:
682
    /* Got a list of supported SASL mechanisms. */
683
79
    if(code != LDAP_SUCCESS && code != LDAP_NO_RESULTS_RETURNED)
684
0
      return CURLE_LOGIN_DENIED;
685
686
79
    rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
687
79
    if(rc < 0)
688
1
      return oldap_map_error(rc, CURLE_BAD_CONTENT_ENCODING);
689
78
    for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
690
154
        rc == LDAP_SUCCESS;
691
123
        rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
692
123
      int i;
693
694
123
      if(!bv.bv_val)
695
47
        break;
696
697
76
      if(bvals) {
698
138
        for(i = 0; bvals[i].bv_val; i++) {
699
89
          size_t llen;
700
89
          unsigned short mech = Curl_sasl_decode_mech((char *) bvals[i].bv_val,
701
89
                                                      bvals[i].bv_len, &llen);
702
89
          if(bvals[i].bv_len == llen)
703
1
            li->sasl.authmechs |= mech;
704
89
        }
705
49
        ber_memfree(bvals);
706
49
      }
707
76
    }
708
78
    ber_free(ber, 0);
709
78
    break;
710
711
9
  case LDAP_RES_SEARCH_RESULT:
712
9
    switch(code) {
713
1
    case LDAP_SIZELIMIT_EXCEEDED:
714
1
      infof(data, "Too many authentication mechanisms\n");
715
1
      FALLTHROUGH();
716
2
    case LDAP_SUCCESS:
717
3
    case LDAP_NO_RESULTS_RETURNED:
718
3
      if(Curl_sasl_can_authenticate(&li->sasl, data))
719
1
        result = oldap_perform_sasl(data);
720
2
      else
721
2
        result = CURLE_LOGIN_DENIED;
722
3
      break;
723
6
    default:
724
6
      result = oldap_map_error(code, CURLE_LOGIN_DENIED);
725
6
      break;
726
9
    }
727
9
    break;
728
104
  default:
729
104
    break;
730
192
  }
731
191
  return result;
732
192
}
733
734
/* Handle a SASL bind response. */
735
static CURLcode oldap_state_sasl_resp(struct Curl_easy *data,
736
                                      LDAPMessage *msg, int code)
737
0
{
738
0
  struct connectdata *conn = data->conn;
739
0
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
740
0
  CURLcode result = CURLE_OK;
741
0
  saslprogress progress;
742
0
  int rc;
743
744
0
  if(!li)
745
0
    return CURLE_FAILED_INIT;
746
0
  li->servercred = NULL;
747
0
  rc = ldap_parse_sasl_bind_result(li->ld, msg, &li->servercred, 0);
748
0
  if(rc != LDAP_SUCCESS) {
749
0
    failf(data, "LDAP local: sasl ldap_parse_result %s", ldap_err2string(rc));
750
0
    result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
751
0
  }
752
0
  else {
753
0
    result = Curl_sasl_continue(&li->sasl, data, code, &progress);
754
0
    if(!result && progress != SASL_INPROGRESS)
755
0
      oldap_state(data, li, OLDAP_STOP);
756
0
  }
757
758
0
  if(li->servercred)
759
0
    ber_bvfree(li->servercred);
760
0
  return result;
761
0
}
762
763
/* Handle a simple bind response. */
764
static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg,
765
                                      int code)
766
1.62k
{
767
1.62k
  struct connectdata *conn = data->conn;
768
1.62k
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
769
1.62k
  CURLcode result = CURLE_OK;
770
1.62k
  struct berval *bv = NULL;
771
1.62k
  int rc;
772
773
1.62k
  if(!li)
774
0
    return CURLE_FAILED_INIT;
775
776
1.62k
  if(code != LDAP_SUCCESS)
777
292
    return oldap_map_error(code, CURLE_LDAP_CANNOT_BIND);
778
779
1.33k
  rc = ldap_parse_sasl_bind_result(li->ld, msg, &bv, 0);
780
1.33k
  if(rc != LDAP_SUCCESS) {
781
166
    failf(data, "LDAP local: bind ldap_parse_sasl_bind_result %s",
782
166
          ldap_err2string(rc));
783
166
    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
784
166
  }
785
1.16k
  else
786
1.16k
    oldap_state(data, li, OLDAP_STOP);
787
788
1.33k
  if(bv)
789
14
    ber_bvfree(bv);
790
1.33k
  return result;
791
1.62k
}
792
793
static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
794
6.31k
{
795
6.31k
  CURLcode result = CURLE_OK;
796
6.31k
  struct connectdata *conn = data->conn;
797
6.31k
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
798
6.31k
  LDAPMessage *msg = NULL;
799
6.31k
  struct timeval tv = {0, 0};
800
6.31k
  int code = LDAP_SUCCESS;
801
6.31k
  int rc;
802
803
6.31k
  if(!li)
804
0
    return CURLE_FAILED_INIT;
805
806
6.31k
  if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) {
807
    /* Get response to last command. */
808
6.31k
    rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg);
809
6.31k
    switch(rc) {
810
3.11k
    case 0:                               /* Timed out. */
811
3.11k
      return CURLE_OK;
812
88
    case LDAP_RES_SEARCH_ENTRY:
813
90
    case LDAP_RES_SEARCH_REFERENCE:
814
90
      break;
815
3.10k
    default:
816
3.10k
      li->msgid = 0;                      /* Nothing to abandon upon error. */
817
3.10k
      if(rc < 0) {
818
1.36k
        failf(data, "LDAP local: connecting ldap_result %s",
819
1.36k
              ldap_err2string(rc));
820
1.36k
        return oldap_map_error(rc, CURLE_COULDNT_CONNECT);
821
1.36k
      }
822
1.74k
      break;
823
6.31k
    }
824
825
    /* Get error code from message. */
826
1.83k
    rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0);
827
1.83k
    if(rc)
828
208
      code = rc;
829
1.62k
    else {
830
      /* store the latest code for later retrieval */
831
1.62k
      data->info.httpcode = code;
832
1.62k
    }
833
834
    /* If protocol version 3 is not supported, fallback to version 2. */
835
1.83k
    if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 &&
836
1.83k
#ifdef USE_SSL
837
1.83k
       (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) &&
838
1.83k
#endif
839
1.83k
       li->sasl.prefmech == SASL_AUTH_NONE) {
840
8
      static const int version = LDAP_VERSION2;
841
842
8
      ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
843
8
      ldap_msgfree(msg);
844
8
      return oldap_perform_bind(data, OLDAP_BINDV2);
845
8
    }
846
1.83k
  }
847
848
  /* Handle response message according to current state. */
849
1.82k
  switch(li->state) {
850
851
0
#ifdef USE_SSL
852
0
  case OLDAP_SSL:
853
0
    result = oldap_ssl_connect(data, OLDAP_SSL);
854
0
    if(!result && ssl_installed(conn)) {
855
0
      if(li->sasl.prefmech != SASL_AUTH_NONE)
856
0
        result = oldap_perform_mechs(data);
857
0
      else
858
0
        result = oldap_perform_bind(data, OLDAP_BIND);
859
0
    }
860
0
    break;
861
7
  case OLDAP_STARTTLS:
862
7
    if(code != LDAP_SUCCESS) {
863
6
      if(data->set.use_ssl != CURLUSESSL_TRY)
864
1
        result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
865
5
      else if(li->sasl.prefmech != SASL_AUTH_NONE)
866
0
        result = oldap_perform_mechs(data);
867
5
      else
868
5
        result = oldap_perform_bind(data, OLDAP_BIND);
869
6
      break;
870
6
    }
871
1
    result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
872
1
    if(result)
873
0
      break;
874
1
    FALLTHROUGH();
875
1
  case OLDAP_TLS:
876
1
    result = oldap_ssl_connect(data, OLDAP_TLS);
877
1
    if(result)
878
1
      result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
879
0
    else if(ssl_installed(conn)) {
880
0
      if(li->sasl.prefmech != SASL_AUTH_NONE)
881
0
        result = oldap_perform_mechs(data);
882
0
      else if(data->state.aptr.user)
883
0
        result = oldap_perform_bind(data, OLDAP_BIND);
884
0
      else {
885
        /* Version 3 supported: no bind required */
886
0
        oldap_state(data, li, OLDAP_STOP);
887
0
        result = CURLE_OK;
888
0
      }
889
0
    }
890
1
    break;
891
0
#endif
892
893
192
  case OLDAP_MECHS:
894
192
    result = oldap_state_mechs_resp(data, msg, code);
895
192
    break;
896
0
  case OLDAP_SASL:
897
0
    result = oldap_state_sasl_resp(data, msg, code);
898
0
    break;
899
1.61k
  case OLDAP_BIND:
900
1.62k
  case OLDAP_BINDV2:
901
1.62k
    result = oldap_state_bind_resp(data, msg, code);
902
1.62k
    break;
903
0
  default:
904
    /* internal error */
905
0
    result = CURLE_COULDNT_CONNECT;
906
0
    break;
907
1.82k
  }
908
909
1.82k
  ldap_msgfree(msg);
910
911
1.82k
  *done = li->state == OLDAP_STOP;
912
1.82k
  if(*done)
913
1.16k
    conn->recv[FIRSTSOCKET] = oldap_recv;
914
915
1.82k
  if(result && li->msgid) {
916
7
    ldap_abandon_ext(li->ld, li->msgid, NULL, NULL);
917
7
    li->msgid = 0;
918
7
  }
919
1.82k
  return result;
920
1.82k
}
921
922
static CURLcode oldap_disconnect(struct Curl_easy *data,
923
                                 struct connectdata *conn,
924
                                 bool dead_connection)
925
6.02k
{
926
6.02k
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
927
6.02k
  (void)dead_connection;
928
#ifndef USE_SSL
929
  (void)data;
930
#endif
931
932
6.02k
  if(li) {
933
3.03k
    if(li->ld) {
934
3.01k
#ifdef USE_SSL
935
3.01k
      if(ssl_installed(conn)) {
936
0
        Sockbuf *sb;
937
0
        ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
938
0
        ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
939
0
      }
940
3.01k
#endif
941
3.01k
      ldap_unbind_ext(li->ld, NULL, NULL);
942
3.01k
      li->ld = NULL;
943
3.01k
    }
944
3.03k
  }
945
6.02k
  return CURLE_OK;
946
6.02k
}
947
948
static CURLcode oldap_do(struct Curl_easy *data, bool *done)
949
1.16k
{
950
1.16k
  struct connectdata *conn = data->conn;
951
1.16k
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
952
1.16k
  struct ldapreqinfo *lr;
953
1.16k
  CURLcode result;
954
1.16k
  int rc;
955
1.16k
  LDAPURLDesc *lud;
956
1.16k
  int msgid;
957
958
1.16k
  if(!li)
959
0
    return CURLE_FAILED_INIT;
960
1.16k
  connkeep(conn, "OpenLDAP do");
961
962
1.16k
  infof(data, "LDAP local: %s", data->state.url);
963
964
1.16k
  result = oldap_url_parse(data, &lud);
965
1.16k
  if(result)
966
0
    goto out;
967
968
1.16k
#ifdef USE_SSL
969
1.16k
  if(ssl_installed(conn)) {
970
0
    Sockbuf *sb;
971
    /* re-install the libcurl SSL handlers into the sockbuf. */
972
0
    ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
973
0
    ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
974
0
  }
975
1.16k
#endif
976
977
1.16k
  rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
978
1.16k
                       lud->lud_filter, lud->lud_attrs, 0,
979
1.16k
                       NULL, NULL, NULL, 0, &msgid);
980
1.16k
  ldap_free_urldesc(lud);
981
1.16k
  if(rc != LDAP_SUCCESS) {
982
325
    failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
983
325
    result = CURLE_LDAP_SEARCH_FAILED;
984
325
    goto out;
985
325
  }
986
987
839
  lr = calloc(1, sizeof(struct ldapreqinfo));
988
839
  if(!lr ||
989
839
     Curl_meta_set(data, CURL_META_LDAP_EASY, lr, oldap_easy_dtor)) {
990
0
    ldap_abandon_ext(li->ld, msgid, NULL, NULL);
991
0
    result = CURLE_OUT_OF_MEMORY;
992
0
    goto out;
993
0
  }
994
995
839
  lr->msgid = msgid;
996
839
  Curl_xfer_setup_recv(data, FIRSTSOCKET, -1);
997
839
  *done = TRUE;
998
999
1.16k
out:
1000
1.16k
  return result;
1001
839
}
1002
1003
static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
1004
                           bool premature)
1005
3.03k
{
1006
3.03k
  struct connectdata *conn = data->conn;
1007
3.03k
  struct ldapreqinfo *lr = Curl_meta_get(data, CURL_META_LDAP_EASY);
1008
1009
3.03k
  (void)res;
1010
3.03k
  (void)premature;
1011
1012
3.03k
  if(lr) {
1013
    /* if there was a search in progress, abandon it */
1014
839
    if(lr->msgid) {
1015
733
      struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
1016
733
      if(li && li->ld) {
1017
733
        ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
1018
733
      }
1019
733
      lr->msgid = 0;
1020
733
    }
1021
839
    Curl_meta_remove(data, CURL_META_LDAP_EASY);
1022
839
  }
1023
1024
3.03k
  return CURLE_OK;
1025
3.03k
}
1026
1027
static CURLcode client_write(struct Curl_easy *data,
1028
                             const char *prefix, size_t plen,
1029
                             const char *value, size_t len,
1030
                             const char *suffix, size_t slen)
1031
2.97k
{
1032
2.97k
  CURLcode result = CURLE_OK;
1033
1034
2.97k
  if(prefix) {
1035
    /* If we have a zero-length value and the prefix ends with a space
1036
       separator, drop the latter. */
1037
2.97k
    if(!len && plen && prefix[plen - 1] == ' ')
1038
1.02k
      plen--;
1039
2.97k
    result = Curl_client_write(data, CLIENTWRITE_BODY, prefix, plen);
1040
2.97k
  }
1041
2.97k
  if(!result && value) {
1042
2.16k
    result = Curl_client_write(data, CLIENTWRITE_BODY, value, len);
1043
2.16k
  }
1044
2.97k
  if(!result && suffix) {
1045
2.16k
    result = Curl_client_write(data, CLIENTWRITE_BODY, suffix, slen);
1046
2.16k
  }
1047
2.97k
  return result;
1048
2.97k
}
1049
1050
static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
1051
                           size_t len, size_t *pnread)
1052
1.94k
{
1053
1.94k
  struct connectdata *conn = data->conn;
1054
1.94k
  struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
1055
1.94k
  struct ldapreqinfo *lr = Curl_meta_get(data, CURL_META_LDAP_EASY);
1056
1.94k
  int rc;
1057
1.94k
  LDAPMessage *msg = NULL;
1058
1.94k
  BerElement *ber = NULL;
1059
1.94k
  struct timeval tv = {0, 0};
1060
1.94k
  struct berval bv, *bvals;
1061
1.94k
  bool binary = FALSE;
1062
1.94k
  CURLcode result = CURLE_AGAIN;
1063
1.94k
  int code;
1064
1.94k
  char *info = NULL;
1065
1066
1.94k
  (void)len;
1067
1.94k
  (void)buf;
1068
1.94k
  (void)sockindex;
1069
1.94k
  *pnread = 0;
1070
1.94k
  if(!li || !lr)
1071
0
    return CURLE_FAILED_INIT;
1072
1073
1.94k
  rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg);
1074
1.94k
  if(rc < 0) {
1075
703
    failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
1076
703
    result = CURLE_RECV_ERROR;
1077
703
  }
1078
1079
  /* error or timed out */
1080
1.94k
  if(!msg)
1081
1.17k
    return result;
1082
1083
768
  result = CURLE_OK;
1084
1085
768
  switch(ldap_msgtype(msg)) {
1086
106
  case LDAP_RES_SEARCH_RESULT:
1087
106
    lr->msgid = 0;
1088
106
    rc = ldap_parse_result(li->ld, msg, &code, NULL, &info, NULL, NULL, 0);
1089
106
    if(rc) {
1090
1
      failf(data, "LDAP local: search ldap_parse_result %s",
1091
1
            ldap_err2string(rc));
1092
1
      result = CURLE_LDAP_SEARCH_FAILED;
1093
1
      break;
1094
1
    }
1095
1096
    /* store the latest code for later retrieval */
1097
105
    data->info.httpcode = code;
1098
1099
105
    switch(code) {
1100
1
    case LDAP_SIZELIMIT_EXCEEDED:
1101
1
      infof(data, "There are more than %d entries", lr->nument);
1102
1
      FALLTHROUGH();
1103
8
    case LDAP_SUCCESS:
1104
8
      data->req.size = data->req.bytecount;
1105
8
      break;
1106
97
    default:
1107
97
      failf(data, "LDAP remote: search failed %s %s", ldap_err2string(code),
1108
97
            info ? info : "");
1109
97
      result = CURLE_LDAP_SEARCH_FAILED;
1110
97
      break;
1111
105
    }
1112
105
    if(info)
1113
15
      ldap_memfree(info);
1114
105
    break;
1115
639
  case LDAP_RES_SEARCH_ENTRY:
1116
639
    lr->nument++;
1117
639
    rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
1118
639
    if(rc < 0) {
1119
7
      result = CURLE_RECV_ERROR;
1120
7
      break;
1121
7
    }
1122
1123
632
    result = client_write(data, STRCONST("DN: "), bv.bv_val, bv.bv_len,
1124
632
                          STRCONST("\n"));
1125
632
    if(result)
1126
3
      break;
1127
1128
629
    for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
1129
1.07k
        rc == LDAP_SUCCESS;
1130
629
        rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
1131
577
      int i;
1132
1133
577
      if(!bv.bv_val)
1134
124
        break;
1135
1136
453
      if(!bvals) {
1137
263
        result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
1138
263
                              STRCONST(":\n"));
1139
263
        if(result)
1140
1
          break;
1141
262
        continue;
1142
263
      }
1143
1144
190
      binary = bv.bv_len > 7 &&
1145
190
        !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7);
1146
1147
823
      for(i = 0; bvals[i].bv_val != NULL; i++) {
1148
636
        bool binval = FALSE;
1149
1150
636
        result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
1151
636
                              STRCONST(":"));
1152
636
        if(result)
1153
1
          break;
1154
1155
635
        if(!binary) {
1156
          /* check for leading or trailing whitespace */
1157
634
          if(ISBLANK(bvals[i].bv_val[0]) ||
1158
634
             ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))
1159
35
            binval = TRUE;
1160
599
          else {
1161
            /* check for unprintable characters */
1162
599
            unsigned int j;
1163
681
            for(j = 0; j < bvals[i].bv_len; j++)
1164
155
              if(!ISPRINT(bvals[i].bv_val[j])) {
1165
73
                binval = TRUE;
1166
73
                break;
1167
73
              }
1168
599
          }
1169
634
        }
1170
635
        if(binary || binval) {
1171
109
          char *val_b64 = NULL;
1172
109
          size_t val_b64_sz = 0;
1173
1174
          /* Binary value, encode to base64. */
1175
109
          if(bvals[i].bv_len)
1176
108
            result = curlx_base64_encode(bvals[i].bv_val, bvals[i].bv_len,
1177
108
                                         &val_b64, &val_b64_sz);
1178
109
          if(!result)
1179
109
            result = client_write(data, STRCONST(": "), val_b64, val_b64_sz,
1180
109
                                  STRCONST("\n"));
1181
109
          free(val_b64);
1182
109
        }
1183
526
        else
1184
526
          result = client_write(data, STRCONST(" "),
1185
526
                                bvals[i].bv_val, bvals[i].bv_len,
1186
526
                                STRCONST("\n"));
1187
635
        if(result)
1188
2
          break;
1189
635
      }
1190
1191
190
      ber_memfree(bvals);
1192
190
      bvals = NULL;
1193
190
      if(!result)
1194
187
        result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
1195
190
      if(result)
1196
3
        break;
1197
190
    }
1198
1199
629
    ber_free(ber, 0);
1200
1201
629
    if(!result)
1202
625
      result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
1203
629
    if(!result)
1204
624
      result = CURLE_AGAIN;
1205
629
    break;
1206
768
  }
1207
1208
768
  ldap_msgfree(msg);
1209
768
  return result;
1210
768
}
1211
1212
#ifdef USE_SSL
1213
static int
1214
ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
1215
0
{
1216
0
  sbiod->sbiod_pvt = arg;
1217
0
  return 0;
1218
0
}
1219
1220
static int
1221
ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
1222
0
{
1223
0
  sbiod->sbiod_pvt = NULL;
1224
0
  return 0;
1225
0
}
1226
1227
/* We do not need to do anything because libcurl does it already */
1228
static int
1229
ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
1230
0
{
1231
0
  (void)sbiod;
1232
0
  return 0;
1233
0
}
1234
1235
static int
1236
ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
1237
0
{
1238
0
  (void)arg;
1239
0
  if(opt == LBER_SB_OPT_DATA_READY) {
1240
0
    struct Curl_easy *data = sbiod->sbiod_pvt;
1241
0
    return Curl_conn_data_pending(data, FIRSTSOCKET);
1242
0
  }
1243
0
  return 0;
1244
0
}
1245
1246
static ber_slen_t
1247
ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
1248
0
{
1249
0
  struct Curl_easy *data = sbiod->sbiod_pvt;
1250
0
  ber_slen_t ret = 0;
1251
0
  if(data) {
1252
0
    struct connectdata *conn = data->conn;
1253
0
    if(conn) {
1254
0
      struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
1255
0
      CURLcode err = CURLE_RECV_ERROR;
1256
0
      size_t nread;
1257
1258
0
      if(!li) {
1259
0
        SET_SOCKERRNO(SOCKEINVAL);
1260
0
        return -1;
1261
0
      }
1262
0
      err = (li->recv)(data, FIRSTSOCKET, buf, len, &nread);
1263
0
      if(err == CURLE_AGAIN) {
1264
0
        SET_SOCKERRNO(SOCKEWOULDBLOCK);
1265
0
      }
1266
0
      ret = err ? -1 : (ber_slen_t)nread;
1267
0
    }
1268
0
  }
1269
0
  return ret;
1270
0
}
1271
static ber_slen_t
1272
ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
1273
0
{
1274
0
  struct Curl_easy *data = sbiod->sbiod_pvt;
1275
0
  ber_slen_t ret = 0;
1276
0
  if(data) {
1277
0
    struct connectdata *conn = data->conn;
1278
0
    if(conn) {
1279
0
      struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
1280
0
      CURLcode err = CURLE_SEND_ERROR;
1281
0
      size_t nwritten;
1282
1283
0
      if(!li) {
1284
0
        SET_SOCKERRNO(SOCKEINVAL);
1285
0
        return -1;
1286
0
      }
1287
0
      err = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &nwritten);
1288
0
      if(err == CURLE_AGAIN) {
1289
0
        SET_SOCKERRNO(SOCKEWOULDBLOCK);
1290
0
      }
1291
0
      ret = err ? -1 : (ber_slen_t)nwritten;
1292
0
    }
1293
0
  }
1294
0
  return ret;
1295
0
}
1296
1297
static Sockbuf_IO ldapsb_tls =
1298
{
1299
  ldapsb_tls_setup,
1300
  ldapsb_tls_remove,
1301
  ldapsb_tls_ctrl,
1302
  ldapsb_tls_read,
1303
  ldapsb_tls_write,
1304
  ldapsb_tls_close
1305
};
1306
#endif /* USE_SSL */
1307
1308
#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */