LCOV - code coverage report
Current view: top level - source3/lib - tldap.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 1251 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 83 0.0 %

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

Generated by: LCOV version 1.13