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