LCOV - code coverage report
Current view: top level - source4/libcli/ldap - ldap_client.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 330 502 65.7 %
Date: 2024-04-21 15:09:00 Functions: 24 29 82.8 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    LDAP protocol helper functions for SAMBA
       4             :    
       5             :    Copyright (C) Andrew Tridgell  2004
       6             :    Copyright (C) Volker Lendecke 2004
       7             :    Copyright (C) Stefan Metzmacher 2004
       8             :    Copyright (C) Simo Sorce 2004
       9             :     
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             :    
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             :    
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             :    
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include <tevent.h>
      27             : #include "lib/socket/socket.h"
      28             : #include "lib/tsocket/tsocket.h"
      29             : #include "libcli/util/tstream.h"
      30             : #include "../lib/util/asn1.h"
      31             : #include "../lib/util/dlinklist.h"
      32             : #include "libcli/ldap/libcli_ldap.h"
      33             : #include "libcli/ldap/ldap_proto.h"
      34             : #include "libcli/ldap/ldap_client.h"
      35             : #include "libcli/composite/composite.h"
      36             : #include "lib/tls/tls.h"
      37             : #include "auth/gensec/gensec.h"
      38             : #include "system/time.h"
      39             : #include "param/param.h"
      40             : #include "libcli/resolve/resolve.h"
      41             : 
      42             : static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status);
      43             : 
      44       26716 : static int ldap_connection_destructor(struct ldap_connection *conn)
      45             : {
      46             :         /*
      47             :          * NT_STATUS_OK means that callbacks of pending requests are not
      48             :          * triggered
      49             :          */
      50       26716 :         ldap_connection_dead(conn, NT_STATUS_OK);
      51       26716 :         return 0;
      52             : }
      53             : 
      54             : /**
      55             :   create a new ldap_connection structure. The event context is optional
      56             : */
      57             : 
      58       26716 : _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx, 
      59             :                                              struct loadparm_context *lp_ctx,
      60             :                                              struct tevent_context *ev)
      61             : {
      62         122 :         struct ldap_connection *conn;
      63             : 
      64       26716 :         if (ev == NULL) {
      65           0 :                 return NULL;
      66             :         }
      67             : 
      68       26716 :         conn = talloc_zero(mem_ctx, struct ldap_connection);
      69       26716 :         if (conn == NULL) {
      70           0 :                 return NULL;
      71             :         }
      72             : 
      73       26716 :         conn->next_messageid  = 1;
      74       26716 :         conn->event.event_ctx = ev;
      75             : 
      76       26716 :         conn->sockets.send_queue = tevent_queue_create(conn,
      77             :                                         "ldap_connection send_queue");
      78       26716 :         if (conn->sockets.send_queue == NULL) {
      79           0 :                 TALLOC_FREE(conn);
      80           0 :                 return NULL;
      81             :         }
      82             : 
      83       26716 :         conn->lp_ctx = lp_ctx;
      84             : 
      85             :         /* set a reasonable request timeout */
      86       26716 :         conn->timeout = 60;
      87             : 
      88             :         /* explicitly avoid reconnections by default */
      89       26716 :         conn->reconnect.max_retries = 0;
      90             : 
      91       26716 :         talloc_set_destructor(conn, ldap_connection_destructor);
      92       26716 :         return conn;
      93             : }
      94             : 
      95             : /*
      96             :   the connection is dead
      97             : */
      98       26716 : static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status)
      99             : {
     100         122 :         struct ldap_request *req;
     101             : 
     102       26716 :         tevent_queue_stop(conn->sockets.send_queue);
     103       26716 :         TALLOC_FREE(conn->sockets.recv_subreq);
     104       26716 :         conn->sockets.active = NULL;
     105       26716 :         TALLOC_FREE(conn->sockets.sasl);
     106       26716 :         TALLOC_FREE(conn->sockets.tls);
     107       26716 :         TALLOC_FREE(conn->sockets.raw);
     108             : 
     109             :         /* return an error for any pending request ... */
     110       26782 :         while (conn->pending) {
     111          66 :                 req = conn->pending;
     112          66 :                 DLIST_REMOVE(req->conn->pending, req);
     113          66 :                 req->conn = NULL;
     114          66 :                 req->state = LDAP_REQUEST_DONE;
     115          66 :                 if (NT_STATUS_IS_OK(status)) {
     116          66 :                         continue;
     117             :                 }
     118           0 :                 req->status = status;
     119           0 :                 if (req->async.fn) {
     120           0 :                         req->async.fn(req);
     121             :                 }
     122             :         }
     123       26716 : }
     124             : 
     125             : static void ldap_reconnect(struct ldap_connection *conn);
     126             : 
     127             : /*
     128             :   handle packet errors
     129             : */
     130           0 : static void ldap_error_handler(struct ldap_connection *conn, NTSTATUS status)
     131             : {
     132           0 :         ldap_connection_dead(conn, status);
     133             : 
     134             :         /* but try to reconnect so that the ldb client can go on */
     135           0 :         ldap_reconnect(conn);
     136           0 : }
     137             : 
     138             : 
     139             : /*
     140             :   match up with a pending message, adding to the replies list
     141             : */
     142     1395562 : static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg)
     143             : {
     144        1116 :         struct ldap_request *req;
     145        1116 :         int i;
     146             : 
     147     1396075 :         for (req=conn->pending; req; req=req->next) {
     148     1396074 :                 if (req->messageid == msg->messageid) break;
     149             :         }
     150             :         /* match a zero message id to the last request sent.
     151             :            It seems that servers send 0 if unable to parse */
     152     1395562 :         if (req == NULL && msg->messageid == 0) {
     153           1 :                 req = conn->pending;
     154             :         }
     155     1395562 :         if (req == NULL) {
     156           0 :                 DEBUG(0,("ldap: no matching message id for %u\n",
     157             :                          msg->messageid));
     158           0 :                 TALLOC_FREE(msg);
     159           0 :                 return;
     160             :         }
     161             : 
     162             :         /* Check for undecoded critical extensions */
     163     1516591 :         for (i=0; msg->controls && msg->controls[i]; i++) {
     164      121029 :                 if (!msg->controls_decoded[i] && 
     165           0 :                     msg->controls[i]->critical) {
     166           0 :                         TALLOC_FREE(msg);
     167           0 :                         req->status = NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION);
     168           0 :                         req->state = LDAP_REQUEST_DONE;
     169           0 :                         DLIST_REMOVE(conn->pending, req);
     170           0 :                         if (req->async.fn) {
     171           0 :                                 req->async.fn(req);
     172             :                         }
     173           0 :                         return;
     174             :                 }
     175             :         }
     176             : 
     177             :         /* add to the list of replies received */
     178     1395562 :         req->replies = talloc_realloc(req, req->replies, 
     179             :                                       struct ldap_message *, req->num_replies+1);
     180     1395562 :         if (req->replies == NULL) {
     181           0 :                 TALLOC_FREE(msg);
     182           0 :                 req->status = NT_STATUS_NO_MEMORY;
     183           0 :                 req->state = LDAP_REQUEST_DONE;
     184           0 :                 DLIST_REMOVE(conn->pending, req);
     185           0 :                 if (req->async.fn) {
     186           0 :                         req->async.fn(req);
     187             :                 }
     188           0 :                 return;
     189             :         }
     190             : 
     191     1395562 :         req->replies[req->num_replies] = talloc_steal(req->replies, msg);
     192     1395562 :         req->num_replies++;
     193             : 
     194     1395562 :         if (msg->type != LDAP_TAG_SearchResultEntry &&
     195      762181 :             msg->type != LDAP_TAG_SearchResultReference) {
     196             :                 /* currently only search results expect multiple
     197             :                    replies */
     198      629758 :                 req->state = LDAP_REQUEST_DONE;
     199      629758 :                 DLIST_REMOVE(conn->pending, req);
     200             :         }
     201             : 
     202     1395562 :         if (req->async.fn) {
     203     1307246 :                 req->async.fn(req);
     204             :         }
     205             : }
     206             : 
     207             : static void ldap_connection_recv_done(struct tevent_req *subreq);
     208             : 
     209     2025399 : static void ldap_connection_recv_next(struct ldap_connection *conn)
     210             : {
     211     2025399 :         struct tevent_req *subreq = NULL;
     212             : 
     213     2025399 :         if (conn->sockets.recv_subreq != NULL) {
     214        4794 :                 return;
     215             :         }
     216             : 
     217     2020605 :         if (conn->sockets.active == NULL) {
     218           0 :                 return;
     219             :         }
     220             : 
     221     2020605 :         if (conn->pending == NULL) {
     222      624268 :                 return;
     223             :         }
     224             : 
     225             :         /*
     226             :          * The minimum size of a LDAP pdu is 7 bytes
     227             :          *
     228             :          * dumpasn1 -hh ldap-unbind-min.dat
     229             :          *
     230             :          *     <30 05 02 01 09 42 00>
     231             :          *    0    5: SEQUENCE {
     232             :          *     <02 01 09>
     233             :          *    2    1:   INTEGER 9
     234             :          *     <42 00>
     235             :          *    5    0:   [APPLICATION 2]
     236             :          *          :     Error: Object has zero length.
     237             :          *          :   }
     238             :          *
     239             :          * dumpasn1 -hh ldap-unbind-windows.dat
     240             :          *
     241             :          *     <30 84 00 00 00 05 02 01 09 42 00>
     242             :          *    0    5: SEQUENCE {
     243             :          *     <02 01 09>
     244             :          *    6    1:   INTEGER 9
     245             :          *     <42 00>
     246             :          *    9    0:   [APPLICATION 2]
     247             :          *          :     Error: Object has zero length.
     248             :          *          :   }
     249             :          *
     250             :          * This means using an initial read size
     251             :          * of 7 is ok.
     252             :          */
     253     1395628 :         subreq = tstream_read_pdu_blob_send(conn,
     254             :                                             conn->event.event_ctx,
     255             :                                             conn->sockets.active,
     256             :                                             7, /* initial_read_size */
     257             :                                             ldap_full_packet,
     258             :                                             conn);
     259     1395628 :         if (subreq == NULL) {
     260           0 :                 ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
     261           0 :                 return;
     262             :         }
     263     1395628 :         tevent_req_set_callback(subreq, ldap_connection_recv_done, conn);
     264     1395628 :         conn->sockets.recv_subreq = subreq;
     265     1395628 :         return;
     266             : }
     267             : 
     268             : /*
     269             :   decode/process LDAP data
     270             : */
     271     1395562 : static void ldap_connection_recv_done(struct tevent_req *subreq)
     272             : {
     273        1116 :         NTSTATUS status;
     274        1116 :         struct ldap_connection *conn =
     275     1395562 :                 tevent_req_callback_data(subreq,
     276             :                 struct ldap_connection);
     277        1116 :         struct ldap_message *msg;
     278        1116 :         struct asn1_data *asn1;
     279        1116 :         DATA_BLOB blob;
     280     1395562 :         struct ldap_request_limits limits = {0};
     281             : 
     282     1395562 :         msg = talloc_zero(conn, struct ldap_message);
     283     1395562 :         if (msg == NULL) {
     284           0 :                 ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
     285           0 :                 return;
     286             :         }
     287             : 
     288     1395562 :         asn1 = asn1_init(conn, ASN1_MAX_TREE_DEPTH);
     289     1395562 :         if (asn1 == NULL) {
     290           0 :                 TALLOC_FREE(msg);
     291           0 :                 ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
     292           0 :                 return;
     293             :         }
     294             : 
     295     1395562 :         conn->sockets.recv_subreq = NULL;
     296             : 
     297     1395562 :         status = tstream_read_pdu_blob_recv(subreq,
     298             :                                             asn1,
     299             :                                             &blob);
     300     1395562 :         TALLOC_FREE(subreq);
     301     1395562 :         if (!NT_STATUS_IS_OK(status)) {
     302           0 :                 TALLOC_FREE(msg);
     303           0 :                 asn1_free(asn1);
     304           0 :                 ldap_error_handler(conn, status);
     305           0 :                 return;
     306             :         }
     307             : 
     308     1395562 :         asn1_load_nocopy(asn1, blob.data, blob.length);
     309             : 
     310     1395562 :         status = ldap_decode(asn1, &limits, samba_ldap_control_handlers(), msg);
     311     1395562 :         asn1_free(asn1);
     312     1395562 :         if (!NT_STATUS_IS_OK(status)) {
     313           0 :                 TALLOC_FREE(msg);
     314           0 :                 ldap_error_handler(conn, status);
     315           0 :                 return;
     316             :         }
     317             : 
     318     1395562 :         ldap_match_message(conn, msg);
     319     1395562 :         ldap_connection_recv_next(conn);
     320             : 
     321     1395562 :         return;
     322             : }
     323             : 
     324             : enum ldap_proto {
     325             :         LDAP_PROTO_NONE,
     326             :         LDAP_PROTO_LDAP,
     327             :         LDAP_PROTO_LDAPS,
     328             :         LDAP_PROTO_LDAPI
     329             : };
     330             : 
     331       26716 : static int ldap_parse_basic_url(
     332             :         const char *url,
     333             :         enum ldap_proto *pproto,
     334             :         TALLOC_CTX *mem_ctx,
     335             :         char **pdest,           /* path for ldapi, host for ldap[s] */
     336             :         uint16_t *pport)        /* Not set for ldapi */
     337             : {
     338       26716 :         enum ldap_proto proto = LDAP_PROTO_NONE;
     339       26716 :         char *host = NULL;
     340         122 :         int ret, port;
     341             : 
     342       26716 :         if (url == NULL) {
     343           0 :                 return EINVAL;
     344             :         }
     345             : 
     346       26716 :         if (strncasecmp_m(url, "ldapi://", strlen("ldapi://")) == 0) {
     347         108 :                 char *path = NULL, *end = NULL;
     348             : 
     349         108 :                 path = talloc_strdup(mem_ctx, url+8);
     350         108 :                 if (path == NULL) {
     351           0 :                         return ENOMEM;
     352             :                 }
     353         108 :                 end = rfc1738_unescape(path);
     354         108 :                 if (end == NULL) {
     355           0 :                         TALLOC_FREE(path);
     356           0 :                         return EINVAL;
     357             :                 }
     358             : 
     359         108 :                 *pproto = LDAP_PROTO_LDAPI;
     360         108 :                 *pdest = path;
     361         108 :                 return 0;
     362             :         }
     363             : 
     364       26608 :         if (strncasecmp_m(url, "ldap://", strlen("ldap://")) == 0) {
     365       26131 :                 url += 7;
     366       26131 :                 proto = LDAP_PROTO_LDAP;
     367       26131 :                 port = 389;
     368             :         }
     369       26608 :         if (strncasecmp_m(url, "ldaps://", strlen("ldaps://")) == 0) {
     370         477 :                 url += 8;
     371         477 :                 port = 636;
     372         477 :                 proto = LDAP_PROTO_LDAPS;
     373             :         }
     374             : 
     375       26608 :         if (proto == LDAP_PROTO_NONE) {
     376           0 :                 return EPROTONOSUPPORT;
     377             :         }
     378             : 
     379       26608 :         if (url[0] == '[') {
     380             :                 /*
     381             :                  * IPv6 with [aa:bb:cc..]:port
     382             :                  */
     383           0 :                 const char *end = NULL;
     384             : 
     385           0 :                 url +=1;
     386             : 
     387           0 :                 end = strchr(url, ']');
     388           0 :                 if (end == NULL) {
     389           0 :                         return EINVAL;
     390             :                 }
     391             : 
     392           0 :                 ret = sscanf(end+1, ":%d", &port);
     393           0 :                 if (ret < 0) {
     394           0 :                         return EINVAL;
     395             :                 }
     396             : 
     397           0 :                 *pdest = talloc_strndup(mem_ctx, url, end-url);
     398           0 :                 if (*pdest == NULL) {
     399           0 :                         return ENOMEM;
     400             :                 }
     401           0 :                 *pproto = proto;
     402           0 :                 *pport = port;
     403           0 :                 return 0;
     404             :         }
     405             : 
     406       26608 :         ret = sscanf(url, "%m[^:/]:%d", &host, &port);
     407       26608 :         if (ret < 1) {
     408           0 :                 return EINVAL;
     409             :         }
     410             : 
     411       26608 :         *pdest = talloc_strdup(mem_ctx, host);
     412       26608 :         SAFE_FREE(host);
     413       26608 :         if (*pdest == NULL) {
     414           0 :                 return ENOMEM;
     415             :         }
     416       26608 :         *pproto = proto;
     417       26608 :         *pport = port;
     418             : 
     419       26608 :         return 0;
     420             : }
     421             : 
     422             : /*
     423             :   connect to a ldap server
     424             : */
     425             : 
     426             : struct ldap_connect_state {
     427             :         struct composite_context *ctx;
     428             :         struct ldap_connection *conn;
     429             :         struct socket_context *sock;
     430             :         struct tstream_context *raw;
     431             :         struct tstream_tls_params *tls_params;
     432             :         struct tstream_context *tls;
     433             : };
     434             : 
     435             : static void ldap_connect_recv_unix_conn(struct composite_context *ctx);
     436             : static void ldap_connect_recv_tcp_conn(struct composite_context *ctx);
     437             : 
     438       26716 : _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
     439             :                                             const char *url)
     440             : {
     441         122 :         struct composite_context *result, *ctx;
     442         122 :         struct ldap_connect_state *state;
     443         122 :         enum ldap_proto proto;
     444       26716 :         char *dest = NULL;
     445         122 :         uint16_t port;
     446         122 :         int ret;
     447             : 
     448       26716 :         result = talloc_zero(conn, struct composite_context);
     449       26716 :         if (result == NULL) goto failed;
     450       26716 :         result->state = COMPOSITE_STATE_IN_PROGRESS;
     451       26716 :         result->async.fn = NULL;
     452       26716 :         result->event_ctx = conn->event.event_ctx;
     453             : 
     454       26716 :         state = talloc(result, struct ldap_connect_state);
     455       26716 :         if (state == NULL) goto failed;
     456       26716 :         state->ctx = result;
     457       26716 :         result->private_data = state;
     458             : 
     459       26716 :         state->conn = conn;
     460             : 
     461       26716 :         if (conn->reconnect.url == NULL) {
     462       26716 :                 conn->reconnect.url = talloc_strdup(conn, url);
     463       26716 :                 if (conn->reconnect.url == NULL) goto failed;
     464             :         }
     465             : 
     466       26716 :         ret = ldap_parse_basic_url(url, &proto, conn, &dest, &port);
     467       26716 :         if (ret != 0) {
     468           0 :                 composite_error(result, map_nt_error_from_unix_common(ret));
     469           0 :                 return result;
     470             :         }
     471             : 
     472       26716 :         if (proto == LDAP_PROTO_LDAPI) {
     473           0 :                 struct socket_address *unix_addr;
     474         108 :                 NTSTATUS status = socket_create(state, "unix",
     475             :                                                 SOCKET_TYPE_STREAM,
     476             :                                                 &state->sock, 0);
     477         108 :                 if (!NT_STATUS_IS_OK(status)) {
     478           0 :                         return NULL;
     479             :                 }
     480             : 
     481         108 :                 conn->host = talloc_asprintf(conn, "%s.%s",
     482             :                                              lpcfg_netbios_name(conn->lp_ctx),
     483             :                                              lpcfg_dnsdomain(conn->lp_ctx));
     484         108 :                 if (composite_nomem(conn->host, state->ctx)) {
     485           0 :                         return result;
     486             :                 }
     487             : 
     488         108 :                 unix_addr = socket_address_from_strings(state, state->sock->backend_name,
     489             :                                                         dest, 0);
     490         108 :                 if (composite_nomem(unix_addr, result)) {
     491           0 :                         return result;
     492             :                 }
     493             : 
     494         108 :                 ctx = socket_connect_send(state->sock, NULL, unix_addr,
     495             :                                           0, result->event_ctx);
     496         108 :                 ctx->async.fn = ldap_connect_recv_unix_conn;
     497         108 :                 ctx->async.private_data = state;
     498         108 :                 return result;
     499             :         }
     500             : 
     501       26608 :         if ((proto == LDAP_PROTO_LDAP) || (proto == LDAP_PROTO_LDAPS)) {
     502             : 
     503       26608 :                 conn->ldaps = (proto == LDAP_PROTO_LDAPS);
     504             : 
     505       26608 :                 conn->host = talloc_move(conn, &dest);
     506       26608 :                 conn->port = port;
     507             : 
     508       26608 :                 if (conn->ldaps) {
     509         477 :                         char *ca_file = lpcfg_tls_cafile(state, conn->lp_ctx);
     510         477 :                         char *crl_file = lpcfg_tls_crlfile(state, conn->lp_ctx);
     511         477 :                         const char *tls_priority = lpcfg_tls_priority(conn->lp_ctx);
     512         477 :                         enum tls_verify_peer_state verify_peer =
     513         477 :                                 lpcfg_tls_verify_peer(conn->lp_ctx);
     514           0 :                         NTSTATUS status;
     515             : 
     516         477 :                         status = tstream_tls_params_client(state,
     517             :                                                            ca_file,
     518             :                                                            crl_file,
     519             :                                                            tls_priority,
     520             :                                                            verify_peer,
     521         477 :                                                            conn->host,
     522             :                                                            &state->tls_params);
     523         477 :                         if (!NT_STATUS_IS_OK(status)) {
     524           6 :                                 composite_error(result, status);
     525           6 :                                 return result;
     526             :                         }
     527             :                 }
     528             : 
     529       26602 :                 ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
     530             :                                                 lpcfg_resolve_context(conn->lp_ctx),
     531             :                                                 result->event_ctx);
     532       26602 :                 if (composite_nomem(ctx, result)) {
     533           0 :                         return result;
     534             :                 }
     535             : 
     536       26602 :                 ctx->async.fn = ldap_connect_recv_tcp_conn;
     537       26602 :                 ctx->async.private_data = state;
     538       26602 :                 return result;
     539             :         }
     540           0 :  failed:
     541           0 :         talloc_free(result);
     542           0 :         return NULL;
     543             : }
     544             : 
     545             : static void ldap_connect_got_tls(struct tevent_req *subreq);
     546             : 
     547       26710 : static void ldap_connect_got_sock(struct composite_context *ctx, 
     548             :                                   struct ldap_connection *conn)
     549             : {
     550         122 :         struct ldap_connect_state *state =
     551       26710 :                 talloc_get_type_abort(ctx->private_data,
     552             :                 struct ldap_connect_state);
     553       26710 :         struct tevent_req *subreq = NULL;
     554         122 :         int fd;
     555         122 :         int ret;
     556             : 
     557       26710 :         socket_set_flags(state->sock, SOCKET_FLAG_NOCLOSE);
     558       26710 :         fd = socket_get_fd(state->sock);
     559       26710 :         TALLOC_FREE(state->sock);
     560             : 
     561       26710 :         smb_set_close_on_exec(fd);
     562             : 
     563       26710 :         ret = set_blocking(fd, false);
     564       26710 :         if (ret == -1) {
     565           0 :                 NTSTATUS status = map_nt_error_from_unix_common(errno);
     566           0 :                 composite_error(state->ctx, status);
     567           0 :                 return;
     568             :         }
     569             : 
     570       26710 :         ret = tstream_bsd_existing_socket(state, fd, &state->raw);
     571       26710 :         if (ret == -1) {
     572           0 :                 NTSTATUS status = map_nt_error_from_unix_common(errno);
     573           0 :                 composite_error(state->ctx, status);
     574           0 :                 return;
     575             :         }
     576             : 
     577       26710 :         if (!conn->ldaps) {
     578       26239 :                 conn->sockets.raw = talloc_move(conn, &state->raw);
     579       26239 :                 conn->sockets.active = conn->sockets.raw;
     580       26239 :                 composite_done(state->ctx);
     581       26239 :                 return;
     582             :         }
     583             : 
     584         471 :         subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
     585             :                                           state->raw, state->tls_params);
     586         471 :         if (composite_nomem(subreq, state->ctx)) {
     587           0 :                 return;
     588             :         }
     589         471 :         tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
     590             : }
     591             : 
     592         471 : static void ldap_connect_got_tls(struct tevent_req *subreq)
     593             : {
     594           0 :         struct ldap_connect_state *state =
     595         471 :                 tevent_req_callback_data(subreq,
     596             :                 struct ldap_connect_state);
     597           0 :         int err;
     598           0 :         int ret;
     599             : 
     600         471 :         ret = tstream_tls_connect_recv(subreq, &err, state, &state->tls);
     601         471 :         TALLOC_FREE(subreq);
     602         471 :         if (ret == -1) {
     603          13 :                 NTSTATUS status = map_nt_error_from_unix_common(err);
     604          13 :                 composite_error(state->ctx, status);
     605          13 :                 return;
     606             :         }
     607             : 
     608         458 :         talloc_steal(state->tls, state->tls_params);
     609             : 
     610         458 :         state->conn->sockets.raw = talloc_move(state->conn, &state->raw);
     611         458 :         state->conn->sockets.tls = talloc_move(state->conn->sockets.raw,
     612             :                                                &state->tls);
     613         458 :         state->conn->sockets.active = state->conn->sockets.tls;
     614         458 :         composite_done(state->ctx);
     615             : }
     616             : 
     617       26602 : static void ldap_connect_recv_tcp_conn(struct composite_context *ctx)
     618             : {
     619         122 :         struct ldap_connect_state *state =
     620       26602 :                 talloc_get_type_abort(ctx->async.private_data,
     621             :                 struct ldap_connect_state);
     622       26602 :         struct ldap_connection *conn = state->conn;
     623         122 :         uint16_t port;
     624       26602 :         NTSTATUS status = socket_connect_multi_recv(ctx, state, &state->sock,
     625             :                                                        &port);
     626       26602 :         if (!NT_STATUS_IS_OK(status)) {
     627           0 :                 composite_error(state->ctx, status);
     628           0 :                 return;
     629             :         }
     630             : 
     631       26602 :         ldap_connect_got_sock(state->ctx, conn);
     632             : }
     633             : 
     634         108 : static void ldap_connect_recv_unix_conn(struct composite_context *ctx)
     635             : {
     636           0 :         struct ldap_connect_state *state =
     637         108 :                 talloc_get_type_abort(ctx->async.private_data,
     638             :                 struct ldap_connect_state);
     639         108 :         struct ldap_connection *conn = state->conn;
     640             : 
     641         108 :         NTSTATUS status = socket_connect_recv(ctx);
     642             : 
     643         108 :         if (!NT_STATUS_IS_OK(state->ctx->status)) {
     644           0 :                 composite_error(state->ctx, status);
     645           0 :                 return;
     646             :         }
     647             : 
     648         108 :         ldap_connect_got_sock(state->ctx, conn);
     649             : }
     650             : 
     651       26716 : _PUBLIC_ NTSTATUS ldap_connect_recv(struct composite_context *ctx)
     652             : {
     653       26716 :         NTSTATUS status = composite_wait(ctx);
     654       26716 :         talloc_free(ctx);
     655       26716 :         return status;
     656             : }
     657             : 
     658       26716 : _PUBLIC_ NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
     659             : {
     660       26716 :         struct composite_context *ctx = ldap_connect_send(conn, url);
     661       26716 :         return ldap_connect_recv(ctx);
     662             : }
     663             : 
     664             : /* set reconnect parameters */
     665             : 
     666           0 : _PUBLIC_ void ldap_set_reconn_params(struct ldap_connection *conn, int max_retries)
     667             : {
     668           0 :         if (conn) {
     669           0 :                 conn->reconnect.max_retries = max_retries;
     670           0 :                 conn->reconnect.retries = 0;
     671           0 :                 conn->reconnect.previous = time_mono(NULL);
     672             :         }
     673           0 : }
     674             : 
     675             : /* Actually this function is NOT ASYNC safe, FIXME? */
     676           0 : static void ldap_reconnect(struct ldap_connection *conn)
     677             : {
     678           0 :         NTSTATUS status;
     679           0 :         time_t now = time_mono(NULL);
     680             : 
     681             :         /* do we have set up reconnect ? */
     682           0 :         if (conn->reconnect.max_retries == 0) return;
     683             : 
     684             :         /* is the retry time expired ? */
     685           0 :         if (now > conn->reconnect.previous + 30) {
     686           0 :                 conn->reconnect.retries = 0;
     687           0 :                 conn->reconnect.previous = now;
     688             :         }
     689             : 
     690             :         /* are we reconnectind too often and too fast? */
     691           0 :         if (conn->reconnect.retries > conn->reconnect.max_retries) return;
     692             : 
     693             :         /* keep track of the number of reconnections */
     694           0 :         conn->reconnect.retries++;
     695             : 
     696             :         /* reconnect */
     697           0 :         status = ldap_connect(conn, conn->reconnect.url);
     698           0 :         if ( ! NT_STATUS_IS_OK(status)) {
     699           0 :                 return;
     700             :         }
     701             : 
     702             :         /* rebind */
     703           0 :         status = ldap_rebind(conn);
     704           0 :         if ( ! NT_STATUS_IS_OK(status)) {
     705           0 :                 ldap_connection_dead(conn, status);
     706             :         }
     707             : }
     708             : 
     709          13 : static void ldap_request_destructor_abandon(struct ldap_request *abandon)
     710             : {
     711          13 :         TALLOC_FREE(abandon);
     712          13 : }
     713             : 
     714             : /* destroy an open ldap request */
     715      629918 : static int ldap_request_destructor(struct ldap_request *req)
     716             : {
     717      629918 :         if (req->state == LDAP_REQUEST_PENDING) {
     718          79 :                 struct ldap_message msg = {
     719             :                         .type = LDAP_TAG_AbandonRequest,
     720          79 :                         .r.AbandonRequest.messageid = req->messageid,
     721             :                 };
     722          79 :                 struct ldap_request *abandon = NULL;
     723             : 
     724          79 :                 DLIST_REMOVE(req->conn->pending, req);
     725             : 
     726          79 :                 abandon = ldap_request_send(req->conn, &msg);
     727          79 :                 if (abandon == NULL) {
     728           0 :                         ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
     729           0 :                         return 0;
     730             :                 }
     731          79 :                 abandon->async.fn = ldap_request_destructor_abandon;
     732          79 :                 abandon->async.private_data = NULL;
     733             :         }
     734             : 
     735      629209 :         return 0;
     736             : }
     737             : 
     738           0 : static void ldap_request_timeout_abandon(struct ldap_request *abandon)
     739             : {
     740           0 :         struct ldap_request *req =
     741           0 :                 talloc_get_type_abort(abandon->async.private_data,
     742             :                 struct ldap_request);
     743             : 
     744           0 :         if (req->state == LDAP_REQUEST_PENDING) {
     745           0 :                 DLIST_REMOVE(req->conn->pending, req);
     746             :         }
     747           0 :         req->state = LDAP_REQUEST_DONE;
     748           0 :         if (req->async.fn) {
     749           0 :                 req->async.fn(req);
     750             :         }
     751           0 : }
     752             : 
     753             : /*
     754             :   called on timeout of a ldap request
     755             : */
     756          14 : static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer *te, 
     757             :                                       struct timeval t, void *private_data)
     758             : {
     759           0 :         struct ldap_request *req =
     760          14 :                 talloc_get_type_abort(private_data,
     761             :                 struct ldap_request);
     762             : 
     763          14 :         req->status = NT_STATUS_IO_TIMEOUT;
     764          14 :         if (req->state == LDAP_REQUEST_PENDING) {
     765           0 :                 struct ldap_message msg = {
     766             :                         .type = LDAP_TAG_AbandonRequest,
     767           0 :                         .r.AbandonRequest.messageid = req->messageid,
     768             :                 };
     769           0 :                 struct ldap_request *abandon = NULL;
     770             : 
     771           0 :                 abandon = ldap_request_send(req->conn, &msg);
     772           0 :                 if (abandon == NULL) {
     773           0 :                         ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
     774           0 :                         return;
     775             :                 }
     776           0 :                 talloc_reparent(req->conn, req, abandon);
     777           0 :                 abandon->async.fn = ldap_request_timeout_abandon;
     778           0 :                 abandon->async.private_data = req;
     779           0 :                 DLIST_REMOVE(req->conn->pending, req);
     780           0 :                 return;
     781             :         }
     782          14 :         req->state = LDAP_REQUEST_DONE;
     783          14 :         if (req->async.fn) {
     784           0 :                 req->async.fn(req);
     785             :         }
     786             : }
     787             : 
     788             : 
     789             : /*
     790             :   called on completion of a failed ldap request
     791             : */
     792           0 : static void ldap_request_failed_complete(struct tevent_context *ev, struct tevent_timer *te,
     793             :                                       struct timeval t, void *private_data)
     794             : {
     795           0 :         struct ldap_request *req =
     796           0 :                 talloc_get_type_abort(private_data,
     797             :                 struct ldap_request);
     798             : 
     799           0 :         if (req->async.fn) {
     800           0 :                 req->async.fn(req);
     801             :         }
     802           0 : }
     803             : 
     804             : static void ldap_request_written(struct tevent_req *subreq);
     805             : 
     806             : /*
     807             :   send a ldap message - async interface
     808             : */
     809      629918 : _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
     810             :                                        struct ldap_message *msg)
     811             : {
     812         709 :         struct ldap_request *req;
     813      629918 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
     814      629918 :         struct tevent_req *subreq = NULL;
     815             : 
     816      629918 :         req = talloc_zero(conn, struct ldap_request);
     817      629918 :         if (req == NULL) return NULL;
     818             : 
     819      629918 :         if (conn->sockets.active == NULL) {
     820           0 :                 status = NT_STATUS_INVALID_CONNECTION;
     821           0 :                 goto failed;
     822             :         }
     823             : 
     824      629918 :         req->state       = LDAP_REQUEST_SEND;
     825      629918 :         req->conn        = conn;
     826      629918 :         req->messageid   = conn->next_messageid++;
     827      629918 :         if (conn->next_messageid == 0) {
     828           0 :                 conn->next_messageid = 1;
     829             :         }
     830      629918 :         req->type        = msg->type;
     831      629918 :         if (req->messageid == -1) {
     832           0 :                 goto failed;
     833             :         }
     834             : 
     835      629918 :         talloc_set_destructor(req, ldap_request_destructor);
     836             : 
     837      629918 :         msg->messageid = req->messageid;
     838             : 
     839      629918 :         if (!ldap_encode(msg, samba_ldap_control_handlers(), &req->data, req)) {
     840           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     841           0 :                 goto failed;            
     842             :         }
     843             : 
     844             :         /* put a timeout on the request */
     845      629918 :         req->time_event = tevent_add_timer(conn->event.event_ctx, req,
     846             :                                            timeval_current_ofs(conn->timeout, 0),
     847             :                                            ldap_request_timeout, req);
     848      629918 :         if (req->time_event == NULL) {
     849           0 :                 status = NT_STATUS_NO_MEMORY;
     850           0 :                 goto failed;
     851             :         }
     852             : 
     853      629918 :         req->write_iov.iov_base = req->data.data;
     854      629918 :         req->write_iov.iov_len = req->data.length;
     855             : 
     856      630627 :         subreq = tstream_writev_queue_send(req, conn->event.event_ctx,
     857             :                                            conn->sockets.active,
     858             :                                            conn->sockets.send_queue,
     859      629918 :                                            &req->write_iov, 1);
     860      629918 :         if (subreq == NULL) {
     861           0 :                 status = NT_STATUS_NO_MEMORY;
     862           0 :                 goto failed;
     863             :         }
     864      629918 :         tevent_req_set_callback(subreq, ldap_request_written, req);
     865             : 
     866      629918 :         req->state = LDAP_REQUEST_PENDING;
     867      629918 :         DLIST_ADD(conn->pending, req);
     868             : 
     869      629209 :         return req;
     870             : 
     871           0 : failed:
     872           0 :         req->status = status;
     873           0 :         req->state = LDAP_REQUEST_ERROR;
     874           0 :         tevent_add_timer(conn->event.event_ctx, req, timeval_zero(),
     875             :                          ldap_request_failed_complete, req);
     876             : 
     877           0 :         return req;
     878             : }
     879             : 
     880      629852 : static void ldap_request_written(struct tevent_req *subreq)
     881             : {
     882         709 :         struct ldap_request *req =
     883      629852 :                 tevent_req_callback_data(subreq,
     884             :                 struct ldap_request);
     885         709 :         int err;
     886         709 :         ssize_t ret;
     887             : 
     888      629852 :         ret = tstream_writev_queue_recv(subreq, &err);
     889      629852 :         TALLOC_FREE(subreq);
     890      629852 :         if (ret == -1) {
     891           0 :                 NTSTATUS error = map_nt_error_from_unix_common(err);
     892           0 :                 ldap_error_handler(req->conn, error);
     893           0 :                 return;
     894             :         }
     895             : 
     896      629852 :         if (req->type == LDAP_TAG_AbandonRequest ||
     897      629129 :             req->type == LDAP_TAG_UnbindRequest)
     898             :         {
     899          15 :                 if (req->state == LDAP_REQUEST_PENDING) {
     900          15 :                         DLIST_REMOVE(req->conn->pending, req);
     901             :                 }
     902          15 :                 req->state = LDAP_REQUEST_DONE;
     903          15 :                 if (req->async.fn) {
     904          13 :                         req->async.fn(req);
     905             :                 }
     906          15 :                 return;
     907             :         }
     908             : 
     909      629837 :         ldap_connection_recv_next(req->conn);
     910             : }
     911             : 
     912             : 
     913             : /*
     914             :   wait for a request to complete
     915             :   note that this does not destroy the request
     916             : */
     917         446 : _PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req)
     918             : {
     919        2988 :         while (req->state < LDAP_REQUEST_DONE) {
     920        2542 :                 if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
     921           0 :                         req->state = LDAP_REQUEST_ERROR;
     922           0 :                         req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
     923           0 :                         break;
     924             :                 }
     925             :         }
     926         446 :         return req->status;
     927             : }
     928             : 
     929             : 
     930             : /*
     931             :   a mapping of ldap response code to strings
     932             : */
     933             : static const struct {
     934             :         enum ldap_result_code code;
     935             :         const char *str;
     936             : } ldap_code_map[] = {
     937             : #define _LDAP_MAP_CODE(c) { c, #c }
     938             :         _LDAP_MAP_CODE(LDAP_SUCCESS),
     939             :         _LDAP_MAP_CODE(LDAP_OPERATIONS_ERROR),
     940             :         _LDAP_MAP_CODE(LDAP_PROTOCOL_ERROR),
     941             :         _LDAP_MAP_CODE(LDAP_TIME_LIMIT_EXCEEDED),
     942             :         _LDAP_MAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED),
     943             :         _LDAP_MAP_CODE(LDAP_COMPARE_FALSE),
     944             :         _LDAP_MAP_CODE(LDAP_COMPARE_TRUE),
     945             :         _LDAP_MAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED),
     946             :         _LDAP_MAP_CODE(LDAP_STRONG_AUTH_REQUIRED),
     947             :         _LDAP_MAP_CODE(LDAP_REFERRAL),
     948             :         _LDAP_MAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED),
     949             :         _LDAP_MAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION),
     950             :         _LDAP_MAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED),
     951             :         _LDAP_MAP_CODE(LDAP_SASL_BIND_IN_PROGRESS),
     952             :         _LDAP_MAP_CODE(LDAP_NO_SUCH_ATTRIBUTE),
     953             :         _LDAP_MAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE),
     954             :         _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_MATCHING),
     955             :         _LDAP_MAP_CODE(LDAP_CONSTRAINT_VIOLATION),
     956             :         _LDAP_MAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS),
     957             :         _LDAP_MAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX),
     958             :         _LDAP_MAP_CODE(LDAP_NO_SUCH_OBJECT),
     959             :         _LDAP_MAP_CODE(LDAP_ALIAS_PROBLEM),
     960             :         _LDAP_MAP_CODE(LDAP_INVALID_DN_SYNTAX),
     961             :         _LDAP_MAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM),
     962             :         _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION),
     963             :         _LDAP_MAP_CODE(LDAP_INVALID_CREDENTIALS),
     964             :         _LDAP_MAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTS),
     965             :         _LDAP_MAP_CODE(LDAP_BUSY),
     966             :         _LDAP_MAP_CODE(LDAP_UNAVAILABLE),
     967             :         _LDAP_MAP_CODE(LDAP_UNWILLING_TO_PERFORM),
     968             :         _LDAP_MAP_CODE(LDAP_LOOP_DETECT),
     969             :         _LDAP_MAP_CODE(LDAP_NAMING_VIOLATION),
     970             :         _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_VIOLATION),
     971             :         _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF),
     972             :         _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_RDN),
     973             :         _LDAP_MAP_CODE(LDAP_ENTRY_ALREADY_EXISTS),
     974             :         _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED),
     975             :         _LDAP_MAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS),
     976             :         _LDAP_MAP_CODE(LDAP_OTHER)
     977             : };
     978             : 
     979             : /*
     980             :   used to setup the status code from a ldap response
     981             : */
     982      594597 : _PUBLIC_ NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
     983             : {
     984         587 :         size_t i;
     985      594597 :         const char *codename = "unknown";
     986             : 
     987      594597 :         if (r->resultcode == LDAP_SUCCESS) {
     988      542595 :                 return NT_STATUS_OK;
     989             :         }
     990             : 
     991       52002 :         if (conn->last_error) {
     992       42013 :                 talloc_free(conn->last_error);
     993             :         }
     994             : 
     995     1116008 :         for (i=0;i<ARRAY_SIZE(ldap_code_map);i++) {
     996     1116008 :                 if ((enum ldap_result_code)r->resultcode == ldap_code_map[i].code) {
     997       52002 :                         codename = ldap_code_map[i].str;
     998       52002 :                         break;
     999             :                 }
    1000             :         }
    1001             : 
    1002      156006 :         conn->last_error = talloc_asprintf(conn, "LDAP error %u %s - %s <%s> <%s>", 
    1003             :                                            r->resultcode,
    1004             :                                            codename,
    1005       52002 :                                            r->dn?r->dn:"(NULL)", 
    1006       52002 :                                            r->errormessage?r->errormessage:"", 
    1007       52002 :                                            r->referral?r->referral:"");
    1008             :         
    1009       52002 :         return NT_STATUS_LDAP(r->resultcode);
    1010             : }
    1011             : 
    1012             : /*
    1013             :   return error string representing the last error
    1014             : */
    1015       52906 : _PUBLIC_ const char *ldap_errstr(struct ldap_connection *conn, 
    1016             :                         TALLOC_CTX *mem_ctx, 
    1017             :                         NTSTATUS status)
    1018             : {
    1019       52906 :         if (NT_STATUS_IS_LDAP(status) && conn->last_error != NULL) {
    1020       52324 :                 return talloc_strdup(mem_ctx, conn->last_error);
    1021             :         }
    1022         582 :         return talloc_asprintf(mem_ctx, "LDAP client internal error: %s", nt_errstr(status));
    1023             : }
    1024             : 
    1025             : 
    1026             : /*
    1027             :   return the Nth result message, waiting if necessary
    1028             : */
    1029       87870 : _PUBLIC_ NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
    1030             : {
    1031       87870 :         *msg = NULL;
    1032             : 
    1033       87870 :         NT_STATUS_HAVE_NO_MEMORY(req);
    1034             : 
    1035      342196 :         while (req->state < LDAP_REQUEST_DONE && n >= req->num_replies) {
    1036      254326 :                 if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
    1037           0 :                         return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
    1038             :                 }
    1039             :         }
    1040             : 
    1041       87870 :         if (n < req->num_replies) {
    1042       87870 :                 *msg = req->replies[n];
    1043       87870 :                 return NT_STATUS_OK;
    1044             :         }
    1045             : 
    1046           0 :         if (!NT_STATUS_IS_OK(req->status)) {
    1047           0 :                 return req->status;
    1048             :         }
    1049             : 
    1050           0 :         return NT_STATUS_NO_MORE_ENTRIES;
    1051             : }
    1052             : 
    1053             : 
    1054             : /*
    1055             :   return a single result message, checking if it is of the expected LDAP type
    1056             : */
    1057          14 : _PUBLIC_ NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
    1058             : {
    1059           0 :         NTSTATUS status;
    1060          14 :         status = ldap_result_n(req, 0, msg);
    1061          14 :         if (!NT_STATUS_IS_OK(status)) {
    1062           0 :                 return status;
    1063             :         }
    1064          14 :         if ((*msg) != NULL && (*msg)->type != (enum ldap_request_tag)type) {
    1065           0 :                 *msg = NULL;
    1066           0 :                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
    1067             :         }
    1068          14 :         return status;
    1069             : }

Generated by: LCOV version 1.14