LCOV - code coverage report
Current view: top level - responder/common - responder_dp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 61 303 20.1 %
Date: 2016-06-29 Functions: 4 13 30.8 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Simo Sorce <ssorce@redhat.com>
       4             :         Stephen Gallagher <sgallagh@redhat.com>
       5             : 
       6             :     Copyright (C) 2009 Red Hat
       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 <sys/time.h>
      24             : #include <time.h>
      25             : #include "util/util.h"
      26             : #include "responder/common/responder_packet.h"
      27             : #include "responder/common/responder.h"
      28             : #include "providers/data_provider.h"
      29             : #include "providers/data_provider/dp_responder_iface.h"
      30             : #include "sbus/sbus_client.h"
      31             : 
      32             : struct sss_dp_req;
      33             : 
      34             : struct sss_dp_callback {
      35             :     struct sss_dp_callback *prev;
      36             :     struct sss_dp_callback *next;
      37             : 
      38             :     struct tevent_req *req;
      39             :     struct sss_dp_req *sdp_req;
      40             : };
      41             : 
      42             : struct sss_dp_req {
      43             :     struct resp_ctx *rctx;
      44             :     struct tevent_context *ev;
      45             :     DBusPendingCall *pending_reply;
      46             : 
      47             :     hash_key_t *key;
      48             : 
      49             :     struct sss_dp_callback *cb_list;
      50             : 
      51             :     dbus_uint16_t dp_err;
      52             :     dbus_uint32_t dp_ret;
      53             :     char *err_msg;
      54             : };
      55             : 
      56           0 : static int sss_dp_callback_destructor(void *ptr)
      57             : {
      58           0 :     struct sss_dp_callback *cb =
      59             :             talloc_get_type(ptr, struct sss_dp_callback);
      60             : 
      61           0 :     DLIST_REMOVE(cb->sdp_req->cb_list, cb);
      62             : 
      63           0 :     return EOK;
      64             : }
      65             : 
      66           0 : static int sss_dp_req_destructor(void *ptr)
      67             : {
      68             :     struct sss_dp_callback *cb;
      69           0 :     struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req);
      70             :     struct sss_dp_req_state *state;
      71             :     int hret;
      72             : 
      73             :     /* Cancel Dbus pending reply if still pending */
      74           0 :     if (sdp_req->pending_reply) {
      75           0 :         dbus_pending_call_cancel(sdp_req->pending_reply);
      76           0 :         sdp_req->pending_reply = NULL;
      77             :     }
      78             : 
      79             :     /* Do not call callbacks if the responder is shutting down, because
      80             :      * the top level responder context (pam_ctx, sudo_ctx, ...) may be
      81             :      * already semi-freed and we may end up accessing freed memory.
      82             :      */
      83           0 :     if (sdp_req->rctx->shutting_down) {
      84           0 :         return 0;
      85             :     }
      86             : 
      87             :     /* If there are callbacks that haven't been invoked, return
      88             :      * an error now.
      89             :      */
      90           0 :     while ((cb = sdp_req->cb_list) != NULL) {
      91           0 :         state = tevent_req_data(cb->req, struct sss_dp_req_state);
      92           0 :         state->dp_err = DP_ERR_FATAL;
      93           0 :         state->dp_ret = EIO;
      94             : 
      95             :         /* tevent_req_done/error will free cb */
      96           0 :         tevent_req_error(cb->req, EIO);
      97             : 
      98             :         /* Freeing the cb removes it from the cb_list.
      99             :          * Therefore, the cb_list should now be pointing
     100             :          * at a new callback. If it's not, it means the
     101             :          * callback handler didn't free cb and may leak
     102             :          * memory. Be paranoid and protect against this
     103             :          * situation.
     104             :          */
     105           0 :         if (cb == sdp_req->cb_list) {
     106           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     107             :                   "BUG: a callback did not free its request. "
     108             :                    "May leak memory\n");
     109             :             /* Skip to the next since a memory leak is non-fatal */
     110           0 :             sdp_req->cb_list = sdp_req->cb_list->next;
     111             :         }
     112             :     }
     113             : 
     114             :     /* Destroy the hash entry */
     115           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Deleting request: [%s]\n", sdp_req->key->str);
     116           0 :     hret = hash_delete(sdp_req->rctx->dp_request_table, sdp_req->key);
     117           0 :     if (hret != HASH_SUCCESS) {
     118             :         /* This should never happen */
     119           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
     120             :               "BUG: Could not clear [%d:%lu:%s] from request queue: [%s]\n",
     121             :                sdp_req->key->type, sdp_req->key->ul, sdp_req->key->str,
     122             :                hash_error_string(hret));
     123           0 :         return -1;
     124             :     }
     125             : 
     126           0 :     return 0;
     127             : }
     128             : 
     129           0 : static void sss_dp_req_timeout(struct tevent_context *ev,
     130             :                                struct tevent_timer *te,
     131             :                                struct timeval t, void *ptr)
     132             : {
     133             :     /* ptr is a pointer to sidereq */
     134             :     /* Just free it to kill all waiting requests when the timeout fires */
     135           0 :     talloc_zfree(ptr);
     136           0 : }
     137             : 
     138           0 : void handle_requests_after_reconnect(struct resp_ctx *rctx)
     139             : {
     140             :     int ret;
     141             :     hash_value_t *values;
     142             :     unsigned long count, i;
     143             :     struct sss_dp_req *sdp_req;
     144             : 
     145           0 :     if (!rctx->dp_request_table) {
     146           0 :         DEBUG(SSSDBG_TRACE_LIBS, "No requests to handle after reconnect\n");
     147           0 :         return;
     148             :     }
     149             : 
     150           0 :     ret = hash_values(rctx->dp_request_table, &count, &values);
     151           0 :     if (ret != HASH_SUCCESS) {
     152           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "hash_values failed, "
     153             :                   "not all request might be handled after reconnect.\n");
     154           0 :         return;
     155             :     }
     156             : 
     157           0 :     DEBUG(SSSDBG_TRACE_LIBS,
     158             :           "Will handle %lu requests after reconnect\n", count);
     159           0 :     for (i=0; i<count; i++) {
     160           0 :         sdp_req = talloc_get_type(values[i].ptr, struct sss_dp_req);
     161           0 :         talloc_free(sdp_req);
     162             :     }
     163             : }
     164             : 
     165           0 : static int sss_dp_get_reply(DBusPendingCall *pending,
     166             :                             dbus_uint16_t *dp_err,
     167             :                             dbus_uint32_t *dp_ret,
     168             :                             char **err_msg)
     169             : {
     170             :     DBusMessage *reply;
     171             :     DBusError dbus_error;
     172             :     dbus_bool_t ret;
     173             :     int type;
     174           0 :     int err = EOK;
     175             : 
     176           0 :     dbus_error_init(&dbus_error);
     177             : 
     178           0 :     reply = dbus_pending_call_steal_reply(pending);
     179           0 :     if (!reply) {
     180             :         /* reply should never be null. This function shouldn't be called
     181             :          * until reply is valid or timeout has occurred. If reply is NULL
     182             :          * here, something is seriously wrong and we should bail out.
     183             :          */
     184           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     185             :               "Severe error. A reply callback was called but no reply "
     186             :                "was received and no timeout occurred\n");
     187             : 
     188             :         /* FIXME: Destroy this connection ? */
     189           0 :         err = EIO;
     190           0 :         goto done;
     191             :     }
     192             : 
     193           0 :     type = dbus_message_get_type(reply);
     194           0 :     switch (type) {
     195             :     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
     196           0 :         ret = dbus_message_get_args(reply, &dbus_error,
     197             :                                     DBUS_TYPE_UINT16, dp_err,
     198             :                                     DBUS_TYPE_UINT32, dp_ret,
     199             :                                     DBUS_TYPE_STRING, err_msg,
     200             :                                     DBUS_TYPE_INVALID);
     201           0 :         if (!ret) {
     202           0 :             DEBUG(SSSDBG_CRIT_FAILURE,"Failed to parse message\n");
     203             :             /* FIXME: Destroy this connection ? */
     204           0 :             if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
     205           0 :             err = EIO;
     206           0 :             goto done;
     207             :         }
     208           0 :         DEBUG(SSSDBG_TRACE_LIBS,
     209             :               "Got reply from Data Provider - "
     210             :                "DP error code: %u errno: %u error message: %s\n",
     211             :               (unsigned int)*dp_err, (unsigned int)*dp_ret,
     212             :               *err_msg ? *err_msg : "none");
     213           0 :         break;
     214             : 
     215             :     case DBUS_MESSAGE_TYPE_ERROR:
     216           0 :         if (strcmp(dbus_message_get_error_name(reply),
     217             :                    DBUS_ERROR_NO_REPLY) == 0) {
     218           0 :             err = ETIME;
     219           0 :             goto done;
     220             :         }
     221           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"The Data Provider returned an error [%s]\n",
     222             :                  dbus_message_get_error_name(reply));
     223             :         /* Falling through to default intentionally*/
     224             :     default:
     225             :         /*
     226             :          * Timeout or other error occurred or something
     227             :          * unexpected happened.
     228             :          * It doesn't matter which, because either way we
     229             :          * know that this connection isn't trustworthy.
     230             :          * We'll destroy it now.
     231             :          */
     232             : 
     233             :         /* FIXME: Destroy this connection ? */
     234           0 :         err = EIO;
     235             :     }
     236             : 
     237             : done:
     238           0 :     dbus_pending_call_unref(pending);
     239           0 :     dbus_message_unref(reply);
     240             : 
     241           0 :     return err;
     242             : }
     243             : 
     244             : static struct tevent_req *
     245             : sss_dp_internal_get_send(struct resp_ctx *rctx,
     246             :                          hash_key_t *key,
     247             :                          struct sss_domain_info *dom,
     248             :                          DBusMessage *msg);
     249             : 
     250             : static void
     251             : sss_dp_req_done(struct tevent_req *sidereq);
     252             : 
     253             : errno_t
     254           3 : sss_dp_issue_request(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx,
     255             :                      const char *strkey, struct sss_domain_info *dom,
     256             :                      dbus_msg_constructor msg_create, void *pvt,
     257             :                      struct tevent_req *nreq)
     258             : {
     259             :     int hret;
     260             :     hash_value_t value;
     261             :     hash_key_t *key;
     262             :     struct tevent_req *sidereq;
     263             :     struct sss_dp_req *sdp_req;
     264             :     struct sss_dp_callback *cb;
     265             :     struct tevent_timer *te;
     266             :     struct timeval tv;
     267             :     DBusMessage *msg;
     268           3 :     TALLOC_CTX *tmp_ctx = NULL;
     269             :     errno_t ret;
     270             : 
     271           3 :     tmp_ctx = talloc_new(NULL);
     272           3 :     if (!tmp_ctx) {
     273           0 :         return ENOMEM;
     274             :     }
     275             : 
     276           3 :     key = talloc(tmp_ctx, hash_key_t);
     277           3 :     if (!key) {
     278           0 :         ret = ENOMEM;
     279           0 :         goto fail;
     280             :     }
     281             : 
     282           3 :     key->type = HASH_KEY_STRING;
     283           3 :     key->str = talloc_asprintf(key, "%p:%s", msg_create, strkey);
     284           3 :     if (!key->str) {
     285           0 :         ret = ENOMEM;
     286           0 :         goto fail;
     287             :     }
     288             : 
     289           3 :     DEBUG(SSSDBG_TRACE_FUNC, "Issuing request for [%s]\n", key->str);
     290             : 
     291             :     /* Check the hash for existing references to this request */
     292           3 :     hret = hash_lookup(rctx->dp_request_table, key, &value);
     293           3 :     switch (hret) {
     294             :     case HASH_SUCCESS:
     295             :         /* Request already in progress */
     296           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     297             :               "Identical request in progress: [%s]\n", key->str);
     298           0 :         break;
     299             : 
     300             :     case HASH_ERROR_KEY_NOT_FOUND:
     301             :         /* No such request in progress
     302             :          * Create a new request
     303             :          */
     304           3 :         msg = msg_create(pvt);
     305           3 :         if (!msg) {
     306           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create D-Bus message\n");
     307           0 :             ret = EIO;
     308           0 :             goto fail;
     309             :         }
     310             : 
     311           3 :         value.type = HASH_VALUE_PTR;
     312           3 :         sidereq = sss_dp_internal_get_send(rctx, key, dom, msg);
     313           3 :         dbus_message_unref(msg);
     314           3 :         if (!sidereq) {
     315           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Cannot send D-Bus message\n");
     316           0 :             ret = EIO;
     317           0 :             goto fail;
     318             :         }
     319           3 :         tevent_req_set_callback(sidereq, sss_dp_req_done, NULL);
     320             : 
     321             :         /* add timeout handling so we do not hang forever should something
     322             :          * go worng in the provider. Use 2 sec less than the idle timeout to
     323             :          * give it a chance to reply to the client before closing the
     324             :          * connection. */
     325           3 :         tv = tevent_timeval_current_ofs(rctx->client_idle_timeout - 2, 0);
     326           3 :         te = tevent_add_timer(rctx->ev, sidereq, tv,
     327             :                               sss_dp_req_timeout, sidereq);
     328           3 :         if (!te) {
     329             :             /* Nothing much we can do */
     330           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
     331           0 :             ret = ENOMEM;
     332           0 :             goto fail;
     333             :         }
     334             : 
     335             :         /* We should now be able to find the sdp_req in the hash table */
     336           3 :         hret = hash_lookup(rctx->dp_request_table, key, &value);
     337           3 :         if (hret != HASH_SUCCESS) {
     338             :             /* Something must have gone wrong with creating the request */
     339           3 :             DEBUG(SSSDBG_CRIT_FAILURE, "The request has disappeared?\n");
     340           3 :             ret = EIO;
     341           3 :             goto fail;
     342             :         }
     343           0 :         break;
     344             : 
     345             :     default:
     346           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     347             :               "Could not query request list (%s)\n",
     348             :                hash_error_string(hret));
     349           0 :         ret = EIO;
     350           0 :         goto fail;
     351             :     }
     352             : 
     353             :     /* Register this request for results */
     354           0 :     sdp_req = talloc_get_type(value.ptr, struct sss_dp_req);
     355           0 :     if (!sdp_req) {
     356           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not retrieve DP request context\n");
     357           0 :         ret = EIO;
     358           0 :         goto fail;
     359             :     }
     360             : 
     361           0 :     cb = talloc_zero(mem_ctx, struct sss_dp_callback);
     362           0 :     if (!cb) {
     363           0 :         ret = ENOMEM;
     364           0 :         goto fail;
     365             :     }
     366             : 
     367           0 :     cb->req = nreq;
     368           0 :     cb->sdp_req = sdp_req;
     369             : 
     370             :     /* Add it to the list of requests to call */
     371           0 :     DLIST_ADD_END(sdp_req->cb_list, cb,
     372             :                   struct sss_dp_callback *);
     373           0 :     talloc_set_destructor((TALLOC_CTX *)cb,
     374             :                           sss_dp_callback_destructor);
     375             : 
     376           0 :     ret = EOK;
     377             : fail:
     378           3 :     talloc_free(tmp_ctx);
     379           3 :     return ret;
     380             : }
     381             : 
     382             : static void
     383           3 : sss_dp_req_done(struct tevent_req *sidereq)
     384             : {
     385             :     /* Nothing to do here. The callbacks have already been invoked */
     386           3 :     talloc_zfree(sidereq);
     387           3 : }
     388             : 
     389             : errno_t
     390           3 : sss_dp_req_recv(TALLOC_CTX *mem_ctx,
     391             :                 struct tevent_req *sidereq,
     392             :                 dbus_uint16_t *dp_err,
     393             :                 dbus_uint32_t *dp_ret,
     394             :                 char **err_msg)
     395             : {
     396           3 :     struct sss_dp_req_state *state =
     397           3 :             tevent_req_data(sidereq, struct sss_dp_req_state);
     398             : 
     399             :     enum tevent_req_state TRROEstate;
     400             :     uint64_t TRROEerr;
     401             : 
     402           3 :     *dp_err = state->dp_err;
     403           3 :     *dp_ret = state->dp_ret;
     404           3 :     *err_msg = talloc_steal(mem_ctx, state->err_msg);
     405             : 
     406           3 :     if (tevent_req_is_error(sidereq, &TRROEstate, &TRROEerr)) {
     407           3 :         if (TRROEstate == TEVENT_REQ_USER_ERROR) {
     408           3 :             *dp_err = DP_ERR_FATAL;
     409           3 :             *dp_ret = TRROEerr;
     410             :         } else {
     411           0 :             return EIO;
     412             :         }
     413             :     }
     414             : 
     415           3 :     return EOK;
     416             : }
     417             : 
     418             : /* Send a request to the data provider
     419             :  * Once this function is called, the communication
     420             :  * with the data provider will always run to
     421             :  * completion. Freeing the returned tevent_req will
     422             :  * cancel the notification of completion, but not
     423             :  * the data provider action.
     424             :  */
     425             : static DBusMessage *sss_dp_get_account_msg(void *pvt);
     426             : 
     427             : struct sss_dp_account_info {
     428             :     struct sss_domain_info *dom;
     429             : 
     430             :     bool fast_reply;
     431             :     enum sss_dp_acct_type type;
     432             :     const char *opt_name;
     433             :     const char *extra;
     434             :     uint32_t opt_id;
     435             : };
     436             : 
     437             : struct tevent_req *
     438           0 : sss_dp_get_account_send(TALLOC_CTX *mem_ctx,
     439             :                         struct resp_ctx *rctx,
     440             :                         struct sss_domain_info *dom,
     441             :                         bool fast_reply,
     442             :                         enum sss_dp_acct_type type,
     443             :                         const char *opt_name,
     444             :                         uint32_t opt_id,
     445             :                         const char *extra)
     446             : {
     447             :     errno_t ret;
     448             :     struct tevent_req *req;
     449             :     struct sss_dp_account_info *info;
     450             :     struct sss_dp_req_state *state;
     451             :     char *key;
     452             : 
     453           0 :     req = tevent_req_create(mem_ctx, &state, struct sss_dp_req_state);
     454           0 :     if (!req) {
     455           0 :         return NULL;
     456             :     }
     457             : 
     458             :     /* either, or, not both */
     459           0 :     if (opt_name && opt_id) {
     460           0 :         ret = EINVAL;
     461           0 :         goto error;
     462             :     }
     463             : 
     464           0 :     if (!dom) {
     465           0 :         ret = EINVAL;
     466           0 :         goto error;
     467             :     }
     468             : 
     469           0 :     info = talloc_zero(state, struct sss_dp_account_info);
     470           0 :     info->fast_reply = fast_reply;
     471           0 :     info->type = type;
     472           0 :     info->opt_name = opt_name;
     473           0 :     info->opt_id = opt_id;
     474           0 :     info->extra = extra;
     475           0 :     info->dom = dom;
     476             : 
     477           0 :     if (opt_name) {
     478           0 :         if (extra) {
     479           0 :             key = talloc_asprintf(state, "%d:%s:%s@%s",
     480             :                                   type, opt_name, extra, dom->name);
     481             :         } else {
     482           0 :             key = talloc_asprintf(state, "%d:%s@%s",
     483             :                                   type, opt_name, dom->name);
     484             :         }
     485           0 :     } else if (opt_id) {
     486           0 :         if (extra) {
     487           0 :             key = talloc_asprintf(state, "%d:%d:%s@%s",
     488             :                                   type, opt_id, extra, dom->name);
     489             :         } else {
     490           0 :             key = talloc_asprintf(state, "%d:%d@%s", type, opt_id, dom->name);
     491             :         }
     492             :     } else {
     493           0 :         key = talloc_asprintf(state, "%d:*@%s", type, dom->name);
     494             :     }
     495           0 :     if (!key) {
     496           0 :         ret = ENOMEM;
     497           0 :         goto error;
     498             :     }
     499             : 
     500           0 :     ret = sss_dp_issue_request(state, rctx, key, dom, sss_dp_get_account_msg,
     501             :                                info, req);
     502           0 :     talloc_free(key);
     503           0 :     if (ret != EOK) {
     504           0 :         DEBUG(SSSDBG_OP_FAILURE,
     505             :               "Could not issue DP request [%d]: %s\n",
     506             :                ret, strerror(ret));
     507           0 :         goto error;
     508             :     }
     509             : 
     510           0 :     return req;
     511             : 
     512             : error:
     513           0 :     tevent_req_error(req, ret);
     514           0 :     tevent_req_post(req, rctx->ev);
     515           0 :     return req;
     516             : }
     517             : 
     518             : static DBusMessage *
     519           0 : sss_dp_get_account_msg(void *pvt)
     520             : {
     521             :     DBusMessage *msg;
     522             :     dbus_bool_t dbret;
     523             :     struct sss_dp_account_info *info;
     524             :     uint32_t dp_flags;
     525             :     uint32_t entry_type;
     526           0 :     uint32_t attrs_type = BE_ATTR_CORE;
     527             :     char *filter;
     528             : 
     529           0 :     info = talloc_get_type(pvt, struct sss_dp_account_info);
     530             : 
     531           0 :     switch (info->type) {
     532             :         case SSS_DP_USER:
     533             :         case SSS_DP_WILDCARD_USER:
     534           0 :             entry_type = BE_REQ_USER;
     535           0 :             break;
     536             :         case SSS_DP_GROUP:
     537             :         case SSS_DP_WILDCARD_GROUP:
     538           0 :             entry_type = BE_REQ_GROUP;
     539           0 :             break;
     540             :         case SSS_DP_INITGROUPS:
     541           0 :             entry_type = BE_REQ_INITGROUPS;
     542           0 :             break;
     543             :         case SSS_DP_NETGR:
     544           0 :             entry_type = BE_REQ_NETGROUP;
     545           0 :             break;
     546             :         case SSS_DP_SERVICES:
     547           0 :             entry_type = BE_REQ_SERVICES;
     548           0 :             break;
     549             :         case SSS_DP_SECID:
     550           0 :             entry_type = BE_REQ_BY_SECID;
     551           0 :             break;
     552             :         case SSS_DP_USER_AND_GROUP:
     553           0 :             entry_type = BE_REQ_USER_AND_GROUP;
     554           0 :             break;
     555             :         case SSS_DP_CERT:
     556           0 :             entry_type = BE_REQ_BY_CERT;
     557           0 :             break;
     558             :     }
     559             : 
     560           0 :     dp_flags = info->fast_reply ? DP_FAST_REPLY : 0;
     561             : 
     562           0 :     if (info->opt_name) {
     563           0 :         if (info->type == SSS_DP_SECID) {
     564           0 :             filter = talloc_asprintf(info, "%s=%s", DP_SEC_ID,
     565             :                                      info->opt_name);
     566           0 :         } else if (info->type == SSS_DP_CERT) {
     567           0 :             filter = talloc_asprintf(info, "%s=%s", DP_CERT,
     568             :                                      info->opt_name);
     569           0 :         } else if (info->type == SSS_DP_WILDCARD_USER ||
     570           0 :                    info->type == SSS_DP_WILDCARD_GROUP) {
     571           0 :             filter = talloc_asprintf(info, "%s=%s", DP_WILDCARD,
     572             :                                      info->opt_name);
     573             :         } else {
     574           0 :             filter = talloc_asprintf(info, "name=%s", info->opt_name);
     575             :         }
     576           0 :     } else if (info->opt_id) {
     577           0 :         filter = talloc_asprintf(info, "idnumber=%u", info->opt_id);
     578             :     } else {
     579           0 :         filter = talloc_strdup(info, ENUM_INDICATOR);
     580             :     }
     581           0 :     if (!filter) {
     582           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
     583           0 :         return NULL;
     584             :     }
     585             : 
     586           0 :     msg = dbus_message_new_method_call(NULL,
     587             :                                        DP_PATH,
     588             :                                        IFACE_DP,
     589             :                                        IFACE_DP_GETACCOUNTINFO);
     590           0 :     if (msg == NULL) {
     591           0 :         talloc_free(filter);
     592           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
     593           0 :         return NULL;
     594             :     }
     595             : 
     596             :     /* create the message */
     597           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     598             :           "Creating request for [%s][%#x][%s][%d][%s:%s]\n",
     599             :           info->dom->name, entry_type, be_req2str(entry_type), attrs_type,
     600             :           filter, info->extra == NULL ? "-" : info->extra);
     601             : 
     602           0 :     if (info->extra == NULL) {
     603             :         /* D-Bus can't deal with NULL. */
     604           0 :         info->extra = "";
     605             :     }
     606             : 
     607           0 :     dbret = dbus_message_append_args(msg,
     608             :                                      DBUS_TYPE_UINT32, &dp_flags,
     609             :                                      DBUS_TYPE_UINT32, &entry_type,
     610             :                                      DBUS_TYPE_UINT32, &attrs_type,
     611             :                                      DBUS_TYPE_STRING, &filter,
     612           0 :                                      DBUS_TYPE_STRING, &info->dom->name,
     613             :                                      DBUS_TYPE_STRING, &info->extra,
     614             :                                      DBUS_TYPE_INVALID);
     615           0 :     talloc_free(filter);
     616           0 :     if (!dbret) {
     617           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
     618           0 :         dbus_message_unref(msg);
     619           0 :         return NULL;
     620             :     }
     621             : 
     622           0 :     return msg;
     623             : }
     624             : 
     625             : errno_t
     626           0 : sss_dp_get_account_recv(TALLOC_CTX *mem_ctx,
     627             :                         struct tevent_req *req,
     628             :                         dbus_uint16_t *dp_err,
     629             :                         dbus_uint32_t *dp_ret,
     630             :                         char **err_msg)
     631             : {
     632           0 :     return sss_dp_req_recv(mem_ctx, req, dp_err, dp_ret, err_msg);
     633             : }
     634             : 
     635             : struct dp_internal_get_state {
     636             :     struct resp_ctx *rctx;
     637             :     struct sss_domain_info *dom;
     638             : 
     639             :     struct sss_dp_req *sdp_req;
     640             :     DBusPendingCall *pending_reply;
     641             : };
     642             : 
     643             : static void sss_dp_internal_get_done(DBusPendingCall *pending, void *ptr);
     644             : 
     645             : static struct tevent_req *
     646           3 : sss_dp_internal_get_send(struct resp_ctx *rctx,
     647             :                          hash_key_t *key,
     648             :                          struct sss_domain_info *dom,
     649             :                          DBusMessage *msg)
     650             : {
     651             :     errno_t ret;
     652             :     int hret;
     653             :     struct tevent_req *req;
     654             :     struct dp_internal_get_state *state;
     655             :     struct be_conn *be_conn;
     656             :     hash_value_t value;
     657             : 
     658             :     /* Internal requests need to be allocated on the responder context
     659             :      * so that they don't go away if a client disconnects. The worst-
     660             :      * case scenario here is that the cache is updated without any
     661             :      * client expecting a response.
     662             :      */
     663           3 :     req = tevent_req_create(rctx,
     664             :                             &state,
     665             :                             struct dp_internal_get_state);
     666           3 :     if (!req)  return NULL;
     667             : 
     668           3 :     state->rctx = rctx;
     669           3 :     state->dom = dom;
     670             : 
     671           3 :     state->sdp_req = talloc_zero(state, struct sss_dp_req);
     672           3 :     if (!state->sdp_req) {
     673           0 :         ret = ENOMEM;
     674           0 :         goto error;
     675             :     }
     676           3 :     state->sdp_req->rctx = rctx;
     677           3 :     state->sdp_req->ev = rctx->ev;
     678             : 
     679             :     /* Copy the key to use when calling the destructor
     680             :      * It needs to be a copy because the original request
     681             :      * might be freed if it no longer cares about the reply.
     682             :      */
     683           3 :     state->sdp_req->key = talloc_steal(state->sdp_req, key);
     684             : 
     685             :     /* double check dp_ctx has actually been initialized.
     686             :      * in some pathological cases it may happen that nss starts up before
     687             :      * dp connection code is actually able to establish a connection.
     688             :      */
     689           3 :     ret = sss_dp_get_domain_conn(rctx, dom->conn_name, &be_conn);
     690           3 :     if (ret != EOK) {
     691           3 :         DEBUG(SSSDBG_CRIT_FAILURE,
     692             :               "BUG: The Data Provider connection for %s is not available!\n",
     693             :               dom->name);
     694           3 :         ret = EIO;
     695           3 :         goto error;
     696             :     }
     697             : 
     698           0 :     ret = sbus_conn_send(be_conn->conn, msg,
     699             :                          SSS_CLI_SOCKET_TIMEOUT / 2,
     700             :                          sss_dp_internal_get_done,
     701             :                          req,
     702           0 :                          &state->sdp_req->pending_reply);
     703           0 :     if (ret != EOK) {
     704             :         /*
     705             :          * Critical Failure
     706             :          * We can't communicate on this connection
     707             :          */
     708           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     709             :               "D-BUS send failed.\n");
     710           0 :         ret = EIO;
     711           0 :         goto error;
     712             :     }
     713             : 
     714             :     /* Add this sdp_req to the hash table */
     715           0 :     value.type = HASH_VALUE_PTR;
     716           0 :     value.ptr = state->sdp_req;
     717             : 
     718           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Entering request [%s]\n", key->str);
     719           0 :     hret = hash_enter(rctx->dp_request_table, key, &value);
     720           0 :     if (hret != HASH_SUCCESS) {
     721           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     722             :               "Could not store request query (%s)\n",
     723             :                hash_error_string(hret));
     724           0 :         ret = EIO;
     725           0 :         goto error;
     726             :     }
     727           0 :     talloc_set_destructor((TALLOC_CTX *)state->sdp_req,
     728             :                           sss_dp_req_destructor);
     729             : 
     730           0 :     return req;
     731             : 
     732             : error:
     733           3 :     tevent_req_error(req, ret);
     734           3 :     tevent_req_post(req, rctx->ev);
     735           3 :     return req;
     736             : }
     737             : 
     738           0 : static void sss_dp_internal_get_done(DBusPendingCall *pending, void *ptr)
     739             : {
     740             :     int ret;
     741             :     struct tevent_req *req;
     742             :     struct sss_dp_req *sdp_req;
     743             :     struct sss_dp_callback *cb;
     744             :     struct dp_internal_get_state *state;
     745             :     struct sss_dp_req_state *cb_state;
     746             : 
     747           0 :     req = talloc_get_type(ptr, struct tevent_req);
     748           0 :     state = tevent_req_data(req, struct dp_internal_get_state);
     749           0 :     sdp_req = state->sdp_req;
     750             : 
     751             :     /* prevent trying to cancel a reply that we already received */
     752           0 :     sdp_req->pending_reply = NULL;
     753             : 
     754           0 :     ret = sss_dp_get_reply(pending,
     755             :                            &sdp_req->dp_err,
     756             :                            &sdp_req->dp_ret,
     757             :                            &sdp_req->err_msg);
     758           0 :     if (ret != EOK) {
     759           0 :         if (ret == ETIME) {
     760           0 :             sdp_req->dp_err = DP_ERR_TIMEOUT;
     761           0 :             sdp_req->dp_ret = ret;
     762           0 :             sdp_req->err_msg = talloc_strdup(sdp_req, "Request timed out");
     763             :         }
     764             :         else {
     765           0 :             sdp_req->dp_err = DP_ERR_FATAL;
     766           0 :             sdp_req->dp_ret = ret;
     767           0 :             sdp_req->err_msg =
     768           0 :                 talloc_strdup(sdp_req,
     769             :                               "Failed to get reply from Data Provider");
     770             :         }
     771             :     }
     772             : 
     773             :     /* Check whether we need to issue any callbacks */
     774           0 :     while ((cb = sdp_req->cb_list) != NULL) {
     775           0 :         cb_state = tevent_req_data(cb->req, struct sss_dp_req_state);
     776           0 :         cb_state->dp_err = sdp_req->dp_err;
     777           0 :         cb_state->dp_ret = sdp_req->dp_ret;
     778           0 :         cb_state->err_msg = talloc_strdup(cb_state, sdp_req->err_msg);
     779             :         /* Don't bother checking for NULL. If it fails due to ENOMEM,
     780             :          * we can't really handle it anyway.
     781             :          */
     782             : 
     783             :         /* tevent_req_done/error will free cb */
     784           0 :         if (ret == EOK) {
     785           0 :             tevent_req_done(cb->req);
     786             :         } else {
     787           0 :             tevent_req_error(cb->req, ret);
     788             :         }
     789             : 
     790             :         /* Freeing the cb removes it from the cb_list.
     791             :          * Therefore, the cb_list should now be pointing
     792             :          * at a new callback. If it's not, it means the
     793             :          * callback handler didn't free cb and may leak
     794             :          * memory. Be paranoid and protect against this
     795             :          * situation.
     796             :          */
     797           0 :         if (cb == sdp_req->cb_list) {
     798           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     799             :                   "BUG: a callback did not free its request. "
     800             :                    "May leak memory\n");
     801             :             /* Skip to the next since a memory leak is non-fatal */
     802           0 :             sdp_req->cb_list = sdp_req->cb_list->next;
     803             :         }
     804             :     }
     805             : 
     806             :     /* We're done with this request. Free the sdp_req
     807             :      * This will clean up the hash table entry as well
     808             :      */
     809           0 :     talloc_zfree(sdp_req);
     810             : 
     811             :     /* Free the sidereq to free the rest of the memory allocated with the
     812             :      * internal dp request. */
     813           0 :     if (ret == EOK) {
     814           0 :         tevent_req_done(req);
     815             :     } else {
     816           0 :         tevent_req_error(req, ret);
     817             :     }
     818           0 : }

Generated by: LCOV version 1.10