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

          Line data    Source code
       1             : /* assuan-socket.c - Socket wrapper
       2             :    Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc.
       3             :    Copyright (C) 2001-2015 g10 Code GmbH
       4             : 
       5             :    This file is part of Assuan.
       6             : 
       7             :    Assuan is free software; you can redistribute it and/or modify it
       8             :    under the terms of the GNU Lesser General Public License as
       9             :    published by the Free Software Foundation; either version 2.1 of
      10             :    the License, or (at your option) any later version.
      11             : 
      12             :    Assuan is distributed in the hope that it will be useful, but
      13             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :    Lesser General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU Lesser General Public
      18             :    License along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #ifdef HAVE_CONFIG_H
      22             : #include <config.h>
      23             : #endif
      24             : 
      25             : #include <stdio.h>
      26             : #include <stdlib.h>
      27             : #ifdef HAVE_W32_SYSTEM
      28             : # define WIN32_LEAN_AND_MEAN
      29             : # include <windows.h>
      30             : # include <wincrypt.h>
      31             : #ifndef HAVE_W32CE_SYSTEM
      32             : # include <io.h>
      33             : #endif
      34             : #else
      35             : # include <sys/types.h>
      36             : # include <sys/socket.h>
      37             : # include <netinet/in.h>
      38             : # include <arpa/inet.h>
      39             : #endif
      40             : #include <errno.h>
      41             : #ifdef HAVE_SYS_STAT_H
      42             : # include <sys/stat.h>
      43             : #endif
      44             : #ifdef HAVE_FCNTL_H
      45             : #include <fcntl.h>
      46             : #endif
      47             : #include <assert.h>
      48             : 
      49             : #include "assuan-defs.h"
      50             : #include "debug.h"
      51             : 
      52             : /* Hacks for Slowaris.  */
      53             : #ifndef PF_LOCAL
      54             : # ifdef PF_UNIX
      55             : #  define PF_LOCAL PF_UNIX
      56             : # else
      57             : #  define PF_LOCAL AF_UNIX
      58             : # endif
      59             : #endif
      60             : #ifndef AF_LOCAL
      61             : # define AF_LOCAL AF_UNIX
      62             : #endif
      63             : 
      64             : #ifdef HAVE_W32_SYSTEM
      65             : #ifndef S_IRUSR
      66             : # define S_IRUSR 0
      67             : # define S_IWUSR 0
      68             : #endif
      69             : #ifndef S_IRGRP
      70             : # define S_IRGRP 0
      71             : # define S_IWGRP 0
      72             : #endif
      73             : #endif
      74             : 
      75             : #ifndef ENAMETOOLONG
      76             : # define ENAMETOOLONG EINVAL
      77             : #endif
      78             : 
      79             : 
      80             : #ifndef SUN_LEN
      81             : # define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
      82             :                        + strlen ((ptr)->sun_path))
      83             : #endif
      84             : 
      85             : 
      86             : /* The standard SOCKS and TOR port.  */
      87             : #define SOCKS_PORT 1080
      88             : #define TOR_PORT   9050
      89             : 
      90             : /* In the future, we can allow access to sock_ctx, if that context's
      91             :    hook functions need to be overridden.  There can only be one global
      92             :    assuan_sock_* user (one library or one application) with this
      93             :    convenience interface, if non-standard hook functions are
      94             :    needed.  */
      95             : static assuan_context_t sock_ctx;
      96             : 
      97             : /* This global flag can be set using assuan_sock_set_flag to enable
      98             :    TOR or SOCKS mode for all sockets.  It may not be reset.  The value
      99             :    is the port to be used. */
     100             : static unsigned short tor_mode;
     101             : 
     102             : 
     103             : 
     104             : #ifdef HAVE_W32_SYSTEM
     105             : /* A table of active Cygwin connections.  This is only used for
     106             :    listening socket which should be only a few.  We do not enter
     107             :    sockets after a connect into this table.  */
     108             : static assuan_fd_t cygwin_fdtable[16];
     109             : /* A critical section to guard access to the table of Cygwin
     110             :    connections. */
     111             : static CRITICAL_SECTION cygwin_fdtable_cs;
     112             : 
     113             : 
     114             : /* Return true if SOCKFD is listed as Cygwin socket.  */
     115             : static int
     116             : is_cygwin_fd (assuan_fd_t sockfd)
     117             : {
     118             :   int ret = 0;
     119             :   int i;
     120             : 
     121             :   EnterCriticalSection (&cygwin_fdtable_cs);
     122             :   for (i=0; i < DIM(cygwin_fdtable); i++)
     123             :     {
     124             :       if (cygwin_fdtable[i] == sockfd)
     125             :         {
     126             :           ret = 1;
     127             :           break;
     128             :         }
     129             :     }
     130             :   LeaveCriticalSection (&cygwin_fdtable_cs);
     131             :   return ret;
     132             : }
     133             : 
     134             : 
     135             : /* Insert SOCKFD into the table of Cygwin sockets.  Return 0 on
     136             :    success or -1 on error.  */
     137             : static int
     138             : insert_cygwin_fd (assuan_fd_t sockfd)
     139             : {
     140             :   int ret = 0;
     141             :   int mark = -1;
     142             :   int i;
     143             : 
     144             :   EnterCriticalSection (&cygwin_fdtable_cs);
     145             : 
     146             :   for (i=0; i < DIM(cygwin_fdtable); i++)
     147             :     {
     148             :       if (cygwin_fdtable[i] == sockfd)
     149             :         goto leave;  /* Already in table.  */
     150             :       else if (cygwin_fdtable[i] == ASSUAN_INVALID_FD)
     151             :         mark = i;
     152             :     }
     153             :   if (mark == -1)
     154             :     {
     155             :       gpg_err_set_errno (EMFILE);
     156             :       ret = -1;
     157             :     }
     158             :   else
     159             :     cygwin_fdtable[mark] = sockfd;
     160             : 
     161             :  leave:
     162             :   LeaveCriticalSection (&cygwin_fdtable_cs);
     163             :   return ret;
     164             : }
     165             : 
     166             : 
     167             : /* Delete SOCKFD from the table of Cygwin sockets.  */
     168             : static void
     169             : delete_cygwin_fd (assuan_fd_t sockfd)
     170             : {
     171             :   int i;
     172             : 
     173             :   EnterCriticalSection (&cygwin_fdtable_cs);
     174             :   for (i=0; i < DIM(cygwin_fdtable); i++)
     175             :     {
     176             :       if (cygwin_fdtable[i] == sockfd)
     177             :         {
     178             :           cygwin_fdtable[i] = ASSUAN_INVALID_FD;
     179             :           break;
     180             :         }
     181             :     }
     182             :   LeaveCriticalSection (&cygwin_fdtable_cs);
     183             :   return;
     184             : }
     185             : 
     186             : 
     187             : #ifdef HAVE_W32CE_SYSTEM
     188             : static wchar_t *
     189             : utf8_to_wchar (const char *string)
     190             : {
     191             :   int n;
     192             :   size_t nbytes;
     193             :   wchar_t *result;
     194             : 
     195             :   if (!string)
     196             :     return NULL;
     197             : 
     198             :   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
     199             :   if (n < 0)
     200             :     return NULL;
     201             : 
     202             :   nbytes = (size_t)(n+1) * sizeof(*result);
     203             :   if (nbytes / sizeof(*result) != (n+1))
     204             :     {
     205             :       SetLastError (ERROR_INVALID_PARAMETER);
     206             :       return NULL;
     207             :     }
     208             :   result = malloc (nbytes);
     209             :   if (!result)
     210             :     return NULL;
     211             : 
     212             :   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
     213             :   if (n < 0)
     214             :     {
     215             :       n = GetLastError ();
     216             :       free (result);
     217             :       result = NULL;
     218             :       SetLastError (n);
     219             :     }
     220             :   return result;
     221             : }
     222             : 
     223             : static HANDLE
     224             : MyCreateFile (LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSharedMode,
     225             :               LPSECURITY_ATTRIBUTES lpSecurityAttributes,
     226             :               DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
     227             :               HANDLE hTemplateFile)
     228             : {
     229             :   wchar_t *filename;
     230             :   HANDLE result;
     231             :   int err;
     232             : 
     233             :   filename = utf8_to_wchar (lpFileName);
     234             :   if (!filename)
     235             :     return INVALID_HANDLE_VALUE;
     236             : 
     237             :   result = CreateFileW (filename, dwDesiredAccess, dwSharedMode,
     238             :                         lpSecurityAttributes, dwCreationDisposition,
     239             :                         dwFlagsAndAttributes, hTemplateFile);
     240             :   err = GetLastError ();
     241             :   free (filename);
     242             :   SetLastError (err);
     243             :   return result;
     244             : }
     245             : static int
     246             : MyDeleteFile (LPCSTR lpFileName)
     247             : {
     248             :   wchar_t *filename;
     249             :   int result, err;
     250             : 
     251             :   filename = utf8_to_wchar (lpFileName);
     252             :   if (!filename)
     253             :     return 0;
     254             : 
     255             :   result = DeleteFileW (filename);
     256             :   err = GetLastError ();
     257             :   free (filename);
     258             :   SetLastError (err);
     259             :   return result;
     260             : }
     261             : #else /*!HAVE_W32CE_SYSTEM*/
     262             : #define MyCreateFile CreateFileA
     263             : #define MyDeleteFile DeleteFileA
     264             : #endif /*!HAVE_W32CE_SYSTEM*/
     265             : 
     266             : int
     267             : _assuan_sock_wsa2errno (int err)
     268             : {
     269             :   switch (err)
     270             :     {
     271             :     case WSAENOTSOCK:
     272             :       return EINVAL;
     273             :     case WSAEWOULDBLOCK:
     274             :       return EAGAIN;
     275             :     case ERROR_BROKEN_PIPE:
     276             :       return EPIPE;
     277             :     case WSANOTINITIALISED:
     278             :       return ENOSYS;
     279             :     default:
     280             :       return EIO;
     281             :     }
     282             : }
     283             : 
     284             : 
     285             : /* W32: Fill BUFFER with LENGTH bytes of random.  Returns -1 on
     286             :    failure, 0 on success.  Sets errno on failure.  */
     287             : static int
     288             : get_nonce (char *buffer, size_t nbytes)
     289             : {
     290             :   HCRYPTPROV prov;
     291             :   int ret = -1;
     292             : 
     293             :   if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL,
     294             :                             (CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) )
     295             :     gpg_err_set_errno (ENODEV);
     296             :   else
     297             :     {
     298             :       if (!CryptGenRandom (prov, nbytes, (unsigned char *) buffer))
     299             :         gpg_err_set_errno (ENODEV);
     300             :       else
     301             :         ret = 0;
     302             :       CryptReleaseContext (prov, 0);
     303             :     }
     304             :   return ret;
     305             : }
     306             : 
     307             : 
     308             : /* W32: The buffer for NONCE needs to be at least 16 bytes.  Returns 0
     309             :    on success and sets errno on failure.  If FNAME has a Cygwin socket
     310             :    descriptor True is stored at CYGWIN.  */
     311             : static int
     312             : read_port_and_nonce (const char *fname, unsigned short *port, char *nonce,
     313             :                      int *cygwin)
     314             : {
     315             :   FILE *fp;
     316             :   char buffer[50], *p;
     317             :   size_t nread;
     318             :   int aval;
     319             : 
     320             :   *cygwin = 0;
     321             :   fp = fopen (fname, "rb");
     322             :   if (!fp)
     323             :     return -1;
     324             :   nread = fread (buffer, 1, sizeof buffer - 1, fp);
     325             :   fclose (fp);
     326             :   if (!nread)
     327             :     {
     328             :       gpg_err_set_errno (ENOENT);
     329             :       return -1;
     330             :     }
     331             :   buffer[nread] = 0;
     332             :   if (!strncmp (buffer, "!<socket >", 10))
     333             :     {
     334             :       /* This is the Cygwin compatible socket emulation.  The format
     335             :        * of the file is:
     336             :        *
     337             :        *   "!<socket >%u %c %08x-%08x-%08x-%08x\x00"
     338             :        *
     339             :        * %d for port number, %c for kind of socket (s for STREAM), and
     340             :        * we have 16-byte random bytes for nonce.  We only support
     341             :        * stream mode.
     342             :        */
     343             :       unsigned int u0;
     344             :       int narr[4];
     345             : 
     346             :       if (sscanf (buffer+10, "%u s %08x-%08x-%08x-%08x",
     347             :                   &u0, narr+0, narr+1, narr+2, narr+3) != 5
     348             :           || u0 < 1 || u0 > 65535)
     349             :         {
     350             :           gpg_err_set_errno (EINVAL);
     351             :           return -1;
     352             :         }
     353             :       *port = u0;
     354             :       memcpy (nonce, narr, 16);
     355             :       *cygwin = 1;
     356             :     }
     357             :   else
     358             :     {
     359             :       /* This is our own socket emulation.  */
     360             :       aval = atoi (buffer);
     361             :       if (aval < 1 || aval > 65535)
     362             :         {
     363             :           gpg_err_set_errno (EINVAL);
     364             :           return -1;
     365             :         }
     366             :       *port = (unsigned int)aval;
     367             :       for (p=buffer; nread && *p != '\n'; p++, nread--)
     368             :         ;
     369             :       if (*p != '\n' || nread != 17)
     370             :         {
     371             :           gpg_err_set_errno (EINVAL);
     372             :           return -1;
     373             :         }
     374             :       p++; nread--;
     375             :       memcpy (nonce, p, 16);
     376             :     }
     377             : 
     378             :   return 0;
     379             : }
     380             : #endif /*HAVE_W32_SYSTEM*/
     381             : 
     382             : 
     383             : #ifndef HAVE_W32_SYSTEM
     384             : /* Find a redirected socket name for fname and return a malloced setup
     385             :    filled sockaddr.  If this does not work out NULL is returned and
     386             :    ERRNO is set.  If the file seems to be a redirect True is stored at
     387             :    R_REDIRECT.  Note that this function uses the standard malloc and
     388             :    not the assuan wrapped one.  The format of the file is:
     389             : 
     390             :    %Assuan%
     391             :    socket=NAME
     392             : 
     393             :    where NAME is the actual socket to use.  No white spaces are
     394             :    allowed, both lines must be terminated by a single LF, extra lines
     395             :    are not allowed.  Environment variables are interpreted in NAME if
     396             :    given in "${VAR} notation; no escape characters are defined, if
     397             :    "${" shall be used verbatim, you need to use an environment
     398             :    variable with that content.
     399             : 
     400             :    The use of an absolute NAME is strongly suggested.  The length of
     401             :    the file is limited to 511 bytes which is more than sufficient for
     402             :    that common value of 107 for sun_path.  */
     403             : static struct sockaddr_un *
     404           0 : eval_redirection (const char *fname, int *r_redirect)
     405             : {
     406             :   FILE *fp;
     407             :   char buffer[512], *name;
     408             :   size_t n;
     409             :   struct sockaddr_un *addr;
     410             :   char *p, *pend;
     411             :   const char *s;
     412             : 
     413           0 :   *r_redirect = 0;
     414             : 
     415           0 :   fp = fopen (fname, "rb");
     416           0 :   if (!fp)
     417           0 :     return NULL;
     418           0 :   n = fread (buffer, 1, sizeof buffer - 1, fp);
     419           0 :   fclose (fp);
     420           0 :   if (!n)
     421             :     {
     422           0 :       gpg_err_set_errno (ENOENT);
     423           0 :       return NULL;
     424             :     }
     425           0 :   buffer[n] = 0;
     426             : 
     427             :   /* Check that it is a redirection file.  We also check that the
     428             :      first byte of the name is not a LF because that would lead to an
     429             :      zero length name. */
     430           0 :   if (n < 17 || buffer[n-1] != '\n'
     431           0 :       || memcmp (buffer, "%Assuan%\nsocket=", 16)
     432           0 :       || buffer[16] == '\n')
     433             :     {
     434           0 :       gpg_err_set_errno (EINVAL);
     435           0 :       return NULL;
     436             :     }
     437           0 :   buffer[n-1] = 0;
     438           0 :   name = buffer + 16;
     439             : 
     440           0 :   *r_redirect = 1;
     441             : 
     442           0 :   addr = calloc (1, sizeof *addr);
     443           0 :   if (!addr)
     444           0 :     return NULL;
     445           0 :   addr->sun_family = AF_LOCAL;
     446             : 
     447           0 :   n = 0;
     448           0 :   for (p=name; *p; p++)
     449             :     {
     450           0 :       if (*p == '$' && p[1] == '{')
     451             :         {
     452           0 :           p += 2;
     453           0 :           pend = strchr (p, '}');
     454           0 :           if (!pend)
     455             :             {
     456           0 :               free (addr);
     457           0 :               gpg_err_set_errno (EINVAL);
     458           0 :               return NULL;
     459             :             }
     460           0 :           *pend = 0;
     461           0 :           if (*p && (s = getenv (p)))
     462             :             {
     463           0 :               for (; *s; s++)
     464             :                 {
     465           0 :                   if (n < sizeof addr->sun_path - 1)
     466           0 :                     addr->sun_path[n++] = *s;
     467             :                   else
     468             :                     {
     469           0 :                       free (addr);
     470           0 :                       gpg_err_set_errno (ENAMETOOLONG);
     471           0 :                       return NULL;
     472             :                   }
     473             :                 }
     474             :             }
     475           0 :           p = pend;
     476             :         }
     477           0 :       else if (*p == '\n')
     478           0 :         break; /* Be nice and stop at the first LF.  */
     479           0 :       else if (n < sizeof addr->sun_path - 1)
     480           0 :         addr->sun_path[n++] = *p;
     481             :       else
     482             :         {
     483           0 :           free (addr);
     484           0 :           gpg_err_set_errno (ENAMETOOLONG);
     485           0 :           return NULL;
     486             :         }
     487             :     }
     488             : 
     489           0 :   return addr;
     490             : }
     491             : #endif /*!HAVE_W32_SYSTEM*/
     492             : 
     493             : 
     494             : 
     495             : /* Return a new socket.  Note that under W32 we consider a socket the
     496             :    same as an System Handle; all functions using such a handle know
     497             :    about this dual use and act accordingly. */
     498             : assuan_fd_t
     499           0 : _assuan_sock_new (assuan_context_t ctx, int domain, int type, int proto)
     500             : {
     501             : #ifdef HAVE_W32_SYSTEM
     502             :   assuan_fd_t res;
     503             :   if (domain == AF_UNIX || domain == AF_LOCAL)
     504             :     domain = AF_INET;
     505             :   res = SOCKET2HANDLE(_assuan_socket (ctx, domain, type, proto));
     506             :   return res;
     507             : #else
     508           0 :   return _assuan_socket (ctx, domain, type, proto);
     509             : #endif
     510             : }
     511             : 
     512             : 
     513             : int
     514           0 : _assuan_sock_set_flag (assuan_context_t ctx, assuan_fd_t sockfd,
     515             :                        const char *name, int value)
     516             : {
     517             :   (void)ctx;
     518             : 
     519           0 :   if (!strcmp (name, "cygwin"))
     520             :     {
     521             : #ifdef HAVE_W32_SYSTEM
     522             :       if (!value)
     523             :         delete_cygwin_fd (sockfd);
     524             :       else if (insert_cygwin_fd (sockfd))
     525             :         return -1;
     526             : #else
     527             :       /* Setting the Cygwin flag on non-Windows is ignored.  */
     528             : #endif
     529             :     }
     530           0 :   else if (!strcmp (name, "tor-mode") || !strcmp (name, "socks"))
     531             :     {
     532             :       /* If SOCKFD is ASSUAN_INVALID_FD this controls global flag to
     533             :          switch AF_INET and AF_INET6 into TOR mode by using a SOCKS5
     534             :          proxy on localhost:9050.  It may only be switched on and this
     535             :          needs to be done before any new threads are started.  Once
     536             :          TOR mode has been enabled, TOR mode can be disabled for a
     537             :          specific socket by using SOCKFD with a VALUE of 0.  */
     538           0 :       if (sockfd == ASSUAN_INVALID_FD)
     539             :         {
     540           0 :           if (tor_mode && !value)
     541             :             {
     542           0 :               gpg_err_set_errno (EPERM);
     543           0 :               return -1; /* Clearing the global flag is not allowed.  */
     544             :             }
     545           0 :           else if (value)
     546             :             {
     547           0 :               if (*name == 's')
     548           0 :                 tor_mode = SOCKS_PORT;
     549             :               else
     550           0 :                 tor_mode = TOR_PORT;
     551             :             }
     552             :         }
     553           0 :       else if (tor_mode && sockfd != ASSUAN_INVALID_FD)
     554             :         {
     555             :           /* Fixme: Disable/enable tormode for the given context.  */
     556             :         }
     557             :       else
     558             :         {
     559           0 :           gpg_err_set_errno (EINVAL);
     560           0 :           return -1;
     561             :         }
     562             :     }
     563             :   else
     564             :     {
     565           0 :       gpg_err_set_errno (EINVAL);
     566           0 :       return -1;
     567             :     }
     568             : 
     569           0 :   return 0;
     570             : }
     571             : 
     572             : 
     573             : int
     574           0 : _assuan_sock_get_flag (assuan_context_t ctx, assuan_fd_t sockfd,
     575             :                        const char *name, int *r_value)
     576             : {
     577             :   (void)ctx;
     578             : 
     579           0 :   if (!strcmp (name, "cygwin"))
     580             :     {
     581             : #ifdef HAVE_W32_SYSTEM
     582             :       *r_value = is_cygwin_fd (sockfd);
     583             : #else
     584           0 :       *r_value = 0;
     585             : #endif
     586             :     }
     587           0 :   else if (!strcmp (name, "tor-mode"))
     588             :     {
     589             :       /* FIXME: Find tor-mode for the given socket.  */
     590           0 :       *r_value = tor_mode == TOR_PORT;
     591             :     }
     592           0 :   else if (!strcmp (name, "socks"))
     593             :     {
     594           0 :       *r_value = tor_mode == SOCKS_PORT;
     595             :     }
     596             :   else
     597             :     {
     598           0 :       gpg_err_set_errno (EINVAL);
     599           0 :       return -1;
     600             :     }
     601             : 
     602           0 :   return 0;
     603             : }
     604             : 
     605             : 
     606             : /* Read NBYTES from SOCKFD into BUFFER.  Return 0 on success.  Handle
     607             :    EAGAIN and EINTR.  */
     608             : static int
     609           0 : do_readn (assuan_context_t ctx, assuan_fd_t sockfd,
     610             :           void *buffer, size_t nbytes)
     611             : {
     612           0 :   char *p = buffer;
     613             :   size_t n;
     614             : 
     615           0 :   while (nbytes)
     616             :     {
     617           0 :       n = _assuan_read (ctx, sockfd, p, nbytes);
     618             :       if (n < 0 && errno == EINTR)
     619             :         ;
     620             :       else if (n < 0 && errno == EAGAIN)
     621             :         _assuan_usleep (ctx, 100000); /* 100ms */
     622             :       else if (n < 0)
     623             :         return -1;
     624           0 :       else if (!n)
     625             :         {
     626           0 :           gpg_err_set_errno (EIO);
     627           0 :           return -1;
     628             :         }
     629             :       else
     630             :         {
     631           0 :           p += n;
     632           0 :           nbytes -= n;
     633             :         }
     634             :     }
     635           0 :   return 0;
     636             : }
     637             : 
     638             : 
     639             : /* Write NBYTES from BUFFER to SOCKFD.  Return 0 on success; on error
     640             :    return -1 and set ERRNO.  */
     641             : static int
     642           0 : do_writen (assuan_context_t ctx, assuan_fd_t sockfd,
     643             :            const void *buffer, size_t nbytes)
     644             : {
     645             :   int ret;
     646             : 
     647           0 :   ret = _assuan_write (ctx, sockfd, buffer, nbytes);
     648           0 :   if (ret >= 0 && ret != nbytes)
     649             :     {
     650           0 :       gpg_err_set_errno (EIO);
     651           0 :       ret = -1;
     652             :     }
     653           0 :   else if (ret >= 0)
     654           0 :     ret = 0;
     655             : 
     656           0 :   return ret;
     657             : }
     658             : 
     659             : 
     660             : /* Connect using the SOCKS5 protocol. */
     661             : static int
     662           0 : socks5_connect (assuan_context_t ctx, assuan_fd_t sock,
     663             :                 unsigned short socksport,
     664             :                 const char *credentials,
     665             :                 const char *hostname, unsigned short hostport,
     666             :                 struct sockaddr *addr, socklen_t length)
     667             : {
     668             :   int ret;
     669             :   /* struct sockaddr_in6 proxyaddr_in6; */
     670             :   struct sockaddr_in  proxyaddr_in;
     671             :   struct sockaddr *proxyaddr;
     672             :   size_t proxyaddrlen;
     673             :   struct sockaddr_in6 *addr_in6;
     674             :   struct sockaddr_in  *addr_in;
     675             :   unsigned char buffer[22+512]; /* The extra 512 gives enough space
     676             :                                    for username/password or the
     677             :                                    hostname. */
     678             :   size_t buflen, hostnamelen;
     679             :   int method;
     680             : 
     681             :   /* memset (&proxyaddr_in6, 0, sizeof proxyaddr_in6); */
     682           0 :   memset (&proxyaddr_in, 0, sizeof proxyaddr_in);
     683             : 
     684             :   /* Either HOSTNAME or ADDR may be given.  */
     685           0 :   if (hostname && addr)
     686             :     {
     687           0 :       gpg_err_set_errno (EINVAL);
     688           0 :       return -1;
     689             :     }
     690             : 
     691             :   /* If a hostname is given it must fit into our buffer and it must be
     692             :      less than 256 so that its length can be encoded in one byte.  */
     693           0 :   hostnamelen = hostname? strlen (hostname) : 0;
     694           0 :   if (hostnamelen > 255)
     695             :     {
     696           0 :       gpg_err_set_errno (ENAMETOOLONG);
     697           0 :       return -1;
     698             :     }
     699             : 
     700             :   /* Connect to local host.  */
     701             :   /* Fixme: First try to use IPv6 but note that
     702             :      _assuan_sock_connect_byname created the socket with AF_INET.  */
     703           0 :   proxyaddr_in.sin_family = AF_INET;
     704           0 :   proxyaddr_in.sin_port = htons (socksport);
     705           0 :   proxyaddr_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
     706           0 :   proxyaddr = (struct sockaddr *)&proxyaddr_in;
     707           0 :   proxyaddrlen = sizeof proxyaddr_in;
     708           0 :   ret = _assuan_connect (ctx, HANDLE2SOCKET (sock), proxyaddr, proxyaddrlen);
     709           0 :   if (ret)
     710           0 :     return ret;
     711           0 :   buffer[0] = 5; /* RFC-1928 VER field.  */
     712           0 :   buffer[1] = 1; /* NMETHODS */
     713           0 :   if (credentials)
     714           0 :     method = 2; /* Method: username/password authentication. */
     715             :   else
     716           0 :     method = 0; /* Method: No authentication required. */
     717           0 :   buffer[2] = method;
     718             : 
     719             :   /* Negotiate method.  */
     720           0 :   ret = do_writen (ctx, sock, buffer, 3);
     721           0 :   if (ret)
     722           0 :     return ret;
     723           0 :   ret = do_readn (ctx, sock, buffer, 2);
     724           0 :   if (ret)
     725           0 :     return ret;
     726           0 :   if (buffer[0] != 5 || buffer[1] != method )
     727             :     {
     728             :       /* Socks server returned wrong version or does not support our
     729             :          requested method.  */
     730           0 :       gpg_err_set_errno (ENOTSUP); /* Fixme: Is there a better errno? */
     731           0 :       return -1;
     732             :     }
     733             : 
     734           0 :   if (credentials)
     735             :     {
     736             :       const char *password;
     737             :       int ulen, plen;
     738             : 
     739           0 :       password = strchr (credentials, ':');
     740           0 :       if (!password)
     741             :         {
     742           0 :           gpg_err_set_errno (EINVAL); /* No password given.  */
     743           0 :           return -1;
     744             :         }
     745           0 :       ulen = password - credentials;
     746           0 :       password++;
     747           0 :       plen = strlen (password);
     748           0 :       if (!ulen || ulen > 255 || !plen || plen > 255)
     749             :         {
     750           0 :           gpg_err_set_errno (EINVAL);
     751           0 :           return -1;
     752             :         }
     753             : 
     754           0 :       buffer[0] = 1; /* VER of the sub-negotiation. */
     755           0 :       buffer[1] = ulen;
     756           0 :       buflen = 2;
     757           0 :       memcpy (buffer+buflen, credentials, ulen);
     758           0 :       buflen += ulen;
     759           0 :       buffer[buflen++] = plen;
     760           0 :       memcpy (buffer+buflen, password, plen);
     761           0 :       buflen += plen;
     762           0 :       ret = do_writen (ctx, sock, buffer, buflen);
     763           0 :       wipememory (buffer, buflen);
     764           0 :       if (ret)
     765           0 :         return ret;
     766           0 :       ret = do_readn (ctx, sock, buffer, 2);
     767           0 :       if (ret)
     768           0 :         return ret;
     769           0 :       if (buffer[0] != 1)
     770             :         {
     771             :           /* SOCKS server returned wrong version.  */
     772           0 :           gpg_err_set_errno (EPROTO);
     773           0 :           return -1;
     774             :         }
     775           0 :       if (buffer[1])
     776             :         {
     777             :           /* SOCKS server denied access.  */
     778           0 :           gpg_err_set_errno (EACCES);
     779           0 :           return -1;
     780             :         }
     781             :     }
     782             : 
     783             :   /* Send request details (rfc-1928, 4).  */
     784           0 :   buffer[0] = 5; /* VER  */
     785           0 :   buffer[1] = 1; /* CMD = CONNECT  */
     786           0 :   buffer[2] = 0; /* RSV  */
     787           0 :   if (hostname)
     788             :     {
     789           0 :       buffer[3] = 3; /* ATYP = DOMAINNAME */
     790           0 :       buflen = 4;
     791           0 :       buffer[buflen++] = hostnamelen;
     792           0 :       memcpy (buffer+buflen, hostname, hostnamelen);
     793           0 :       buflen += hostnamelen;
     794           0 :       buffer[buflen++] = (hostport >> 8); /* DST.PORT */
     795           0 :       buffer[buflen++] = hostport;
     796             :     }
     797           0 :   else if (addr->sa_family == AF_INET6)
     798             :     {
     799           0 :       addr_in6 = (struct sockaddr_in6 *)addr;
     800             : 
     801           0 :       buffer[3] = 4; /* ATYP = IPv6 */
     802           0 :       memcpy (buffer+ 4, &addr_in6->sin6_addr.s6_addr, 16); /* DST.ADDR */
     803           0 :       memcpy (buffer+20, &addr_in6->sin6_port, 2);          /* DST.PORT */
     804           0 :       buflen = 22;
     805             :     }
     806             :   else
     807             :     {
     808           0 :       addr_in = (struct sockaddr_in *)addr;
     809             : 
     810           0 :       buffer[3] = 1; /* ATYP = IPv4 */
     811           0 :       memcpy (buffer+4, &addr_in->sin_addr.s_addr, 4); /* DST.ADDR */
     812           0 :       memcpy (buffer+8, &addr_in->sin_port, 2);        /* DST.PORT */
     813           0 :       buflen = 10;
     814             :     }
     815           0 :   ret = do_writen (ctx, sock, buffer, buflen);
     816           0 :   if (ret)
     817           0 :     return ret;
     818           0 :   ret = do_readn (ctx, sock, buffer, 10 /* Length for IPv4 */);
     819           0 :   if (ret)
     820           0 :     return ret;
     821           0 :   if (buffer[0] != 5 || buffer[2] != 0 )
     822             :     {
     823             :       /* Socks server returned wrong version or the reserved field is
     824             :          not zero.  */
     825           0 :       gpg_err_set_errno (EPROTO);
     826           0 :       return -1;
     827             :     }
     828           0 :   if (buffer[1])
     829             :     {
     830           0 :       switch (buffer[1])
     831             :         {
     832             :         case 0x01: /* General SOCKS server failure.  */
     833           0 :           gpg_err_set_errno (ENETDOWN);
     834           0 :           break;
     835             :         case 0x02: /* Connection not allowed by ruleset.  */
     836           0 :           gpg_err_set_errno (EACCES);
     837           0 :           break;
     838             :         case 0x03: /* Network unreachable */
     839           0 :           gpg_err_set_errno (ENETUNREACH);
     840           0 :           break;
     841             :         case 0x04: /* Host unreachable */
     842           0 :           gpg_err_set_errno (EHOSTUNREACH);
     843           0 :           break;
     844             :         case 0x05: /* Connection refused */
     845           0 :           gpg_err_set_errno (ECONNREFUSED);
     846           0 :           break;
     847             :         case 0x06: /* TTL expired */
     848           0 :           gpg_err_set_errno (ETIMEDOUT);
     849           0 :           break;
     850             :         case 0x08: /* Address type not supported */
     851           0 :           gpg_err_set_errno (EPROTONOSUPPORT);
     852           0 :           break;
     853             :         case 0x07: /* Command not supported */
     854             :         default:
     855           0 :           gpg_err_set_errno (ENOTSUP); /* Fixme: Is there a better errno? */
     856             :         }
     857           0 :       return -1;
     858             :     }
     859           0 :   if (buffer[3] == 4)
     860             :     {
     861             :       /* ATYP indicates a v6 address.  We need to read the remaining
     862             :          12 bytes.  */
     863           0 :       ret = do_readn (ctx, sock, buffer+10, 12);
     864           0 :       if (ret)
     865           0 :         return ret;
     866             :     }
     867             : 
     868             :   /* FIXME: We have not way to store the actual address used by the
     869             :      server.  */
     870             : 
     871             : 
     872           0 :   return 0;
     873             : }
     874             : 
     875             : 
     876             : /* Return true if SOCKS shall be used.  This is the case if tor_mode
     877             :    is enabled and the desired address is not the loopback
     878             :    address.  */
     879             : static int
     880           0 : use_socks (struct sockaddr *addr)
     881             : {
     882           0 :   if (!tor_mode)
     883           0 :     return 0;
     884           0 :   else if (addr->sa_family == AF_INET6)
     885             :     {
     886           0 :       struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
     887             :       const unsigned char *s;
     888             :       int i;
     889             : 
     890           0 :       s = (unsigned char *)&addr_in6->sin6_addr.s6_addr;
     891           0 :       if (s[15] != 1)
     892           0 :         return 1;   /* Last octet is not 1 - not the loopback address.  */
     893           0 :       for (i=0; i < 15; i++, s++)
     894           0 :         if (*s)
     895           0 :           return 1; /* Non-zero octet found - not the loopback address.  */
     896             : 
     897           0 :       return 0; /* This is the loopback address.  */
     898             :     }
     899           0 :   else if (addr->sa_family == AF_INET)
     900             :     {
     901           0 :       struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
     902             : 
     903           0 :       if (*(unsigned char*)&addr_in->sin_addr.s_addr == 127)
     904           0 :         return 0; /* Loopback (127.0.0.0/8) */
     905             : 
     906           0 :       return 1;
     907             :     }
     908             :   else
     909           0 :     return 0;
     910             : }
     911             : 
     912             : 
     913             : int
     914           0 : _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
     915             :                       struct sockaddr *addr, int addrlen)
     916             : {
     917             : #ifdef HAVE_W32_SYSTEM
     918             :   if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
     919             :     {
     920             :       struct sockaddr_in myaddr;
     921             :       struct sockaddr_un *unaddr;
     922             :       unsigned short port;
     923             :       char nonce[16];
     924             :       int cygwin;
     925             :       int ret;
     926             : 
     927             :       unaddr = (struct sockaddr_un *)addr;
     928             :       if (read_port_and_nonce (unaddr->sun_path, &port, nonce, &cygwin))
     929             :         return -1;
     930             : 
     931             :       myaddr.sin_family = AF_INET;
     932             :       myaddr.sin_port = htons (port);
     933             :       myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
     934             : 
     935             :       /* Set return values.  */
     936             :       unaddr->sun_family = myaddr.sin_family;
     937             :       unaddr->sun_port = myaddr.sin_port;
     938             :       unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr;
     939             : 
     940             :       ret = _assuan_connect (ctx, HANDLE2SOCKET(sockfd),
     941             :                             (struct sockaddr *)&myaddr, sizeof myaddr);
     942             :       if (!ret)
     943             :         {
     944             :           /* Send the nonce. */
     945             :           ret = do_writen (ctx, sockfd, nonce, 16);
     946             :           if (!ret && cygwin)
     947             :             {
     948             :               char buffer[16];
     949             : 
     950             :               /* The client sends the nonce back - not useful.  We do
     951             :                  a dummy read.  */
     952             :               ret = do_readn (ctx, sockfd, buffer, 16);
     953             :               if (!ret)
     954             :                 {
     955             :                   /* Send our credentials.  */
     956             :                   int n = getpid ();
     957             :                   memcpy (buffer, &n, 4);
     958             :                   memset (buffer+4, 0, 4); /* uid = gid = 0 */
     959             :                   ret = do_writen (ctx, sockfd, buffer, 8);
     960             :                   if (!ret)
     961             :                     {
     962             :                       /* Receive credentials.  We don't need them.  */
     963             :                       ret = do_readn (ctx, sockfd, buffer, 8);
     964             :                     }
     965             :                 }
     966             :             }
     967             :         }
     968             :       return ret;
     969             :     }
     970             :   else if (use_socks (addr))
     971             :     {
     972             :       return socks5_connect (ctx, sockfd, tor_mode,
     973             :                              NULL, NULL, 0, addr, addrlen);
     974             :     }
     975             :   else
     976             :     {
     977             :       return _assuan_connect (ctx, HANDLE2SOCKET (sockfd), addr, addrlen);
     978             :     }
     979             : #else
     980             : # if HAVE_STAT
     981           0 :   if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
     982             :     {
     983             :       struct sockaddr_un *unaddr;
     984             :       struct stat statbuf;
     985             :       int redirect, res;
     986             : 
     987           0 :       unaddr = (struct sockaddr_un *)addr;
     988           0 :       if (!stat (unaddr->sun_path, &statbuf)
     989           0 :           && !S_ISSOCK (statbuf.st_mode)
     990           0 :           && S_ISREG (statbuf.st_mode))
     991             :         {
     992             :           /* The given socket file is not a socket but a regular file.
     993             :              We use the content of that file to redirect to another
     994             :              socket file.  This can be used to use sockets on file
     995             :              systems which do not support sockets or if for example a
     996             :              home directory is shared by several machines.  */
     997           0 :           unaddr = eval_redirection (unaddr->sun_path, &redirect);
     998           0 :           if (unaddr)
     999             :             {
    1000           0 :               res = _assuan_connect (ctx, sockfd, (struct sockaddr *)unaddr,
    1001           0 :                                      SUN_LEN (unaddr));
    1002           0 :               free (unaddr);
    1003           0 :               return res;
    1004             :             }
    1005           0 :           if (redirect)
    1006           0 :             return -1;
    1007             :           /* Continue using the standard connect.  */
    1008             :         }
    1009             : 
    1010             :     }
    1011             : # endif /*HAVE_STAT*/
    1012             : 
    1013           0 :   if (use_socks (addr))
    1014             :     {
    1015           0 :       return socks5_connect (ctx, sockfd, tor_mode,
    1016             :                              NULL, NULL, 0, addr, addrlen);
    1017             :     }
    1018             :   else
    1019             :     {
    1020           0 :       return _assuan_connect (ctx, sockfd, addr, addrlen);
    1021             :     }
    1022             : #endif
    1023             : }
    1024             : 
    1025             : 
    1026             : /* Connect to HOST specified as host name on PORT.  The current
    1027             :    implementation requires that either the flags ASSUAN_SOCK_SOCKS or
    1028             :    ASSUAN_SOCK_TOR are give in FLAGS.  On success a new socket is
    1029             :    returned; on error ASSUAN_INVALID_FD is returned and ERRNO set.  If
    1030             :    CREDENTIALS is not NULL, it is a string used for password based
    1031             :    authentication.  Username and password are separated by a
    1032             :    colon.  RESERVED must be 0. */
    1033             : assuan_fd_t
    1034           0 : _assuan_sock_connect_byname (assuan_context_t ctx, const char *host,
    1035             :                              unsigned short port, int reserved,
    1036             :                              const char *credentials, unsigned int flags)
    1037             : {
    1038             :   assuan_fd_t fd;
    1039             :   unsigned short socksport;
    1040             : 
    1041           0 :   if ((flags & ASSUAN_SOCK_TOR))
    1042           0 :     socksport = TOR_PORT;
    1043           0 :   else if ((flags & ASSUAN_SOCK_SOCKS))
    1044           0 :     socksport = SOCKS_PORT;
    1045             :   else
    1046             :     {
    1047           0 :       gpg_err_set_errno (ENOTSUP);
    1048           0 :       return ASSUAN_INVALID_FD;
    1049             :     }
    1050             : 
    1051           0 :   fd = _assuan_sock_new (ctx, AF_INET, SOCK_STREAM, 0);
    1052           0 :   if (fd == ASSUAN_INVALID_FD)
    1053           0 :     return fd;
    1054             : 
    1055           0 :   if (socks5_connect (ctx, fd, socksport,
    1056             :                       credentials, host, port, NULL, 0))
    1057             :     {
    1058           0 :       int save_errno = errno;
    1059           0 :       assuan_sock_close (fd);
    1060           0 :       gpg_err_set_errno (save_errno);
    1061           0 :       return ASSUAN_INVALID_FD;
    1062             :     }
    1063             : 
    1064           0 :   return fd;
    1065             : }
    1066             : 
    1067             : 
    1068             : int
    1069           0 : _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
    1070             :                    struct sockaddr *addr, int addrlen)
    1071             : {
    1072             : #ifdef HAVE_W32_SYSTEM
    1073             :   if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
    1074             :     {
    1075             :       struct sockaddr_in myaddr;
    1076             :       struct sockaddr_un *unaddr;
    1077             :       HANDLE filehd;
    1078             :       int len = sizeof myaddr;
    1079             :       int rc;
    1080             :       union {
    1081             :         char data[16];
    1082             :         int  aint[4];
    1083             :       } nonce;
    1084             :       char tmpbuf[50+16];
    1085             :       DWORD nwritten;
    1086             : 
    1087             :       if (get_nonce (nonce.data, 16))
    1088             :         return -1;
    1089             : 
    1090             :       unaddr = (struct sockaddr_un *)addr;
    1091             : 
    1092             :       myaddr.sin_port = 0;
    1093             :       myaddr.sin_family = AF_INET;
    1094             :       myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
    1095             : 
    1096             :       filehd = MyCreateFile (unaddr->sun_path,
    1097             :                              GENERIC_WRITE,
    1098             :                              FILE_SHARE_READ,
    1099             :                              NULL,
    1100             :                              CREATE_NEW,
    1101             :                              FILE_ATTRIBUTE_NORMAL,
    1102             :                              NULL);
    1103             :       if (filehd == INVALID_HANDLE_VALUE)
    1104             :         {
    1105             :           if (GetLastError () == ERROR_FILE_EXISTS)
    1106             :             gpg_err_set_errno (EADDRINUSE);
    1107             :           return -1;
    1108             :         }
    1109             : 
    1110             :       rc = bind (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, len);
    1111             :       if (!rc)
    1112             :         rc = getsockname (HANDLE2SOCKET (sockfd),
    1113             :                           (struct sockaddr *)&myaddr, &len);
    1114             :       if (rc)
    1115             :         {
    1116             :           int save_e = errno;
    1117             :           CloseHandle (filehd);
    1118             :           MyDeleteFile (unaddr->sun_path);
    1119             :           gpg_err_set_errno (save_e);
    1120             :           return rc;
    1121             :         }
    1122             : 
    1123             :       if (is_cygwin_fd (sockfd))
    1124             :         {
    1125             :           snprintf (tmpbuf, sizeof tmpbuf,
    1126             :                     "!<socket >%d s %08x-%08x-%08x-%08x",
    1127             :                     ntohs (myaddr.sin_port),
    1128             :                     nonce.aint[0], nonce.aint[1], nonce.aint[2], nonce.aint[3]);
    1129             :           len = strlen (tmpbuf) + 1;
    1130             :         }
    1131             :       else
    1132             :         {
    1133             :           snprintf (tmpbuf, sizeof tmpbuf-16, "%d\n", ntohs (myaddr.sin_port));
    1134             :           len = strlen (tmpbuf);
    1135             :           memcpy (tmpbuf+len, nonce.data,16);
    1136             :           len += 16;
    1137             :         }
    1138             : 
    1139             :       if (!WriteFile (filehd, tmpbuf, len, &nwritten, NULL))
    1140             :         {
    1141             :           CloseHandle (filehd);
    1142             :           MyDeleteFile (unaddr->sun_path);
    1143             :           gpg_err_set_errno (EIO);
    1144             :           return -1;
    1145             :         }
    1146             :       CloseHandle (filehd);
    1147             :       return 0;
    1148             :     }
    1149             :   else
    1150             :     {
    1151             :       int res = bind (HANDLE2SOCKET(sockfd), addr, addrlen);
    1152             :       if (res < 0)
    1153             :         gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()));
    1154             :       return res;
    1155             :     }
    1156             : #else
    1157           0 :   return bind (sockfd, addr, addrlen);
    1158             : #endif
    1159             : }
    1160             : 
    1161             : 
    1162             : /* Setup the ADDR structure for a Unix domain socket with the socket
    1163             :    name FNAME.  If this is a redirected socket and R_REDIRECTED is not
    1164             :    NULL, it will be setup for the real socket.  Returns 0 on success
    1165             :    and stores 1 at R_REDIRECTED if it is a redirected socket.  On
    1166             :    error -1 is returned and ERRNO will be set.  */
    1167             : int
    1168           0 : _assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
    1169             :                               int *r_redirected)
    1170             : {
    1171           0 :   struct sockaddr_un *unaddr = (struct sockaddr_un *)addr;
    1172             : #if !defined(HAVE_W32_SYSTEM) && defined(HAVE_STAT)
    1173             :   struct stat statbuf;
    1174             : #endif
    1175             : 
    1176           0 :   if (r_redirected)
    1177           0 :     *r_redirected = 0;
    1178             : 
    1179             : #if !defined(HAVE_W32_SYSTEM) && defined(HAVE_STAT)
    1180           0 :   if (r_redirected
    1181           0 :       && !stat (fname, &statbuf)
    1182           0 :       && !S_ISSOCK (statbuf.st_mode)
    1183           0 :       && S_ISREG (statbuf.st_mode))
    1184             :     {
    1185             :       /* The given socket file is not a socket but a regular file.  We
    1186             :          use the content of that file to redirect to another socket
    1187             :          file.  This can be used to use sockets on file systems which
    1188             :          do not support sockets or if for example a home directory is
    1189             :          shared by several machines.  */
    1190             :       struct sockaddr_un *unaddr_new;
    1191             :       int redirect;
    1192             : 
    1193           0 :       unaddr_new = eval_redirection (fname, &redirect);
    1194           0 :       if (unaddr_new)
    1195             :         {
    1196           0 :           memcpy (unaddr, unaddr_new, sizeof *unaddr);
    1197           0 :           free (unaddr_new);
    1198           0 :           *r_redirected = 1;
    1199           0 :           return 0;
    1200             :         }
    1201           0 :       if (redirect)
    1202             :         {
    1203           0 :           *r_redirected = 1;
    1204           0 :           return -1;  /* Error.  */
    1205             :         }
    1206             :       /* Fallback to standard setup.  */
    1207             :     }
    1208             : #endif /*!HAVE_W32_SYSTEM && HAVE_STAT*/
    1209             : 
    1210           0 :   if (strlen (fname)+1 >= sizeof unaddr->sun_path)
    1211             :     {
    1212           0 :       gpg_err_set_errno (ENAMETOOLONG);
    1213           0 :       return -1;
    1214             :     }
    1215             : 
    1216           0 :   memset (unaddr, 0, sizeof *unaddr);
    1217           0 :   unaddr->sun_family = AF_LOCAL;
    1218           0 :   strncpy (unaddr->sun_path, fname, sizeof unaddr->sun_path - 1);
    1219           0 :   unaddr->sun_path[sizeof unaddr->sun_path - 1] = 0;
    1220             : 
    1221           0 :   return 0;
    1222             : }
    1223             : 
    1224             : 
    1225             : int
    1226           0 : _assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
    1227             :                         int addrlen, assuan_sock_nonce_t *nonce)
    1228             : {
    1229             : #ifdef HAVE_W32_SYSTEM
    1230             :   if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
    1231             :     {
    1232             :       struct sockaddr_un *unaddr;
    1233             :       unsigned short port;
    1234             :       int dummy;
    1235             : 
    1236             :       if (sizeof nonce->nonce != 16)
    1237             :         {
    1238             :           gpg_err_set_errno (EINVAL);
    1239             :           return -1;
    1240             :         }
    1241             :       nonce->length = 16;
    1242             :       unaddr = (struct sockaddr_un *)addr;
    1243             :       if (read_port_and_nonce (unaddr->sun_path, &port, nonce->nonce, &dummy))
    1244             :         return -1;
    1245             :     }
    1246             :   else
    1247             :     {
    1248             :       nonce->length = 42; /* Arbitrary value to detect unitialized nonce. */
    1249             :       nonce->nonce[0] = 42;
    1250             :     }
    1251             : #else
    1252             :   (void)addr;
    1253             :   (void)addrlen;
    1254           0 :   nonce->length = 0;
    1255             : #endif
    1256           0 :   return 0;
    1257             : }
    1258             : 
    1259             : 
    1260             : int
    1261           0 : _assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd,
    1262             :                           assuan_sock_nonce_t *nonce)
    1263             : {
    1264             : #ifdef HAVE_W32_SYSTEM
    1265             :   char buffer[16];
    1266             :   int n;
    1267             : 
    1268             :   if (sizeof nonce->nonce != 16)
    1269             :     {
    1270             :       gpg_err_set_errno (EINVAL);
    1271             :       return -1;
    1272             :     }
    1273             : 
    1274             :   if (nonce->length == 42 && nonce->nonce[0] == 42)
    1275             :     return 0; /* Not a Unix domain socket.  */
    1276             : 
    1277             :   if (nonce->length != 16)
    1278             :     {
    1279             :       gpg_err_set_errno (EINVAL);
    1280             :       return -1;
    1281             :     }
    1282             : 
    1283             :   if (do_readn (ctx, fd, buffer, 16))
    1284             :     return -1;
    1285             :   if (memcmp (buffer, nonce->nonce, 16))
    1286             :     {
    1287             :       gpg_err_set_errno (EACCES);
    1288             :       return -1;
    1289             :     }
    1290             :   if (is_cygwin_fd (fd))
    1291             :     {
    1292             :       /* Send the nonce back to the client.  */
    1293             :       if (do_writen (ctx, fd, buffer, 16))
    1294             :         return -1;
    1295             :       /* Read the credentials.  Cygwin uses the
    1296             :             struct ucred { pid_t pid; uid_t uid; gid_t gid; };
    1297             :          with pid_t being an int (4 bytes) and uid_t and gid_t being
    1298             :          shorts (2 bytes).  Thus we need to read 8 bytes.  However we
    1299             :          we ignore the values because they are not kernel controlled.  */
    1300             :       if (do_readn (ctx, fd, buffer, 8))
    1301             :         return -1;
    1302             :       /* Send our credentials: We use the uid and gid we received but
    1303             :          our own pid.  */
    1304             :       n = getpid ();
    1305             :       memcpy (buffer, &n, 4);
    1306             :       if (do_writen (ctx, fd, buffer, 8))
    1307             :         return -1;
    1308             :     }
    1309             : 
    1310             : #else
    1311             :   (void)fd;
    1312             :   (void)nonce;
    1313             : #endif
    1314           0 :   return 0;
    1315             : }
    1316             : 
    1317             : 
    1318             : /* Public API.  */
    1319             : 
    1320             : gpg_error_t
    1321           2 : assuan_sock_init ()
    1322             : {
    1323             :   gpg_error_t err;
    1324             : #ifdef HAVE_W32_SYSTEM
    1325             :   WSADATA wsadat;
    1326             : #endif
    1327             : 
    1328           2 :   if (sock_ctx != NULL)
    1329           0 :     return 0;
    1330             : 
    1331             : #ifdef HAVE_W32_SYSTEM
    1332             :   InitializeCriticalSection (&cygwin_fdtable_cs);
    1333             : #endif
    1334             : 
    1335           2 :   err = assuan_new (&sock_ctx);
    1336             : 
    1337             : #ifdef HAVE_W32_SYSTEM
    1338             :   if (! err)
    1339             :     WSAStartup (0x202, &wsadat);
    1340             : #endif
    1341             : 
    1342           2 :   return err;
    1343             : }
    1344             : 
    1345             : 
    1346             : void
    1347           0 : assuan_sock_deinit ()
    1348             : {
    1349           0 :   if (sock_ctx == NULL)
    1350           0 :     return;
    1351             : 
    1352             : #ifdef HAVE_W32_SYSTEM
    1353             :   WSACleanup ();
    1354             : #endif
    1355             : 
    1356           0 :   assuan_release (sock_ctx);
    1357           0 :   sock_ctx = NULL;
    1358             : 
    1359             : #ifdef HAVE_W32_SYSTEM
    1360             :   DeleteCriticalSection (&cygwin_fdtable_cs);
    1361             : #endif
    1362             : }
    1363             : 
    1364             : 
    1365             : int
    1366           0 : assuan_sock_close (assuan_fd_t fd)
    1367             : {
    1368             : #ifdef HAVE_W32_SYSTEM
    1369             :   if (fd != ASSUAN_INVALID_FD)
    1370             :     delete_cygwin_fd (fd);
    1371             : #endif
    1372           0 :   return _assuan_close (sock_ctx, fd);
    1373             : }
    1374             : 
    1375             : assuan_fd_t
    1376           0 : assuan_sock_new (int domain, int type, int proto)
    1377             : {
    1378           0 :   return _assuan_sock_new (sock_ctx, domain, type, proto);
    1379             : }
    1380             : 
    1381             : int
    1382           0 : assuan_sock_set_flag (assuan_fd_t sockfd, const char *name, int value)
    1383             : {
    1384           0 :   return _assuan_sock_set_flag (sock_ctx, sockfd, name, value);
    1385             : }
    1386             : 
    1387             : int
    1388           0 : assuan_sock_get_flag (assuan_fd_t sockfd, const char *name, int *r_value)
    1389             : {
    1390           0 :   return _assuan_sock_get_flag (sock_ctx, sockfd, name, r_value);
    1391             : }
    1392             : 
    1393             : int
    1394           0 : assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
    1395             : {
    1396           0 :   return _assuan_sock_connect (sock_ctx, sockfd, addr, addrlen);
    1397             : }
    1398             : 
    1399             : assuan_fd_t
    1400           0 : assuan_sock_connect_byname (const char *host, unsigned short port,
    1401             :                             int reserved, const char *credentials,
    1402             :                             unsigned int flags)
    1403             : {
    1404           0 :   return _assuan_sock_connect_byname (sock_ctx,
    1405             :                                       host, port, reserved, credentials, flags);
    1406             : }
    1407             : 
    1408             : int
    1409           0 : assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
    1410             : {
    1411           0 :   return _assuan_sock_bind (sock_ctx, sockfd, addr, addrlen);
    1412             : }
    1413             : 
    1414             : int
    1415           0 : assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
    1416             :                              int *r_redirected)
    1417             : {
    1418           0 :   return _assuan_sock_set_sockaddr_un (fname, addr, r_redirected);
    1419             : }
    1420             : 
    1421             : int
    1422           0 : assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
    1423             :                        assuan_sock_nonce_t *nonce)
    1424             : {
    1425           0 :   return _assuan_sock_get_nonce (sock_ctx, addr, addrlen, nonce);
    1426             : }
    1427             : 
    1428             : int
    1429           0 : assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
    1430             : {
    1431           0 :   return _assuan_sock_check_nonce (sock_ctx, fd, nonce);
    1432             : }

Generated by: LCOV version 1.11