LCOV - code coverage report
Current view: top level - responder/common - responder_dp.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 312 0.0 %
Date: 2015-10-19 Functions: 0 13 0.0 %

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

Generated by: LCOV version 1.10