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

Generated by: LCOV version 1.10