xref: /third_party/curl/lib/openldap.c (revision 13498266)
113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                      _   _ ____  _
313498266Sopenharmony_ci *  Project         ___| | | |  _ \| |
413498266Sopenharmony_ci *                 / __| | | | |_) | |
513498266Sopenharmony_ci *                | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                 \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci * Copyright (C) Howard Chu, <hyc@openldap.org>
1013498266Sopenharmony_ci *
1113498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1213498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1313498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1413498266Sopenharmony_ci *
1513498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1613498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1713498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1813498266Sopenharmony_ci *
1913498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
2013498266Sopenharmony_ci * KIND, either express or implied.
2113498266Sopenharmony_ci *
2213498266Sopenharmony_ci * SPDX-License-Identifier: curl
2313498266Sopenharmony_ci *
2413498266Sopenharmony_ci ***************************************************************************/
2513498266Sopenharmony_ci
2613498266Sopenharmony_ci#include "curl_setup.h"
2713498266Sopenharmony_ci
2813498266Sopenharmony_ci#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
2913498266Sopenharmony_ci
3013498266Sopenharmony_ci/*
3113498266Sopenharmony_ci * Notice that USE_OPENLDAP is only a source code selection switch. When
3213498266Sopenharmony_ci * libcurl is built with USE_OPENLDAP defined the libcurl source code that
3313498266Sopenharmony_ci * gets compiled is the code from openldap.c, otherwise the code that gets
3413498266Sopenharmony_ci * compiled is the code from ldap.c.
3513498266Sopenharmony_ci *
3613498266Sopenharmony_ci * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
3713498266Sopenharmony_ci * might be required for compilation and runtime. In order to use ancient
3813498266Sopenharmony_ci * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
3913498266Sopenharmony_ci */
4013498266Sopenharmony_ci
4113498266Sopenharmony_ci#include <ldap.h>
4213498266Sopenharmony_ci
4313498266Sopenharmony_ci#include "urldata.h"
4413498266Sopenharmony_ci#include <curl/curl.h>
4513498266Sopenharmony_ci#include "sendf.h"
4613498266Sopenharmony_ci#include "vtls/vtls.h"
4713498266Sopenharmony_ci#include "transfer.h"
4813498266Sopenharmony_ci#include "curl_ldap.h"
4913498266Sopenharmony_ci#include "curl_base64.h"
5013498266Sopenharmony_ci#include "cfilters.h"
5113498266Sopenharmony_ci#include "connect.h"
5213498266Sopenharmony_ci#include "curl_sasl.h"
5313498266Sopenharmony_ci#include "strcase.h"
5413498266Sopenharmony_ci/* The last 3 #include files should be in this order */
5513498266Sopenharmony_ci#include "curl_printf.h"
5613498266Sopenharmony_ci#include "curl_memory.h"
5713498266Sopenharmony_ci#include "memdebug.h"
5813498266Sopenharmony_ci
5913498266Sopenharmony_ci/*
6013498266Sopenharmony_ci * Uncommenting this will enable the built-in debug logging of the openldap
6113498266Sopenharmony_ci * library. The debug log level can be set using the CURL_OPENLDAP_TRACE
6213498266Sopenharmony_ci * environment variable. The debug output is written to stderr.
6313498266Sopenharmony_ci *
6413498266Sopenharmony_ci * The library supports the following debug flags:
6513498266Sopenharmony_ci * LDAP_DEBUG_NONE         0x0000
6613498266Sopenharmony_ci * LDAP_DEBUG_TRACE        0x0001
6713498266Sopenharmony_ci * LDAP_DEBUG_CONSTRUCT    0x0002
6813498266Sopenharmony_ci * LDAP_DEBUG_DESTROY      0x0004
6913498266Sopenharmony_ci * LDAP_DEBUG_PARAMETER    0x0008
7013498266Sopenharmony_ci * LDAP_DEBUG_ANY          0xffff
7113498266Sopenharmony_ci *
7213498266Sopenharmony_ci * For example, use CURL_OPENLDAP_TRACE=0 for no debug,
7313498266Sopenharmony_ci * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only,
7413498266Sopenharmony_ci * CURL_OPENLDAP_TRACE=65535 for all debug message levels.
7513498266Sopenharmony_ci */
7613498266Sopenharmony_ci/* #define CURL_OPENLDAP_DEBUG */
7713498266Sopenharmony_ci
7813498266Sopenharmony_ci/* Machine states. */
7913498266Sopenharmony_citypedef enum {
8013498266Sopenharmony_ci  OLDAP_STOP,           /* Do nothing state, stops the state machine */
8113498266Sopenharmony_ci  OLDAP_SSL,            /* Performing SSL handshake. */
8213498266Sopenharmony_ci  OLDAP_STARTTLS,       /* STARTTLS request sent. */
8313498266Sopenharmony_ci  OLDAP_TLS,            /* Performing TLS handshake. */
8413498266Sopenharmony_ci  OLDAP_MECHS,          /* Get SASL authentication mechanisms. */
8513498266Sopenharmony_ci  OLDAP_SASL,           /* SASL binding reply. */
8613498266Sopenharmony_ci  OLDAP_BIND,           /* Simple bind reply. */
8713498266Sopenharmony_ci  OLDAP_BINDV2,         /* Simple bind reply in protocol version 2. */
8813498266Sopenharmony_ci  OLDAP_LAST            /* Never used */
8913498266Sopenharmony_ci} ldapstate;
9013498266Sopenharmony_ci
9113498266Sopenharmony_ci#ifndef _LDAP_PVT_H
9213498266Sopenharmony_ciextern int ldap_pvt_url_scheme2proto(const char *);
9313498266Sopenharmony_ciextern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
9413498266Sopenharmony_ci                        LDAP **ld);
9513498266Sopenharmony_ci#endif
9613498266Sopenharmony_ci
9713498266Sopenharmony_cistatic CURLcode oldap_setup_connection(struct Curl_easy *data,
9813498266Sopenharmony_ci                                       struct connectdata *conn);
9913498266Sopenharmony_cistatic CURLcode oldap_do(struct Curl_easy *data, bool *done);
10013498266Sopenharmony_cistatic CURLcode oldap_done(struct Curl_easy *data, CURLcode, bool);
10113498266Sopenharmony_cistatic CURLcode oldap_connect(struct Curl_easy *data, bool *done);
10213498266Sopenharmony_cistatic CURLcode oldap_connecting(struct Curl_easy *data, bool *done);
10313498266Sopenharmony_cistatic CURLcode oldap_disconnect(struct Curl_easy *data,
10413498266Sopenharmony_ci                                 struct connectdata *conn, bool dead);
10513498266Sopenharmony_ci
10613498266Sopenharmony_cistatic CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
10713498266Sopenharmony_ci                                   const struct bufref *initresp);
10813498266Sopenharmony_cistatic CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
10913498266Sopenharmony_ci                                    const struct bufref *resp);
11013498266Sopenharmony_cistatic CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech);
11113498266Sopenharmony_cistatic CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out);
11213498266Sopenharmony_ci
11313498266Sopenharmony_cistatic Curl_recv oldap_recv;
11413498266Sopenharmony_ci
11513498266Sopenharmony_ci/*
11613498266Sopenharmony_ci * LDAP protocol handler.
11713498266Sopenharmony_ci */
11813498266Sopenharmony_ci
11913498266Sopenharmony_ciconst struct Curl_handler Curl_handler_ldap = {
12013498266Sopenharmony_ci  "LDAP",                               /* scheme */
12113498266Sopenharmony_ci  oldap_setup_connection,               /* setup_connection */
12213498266Sopenharmony_ci  oldap_do,                             /* do_it */
12313498266Sopenharmony_ci  oldap_done,                           /* done */
12413498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
12513498266Sopenharmony_ci  oldap_connect,                        /* connect_it */
12613498266Sopenharmony_ci  oldap_connecting,                     /* connecting */
12713498266Sopenharmony_ci  ZERO_NULL,                            /* doing */
12813498266Sopenharmony_ci  ZERO_NULL,                            /* proto_getsock */
12913498266Sopenharmony_ci  ZERO_NULL,                            /* doing_getsock */
13013498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
13113498266Sopenharmony_ci  ZERO_NULL,                            /* perform_getsock */
13213498266Sopenharmony_ci  oldap_disconnect,                     /* disconnect */
13313498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
13413498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
13513498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
13613498266Sopenharmony_ci  PORT_LDAP,                            /* defport */
13713498266Sopenharmony_ci  CURLPROTO_LDAP,                       /* protocol */
13813498266Sopenharmony_ci  CURLPROTO_LDAP,                       /* family */
13913498266Sopenharmony_ci  PROTOPT_NONE                          /* flags */
14013498266Sopenharmony_ci};
14113498266Sopenharmony_ci
14213498266Sopenharmony_ci#ifdef USE_SSL
14313498266Sopenharmony_ci/*
14413498266Sopenharmony_ci * LDAPS protocol handler.
14513498266Sopenharmony_ci */
14613498266Sopenharmony_ci
14713498266Sopenharmony_ciconst struct Curl_handler Curl_handler_ldaps = {
14813498266Sopenharmony_ci  "LDAPS",                              /* scheme */
14913498266Sopenharmony_ci  oldap_setup_connection,               /* setup_connection */
15013498266Sopenharmony_ci  oldap_do,                             /* do_it */
15113498266Sopenharmony_ci  oldap_done,                           /* done */
15213498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
15313498266Sopenharmony_ci  oldap_connect,                        /* connect_it */
15413498266Sopenharmony_ci  oldap_connecting,                     /* connecting */
15513498266Sopenharmony_ci  ZERO_NULL,                            /* doing */
15613498266Sopenharmony_ci  ZERO_NULL,                            /* proto_getsock */
15713498266Sopenharmony_ci  ZERO_NULL,                            /* doing_getsock */
15813498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
15913498266Sopenharmony_ci  ZERO_NULL,                            /* perform_getsock */
16013498266Sopenharmony_ci  oldap_disconnect,                     /* disconnect */
16113498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
16213498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
16313498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
16413498266Sopenharmony_ci  PORT_LDAPS,                           /* defport */
16513498266Sopenharmony_ci  CURLPROTO_LDAPS,                      /* protocol */
16613498266Sopenharmony_ci  CURLPROTO_LDAP,                       /* family */
16713498266Sopenharmony_ci  PROTOPT_SSL                           /* flags */
16813498266Sopenharmony_ci};
16913498266Sopenharmony_ci#endif
17013498266Sopenharmony_ci
17113498266Sopenharmony_ci/* SASL parameters for the ldap protocol */
17213498266Sopenharmony_cistatic const struct SASLproto saslldap = {
17313498266Sopenharmony_ci  "ldap",                     /* The service name */
17413498266Sopenharmony_ci  oldap_perform_auth,         /* Send authentication command */
17513498266Sopenharmony_ci  oldap_continue_auth,        /* Send authentication continuation */
17613498266Sopenharmony_ci  oldap_cancel_auth,          /* Send authentication cancellation */
17713498266Sopenharmony_ci  oldap_get_message,          /* Get SASL response message */
17813498266Sopenharmony_ci  0,                          /* Maximum initial response length (no max) */
17913498266Sopenharmony_ci  LDAP_SASL_BIND_IN_PROGRESS, /* Code received when continuation is expected */
18013498266Sopenharmony_ci  LDAP_SUCCESS,               /* Code to receive upon authentication success */
18113498266Sopenharmony_ci  SASL_AUTH_NONE,             /* Default mechanisms */
18213498266Sopenharmony_ci  0                           /* Configuration flags */
18313498266Sopenharmony_ci};
18413498266Sopenharmony_ci
18513498266Sopenharmony_cistruct ldapconninfo {
18613498266Sopenharmony_ci  struct SASL sasl;          /* SASL-related parameters */
18713498266Sopenharmony_ci  LDAP *ld;                  /* Openldap connection handle. */
18813498266Sopenharmony_ci  Curl_recv *recv;           /* For stacking SSL handler */
18913498266Sopenharmony_ci  Curl_send *send;
19013498266Sopenharmony_ci  struct berval *servercred; /* SASL data from server. */
19113498266Sopenharmony_ci  ldapstate state;           /* Current machine state. */
19213498266Sopenharmony_ci  int proto;                 /* LDAP_PROTO_TCP/LDAP_PROTO_UDP/LDAP_PROTO_IPC */
19313498266Sopenharmony_ci  int msgid;                 /* Current message id. */
19413498266Sopenharmony_ci};
19513498266Sopenharmony_ci
19613498266Sopenharmony_cistruct ldapreqinfo {
19713498266Sopenharmony_ci  int msgid;
19813498266Sopenharmony_ci  int nument;
19913498266Sopenharmony_ci};
20013498266Sopenharmony_ci
20113498266Sopenharmony_ci/*
20213498266Sopenharmony_ci * oldap_state()
20313498266Sopenharmony_ci *
20413498266Sopenharmony_ci * This is the ONLY way to change LDAP state!
20513498266Sopenharmony_ci */
20613498266Sopenharmony_cistatic void oldap_state(struct Curl_easy *data, ldapstate newstate)
20713498266Sopenharmony_ci{
20813498266Sopenharmony_ci  struct ldapconninfo *ldapc = data->conn->proto.ldapc;
20913498266Sopenharmony_ci
21013498266Sopenharmony_ci#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
21113498266Sopenharmony_ci  /* for debug purposes */
21213498266Sopenharmony_ci  static const char * const names[] = {
21313498266Sopenharmony_ci    "STOP",
21413498266Sopenharmony_ci    "SSL",
21513498266Sopenharmony_ci    "STARTTLS",
21613498266Sopenharmony_ci    "TLS",
21713498266Sopenharmony_ci    "MECHS",
21813498266Sopenharmony_ci    "SASL",
21913498266Sopenharmony_ci    "BIND",
22013498266Sopenharmony_ci    "BINDV2",
22113498266Sopenharmony_ci    /* LAST */
22213498266Sopenharmony_ci  };
22313498266Sopenharmony_ci
22413498266Sopenharmony_ci  if(ldapc->state != newstate)
22513498266Sopenharmony_ci    infof(data, "LDAP %p state change from %s to %s",
22613498266Sopenharmony_ci          (void *)ldapc, names[ldapc->state], names[newstate]);
22713498266Sopenharmony_ci#endif
22813498266Sopenharmony_ci
22913498266Sopenharmony_ci  ldapc->state = newstate;
23013498266Sopenharmony_ci}
23113498266Sopenharmony_ci
23213498266Sopenharmony_ci/* Map some particular LDAP error codes to CURLcode values. */
23313498266Sopenharmony_cistatic CURLcode oldap_map_error(int rc, CURLcode result)
23413498266Sopenharmony_ci{
23513498266Sopenharmony_ci  switch(rc) {
23613498266Sopenharmony_ci  case LDAP_NO_MEMORY:
23713498266Sopenharmony_ci    result = CURLE_OUT_OF_MEMORY;
23813498266Sopenharmony_ci    break;
23913498266Sopenharmony_ci  case LDAP_INVALID_CREDENTIALS:
24013498266Sopenharmony_ci    result = CURLE_LOGIN_DENIED;
24113498266Sopenharmony_ci    break;
24213498266Sopenharmony_ci  case LDAP_PROTOCOL_ERROR:
24313498266Sopenharmony_ci    result = CURLE_UNSUPPORTED_PROTOCOL;
24413498266Sopenharmony_ci    break;
24513498266Sopenharmony_ci  case LDAP_INSUFFICIENT_ACCESS:
24613498266Sopenharmony_ci    result = CURLE_REMOTE_ACCESS_DENIED;
24713498266Sopenharmony_ci    break;
24813498266Sopenharmony_ci  }
24913498266Sopenharmony_ci  return result;
25013498266Sopenharmony_ci}
25113498266Sopenharmony_ci
25213498266Sopenharmony_cistatic CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
25313498266Sopenharmony_ci{
25413498266Sopenharmony_ci  CURLcode result = CURLE_OK;
25513498266Sopenharmony_ci  int rc = LDAP_URL_ERR_BADURL;
25613498266Sopenharmony_ci  static const char * const url_errs[] = {
25713498266Sopenharmony_ci    "success",
25813498266Sopenharmony_ci    "out of memory",
25913498266Sopenharmony_ci    "bad parameter",
26013498266Sopenharmony_ci    "unrecognized scheme",
26113498266Sopenharmony_ci    "unbalanced delimiter",
26213498266Sopenharmony_ci    "bad URL",
26313498266Sopenharmony_ci    "bad host or port",
26413498266Sopenharmony_ci    "bad or missing attributes",
26513498266Sopenharmony_ci    "bad or missing scope",
26613498266Sopenharmony_ci    "bad or missing filter",
26713498266Sopenharmony_ci    "bad or missing extensions"
26813498266Sopenharmony_ci  };
26913498266Sopenharmony_ci
27013498266Sopenharmony_ci  *ludp = NULL;
27113498266Sopenharmony_ci  if(!data->state.up.user && !data->state.up.password &&
27213498266Sopenharmony_ci     !data->state.up.options)
27313498266Sopenharmony_ci    rc = ldap_url_parse(data->state.url, ludp);
27413498266Sopenharmony_ci  if(rc != LDAP_URL_SUCCESS) {
27513498266Sopenharmony_ci    const char *msg = "url parsing problem";
27613498266Sopenharmony_ci
27713498266Sopenharmony_ci    result = rc == LDAP_URL_ERR_MEM? CURLE_OUT_OF_MEMORY: CURLE_URL_MALFORMAT;
27813498266Sopenharmony_ci    rc -= LDAP_URL_SUCCESS;
27913498266Sopenharmony_ci    if((size_t) rc < sizeof(url_errs) / sizeof(url_errs[0]))
28013498266Sopenharmony_ci      msg = url_errs[rc];
28113498266Sopenharmony_ci    failf(data, "LDAP local: %s", msg);
28213498266Sopenharmony_ci  }
28313498266Sopenharmony_ci  return result;
28413498266Sopenharmony_ci}
28513498266Sopenharmony_ci
28613498266Sopenharmony_ci/* Parse the login options. */
28713498266Sopenharmony_cistatic CURLcode oldap_parse_login_options(struct connectdata *conn)
28813498266Sopenharmony_ci{
28913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
29013498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
29113498266Sopenharmony_ci  const char *ptr = conn->options;
29213498266Sopenharmony_ci
29313498266Sopenharmony_ci  while(!result && ptr && *ptr) {
29413498266Sopenharmony_ci    const char *key = ptr;
29513498266Sopenharmony_ci    const char *value;
29613498266Sopenharmony_ci
29713498266Sopenharmony_ci    while(*ptr && *ptr != '=')
29813498266Sopenharmony_ci      ptr++;
29913498266Sopenharmony_ci
30013498266Sopenharmony_ci    value = ptr + 1;
30113498266Sopenharmony_ci
30213498266Sopenharmony_ci    while(*ptr && *ptr != ';')
30313498266Sopenharmony_ci      ptr++;
30413498266Sopenharmony_ci
30513498266Sopenharmony_ci    if(checkprefix("AUTH=", key))
30613498266Sopenharmony_ci      result = Curl_sasl_parse_url_auth_option(&li->sasl, value, ptr - value);
30713498266Sopenharmony_ci    else
30813498266Sopenharmony_ci      result = CURLE_SETOPT_OPTION_SYNTAX;
30913498266Sopenharmony_ci
31013498266Sopenharmony_ci    if(*ptr == ';')
31113498266Sopenharmony_ci      ptr++;
31213498266Sopenharmony_ci  }
31313498266Sopenharmony_ci
31413498266Sopenharmony_ci  return result == CURLE_URL_MALFORMAT? CURLE_SETOPT_OPTION_SYNTAX: result;
31513498266Sopenharmony_ci}
31613498266Sopenharmony_ci
31713498266Sopenharmony_cistatic CURLcode oldap_setup_connection(struct Curl_easy *data,
31813498266Sopenharmony_ci                                       struct connectdata *conn)
31913498266Sopenharmony_ci{
32013498266Sopenharmony_ci  CURLcode result;
32113498266Sopenharmony_ci  LDAPURLDesc *lud;
32213498266Sopenharmony_ci  (void)conn;
32313498266Sopenharmony_ci
32413498266Sopenharmony_ci  /* Early URL syntax check. */
32513498266Sopenharmony_ci  result = oldap_url_parse(data, &lud);
32613498266Sopenharmony_ci  ldap_free_urldesc(lud);
32713498266Sopenharmony_ci
32813498266Sopenharmony_ci  return result;
32913498266Sopenharmony_ci}
33013498266Sopenharmony_ci
33113498266Sopenharmony_ci/*
33213498266Sopenharmony_ci * Get the SASL authentication challenge from the server credential buffer.
33313498266Sopenharmony_ci */
33413498266Sopenharmony_cistatic CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out)
33513498266Sopenharmony_ci{
33613498266Sopenharmony_ci  struct berval *servercred = data->conn->proto.ldapc->servercred;
33713498266Sopenharmony_ci
33813498266Sopenharmony_ci  if(!servercred || !servercred->bv_val)
33913498266Sopenharmony_ci    return CURLE_WEIRD_SERVER_REPLY;
34013498266Sopenharmony_ci  Curl_bufref_set(out, servercred->bv_val, servercred->bv_len, NULL);
34113498266Sopenharmony_ci  return CURLE_OK;
34213498266Sopenharmony_ci}
34313498266Sopenharmony_ci
34413498266Sopenharmony_ci/*
34513498266Sopenharmony_ci * Sends an initial SASL bind request to the server.
34613498266Sopenharmony_ci */
34713498266Sopenharmony_cistatic CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
34813498266Sopenharmony_ci                                   const struct bufref *initresp)
34913498266Sopenharmony_ci{
35013498266Sopenharmony_ci  struct connectdata *conn = data->conn;
35113498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
35213498266Sopenharmony_ci  CURLcode result = CURLE_OK;
35313498266Sopenharmony_ci  struct berval cred;
35413498266Sopenharmony_ci  struct berval *pcred = &cred;
35513498266Sopenharmony_ci  int rc;
35613498266Sopenharmony_ci
35713498266Sopenharmony_ci  cred.bv_val = (char *) Curl_bufref_ptr(initresp);
35813498266Sopenharmony_ci  cred.bv_len = Curl_bufref_len(initresp);
35913498266Sopenharmony_ci  if(!cred.bv_val)
36013498266Sopenharmony_ci    pcred = NULL;
36113498266Sopenharmony_ci  rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
36213498266Sopenharmony_ci  if(rc != LDAP_SUCCESS)
36313498266Sopenharmony_ci    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
36413498266Sopenharmony_ci  return result;
36513498266Sopenharmony_ci}
36613498266Sopenharmony_ci
36713498266Sopenharmony_ci/*
36813498266Sopenharmony_ci * Sends SASL continuation.
36913498266Sopenharmony_ci */
37013498266Sopenharmony_cistatic CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
37113498266Sopenharmony_ci                                    const struct bufref *resp)
37213498266Sopenharmony_ci{
37313498266Sopenharmony_ci  struct connectdata *conn = data->conn;
37413498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
37513498266Sopenharmony_ci  CURLcode result = CURLE_OK;
37613498266Sopenharmony_ci  struct berval cred;
37713498266Sopenharmony_ci  struct berval *pcred = &cred;
37813498266Sopenharmony_ci  int rc;
37913498266Sopenharmony_ci
38013498266Sopenharmony_ci  cred.bv_val = (char *) Curl_bufref_ptr(resp);
38113498266Sopenharmony_ci  cred.bv_len = Curl_bufref_len(resp);
38213498266Sopenharmony_ci  if(!cred.bv_val)
38313498266Sopenharmony_ci    pcred = NULL;
38413498266Sopenharmony_ci  rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
38513498266Sopenharmony_ci  if(rc != LDAP_SUCCESS)
38613498266Sopenharmony_ci    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
38713498266Sopenharmony_ci  return result;
38813498266Sopenharmony_ci}
38913498266Sopenharmony_ci
39013498266Sopenharmony_ci/*
39113498266Sopenharmony_ci * Sends SASL bind cancellation.
39213498266Sopenharmony_ci */
39313498266Sopenharmony_cistatic CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech)
39413498266Sopenharmony_ci{
39513498266Sopenharmony_ci  struct ldapconninfo *li = data->conn->proto.ldapc;
39613498266Sopenharmony_ci  CURLcode result = CURLE_OK;
39713498266Sopenharmony_ci  int rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL,
39813498266Sopenharmony_ci                          &li->msgid);
39913498266Sopenharmony_ci
40013498266Sopenharmony_ci  (void)mech;
40113498266Sopenharmony_ci  if(rc != LDAP_SUCCESS)
40213498266Sopenharmony_ci    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
40313498266Sopenharmony_ci  return result;
40413498266Sopenharmony_ci}
40513498266Sopenharmony_ci
40613498266Sopenharmony_ci/* Starts LDAP simple bind. */
40713498266Sopenharmony_cistatic CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
40813498266Sopenharmony_ci{
40913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
41013498266Sopenharmony_ci  struct connectdata *conn = data->conn;
41113498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
41213498266Sopenharmony_ci  char *binddn = NULL;
41313498266Sopenharmony_ci  struct berval passwd;
41413498266Sopenharmony_ci  int rc;
41513498266Sopenharmony_ci
41613498266Sopenharmony_ci  passwd.bv_val = NULL;
41713498266Sopenharmony_ci  passwd.bv_len = 0;
41813498266Sopenharmony_ci
41913498266Sopenharmony_ci  if(data->state.aptr.user) {
42013498266Sopenharmony_ci    binddn = conn->user;
42113498266Sopenharmony_ci    passwd.bv_val = conn->passwd;
42213498266Sopenharmony_ci    passwd.bv_len = strlen(passwd.bv_val);
42313498266Sopenharmony_ci  }
42413498266Sopenharmony_ci
42513498266Sopenharmony_ci  rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
42613498266Sopenharmony_ci                      NULL, NULL, &li->msgid);
42713498266Sopenharmony_ci  if(rc == LDAP_SUCCESS)
42813498266Sopenharmony_ci    oldap_state(data, newstate);
42913498266Sopenharmony_ci  else
43013498266Sopenharmony_ci    result = oldap_map_error(rc,
43113498266Sopenharmony_ci                             data->state.aptr.user?
43213498266Sopenharmony_ci                             CURLE_LOGIN_DENIED: CURLE_LDAP_CANNOT_BIND);
43313498266Sopenharmony_ci  return result;
43413498266Sopenharmony_ci}
43513498266Sopenharmony_ci
43613498266Sopenharmony_ci/* Query the supported SASL authentication mechanisms. */
43713498266Sopenharmony_cistatic CURLcode oldap_perform_mechs(struct Curl_easy *data)
43813498266Sopenharmony_ci{
43913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
44013498266Sopenharmony_ci  struct ldapconninfo *li = data->conn->proto.ldapc;
44113498266Sopenharmony_ci  int rc;
44213498266Sopenharmony_ci  static const char * const supportedSASLMechanisms[] = {
44313498266Sopenharmony_ci    "supportedSASLMechanisms",
44413498266Sopenharmony_ci    NULL
44513498266Sopenharmony_ci  };
44613498266Sopenharmony_ci
44713498266Sopenharmony_ci  rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
44813498266Sopenharmony_ci                       (char **) supportedSASLMechanisms, 0,
44913498266Sopenharmony_ci                       NULL, NULL, NULL, 0, &li->msgid);
45013498266Sopenharmony_ci  if(rc == LDAP_SUCCESS)
45113498266Sopenharmony_ci    oldap_state(data, OLDAP_MECHS);
45213498266Sopenharmony_ci  else
45313498266Sopenharmony_ci    result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
45413498266Sopenharmony_ci  return result;
45513498266Sopenharmony_ci}
45613498266Sopenharmony_ci
45713498266Sopenharmony_ci/* Starts SASL bind. */
45813498266Sopenharmony_cistatic CURLcode oldap_perform_sasl(struct Curl_easy *data)
45913498266Sopenharmony_ci{
46013498266Sopenharmony_ci  saslprogress progress = SASL_IDLE;
46113498266Sopenharmony_ci  struct ldapconninfo *li = data->conn->proto.ldapc;
46213498266Sopenharmony_ci  CURLcode result = Curl_sasl_start(&li->sasl, data, TRUE, &progress);
46313498266Sopenharmony_ci
46413498266Sopenharmony_ci  oldap_state(data, OLDAP_SASL);
46513498266Sopenharmony_ci  if(!result && progress != SASL_INPROGRESS)
46613498266Sopenharmony_ci    result = CURLE_LOGIN_DENIED;
46713498266Sopenharmony_ci  return result;
46813498266Sopenharmony_ci}
46913498266Sopenharmony_ci
47013498266Sopenharmony_ci#ifdef USE_SSL
47113498266Sopenharmony_cistatic Sockbuf_IO ldapsb_tls;
47213498266Sopenharmony_ci
47313498266Sopenharmony_cistatic bool ssl_installed(struct connectdata *conn)
47413498266Sopenharmony_ci{
47513498266Sopenharmony_ci  return conn->proto.ldapc->recv != NULL;
47613498266Sopenharmony_ci}
47713498266Sopenharmony_ci
47813498266Sopenharmony_cistatic CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
47913498266Sopenharmony_ci{
48013498266Sopenharmony_ci  CURLcode result = CURLE_OK;
48113498266Sopenharmony_ci  struct connectdata *conn = data->conn;
48213498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
48313498266Sopenharmony_ci  bool ssldone = 0;
48413498266Sopenharmony_ci
48513498266Sopenharmony_ci  result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
48613498266Sopenharmony_ci  if(!result) {
48713498266Sopenharmony_ci    oldap_state(data, newstate);
48813498266Sopenharmony_ci
48913498266Sopenharmony_ci    if(ssldone) {
49013498266Sopenharmony_ci      Sockbuf *sb;
49113498266Sopenharmony_ci
49213498266Sopenharmony_ci      /* Install the libcurl SSL handlers into the sockbuf. */
49313498266Sopenharmony_ci      ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
49413498266Sopenharmony_ci      ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
49513498266Sopenharmony_ci      li->recv = conn->recv[FIRSTSOCKET];
49613498266Sopenharmony_ci      li->send = conn->send[FIRSTSOCKET];
49713498266Sopenharmony_ci    }
49813498266Sopenharmony_ci  }
49913498266Sopenharmony_ci
50013498266Sopenharmony_ci  return result;
50113498266Sopenharmony_ci}
50213498266Sopenharmony_ci
50313498266Sopenharmony_ci/* Send the STARTTLS request */
50413498266Sopenharmony_cistatic CURLcode oldap_perform_starttls(struct Curl_easy *data)
50513498266Sopenharmony_ci{
50613498266Sopenharmony_ci  CURLcode result = CURLE_OK;
50713498266Sopenharmony_ci  struct ldapconninfo *li = data->conn->proto.ldapc;
50813498266Sopenharmony_ci  int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid);
50913498266Sopenharmony_ci
51013498266Sopenharmony_ci  if(rc == LDAP_SUCCESS)
51113498266Sopenharmony_ci    oldap_state(data, OLDAP_STARTTLS);
51213498266Sopenharmony_ci  else
51313498266Sopenharmony_ci    result = oldap_map_error(rc, CURLE_USE_SSL_FAILED);
51413498266Sopenharmony_ci  return result;
51513498266Sopenharmony_ci}
51613498266Sopenharmony_ci#endif
51713498266Sopenharmony_ci
51813498266Sopenharmony_cistatic CURLcode oldap_connect(struct Curl_easy *data, bool *done)
51913498266Sopenharmony_ci{
52013498266Sopenharmony_ci  struct connectdata *conn = data->conn;
52113498266Sopenharmony_ci  struct ldapconninfo *li;
52213498266Sopenharmony_ci  static const int version = LDAP_VERSION3;
52313498266Sopenharmony_ci  int rc;
52413498266Sopenharmony_ci  char *hosturl;
52513498266Sopenharmony_ci#ifdef CURL_OPENLDAP_DEBUG
52613498266Sopenharmony_ci  static int do_trace = -1;
52713498266Sopenharmony_ci#endif
52813498266Sopenharmony_ci
52913498266Sopenharmony_ci  (void)done;
53013498266Sopenharmony_ci
53113498266Sopenharmony_ci  DEBUGASSERT(!conn->proto.ldapc);
53213498266Sopenharmony_ci  li = calloc(1, sizeof(struct ldapconninfo));
53313498266Sopenharmony_ci  if(!li)
53413498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
53513498266Sopenharmony_ci  else {
53613498266Sopenharmony_ci    CURLcode result;
53713498266Sopenharmony_ci    li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
53813498266Sopenharmony_ci    conn->proto.ldapc = li;
53913498266Sopenharmony_ci
54013498266Sopenharmony_ci    /* Initialize the SASL storage */
54113498266Sopenharmony_ci    Curl_sasl_init(&li->sasl, data, &saslldap);
54213498266Sopenharmony_ci
54313498266Sopenharmony_ci    /* Clear the TLS upgraded flag */
54413498266Sopenharmony_ci    conn->bits.tls_upgraded = FALSE;
54513498266Sopenharmony_ci
54613498266Sopenharmony_ci    result = oldap_parse_login_options(conn);
54713498266Sopenharmony_ci    if(result)
54813498266Sopenharmony_ci      return result;
54913498266Sopenharmony_ci  }
55013498266Sopenharmony_ci
55113498266Sopenharmony_ci  hosturl = aprintf("ldap%s://%s:%d",
55213498266Sopenharmony_ci                    conn->handler->flags & PROTOPT_SSL? "s": "",
55313498266Sopenharmony_ci                    conn->host.name, conn->remote_port);
55413498266Sopenharmony_ci  if(!hosturl)
55513498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
55613498266Sopenharmony_ci
55713498266Sopenharmony_ci  rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
55813498266Sopenharmony_ci  if(rc) {
55913498266Sopenharmony_ci    failf(data, "LDAP local: Cannot connect to %s, %s",
56013498266Sopenharmony_ci          hosturl, ldap_err2string(rc));
56113498266Sopenharmony_ci    free(hosturl);
56213498266Sopenharmony_ci    return CURLE_COULDNT_CONNECT;
56313498266Sopenharmony_ci  }
56413498266Sopenharmony_ci
56513498266Sopenharmony_ci  free(hosturl);
56613498266Sopenharmony_ci
56713498266Sopenharmony_ci#ifdef CURL_OPENLDAP_DEBUG
56813498266Sopenharmony_ci  if(do_trace < 0) {
56913498266Sopenharmony_ci    const char *env = getenv("CURL_OPENLDAP_TRACE");
57013498266Sopenharmony_ci    do_trace = (env && strtol(env, NULL, 10) > 0);
57113498266Sopenharmony_ci  }
57213498266Sopenharmony_ci  if(do_trace)
57313498266Sopenharmony_ci    ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
57413498266Sopenharmony_ci#endif
57513498266Sopenharmony_ci
57613498266Sopenharmony_ci  /* Try version 3 first. */
57713498266Sopenharmony_ci  ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
57813498266Sopenharmony_ci
57913498266Sopenharmony_ci  /* Do not chase referrals. */
58013498266Sopenharmony_ci  ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
58113498266Sopenharmony_ci
58213498266Sopenharmony_ci#ifdef USE_SSL
58313498266Sopenharmony_ci  if(conn->handler->flags & PROTOPT_SSL)
58413498266Sopenharmony_ci    return oldap_ssl_connect(data, OLDAP_SSL);
58513498266Sopenharmony_ci
58613498266Sopenharmony_ci  if(data->set.use_ssl) {
58713498266Sopenharmony_ci    CURLcode result = oldap_perform_starttls(data);
58813498266Sopenharmony_ci
58913498266Sopenharmony_ci    if(!result || data->set.use_ssl != CURLUSESSL_TRY)
59013498266Sopenharmony_ci      return result;
59113498266Sopenharmony_ci  }
59213498266Sopenharmony_ci#endif
59313498266Sopenharmony_ci
59413498266Sopenharmony_ci  if(li->sasl.prefmech != SASL_AUTH_NONE)
59513498266Sopenharmony_ci    return oldap_perform_mechs(data);
59613498266Sopenharmony_ci
59713498266Sopenharmony_ci  /* Force bind even if anonymous bind is not needed in protocol version 3
59813498266Sopenharmony_ci     to detect missing version 3 support. */
59913498266Sopenharmony_ci  return oldap_perform_bind(data, OLDAP_BIND);
60013498266Sopenharmony_ci}
60113498266Sopenharmony_ci
60213498266Sopenharmony_ci/* Handle the supported SASL mechanisms query response */
60313498266Sopenharmony_cistatic CURLcode oldap_state_mechs_resp(struct Curl_easy *data,
60413498266Sopenharmony_ci                                       LDAPMessage *msg, int code)
60513498266Sopenharmony_ci{
60613498266Sopenharmony_ci  struct connectdata *conn = data->conn;
60713498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
60813498266Sopenharmony_ci  int rc;
60913498266Sopenharmony_ci  BerElement *ber = NULL;
61013498266Sopenharmony_ci  CURLcode result = CURLE_OK;
61113498266Sopenharmony_ci  struct berval bv, *bvals;
61213498266Sopenharmony_ci
61313498266Sopenharmony_ci  switch(ldap_msgtype(msg)) {
61413498266Sopenharmony_ci  case LDAP_RES_SEARCH_ENTRY:
61513498266Sopenharmony_ci    /* Got a list of supported SASL mechanisms. */
61613498266Sopenharmony_ci    if(code != LDAP_SUCCESS && code != LDAP_NO_RESULTS_RETURNED)
61713498266Sopenharmony_ci      return CURLE_LOGIN_DENIED;
61813498266Sopenharmony_ci
61913498266Sopenharmony_ci    rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
62013498266Sopenharmony_ci    if(rc < 0)
62113498266Sopenharmony_ci      return oldap_map_error(rc, CURLE_BAD_CONTENT_ENCODING);
62213498266Sopenharmony_ci    for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
62313498266Sopenharmony_ci        rc == LDAP_SUCCESS;
62413498266Sopenharmony_ci        rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
62513498266Sopenharmony_ci      int i;
62613498266Sopenharmony_ci
62713498266Sopenharmony_ci      if(!bv.bv_val)
62813498266Sopenharmony_ci        break;
62913498266Sopenharmony_ci
63013498266Sopenharmony_ci      if(bvals) {
63113498266Sopenharmony_ci        for(i = 0; bvals[i].bv_val; i++) {
63213498266Sopenharmony_ci          size_t llen;
63313498266Sopenharmony_ci          unsigned short mech = Curl_sasl_decode_mech((char *) bvals[i].bv_val,
63413498266Sopenharmony_ci                                                      bvals[i].bv_len, &llen);
63513498266Sopenharmony_ci          if(bvals[i].bv_len == llen)
63613498266Sopenharmony_ci            li->sasl.authmechs |= mech;
63713498266Sopenharmony_ci        }
63813498266Sopenharmony_ci        ber_memfree(bvals);
63913498266Sopenharmony_ci      }
64013498266Sopenharmony_ci    }
64113498266Sopenharmony_ci    ber_free(ber, 0);
64213498266Sopenharmony_ci    break;
64313498266Sopenharmony_ci
64413498266Sopenharmony_ci  case LDAP_RES_SEARCH_RESULT:
64513498266Sopenharmony_ci    switch(code) {
64613498266Sopenharmony_ci    case LDAP_SIZELIMIT_EXCEEDED:
64713498266Sopenharmony_ci      infof(data, "Too many authentication mechanisms\n");
64813498266Sopenharmony_ci      FALLTHROUGH();
64913498266Sopenharmony_ci    case LDAP_SUCCESS:
65013498266Sopenharmony_ci    case LDAP_NO_RESULTS_RETURNED:
65113498266Sopenharmony_ci      if(Curl_sasl_can_authenticate(&li->sasl, data))
65213498266Sopenharmony_ci        result = oldap_perform_sasl(data);
65313498266Sopenharmony_ci      else
65413498266Sopenharmony_ci        result = CURLE_LOGIN_DENIED;
65513498266Sopenharmony_ci      break;
65613498266Sopenharmony_ci    default:
65713498266Sopenharmony_ci      result = oldap_map_error(code, CURLE_LOGIN_DENIED);
65813498266Sopenharmony_ci      break;
65913498266Sopenharmony_ci    }
66013498266Sopenharmony_ci    break;
66113498266Sopenharmony_ci  default:
66213498266Sopenharmony_ci    break;
66313498266Sopenharmony_ci  }
66413498266Sopenharmony_ci  return result;
66513498266Sopenharmony_ci}
66613498266Sopenharmony_ci
66713498266Sopenharmony_ci/* Handle a SASL bind response. */
66813498266Sopenharmony_cistatic CURLcode oldap_state_sasl_resp(struct Curl_easy *data,
66913498266Sopenharmony_ci                                      LDAPMessage *msg, int code)
67013498266Sopenharmony_ci{
67113498266Sopenharmony_ci  struct connectdata *conn = data->conn;
67213498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
67313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
67413498266Sopenharmony_ci  saslprogress progress;
67513498266Sopenharmony_ci  int rc;
67613498266Sopenharmony_ci
67713498266Sopenharmony_ci  li->servercred = NULL;
67813498266Sopenharmony_ci  rc = ldap_parse_sasl_bind_result(li->ld, msg, &li->servercred, 0);
67913498266Sopenharmony_ci  if(rc != LDAP_SUCCESS) {
68013498266Sopenharmony_ci    failf(data, "LDAP local: sasl ldap_parse_result %s", ldap_err2string(rc));
68113498266Sopenharmony_ci    result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
68213498266Sopenharmony_ci  }
68313498266Sopenharmony_ci  else {
68413498266Sopenharmony_ci    result = Curl_sasl_continue(&li->sasl, data, code, &progress);
68513498266Sopenharmony_ci    if(!result && progress != SASL_INPROGRESS)
68613498266Sopenharmony_ci      oldap_state(data, OLDAP_STOP);
68713498266Sopenharmony_ci  }
68813498266Sopenharmony_ci
68913498266Sopenharmony_ci  if(li->servercred)
69013498266Sopenharmony_ci    ber_bvfree(li->servercred);
69113498266Sopenharmony_ci  return result;
69213498266Sopenharmony_ci}
69313498266Sopenharmony_ci
69413498266Sopenharmony_ci/* Handle a simple bind response. */
69513498266Sopenharmony_cistatic CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg,
69613498266Sopenharmony_ci                                      int code)
69713498266Sopenharmony_ci{
69813498266Sopenharmony_ci  struct connectdata *conn = data->conn;
69913498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
70013498266Sopenharmony_ci  CURLcode result = CURLE_OK;
70113498266Sopenharmony_ci  struct berval *bv = NULL;
70213498266Sopenharmony_ci  int rc;
70313498266Sopenharmony_ci
70413498266Sopenharmony_ci  if(code != LDAP_SUCCESS)
70513498266Sopenharmony_ci    return oldap_map_error(code, CURLE_LDAP_CANNOT_BIND);
70613498266Sopenharmony_ci
70713498266Sopenharmony_ci  rc = ldap_parse_sasl_bind_result(li->ld, msg, &bv, 0);
70813498266Sopenharmony_ci  if(rc != LDAP_SUCCESS) {
70913498266Sopenharmony_ci    failf(data, "LDAP local: bind ldap_parse_sasl_bind_result %s",
71013498266Sopenharmony_ci          ldap_err2string(rc));
71113498266Sopenharmony_ci    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
71213498266Sopenharmony_ci  }
71313498266Sopenharmony_ci  else
71413498266Sopenharmony_ci    oldap_state(data, OLDAP_STOP);
71513498266Sopenharmony_ci
71613498266Sopenharmony_ci  if(bv)
71713498266Sopenharmony_ci    ber_bvfree(bv);
71813498266Sopenharmony_ci  return result;
71913498266Sopenharmony_ci}
72013498266Sopenharmony_ci
72113498266Sopenharmony_cistatic CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
72213498266Sopenharmony_ci{
72313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
72413498266Sopenharmony_ci  struct connectdata *conn = data->conn;
72513498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
72613498266Sopenharmony_ci  LDAPMessage *msg = NULL;
72713498266Sopenharmony_ci  struct timeval tv = {0, 0};
72813498266Sopenharmony_ci  int code = LDAP_SUCCESS;
72913498266Sopenharmony_ci  int rc;
73013498266Sopenharmony_ci
73113498266Sopenharmony_ci  if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) {
73213498266Sopenharmony_ci    /* Get response to last command. */
73313498266Sopenharmony_ci    rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg);
73413498266Sopenharmony_ci    switch(rc) {
73513498266Sopenharmony_ci    case 0:                               /* Timed out. */
73613498266Sopenharmony_ci      return CURLE_OK;
73713498266Sopenharmony_ci    case LDAP_RES_SEARCH_ENTRY:
73813498266Sopenharmony_ci    case LDAP_RES_SEARCH_REFERENCE:
73913498266Sopenharmony_ci      break;
74013498266Sopenharmony_ci    default:
74113498266Sopenharmony_ci      li->msgid = 0;                      /* Nothing to abandon upon error. */
74213498266Sopenharmony_ci      if(rc < 0) {
74313498266Sopenharmony_ci        failf(data, "LDAP local: connecting ldap_result %s",
74413498266Sopenharmony_ci              ldap_err2string(rc));
74513498266Sopenharmony_ci        return oldap_map_error(rc, CURLE_COULDNT_CONNECT);
74613498266Sopenharmony_ci      }
74713498266Sopenharmony_ci      break;
74813498266Sopenharmony_ci    }
74913498266Sopenharmony_ci
75013498266Sopenharmony_ci    /* Get error code from message. */
75113498266Sopenharmony_ci    rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0);
75213498266Sopenharmony_ci    if(rc)
75313498266Sopenharmony_ci      code = rc;
75413498266Sopenharmony_ci    else {
75513498266Sopenharmony_ci      /* store the latest code for later retrieval */
75613498266Sopenharmony_ci      data->info.httpcode = code;
75713498266Sopenharmony_ci    }
75813498266Sopenharmony_ci
75913498266Sopenharmony_ci    /* If protocol version 3 is not supported, fallback to version 2. */
76013498266Sopenharmony_ci    if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 &&
76113498266Sopenharmony_ci#ifdef USE_SSL
76213498266Sopenharmony_ci       (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) &&
76313498266Sopenharmony_ci#endif
76413498266Sopenharmony_ci       li->sasl.prefmech == SASL_AUTH_NONE) {
76513498266Sopenharmony_ci      static const int version = LDAP_VERSION2;
76613498266Sopenharmony_ci
76713498266Sopenharmony_ci      ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
76813498266Sopenharmony_ci      ldap_msgfree(msg);
76913498266Sopenharmony_ci      return oldap_perform_bind(data, OLDAP_BINDV2);
77013498266Sopenharmony_ci    }
77113498266Sopenharmony_ci  }
77213498266Sopenharmony_ci
77313498266Sopenharmony_ci  /* Handle response message according to current state. */
77413498266Sopenharmony_ci  switch(li->state) {
77513498266Sopenharmony_ci
77613498266Sopenharmony_ci#ifdef USE_SSL
77713498266Sopenharmony_ci  case OLDAP_SSL:
77813498266Sopenharmony_ci    result = oldap_ssl_connect(data, OLDAP_SSL);
77913498266Sopenharmony_ci    if(!result && ssl_installed(conn)) {
78013498266Sopenharmony_ci      if(li->sasl.prefmech != SASL_AUTH_NONE)
78113498266Sopenharmony_ci        result = oldap_perform_mechs(data);
78213498266Sopenharmony_ci      else
78313498266Sopenharmony_ci        result = oldap_perform_bind(data, OLDAP_BIND);
78413498266Sopenharmony_ci    }
78513498266Sopenharmony_ci    break;
78613498266Sopenharmony_ci  case OLDAP_STARTTLS:
78713498266Sopenharmony_ci    if(code != LDAP_SUCCESS) {
78813498266Sopenharmony_ci      if(data->set.use_ssl != CURLUSESSL_TRY)
78913498266Sopenharmony_ci        result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
79013498266Sopenharmony_ci      else if(li->sasl.prefmech != SASL_AUTH_NONE)
79113498266Sopenharmony_ci        result = oldap_perform_mechs(data);
79213498266Sopenharmony_ci      else
79313498266Sopenharmony_ci        result = oldap_perform_bind(data, OLDAP_BIND);
79413498266Sopenharmony_ci      break;
79513498266Sopenharmony_ci    }
79613498266Sopenharmony_ci    result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
79713498266Sopenharmony_ci    if(result)
79813498266Sopenharmony_ci      break;
79913498266Sopenharmony_ci    FALLTHROUGH();
80013498266Sopenharmony_ci  case OLDAP_TLS:
80113498266Sopenharmony_ci    result = oldap_ssl_connect(data, OLDAP_TLS);
80213498266Sopenharmony_ci    if(result)
80313498266Sopenharmony_ci      result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
80413498266Sopenharmony_ci    else if(ssl_installed(conn)) {
80513498266Sopenharmony_ci      conn->bits.tls_upgraded = TRUE;
80613498266Sopenharmony_ci      if(li->sasl.prefmech != SASL_AUTH_NONE)
80713498266Sopenharmony_ci        result = oldap_perform_mechs(data);
80813498266Sopenharmony_ci      else if(data->state.aptr.user)
80913498266Sopenharmony_ci        result = oldap_perform_bind(data, OLDAP_BIND);
81013498266Sopenharmony_ci      else {
81113498266Sopenharmony_ci        /* Version 3 supported: no bind required */
81213498266Sopenharmony_ci        oldap_state(data, OLDAP_STOP);
81313498266Sopenharmony_ci        result = CURLE_OK;
81413498266Sopenharmony_ci      }
81513498266Sopenharmony_ci    }
81613498266Sopenharmony_ci    break;
81713498266Sopenharmony_ci#endif
81813498266Sopenharmony_ci
81913498266Sopenharmony_ci  case OLDAP_MECHS:
82013498266Sopenharmony_ci    result = oldap_state_mechs_resp(data, msg, code);
82113498266Sopenharmony_ci    break;
82213498266Sopenharmony_ci  case OLDAP_SASL:
82313498266Sopenharmony_ci    result = oldap_state_sasl_resp(data, msg, code);
82413498266Sopenharmony_ci    break;
82513498266Sopenharmony_ci  case OLDAP_BIND:
82613498266Sopenharmony_ci  case OLDAP_BINDV2:
82713498266Sopenharmony_ci    result = oldap_state_bind_resp(data, msg, code);
82813498266Sopenharmony_ci    break;
82913498266Sopenharmony_ci  default:
83013498266Sopenharmony_ci    /* internal error */
83113498266Sopenharmony_ci    result = CURLE_COULDNT_CONNECT;
83213498266Sopenharmony_ci    break;
83313498266Sopenharmony_ci  }
83413498266Sopenharmony_ci
83513498266Sopenharmony_ci  ldap_msgfree(msg);
83613498266Sopenharmony_ci
83713498266Sopenharmony_ci  *done = li->state == OLDAP_STOP;
83813498266Sopenharmony_ci  if(*done)
83913498266Sopenharmony_ci    conn->recv[FIRSTSOCKET] = oldap_recv;
84013498266Sopenharmony_ci
84113498266Sopenharmony_ci  if(result && li->msgid) {
84213498266Sopenharmony_ci    ldap_abandon_ext(li->ld, li->msgid, NULL, NULL);
84313498266Sopenharmony_ci    li->msgid = 0;
84413498266Sopenharmony_ci  }
84513498266Sopenharmony_ci  return result;
84613498266Sopenharmony_ci}
84713498266Sopenharmony_ci
84813498266Sopenharmony_cistatic CURLcode oldap_disconnect(struct Curl_easy *data,
84913498266Sopenharmony_ci                                 struct connectdata *conn,
85013498266Sopenharmony_ci                                 bool dead_connection)
85113498266Sopenharmony_ci{
85213498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
85313498266Sopenharmony_ci  (void) dead_connection;
85413498266Sopenharmony_ci#ifndef USE_SSL
85513498266Sopenharmony_ci  (void)data;
85613498266Sopenharmony_ci#endif
85713498266Sopenharmony_ci
85813498266Sopenharmony_ci  if(li) {
85913498266Sopenharmony_ci    if(li->ld) {
86013498266Sopenharmony_ci#ifdef USE_SSL
86113498266Sopenharmony_ci      if(ssl_installed(conn)) {
86213498266Sopenharmony_ci        Sockbuf *sb;
86313498266Sopenharmony_ci        ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
86413498266Sopenharmony_ci        ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
86513498266Sopenharmony_ci      }
86613498266Sopenharmony_ci#endif
86713498266Sopenharmony_ci      ldap_unbind_ext(li->ld, NULL, NULL);
86813498266Sopenharmony_ci      li->ld = NULL;
86913498266Sopenharmony_ci    }
87013498266Sopenharmony_ci    Curl_sasl_cleanup(conn, li->sasl.authused);
87113498266Sopenharmony_ci    conn->proto.ldapc = NULL;
87213498266Sopenharmony_ci    free(li);
87313498266Sopenharmony_ci  }
87413498266Sopenharmony_ci  return CURLE_OK;
87513498266Sopenharmony_ci}
87613498266Sopenharmony_ci
87713498266Sopenharmony_cistatic CURLcode oldap_do(struct Curl_easy *data, bool *done)
87813498266Sopenharmony_ci{
87913498266Sopenharmony_ci  struct connectdata *conn = data->conn;
88013498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
88113498266Sopenharmony_ci  struct ldapreqinfo *lr;
88213498266Sopenharmony_ci  CURLcode result;
88313498266Sopenharmony_ci  int rc;
88413498266Sopenharmony_ci  LDAPURLDesc *lud;
88513498266Sopenharmony_ci  int msgid;
88613498266Sopenharmony_ci
88713498266Sopenharmony_ci  connkeep(conn, "OpenLDAP do");
88813498266Sopenharmony_ci
88913498266Sopenharmony_ci  infof(data, "LDAP local: %s", data->state.url);
89013498266Sopenharmony_ci
89113498266Sopenharmony_ci  result = oldap_url_parse(data, &lud);
89213498266Sopenharmony_ci  if(!result) {
89313498266Sopenharmony_ci#ifdef USE_SSL
89413498266Sopenharmony_ci    if(ssl_installed(conn)) {
89513498266Sopenharmony_ci      Sockbuf *sb;
89613498266Sopenharmony_ci      /* re-install the libcurl SSL handlers into the sockbuf. */
89713498266Sopenharmony_ci      ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
89813498266Sopenharmony_ci      ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
89913498266Sopenharmony_ci    }
90013498266Sopenharmony_ci#endif
90113498266Sopenharmony_ci
90213498266Sopenharmony_ci    rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
90313498266Sopenharmony_ci                         lud->lud_filter, lud->lud_attrs, 0,
90413498266Sopenharmony_ci                         NULL, NULL, NULL, 0, &msgid);
90513498266Sopenharmony_ci    ldap_free_urldesc(lud);
90613498266Sopenharmony_ci    if(rc != LDAP_SUCCESS) {
90713498266Sopenharmony_ci      failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
90813498266Sopenharmony_ci      result = CURLE_LDAP_SEARCH_FAILED;
90913498266Sopenharmony_ci    }
91013498266Sopenharmony_ci    else {
91113498266Sopenharmony_ci      lr = calloc(1, sizeof(struct ldapreqinfo));
91213498266Sopenharmony_ci      if(!lr) {
91313498266Sopenharmony_ci        ldap_abandon_ext(li->ld, msgid, NULL, NULL);
91413498266Sopenharmony_ci        result = CURLE_OUT_OF_MEMORY;
91513498266Sopenharmony_ci      }
91613498266Sopenharmony_ci      else {
91713498266Sopenharmony_ci        lr->msgid = msgid;
91813498266Sopenharmony_ci        data->req.p.ldap = lr;
91913498266Sopenharmony_ci        Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
92013498266Sopenharmony_ci        *done = TRUE;
92113498266Sopenharmony_ci      }
92213498266Sopenharmony_ci    }
92313498266Sopenharmony_ci  }
92413498266Sopenharmony_ci  return result;
92513498266Sopenharmony_ci}
92613498266Sopenharmony_ci
92713498266Sopenharmony_cistatic CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
92813498266Sopenharmony_ci                           bool premature)
92913498266Sopenharmony_ci{
93013498266Sopenharmony_ci  struct connectdata *conn = data->conn;
93113498266Sopenharmony_ci  struct ldapreqinfo *lr = data->req.p.ldap;
93213498266Sopenharmony_ci
93313498266Sopenharmony_ci  (void)res;
93413498266Sopenharmony_ci  (void)premature;
93513498266Sopenharmony_ci
93613498266Sopenharmony_ci  if(lr) {
93713498266Sopenharmony_ci    /* if there was a search in progress, abandon it */
93813498266Sopenharmony_ci    if(lr->msgid) {
93913498266Sopenharmony_ci      struct ldapconninfo *li = conn->proto.ldapc;
94013498266Sopenharmony_ci      ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
94113498266Sopenharmony_ci      lr->msgid = 0;
94213498266Sopenharmony_ci    }
94313498266Sopenharmony_ci    data->req.p.ldap = NULL;
94413498266Sopenharmony_ci    free(lr);
94513498266Sopenharmony_ci  }
94613498266Sopenharmony_ci
94713498266Sopenharmony_ci  return CURLE_OK;
94813498266Sopenharmony_ci}
94913498266Sopenharmony_ci
95013498266Sopenharmony_cistatic CURLcode client_write(struct Curl_easy *data,
95113498266Sopenharmony_ci                             const char *prefix, size_t plen,
95213498266Sopenharmony_ci                             const char *value, size_t len,
95313498266Sopenharmony_ci                             const char *suffix, size_t slen)
95413498266Sopenharmony_ci{
95513498266Sopenharmony_ci  CURLcode result = CURLE_OK;
95613498266Sopenharmony_ci
95713498266Sopenharmony_ci  if(prefix) {
95813498266Sopenharmony_ci    /* If we have a zero-length value and the prefix ends with a space
95913498266Sopenharmony_ci       separator, drop the latter. */
96013498266Sopenharmony_ci    if(!len && plen && prefix[plen - 1] == ' ')
96113498266Sopenharmony_ci      plen--;
96213498266Sopenharmony_ci    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, plen);
96313498266Sopenharmony_ci  }
96413498266Sopenharmony_ci  if(!result && value) {
96513498266Sopenharmony_ci    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len);
96613498266Sopenharmony_ci  }
96713498266Sopenharmony_ci  if(!result && suffix) {
96813498266Sopenharmony_ci    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, slen);
96913498266Sopenharmony_ci  }
97013498266Sopenharmony_ci  return result;
97113498266Sopenharmony_ci}
97213498266Sopenharmony_ci
97313498266Sopenharmony_cistatic ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
97413498266Sopenharmony_ci                          size_t len, CURLcode *err)
97513498266Sopenharmony_ci{
97613498266Sopenharmony_ci  struct connectdata *conn = data->conn;
97713498266Sopenharmony_ci  struct ldapconninfo *li = conn->proto.ldapc;
97813498266Sopenharmony_ci  struct ldapreqinfo *lr = data->req.p.ldap;
97913498266Sopenharmony_ci  int rc;
98013498266Sopenharmony_ci  LDAPMessage *msg = NULL;
98113498266Sopenharmony_ci  BerElement *ber = NULL;
98213498266Sopenharmony_ci  struct timeval tv = {0, 0};
98313498266Sopenharmony_ci  struct berval bv, *bvals;
98413498266Sopenharmony_ci  int binary = 0;
98513498266Sopenharmony_ci  CURLcode result = CURLE_AGAIN;
98613498266Sopenharmony_ci  int code;
98713498266Sopenharmony_ci  char *info = NULL;
98813498266Sopenharmony_ci
98913498266Sopenharmony_ci  (void)len;
99013498266Sopenharmony_ci  (void)buf;
99113498266Sopenharmony_ci  (void)sockindex;
99213498266Sopenharmony_ci
99313498266Sopenharmony_ci  rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg);
99413498266Sopenharmony_ci  if(rc < 0) {
99513498266Sopenharmony_ci    failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
99613498266Sopenharmony_ci    result = CURLE_RECV_ERROR;
99713498266Sopenharmony_ci  }
99813498266Sopenharmony_ci
99913498266Sopenharmony_ci  *err = result;
100013498266Sopenharmony_ci
100113498266Sopenharmony_ci  /* error or timed out */
100213498266Sopenharmony_ci  if(!msg)
100313498266Sopenharmony_ci    return -1;
100413498266Sopenharmony_ci
100513498266Sopenharmony_ci  result = CURLE_OK;
100613498266Sopenharmony_ci
100713498266Sopenharmony_ci  switch(ldap_msgtype(msg)) {
100813498266Sopenharmony_ci  case LDAP_RES_SEARCH_RESULT:
100913498266Sopenharmony_ci    lr->msgid = 0;
101013498266Sopenharmony_ci    rc = ldap_parse_result(li->ld, msg, &code, NULL, &info, NULL, NULL, 0);
101113498266Sopenharmony_ci    if(rc) {
101213498266Sopenharmony_ci      failf(data, "LDAP local: search ldap_parse_result %s",
101313498266Sopenharmony_ci            ldap_err2string(rc));
101413498266Sopenharmony_ci      result = CURLE_LDAP_SEARCH_FAILED;
101513498266Sopenharmony_ci      break;
101613498266Sopenharmony_ci    }
101713498266Sopenharmony_ci
101813498266Sopenharmony_ci    /* store the latest code for later retrieval */
101913498266Sopenharmony_ci    data->info.httpcode = code;
102013498266Sopenharmony_ci
102113498266Sopenharmony_ci    switch(code) {
102213498266Sopenharmony_ci    case LDAP_SIZELIMIT_EXCEEDED:
102313498266Sopenharmony_ci      infof(data, "There are more than %d entries", lr->nument);
102413498266Sopenharmony_ci      FALLTHROUGH();
102513498266Sopenharmony_ci    case LDAP_SUCCESS:
102613498266Sopenharmony_ci      data->req.size = data->req.bytecount;
102713498266Sopenharmony_ci      break;
102813498266Sopenharmony_ci    default:
102913498266Sopenharmony_ci      failf(data, "LDAP remote: search failed %s %s", ldap_err2string(code),
103013498266Sopenharmony_ci            info ? info : "");
103113498266Sopenharmony_ci      result = CURLE_LDAP_SEARCH_FAILED;
103213498266Sopenharmony_ci      break;
103313498266Sopenharmony_ci    }
103413498266Sopenharmony_ci    if(info)
103513498266Sopenharmony_ci      ldap_memfree(info);
103613498266Sopenharmony_ci    break;
103713498266Sopenharmony_ci  case LDAP_RES_SEARCH_ENTRY:
103813498266Sopenharmony_ci    lr->nument++;
103913498266Sopenharmony_ci    rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
104013498266Sopenharmony_ci    if(rc < 0) {
104113498266Sopenharmony_ci      result = CURLE_RECV_ERROR;
104213498266Sopenharmony_ci      break;
104313498266Sopenharmony_ci    }
104413498266Sopenharmony_ci
104513498266Sopenharmony_ci    result = client_write(data, STRCONST("DN: "), bv.bv_val, bv.bv_len,
104613498266Sopenharmony_ci                          STRCONST("\n"));
104713498266Sopenharmony_ci    if(result)
104813498266Sopenharmony_ci      break;
104913498266Sopenharmony_ci
105013498266Sopenharmony_ci    for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
105113498266Sopenharmony_ci        rc == LDAP_SUCCESS;
105213498266Sopenharmony_ci        rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
105313498266Sopenharmony_ci      int i;
105413498266Sopenharmony_ci
105513498266Sopenharmony_ci      if(!bv.bv_val)
105613498266Sopenharmony_ci        break;
105713498266Sopenharmony_ci
105813498266Sopenharmony_ci      if(!bvals) {
105913498266Sopenharmony_ci        result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
106013498266Sopenharmony_ci                              STRCONST(":\n"));
106113498266Sopenharmony_ci        if(result)
106213498266Sopenharmony_ci          break;
106313498266Sopenharmony_ci        continue;
106413498266Sopenharmony_ci      }
106513498266Sopenharmony_ci
106613498266Sopenharmony_ci      binary = bv.bv_len > 7 &&
106713498266Sopenharmony_ci               !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7);
106813498266Sopenharmony_ci
106913498266Sopenharmony_ci      for(i = 0; bvals[i].bv_val != NULL; i++) {
107013498266Sopenharmony_ci        int binval = 0;
107113498266Sopenharmony_ci
107213498266Sopenharmony_ci        result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
107313498266Sopenharmony_ci                              STRCONST(":"));
107413498266Sopenharmony_ci        if(result)
107513498266Sopenharmony_ci          break;
107613498266Sopenharmony_ci
107713498266Sopenharmony_ci        if(!binary) {
107813498266Sopenharmony_ci          /* check for leading or trailing whitespace */
107913498266Sopenharmony_ci          if(ISBLANK(bvals[i].bv_val[0]) ||
108013498266Sopenharmony_ci             ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))
108113498266Sopenharmony_ci            binval = 1;
108213498266Sopenharmony_ci          else {
108313498266Sopenharmony_ci            /* check for unprintable characters */
108413498266Sopenharmony_ci            unsigned int j;
108513498266Sopenharmony_ci            for(j = 0; j < bvals[i].bv_len; j++)
108613498266Sopenharmony_ci              if(!ISPRINT(bvals[i].bv_val[j])) {
108713498266Sopenharmony_ci                binval = 1;
108813498266Sopenharmony_ci                break;
108913498266Sopenharmony_ci              }
109013498266Sopenharmony_ci          }
109113498266Sopenharmony_ci        }
109213498266Sopenharmony_ci        if(binary || binval) {
109313498266Sopenharmony_ci          char *val_b64 = NULL;
109413498266Sopenharmony_ci          size_t val_b64_sz = 0;
109513498266Sopenharmony_ci
109613498266Sopenharmony_ci          /* Binary value, encode to base64. */
109713498266Sopenharmony_ci          if(bvals[i].bv_len)
109813498266Sopenharmony_ci            result = Curl_base64_encode(bvals[i].bv_val, bvals[i].bv_len,
109913498266Sopenharmony_ci                                        &val_b64, &val_b64_sz);
110013498266Sopenharmony_ci          if(!result)
110113498266Sopenharmony_ci            result = client_write(data, STRCONST(": "), val_b64, val_b64_sz,
110213498266Sopenharmony_ci                                  STRCONST("\n"));
110313498266Sopenharmony_ci          free(val_b64);
110413498266Sopenharmony_ci        }
110513498266Sopenharmony_ci        else
110613498266Sopenharmony_ci          result = client_write(data, STRCONST(" "),
110713498266Sopenharmony_ci                                bvals[i].bv_val, bvals[i].bv_len,
110813498266Sopenharmony_ci                                STRCONST("\n"));
110913498266Sopenharmony_ci        if(result)
111013498266Sopenharmony_ci          break;
111113498266Sopenharmony_ci      }
111213498266Sopenharmony_ci
111313498266Sopenharmony_ci      ber_memfree(bvals);
111413498266Sopenharmony_ci      bvals = NULL;
111513498266Sopenharmony_ci      if(!result)
111613498266Sopenharmony_ci        result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
111713498266Sopenharmony_ci      if(result)
111813498266Sopenharmony_ci        break;
111913498266Sopenharmony_ci    }
112013498266Sopenharmony_ci
112113498266Sopenharmony_ci    ber_free(ber, 0);
112213498266Sopenharmony_ci
112313498266Sopenharmony_ci    if(!result)
112413498266Sopenharmony_ci      result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
112513498266Sopenharmony_ci    if(!result)
112613498266Sopenharmony_ci      result = CURLE_AGAIN;
112713498266Sopenharmony_ci    break;
112813498266Sopenharmony_ci  }
112913498266Sopenharmony_ci
113013498266Sopenharmony_ci  ldap_msgfree(msg);
113113498266Sopenharmony_ci  *err = result;
113213498266Sopenharmony_ci  return result? -1: 0;
113313498266Sopenharmony_ci}
113413498266Sopenharmony_ci
113513498266Sopenharmony_ci#ifdef USE_SSL
113613498266Sopenharmony_cistatic int
113713498266Sopenharmony_cildapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
113813498266Sopenharmony_ci{
113913498266Sopenharmony_ci  sbiod->sbiod_pvt = arg;
114013498266Sopenharmony_ci  return 0;
114113498266Sopenharmony_ci}
114213498266Sopenharmony_ci
114313498266Sopenharmony_cistatic int
114413498266Sopenharmony_cildapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
114513498266Sopenharmony_ci{
114613498266Sopenharmony_ci  sbiod->sbiod_pvt = NULL;
114713498266Sopenharmony_ci  return 0;
114813498266Sopenharmony_ci}
114913498266Sopenharmony_ci
115013498266Sopenharmony_ci/* We don't need to do anything because libcurl does it already */
115113498266Sopenharmony_cistatic int
115213498266Sopenharmony_cildapsb_tls_close(Sockbuf_IO_Desc *sbiod)
115313498266Sopenharmony_ci{
115413498266Sopenharmony_ci  (void)sbiod;
115513498266Sopenharmony_ci  return 0;
115613498266Sopenharmony_ci}
115713498266Sopenharmony_ci
115813498266Sopenharmony_cistatic int
115913498266Sopenharmony_cildapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
116013498266Sopenharmony_ci{
116113498266Sopenharmony_ci  (void)arg;
116213498266Sopenharmony_ci  if(opt == LBER_SB_OPT_DATA_READY) {
116313498266Sopenharmony_ci    struct Curl_easy *data = sbiod->sbiod_pvt;
116413498266Sopenharmony_ci    return Curl_conn_data_pending(data, FIRSTSOCKET);
116513498266Sopenharmony_ci  }
116613498266Sopenharmony_ci  return 0;
116713498266Sopenharmony_ci}
116813498266Sopenharmony_ci
116913498266Sopenharmony_cistatic ber_slen_t
117013498266Sopenharmony_cildapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
117113498266Sopenharmony_ci{
117213498266Sopenharmony_ci  struct Curl_easy *data = sbiod->sbiod_pvt;
117313498266Sopenharmony_ci  ber_slen_t ret = 0;
117413498266Sopenharmony_ci  if(data) {
117513498266Sopenharmony_ci    struct connectdata *conn = data->conn;
117613498266Sopenharmony_ci    if(conn) {
117713498266Sopenharmony_ci      struct ldapconninfo *li = conn->proto.ldapc;
117813498266Sopenharmony_ci      CURLcode err = CURLE_RECV_ERROR;
117913498266Sopenharmony_ci
118013498266Sopenharmony_ci      ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err);
118113498266Sopenharmony_ci      if(ret < 0 && err == CURLE_AGAIN) {
118213498266Sopenharmony_ci        SET_SOCKERRNO(EWOULDBLOCK);
118313498266Sopenharmony_ci      }
118413498266Sopenharmony_ci    }
118513498266Sopenharmony_ci  }
118613498266Sopenharmony_ci  return ret;
118713498266Sopenharmony_ci}
118813498266Sopenharmony_ci
118913498266Sopenharmony_cistatic ber_slen_t
119013498266Sopenharmony_cildapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
119113498266Sopenharmony_ci{
119213498266Sopenharmony_ci  struct Curl_easy *data = sbiod->sbiod_pvt;
119313498266Sopenharmony_ci  ber_slen_t ret = 0;
119413498266Sopenharmony_ci  if(data) {
119513498266Sopenharmony_ci    struct connectdata *conn = data->conn;
119613498266Sopenharmony_ci    if(conn) {
119713498266Sopenharmony_ci      struct ldapconninfo *li = conn->proto.ldapc;
119813498266Sopenharmony_ci      CURLcode err = CURLE_SEND_ERROR;
119913498266Sopenharmony_ci      ret = (li->send)(data, FIRSTSOCKET, buf, len, &err);
120013498266Sopenharmony_ci      if(ret < 0 && err == CURLE_AGAIN) {
120113498266Sopenharmony_ci        SET_SOCKERRNO(EWOULDBLOCK);
120213498266Sopenharmony_ci      }
120313498266Sopenharmony_ci    }
120413498266Sopenharmony_ci  }
120513498266Sopenharmony_ci  return ret;
120613498266Sopenharmony_ci}
120713498266Sopenharmony_ci
120813498266Sopenharmony_cistatic Sockbuf_IO ldapsb_tls =
120913498266Sopenharmony_ci{
121013498266Sopenharmony_ci  ldapsb_tls_setup,
121113498266Sopenharmony_ci  ldapsb_tls_remove,
121213498266Sopenharmony_ci  ldapsb_tls_ctrl,
121313498266Sopenharmony_ci  ldapsb_tls_read,
121413498266Sopenharmony_ci  ldapsb_tls_write,
121513498266Sopenharmony_ci  ldapsb_tls_close
121613498266Sopenharmony_ci};
121713498266Sopenharmony_ci#endif /* USE_SSL */
121813498266Sopenharmony_ci
121913498266Sopenharmony_ci#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */
1220