diff options
author | Patrick Monnerat <patrick@monnerat.net> | 2022-01-10 11:57:02 +0100 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2022-01-11 11:17:27 +0100 |
commit | eeca818b1e8d1e61c2d4d833aed56ce4c510a9d4 (patch) | |
tree | 0074d4575aacf3ff84f76ffe3d2c6758ff92a1f7 | |
parent | ce5463e60c8957fd4ee41266e38c4452b3e91746 (diff) | |
download | curl-eeca818b1e8d1e61c2d4d833aed56ce4c510a9d4.tar.gz |
openldap: implement SASL authentication
As credentials can be quite different depending on the mechanism used,
there are no default mechanisms for LDAP and simple bind with a DN is
then used.
The caller has to provide mechanism(s) using CURLOPT_LOGIN_OPTIONS to
enable SASL authentication and disable simple bind.
Closes #8152
-rw-r--r-- | docs/cmdline-opts/login-options.d | 2 | ||||
-rw-r--r-- | docs/cmdline-opts/oauth2-bearer.d | 2 | ||||
-rw-r--r-- | docs/libcurl/curl_version_info.3 | 6 | ||||
-rw-r--r-- | docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.3 | 6 | ||||
-rw-r--r-- | docs/libcurl/opts/CURLOPT_SASL_AUTHZID.3 | 6 | ||||
-rw-r--r-- | docs/libcurl/opts/CURLOPT_SERVICE_NAME.3 | 11 | ||||
-rw-r--r-- | docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3 | 12 | ||||
-rw-r--r-- | lib/openldap.c | 322 |
8 files changed, 332 insertions, 35 deletions
diff --git a/docs/cmdline-opts/login-options.d b/docs/cmdline-opts/login-options.d index 4c53db3fd..b524ebb0a 100644 --- a/docs/cmdline-opts/login-options.d +++ b/docs/cmdline-opts/login-options.d @@ -1,6 +1,6 @@ Long: login-options Arg: <options> -Protocols: IMAP POP3 SMTP +Protocols: IMAP LDAP POP3 SMTP Help: Server login options Added: 7.34.0 Category: imap pop3 smtp auth diff --git a/docs/cmdline-opts/oauth2-bearer.d b/docs/cmdline-opts/oauth2-bearer.d index e5ed0e87f..07bb54bde 100644 --- a/docs/cmdline-opts/oauth2-bearer.d +++ b/docs/cmdline-opts/oauth2-bearer.d @@ -1,7 +1,7 @@ Long: oauth2-bearer Help: OAuth 2 Bearer Token Arg: <token> -Protocols: IMAP POP3 SMTP HTTP +Protocols: IMAP LDAP POP3 SMTP HTTP Category: auth Example: --oauth2-bearer "mF_9.B5f-4.1JqM" $URL Added: 7.33.0 diff --git a/docs/libcurl/curl_version_info.3 b/docs/libcurl/curl_version_info.3 index 7fb494b0c..d8f4b805b 100644 --- a/docs/libcurl/curl_version_info.3 +++ b/docs/libcurl/curl_version_info.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. +.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -172,8 +172,8 @@ supports IPv6 .IP CURL_VERSION_KERBEROS4 supports Kerberos V4 (when using FTP). Legacy bit. Deprecated since 7.33.0. .IP CURL_VERSION_KERBEROS5 -supports Kerberos V5 authentication for FTP, IMAP, POP3, SMTP and SOCKSv5 proxy -(Added in 7.40.0) +supports Kerberos V5 authentication for FTP, IMAP, LDAP, POP3, SMTP and +SOCKSv5 proxy. (Added in 7.40.0) .IP CURL_VERSION_LARGEFILE libcurl was built with support for large files. (Added in 7.11.1) .IP CURL_VERSION_UNICODE diff --git a/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.3 b/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.3 index 5bb997cb6..5ec942174 100644 --- a/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.3 +++ b/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. +.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -46,7 +46,7 @@ option. .SH DEFAULT NULL .SH PROTOCOLS -Only IMAP, POP3 and SMTP support login options. +Only IMAP, LDAP, POP3 and SMTP support login options. .SH EXAMPLE .nf CURL *curl = curl_easy_init(); @@ -58,7 +58,7 @@ if(curl) { } .fi .SH AVAILABILITY -Added in 7.34.0 +Added in 7.34.0. Support for OpenLDAP added in 7.82.0. .SH RETURN VALUE Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.3 b/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.3 index 87cd42859..7468235cc 100644 --- a/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.3 +++ b/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. +.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -45,7 +45,7 @@ or a shared mailbox for example. .SH DEFAULT blank .SH PROTOCOLS -IMAP, POP3 and SMTP +IMAP, LDAP, POP3 and SMTP .SH EXAMPLE .nf CURL *curl = curl_easy_init(); @@ -59,7 +59,7 @@ if(curl) { } .fi .SH AVAILABILITY -Added in 7.66.0 +Added in 7.66.0. Support for OpenLDAP added in 7.82.0. .SH RETURN VALUE Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. .SH "SEE ALSO" diff --git a/docs/libcurl/opts/CURLOPT_SERVICE_NAME.3 b/docs/libcurl/opts/CURLOPT_SERVICE_NAME.3 index 9246f8249..7fc2b0fd9 100644 --- a/docs/libcurl/opts/CURLOPT_SERVICE_NAME.3 +++ b/docs/libcurl/opts/CURLOPT_SERVICE_NAME.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. +.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -32,15 +32,15 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SERVICE_NAME, char *name); .SH DESCRIPTION Pass a char * as parameter to a string holding the \fIname\fP of the service for DIGEST-MD5, SPNEGO and Kerberos 5 authentication mechanisms. The default -service names are "ftp", "HTTP", "imap", "pop" and "smtp". This option allows -you to change them. +service names are "ftp", "HTTP", "imap", "ldap", "pop" and "smtp". This option +allows you to change them. The application does not have to keep the string around after setting this option. .SH DEFAULT See above .SH PROTOCOLS -HTTP, FTP, IMAP, POP and SMTP +HTTP, FTP, IMAP, LDAP, POP3 and SMTP .SH EXAMPLE .nf CURL *curl = curl_easy_init(); @@ -52,7 +52,8 @@ if(curl) { } .fi .SH AVAILABILITY -Added in 7.43.0 for HTTP, 7.49.0 for FTP, IMAP, POP3 and SMTP. +Added in 7.43.0 for HTTP, 7.49.0 for FTP, IMAP, POP3 and SMTP, +7.82.0 for OpenLDAP. .SH RETURN VALUE Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3 b/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3 index 3583287f7..22ae95501 100644 --- a/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3 +++ b/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. +.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -31,18 +31,18 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_XOAUTH2_BEARER, char *token); .fi .SH DESCRIPTION Pass a char * as parameter, which should point to the null-terminated OAuth -2.0 Bearer Access Token for use with HTTP, IMAP, POP3 and SMTP servers +2.0 Bearer Access Token for use with HTTP, IMAP, LDAP, POP3 and SMTP servers that support the OAuth 2.0 Authorization Framework. -Note: For IMAP, POP3 and SMTP, the user name used to generate the Bearer Token -should be supplied via the \fICURLOPT_USERNAME(3)\fP option. +Note: For IMAP, LDAP, POP3 and SMTP, the user name used to generate the +Bearer Token should be supplied via the \fICURLOPT_USERNAME(3)\fP option. The application does not have to keep the string around after setting this option. .SH DEFAULT NULL .SH PROTOCOLS -IMAP, POP3 and SMTP +HTTP, IMAP, LDAP, POP3 and SMTP .SH EXAMPLE .nf CURL *curl = curl_easy_init(); @@ -54,7 +54,7 @@ if(curl) { } .fi .SH AVAILABILITY -Added in 7.33.0 +Added in 7.33.0. Support for OpenLAP added in 7.82.0. .SH RETURN VALUE Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or CURLE_OUT_OF_MEMORY if there was insufficient heap space. diff --git a/lib/openldap.c b/lib/openldap.c index 0ffb6a36a..2488d15ee 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2011 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2011 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010, Howard Chu, <hyc@openldap.org> * * This software is licensed as described in the file COPYING, which @@ -46,6 +46,8 @@ #include "curl_ldap.h" #include "curl_base64.h" #include "connect.h" +#include "curl_sasl.h" +#include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -76,6 +78,8 @@ typedef enum { OLDAP_SSL, /* Performing SSL handshake. */ OLDAP_STARTTLS, /* STARTTLS request sent. */ OLDAP_TLS, /* Performing TLS handshake. */ + OLDAP_MECHS, /* Get SASL authentication mechanisms. */ + OLDAP_SASL, /* SASL binding reply. */ OLDAP_BIND, /* Simple bind reply. */ OLDAP_BINDV2, /* Simple bind reply in protocol version 2. */ OLDAP_LAST /* Never used */ @@ -96,6 +100,13 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done); static CURLcode oldap_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead); +static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp); +static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp); +static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech); +static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out); + static Curl_recv oldap_recv; /* @@ -154,10 +165,26 @@ const struct Curl_handler Curl_handler_ldaps = { }; #endif +/* SASL parameters for the ldap protocol */ +static const struct SASLproto saslldap = { + "ldap", /* The service name */ + oldap_perform_auth, /* Send authentication command */ + oldap_continue_auth, /* Send authentication continuation */ + oldap_cancel_auth, /* Send authentication cancellation */ + oldap_get_message, /* Get SASL response message */ + 0, /* Maximum initial response length (no max) */ + LDAP_SASL_BIND_IN_PROGRESS, /* Code received when continuation is expected */ + LDAP_SUCCESS, /* Code to receive upon authentication success */ + SASL_AUTH_NONE, /* Default mechanisms */ + 0 /* Configuration flags */ +}; + struct ldapconninfo { + struct SASL sasl; /* SASL-related parameters */ LDAP *ld; /* Openldap connection handle. */ Curl_recv *recv; /* For stacking SSL handler */ Curl_send *send; + struct berval *servercred; /* SASL data from server. */ ldapstate state; /* Current machine state. */ int proto; /* LDAP_PROTO_TCP/LDAP_PROTO_UDP/LDAP_PROTO_IPC */ int msgid; /* Current message id. */ @@ -184,6 +211,8 @@ static void state(struct Curl_easy *data, ldapstate newstate) "SSL", "STARTTLS", "TLS", + "MECHS", + "SASL", "BIND", "BINDV2", /* LAST */ @@ -251,6 +280,37 @@ static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp) return result; } +/* Parse the login options. */ +static CURLcode oldap_parse_login_options(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct ldapconninfo *li = conn->proto.ldapc; + const char *ptr = conn->options; + + while(!result && ptr && *ptr) { + const char *key = ptr; + const char *value; + + while(*ptr && *ptr != '=') + ptr++; + + value = ptr + 1; + + while(*ptr && *ptr != ';') + ptr++; + + if(checkprefix("AUTH=", key)) + result = Curl_sasl_parse_url_auth_option(&li->sasl, value, ptr - value); + else + result = CURLE_SETOPT_OPTION_SYNTAX; + + if(*ptr == ';') + ptr++; + } + + return result == CURLE_URL_MALFORMAT? CURLE_SETOPT_OPTION_SYNTAX: result; +} + static CURLcode oldap_setup_connection(struct Curl_easy *data, struct connectdata *conn) { @@ -271,14 +331,94 @@ static CURLcode oldap_setup_connection(struct Curl_easy *data, conn->proto.ldapc = li; connkeep(conn, "OpenLDAP default"); + /* Initialize the SASL storage */ + Curl_sasl_init(&li->sasl, data, &saslldap); + /* Clear the TLS upgraded flag */ conn->bits.tls_upgraded = FALSE; + + result = oldap_parse_login_options(conn); } } return result; } +/* + * Get the SASL authentication challenge from the server credential buffer. + */ +static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out) +{ + struct berval *servercred = data->conn->proto.ldapc->servercred; + + if(!servercred || !servercred->bv_val) + return CURLE_WEIRD_SERVER_REPLY; + Curl_bufref_set(out, servercred->bv_val, servercred->bv_len, NULL); + return CURLE_OK; +} + +/* + * Sends an initial SASL bind request to the server. + */ +static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + CURLcode result = CURLE_OK; + struct berval cred; + struct berval *pcred = &cred; + int rc; + + cred.bv_val = (char *) Curl_bufref_ptr(initresp); + cred.bv_len = Curl_bufref_len(initresp); + if(!cred.bv_val) + pcred = NULL; + rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid); + if(rc != LDAP_SUCCESS) + result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND); + return result; +} + +/* + * Sends SASL continuation. + */ +static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + CURLcode result = CURLE_OK; + struct berval cred; + struct berval *pcred = &cred; + int rc; + + cred.bv_val = (char *) Curl_bufref_ptr(resp); + cred.bv_len = Curl_bufref_len(resp); + if(!cred.bv_val) + pcred = NULL; + rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid); + if(rc != LDAP_SUCCESS) + result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND); + return result; +} + +/* + * Sends SASL bind cancellation. + */ +static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech) +{ + struct ldapconninfo *li = data->conn->proto.ldapc; + CURLcode result = CURLE_OK; + int rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL, + &li->msgid); + + (void)mech; + if(rc != LDAP_SUCCESS) + result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND); + return result; +} + /* Starts LDAP simple bind. */ static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate) { @@ -309,6 +449,40 @@ static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate) return result; } +/* Query the supported SASL authentication mechanisms. */ +static CURLcode oldap_perform_mechs(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct ldapconninfo *li = data->conn->proto.ldapc; + int rc; + static const char * const supportedSASLMechanisms[] = { + "supportedSASLMechanisms", + NULL + }; + + rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)", + (char **) supportedSASLMechanisms, 0, + NULL, NULL, NULL, 0, &li->msgid); + if(rc == LDAP_SUCCESS) + state(data, OLDAP_MECHS); + else + result = oldap_map_error(rc, CURLE_LOGIN_DENIED); + return result; +} + +/* Starts SASL bind. */ +static CURLcode oldap_perform_sasl(struct Curl_easy *data) +{ + saslprogress progress = SASL_IDLE; + struct ldapconninfo *li = data->conn->proto.ldapc; + CURLcode result = Curl_sasl_start(&li->sasl, data, TRUE, &progress); + + state(data, OLDAP_SASL); + if(!result && progress != SASL_INPROGRESS) + result = CURLE_LOGIN_DENIED; + return result; +} + #ifdef USE_SSL static Sockbuf_IO ldapsb_tls; @@ -414,11 +588,106 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done) } #endif + if(li->sasl.prefmech != SASL_AUTH_NONE) + return oldap_perform_mechs(data); + /* Force bind even if anonymous bind is not needed in protocol version 3 to detect missing version 3 support. */ return oldap_perform_bind(data, OLDAP_BIND); } +/* Handle the supported SASL mechanisms query response */ +static CURLcode oldap_state_mechs_resp(struct Curl_easy *data, + LDAPMessage *msg, int code) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + int rc; + BerElement *ber = NULL; + CURLcode result = CURLE_OK; + struct berval bv, *bvals; + + switch(ldap_msgtype(msg)) { + case LDAP_RES_SEARCH_ENTRY: + /* Got a list of supported SASL mechanisms. */ + if(code != LDAP_SUCCESS && code != LDAP_NO_RESULTS_RETURNED) + return CURLE_LOGIN_DENIED; + + rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv); + if(rc < 0) + return oldap_map_error(rc, CURLE_BAD_CONTENT_ENCODING); + for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals); + rc == LDAP_SUCCESS; + rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) { + int i; + + if(!bv.bv_val) + break; + + if(bvals) { + for(i = 0; bvals[i].bv_val; i++) { + size_t llen; + unsigned short mech = Curl_sasl_decode_mech((char *) bvals[i].bv_val, + bvals[i].bv_len, &llen); + if(bvals[i].bv_len == llen) + li->sasl.authmechs |= mech; + } + ber_memfree(bvals); + } + } + ber_free(ber, 0); + break; + + case LDAP_RES_SEARCH_RESULT: + switch(code) { + case LDAP_SIZELIMIT_EXCEEDED: + infof(data, "Too many authentication mechanisms\n"); + /* FALLTHROUGH */ + case LDAP_SUCCESS: + case LDAP_NO_RESULTS_RETURNED: + if(Curl_sasl_can_authenticate(&li->sasl, conn)) + result = oldap_perform_sasl(data); + else + result = CURLE_LOGIN_DENIED; + break; + default: + result = oldap_map_error(code, CURLE_LOGIN_DENIED); + break; + } + break; + default: + break; + } + return result; +} + +/* Handle a SASL bind response. */ +static CURLcode oldap_state_sasl_resp(struct Curl_easy *data, + LDAPMessage *msg, int code) +{ + struct connectdata *conn = data->conn; + struct ldapconninfo *li = conn->proto.ldapc; + CURLcode result = CURLE_OK; + saslprogress progress; + int rc; + + li->servercred = NULL; + rc = ldap_parse_sasl_bind_result(li->ld, msg, &li->servercred, 0); + if(rc != LDAP_SUCCESS) { + failf(data, "LDAP local: sasl ldap_parse_result %s", ldap_err2string(rc)); + result = oldap_map_error(rc, CURLE_LOGIN_DENIED); + } + else { + result = Curl_sasl_continue(&li->sasl, data, code, &progress); + if(!result && progress != SASL_INPROGRESS) + state(data, OLDAP_STOP); + } + + if(li->servercred) + ber_bvfree(li->servercred); + return result; +} + /* Handle a simple bind response. */ static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg, int code) @@ -459,12 +728,20 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) { /* Get response to last command. */ rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg); - if(!rc) - return CURLE_OK; /* Timed out. */ - if(rc < 0) { - failf(data, "LDAP local: connecting ldap_result %s", - ldap_err2string(rc)); - return oldap_map_error(rc, CURLE_COULDNT_CONNECT); + switch(rc) { + case 0: /* Timed out. */ + return CURLE_OK; + case LDAP_RES_SEARCH_ENTRY: + case LDAP_RES_SEARCH_REFERENCE: + break; + default: + li->msgid = 0; /* Nothing to abandon upon error. */ + if(rc < 0) { + failf(data, "LDAP local: connecting ldap_result %s", + ldap_err2string(rc)); + return oldap_map_error(rc, CURLE_COULDNT_CONNECT); + } + break; } /* Get error code from message. */ @@ -477,11 +754,11 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) } /* If protocol version 3 is not supported, fallback to version 2. */ - if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 + if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 && #ifdef USE_SSL - && (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) + (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) && #endif - ) { + li->sasl.prefmech == SASL_AUTH_NONE) { static const int version = LDAP_VERSION2; ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version); @@ -496,13 +773,19 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) #ifdef USE_SSL case OLDAP_SSL: result = oldap_ssl_connect(data, OLDAP_SSL); - if(!result && ssl_installed(conn)) - result = oldap_perform_bind(data, OLDAP_BIND); + if(!result && ssl_installed(conn)) { + if(li->sasl.prefmech != SASL_AUTH_NONE) + result = oldap_perform_mechs(data); + else + result = oldap_perform_bind(data, OLDAP_BIND); + } break; case OLDAP_STARTTLS: if(code != LDAP_SUCCESS) { if(data->set.use_ssl != CURLUSESSL_TRY) result = oldap_map_error(code, CURLE_USE_SSL_FAILED); + else if(li->sasl.prefmech != SASL_AUTH_NONE) + result = oldap_perform_mechs(data); else result = oldap_perform_bind(data, OLDAP_BIND); break; @@ -514,7 +797,9 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) result = oldap_map_error(code, CURLE_USE_SSL_FAILED); else if(ssl_installed(conn)) { conn->bits.tls_upgraded = TRUE; - if(conn->bits.user_passwd) + if(li->sasl.prefmech != SASL_AUTH_NONE) + result = oldap_perform_mechs(data); + else if(conn->bits.user_passwd) result = oldap_perform_bind(data, OLDAP_BIND); else { state(data, OLDAP_STOP); /* Version 3 supported: no bind required */ @@ -524,6 +809,12 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) break; #endif + case OLDAP_MECHS: + result = oldap_state_mechs_resp(data, msg, code); + break; + case OLDAP_SASL: + result = oldap_state_sasl_resp(data, msg, code); + break; case OLDAP_BIND: case OLDAP_BINDV2: result = oldap_state_bind_resp(data, msg, code); @@ -540,6 +831,10 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) if(*done) conn->recv[FIRSTSOCKET] = oldap_recv; + if(result && li->msgid) { + ldap_abandon_ext(li->ld, li->msgid, NULL, NULL); + li->msgid = 0; + } return result; } @@ -562,6 +857,7 @@ static CURLcode oldap_disconnect(struct Curl_easy *data, ldap_unbind_ext(li->ld, NULL, NULL); li->ld = NULL; } + Curl_sasl_cleanup(conn, li->sasl.authused); conn->proto.ldapc = NULL; free(li); } |