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