LCOV - code coverage report
Current view: top level - src - assuan-socket-connect.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 121 0.0 %
Date: 2015-11-05 17:06:03 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /* assuan-socket-connect.c - Assuan socket based client
       2             :    Copyright (C) 2002, 2003, 2004, 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             : #include <config.h>
      21             : #include <stdlib.h>
      22             : #include <stddef.h>
      23             : #include <stdio.h>
      24             : #include <string.h>
      25             : #include <errno.h>
      26             : #ifdef HAVE_STDINT_H
      27             : # include <stdint.h>
      28             : #endif
      29             : #ifdef HAVE_UNISTD_H
      30             : # include <unistd.h>
      31             : #endif
      32             : #ifdef HAVE_SYS_TYPES_H
      33             : # include <sys/types.h>
      34             : #endif
      35             : #ifdef HAVE_W32_SYSTEM
      36             : # ifdef HAVE_WINSOCK2_H
      37             : #  include <winsock2.h>
      38             : # endif
      39             : # include <windows.h>
      40             : #else
      41             : # include <sys/socket.h>
      42             : # include <sys/un.h>
      43             : # include <netinet/in.h>
      44             : # include <arpa/inet.h>
      45             : #endif
      46             : 
      47             : #include "assuan-defs.h"
      48             : #include "debug.h"
      49             : 
      50             : /* Hacks for Slowaris.  */
      51             : #ifndef PF_LOCAL
      52             : # ifdef PF_UNIX
      53             : #  define PF_LOCAL PF_UNIX
      54             : # else
      55             : #  define PF_LOCAL AF_UNIX
      56             : # endif
      57             : #endif
      58             : #ifndef AF_LOCAL
      59             : # define AF_LOCAL AF_UNIX
      60             : #endif
      61             : #ifndef INADDR_NONE
      62             : #define INADDR_NONE  ((unsigned long)(-1))
      63             : #endif /*INADDR_NONE*/
      64             : 
      65             : #ifndef SUN_LEN
      66             : # define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
      67             :                        + strlen ((ptr)->sun_path))
      68             : #endif
      69             : 
      70             : 
      71             : #undef WITH_IPV6
      72             : #if defined (AF_INET6) && defined(PF_INET) \
      73             :     && defined (INET6_ADDRSTRLEN) && defined(HAVE_INET_PTON)
      74             : # define WITH_IPV6 1
      75             : #endif
      76             : 
      77             : 
      78             : 
      79             : /* Returns true if STR represents a valid port number in decimal
      80             :    notation and no garbage is following.  */
      81             : static int
      82           0 : parse_portno (const char *str, uint16_t *r_port)
      83             : {
      84             :   unsigned int value;
      85             : 
      86           0 :   for (value=0; *str && (*str >= '0' && *str <= '9'); str++)
      87             :     {
      88           0 :       value = value * 10 + (*str - '0');
      89           0 :       if (value > 65535)
      90           0 :         return 0;
      91             :     }
      92           0 :   if (*str || !value)
      93           0 :     return 0;
      94             : 
      95           0 :   *r_port = value;
      96           0 :   return 1;
      97             : }
      98             : 
      99             : 
     100             : static gpg_error_t
     101           0 : _assuan_connect_finalize (assuan_context_t ctx, assuan_fd_t fd,
     102             :                           unsigned int flags)
     103             : {
     104             :   gpg_error_t err;
     105             : 
     106           0 :   ctx->engine.release = _assuan_client_release;
     107           0 :   ctx->engine.readfnc = _assuan_simple_read;
     108           0 :   ctx->engine.writefnc = _assuan_simple_write;
     109           0 :   ctx->engine.sendfd = NULL;
     110           0 :   ctx->engine.receivefd = NULL;
     111           0 :   ctx->finish_handler = _assuan_client_finish;
     112           0 :   ctx->inbound.fd = fd;
     113           0 :   ctx->outbound.fd = fd;
     114           0 :   ctx->max_accepts = -1;
     115             : 
     116           0 :   if (flags & ASSUAN_SOCKET_CONNECT_FDPASSING)
     117           0 :     _assuan_init_uds_io (ctx);
     118             : 
     119             :   /* initial handshake */
     120             :   {
     121             :     assuan_response_t response;
     122             :     int off;
     123             : 
     124           0 :     err = _assuan_read_from_server (ctx, &response, &off, 0);
     125           0 :     if (err)
     126           0 :       TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
     127             :               "can't connect to server: %s\n", gpg_strerror (err));
     128           0 :     else if (response != ASSUAN_RESPONSE_OK)
     129             :       {
     130           0 :         char *sname = _assuan_encode_c_string (ctx, ctx->inbound.line);
     131           0 :         if (sname)
     132             :           {
     133           0 :             TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
     134             :                     "can't connect to server: %s", sname);
     135           0 :             _assuan_free (ctx, sname);
     136             :           }
     137           0 :         err = _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED);
     138             :       }
     139             :   }
     140             : 
     141           0 :   return err;
     142             : }
     143             : 
     144             : 
     145             : /* Attach an existing connected file descriptor FD to an allocated handle CTX
     146             :  * and initialize the connection.
     147             :  */
     148             : gpg_error_t
     149           0 : assuan_socket_connect_fd (assuan_context_t ctx, int fd, unsigned int flags)
     150             : {
     151             :   gpg_error_t err;
     152             :   assuan_fd_t afd;
     153             : 
     154           0 :   if (!ctx || fd < 0)
     155           0 :     return GPG_ERR_INV_ARG;
     156           0 :   afd = assuan_fd_from_posix_fd (fd);
     157           0 :   if (afd == ASSUAN_INVALID_FD)
     158           0 :     return GPG_ERR_INV_ARG;
     159             : 
     160           0 :   err = _assuan_connect_finalize(ctx, afd, flags);
     161             : 
     162           0 :   if (err)
     163           0 :     _assuan_reset (ctx);
     164             : 
     165           0 :   return err;
     166             : }
     167             : 
     168             : 
     169             : /* Make a connection to the Unix domain socket NAME and return a new
     170             :    Assuan context in CTX.  SERVER_PID is currently not used but may
     171             :    become handy in the future.  Defined flag bits are:
     172             : 
     173             :      ASSUAN_SOCKET_CONNECT_FDPASSING
     174             :         sendmsg and recvmsg are used.
     175             : 
     176             :    NAME must either start with a slash and optional with a drive
     177             :    prefix ("c:") or use one of these URL schemata:
     178             : 
     179             :       file://<fname>
     180             : 
     181             :         This is the same as the default just with an explicit schemata.
     182             : 
     183             :       assuan://<ipaddr>:<port>
     184             :       assuan://[<ip6addr>]:<port>
     185             : 
     186             :         Connect using TCP to PORT of the server with the numerical
     187             :         IPADDR.  Note that '[' and ']' are literal characters.
     188             : 
     189             :   */
     190             : gpg_error_t
     191           0 : assuan_socket_connect (assuan_context_t ctx, const char *name,
     192             :                        pid_t server_pid, unsigned int flags)
     193             : {
     194           0 :   gpg_error_t err = 0;
     195             :   assuan_fd_t fd;
     196             : #ifdef WITH_IPV6
     197             :   struct sockaddr_in6 srvr_addr_in6;
     198             : #endif
     199             :   struct sockaddr_un srvr_addr_un;
     200             :   struct sockaddr_in srvr_addr_in;
     201           0 :   struct sockaddr *srvr_addr = NULL;
     202           0 :   uint16_t port = 0;
     203           0 :   size_t len = 0;
     204             :   const char *s;
     205           0 :   int af = AF_LOCAL;
     206           0 :   int pf = PF_LOCAL;
     207             : 
     208           0 :   TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_socket_connect", ctx,
     209             :           "name=%s, flags=0x%x", name ? name : "(null)", flags);
     210             : 
     211           0 :   if (!ctx || !name)
     212           0 :     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
     213             : 
     214           0 :   if (!strncmp (name, "file://", 7) && name[7])
     215           0 :     name += 7;
     216           0 :   else if (!strncmp (name, "assuan://", 9) && name[9])
     217             :     {
     218           0 :       name += 9;
     219           0 :       af = AF_INET;
     220           0 :       pf = PF_INET;
     221             :     }
     222             :   else /* Default.  */
     223             :     {
     224             :       /* We require that the name starts with a slash if no URL
     225             :          schemata is used.  To make things easier we allow an optional
     226             :          driver prefix.  */
     227           0 :       s = name;
     228           0 :       if (*s && s[1] == ':')
     229           0 :         s += 2;
     230           0 :       if (*s != DIRSEP_C && *s != '/')
     231           0 :         return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
     232             :     }
     233             : 
     234           0 :   if (af == AF_LOCAL)
     235             :     {
     236           0 :       if (strlen (name)+1 >= sizeof srvr_addr_un.sun_path)
     237           0 :         return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
     238             : 
     239           0 :       memset (&srvr_addr_un, 0, sizeof srvr_addr_un);
     240           0 :       srvr_addr_un.sun_family = AF_LOCAL;
     241           0 :       strncpy (srvr_addr_un.sun_path, name, sizeof (srvr_addr_un.sun_path) - 1);
     242           0 :       srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path) - 1] = 0;
     243           0 :       len = SUN_LEN (&srvr_addr_un);
     244             : 
     245           0 :       srvr_addr = (struct sockaddr *)&srvr_addr_un;
     246             :     }
     247             :   else
     248             :     {
     249             :       char *addrstr, *p;
     250             : #ifdef HAVE_INET_PTON
     251           0 :       void *addrbuf = NULL;
     252             : #endif
     253             : 
     254           0 :       addrstr = _assuan_malloc (ctx, strlen (name) + 1);
     255           0 :       if (!addrstr)
     256           0 :         return _assuan_error (ctx, gpg_err_code_from_syserror ());
     257             : 
     258           0 :       if (*name == '[')
     259             :         {
     260           0 :           strcpy (addrstr, name+1);
     261           0 :           p = strchr (addrstr, ']');
     262           0 :           if (!p || p[1] != ':' || !parse_portno (p+2, &port))
     263           0 :             err = _assuan_error (ctx, GPG_ERR_BAD_URI);
     264             :           else
     265             :             {
     266           0 :               *p = 0;
     267             : #ifdef WITH_IPV6
     268           0 :               af = AF_INET6;
     269           0 :               pf = PF_INET6;
     270           0 :               memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6);
     271           0 :               srvr_addr_in6.sin6_family = af;
     272           0 :               srvr_addr_in6.sin6_port = htons (port);
     273             : #ifdef HAVE_INET_PTON
     274           0 :               addrbuf = &srvr_addr_in6.sin6_addr;
     275             : #endif
     276           0 :               srvr_addr = (struct sockaddr *)&srvr_addr_in6;
     277           0 :               len = sizeof srvr_addr_in6;
     278             : #else
     279             :               err =  _assuan_error (ctx, GPG_ERR_EAFNOSUPPORT);
     280             : #endif
     281             :             }
     282             :         }
     283             :       else
     284             :         {
     285           0 :           strcpy (addrstr, name);
     286           0 :           p = strchr (addrstr, ':');
     287           0 :           if (!p || !parse_portno (p+1, &port))
     288           0 :             err = _assuan_error (ctx, GPG_ERR_BAD_URI);
     289             :           else
     290             :             {
     291           0 :               *p = 0;
     292           0 :               memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
     293           0 :               srvr_addr_in.sin_family = af;
     294           0 :               srvr_addr_in.sin_port = htons (port);
     295             : #ifdef HAVE_INET_PTON
     296           0 :               addrbuf = &srvr_addr_in.sin_addr;
     297             : #endif
     298           0 :               srvr_addr = (struct sockaddr *)&srvr_addr_in;
     299           0 :               len = sizeof srvr_addr_in;
     300             :             }
     301             :         }
     302             : 
     303           0 :       if (!err)
     304             :         {
     305             : #ifdef HAVE_INET_PTON
     306           0 :           switch (inet_pton (af, addrstr, addrbuf))
     307             :             {
     308           0 :             case 1:  break;
     309           0 :             case 0:  err = _assuan_error (ctx, GPG_ERR_BAD_URI); break;
     310           0 :             default: err = _assuan_error (ctx, gpg_err_code_from_syserror ());
     311             :             }
     312             : #else /*!HAVE_INET_PTON*/
     313             :           /* We need to use the old function.  If we are here v6
     314             :              support isn't enabled anyway and thus we can do fine
     315             :              without.  Note that Windows as a compatible inet_pton
     316             :              function named inetPton, but only since Vista.  */
     317             :           srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr);
     318             :           if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE)
     319             :             err = _assuan_error (ctx, GPG_ERR_BAD_URI);
     320             : #endif /*!HAVE_INET_PTON*/
     321             :         }
     322             : 
     323           0 :       _assuan_free (ctx, addrstr);
     324           0 :       if (err)
     325           0 :         return err;
     326             :     }
     327             : 
     328           0 :   fd = _assuan_sock_new (ctx, pf, SOCK_STREAM, 0);
     329           0 :   if (fd == ASSUAN_INVALID_FD)
     330             :     {
     331           0 :       err = _assuan_error (ctx, gpg_err_code_from_syserror ());
     332           0 :       TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
     333             :               "can't create socket: %s", strerror (errno));
     334           0 :       return err;
     335             :     }
     336             : 
     337           0 :   if (_assuan_sock_connect (ctx, fd, srvr_addr, len) == -1)
     338             :     {
     339           0 :       TRACE2 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
     340             :               "can't connect to `%s': %s\n", name, strerror (errno));
     341           0 :       _assuan_close (ctx, fd);
     342           0 :       return _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED);
     343             :     }
     344             : 
     345           0 :   err = _assuan_connect_finalize (ctx, fd, flags);
     346             : 
     347           0 :   if (err)
     348           0 :     _assuan_reset (ctx);
     349             : 
     350           0 :   return err;
     351             : }

Generated by: LCOV version 1.11