LCOV - code coverage report
Current view: top level - providers/data_provider - dp_request_reply.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 129 0.0 %
Date: 2016-06-29 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Pavel Březina <pbrezina@redhat.com>
       4             : 
       5             :     Copyright (C) 2016 Red Hat
       6             : 
       7             :     This program is free software; you can redistribute it and/or modify
       8             :     it under the terms of the GNU General Public License as published by
       9             :     the Free Software Foundation; either version 3 of the License, or
      10             :     (at your option) any later version.
      11             : 
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU General Public License
      18             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include <talloc.h>
      22             : #include <tevent.h>
      23             : #include <dbus/dbus.h>
      24             : 
      25             : #include "sbus/sssd_dbus_errors.h"
      26             : #include "providers/data_provider/dp_private.h"
      27             : #include "providers/backend.h"
      28             : #include "util/dlinklist.h"
      29             : #include "util/sss_utf8.h"
      30             : #include "util/util.h"
      31             : 
      32           0 : void dp_req_reply_default(const char *req_name,
      33             :                           struct sbus_request *sbus_req,
      34             :                           void *data)
      35             : {
      36           0 :     DP_REQ_DEBUG(SSSDBG_TRACE_FUNC, req_name, "Replying with empty message");
      37             : 
      38           0 :     sbus_request_return_and_finish(sbus_req, DBUS_TYPE_INVALID);
      39           0 : }
      40             : 
      41           0 : static DBusError *dp_req_reply_gen_error(TALLOC_CTX *mem_ctx,
      42             :                                          const char *req_name,
      43             :                                          errno_t ret)
      44             : {
      45             :     DBusError *error;
      46             : 
      47           0 :     switch (ret) {
      48             :     case EOK:
      49           0 :         DP_REQ_DEBUG(SSSDBG_CRIT_FAILURE, req_name,
      50             :                      "Bug: Success case must be handled by custom handler.");
      51           0 :         error = sbus_error_new(mem_ctx, SBUS_ERROR_INTERNAL,
      52             :                      "Operation succeeded but result was not handled");
      53           0 :         break;
      54             :     case ERR_OFFLINE:
      55           0 :         DP_REQ_DEBUG(SSSDBG_MINOR_FAILURE, req_name,
      56             :                      "Finished. Backend is currently offline.");
      57             : 
      58           0 :         error = sbus_error_new(mem_ctx, SBUS_ERROR_DP_OFFLINE,
      59             :                      "Backend is currently offline");
      60           0 :         break;
      61             :     case ERR_MISSING_DP_TARGET:
      62           0 :         DP_REQ_DEBUG(SSSDBG_MINOR_FAILURE, req_name,
      63             :                      "Finished. Target is not supported "
      64             :                      "with this configuration.");
      65             : 
      66           0 :         error = sbus_error_new(mem_ctx, SBUS_ERROR_DP_NOTSUP,
      67             :                      "Target is not supported.");
      68           0 :         break;
      69             :     default:
      70           0 :         DP_REQ_DEBUG(SSSDBG_CRIT_FAILURE, req_name,
      71             :                      "Finished. Error [%d]: %s", ret, sss_strerror(ret));
      72             : 
      73           0 :         error = sbus_error_new(mem_ctx, SBUS_ERROR_DP_FATAL,
      74             :                      "An error occurred [%d]: %s", ret, sss_strerror(ret));
      75           0 :         break;
      76             :     }
      77             : 
      78           0 :     return error;
      79             : }
      80             : 
      81           0 : void dp_req_reply_error(struct sbus_request *sbus_req,
      82             :                         const char *req_name,
      83             :                         errno_t ret)
      84             : {
      85             :     DBusError *error;
      86             : 
      87           0 :     error = dp_req_reply_gen_error(sbus_req, req_name, ret);
      88           0 :     if (error == NULL) {
      89           0 :         DP_REQ_DEBUG(SSSDBG_CRIT_FAILURE, req_name,
      90             :                      "Out of memory, killing request...");
      91           0 :         talloc_free(sbus_req);
      92           0 :         return;
      93             :     }
      94             : 
      95           0 :     sbus_request_fail_and_finish(sbus_req, error);
      96             : }
      97             : 
      98           0 : static void dp_req_reply_list_error(struct dp_sbus_req_item *list,
      99             :                                     const char *req_name,
     100             :                                     errno_t ret)
     101             : {
     102             :     struct dp_sbus_req_item *next_item;
     103             :     struct dp_sbus_req_item *item;
     104             :     DBusError *error;
     105             : 
     106           0 :     error = dp_req_reply_gen_error(NULL, req_name, ret);
     107           0 :     if (error == NULL) {
     108           0 :         DP_REQ_DEBUG(SSSDBG_CRIT_FAILURE, req_name,
     109             :                      "Out of memory, killing request...");
     110             : 
     111           0 :         for (item = list; item != NULL; item = next_item) {
     112           0 :             next_item = item->next;
     113           0 :             talloc_free(item->sbus_req);
     114             :         }
     115             : 
     116           0 :         return;
     117             :     }
     118             : 
     119           0 :     for (item = list; item != NULL; item = next_item) {
     120           0 :         next_item = item->next;
     121           0 :         sbus_request_fail_and_finish(item->sbus_req, error);
     122             :     }
     123             : 
     124           0 :     talloc_free(error);
     125           0 :     return;
     126             : }
     127             : 
     128           0 : static void dp_req_reply_list_success(struct dp_sbus_req_item *list,
     129             :                                       dp_req_reply_fn reply_fn,
     130             :                                       const char *request_name,
     131             :                                       void *output_data)
     132             : {
     133             :     struct dp_sbus_req_item *next_item;
     134             :     struct dp_sbus_req_item *item;
     135             : 
     136           0 :     DP_REQ_DEBUG(SSSDBG_TRACE_FUNC, request_name, "Finished. Success.");
     137             : 
     138           0 :     for (item = list; item != NULL; item = next_item) {
     139           0 :         next_item = item->next;
     140           0 :         reply_fn(request_name, item->sbus_req, output_data);
     141             :     }
     142           0 : }
     143             : 
     144             : struct dp_req_with_reply_state {
     145             :     struct data_provider *provider;
     146             : 
     147             :     void *postprocess_data;
     148             :     dp_req_post_fn postprocess_fn;
     149             : 
     150             :     const char *output_dtype;
     151             :     dp_req_reply_fn reply_fn;
     152             :     const char *key;
     153             :     const char *name;
     154             : };
     155             : 
     156             : static errno_t dp_req_with_reply_step(struct data_provider *provider,
     157             :                                       struct dp_client *dp_cli,
     158             :                                       const char *domain,
     159             :                                       const char *request_name,
     160             :                                       const char *custom_key,
     161             :                                       struct sbus_request *sbus_req,
     162             :                                       enum dp_targets target,
     163             :                                       enum dp_methods method,
     164             :                                       uint32_t dp_flags,
     165             :                                       void *request_data,
     166             :                                       dp_req_post_fn postprocess_fn,
     167             :                                       void *postprocess_data,
     168             :                                       dp_req_reply_fn reply_fn,
     169             :                                       const char *output_dtype);
     170             : 
     171             : static void dp_req_with_reply_done(struct tevent_req *req);
     172             : 
     173           0 : void _dp_req_with_reply(struct dp_client *dp_cli,
     174             :                         const char *domain,
     175             :                         const char *request_name,
     176             :                         const char *custom_key,
     177             :                         struct sbus_request *sbus_req,
     178             :                         enum dp_targets target,
     179             :                         enum dp_methods method,
     180             :                         uint32_t dp_flags,
     181             :                         void *request_data,
     182             :                         dp_req_post_fn postprocess_fn,
     183             :                         void *postprocess_data,
     184             :                         dp_req_reply_fn reply_fn,
     185             :                         const char *output_dtype)
     186             : {
     187             :     TALLOC_CTX *tmp_ctx;
     188             :     struct data_provider *provider;
     189             :     const char *key;
     190             :     bool has_key;
     191             :     errno_t ret;
     192             : 
     193           0 :     tmp_ctx = talloc_new(NULL);
     194           0 :     if (tmp_ctx == NULL) {
     195           0 :         ret = ENOMEM;
     196           0 :         goto done;
     197             :     }
     198             : 
     199           0 :     provider = dp_client_provider(dp_cli);
     200             : 
     201           0 :     if (custom_key == NULL) {
     202             :         /* It may not be always possible or desirable to have a meaningful key
     203             :          * to chain sbus request. In such cases, we generate a unique key from
     204             :          * sbus_req address that allows us to use the same code but the
     205             :          * chaining is logically disabled. */
     206           0 :         custom_key = talloc_asprintf(tmp_ctx, "%p", sbus_req);
     207           0 :         if (custom_key == NULL) {
     208           0 :             ret = ENOMEM;
     209           0 :             goto done;
     210             :         }
     211             :     }
     212             : 
     213           0 :     key = dp_req_table_key(tmp_ctx, target, method, dp_flags, custom_key);
     214           0 :     if (key == NULL) {
     215           0 :         ret = ENOMEM;
     216           0 :         goto done;
     217             :     }
     218             : 
     219           0 :     has_key = dp_req_table_has_key(provider->requests.reply_table, key);
     220           0 :     if (has_key) {
     221           0 :         ret = dp_req_table_add(provider->requests.reply_table,
     222             :                                key, NULL, sbus_req);
     223           0 :         if (ret != EOK) {
     224           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Unable to attach sbus request to "
     225             :                   "existing data provider request [%d]: %s\n",
     226             :                   ret, sss_strerror(ret));
     227           0 :             goto done;
     228             :         }
     229             : 
     230           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Attaching to DP request: %s\n", key);
     231             : 
     232           0 :         ret = EOK;
     233           0 :         goto done;
     234             :     }
     235             : 
     236           0 :     ret = dp_req_with_reply_step(provider, dp_cli, domain, request_name, key,
     237             :                                  sbus_req, target, method, dp_flags,
     238             :                                  request_data, postprocess_fn, postprocess_data,
     239             :                                  reply_fn, output_dtype);
     240             : 
     241             : done:
     242           0 :     if (ret == ENOMEM) {
     243           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to allocate memory for "
     244             :               "new DP request, killing D-Bus request...\n");
     245           0 :         talloc_zfree(sbus_req);
     246           0 :     } else if (ret != EOK) {
     247           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize "
     248             :               "DP request [%d: %s], killing D-Bus request...\n",
     249             :               ret, sss_strerror(ret));
     250           0 :         talloc_zfree(sbus_req);
     251             :     }
     252             : 
     253           0 :     talloc_free(tmp_ctx);
     254           0 : }
     255             : 
     256           0 : static errno_t dp_req_with_reply_step(struct data_provider *provider,
     257             :                                       struct dp_client *dp_cli,
     258             :                                       const char *domain,
     259             :                                       const char *request_name,
     260             :                                       const char *custom_key,
     261             :                                       struct sbus_request *sbus_req,
     262             :                                       enum dp_targets target,
     263             :                                       enum dp_methods method,
     264             :                                       uint32_t dp_flags,
     265             :                                       void *request_data,
     266             :                                       dp_req_post_fn postprocess_fn,
     267             :                                       void *postprocess_data,
     268             :                                       dp_req_reply_fn reply_fn,
     269             :                                       const char *output_dtype)
     270             : {
     271             :     TALLOC_CTX *tmp_ctx;
     272             :     struct dp_req_with_reply_state *state;
     273             :     struct tevent_req *req;
     274             :     errno_t ret;
     275             : 
     276           0 :     tmp_ctx = talloc_new(NULL);
     277           0 :     if (tmp_ctx == NULL) {
     278           0 :         return ENOMEM;
     279             :     }
     280             : 
     281           0 :     state = talloc_zero(tmp_ctx, struct dp_req_with_reply_state);
     282           0 :     if (state == NULL) {
     283           0 :         ret = ENOMEM;
     284           0 :         goto done;
     285             :     }
     286             : 
     287           0 :     state->provider = provider;
     288           0 :     state->reply_fn = reply_fn;
     289           0 :     state->key = talloc_strdup(state, custom_key);
     290           0 :     if (state->key == NULL) {
     291           0 :         ret = ENOMEM;
     292           0 :         goto done;
     293             :     }
     294             : 
     295           0 :     if (postprocess_fn != NULL) {
     296           0 :         state->postprocess_data = postprocess_data;
     297           0 :         state->postprocess_fn = postprocess_fn;
     298             :     }
     299             : 
     300           0 :     state->output_dtype = talloc_strdup(state, output_dtype);
     301           0 :     if (state->output_dtype == NULL) {
     302           0 :         ret = ENOMEM;
     303           0 :         goto done;
     304             :     }
     305             : 
     306           0 :     req = dp_req_send(tmp_ctx, provider, dp_cli, domain, request_name, target,
     307             :                       method, dp_flags, request_data, &state->name);
     308           0 :     if (req == NULL) {
     309           0 :         ret = ENOMEM;
     310           0 :         goto done;
     311             :     }
     312             : 
     313           0 :     ret = dp_req_table_add(provider->requests.reply_table,
     314             :                            custom_key, req, sbus_req);
     315           0 :     if (ret != EOK) {
     316           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add request to table "
     317             :               "[%d]: %s\n", ret, sss_strerror(ret));
     318           0 :         goto done;
     319             :     }
     320             : 
     321           0 :     tevent_req_set_callback(req, dp_req_with_reply_done, state);
     322             : 
     323           0 :     talloc_steal(provider, req);
     324           0 :     talloc_steal(req, state);
     325           0 :     talloc_steal(state, state->name);
     326             : 
     327           0 :     ret = EOK;
     328             : 
     329             : done:
     330           0 :     talloc_free(tmp_ctx);
     331           0 :     return ret;
     332             : }
     333             : 
     334           0 : static void dp_req_with_reply_done(struct tevent_req *req)
     335             : {
     336             :     struct dp_req_with_reply_state *state;
     337             :     struct dp_table_value *value;
     338             :     void *output_data;
     339             :     errno_t ret;
     340             : 
     341           0 :     state = tevent_req_callback_data(req, struct dp_req_with_reply_state);
     342             : 
     343           0 :     value = dp_req_table_lookup(state->provider->requests.reply_table,
     344             :                                 state->key);
     345           0 :     if (value == NULL) {
     346           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup table!\n");
     347           0 :         return;
     348             :     }
     349             : 
     350           0 :     ret = _dp_req_recv(state, req, state->output_dtype, &output_data);
     351           0 :     if (ret != EOK) {
     352           0 :         dp_req_reply_list_error(value->list, state->name, ret);
     353           0 :         goto done;
     354             :     }
     355             : 
     356             :     /* Run postprocess function if any. */
     357           0 :     if (state->postprocess_fn != NULL) {
     358           0 :         state->postprocess_fn(state->name,
     359             :                               state->provider,
     360             :                               state->postprocess_data,
     361             :                               output_data);
     362             :     }
     363             : 
     364             :     /* Reply with data. */
     365           0 :     dp_req_reply_list_success(value->list, state->reply_fn,
     366             :                               state->name, output_data);
     367             : 
     368             : done:
     369             :     /* Freeing value will remove it from the table as well. */
     370           0 :     talloc_free(value);
     371           0 :     talloc_free(req);
     372             : }

Generated by: LCOV version 1.10