LCOV - code coverage report
Current view: top level - responder/common - responder_packet.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 49 111 44.1 %
Date: 2015-10-19 Functions: 9 13 69.2 %

          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             : 
      22             : #include <sys/types.h>
      23             : #include <sys/socket.h>
      24             : #include <string.h>
      25             : #include <errno.h>
      26             : #include <talloc.h>
      27             : 
      28             : #include "util/util.h"
      29             : #include "responder/common/responder_packet.h"
      30             : 
      31             : #define SSSSRV_PACKET_MEM_SIZE 512
      32             : 
      33             : struct sss_packet {
      34             :     size_t memsize;
      35             : 
      36             :     /* Structure of the buffer:
      37             :     * Bytes    Content
      38             :     * ---------------------------------
      39             :     * 0-15     packet header
      40             :     * 0-3      packet length (uint32_t)
      41             :     * 4-7      command type (uint32_t)
      42             :     * 8-11     status (uint32_t)
      43             :     * 12-15    reserved
      44             :     * 16+      packet body */
      45             :     uint8_t *buffer;
      46             : 
      47             :     /* io pointer */
      48             :     size_t iop;
      49             : };
      50             : 
      51             : /* Offsets to data in sss_packet's buffer */
      52             : #define SSS_PACKET_LEN_OFFSET 0
      53             : #define SSS_PACKET_CMD_OFFSET sizeof(uint32_t)
      54             : #define SSS_PACKET_ERR_OFFSET (2*(sizeof(uint32_t)))
      55             : #define SSS_PACKET_BODY_OFFSET (4*(sizeof(uint32_t)))
      56             : 
      57             : static void sss_packet_set_len(struct sss_packet *packet, uint32_t len);
      58             : static void sss_packet_set_cmd(struct sss_packet *packet,
      59             :                                enum sss_cli_command cmd);
      60             : static uint32_t sss_packet_get_len(struct sss_packet *packet);
      61             : 
      62             : /*
      63             :  * Allocate a new packet structure
      64             :  *
      65             :  * - if size is defined use it otherwise the default packet will be
      66             :  *   SSSSRV_PACKET_MEM_SIZE bytes.
      67             :  */
      68         104 : int sss_packet_new(TALLOC_CTX *mem_ctx, size_t size,
      69             :                    enum sss_cli_command cmd,
      70             :                    struct sss_packet **rpacket)
      71             : {
      72             :     struct sss_packet *packet;
      73             : 
      74         104 :     packet = talloc(mem_ctx, struct sss_packet);
      75         104 :     if (!packet) return ENOMEM;
      76             : 
      77         104 :     if (size) {
      78           6 :         int n = (size + SSS_NSS_HEADER_SIZE) % SSSSRV_PACKET_MEM_SIZE;
      79           6 :         packet->memsize = (n + 1) * SSSSRV_PACKET_MEM_SIZE;
      80             :     } else {
      81          98 :         packet->memsize = SSSSRV_PACKET_MEM_SIZE;
      82             :     }
      83             : 
      84         104 :     packet->buffer = talloc_size(packet, packet->memsize);
      85         104 :     if (!packet->buffer) {
      86           0 :         talloc_free(packet);
      87           0 :         return ENOMEM;
      88             :     }
      89         104 :     memset(packet->buffer, 0, SSS_NSS_HEADER_SIZE);
      90             : 
      91         104 :     sss_packet_set_len(packet, size + SSS_NSS_HEADER_SIZE);
      92         104 :     sss_packet_set_cmd(packet, cmd);
      93             : 
      94         104 :     packet->iop = 0;
      95             : 
      96         104 :     *rpacket = packet;
      97             : 
      98         104 :     return EOK;
      99             : }
     100             : 
     101             : /* grows a packet size only in SSSSRV_PACKET_MEM_SIZE chunks */
     102         114 : int sss_packet_grow(struct sss_packet *packet, size_t size)
     103             : {
     104             :     size_t totlen, len;
     105             :     uint8_t *newmem;
     106             :     uint32_t packet_len;
     107             : 
     108         114 :     if (size == 0) {
     109           0 :         return EOK;
     110             :     }
     111             : 
     112         114 :     totlen = packet->memsize;
     113         114 :     packet_len = sss_packet_get_len(packet);
     114             : 
     115         114 :     len = packet_len + size;
     116             : 
     117             :     /* make sure we do not overflow */
     118         114 :     if (totlen < len) {
     119           0 :         int n = len / SSSSRV_PACKET_MEM_SIZE + 1;
     120           0 :         totlen += n * SSSSRV_PACKET_MEM_SIZE;
     121           0 :         if (totlen < len) {
     122           0 :             return EINVAL;
     123             :         }
     124             :     }
     125             : 
     126         114 :     if (totlen > packet->memsize) {
     127           0 :         newmem = talloc_realloc_size(packet, packet->buffer, totlen);
     128           0 :         if (!newmem) {
     129           0 :             return ENOMEM;
     130             :         }
     131             : 
     132           0 :         packet->memsize = totlen;
     133             : 
     134             :         /* re-set pointers if realloc had to move memory */
     135           0 :         if (newmem != packet->buffer) {
     136           0 :             packet->buffer = newmem;
     137             :         }
     138             :     }
     139             : 
     140         114 :     packet_len += size;
     141         114 :     sss_packet_set_len(packet, packet_len);
     142             : 
     143             : 
     144         114 :     return 0;
     145             : }
     146             : 
     147             : /* reclaim backet previously resrved space in the packet
     148             :  * usually done in functione recovering from not fatal erros */
     149           0 : int sss_packet_shrink(struct sss_packet *packet, size_t size)
     150             : {
     151             :     size_t newlen;
     152           0 :     size_t oldlen = sss_packet_get_len(packet);
     153             : 
     154           0 :     if (size > oldlen) return EINVAL;
     155             : 
     156           0 :     newlen = oldlen - size;
     157           0 :     if (newlen < SSS_NSS_HEADER_SIZE) return EINVAL;
     158             : 
     159           0 :     sss_packet_set_len(packet, newlen);
     160           0 :     return 0;
     161             : }
     162             : 
     163           5 : int sss_packet_set_size(struct sss_packet *packet, size_t size)
     164             : {
     165             :     size_t newlen;
     166             : 
     167           5 :     newlen = SSS_NSS_HEADER_SIZE + size;
     168             : 
     169             :     /* make sure we do not overflow */
     170           5 :     if (packet->memsize < newlen) return EINVAL;
     171             : 
     172           5 :     sss_packet_set_len(packet, newlen);
     173             : 
     174           5 :     return 0;
     175             : }
     176             : 
     177           0 : int sss_packet_recv(struct sss_packet *packet, int fd)
     178             : {
     179             :     size_t rb;
     180             :     size_t len;
     181             :     void *buf;
     182             : 
     183           0 :     buf = (uint8_t *)packet->buffer + packet->iop;
     184           0 :     if (packet->iop > 4) len = sss_packet_get_len(packet) - packet->iop;
     185           0 :     else len = packet->memsize - packet->iop;
     186             : 
     187             :     /* check for wrapping */
     188           0 :     if (len > packet->memsize) {
     189           0 :         return EINVAL;
     190             :     }
     191             : 
     192           0 :     errno = 0;
     193           0 :     rb = recv(fd, buf, len, 0);
     194             : 
     195           0 :     if (rb == -1) {
     196           0 :         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
     197           0 :             return EAGAIN;
     198             :         } else {
     199           0 :             return errno;
     200             :         }
     201             :     }
     202             : 
     203           0 :     if (rb == 0) {
     204           0 :         return ENODATA;
     205             :     }
     206             : 
     207           0 :     if (sss_packet_get_len(packet) > packet->memsize) {
     208           0 :         return EINVAL;
     209             :     }
     210             : 
     211           0 :     packet->iop += rb;
     212           0 :     if (packet->iop < 4) {
     213           0 :         return EAGAIN;
     214             :     }
     215             : 
     216           0 :     if (packet->iop < sss_packet_get_len(packet)) {
     217           0 :         return EAGAIN;
     218             :     }
     219             : 
     220           0 :     return EOK;
     221             : }
     222             : 
     223           0 : int sss_packet_send(struct sss_packet *packet, int fd)
     224             : {
     225             :     size_t rb;
     226             :     size_t len;
     227             :     void *buf;
     228             : 
     229           0 :     if (!packet) {
     230             :         /* No packet object to write to? */
     231           0 :         return EINVAL;
     232             :     }
     233             : 
     234           0 :     buf = packet->buffer + packet->iop;
     235           0 :     len = sss_packet_get_len(packet) - packet->iop;
     236             : 
     237           0 :     errno = 0;
     238           0 :     rb = send(fd, buf, len, 0);
     239             : 
     240           0 :     if (rb == -1) {
     241           0 :         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
     242           0 :             return EAGAIN;
     243             :         } else {
     244           0 :             return errno;
     245             :         }
     246             :     }
     247             : 
     248           0 :     if (rb == 0) {
     249           0 :         return EIO;
     250             :     }
     251             : 
     252           0 :     packet->iop += rb;
     253             : 
     254           0 :     if (packet->iop < sss_packet_get_len(packet)) {
     255           0 :         return EAGAIN;
     256             :     }
     257             : 
     258           0 :     return EOK;
     259             : }
     260             : 
     261           0 : enum sss_cli_command sss_packet_get_cmd(struct sss_packet *packet)
     262             : {
     263             :     uint32_t cmd;
     264             : 
     265           0 :     SAFEALIGN_COPY_UINT32(&cmd, packet->buffer + SSS_PACKET_CMD_OFFSET, NULL);
     266           0 :     return (enum sss_cli_command)cmd;
     267             : }
     268             : 
     269          72 : uint32_t sss_packet_get_status(struct sss_packet *packet)
     270             : {
     271             :     uint32_t status;
     272             : 
     273          72 :     SAFEALIGN_COPY_UINT32(&status, packet->buffer + SSS_PACKET_ERR_OFFSET,
     274             :                           NULL);
     275          72 :     return status;
     276             : }
     277             : 
     278         188 : void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen)
     279             : {
     280         188 :     *body = packet->buffer + SSS_PACKET_BODY_OFFSET;
     281         188 :     *blen = sss_packet_get_len(packet) - SSS_NSS_HEADER_SIZE;
     282         188 : }
     283             : 
     284          41 : void sss_packet_set_error(struct sss_packet *packet, int error)
     285             : {
     286          41 :     SAFEALIGN_SETMEM_UINT32(packet->buffer + SSS_PACKET_ERR_OFFSET, error,
     287             :                             NULL);
     288          41 : }
     289             : 
     290         223 : static void sss_packet_set_len(struct sss_packet *packet, uint32_t len)
     291             : {
     292         223 :     SAFEALIGN_SETMEM_UINT32(packet->buffer + SSS_PACKET_LEN_OFFSET, len, NULL);
     293         223 : }
     294             : 
     295         104 : static void sss_packet_set_cmd(struct sss_packet *packet,
     296             :                                enum sss_cli_command cmd)
     297             : {
     298         104 :     SAFEALIGN_SETMEM_UINT32(packet->buffer + SSS_PACKET_CMD_OFFSET, cmd, NULL);
     299         104 : }
     300             : 
     301         302 : static uint32_t sss_packet_get_len(struct sss_packet *packet)
     302             : {
     303             :     uint32_t len;
     304             : 
     305         302 :     SAFEALIGN_COPY_UINT32(&len, packet->buffer + SSS_PACKET_LEN_OFFSET, NULL);
     306         302 :     return len;
     307             : }

Generated by: LCOV version 1.10