LCOV - code coverage report
Current view: top level - source3/lib - tldap.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 746 1366 54.6 %
Date: 2024-02-28 12:06:22 Functions: 55 83 66.3 %

          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        1198 : bool tevent_req_ldap_error(struct tevent_req *req, TLDAPRC rc)
      37             : {
      38           0 :         uint64_t err;
      39             : 
      40        1198 :         if (TLDAP_RC_IS_SUCCESS(rc)) {
      41        1198 :                 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         728 : bool tevent_req_is_ldap_error(struct tevent_req *req, TLDAPRC *perr)
      52             : {
      53           0 :         enum tevent_req_state state;
      54           0 :         uint64_t err;
      55             : 
      56         728 :         if (!tevent_req_is_error(req, &state, &err)) {
      57         728 :                 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         722 : static void tldap_debug(struct tldap_context *ld,
     142             :                          enum tldap_debug_level level,
     143             :                          const char *fmt, ...)
     144             : {
     145           0 :         va_list ap;
     146         722 :         if (!ld) {
     147         722 :                 return;
     148             :         }
     149         722 :         if (ld->log_fn == NULL) {
     150         722 :                 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         112 : static int tldap_next_msgid(struct tldap_context *ld)
     158             : {
     159           0 :         int result;
     160             : 
     161         112 :         result = ld->msgid++;
     162         112 :         if (ld->msgid == INT_MAX) {
     163           0 :                 ld->msgid = 1;
     164             :         }
     165         112 :         return result;
     166             : }
     167             : 
     168           2 : struct tldap_context *tldap_context_create(TALLOC_CTX *mem_ctx, int fd)
     169             : {
     170           0 :         struct tldap_context *ctx;
     171           0 :         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         112 : bool tldap_connection_ok(struct tldap_context *ld)
     193             : {
     194           0 :         int ret;
     195             : 
     196         112 :         if (ld == NULL) {
     197           0 :                 return false;
     198             :         }
     199             : 
     200         112 :         if (ld->conn == NULL) {
     201           0 :                 return false;
     202             :         }
     203             : 
     204         112 :         ret = tstream_pending_bytes(ld->conn);
     205         112 :         if (ret == -1) {
     206           0 :                 return false;
     207             :         }
     208             : 
     209         112 :         return true;
     210             : }
     211             : 
     212        1208 : static size_t tldap_pending_reqs(struct tldap_context *ld)
     213             : {
     214        1208 :         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           0 :         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           0 :         struct tldap_ctx_attribute *tmp, *attr;
     247           0 :         char *tmpname;
     248           0 :         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         600 : static struct tevent_req *read_ldap_send(TALLOC_CTX *mem_ctx,
     308             :                                          struct tevent_context *ev,
     309             :                                          struct tstream_context *conn)
     310             : {
     311           0 :         struct tevent_req *req, *subreq;
     312           0 :         struct read_ldap_state *state;
     313             : 
     314         600 :         req = tevent_req_create(mem_ctx, &state, struct read_ldap_state);
     315         600 :         if (req == NULL) {
     316           0 :                 return NULL;
     317             :         }
     318         600 :         state->done = false;
     319             : 
     320         600 :         subreq = tstream_read_packet_send(state, ev, conn, 2, read_ldap_more,
     321             :                                           state);
     322         600 :         if (tevent_req_nomem(subreq, req)) {
     323           0 :                 return tevent_req_post(req, ev);
     324             :         }
     325         600 :         tevent_req_set_callback(subreq, read_ldap_done, req);
     326         600 :         return req;
     327             : }
     328             : 
     329        1682 : static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data)
     330             : {
     331        1682 :         struct read_ldap_state *state = talloc_get_type_abort(
     332             :                 private_data, struct read_ldap_state);
     333           0 :         size_t len;
     334           0 :         int i, lensize;
     335             : 
     336        1682 :         if (state->done) {
     337             :                 /* We've been here, we're done */
     338         118 :                 return 0;
     339             :         }
     340             : 
     341             :         /*
     342             :          * From ldap.h: LDAP_TAG_MESSAGE is 0x30
     343             :          */
     344        1564 :         if (buf[0] != 0x30) {
     345           0 :                 return -1;
     346             :         }
     347             : 
     348        1564 :         len = buf[1];
     349        1564 :         if ((len & 0x80) == 0) {
     350         118 :                 state->done = true;
     351         118 :                 return len;
     352             :         }
     353             : 
     354        1446 :         lensize = (len & 0x7f);
     355        1446 :         len = 0;
     356             : 
     357        1446 :         if (buflen == 2) {
     358             :                 /* Please get us the full length */
     359         482 :                 return lensize;
     360             :         }
     361         964 :         if (buflen > 2 + lensize) {
     362         482 :                 state->done = true;
     363         482 :                 return 0;
     364             :         }
     365         482 :         if (buflen != 2 + lensize) {
     366           0 :                 return -1;
     367             :         }
     368             : 
     369        1446 :         for (i=0; i<lensize; i++) {
     370         964 :                 len = (len << 8) | buf[2+i];
     371             :         }
     372         482 :         return len;
     373             : }
     374             : 
     375         600 : static void read_ldap_done(struct tevent_req *subreq)
     376             : {
     377         600 :         struct tevent_req *req = tevent_req_callback_data(
     378             :                 subreq, struct tevent_req);
     379         600 :         struct read_ldap_state *state = tevent_req_data(
     380             :                 req, struct read_ldap_state);
     381           0 :         ssize_t nread;
     382           0 :         int err;
     383             : 
     384         600 :         nread = tstream_read_packet_recv(subreq, state, &state->buf, &err);
     385         600 :         TALLOC_FREE(subreq);
     386         600 :         if (nread == -1) {
     387           0 :                 tevent_req_error(req, err);
     388           0 :                 return;
     389             :         }
     390         600 :         tevent_req_done(req);
     391             : }
     392             : 
     393         600 : static ssize_t read_ldap_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     394             :                               uint8_t **pbuf, int *perrno)
     395             : {
     396         600 :         struct read_ldap_state *state = tevent_req_data(
     397             :                 req, struct read_ldap_state);
     398             : 
     399         600 :         if (tevent_req_is_unix_error(req, perrno)) {
     400           0 :                 return -1;
     401             :         }
     402         600 :         *pbuf = talloc_move(mem_ctx, &state->buf);
     403         600 :         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         112 : static bool tldap_push_controls(struct asn1_data *data,
     417             :                                 struct tldap_control *sctrls,
     418             :                                 int num_sctrls)
     419             : {
     420           0 :         int i;
     421             : 
     422         112 :         if ((sctrls == NULL) || (num_sctrls == 0)) {
     423          10 :                 return true;
     424             :         }
     425             : 
     426         102 :         if (!asn1_push_tag(data, ASN1_CONTEXT(0))) return false;
     427             : 
     428         204 :         for (i=0; i<num_sctrls; i++) {
     429         102 :                 struct tldap_control *c = &sctrls[i];
     430         102 :                 if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
     431         102 :                 if (!asn1_write_OctetString(data, c->oid, strlen(c->oid))) return false;
     432         102 :                 if (c->critical) {
     433         102 :                         if (!asn1_write_BOOLEAN(data, true)) return false;
     434             :                 }
     435         102 :                 if (c->value.data != NULL) {
     436         100 :                         if (!asn1_write_OctetString(data, c->value.data,
     437           0 :                                                c->value.length)) return false;
     438             :                 }
     439         102 :                 if (!asn1_pop_tag(data)) return false; /* ASN1_SEQUENCE(0) */
     440             :         }
     441             : 
     442         102 :         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         112 : 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           0 :         struct tevent_req *req, *subreq;
     493           0 :         struct tldap_msg_state *state;
     494           0 :         DATA_BLOB blob;
     495           0 :         bool ok;
     496             : 
     497         112 :         tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_send: sending msg %d\n",
     498             :                     id);
     499             : 
     500         112 :         req = tevent_req_create(mem_ctx, &state, struct tldap_msg_state);
     501         112 :         if (req == NULL) {
     502           0 :                 return NULL;
     503             :         }
     504         112 :         state->ld = ld;
     505         112 :         state->ev = ev;
     506         112 :         state->id = id;
     507             : 
     508         112 :         ok = tldap_connection_ok(ld);
     509         112 :         if (!ok) {
     510           0 :                 tevent_req_ldap_error(req, TLDAP_SERVER_DOWN);
     511           0 :                 return tevent_req_post(req, ev);
     512             :         }
     513             : 
     514         112 :         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         112 :         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         112 :         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         112 :         if (!tldap_msg_set_pending(req)) {
     531           0 :                 tevent_req_oom(req);
     532           0 :                 return tevent_req_post(req, ev);;
     533             :         }
     534             : 
     535         112 :         state->iov.iov_base = (void *)blob.data;
     536         112 :         state->iov.iov_len = blob.length;
     537             : 
     538         112 :         subreq = tstream_writev_queue_send(state, ev, ld->conn, ld->outgoing,
     539         112 :                                            &state->iov, 1);
     540         112 :         if (tevent_req_nomem(subreq, req)) {
     541           0 :                 return tevent_req_post(req, ev);
     542             :         }
     543         112 :         tevent_req_set_callback(subreq, tldap_msg_sent, req);
     544         112 :         return req;
     545             : }
     546             : 
     547         600 : static void tldap_msg_unset_pending(struct tevent_req *req)
     548             : {
     549         600 :         struct tldap_msg_state *state = tevent_req_data(
     550             :                 req, struct tldap_msg_state);
     551         600 :         struct tldap_context *ld = state->ld;
     552         600 :         int num_pending = tldap_pending_reqs(ld);
     553           0 :         int i;
     554             : 
     555         600 :         tevent_req_set_cleanup_fn(req, NULL);
     556             : 
     557         600 :         for (i=0; i<num_pending; i++) {
     558         600 :                 if (req == ld->pending[i]) {
     559         600 :                         break;
     560             :                 }
     561             :         }
     562         600 :         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         600 :         if (num_pending == 1) {
     572         600 :                 TALLOC_FREE(ld->pending);
     573         600 :                 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         600 : static bool tldap_msg_set_pending(struct tevent_req *req)
     598             : {
     599         600 :         struct tldap_msg_state *state = tevent_req_data(
     600             :                 req, struct tldap_msg_state);
     601           0 :         struct tldap_context *ld;
     602           0 :         struct tevent_req **pending;
     603           0 :         int num_pending;
     604             : 
     605         600 :         ld = state->ld;
     606         600 :         num_pending = tldap_pending_reqs(ld);
     607             : 
     608         600 :         pending = talloc_realloc(ld, ld->pending, struct tevent_req *,
     609             :                                  num_pending+1);
     610         600 :         if (pending == NULL) {
     611           0 :                 return false;
     612             :         }
     613         600 :         pending[num_pending] = req;
     614         600 :         ld->pending = pending;
     615         600 :         tevent_req_set_cleanup_fn(req, tldap_msg_cleanup);
     616             : 
     617         600 :         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         600 :         ld->read_req = read_ldap_send(ld->pending, state->ev, ld->conn);
     626         600 :         if (ld->read_req == NULL) {
     627           0 :                 tldap_msg_unset_pending(req);
     628           0 :                 return false;
     629             :         }
     630         600 :         tevent_req_set_callback(ld->read_req, tldap_msg_received, ld);
     631         600 :         return true;
     632             : }
     633             : 
     634         112 : static void tldap_msg_sent(struct tevent_req *subreq)
     635             : {
     636         112 :         struct tevent_req *req = tevent_req_callback_data(
     637             :                 subreq, struct tevent_req);
     638         112 :         struct tldap_msg_state *state = tevent_req_data(
     639             :                 req, struct tldap_msg_state);
     640           0 :         ssize_t nwritten;
     641           0 :         int err;
     642             : 
     643         112 :         nwritten = tstream_writev_queue_recv(subreq, &err);
     644         112 :         TALLOC_FREE(subreq);
     645         112 :         if (nwritten == -1) {
     646           0 :                 tldap_context_disconnect(state->ld, TLDAP_SERVER_DOWN);
     647           0 :                 return;
     648             :         }
     649             : }
     650             : 
     651         600 : static int tldap_msg_msgid(struct tevent_req *req)
     652             : {
     653         600 :         struct tldap_msg_state *state = tevent_req_data(
     654             :                 req, struct tldap_msg_state);
     655             : 
     656         600 :         return state->id;
     657             : }
     658             : 
     659         600 : static void tldap_msg_received(struct tevent_req *subreq)
     660             : {
     661         600 :         struct tldap_context *ld = tevent_req_callback_data(
     662             :                 subreq, struct tldap_context);
     663           0 :         struct tevent_req *req;
     664           0 :         struct tldap_msg_state *state;
     665           0 :         struct asn1_data *data;
     666           0 :         uint8_t *inbuf;
     667           0 :         ssize_t received;
     668           0 :         size_t num_pending;
     669           0 :         size_t i;
     670           0 :         int err;
     671         600 :         TLDAPRC status = TLDAP_PROTOCOL_ERROR;
     672           0 :         int id;
     673           0 :         uint8_t type;
     674           0 :         bool ok;
     675             : 
     676         600 :         received = read_ldap_recv(subreq, talloc_tos(), &inbuf, &err);
     677         600 :         TALLOC_FREE(subreq);
     678         600 :         ld->read_req = NULL;
     679         600 :         if (received == -1) {
     680           0 :                 status = TLDAP_SERVER_DOWN;
     681           0 :                 goto fail;
     682             :         }
     683             : 
     684         600 :         data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
     685         600 :         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         600 :         asn1_load_nocopy(data, inbuf, received);
     694             : 
     695         600 :         ok = true;
     696         600 :         ok &= asn1_start_tag(data, ASN1_SEQUENCE(0));
     697         600 :         ok &= asn1_read_Integer(data, &id);
     698         600 :         ok &= asn1_peek_uint8(data, &type);
     699             : 
     700         600 :         if (!ok) {
     701           0 :                 status = TLDAP_PROTOCOL_ERROR;
     702           0 :                 goto fail;
     703             :         }
     704             : 
     705         600 :         tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_received: got msg %d "
     706             :                     "type %d\n", id, (int)type);
     707             : 
     708         600 :         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         600 :         num_pending = talloc_array_length(ld->pending);
     720             : 
     721         600 :         for (i=0; i<num_pending; i++) {
     722         600 :                 if (id == tldap_msg_msgid(ld->pending[i])) {
     723         600 :                         break;
     724             :                 }
     725             :         }
     726         600 :         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         600 :         req = ld->pending[i];
     736         600 :         state = tevent_req_data(req, struct tldap_msg_state);
     737             : 
     738         600 :         state->inbuf = talloc_move(state, &inbuf);
     739         600 :         state->data = talloc_move(state, &data);
     740             : 
     741         600 :         tldap_msg_unset_pending(req);
     742         600 :         num_pending = talloc_array_length(ld->pending);
     743             : 
     744         600 :         tevent_req_defer_callback(req, state->ev);
     745         600 :         tevent_req_done(req);
     746             : 
     747         600 :  done:
     748         600 :         if (num_pending == 0) {
     749         600 :                 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         600 : static TLDAPRC tldap_msg_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     766             :                               struct tldap_message **pmsg)
     767             : {
     768         600 :         struct tldap_msg_state *state = tevent_req_data(
     769             :                 req, struct tldap_msg_state);
     770           0 :         struct tldap_message *msg;
     771           0 :         TLDAPRC err;
     772           0 :         uint8_t msgtype;
     773             : 
     774         600 :         if (tevent_req_is_ldap_error(req, &err)) {
     775           0 :                 return err;
     776             :         }
     777             : 
     778         600 :         if (!asn1_peek_uint8(state->data, &msgtype)) {
     779           0 :                 return TLDAP_PROTOCOL_ERROR;
     780             :         }
     781             : 
     782         600 :         if (pmsg == NULL) {
     783           0 :                 return TLDAP_SUCCESS;
     784             :         }
     785             : 
     786         600 :         msg = talloc_zero(mem_ctx, struct tldap_message);
     787         600 :         if (msg == NULL) {
     788           0 :                 return TLDAP_NO_MEMORY;
     789             :         }
     790         600 :         msg->id = state->id;
     791             : 
     792         600 :         msg->inbuf = talloc_move(msg, &state->inbuf);
     793         600 :         msg->data = talloc_move(msg, &state->data);
     794         600 :         msg->type = msgtype;
     795             : 
     796         600 :         *pmsg = msg;
     797         600 :         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         112 : static struct tevent_req *tldap_req_create(TALLOC_CTX *mem_ctx,
     807             :                                            struct tldap_context *ld,
     808             :                                            struct tldap_req_state **pstate)
     809             : {
     810           0 :         struct tevent_req *req;
     811           0 :         struct tldap_req_state *state;
     812             : 
     813         112 :         req = tevent_req_create(mem_ctx, &state, struct tldap_req_state);
     814         112 :         if (req == NULL) {
     815           0 :                 return NULL;
     816             :         }
     817         112 :         state->out = asn1_init(state, ASN1_MAX_TREE_DEPTH);
     818         112 :         if (state->out == NULL) {
     819           0 :                 goto err;
     820             :         }
     821         112 :         state->id = tldap_next_msgid(ld);
     822             : 
     823         112 :         if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
     824         112 :         if (!asn1_write_Integer(state->out, state->id)) goto err;
     825             : 
     826         112 :         *pstate = state;
     827         112 :         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        8310 : static char *blob2string_talloc(TALLOC_CTX *mem_ctx, DATA_BLOB blob)
     845             : {
     846        8310 :         char *result = talloc_array(mem_ctx, char, blob.length+1);
     847             : 
     848        8310 :         if (result == NULL) {
     849           0 :                 return NULL;
     850             :         }
     851             : 
     852        8310 :         memcpy(result, blob.data, blob.length);
     853        8310 :         result[blob.length] = '\0';
     854        8310 :         return result;
     855             : }
     856             : 
     857        8310 : static bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
     858             :                                          struct asn1_data *data,
     859             :                                          char **presult)
     860             : {
     861           0 :         DATA_BLOB string;
     862           0 :         char *result;
     863        8310 :         if (!asn1_read_OctetString(data, mem_ctx, &string))
     864           0 :                 return false;
     865             : 
     866        8310 :         result = blob2string_talloc(mem_ctx, string);
     867             : 
     868        8310 :         data_blob_free(&string);
     869             : 
     870        8310 :         if (result == NULL) {
     871           0 :                 return false;
     872             :         }
     873        8310 :         *presult = result;
     874        8310 :         return true;
     875             : }
     876             : 
     877             : static bool tldap_decode_controls(struct tldap_req_state *state);
     878             : 
     879         112 : static bool tldap_decode_response(struct tldap_req_state *state)
     880             : {
     881         112 :         struct asn1_data *data = state->result->data;
     882         112 :         struct tldap_message *msg = state->result;
     883           0 :         int rc;
     884         112 :         bool ok = true;
     885             : 
     886         112 :         ok &= asn1_read_enumerated(data, &rc);
     887         112 :         if (ok) {
     888         112 :                 msg->lderr = TLDAP_RC(rc);
     889             :         }
     890             : 
     891         112 :         ok &= asn1_read_OctetString_talloc(msg, data, &msg->res_matcheddn);
     892         112 :         ok &= asn1_read_OctetString_talloc(msg, data,
     893             :                                            &msg->res_diagnosticmessage);
     894         112 :         if (!ok) return ok;
     895         112 :         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         112 :                 msg->res_referral = NULL;
     902             :         }
     903             : 
     904         112 :         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           0 :         struct tevent_req *req, *subreq;
     921           0 :         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           0 :         TLDAPRC rc;
     974           0 :         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           0 :                 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           4 :                 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           4 :         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           0 :         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           0 :         struct tevent_context *ev;
    1070           0 :         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           0 :         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           0 :         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        1206 : static bool tldap_is_alpha(char c)
    1138             : {
    1139        1212 :         return (((c >= 'a') && (c <= 'z')) || \
    1140           6 :                 ((c >= 'A') && (c <= 'Z')));
    1141             : }
    1142             : 
    1143        1090 : static bool tldap_is_adh(char c)
    1144             : {
    1145        1090 :         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         120 : static bool tldap_is_attrdesc(const char *s, int len, bool no_tagopts)
    1170             : {
    1171         120 :         bool is_oid = false;
    1172         120 :         bool dot = false;
    1173           0 :         int i;
    1174             : 
    1175             :         /* first char has stricter rules */
    1176         120 :         if (isdigit(*s)) {
    1177           4 :                 is_oid = true;
    1178         116 :         } else if (!tldap_is_alpha(*s)) {
    1179             :                 /* bad first char */
    1180           0 :                 return false;
    1181             :         }
    1182             : 
    1183        1238 :         for (i = 1; i < len; i++) {
    1184             : 
    1185        1118 :                 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        1090 :                         if (tldap_is_adh(s[i])) {
    1200        1090 :                                 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         120 :         if (dot) {
    1224             :                 /* malformed */
    1225           0 :                 return false;
    1226             :         }
    1227             : 
    1228         120 :         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          14 :         while (*s) {
    1239          14 :                 s = strchr(s, ')');
    1240          14 :                 if (s && (*(s - 1) == '\\')) {
    1241           0 :                         s++;
    1242           0 :                         continue;
    1243             :                 }
    1244          14 :                 break;
    1245             :         }
    1246          14 :         if (!s || !(*s == ')')) {
    1247             :                 /* malformed filter */
    1248           0 :                 return NULL;
    1249             :         }
    1250             : 
    1251          14 :         *_s = s;
    1252             : 
    1253          14 :         return talloc_strndup(memctx, value, s - value);
    1254             : }
    1255             : 
    1256          14 : static int tldap_hex2char(const char *x)
    1257             : {
    1258          14 :         if (isxdigit(x[0]) && isxdigit(x[1])) {
    1259           7 :                 const char h1 = x[0], h2 = x[1];
    1260           7 :                 int c = 0;
    1261             : 
    1262           7 :                 if (h1 >= 'a') c = h1 - (int)'a' + 10;
    1263           7 :                 else if (h1 >= 'A') c = h1 - (int)'A' + 10;
    1264           7 :                 else if (h1 >= '0') c = h1 - (int)'0';
    1265           7 :                 c = c << 4;
    1266           7 :                 if (h2 >= 'a') c += h2 - (int)'a' + 10;
    1267           6 :                 else if (h2 >= 'A') c += h2 - (int)'A' + 10;
    1268           6 :                 else if (h2 >= '0') c += h2 - (int)'0';
    1269             : 
    1270           7 :                 return c;
    1271             :         }
    1272             : 
    1273           0 :         return -1;
    1274             : }
    1275             : 
    1276          16 : static bool tldap_find_first_star(const char *val, const char **star)
    1277             : {
    1278           0 :         const char *s;
    1279             : 
    1280          44 :         for (s = val; *s; s++) {
    1281          44 :                 switch (*s) {
    1282           0 :                 case '\\':
    1283           0 :                         if (isxdigit(s[1]) && isxdigit(s[2])) {
    1284           0 :                                 s += 2;
    1285           0 :                                 break;
    1286             :                         }
    1287             :                         /* not hex based escape, check older syntax */
    1288           0 :                         switch (s[1]) {
    1289           0 :                         case '(':
    1290             :                         case ')':
    1291             :                         case '*':
    1292             :                         case '\\':
    1293           0 :                                 s++;
    1294           0 :                                 break;
    1295           0 :                         default:
    1296             :                                 /* invalid escape sequence */
    1297           0 :                                 return false;
    1298             :                         }
    1299           0 :                         break;
    1300           6 :                 case ')':
    1301             :                         /* end of val, nothing found */
    1302           6 :                         *star = s;
    1303           6 :                         return true;
    1304             : 
    1305          10 :                 case '*':
    1306          10 :                         *star = s;
    1307          10 :                         return true;
    1308             :                 }
    1309             :         }
    1310             : 
    1311             :         /* string ended without closing parenthesis, filter is malformed */
    1312           0 :         return false;
    1313             : }
    1314             : 
    1315          24 : static bool tldap_unescape_inplace(char *value, size_t *val_len)
    1316             : {
    1317           2 :         int c;
    1318           2 :         size_t i, p;
    1319             : 
    1320         178 :         for (i = 0,p = 0; i < *val_len; i++) {
    1321             : 
    1322         154 :                 switch (value[i]) {
    1323           0 :                 case '(':
    1324             :                 case ')':
    1325             :                 case '*':
    1326             :                         /* these must be escaped */
    1327           0 :                         return false;
    1328             : 
    1329          14 :                 case '\\':
    1330          14 :                         if (!value[i + 1]) {
    1331             :                                 /* invalid EOL */
    1332           0 :                                 return false;
    1333             :                         }
    1334          14 :                         i++;
    1335             : 
    1336             :                         /* LDAPv3 escaped */
    1337          14 :                         c = tldap_hex2char(&value[i]);
    1338          14 :                         if (c >= 0 && c < 256) {
    1339           7 :                                 value[p] = c;
    1340           7 :                                 i++;
    1341           7 :                                 p++;
    1342           7 :                                 break;
    1343             :                         }
    1344             : 
    1345             :                         /* LDAPv2 escaped */
    1346           7 :                         switch (value[i]) {
    1347           7 :                         case '(':
    1348             :                         case ')':
    1349             :                         case '*':
    1350             :                         case '\\':
    1351           7 :                                 value[p] = value[i];
    1352           7 :                                 p++;
    1353             : 
    1354           7 :                                 break;
    1355           0 :                         default:
    1356             :                                 /* invalid */
    1357           0 :                                 return false;
    1358             :                         }
    1359           7 :                         break;
    1360             : 
    1361         140 :                 default:
    1362         140 :                         value[p] = value[i];
    1363         140 :                         p++;
    1364             :                 }
    1365             :         }
    1366          24 :         value[p] = '\0';
    1367          24 :         *val_len = p;
    1368          24 :         return true;
    1369             : }
    1370             : 
    1371             : static bool tldap_push_filter_basic(struct tldap_context *ld,
    1372             :                                     struct asn1_data *data,
    1373             :                                     const char **_s);
    1374             : static bool tldap_push_filter_substring(struct tldap_context *ld,
    1375             :                                         struct asn1_data *data,
    1376             :                                         const char *val,
    1377             :                                         const char **_s);
    1378         134 : static bool tldap_push_filter_int(struct tldap_context *ld,
    1379             :                                   struct asn1_data *data,
    1380             :                                   const char **_s)
    1381             : {
    1382         134 :         const char *s = *_s;
    1383           0 :         bool ret;
    1384             : 
    1385         134 :         if (*s != '(') {
    1386           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1387             :                             "Incomplete or malformed filter\n");
    1388           0 :                 return false;
    1389             :         }
    1390         134 :         s++;
    1391             : 
    1392             :         /* we are right after a parenthesis,
    1393             :          * find out what op we have at hand */
    1394         134 :         switch (*s) {
    1395           2 :         case '&':
    1396           2 :                 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: AND\n");
    1397           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_AND)) return false;
    1398           2 :                 s++;
    1399           2 :                 break;
    1400             : 
    1401           4 :         case '|':
    1402           4 :                 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: OR\n");
    1403           4 :                 if (!asn1_push_tag(data, TLDAP_FILTER_OR)) return false;
    1404           4 :                 s++;
    1405           4 :                 break;
    1406             : 
    1407           4 :         case '!':
    1408           4 :                 tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: NOT\n");
    1409           4 :                 if (!asn1_push_tag(data, TLDAP_FILTER_NOT)) return false;
    1410           4 :                 s++;
    1411           4 :                 ret = tldap_push_filter_int(ld, data, &s);
    1412           4 :                 if (!ret) {
    1413           0 :                         return false;
    1414             :                 }
    1415           4 :                 if (!asn1_pop_tag(data)) return false;
    1416           4 :                 goto done;
    1417             : 
    1418           0 :         case '(':
    1419             :         case ')':
    1420           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1421           0 :                             "Invalid parenthesis '%c'\n", *s);
    1422           0 :                 return false;
    1423             : 
    1424           0 :         case '\0':
    1425           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1426             :                             "Invalid filter termination\n");
    1427           0 :                 return false;
    1428             : 
    1429         124 :         default:
    1430         124 :                 ret = tldap_push_filter_basic(ld, data, &s);
    1431         124 :                 if (!ret) {
    1432           0 :                         return false;
    1433             :                 }
    1434         124 :                 goto done;
    1435             :         }
    1436             : 
    1437             :         /* only and/or filters get here.
    1438             :          * go through the list of filters */
    1439             : 
    1440           6 :         if (*s == ')') {
    1441             :                 /* RFC 4526: empty and/or */
    1442           0 :                 if (!asn1_pop_tag(data)) return false;
    1443           0 :                 goto done;
    1444             :         }
    1445             : 
    1446          22 :         while (*s) {
    1447          22 :                 ret = tldap_push_filter_int(ld, data, &s);
    1448          22 :                 if (!ret) {
    1449           0 :                         return false;
    1450             :                 }
    1451             : 
    1452          22 :                 if (*s == ')') {
    1453             :                         /* end of list, return */
    1454           6 :                         if (!asn1_pop_tag(data)) return false;
    1455           6 :                         break;
    1456             :                 }
    1457             :         }
    1458             : 
    1459           0 : done:
    1460         134 :         if (*s != ')') {
    1461           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1462             :                             "Incomplete or malformed filter\n");
    1463           0 :                 return false;
    1464             :         }
    1465         134 :         s++;
    1466             : 
    1467         134 :         if (asn1_has_error(data)) {
    1468           0 :                 return false;
    1469             :         }
    1470             : 
    1471         134 :         *_s = s;
    1472         134 :         return true;
    1473             : }
    1474             : 
    1475             : 
    1476         124 : static bool tldap_push_filter_basic(struct tldap_context *ld,
    1477             :                                     struct asn1_data *data,
    1478             :                                     const char **_s)
    1479             : {
    1480         124 :         TALLOC_CTX *tmpctx = talloc_tos();
    1481         124 :         const char *s = *_s;
    1482           0 :         const char *e;
    1483           0 :         const char *eq;
    1484           0 :         const char *val;
    1485           0 :         const char *type;
    1486           0 :         const char *dn;
    1487           0 :         const char *rule;
    1488           0 :         const char *star;
    1489         124 :         size_t type_len = 0;
    1490           0 :         char *uval;
    1491           0 :         size_t uval_len;
    1492         124 :         bool write_octect = true;
    1493           0 :         bool ret;
    1494             : 
    1495         124 :         eq = strchr(s, '=');
    1496         124 :         if (!eq) {
    1497           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1498             :                             "Invalid filter, missing equal sign\n");
    1499           0 :                 return false;
    1500             :         }
    1501             : 
    1502         124 :         val = eq + 1;
    1503         124 :         e = eq - 1;
    1504             : 
    1505         124 :         switch (*e) {
    1506           2 :         case '<':
    1507           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_LE)) return false;
    1508           2 :                 break;
    1509             : 
    1510           2 :         case '>':
    1511           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_GE)) return false;
    1512           2 :                 break;
    1513             : 
    1514           2 :         case '~':
    1515           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_APX)) return false;
    1516           2 :                 break;
    1517             : 
    1518           6 :         case ':':
    1519           6 :                 if (!asn1_push_tag(data, TLDAP_FILTER_EXT)) return false;
    1520           6 :                 write_octect = false;
    1521             : 
    1522           6 :                 type = NULL;
    1523           6 :                 dn = NULL;
    1524           6 :                 rule = NULL;
    1525             : 
    1526           6 :                 if (*s == ':') { /* [:dn]:rule:= value */
    1527           2 :                         if (s == e) {
    1528             :                                 /* malformed filter */
    1529           0 :                                 return false;
    1530             :                         }
    1531           2 :                         dn = s;
    1532             :                 } else { /* type[:dn][:rule]:= value */
    1533           4 :                         type = s;
    1534           4 :                         dn = strchr(s, ':');
    1535           4 :                         type_len = dn - type;
    1536           4 :                         if (dn == e) { /* type:= value */
    1537           2 :                                 dn = NULL;
    1538             :                         }
    1539             :                 }
    1540           6 :                 if (dn) {
    1541           4 :                         dn++;
    1542             : 
    1543           4 :                         rule = strchr(dn, ':');
    1544           4 :                         if (rule == NULL) {
    1545           0 :                                 return false;
    1546             :                         }
    1547           4 :                         if ((rule == dn + 1) || rule + 1 == e) {
    1548             :                                 /* malformed filter, contains "::" */
    1549           0 :                                 return false;
    1550             :                         }
    1551             : 
    1552           4 :                         if (strncasecmp_m(dn, "dn:", 3) != 0) {
    1553           0 :                                 if (rule == e) {
    1554           0 :                                         rule = dn;
    1555           0 :                                         dn = NULL;
    1556             :                                 } else {
    1557             :                                         /* malformed filter. With two
    1558             :                                          * optionals, the first must be "dn"
    1559             :                                          */
    1560           0 :                                         return false;
    1561             :                                 }
    1562             :                         } else {
    1563           4 :                                 if (rule == e) {
    1564           0 :                                         rule = NULL;
    1565             :                                 } else {
    1566           4 :                                         rule++;
    1567             :                                 }
    1568             :                         }
    1569             :                 }
    1570             : 
    1571           6 :                 if (!type && !dn && !rule) {
    1572             :                         /* malformed filter, there must be at least one */
    1573           0 :                         return false;
    1574             :                 }
    1575             : 
    1576             :                 /*
    1577             :                   MatchingRuleAssertion ::= SEQUENCE {
    1578             :                   matchingRule    [1] MatchingRuleID OPTIONAL,
    1579             :                   type      [2] AttributeDescription OPTIONAL,
    1580             :                   matchValue      [3] AssertionValue,
    1581             :                   dnAttributes    [4] BOOLEAN DEFAULT FALSE
    1582             :                   }
    1583             :                 */
    1584             : 
    1585             :                 /* check and add rule */
    1586           6 :                 if (rule) {
    1587           4 :                         ret = tldap_is_attrdesc(rule, e - rule, true);
    1588           4 :                         if (!ret) {
    1589           0 :                                 return false;
    1590             :                         }
    1591           4 :                         if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1))) return false;
    1592           4 :                         if (!asn1_write(data, rule, e - rule)) return false;
    1593           4 :                         if (!asn1_pop_tag(data)) return false;
    1594             :                 }
    1595             : 
    1596             :                 /* check and add type */
    1597           6 :                 if (type) {
    1598           4 :                         ret = tldap_is_attrdesc(type, type_len, false);
    1599           4 :                         if (!ret) {
    1600           0 :                                 return false;
    1601             :                         }
    1602           4 :                         if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2))) return false;
    1603           4 :                         if (!asn1_write(data, type, type_len)) return false;
    1604           4 :                         if (!asn1_pop_tag(data)) return false;
    1605             :                 }
    1606             : 
    1607           6 :                 uval = tldap_get_val(tmpctx, val, _s);
    1608           6 :                 if (!uval) {
    1609           0 :                         return false;
    1610             :                 }
    1611           6 :                 uval_len = *_s - val;
    1612           6 :                 ret = tldap_unescape_inplace(uval, &uval_len);
    1613           6 :                 if (!ret) {
    1614           0 :                         return false;
    1615             :                 }
    1616             : 
    1617           6 :                 if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3))) return false;
    1618           6 :                 if (!asn1_write(data, uval, uval_len)) return false;
    1619           6 :                 if (!asn1_pop_tag(data)) return false;
    1620             : 
    1621           6 :                 if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4))) return false;
    1622           6 :                 if (!asn1_write_uint8(data, dn?1:0)) return false;
    1623           6 :                 if (!asn1_pop_tag(data)) return false;
    1624           6 :                 break;
    1625             : 
    1626         112 :         default:
    1627         112 :                 e = eq;
    1628             : 
    1629         112 :                 ret = tldap_is_attrdesc(s, e - s, false);
    1630         112 :                 if (!ret) {
    1631           0 :                         return false;
    1632             :                 }
    1633             : 
    1634         112 :                 if (strncmp(val, "*)", 2) == 0) {
    1635             :                         /* presence */
    1636         106 :                         if (!asn1_push_tag(data, TLDAP_FILTER_PRES)) return false;
    1637         106 :                         if (!asn1_write(data, s, e - s)) return false;
    1638         106 :                         *_s = val + 1;
    1639         106 :                         write_octect = false;
    1640         106 :                         break;
    1641             :                 }
    1642             : 
    1643           6 :                 ret = tldap_find_first_star(val, &star);
    1644           6 :                 if (!ret) {
    1645           0 :                         return false;
    1646             :                 }
    1647           6 :                 if (*star == '*') {
    1648             :                         /* substring */
    1649           4 :                         if (!asn1_push_tag(data, TLDAP_FILTER_SUB)) return false;
    1650           4 :                         if (!asn1_write_OctetString(data, s, e - s)) return false;
    1651           4 :                         ret = tldap_push_filter_substring(ld, data, val, &s);
    1652           4 :                         if (!ret) {
    1653           0 :                                 return false;
    1654             :                         }
    1655           4 :                         *_s = s;
    1656           4 :                         write_octect = false;
    1657           4 :                         break;
    1658             :                 }
    1659             : 
    1660             :                 /* if nothing else, then it is just equality */
    1661           2 :                 if (!asn1_push_tag(data, TLDAP_FILTER_EQ)) return false;
    1662           2 :                 write_octect = true;
    1663           2 :                 break;
    1664             :         }
    1665             : 
    1666         124 :         if (write_octect) {
    1667           8 :                 uval = tldap_get_val(tmpctx, val, _s);
    1668           8 :                 if (!uval) {
    1669           0 :                         return false;
    1670             :                 }
    1671           8 :                 uval_len = *_s - val;
    1672           8 :                 ret = tldap_unescape_inplace(uval, &uval_len);
    1673           8 :                 if (!ret) {
    1674           0 :                         return false;
    1675             :                 }
    1676             : 
    1677           8 :                 if (!asn1_write_OctetString(data, s, e - s)) return false;
    1678           8 :                 if (!asn1_write_OctetString(data, uval, uval_len)) return false;
    1679             :         }
    1680             : 
    1681         124 :         if (asn1_has_error(data)) {
    1682           0 :                 return false;
    1683             :         }
    1684         124 :         return asn1_pop_tag(data);
    1685             : }
    1686             : 
    1687           4 : static bool tldap_push_filter_substring(struct tldap_context *ld,
    1688             :                                         struct asn1_data *data,
    1689             :                                         const char *val,
    1690             :                                         const char **_s)
    1691             : {
    1692           4 :         TALLOC_CTX *tmpctx = talloc_tos();
    1693           4 :         bool initial = true;
    1694           0 :         const char *star;
    1695           0 :         char *chunk;
    1696           0 :         size_t chunk_len;
    1697           0 :         bool ret;
    1698             : 
    1699             :         /*
    1700             :           SubstringFilter ::= SEQUENCE {
    1701             :                   type      AttributeDescription,
    1702             :                   -- at least one must be present
    1703             :                   substrings      SEQUENCE OF CHOICE {
    1704             :                           initial [0] LDAPString,
    1705             :                           any     [1] LDAPString,
    1706             :                           final   [2] LDAPString } }
    1707             :         */
    1708           4 :         if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
    1709             : 
    1710           0 :         do {
    1711          10 :                 ret = tldap_find_first_star(val, &star);
    1712          10 :                 if (!ret) {
    1713           0 :                         return false;
    1714             :                 }
    1715          10 :                 chunk_len = star - val;
    1716             : 
    1717          10 :                 switch (*star) {
    1718           6 :                 case '*':
    1719           6 :                         if (!initial && chunk_len == 0) {
    1720             :                                 /* found '**', which is illegal */
    1721           0 :                                 return false;
    1722             :                         }
    1723           6 :                         break;
    1724           4 :                 case ')':
    1725           4 :                         if (initial) {
    1726             :                                 /* no stars ?? */
    1727           0 :                                 return false;
    1728             :                         }
    1729             :                         /* we are done */
    1730           4 :                         break;
    1731           0 :                 default:
    1732             :                         /* ?? */
    1733           0 :                         return false;
    1734             :                 }
    1735             : 
    1736          10 :                 if (initial && chunk_len == 0) {
    1737           2 :                         val = star + 1;
    1738           2 :                         initial = false;
    1739           2 :                         continue;
    1740             :                 }
    1741             : 
    1742           8 :                 chunk = talloc_strndup(tmpctx, val, chunk_len);
    1743           8 :                 if (!chunk) {
    1744           0 :                         return false;
    1745             :                 }
    1746           8 :                 ret = tldap_unescape_inplace(chunk, &chunk_len);
    1747           8 :                 if (!ret) {
    1748           0 :                         return false;
    1749             :                 }
    1750           8 :                 switch (*star) {
    1751           4 :                 case '*':
    1752           4 :                         if (initial) {
    1753           2 :                                 if (!asn1_push_tag(data, TLDAP_SUB_INI)) return false;
    1754           2 :                                 initial = false;
    1755             :                         } else {
    1756           2 :                                 if (!asn1_push_tag(data, TLDAP_SUB_ANY)) return false;
    1757             :                         }
    1758           4 :                         break;
    1759           4 :                 case ')':
    1760           4 :                         if (!asn1_push_tag(data, TLDAP_SUB_FIN)) return false;
    1761           4 :                         break;
    1762           0 :                 default:
    1763             :                         /* ?? */
    1764           0 :                         return false;
    1765             :                 }
    1766           8 :                 if (!asn1_write(data, chunk, chunk_len)) return false;
    1767           8 :                 if (!asn1_pop_tag(data)) return false;
    1768             : 
    1769           8 :                 val = star + 1;
    1770             : 
    1771          10 :         } while (*star == '*');
    1772             : 
    1773           4 :         *_s = star;
    1774             : 
    1775             :         /* end of sequence */
    1776           4 :         return asn1_pop_tag(data);
    1777             : }
    1778             : 
    1779             : /* NOTE: although openldap libraries allow for spaces in some places, mostly
    1780             :  * around parentheses, we do not allow any spaces (except in values of
    1781             :  * course) as I couldn't find any place in RFC 4512 or RFC 4515 where
    1782             :  * leading or trailing spaces were allowed.
    1783             :  */
    1784         108 : static bool tldap_push_filter(struct tldap_context *ld,
    1785             :                               struct asn1_data *data,
    1786             :                               const char *filter)
    1787             : {
    1788         108 :         const char *s = filter;
    1789           0 :         bool ret;
    1790             : 
    1791         108 :         ret = tldap_push_filter_int(ld, data, &s);
    1792         108 :         if (ret && *s) {
    1793           0 :                 tldap_debug(ld, TLDAP_DEBUG_ERROR,
    1794             :                             "Incomplete or malformed filter\n");
    1795           0 :                 return false;
    1796             :         }
    1797         108 :         return ret;
    1798             : }
    1799             : 
    1800             : /*****************************************************************************/
    1801             : 
    1802             : static void tldap_search_done(struct tevent_req *subreq);
    1803             : 
    1804         108 : struct tevent_req *tldap_search_send(TALLOC_CTX *mem_ctx,
    1805             :                                      struct tevent_context *ev,
    1806             :                                      struct tldap_context *ld,
    1807             :                                      const char *base, int scope,
    1808             :                                      const char *filter,
    1809             :                                      const char **attrs,
    1810             :                                      int num_attrs,
    1811             :                                      int attrsonly,
    1812             :                                      struct tldap_control *sctrls,
    1813             :                                      int num_sctrls,
    1814             :                                      struct tldap_control *cctrls,
    1815             :                                      int num_cctrls,
    1816             :                                      int timelimit,
    1817             :                                      int sizelimit,
    1818             :                                      int deref)
    1819             : {
    1820           0 :         struct tevent_req *req, *subreq;
    1821           0 :         struct tldap_req_state *state;
    1822           0 :         int i;
    1823             : 
    1824         108 :         req = tldap_req_create(mem_ctx, ld, &state);
    1825         108 :         if (req == NULL) {
    1826           0 :                 return NULL;
    1827             :         }
    1828             : 
    1829         108 :         if (!asn1_push_tag(state->out, TLDAP_REQ_SEARCH)) goto encoding_error;
    1830         108 :         if (!asn1_write_OctetString(state->out, base, strlen(base))) goto encoding_error;
    1831         108 :         if (!asn1_write_enumerated(state->out, scope)) goto encoding_error;
    1832         108 :         if (!asn1_write_enumerated(state->out, deref)) goto encoding_error;
    1833         108 :         if (!asn1_write_Integer(state->out, sizelimit)) goto encoding_error;
    1834         108 :         if (!asn1_write_Integer(state->out, timelimit)) goto encoding_error;
    1835         108 :         if (!asn1_write_BOOLEAN(state->out, attrsonly)) goto encoding_error;
    1836             : 
    1837         108 :         if (!tldap_push_filter(ld, state->out, filter)) {
    1838           0 :                 goto encoding_error;
    1839             :         }
    1840             : 
    1841         108 :         if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto encoding_error;
    1842         114 :         for (i=0; i<num_attrs; i++) {
    1843           6 :                 if (!asn1_write_OctetString(state->out, attrs[i], strlen(attrs[i]))) goto encoding_error;
    1844             :         }
    1845         108 :         if (!asn1_pop_tag(state->out)) goto encoding_error;
    1846         108 :         if (!asn1_pop_tag(state->out)) goto encoding_error;
    1847             : 
    1848         108 :         subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
    1849             :                                 sctrls, num_sctrls);
    1850         108 :         if (tevent_req_nomem(subreq, req)) {
    1851           0 :                 return tevent_req_post(req, ev);
    1852             :         }
    1853         108 :         tevent_req_set_callback(subreq, tldap_search_done, req);
    1854         108 :         return req;
    1855             : 
    1856           0 :  encoding_error:
    1857           0 :         tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
    1858           0 :         return tevent_req_post(req, ev);
    1859             : }
    1860             : 
    1861         596 : static void tldap_search_done(struct tevent_req *subreq)
    1862             : {
    1863         596 :         struct tevent_req *req = tevent_req_callback_data(
    1864             :                 subreq, struct tevent_req);
    1865         596 :         struct tldap_req_state *state = tevent_req_data(
    1866             :                 req, struct tldap_req_state);
    1867           0 :         TLDAPRC rc;
    1868             : 
    1869         596 :         rc = tldap_msg_recv(subreq, state, &state->result);
    1870         596 :         if (tevent_req_ldap_error(req, rc)) {
    1871           0 :                 return;
    1872             :         }
    1873         596 :         switch (state->result->type) {
    1874         488 :         case TLDAP_RES_SEARCH_ENTRY:
    1875             :         case TLDAP_RES_SEARCH_REFERENCE:
    1876         488 :                 if (!tldap_msg_set_pending(subreq)) {
    1877           0 :                         tevent_req_oom(req);
    1878           0 :                         return;
    1879             :                 }
    1880         488 :                 tevent_req_notify_callback(req);
    1881         596 :                 break;
    1882         108 :         case TLDAP_RES_SEARCH_RESULT:
    1883         108 :                 TALLOC_FREE(subreq);
    1884         108 :                 if (!asn1_start_tag(state->result->data,
    1885         108 :                                     state->result->type) ||
    1886         108 :                     !tldap_decode_response(state) ||
    1887         108 :                     !asn1_end_tag(state->result->data) ||
    1888         108 :                     !tldap_decode_controls(state)) {
    1889           0 :                         tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
    1890           0 :                         return;
    1891             :                 }
    1892         108 :                 tevent_req_done(req);
    1893         108 :                 break;
    1894           0 :         default:
    1895           0 :                 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
    1896           0 :                 return;
    1897             :         }
    1898             : }
    1899             : 
    1900         596 : TLDAPRC tldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
    1901             :                           struct tldap_message **pmsg)
    1902             : {
    1903         596 :         struct tldap_req_state *state = tevent_req_data(
    1904             :                 req, struct tldap_req_state);
    1905           0 :         TLDAPRC rc;
    1906             : 
    1907         596 :         if (!tevent_req_is_in_progress(req)
    1908         108 :             && tevent_req_is_ldap_error(req, &rc)) {
    1909           0 :                 return rc;
    1910             :         }
    1911             : 
    1912         596 :         if (tevent_req_is_in_progress(req)) {
    1913         488 :                 switch (state->result->type) {
    1914         488 :                 case TLDAP_RES_SEARCH_ENTRY:
    1915             :                 case TLDAP_RES_SEARCH_REFERENCE:
    1916         488 :                         break;
    1917           0 :                 default:
    1918           0 :                         return TLDAP_OPERATIONS_ERROR;
    1919             :                 }
    1920             :         }
    1921             : 
    1922         596 :         *pmsg = talloc_move(mem_ctx, &state->result);
    1923         596 :         return TLDAP_SUCCESS;
    1924             : }
    1925             : 
    1926             : struct tldap_search_all_state {
    1927             :         struct tldap_message **msgs;
    1928             :         struct tldap_message *result;
    1929             : };
    1930             : 
    1931             : static void tldap_search_all_done(struct tevent_req *subreq);
    1932             : 
    1933          10 : struct tevent_req *tldap_search_all_send(
    1934             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
    1935             :         struct tldap_context *ld, const char *base, int scope,
    1936             :         const char *filter, const char **attrs, int num_attrs, int attrsonly,
    1937             :         struct tldap_control *sctrls, int num_sctrls,
    1938             :         struct tldap_control *cctrls, int num_cctrls,
    1939             :         int timelimit, int sizelimit, int deref)
    1940             : {
    1941           0 :         struct tevent_req *req, *subreq;
    1942           0 :         struct tldap_search_all_state *state;
    1943             : 
    1944          10 :         req = tevent_req_create(mem_ctx, &state,
    1945             :                                 struct tldap_search_all_state);
    1946          10 :         if (req == NULL) {
    1947           0 :                 return NULL;
    1948             :         }
    1949             : 
    1950          10 :         subreq = tldap_search_send(state, ev, ld, base, scope, filter,
    1951             :                                    attrs, num_attrs, attrsonly,
    1952             :                                    sctrls, num_sctrls, cctrls, num_cctrls,
    1953             :                                    timelimit, sizelimit, deref);
    1954          10 :         if (tevent_req_nomem(subreq, req)) {
    1955           0 :                 return tevent_req_post(req, ev);
    1956             :         }
    1957          10 :         tevent_req_set_callback(subreq, tldap_search_all_done, req);
    1958          10 :         return req;
    1959             : }
    1960             : 
    1961          20 : static void tldap_search_all_done(struct tevent_req *subreq)
    1962             : {
    1963          20 :         struct tevent_req *req = tevent_req_callback_data(
    1964             :                 subreq, struct tevent_req);
    1965          20 :         struct tldap_search_all_state *state = tevent_req_data(
    1966             :                 req, struct tldap_search_all_state);
    1967           0 :         struct tldap_message *msg, **tmp;
    1968           0 :         size_t num_msgs;
    1969           0 :         TLDAPRC rc;
    1970           0 :         int msgtype;
    1971             : 
    1972          20 :         rc = tldap_search_recv(subreq, state, &msg);
    1973             :         /* No TALLOC_FREE(subreq), this is multi-step */
    1974          20 :         if (tevent_req_ldap_error(req, rc)) {
    1975          10 :                 return;
    1976             :         }
    1977             : 
    1978          20 :         msgtype = tldap_msg_type(msg);
    1979          20 :         if (msgtype == TLDAP_RES_SEARCH_RESULT) {
    1980          10 :                 state->result = msg;
    1981          10 :                 tevent_req_done(req);
    1982          10 :                 return;
    1983             :         }
    1984             : 
    1985          10 :         num_msgs = talloc_array_length(state->msgs);
    1986             : 
    1987          10 :         tmp = talloc_realloc(state, state->msgs, struct tldap_message *,
    1988             :                              num_msgs + 1);
    1989          10 :         if (tevent_req_nomem(tmp, req)) {
    1990           0 :                 return;
    1991             :         }
    1992          10 :         state->msgs = tmp;
    1993          10 :         state->msgs[num_msgs] = talloc_move(state->msgs, &msg);
    1994             : }
    1995             : 
    1996          10 : TLDAPRC tldap_search_all_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
    1997             :                               struct tldap_message ***msgs,
    1998             :                               struct tldap_message **result)
    1999             : {
    2000          10 :         struct tldap_search_all_state *state = tevent_req_data(
    2001             :                 req, struct tldap_search_all_state);
    2002           0 :         TLDAPRC rc;
    2003             : 
    2004          10 :         if (tevent_req_is_ldap_error(req, &rc)) {
    2005           0 :                 return rc;
    2006             :         }
    2007             : 
    2008          10 :         if (msgs != NULL) {
    2009          10 :                 *msgs = talloc_move(mem_ctx, &state->msgs);
    2010             :         }
    2011          10 :         if (result != NULL) {
    2012          10 :                 *result = talloc_move(mem_ctx, &state->result);
    2013             :         }
    2014             : 
    2015          10 :         return TLDAP_SUCCESS;
    2016             : }
    2017             : 
    2018           8 : TLDAPRC tldap_search(struct tldap_context *ld,
    2019             :                      const char *base, int scope, const char *filter,
    2020             :                      const char **attrs, int num_attrs, int attrsonly,
    2021             :                      struct tldap_control *sctrls, int num_sctrls,
    2022             :                      struct tldap_control *cctrls, int num_cctrls,
    2023             :                      int timelimit, int sizelimit, int deref,
    2024             :                      TALLOC_CTX *mem_ctx, struct tldap_message ***pmsgs)
    2025             : {
    2026           0 :         TALLOC_CTX *frame;
    2027           0 :         struct tevent_context *ev;
    2028           0 :         struct tevent_req *req;
    2029           8 :         TLDAPRC rc = TLDAP_NO_MEMORY;
    2030           0 :         struct tldap_message **msgs;
    2031           0 :         struct tldap_message *result;
    2032             : 
    2033           8 :         if (tldap_pending_reqs(ld)) {
    2034           0 :                 return TLDAP_BUSY;
    2035             :         }
    2036             : 
    2037           8 :         frame = talloc_stackframe();
    2038             : 
    2039           8 :         ev = samba_tevent_context_init(frame);
    2040           8 :         if (ev == NULL) {
    2041           0 :                 goto fail;
    2042             :         }
    2043           8 :         req = tldap_search_all_send(frame, ev, ld, base, scope, filter,
    2044             :                                     attrs, num_attrs, attrsonly,
    2045             :                                     sctrls, num_sctrls, cctrls, num_cctrls,
    2046             :                                     timelimit, sizelimit, deref);
    2047           8 :         if (req == NULL) {
    2048           0 :                 goto fail;
    2049             :         }
    2050           8 :         if (!tevent_req_poll(req, ev)) {
    2051           0 :                 rc = TLDAP_OPERATIONS_ERROR;
    2052           0 :                 goto fail;
    2053             :         }
    2054           8 :         rc = tldap_search_all_recv(req, frame, &msgs, &result);
    2055           8 :         TALLOC_FREE(req);
    2056           8 :         if (!TLDAP_RC_IS_SUCCESS(rc)) {
    2057           0 :                 goto fail;
    2058             :         }
    2059             : 
    2060           8 :         TALLOC_FREE(ld->last_msg);
    2061           8 :         ld->last_msg = talloc_move(ld, &result);
    2062             : 
    2063           8 :         if (pmsgs != NULL) {
    2064           6 :                 *pmsgs = talloc_move(mem_ctx, &msgs);
    2065             :         }
    2066           2 : fail:
    2067           8 :         TALLOC_FREE(frame);
    2068           8 :         return rc;
    2069             : }
    2070             : 
    2071         480 : static bool tldap_parse_search_entry(struct tldap_message *msg)
    2072             : {
    2073         480 :         int num_attribs = 0;
    2074             : 
    2075         480 :         if (msg->type != TLDAP_RES_SEARCH_ENTRY) {
    2076           0 :                 return false;
    2077             :         }
    2078         480 :         if (!asn1_start_tag(msg->data, TLDAP_RES_SEARCH_ENTRY)) {
    2079           0 :                 return false;
    2080             :         }
    2081             : 
    2082             :         /* dn */
    2083             : 
    2084         480 :         if (!asn1_read_OctetString_talloc(msg, msg->data, &msg->dn)) return false;
    2085             : 
    2086         480 :         if (msg->dn == NULL) {
    2087           0 :                 return false;
    2088             :         }
    2089             : 
    2090             :         /*
    2091             :          * Attributes: We overallocate msg->attribs by one, so that while
    2092             :          * looping over the attributes we can directly parse into the last
    2093             :          * array element. Same for the values in the inner loop.
    2094             :          */
    2095             : 
    2096         480 :         msg->attribs = talloc_array(msg, struct tldap_attribute, 1);
    2097         480 :         if (msg->attribs == NULL) {
    2098           0 :                 return false;
    2099             :         }
    2100             : 
    2101         480 :         if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
    2102        7990 :         while (asn1_peek_tag(msg->data, ASN1_SEQUENCE(0))) {
    2103           0 :                 struct tldap_attribute *attrib;
    2104        7510 :                 int num_values = 0;
    2105             : 
    2106        7510 :                 attrib = &msg->attribs[num_attribs];
    2107        7510 :                 attrib->values = talloc_array(msg->attribs, DATA_BLOB, 1);
    2108        7510 :                 if (attrib->values == NULL) {
    2109           0 :                         return false;
    2110             :                 }
    2111        7510 :                 if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
    2112        7510 :                 if (!asn1_read_OctetString_talloc(msg->attribs, msg->data,
    2113           0 :                                              &attrib->name)) return false;
    2114        7510 :                 if (!asn1_start_tag(msg->data, ASN1_SET)) return false;
    2115             : 
    2116       15892 :                 while (asn1_peek_tag(msg->data, ASN1_OCTET_STRING)) {
    2117        8382 :                         if (!asn1_read_OctetString(msg->data, msg,
    2118        8382 :                                               &attrib->values[num_values])) return false;
    2119             : 
    2120        8382 :                         attrib->values = talloc_realloc(
    2121             :                                 msg->attribs, attrib->values, DATA_BLOB,
    2122             :                                 num_values + 2);
    2123        8382 :                         if (attrib->values == NULL) {
    2124           0 :                                 return false;
    2125             :                         }
    2126        8382 :                         num_values += 1;
    2127             :                 }
    2128        7510 :                 attrib->values = talloc_realloc(msg->attribs, attrib->values,
    2129             :                                                 DATA_BLOB, num_values);
    2130        7510 :                 attrib->num_values = num_values;
    2131             : 
    2132        7510 :                 if (!asn1_end_tag(msg->data)) return false; /* ASN1_SET */
    2133        7510 :                 if (!asn1_end_tag(msg->data)) return false; /* ASN1_SEQUENCE(0) */
    2134        7510 :                 msg->attribs = talloc_realloc(
    2135             :                         msg, msg->attribs, struct tldap_attribute,
    2136             :                         num_attribs + 2);
    2137        7510 :                 if (msg->attribs == NULL) {
    2138           0 :                         return false;
    2139             :                 }
    2140        7510 :                 num_attribs += 1;
    2141             :         }
    2142         480 :         msg->attribs = talloc_realloc(
    2143             :                 msg, msg->attribs, struct tldap_attribute, num_attribs);
    2144         480 :         return asn1_end_tag(msg->data);
    2145             : }
    2146             : 
    2147         478 : bool tldap_entry_dn(struct tldap_message *msg, char **dn)
    2148             : {
    2149         478 :         if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
    2150           0 :                 return false;
    2151             :         }
    2152         478 :         *dn = msg->dn;
    2153         478 :         return true;
    2154             : }
    2155             : 
    2156           4 : bool tldap_entry_attributes(struct tldap_message *msg,
    2157             :                             struct tldap_attribute **attributes,
    2158             :                             int *num_attributes)
    2159             : {
    2160           4 :         if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
    2161           0 :                 return false;
    2162             :         }
    2163           4 :         *attributes = msg->attribs;
    2164           4 :         *num_attributes = talloc_array_length(msg->attribs);
    2165           4 :         return true;
    2166             : }
    2167             : 
    2168         108 : static bool tldap_decode_controls(struct tldap_req_state *state)
    2169             : {
    2170         108 :         struct tldap_message *msg = state->result;
    2171         108 :         struct asn1_data *data = msg->data;
    2172         108 :         struct tldap_control *sctrls = NULL;
    2173         108 :         int num_controls = 0;
    2174         108 :         bool ret = false;
    2175             : 
    2176         108 :         msg->res_sctrls = NULL;
    2177             : 
    2178         108 :         if (!asn1_peek_tag(data, ASN1_CONTEXT(0))) {
    2179          12 :                 return true;
    2180             :         }
    2181             : 
    2182          96 :         if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto out;
    2183             : 
    2184         192 :         while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
    2185           0 :                 struct tldap_control *c;
    2186          96 :                 char *oid = NULL;
    2187             : 
    2188          96 :                 sctrls = talloc_realloc(msg, sctrls, struct tldap_control,
    2189             :                                         num_controls + 1);
    2190          96 :                 if (sctrls == NULL) {
    2191           0 :                         goto out;
    2192             :                 }
    2193          96 :                 c = &sctrls[num_controls];
    2194             : 
    2195          96 :                 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto out;
    2196          96 :                 if (!asn1_read_OctetString_talloc(msg, data, &oid)) goto out;
    2197          96 :                 if (asn1_has_error(data) || (oid == NULL)) {
    2198           0 :                         goto out;
    2199             :                 }
    2200          96 :                 c->oid = oid;
    2201          96 :                 if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
    2202           0 :                         if (!asn1_read_BOOLEAN(data, &c->critical)) goto out;
    2203             :                 } else {
    2204          96 :                         c->critical = false;
    2205             :                 }
    2206          96 :                 c->value = data_blob_null;
    2207          96 :                 if (asn1_peek_tag(data, ASN1_OCTET_STRING) &&
    2208          96 :                     !asn1_read_OctetString(data, msg, &c->value)) {
    2209           0 :                         goto out;
    2210             :                 }
    2211          96 :                 if (!asn1_end_tag(data)) goto out; /* ASN1_SEQUENCE(0) */
    2212             : 
    2213          96 :                 num_controls += 1;
    2214             :         }
    2215             : 
    2216          96 :         if (!asn1_end_tag(data)) goto out;      /* ASN1_CONTEXT(0) */
    2217             : 
    2218          96 :         ret = true;
    2219             : 
    2220          96 :  out:
    2221             : 
    2222          96 :         if (ret) {
    2223          96 :                 msg->res_sctrls = sctrls;
    2224             :         } else {
    2225           0 :                 TALLOC_FREE(sctrls);
    2226             :         }
    2227          96 :         return ret;
    2228             : }
    2229             : 
    2230           0 : static void tldap_simple_done(struct tevent_req *subreq, int type)
    2231             : {
    2232           0 :         struct tevent_req *req = tevent_req_callback_data(
    2233             :                 subreq, struct tevent_req);
    2234           0 :         struct tldap_req_state *state = tevent_req_data(
    2235             :                 req, struct tldap_req_state);
    2236           0 :         TLDAPRC rc;
    2237             : 
    2238           0 :         rc = tldap_msg_recv(subreq, state, &state->result);
    2239           0 :         TALLOC_FREE(subreq);
    2240           0 :         if (tevent_req_ldap_error(req, rc)) {
    2241           0 :                 return;
    2242             :         }
    2243           0 :         if (state->result->type != type) {
    2244           0 :                 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
    2245           0 :                 return;
    2246             :         }
    2247           0 :         if (!asn1_start_tag(state->result->data, state->result->type) ||
    2248           0 :             !tldap_decode_response(state) ||
    2249           0 :             !asn1_end_tag(state->result->data) ||
    2250           0 :             !tldap_decode_controls(state)) {
    2251           0 :                 tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
    2252           0 :                 return;
    2253             :         }
    2254           0 :         if (!TLDAP_RC_IS_SUCCESS(state->result->lderr)) {
    2255           0 :                 tevent_req_ldap_error(req, state->result->lderr);
    2256           0 :                 return;
    2257             :         }
    2258           0 :         tevent_req_done(req);
    2259             : }
    2260             : 
    2261           0 : static TLDAPRC tldap_simple_recv(struct tevent_req *req)
    2262             : {
    2263           0 :         TLDAPRC rc;
    2264           0 :         if (tevent_req_is_ldap_error(req, &rc)) {
    2265           0 :                 return rc;
    2266             :         }
    2267           0 :         return TLDAP_SUCCESS;
    2268             : }
    2269             : 
    2270             : static void tldap_add_done(struct tevent_req *subreq);
    2271             : 
    2272           0 : struct tevent_req *tldap_add_send(TALLOC_CTX *mem_ctx,
    2273             :                                   struct tevent_context *ev,
    2274             :                                   struct tldap_context *ld,
    2275             :                                   const char *dn,
    2276             :                                   struct tldap_mod *attributes,
    2277             :                                   int num_attributes,
    2278             :                                   struct tldap_control *sctrls,
    2279             :                                   int num_sctrls,
    2280             :                                   struct tldap_control *cctrls,
    2281             :                                   int num_cctrls)
    2282             : {
    2283           0 :         struct tevent_req *req, *subreq;
    2284           0 :         struct tldap_req_state *state;
    2285           0 :         int i, j;
    2286             : 
    2287           0 :         req = tldap_req_create(mem_ctx, ld, &state);
    2288           0 :         if (req == NULL) {
    2289           0 :                 return NULL;
    2290             :         }
    2291             : 
    2292           0 :         if (!asn1_push_tag(state->out, TLDAP_REQ_ADD)) goto err;
    2293           0 :         if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
    2294           0 :         if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2295             : 
    2296           0 :         for (i=0; i<num_attributes; i++) {
    2297           0 :                 struct tldap_mod *attrib = &attributes[i];
    2298           0 :                 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2299           0 :                 if (!asn1_write_OctetString(state->out, attrib->attribute,
    2300           0 :                                        strlen(attrib->attribute))) goto err;
    2301           0 :                 if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
    2302           0 :                 for (j=0; j<attrib->num_values; j++) {
    2303           0 :                         if (!asn1_write_OctetString(state->out,
    2304           0 :                                                attrib->values[j].data,
    2305           0 :                                                attrib->values[j].length)) goto err;
    2306             :                 }
    2307           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2308           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2309             :         }
    2310             : 
    2311           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2312           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2313             : 
    2314           0 :         subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
    2315             :                                 sctrls, num_sctrls);
    2316           0 :         if (tevent_req_nomem(subreq, req)) {
    2317           0 :                 return tevent_req_post(req, ev);
    2318             :         }
    2319           0 :         tevent_req_set_callback(subreq, tldap_add_done, req);
    2320           0 :         return req;
    2321             : 
    2322           0 :   err:
    2323             : 
    2324           0 :         tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
    2325           0 :         return tevent_req_post(req, ev);
    2326             : }
    2327             : 
    2328           0 : static void tldap_add_done(struct tevent_req *subreq)
    2329             : {
    2330           0 :         tldap_simple_done(subreq, TLDAP_RES_ADD);
    2331           0 : }
    2332             : 
    2333           0 : TLDAPRC tldap_add_recv(struct tevent_req *req)
    2334             : {
    2335           0 :         return tldap_simple_recv(req);
    2336             : }
    2337             : 
    2338           0 : TLDAPRC tldap_add(struct tldap_context *ld, const char *dn,
    2339             :                   struct tldap_mod *attributes, int num_attributes,
    2340             :                   struct tldap_control *sctrls, int num_sctrls,
    2341             :                   struct tldap_control *cctrls, int num_cctrls)
    2342             : {
    2343           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2344           0 :         struct tevent_context *ev;
    2345           0 :         struct tevent_req *req;
    2346           0 :         TLDAPRC rc = TLDAP_NO_MEMORY;
    2347             : 
    2348           0 :         ev = samba_tevent_context_init(frame);
    2349           0 :         if (ev == NULL) {
    2350           0 :                 goto fail;
    2351             :         }
    2352           0 :         req = tldap_add_send(frame, ev, ld, dn, attributes, num_attributes,
    2353             :                              sctrls, num_sctrls, cctrls, num_cctrls);
    2354           0 :         if (req == NULL) {
    2355           0 :                 goto fail;
    2356             :         }
    2357           0 :         if (!tevent_req_poll(req, ev)) {
    2358           0 :                 rc = TLDAP_OPERATIONS_ERROR;
    2359           0 :                 goto fail;
    2360             :         }
    2361           0 :         rc = tldap_add_recv(req);
    2362           0 :         tldap_save_msg(ld, req);
    2363           0 :  fail:
    2364           0 :         TALLOC_FREE(frame);
    2365           0 :         return rc;
    2366             : }
    2367             : 
    2368             : static void tldap_modify_done(struct tevent_req *subreq);
    2369             : 
    2370           0 : struct tevent_req *tldap_modify_send(TALLOC_CTX *mem_ctx,
    2371             :                                      struct tevent_context *ev,
    2372             :                                      struct tldap_context *ld,
    2373             :                                      const char *dn,
    2374             :                                      struct tldap_mod *mods, int num_mods,
    2375             :                                      struct tldap_control *sctrls,
    2376             :                                      int num_sctrls,
    2377             :                                      struct tldap_control *cctrls,
    2378             :                                      int num_cctrls)
    2379             : {
    2380           0 :         struct tevent_req *req, *subreq;
    2381           0 :         struct tldap_req_state *state;
    2382           0 :         int i, j;
    2383             : 
    2384           0 :         req = tldap_req_create(mem_ctx, ld, &state);
    2385           0 :         if (req == NULL) {
    2386           0 :                 return NULL;
    2387             :         }
    2388             : 
    2389           0 :         if (!asn1_push_tag(state->out, TLDAP_REQ_MODIFY)) goto err;
    2390           0 :         if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
    2391           0 :         if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2392             : 
    2393           0 :         for (i=0; i<num_mods; i++) {
    2394           0 :                 struct tldap_mod *mod = &mods[i];
    2395           0 :                 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2396           0 :                 if (!asn1_write_enumerated(state->out, mod->mod_op)) goto err;
    2397           0 :                 if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
    2398           0 :                 if (!asn1_write_OctetString(state->out, mod->attribute,
    2399           0 :                                        strlen(mod->attribute))) goto err;
    2400           0 :                 if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
    2401           0 :                 for (j=0; j<mod->num_values; j++) {
    2402           0 :                         if (!asn1_write_OctetString(state->out,
    2403           0 :                                                mod->values[j].data,
    2404           0 :                                                mod->values[j].length)) goto err;
    2405             :                 }
    2406           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2407           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2408           0 :                 if (!asn1_pop_tag(state->out)) goto err;
    2409             :         }
    2410             : 
    2411           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2412           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2413             : 
    2414           0 :         subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
    2415             :                                 sctrls, num_sctrls);
    2416           0 :         if (tevent_req_nomem(subreq, req)) {
    2417           0 :                 return tevent_req_post(req, ev);
    2418             :         }
    2419           0 :         tevent_req_set_callback(subreq, tldap_modify_done, req);
    2420           0 :         return req;
    2421             : 
    2422           0 :   err:
    2423             : 
    2424           0 :         tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
    2425           0 :         return tevent_req_post(req, ev);
    2426             : }
    2427             : 
    2428           0 : static void tldap_modify_done(struct tevent_req *subreq)
    2429             : {
    2430           0 :         tldap_simple_done(subreq, TLDAP_RES_MODIFY);
    2431           0 : }
    2432             : 
    2433           0 : TLDAPRC tldap_modify_recv(struct tevent_req *req)
    2434             : {
    2435           0 :         return tldap_simple_recv(req);
    2436             : }
    2437             : 
    2438           0 : TLDAPRC tldap_modify(struct tldap_context *ld, const char *dn,
    2439             :                      struct tldap_mod *mods, int num_mods,
    2440             :                      struct tldap_control *sctrls, int num_sctrls,
    2441             :                      struct tldap_control *cctrls, int num_cctrls)
    2442             :  {
    2443           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2444           0 :         struct tevent_context *ev;
    2445           0 :         struct tevent_req *req;
    2446           0 :         TLDAPRC rc = TLDAP_NO_MEMORY;
    2447             : 
    2448           0 :         ev = samba_tevent_context_init(frame);
    2449           0 :         if (ev == NULL) {
    2450           0 :                 goto fail;
    2451             :         }
    2452           0 :         req = tldap_modify_send(frame, ev, ld, dn, mods, num_mods,
    2453             :                                 sctrls, num_sctrls, cctrls, num_cctrls);
    2454           0 :         if (req == NULL) {
    2455           0 :                 goto fail;
    2456             :         }
    2457           0 :         if (!tevent_req_poll(req, ev)) {
    2458           0 :                 rc = TLDAP_OPERATIONS_ERROR;
    2459           0 :                 goto fail;
    2460             :         }
    2461           0 :         rc = tldap_modify_recv(req);
    2462           0 :         tldap_save_msg(ld, req);
    2463           0 :  fail:
    2464           0 :         TALLOC_FREE(frame);
    2465           0 :         return rc;
    2466             : }
    2467             : 
    2468             : static void tldap_delete_done(struct tevent_req *subreq);
    2469             : 
    2470           0 : struct tevent_req *tldap_delete_send(TALLOC_CTX *mem_ctx,
    2471             :                                      struct tevent_context *ev,
    2472             :                                      struct tldap_context *ld,
    2473             :                                      const char *dn,
    2474             :                                      struct tldap_control *sctrls,
    2475             :                                      int num_sctrls,
    2476             :                                      struct tldap_control *cctrls,
    2477             :                                      int num_cctrls)
    2478             : {
    2479           0 :         struct tevent_req *req, *subreq;
    2480           0 :         struct tldap_req_state *state;
    2481             : 
    2482           0 :         req = tldap_req_create(mem_ctx, ld, &state);
    2483           0 :         if (req == NULL) {
    2484           0 :                 return NULL;
    2485             :         }
    2486             : 
    2487           0 :         if (!asn1_push_tag(state->out, TLDAP_REQ_DELETE)) goto err;
    2488           0 :         if (!asn1_write(state->out, dn, strlen(dn))) goto err;
    2489           0 :         if (!asn1_pop_tag(state->out)) goto err;
    2490             : 
    2491           0 :         subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
    2492             :                                 sctrls, num_sctrls);
    2493           0 :         if (tevent_req_nomem(subreq, req)) {
    2494           0 :                 return tevent_req_post(req, ev);
    2495             :         }
    2496           0 :         tevent_req_set_callback(subreq, tldap_delete_done, req);
    2497           0 :         return req;
    2498             : 
    2499           0 :   err:
    2500             : 
    2501           0 :         tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
    2502           0 :         return tevent_req_post(req, ev);
    2503             : }
    2504             : 
    2505           0 : static void tldap_delete_done(struct tevent_req *subreq)
    2506             : {
    2507           0 :         tldap_simple_done(subreq, TLDAP_RES_DELETE);
    2508           0 : }
    2509             : 
    2510           0 : TLDAPRC tldap_delete_recv(struct tevent_req *req)
    2511             : {
    2512           0 :         return tldap_simple_recv(req);
    2513             : }
    2514             : 
    2515           0 : TLDAPRC tldap_delete(struct tldap_context *ld, const char *dn,
    2516             :                      struct tldap_control *sctrls, int num_sctrls,
    2517             :                      struct tldap_control *cctrls, int num_cctrls)
    2518             : {
    2519           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2520           0 :         struct tevent_context *ev;
    2521           0 :         struct tevent_req *req;
    2522           0 :         TLDAPRC rc = TLDAP_NO_MEMORY;
    2523             : 
    2524           0 :         ev = samba_tevent_context_init(frame);
    2525           0 :         if (ev == NULL) {
    2526           0 :                 goto fail;
    2527             :         }
    2528           0 :         req = tldap_delete_send(frame, ev, ld, dn, sctrls, num_sctrls,
    2529             :                                 cctrls, num_cctrls);
    2530           0 :         if (req == NULL) {
    2531           0 :                 goto fail;
    2532             :         }
    2533           0 :         if (!tevent_req_poll(req, ev)) {
    2534           0 :                 rc = TLDAP_OPERATIONS_ERROR;
    2535           0 :                 goto fail;
    2536             :         }
    2537           0 :         rc = tldap_delete_recv(req);
    2538           0 :         tldap_save_msg(ld, req);
    2539           0 :  fail:
    2540           0 :         TALLOC_FREE(frame);
    2541           0 :         return rc;
    2542             : }
    2543             : 
    2544           0 : int tldap_msg_id(const struct tldap_message *msg)
    2545             : {
    2546           0 :         return msg->id;
    2547             : }
    2548             : 
    2549        1550 : int tldap_msg_type(const struct tldap_message *msg)
    2550             : {
    2551        1550 :         return msg->type;
    2552             : }
    2553             : 
    2554           0 : const char *tldap_msg_matcheddn(struct tldap_message *msg)
    2555             : {
    2556           0 :         if (msg == NULL) {
    2557           0 :                 return NULL;
    2558             :         }
    2559           0 :         return msg->res_matcheddn;
    2560             : }
    2561             : 
    2562           0 : const char *tldap_msg_diagnosticmessage(struct tldap_message *msg)
    2563             : {
    2564           0 :         if (msg == NULL) {
    2565           0 :                 return NULL;
    2566             :         }
    2567           0 :         return msg->res_diagnosticmessage;
    2568             : }
    2569             : 
    2570           0 : const char *tldap_msg_referral(struct tldap_message *msg)
    2571             : {
    2572           0 :         if (msg == NULL) {
    2573           0 :                 return NULL;
    2574             :         }
    2575           0 :         return msg->res_referral;
    2576             : }
    2577             : 
    2578          96 : void tldap_msg_sctrls(struct tldap_message *msg, int *num_sctrls,
    2579             :                       struct tldap_control **sctrls)
    2580             : {
    2581          96 :         if (msg == NULL) {
    2582           0 :                 *sctrls = NULL;
    2583           0 :                 *num_sctrls = 0;
    2584           0 :                 return;
    2585             :         }
    2586          96 :         *sctrls = msg->res_sctrls;
    2587          96 :         *num_sctrls = talloc_array_length(msg->res_sctrls);
    2588             : }
    2589             : 
    2590           0 : struct tldap_message *tldap_ctx_lastmsg(struct tldap_context *ld)
    2591             : {
    2592           0 :         return ld->last_msg;
    2593             : }
    2594             : 
    2595             : static const struct { TLDAPRC rc; const char *string; } tldaprc_errmap[] =
    2596             : {
    2597             :         { TLDAP_SUCCESS,
    2598             :           "TLDAP_SUCCESS" },
    2599             :         { TLDAP_OPERATIONS_ERROR,
    2600             :           "TLDAP_OPERATIONS_ERROR" },
    2601             :         { TLDAP_PROTOCOL_ERROR,
    2602             :           "TLDAP_PROTOCOL_ERROR" },
    2603             :         { TLDAP_TIMELIMIT_EXCEEDED,
    2604             :           "TLDAP_TIMELIMIT_EXCEEDED" },
    2605             :         { TLDAP_SIZELIMIT_EXCEEDED,
    2606             :           "TLDAP_SIZELIMIT_EXCEEDED" },
    2607             :         { TLDAP_COMPARE_FALSE,
    2608             :           "TLDAP_COMPARE_FALSE" },
    2609             :         { TLDAP_COMPARE_TRUE,
    2610             :           "TLDAP_COMPARE_TRUE" },
    2611             :         { TLDAP_STRONG_AUTH_NOT_SUPPORTED,
    2612             :           "TLDAP_STRONG_AUTH_NOT_SUPPORTED" },
    2613             :         { TLDAP_STRONG_AUTH_REQUIRED,
    2614             :           "TLDAP_STRONG_AUTH_REQUIRED" },
    2615             :         { TLDAP_REFERRAL,
    2616             :           "TLDAP_REFERRAL" },
    2617             :         { TLDAP_ADMINLIMIT_EXCEEDED,
    2618             :           "TLDAP_ADMINLIMIT_EXCEEDED" },
    2619             :         { TLDAP_UNAVAILABLE_CRITICAL_EXTENSION,
    2620             :           "TLDAP_UNAVAILABLE_CRITICAL_EXTENSION" },
    2621             :         { TLDAP_CONFIDENTIALITY_REQUIRED,
    2622             :           "TLDAP_CONFIDENTIALITY_REQUIRED" },
    2623             :         { TLDAP_SASL_BIND_IN_PROGRESS,
    2624             :           "TLDAP_SASL_BIND_IN_PROGRESS" },
    2625             :         { TLDAP_NO_SUCH_ATTRIBUTE,
    2626             :           "TLDAP_NO_SUCH_ATTRIBUTE" },
    2627             :         { TLDAP_UNDEFINED_TYPE,
    2628             :           "TLDAP_UNDEFINED_TYPE" },
    2629             :         { TLDAP_INAPPROPRIATE_MATCHING,
    2630             :           "TLDAP_INAPPROPRIATE_MATCHING" },
    2631             :         { TLDAP_CONSTRAINT_VIOLATION,
    2632             :           "TLDAP_CONSTRAINT_VIOLATION" },
    2633             :         { TLDAP_TYPE_OR_VALUE_EXISTS,
    2634             :           "TLDAP_TYPE_OR_VALUE_EXISTS" },
    2635             :         { TLDAP_INVALID_SYNTAX,
    2636             :           "TLDAP_INVALID_SYNTAX" },
    2637             :         { TLDAP_NO_SUCH_OBJECT,
    2638             :           "TLDAP_NO_SUCH_OBJECT" },
    2639             :         { TLDAP_ALIAS_PROBLEM,
    2640             :           "TLDAP_ALIAS_PROBLEM" },
    2641             :         { TLDAP_INVALID_DN_SYNTAX,
    2642             :           "TLDAP_INVALID_DN_SYNTAX" },
    2643             :         { TLDAP_IS_LEAF,
    2644             :           "TLDAP_IS_LEAF" },
    2645             :         { TLDAP_ALIAS_DEREF_PROBLEM,
    2646             :           "TLDAP_ALIAS_DEREF_PROBLEM" },
    2647             :         { TLDAP_INAPPROPRIATE_AUTH,
    2648             :           "TLDAP_INAPPROPRIATE_AUTH" },
    2649             :         { TLDAP_INVALID_CREDENTIALS,
    2650             :           "TLDAP_INVALID_CREDENTIALS" },
    2651             :         { TLDAP_INSUFFICIENT_ACCESS,
    2652             :           "TLDAP_INSUFFICIENT_ACCESS" },
    2653             :         { TLDAP_BUSY,
    2654             :           "TLDAP_BUSY" },
    2655             :         { TLDAP_UNAVAILABLE,
    2656             :           "TLDAP_UNAVAILABLE" },
    2657             :         { TLDAP_UNWILLING_TO_PERFORM,
    2658             :           "TLDAP_UNWILLING_TO_PERFORM" },
    2659             :         { TLDAP_LOOP_DETECT,
    2660             :           "TLDAP_LOOP_DETECT" },
    2661             :         { TLDAP_NAMING_VIOLATION,
    2662             :           "TLDAP_NAMING_VIOLATION" },
    2663             :         { TLDAP_OBJECT_CLASS_VIOLATION,
    2664             :           "TLDAP_OBJECT_CLASS_VIOLATION" },
    2665             :         { TLDAP_NOT_ALLOWED_ON_NONLEAF,
    2666             :           "TLDAP_NOT_ALLOWED_ON_NONLEAF" },
    2667             :         { TLDAP_NOT_ALLOWED_ON_RDN,
    2668             :           "TLDAP_NOT_ALLOWED_ON_RDN" },
    2669             :         { TLDAP_ALREADY_EXISTS,
    2670             :           "TLDAP_ALREADY_EXISTS" },
    2671             :         { TLDAP_NO_OBJECT_CLASS_MODS,
    2672             :           "TLDAP_NO_OBJECT_CLASS_MODS" },
    2673             :         { TLDAP_RESULTS_TOO_LARGE,
    2674             :           "TLDAP_RESULTS_TOO_LARGE" },
    2675             :         { TLDAP_AFFECTS_MULTIPLE_DSAS,
    2676             :           "TLDAP_AFFECTS_MULTIPLE_DSAS" },
    2677             :         { TLDAP_OTHER,
    2678             :           "TLDAP_OTHER" },
    2679             :         { TLDAP_SERVER_DOWN,
    2680             :           "TLDAP_SERVER_DOWN" },
    2681             :         { TLDAP_LOCAL_ERROR,
    2682             :           "TLDAP_LOCAL_ERROR" },
    2683             :         { TLDAP_ENCODING_ERROR,
    2684             :           "TLDAP_ENCODING_ERROR" },
    2685             :         { TLDAP_DECODING_ERROR,
    2686             :           "TLDAP_DECODING_ERROR" },
    2687             :         { TLDAP_TIMEOUT,
    2688             :           "TLDAP_TIMEOUT" },
    2689             :         { TLDAP_AUTH_UNKNOWN,
    2690             :           "TLDAP_AUTH_UNKNOWN" },
    2691             :         { TLDAP_FILTER_ERROR,
    2692             :           "TLDAP_FILTER_ERROR" },
    2693             :         { TLDAP_USER_CANCELLED,
    2694             :           "TLDAP_USER_CANCELLED" },
    2695             :         { TLDAP_PARAM_ERROR,
    2696             :           "TLDAP_PARAM_ERROR" },
    2697             :         { TLDAP_NO_MEMORY,
    2698             :           "TLDAP_NO_MEMORY" },
    2699             :         { TLDAP_CONNECT_ERROR,
    2700             :           "TLDAP_CONNECT_ERROR" },
    2701             :         { TLDAP_NOT_SUPPORTED,
    2702             :           "TLDAP_NOT_SUPPORTED" },
    2703             :         { TLDAP_CONTROL_NOT_FOUND,
    2704             :           "TLDAP_CONTROL_NOT_FOUND" },
    2705             :         { TLDAP_NO_RESULTS_RETURNED,
    2706             :           "TLDAP_NO_RESULTS_RETURNED" },
    2707             :         { TLDAP_MORE_RESULTS_TO_RETURN,
    2708             :           "TLDAP_MORE_RESULTS_TO_RETURN" },
    2709             :         { TLDAP_CLIENT_LOOP,
    2710             :           "TLDAP_CLIENT_LOOP" },
    2711             :         { TLDAP_REFERRAL_LIMIT_EXCEEDED,
    2712             :           "TLDAP_REFERRAL_LIMIT_EXCEEDED" },
    2713             : };
    2714             : 
    2715           0 : const char *tldap_rc2string(TLDAPRC rc)
    2716             : {
    2717           0 :         size_t i;
    2718             : 
    2719           0 :         for (i=0; i<ARRAY_SIZE(tldaprc_errmap); i++) {
    2720           0 :                 if (TLDAP_RC_EQUAL(rc, tldaprc_errmap[i].rc)) {
    2721           0 :                         return tldaprc_errmap[i].string;
    2722             :                 }
    2723             :         }
    2724             : 
    2725           0 :         return "Unknown LDAP Error";
    2726             : }

Generated by: LCOV version 1.14