LCOV - code coverage report
Current view: top level - source4/libcli/ldap - ldap_client.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 347 552 62.9 %
Date: 2024-05-31 13:13:24 Functions: 24 30 80.0 %

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

Generated by: LCOV version 1.14