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