LCOV - code coverage report
Current view: top level - src - assuan-uds.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 75 88 85.2 %
Date: 2016-12-01 18:29:29 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /* assuan-uds.c - Assuan unix domain socket utilities
       2             :    Copyright (C) 2006, 2009 Free Software Foundation, Inc.
       3             : 
       4             :    This file is part of Assuan.
       5             : 
       6             :    Assuan is free software; you can redistribute it and/or modify it
       7             :    under the terms of the GNU Lesser General Public License as
       8             :    published by the Free Software Foundation; either version 2.1 of
       9             :    the License, or (at your option) any later version.
      10             : 
      11             :    Assuan is distributed in the hope that it will be useful, but
      12             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :    Lesser General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU Lesser General Public
      17             :    License along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #ifdef HAVE_CONFIG_H
      21             : #include <config.h>
      22             : #endif
      23             : 
      24             : #include <stdlib.h>
      25             : #include <stddef.h>
      26             : #include <stdio.h>
      27             : #include <errno.h>
      28             : #ifdef HAVE_SYS_TYPES_H
      29             : # include <sys/types.h>
      30             : #endif
      31             : #ifndef HAVE_W32_SYSTEM
      32             : # include <sys/socket.h>
      33             : # include <sys/un.h>
      34             : #else
      35             : # ifdef HAVE_WINSOCK2_H
      36             : #  include <winsock2.h>
      37             : # endif
      38             : # include <windows.h>
      39             : #endif
      40             : #if HAVE_SYS_UIO_H
      41             : #include <sys/uio.h>
      42             : #endif
      43             : #ifdef HAVE_UNISTD_H
      44             : # include <unistd.h>
      45             : #endif
      46             : #ifdef HAVE_FCNTL_H
      47             : #include <fcntl.h>
      48             : #endif
      49             : #include <string.h>
      50             : #include <assert.h>
      51             : 
      52             : #include "assuan-defs.h"
      53             : #include "debug.h"
      54             : 
      55             : #ifdef USE_DESCRIPTOR_PASSING
      56             : /* Provide replacement for missing CMSG maccros.  We assume that
      57             :    size_t matches the alignment requirement.  NOTE: This is not true
      58             :    on Mac OS X, so be extra careful to define _DARWIN_C_SOURCE to get
      59             :    those definitions instead of using these.  */
      60             : #define MY_ALIGN(n) ((((n))+ sizeof(size_t)-1) & (size_t)~(sizeof(size_t)-1))
      61             : #ifndef CMSG_SPACE
      62             : #define CMSG_SPACE(n) (MY_ALIGN(sizeof(struct cmsghdr)) + MY_ALIGN((n)))
      63             : #endif
      64             : #ifndef CMSG_LEN
      65             : #define CMSG_LEN(n) (MY_ALIGN(sizeof(struct cmsghdr)) + (n))
      66             : #endif
      67             : #ifndef CMSG_FIRSTHDR
      68             : #define CMSG_FIRSTHDR(mhdr) \
      69             :   ((size_t)(mhdr)->msg_controllen >= sizeof (struct cmsghdr)                    \
      70             :    ? (struct cmsghdr*) (mhdr)->msg_control : (struct cmsghdr*)NULL)
      71             : #endif
      72             : #ifndef CMSG_DATA
      73             : #define CMSG_DATA(cmsg) ((unsigned char*)((struct cmsghdr*)(cmsg)+1))
      74             : #endif
      75             : #endif /*USE_DESCRIPTOR_PASSING*/
      76             : 
      77             : 
      78             : /* Read from a unix domain socket using sendmsg.  */
      79             : static ssize_t
      80          32 : uds_reader (assuan_context_t ctx, void *buf, size_t buflen)
      81             : {
      82             : #ifndef HAVE_W32_SYSTEM
      83          32 :   int len = 0;
      84             :   /* This loop should be OK.  As FDs are followed by data, the
      85             :      readable status of the socket does not change and no new
      86             :      select/event-loop round is necessary.  */
      87          96 :   while (!len)  /* No data is buffered.  */
      88             :     {
      89             :       struct msghdr msg;
      90             :       struct iovec iovec;
      91             : #ifdef USE_DESCRIPTOR_PASSING
      92             :       union {
      93             :         struct cmsghdr cm;
      94             :         char control[CMSG_SPACE(sizeof (int))];
      95             :       } control_u;
      96             :       struct cmsghdr *cmptr;
      97             : #endif /*USE_DESCRIPTOR_PASSING*/
      98             : 
      99          32 :       memset (&msg, 0, sizeof (msg));
     100             : 
     101          32 :       msg.msg_name = NULL;
     102          32 :       msg.msg_namelen = 0;
     103          32 :       msg.msg_iov = &iovec;
     104          32 :       msg.msg_iovlen = 1;
     105          32 :       iovec.iov_base = buf;
     106          32 :       iovec.iov_len = buflen;
     107             : #ifdef USE_DESCRIPTOR_PASSING
     108          32 :       msg.msg_control = control_u.control;
     109          32 :       msg.msg_controllen = sizeof (control_u.control);
     110             : #endif
     111             : 
     112          32 :       len = _assuan_recvmsg (ctx, ctx->inbound.fd, &msg, 0);
     113          32 :       if (len < 0)
     114           0 :         return -1;
     115          32 :       if (len == 0)
     116           0 :         return 0;
     117             : 
     118             : #ifdef USE_DESCRIPTOR_PASSING
     119          32 :       cmptr = CMSG_FIRSTHDR (&msg);
     120          32 :       if (cmptr && cmptr->cmsg_len == CMSG_LEN (sizeof(int)))
     121             :         {
     122           6 :           if (cmptr->cmsg_level != SOL_SOCKET
     123           6 :               || cmptr->cmsg_type != SCM_RIGHTS)
     124           0 :             TRACE0 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx,
     125             :                     "unexpected ancillary data received");
     126             :           else
     127             :             {
     128             :               int fd;
     129             : 
     130           6 :               memcpy (&fd, CMSG_DATA (cmptr), sizeof (fd));
     131             : 
     132           6 :               if (ctx->uds.pendingfdscount >= DIM (ctx->uds.pendingfds))
     133             :                 {
     134           0 :                   TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx,
     135             :                           "too many descriptors pending - "
     136             :                           "closing received descriptor %d", fd);
     137           0 :                   _assuan_close (ctx, fd);
     138             :                 }
     139             :               else
     140           6 :                 ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd;
     141             :             }
     142             :         }
     143             : #endif /*USE_DESCRIPTOR_PASSING*/
     144             :     }
     145             : 
     146          32 :   return len;
     147             : #else /*HAVE_W32_SYSTEM*/
     148             :   int res = recvfrom (HANDLE2SOCKET(ctx->inbound.fd), buf, buflen, 0, NULL, NULL);
     149             :   if (res < 0)
     150             :     gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
     151             :   return res;
     152             : #endif /*HAVE_W32_SYSTEM*/
     153             : }
     154             : 
     155             : 
     156             : /* Write to the domain server.  */
     157             : static ssize_t
     158          53 : uds_writer (assuan_context_t ctx, const void *buf, size_t buflen)
     159             : {
     160             : #ifndef HAVE_W32_SYSTEM
     161             :   struct msghdr msg;
     162             :   struct iovec iovec;
     163             :   ssize_t len;
     164             : 
     165          53 :   memset (&msg, 0, sizeof (msg));
     166             : 
     167          53 :   msg.msg_name = NULL;
     168          53 :   msg.msg_namelen = 0;
     169          53 :   msg.msg_iovlen = 1;
     170          53 :   msg.msg_iov = &iovec;
     171          53 :   iovec.iov_base = (void*)buf;
     172          53 :   iovec.iov_len = buflen;
     173             : 
     174          53 :   len = _assuan_sendmsg (ctx, ctx->outbound.fd, &msg, 0);
     175             : 
     176          53 :   return len;
     177             : #else /*HAVE_W32_SYSTEM*/
     178             :   int res = sendto (HANDLE2SOCKET(ctx->outbound.fd), buf, buflen, 0,
     179             :                     (struct sockaddr *)&ctx->serveraddr,
     180             :                     sizeof (struct sockaddr_in));
     181             :   if (res < 0)
     182             :     gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()));
     183             :   return res;
     184             : #endif /*HAVE_W32_SYSTEM*/
     185             : }
     186             : 
     187             : 
     188             : static gpg_error_t
     189           6 : uds_sendfd (assuan_context_t ctx, assuan_fd_t fd)
     190             : {
     191             : #ifdef USE_DESCRIPTOR_PASSING
     192             :   struct msghdr msg;
     193             :   struct iovec iovec;
     194             :   union {
     195             :     struct cmsghdr cm;
     196             :     char control[CMSG_SPACE(sizeof (int))];
     197             :   } control_u;
     198             :   struct cmsghdr *cmptr;
     199             :   int len;
     200             :   char buffer[80];
     201             : 
     202             :   /* We need to send some real data so that a read won't return 0
     203             :      which will be taken as an EOF.  It also helps with debugging. */
     204           6 :   snprintf (buffer, sizeof(buffer)-1, "# descriptor %d is in flight\n", fd);
     205           6 :   buffer[sizeof(buffer)-1] = 0;
     206             : 
     207           6 :   memset (&msg, 0, sizeof (msg));
     208             : 
     209           6 :   memset (&control_u, 0, sizeof (control_u));
     210             : 
     211           6 :   msg.msg_name = NULL;
     212           6 :   msg.msg_namelen = 0;
     213           6 :   msg.msg_iovlen = 1;
     214           6 :   msg.msg_iov = &iovec;
     215           6 :   iovec.iov_base = buffer;
     216           6 :   iovec.iov_len = strlen (buffer);
     217             : 
     218           6 :   msg.msg_control = control_u.control;
     219           6 :   msg.msg_controllen = sizeof (control_u.control);
     220           6 :   cmptr = CMSG_FIRSTHDR (&msg);
     221           6 :   cmptr->cmsg_len = CMSG_LEN(sizeof(int));
     222           6 :   cmptr->cmsg_level = SOL_SOCKET;
     223           6 :   cmptr->cmsg_type = SCM_RIGHTS;
     224             : 
     225           6 :   memcpy (CMSG_DATA (cmptr), &fd, sizeof (fd));
     226             : 
     227           6 :   len = _assuan_sendmsg (ctx, ctx->outbound.fd, &msg, 0);
     228           6 :   if (len < 0)
     229             :     {
     230           0 :       int saved_errno = errno;
     231           0 :       TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_sendfd", ctx,
     232             :               "uds_sendfd: %s", strerror (errno));
     233           0 :       errno = saved_errno;
     234           0 :       return _assuan_error (ctx, gpg_err_code_from_syserror ());
     235             :     }
     236             :   else
     237           6 :     return 0;
     238             : #else
     239             :   return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED);
     240             : #endif
     241             : }
     242             : 
     243             : 
     244             : static gpg_error_t
     245           6 : uds_receivefd (assuan_context_t ctx, assuan_fd_t *fd)
     246             : {
     247             : #ifdef USE_DESCRIPTOR_PASSING
     248             :   int i;
     249             : 
     250           6 :   if (!ctx->uds.pendingfdscount)
     251             :     {
     252           0 :       TRACE0 (ctx, ASSUAN_LOG_SYSIO, "uds_receivefd", ctx,
     253             :               "no pending file descriptors");
     254           0 :       return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
     255             :     }
     256           6 :   assert (ctx->uds.pendingfdscount <= DIM(ctx->uds.pendingfds));
     257             : 
     258           6 :   *fd = ctx->uds.pendingfds[0];
     259           6 :   for (i=1; i < ctx->uds.pendingfdscount; i++)
     260           0 :     ctx->uds.pendingfds[i-1] = ctx->uds.pendingfds[i];
     261           6 :   ctx->uds.pendingfdscount--;
     262             : 
     263           6 :   return 0;
     264             : #else
     265             :   return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED);
     266             : #endif
     267             : }
     268             : 
     269             : 
     270             : /* Close all pending fds. */
     271             : void
     272           6 : _assuan_uds_close_fds (assuan_context_t ctx)
     273             : {
     274             :   int i;
     275             : 
     276           6 :   for (i = 0; i < ctx->uds.pendingfdscount; i++)
     277           0 :     _assuan_close (ctx, ctx->uds.pendingfds[i]);
     278           6 :   ctx->uds.pendingfdscount = 0;
     279           6 : }
     280             : 
     281             : /* Deinitialize the unix domain socket I/O functions.  */
     282             : void
     283           6 : _assuan_uds_deinit (assuan_context_t ctx)
     284             : {
     285           6 :   _assuan_uds_close_fds (ctx);
     286           6 : }
     287             : 
     288             : 
     289             : /* Helper function to initialize a context for domain I/O.  */
     290             : void
     291           2 : _assuan_init_uds_io (assuan_context_t ctx)
     292             : {
     293           2 :   ctx->engine.readfnc = uds_reader;
     294           2 :   ctx->engine.writefnc = uds_writer;
     295           2 :   ctx->engine.sendfd = uds_sendfd;
     296           2 :   ctx->engine.receivefd = uds_receivefd;
     297             : 
     298           2 :   ctx->uds.pendingfdscount = 0;
     299           2 : }
     300             : 

Generated by: LCOV version 1.11