blob: f2ffdfe679334330d12ddadbf2d1cf19bc87d384 [file] [log] [blame]
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Alex Deymo486467e2017-12-19 19:04:07 +01008 * Copyright (C) 2010, 2017, Howard Chu, <hyc@openldap.org>
Alex Deymod15eaac2016-06-28 14:49:26 -07009 * Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
Lucas Eckels9bd90e62012-08-06 15:07:02 -070010 *
11 * This software is licensed as described in the file COPYING, which
12 * you should have received as part of this distribution. The terms
Alex Deymod15eaac2016-06-28 14:49:26 -070013 * are also available at https://curl.haxx.se/docs/copyright.html.
Lucas Eckels9bd90e62012-08-06 15:07:02 -070014 *
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 ***************************************************************************/
23
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070024#include "curl_setup.h"
Lucas Eckels9bd90e62012-08-06 15:07:02 -070025
26#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
27
28/*
29 * Notice that USE_OPENLDAP is only a source code selection switch. When
30 * libcurl is built with USE_OPENLDAP defined the libcurl source code that
31 * gets compiled is the code from openldap.c, otherwise the code that gets
32 * compiled is the code from ldap.c.
33 *
34 * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
35 * might be required for compilation and runtime. In order to use ancient
36 * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
37 */
38
39#include <ldap.h>
40
41#include "urldata.h"
42#include <curl/curl.h>
43#include "sendf.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070044#include "vtls/vtls.h"
Lucas Eckels9bd90e62012-08-06 15:07:02 -070045#include "transfer.h"
46#include "curl_ldap.h"
Lucas Eckels9bd90e62012-08-06 15:07:02 -070047#include "curl_base64.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070048#include "connect.h"
Alex Deymod15eaac2016-06-28 14:49:26 -070049/* The last 3 #include files should be in this order */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070050#include "curl_printf.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070051#include "curl_memory.h"
Lucas Eckels9bd90e62012-08-06 15:07:02 -070052#include "memdebug.h"
53
Elliott Hughes0128fe42018-02-27 14:57:55 -080054/*
55 * Uncommenting this will enable the built-in debug logging of the openldap
56 * library. The debug log level can be set using the CURL_OPENLDAP_TRACE
57 * environment variable. The debug output is written to stderr.
58 *
59 * The library supports the following debug flags:
60 * LDAP_DEBUG_NONE 0x0000
61 * LDAP_DEBUG_TRACE 0x0001
62 * LDAP_DEBUG_CONSTRUCT 0x0002
63 * LDAP_DEBUG_DESTROY 0x0004
64 * LDAP_DEBUG_PARAMETER 0x0008
65 * LDAP_DEBUG_ANY 0xffff
66 *
67 * For example, use CURL_OPENLDAP_TRACE=0 for no debug,
68 * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only,
69 * CURL_OPENLDAP_TRACE=65535 for all debug message levels.
70 */
71/* #define CURL_OPENLDAP_DEBUG */
72
Lucas Eckels9bd90e62012-08-06 15:07:02 -070073#ifndef _LDAP_PVT_H
74extern int ldap_pvt_url_scheme2proto(const char *);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070075extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
76 LDAP **ld);
Lucas Eckels9bd90e62012-08-06 15:07:02 -070077#endif
78
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070079static CURLcode ldap_setup_connection(struct connectdata *conn);
Lucas Eckels9bd90e62012-08-06 15:07:02 -070080static CURLcode ldap_do(struct connectdata *conn, bool *done);
81static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool);
82static CURLcode ldap_connect(struct connectdata *conn, bool *done);
83static CURLcode ldap_connecting(struct connectdata *conn, bool *done);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070084static CURLcode ldap_disconnect(struct connectdata *conn, bool dead);
Lucas Eckels9bd90e62012-08-06 15:07:02 -070085
86static Curl_recv ldap_recv;
87
88/*
89 * LDAP protocol handler.
90 */
91
92const struct Curl_handler Curl_handler_ldap = {
93 "LDAP", /* scheme */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070094 ldap_setup_connection, /* setup_connection */
Lucas Eckels9bd90e62012-08-06 15:07:02 -070095 ldap_do, /* do_it */
96 ldap_done, /* done */
97 ZERO_NULL, /* do_more */
98 ldap_connect, /* connect_it */
99 ldap_connecting, /* connecting */
100 ZERO_NULL, /* doing */
101 ZERO_NULL, /* proto_getsock */
102 ZERO_NULL, /* doing_getsock */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700103 ZERO_NULL, /* domore_getsock */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700104 ZERO_NULL, /* perform_getsock */
105 ldap_disconnect, /* disconnect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700106 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700107 ZERO_NULL, /* connection_check */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700108 PORT_LDAP, /* defport */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700109 CURLPROTO_LDAP, /* protocol */
110 PROTOPT_NONE /* flags */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700111};
112
113#ifdef USE_SSL
114/*
115 * LDAPS protocol handler.
116 */
117
118const struct Curl_handler Curl_handler_ldaps = {
119 "LDAPS", /* scheme */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700120 ldap_setup_connection, /* setup_connection */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700121 ldap_do, /* do_it */
122 ldap_done, /* done */
123 ZERO_NULL, /* do_more */
124 ldap_connect, /* connect_it */
125 ldap_connecting, /* connecting */
126 ZERO_NULL, /* doing */
127 ZERO_NULL, /* proto_getsock */
128 ZERO_NULL, /* doing_getsock */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700129 ZERO_NULL, /* domore_getsock */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700130 ZERO_NULL, /* perform_getsock */
131 ldap_disconnect, /* disconnect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700132 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700133 ZERO_NULL, /* connection_check */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700134 PORT_LDAPS, /* defport */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700135 CURLPROTO_LDAP, /* protocol */
136 PROTOPT_SSL /* flags */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700137};
138#endif
139
140static const char *url_errs[] = {
141 "success",
142 "out of memory",
143 "bad parameter",
144 "unrecognized scheme",
145 "unbalanced delimiter",
146 "bad URL",
147 "bad host or port",
148 "bad or missing attributes",
149 "bad or missing scope",
150 "bad or missing filter",
151 "bad or missing extensions"
152};
153
154typedef struct ldapconninfo {
155 LDAP *ld;
156 Curl_recv *recv; /* for stacking SSL handler */
157 Curl_send *send;
158 int proto;
159 int msgid;
160 bool ssldone;
161 bool sslinst;
162 bool didbind;
163} ldapconninfo;
164
165typedef struct ldapreqinfo {
166 int msgid;
167 int nument;
168} ldapreqinfo;
169
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700170static CURLcode ldap_setup_connection(struct connectdata *conn)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700171{
172 ldapconninfo *li;
173 LDAPURLDesc *lud;
Alex Deymo486467e2017-12-19 19:04:07 +0100174 struct Curl_easy *data = conn->data;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700175 int rc, proto;
176 CURLcode status;
177
178 rc = ldap_url_parse(data->change.url, &lud);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700179 if(rc != LDAP_URL_SUCCESS) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700180 const char *msg = "url parsing problem";
181 status = CURLE_URL_MALFORMAT;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700182 if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
183 if(rc == LDAP_URL_ERR_MEM)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700184 status = CURLE_OUT_OF_MEMORY;
185 msg = url_errs[rc];
186 }
187 failf(conn->data, "LDAP local: %s", msg);
188 return status;
189 }
190 proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
191 ldap_free_urldesc(lud);
192
193 li = calloc(1, sizeof(ldapconninfo));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700194 if(!li)
195 return CURLE_OUT_OF_MEMORY;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700196 li->proto = proto;
197 conn->proto.generic = li;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700198 connkeep(conn, "OpenLDAP default");
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700199 /* TODO:
200 * - provide option to choose SASL Binds instead of Simple
201 */
202 return CURLE_OK;
203}
204
205#ifdef USE_SSL
206static Sockbuf_IO ldapsb_tls;
207#endif
208
209static CURLcode ldap_connect(struct connectdata *conn, bool *done)
210{
211 ldapconninfo *li = conn->proto.generic;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700212 struct Curl_easy *data = conn->data;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700213 int rc, proto = LDAP_VERSION3;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700214 char hosturl[1024];
215 char *ptr;
216
217 (void)done;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700218
219 strcpy(hosturl, "ldap");
Alex Deymo486467e2017-12-19 19:04:07 +0100220 ptr = hosturl + 4;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700221 if(conn->handler->flags & PROTOPT_SSL)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700222 *ptr++ = 's';
223 snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700224 conn->host.name, conn->remote_port);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700225
Elliott Hughes0128fe42018-02-27 14:57:55 -0800226#ifdef CURL_OPENLDAP_DEBUG
227 static int do_trace = 0;
228 const char *env = getenv("CURL_OPENLDAP_TRACE");
229 do_trace = (env && strtol(env, NULL, 10) > 0);
230 if(do_trace) {
231 ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
232 }
233#endif
234
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700235 rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700236 if(rc) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700237 failf(data, "LDAP local: Cannot connect to %s, %s",
238 hosturl, ldap_err2string(rc));
239 return CURLE_COULDNT_CONNECT;
240 }
241
242 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
243
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700244#ifdef USE_SSL
245 if(conn->handler->flags & PROTOPT_SSL) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700246 CURLcode result;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700247 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
248 if(result)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700249 return result;
250 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700251#endif
252
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700253 return CURLE_OK;
254}
255
256static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
257{
258 ldapconninfo *li = conn->proto.generic;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700259 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700260 LDAPMessage *msg = NULL;
261 struct timeval tv = {0, 1}, *tvp;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700262 int rc, err;
263 char *info = NULL;
264
265#ifdef USE_SSL
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700266 if(conn->handler->flags & PROTOPT_SSL) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700267 /* Is the SSL handshake complete yet? */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700268 if(!li->ssldone) {
269 CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
270 &li->ssldone);
271 if(result || !li->ssldone)
272 return result;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700273 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700274
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700275 /* Have we installed the libcurl SSL handlers into the sockbuf yet? */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700276 if(!li->sslinst) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700277 Sockbuf *sb;
278 ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
279 ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn);
280 li->sslinst = TRUE;
281 li->recv = conn->recv[FIRSTSOCKET];
282 li->send = conn->send[FIRSTSOCKET];
283 }
284 }
285#endif
286
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700287 tvp = &tv;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700288
289retry:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700290 if(!li->didbind) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700291 char *binddn;
292 struct berval passwd;
293
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700294 if(conn->bits.user_passwd) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700295 binddn = conn->user;
296 passwd.bv_val = conn->passwd;
297 passwd.bv_len = strlen(passwd.bv_val);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700298 }
299 else {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700300 binddn = NULL;
301 passwd.bv_val = NULL;
302 passwd.bv_len = 0;
303 }
304 rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
305 NULL, NULL, &li->msgid);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700306 if(rc)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700307 return CURLE_LDAP_CANNOT_BIND;
308 li->didbind = TRUE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700309 if(tvp)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700310 return CURLE_OK;
311 }
312
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700313 rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg);
314 if(rc < 0) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700315 failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc));
316 return CURLE_LDAP_CANNOT_BIND;
317 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700318 if(rc == 0) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700319 /* timed out */
320 return CURLE_OK;
321 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700322
323 rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1);
324 if(rc) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700325 failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc));
326 return CURLE_LDAP_CANNOT_BIND;
327 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700328
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700329 /* Try to fallback to LDAPv2? */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700330 if(err == LDAP_PROTOCOL_ERROR) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700331 int proto;
332 ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700333 if(proto == LDAP_VERSION3) {
334 if(info) {
335 ldap_memfree(info);
336 info = NULL;
337 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700338 proto = LDAP_VERSION2;
339 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
340 li->didbind = FALSE;
341 goto retry;
342 }
343 }
344
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700345 if(err) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700346 failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc),
347 info ? info : "");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700348 if(info)
349 ldap_memfree(info);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700350 return CURLE_LOGIN_DENIED;
351 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700352
353 if(info)
354 ldap_memfree(info);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700355 conn->recv[FIRSTSOCKET] = ldap_recv;
356 *done = TRUE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700357
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700358 return CURLE_OK;
359}
360
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700361static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700362{
363 ldapconninfo *li = conn->proto.generic;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700364 (void) dead_connection;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700365
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700366 if(li) {
367 if(li->ld) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700368 ldap_unbind_ext(li->ld, NULL, NULL);
369 li->ld = NULL;
370 }
371 conn->proto.generic = NULL;
372 free(li);
373 }
374 return CURLE_OK;
375}
376
377static CURLcode ldap_do(struct connectdata *conn, bool *done)
378{
379 ldapconninfo *li = conn->proto.generic;
380 ldapreqinfo *lr;
381 CURLcode status = CURLE_OK;
382 int rc = 0;
383 LDAPURLDesc *ludp = NULL;
384 int msgid;
Alex Deymo486467e2017-12-19 19:04:07 +0100385 struct Curl_easy *data = conn->data;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700386
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700387 connkeep(conn, "OpenLDAP do");
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700388
389 infof(data, "LDAP local: %s\n", data->change.url);
390
391 rc = ldap_url_parse(data->change.url, &ludp);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700392 if(rc != LDAP_URL_SUCCESS) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700393 const char *msg = "url parsing problem";
394 status = CURLE_URL_MALFORMAT;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700395 if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
396 if(rc == LDAP_URL_ERR_MEM)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700397 status = CURLE_OUT_OF_MEMORY;
398 msg = url_errs[rc];
399 }
400 failf(conn->data, "LDAP local: %s", msg);
401 return status;
402 }
403
404 rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope,
405 ludp->lud_filter, ludp->lud_attrs, 0,
406 NULL, NULL, NULL, 0, &msgid);
407 ldap_free_urldesc(ludp);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700408 if(rc != LDAP_SUCCESS) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700409 failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
410 return CURLE_LDAP_SEARCH_FAILED;
411 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700412 lr = calloc(1, sizeof(ldapreqinfo));
413 if(!lr)
414 return CURLE_OUT_OF_MEMORY;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700415 lr->msgid = msgid;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700416 data->req.protop = lr;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700417 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
418 *done = TRUE;
419 return CURLE_OK;
420}
421
422static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
423 bool premature)
424{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700425 ldapreqinfo *lr = conn->data->req.protop;
426
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700427 (void)res;
428 (void)premature;
429
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700430 if(lr) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700431 /* if there was a search in progress, abandon it */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700432 if(lr->msgid) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700433 ldapconninfo *li = conn->proto.generic;
434 ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
435 lr->msgid = 0;
436 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700437 conn->data->req.protop = NULL;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700438 free(lr);
439 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700440
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700441 return CURLE_OK;
442}
443
444static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
445 size_t len, CURLcode *err)
446{
447 ldapconninfo *li = conn->proto.generic;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700448 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700449 ldapreqinfo *lr = data->req.protop;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700450 int rc, ret;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700451 LDAPMessage *msg = NULL;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700452 LDAPMessage *ent;
453 BerElement *ber = NULL;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700454 struct timeval tv = {0, 1};
455
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700456 (void)len;
457 (void)buf;
458 (void)sockindex;
459
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700460 rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg);
461 if(rc < 0) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700462 failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
463 *err = CURLE_RECV_ERROR;
464 return -1;
465 }
466
467 *err = CURLE_AGAIN;
468 ret = -1;
469
470 /* timed out */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700471 if(!msg)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700472 return ret;
473
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700474 for(ent = ldap_first_message(li->ld, msg); ent;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700475 ent = ldap_next_message(li->ld, ent)) {
476 struct berval bv, *bvals, **bvp = &bvals;
477 int binary = 0, msgtype;
Alex Deymod15eaac2016-06-28 14:49:26 -0700478 CURLcode writeerr;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700479
480 msgtype = ldap_msgtype(ent);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700481 if(msgtype == LDAP_RES_SEARCH_RESULT) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700482 int code;
483 char *info = NULL;
484 rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700485 if(rc) {
486 failf(data, "LDAP local: search ldap_parse_result %s",
487 ldap_err2string(rc));
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700488 *err = CURLE_LDAP_SEARCH_FAILED;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700489 }
490 else if(code && code != LDAP_SIZELIMIT_EXCEEDED) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700491 failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc),
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700492 info ? info : "");
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700493 *err = CURLE_LDAP_SEARCH_FAILED;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700494 }
495 else {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700496 /* successful */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700497 if(code == LDAP_SIZELIMIT_EXCEEDED)
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700498 infof(data, "There are more than %d entries\n", lr->nument);
499 data->req.size = data->req.bytecount;
500 *err = CURLE_OK;
501 ret = 0;
502 }
503 lr->msgid = 0;
504 ldap_memfree(info);
505 break;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700506 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700507 else if(msgtype != LDAP_RES_SEARCH_ENTRY)
508 continue;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700509
510 lr->nument++;
511 rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700512 if(rc < 0) {
513 /* TODO: verify that this is really how this return code should be
514 handled */
515 *err = CURLE_RECV_ERROR;
516 return -1;
517 }
Alex Deymod15eaac2016-06-28 14:49:26 -0700518 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
519 if(writeerr) {
520 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700521 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700522 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700523
Alex Deymod15eaac2016-06-28 14:49:26 -0700524 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
525 bv.bv_len);
526 if(writeerr) {
527 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700528 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700529 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700530
Alex Deymod15eaac2016-06-28 14:49:26 -0700531 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
532 if(writeerr) {
533 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700534 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700535 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700536 data->req.bytecount += bv.bv_len + 5;
537
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700538 for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700539 rc == LDAP_SUCCESS;
540 rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp)) {
541 int i;
542
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700543 if(bv.bv_val == NULL) break;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700544
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700545 if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700546 binary = 1;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700547 else
548 binary = 0;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700549
Alex Deymo486467e2017-12-19 19:04:07 +0100550 for(i = 0; bvals[i].bv_val != NULL; i++) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700551 int binval = 0;
Alex Deymod15eaac2016-06-28 14:49:26 -0700552 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
553 if(writeerr) {
554 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700555 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700556 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700557
Alex Deymod15eaac2016-06-28 14:49:26 -0700558 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
559 bv.bv_len);
560 if(writeerr) {
561 *err = writeerr;
562 return -1;
563 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700564
Alex Deymod15eaac2016-06-28 14:49:26 -0700565 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
566 if(writeerr) {
567 *err = writeerr;
568 return -1;
569 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700570 data->req.bytecount += bv.bv_len + 2;
571
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700572 if(!binary) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700573 /* check for leading or trailing whitespace */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700574 if(ISSPACE(bvals[i].bv_val[0]) ||
575 ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700576 binval = 1;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700577 else {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700578 /* check for unprintable characters */
579 unsigned int j;
Alex Deymo486467e2017-12-19 19:04:07 +0100580 for(j = 0; j<bvals[i].bv_len; j++)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700581 if(!ISPRINT(bvals[i].bv_val[j])) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700582 binval = 1;
583 break;
584 }
585 }
586 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700587 if(binary || binval) {
588 char *val_b64 = NULL;
589 size_t val_b64_sz = 0;
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700590 /* Binary value, encode to base64. */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700591 CURLcode error = Curl_base64_encode(data,
592 bvals[i].bv_val,
593 bvals[i].bv_len,
594 &val_b64,
595 &val_b64_sz);
596 if(error) {
597 ber_memfree(bvals);
598 ber_free(ber, 0);
599 ldap_msgfree(msg);
600 *err = error;
601 return -1;
602 }
Alex Deymod15eaac2016-06-28 14:49:26 -0700603 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY,
604 (char *)": ", 2);
605 if(writeerr) {
606 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700607 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700608 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700609
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700610 data->req.bytecount += 2;
611 if(val_b64_sz > 0) {
Alex Deymod15eaac2016-06-28 14:49:26 -0700612 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700613 val_b64_sz);
Alex Deymod15eaac2016-06-28 14:49:26 -0700614 if(writeerr) {
615 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700616 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700617 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700618 free(val_b64);
619 data->req.bytecount += val_b64_sz;
620 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700621 }
622 else {
Alex Deymod15eaac2016-06-28 14:49:26 -0700623 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
624 if(writeerr) {
625 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700626 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700627 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700628
Alex Deymod15eaac2016-06-28 14:49:26 -0700629 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
630 bvals[i].bv_len);
631 if(writeerr) {
632 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700633 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700634 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700635
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700636 data->req.bytecount += bvals[i].bv_len + 1;
637 }
Alex Deymod15eaac2016-06-28 14:49:26 -0700638 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
639 if(writeerr) {
640 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700641 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700642 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700643
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700644 data->req.bytecount++;
645 }
646 ber_memfree(bvals);
Alex Deymod15eaac2016-06-28 14:49:26 -0700647 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
648 if(writeerr) {
649 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700650 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700651 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700652 data->req.bytecount++;
653 }
Alex Deymod15eaac2016-06-28 14:49:26 -0700654 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
655 if(writeerr) {
656 *err = writeerr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700657 return -1;
Alex Deymod15eaac2016-06-28 14:49:26 -0700658 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700659 data->req.bytecount++;
660 ber_free(ber, 0);
661 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700662 ldap_msgfree(msg);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700663 return ret;
664}
665
666#ifdef USE_SSL
667static int
668ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
669{
670 sbiod->sbiod_pvt = arg;
671 return 0;
672}
673
674static int
675ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
676{
677 sbiod->sbiod_pvt = NULL;
678 return 0;
679}
680
681/* We don't need to do anything because libcurl does it already */
682static int
683ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
684{
685 (void)sbiod;
686 return 0;
687}
688
689static int
690ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
691{
692 (void)arg;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700693 if(opt == LBER_SB_OPT_DATA_READY) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700694 struct connectdata *conn = sbiod->sbiod_pvt;
695 return Curl_ssl_data_pending(conn, FIRSTSOCKET);
696 }
697 return 0;
698}
699
700static ber_slen_t
701ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
702{
703 struct connectdata *conn = sbiod->sbiod_pvt;
704 ldapconninfo *li = conn->proto.generic;
705 ber_slen_t ret;
706 CURLcode err = CURLE_RECV_ERROR;
707
Alex Deymo486467e2017-12-19 19:04:07 +0100708 ret = (li->recv)(conn, FIRSTSOCKET, buf, len, &err);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700709 if(ret < 0 && err == CURLE_AGAIN) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700710 SET_SOCKERRNO(EWOULDBLOCK);
711 }
712 return ret;
713}
714
715static ber_slen_t
716ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
717{
718 struct connectdata *conn = sbiod->sbiod_pvt;
719 ldapconninfo *li = conn->proto.generic;
720 ber_slen_t ret;
721 CURLcode err = CURLE_SEND_ERROR;
722
Alex Deymo486467e2017-12-19 19:04:07 +0100723 ret = (li->send)(conn, FIRSTSOCKET, buf, len, &err);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700724 if(ret < 0 && err == CURLE_AGAIN) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700725 SET_SOCKERRNO(EWOULDBLOCK);
726 }
727 return ret;
728}
729
730static Sockbuf_IO ldapsb_tls =
731{
732 ldapsb_tls_setup,
733 ldapsb_tls_remove,
734 ldapsb_tls_ctrl,
735 ldapsb_tls_read,
736 ldapsb_tls_write,
737 ldapsb_tls_close
738};
739#endif /* USE_SSL */
740
741#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */