LCOV - code coverage report
Current view: top level - source3/lib - tldap_util.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 162 423 38.3 %
Date: 2024-04-21 15:09:00 Functions: 14 30 46.7 %

          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 "includes.h"
      21             : #include "tldap.h"
      22             : #include "tldap_util.h"
      23             : #include "../libcli/security/security.h"
      24             : #include "../lib/util/asn1.h"
      25             : #include "lib/util/smb_strtox.h"
      26             : 
      27           2 : bool tldap_entry_values(struct tldap_message *msg, const char *attribute,
      28             :                         DATA_BLOB **values, int *num_values)
      29             : {
      30           0 :         struct tldap_attribute *attributes;
      31           0 :         int i, num_attributes;
      32             : 
      33           2 :         if (!tldap_entry_attributes(msg, &attributes, &num_attributes)) {
      34           0 :                 return false;
      35             :         }
      36             : 
      37           4 :         for (i=0; i<num_attributes; i++) {
      38           4 :                 if (strequal(attribute, attributes[i].name)) {
      39           2 :                         break;
      40             :                 }
      41             :         }
      42           2 :         if (i == num_attributes) {
      43           0 :                 return false;
      44             :         }
      45           2 :         *num_values = attributes[i].num_values;
      46           2 :         *values = attributes[i].values;
      47           2 :         return true;
      48             : }
      49             : 
      50           2 : bool tldap_get_single_valueblob(struct tldap_message *msg,
      51             :                                 const char *attribute, DATA_BLOB *blob)
      52             : {
      53           0 :         int num_values;
      54           0 :         DATA_BLOB *values;
      55             : 
      56           2 :         if (attribute == NULL) {
      57           0 :                 return NULL;
      58             :         }
      59           2 :         if (!tldap_entry_values(msg, attribute, &values, &num_values)) {
      60           0 :                 return NULL;
      61             :         }
      62           2 :         if (num_values != 1) {
      63           0 :                 return NULL;
      64             :         }
      65           2 :         *blob = values[0];
      66           2 :         return true;
      67             : }
      68             : 
      69           2 : char *tldap_talloc_single_attribute(struct tldap_message *msg,
      70             :                                     const char *attribute,
      71             :                                     TALLOC_CTX *mem_ctx)
      72             : {
      73           0 :         DATA_BLOB val;
      74           0 :         char *result;
      75           0 :         size_t len;
      76             : 
      77           2 :         if (!tldap_get_single_valueblob(msg, attribute, &val)) {
      78           0 :                 return NULL;
      79             :         }
      80           2 :         if (!convert_string_talloc(mem_ctx, CH_UTF8, CH_UNIX,
      81           2 :                                    val.data, val.length,
      82             :                                    &result, &len)) {
      83           0 :                 return NULL;
      84             :         }
      85           2 :         return result;
      86             : }
      87             : 
      88           0 : bool tldap_pull_binsid(struct tldap_message *msg, const char *attribute,
      89             :                        struct dom_sid *sid)
      90             : {
      91           0 :         DATA_BLOB val;
      92           0 :         ssize_t ret;
      93             : 
      94           0 :         if (!tldap_get_single_valueblob(msg, attribute, &val)) {
      95           0 :                 return false;
      96             :         }
      97           0 :         ret = sid_parse(val.data, val.length, sid);
      98           0 :         return (ret != -1);
      99             : }
     100             : 
     101           0 : bool tldap_pull_guid(struct tldap_message *msg, const char *attribute,
     102             :                      struct GUID *guid)
     103             : {
     104           0 :         DATA_BLOB val;
     105             : 
     106           0 :         if (!tldap_get_single_valueblob(msg, attribute, &val)) {
     107           0 :                 return false;
     108             :         }
     109           0 :         return NT_STATUS_IS_OK(GUID_from_data_blob(&val, guid));
     110             : }
     111             : 
     112           0 : static bool tldap_add_blob_vals(TALLOC_CTX *mem_ctx, struct tldap_mod *mod,
     113             :                                 DATA_BLOB *newvals, int num_newvals)
     114             : {
     115           0 :         int num_values = talloc_array_length(mod->values);
     116           0 :         int i;
     117           0 :         DATA_BLOB *tmp;
     118             : 
     119           0 :         tmp = talloc_realloc(mem_ctx, mod->values, DATA_BLOB,
     120             :                              num_values + num_newvals);
     121           0 :         if (tmp == NULL) {
     122           0 :                 return false;
     123             :         }
     124           0 :         mod->values = tmp;
     125             : 
     126           0 :         for (i=0; i<num_newvals; i++) {
     127           0 :                 mod->values[i+num_values].data = (uint8_t *)talloc_memdup(
     128             :                         mod->values, newvals[i].data, newvals[i].length);
     129           0 :                 if (mod->values[i+num_values].data == NULL) {
     130           0 :                         return false;
     131             :                 }
     132           0 :                 mod->values[i+num_values].length = newvals[i].length;
     133             :         }
     134           0 :         mod->num_values = num_values + num_newvals;
     135           0 :         return true;
     136             : }
     137             : 
     138           0 : bool tldap_add_mod_blobs(TALLOC_CTX *mem_ctx,
     139             :                          struct tldap_mod **pmods, int *pnum_mods,
     140             :                          int mod_op, const char *attrib,
     141             :                          DATA_BLOB *newvals, int num_newvals)
     142             : {
     143           0 :         struct tldap_mod new_mod;
     144           0 :         struct tldap_mod *mods = *pmods;
     145           0 :         struct tldap_mod *mod = NULL;
     146           0 :         int i, num_mods;
     147             : 
     148           0 :         if (mods == NULL) {
     149           0 :                 mods = talloc_array(mem_ctx, struct tldap_mod, 0);
     150             :         }
     151           0 :         if (mods == NULL) {
     152           0 :                 return false;
     153             :         }
     154             : 
     155           0 :         num_mods = *pnum_mods;
     156             : 
     157           0 :         for (i=0; i<num_mods; i++) {
     158           0 :                 if ((mods[i].mod_op == mod_op)
     159           0 :                     && strequal(mods[i].attribute, attrib)) {
     160           0 :                         mod = &mods[i];
     161           0 :                         break;
     162             :                 }
     163             :         }
     164             : 
     165           0 :         if (mod == NULL) {
     166           0 :                 new_mod.mod_op = mod_op;
     167           0 :                 new_mod.attribute = talloc_strdup(mods, attrib);
     168           0 :                 if (new_mod.attribute == NULL) {
     169           0 :                         return false;
     170             :                 }
     171           0 :                 new_mod.num_values = 0;
     172           0 :                 new_mod.values = NULL;
     173           0 :                 mod = &new_mod;
     174             :         }
     175             : 
     176           0 :         if ((num_newvals != 0)
     177           0 :             && !tldap_add_blob_vals(mods, mod, newvals, num_newvals)) {
     178           0 :                 return false;
     179             :         }
     180             : 
     181           0 :         if ((i == num_mods) && (talloc_array_length(mods) < num_mods + 1)) {
     182           0 :                 mods = talloc_realloc(talloc_tos(), mods, struct tldap_mod,
     183             :                                       num_mods+1);
     184           0 :                 if (mods == NULL) {
     185           0 :                         return false;
     186             :                 }
     187           0 :                 mods[num_mods] = *mod;
     188             :         }
     189             : 
     190           0 :         *pmods = mods;
     191           0 :         *pnum_mods += 1;
     192           0 :         return true;
     193             : }
     194             : 
     195           0 : bool tldap_add_mod_str(TALLOC_CTX *mem_ctx,
     196             :                        struct tldap_mod **pmods, int *pnum_mods,
     197             :                        int mod_op, const char *attrib, const char *str)
     198             : {
     199           0 :         DATA_BLOB utf8;
     200           0 :         bool ret;
     201             : 
     202           0 :         if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_UTF8, str,
     203             :                                    strlen(str), &utf8.data, &utf8.length)) {
     204           0 :                 return false;
     205             :         }
     206             : 
     207           0 :         ret = tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods, mod_op, attrib,
     208             :                                   &utf8, 1);
     209           0 :         TALLOC_FREE(utf8.data);
     210           0 :         return ret;
     211             : }
     212             : 
     213           0 : static bool tldap_make_mod_blob_int(struct tldap_message *existing,
     214             :                                     TALLOC_CTX *mem_ctx,
     215             :                                     struct tldap_mod **pmods, int *pnum_mods,
     216             :                                     const char *attrib, DATA_BLOB newval,
     217             :                                     int (*comparison)(const DATA_BLOB *d1,
     218             :                                                       const DATA_BLOB *d2))
     219             : {
     220           0 :         int num_values = 0;
     221           0 :         DATA_BLOB *values = NULL;
     222           0 :         DATA_BLOB oldval = data_blob_null;
     223             : 
     224           0 :         if ((existing != NULL)
     225           0 :             && tldap_entry_values(existing, attrib, &values, &num_values)) {
     226             : 
     227           0 :                 if (num_values > 1) {
     228             :                         /* can't change multivalue attributes atm */
     229           0 :                         return false;
     230             :                 }
     231           0 :                 if (num_values == 1) {
     232           0 :                         oldval = values[0];
     233             :                 }
     234             :         }
     235             : 
     236           0 :         if ((oldval.data != NULL) && (newval.data != NULL)
     237           0 :             && (comparison(&oldval, &newval) == 0)) {
     238             :                 /* Believe it or not, but LDAP will deny a delete and
     239             :                    an add at the same time if the values are the
     240             :                    same... */
     241           0 :                 DEBUG(10,("tldap_make_mod_blob_int: attribute |%s| not "
     242             :                           "changed.\n", attrib));
     243           0 :                 return true;
     244             :         }
     245             : 
     246           0 :         if (oldval.data != NULL) {
     247             :                 /* By deleting exactly the value we found in the entry this
     248             :                  * should be race-free in the sense that the LDAP-Server will
     249             :                  * deny the complete operation if somebody changed the
     250             :                  * attribute behind our back. */
     251             :                 /* This will also allow modifying single valued attributes in
     252             :                  * Novell NDS. In NDS you have to first remove attribute and
     253             :                  * then you could add new value */
     254             : 
     255           0 :                 DEBUG(10, ("tldap_make_mod_blob_int: deleting attribute |%s|\n",
     256             :                            attrib));
     257           0 :                 if (!tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods,
     258             :                                          TLDAP_MOD_DELETE,
     259             :                                          attrib, &oldval, 1)) {
     260           0 :                         return false;
     261             :                 }
     262             :         }
     263             : 
     264             :         /* Regardless of the real operation (add or modify)
     265             :            we add the new value here. We rely on deleting
     266             :            the old value, should it exist. */
     267             : 
     268           0 :         if (newval.data != NULL) {
     269           0 :                 DEBUG(10, ("tldap_make_mod_blob_int: adding attribute |%s| value len "
     270             :                            "%d\n", attrib, (int)newval.length));
     271           0 :                 if (!tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods,
     272             :                                          TLDAP_MOD_ADD,
     273             :                                          attrib, &newval, 1)) {
     274           0 :                         return false;
     275             :                 }
     276             :         }
     277           0 :         return true;
     278             : }
     279             : 
     280           0 : bool tldap_make_mod_blob(struct tldap_message *existing, TALLOC_CTX *mem_ctx,
     281             :                          struct tldap_mod **pmods, int *pnum_mods,
     282             :                          const char *attrib, DATA_BLOB newval)
     283             : {
     284           0 :         return tldap_make_mod_blob_int(existing, mem_ctx, pmods, pnum_mods,
     285             :                                        attrib, newval, data_blob_cmp);
     286             : }
     287             : 
     288           0 : static int compare_utf8_blobs(const DATA_BLOB *d1, const DATA_BLOB *d2)
     289             : {
     290           0 :         char *s1, *s2;
     291           0 :         size_t s1len, s2len;
     292           0 :         int ret;
     293             : 
     294           0 :         if (!convert_string_talloc(talloc_tos(), CH_UTF8, CH_UNIX, d1->data,
     295           0 :                                    d1->length, &s1, &s1len)) {
     296             :                 /* can't do much here */
     297           0 :                 return 0;
     298             :         }
     299           0 :         if (!convert_string_talloc(talloc_tos(), CH_UTF8, CH_UNIX, d2->data,
     300           0 :                                    d2->length, &s2, &s2len)) {
     301             :                 /* can't do much here */
     302           0 :                 TALLOC_FREE(s1);
     303           0 :                 return 0;
     304             :         }
     305           0 :         ret = strcasecmp_m(s1, s2);
     306           0 :         TALLOC_FREE(s2);
     307           0 :         TALLOC_FREE(s1);
     308           0 :         return ret;
     309             : }
     310             : 
     311           0 : bool tldap_make_mod_fmt(struct tldap_message *existing, TALLOC_CTX *mem_ctx,
     312             :                         struct tldap_mod **pmods, int *pnum_mods,
     313             :                         const char *attrib, const char *fmt, ...)
     314             : {
     315           0 :         va_list ap;
     316           0 :         char *newval;
     317           0 :         bool ret;
     318           0 :         DATA_BLOB blob = data_blob_null;
     319             : 
     320           0 :         va_start(ap, fmt);
     321           0 :         newval = talloc_vasprintf(talloc_tos(), fmt, ap);
     322           0 :         va_end(ap);
     323             : 
     324           0 :         if (newval == NULL) {
     325           0 :                 return false;
     326             :         }
     327             : 
     328           0 :         blob.length = strlen(newval);
     329           0 :         if (blob.length != 0) {
     330           0 :                 blob.data = discard_const_p(uint8_t, newval);
     331             :         }
     332           0 :         ret = tldap_make_mod_blob_int(existing, mem_ctx, pmods, pnum_mods,
     333             :                                       attrib, blob, compare_utf8_blobs);
     334           0 :         TALLOC_FREE(newval);
     335           0 :         return ret;
     336             : }
     337             : 
     338           0 : const char *tldap_errstr(TALLOC_CTX *mem_ctx, struct tldap_context *ld,
     339             :                          TLDAPRC rc)
     340             : {
     341           0 :         const char *ld_error = NULL;
     342           0 :         char *res;
     343             : 
     344           0 :         if (ld != NULL) {
     345           0 :                 ld_error = tldap_msg_diagnosticmessage(tldap_ctx_lastmsg(ld));
     346             :         }
     347           0 :         res = talloc_asprintf(mem_ctx, "LDAP error %d (%s), %s",
     348           0 :                               (int)TLDAP_RC_V(rc), tldap_rc2string(rc),
     349             :                               ld_error ? ld_error : "unknown");
     350           0 :         return res;
     351             : }
     352             : 
     353           0 : TLDAPRC tldap_search_va(struct tldap_context *ld, const char *base, int scope,
     354             :                         const char *attrs[], int num_attrs, int attrsonly,
     355             :                         TALLOC_CTX *mem_ctx, struct tldap_message ***res,
     356             :                         const char *fmt, va_list ap)
     357             : {
     358           0 :         char *filter;
     359           0 :         TLDAPRC rc;
     360             : 
     361           0 :         filter = talloc_vasprintf(talloc_tos(), fmt, ap);
     362           0 :         if (filter == NULL) {
     363           0 :                 return TLDAP_NO_MEMORY;
     364             :         }
     365             : 
     366           0 :         rc = tldap_search(ld, base, scope, filter,
     367             :                           attrs, num_attrs, attrsonly,
     368             :                           NULL /*sctrls*/, 0, NULL /*cctrls*/, 0,
     369             :                           0 /*timelimit*/, 0 /*sizelimit*/, 0 /*deref*/,
     370             :                           mem_ctx, res);
     371           0 :         TALLOC_FREE(filter);
     372           0 :         return rc;
     373             : }
     374             : 
     375           0 : TLDAPRC tldap_search_fmt(struct tldap_context *ld, const char *base, int scope,
     376             :                          const char *attrs[], int num_attrs, int attrsonly,
     377             :                          TALLOC_CTX *mem_ctx, struct tldap_message ***res,
     378             :                          const char *fmt, ...)
     379             : {
     380           0 :         va_list ap;
     381           0 :         TLDAPRC rc;
     382             : 
     383           0 :         va_start(ap, fmt);
     384           0 :         rc = tldap_search_va(ld, base, scope, attrs, num_attrs, attrsonly,
     385             :                              mem_ctx, res, fmt, ap);
     386           0 :         va_end(ap);
     387           0 :         return rc;
     388             : }
     389             : 
     390           0 : bool tldap_pull_uint64(struct tldap_message *msg, const char *attr,
     391             :                        uint64_t *presult)
     392             : {
     393           0 :         char *str;
     394           0 :         uint64_t result;
     395           0 :         int error = 0;
     396             : 
     397           0 :         str = tldap_talloc_single_attribute(msg, attr, talloc_tos());
     398           0 :         if (str == NULL) {
     399           0 :                 DEBUG(10, ("Could not find attribute %s\n", attr));
     400           0 :                 return false;
     401             :         }
     402             : 
     403           0 :         result = smb_strtoull(str, NULL, 10, &error, SMB_STR_STANDARD);
     404           0 :         if (error != 0) {
     405           0 :                 DBG_DEBUG("Attribute conversion failed (%s)\n",
     406             :                           strerror(error));
     407           0 :                 TALLOC_FREE(str);
     408           0 :                 return false;
     409             :         }
     410             : 
     411           0 :         TALLOC_FREE(str);
     412           0 :         *presult = result;
     413           0 :         return true;
     414             : }
     415             : 
     416           0 : bool tldap_pull_uint32(struct tldap_message *msg, const char *attr,
     417             :                        uint32_t *presult)
     418             : {
     419           0 :         uint64_t result;
     420             : 
     421           0 :         if (!tldap_pull_uint64(msg, attr, &result)) {
     422           0 :                 return false;
     423             :         }
     424           0 :         *presult = (uint32_t)result;
     425           0 :         return true;
     426             : }
     427             : 
     428             : struct tldap_fetch_rootdse_state {
     429             :         struct tldap_context *ld;
     430             :         struct tldap_message *rootdse;
     431             : };
     432             : 
     433             : static void tldap_fetch_rootdse_done(struct tevent_req *subreq);
     434             : 
     435           2 : struct tevent_req *tldap_fetch_rootdse_send(TALLOC_CTX *mem_ctx,
     436             :                                             struct tevent_context *ev,
     437             :                                             struct tldap_context *ld)
     438             : {
     439           0 :         struct tevent_req *req, *subreq;
     440           0 :         struct tldap_fetch_rootdse_state *state;
     441           0 :         static const char *attrs[2] = { "*", "+" };
     442             : 
     443           2 :         req = tevent_req_create(mem_ctx, &state,
     444             :                                 struct tldap_fetch_rootdse_state);
     445           2 :         if (req == NULL) {
     446           0 :                 return NULL;
     447             :         }
     448           2 :         state->ld = ld;
     449           2 :         state->rootdse = NULL;
     450             : 
     451           2 :         subreq = tldap_search_send(
     452             :                 mem_ctx, ev, ld, "", TLDAP_SCOPE_BASE, "(objectclass=*)",
     453             :                 attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0, 0, 0, 0);
     454           2 :         if (tevent_req_nomem(subreq, req)) {
     455           0 :                 return tevent_req_post(req, ev);
     456             :         }
     457           2 :         tevent_req_set_callback(subreq, tldap_fetch_rootdse_done, req);
     458           2 :         return req;
     459             : }
     460             : 
     461           4 : static void tldap_fetch_rootdse_done(struct tevent_req *subreq)
     462             : {
     463           4 :         struct tevent_req *req = tevent_req_callback_data(
     464             :                 subreq, struct tevent_req);
     465           4 :         struct tldap_fetch_rootdse_state *state = tevent_req_data(
     466             :                 req, struct tldap_fetch_rootdse_state);
     467           0 :         struct tldap_message *msg;
     468           0 :         TLDAPRC rc;
     469             : 
     470           4 :         rc = tldap_search_recv(subreq, state, &msg);
     471           4 :         if (tevent_req_ldap_error(req, rc)) {
     472           0 :                 return;
     473             :         }
     474             : 
     475           4 :         switch (tldap_msg_type(msg)) {
     476           2 :         case TLDAP_RES_SEARCH_ENTRY:
     477           2 :                 if (state->rootdse != NULL) {
     478           0 :                         goto protocol_error;
     479             :                 }
     480           2 :                 state->rootdse = msg;
     481           2 :                 break;
     482           2 :         case TLDAP_RES_SEARCH_RESULT:
     483           2 :                 TALLOC_FREE(subreq);
     484           2 :                 if (state->rootdse == NULL) {
     485           0 :                         goto protocol_error;
     486             :                 }
     487           2 :                 tevent_req_done(req);
     488           2 :                 break;
     489           0 :         default:
     490           0 :                 goto protocol_error;
     491             :         }
     492           4 :         return;
     493             : 
     494           0 : protocol_error:
     495           0 :         tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
     496           0 :         return;
     497             : }
     498             : 
     499           2 : TLDAPRC tldap_fetch_rootdse_recv(struct tevent_req *req)
     500             : {
     501           2 :         struct tldap_fetch_rootdse_state *state = tevent_req_data(
     502             :                 req, struct tldap_fetch_rootdse_state);
     503           0 :         TLDAPRC rc;
     504           0 :         char *dn;
     505             : 
     506           2 :         if (tevent_req_is_ldap_error(req, &rc)) {
     507           0 :                 return rc;
     508             :         }
     509             :         /* Trigger parsing the dn, just to make sure it's ok */
     510           2 :         if (!tldap_entry_dn(state->rootdse, &dn)) {
     511           0 :                 return TLDAP_DECODING_ERROR;
     512             :         }
     513           2 :         if (!tldap_context_setattr(state->ld, "tldap:rootdse",
     514           2 :                                    &state->rootdse)) {
     515           0 :                 return TLDAP_NO_MEMORY;
     516             :         }
     517           2 :         return TLDAP_SUCCESS;
     518             : }
     519             : 
     520           2 : TLDAPRC tldap_fetch_rootdse(struct tldap_context *ld)
     521             : {
     522           2 :         TALLOC_CTX *frame = talloc_stackframe();
     523           0 :         struct tevent_context *ev;
     524           0 :         struct tevent_req *req;
     525           2 :         TLDAPRC rc = TLDAP_NO_MEMORY;
     526             : 
     527           2 :         ev = samba_tevent_context_init(frame);
     528           2 :         if (ev == NULL) {
     529           0 :                 goto fail;
     530             :         }
     531           2 :         req = tldap_fetch_rootdse_send(frame, ev, ld);
     532           2 :         if (req == NULL) {
     533           0 :                 goto fail;
     534             :         }
     535           2 :         if (!tevent_req_poll(req, ev)) {
     536           0 :                 rc = TLDAP_OPERATIONS_ERROR;
     537           0 :                 goto fail;
     538             :         }
     539             : 
     540           2 :         rc = tldap_fetch_rootdse_recv(req);
     541           2 :  fail:
     542           2 :         TALLOC_FREE(frame);
     543           2 :         return rc;
     544             : }
     545             : 
     546           2 : struct tldap_message *tldap_rootdse(struct tldap_context *ld)
     547             : {
     548           2 :         return talloc_get_type(tldap_context_getattr(ld, "tldap:rootdse"),
     549             :                                struct tldap_message);
     550             : }
     551             : 
     552           0 : bool tldap_entry_has_attrvalue(struct tldap_message *msg,
     553             :                                const char *attribute,
     554             :                                const DATA_BLOB blob)
     555             : {
     556           0 :         int i, num_values;
     557           0 :         DATA_BLOB *values;
     558             : 
     559           0 :         if (!tldap_entry_values(msg, attribute, &values, &num_values)) {
     560           0 :                 return false;
     561             :         }
     562           0 :         for (i=0; i<num_values; i++) {
     563           0 :                 if (data_blob_cmp(&values[i], &blob) == 0) {
     564           0 :                         return true;
     565             :                 }
     566             :         }
     567           0 :         return false;
     568             : }
     569             : 
     570           0 : bool tldap_supports_control(struct tldap_context *ld, const char *oid)
     571             : {
     572           0 :         struct tldap_message *rootdse = tldap_rootdse(ld);
     573             : 
     574           0 :         if (rootdse == NULL) {
     575           0 :                 return false;
     576             :         }
     577           0 :         return tldap_entry_has_attrvalue(rootdse, "supportedControl",
     578             :                                          data_blob_const(oid, strlen(oid)));
     579             : }
     580             : 
     581           8 : struct tldap_control *tldap_add_control(TALLOC_CTX *mem_ctx,
     582             :                                         struct tldap_control *ctrls,
     583             :                                         int num_ctrls,
     584             :                                         struct tldap_control *ctrl)
     585             : {
     586           0 :         struct tldap_control *result;
     587             : 
     588           8 :         result = talloc_array(mem_ctx, struct tldap_control, num_ctrls+1);
     589           8 :         if (result == NULL) {
     590           0 :                 return NULL;
     591             :         }
     592           8 :         if (num_ctrls > 0) {
     593           0 :                 memcpy(result, ctrls, sizeof(struct tldap_control) * num_ctrls);
     594             :         }
     595           8 :         result[num_ctrls] = *ctrl;
     596           8 :         return result;
     597             : }
     598             : 
     599             : /*
     600             :  * Find a control returned by the server
     601             :  */
     602          96 : struct tldap_control *tldap_msg_findcontrol(struct tldap_message *msg,
     603             :                                             const char *oid)
     604             : {
     605           0 :         struct tldap_control *controls;
     606           0 :         int i, num_controls;
     607             : 
     608          96 :         tldap_msg_sctrls(msg, &num_controls, &controls);
     609             : 
     610          96 :         for (i=0; i<num_controls; i++) {
     611          96 :                 if (strcmp(controls[i].oid, oid) == 0) {
     612          96 :                         return &controls[i];
     613             :                 }
     614             :         }
     615           0 :         return NULL;
     616             : }
     617             : 
     618             : struct tldap_search_paged_state {
     619             :         struct tevent_context *ev;
     620             :         struct tldap_context *ld;
     621             :         const char *base;
     622             :         const char *filter;
     623             :         int scope;
     624             :         const char **attrs;
     625             :         int num_attrs;
     626             :         int attrsonly;
     627             :         struct tldap_control *sctrls;
     628             :         int num_sctrls;
     629             :         struct tldap_control *cctrls;
     630             :         int num_cctrls;
     631             :         int timelimit;
     632             :         int sizelimit;
     633             :         int deref;
     634             : 
     635             :         int page_size;
     636             :         struct asn1_data *asn1;
     637             :         DATA_BLOB cookie;
     638             :         struct tldap_message *result;
     639             : };
     640             : 
     641          96 : static struct tevent_req *tldap_ship_paged_search(
     642             :         TALLOC_CTX *mem_ctx,
     643             :         struct tldap_search_paged_state *state)
     644             : {
     645           0 :         struct tldap_control *pgctrl;
     646          96 :         struct asn1_data *asn1 = NULL;
     647             : 
     648          96 :         asn1 = asn1_init(state, ASN1_MAX_TREE_DEPTH);
     649          96 :         if (asn1 == NULL) {
     650           0 :                 return NULL;
     651             :         }
     652          96 :         if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) goto err;
     653          96 :         if (!asn1_write_Integer(asn1, state->page_size)) goto err;
     654          96 :         if (!asn1_write_OctetString(asn1, state->cookie.data, state->cookie.length)) goto err;
     655          96 :         if (!asn1_pop_tag(asn1)) goto err;
     656          96 :         state->asn1 = asn1;
     657             : 
     658          96 :         pgctrl = &state->sctrls[state->num_sctrls-1];
     659          96 :         pgctrl->oid = TLDAP_CONTROL_PAGEDRESULTS;
     660          96 :         pgctrl->critical = true;
     661          96 :         if (!asn1_blob(state->asn1, &pgctrl->value)) {
     662           0 :                 goto err;
     663             :         }
     664          96 :         return tldap_search_send(mem_ctx, state->ev, state->ld, state->base,
     665             :                                  state->scope, state->filter, state->attrs,
     666             :                                  state->num_attrs, state->attrsonly,
     667             :                                  state->sctrls, state->num_sctrls,
     668             :                                  state->cctrls, state->num_cctrls,
     669             :                                  state->timelimit, state->sizelimit,
     670             :                                  state->deref);
     671             : 
     672           0 :   err:
     673             : 
     674           0 :         TALLOC_FREE(asn1);
     675           0 :         return NULL;
     676             : }
     677             : 
     678             : static void tldap_search_paged_done(struct tevent_req *subreq);
     679             : 
     680           2 : struct tevent_req *tldap_search_paged_send(TALLOC_CTX *mem_ctx,
     681             :                                            struct tevent_context *ev,
     682             :                                            struct tldap_context *ld,
     683             :                                            const char *base, int scope,
     684             :                                            const char *filter,
     685             :                                            const char **attrs,
     686             :                                            int num_attrs,
     687             :                                            int attrsonly,
     688             :                                            struct tldap_control *sctrls,
     689             :                                            int num_sctrls,
     690             :                                            struct tldap_control *cctrls,
     691             :                                            int num_cctrls,
     692             :                                            int timelimit,
     693             :                                            int sizelimit,
     694             :                                            int deref,
     695             :                                            int page_size)
     696             : {
     697           0 :         struct tevent_req *req, *subreq;
     698           0 :         struct tldap_search_paged_state *state;
     699           0 :         struct tldap_control empty_control;
     700             : 
     701           2 :         req = tevent_req_create(mem_ctx, &state,
     702             :                                 struct tldap_search_paged_state);
     703           2 :         if (req == NULL) {
     704           0 :                 return NULL;
     705             :         }
     706           2 :         state->ev = ev;
     707           2 :         state->ld = ld;
     708           2 :         state->base = base;
     709           2 :         state->filter = filter;
     710           2 :         state->scope = scope;
     711           2 :         state->attrs = attrs;
     712           2 :         state->num_attrs = num_attrs;
     713           2 :         state->attrsonly = attrsonly;
     714           2 :         state->cctrls = cctrls;
     715           2 :         state->num_cctrls = num_cctrls;
     716           2 :         state->timelimit = timelimit;
     717           2 :         state->sizelimit = sizelimit;
     718           2 :         state->deref = deref;
     719             : 
     720           2 :         state->page_size = page_size;
     721           2 :         state->asn1 = NULL;
     722           2 :         state->cookie = data_blob_null;
     723             : 
     724           2 :         ZERO_STRUCT(empty_control);
     725             : 
     726           2 :         state->sctrls = tldap_add_control(state, sctrls, num_sctrls,
     727             :                                           &empty_control);
     728           2 :         if (tevent_req_nomem(state->sctrls, req)) {
     729           0 :                 return tevent_req_post(req, ev);
     730             :         }
     731           2 :         state->num_sctrls = num_sctrls+1;
     732             : 
     733           2 :         subreq = tldap_ship_paged_search(state, state);
     734           2 :         if (tevent_req_nomem(subreq, req)) {
     735           0 :                 return tevent_req_post(req, ev);
     736             :         }
     737           2 :         tevent_req_set_callback(subreq, tldap_search_paged_done, req);
     738             : 
     739           2 :         return req;
     740             : }
     741             : 
     742         572 : static void tldap_search_paged_done(struct tevent_req *subreq)
     743             : {
     744         572 :         struct tevent_req *req = tevent_req_callback_data(
     745             :                 subreq, struct tevent_req);
     746         572 :         struct tldap_search_paged_state *state = tevent_req_data(
     747             :                 req, struct tldap_search_paged_state);
     748         572 :         struct asn1_data *asn1 = NULL;
     749           0 :         struct tldap_control *pgctrl;
     750           0 :         TLDAPRC rc;
     751           0 :         int size;
     752             : 
     753         572 :         rc = tldap_search_recv(subreq, state, &state->result);
     754         572 :         if (tevent_req_ldap_error(req, rc)) {
     755         572 :                 return;
     756             :         }
     757             : 
     758         572 :         TALLOC_FREE(state->asn1);
     759             : 
     760         572 :         switch (tldap_msg_type(state->result)) {
     761         476 :         case TLDAP_RES_SEARCH_ENTRY:
     762             :         case TLDAP_RES_SEARCH_REFERENCE:
     763         476 :                 tevent_req_notify_callback(req);
     764         476 :                 return;
     765          96 :         case TLDAP_RES_SEARCH_RESULT:
     766          96 :                 break;
     767           0 :         default:
     768           0 :                 TALLOC_FREE(subreq);
     769           0 :                 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
     770           0 :                 return;
     771             :         }
     772             : 
     773          96 :         TALLOC_FREE(subreq);
     774             : 
     775             :         /* We've finished one paged search, fire the next */
     776             : 
     777          96 :         pgctrl = tldap_msg_findcontrol(state->result,
     778             :                                        TLDAP_CONTROL_PAGEDRESULTS);
     779          96 :         if (pgctrl == NULL) {
     780             :                 /* RFC2696 requires the server to return the control */
     781           0 :                 tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
     782           0 :                 return;
     783             :         }
     784             : 
     785          96 :         TALLOC_FREE(state->cookie.data);
     786             : 
     787          96 :         asn1 = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
     788          96 :         if (tevent_req_nomem(asn1, req)) {
     789           0 :                 return;
     790             :         }
     791             : 
     792          96 :         asn1_load_nocopy(asn1, pgctrl->value.data, pgctrl->value.length);
     793          96 :         if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) goto err;
     794          96 :         if (!asn1_read_Integer(asn1, &size)) goto err;
     795          96 :         if (!asn1_read_OctetString(asn1, state, &state->cookie)) goto err;
     796          96 :         if (!asn1_end_tag(asn1)) goto err;
     797             : 
     798          96 :         TALLOC_FREE(asn1);
     799             : 
     800          96 :         if (state->cookie.length == 0) {
     801             :                 /* We're done, no cookie anymore */
     802           2 :                 tevent_req_done(req);
     803           2 :                 return;
     804             :         }
     805             : 
     806          94 :         TALLOC_FREE(state->result);
     807             : 
     808          94 :         subreq = tldap_ship_paged_search(state, state);
     809          94 :         if (tevent_req_nomem(subreq, req)) {
     810           0 :                 return;
     811             :         }
     812          94 :         tevent_req_set_callback(subreq, tldap_search_paged_done, req);
     813             : 
     814          94 :         return;
     815           0 : err:
     816             : 
     817           0 :         TALLOC_FREE(asn1);
     818           0 :         tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
     819             : }
     820             : 
     821         478 : TLDAPRC tldap_search_paged_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     822             :                                 struct tldap_message **pmsg)
     823             : {
     824         478 :         struct tldap_search_paged_state *state = tevent_req_data(
     825             :                 req, struct tldap_search_paged_state);
     826           0 :         TLDAPRC rc;
     827             : 
     828         478 :         if (!tevent_req_is_in_progress(req)
     829           2 :             && tevent_req_is_ldap_error(req, &rc)) {
     830           0 :                 return rc;
     831             :         }
     832         478 :         if (tevent_req_is_in_progress(req)) {
     833         476 :                 switch (tldap_msg_type(state->result)) {
     834         476 :                 case TLDAP_RES_SEARCH_ENTRY:
     835             :                 case TLDAP_RES_SEARCH_REFERENCE:
     836         476 :                         break;
     837           0 :                 default:
     838           0 :                         return TLDAP_PROTOCOL_ERROR;
     839             :                 }
     840             :         }
     841         478 :         *pmsg = talloc_move(mem_ctx, &state->result);
     842         478 :         return TLDAP_SUCCESS;
     843             : }

Generated by: LCOV version 1.14