LCOV - code coverage report
Current view: top level - responder/common - responder_cmd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 25 107 23.4 %
Date: 2016-06-29 Functions: 3 12 25.0 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    SSS Client Responder, command parser
       5             : 
       6             :    Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
       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             : #include <errno.h>
      22             : #include "db/sysdb.h"
      23             : #include "util/util.h"
      24             : #include "responder/common/responder.h"
      25             : #include "responder/common/responder_packet.h"
      26             : 
      27           4 : int sss_cmd_send_error(struct cli_ctx *cctx, int err)
      28             : {
      29             :     int ret;
      30             : 
      31             :     /* create response packet */
      32           8 :     ret = sss_packet_new(cctx->creq, 0,
      33           4 :                          sss_packet_get_cmd(cctx->creq->in),
      34           4 :                          &cctx->creq->out);
      35           4 :     if (ret != EOK) {
      36           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create new packet: %d\n", ret);
      37           0 :         return ret;
      38             :     }
      39             : 
      40           4 :     sss_packet_set_error(cctx->creq->out, err);
      41           4 :     return EOK;
      42             : }
      43             : 
      44           0 : int sss_cmd_empty_packet(struct sss_packet *packet)
      45             : {
      46             :     uint8_t *body;
      47             :     size_t blen;
      48             :     int ret;
      49             : 
      50           0 :     ret = sss_packet_grow(packet, 2*sizeof(uint32_t));
      51           0 :     if (ret != EOK) return ret;
      52             : 
      53           0 :     sss_packet_get_body(packet, &body, &blen);
      54             : 
      55             :     /* num results */
      56           0 :     SAFEALIGN_SETMEM_UINT32(body, 0, NULL);
      57             : 
      58             :     /* reserved */
      59           0 :     SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
      60             : 
      61           0 :     return EOK;
      62             : }
      63             : 
      64           0 : int sss_cmd_send_empty(struct cli_ctx *cctx, TALLOC_CTX *freectx)
      65             : {
      66             :     int ret;
      67             : 
      68             :     /* create response packet */
      69           0 :     ret = sss_packet_new(cctx->creq, 0,
      70           0 :                          sss_packet_get_cmd(cctx->creq->in),
      71           0 :                          &cctx->creq->out);
      72           0 :     if (ret != EOK) {
      73           0 :         return ret;
      74             :     }
      75             : 
      76           0 :     ret = sss_cmd_empty_packet(cctx->creq->out);
      77           0 :     if (ret != EOK) {
      78           0 :         return ret;
      79             :     }
      80             : 
      81           0 :     sss_packet_set_error(cctx->creq->out, EOK);
      82           0 :     sss_cmd_done(cctx, freectx);
      83           0 :     return EOK;
      84             : }
      85             : 
      86           0 : void sss_cmd_done(struct cli_ctx *cctx, void *freectx)
      87             : {
      88             :     /* now that the packet is in place, unlock queue
      89             :      * making the event writable */
      90           0 :     TEVENT_FD_WRITEABLE(cctx->cfde);
      91             : 
      92             :     /* free all request related data through the talloc hierarchy */
      93           0 :     talloc_free(freectx);
      94           0 : }
      95             : 
      96           0 : int sss_cmd_get_version(struct cli_ctx *cctx)
      97             : {
      98             :     uint8_t *req_body;
      99             :     size_t req_blen;
     100             :     uint8_t *body;
     101             :     size_t blen;
     102             :     int ret;
     103             :     uint32_t client_version;
     104             :     uint32_t protocol_version;
     105             :     int i;
     106             :     static struct cli_protocol_version *cli_protocol_version = NULL;
     107             : 
     108           0 :     cctx->cli_protocol_version = NULL;
     109             : 
     110           0 :     if (cli_protocol_version == NULL) {
     111           0 :         cli_protocol_version = register_cli_protocol_version();
     112             :     }
     113             : 
     114           0 :     if (cli_protocol_version != NULL) {
     115           0 :         cctx->cli_protocol_version = &cli_protocol_version[0];
     116             : 
     117           0 :         sss_packet_get_body(cctx->creq->in, &req_body, &req_blen);
     118           0 :         if (req_blen == sizeof(uint32_t)) {
     119           0 :             memcpy(&client_version, req_body, sizeof(uint32_t));
     120           0 :             DEBUG(SSSDBG_FUNC_DATA,
     121             :                   "Received client version [%d].\n", client_version);
     122             : 
     123           0 :             i=0;
     124           0 :             while(cli_protocol_version[i].version>0) {
     125           0 :                 if (cli_protocol_version[i].version == client_version) {
     126           0 :                     cctx->cli_protocol_version = &cli_protocol_version[i];
     127           0 :                     break;
     128             :                 }
     129           0 :                 i++;
     130             :             }
     131             :         }
     132             :     }
     133             : 
     134             :     /* create response packet */
     135           0 :     ret = sss_packet_new(cctx->creq, sizeof(uint32_t),
     136           0 :                          sss_packet_get_cmd(cctx->creq->in),
     137           0 :                          &cctx->creq->out);
     138           0 :     if (ret != EOK) {
     139           0 :         return ret;
     140             :     }
     141           0 :     sss_packet_get_body(cctx->creq->out, &body, &blen);
     142             : 
     143           0 :     protocol_version = (cctx->cli_protocol_version != NULL)
     144           0 :                        ? cctx->cli_protocol_version->version : 0;
     145             : 
     146           0 :     SAFEALIGN_COPY_UINT32(body, &protocol_version, NULL);
     147           0 :     DEBUG(SSSDBG_FUNC_DATA, "Offered version [%d].\n", protocol_version);
     148             : 
     149           0 :     sss_cmd_done(cctx, NULL);
     150           0 :     return EOK;
     151             : }
     152             : 
     153          96 : int sss_cmd_execute(struct cli_ctx *cctx,
     154             :                     enum sss_cli_command cmd,
     155             :                     struct sss_cmd_table *sss_cmds)
     156             : {
     157             :     int i;
     158             : 
     159         851 :     for (i = 0; sss_cmds[i].cmd != SSS_CLI_NULL; i++) {
     160         851 :         if (cmd == sss_cmds[i].cmd) {
     161          96 :             return sss_cmds[i].fn(cctx);
     162             :         }
     163             :     }
     164             : 
     165           0 :     return EINVAL;
     166             : }
     167             : struct setent_req_list {
     168             :     struct setent_req_list *prev;
     169             :     struct setent_req_list *next;
     170             :     /* Need to modify the list from a talloc destructor */
     171             :     struct setent_req_list **head;
     172             : 
     173             :     void *pvt;
     174             : 
     175             :     struct tevent_req *req;
     176             : };
     177             : 
     178             : struct tevent_req *
     179           0 : setent_get_req(struct setent_req_list *sl)
     180             : {
     181           0 :     return sl->req;
     182             : }
     183             : 
     184           0 : int setent_remove_ref(TALLOC_CTX *ctx)
     185             : {
     186           0 :     struct setent_req_list *entry =
     187             :             talloc_get_type(ctx, struct setent_req_list);
     188           0 :     DLIST_REMOVE(*(entry->head), entry);
     189           0 :     return 0;
     190             : }
     191             : 
     192           0 : errno_t setent_add_ref(TALLOC_CTX *memctx,
     193             :                        void *pvt,
     194             :                        struct setent_req_list **list,
     195             :                        struct tevent_req *req)
     196             : {
     197             :     struct setent_req_list *entry;
     198             : 
     199           0 :     entry = talloc_zero(memctx, struct setent_req_list);
     200           0 :     if (!entry) {
     201           0 :         return ENOMEM;
     202             :     }
     203             : 
     204           0 :     entry->req = req;
     205           0 :     entry->pvt = pvt;
     206           0 :     DLIST_ADD_END(*list, entry, struct setent_req_list *);
     207           0 :     entry->head = list;
     208             : 
     209           0 :     talloc_set_destructor((TALLOC_CTX *)entry, setent_remove_ref);
     210           0 :     return EOK;
     211             : }
     212             : 
     213           0 : void setent_notify(struct setent_req_list **list, errno_t err)
     214             : {
     215             :     struct setent_req_list *reql;
     216             : 
     217             :     /* Notify the waiting clients */
     218           0 :     while ((reql = *list) != NULL) {
     219             :         /* Each tevent_req_done() call will free
     220             :          * the request, removing it from the list.
     221             :          */
     222           0 :         if (err == EOK) {
     223           0 :             tevent_req_done(reql->req);
     224             :         } else {
     225           0 :             tevent_req_error(reql->req, err);
     226             :         }
     227             : 
     228           0 :         if (reql == *list) {
     229             :             /* The consumer failed to free the
     230             :              * request. Log a bug and continue.
     231             :              */
     232           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     233             :                   "BUG: a callback did not free its request. "
     234             :                    "May leak memory\n");
     235             :             /* Skip to the next since a memory leak is non-fatal */
     236           0 :             *list = (*list)->next;
     237             :         }
     238             :     }
     239           0 : }
     240             : 
     241           0 : void setent_notify_done(struct setent_req_list **list)
     242             : {
     243           0 :     return setent_notify(list, EOK);
     244             : }
     245             : 
     246             : /*
     247             :  * Return values:
     248             :  *  EOK     -   cache hit
     249             :  *  EAGAIN  -   cache hit, but schedule off band update
     250             :  *  ENOENT  -   cache miss
     251             :  */
     252             : errno_t
     253          59 : sss_cmd_check_cache(struct ldb_message *msg,
     254             :                     int cache_refresh_percent,
     255             :                     uint64_t cache_expire)
     256             : {
     257             :     uint64_t lastUpdate;
     258          59 :     uint64_t midpoint_refresh = 0;
     259             :     time_t now;
     260             : 
     261          59 :     now = time(NULL);
     262          59 :     lastUpdate = ldb_msg_find_attr_as_uint64(msg, SYSDB_LAST_UPDATE, 0);
     263          59 :     midpoint_refresh = 0;
     264             : 
     265          59 :     if(cache_refresh_percent) {
     266          14 :         midpoint_refresh = lastUpdate +
     267           7 :             (cache_expire - lastUpdate)*cache_refresh_percent/100.0;
     268           7 :         if (midpoint_refresh - lastUpdate < 10) {
     269             :             /* If the percentage results in an expiration
     270             :              * less than ten seconds after the lastUpdate time,
     271             :              * that's too often we will simply set it to 10s
     272             :              */
     273           0 :             midpoint_refresh = lastUpdate+10;
     274             :         }
     275             :     }
     276             : 
     277          59 :     if (cache_expire > now) {
     278             :         /* cache still valid */
     279             : 
     280          47 :         if (midpoint_refresh && midpoint_refresh < now) {
     281             :             /* We're past the cache refresh timeout
     282             :              * We'll return the value from the cache, but we'll also
     283             :              * queue the cache entry for update out-of-band.
     284             :              */
     285           7 :             return EAGAIN;
     286             :         } else {
     287             :             /* Cache is still valid. */
     288          40 :             return EOK;
     289             :         }
     290             :     }
     291             : 
     292             :     /* Cache needs to be updated */
     293          12 :     return ENOENT;
     294             : }

Generated by: LCOV version 1.10