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

Generated by: LCOV version 1.12