Coverage Report

Created: 2022-12-08 06:09

/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
}