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