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