quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

openldap.c (37746B)


      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_getsock */
    130   ZERO_NULL,                            /* doing_getsock */
    131   ZERO_NULL,                            /* domore_getsock */
    132   ZERO_NULL,                            /* perform_getsock */
    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_getsock */
    160   ZERO_NULL,                            /* doing_getsock */
    161   ZERO_NULL,                            /* domore_getsock */
    162   ZERO_NULL,                            /* perform_getsock */
    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 #define CURL_META_LDAP_EASY   "meta:proto:ldap:easy"
    208 /* meta key for storing ldapconninfo at connection */
    209 #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 {
    220 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
    221   /* for debug purposes */
    222   static const char * const names[] = {
    223     "STOP",
    224     "SSL",
    225     "STARTTLS",
    226     "TLS",
    227     "MECHS",
    228     "SASL",
    229     "BIND",
    230     "BINDV2",
    231     /* LAST */
    232   };
    233 
    234   if(li->state != newstate)
    235     infof(data, "LDAP %p state change from %s to %s",
    236           (void *)li, names[li->state], names[newstate]);
    237 #endif
    238   (void)data;
    239   li->state = newstate;
    240 }
    241 
    242 /* Map some particular LDAP error codes to CURLcode values. */
    243 static CURLcode oldap_map_error(int rc, CURLcode result)
    244 {
    245   switch(rc) {
    246   case LDAP_NO_MEMORY:
    247     return CURLE_OUT_OF_MEMORY;
    248   case LDAP_INVALID_CREDENTIALS:
    249     return CURLE_LOGIN_DENIED;
    250   case LDAP_PROTOCOL_ERROR:
    251     return CURLE_UNSUPPORTED_PROTOCOL;
    252   case LDAP_INSUFFICIENT_ACCESS:
    253     return CURLE_REMOTE_ACCESS_DENIED;
    254   }
    255   return result;
    256 }
    257 
    258 static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
    259 {
    260   CURLcode result = CURLE_OK;
    261   int rc = LDAP_URL_ERR_BADURL;
    262   static const char * const url_errs[] = {
    263     "success",
    264     "out of memory",
    265     "bad parameter",
    266     "unrecognized scheme",
    267     "unbalanced delimiter",
    268     "bad URL",
    269     "bad host or port",
    270     "bad or missing attributes",
    271     "bad or missing scope",
    272     "bad or missing filter",
    273     "bad or missing extensions"
    274   };
    275 
    276   *ludp = NULL;
    277   if(!data->state.up.user && !data->state.up.password &&
    278      !data->state.up.options)
    279     rc = ldap_url_parse(data->state.url, ludp);
    280   if(rc != LDAP_URL_SUCCESS) {
    281     const char *msg = "url parsing problem";
    282 
    283     result = rc == LDAP_URL_ERR_MEM ? CURLE_OUT_OF_MEMORY :
    284       CURLE_URL_MALFORMAT;
    285     rc -= LDAP_URL_SUCCESS;
    286     if((size_t) rc < CURL_ARRAYSIZE(url_errs))
    287       msg = url_errs[rc];
    288     failf(data, "LDAP local: %s", msg);
    289   }
    290   return result;
    291 }
    292 
    293 /* Parse the login options. */
    294 static CURLcode oldap_parse_login_options(struct connectdata *conn)
    295 {
    296   CURLcode result = CURLE_OK;
    297   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    298   const char *ptr = conn->options;
    299 
    300   DEBUGASSERT(li);
    301   if(!li)
    302     return CURLE_FAILED_INIT;
    303 
    304   while(!result && ptr && *ptr) {
    305     const char *key = ptr;
    306     const char *value;
    307 
    308     while(*ptr && *ptr != '=')
    309       ptr++;
    310 
    311     value = ptr + 1;
    312 
    313     while(*ptr && *ptr != ';')
    314       ptr++;
    315 
    316     if(checkprefix("AUTH=", key))
    317       result = Curl_sasl_parse_url_auth_option(&li->sasl, value, ptr - value);
    318     else
    319       result = CURLE_SETOPT_OPTION_SYNTAX;
    320 
    321     if(*ptr == ';')
    322       ptr++;
    323   }
    324 
    325   return result == CURLE_URL_MALFORMAT ? CURLE_SETOPT_OPTION_SYNTAX : result;
    326 }
    327 
    328 static CURLcode oldap_setup_connection(struct Curl_easy *data,
    329                                        struct connectdata *conn)
    330 {
    331   CURLcode result;
    332   LDAPURLDesc *lud;
    333   (void)conn;
    334 
    335   /* Early URL syntax check. */
    336   result = oldap_url_parse(data, &lud);
    337   ldap_free_urldesc(lud);
    338 
    339   return result;
    340 }
    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 {
    347   struct ldapconninfo *li =
    348     Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
    349   struct berval *servercred = li ? li->servercred : NULL;
    350   DEBUGASSERT(li);
    351   if(!li)
    352     return CURLE_FAILED_INIT;
    353 
    354   if(!servercred || !servercred->bv_val)
    355     return CURLE_WEIRD_SERVER_REPLY;
    356   Curl_bufref_set(out, servercred->bv_val, servercred->bv_len, NULL);
    357   return CURLE_OK;
    358 }
    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 {
    366   struct connectdata *conn = data->conn;
    367   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    368   struct berval cred;
    369   struct berval *pcred = &cred;
    370   int rc;
    371 
    372   DEBUGASSERT(li);
    373   if(!li)
    374     return CURLE_FAILED_INIT;
    375   cred.bv_val = (char *)CURL_UNCONST(Curl_bufref_ptr(initresp));
    376   cred.bv_len = Curl_bufref_len(initresp);
    377   if(!cred.bv_val)
    378     pcred = NULL;
    379   rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
    380   if(rc != LDAP_SUCCESS)
    381     return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
    382   return CURLE_OK;
    383 }
    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 {
    391   struct connectdata *conn = data->conn;
    392   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    393   struct berval cred;
    394   struct berval *pcred = &cred;
    395   int rc;
    396 
    397   if(!li)
    398     return CURLE_FAILED_INIT;
    399   cred.bv_val = (char *)CURL_UNCONST(Curl_bufref_ptr(resp));
    400   cred.bv_len = Curl_bufref_len(resp);
    401   if(!cred.bv_val)
    402     pcred = NULL;
    403   rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
    404   if(rc != LDAP_SUCCESS)
    405     return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
    406   return CURLE_OK;
    407 }
    408 
    409 /*
    410  * Sends SASL bind cancellation.
    411  */
    412 static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech)
    413 {
    414   struct ldapconninfo *li =
    415     Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
    416   int rc;
    417 
    418   (void)mech;
    419   if(!li)
    420     return CURLE_FAILED_INIT;
    421   rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL,
    422                       &li->msgid);
    423   if(rc != LDAP_SUCCESS)
    424     return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
    425   return CURLE_OK;
    426 }
    427 
    428 /* Starts LDAP simple bind. */
    429 static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
    430 {
    431   struct connectdata *conn = data->conn;
    432   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    433   char *binddn = NULL;
    434   struct berval passwd;
    435   int rc;
    436 
    437   if(!li)
    438     return CURLE_FAILED_INIT;
    439   passwd.bv_val = NULL;
    440   passwd.bv_len = 0;
    441 
    442   if(data->state.aptr.user) {
    443     binddn = conn->user;
    444     passwd.bv_val = conn->passwd;
    445     passwd.bv_len = strlen(passwd.bv_val);
    446   }
    447 
    448   rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
    449                       NULL, NULL, &li->msgid);
    450   if(rc != LDAP_SUCCESS)
    451     return oldap_map_error(rc,
    452                            data->state.aptr.user ?
    453                            CURLE_LOGIN_DENIED : CURLE_LDAP_CANNOT_BIND);
    454   oldap_state(data, li, newstate);
    455   return CURLE_OK;
    456 }
    457 
    458 /* Query the supported SASL authentication mechanisms. */
    459 static CURLcode oldap_perform_mechs(struct Curl_easy *data)
    460 {
    461   struct ldapconninfo *li =
    462     Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
    463   int rc;
    464   static const char * const supportedSASLMechanisms[] = {
    465     "supportedSASLMechanisms",
    466     NULL
    467   };
    468 
    469   if(!li)
    470     return CURLE_FAILED_INIT;
    471   rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
    472                        (char **)CURL_UNCONST(supportedSASLMechanisms), 0,
    473                        NULL, NULL, NULL, 0, &li->msgid);
    474   if(rc != LDAP_SUCCESS)
    475     return oldap_map_error(rc, CURLE_LOGIN_DENIED);
    476   oldap_state(data, li, OLDAP_MECHS);
    477   return CURLE_OK;
    478 }
    479 
    480 /* Starts SASL bind. */
    481 static CURLcode oldap_perform_sasl(struct Curl_easy *data)
    482 {
    483   struct ldapconninfo *li =
    484     Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
    485   saslprogress progress = SASL_IDLE;
    486   CURLcode result;
    487 
    488   if(!li)
    489     return CURLE_FAILED_INIT;
    490   result = Curl_sasl_start(&li->sasl, data, TRUE, &progress);
    491 
    492   oldap_state(data, li, OLDAP_SASL);
    493   if(!result && progress != SASL_INPROGRESS)
    494     result = Curl_sasl_is_blocked(&li->sasl, data);
    495   return result;
    496 }
    497 
    498 #ifdef USE_SSL
    499 static Sockbuf_IO ldapsb_tls;
    500 
    501 static bool ssl_installed(struct connectdata *conn)
    502 {
    503   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    504   return li && li->recv != NULL;
    505 }
    506 
    507 static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
    508 {
    509   struct connectdata *conn = data->conn;
    510   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    511   bool ssldone = FALSE;
    512   CURLcode result;
    513 
    514   if(!li)
    515     return CURLE_FAILED_INIT;
    516   result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
    517   if(!result) {
    518     oldap_state(data, li, newstate);
    519 
    520     if(ssldone) {
    521       Sockbuf *sb;
    522 
    523       /* Install the libcurl SSL handlers into the sockbuf. */
    524       ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
    525       ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
    526       li->recv = conn->recv[FIRSTSOCKET];
    527       li->send = conn->send[FIRSTSOCKET];
    528     }
    529   }
    530 
    531   return result;
    532 }
    533 
    534 /* Send the STARTTLS request */
    535 static CURLcode oldap_perform_starttls(struct Curl_easy *data)
    536 {
    537   struct ldapconninfo *li =
    538     Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
    539   int rc;
    540 
    541   if(!li)
    542     return CURLE_FAILED_INIT;
    543   rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid);
    544   if(rc != LDAP_SUCCESS)
    545     return oldap_map_error(rc, CURLE_USE_SSL_FAILED);
    546   oldap_state(data, li, OLDAP_STARTTLS);
    547   return CURLE_OK;
    548 }
    549 #endif
    550 
    551 static void oldap_easy_dtor(void *key, size_t klen, void *entry)
    552 {
    553   struct ldapreqinfo *lr = entry;
    554   (void)key;
    555   (void)klen;
    556   free(lr);
    557 }
    558 
    559 static void oldap_conn_dtor(void *key, size_t klen, void *entry)
    560 {
    561   struct ldapconninfo *li = entry;
    562   (void)key;
    563   (void)klen;
    564   if(li->ld) {
    565     ldap_unbind_ext(li->ld, NULL, NULL);
    566     li->ld = NULL;
    567   }
    568   free(li);
    569 }
    570 
    571 static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
    572 {
    573   struct connectdata *conn = data->conn;
    574   struct ldapconninfo *li;
    575   static const int version = LDAP_VERSION3;
    576   char *hosturl = NULL;
    577   CURLcode result;
    578   int rc;
    579 #ifdef CURL_OPENLDAP_DEBUG
    580   static int do_trace = -1;
    581 #endif
    582 
    583   (void)done;
    584 
    585   li = calloc(1, sizeof(struct ldapconninfo));
    586   if(!li) {
    587     result = CURLE_OUT_OF_MEMORY;
    588     goto out;
    589   }
    590 
    591   result = Curl_conn_meta_set(conn, CURL_META_LDAP_CONN, li, oldap_conn_dtor);
    592   if(result)
    593     goto out;
    594 
    595   li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
    596 
    597   /* Initialize the SASL storage */
    598   Curl_sasl_init(&li->sasl, data, &saslldap);
    599 
    600   result = oldap_parse_login_options(conn);
    601   if(result)
    602     goto out;
    603 
    604   hosturl = aprintf("%s://%s%s%s:%d",
    605                     conn->handler->scheme,
    606                     conn->bits.ipv6_ip ? "[" : "",
    607                     conn->host.name,
    608                     conn->bits.ipv6_ip ? "]" : "",
    609                     conn->remote_port);
    610   if(!hosturl) {
    611     result = CURLE_OUT_OF_MEMORY;
    612     goto out;
    613   }
    614 
    615   rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
    616   if(rc) {
    617     failf(data, "LDAP local: Cannot connect to %s, %s",
    618           hosturl, ldap_err2string(rc));
    619     result = CURLE_COULDNT_CONNECT;
    620     goto out;
    621   }
    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   ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
    636 
    637   /* Do not chase referrals. */
    638   ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
    639 
    640 #ifdef USE_SSL
    641   if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
    642     result = oldap_ssl_connect(data, OLDAP_SSL);
    643     goto out;
    644   }
    645 
    646   if(data->set.use_ssl) {
    647     result = oldap_perform_starttls(data);
    648     if(!result || data->set.use_ssl != CURLUSESSL_TRY)
    649       goto out;
    650   }
    651 #endif
    652 
    653   if(li->sasl.prefmech != SASL_AUTH_NONE) {
    654     result = oldap_perform_mechs(data);
    655     goto out;
    656   }
    657 
    658   /* Force bind even if anonymous bind is not needed in protocol version 3
    659      to detect missing version 3 support. */
    660   result = oldap_perform_bind(data, OLDAP_BIND);
    661 
    662 out:
    663   free(hosturl);
    664   return result;
    665 }
    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 {
    671   struct connectdata *conn = data->conn;
    672   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    673   int rc;
    674   BerElement *ber = NULL;
    675   CURLcode result = CURLE_OK;
    676   struct berval bv, *bvals;
    677 
    678   if(!li)
    679     return CURLE_FAILED_INIT;
    680   switch(ldap_msgtype(msg)) {
    681   case LDAP_RES_SEARCH_ENTRY:
    682     /* Got a list of supported SASL mechanisms. */
    683     if(code != LDAP_SUCCESS && code != LDAP_NO_RESULTS_RETURNED)
    684       return CURLE_LOGIN_DENIED;
    685 
    686     rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
    687     if(rc < 0)
    688       return oldap_map_error(rc, CURLE_BAD_CONTENT_ENCODING);
    689     for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
    690         rc == LDAP_SUCCESS;
    691         rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
    692       int i;
    693 
    694       if(!bv.bv_val)
    695         break;
    696 
    697       if(bvals) {
    698         for(i = 0; bvals[i].bv_val; i++) {
    699           size_t llen;
    700           unsigned short mech = Curl_sasl_decode_mech((char *) bvals[i].bv_val,
    701                                                       bvals[i].bv_len, &llen);
    702           if(bvals[i].bv_len == llen)
    703             li->sasl.authmechs |= mech;
    704         }
    705         ber_memfree(bvals);
    706       }
    707     }
    708     ber_free(ber, 0);
    709     break;
    710 
    711   case LDAP_RES_SEARCH_RESULT:
    712     switch(code) {
    713     case LDAP_SIZELIMIT_EXCEEDED:
    714       infof(data, "Too many authentication mechanisms\n");
    715       FALLTHROUGH();
    716     case LDAP_SUCCESS:
    717     case LDAP_NO_RESULTS_RETURNED:
    718       if(Curl_sasl_can_authenticate(&li->sasl, data))
    719         result = oldap_perform_sasl(data);
    720       else
    721         result = CURLE_LOGIN_DENIED;
    722       break;
    723     default:
    724       result = oldap_map_error(code, CURLE_LOGIN_DENIED);
    725       break;
    726     }
    727     break;
    728   default:
    729     break;
    730   }
    731   return result;
    732 }
    733 
    734 /* Handle a SASL bind response. */
    735 static CURLcode oldap_state_sasl_resp(struct Curl_easy *data,
    736                                       LDAPMessage *msg, int code)
    737 {
    738   struct connectdata *conn = data->conn;
    739   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    740   CURLcode result = CURLE_OK;
    741   saslprogress progress;
    742   int rc;
    743 
    744   if(!li)
    745     return CURLE_FAILED_INIT;
    746   li->servercred = NULL;
    747   rc = ldap_parse_sasl_bind_result(li->ld, msg, &li->servercred, 0);
    748   if(rc != LDAP_SUCCESS) {
    749     failf(data, "LDAP local: sasl ldap_parse_result %s", ldap_err2string(rc));
    750     result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
    751   }
    752   else {
    753     result = Curl_sasl_continue(&li->sasl, data, code, &progress);
    754     if(!result && progress != SASL_INPROGRESS)
    755       oldap_state(data, li, OLDAP_STOP);
    756   }
    757 
    758   if(li->servercred)
    759     ber_bvfree(li->servercred);
    760   return result;
    761 }
    762 
    763 /* Handle a simple bind response. */
    764 static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg,
    765                                       int code)
    766 {
    767   struct connectdata *conn = data->conn;
    768   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    769   CURLcode result = CURLE_OK;
    770   struct berval *bv = NULL;
    771   int rc;
    772 
    773   if(!li)
    774     return CURLE_FAILED_INIT;
    775 
    776   if(code != LDAP_SUCCESS)
    777     return oldap_map_error(code, CURLE_LDAP_CANNOT_BIND);
    778 
    779   rc = ldap_parse_sasl_bind_result(li->ld, msg, &bv, 0);
    780   if(rc != LDAP_SUCCESS) {
    781     failf(data, "LDAP local: bind ldap_parse_sasl_bind_result %s",
    782           ldap_err2string(rc));
    783     result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
    784   }
    785   else
    786     oldap_state(data, li, OLDAP_STOP);
    787 
    788   if(bv)
    789     ber_bvfree(bv);
    790   return result;
    791 }
    792 
    793 static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
    794 {
    795   CURLcode result = CURLE_OK;
    796   struct connectdata *conn = data->conn;
    797   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    798   LDAPMessage *msg = NULL;
    799   struct timeval tv = {0, 0};
    800   int code = LDAP_SUCCESS;
    801   int rc;
    802 
    803   if(!li)
    804     return CURLE_FAILED_INIT;
    805 
    806   if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) {
    807     /* Get response to last command. */
    808     rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg);
    809     switch(rc) {
    810     case 0:                               /* Timed out. */
    811       return CURLE_OK;
    812     case LDAP_RES_SEARCH_ENTRY:
    813     case LDAP_RES_SEARCH_REFERENCE:
    814       break;
    815     default:
    816       li->msgid = 0;                      /* Nothing to abandon upon error. */
    817       if(rc < 0) {
    818         failf(data, "LDAP local: connecting ldap_result %s",
    819               ldap_err2string(rc));
    820         return oldap_map_error(rc, CURLE_COULDNT_CONNECT);
    821       }
    822       break;
    823     }
    824 
    825     /* Get error code from message. */
    826     rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0);
    827     if(rc)
    828       code = rc;
    829     else {
    830       /* store the latest code for later retrieval */
    831       data->info.httpcode = code;
    832     }
    833 
    834     /* If protocol version 3 is not supported, fallback to version 2. */
    835     if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 &&
    836 #ifdef USE_SSL
    837        (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) &&
    838 #endif
    839        li->sasl.prefmech == SASL_AUTH_NONE) {
    840       static const int version = LDAP_VERSION2;
    841 
    842       ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
    843       ldap_msgfree(msg);
    844       return oldap_perform_bind(data, OLDAP_BINDV2);
    845     }
    846   }
    847 
    848   /* Handle response message according to current state. */
    849   switch(li->state) {
    850 
    851 #ifdef USE_SSL
    852   case OLDAP_SSL:
    853     result = oldap_ssl_connect(data, OLDAP_SSL);
    854     if(!result && ssl_installed(conn)) {
    855       if(li->sasl.prefmech != SASL_AUTH_NONE)
    856         result = oldap_perform_mechs(data);
    857       else
    858         result = oldap_perform_bind(data, OLDAP_BIND);
    859     }
    860     break;
    861   case OLDAP_STARTTLS:
    862     if(code != LDAP_SUCCESS) {
    863       if(data->set.use_ssl != CURLUSESSL_TRY)
    864         result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
    865       else if(li->sasl.prefmech != SASL_AUTH_NONE)
    866         result = oldap_perform_mechs(data);
    867       else
    868         result = oldap_perform_bind(data, OLDAP_BIND);
    869       break;
    870     }
    871     result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
    872     if(result)
    873       break;
    874     FALLTHROUGH();
    875   case OLDAP_TLS:
    876     result = oldap_ssl_connect(data, OLDAP_TLS);
    877     if(result)
    878       result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
    879     else if(ssl_installed(conn)) {
    880       if(li->sasl.prefmech != SASL_AUTH_NONE)
    881         result = oldap_perform_mechs(data);
    882       else if(data->state.aptr.user)
    883         result = oldap_perform_bind(data, OLDAP_BIND);
    884       else {
    885         /* Version 3 supported: no bind required */
    886         oldap_state(data, li, OLDAP_STOP);
    887         result = CURLE_OK;
    888       }
    889     }
    890     break;
    891 #endif
    892 
    893   case OLDAP_MECHS:
    894     result = oldap_state_mechs_resp(data, msg, code);
    895     break;
    896   case OLDAP_SASL:
    897     result = oldap_state_sasl_resp(data, msg, code);
    898     break;
    899   case OLDAP_BIND:
    900   case OLDAP_BINDV2:
    901     result = oldap_state_bind_resp(data, msg, code);
    902     break;
    903   default:
    904     /* internal error */
    905     result = CURLE_COULDNT_CONNECT;
    906     break;
    907   }
    908 
    909   ldap_msgfree(msg);
    910 
    911   *done = li->state == OLDAP_STOP;
    912   if(*done)
    913     conn->recv[FIRSTSOCKET] = oldap_recv;
    914 
    915   if(result && li->msgid) {
    916     ldap_abandon_ext(li->ld, li->msgid, NULL, NULL);
    917     li->msgid = 0;
    918   }
    919   return result;
    920 }
    921 
    922 static CURLcode oldap_disconnect(struct Curl_easy *data,
    923                                  struct connectdata *conn,
    924                                  bool dead_connection)
    925 {
    926   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    927   (void) dead_connection;
    928 #ifndef USE_SSL
    929   (void)data;
    930 #endif
    931 
    932   if(li) {
    933     if(li->ld) {
    934 #ifdef USE_SSL
    935       if(ssl_installed(conn)) {
    936         Sockbuf *sb;
    937         ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
    938         ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
    939       }
    940 #endif
    941       ldap_unbind_ext(li->ld, NULL, NULL);
    942       li->ld = NULL;
    943     }
    944   }
    945   return CURLE_OK;
    946 }
    947 
    948 static CURLcode oldap_do(struct Curl_easy *data, bool *done)
    949 {
    950   struct connectdata *conn = data->conn;
    951   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
    952   struct ldapreqinfo *lr;
    953   CURLcode result;
    954   int rc;
    955   LDAPURLDesc *lud;
    956   int msgid;
    957 
    958   if(!li)
    959     return CURLE_FAILED_INIT;
    960   connkeep(conn, "OpenLDAP do");
    961 
    962   infof(data, "LDAP local: %s", data->state.url);
    963 
    964   result = oldap_url_parse(data, &lud);
    965   if(result)
    966     goto out;
    967 
    968 #ifdef USE_SSL
    969   if(ssl_installed(conn)) {
    970     Sockbuf *sb;
    971     /* re-install the libcurl SSL handlers into the sockbuf. */
    972     ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
    973     ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
    974   }
    975 #endif
    976 
    977   rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
    978                        lud->lud_filter, lud->lud_attrs, 0,
    979                        NULL, NULL, NULL, 0, &msgid);
    980   ldap_free_urldesc(lud);
    981   if(rc != LDAP_SUCCESS) {
    982     failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
    983     result = CURLE_LDAP_SEARCH_FAILED;
    984     goto out;
    985   }
    986 
    987   lr = calloc(1, sizeof(struct ldapreqinfo));
    988   if(!lr ||
    989      Curl_meta_set(data, CURL_META_LDAP_EASY, lr, oldap_easy_dtor)) {
    990     ldap_abandon_ext(li->ld, msgid, NULL, NULL);
    991     result = CURLE_OUT_OF_MEMORY;
    992     goto out;
    993   }
    994 
    995   lr->msgid = msgid;
    996   Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
    997   *done = TRUE;
    998 
    999 out:
   1000   return result;
   1001 }
   1002 
   1003 static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
   1004                            bool premature)
   1005 {
   1006   struct connectdata *conn = data->conn;
   1007   struct ldapreqinfo *lr = Curl_meta_get(data, CURL_META_LDAP_EASY);
   1008 
   1009   (void)res;
   1010   (void)premature;
   1011 
   1012   if(lr) {
   1013     /* if there was a search in progress, abandon it */
   1014     if(lr->msgid) {
   1015       struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
   1016       if(li && li->ld) {
   1017         ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
   1018       }
   1019       lr->msgid = 0;
   1020     }
   1021     Curl_meta_remove(data, CURL_META_LDAP_EASY);
   1022   }
   1023 
   1024   return CURLE_OK;
   1025 }
   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 {
   1032   CURLcode result = CURLE_OK;
   1033 
   1034   if(prefix) {
   1035     /* If we have a zero-length value and the prefix ends with a space
   1036        separator, drop the latter. */
   1037     if(!len && plen && prefix[plen - 1] == ' ')
   1038       plen--;
   1039     result = Curl_client_write(data, CLIENTWRITE_BODY, prefix, plen);
   1040   }
   1041   if(!result && value) {
   1042     result = Curl_client_write(data, CLIENTWRITE_BODY, value, len);
   1043   }
   1044   if(!result && suffix) {
   1045     result = Curl_client_write(data, CLIENTWRITE_BODY, suffix, slen);
   1046   }
   1047   return result;
   1048 }
   1049 
   1050 static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
   1051                            size_t len, size_t *pnread)
   1052 {
   1053   struct connectdata *conn = data->conn;
   1054   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
   1055   struct ldapreqinfo *lr = Curl_meta_get(data, CURL_META_LDAP_EASY);
   1056   int rc;
   1057   LDAPMessage *msg = NULL;
   1058   BerElement *ber = NULL;
   1059   struct timeval tv = {0, 0};
   1060   struct berval bv, *bvals;
   1061   bool binary = FALSE;
   1062   CURLcode result = CURLE_AGAIN;
   1063   int code;
   1064   char *info = NULL;
   1065 
   1066   (void)len;
   1067   (void)buf;
   1068   (void)sockindex;
   1069   *pnread = 0;
   1070   if(!li || !lr)
   1071     return CURLE_FAILED_INIT;
   1072 
   1073   rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg);
   1074   if(rc < 0) {
   1075     failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
   1076     result = CURLE_RECV_ERROR;
   1077   }
   1078 
   1079   /* error or timed out */
   1080   if(!msg)
   1081     return result;
   1082 
   1083   result = CURLE_OK;
   1084 
   1085   switch(ldap_msgtype(msg)) {
   1086   case LDAP_RES_SEARCH_RESULT:
   1087     lr->msgid = 0;
   1088     rc = ldap_parse_result(li->ld, msg, &code, NULL, &info, NULL, NULL, 0);
   1089     if(rc) {
   1090       failf(data, "LDAP local: search ldap_parse_result %s",
   1091             ldap_err2string(rc));
   1092       result = CURLE_LDAP_SEARCH_FAILED;
   1093       break;
   1094     }
   1095 
   1096     /* store the latest code for later retrieval */
   1097     data->info.httpcode = code;
   1098 
   1099     switch(code) {
   1100     case LDAP_SIZELIMIT_EXCEEDED:
   1101       infof(data, "There are more than %d entries", lr->nument);
   1102       FALLTHROUGH();
   1103     case LDAP_SUCCESS:
   1104       data->req.size = data->req.bytecount;
   1105       break;
   1106     default:
   1107       failf(data, "LDAP remote: search failed %s %s", ldap_err2string(code),
   1108             info ? info : "");
   1109       result = CURLE_LDAP_SEARCH_FAILED;
   1110       break;
   1111     }
   1112     if(info)
   1113       ldap_memfree(info);
   1114     break;
   1115   case LDAP_RES_SEARCH_ENTRY:
   1116     lr->nument++;
   1117     rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
   1118     if(rc < 0) {
   1119       result = CURLE_RECV_ERROR;
   1120       break;
   1121     }
   1122 
   1123     result = client_write(data, STRCONST("DN: "), bv.bv_val, bv.bv_len,
   1124                           STRCONST("\n"));
   1125     if(result)
   1126       break;
   1127 
   1128     for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
   1129         rc == LDAP_SUCCESS;
   1130         rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
   1131       int i;
   1132 
   1133       if(!bv.bv_val)
   1134         break;
   1135 
   1136       if(!bvals) {
   1137         result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
   1138                               STRCONST(":\n"));
   1139         if(result)
   1140           break;
   1141         continue;
   1142       }
   1143 
   1144       binary = bv.bv_len > 7 &&
   1145         !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7);
   1146 
   1147       for(i = 0; bvals[i].bv_val != NULL; i++) {
   1148         bool binval = FALSE;
   1149 
   1150         result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
   1151                               STRCONST(":"));
   1152         if(result)
   1153           break;
   1154 
   1155         if(!binary) {
   1156           /* check for leading or trailing whitespace */
   1157           if(ISBLANK(bvals[i].bv_val[0]) ||
   1158              ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))
   1159             binval = TRUE;
   1160           else {
   1161             /* check for unprintable characters */
   1162             unsigned int j;
   1163             for(j = 0; j < bvals[i].bv_len; j++)
   1164               if(!ISPRINT(bvals[i].bv_val[j])) {
   1165                 binval = TRUE;
   1166                 break;
   1167               }
   1168           }
   1169         }
   1170         if(binary || binval) {
   1171           char *val_b64 = NULL;
   1172           size_t val_b64_sz = 0;
   1173 
   1174           /* Binary value, encode to base64. */
   1175           if(bvals[i].bv_len)
   1176             result = curlx_base64_encode(bvals[i].bv_val, bvals[i].bv_len,
   1177                                          &val_b64, &val_b64_sz);
   1178           if(!result)
   1179             result = client_write(data, STRCONST(": "), val_b64, val_b64_sz,
   1180                                   STRCONST("\n"));
   1181           free(val_b64);
   1182         }
   1183         else
   1184           result = client_write(data, STRCONST(" "),
   1185                                 bvals[i].bv_val, bvals[i].bv_len,
   1186                                 STRCONST("\n"));
   1187         if(result)
   1188           break;
   1189       }
   1190 
   1191       ber_memfree(bvals);
   1192       bvals = NULL;
   1193       if(!result)
   1194         result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
   1195       if(result)
   1196         break;
   1197     }
   1198 
   1199     ber_free(ber, 0);
   1200 
   1201     if(!result)
   1202       result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
   1203     if(!result)
   1204       result = CURLE_AGAIN;
   1205     break;
   1206   }
   1207 
   1208   ldap_msgfree(msg);
   1209   return result;
   1210 }
   1211 
   1212 #ifdef USE_SSL
   1213 static int
   1214 ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
   1215 {
   1216   sbiod->sbiod_pvt = arg;
   1217   return 0;
   1218 }
   1219 
   1220 static int
   1221 ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
   1222 {
   1223   sbiod->sbiod_pvt = NULL;
   1224   return 0;
   1225 }
   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 {
   1231   (void)sbiod;
   1232   return 0;
   1233 }
   1234 
   1235 static int
   1236 ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
   1237 {
   1238   (void)arg;
   1239   if(opt == LBER_SB_OPT_DATA_READY) {
   1240     struct Curl_easy *data = sbiod->sbiod_pvt;
   1241     return Curl_conn_data_pending(data, FIRSTSOCKET);
   1242   }
   1243   return 0;
   1244 }
   1245 
   1246 static ber_slen_t
   1247 ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
   1248 {
   1249   struct Curl_easy *data = sbiod->sbiod_pvt;
   1250   ber_slen_t ret = 0;
   1251   if(data) {
   1252     struct connectdata *conn = data->conn;
   1253     if(conn) {
   1254       struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
   1255       CURLcode err = CURLE_RECV_ERROR;
   1256       size_t nread;
   1257 
   1258       if(!li) {
   1259         SET_SOCKERRNO(SOCKEINVAL);
   1260         return -1;
   1261       }
   1262       err = (li->recv)(data, FIRSTSOCKET, buf, len, &nread);
   1263       if(err == CURLE_AGAIN) {
   1264         SET_SOCKERRNO(SOCKEWOULDBLOCK);
   1265       }
   1266       ret = err ? -1 : (ber_slen_t)nread;
   1267     }
   1268   }
   1269   return ret;
   1270 }
   1271 static ber_slen_t
   1272 ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
   1273 {
   1274   struct Curl_easy *data = sbiod->sbiod_pvt;
   1275   ber_slen_t ret = 0;
   1276   if(data) {
   1277     struct connectdata *conn = data->conn;
   1278     if(conn) {
   1279       struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
   1280       CURLcode err = CURLE_SEND_ERROR;
   1281       size_t nwritten;
   1282 
   1283       if(!li) {
   1284         SET_SOCKERRNO(SOCKEINVAL);
   1285         return -1;
   1286       }
   1287       err = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &nwritten);
   1288       if(err == CURLE_AGAIN) {
   1289         SET_SOCKERRNO(SOCKEWOULDBLOCK);
   1290       }
   1291       ret = err ? -1 : (ber_slen_t)nwritten;
   1292     }
   1293   }
   1294   return ret;
   1295 }
   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 */