[Gpg4win-devel] Important Assuan change under Windows.

Werner Koch wk at gnupg.org
Mon Oct 1 17:26:57 CEST 2007


Hi,

while reviewing our Windows implementation of the Unix domain socket
emulation, a serious flaw was detected: Any regular user on the local
box would be able to connect to a server of another user.  Given that
the GnuPG-2 port to Windows is still in development and not for
production use; no harm is caused.

No version of GnuPG-1 (e.g. 1.4.7) is affected.

I have fixed this now in the SVN of libassuan and GnuPG.

Required changed for clients:

 * Build against the latest libassuan (-r 267).
 * That's all.

Required changes for servers:

 * Build against the latest libassuan (-r 267)
 * Remove the w32-afunix calls.
 * Replace the socket creation calls with the new assuan wrappers.
 * Save a nonce created by the wrapper's bind implementaion.
 * On connection check that nonce.
 

Here is a commented server example:

  static assuan_sock_nonce_t socket_nonce;

This variable is used to save the nonce.

    struct sockaddr_un *serv_addr;
    socklen_t len;
    assuan_fd_t fd;
  
The assuan_fd_t is used to cope with the problem that under Windows
system file descriptors (as used by Libassuan) are actually of type
HANDLE and implemented as pointers.  With 32 bit systems it is not a
problem to cast them to ints, however with 64 bit Windows this won't
work, thus we use this new type.  Under Unix it is typedefed as int or
course.

    fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
    if (fd == ASSUAN_INVALID_FD)
      handle_error()

This is identical to socket.  Again for portability, ASSUAN_INVALID_FD
is used instead of the -1.

    serv_addr = xmalloc (sizeof (*serv_addr)); 
    memset (serv_addr, 0, sizeof *serv_addr);
    serv_addr->sun_family = AF_UNIX;
    assert (strlen (socket_name) + 1 < sizeof (serv_addr->sun_path));
    strcpy (serv_addr->sun_path, socket_name);
    len = (offsetof (struct sockaddr_un, sun_path)
	   + strlen (serv_addr->sun_path) + 1);
  
    rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);

Here we have called the wrapper for bind.  Only under Windows and only
if a AF_UNIX socket is used, the bind wrapper makes a difference: In
that case bind is called for AF_INET on the loopback interface and the
returned TCP port is written to the file given by SOCKET_NAME.  In
addition a random nonce is written to the file.

    if (rc != -1 
        && (rc=assuan_sock_get_nonce ((struct sockaddr*)serv_addr, len,
                                       &socket_nonce)))
      fprintf (stderr, "error getting nonce for the socket\n");
   if (rc == -1)
      handle_error ();

Calling assuan_sock_get_nonce is important.  It returns the nonce used
by the server and is required later.  It does not harm to call it for
non AF_UNIX or non-Windows systems - in that case the entire nonce
feature has an internal shortcut.

For each connection - after the accept and before the first read - a new
call is required:

  if (assuan_sock_check_nonce (accepted_fd, &socket_nonce))
    {
      fprintf (stderr, "error reading nonce: %s\n", strerror (errno));
      assuan_sock_close (fd);
    }
  else
    process_request ()

If it is a Unix domain socket under Windows (as indicated by
SOCKET_NONE), assuan_sock_check_nonce reads 16 bytes from the client and
compares it to the nonce associated with the listening socket.  Thus
only clients who are actually able to read the socket file and send the
nonce to the server are granted access.  Sending the nonce is handled on
the client side by assuan_sock_connect.

The check has not been integrated into something like a
assuan_sock_accept so that it better integrates with an event system or
alike.  Assuan uses its own read code to read for the socket in during
the check; it is not expected that it blocks; in case that is a problem,
setting the socket to non-blocking mode will solve the problem.


Shalom-Salam,

   Werner

-- 
Die Gedanken sind frei.  Auschnahme regelt ein Bundeschgesetz.




More information about the Gpg4win-devel mailing list