LCOV - code coverage report
Current view: top level - providers/ldap - sdap_async.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 1248 0.0 %
Date: 2015-10-19 Functions: 0 71 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Async LDAP Helper routines
       5             : 
       6             :     Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
       7             : 
       8             :     This program is free software; you can redistribute it and/or modify
       9             :     it under the terms of the GNU General Public License as published by
      10             :     the Free Software Foundation; either version 3 of the License, or
      11             :     (at your option) any later version.
      12             : 
      13             :     This program is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :     GNU General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU General Public License
      19             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : 
      23             : #include <ctype.h>
      24             : #include "util/util.h"
      25             : #include "util/strtonum.h"
      26             : #include "providers/ldap/sdap_async_private.h"
      27             : 
      28             : #define REPLY_REALLOC_INCREMENT 10
      29             : 
      30             : /* ==LDAP-Memory-Handling================================================= */
      31             : 
      32           0 : static int lmsg_destructor(void *mem)
      33             : {
      34           0 :     ldap_msgfree((LDAPMessage *)mem);
      35           0 :     return 0;
      36             : }
      37             : 
      38           0 : static int sdap_msg_attach(TALLOC_CTX *memctx, LDAPMessage *msg)
      39             : {
      40             :     void *h;
      41             : 
      42           0 :     if (!msg) return EINVAL;
      43             : 
      44           0 :     h = sss_mem_attach(memctx, msg, lmsg_destructor);
      45           0 :     if (!h) return ENOMEM;
      46             : 
      47           0 :     return EOK;
      48             : }
      49             : 
      50             : /* ==sdap-hanlde-utility-functions======================================== */
      51             : 
      52             : static inline void sdap_handle_release(struct sdap_handle *sh);
      53             : static int sdap_handle_destructor(void *mem);
      54             : 
      55           0 : struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx)
      56             : {
      57             :     struct sdap_handle *sh;
      58             : 
      59           0 :     sh = talloc_zero(memctx, struct sdap_handle);
      60           0 :     if (!sh) return NULL;
      61             : 
      62           0 :     talloc_set_destructor((TALLOC_CTX *)sh, sdap_handle_destructor);
      63             : 
      64           0 :     return sh;
      65             : }
      66             : 
      67           0 : static int sdap_handle_destructor(void *mem)
      68             : {
      69           0 :     struct sdap_handle *sh = talloc_get_type(mem, struct sdap_handle);
      70             : 
      71             :     /* if the structure is currently locked, then mark it to be released
      72             :      * and prevent talloc from freeing the memory */
      73           0 :     if (sh->destructor_lock) {
      74           0 :         sh->release_memory = true;
      75           0 :         return -1;
      76             :     }
      77             : 
      78           0 :     sdap_handle_release(sh);
      79           0 :     return 0;
      80             : }
      81             : 
      82           0 : static void sdap_handle_release(struct sdap_handle *sh)
      83             : {
      84             :     struct sdap_op *op;
      85             : 
      86           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
      87             :           "Trace: sh[%p], connected[%d], ops[%p], ldap[%p], "
      88             :               "destructor_lock[%d], release_memory[%d]\n",
      89             :               sh, (int)sh->connected, sh->ops, sh->ldap,
      90             :               (int)sh->destructor_lock, (int)sh->release_memory);
      91             : 
      92           0 :     if (sh->destructor_lock) return;
      93           0 :     sh->destructor_lock = true;
      94             : 
      95             :     /* make sure nobody tries to reuse this connection from now on */
      96           0 :     sh->connected = false;
      97             : 
      98           0 :     remove_ldap_connection_callbacks(sh);
      99             : 
     100           0 :     while (sh->ops) {
     101           0 :         op = sh->ops;
     102           0 :         op->callback(op, NULL, EIO, op->data);
     103             :         /* calling the callback may result in freeing the op */
     104             :         /* check if it is still the same or avoid freeing */
     105           0 :         if (op == sh->ops) talloc_free(op);
     106             :     }
     107             : 
     108           0 :     if (sh->ldap) {
     109           0 :         ldap_unbind_ext(sh->ldap, NULL, NULL);
     110           0 :         sh->ldap = NULL;
     111             :     }
     112             : 
     113             :     /* ok, we have done the job, unlock now */
     114           0 :     sh->destructor_lock = false;
     115             : 
     116             :     /* finally if a destructor was ever called, free sh before
     117             :      * exiting */
     118           0 :     if (sh->release_memory) {
     119             :         /* neutralize the destructor as we already handled
     120             :          * all was needed to be released */
     121           0 :         talloc_set_destructor((TALLOC_CTX *)sh, NULL);
     122           0 :         talloc_free(sh);
     123             :     }
     124             : }
     125             : 
     126             : /* ==Parse-Results-And-Handle-Disconnections============================== */
     127             : static void sdap_process_message(struct tevent_context *ev,
     128             :                                  struct sdap_handle *sh, LDAPMessage *msg);
     129             : static void sdap_process_result(struct tevent_context *ev, void *pvt);
     130             : static void sdap_process_next_reply(struct tevent_context *ev,
     131             :                                     struct tevent_timer *te,
     132             :                                     struct timeval tv, void *pvt);
     133             : 
     134           0 : void sdap_ldap_result(struct tevent_context *ev, struct tevent_fd *fde,
     135             :                       uint16_t flags, void *pvt)
     136             : {
     137           0 :     sdap_process_result(ev, pvt);
     138           0 : }
     139             : 
     140           0 : static void sdap_ldap_next_result(struct tevent_context *ev,
     141             :                                   struct tevent_timer *te,
     142             :                                   struct timeval tv, void *pvt)
     143             : {
     144           0 :     sdap_process_result(ev, pvt);
     145           0 : }
     146             : 
     147           0 : static void sdap_process_result(struct tevent_context *ev, void *pvt)
     148             : {
     149           0 :     struct sdap_handle *sh = talloc_get_type(pvt, struct sdap_handle);
     150           0 :     struct timeval no_timeout = {0, 0};
     151             :     struct tevent_timer *te;
     152             :     LDAPMessage *msg;
     153             :     int ret;
     154             : 
     155           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     156             :           "Trace: sh[%p], connected[%d], ops[%p], ldap[%p]\n",
     157             :               sh, (int)sh->connected, sh->ops, sh->ldap);
     158             : 
     159           0 :     if (!sh->connected || !sh->ldap) {
     160           0 :         DEBUG(SSSDBG_OP_FAILURE, "ERROR: LDAP connection is not connected!\n");
     161           0 :         sdap_handle_release(sh);
     162           0 :         return;
     163             :     }
     164             : 
     165           0 :     ret = ldap_result(sh->ldap, LDAP_RES_ANY, 0, &no_timeout, &msg);
     166           0 :     if (ret == 0) {
     167             :         /* this almost always means we have reached the end of
     168             :          * the list of received messages */
     169           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Trace: ldap_result found nothing!\n");
     170           0 :         return;
     171             :     }
     172             : 
     173           0 :     if (ret == -1) {
     174           0 :         ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &ret);
     175           0 :         DEBUG(SSSDBG_OP_FAILURE,
     176             :               "ldap_result error: [%s]\n", ldap_err2string(ret));
     177           0 :         sdap_handle_release(sh);
     178           0 :         return;
     179             :     }
     180             : 
     181             :     /* We don't know if this will be the last result.
     182             :      *
     183             :      * important: we must do this before actually processing the message
     184             :      * because the message processing might even free the sdap_handler
     185             :      * so it must be the last operation.
     186             :      * FIXME: use tevent_immediate/tevent_queues, when avilable */
     187           0 :     memset(&no_timeout, 0, sizeof(struct timeval));
     188             : 
     189           0 :     te = tevent_add_timer(ev, sh, no_timeout, sdap_ldap_next_result, sh);
     190           0 :     if (!te) {
     191           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     192             :               "Failed to add critical timer to fetch next result!\n");
     193             :     }
     194             : 
     195             :     /* now process this message */
     196           0 :     sdap_process_message(ev, sh, msg);
     197             : }
     198             : 
     199           0 : static const char *sdap_ldap_result_str(int msgtype)
     200             : {
     201           0 :     switch (msgtype) {
     202             :     case LDAP_RES_BIND:
     203           0 :         return "LDAP_RES_BIND";
     204             : 
     205             :     case LDAP_RES_SEARCH_ENTRY:
     206           0 :         return "LDAP_RES_SEARCH_ENTRY";
     207             : 
     208             :     case LDAP_RES_SEARCH_REFERENCE:
     209           0 :         return "LDAP_RES_SEARCH_REFERENCE";
     210             : 
     211             :     case LDAP_RES_SEARCH_RESULT:
     212           0 :         return "LDAP_RES_SEARCH_RESULT";
     213             : 
     214             :     case LDAP_RES_MODIFY:
     215           0 :         return "LDAP_RES_MODIFY";
     216             : 
     217             :     case LDAP_RES_ADD:
     218           0 :         return "LDAP_RES_ADD";
     219             : 
     220             :     case LDAP_RES_DELETE:
     221           0 :         return "LDAP_RES_DELETE";
     222             : 
     223             :     case LDAP_RES_MODDN:
     224             :     /* These are the same result
     225             :     case LDAP_RES_MODRDN:
     226             :     case LDAP_RES_RENAME:
     227             :     */
     228           0 :         return "LDAP_RES_RENAME";
     229             : 
     230             :     case LDAP_RES_COMPARE:
     231           0 :         return "LDAP_RES_COMPARE";
     232             : 
     233             :     case LDAP_RES_EXTENDED:
     234           0 :         return "LDAP_RES_EXTENDED";
     235             : 
     236             :     case LDAP_RES_INTERMEDIATE:
     237           0 :         return "LDAP_RES_INTERMEDIATE";
     238             : 
     239             :     case LDAP_RES_ANY:
     240           0 :         return "LDAP_RES_ANY";
     241             : 
     242             :     case LDAP_RES_UNSOLICITED:
     243           0 :         return "LDAP_RES_UNSOLICITED";
     244             : 
     245             :     default:
     246             :         /* Unmatched, fall through */
     247           0 :         break;
     248             :     }
     249             : 
     250             :     /* Unknown result type */
     251           0 :     return "Unknown result type!";
     252             : }
     253             : 
     254             : /* process a messgae calling the right operation callback.
     255             :  * msg is completely taken care of (including freeeing it)
     256             :  * NOTE: this function may even end up freeing the sdap_handle
     257             :  * so sdap_hanbdle must not be used after this function is called
     258             :  */
     259           0 : static void sdap_process_message(struct tevent_context *ev,
     260             :                                  struct sdap_handle *sh, LDAPMessage *msg)
     261             : {
     262             :     struct sdap_msg *reply;
     263             :     struct sdap_op *op;
     264             :     int msgid;
     265             :     int msgtype;
     266             :     int ret;
     267             : 
     268           0 :     msgid = ldap_msgid(msg);
     269           0 :     if (msgid == -1) {
     270           0 :         DEBUG(SSSDBG_OP_FAILURE, "can't fire callback, message id invalid!\n");
     271           0 :         ldap_msgfree(msg);
     272           0 :         return;
     273             :     }
     274             : 
     275           0 :     msgtype = ldap_msgtype(msg);
     276             : 
     277           0 :     for (op = sh->ops; op; op = op->next) {
     278           0 :         if (op->msgid == msgid) break;
     279             :     }
     280             : 
     281           0 :     if (op == NULL) {
     282           0 :         DEBUG(SSSDBG_OP_FAILURE,
     283             :               "Unmatched msgid, discarding message (type: %0x)\n",
     284             :                   msgtype);
     285           0 :         ldap_msgfree(msg);
     286           0 :         return;
     287             :     }
     288             : 
     289             :     /* shouldn't happen */
     290           0 :     if (op->done) {
     291           0 :         DEBUG(SSSDBG_OP_FAILURE,
     292             :               "Operation [%p] already handled (type: %0x)\n", op, msgtype);
     293           0 :         ldap_msgfree(msg);
     294           0 :         return;
     295             :     }
     296             : 
     297           0 :     DEBUG(SSSDBG_TRACE_ALL,
     298             :           "Message type: [%s]\n", sdap_ldap_result_str(msgtype));
     299             : 
     300           0 :     switch (msgtype) {
     301             :     case LDAP_RES_SEARCH_ENTRY:
     302             :     case LDAP_RES_SEARCH_REFERENCE:
     303             :         /* go and process entry */
     304           0 :         break;
     305             : 
     306             :     case LDAP_RES_BIND:
     307             :     case LDAP_RES_SEARCH_RESULT:
     308             :     case LDAP_RES_MODIFY:
     309             :     case LDAP_RES_ADD:
     310             :     case LDAP_RES_DELETE:
     311             :     case LDAP_RES_MODDN:
     312             :     case LDAP_RES_COMPARE:
     313             :     case LDAP_RES_EXTENDED:
     314             :     case LDAP_RES_INTERMEDIATE:
     315             :         /* no more results expected with this msgid */
     316           0 :         op->done = true;
     317           0 :         break;
     318             : 
     319             :     default:
     320             :         /* unkwon msg type ?? */
     321           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     322             :               "Couldn't figure out the msg type! [%0x]\n", msgtype);
     323           0 :         ldap_msgfree(msg);
     324           0 :         return;
     325             :     }
     326             : 
     327           0 :     reply = talloc_zero(op, struct sdap_msg);
     328           0 :     if (!reply) {
     329           0 :         ldap_msgfree(msg);
     330           0 :         ret = ENOMEM;
     331             :     } else {
     332           0 :         reply->msg = msg;
     333           0 :         ret = sdap_msg_attach(reply, msg);
     334           0 :         if (ret != EOK) {
     335           0 :             ldap_msgfree(msg);
     336           0 :             talloc_zfree(reply);
     337             :         }
     338             :     }
     339             : 
     340           0 :     if (op->list) {
     341             :         /* list exist, queue it */
     342             : 
     343           0 :         op->last->next = reply;
     344           0 :         op->last = reply;
     345             : 
     346             :     } else {
     347             :         /* create list, then call callback */
     348           0 :         op->list = op->last = reply;
     349             : 
     350             :         /* must be the last operation as it may end up freeing all memory
     351             :          * including all ops handlers */
     352           0 :         op->callback(op, reply, ret, op->data);
     353             :     }
     354             : }
     355             : 
     356           0 : static void sdap_unlock_next_reply(struct sdap_op *op)
     357             : {
     358             :     struct timeval tv;
     359             :     struct tevent_timer *te;
     360             :     struct sdap_msg *next_reply;
     361             : 
     362           0 :     if (op->list) {
     363           0 :         next_reply = op->list->next;
     364             :         /* get rid of the previous reply, it has been processed already */
     365           0 :         talloc_zfree(op->list);
     366           0 :         op->list = next_reply;
     367             :     }
     368             : 
     369             :     /* if there are still replies to parse, queue a new operation */
     370           0 :     if (op->list) {
     371             :         /* use a very small timeout, so that fd operations have a chance to be
     372             :          * served while processing a long reply */
     373           0 :         tv = tevent_timeval_current();
     374             : 
     375             :         /* wait 5 microsecond */
     376           0 :         tv.tv_usec += 5;
     377           0 :         tv.tv_sec += tv.tv_usec / 1000000;
     378           0 :         tv.tv_usec = tv.tv_usec % 1000000;
     379             : 
     380           0 :         te = tevent_add_timer(op->ev, op, tv,
     381             :                               sdap_process_next_reply, op);
     382           0 :         if (!te) {
     383           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     384             :                   "Failed to add critical timer for next reply!\n");
     385           0 :             op->callback(op, NULL, EFAULT, op->data);
     386             :         }
     387             :     }
     388           0 : }
     389             : 
     390           0 : static void sdap_process_next_reply(struct tevent_context *ev,
     391             :                                     struct tevent_timer *te,
     392             :                                     struct timeval tv, void *pvt)
     393             : {
     394           0 :     struct sdap_op *op = talloc_get_type(pvt, struct sdap_op);
     395             : 
     396           0 :     op->callback(op, op->list, EOK, op->data);
     397           0 : }
     398             : 
     399             : /* ==LDAP-Operations-Helpers============================================== */
     400             : 
     401           0 : static int sdap_op_destructor(void *mem)
     402             : {
     403           0 :     struct sdap_op *op = (struct sdap_op *)mem;
     404             : 
     405           0 :     DLIST_REMOVE(op->sh->ops, op);
     406             : 
     407           0 :     if (op->done) {
     408           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Operation %d finished\n", op->msgid);
     409           0 :         return 0;
     410             :     }
     411             : 
     412             :     /* we don't check the result here, if a message was really abandoned,
     413             :      * hopefully the server will get an abandon.
     414             :      * If the operation was already fully completed, this is going to be
     415             :      * just a noop */
     416           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Abandoning operation %d\n", op->msgid);
     417           0 :     ldap_abandon_ext(op->sh->ldap, op->msgid, NULL, NULL);
     418             : 
     419           0 :     return 0;
     420             : }
     421             : 
     422           0 : static void sdap_op_timeout(struct tevent_req *req)
     423             : {
     424           0 :     struct sdap_op *op = tevent_req_callback_data(req, struct sdap_op);
     425             : 
     426             :     /* should never happen, but just in case */
     427           0 :     if (op->done) {
     428           0 :         DEBUG(SSSDBG_OP_FAILURE, "Timeout happened after op was finished !?\n");
     429           0 :         return;
     430             :     }
     431             : 
     432             :     /* signal the caller that we have a timeout */
     433           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Issuing timeout for %d\n", op->msgid);
     434           0 :     op->callback(op, NULL, ETIMEDOUT, op->data);
     435             : }
     436             : 
     437           0 : int sdap_op_add(TALLOC_CTX *memctx, struct tevent_context *ev,
     438             :                 struct sdap_handle *sh, int msgid,
     439             :                 sdap_op_callback_t *callback, void *data,
     440             :                 int timeout, struct sdap_op **_op)
     441             : {
     442             :     struct sdap_op *op;
     443             : 
     444           0 :     op = talloc_zero(memctx, struct sdap_op);
     445           0 :     if (!op) return ENOMEM;
     446             : 
     447           0 :     op->sh = sh;
     448           0 :     op->msgid = msgid;
     449           0 :     op->callback = callback;
     450           0 :     op->data = data;
     451           0 :     op->ev = ev;
     452             : 
     453           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     454             :           "New operation %d timeout %d\n", op->msgid, timeout);
     455             : 
     456             :     /* check if we need to set a timeout */
     457           0 :     if (timeout) {
     458             :         struct tevent_req *req;
     459             :         struct timeval tv;
     460             : 
     461           0 :         tv = tevent_timeval_current();
     462           0 :         tv = tevent_timeval_add(&tv, timeout, 0);
     463             : 
     464             :         /* allocate on op, so when it get freed the timeout is removed */
     465           0 :         req = tevent_wakeup_send(op, ev, tv);
     466           0 :         if (!req) {
     467           0 :             talloc_zfree(op);
     468           0 :             return ENOMEM;
     469             :         }
     470           0 :         tevent_req_set_callback(req, sdap_op_timeout, op);
     471             :     }
     472             : 
     473           0 :     DLIST_ADD(sh->ops, op);
     474             : 
     475           0 :     talloc_set_destructor((TALLOC_CTX *)op, sdap_op_destructor);
     476             : 
     477           0 :     *_op = op;
     478           0 :     return EOK;
     479             : }
     480             : 
     481             : /* ==Modify-Password====================================================== */
     482             : 
     483             : struct sdap_exop_modify_passwd_state {
     484             :     struct sdap_handle *sh;
     485             : 
     486             :     struct sdap_op *op;
     487             : 
     488             :     char *user_error_message;
     489             : };
     490             : 
     491             : static void sdap_exop_modify_passwd_done(struct sdap_op *op,
     492             :                                          struct sdap_msg *reply,
     493             :                                          int error, void *pvt);
     494             : 
     495           0 : struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx,
     496             :                                            struct tevent_context *ev,
     497             :                                            struct sdap_handle *sh,
     498             :                                            char *user_dn,
     499             :                                            const char *password,
     500             :                                            const char *new_password,
     501             :                                            int timeout)
     502             : {
     503           0 :     struct tevent_req *req = NULL;
     504             :     struct sdap_exop_modify_passwd_state *state;
     505             :     int ret;
     506           0 :     BerElement *ber = NULL;
     507           0 :     struct berval *bv = NULL;
     508             :     int msgid;
     509           0 :     LDAPControl **request_controls = NULL;
     510           0 :     LDAPControl *ctrls[2] = { NULL, NULL };
     511             : 
     512           0 :     req = tevent_req_create(memctx, &state,
     513             :                             struct sdap_exop_modify_passwd_state);
     514           0 :     if (!req) return NULL;
     515             : 
     516           0 :     state->sh = sh;
     517           0 :     state->user_error_message = NULL;
     518             : 
     519           0 :     ber = ber_alloc_t( LBER_USE_DER );
     520           0 :     if (ber == NULL) {
     521           0 :         DEBUG(SSSDBG_TRACE_LIBS, "ber_alloc_t failed.\n");
     522           0 :         talloc_zfree(req);
     523           0 :         return NULL;
     524             :     }
     525             : 
     526           0 :     ret = ber_printf( ber, "{tststs}", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
     527             :                      user_dn,
     528             :                      LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, password,
     529             :                      LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, new_password);
     530           0 :     if (ret == -1) {
     531           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "ber_printf failed.\n");
     532           0 :         ber_free(ber, 1);
     533           0 :         talloc_zfree(req);
     534           0 :         return NULL;
     535             :     }
     536             : 
     537           0 :     ret = ber_flatten(ber, &bv);
     538           0 :     ber_free(ber, 1);
     539           0 :     if (ret == -1) {
     540           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "ber_flatten failed.\n");
     541           0 :         talloc_zfree(req);
     542           0 :         return NULL;
     543             :     }
     544             : 
     545           0 :     ret = sdap_control_create(state->sh, LDAP_CONTROL_PASSWORDPOLICYREQUEST,
     546             :                               0, NULL, 0, &ctrls[0]);
     547           0 :     if (ret != LDAP_SUCCESS && ret != LDAP_NOT_SUPPORTED) {
     548           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sdap_control_create failed to create "
     549             :                   "Password Policy control.\n");
     550           0 :         ret = ERR_INTERNAL;
     551           0 :         goto fail;
     552             :     }
     553           0 :     request_controls = ctrls;
     554             : 
     555           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Executing extended operation\n");
     556             : 
     557           0 :     ret = ldap_extended_operation(state->sh->ldap, LDAP_EXOP_MODIFY_PASSWD,
     558             :                                   bv, request_controls, NULL, &msgid);
     559           0 :     ber_bvfree(bv);
     560           0 :     if (ctrls[0]) ldap_control_free(ctrls[0]);
     561           0 :     if (ret == -1 || msgid == -1) {
     562           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "ldap_extended_operation failed\n");
     563           0 :         ret = ERR_NETWORK_IO;
     564           0 :         goto fail;
     565             :     }
     566           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     567             :           "ldap_extended_operation sent, msgid = %d\n", msgid);
     568             : 
     569           0 :     ret = sdap_op_add(state, ev, state->sh, msgid,
     570           0 :                       sdap_exop_modify_passwd_done, req, timeout, &state->op);
     571           0 :     if (ret) {
     572           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set up operation!\n");
     573           0 :         ret = ERR_INTERNAL;
     574           0 :         goto fail;
     575             :     }
     576             : 
     577           0 :     return req;
     578             : 
     579             : fail:
     580           0 :     tevent_req_error(req, ret);
     581           0 :     tevent_req_post(req, ev);
     582           0 :     return req;
     583             : }
     584             : 
     585           0 : static void sdap_exop_modify_passwd_done(struct sdap_op *op,
     586             :                                          struct sdap_msg *reply,
     587             :                                          int error, void *pvt)
     588             : {
     589           0 :     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     590           0 :     struct sdap_exop_modify_passwd_state *state = tevent_req_data(req,
     591             :                                          struct sdap_exop_modify_passwd_state);
     592           0 :     char *errmsg = NULL;
     593             :     int ret;
     594           0 :     LDAPControl **response_controls = NULL;
     595             :     int c;
     596             :     ber_int_t pp_grace;
     597             :     ber_int_t pp_expire;
     598             :     LDAPPasswordPolicyError pp_error;
     599             :     int result;
     600             : 
     601           0 :     if (error) {
     602           0 :         tevent_req_error(req, error);
     603           0 :         return;
     604             :     }
     605             : 
     606           0 :     ret = ldap_parse_result(state->sh->ldap, reply->msg,
     607             :                             &result, NULL, &errmsg, NULL,
     608             :                             &response_controls, 0);
     609           0 :     if (ret != LDAP_SUCCESS) {
     610           0 :         DEBUG(SSSDBG_OP_FAILURE,
     611             :               "ldap_parse_result failed (%d)\n", state->op->msgid);
     612           0 :         ret = ERR_INTERNAL;
     613           0 :         goto done;
     614             :     }
     615             : 
     616           0 :     if (response_controls == NULL) {
     617           0 :         DEBUG(SSSDBG_FUNC_DATA, "Server returned no controls.\n");
     618             :     } else {
     619           0 :         for (c = 0; response_controls[c] != NULL; c++) {
     620           0 :             DEBUG(SSSDBG_TRACE_ALL, "Server returned control [%s].\n",
     621             :                       response_controls[c]->ldctl_oid);
     622           0 :             if (strcmp(response_controls[c]->ldctl_oid,
     623             :                        LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) {
     624           0 :                 ret = ldap_parse_passwordpolicy_control(state->sh->ldap,
     625           0 :                                                         response_controls[c],
     626             :                                                         &pp_expire, &pp_grace,
     627             :                                                         &pp_error);
     628           0 :                 if (ret != LDAP_SUCCESS) {
     629           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
     630             :                           "ldap_parse_passwordpolicy_control failed.\n");
     631           0 :                     ret = ERR_NETWORK_IO;
     632           0 :                     goto done;
     633             :                 }
     634             : 
     635           0 :                 DEBUG(SSSDBG_TRACE_LIBS,
     636             :                       "Password Policy Response: expire [%d] grace [%d] "
     637             :                           "error [%s].\n", pp_expire, pp_grace,
     638             :                           ldap_passwordpolicy_err2txt(pp_error));
     639             :             }
     640             :         }
     641             :     }
     642             : 
     643           0 :     DEBUG(SSSDBG_MINOR_FAILURE, "ldap_extended_operation result: %s(%d), %s\n",
     644             :             sss_ldap_err2string(result), result, errmsg);
     645             : 
     646           0 :     switch (result) {
     647             :     case LDAP_SUCCESS:
     648           0 :         ret = EOK;
     649           0 :         break;
     650             :     case LDAP_CONSTRAINT_VIOLATION:
     651           0 :         if (errmsg && strlen(errmsg) != 0) {
     652           0 :             state->user_error_message = talloc_strdup(state, errmsg);
     653             :         } else {
     654           0 :             state->user_error_message = talloc_strdup(state,
     655             :                 "Please make sure the password meets the "
     656             :                 "complexity constraints.");
     657             :         }
     658             : 
     659           0 :         if (state->user_error_message == NULL) {
     660           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed\n");
     661           0 :             ret = ENOMEM;
     662           0 :             goto done;
     663             :         }
     664             : 
     665           0 :         ret = ERR_CHPASS_DENIED;
     666           0 :         break;
     667             :     default:
     668           0 :         if (errmsg) {
     669           0 :             state->user_error_message = talloc_strdup(state, errmsg);
     670           0 :             if (state->user_error_message == NULL) {
     671           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
     672           0 :                 ret = ENOMEM;
     673           0 :                 goto done;
     674             :             }
     675             :         }
     676           0 :         ret = ERR_NETWORK_IO;
     677           0 :         break;
     678             :     }
     679             : 
     680             : done:
     681           0 :     ldap_controls_free(response_controls);
     682           0 :     ldap_memfree(errmsg);
     683             : 
     684           0 :     if (ret == EOK) {
     685           0 :         tevent_req_done(req);
     686             :     } else {
     687           0 :         tevent_req_error(req, ret);
     688             :     }
     689             : }
     690             : 
     691           0 : errno_t sdap_exop_modify_passwd_recv(struct tevent_req *req,
     692             :                                      TALLOC_CTX * mem_ctx,
     693             :                                      char **user_error_message)
     694             : {
     695           0 :     struct sdap_exop_modify_passwd_state *state = tevent_req_data(req,
     696             :                                          struct sdap_exop_modify_passwd_state);
     697             : 
     698           0 :     *user_error_message = talloc_steal(mem_ctx, state->user_error_message);
     699             : 
     700           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     701             : 
     702           0 :     return EOK;
     703             : }
     704             : 
     705             : /* ==Update-passwordLastChanged-attribute====================== */
     706             : struct update_last_changed_state {
     707             :     struct tevent_context *ev;
     708             :     struct sdap_handle *sh;
     709             :     struct sdap_op *op;
     710             : 
     711             :     const char *dn;
     712             :     LDAPMod **mods;
     713             : };
     714             : 
     715             : static void sdap_modify_shadow_lastchange_done(struct sdap_op *op,
     716             :                                                struct sdap_msg *reply,
     717             :                                                int error, void *pvt);
     718             : 
     719             : struct tevent_req *
     720           0 : sdap_modify_shadow_lastchange_send(TALLOC_CTX *mem_ctx,
     721             :                                    struct tevent_context *ev,
     722             :                                    struct sdap_handle *sh,
     723             :                                    const char *dn,
     724             :                                    char *lastchanged_name)
     725             : {
     726             :     struct tevent_req *req;
     727             :     struct update_last_changed_state *state;
     728             :     char **values;
     729             :     errno_t ret;
     730             :     int msgid;
     731             : 
     732           0 :     req = tevent_req_create(mem_ctx, &state, struct update_last_changed_state);
     733           0 :     if (req == NULL) {
     734           0 :         return NULL;
     735             :     }
     736             : 
     737           0 :     state->ev = ev;
     738           0 :     state->sh = sh;
     739           0 :     state->dn = dn;
     740           0 :     state->mods = talloc_zero_array(state, LDAPMod *, 2);
     741           0 :     if (state->mods == NULL) {
     742           0 :         ret = ENOMEM;
     743           0 :         goto done;
     744             :     }
     745           0 :     state->mods[0] = talloc_zero(state->mods, LDAPMod);
     746           0 :     state->mods[1] = talloc_zero(state->mods, LDAPMod);
     747           0 :     if (!state->mods[0] || !state->mods[1]) {
     748           0 :         ret = ENOMEM;
     749           0 :         goto done;
     750             :     }
     751           0 :     values = talloc_zero_array(state->mods[0], char *, 2);
     752           0 :     if (values == NULL) {
     753           0 :         ret = ENOMEM;
     754           0 :         goto done;
     755             :     }
     756             :     /* The attribute contains number of days since the epoch */
     757           0 :     values[0] = talloc_asprintf(values, "%ld", (long)time(NULL)/86400);
     758           0 :     if (values[0] == NULL) {
     759           0 :         ret = ENOMEM;
     760           0 :         goto done;
     761             :     }
     762           0 :     state->mods[0]->mod_op = LDAP_MOD_REPLACE;
     763           0 :     state->mods[0]->mod_type = lastchanged_name;
     764           0 :     state->mods[0]->mod_vals.modv_strvals = values;
     765           0 :     state->mods[1] = NULL;
     766             : 
     767           0 :     ret = ldap_modify_ext(state->sh->ldap, state->dn, state->mods,
     768             :             NULL, NULL, &msgid);
     769           0 :     if (ret) {
     770           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to send operation!\n");
     771           0 :         goto done;
     772             :     }
     773             : 
     774           0 :     ret = sdap_op_add(state, state->ev, state->sh, msgid,
     775           0 :             sdap_modify_shadow_lastchange_done, req, 5, &state->op);
     776           0 :     if (ret) {
     777           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set up operation!\n");
     778           0 :         goto done;
     779             :     }
     780             : 
     781             : done:
     782           0 :     if (ret != EOK) {
     783           0 :         tevent_req_error(req, ret);
     784           0 :         tevent_req_post(req, ev);
     785             :     }
     786           0 :     return req;
     787             : }
     788             : 
     789           0 : static void sdap_modify_shadow_lastchange_done(struct sdap_op *op,
     790             :                                                struct sdap_msg *reply,
     791             :                                                int error, void *pvt)
     792             : {
     793           0 :     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     794             :     struct update_last_changed_state *state;
     795           0 :     state = tevent_req_data(req, struct update_last_changed_state);
     796             :     char *errmsg;
     797             :     int result;
     798           0 :     errno_t ret = EOK;
     799             :     int lret;
     800             : 
     801           0 :     if (error) {
     802           0 :         tevent_req_error(req, error);
     803           0 :         return;
     804             :     }
     805             : 
     806           0 :     lret = ldap_parse_result(state->sh->ldap, reply->msg,
     807             :                             &result, NULL, &errmsg, NULL,
     808             :                             NULL, 0);
     809           0 :     if (lret != LDAP_SUCCESS) {
     810           0 :         DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_result failed (%d)\n",
     811             :                                   state->op->msgid);
     812           0 :         ret = EIO;
     813           0 :         goto done;
     814             :     }
     815             : 
     816           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Updating lastPwdChange result: %s(%d), %s\n",
     817             :                               sss_ldap_err2string(result),
     818             :                               result, errmsg);
     819             : 
     820             : done:
     821           0 :     ldap_memfree(errmsg);
     822             : 
     823           0 :     if (ret == EOK) {
     824           0 :         tevent_req_done(req);
     825             :     } else {
     826           0 :         tevent_req_error(req, ret);
     827             :     }
     828             : }
     829             : 
     830           0 : errno_t sdap_modify_shadow_lastchange_recv(struct tevent_req *req)
     831             : {
     832           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     833             : 
     834           0 :     return EOK;
     835             : }
     836             : 
     837             : 
     838             : /* ==Fetch-RootDSE============================================= */
     839             : 
     840             : struct sdap_get_rootdse_state {
     841             :     struct tevent_context *ev;
     842             :     struct sdap_options *opts;
     843             :     struct sdap_handle *sh;
     844             : 
     845             :     struct sysdb_attrs *rootdse;
     846             : };
     847             : 
     848             : static void sdap_get_rootdse_done(struct tevent_req *subreq);
     849             : static void sdap_get_matching_rule_done(struct tevent_req *subreq);
     850             : 
     851           0 : struct tevent_req *sdap_get_rootdse_send(TALLOC_CTX *memctx,
     852             :                                          struct tevent_context *ev,
     853             :                                          struct sdap_options *opts,
     854             :                                          struct sdap_handle *sh)
     855             : {
     856             :     struct tevent_req *req, *subreq;
     857             :     struct sdap_get_rootdse_state *state;
     858           0 :     const char *attrs[] = {
     859             :             "*",
     860             :             "altServer",
     861             :             SDAP_ROOTDSE_ATTR_NAMING_CONTEXTS,
     862             :             "supportedControl",
     863             :             "supportedExtension",
     864             :             "supportedFeatures",
     865             :             "supportedLDAPVersion",
     866             :             "supportedSASLMechanisms",
     867             :             SDAP_ROOTDSE_ATTR_AD_VERSION,
     868             :             SDAP_ROOTDSE_ATTR_DEFAULT_NAMING_CONTEXT,
     869             :             SDAP_IPA_LAST_USN, SDAP_AD_LAST_USN,
     870             :             NULL
     871             :     };
     872             : 
     873           0 :     DEBUG(SSSDBG_TRACE_ALL, "Getting rootdse\n");
     874             : 
     875           0 :     req = tevent_req_create(memctx, &state, struct sdap_get_rootdse_state);
     876           0 :     if (!req) return NULL;
     877             : 
     878           0 :     state->ev = ev;
     879           0 :     state->opts = opts;
     880           0 :     state->sh = sh;
     881           0 :     state->rootdse = NULL;
     882             : 
     883           0 :     subreq = sdap_get_generic_send(state, ev, opts, sh,
     884             :                                    "", LDAP_SCOPE_BASE,
     885             :                                    "(objectclass=*)", attrs, NULL, 0,
     886           0 :                                    dp_opt_get_int(state->opts->basic,
     887             :                                                   SDAP_SEARCH_TIMEOUT),
     888             :                                    false);
     889           0 :     if (!subreq) {
     890           0 :         talloc_zfree(req);
     891           0 :         return NULL;
     892             :     }
     893           0 :     tevent_req_set_callback(subreq, sdap_get_rootdse_done, req);
     894             : 
     895           0 :     return req;
     896             : }
     897             : 
     898             : /* This is not a real attribute, it's just there to avoid
     899             :  * actually pulling real data down, to save bandwidth
     900             :  */
     901             : #define SDAP_MATCHING_RULE_TEST_ATTR "sssmatchingruletest"
     902             : 
     903           0 : static void sdap_get_rootdse_done(struct tevent_req *subreq)
     904             : {
     905           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     906             :                                                       struct tevent_req);
     907           0 :     struct sdap_get_rootdse_state *state = tevent_req_data(req,
     908             :                                              struct sdap_get_rootdse_state);
     909             :     struct sysdb_attrs **results;
     910             :     size_t num_results;
     911             :     int ret;
     912             :     const char *filter;
     913           0 :     const char *attrs[] = { SDAP_MATCHING_RULE_TEST_ATTR, NULL };
     914             : 
     915           0 :     ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
     916           0 :     talloc_zfree(subreq);
     917           0 :     if (ret) {
     918           0 :         tevent_req_error(req, ret);
     919           0 :         return;
     920             :     }
     921             : 
     922           0 :     if (num_results == 0 || !results) {
     923           0 :         DEBUG(SSSDBG_OP_FAILURE, "RootDSE could not be retrieved. "
     924             :                   "Please check that anonymous access to RootDSE is allowed\n"
     925             :               );
     926           0 :         tevent_req_error(req, ENOENT);
     927           0 :         return;
     928             :     }
     929             : 
     930           0 :     if (num_results > 1) {
     931           0 :         DEBUG(SSSDBG_OP_FAILURE,
     932             :               "Multiple replies when searching for RootDSE ??\n");
     933           0 :         tevent_req_error(req, EIO);
     934           0 :         return;
     935             :     }
     936             : 
     937           0 :     state->rootdse = talloc_steal(state, results[0]);
     938           0 :     talloc_zfree(results);
     939             : 
     940           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Got rootdse\n");
     941             : 
     942             :     /* Auto-detect the ldap matching rule if requested */
     943           0 :     if ((!dp_opt_get_bool(state->opts->basic,
     944             :                           SDAP_AD_MATCHING_RULE_INITGROUPS))
     945           0 :             && !dp_opt_get_bool(state->opts->basic,
     946             :                                 SDAP_AD_MATCHING_RULE_GROUPS)) {
     947             :         /* This feature is disabled for both groups
     948             :          * and initgroups. Skip the auto-detection
     949             :          * lookup.
     950             :          */
     951           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
     952             :               "Skipping auto-detection of match rule\n");
     953           0 :         tevent_req_done(req);
     954           0 :         return;
     955             :     }
     956             : 
     957           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     958             :           "Auto-detecting support for match rule\n");
     959             : 
     960             :     /* Create a filter using the matching rule. It need not point
     961             :      * at any valid data. We're only going to be looking for the
     962             :      * error code.
     963             :      */
     964           0 :     filter = "("SDAP_MATCHING_RULE_TEST_ATTR":"
     965             :              SDAP_MATCHING_RULE_IN_CHAIN":=)";
     966             : 
     967             :     /* Perform a trivial query with the matching rule in play.
     968             :      * If it returns success, we know it is available. If it
     969             :      * returns EIO, we know it isn't.
     970             :      */
     971           0 :     subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
     972             :                                    "", LDAP_SCOPE_BASE, filter, attrs, NULL,
     973           0 :                                    0, dp_opt_get_int(state->opts->basic,
     974             :                                                      SDAP_SEARCH_TIMEOUT),
     975             :                                    false);
     976           0 :     if (!subreq) {
     977           0 :         tevent_req_error(req, ENOMEM);
     978           0 :         return;
     979             :     }
     980           0 :     tevent_req_set_callback(subreq, sdap_get_matching_rule_done, req);
     981             : }
     982             : 
     983           0 : static void sdap_get_matching_rule_done(struct tevent_req *subreq)
     984             : {
     985             :     errno_t ret;
     986           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     987             :                                                       struct tevent_req);
     988           0 :     struct sdap_get_rootdse_state *state = tevent_req_data(req,
     989             :                                              struct sdap_get_rootdse_state);
     990             :     size_t num_results;
     991             :     struct sysdb_attrs **results;
     992             : 
     993           0 :     ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
     994           0 :     talloc_zfree(subreq);
     995           0 :     if (ret == EOK) {
     996             :         /* The search succeeded */
     997           0 :         state->opts->support_matching_rule = true;
     998           0 :     } else if (ret == EIO) {
     999             :         /* The search failed. Disable support for
    1000             :          * matching rule lookups.
    1001             :          */
    1002           0 :         state->opts->support_matching_rule = false;
    1003             :     } else {
    1004           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1005             :               "Unexpected error while testing for matching rule support\n");
    1006           0 :         tevent_req_error(req, ret);
    1007           0 :         return;
    1008             :     }
    1009             : 
    1010           0 :     DEBUG(SSSDBG_CONF_SETTINGS,
    1011             :           "LDAP server %s the matching rule extension\n",
    1012             :           state->opts->support_matching_rule
    1013             :               ? "supports"
    1014             :               : "does not support");
    1015             : 
    1016           0 :     tevent_req_done(req);
    1017             : }
    1018             : 
    1019           0 : int sdap_get_rootdse_recv(struct tevent_req *req,
    1020             :                           TALLOC_CTX *memctx,
    1021             :                           struct sysdb_attrs **rootdse)
    1022             : {
    1023           0 :     struct sdap_get_rootdse_state *state = tevent_req_data(req,
    1024             :                                              struct sdap_get_rootdse_state);
    1025             : 
    1026           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1027             : 
    1028           0 :     *rootdse = talloc_steal(memctx, state->rootdse);
    1029             : 
    1030           0 :     return EOK;
    1031             : }
    1032             : 
    1033             : /* ==Helpers for parsing replies============================== */
    1034             : struct sdap_reply {
    1035             :     size_t reply_max;
    1036             :     size_t reply_count;
    1037             :     struct sysdb_attrs **reply;
    1038             : };
    1039             : 
    1040           0 : static errno_t add_to_reply(TALLOC_CTX *mem_ctx,
    1041             :                             struct sdap_reply *sreply,
    1042             :                             struct sysdb_attrs *msg)
    1043             : {
    1044           0 :     if (sreply->reply == NULL || sreply->reply_max == sreply->reply_count) {
    1045           0 :         sreply->reply_max += REPLY_REALLOC_INCREMENT;
    1046           0 :         sreply->reply = talloc_realloc(mem_ctx, sreply->reply,
    1047             :                                        struct sysdb_attrs *,
    1048             :                                        sreply->reply_max);
    1049           0 :         if (sreply->reply == NULL) {
    1050           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_realloc failed.\n");
    1051           0 :             return ENOMEM;
    1052             :         }
    1053             :     }
    1054             : 
    1055           0 :     sreply->reply[sreply->reply_count++] = talloc_steal(sreply->reply, msg);
    1056             : 
    1057           0 :     return EOK;
    1058             : }
    1059             : 
    1060             : struct sdap_deref_reply {
    1061             :     size_t reply_max;
    1062             :     size_t reply_count;
    1063             :     struct sdap_deref_attrs **reply;
    1064             : };
    1065             : 
    1066           0 : static errno_t add_to_deref_reply(TALLOC_CTX *mem_ctx,
    1067             :                                   int num_maps,
    1068             :                                   struct sdap_deref_reply *dreply,
    1069             :                                   struct sdap_deref_attrs **res)
    1070             : {
    1071             :     int i;
    1072             : 
    1073           0 :     if (res == NULL) {
    1074             :         /* Nothing to add, probably ACIs prevented us from dereferencing
    1075             :          * the attribute */
    1076           0 :         return EOK;
    1077             :     }
    1078             : 
    1079           0 :     for (i=0; i < num_maps; i++) {
    1080           0 :         if (res[i]->attrs == NULL) continue; /* Nothing in this map */
    1081             : 
    1082           0 :         if (dreply->reply == NULL ||
    1083           0 :             dreply->reply_max == dreply->reply_count) {
    1084           0 :             dreply->reply_max += REPLY_REALLOC_INCREMENT;
    1085           0 :             dreply->reply = talloc_realloc(mem_ctx, dreply->reply,
    1086             :                                         struct sdap_deref_attrs *,
    1087             :                                         dreply->reply_max);
    1088           0 :             if (dreply->reply == NULL) {
    1089           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "talloc_realloc failed.\n");
    1090           0 :                 return ENOMEM;
    1091             :             }
    1092             :         }
    1093             : 
    1094           0 :         dreply->reply[dreply->reply_count++] =
    1095           0 :             talloc_steal(dreply->reply, res[i]);
    1096             :     }
    1097             : 
    1098           0 :     return EOK;
    1099             : }
    1100             : 
    1101           0 : static void sdap_print_server(struct sdap_handle *sh)
    1102             : {
    1103             :     int ret;
    1104             :     int fd;
    1105             :     struct sockaddr_storage ss;
    1106           0 :     socklen_t ss_len = sizeof(ss);
    1107             :     char ip[NI_MAXHOST];
    1108             : 
    1109           0 :     if (!DEBUG_IS_SET(SSSDBG_TRACE_INTERNAL)) {
    1110           0 :         return;
    1111             :     }
    1112             : 
    1113           0 :     ret = get_fd_from_ldap(sh->ldap, &fd);
    1114           0 :     if (ret != EOK) {
    1115           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "cannot get sdap fd\n");
    1116           0 :         return;
    1117             :     }
    1118             : 
    1119           0 :     ret = getpeername(fd, (struct sockaddr *) &ss, &ss_len);
    1120           0 :     if (ret == -1) {
    1121           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "getsockname failed\n");
    1122           0 :         return;
    1123             :     }
    1124             : 
    1125           0 :     ret = getnameinfo((struct sockaddr *) &ss, ss_len,
    1126             :                       ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
    1127           0 :     if (ret != 0) {
    1128           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "getnameinfo failed\n");
    1129           0 :         return;
    1130             :     }
    1131             : 
    1132           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Searching %s\n", ip);
    1133             : }
    1134             : 
    1135             : /* ==Generic Search exposing all options======================= */
    1136             : typedef errno_t (*sdap_parse_cb)(struct sdap_handle *sh,
    1137             :                                  struct sdap_msg *msg,
    1138             :                                  void *pvt);
    1139             : 
    1140             : struct sdap_get_generic_ext_state {
    1141             :     struct tevent_context *ev;
    1142             :     struct sdap_options *opts;
    1143             :     struct sdap_handle *sh;
    1144             :     const char *search_base;
    1145             :     int scope;
    1146             :     const char *filter;
    1147             :     const char **attrs;
    1148             :     int timeout;
    1149             :     int attrsonly;
    1150             :     int sizelimit;
    1151             : 
    1152             :     struct sdap_op *op;
    1153             : 
    1154             :     struct berval cookie;
    1155             : 
    1156             :     LDAPControl **serverctrls;
    1157             :     int nserverctrls;
    1158             :     LDAPControl **clientctrls;
    1159             : 
    1160             :     size_t ref_count;
    1161             :     char **refs;
    1162             : 
    1163             :     sdap_parse_cb parse_cb;
    1164             :     void *cb_data;
    1165             : 
    1166             :     bool allow_paging;
    1167             : };
    1168             : 
    1169             : static errno_t sdap_get_generic_ext_step(struct tevent_req *req);
    1170             : 
    1171             : static void sdap_get_generic_op_finished(struct sdap_op *op,
    1172             :                                          struct sdap_msg *reply,
    1173             :                                          int error, void *pvt);
    1174             : 
    1175             : static struct tevent_req *
    1176           0 : sdap_get_generic_ext_send(TALLOC_CTX *memctx,
    1177             :                           struct tevent_context *ev,
    1178             :                           struct sdap_options *opts,
    1179             :                           struct sdap_handle *sh,
    1180             :                           const char *search_base,
    1181             :                           int scope,
    1182             :                           const char *filter,
    1183             :                           const char **attrs,
    1184             :                           int attrsonly,
    1185             :                           LDAPControl **serverctrls,
    1186             :                           LDAPControl **clientctrls,
    1187             :                           int sizelimit,
    1188             :                           int timeout,
    1189             :                           bool allow_paging,
    1190             :                           sdap_parse_cb parse_cb,
    1191             :                           void *cb_data)
    1192             : {
    1193             :     errno_t ret;
    1194             :     struct sdap_get_generic_ext_state *state;
    1195             :     struct tevent_req *req;
    1196             :     int i;
    1197             :     LDAPControl *control;
    1198             : 
    1199           0 :     req = tevent_req_create(memctx, &state, struct sdap_get_generic_ext_state);
    1200           0 :     if (!req) return NULL;
    1201             : 
    1202           0 :     state->ev = ev;
    1203           0 :     state->opts = opts;
    1204           0 :     state->sh = sh;
    1205           0 :     state->search_base = search_base;
    1206           0 :     state->scope = scope;
    1207           0 :     state->filter = filter;
    1208           0 :     state->attrs = attrs;
    1209           0 :     state->attrsonly = attrsonly;
    1210           0 :     state->op = NULL;
    1211           0 :     state->sizelimit = sizelimit;
    1212           0 :     state->timeout = timeout;
    1213           0 :     state->cookie.bv_len = 0;
    1214           0 :     state->cookie.bv_val = NULL;
    1215           0 :     state->parse_cb = parse_cb;
    1216           0 :     state->cb_data = cb_data;
    1217           0 :     state->clientctrls = clientctrls;
    1218             : 
    1219           0 :     if (state->sh == NULL || state->sh->ldap == NULL) {
    1220           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1221             :               "Trying LDAP search while not connected.\n");
    1222           0 :         tevent_req_error(req, EIO);
    1223           0 :         tevent_req_post(req, ev);
    1224           0 :         return req;
    1225             :     }
    1226             : 
    1227           0 :     sdap_print_server(sh);
    1228             : 
    1229             :     /* Be extra careful and never allow paging for BASE searches,
    1230             :      * even if requested.
    1231             :      */
    1232           0 :     if (scope == LDAP_SCOPE_BASE) {
    1233           0 :         state->allow_paging = false;
    1234             :     } else {
    1235           0 :         state->allow_paging = allow_paging;
    1236             :     }
    1237             : 
    1238             :     /* Also check for deref/asq requests and force
    1239             :      * paging on for those requests
    1240             :      */
    1241             :     /* X-DEREF */
    1242           0 :     control = ldap_control_find(LDAP_CONTROL_X_DEREF,
    1243             :                                 serverctrls,
    1244             :                                 NULL);
    1245           0 :     if (control) {
    1246           0 :         state->allow_paging = true;
    1247             :     }
    1248             : 
    1249             :     /* ASQ */
    1250           0 :     control = ldap_control_find(LDAP_SERVER_ASQ_OID,
    1251             :                                 serverctrls,
    1252             :                                 NULL);
    1253           0 :     if (control) {
    1254           0 :         state->allow_paging = true;
    1255             :     }
    1256             : 
    1257           0 :     for (state->nserverctrls=0;
    1258           0 :          serverctrls && serverctrls[state->nserverctrls];
    1259           0 :          state->nserverctrls++) ;
    1260             : 
    1261             :     /* One extra space for NULL, one for page control */
    1262           0 :     state->serverctrls = talloc_array(state, LDAPControl *,
    1263             :                                       state->nserverctrls+2);
    1264           0 :     if (!state->serverctrls) {
    1265           0 :         tevent_req_error(req, ENOMEM);
    1266           0 :         tevent_req_post(req, ev);
    1267           0 :         return req;
    1268             :     }
    1269             : 
    1270           0 :     for (i=0; i < state->nserverctrls; i++) {
    1271           0 :         state->serverctrls[i] = serverctrls[i];
    1272             :     }
    1273           0 :     state->serverctrls[i] = NULL;
    1274             : 
    1275           0 :     ret = sdap_get_generic_ext_step(req);
    1276           0 :     if (ret != EOK) {
    1277           0 :         tevent_req_error(req, ret);
    1278           0 :         tevent_req_post(req, ev);
    1279           0 :         return req;
    1280             :     }
    1281             : 
    1282           0 :     return req;
    1283             : }
    1284             : 
    1285           0 : static errno_t sdap_get_generic_ext_step(struct tevent_req *req)
    1286             : {
    1287           0 :     struct sdap_get_generic_ext_state *state =
    1288           0 :             tevent_req_data(req, struct sdap_get_generic_ext_state);
    1289             :     char *errmsg;
    1290             :     int lret;
    1291             :     int optret;
    1292             :     errno_t ret;
    1293             :     int msgid;
    1294             :     bool disable_paging;
    1295             : 
    1296           0 :     LDAPControl *page_control = NULL;
    1297             : 
    1298             :     /* Make sure to free any previous operations so
    1299             :      * if we are handling a large number of pages we
    1300             :      * don't waste memory.
    1301             :      */
    1302           0 :     talloc_zfree(state->op);
    1303             : 
    1304           0 :     DEBUG(SSSDBG_TRACE_FUNC,
    1305             :          "calling ldap_search_ext with [%s][%s].\n",
    1306             :           state->filter ? state->filter : "no filter",
    1307             :           state->search_base);
    1308           0 :     if (DEBUG_IS_SET(SSSDBG_TRACE_LIBS)) {
    1309             :         int i;
    1310             : 
    1311           0 :         if (state->attrs) {
    1312           0 :             for (i = 0; state->attrs[i]; i++) {
    1313           0 :                 DEBUG(SSSDBG_TRACE_LIBS,
    1314             :                       "Requesting attrs: [%s]\n", state->attrs[i]);
    1315             :             }
    1316             :         }
    1317             :     }
    1318             : 
    1319           0 :     disable_paging = dp_opt_get_bool(state->opts->basic, SDAP_DISABLE_PAGING);
    1320             : 
    1321           0 :     if (!disable_paging
    1322           0 :             && state->allow_paging
    1323           0 :             && sdap_is_control_supported(state->sh,
    1324             :                                          LDAP_CONTROL_PAGEDRESULTS)) {
    1325           0 :         lret = ldap_create_page_control(state->sh->ldap,
    1326           0 :                                         state->sh->page_size,
    1327           0 :                                         state->cookie.bv_val ?
    1328             :                                             &state->cookie :
    1329             :                                             NULL,
    1330             :                                         false,
    1331             :                                         &page_control);
    1332           0 :         if (lret != LDAP_SUCCESS) {
    1333           0 :             ret = EIO;
    1334           0 :             goto done;
    1335             :         }
    1336           0 :         state->serverctrls[state->nserverctrls] = page_control;
    1337           0 :         state->serverctrls[state->nserverctrls+1] = NULL;
    1338             :     }
    1339             : 
    1340           0 :     lret = ldap_search_ext(state->sh->ldap, state->search_base,
    1341             :                            state->scope, state->filter,
    1342           0 :                            discard_const(state->attrs),
    1343             :                            state->attrsonly, state->serverctrls,
    1344             :                            state->clientctrls, NULL, state->sizelimit, &msgid);
    1345           0 :     ldap_control_free(page_control);
    1346           0 :     state->serverctrls[state->nserverctrls] = NULL;
    1347           0 :     if (lret != LDAP_SUCCESS) {
    1348           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1349             :               "ldap_search_ext failed: %s\n", sss_ldap_err2string(lret));
    1350           0 :         if (lret == LDAP_SERVER_DOWN) {
    1351           0 :             ret = ETIMEDOUT;
    1352           0 :             optret = sss_ldap_get_diagnostic_msg(state, state->sh->ldap,
    1353             :                                                  &errmsg);
    1354           0 :             if (optret == LDAP_SUCCESS) {
    1355           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Connection error: %s\n", errmsg);
    1356           0 :                 sss_log(SSS_LOG_ERR, "LDAP connection error: %s", errmsg);
    1357             :             }
    1358             :             else {
    1359           0 :                 sss_log(SSS_LOG_ERR, "LDAP connection error, %s",
    1360             :                                      sss_ldap_err2string(lret));
    1361             :             }
    1362           0 :         } else if (lret == LDAP_FILTER_ERROR) {
    1363           0 :             ret = ERR_INVALID_FILTER;
    1364             :         } else {
    1365           0 :             ret = EIO;
    1366             :         }
    1367           0 :         goto done;
    1368             :     }
    1369           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "ldap_search_ext called, msgid = %d\n", msgid);
    1370             : 
    1371           0 :     ret = sdap_op_add(state, state->ev, state->sh, msgid,
    1372             :                       sdap_get_generic_op_finished, req,
    1373             :                       state->timeout,
    1374             :                       &state->op);
    1375           0 :     if (ret != EOK) {
    1376           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set up operation!\n");
    1377           0 :         goto done;
    1378             :     }
    1379             : 
    1380             : done:
    1381           0 :     return ret;
    1382             : }
    1383             : 
    1384             : static errno_t
    1385           0 : sdap_get_generic_ext_add_references(struct sdap_get_generic_ext_state *state,
    1386             :                                     char **refs)
    1387             : {
    1388             :     int i;
    1389             : 
    1390           0 :     if (refs == NULL) {
    1391             :         /* Rare, but it's possible that we might get a reference result with
    1392             :          * no references attached.
    1393             :          */
    1394           0 :         return EOK;
    1395             :     }
    1396             : 
    1397           0 :     for (i = 0; refs[i]; i++) {
    1398           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Additional References: %s\n", refs[i]);
    1399             :     }
    1400             : 
    1401             :     /* Extend the size of the ref array */
    1402           0 :     state->refs = talloc_realloc(state, state->refs, char *,
    1403             :                                  state->ref_count + i);
    1404           0 :     if (state->refs == NULL) {
    1405           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1406             :               "talloc_realloc failed extending ref_array.\n");
    1407           0 :         return ENOMEM;
    1408             :     }
    1409             : 
    1410             :     /* Copy in all the references */
    1411           0 :     for (i = 0; refs[i]; i++) {
    1412           0 :         state->refs[state->ref_count + i] =
    1413           0 :                 talloc_strdup(state->refs, refs[i]);
    1414             : 
    1415           0 :         if (state->refs[state->ref_count + i] == NULL) {
    1416           0 :             return ENOMEM;
    1417             :         }
    1418             :     }
    1419             : 
    1420           0 :     state->ref_count += i;
    1421             : 
    1422           0 :     return EOK;
    1423             : }
    1424             : 
    1425           0 : static void sdap_get_generic_op_finished(struct sdap_op *op,
    1426             :                                          struct sdap_msg *reply,
    1427             :                                          int error, void *pvt)
    1428             : {
    1429           0 :     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
    1430           0 :     struct sdap_get_generic_ext_state *state = tevent_req_data(req,
    1431             :                                             struct sdap_get_generic_ext_state);
    1432           0 :     char *errmsg = NULL;
    1433           0 :     char **refs = NULL;
    1434             :     int result;
    1435             :     int ret;
    1436             :     int lret;
    1437             :     ber_int_t total_count;
    1438             :     struct berval cookie;
    1439           0 :     LDAPControl **returned_controls = NULL;
    1440             :     LDAPControl *page_control;
    1441             : 
    1442           0 :     if (error) {
    1443           0 :         tevent_req_error(req, error);
    1444           0 :         return;
    1445             :     }
    1446             : 
    1447           0 :     switch (ldap_msgtype(reply->msg)) {
    1448             :     case LDAP_RES_SEARCH_REFERENCE:
    1449           0 :         ret = ldap_parse_reference(state->sh->ldap, reply->msg,
    1450             :                                    &refs, NULL, 0);
    1451           0 :         if (ret != LDAP_SUCCESS) {
    1452           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1453             :                   "ldap_parse_reference failed (%d)\n", state->op->msgid);
    1454           0 :             tevent_req_error(req, EIO);
    1455           0 :             return;
    1456             :         }
    1457             : 
    1458           0 :         ret = sdap_get_generic_ext_add_references(state, refs);
    1459           0 :         if (ret != EOK) {
    1460           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1461             :                   "sdap_get_generic_ext_add_references failed: %s(%d)",
    1462             :                   sss_strerror(ret), ret);
    1463           0 :             ldap_memvfree((void **)refs);
    1464           0 :             tevent_req_error(req, ret);
    1465           0 :             return;
    1466             :         }
    1467             : 
    1468             :         /* Remove the original strings */
    1469           0 :         ldap_memvfree((void **)refs);
    1470             : 
    1471             :         /* unlock the operation so that we can proceed with the next result */
    1472           0 :         sdap_unlock_next_reply(state->op);
    1473           0 :         break;
    1474             : 
    1475             :     case LDAP_RES_SEARCH_ENTRY:
    1476           0 :         ret = state->parse_cb(state->sh, reply, state->cb_data);
    1477           0 :         if (ret != EOK) {
    1478           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "reply parsing callback failed.\n");
    1479           0 :             tevent_req_error(req, ret);
    1480           0 :             return;
    1481             :         }
    1482             : 
    1483           0 :         sdap_unlock_next_reply(state->op);
    1484           0 :         break;
    1485             : 
    1486             :     case LDAP_RES_SEARCH_RESULT:
    1487           0 :         ret = ldap_parse_result(state->sh->ldap, reply->msg,
    1488             :                                 &result, NULL, &errmsg, &refs,
    1489             :                                 &returned_controls, 0);
    1490           0 :         if (ret != LDAP_SUCCESS) {
    1491           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1492             :                   "ldap_parse_result failed (%d)\n", state->op->msgid);
    1493           0 :             tevent_req_error(req, EIO);
    1494           0 :             return;
    1495             :         }
    1496             : 
    1497           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Search result: %s(%d), %s\n",
    1498             :                   sss_ldap_err2string(result), result,
    1499             :                   errmsg ? errmsg : "no errmsg set");
    1500             : 
    1501           0 :         if (result == LDAP_SIZELIMIT_EXCEEDED) {
    1502             :             /* Try to return what we've got */
    1503           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    1504             :                   "LDAP sizelimit was exceeded, returning incomplete data\n");
    1505           0 :         } else if (result == LDAP_INAPPROPRIATE_MATCHING) {
    1506             :             /* This error should only occur when we're testing for
    1507             :              * specialized functionality like the ldap matching rule
    1508             :              * filter for Active Directory. Warn at a higher log
    1509             :              * level and return EIO.
    1510             :              */
    1511           0 :             DEBUG(SSSDBG_TRACE_INTERNAL,
    1512             :                   "LDAP_INAPPROPRIATE_MATCHING:  %s\n",
    1513             :                    errmsg ? errmsg : "no errmsg set");
    1514           0 :             ldap_memfree(errmsg);
    1515           0 :             tevent_req_error(req, EIO);
    1516           0 :             return;
    1517           0 :         } else if (result == LDAP_UNAVAILABLE_CRITICAL_EXTENSION) {
    1518           0 :             ldap_memfree(errmsg);
    1519           0 :             tevent_req_error(req, ENOTSUP);
    1520           0 :             return;
    1521           0 :         } else if (result == LDAP_REFERRAL) {
    1522           0 :             ret = sdap_get_generic_ext_add_references(state, refs);
    1523           0 :             if (ret != EOK) {
    1524           0 :                 DEBUG(SSSDBG_OP_FAILURE,
    1525             :                       "sdap_get_generic_ext_add_references failed: %s(%d)",
    1526             :                       sss_strerror(ret), ret);
    1527           0 :                 tevent_req_error(req, ret);
    1528             :             }
    1529             :             /* For referrals, we need to fall through as if it was LDAP_SUCCESS */
    1530           0 :         } else if (result != LDAP_SUCCESS && result != LDAP_NO_SUCH_OBJECT) {
    1531           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1532             :                   "Unexpected result from ldap: %s(%d), %s\n",
    1533             :                    sss_ldap_err2string(result), result,
    1534             :                    errmsg ? errmsg : "no errmsg set");
    1535           0 :             ldap_memfree(errmsg);
    1536           0 :             tevent_req_error(req, EIO);
    1537           0 :             return;
    1538             :         }
    1539           0 :         ldap_memfree(errmsg);
    1540             : 
    1541             :         /* Determine if there are more pages to retrieve */
    1542           0 :         page_control = ldap_control_find(LDAP_CONTROL_PAGEDRESULTS,
    1543             :                                          returned_controls, NULL );
    1544           0 :         if (!page_control) {
    1545             :             /* No paging support. We are done */
    1546           0 :             tevent_req_done(req);
    1547           0 :             return;
    1548             :         }
    1549             : 
    1550           0 :         lret = ldap_parse_pageresponse_control(state->sh->ldap, page_control,
    1551             :                                                &total_count, &cookie);
    1552           0 :         ldap_controls_free(returned_controls);
    1553           0 :         if (lret != LDAP_SUCCESS) {
    1554           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not determine page control\n");
    1555           0 :             tevent_req_error(req, EIO);
    1556           0 :             return;
    1557             :         }
    1558           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Total count [%d]\n", total_count);
    1559             : 
    1560           0 :         if (cookie.bv_val != NULL && cookie.bv_len > 0) {
    1561             :             /* Cookie contains data, which means there are more requests
    1562             :              * to be processed.
    1563             :              */
    1564           0 :             talloc_zfree(state->cookie.bv_val);
    1565           0 :             state->cookie.bv_len = cookie.bv_len;
    1566           0 :             state->cookie.bv_val = talloc_memdup(state,
    1567             :                                                  cookie.bv_val,
    1568             :                                                  cookie.bv_len);
    1569           0 :             if (!state->cookie.bv_val) {
    1570           0 :                 tevent_req_error(req, ENOMEM);
    1571           0 :                 return;
    1572             :             }
    1573           0 :             ber_memfree(cookie.bv_val);
    1574             : 
    1575           0 :             ret = sdap_get_generic_ext_step(req);
    1576           0 :             if (ret != EOK) {
    1577           0 :                 tevent_req_error(req, ENOMEM);
    1578           0 :                 return;
    1579             :             }
    1580             : 
    1581           0 :             return;
    1582             :         }
    1583             :         /* The cookie must be freed even if len == 0 */
    1584           0 :         ber_memfree(cookie.bv_val);
    1585             : 
    1586             :         /* This was the last page. We're done */
    1587             : 
    1588           0 :         tevent_req_done(req);
    1589           0 :         return;
    1590             : 
    1591             :     default:
    1592             :         /* what is going on here !? */
    1593           0 :         tevent_req_error(req, EIO);
    1594           0 :         return;
    1595             :     }
    1596             : }
    1597             : 
    1598             : static int
    1599           0 : sdap_get_generic_ext_recv(struct tevent_req *req,
    1600             :                           TALLOC_CTX *mem_ctx,
    1601             :                           size_t *ref_count,
    1602             :                           char ***refs)
    1603             : {
    1604           0 :     struct sdap_get_generic_ext_state *state =
    1605           0 :             tevent_req_data(req, struct sdap_get_generic_ext_state);
    1606             : 
    1607           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1608             : 
    1609           0 :     if (ref_count) {
    1610           0 :         *ref_count = state->ref_count;
    1611             :     }
    1612             : 
    1613           0 :     if (refs) {
    1614           0 :         *refs = talloc_steal(mem_ctx, state->refs);
    1615             :     }
    1616             : 
    1617           0 :     return EOK;
    1618             : }
    1619             : 
    1620             : /* This search handler can be used by most calls */
    1621           0 : static void generic_ext_search_handler(struct tevent_req *subreq,
    1622             :                                        struct sdap_options *opts)
    1623             : {
    1624           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    1625             :                                                       struct tevent_req);
    1626             :     int ret;
    1627             :     size_t ref_count, i;
    1628             :     char **refs;
    1629             : 
    1630           0 :     ret = sdap_get_generic_ext_recv(subreq, req, &ref_count, &refs);
    1631           0 :     talloc_zfree(subreq);
    1632           0 :     if (ret != EOK) {
    1633           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1634             :               "sdap_get_generic_ext_recv failed [%d]: %s\n",
    1635             :               ret, sss_strerror(ret));
    1636           0 :         tevent_req_error(req, ret);
    1637           0 :         return;
    1638             :     }
    1639             : 
    1640           0 :     if (ref_count > 0) {
    1641           0 :         if (dp_opt_get_bool(opts->basic, SDAP_REFERRALS)) {
    1642             :             /* We got back referrals here, but they should have
    1643             :              * been processed internally by openldap libs.
    1644             :              * This should never happen.
    1645             :              */
    1646           0 :             talloc_free(refs);
    1647           0 :             tevent_req_error(req, EINVAL);
    1648           0 :             return;
    1649             :         }
    1650             : 
    1651             :         /* We will ignore referrals in the generic handler */
    1652           0 :         DEBUG(SSSDBG_TRACE_ALL,
    1653             :               "Request included referrals which were ignored.\n");
    1654           0 :         if (debug_level & SSSDBG_TRACE_ALL) {
    1655           0 :             for(i = 0; i < ref_count; i++) {
    1656           0 :                 DEBUG(SSSDBG_TRACE_ALL,
    1657             :                       "    Ref: %s\n", refs[i]);
    1658             :             }
    1659             :         }
    1660             :     }
    1661             : 
    1662           0 :     tevent_req_done(req);
    1663             : }
    1664             : 
    1665             : /* ==Generic Search exposing all options======================= */
    1666             : struct sdap_get_and_parse_generic_state {
    1667             :     struct sdap_attr_map *map;
    1668             :     int map_num_attrs;
    1669             : 
    1670             :     struct sdap_reply sreply;
    1671             :     struct sdap_options *opts;
    1672             : };
    1673             : 
    1674             : static void sdap_get_and_parse_generic_done(struct tevent_req *subreq);
    1675             : static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
    1676             :                                                       struct sdap_msg *msg,
    1677             :                                                       void *pvt);
    1678             : 
    1679           0 : struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx,
    1680             :                                                    struct tevent_context *ev,
    1681             :                                                    struct sdap_options *opts,
    1682             :                                                    struct sdap_handle *sh,
    1683             :                                                    const char *search_base,
    1684             :                                                    int scope,
    1685             :                                                    const char *filter,
    1686             :                                                    const char **attrs,
    1687             :                                                    struct sdap_attr_map *map,
    1688             :                                                    int map_num_attrs,
    1689             :                                                    int attrsonly,
    1690             :                                                    LDAPControl **serverctrls,
    1691             :                                                    LDAPControl **clientctrls,
    1692             :                                                    int sizelimit,
    1693             :                                                    int timeout,
    1694             :                                                    bool allow_paging)
    1695             : {
    1696           0 :     struct tevent_req *req = NULL;
    1697           0 :     struct tevent_req *subreq = NULL;
    1698           0 :     struct sdap_get_and_parse_generic_state *state = NULL;
    1699             : 
    1700           0 :     req = tevent_req_create(memctx, &state,
    1701             :                             struct sdap_get_and_parse_generic_state);
    1702           0 :     if (!req) return NULL;
    1703             : 
    1704           0 :     state->map = map;
    1705           0 :     state->map_num_attrs = map_num_attrs;
    1706           0 :     state->opts = opts;
    1707             : 
    1708           0 :     subreq = sdap_get_generic_ext_send(state, ev, opts, sh, search_base,
    1709             :                                        scope, filter, attrs, false, NULL,
    1710             :                                        NULL, sizelimit, timeout, allow_paging,
    1711             :                                        sdap_get_and_parse_generic_parse_entry, state);
    1712           0 :     if (!subreq) {
    1713           0 :         talloc_zfree(req);
    1714           0 :         return NULL;
    1715             :     }
    1716           0 :     tevent_req_set_callback(subreq, sdap_get_and_parse_generic_done, req);
    1717             : 
    1718           0 :     return req;
    1719             : }
    1720             : 
    1721           0 : static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
    1722             :                                                       struct sdap_msg *msg,
    1723             :                                                       void *pvt)
    1724             : {
    1725             :     errno_t ret;
    1726             :     struct sysdb_attrs *attrs;
    1727           0 :     struct sdap_get_and_parse_generic_state *state =
    1728             :                 talloc_get_type(pvt, struct sdap_get_and_parse_generic_state);
    1729             : 
    1730           0 :     bool disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
    1731             :                                                SDAP_DISABLE_RANGE_RETRIEVAL);
    1732             : 
    1733           0 :     ret = sdap_parse_entry(state, sh, msg,
    1734             :                            state->map, state->map_num_attrs,
    1735             :                            &attrs, disable_range_rtrvl);
    1736           0 :     if (ret != EOK) {
    1737           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1738             :               "sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
    1739           0 :         return ret;
    1740             :     }
    1741             : 
    1742           0 :     ret = add_to_reply(state, &state->sreply, attrs);
    1743           0 :     if (ret != EOK) {
    1744           0 :         talloc_free(attrs);
    1745           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
    1746           0 :         return ret;
    1747             :     }
    1748             : 
    1749             :     /* add_to_reply steals attrs, no need to free them here */
    1750           0 :     return EOK;
    1751             : }
    1752             : 
    1753           0 : static void sdap_get_and_parse_generic_done(struct tevent_req *subreq)
    1754             : {
    1755           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    1756             :                                                       struct tevent_req);
    1757           0 :     struct sdap_get_and_parse_generic_state *state =
    1758           0 :                 tevent_req_data(req, struct sdap_get_and_parse_generic_state);
    1759             : 
    1760           0 :     return generic_ext_search_handler(subreq, state->opts);
    1761             : }
    1762             : 
    1763           0 : int sdap_get_and_parse_generic_recv(struct tevent_req *req,
    1764             :                                     TALLOC_CTX *mem_ctx,
    1765             :                                     size_t *reply_count,
    1766             :                                     struct sysdb_attrs ***reply)
    1767             : {
    1768           0 :     struct sdap_get_and_parse_generic_state *state = tevent_req_data(req,
    1769             :                                      struct sdap_get_and_parse_generic_state);
    1770             : 
    1771           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1772             : 
    1773           0 :     *reply_count = state->sreply.reply_count;
    1774           0 :     *reply = talloc_steal(mem_ctx, state->sreply.reply);
    1775             : 
    1776           0 :     return EOK;
    1777             : }
    1778             : 
    1779             : 
    1780             : /* ==Simple generic search============================================== */
    1781             : struct sdap_get_generic_state {
    1782             :     size_t reply_count;
    1783             :     struct sysdb_attrs **reply;
    1784             : };
    1785             : 
    1786             : static void sdap_get_generic_done(struct tevent_req *subreq);
    1787             : 
    1788           0 : struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
    1789             :                                          struct tevent_context *ev,
    1790             :                                          struct sdap_options *opts,
    1791             :                                          struct sdap_handle *sh,
    1792             :                                          const char *search_base,
    1793             :                                          int scope,
    1794             :                                          const char *filter,
    1795             :                                          const char **attrs,
    1796             :                                          struct sdap_attr_map *map,
    1797             :                                          int map_num_attrs,
    1798             :                                          int timeout,
    1799             :                                          bool allow_paging)
    1800             : {
    1801           0 :     struct tevent_req *req = NULL;
    1802           0 :     struct tevent_req *subreq = NULL;
    1803           0 :     struct sdap_get_generic_state *state = NULL;
    1804             : 
    1805           0 :     req = tevent_req_create(memctx, &state, struct sdap_get_generic_state);
    1806           0 :     if (!req) return NULL;
    1807             : 
    1808           0 :     subreq = sdap_get_and_parse_generic_send(memctx, ev, opts, sh, search_base,
    1809             :                                              scope, filter, attrs,
    1810             :                                              map, map_num_attrs,
    1811             :                                              false, NULL, NULL, 0, timeout,
    1812             :                                              allow_paging);
    1813           0 :     if (subreq == NULL) {
    1814           0 :         return NULL;
    1815             :     }
    1816           0 :     tevent_req_set_callback(subreq, sdap_get_generic_done, req);
    1817             : 
    1818           0 :     return req;
    1819             : }
    1820             : 
    1821           0 : static void sdap_get_generic_done(struct tevent_req *subreq)
    1822             : {
    1823           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    1824             :                                                       struct tevent_req);
    1825           0 :     struct sdap_get_generic_state *state =
    1826           0 :                 tevent_req_data(req, struct sdap_get_generic_state);
    1827             :     errno_t ret;
    1828             : 
    1829           0 :     ret = sdap_get_and_parse_generic_recv(subreq, state,
    1830             :                                           &state->reply_count, &state->reply);
    1831           0 :     if (ret != EOK) {
    1832           0 :         tevent_req_error(req, ret);
    1833           0 :         return;
    1834             :     }
    1835           0 :     tevent_req_done(req);
    1836             : }
    1837             : 
    1838           0 : int sdap_get_generic_recv(struct tevent_req *req,
    1839             :                           TALLOC_CTX *mem_ctx,
    1840             :                           size_t *reply_count,
    1841             :                           struct sysdb_attrs ***reply)
    1842             : {
    1843           0 :     struct sdap_get_generic_state *state =
    1844           0 :                 tevent_req_data(req, struct sdap_get_generic_state);
    1845             : 
    1846           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1847             : 
    1848           0 :     *reply_count = state->reply_count;
    1849           0 :     *reply = talloc_steal(mem_ctx, state->reply);
    1850             : 
    1851           0 :     return EOK;
    1852             : }
    1853             : 
    1854             : /* ==OpenLDAP deref search============================================== */
    1855             : static int sdap_x_deref_create_control(struct sdap_handle *sh,
    1856             :                                        const char *deref_attr,
    1857             :                                        const char **attrs,
    1858             :                                        LDAPControl **ctrl);
    1859             : 
    1860             : static void sdap_x_deref_search_done(struct tevent_req *subreq);
    1861             : static int sdap_x_deref_search_ctrls_destructor(void *ptr);
    1862             : 
    1863             : static errno_t sdap_x_deref_parse_entry(struct sdap_handle *sh,
    1864             :                                         struct sdap_msg *msg,
    1865             :                                         void *pvt);
    1866             : struct sdap_x_deref_search_state {
    1867             :     struct sdap_handle *sh;
    1868             :     struct sdap_op *op;
    1869             :     struct sdap_attr_map_info *maps;
    1870             :     LDAPControl **ctrls;
    1871             :     struct sdap_options *opts;
    1872             : 
    1873             :     struct sdap_deref_reply dreply;
    1874             :     int num_maps;
    1875             : };
    1876             : 
    1877             : static struct tevent_req *
    1878           0 : sdap_x_deref_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
    1879             :                          struct sdap_options *opts, struct sdap_handle *sh,
    1880             :                          const char *base_dn, const char *filter,
    1881             :                          const char *deref_attr, const char **attrs,
    1882             :                          struct sdap_attr_map_info *maps, int num_maps,
    1883             :                          int timeout)
    1884             : {
    1885           0 :     struct tevent_req *req = NULL;
    1886           0 :     struct tevent_req *subreq = NULL;
    1887             :     struct sdap_x_deref_search_state *state;
    1888             :     int ret;
    1889             : 
    1890           0 :     req = tevent_req_create(memctx, &state, struct sdap_x_deref_search_state);
    1891           0 :     if (!req) return NULL;
    1892             : 
    1893           0 :     state->sh = sh;
    1894           0 :     state->maps = maps;
    1895           0 :     state->op = NULL;
    1896           0 :     state->opts = opts;
    1897           0 :     state->num_maps = num_maps;
    1898           0 :     state->ctrls = talloc_zero_array(state, LDAPControl *, 2);
    1899           0 :     if (state->ctrls == NULL) {
    1900           0 :         talloc_zfree(req);
    1901           0 :         return NULL;
    1902             :     }
    1903           0 :     talloc_set_destructor((TALLOC_CTX *) state->ctrls,
    1904             :                           sdap_x_deref_search_ctrls_destructor);
    1905             : 
    1906           0 :     ret = sdap_x_deref_create_control(sh, deref_attr,
    1907           0 :                                       attrs, &state->ctrls[0]);
    1908           0 :     if (ret != EOK) {
    1909           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not create OpenLDAP deref control\n");
    1910           0 :         talloc_zfree(req);
    1911           0 :         return NULL;
    1912             :     }
    1913             : 
    1914           0 :     DEBUG(SSSDBG_TRACE_FUNC,
    1915             :           "Dereferencing entry [%s] using OpenLDAP deref\n", base_dn);
    1916           0 :     subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
    1917             :                                        filter == NULL ? LDAP_SCOPE_BASE
    1918             :                                                       : LDAP_SCOPE_SUBTREE,
    1919             :                                        filter, attrs,
    1920           0 :                                        false, state->ctrls, NULL, 0, timeout,
    1921             :                                        true, sdap_x_deref_parse_entry,
    1922             :                                        state);
    1923           0 :     if (!subreq) {
    1924           0 :         talloc_zfree(req);
    1925           0 :         return NULL;
    1926             :     }
    1927           0 :     tevent_req_set_callback(subreq, sdap_x_deref_search_done, req);
    1928             : 
    1929           0 :     return req;
    1930             : }
    1931             : 
    1932           0 : static int sdap_x_deref_create_control(struct sdap_handle *sh,
    1933             :                                        const char *deref_attr,
    1934             :                                        const char **attrs,
    1935             :                                        LDAPControl **ctrl)
    1936             : {
    1937             :     struct berval derefval;
    1938             :     int ret;
    1939             :     struct LDAPDerefSpec ds[2];
    1940             : 
    1941           0 :     ds[0].derefAttr = discard_const(deref_attr);
    1942           0 :     ds[0].attributes = discard_const(attrs);
    1943             : 
    1944           0 :     ds[1].derefAttr = NULL; /* sentinel */
    1945             : 
    1946           0 :     ret = ldap_create_deref_control_value(sh->ldap, ds, &derefval);
    1947           0 :     if (ret != LDAP_SUCCESS) {
    1948           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sss_ldap_control_create failed: %s\n",
    1949             :                   ldap_err2string(ret));
    1950           0 :         return ret;
    1951             :     }
    1952             : 
    1953           0 :     ret = sdap_control_create(sh, LDAP_CONTROL_X_DEREF,
    1954             :                               1, &derefval, 1, ctrl);
    1955           0 :     ldap_memfree(derefval.bv_val);
    1956           0 :     if (ret != EOK) {
    1957           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sss_ldap_control_create failed\n");
    1958           0 :         return ret;
    1959             :     }
    1960             : 
    1961           0 :     return EOK;
    1962             : }
    1963             : 
    1964           0 : static errno_t sdap_x_deref_parse_entry(struct sdap_handle *sh,
    1965             :                                         struct sdap_msg *msg,
    1966             :                                         void *pvt)
    1967             : {
    1968             :     errno_t ret;
    1969           0 :     LDAPControl **ctrls = NULL;
    1970           0 :     LDAPControl *derefctrl = NULL;
    1971           0 :     LDAPDerefRes    *deref_res = NULL;
    1972             :     LDAPDerefRes    *dref;
    1973             :     struct sdap_deref_attrs **res;
    1974             :     TALLOC_CTX *tmp_ctx;
    1975             : 
    1976           0 :     struct sdap_x_deref_search_state *state = talloc_get_type(pvt,
    1977             :                                             struct sdap_x_deref_search_state);
    1978             : 
    1979           0 :     tmp_ctx = talloc_new(NULL);
    1980           0 :     if (!tmp_ctx) return ENOMEM;
    1981             : 
    1982           0 :     ret = ldap_get_entry_controls(state->sh->ldap, msg->msg,
    1983             :                                   &ctrls);
    1984           0 :     if (ret != LDAP_SUCCESS) {
    1985           0 :         DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_result failed\n");
    1986           0 :         goto done;
    1987             :     }
    1988             : 
    1989           0 :     if (!ctrls) {
    1990             :         /* When we attempt to request attributes that are not present in
    1991             :          * the dereferenced links, some serves might not send the dereference
    1992             :          * control back at all. Be permissive and treat the search as if
    1993             :          * it didn't find anything.
    1994             :          */
    1995           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "No controls found for entry\n");
    1996           0 :         ret = EOK;
    1997           0 :         goto done;
    1998             :     }
    1999             : 
    2000           0 :     res = NULL;
    2001             : 
    2002           0 :     derefctrl = ldap_control_find(LDAP_CONTROL_X_DEREF, ctrls, NULL);
    2003           0 :     if (!derefctrl) {
    2004           0 :         DEBUG(SSSDBG_FUNC_DATA, "No deref controls found\n");
    2005           0 :         ret = EOK;
    2006           0 :         goto done;
    2007             :     }
    2008             : 
    2009           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Got deref control\n");
    2010             : 
    2011           0 :     ret = ldap_parse_derefresponse_control(state->sh->ldap,
    2012             :                                             derefctrl,
    2013             :                                             &deref_res);
    2014           0 :     if (ret != LDAP_SUCCESS) {
    2015           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2016             :               "ldap_parse_derefresponse_control failed: %s\n",
    2017             :                ldap_err2string(ret));
    2018           0 :         goto done;
    2019             :     }
    2020             : 
    2021           0 :     for (dref = deref_res; dref; dref=dref->next) {
    2022           0 :         ret = sdap_parse_deref(tmp_ctx, state->maps, state->num_maps,
    2023             :                                dref, &res);
    2024           0 :         if (ret) {
    2025           0 :             DEBUG(SSSDBG_OP_FAILURE, "sdap_parse_deref failed [%d]: %s\n",
    2026             :                   ret, strerror(ret));
    2027           0 :             goto done;
    2028             :         }
    2029             : 
    2030           0 :         ret = add_to_deref_reply(state, state->num_maps,
    2031             :                                  &state->dreply, res);
    2032           0 :         if (ret != EOK) {
    2033           0 :             DEBUG(SSSDBG_OP_FAILURE, "add_to_deref_reply failed.\n");
    2034           0 :             goto done;
    2035             :         }
    2036             :     }
    2037             : 
    2038           0 :     DEBUG(SSSDBG_TRACE_FUNC,
    2039             :           "All deref results from a single control parsed\n");
    2040           0 :     ldap_derefresponse_free(deref_res);
    2041           0 :     deref_res = NULL;
    2042             : 
    2043           0 :     ret = EOK;
    2044             : done:
    2045           0 :     talloc_zfree(tmp_ctx);
    2046           0 :     ldap_controls_free(ctrls);
    2047           0 :     ldap_derefresponse_free(deref_res);
    2048           0 :     return ret;
    2049             : }
    2050             : 
    2051           0 : static void sdap_x_deref_search_done(struct tevent_req *subreq)
    2052             : {
    2053           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    2054             :                                                       struct tevent_req);
    2055           0 :     struct sdap_x_deref_search_state *state =
    2056           0 :                 tevent_req_data(req, struct sdap_x_deref_search_state);
    2057             : 
    2058           0 :     return generic_ext_search_handler(subreq, state->opts);
    2059             : }
    2060             : 
    2061           0 : static int sdap_x_deref_search_ctrls_destructor(void *ptr)
    2062             : {
    2063           0 :     LDAPControl **ctrls = talloc_get_type(ptr, LDAPControl *);;
    2064             : 
    2065           0 :     if (ctrls && ctrls[0]) {
    2066           0 :         ldap_control_free(ctrls[0]);
    2067             :     }
    2068             : 
    2069           0 :     return 0;
    2070             : }
    2071             : 
    2072             : static int
    2073           0 : sdap_x_deref_search_recv(struct tevent_req *req,
    2074             :                          TALLOC_CTX *mem_ctx,
    2075             :                          size_t *reply_count,
    2076             :                          struct sdap_deref_attrs ***reply)
    2077             : {
    2078           0 :     struct sdap_x_deref_search_state *state = tevent_req_data(req,
    2079             :                                             struct sdap_x_deref_search_state);
    2080             : 
    2081           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    2082             : 
    2083           0 :     *reply_count = state->dreply.reply_count;
    2084           0 :     *reply = talloc_steal(mem_ctx, state->dreply.reply);
    2085             : 
    2086           0 :     return EOK;
    2087             : }
    2088             : 
    2089             : /* ==Security Descriptor (ACL) search=================================== */
    2090             : struct sdap_sd_search_state {
    2091             :   LDAPControl **ctrls;
    2092             :   struct sdap_options *opts;
    2093             :   size_t reply_count;
    2094             :   struct sysdb_attrs **reply;
    2095             :   struct sdap_reply sreply;
    2096             : 
    2097             :   /* Referrals returned by the search */
    2098             :   size_t ref_count;
    2099             :   char **refs;
    2100             : };
    2101             : 
    2102             : static int sdap_sd_search_create_control(struct sdap_handle *sh,
    2103             :                                          int val,
    2104             :                                          LDAPControl **ctrl);
    2105             : static int sdap_sd_search_ctrls_destructor(void *ptr);
    2106             : static errno_t sdap_sd_search_parse_entry(struct sdap_handle *sh,
    2107             :                                           struct sdap_msg *msg,
    2108             :                                           void *pvt);
    2109             : static void sdap_sd_search_done(struct tevent_req *subreq);
    2110             : 
    2111             : struct tevent_req *
    2112           0 : sdap_sd_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
    2113             :                      struct sdap_options *opts, struct sdap_handle *sh,
    2114             :                      const char *base_dn, int sd_flags,
    2115             :                      const char **attrs, int timeout)
    2116             : {
    2117           0 :     struct tevent_req *req = NULL;
    2118           0 :     struct tevent_req *subreq = NULL;
    2119             :     struct sdap_sd_search_state *state;
    2120             :     int ret;
    2121             : 
    2122           0 :     req = tevent_req_create(memctx, &state, struct sdap_sd_search_state);
    2123           0 :     if (!req) return NULL;
    2124             : 
    2125           0 :     state->ctrls = talloc_zero_array(state, LDAPControl *, 2);
    2126           0 :     state->opts = opts;
    2127           0 :     if (state->ctrls == NULL) {
    2128           0 :         ret = EIO;
    2129           0 :         goto fail;
    2130             :     }
    2131           0 :     talloc_set_destructor((TALLOC_CTX *) state->ctrls,
    2132             :                           sdap_sd_search_ctrls_destructor);
    2133             : 
    2134           0 :     ret = sdap_sd_search_create_control(sh, sd_flags, &state->ctrls[0]);
    2135           0 :     if (ret != EOK) {
    2136           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not create SD control\n");
    2137           0 :         ret = EIO;
    2138           0 :         goto fail;
    2139             :     }
    2140             : 
    2141           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Searching entry [%s] using SD\n", base_dn);
    2142           0 :     subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
    2143             :                                        LDAP_SCOPE_BASE, "(objectclass=*)", attrs,
    2144           0 :                                        false, state->ctrls, NULL, 0, timeout,
    2145             :                                        true, sdap_sd_search_parse_entry,
    2146             :                                        state);
    2147           0 :     if (!subreq) {
    2148           0 :         ret = EIO;
    2149           0 :         goto fail;
    2150             :     }
    2151           0 :     tevent_req_set_callback(subreq, sdap_sd_search_done, req);
    2152           0 :     return req;
    2153             : 
    2154             : fail:
    2155           0 :     tevent_req_error(req, ret);
    2156           0 :     tevent_req_post(req, ev);
    2157           0 :     return req;
    2158             : }
    2159             : 
    2160           0 : static int sdap_sd_search_create_control(struct sdap_handle *sh,
    2161             :                                          int val,
    2162             :                                          LDAPControl **ctrl)
    2163             : {
    2164             :     struct berval *sdval;
    2165             :     int ret;
    2166           0 :     BerElement *ber = NULL;
    2167           0 :     ber = ber_alloc_t(LBER_USE_DER);
    2168           0 :     if (ber == NULL) {
    2169           0 :         DEBUG(SSSDBG_OP_FAILURE, "ber_alloc_t failed.\n");
    2170           0 :         return ENOMEM;
    2171             :     }
    2172             : 
    2173           0 :     ret = ber_printf(ber, "{i}", val);
    2174           0 :     if (ret == -1) {
    2175           0 :         DEBUG(SSSDBG_OP_FAILURE, "ber_printf failed.\n");
    2176           0 :         ber_free(ber, 1);
    2177           0 :         return EIO;
    2178             :     }
    2179             : 
    2180           0 :     ret = ber_flatten(ber, &sdval);
    2181           0 :     ber_free(ber, 1);
    2182           0 :     if (ret == -1) {
    2183           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "ber_flatten failed.\n");
    2184           0 :         return EIO;
    2185             :     }
    2186             : 
    2187           0 :     ret = sdap_control_create(sh, LDAP_SERVER_SD_OID, 1, sdval, 1, ctrl);
    2188           0 :     ber_bvfree(sdval);
    2189           0 :     if (ret != EOK) {
    2190           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sdap_control_create failed\n");
    2191           0 :         return ret;
    2192             :     }
    2193             : 
    2194           0 :     return EOK;
    2195             : }
    2196             : 
    2197           0 : static errno_t sdap_sd_search_parse_entry(struct sdap_handle *sh,
    2198             :                                           struct sdap_msg *msg,
    2199             :                                           void *pvt)
    2200             : {
    2201             :     errno_t ret;
    2202             :     struct sysdb_attrs *attrs;
    2203           0 :     struct sdap_sd_search_state *state =
    2204             :                 talloc_get_type(pvt, struct sdap_sd_search_state);
    2205             : 
    2206           0 :     bool disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
    2207             :                                                SDAP_DISABLE_RANGE_RETRIEVAL);
    2208             : 
    2209           0 :     ret = sdap_parse_entry(state, sh, msg,
    2210             :                            NULL, 0,
    2211             :                            &attrs, disable_range_rtrvl);
    2212           0 :     if (ret != EOK) {
    2213           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    2214             :               "sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
    2215           0 :         return ret;
    2216             :     }
    2217             : 
    2218           0 :     ret = add_to_reply(state, &state->sreply, attrs);
    2219           0 :     if (ret != EOK) {
    2220           0 :         talloc_free(attrs);
    2221           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
    2222           0 :         return ret;
    2223             :     }
    2224             : 
    2225             :     /* add_to_reply steals attrs, no need to free them here */
    2226           0 :     return EOK;
    2227             : }
    2228             : 
    2229           0 : static void sdap_sd_search_done(struct tevent_req *subreq)
    2230             : {
    2231             :     int ret;
    2232             : 
    2233           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    2234             :                                                       struct tevent_req);
    2235           0 :     struct sdap_sd_search_state *state =
    2236           0 :                 tevent_req_data(req, struct sdap_sd_search_state);
    2237             : 
    2238           0 :     ret = sdap_get_generic_ext_recv(subreq, state,
    2239             :                                     &state->ref_count,
    2240             :                                     &state->refs);
    2241           0 :     talloc_zfree(subreq);
    2242           0 :     if (ret != EOK) {
    2243           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2244             :               "sdap_get_generic_ext_recv failed [%d]: %s\n",
    2245             :               ret, sss_strerror(ret));
    2246           0 :         tevent_req_error(req, ret);
    2247           0 :         return;
    2248             :     }
    2249             : 
    2250           0 :     tevent_req_done(req);
    2251             : }
    2252             : 
    2253           0 : static int sdap_sd_search_ctrls_destructor(void *ptr)
    2254             : {
    2255           0 :     LDAPControl **ctrls = talloc_get_type(ptr, LDAPControl *);;
    2256           0 :     if (ctrls && ctrls[0]) {
    2257           0 :         ldap_control_free(ctrls[0]);
    2258             :     }
    2259             : 
    2260           0 :     return 0;
    2261             : }
    2262             : 
    2263           0 : int sdap_sd_search_recv(struct tevent_req *req,
    2264             :                         TALLOC_CTX *mem_ctx,
    2265             :                         size_t *_reply_count,
    2266             :                         struct sysdb_attrs ***_reply,
    2267             :                         size_t *_ref_count,
    2268             :                         char ***_refs)
    2269             : {
    2270           0 :     struct sdap_sd_search_state *state = tevent_req_data(req,
    2271             :                                             struct sdap_sd_search_state);
    2272           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    2273             : 
    2274           0 :     *_reply_count = state->sreply.reply_count;
    2275           0 :     *_reply = talloc_steal(mem_ctx, state->sreply.reply);
    2276             : 
    2277           0 :     if(_ref_count) {
    2278           0 :         *_ref_count = state->ref_count;
    2279             :     }
    2280             : 
    2281           0 :     if (_refs) {
    2282           0 :         *_refs = talloc_steal(mem_ctx, state->refs);
    2283             :     }
    2284             : 
    2285           0 :     return EOK;
    2286             : }
    2287             : 
    2288             : /* ==Attribute scoped search============================================ */
    2289             : struct sdap_asq_search_state {
    2290             :     struct sdap_attr_map_info *maps;
    2291             :     int num_maps;
    2292             :     LDAPControl **ctrls;
    2293             :     struct sdap_options *opts;
    2294             : 
    2295             :     struct sdap_deref_reply dreply;
    2296             : };
    2297             : 
    2298             : static int sdap_asq_search_create_control(struct sdap_handle *sh,
    2299             :                                           const char *attr,
    2300             :                                           LDAPControl **ctrl);
    2301             : static int sdap_asq_search_ctrls_destructor(void *ptr);
    2302             : static errno_t sdap_asq_search_parse_entry(struct sdap_handle *sh,
    2303             :                                            struct sdap_msg *msg,
    2304             :                                            void *pvt);
    2305             : static void sdap_asq_search_done(struct tevent_req *subreq);
    2306             : 
    2307             : static struct tevent_req *
    2308           0 : sdap_asq_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
    2309             :                      struct sdap_options *opts, struct sdap_handle *sh,
    2310             :                      const char *base_dn, const char *deref_attr,
    2311             :                      const char **attrs, struct sdap_attr_map_info *maps,
    2312             :                      int num_maps, int timeout)
    2313             : {
    2314           0 :     struct tevent_req *req = NULL;
    2315           0 :     struct tevent_req *subreq = NULL;
    2316             :     struct sdap_asq_search_state *state;
    2317             :     int ret;
    2318             : 
    2319           0 :     req = tevent_req_create(memctx, &state, struct sdap_asq_search_state);
    2320           0 :     if (!req) return NULL;
    2321             : 
    2322           0 :     state->maps = maps;
    2323           0 :     state->num_maps = num_maps;
    2324           0 :     state->ctrls = talloc_zero_array(state, LDAPControl *, 2);
    2325           0 :     state->opts = opts;
    2326           0 :     if (state->ctrls == NULL) {
    2327           0 :         talloc_zfree(req);
    2328           0 :         return NULL;
    2329             :     }
    2330           0 :     talloc_set_destructor((TALLOC_CTX *) state->ctrls,
    2331             :                           sdap_asq_search_ctrls_destructor);
    2332             : 
    2333           0 :     ret = sdap_asq_search_create_control(sh, deref_attr, &state->ctrls[0]);
    2334           0 :     if (ret != EOK) {
    2335           0 :         talloc_zfree(req);
    2336           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not create ASQ control\n");
    2337           0 :         return NULL;
    2338             :     }
    2339             : 
    2340           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Dereferencing entry [%s] using ASQ\n", base_dn);
    2341           0 :     subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
    2342             :                                        LDAP_SCOPE_BASE, NULL, attrs,
    2343           0 :                                        false, state->ctrls, NULL, 0, timeout,
    2344             :                                        true, sdap_asq_search_parse_entry,
    2345             :                                        state);
    2346           0 :     if (!subreq) {
    2347           0 :         talloc_zfree(req);
    2348           0 :         return NULL;
    2349             :     }
    2350           0 :     tevent_req_set_callback(subreq, sdap_asq_search_done, req);
    2351             : 
    2352           0 :     return req;
    2353             : }
    2354             : 
    2355             : 
    2356           0 : static int sdap_asq_search_create_control(struct sdap_handle *sh,
    2357             :                                           const char *attr,
    2358             :                                           LDAPControl **ctrl)
    2359             : {
    2360             :     struct berval *asqval;
    2361             :     int ret;
    2362           0 :     BerElement *ber = NULL;
    2363             : 
    2364           0 :     ber = ber_alloc_t(LBER_USE_DER);
    2365           0 :     if (ber == NULL) {
    2366           0 :         DEBUG(SSSDBG_OP_FAILURE, "ber_alloc_t failed.\n");
    2367           0 :         return ENOMEM;
    2368             :     }
    2369             : 
    2370           0 :     ret = ber_printf(ber, "{s}", attr);
    2371           0 :     if (ret == -1) {
    2372           0 :         DEBUG(SSSDBG_OP_FAILURE, "ber_printf failed.\n");
    2373           0 :         ber_free(ber, 1);
    2374           0 :         return EIO;
    2375             :     }
    2376             : 
    2377           0 :     ret = ber_flatten(ber, &asqval);
    2378           0 :     ber_free(ber, 1);
    2379           0 :     if (ret == -1) {
    2380           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "ber_flatten failed.\n");
    2381           0 :         return EIO;
    2382             :     }
    2383             : 
    2384           0 :     ret = sdap_control_create(sh, LDAP_SERVER_ASQ_OID, 1, asqval, 1, ctrl);
    2385           0 :     ber_bvfree(asqval);
    2386           0 :     if (ret != EOK) {
    2387           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sdap_control_create failed\n");
    2388           0 :         return ret;
    2389             :     }
    2390             : 
    2391           0 :     return EOK;
    2392             : }
    2393             : 
    2394           0 : static errno_t sdap_asq_search_parse_entry(struct sdap_handle *sh,
    2395             :                                            struct sdap_msg *msg,
    2396             :                                            void *pvt)
    2397             : {
    2398             :     errno_t ret;
    2399           0 :     struct sdap_asq_search_state *state =
    2400             :                 talloc_get_type(pvt, struct sdap_asq_search_state);
    2401             :     struct berval **vals;
    2402             :     int i, mi;
    2403             :     struct sdap_attr_map *map;
    2404             :     int num_attrs;
    2405             :     struct sdap_deref_attrs **res;
    2406             :     char *tmp;
    2407             :     char *dn;
    2408             :     TALLOC_CTX *tmp_ctx;
    2409             :     bool disable_range_rtrvl;
    2410             : 
    2411           0 :     tmp_ctx = talloc_new(NULL);
    2412           0 :     if (!tmp_ctx) return ENOMEM;
    2413             : 
    2414           0 :     res = talloc_array(tmp_ctx, struct sdap_deref_attrs *,
    2415             :                        state->num_maps);
    2416           0 :     if (!res) {
    2417           0 :         ret = ENOMEM;
    2418           0 :         goto done;
    2419             :     }
    2420             : 
    2421           0 :     for (mi =0; mi < state->num_maps; mi++) {
    2422           0 :         res[mi] = talloc_zero(res, struct sdap_deref_attrs);
    2423           0 :         if (!res[mi]) {
    2424           0 :             ret = ENOMEM;
    2425           0 :             goto done;
    2426             :         }
    2427           0 :         res[mi]->map = state->maps[mi].map;
    2428           0 :         res[mi]->attrs = NULL;
    2429             :     }
    2430             : 
    2431             : 
    2432           0 :     tmp = ldap_get_dn(sh->ldap, msg->msg);
    2433           0 :     if (!tmp) {
    2434           0 :         ret = EINVAL;
    2435           0 :         goto done;
    2436             :     }
    2437             : 
    2438           0 :     dn = talloc_strdup(tmp_ctx, tmp);
    2439           0 :     ldap_memfree(tmp);
    2440           0 :     if (!dn) {
    2441           0 :         ret = ENOMEM;
    2442           0 :         goto done;
    2443             :     }
    2444             : 
    2445             :     /* Find all suitable maps in the list */
    2446           0 :     vals = ldap_get_values_len(sh->ldap, msg->msg, "objectClass");
    2447           0 :     if (!vals) {
    2448           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2449             :               "Unknown entry type, no objectClass found for DN [%s]!\n", dn);
    2450           0 :         ret = EINVAL;
    2451           0 :         goto done;
    2452             :     }
    2453           0 :     for (mi =0; mi < state->num_maps; mi++) {
    2454           0 :         map = NULL;
    2455           0 :         for (i = 0; vals[i]; i++) {
    2456             :             /* the objectclass is always the first name in the map */
    2457           0 :             if (strncasecmp(state->maps[mi].map[0].name,
    2458           0 :                             vals[i]->bv_val, vals[i]->bv_len) == 0) {
    2459             :                 /* it's an entry of the right type */
    2460           0 :                 DEBUG(SSSDBG_TRACE_INTERNAL,
    2461             :                       "Matched objectclass [%s] on DN [%s], will use associated map\n",
    2462             :                        state->maps[mi].map[0].name, dn);
    2463           0 :                 map = state->maps[mi].map;
    2464           0 :                 num_attrs = state->maps[mi].num_attrs;
    2465           0 :                 break;
    2466             :             }
    2467             :         }
    2468           0 :         if (!map) {
    2469           0 :             DEBUG(SSSDBG_TRACE_INTERNAL,
    2470             :                   "DN [%s] did not match the objectClass [%s]\n",
    2471             :                    dn, state->maps[mi].map[0].name);
    2472           0 :             continue;
    2473             :         }
    2474             : 
    2475           0 :         disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
    2476             :                                               SDAP_DISABLE_RANGE_RETRIEVAL);
    2477             : 
    2478           0 :         ret = sdap_parse_entry(res[mi], sh, msg,
    2479             :                                map, num_attrs,
    2480           0 :                                &res[mi]->attrs, disable_range_rtrvl);
    2481           0 :         if (ret != EOK) {
    2482           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    2483             :                   "sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
    2484           0 :             goto done;
    2485             :         }
    2486             :     }
    2487           0 :     ldap_value_free_len(vals);
    2488             : 
    2489           0 :     ret = add_to_deref_reply(state, state->num_maps,
    2490             :                              &state->dreply, res);
    2491           0 :     if (ret != EOK) {
    2492           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "add_to_deref_reply failed.\n");
    2493           0 :         goto done;
    2494             :     }
    2495             : 
    2496           0 :     ret = EOK;
    2497             : done:
    2498           0 :     talloc_zfree(tmp_ctx);
    2499           0 :     return ret;
    2500             : }
    2501             : 
    2502           0 : static void sdap_asq_search_done(struct tevent_req *subreq)
    2503             : {
    2504           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    2505             :                                                       struct tevent_req);
    2506           0 :     struct sdap_asq_search_state *state =
    2507           0 :                 tevent_req_data(req, struct sdap_asq_search_state);
    2508             : 
    2509           0 :     return generic_ext_search_handler(subreq, state->opts);
    2510             : }
    2511             : 
    2512           0 : static int sdap_asq_search_ctrls_destructor(void *ptr)
    2513             : {
    2514           0 :     LDAPControl **ctrls = talloc_get_type(ptr, LDAPControl *);;
    2515             : 
    2516           0 :     if (ctrls && ctrls[0]) {
    2517           0 :         ldap_control_free(ctrls[0]);
    2518             :     }
    2519             : 
    2520           0 :     return 0;
    2521             : }
    2522             : 
    2523           0 : int sdap_asq_search_recv(struct tevent_req *req,
    2524             :                          TALLOC_CTX *mem_ctx,
    2525             :                          size_t *reply_count,
    2526             :                          struct sdap_deref_attrs ***reply)
    2527             : {
    2528           0 :     struct sdap_asq_search_state *state = tevent_req_data(req,
    2529             :                                             struct sdap_asq_search_state);
    2530           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    2531             : 
    2532           0 :     *reply_count = state->dreply.reply_count;
    2533           0 :     *reply = talloc_steal(mem_ctx, state->dreply.reply);
    2534             : 
    2535           0 :     return EOK;
    2536             : }
    2537             : 
    2538             : /* ==Posix attribute presence test================================= */
    2539             : static errno_t sdap_posix_check_next(struct tevent_req *req);
    2540             : static void sdap_posix_check_done(struct tevent_req *subreq);
    2541             : static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
    2542             :                                       struct sdap_msg *msg,
    2543             :                                       void *pvt);
    2544             : 
    2545             : struct sdap_posix_check_state {
    2546             :     struct tevent_context *ev;
    2547             :     struct sdap_options *opts;
    2548             :     struct sdap_handle *sh;
    2549             :     struct sdap_search_base **search_bases;
    2550             :     int timeout;
    2551             : 
    2552             :     const char **attrs;
    2553             :     const char *filter;
    2554             :     size_t base_iter;
    2555             : 
    2556             :     bool has_posix;
    2557             : };
    2558             : 
    2559             : struct tevent_req *
    2560           0 : sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
    2561             :                       struct sdap_options *opts, struct sdap_handle *sh,
    2562             :                       struct sdap_search_base **search_bases,
    2563             :                       int timeout)
    2564             : {
    2565           0 :     struct tevent_req *req = NULL;
    2566             :     struct sdap_posix_check_state *state;
    2567             :     errno_t ret;
    2568             : 
    2569           0 :     req = tevent_req_create(memctx, &state, struct sdap_posix_check_state);
    2570           0 :     if (req == NULL) {
    2571           0 :         return NULL;
    2572             :     }
    2573           0 :     state->ev = ev;
    2574           0 :     state->sh = sh;
    2575           0 :     state->opts = opts;
    2576           0 :     state->search_bases = search_bases;
    2577           0 :     state->timeout = timeout;
    2578             : 
    2579           0 :     state->attrs = talloc_array(state, const char *, 4);
    2580           0 :     if (state->attrs == NULL) {
    2581           0 :         ret = ENOMEM;
    2582           0 :         goto fail;
    2583             :     }
    2584           0 :     state->attrs[0] = "objectclass";
    2585           0 :     state->attrs[1] = opts->user_map[SDAP_AT_USER_UID].name;
    2586           0 :     state->attrs[2] = opts->group_map[SDAP_AT_GROUP_GID].name;
    2587           0 :     state->attrs[3] = NULL;
    2588             : 
    2589           0 :     state->filter = talloc_asprintf(state,
    2590             :         "(|(&(%s=*)(objectclass=%s))(&(%s=*)(objectclass=%s)))",
    2591           0 :                                     opts->user_map[SDAP_AT_USER_UID].name,
    2592           0 :                                     opts->user_map[SDAP_OC_USER].name,
    2593           0 :                                     opts->group_map[SDAP_AT_GROUP_GID].name,
    2594           0 :                                     opts->group_map[SDAP_OC_GROUP].name);
    2595           0 :     if (state->filter == NULL) {
    2596           0 :         ret = ENOMEM;
    2597           0 :         goto fail;
    2598             :     }
    2599             : 
    2600           0 :     ret = sdap_posix_check_next(req);
    2601           0 :     if (ret != EOK) {
    2602           0 :         goto fail;
    2603             :     }
    2604             : 
    2605           0 :     return req;
    2606             : 
    2607             : fail:
    2608           0 :     tevent_req_error(req, ret);
    2609           0 :     tevent_req_post(req, ev);
    2610           0 :     return req;
    2611             : }
    2612             : 
    2613           0 : static errno_t sdap_posix_check_next(struct tevent_req *req)
    2614             : {
    2615           0 :     struct tevent_req *subreq = NULL;
    2616           0 :     struct sdap_posix_check_state *state =
    2617           0 :         tevent_req_data(req, struct sdap_posix_check_state);
    2618             : 
    2619           0 :     DEBUG(SSSDBG_TRACE_FUNC,
    2620             :           "Searching for POSIX attributes with base [%s]\n",
    2621             :            state->search_bases[state->base_iter]->basedn);
    2622             : 
    2623           0 :     subreq = sdap_get_generic_ext_send(state, state->ev, state->opts,
    2624             :                                  state->sh,
    2625           0 :                                  state->search_bases[state->base_iter]->basedn,
    2626             :                                  LDAP_SCOPE_SUBTREE, state->filter,
    2627             :                                  state->attrs, false,
    2628             :                                  NULL, NULL, 1, state->timeout,
    2629             :                                  false, sdap_posix_check_parse,
    2630             :                                  state);
    2631           0 :     if (subreq == NULL) {
    2632           0 :         return ENOMEM;
    2633             :     }
    2634           0 :     tevent_req_set_callback(subreq, sdap_posix_check_done, req);
    2635             : 
    2636           0 :     return EOK;
    2637             : }
    2638             : 
    2639           0 : static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
    2640             :                                       struct sdap_msg *msg,
    2641             :                                       void *pvt)
    2642             : {
    2643           0 :     struct berval **vals = NULL;
    2644           0 :     struct sdap_posix_check_state *state =
    2645             :         talloc_get_type(pvt, struct sdap_posix_check_state);
    2646             :     char *dn;
    2647             :     char *endptr;
    2648             : 
    2649           0 :     dn = ldap_get_dn(sh->ldap, msg->msg);
    2650           0 :     if (dn == NULL) {
    2651           0 :         DEBUG(SSSDBG_TRACE_LIBS,
    2652             :               "Search did not find any entry with POSIX attributes\n");
    2653           0 :         goto done;
    2654             :     }
    2655           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Found [%s] with POSIX attributes\n", dn);
    2656           0 :     ldap_memfree(dn);
    2657             : 
    2658           0 :     vals = ldap_get_values_len(sh->ldap, msg->msg,
    2659           0 :                                state->opts->user_map[SDAP_AT_USER_UID].name);
    2660           0 :     if (vals == NULL) {
    2661           0 :         vals = ldap_get_values_len(sh->ldap, msg->msg,
    2662           0 :                                state->opts->group_map[SDAP_AT_GROUP_GID].name);
    2663           0 :         if (vals == NULL) {
    2664           0 :             DEBUG(SSSDBG_TRACE_LIBS, "Entry does not have POSIX attrs?\n");
    2665           0 :             goto done;
    2666             :         }
    2667             :     }
    2668             : 
    2669           0 :     if (vals[0] == NULL) {
    2670           0 :         DEBUG(SSSDBG_TRACE_LIBS, "No value for POSIX attr\n");
    2671           0 :         goto done;
    2672             :     }
    2673             : 
    2674           0 :     errno = 0;
    2675           0 :     strtouint32(vals[0]->bv_val, &endptr, 10);
    2676           0 :     if (errno || *endptr || (vals[0]->bv_val == endptr)) {
    2677           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    2678             :               "POSIX attribute is not a number: %s\n", vals[0]->bv_val);
    2679             :     }
    2680             : 
    2681           0 :     state->has_posix = true;
    2682             : done:
    2683           0 :     ldap_value_free_len(vals);
    2684           0 :     return EOK;
    2685             : }
    2686             : 
    2687           0 : static void sdap_posix_check_done(struct tevent_req *subreq)
    2688             : {
    2689           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    2690             :                                                       struct tevent_req);
    2691           0 :     struct sdap_posix_check_state *state =
    2692           0 :         tevent_req_data(req, struct sdap_posix_check_state);
    2693             :     errno_t ret;
    2694             : 
    2695           0 :     ret = sdap_get_generic_ext_recv(subreq, NULL, NULL, NULL);
    2696           0 :     talloc_zfree(subreq);
    2697           0 :     if (ret != EOK) {
    2698           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2699             :               "sdap_get_generic_ext_recv failed [%d]: %s\n",
    2700             :               ret, strerror(ret));
    2701           0 :         tevent_req_error(req, ret);
    2702           0 :         return;
    2703             :     }
    2704             : 
    2705             :     /* Positive hit is definitve, no need to search other bases */
    2706           0 :     if (state->has_posix == true) {
    2707           0 :         DEBUG(SSSDBG_FUNC_DATA, "Server has POSIX attributes\n");
    2708           0 :         tevent_req_done(req);
    2709           0 :         return;
    2710             :     }
    2711             : 
    2712           0 :     state->base_iter++;
    2713           0 :     if (state->search_bases[state->base_iter]) {
    2714             :         /* There are more search bases to try */
    2715           0 :         ret = sdap_posix_check_next(req);
    2716           0 :         if (ret != EOK) {
    2717           0 :             tevent_req_error(req, ret);
    2718             :         }
    2719           0 :         return;
    2720             :     }
    2721             : 
    2722             :     /* All bases done! */
    2723           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Cycled through all bases\n");
    2724           0 :     tevent_req_done(req);
    2725             : }
    2726             : 
    2727           0 : int sdap_posix_check_recv(struct tevent_req *req,
    2728             :                           bool *_has_posix)
    2729             : {
    2730           0 :     struct sdap_posix_check_state *state = tevent_req_data(req,
    2731             :                                             struct sdap_posix_check_state);
    2732             : 
    2733           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    2734             : 
    2735           0 :     *_has_posix = state->has_posix;
    2736           0 :     return EOK;
    2737             : }
    2738             : 
    2739             : /* ==Generic Deref Search============================================ */
    2740             : enum sdap_deref_type {
    2741             :     SDAP_DEREF_OPENLDAP,
    2742             :     SDAP_DEREF_ASQ
    2743             : };
    2744             : 
    2745             : struct sdap_deref_search_state {
    2746             :     struct sdap_handle *sh;
    2747             :     size_t reply_count;
    2748             :     struct sdap_deref_attrs **reply;
    2749             :     enum sdap_deref_type deref_type;
    2750             : };
    2751             : 
    2752             : static void sdap_deref_search_done(struct tevent_req *subreq);
    2753             : static void sdap_deref_search_with_filter_done(struct tevent_req *subreq);
    2754             : 
    2755             : struct tevent_req *
    2756           0 : sdap_deref_search_with_filter_send(TALLOC_CTX *memctx,
    2757             :                                    struct tevent_context *ev,
    2758             :                                    struct sdap_options *opts,
    2759             :                                    struct sdap_handle *sh,
    2760             :                                    const char *search_base,
    2761             :                                    const char *filter,
    2762             :                                    const char *deref_attr,
    2763             :                                    const char **attrs,
    2764             :                                    int num_maps,
    2765             :                                    struct sdap_attr_map_info *maps,
    2766             :                                    int timeout)
    2767             : {
    2768           0 :     struct tevent_req *req = NULL;
    2769           0 :     struct tevent_req *subreq = NULL;
    2770             :     struct sdap_deref_search_state *state;
    2771             : 
    2772           0 :     req = tevent_req_create(memctx, &state, struct sdap_deref_search_state);
    2773           0 :     if (!req) return NULL;
    2774             : 
    2775           0 :     state->sh = sh;
    2776           0 :     state->reply_count = 0;
    2777           0 :     state->reply = NULL;
    2778             : 
    2779           0 :     if (sdap_is_control_supported(sh, LDAP_CONTROL_X_DEREF)) {
    2780           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Server supports OpenLDAP deref\n");
    2781           0 :         state->deref_type = SDAP_DEREF_OPENLDAP;
    2782             : 
    2783           0 :         subreq = sdap_x_deref_search_send(state, ev, opts, sh, search_base,
    2784             :                                           filter, deref_attr, attrs, maps,
    2785             :                                           num_maps, timeout);
    2786           0 :         if (!subreq) {
    2787           0 :             DEBUG(SSSDBG_OP_FAILURE, "Cannot start OpenLDAP deref search\n");
    2788           0 :             goto fail;
    2789             :         }
    2790             :     } else {
    2791           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2792             :               "Server does not support any known deref method!\n");
    2793           0 :         goto fail;
    2794             :     }
    2795             : 
    2796           0 :     tevent_req_set_callback(subreq, sdap_deref_search_with_filter_done, req);
    2797           0 :     return req;
    2798             : 
    2799             : fail:
    2800           0 :     talloc_zfree(req);
    2801           0 :     return NULL;
    2802             : }
    2803             : 
    2804           0 : static void sdap_deref_search_with_filter_done(struct tevent_req *subreq)
    2805             : {
    2806           0 :     sdap_deref_search_done(subreq);
    2807           0 : }
    2808             : 
    2809           0 : int sdap_deref_search_with_filter_recv(struct tevent_req *req,
    2810             :                                        TALLOC_CTX *mem_ctx,
    2811             :                                        size_t *reply_count,
    2812             :                                        struct sdap_deref_attrs ***reply)
    2813             : {
    2814           0 :     return sdap_deref_search_recv(req, mem_ctx, reply_count, reply);
    2815             : }
    2816             : 
    2817             : struct tevent_req *
    2818           0 : sdap_deref_search_send(TALLOC_CTX *memctx,
    2819             :                        struct tevent_context *ev,
    2820             :                        struct sdap_options *opts,
    2821             :                        struct sdap_handle *sh,
    2822             :                        const char *base_dn,
    2823             :                        const char *deref_attr,
    2824             :                        const char **attrs,
    2825             :                        int num_maps,
    2826             :                        struct sdap_attr_map_info *maps,
    2827             :                        int timeout)
    2828             : {
    2829           0 :     struct tevent_req *req = NULL;
    2830           0 :     struct tevent_req *subreq = NULL;
    2831             :     struct sdap_deref_search_state *state;
    2832             : 
    2833           0 :     req = tevent_req_create(memctx, &state, struct sdap_deref_search_state);
    2834           0 :     if (!req) return NULL;
    2835             : 
    2836           0 :     state->sh = sh;
    2837           0 :     state->reply_count = 0;
    2838           0 :     state->reply = NULL;
    2839             : 
    2840           0 :     if (sdap_is_control_supported(sh, LDAP_SERVER_ASQ_OID)) {
    2841           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Server supports ASQ\n");
    2842           0 :         state->deref_type = SDAP_DEREF_ASQ;
    2843             : 
    2844           0 :         subreq = sdap_asq_search_send(state, ev, opts, sh, base_dn,
    2845             :                                       deref_attr, attrs, maps, num_maps,
    2846             :                                       timeout);
    2847           0 :         if (!subreq) {
    2848           0 :             DEBUG(SSSDBG_OP_FAILURE, "Cannot start ASQ search\n");
    2849           0 :             goto fail;
    2850             :         }
    2851           0 :     } else if (sdap_is_control_supported(sh, LDAP_CONTROL_X_DEREF)) {
    2852           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Server supports OpenLDAP deref\n");
    2853           0 :         state->deref_type = SDAP_DEREF_OPENLDAP;
    2854             : 
    2855           0 :         subreq = sdap_x_deref_search_send(state, ev, opts, sh, base_dn, NULL,
    2856             :                                           deref_attr, attrs, maps, num_maps,
    2857             :                                           timeout);
    2858           0 :         if (!subreq) {
    2859           0 :             DEBUG(SSSDBG_OP_FAILURE, "Cannot start OpenLDAP deref search\n");
    2860           0 :             goto fail;
    2861             :         }
    2862             :     } else {
    2863           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2864             :               "Server does not support any known deref method!\n");
    2865           0 :         goto fail;
    2866             :     }
    2867             : 
    2868           0 :     tevent_req_set_callback(subreq, sdap_deref_search_done, req);
    2869           0 :     return req;
    2870             : 
    2871             : fail:
    2872           0 :     talloc_zfree(req);
    2873           0 :     return NULL;
    2874             : }
    2875             : 
    2876           0 : static void sdap_deref_search_done(struct tevent_req *subreq)
    2877             : {
    2878           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    2879             :                                                       struct tevent_req);
    2880           0 :     struct sdap_deref_search_state *state = tevent_req_data(req,
    2881             :                                             struct sdap_deref_search_state);
    2882             :     int ret;
    2883             : 
    2884           0 :     switch (state->deref_type) {
    2885             :     case SDAP_DEREF_OPENLDAP:
    2886           0 :         ret = sdap_x_deref_search_recv(subreq, state,
    2887             :                 &state->reply_count, &state->reply);
    2888           0 :         break;
    2889             :     case SDAP_DEREF_ASQ:
    2890           0 :         ret = sdap_asq_search_recv(subreq, state,
    2891             :                 &state->reply_count, &state->reply);
    2892           0 :         break;
    2893             :     default:
    2894           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unknown deref method\n");
    2895           0 :         tevent_req_error(req, EINVAL);
    2896           0 :         return;
    2897             :     }
    2898             : 
    2899           0 :     talloc_zfree(subreq);
    2900           0 :     if (ret != EOK) {
    2901           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2902             :               "dereference processing failed [%d]: %s\n", ret, strerror(ret));
    2903           0 :         if (ret == ENOTSUP) {
    2904           0 :             sss_log(SSS_LOG_WARNING,
    2905             :                 "LDAP server claims to support deref, but deref search failed. "
    2906             :                 "Disabling deref for further requests. You can permanently "
    2907             :                 "disable deref by setting ldap_deref_threshold to 0 in domain "
    2908             :                 "configuration.");
    2909           0 :             state->sh->disable_deref = true;
    2910             :         } else {
    2911           0 :             sss_log(SSS_LOG_WARNING, "dereference processing failed : %s", strerror(ret));
    2912             :         }
    2913           0 :         tevent_req_error(req, ret);
    2914           0 :         return;
    2915             :     }
    2916             : 
    2917           0 :     tevent_req_done(req);
    2918             : }
    2919             : 
    2920           0 : int sdap_deref_search_recv(struct tevent_req *req,
    2921             :                            TALLOC_CTX *mem_ctx,
    2922             :                            size_t *reply_count,
    2923             :                            struct sdap_deref_attrs ***reply)
    2924             : {
    2925           0 :     struct sdap_deref_search_state *state = tevent_req_data(req,
    2926             :                                             struct sdap_deref_search_state);
    2927           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    2928             : 
    2929           0 :     *reply_count = state->reply_count;
    2930           0 :     *reply = talloc_steal(mem_ctx, state->reply);
    2931             : 
    2932           0 :     return EOK;
    2933             : }
    2934             : 
    2935           0 : bool sdap_has_deref_support(struct sdap_handle *sh, struct sdap_options *opts)
    2936             : {
    2937           0 :     const char *deref_oids[][2] = { { LDAP_SERVER_ASQ_OID, "ASQ" },
    2938             :                                     { LDAP_CONTROL_X_DEREF, "OpenLDAP" },
    2939             :                                     { NULL, NULL }
    2940             :                                   };
    2941             :     int i;
    2942             :     int deref_threshold;
    2943             : 
    2944           0 :     if (sh->disable_deref) {
    2945           0 :         return false;
    2946             :     }
    2947             : 
    2948           0 :     deref_threshold = dp_opt_get_int(opts->basic, SDAP_DEREF_THRESHOLD);
    2949           0 :     if (deref_threshold == 0) {
    2950           0 :         return false;
    2951             :     }
    2952             : 
    2953           0 :     for (i=0; deref_oids[i][0]; i++) {
    2954           0 :         if (sdap_is_control_supported(sh, deref_oids[i][0])) {
    2955           0 :             DEBUG(SSSDBG_TRACE_FUNC, "The server supports deref method %s\n",
    2956             :                       deref_oids[i][1]);
    2957           0 :             return true;
    2958             :         }
    2959             :     }
    2960             : 
    2961           0 :     return false;
    2962             : }

Generated by: LCOV version 1.10