LCOV - code coverage report
Current view: top level - source3/lib - tldap.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 742 1251 59.3 %
Date: 2021-09-23 10:06:22 Functions: 55 87 63.2 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Infrastructure for async ldap client requests
       4             :    Copyright (C) Volker Lendecke 2009
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "replace.h"
      21             : #include "tldap.h"
      22             : #include "system/network.h"
      23             : #include "system/locale.h"
      24             : #include "lib/util/talloc_stack.h"
      25             : #include "lib/util/samba_util.h"
      26             : #include "lib/util_tsock.h"
      27             : #include "../lib/util/asn1.h"
      28             : #include "../lib/tsocket/tsocket.h"
      29             : #include "../lib/util/tevent_unix.h"
      30             : 
      31             : static TLDAPRC tldap_simple_recv(struct tevent_req *req);
      32             : static bool tldap_msg_set_pending(struct tevent_req *req);
      33             : 
      34             : #define TEVENT_TLDAP_RC_MAGIC (0x87bcd26e)
      35             : 
      36        1126 : bool tevent_req_ldap_error(struct tevent_req *req, TLDAPRC rc)
      37             : {
      38             :         uint64_t err;
      39             : 
      40        1126 :         if (TLDAP_RC_IS_SUCCESS(rc)) {
      41        1126 :                 return false;
      42             :         }
      43             : 
      44           0 :         err = TEVENT_TLDAP_RC_MAGIC;
      45           0 :         err <<= 32;
      46           0 :         err |= TLDAP_RC_V(rc);
      47             : 
      48           0 :         return tevent_req_error(req, err);
      49             : }
      50             : 
      51         686 : bool tevent_req_is_ldap_error(struct tevent_req *req, TLDAPRC *perr)
      52             : {
      53             :         enum tevent_req_state state;
      54             :         uint64_t err;
      55             : 
      56         686 :         if (!tevent_req_is_error(req, &state, &err)) {
      57         686 :                 return false;
      58             :         }
      59           0 :         switch (state) {
      60           0 :         case TEVENT_REQ_TIMED_OUT:
      61           0 :                 *perr = TLDAP_TIMEOUT;
      62           0 :                 break;
      63           0 :         case TEVENT_REQ_NO_MEMORY:
      64           0 :                 *perr = TLDAP_NO_MEMORY;
      65           0 :                 break;
      66           0 :         case TEVENT_REQ_USER_ERROR:
      67           0 :                 if ((err >> 32) != TEVENT_TLDAP_RC_MAGIC) {
      68           0 :                         abort();
      69             :                 }
      70           0 :                 *perr = TLDAP_RC(err & 0xffffffff);
      71           0 :                 break;
      72           0 :         default:
      73           0 :                 *perr = TLDAP_OPERATIONS_ERROR;
      74           0 :                 break;
      75             :         }
      76           0 :         return true;
      77             : }
      78             : 
      79             : struct tldap_ctx_attribute {
      80             :         char *name;
      81             :         void *ptr;
      82             : };
      83             : 
      84             : struct tldap_context {
      85             :         int ld_version;
      86             :         struct tstream_context *conn;
      87             :         int msgid;
      88             :         struct tevent_queue *outgoing;
      89             :         struct tevent_req **pending;
      90             :         struct tevent_req *read_req;
      91             : 
      92             :         /* For the sync wrappers we need something like get_last_error... */
      93             :         struct tldap_message *last_msg;
      94             : 
      95             :         /* debug */
      96             :         void (*log_fn)(void *context, enum tldap_debug_level level,
      97             :                        const char *fmt, va_list ap);
      98             :         void *log_private;
      99             : 
     100             :         struct tldap_ctx_attribute *ctx_attrs;
     101             : };
     102             : 
     103             : struct tldap_message {
     104             :         struct asn1_data *data;
     105             :         uint8_t *inbuf;
     106             :         int type;
     107             :         int id;
     108             : 
     109             :         /* RESULT_ENTRY */
     110             :         char *dn;
     111             :         struct tldap_attribute *attribs;
     112             : 
     113             :         /* Error data sent by the server */
     114             :         TLDAPRC lderr;
     115             :         char *res_matcheddn;
     116             :         char *res_diagnosticmessage;
     117             :         char *res_referral;
     118             :         DATA_BLOB res_serverSaslCreds;
     119             :         struct tldap_control *res_sctrls;
     120             : 
     121             :         /* Controls sent by the server */
     122             :         struct tldap_control *ctrls;
     123             : };
     124             : 
     125           0 : void tldap_set_debug(struct tldap_context *ld,
     126             :                      void (*log_fn)(void *log_private,
     127             :                                     enum tldap_debug_level level,
     128             :                                     const char *fmt,
     129             :                                     va_list ap) PRINTF_ATTRIBUTE(3,0),
     130             :                      void *log_private)
     131             : {
     132           0 :         ld->log_fn = log_fn;
     133           0 :         ld->log_private = log_private;
     134           0 : }
     135             : 
     136             : static void tldap_debug(
     137             :         struct tldap_context *ld,
     138             :         enum tldap_debug_level level,
     139             :         const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
     140             : 
     141         680 : static void tldap_debug(struct tldap_context *ld,
     142             :                          enum tldap_debug_level level,
     143             :                          const char *fmt, ...)
     144             : {
     145             :         va_list ap;
     146         680 :         if (!ld) {
     147         680 :                 return;
     148             :         }
     149         680 :         if (ld->log_fn == NULL) {
     150         680 :                 return;
     151             :         }
     152           0 :         va_start(ap, fmt);
     153           0 :         ld->log_fn(ld->log_private, level, fmt, ap);
     154           0 :         va_end(ap);
     155             : }
     156             : 
     157         106 : static int tldap_next_msgid(struct tldap_context *ld)
     158             : {
     159             :         int result;
     160             : 
     161         106 :         result = ld->msgid++;
     162         106 :         if (ld->msgid == 2147483647) {
     163           0 :                 ld->msgid = 1;
     164             :         }
     165         106 :         return result;
     166             : }
     167             : 
     168           2 : struct tldap_context *tldap_context_create(TALLOC_CTX *mem_ctx, int fd)
     169             : {
     170             :         struct tldap_context *ctx;
     171             :         int ret;
     172             : 
     173           2 :         ctx = talloc_zero(mem_ctx, struct tldap_context);
     174           2 :         if (ctx == NULL) {
     175           0 :                 return NULL;
     176             :         }
     177           2 :         ret = tstream_bsd_existing_socket(ctx, fd, &ctx->conn);
     178           2 :         if (ret == -1) {
     179           0 :                 TALLOC_FREE(ctx);
     180           0 :                 return NULL;
     181             :         }
     182           2 :         ctx->msgid = 1;
     183           2 :         ctx->ld_version = 3;
     184           2 :         ctx->outgoing = tevent_queue_create(ctx, "tldap_outgoing");
     185           2 :         if (ctx->outgoing == NULL) {
     186           0 :                 TALLOC_FREE(ctx);
     187           0 :                 return NULL;
     188             :         }
     189           2 :         return ctx;
     190             : }
     191             : 
     192         106 : bool tldap_connection_ok(struct tldap_context *ld)
     193             : {
     194             :         int ret;
     195             : 
     196         106 :         if (ld == NULL) {
     197           0 :                 return false;
     198             :         }
     199             : 
     200         106 :         if (ld->conn == NULL) {
     201           0 :                 return false;
     202             :         }
     203             : 
     204         106 :         ret = tstream_pending_bytes(ld->conn);
     205         106 :         if (ret == -1) {
     206           0 :                 return false;
     207             :         }
     208             : 
     209         106 :         return true;
     210             : }
     211             : 
     212        1136 : static size_t tldap_pending_reqs(struct tldap_context *ld)
     213             : {
     214        1136 :         return talloc_array_length(ld->pending);
     215             : }
     216             : 
     217           2 : struct tstream_context *tldap_get_tstream(struct tldap_context *ld)
     218             : {
     219           2 :         return ld->conn;
     220             : }
     221             : 
     222           2 : void tldap_set_tstream(struct tldap_context *ld,
     223             :                        struct tstream_context *stream)
     224             : {
     225           2 :         ld->conn = stream;
     226           2 : }
     227             : 
     228           4 : static struct tldap_ctx_attribute *tldap_context_findattr(
     229             :         struct tldap_context *ld, const char *name)
     230             : {
     231             :         size_t i, num_attrs;
     232             : 
     233           4 :         num_attrs = talloc_array_length(ld->ctx_attrs);
     234             : 
     235           4 :         for (i=0; i<num_attrs; i++) {
     236           2 :                 if (strcmp(ld->ctx_attrs[i].name, name) == 0) {
     237           2 :                         return &ld->ctx_attrs[i];
     238             :                 }
     239             :         }
     240           2 :         return NULL;
     241             : }
     242             : 
     243           2 : bool tldap_context_setattr(struct tldap_context *ld,
     244             :                            const char *name, const void *_pptr)
     245             : {
     246             :         struct tldap_ctx_attribute *tmp, *attr;
     247             :         char *tmpname;
     248             :         int num_attrs;
     249           2 :         void **pptr = (void **)discard_const_p(void,_pptr);
     250             : 
     251           2 :         attr = tldap_context_findattr(ld, name);
     252           2 :         if (attr != NULL) {
     253             :                 /*
     254             :                  * We don't actually delete attrs, we don't expect tons of
     255             :                  * attributes being shuffled around.
     256             :                  */
     257           0 :                 TALLOC_FREE(attr->ptr);
     258           0 :                 if (*pptr != NULL) {
     259           0 :                         attr->ptr = talloc_move(ld->ctx_attrs, pptr);
     260           0 :                         *pptr = NULL;
     261             :                 }
     262           0 :                 return true;
     263             :         }
     264             : 
     265           2 :         tmpname = talloc_strdup(ld, name);
     266           2 :         if (tmpname == NULL) {
     267           0 :                 return false;
     268             :         }
     269             : 
     270           2 :         num_attrs = talloc_array_length(ld->ctx_attrs);
     271             : 
     272           2 :         tmp = talloc_realloc(ld, ld->ctx_attrs, struct tldap_ctx_attribute,
     273             :                              num_attrs+1);
     274           2 :         if (tmp == NULL) {
     275           0 :                 TALLOC_FREE(tmpname);
     276           0 :                 return false;
     277             :         }
     278           2 :         tmp[num_attrs].name = talloc_move(tmp, &tmpname);
     279           2 :         if (*pptr != NULL) {
     280           2 :                 tmp[num_attrs].ptr = talloc_move(tmp, pptr);
     281             :         } else {
     282           0 :                 tmp[num_attrs].ptr = NULL;
     283             :         }
     284           2 :         *pptr = NULL;
     285           2 :         ld->ctx_attrs = tmp;
     286           2 :         return true;
     287             : }
     288             : 
     289           2 : void *tldap_context_getattr(struct tldap_context *ld, const char *name)
     290             : {
     291           2 :         struct tldap_ctx_attribute *attr = tldap_context_findattr(ld, name);
     292             : 
     293           2 :         if (attr == NULL) {
     294           0 :                 return NULL;
     295             :         }
     296           2 :         return attr->ptr;
     297             : }
     298             : 
     299             : struct read_ldap_state {
     300             :         uint8_t *buf;
     301             :         bool done;
     302             : };
     303             : 
     304             : static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data);
     305             : static void read_ldap_done(struct tevent_req *subreq);
     306             : 
     307         564 : static struct tevent_req *read_ldap_send(TALLOC_CTX *mem_ctx,
     308             :                                          struct tevent_context *ev,
     309             :                                          struct tstream_context *conn)
     310             : {
     311             :         struct tevent_req *req, *subreq;
     312             :         struct read_ldap_state *state;
     313             : 
     314         564 :         req = tevent_req_create(mem_ctx, &state, struct read_ldap_state);
     315         564 :         if (req == NULL) {
     316           0 :                 return NULL;
     317             :         }
     318         564 :         state->done = false;
     319             : 
     320         564 :         subreq = tstream_read_packet_send(state, ev, conn, 2, read_ldap_more,
     321             :                                           state);
     322         564 :         if (tevent_req_nomem(subreq, req)) {
     323           0 :                 return tevent_req_post(req, ev);
     324             :         }
     325         564 :         tevent_req_set_callback(subreq, read_ldap_done, req);
     326         564 :         return req;
     327             : }
     328             : 
     329        1580 : static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data)
     330             : {
     331        1580 :         struct read_ldap_state *state = talloc_get_type_abort(
     332             :                 private_data, struct read_ldap_state);
     333             :         size_t len;
     334             :         int i, lensize;
     335             : 
     336        1580 :         if (state->done) {
     337             :                 /* We've been here, we're done */
     338         112 :                 return 0;
     339             :         }
     340             : 
     341             :         /*
     342             :          * From ldap.h: LDAP_TAG_MESSAGE is 0x30
     343             :          */
     344        1468 :         if (buf[0] != 0x30) {
     345           0 :                 return -1;
     346             :         }
     347             : 
     348        1468 :         len = buf[1];
     349        1468 :         if ((len & 0x80) == 0) {
     350         112 :                 state->done = true;
     351         112 :                 return len;
     352             :         }
     353             : 
     354        1356 :         lensize = (len & 0x7f);
     355        1356 :         len = 0;
     356             : 
     357        1356 :         if (buflen == 2) {
     358             :                 /* Please get us the full length */
     359         452 :                 return lensize;
     360             :         }
     361         904 :         if (buflen > 2 + lensize) {
     362         452 :                 state->done = true;
     363         452 :                 return 0;
     364             :         }
     365         452 :         if (buflen != 2 + lensize) {
     366           0 :                 return -1;
     367             :         }
     368             : 
     369        1356 :         for (i=0; i<lensize; i++) {
     370         904 :                 len = (len << 8) | buf[2+i];
     371             :         }
     372         452 :         return len;
     373             : }
     374             : 
     375         564 : static void read_ldap_done(struct tevent_req *subreq)
     376             : {
     377         564 :         struct tevent_req *req = tevent_req_callback_data(
     378             :                 subreq, struct tevent_req);
     379         564 :         struct read_ldap_state *state = tevent_req_data(
     380             :                 req, struct read_ldap_state);
     381             :         ssize_t nread;
     382             :         int err;
     383             : 
     384         564 :         nread = tstream_read_packet_recv(subreq, state, &state->buf, &err);
     385         564 :         TALLOC_FREE(subreq);
     386         564 :         if (nread == -1) {
     387           0 :                 tevent_req_error(req, err);
     388           0 :                 return;
     389             :         }
     390         564 :         tevent_req_done(req);
     391             : }
     392             : 
     393         564 : static ssize_t read_ldap_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     394             :                               uint8_t **pbuf, int *perrno)
     395             : {
     396         564 :         struct read_ldap_state *state = tevent_req_data(
     397             :                 req, struct read_ldap_state);
     398             : 
     399         564 :         if (tevent_req_is_unix_error(req, perrno)) {
     400           0 :                 return -1;
     401             :         }
     402         564 :         *pbuf = talloc_move(mem_ctx, &state->buf);
     403         564 :         return talloc_get_size(*pbuf);
     404             : }
     405             : 
     406             : struct tldap_msg_state {
     407             :         struct tldap_context *ld;
     408             :         struct tevent_context *ev;
     409             :         int id;
     410             :         struct iovec iov;
     411             : 
     412             :         struct asn1_data *data;
     413             :         uint8_t *inbuf;
     414             : };
     415             : 
     416         106 : static bool tldap_push_controls(struct asn1_data *data,
     417             :                                 struct tldap_control *sctrls,
     418             :                                 int num_sctrls)
     419             : {
     420             :         int i;
     421             : 
     422         106 :         if ((sctrls == NULL) || (num_sctrls == 0)) {
     423          10 :                 return true;
     424             :         }
     425             : 
     426          96 :         if (!asn1_push_tag(data, ASN1_CONTEXT(0))) return false;
     427             : 
     428         192 :         for (i=0; i<num_sctrls; i++) {
     429          96 :                 struct tldap_control *c = &sctrls[i];
     430          96 :                 if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
     431          96 :                 if (!asn1_write_OctetString(data, c->oid, strlen(c->oid))) return false;
     432          96 :                 if (c->critical) {
     433          96 :                         if (!asn1_write_BOOLEAN(data, true)) return false;
     434             :                 }
     435          96 :                 if (c->value.data != NULL) {
     436          94 :                         if (!asn1_write_OctetString(data, c->value.data,
     437           0 :                                                c->value.length)) return false;
     438             :                 }
     439          96 :                 if (!asn1_pop_tag(data)) return false; /* ASN1_SEQUENCE(0) */
     440             :         }
     441             : 
     442          96 :         return asn1_pop_tag(data); /* ASN1_CONTEXT(0) */
     443             : }
     444             : 
     445             : #define tldap_context_disconnect(ld, status) \
     446             :         _tldap_context_disconnect(ld, status, __location__)
     447             : 
     448           0 : static void _tldap_context_disconnect(struct tldap_context *ld,
     449             :                                       TLDAPRC status,
     450             :                                       const char *location)
     451             : {
     452           0 :         if (ld->conn == NULL) {
     453             :                 /*
     454             :                  * We don't need to tldap_debug() on
     455             :                  * a potential 2nd run.
     456             :                  *
     457             :                  * The rest of the function would just
     458             :                  * be a noop for the 2nd run anyway.
     459             :                  */
     460           0 :                 return;
     461             :         }
     462             : 
     463           0 :         tldap_debug(ld, TLDAP_DEBUG_WARNING,
     464             :                     "tldap_context_disconnect: %s at %s\n",
     465             :                     tldap_rc2string(status),
     466             :                     location);
     467           0 :         tevent_queue_stop(ld->outgoing);
     468           0 :         TALLOC_FREE(ld->read_req);
     469           0 :         TALLOC_FREE(ld->conn);
     470             : 
     471           0 :         while (talloc_array_length(ld->pending) > 0) {
     472           0 :                 struct tevent_req *req = NULL;
     473           0 :                 struct tldap_msg_state *state = NULL;
     474             : 
     475           0 :                 req = ld->pending[0];
     476           0 :                 state = tevent_req_data(req, struct tldap_msg_state);
     477           0 :                 tevent_req_defer_callback(req, state->ev);
     478           0 :                 tevent_req_ldap_error(req, status);
     479             :         }
     480             : }
     481             : 
     482             : static void tldap_msg_sent(struct tevent_req *subreq);
     483             : static void tldap_msg_received(struct tevent_req *subreq);
     484             : 
     485         106 : static struct tevent_req *tldap_msg_send(TALLOC_CTX *mem_ctx,
     486             :                                          struct tevent_context *ev,
     487             :                                          struct tldap_context *ld,
     488             :                                          int id, struct asn1_data *data,
     489             :                                          struct tldap_control *sctrls,
     490             :                                          int num_sctrls)
     491             : {
     492             :         struct tevent_req *req, *subreq;
     493             :         struct tldap_msg_state *state;
     494             :         DATA_BLOB blob;
     495             :         bool ok;
     496             : 
     497         106 :         tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_send: sending msg %d\n",
     498             :                     id);
     499             : 
     500         106 :         req = tevent_req_create(mem_ctx, &state, struct tldap_msg_state);
     501         106 :         if (req == NULL) {
     502           0 :                 return NULL;
     503             :         }
     504         106 :         state->ld = ld;
     505         106 :         state->ev = ev;
     506         106 :         state->id = id;
     507             : 
     508         106 :         ok = tldap_connection_ok(ld);
     509         106 :         if (!ok) {
     510           0 :                 tevent_req_ldap_error(req, TLDAP_SERVER_DOWN);
     511           0 :                 return tevent_req_post(req, ev);
     512             :         }
     513             : 
     514         106 :         if (!tldap_push_controls(data, sctrls, num_sctrls)) {
     515           0 :                 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
     516           0 :                 return tevent_req_post(req, ev);
     517             :         }
     518             : 
     519             : 
     520         106 :         if (!asn1_pop_tag(data)) {
     521           0 :                 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
     522           0 :                 return tevent_req_post(req, ev);
     523             :         }
     524             : 
     525         106 :         if (!asn1_blob(data, &blob)) {
     526           0 :                 tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
     527           0 :                 return tevent_req_post(req, ev);
     528             :         }
     529             : 
     530         106 :         if (!tldap_msg_set_pending(req)) {
     531           0 :                 tevent_req_oom(req);
     532           0 :                 return tevent_req_post(req, ev);;
     533             :         }
     534             : 
     535         106 :         state->iov.iov_base = (void *)blob.data;
     536         106 :         state->iov.iov_len = blob.length;
     537             : 
     538         106 :         subreq = tstream_writev_queue_send(state, ev, ld->conn, ld->outgoing,
     539         106 :                                            &state->iov, 1);
     540         106 :         if (tevent_req_nomem(subreq, req)) {
     541           0 :                 return tevent_req_post(req, ev);
     542             :         }
     543         106 :         tevent_req_set_callback(subreq, tldap_msg_sent, req);
     544         106 :         return req;
     545             : }
     546             : 
     547         564 : static void tldap_msg_unset_pending(struct tevent_req *req)
     548             : {
     549         564 :         struct tldap_msg_state *state = tevent_req_data(
     550             :                 req, struct tldap_msg_state);
     551         564 :         struct tldap_context *ld = state->ld;
     552         564 :         int num_pending = tldap_pending_reqs(ld);
     553             :         int i;
     554             : 
     555         564 :         tevent_req_set_cleanup_fn(req, NULL);
     556             : 
     557         564 :         for (i=0; i<num_pending; i++) {
     558         564 :                 if (req == ld->pending[i]) {
     559         564 :                         break;
     560             :                 }
     561             :         }
     562         564 :         if (i == num_pending) {
     563             :                 /*
     564             :                  * Something's seriously broken. Just returning here is the
     565             :                  * right thing nevertheless, the point of this routine is to
     566             :                  * remove ourselves from cli->pending.
     567             :                  */
     568           0 :                 return;
     569             :         }
     570             : 
     571         564 :         if (num_pending == 1) {
     572         564 :                 TALLOC_FREE(ld->pending);
     573         564 :                 return;
     574             :         }
     575             : 
     576             :         /*
     577             :          * Remove ourselves from the cli->pending array
     578             :          */
     579           0 :         if (num_pending > 1) {
     580           0 :                 ld->pending[i] = ld->pending[num_pending-1];
     581             :         }
     582             : 
     583             :         /*
     584             :          * No NULL check here, we're shrinking by sizeof(void *), and
     585             :          * talloc_realloc just adjusts the size for this.
     586             :          */
     587           0 :         ld->pending = talloc_realloc(NULL, ld->pending, struct tevent_req *,
     588             :                                      num_pending - 1);
     589             : }
     590             : 
     591           0 : static void tldap_msg_cleanup(struct tevent_req *req,
     592             :                               enum tevent_req_state req_state)
     593             : {
     594           0 :         tldap_msg_unset_pending(req);
     595           0 : }
     596             : 
     597         564 : static bool tldap_msg_set_pending(struct tevent_req *req)
     598             : {
     599         564 :         struct tldap_msg_state *state = tevent_req_data(
     600             :                 req, struct tldap_msg_state);
     601             :         struct tldap_context *ld;
     602             :         struct tevent_req **pending;
     603             :         int num_pending;
     604             : 
     605         564 :         ld = state->ld;
     606         564 :         num_pending = tldap_pending_reqs(ld);
     607             : 
     608         564 :         pending = talloc_realloc(ld, ld->pending, struct tevent_req *,
     609             :                                  num_pending+1);
     610         564 :         if (pending == NULL) {
     611           0 :                 return false;
     612             :         }
     613         564 :         pending[num_pending] = req;
     614         564 :         ld->pending = pending;
     615         564 :         tevent_req_set_cleanup_fn(req, tldap_msg_cleanup);
     616             : 
     617         564 :         if (ld->read_req != NULL) {
     618           0 :                 return true;
     619             :         }
     620             : 
     621             :         /*
     622             :          * We're the first one, add the read_ldap request that waits for the
     623             :          * answer from the server
     624             :          */
     625         564 :         ld->read_req = read_ldap_send(ld->pending, state->ev, ld->conn);
     626         564 :         if (ld->read_req == NULL) {
     627           0 :                 tldap_msg_unset_pending(req);
     628           0 :                 return false;
     629             :         }
     630         564 :         tevent_req_set_callback(ld->read_req, tldap_msg_received, ld);
     631         564 :         return true;
     632             : }
     633             : 
     634         106 : static void tldap_msg_sent(struct tevent_req *subreq)
     635             : {
     636         106 :         struct tevent_req *req = tevent_req_callback_data(
     637             :                 subreq, struct tevent_req);
     638         106 :         struct tldap_msg_state *state = tevent_req_data(
     639             :                 req, struct tldap_msg_state);
     640             :         ssize_t nwritten;
     641             :         int err;
     642             : 
     643         106 :         nwritten = tstream_writev_queue_recv(subreq, &err);
     644         106 :         TALLOC_FREE(subreq);
     645         106 :         if (nwritten == -1) {
     646           0 :                 tldap_context_disconnect(state->ld, TLDAP_SERVER_DOWN);
     647           0 :                 return;
     648             :         }
     649             : }
     650             : 
     651         564 : static int tldap_msg_msgid(struct tevent_req *req)
     652             : {
     653         564 :         struct tldap_msg_state *state = tevent_req_data(
     654             :                 req, struct tldap_msg_state);
     655             : 
     656         564 :         return state->id;
     657             : }
     658             : 
     659         564 : static void tldap_msg_received(struct tevent_req *subreq)
     660             : {
     661         564 :         struct tldap_context *ld = tevent_req_callback_data(
     662             :                 subreq, struct tldap_context);
     663             :         struct tevent_req *req;
     664             :         struct tldap_msg_state *state;
     665             :         struct asn1_data *data;
     666             :         uint8_t *inbuf;
     667             :         ssize_t received;
     668             :         size_t num_pending;
     669             :         size_t i;
     670             :         int err;
     671         564 :         TLDAPRC status = TLDAP_PROTOCOL_ERROR;
     672             :         int id;
     673             :         uint8_t type;
     674             :         bool ok;
     675             : 
     676         564 :         received = read_ldap_recv(subreq, talloc_tos(), &inbuf, &err);
     677         564 :         TALLOC_FREE(subreq);
     678         564 :         ld->read_req = NULL;
     679         564 :         if (received == -1) {
     680           0 :                 status = TLDAP_SERVER_DOWN;
     681           0 :                 goto fail;
     682             :         }
     683             : 
     684         564 :         data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
     685         564 :         if (data == NULL) {
     686             :                 /*
     687             :                  * We have to disconnect all, we can't tell which of
     688             :                  * the requests this reply is for.
     689             :                  */
     690           0 :                 status = TLDAP_NO_MEMORY;
     691           0 :                 goto fail;
     692             :         }
     693         564 :         asn1_load_nocopy(data, inbuf, received);
     694             : 
     695         564 :         ok = true;
     696         564 :         ok &= asn1_start_tag(data, ASN1_SEQUENCE(0));
     697         564 :         ok &= asn1_read_Integer(data, &id);
     698         564 :         ok &= asn1_peek_uint8(data, &type);
     699             : 
     700         564 :         if (!ok) {
     701           0 :                 status = TLDAP_PROTOCOL_ERROR;
     702           0 :                 goto fail;
     703             :         }
     704             : 
     705         564 :         tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_received: got msg %d "
     706             :                     "type %d\n", id, (int)type);
     707             : 
     708         564 :         if (id == 0) {
     709           0 :                 tldap_debug(
     710             :                         ld,
     711             :                         TLDAP_DEBUG_WARNING,
     712             :                         "tldap_msg_received: got msgid 0 of "
     713             :                         "type %"PRIu8", disconnecting\n",
     714             :                         type);
     715           0 :                 tldap_context_disconnect(ld, TLDAP_SERVER_DOWN);
     716           0 :                 return;
     717             :         }
     718             : 
     719         564 :         num_pending = talloc_array_length(ld->pending);
     720             : 
     721         564 :         for (i=0; i<num_pending; i++) {
     722         564 :                 if (id == tldap_msg_msgid(ld->pending[i])) {
     723         564 :                         break;
     724             :                 }
     725             :         }
     726         564 :         if (i == num_pending) {
     727             :                 /* Dump unexpected reply */
     728           0 :                 tldap_debug(ld, TLDAP_DEBUG_WARNING, "tldap_msg_received: "
     729             :                             "No request pending for msg %d\n", id);
     730           0 :                 TALLOC_FREE(data);
     731           0 :                 TALLOC_FREE(inbuf);
     732           0 :                 goto done;
     733             :         }
     734             : 
     735         564 :         req = ld->pending[i];
     736         564 :         state = tevent_req_data(req, struct tldap_msg_state);
     737             : 
     738         564 :         state->inbuf = talloc_move(state, &inbuf);
     739         564 :         state->data = talloc_move(state, &data);
     740             : 
     741         564 :         tldap_msg_unset_pending(req);
     742         564 :         num_pending = talloc_array_length(ld->pending);
     743             : 
     744         564 :         tevent_req_defer_callback(req, state->ev);
     745         564 :         tevent_req_done(req);
     746             : 
     747         564 :  done:
     748         564 :         if (num_pending == 0) {
     749         564 :                 return;
     750             :         }
     751             : 
     752           0 :         state = tevent_req_data(ld->pending[0],      struct tldap_msg_state);
     753           0 :         ld->read_req = read_ldap_send(ld->pending, state->ev, ld->conn);
     754           0 :         if (ld->read_req == NULL) {
     755           0 :                 status = TLDAP_NO_MEMORY;
     756           0 :                 goto fail;
     757             :         }
     758           0 :         tevent_req_set_callback(ld->read_req, tldap_msg_received, ld);
     759           0 :         return;
     760             : 
     761           0 :  fail:
     762           0 :         tldap_context_disconnect(ld, status);
     763             : }
     764             : 
     765         564 : static TLDAPRC tldap_msg_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     766             :                               struct tldap_message **pmsg)
     767             : {
     768         564 :         struct tldap_msg_state *state = tevent_req_data(
     769             :                 req, struct tldap_msg_state);
     770             :         struct tldap_message *msg;
     771             :         TLDAPRC err;
     772             :         uint8_t msgtype;
     773             : 
     774         564 :         if (tevent_req_is_ldap_error(req, &err)) {
     775           0 :                 return err;
     776             :         }
     777             : 
     778         564 :         if (!asn1_peek_uint8(state->data, &msgtype)) {
     779           0 :                 return TLDAP_PROTOCOL_ERROR;
     780             :         }
     781             : 
     782         564 :         if (pmsg == NULL) {
     783           0 :                 return TLDAP_SUCCESS;
     784             :         }
     785             : 
     786         564 :         msg = talloc_zero(mem_ctx, struct tldap_message);
     787         564 :         if (msg == NULL) {
     788           0 :                 return TLDAP_NO_MEMORY;
     789             :         }
     790         564 :         msg->id = state->id;
     791             : 
     792         564 :         msg->inbuf = talloc_move(msg, &state->inbuf);
     793         564 :         msg->data = talloc_move(msg, &state->data);
     794         564 :         msg->type = msgtype;
     795             : 
     796         564 :         *pmsg = msg;
     797         564 :         return TLDAP_SUCCESS;
     798             : }
     799             : 
     800             : struct tldap_req_state {
     801             :         int id;
     802             :         struct asn1_data *out;
     803             :         struct tldap_message *result;
     804             : };
     805             : 
     806         106 : static struct tevent_req *tldap_req_create(TALLOC_CTX *mem_ctx,
     807             :                                            struct tldap_context *ld,
     808             :                                            struct tldap_req_state **pstate)
     809             : {
     810             :         struct tevent_req *req;
     811             :         struct tldap_req_state *state;
     812             : 
     813         106 :         req = tevent_req_create(mem_ctx, &state, struct tldap_req_state);
     814         106 :         if (req == NULL) {
     815           0 :                 return NULL;
     816             :         }
     817         106 :         state->out = asn1_init(state, ASN1_MAX_TREE_DEPTH);
     818         106 :         if (state->out == NULL) {
     819           0 :                 goto err;
     820             :         }
     821         106 :         state->id = tldap_next_msgid(ld);
     822             : 
     823         106 :         if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
     824         106 :         if (!asn1_write_Integer(state->out, state->id)) goto err;
     825             : 
     826         106 :         *pstate = state;
     827         106 :         return req;
     828             : 
     829           0 :   err:
     830             : 
     831           0 :         TALLOC_FREE(req);
     832           0 :         return NULL;
     833             : }
     834             : 
     835           0 : static void tldap_save_msg(struct tldap_context *ld, struct tevent_req *req)
     836             : {
     837           0 :         struct tldap_req_state *state = tevent_req_data(
     838             :                 req, struct tldap_req_state);
     839             : 
     840           0 :         TALLOC_FREE(ld->last_msg);
     841           0 :         ld->last_msg = talloc_move(ld, &state->result);
     842           0 : }
     843             : 
     844        7882 : static char *blob2string_talloc(TALLOC_CTX *mem_ctx, DATA_BLOB blob)
     845             : {
     846        7882 :         char *result = talloc_array(mem_ctx, char, blob.length+1);
     847             : 
     848        7882 :         if (result == NULL) {
     849           0 :                 return NULL;
     850             :         }
     851             : 
     852        7882 :         memcpy(result, blob.data, blob.length);
     853        7882 :         result[blob.length] = '\0';
     854        7882 :         return result;
     855             : }
     856             : 
     857        7882 : static bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
     858             :                                          struct asn1_data *data,
     859             :                                          char **presult)
     860             : {
     861             :         DATA_BLOB string;
     862             :         char *result;
     863        7882 :         if (!asn1_read_OctetString(data, mem_ctx, &string))
     864           0 :                 return false;
     865             : 
     866        7882 :         result = blob2string_talloc(mem_ctx, string);
     867             : 
     868        7882 :         data_blob_free(&string);
     869             : 
     870        7882 :         if (result == NULL) {
     871           0 :                 return false;
     872             :         }
     873        7882 :         *presult = result;
     874        7882 :         return true;
     875             : }
     876             : 
     877             : static bool tldap_decode_controls(struct tldap_req_state *state);
     878             : 
     879         106 : static bool tldap_decode_response(struct tldap_req_state *state)
     880             : {
     881         106 :         struct asn1_data *data = state->result->data;
     882         106 :         struct tldap_message *msg = state->result;
     883             :         int rc;
     884         106 :         bool ok = true;
     885             : 
     886         106 :         ok &= asn1_read_enumerated(data, &rc);
     887         106 :         if (ok) {
     888         106 :                 msg->lderr = TLDAP_RC(rc);
     889             :         }
     890             : 
     891         106 :         ok &= asn1_read_OctetString_talloc(msg, data, &msg->res_matcheddn);
     892         106 :         ok &= asn1_read_OctetString_talloc(msg, data,
     893             :                                            &msg->res_diagnosticmessage);
     894         106 :         if (!ok) return ok;
     895         106 :         if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
     896           0 :                 ok &= asn1_start_tag(data, ASN1_CONTEXT(3));
     897           0 :                 ok &= asn1_read_OctetString_talloc(msg, data,
     898             :                                                    &msg->res_referral);
     899           0 :                 ok &= asn1_end_tag(data);
     900             :         } else {
     901         106 :                 msg->res_referral = NULL;
     902             :         }
     903             : 
     904         106 :         return ok;
     905             : }
     906             : 
     907             : static void tldap_sasl_bind_done(struct tevent_req *subreq);
     908             : 
     909           4 : struct tevent_req *tldap_sasl_bind_send(TALLOC_CTX *mem_ctx,
     910             :                                         struct tevent_context *ev,
     911             :                                         struct tldap_context *ld,
     912             :                                         const char *dn,
     913             :                                         const char *mechanism,
     914             :                                         DATA_BLOB *creds,
     915             :                                         struct tldap_control *sctrls,
     916             :                                         int num_sctrls,
     917             :                                         struct tldap_control *cctrls,
     918             :                                         int num_cctrls)
     919             : {
     920             :         struct tevent_req *req, *subreq;
     921             :         struct tldap_req_state *state;
     922             : 
     923           4 :         req = tldap_req_create(mem_ctx, ld, &state);
     924           4 :         if (req == NULL) {
     925           0 :                 return NULL;
     926             :         }
     927             : 
     928           4 :         if (dn == NULL) {
     929           0 :                 dn = "";
     930             :         }
     931             : 
     932           4 :         if (!asn1_push_tag(state->out, TLDAP_REQ_BIND)) goto err;
     933           4 :         if (!asn1_write_Integer(state->out, ld->ld_version)) goto err;
     934           4 :         if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
     935             : 
     936           4 :         if (mechanism == NULL) {
     937           0 :                 if (!asn1_push_tag(state->out, ASN1_CONTEXT_SIMPLE(0))) goto err;
     938           0 :                 if (!asn1_write(state->out, creds->data, creds->length)) goto err;
     939           0 :                 if (!asn1_pop_tag(state->out)) goto err;
     940             :         } else {
     941           4 :                 if (!asn1_push_tag(state->out, ASN1_CONTEXT(3))) goto err;
     942           4 :                 if (!asn1_write_OctetString(state->out, mechanism,
     943           0 :                                        strlen(mechanism))) goto err;
     944           4 :                 if ((creds != NULL) && (creds->data != NULL)) {
     945           4 :                         if (!asn1_write_OctetString(state->out, creds->data,
     946           0 :                                                creds->length)) goto err;
     947             :                 }
     948           4 :                 if (!asn1_pop_tag(state->out)) goto err;
     949             :         }
     950             : 
     951           4 :         if (!asn1_pop_tag(state->out)) goto err;
     952             : 
     953           4 :         subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
     954             :                                 sctrls, num_sctrls);
     955           4 :         if (tevent_req_nomem(subreq, req)) {
     956           0 :                 return tevent_req_post(req, ev);
     957             :         }
     958           4 :         tevent_req_set_callback(subreq, tldap_sasl_bind_done, req);
     959           4 :         return req;
     960             : 
     961           0 :   err:
     962             : 
     963           0 :         tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
     964           0 :         return tevent_req_post(req, ev);
     965             : }
     966             : 
     967           4 : static void tldap_sasl_bind_done(struct tevent_req *subreq)
     968             : {
     969           4 :         struct tevent_req *req = tevent_req_callback_data(
     970             :                 subreq, struct tevent_req);
     971           4 :         struct tldap_req_state *state = tevent_req_data(
     972             :                 req, struct tldap_req_state);
     973             :         TLDAPRC rc;
     974             :         bool ok;
     975             : 
     976           4 :         rc = tldap_msg_recv(subreq, state, &state->result);
     977           4 :         TALLOC_FREE(subreq);
     978           4 :         if (tevent_req_ldap_error(req, rc)) {
     979           0 :                 return;
     980             :         }
     981           4 :         if (state->result->type != TLDAP_RES_BIND) {
     982           0 :                 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
     983           0 :                 return;
     984             :         }
     985             : 
     986           4 :         ok = asn1_start_tag(state->result->data, TLDAP_RES_BIND);
     987           4 :         ok &= tldap_decode_response(state);
     988             : 
     989           4 :         if (asn1_peek_tag(state->result->data, ASN1_CONTEXT_SIMPLE(7))) {
     990             :                 int len;
     991             : 
     992           4 :                 ok &= asn1_start_tag(state->result->data,
     993             :                                      ASN1_CONTEXT_SIMPLE(7));
     994           4 :                 if (!ok) {
     995           0 :                         goto decode_error;
     996             :                 }
     997             : 
     998           4 :                 len = asn1_tag_remaining(state->result->data);
     999           4 :                 if (len == -1) {
    1000           0 :                         goto decode_error;
    1001             :                 }
    1002             : 
    1003           4 :                 state->result->res_serverSaslCreds =
    1004           4 :                         data_blob_talloc(state->result, NULL, len);
    1005           4 :                 if (state->result->res_serverSaslCreds.data == NULL) {
    1006           0 :                         goto decode_error;
    1007             :                 }
    1008             : 
    1009           6 :                 ok = asn1_read(state->result->data,
    1010           4 :                                state->result->res_serverSaslCreds.data,
    1011           4 :                                state->result->res_serverSaslCreds.length);
    1012             : 
    1013           4 :                 ok &= asn1_end_tag(state->result->data);
    1014             :         }
    1015             : 
    1016           4 :         ok &= asn1_end_tag(state->result->data);
    1017             : 
    1018           4 :         if (!ok) {
    1019           0 :                 goto decode_error;
    1020             :         }
    1021             : 
    1022           5 :         if (!TLDAP_RC_IS_SUCCESS(state->result->lderr) &&
    1023           2 :             !TLDAP_RC_EQUAL(state->result->lderr,
    1024             :                             TLDAP_SASL_BIND_IN_PROGRESS)) {
    1025           0 :                 tevent_req_ldap_error(req, state->result->lderr);
    1026           0 :                 return;
    1027             :         }
    1028           4 :         tevent_req_done(req);
    1029           4 :         return;
    1030             : 
    1031           0 : decode_error:
    1032           0 :         tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
    1033           0 :         return;
    1034             : }
    1035             : 
    1036           4 : TLDAPRC tldap_sasl_bind_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
    1037             :                              DATA_BLOB *serverSaslCreds)
    1038             : {
    1039           4 :         struct tldap_req_state *state = tevent_req_data(
    1040             :                 req, struct tldap_req_state);
    1041             :         TLDAPRC rc;
    1042             : 
    1043           4 :         if (tevent_req_is_ldap_error(req, &rc)) {
    1044           0 :                 return rc;
    1045             :         }
    1046             : 
    1047           4 :         if (serverSaslCreds != NULL) {
    1048           4 :                 serverSaslCreds->data = talloc_move(
    1049             :                         mem_ctx, &state->result->res_serverSaslCreds.data);
    1050           4 :                 serverSaslCreds->length =
    1051           4 :                         state->result->res_serverSaslCreds.length;
    1052             :         }
    1053             : 
    1054           4 :         return state->result->lderr;
    1055             : }
    1056             : 
    1057           0 : TLDAPRC tldap_sasl_bind(struct tldap_context *ld,
    1058             :                         const char *dn,
    1059             :                         const char *mechanism,
    1060             :                         DATA_BLOB *creds,
    1061             :                         struct tldap_control *sctrls,
    1062             :                         int num_sctrls,
    1063             :                         struct tldap_control *cctrls,
    1064             :                         int num_cctrls,
    1065             :                         TALLOC_CTX *mem_ctx,
    1066             :                         DATA_BLOB *serverSaslCreds)
    1067             : {
    1068           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1069             :         struct tevent_context *ev;
    1070             :         struct tevent_req *req;
    1071           0 :         TLDAPRC rc = TLDAP_NO_MEMORY;
    1072             : 
    1073           0 :         ev = samba_tevent_context_init(frame);
    1074           0 :         if (ev == NULL) {
    1075           0 :                 goto fail;
    1076             :         }
    1077           0 :         req = tldap_sasl_bind_send(frame, ev, ld, dn, mechanism, creds,
    1078             :                                    sctrls, num_sctrls, cctrls, num_cctrls);
    1079           0 :         if (req == NULL) {
    1080           0 :                 goto fail;
    1081             :         }
    1082           0 :         if (!tevent_req_poll(req, ev)) {
    1083           0 :                 rc = TLDAP_OPERATIONS_ERROR;
    1084           0 :                 goto fail;
    1085             :         }
    1086           0 :         rc = tldap_sasl_bind_recv(req, mem_ctx, serverSaslCreds);
    1087           0 :         tldap_save_msg(ld, req);
    1088           0 :  fail:
    1089           0 :         TALLOC_FREE(frame);
    1090           0 :         return rc;
    1091             : }
    1092             : 
    1093           0 : struct tevent_req *tldap_simple_bind_send(TALLOC_CTX *mem_ctx,
    1094             :                                           struct tevent_context *ev,
    1095             :                                           struct tldap_context *ld,
    1096             :                                           const char *dn,
    1097             :                                           const char *passwd)
    1098             : {
    1099             :         DATA_BLOB cred;
    1100             : 
    1101           0 :         if (passwd != NULL) {
    1102           0 :                 cred.data = discard_const_p(uint8_t, passwd);
    1103           0 :                 cred.length = strlen(passwd);
    1104             :         } else {
    1105           0 :                 cred.data = discard_const_p(uint8_t, "");
    1106           0 :                 cred.length = 0;
    1107             :         }
    1108           0 :         return tldap_sasl_bind_send(mem_ctx, ev, ld, dn, NULL, &cred, NULL, 0,
    1109             :                                     NULL, 0);
    1110             : }
    1111             : 
    1112           0 : TLDAPRC tldap_simple_bind_recv(struct tevent_req *req)
    1113             : {
    1114           0 :         return tldap_sasl_bind_recv(req, NULL, NULL);
    1115             : }
    1116             : 
    1117           0 : TLDAPRC tldap_simple_bind(struct tldap_context *ld, const char *dn,
    1118             :                           const char *passwd)
    1119             : {
    1120             :         DATA_BLOB cred;
    1121             : 
    1122           0 :         if (passwd != NULL) {
    1123           0 :                 cred.data = discard_const_p(uint8_t, passwd);
    1124           0 :                 cred.length = strlen(passwd);
    1125             :         } else {
    1126           0 :                 cred.data = discard_const_p(uint8_t, "");
    1127           0 :                 cred.length = 0;
    1128             :         }
    1129           0 :         return tldap_sasl_bind(ld, dn, NULL, &cred, NULL, 0, NULL, 0,
    1130             :                                NULL, NULL);
    1131             : }
    1132             : 
    1133             : /*****************************************************************************/
    1134             : 
    1135             : /* can't use isalpha() as only a strict set is valid for LDAP */
    1136             : 
    1137        1140 : static bool tldap_is_alpha(char c)
    1138             : {
    1139        1713 :         return (((c >= 'a') && (c <= 'z')) || \
    1140           6 :                 ((c >= 'A') && (c <= 'Z')));
    1141             : }
    1142             : 
    1143        1030 : static bool tldap_is_adh(char c)
    1144             : {
    1145        1030 :         return tldap_is_alpha(c) || isdigit(c) || (c == '-');
    1146             : }
    1147             : 
    1148             : #define TLDAP_FILTER_AND  ASN1_CONTEXT(0)
    1149             : #define TLDAP_FILTER_OR   ASN1_CONTEXT(1)
    1150             : #define TLDAP_FILTER_NOT  ASN1_CONTEXT(2)
    1151             : #define TLDAP_FILTER_EQ   ASN1_CONTEXT(3)
    1152             : #define TLDAP_FILTER_SUB  ASN1_CONTEXT(4)
    1153             : #define TLDAP_FILTER_LE   ASN1_CONTEXT(5)
    1154             : #define TLDAP_FILTER_GE   ASN1_CONTEXT(6)
    1155             : #define TLDAP_FILTER_PRES ASN1_CONTEXT_SIMPLE(7)
    1156             : #define TLDAP_FILTER_APX  ASN1_CONTEXT(8)
    1157             : #define TLDAP_FILTER_EXT  ASN1_CONTEXT(9)
    1158             : 
    1159             : #define TLDAP_SUB_INI ASN1_CONTEXT_SIMPLE(0)
    1160             : #define TLDAP_SUB_ANY ASN1_CONTEXT_SIMPLE(1)
    1161             : #define TLDAP_SUB_FIN ASN1_CONTEXT_SIMPLE(2)
    1162             : 
    1163             : 
    1164             : /* oid's should be numerical only in theory,
    1165             :  * but apparently some broken servers may have alphanum aliases instead.
    1166             :  * Do like openldap libraries and allow alphanum aliases for oids, but
    1167             :  * do not allow Tagging options in that case.
    1168             :  */
    1169         114 : static bool tldap_is_attrdesc(const char *s, int len, bool no_tagopts)
    1170             : {
    1171         114 :         bool is_oid = false;
    1172         114 :         bool dot = false;
    1173             :         int i;
    1174             : 
    1175             :         /* first char has stricter rules */
    1176         114 :         if (isdigit(*s)) {
    1177           4 :                 is_oid = true;
    1178         110 :         } else if (!tldap_is_alpha(*s)) {
    1179             :                 /* bad first char */
    1180           0 :                 return false;
    1181             :         }
    1182             : 
    1183        1172 :         for (i = 1; i < len; i++) {
    1184             : 
    1185        1058 :                 if (is_oid) {
    1186          28 :                         if (isdigit(s[i])) {
    1187          16 :                                 dot = false;
    1188          16 :                                 continue;
    1189             :                         }
    1190          12 :                         if (s[i] == '.') {
    1191          12 :                                 if (dot) {
    1192             :                                         /* malformed */
    1193           0 :                                         return false;
    1194             :                                 }
    1195          12 :                                 dot = true;
    1196          12 :                                 continue;
    1197             :                         }
    1198             :                 } else {
    1199        1030 :                         if (tldap_is_adh(s[i])) {
    1200        1030 :                                 continue;
    1201             :                         }
    1202             :                 }
    1203             : 
    1204           0 :                 if (s[i] == ';') {
    1205           0 :                         if (no_tagopts) {
    1206             :                                 /* no tagging options */
    1207           0 :                                 return false;
    1208             :                         }
    1209           0 :                         if (dot) {
    1210             :                                 /* malformed */
    1211           0 :                                 return false;
    1212             :                         }
    1213           0 :                         if ((i + 1) == len) {
    1214             :                                 /* malformed */
    1215           0 :                                 return false;
    1216             :                         }
    1217             : 
    1218           0 :                         is_oid = false;
    1219           0 :                         continue;
    1220             :                 }
    1221             :         }
    1222             : 
    1223         114 :         if (dot) {
    1224             :                 /* malformed */
    1225           0 :                 return false;
    1226             :         }
    1227             : 
    1228         114 :         return true;
    1229             : }
    1230             : 
    1231             : /* this function copies the value until the closing parenthesis is found. */
    1232          14 : static char *tldap_get_val(TALLOC_CTX *memctx,
    1233             :                            const char *value, const char **_s)
    1234             : {
    1235          14 :         const char *s = value;
    1236             : 
    1237             :         /* find terminator */
    1238          21 :         while (*s) {
    1239          14 :                 s = strchr(s, ')');
    1240          14 :                 if (s && (*(s - 1) == '\\')) {
    1241           0 :                         continue;
    1242             :                 }
    1243          14 :                 break;
    1244             :         }
    1245          14 :         if (!s || !(*s == ')')) {
    1246             :                 /* malformed filter */
    1247           0 :                 return NULL;
    1248             :         }
    1249             : 
    1250          14 :         *_s = s;
    1251             : 
    1252          14 :         return talloc_strndup(memctx, value, s - value);
    1253             : }
    1254             : 
    1255          14 : static int tldap_hex2char(const char *x)
    1256             : {
    1257          14 :         if (isxdigit(x[0]) && isxdigit(x[1])) {
    1258           7 :                 const char h1 = x[0], h2 = x[1];
    1259           7 :                 int c = 0;
    1260             : 
    1261           7 :                 if (h1 >= 'a') c = h1 - (int)'a' + 10;
    1262           7 :                 else if (h1 >= 'A') c = h1 - (int)'A' + 10;
    1263           7 :                 else if (h1 >= '0') c = h1 - (int)'0';
    1264           7 :                 c = c << 4;
    1265           7 :                 if (h2 >= 'a') c += h2 - (int)'a' + 10;
    1266           6 :                 else if (h2 >= 'A') c += h2 - (int)'A' + 10;
    1267           6 :                 else if (h2 >= '0') c += h2 - (int)'0';
    1268             : 
    1269           0 :                 return c;
    1270             :         }
    1271             : 
    1272           0 :         return -1;
    1273             : }
    1274             : 
    1275          16 : static bool tldap_find_first_star(const char *val, const char **star)
    1276             : {
    1277             :         const char *s;
    1278             : 
    1279          44 :         for (s = val; *s; s++) {
    1280          44 :                 switch (*s) {
    1281           0 :                 case '\\':
    1282           0 :                         if (isxdigit(s[1]) && isxdigit(s[2])) {
    1283           0 :                                 s += 2;
    1284           0 :                                 break;
    1285             :                         }
    1286             :                         /* not hex based escape, check older syntax */
    1287           0 :                         switch (s[1]) {
    1288           0 :                         case '(':
    1289             :                         case ')':
    1290             :                         case '*':
    1291             :                         case '\\':
    1292           0 :                                 s++;
    1293           0 :                                 break;
    1294           0 :                         default:
    1295             :                                 /* invalid escape sequence */
    1296           0 :                                 return false;
    1297             :                         }
    1298           0 :                         break;
    1299           6 :                 case ')':
    1300             :                         /* end of val, nothing found */
    1301           6 :                         *star = s;
    1302           6 :                         return true;
    1303             : 
    1304          10 :                 case '*':
    1305          10 :                         *star = s;
    1306          10 :                         return true;
    1307             :                 }
    1308             :         }
    1309             : 
    1310             :         /* string ended without closing parenthesis, filter is malformed */
    1311           0 :         return false;
    1312             : }
    1313             : 
    1314          24 : static bool tldap_unescape_inplace(char *value, size_t *val_len)
    1315             : {
    1316             :         int c;
    1317             :         size_t i, p;
    1318             : 
    1319         178 :         for (i = 0,p = 0; i < *val_len; i++) {
    1320             : 
    1321         154 :                 switch (value[i]) {
    1322           0 :                 case '(':
    1323             :                 case ')':
    1324             :                 case '*':
    1325             :                         /* these must be escaped */
    1326           0 :                         return false;
    1327             : 
    1328          14 :                 case '\\':
    1329          14 :                         if (!value[i + 1]) {
    1330             :                                 /* invalid EOL */
    1331           0 :                                 return false;
    1332             :                         }
    1333          14 :                         i++;
    1334             : 
    1335             :                         /* LDAPv3 escaped */
    1336          14 :                         c = tldap_hex2char(&value[i]);
    1337          14 :                         if (c >= 0 && c < 256) {
    1338           7 :                                 value[p] = c;
    1339           7 :                                 i++;
    1340           7 :                                 p++;
    1341           7 :                                 break;
    1342             :                         }
    1343             : 
    1344             :                         /* LDAPv2 escaped */
    1345           0 :                         switch (value[i]) {
    1346           7 :                         case '(':
    1347             :                         case ')':
    1348             :                         case '*':
    1349             :                         case '\\':
    1350           7 :                                 value[p] = value[i];
    1351           7 :                                 p++;
    1352             : 
    1353           0 :                                 break;
    1354           0 :                         default:
    1355             :                                 /* invalid */
    1356           0 :                                 return false;
    1357             :                         }
    1358           7 :                         break;
    1359             : 
    1360         140 :                 default:
    1361         140 :                         value[p] = value[i];
    1362         140 :                         p++;
    1363             :                 }
    1364             :         }
    1365          24 :         value[p] = '\0';
    1366          24 :         *val_len = p;
    1367          24 :         return true;
    1368             : }
    1369             : 
    1370             : static bool tldap_push_filter_basic(struct tldap_context *ld,
    1371             :                                     struct asn1_data *data,
    1372             :                                     const char **_s);
    1373             : static bool tldap_push_filter_substring(struct tldap_context *ld,
    1374             :                                         struct asn1_data *data,
    1375             :                                         const char *val,
    1376             :                                         const char **_s);
    1377         128 : static bool tldap_push_filter_int(struct tldap_context *ld,
    1378             :                                   struct asn1_data *data,
    1379             :                                   const char **_s)
    1380             : {
    1381         128 :         const char *s = *_s;
    1382             :         bool ret;
    1383             : 
    1384         128 :         if (*s != '(') {
    1385           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1386             :                             "Incomplete or malformed filter\n");
    1387           0 :                 return false;
    1388             :         }
    1389         128 :         s++;
    1390             : 
    1391             :         /* we are right after a parenthesis,
    1392             :          * find out what op we have at hand */
    1393         128 :         switch (*s) {
    1394           2 :         case '&':
    1395           2 :                 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: AND\n");
    1396           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_AND)) return false;
    1397           2 :                 s++;
    1398           2 :                 break;
    1399             : 
    1400           4 :         case '|':
    1401           4 :                 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: OR\n");
    1402           4 :                 if (!asn1_push_tag(data, TLDAP_FILTER_OR)) return false;
    1403           4 :                 s++;
    1404           4 :                 break;
    1405             : 
    1406           4 :         case '!':
    1407           4 :                 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: NOT\n");
    1408           4 :                 if (!asn1_push_tag(data, TLDAP_FILTER_NOT)) return false;
    1409           4 :                 s++;
    1410           4 :                 ret = tldap_push_filter_int(ld, data, &s);
    1411           4 :                 if (!ret) {
    1412           0 :                         return false;
    1413             :                 }
    1414           4 :                 if (!asn1_pop_tag(data)) return false;
    1415           4 :                 goto done;
    1416             : 
    1417           0 :         case '(':
    1418             :         case ')':
    1419           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1420           0 :                             "Invalid parenthesis '%c'\n", *s);
    1421           0 :                 return false;
    1422             : 
    1423           0 :         case '\0':
    1424           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1425             :                             "Invalid filter termination\n");
    1426           0 :                 return false;
    1427             : 
    1428         118 :         default:
    1429         118 :                 ret = tldap_push_filter_basic(ld, data, &s);
    1430         118 :                 if (!ret) {
    1431           0 :                         return false;
    1432             :                 }
    1433         118 :                 goto done;
    1434             :         }
    1435             : 
    1436             :         /* only and/or filters get here.
    1437             :          * go through the list of filters */
    1438             : 
    1439           6 :         if (*s == ')') {
    1440             :                 /* RFC 4526: empty and/or */
    1441           0 :                 if (!asn1_pop_tag(data)) return false;
    1442           0 :                 goto done;
    1443             :         }
    1444             : 
    1445          25 :         while (*s) {
    1446          22 :                 ret = tldap_push_filter_int(ld, data, &s);
    1447          22 :                 if (!ret) {
    1448           0 :                         return false;
    1449             :                 }
    1450             : 
    1451          22 :                 if (*s == ')') {
    1452             :                         /* end of list, return */
    1453           6 :                         if (!asn1_pop_tag(data)) return false;
    1454           6 :                         break;
    1455             :                 }
    1456             :         }
    1457             : 
    1458           0 : done:
    1459         128 :         if (*s != ')') {
    1460           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1461             :                             "Incomplete or malformed filter\n");
    1462           0 :                 return false;
    1463             :         }
    1464         128 :         s++;
    1465             : 
    1466         128 :         if (asn1_has_error(data)) {
    1467           0 :                 return false;
    1468             :         }
    1469             : 
    1470         128 :         *_s = s;
    1471         128 :         return true;
    1472             : }
    1473             : 
    1474             : 
    1475         118 : static bool tldap_push_filter_basic(struct tldap_context *ld,
    1476             :                                     struct asn1_data *data,
    1477             :                                     const char **_s)
    1478             : {
    1479         118 :         TALLOC_CTX *tmpctx = talloc_tos();
    1480         118 :         const char *s = *_s;
    1481             :         const char *e;
    1482             :         const char *eq;
    1483             :         const char *val;
    1484             :         const char *type;
    1485             :         const char *dn;
    1486             :         const char *rule;
    1487             :         const char *star;
    1488         118 :         size_t type_len = 0;
    1489             :         char *uval;
    1490             :         size_t uval_len;
    1491         118 :         bool write_octect = true;
    1492             :         bool ret;
    1493             : 
    1494         118 :         eq = strchr(s, '=');
    1495         118 :         if (!eq) {
    1496           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1497             :                             "Invalid filter, missing equal sign\n");
    1498           0 :                 return false;
    1499             :         }
    1500             : 
    1501         118 :         val = eq + 1;
    1502         118 :         e = eq - 1;
    1503             : 
    1504         118 :         switch (*e) {
    1505           2 :         case '<':
    1506           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_LE)) return false;
    1507           2 :                 break;
    1508             : 
    1509           2 :         case '>':
    1510           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_GE)) return false;
    1511           2 :                 break;
    1512             : 
    1513           2 :         case '~':
    1514           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_APX)) return false;
    1515           2 :                 break;
    1516             : 
    1517           6 :         case ':':
    1518           6 :                 if (!asn1_push_tag(data, TLDAP_FILTER_EXT)) return false;
    1519           6 :                 write_octect = false;
    1520             : 
    1521           6 :                 type = NULL;
    1522           6 :                 dn = NULL;
    1523           6 :                 rule = NULL;
    1524             : 
    1525           6 :                 if (*s == ':') { /* [:dn]:rule:= value */
    1526           2 :                         if (s == e) {
    1527             :                                 /* malformed filter */
    1528           0 :                                 return false;
    1529             :                         }
    1530           2 :                         dn = s;
    1531             :                 } else { /* type[:dn][:rule]:= value */
    1532           4 :                         type = s;
    1533           4 :                         dn = strchr(s, ':');
    1534           4 :                         type_len = dn - type;
    1535           4 :                         if (dn == e) { /* type:= value */
    1536           2 :                                 dn = NULL;
    1537             :                         }
    1538             :                 }
    1539           6 :                 if (dn) {
    1540           4 :                         dn++;
    1541             : 
    1542           4 :                         rule = strchr(dn, ':');
    1543           4 :                         if (rule == NULL) {
    1544           0 :                                 return false;
    1545             :                         }
    1546           4 :                         if ((rule == dn + 1) || rule + 1 == e) {
    1547             :                                 /* malformed filter, contains "::" */
    1548           0 :                                 return false;
    1549             :                         }
    1550             : 
    1551           4 :                         if (strncasecmp_m(dn, "dn:", 3) != 0) {
    1552           0 :                                 if (rule == e) {
    1553           0 :                                         rule = dn;
    1554           0 :                                         dn = NULL;
    1555             :                                 } else {
    1556             :                                         /* malformed filter. With two
    1557             :                                          * optionals, the first must be "dn"
    1558             :                                          */
    1559           0 :                                         return false;
    1560             :                                 }
    1561             :                         } else {
    1562           4 :                                 if (rule == e) {
    1563           0 :                                         rule = NULL;
    1564             :                                 } else {
    1565           4 :                                         rule++;
    1566             :                                 }
    1567             :                         }
    1568             :                 }
    1569             : 
    1570           6 :                 if (!type && !dn && !rule) {
    1571             :                         /* malformed filter, there must be at least one */
    1572           0 :                         return false;
    1573             :                 }
    1574             : 
    1575             :                 /*
    1576             :                   MatchingRuleAssertion ::= SEQUENCE {
    1577             :                   matchingRule    [1] MatchingRuleID OPTIONAL,
    1578             :                   type      [2] AttributeDescription OPTIONAL,
    1579             :                   matchValue      [3] AssertionValue,
    1580             :                   dnAttributes    [4] BOOLEAN DEFAULT FALSE
    1581             :                   }
    1582             :                 */
    1583             : 
    1584             :                 /* check and add rule */
    1585           6 :                 if (rule) {
    1586           4 :                         ret = tldap_is_attrdesc(rule, e - rule, true);
    1587           4 :                         if (!ret) {
    1588           0 :                                 return false;
    1589             :                         }
    1590           4 :                         if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1))) return false;
    1591           4 :                         if (!asn1_write(data, rule, e - rule)) return false;
    1592           4 :                         if (!asn1_pop_tag(data)) return false;
    1593             :                 }
    1594             : 
    1595             :                 /* check and add type */
    1596           6 :                 if (type) {
    1597           4 :                         ret = tldap_is_attrdesc(type, type_len, false);
    1598           4 :                         if (!ret) {
    1599           0 :                                 return false;
    1600             :                         }
    1601           4 :                         if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2))) return false;
    1602           4 :                         if (!asn1_write(data, type, type_len)) return false;
    1603           4 :                         if (!asn1_pop_tag(data)) return false;
    1604             :                 }
    1605             : 
    1606           6 :                 uval = tldap_get_val(tmpctx, val, _s);
    1607           6 :                 if (!uval) {
    1608           0 :                         return false;
    1609             :                 }
    1610           6 :                 uval_len = *_s - val;
    1611           6 :                 ret = tldap_unescape_inplace(uval, &uval_len);
    1612           6 :                 if (!ret) {
    1613           0 :                         return false;
    1614             :                 }
    1615             : 
    1616           6 :                 if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3))) return false;
    1617           6 :                 if (!asn1_write(data, uval, uval_len)) return false;
    1618           6 :                 if (!asn1_pop_tag(data)) return false;
    1619             : 
    1620           6 :                 if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4))) return false;
    1621           6 :                 if (!asn1_write_uint8(data, dn?1:0)) return false;
    1622           6 :                 if (!asn1_pop_tag(data)) return false;
    1623           6 :                 break;
    1624             : 
    1625         106 :         default:
    1626         106 :                 e = eq;
    1627             : 
    1628         106 :                 ret = tldap_is_attrdesc(s, e - s, false);
    1629         106 :                 if (!ret) {
    1630           0 :                         return false;
    1631             :                 }
    1632             : 
    1633         106 :                 if (strncmp(val, "*)", 2) == 0) {
    1634             :                         /* presence */
    1635         100 :                         if (!asn1_push_tag(data, TLDAP_FILTER_PRES)) return false;
    1636         100 :                         if (!asn1_write(data, s, e - s)) return false;
    1637         100 :                         *_s = val + 1;
    1638         100 :                         write_octect = false;
    1639         100 :                         break;
    1640             :                 }
    1641             : 
    1642           6 :                 ret = tldap_find_first_star(val, &star);
    1643           6 :                 if (!ret) {
    1644           0 :                         return false;
    1645             :                 }
    1646           6 :                 if (*star == '*') {
    1647             :                         /* substring */
    1648           4 :                         if (!asn1_push_tag(data, TLDAP_FILTER_SUB)) return false;
    1649           4 :                         if (!asn1_write_OctetString(data, s, e - s)) return false;
    1650           4 :                         ret = tldap_push_filter_substring(ld, data, val, &s);
    1651           4 :                         if (!ret) {
    1652           0 :                                 return false;
    1653             :                         }
    1654           4 :                         *_s = s;
    1655           4 :                         write_octect = false;
    1656           4 :                         break;
    1657             :                 }
    1658             : 
    1659             :                 /* if nothing else, then it is just equality */
    1660           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_EQ)) return false;
    1661           2 :                 write_octect = true;
    1662           2 :                 break;
    1663             :         }
    1664             : 
    1665         118 :         if (write_octect) {
    1666           8 :                 uval = tldap_get_val(tmpctx, val, _s);
    1667           8 :                 if (!uval) {
    1668           0 :                         return false;
    1669             :                 }
    1670           8 :                 uval_len = *_s - val;
    1671           8 :                 ret = tldap_unescape_inplace(uval, &uval_len);
    1672           8 :                 if (!ret) {
    1673           0 :                         return false;
    1674             :                 }
    1675             : 
    1676           8 :                 if (!asn1_write_OctetString(data, s, e - s)) return false;
    1677           8 :                 if (!asn1_write_OctetString(data, uval, uval_len)) return false;
    1678             :         }
    1679             : 
    1680         118 :         if (asn1_has_error(data)) {
    1681           0 :                 return false;
    1682             :         }
    1683         118 :         return asn1_pop_tag(data);
    1684             : }
    1685             : 
    1686           4 : static bool tldap_push_filter_substring(struct tldap_context *ld,
    1687             :                                         struct asn1_data *data,
    1688             :                                         const char *val,
    1689             :                                         const char **_s)
    1690             : {
    1691           4 :         TALLOC_CTX *tmpctx = talloc_tos();
    1692           4 :         bool initial = true;
    1693             :         const char *star;
    1694             :         char *chunk;
    1695             :         size_t chunk_len;
    1696             :         bool ret;
    1697             : 
    1698             :         /*
    1699             :           SubstringFilter ::= SEQUENCE {
    1700             :                   type      AttributeDescription,
    1701             :                   -- at least one must be present
    1702             :                   substrings      SEQUENCE OF CHOICE {
    1703             :                           initial [0] LDAPString,
    1704             :                           any     [1] LDAPString,
    1705             :                           final   [2] LDAPString } }
    1706             :         */
    1707           4 :         if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
    1708             : 
    1709             :         do {
    1710          10 :                 ret = tldap_find_first_star(val, &star);
    1711          10 :                 if (!ret) {
    1712           0 :                         return false;
    1713             :                 }
    1714          10 :                 chunk_len = star - val;
    1715             : 
    1716          10 :                 switch (*star) {
    1717           6 :                 case '*':
    1718           6 :                         if (!initial && chunk_len == 0) {
    1719             :                                 /* found '**', which is illegal */
    1720           0 :                                 return false;
    1721             :                         }
    1722           6 :                         break;
    1723           4 :                 case ')':
    1724           4 :                         if (initial) {
    1725             :                                 /* no stars ?? */
    1726           0 :                                 return false;
    1727             :                         }
    1728             :                         /* we are done */
    1729           4 :                         break;
    1730           0 :                 default:
    1731             :                         /* ?? */
    1732           0 :                         return false;
    1733             :                 }
    1734             : 
    1735          10 :                 if (initial && chunk_len == 0) {
    1736           2 :                         val = star + 1;
    1737           2 :                         initial = false;
    1738           2 :                         continue;
    1739             :                 }
    1740             : 
    1741           8 :                 chunk = talloc_strndup(tmpctx, val, chunk_len);
    1742           8 :                 if (!chunk) {
    1743           0 :                         return false;
    1744             :                 }
    1745           8 :                 ret = tldap_unescape_inplace(chunk, &chunk_len);
    1746           8 :                 if (!ret) {
    1747           0 :                         return false;
    1748             :                 }
    1749           8 :                 switch (*star) {
    1750           4 :                 case '*':
    1751           4 :                         if (initial) {
    1752           2 :                                 if (!asn1_push_tag(data, TLDAP_SUB_INI)) return false;
    1753           2 :                                 initial = false;
    1754             :                         } else {
    1755           2 :                                 if (!asn1_push_tag(data, TLDAP_SUB_ANY)) return false;
    1756             :                         }
    1757           4 :                         break;
    1758           4 :                 case ')':
    1759           4 :                         if (!asn1_push_tag(data, TLDAP_SUB_FIN)) return false;
    1760           4 :                         break;
    1761           0 :                 default:
    1762             :                         /* ?? */
    1763           0 :                         return false;
    1764             :                 }
    1765           8 :                 if (!asn1_write(data, chunk, chunk_len)) return false;
    1766           8 :                 if (!asn1_pop_tag(data)) return false;
    1767             : 
    1768           8 :                 val = star + 1;
    1769             : 
    1770          10 :         } while (*star == '*');
    1771             : 
    1772           4 :         *_s = star;
    1773             : 
    1774             :         /* end of sequence */
    1775           4 :         return asn1_pop_tag(data);
    1776             : }
    1777             : 
    1778             : /* NOTE: although openldap libraries allow for spaces in some places, mosly
    1779             :  * around parenthesis, we do not allow any spaces (except in values of
    1780             :  * course) as I couldn't fine any place in RFC 4512 or RFC 4515 where
    1781             :  * leading or trailing spaces where allowed.
    1782             :  */
    1783         102 : static bool tldap_push_filter(struct tldap_context *ld,
    1784             :                               struct asn1_data *data,
    1785             :                               const char *filter)
    1786             : {
    1787         102 :         const char *s = filter;
    1788             :         bool ret;
    1789             : 
    1790         102 :         ret = tldap_push_filter_int(ld, data, &s);
    1791         102 :         if (ret && *s) {
    1792           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1793             :                             "Incomplete or malformed filter\n");
    1794           0 :                 return false;
    1795             :         }
    1796         102 :         return ret;
    1797             : }
    1798             : 
    1799             : /*****************************************************************************/
    1800             : 
    1801             : static void tldap_search_done(struct tevent_req *subreq);
    1802             : 
    1803         102 : struct tevent_req *tldap_search_send(TALLOC_CTX *mem_ctx,
    1804             :                                      struct tevent_context *ev,
    1805             :                                      struct tldap_context *ld,
    1806             :                                      const char *base, int scope,
    1807             :                                      const char *filter,
    1808             :                                      const char **attrs,
    1809             :                                      int num_attrs,
    1810             :                                      int attrsonly,
    1811             :                                      struct tldap_control *sctrls,
    1812             :                                      int num_sctrls,
    1813             :                                      struct tldap_control *cctrls,
    1814             :                                      int num_cctrls,
    1815             :                                      int timelimit,
    1816             :                                      int sizelimit,
    1817             :                                      int deref)
    1818             : {
    1819             :         struct tevent_req *req, *subreq;
    1820             :         struct tldap_req_state *state;
    1821             :         int i;
    1822             : 
    1823         102 :         req = tldap_req_create(mem_ctx, ld, &state);
    1824         102 :         if (req == NULL) {
    1825           0 :                 return NULL;
    1826             :         }
    1827             : 
    1828         102 :         if (!asn1_push_tag(state->out, TLDAP_REQ_SEARCH)) goto encoding_error;
    1829         102 :         if (!asn1_write_OctetString(state->out, base, strlen(base))) goto encoding_error;
    1830         102 :         if (!asn1_write_enumerated(state->out, scope)) goto encoding_error;
    1831         102 :         if (!asn1_write_enumerated(state->out, deref)) goto encoding_error;
    1832         102 :         if (!asn1_write_Integer(state->out, sizelimit)) goto encoding_error;
    1833         102 :         if (!asn1_write_Integer(state->out, timelimit)) goto encoding_error;
    1834         102 :         if (!asn1_write_BOOLEAN(state->out, attrsonly)) goto encoding_error;
    1835             : 
    1836         102 :         if (!tldap_push_filter(ld, state->out, filter)) {
    1837           0 :                 goto encoding_error;
    1838             :         }
    1839             : 
    1840         102 :         if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto encoding_error;
    1841         108 :         for (i=0; i<num_attrs; i++) {
    1842           6 :                 if (!asn1_write_OctetString(state->out, attrs[i], strlen(attrs[i]))) goto encoding_error;
    1843             :         }
    1844         102 :         if (!asn1_pop_tag(state->out)) goto encoding_error;
    1845         102 :         if (!asn1_pop_tag(state->out)) goto encoding_error;
    1846             : 
    1847         102 :         subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
    1848             :                                 sctrls, num_sctrls);
    1849         102 :         if (tevent_req_nomem(subreq, req)) {
    1850           0 :                 return tevent_req_post(req, ev);
    1851             :         }
    1852         102 :         tevent_req_set_callback(subreq, tldap_search_done, req);
    1853         102 :         return req;
    1854             : 
    1855           0 :  encoding_error:
    1856           0 :         tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
    1857           0 :         return tevent_req_post(req, ev);
    1858             : }
    1859             : 
    1860         560 : static void tldap_search_done(struct tevent_req *subreq)
    1861             : {
    1862         560 :         struct tevent_req *req = tevent_req_callback_data(
    1863             :                 subreq, struct tevent_req);
    1864         560 :         struct tldap_req_state *state = tevent_req_data(
    1865             :                 req, struct tldap_req_state);
    1866             :         TLDAPRC rc;
    1867             : 
    1868         560 :         rc = tldap_msg_recv(subreq, state, &state->result);
    1869         560 :         if (tevent_req_ldap_error(req, rc)) {
    1870           0 :                 return;
    1871             :         }
    1872         560 :         switch (state->result->type) {
    1873         458 :         case TLDAP_RES_SEARCH_ENTRY:
    1874             :         case TLDAP_RES_SEARCH_REFERENCE:
    1875         458 :                 if (!tldap_msg_set_pending(subreq)) {
    1876           0 :                         tevent_req_oom(req);
    1877           0 :                         return;
    1878             :                 }
    1879         458 :                 tevent_req_notify_callback(req);
    1880         509 :                 break;
    1881         102 :         case TLDAP_RES_SEARCH_RESULT:
    1882         102 :                 TALLOC_FREE(subreq);
    1883         102 :                 if (!asn1_start_tag(state->result->data,
    1884         153 :                                     state->result->type) ||
    1885         153 :                     !tldap_decode_response(state) ||
    1886         153 :                     !asn1_end_tag(state->result->data) ||
    1887         102 :                     !tldap_decode_controls(state)) {
    1888           0 :                         tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
    1889           0 :                         return;
    1890             :                 }
    1891         102 :                 tevent_req_done(req);
    1892         102 :                 break;
    1893           0 :         default:
    1894           0 :                 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
    1895           0 :                 return;
    1896             :         }
    1897             : }
    1898             : 
    1899         560 : TLDAPRC tldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
    1900             :                           struct tldap_message **pmsg)
    1901             : {
    1902         560 :         struct tldap_req_state *state = tevent_req_data(
    1903             :                 req, struct tldap_req_state);
    1904             :         TLDAPRC rc;
    1905             : 
    1906         560 :         if (!tevent_req_is_in_progress(req)
    1907         102 :             && tevent_req_is_ldap_error(req, &rc)) {
    1908           0 :                 return rc;
    1909             :         }
    1910             : 
    1911         560 :         if (tevent_req_is_in_progress(req)) {
    1912         458 :                 switch (state->result->type) {
    1913         458 :                 case TLDAP_RES_SEARCH_ENTRY:
    1914             :                 case TLDAP_RES_SEARCH_REFERENCE:
    1915         458 :                         break;
    1916           0 :                 default:
    1917           0 :                         return TLDAP_OPERATIONS_ERROR;
    1918             :                 }
    1919          51 :         }
    1920             : 
    1921         560 :         *pmsg = talloc_move(mem_ctx, &state->result);
    1922         560 :         return TLDAP_SUCCESS;
    1923             : }
    1924             : 
    1925             : struct tldap_search_all_state {
    1926             :         struct tldap_message **msgs;
    1927             :         struct tldap_message *result;
    1928             : };
    1929             : 
    1930             : static void tldap_search_all_done(struct tevent_req *subreq);
    1931             : 
    1932          10 : struct tevent_req *tldap_search_all_send(
    1933             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
    1934             :         struct tldap_context *ld, const char *base, int scope,
    1935             :         const char *filter, const char **attrs, int num_attrs, int attrsonly,
    1936             :         struct tldap_control *sctrls, int num_sctrls,
    1937             :         struct tldap_control *cctrls, int num_cctrls,
    1938             :         int timelimit, int sizelimit, int deref)
    1939             : {
    1940             :         struct tevent_req *req, *subreq;
    1941             :         struct tldap_search_all_state *state;
    1942             : 
    1943          10 :         req = tevent_req_create(mem_ctx, &state,
    1944             :                                 struct tldap_search_all_state);
    1945          10 :         if (req == NULL) {
    1946           0 :                 return NULL;
    1947             :         }
    1948             : 
    1949          10 :         subreq = tldap_search_send(state, ev, ld, base, scope, filter,
    1950             :                                    attrs, num_attrs, attrsonly,
    1951             :                                    sctrls, num_sctrls, cctrls, num_cctrls,
    1952             :                                    timelimit, sizelimit, deref);
    1953          10 :         if (tevent_req_nomem(subreq, req)) {
    1954           0 :                 return tevent_req_post(req, ev);
    1955             :         }
    1956          10 :         tevent_req_set_callback(subreq, tldap_search_all_done, req);
    1957          10 :         return req;
    1958             : }
    1959             : 
    1960          20 : static void tldap_search_all_done(struct tevent_req *subreq)
    1961             : {
    1962          20 :         struct tevent_req *req = tevent_req_callback_data(
    1963             :                 subreq, struct tevent_req);
    1964          20 :         struct tldap_search_all_state *state = tevent_req_data(
    1965             :                 req, struct tldap_search_all_state);
    1966             :         struct tldap_message *msg, **tmp;
    1967             :         size_t num_msgs;
    1968             :         TLDAPRC rc;
    1969             :         int msgtype;
    1970             : 
    1971          20 :         rc = tldap_search_recv(subreq, state, &msg);
    1972             :         /* No TALLOC_FREE(subreq), this is multi-step */
    1973          20 :         if (tevent_req_ldap_error(req, rc)) {
    1974          10 :                 return;
    1975             :         }
    1976             : 
    1977          20 :         msgtype = tldap_msg_type(msg);
    1978          20 :         if (msgtype == TLDAP_RES_SEARCH_RESULT) {
    1979          10 :                 state->result = msg;
    1980          10 :                 tevent_req_done(req);
    1981          10 :                 return;
    1982             :         }
    1983             : 
    1984          10 :         num_msgs = talloc_array_length(state->msgs);
    1985             : 
    1986          10 :         tmp = talloc_realloc(state, state->msgs, struct tldap_message *,
    1987             :                              num_msgs + 1);
    1988          10 :         if (tevent_req_nomem(tmp, req)) {
    1989           0 :                 return;
    1990             :         }
    1991          10 :         state->msgs = tmp;
    1992          10 :         state->msgs[num_msgs] = talloc_move(state->msgs, &msg);
    1993             : }
    1994             : 
    1995          10 : TLDAPRC tldap_search_all_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
    1996             :                               struct tldap_message ***msgs,
    1997             :                               struct tldap_message **result)
    1998             : {
    1999          10 :         struct tldap_search_all_state *state = tevent_req_data(
    2000             :                 req, struct tldap_search_all_state);
    2001             :         TLDAPRC rc;
    2002             : 
    2003          10 :         if (tevent_req_is_ldap_error(req, &rc)) {
    2004           0 :                 return rc;
    2005             :         }
    2006             : 
    2007          10 :         if (msgs != NULL) {
    2008          10 :                 *msgs = talloc_move(mem_ctx, &state->msgs);
    2009             :         }
    2010          10 :         if (result != NULL) {
    2011          10 :                 *result = talloc_move(mem_ctx, &state->result);
    2012             :         }
    2013             : 
    2014          10 :         return TLDAP_SUCCESS;
    2015             : }
    2016             : 
    2017           8 : TLDAPRC tldap_search(struct tldap_context *ld,
    2018             :                      const char *base, int scope, const char *filter,
    2019             :                      const char **attrs, int num_attrs, int attrsonly,
    2020             :                      struct tldap_control *sctrls, int num_sctrls,
    2021             :                      struct tldap_control *cctrls, int num_cctrls,
    2022             :                      int timelimit, int sizelimit, int deref,
    2023             :                      TALLOC_CTX *mem_ctx, struct tldap_message ***pmsgs)
    2024             : {
    2025             :         TALLOC_CTX *frame;
    2026             :         struct tevent_context *ev;
    2027             :         struct tevent_req *req;
    2028           8 :         TLDAPRC rc = TLDAP_NO_MEMORY;
    2029             :         struct tldap_message **msgs;
    2030             :         struct tldap_message *result;
    2031             : 
    2032           8 :         if (tldap_pending_reqs(ld)) {
    2033           0 :                 return TLDAP_BUSY;
    2034             :         }
    2035             : 
    2036           8 :         frame = talloc_stackframe();
    2037             : 
    2038           8 :         ev = samba_tevent_context_init(frame);
    2039           8 :         if (ev == NULL) {
    2040           0 :                 goto fail;
    2041             :         }
    2042           8 :         req = tldap_search_all_send(frame, ev, ld, base, scope, filter,
    2043             :                                     attrs, num_attrs, attrsonly,
    2044             :                                     sctrls, num_sctrls, cctrls, num_cctrls,
    2045             :                                     timelimit, sizelimit, deref);
    2046           8 :         if (req == NULL) {
    2047           0 :                 goto fail;
    2048             :         }
    2049           8 :         if (!tevent_req_poll(req, ev)) {
    2050           0 :                 rc = TLDAP_OPERATIONS_ERROR;
    2051           0 :                 goto fail;
    2052             :         }
    2053           8 :         rc = tldap_search_all_recv(req, frame, &msgs, &result);
    2054           8 :         TALLOC_FREE(req);
    2055           8 :         if (!TLDAP_RC_IS_SUCCESS(rc)) {
    2056           0 :                 goto fail;
    2057             :         }
    2058             : 
    2059           8 :         TALLOC_FREE(ld->last_msg);
    2060           8 :         ld->last_msg = talloc_move(ld, &result);
    2061             : 
    2062           8 :         if (pmsgs != NULL) {
    2063           6 :                 *pmsgs = talloc_move(mem_ctx, &msgs);
    2064             :         }
    2065           6 : fail:
    2066           8 :         TALLOC_FREE(frame);
    2067           8 :         return rc;
    2068             : }
    2069             : 
    2070         450 : static bool tldap_parse_search_entry(struct tldap_message *msg)
    2071             : {
    2072         450 :         int num_attribs = 0;
    2073             : 
    2074         450 :         if (msg->type != TLDAP_RES_SEARCH_ENTRY) {
    2075           0 :                 return false;
    2076             :         }
    2077         450 :         if (!asn1_start_tag(msg->data, TLDAP_RES_SEARCH_ENTRY)) {
    2078           0 :                 return false;
    2079             :         }
    2080             : 
    2081             :         /* dn */
    2082             : 
    2083         450 :         if (!asn1_read_OctetString_talloc(msg, msg->data, &msg->dn)) return false;
    2084             : 
    2085         450 :         if (msg->dn == NULL) {
    2086           0 :                 return false;
    2087             :         }
    2088             : 
    2089             :         /*
    2090             :          * Attributes: We overallocate msg->attribs by one, so that while
    2091             :          * looping over the attributes we can directly parse into the last
    2092             :          * array element. Same for the values in the inner loop.
    2093             :          */
    2094             : 
    2095         450 :         msg->attribs = talloc_array(msg, struct tldap_attribute, 1);
    2096         450 :         if (msg->attribs == NULL) {
    2097           0 :                 return false;
    2098             :         }
    2099             : 
    2100         450 :         if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
    2101        7805 :         while (asn1_peek_tag(msg->data, ASN1_SEQUENCE(0))) {
    2102             :                 struct tldap_attribute *attrib;
    2103        7130 :                 int num_values = 0;
    2104             : 
    2105        7130 :                 attrib = &msg->attribs[num_attribs];
    2106        7130 :                 attrib->values = talloc_array(msg->attribs, DATA_BLOB, 1);
    2107        7130 :                 if (attrib->values == NULL) {
    2108           0 :                         return false;
    2109             :                 }
    2110        7130 :                 if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
    2111        7130 :                 if (!asn1_read_OctetString_talloc(msg->attribs, msg->data,
    2112           0 :                                              &attrib->name)) return false;
    2113        7130 :                 if (!asn1_start_tag(msg->data, ASN1_SET)) return false;
    2114             : 
    2115       18655 :                 while (asn1_peek_tag(msg->data, ASN1_OCTET_STRING)) {
    2116        7960 :                         if (!asn1_read_OctetString(msg->data, msg,
    2117        7960 :                                               &attrib->values[num_values])) return false;
    2118             : 
    2119        7960 :                         attrib->values = talloc_realloc(
    2120             :                                 msg->attribs, attrib->values, DATA_BLOB,
    2121             :                                 num_values + 2);
    2122        7960 :                         if (attrib->values == NULL) {
    2123           0 :                                 return false;
    2124             :                         }
    2125        7960 :                         num_values += 1;
    2126             :                 }
    2127        7130 :                 attrib->values = talloc_realloc(msg->attribs, attrib->values,
    2128             :                                                 DATA_BLOB, num_values);
    2129        7130 :                 attrib->num_values = num_values;
    2130             : 
    2131        7130 :                 if (!asn1_end_tag(msg->data)) return false; /* ASN1_SET */
    2132        7130 :                 if (!asn1_end_tag(msg->data)) return false; /* ASN1_SEQUENCE(0) */
    2133        7130 :                 msg->attribs = talloc_realloc(
    2134             :                         msg, msg->attribs, struct tldap_attribute,
    2135             :                         num_attribs + 2);
    2136        7130 :                 if (msg->attribs == NULL) {
    2137           0 :                         return false;
    2138             :                 }
    2139        7130 :                 num_attribs += 1;
    2140             :         }
    2141         450 :         msg->attribs = talloc_realloc(
    2142             :                 msg, msg->attribs, struct tldap_attribute, num_attribs);
    2143         450 :         return asn1_end_tag(msg->data);
    2144             : }
    2145             : 
    2146         448 : bool tldap_entry_dn(struct tldap_message *msg, char **dn)
    2147             : {
    2148         448 :         if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
    2149           0 :                 return false;
    2150             :         }
    2151         448 :         *dn = msg->dn;
    2152         448 :         return true;
    2153             : }
    2154             : 
    2155           4 : bool tldap_entry_attributes(struct tldap_message *msg,
    2156             :                             struct tldap_attribute **attributes,
    2157             :                             int *num_attributes)
    2158             : {
    2159           4 :         if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
    2160           0 :                 return false;
    2161             :         }
    2162           4 :         *attributes = msg->attribs;
    2163           4 :         *num_attributes = talloc_array_length(msg->attribs);
    2164           4 :         return true;
    2165             : }
    2166             : 
    2167         102 : static bool tldap_decode_controls(struct tldap_req_state *state)
    2168             : {
    2169         102 :         struct tldap_message *msg = state->result;
    2170         102 :         struct asn1_data *data = msg->data;
    2171         102 :         struct tldap_control *sctrls = NULL;
    2172         102 :         int num_controls = 0;
    2173         102 :         bool ret = false;
    2174             : 
    2175         102 :         msg->res_sctrls = NULL;
    2176             : 
    2177         102 :         if (!asn1_peek_tag(data, ASN1_CONTEXT(0))) {
    2178          12 :                 return true;
    2179             :         }
    2180             : 
    2181          90 :         if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto out;
    2182             : 
    2183         225 :         while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
    2184             :                 struct tldap_control *c;
    2185          90 :                 char *oid = NULL;
    2186             : 
    2187          90 :                 sctrls = talloc_realloc(msg, sctrls, struct tldap_control,
    2188             :                                         num_controls + 1);
    2189          90 :                 if (sctrls == NULL) {
    2190           0 :                         goto out;
    2191             :                 }
    2192          90 :                 c = &sctrls[num_controls];
    2193             : 
    2194          90 :                 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto out;
    2195          90 :                 if (!asn1_read_OctetString_talloc(msg, data, &oid)) goto out;
    2196          90 :                 if (asn1_has_error(data) || (oid == NULL)) {
    2197           0 :                         goto out;
    2198             :                 }
    2199          90 :                 c->oid = oid;
    2200          90 :                 if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
    2201           0 :                         if (!asn1_read_BOOLEAN(data, &c->critical)) goto out;
    2202             :                 } else {
    2203          90 :                         c->critical = false;
    2204             :                 }
    2205          90 :                 c->value = data_blob_null;
    2206         135 :                 if (asn1_peek_tag(data, ASN1_OCTET_STRING) &&
    2207          90 :                     !asn1_read_OctetString(data, msg, &c->value)) {
    2208           0 :                         goto out;
    2209             :                 }
    2210          90 :                 if (!asn1_end_tag(data)) goto out; /* ASN1_SEQUENCE(0) */
    2211             : 
    2212          90 :                 num_controls += 1;
    2213             :         }
    2214             : 
    2215          90 :         if (!asn1_end_tag(data)) goto out;      /* ASN1_CONTEXT(0) */
    2216             : 
    2217          90 :         ret = true;
    2218             : 
    2219          90 :  out:
    2220             : 
    2221          90 :         if (ret) {
    2222          90 :                 msg->res_sctrls = sctrls;
    2223             :         } else {
    2224           0 :                 TALLOC_FREE(sctrls);
    2225             :         }
    2226          90 :         return ret;
    2227             : }
    2228             : 
    2229           0 : static void tldap_simple_done(struct tevent_req *subreq, int type)
    2230             : {
    2231           0 :         struct tevent_req *req = tevent_req_callback_data(
    2232             :                 subreq, struct tevent_req);
    2233           0 :         struct tldap_req_state *state = tevent_req_data(
    2234             :                 req, struct tldap_req_state);
    2235             :         TLDAPRC rc;
    2236             : 
    2237           0 :         rc = tldap_msg_recv(subreq, state, &state->result);
    2238           0 :         TALLOC_FREE(subreq);
    2239           0 :         if (tevent_req_ldap_error(req, rc)) {
    2240           0 :                 return;
    2241             :         }
    2242           0 :         if (state->result->type != type) {
    2243           0 :                 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
    2244           0 :                 return;
    2245             :         }
    2246           0 :         if (!asn1_start_tag(state->result->data, state->result->type) ||
    2247           0 :             !tldap_decode_response(state) ||
    2248           0 :             !asn1_end_tag(state->result->data) ||
    2249           0 :             !tldap_decode_controls(state)) {
    2250           0 :                 tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
    2251           0 :                 return;
    2252             :         }
    2253           0 :         if (!TLDAP_RC_IS_SUCCESS(state->result->lderr)) {
    2254           0 :                 tevent_req_ldap_error(req, state->result->lderr);
    2255           0 :                 return;
    2256             :         }
    2257           0 :         tevent_req_done(req);
    2258             : }
    2259             : 
    2260           0 : static TLDAPRC tldap_simple_recv(struct tevent_req *req)
    2261             : {
    2262             :         TLDAPRC rc;
    2263           0 :         if (tevent_req_is_ldap_error(req, &rc)) {
    2264           0 :                 return rc;
    2265             :         }
    2266           0 :         return TLDAP_SUCCESS;
    2267             : }
    2268             : 
    2269             : static void tldap_add_done(struct tevent_req *subreq);
    2270             : 
    2271           0 : struct tevent_req *tldap_add_send(TALLOC_CTX *mem_ctx,
    2272             :                                   struct tevent_context *ev,
    2273             :                                   struct tldap_context *ld,
    2274             :                                   const char *dn,
    2275             :                                   struct tldap_mod *attributes,
    2276             :                                   int num_attributes,
    2277             :                                   struct tldap_control *sctrls,
    2278             :                                   int num_sctrls,
    2279             :                                   struct tldap_control *cctrls,
    2280             :                                   int num_cctrls)
    2281             : {
    2282             :         struct tevent_req *req, *subreq;
    2283             :         struct tldap_req_state *state;
    2284             :         int i, j;
    2285             : 
    2286           0 :         req = tldap_req_create(mem_ctx, ld, &state);
    2287           0 :         if (req == NULL) {
    2288           0 :                 return NULL;
    2289             :         }
    2290             : 
    2291           0 :         if (!asn1_push_tag(state->out, TLDAP_REQ_ADD)) goto err;
    2292           0 :         if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
    2293           0 :         if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2294             : 
    2295           0 :         for (i=0; i<num_attributes; i++) {
    2296           0 :                 struct tldap_mod *attrib = &attributes[i];
    2297           0 :                 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2298           0 :                 if (!asn1_write_OctetString(state->out, attrib->attribute,
    2299           0 :                                        strlen(attrib->attribute))) goto err;
    2300           0 :                 if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
    2301           0 :                 for (j=0; j<attrib->num_values; j++) {
    2302           0 :                         if (!asn1_write_OctetString(state->out,
    2303           0 :                                                attrib->values[j].data,
    2304           0 :                                                attrib->values[j].length)) goto err;
    2305             :                 }
    2306           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2307           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2308             :         }
    2309             : 
    2310           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2311           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2312             : 
    2313           0 :         subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
    2314             :                                 sctrls, num_sctrls);
    2315           0 :         if (tevent_req_nomem(subreq, req)) {
    2316           0 :                 return tevent_req_post(req, ev);
    2317             :         }
    2318           0 :         tevent_req_set_callback(subreq, tldap_add_done, req);
    2319           0 :         return req;
    2320             : 
    2321           0 :   err:
    2322             : 
    2323           0 :         tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
    2324           0 :         return tevent_req_post(req, ev);
    2325             : }
    2326             : 
    2327           0 : static void tldap_add_done(struct tevent_req *subreq)
    2328             : {
    2329           0 :         tldap_simple_done(subreq, TLDAP_RES_ADD);
    2330           0 : }
    2331             : 
    2332           0 : TLDAPRC tldap_add_recv(struct tevent_req *req)
    2333             : {
    2334           0 :         return tldap_simple_recv(req);
    2335             : }
    2336             : 
    2337           0 : TLDAPRC tldap_add(struct tldap_context *ld, const char *dn,
    2338             :                   struct tldap_mod *attributes, int num_attributes,
    2339             :                   struct tldap_control *sctrls, int num_sctrls,
    2340             :                   struct tldap_control *cctrls, int num_cctrls)
    2341             : {
    2342           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2343             :         struct tevent_context *ev;
    2344             :         struct tevent_req *req;
    2345           0 :         TLDAPRC rc = TLDAP_NO_MEMORY;
    2346             : 
    2347           0 :         ev = samba_tevent_context_init(frame);
    2348           0 :         if (ev == NULL) {
    2349           0 :                 goto fail;
    2350             :         }
    2351           0 :         req = tldap_add_send(frame, ev, ld, dn, attributes, num_attributes,
    2352             :                              sctrls, num_sctrls, cctrls, num_cctrls);
    2353           0 :         if (req == NULL) {
    2354           0 :                 goto fail;
    2355             :         }
    2356           0 :         if (!tevent_req_poll(req, ev)) {
    2357           0 :                 rc = TLDAP_OPERATIONS_ERROR;
    2358           0 :                 goto fail;
    2359             :         }
    2360           0 :         rc = tldap_add_recv(req);
    2361           0 :         tldap_save_msg(ld, req);
    2362           0 :  fail:
    2363           0 :         TALLOC_FREE(frame);
    2364           0 :         return rc;
    2365             : }
    2366             : 
    2367             : static void tldap_modify_done(struct tevent_req *subreq);
    2368             : 
    2369           0 : struct tevent_req *tldap_modify_send(TALLOC_CTX *mem_ctx,
    2370             :                                      struct tevent_context *ev,
    2371             :                                      struct tldap_context *ld,
    2372             :                                      const char *dn,
    2373             :                                      struct tldap_mod *mods, int num_mods,
    2374             :                                      struct tldap_control *sctrls,
    2375             :                                      int num_sctrls,
    2376             :                                      struct tldap_control *cctrls,
    2377             :                                      int num_cctrls)
    2378             : {
    2379             :         struct tevent_req *req, *subreq;
    2380             :         struct tldap_req_state *state;
    2381             :         int i, j;
    2382             : 
    2383           0 :         req = tldap_req_create(mem_ctx, ld, &state);
    2384           0 :         if (req == NULL) {
    2385           0 :                 return NULL;
    2386             :         }
    2387             : 
    2388           0 :         if (!asn1_push_tag(state->out, TLDAP_REQ_MODIFY)) goto err;
    2389           0 :         if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
    2390           0 :         if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2391             : 
    2392           0 :         for (i=0; i<num_mods; i++) {
    2393           0 :                 struct tldap_mod *mod = &mods[i];
    2394           0 :                 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2395           0 :                 if (!asn1_write_enumerated(state->out, mod->mod_op)) goto err;
    2396           0 :                 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2397           0 :                 if (!asn1_write_OctetString(state->out, mod->attribute,
    2398           0 :                                        strlen(mod->attribute))) goto err;
    2399           0 :                 if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
    2400           0 :                 for (j=0; j<mod->num_values; j++) {
    2401           0 :                         if (!asn1_write_OctetString(state->out,
    2402           0 :                                                mod->values[j].data,
    2403           0 :                                                mod->values[j].length)) goto err;
    2404             :                 }
    2405           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2406           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2407           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2408             :         }
    2409             : 
    2410           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2411           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2412             : 
    2413           0 :         subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
    2414             :                                 sctrls, num_sctrls);
    2415           0 :         if (tevent_req_nomem(subreq, req)) {
    2416           0 :                 return tevent_req_post(req, ev);
    2417             :         }
    2418           0 :         tevent_req_set_callback(subreq, tldap_modify_done, req);
    2419           0 :         return req;
    2420             : 
    2421           0 :   err:
    2422             : 
    2423           0 :         tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
    2424           0 :         return tevent_req_post(req, ev);
    2425             : }
    2426             : 
    2427           0 : static void tldap_modify_done(struct tevent_req *subreq)
    2428             : {
    2429           0 :         tldap_simple_done(subreq, TLDAP_RES_MODIFY);
    2430           0 : }
    2431             : 
    2432           0 : TLDAPRC tldap_modify_recv(struct tevent_req *req)
    2433             : {
    2434           0 :         return tldap_simple_recv(req);
    2435             : }
    2436             : 
    2437           0 : TLDAPRC tldap_modify(struct tldap_context *ld, const char *dn,
    2438             :                      struct tldap_mod *mods, int num_mods,
    2439             :                      struct tldap_control *sctrls, int num_sctrls,
    2440             :                      struct tldap_control *cctrls, int num_cctrls)
    2441             :  {
    2442           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2443             :         struct tevent_context *ev;
    2444             :         struct tevent_req *req;
    2445           0 :         TLDAPRC rc = TLDAP_NO_MEMORY;
    2446             : 
    2447           0 :         ev = samba_tevent_context_init(frame);
    2448           0 :         if (ev == NULL) {
    2449           0 :                 goto fail;
    2450             :         }
    2451           0 :         req = tldap_modify_send(frame, ev, ld, dn, mods, num_mods,
    2452             :                                 sctrls, num_sctrls, cctrls, num_cctrls);
    2453           0 :         if (req == NULL) {
    2454           0 :                 goto fail;
    2455             :         }
    2456           0 :         if (!tevent_req_poll(req, ev)) {
    2457           0 :                 rc = TLDAP_OPERATIONS_ERROR;
    2458           0 :                 goto fail;
    2459             :         }
    2460           0 :         rc = tldap_modify_recv(req);
    2461           0 :         tldap_save_msg(ld, req);
    2462           0 :  fail:
    2463           0 :         TALLOC_FREE(frame);
    2464           0 :         return rc;
    2465             : }
    2466             : 
    2467             : static void tldap_delete_done(struct tevent_req *subreq);
    2468             : 
    2469           0 : struct tevent_req *tldap_delete_send(TALLOC_CTX *mem_ctx,
    2470             :                                      struct tevent_context *ev,
    2471             :                                      struct tldap_context *ld,
    2472             :                                      const char *dn,
    2473             :                                      struct tldap_control *sctrls,
    2474             :                                      int num_sctrls,
    2475             :                                      struct tldap_control *cctrls,
    2476             :                                      int num_cctrls)
    2477             : {
    2478             :         struct tevent_req *req, *subreq;
    2479             :         struct tldap_req_state *state;
    2480             : 
    2481           0 :         req = tldap_req_create(mem_ctx, ld, &state);
    2482           0 :         if (req == NULL) {
    2483           0 :                 return NULL;
    2484             :         }
    2485             : 
    2486           0 :         if (!asn1_push_tag(state->out, TLDAP_REQ_DELETE)) goto err;
    2487           0 :         if (!asn1_write(state->out, dn, strlen(dn))) goto err;
    2488           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2489             : 
    2490           0 :         subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
    2491             :                                 sctrls, num_sctrls);
    2492           0 :         if (tevent_req_nomem(subreq, req)) {
    2493           0 :                 return tevent_req_post(req, ev);
    2494             :         }
    2495           0 :         tevent_req_set_callback(subreq, tldap_delete_done, req);
    2496           0 :         return req;
    2497             : 
    2498           0 :   err:
    2499             : 
    2500           0 :         tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
    2501           0 :         return tevent_req_post(req, ev);
    2502             : }
    2503             : 
    2504           0 : static void tldap_delete_done(struct tevent_req *subreq)
    2505             : {
    2506           0 :         tldap_simple_done(subreq, TLDAP_RES_DELETE);
    2507           0 : }
    2508             : 
    2509           0 : TLDAPRC tldap_delete_recv(struct tevent_req *req)
    2510             : {
    2511           0 :         return tldap_simple_recv(req);
    2512             : }
    2513             : 
    2514           0 : TLDAPRC tldap_delete(struct tldap_context *ld, const char *dn,
    2515             :                      struct tldap_control *sctrls, int num_sctrls,
    2516             :                      struct tldap_control *cctrls, int num_cctrls)
    2517             : {
    2518           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2519             :         struct tevent_context *ev;
    2520             :         struct tevent_req *req;
    2521           0 :         TLDAPRC rc = TLDAP_NO_MEMORY;
    2522             : 
    2523           0 :         ev = samba_tevent_context_init(frame);
    2524           0 :         if (ev == NULL) {
    2525           0 :                 goto fail;
    2526             :         }
    2527           0 :         req = tldap_delete_send(frame, ev, ld, dn, sctrls, num_sctrls,
    2528             :                                 cctrls, num_cctrls);
    2529           0 :         if (req == NULL) {
    2530           0 :                 goto fail;
    2531             :         }
    2532           0 :         if (!tevent_req_poll(req, ev)) {
    2533           0 :                 rc = TLDAP_OPERATIONS_ERROR;
    2534           0 :                 goto fail;
    2535             :         }
    2536           0 :         rc = tldap_delete_recv(req);
    2537           0 :         tldap_save_msg(ld, req);
    2538           0 :  fail:
    2539           0 :         TALLOC_FREE(frame);
    2540           0 :         return rc;
    2541             : }
    2542             : 
    2543           0 : int tldap_msg_id(const struct tldap_message *msg)
    2544             : {
    2545           0 :         return msg->id;
    2546             : }
    2547             : 
    2548        1454 : int tldap_msg_type(const struct tldap_message *msg)
    2549             : {
    2550        1454 :         return msg->type;
    2551             : }
    2552             : 
    2553           0 : const char *tldap_msg_matcheddn(struct tldap_message *msg)
    2554             : {
    2555           0 :         if (msg == NULL) {
    2556           0 :                 return NULL;
    2557             :         }
    2558           0 :         return msg->res_matcheddn;
    2559             : }
    2560             : 
    2561           0 : const char *tldap_msg_diagnosticmessage(struct tldap_message *msg)
    2562             : {
    2563           0 :         if (msg == NULL) {
    2564           0 :                 return NULL;
    2565             :         }
    2566           0 :         return msg->res_diagnosticmessage;
    2567             : }
    2568             : 
    2569           0 : const char *tldap_msg_referral(struct tldap_message *msg)
    2570             : {
    2571           0 :         if (msg == NULL) {
    2572           0 :                 return NULL;
    2573             :         }
    2574           0 :         return msg->res_referral;
    2575             : }
    2576             : 
    2577          90 : void tldap_msg_sctrls(struct tldap_message *msg, int *num_sctrls,
    2578             :                       struct tldap_control **sctrls)
    2579             : {
    2580          90 :         if (msg == NULL) {
    2581           0 :                 *sctrls = NULL;
    2582           0 :                 *num_sctrls = 0;
    2583           0 :                 return;
    2584             :         }
    2585          90 :         *sctrls = msg->res_sctrls;
    2586          90 :         *num_sctrls = talloc_array_length(msg->res_sctrls);
    2587             : }
    2588             : 
    2589           0 : struct tldap_message *tldap_ctx_lastmsg(struct tldap_context *ld)
    2590             : {
    2591           0 :         return ld->last_msg;
    2592             : }
    2593             : 
    2594             : static const struct { TLDAPRC rc; const char *string; } tldaprc_errmap[] =
    2595             : {
    2596             :         { TLDAP_SUCCESS,
    2597             :           "TLDAP_SUCCESS" },
    2598             :         { TLDAP_OPERATIONS_ERROR,
    2599             :           "TLDAP_OPERATIONS_ERROR" },
    2600             :         { TLDAP_PROTOCOL_ERROR,
    2601             :           "TLDAP_PROTOCOL_ERROR" },
    2602             :         { TLDAP_TIMELIMIT_EXCEEDED,
    2603             :           "TLDAP_TIMELIMIT_EXCEEDED" },
    2604             :         { TLDAP_SIZELIMIT_EXCEEDED,
    2605             :           "TLDAP_SIZELIMIT_EXCEEDED" },
    2606             :         { TLDAP_COMPARE_FALSE,
    2607             :           "TLDAP_COMPARE_FALSE" },
    2608             :         { TLDAP_COMPARE_TRUE,
    2609             :           "TLDAP_COMPARE_TRUE" },
    2610             :         { TLDAP_STRONG_AUTH_NOT_SUPPORTED,
    2611             :           "TLDAP_STRONG_AUTH_NOT_SUPPORTED" },
    2612             :         { TLDAP_STRONG_AUTH_REQUIRED,
    2613             :           "TLDAP_STRONG_AUTH_REQUIRED" },
    2614             :         { TLDAP_REFERRAL,
    2615             :           "TLDAP_REFERRAL" },
    2616             :         { TLDAP_ADMINLIMIT_EXCEEDED,
    2617             :           "TLDAP_ADMINLIMIT_EXCEEDED" },
    2618             :         { TLDAP_UNAVAILABLE_CRITICAL_EXTENSION,
    2619             :           "TLDAP_UNAVAILABLE_CRITICAL_EXTENSION" },
    2620             :         { TLDAP_CONFIDENTIALITY_REQUIRED,
    2621             :           "TLDAP_CONFIDENTIALITY_REQUIRED" },
    2622             :         { TLDAP_SASL_BIND_IN_PROGRESS,
    2623             :           "TLDAP_SASL_BIND_IN_PROGRESS" },
    2624             :         { TLDAP_NO_SUCH_ATTRIBUTE,
    2625             :           "TLDAP_NO_SUCH_ATTRIBUTE" },
    2626             :         { TLDAP_UNDEFINED_TYPE,
    2627             :           "TLDAP_UNDEFINED_TYPE" },
    2628             :         { TLDAP_INAPPROPRIATE_MATCHING,
    2629             :           "TLDAP_INAPPROPRIATE_MATCHING" },
    2630             :         { TLDAP_CONSTRAINT_VIOLATION,
    2631             :           "TLDAP_CONSTRAINT_VIOLATION" },
    2632             :         { TLDAP_TYPE_OR_VALUE_EXISTS,
    2633             :           "TLDAP_TYPE_OR_VALUE_EXISTS" },
    2634             :         { TLDAP_INVALID_SYNTAX,
    2635             :           "TLDAP_INVALID_SYNTAX" },
    2636             :         { TLDAP_NO_SUCH_OBJECT,
    2637             :           "TLDAP_NO_SUCH_OBJECT" },
    2638             :         { TLDAP_ALIAS_PROBLEM,
    2639             :           "TLDAP_ALIAS_PROBLEM" },
    2640             :         { TLDAP_INVALID_DN_SYNTAX,
    2641             :           "TLDAP_INVALID_DN_SYNTAX" },
    2642             :         { TLDAP_IS_LEAF,
    2643             :           "TLDAP_IS_LEAF" },
    2644             :         { TLDAP_ALIAS_DEREF_PROBLEM,
    2645             :           "TLDAP_ALIAS_DEREF_PROBLEM" },
    2646             :         { TLDAP_INAPPROPRIATE_AUTH,
    2647             :           "TLDAP_INAPPROPRIATE_AUTH" },
    2648             :         { TLDAP_INVALID_CREDENTIALS,
    2649             :           "TLDAP_INVALID_CREDENTIALS" },
    2650             :         { TLDAP_INSUFFICIENT_ACCESS,
    2651             :           "TLDAP_INSUFFICIENT_ACCESS" },
    2652             :         { TLDAP_BUSY,
    2653             :           "TLDAP_BUSY" },
    2654             :         { TLDAP_UNAVAILABLE,
    2655             :           "TLDAP_UNAVAILABLE" },
    2656             :         { TLDAP_UNWILLING_TO_PERFORM,
    2657             :           "TLDAP_UNWILLING_TO_PERFORM" },
    2658             :         { TLDAP_LOOP_DETECT,
    2659             :           "TLDAP_LOOP_DETECT" },
    2660             :         { TLDAP_NAMING_VIOLATION,
    2661             :           "TLDAP_NAMING_VIOLATION" },
    2662             :         { TLDAP_OBJECT_CLASS_VIOLATION,
    2663             :           "TLDAP_OBJECT_CLASS_VIOLATION" },
    2664             :         { TLDAP_NOT_ALLOWED_ON_NONLEAF,
    2665             :           "TLDAP_NOT_ALLOWED_ON_NONLEAF" },
    2666             :         { TLDAP_NOT_ALLOWED_ON_RDN,
    2667             :           "TLDAP_NOT_ALLOWED_ON_RDN" },
    2668             :         { TLDAP_ALREADY_EXISTS,
    2669             :           "TLDAP_ALREADY_EXISTS" },
    2670             :         { TLDAP_NO_OBJECT_CLASS_MODS,
    2671             :           "TLDAP_NO_OBJECT_CLASS_MODS" },
    2672             :         { TLDAP_RESULTS_TOO_LARGE,
    2673             :           "TLDAP_RESULTS_TOO_LARGE" },
    2674             :         { TLDAP_AFFECTS_MULTIPLE_DSAS,
    2675             :           "TLDAP_AFFECTS_MULTIPLE_DSAS" },
    2676             :         { TLDAP_OTHER,
    2677             :           "TLDAP_OTHER" },
    2678             :         { TLDAP_SERVER_DOWN,
    2679             :           "TLDAP_SERVER_DOWN" },
    2680             :         { TLDAP_LOCAL_ERROR,
    2681             :           "TLDAP_LOCAL_ERROR" },
    2682             :         { TLDAP_ENCODING_ERROR,
    2683             :           "TLDAP_ENCODING_ERROR" },
    2684             :         { TLDAP_DECODING_ERROR,
    2685             :           "TLDAP_DECODING_ERROR" },
    2686             :         { TLDAP_TIMEOUT,
    2687             :           "TLDAP_TIMEOUT" },
    2688             :         { TLDAP_AUTH_UNKNOWN,
    2689             :           "TLDAP_AUTH_UNKNOWN" },
    2690             :         { TLDAP_FILTER_ERROR,
    2691             :           "TLDAP_FILTER_ERROR" },
    2692             :         { TLDAP_USER_CANCELLED,
    2693             :           "TLDAP_USER_CANCELLED" },
    2694             :         { TLDAP_PARAM_ERROR,
    2695             :           "TLDAP_PARAM_ERROR" },
    2696             :         { TLDAP_NO_MEMORY,
    2697             :           "TLDAP_NO_MEMORY" },
    2698             :         { TLDAP_CONNECT_ERROR,
    2699             :           "TLDAP_CONNECT_ERROR" },
    2700             :         { TLDAP_NOT_SUPPORTED,
    2701             :           "TLDAP_NOT_SUPPORTED" },
    2702             :         { TLDAP_CONTROL_NOT_FOUND,
    2703             :           "TLDAP_CONTROL_NOT_FOUND" },
    2704             :         { TLDAP_NO_RESULTS_RETURNED,
    2705             :           "TLDAP_NO_RESULTS_RETURNED" },
    2706             :         { TLDAP_MORE_RESULTS_TO_RETURN,
    2707             :           "TLDAP_MORE_RESULTS_TO_RETURN" },
    2708             :         { TLDAP_CLIENT_LOOP,
    2709             :           "TLDAP_CLIENT_LOOP" },
    2710             :         { TLDAP_REFERRAL_LIMIT_EXCEEDED,
    2711             :           "TLDAP_REFERRAL_LIMIT_EXCEEDED" },
    2712             : };
    2713             : 
    2714           0 : const char *tldap_rc2string(TLDAPRC rc)
    2715             : {
    2716             :         size_t i;
    2717             : 
    2718           0 :         for (i=0; i<ARRAY_SIZE(tldaprc_errmap); i++) {
    2719           0 :                 if (TLDAP_RC_EQUAL(rc, tldaprc_errmap[i].rc)) {
    2720           0 :                         return tldaprc_errmap[i].string;
    2721             :                 }
    2722             :         }
    2723             : 
    2724           0 :         return "Unknown LDAP Error";
    2725             : }

Generated by: LCOV version 1.13