Link libgnunetblockgroup to libgnunetblock
[oweals/gnunet.git] / src / util / win.c
index 18e3e80c014790cde3351e24cab7418fb61ca9d1..97877b0cacad2d84654eb9910193295e5b3c6adb 100644 (file)
-/*\r
-     This file is part of GNUnet.\r
-     (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors)\r
-\r
-     GNUnet is free software; you can redistribute it and/or modify\r
-     it under the terms of the GNU General Public License as published\r
-     by the Free Software Foundation; either version 2, or (at your\r
-     option) any later version.\r
-\r
-     GNUnet is distributed in the hope that it will be useful, but\r
-     WITHOUT ANY WARRANTY; without even the implied warranty of\r
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
-     General Public License for more details.\r
-\r
-     You should have received a copy of the GNU General Public License\r
-     along with GNUnet; see the file COPYING.  If not, write to the\r
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
-     Boston, MA 02111-1307, USA.\r
-*/\r
-\r
-/**\r
- * @file util/win.c\r
- * @brief Helper functions for MS Windows in C++\r
- * @author Nils Durner\r
- */\r
-\r
-#ifndef _WIN_C\r
-#define _WIN_C\r
-\r
-#include "winproc.h"\r
-#include "platform.h"\r
-#include "gnunet_common.h"\r
-#include "gnunet_connection_lib.h"\r
-\r
-#include <ntdef.h>\r
-\r
-#ifndef INHERITED_ACE\r
-#define INHERITED_ACE 0x10\r
-#endif\r
-\r
-int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);\r
-\r
-#define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \\r
-  union { \\r
-    struct { \\r
-      ULONG Length; \\r
-      DWORD Flags; \\r
-    }; \\r
-  }; \\r
-\r
-#define _IP_ADAPTER_UNICAST_ADDRESS_BASE \\r
-  SOCKET_ADDRESS                     Address; \\r
-  IP_PREFIX_ORIGIN                   PrefixOrigin; \\r
-  IP_SUFFIX_ORIGIN                   SuffixOrigin; \\r
-  IP_DAD_STATE                       DadState; \\r
-  ULONG                              ValidLifetime; \\r
-  ULONG                              PreferredLifetime; \\r
-  ULONG                              LeaseLifetime;\r
-\r
-#define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \\r
-  UINT8                              OnLinkPrefixLength;\r
-\r
-\r
-#define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix,addition) \\r
-typedef struct _IP_ADAPTER_UNICAST_ADDRESS##suffix { \\r
-  _IP_ADAPTER_UNICAST_ADDRESS_HEAD \\r
-  struct _IP_ADAPTER_UNICAST_ADDRESS##suffix *Next; \\r
-  _IP_ADAPTER_UNICAST_ADDRESS_BASE \\r
-  addition \\r
-} IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix;\r
-\r
-/* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */\r
-_IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA)\r
-\r
-\r
-typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS {\r
-  union {\r
-    ULONGLONG Alignment;\r
-    struct {\r
-      ULONG Length;\r
-      DWORD Reserved;\r
-    };\r
-  };\r
-  struct _IP_ADAPTER_WINS_SERVER_ADDRESS  *Next;\r
-  SOCKET_ADDRESS                         Address;\r
-} IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH;\r
-\r
-typedef struct _IP_ADAPTER_GATEWAY_ADDRESS {\r
-  union {\r
-    ULONGLONG Alignment;\r
-    struct {\r
-      ULONG Length;\r
-      DWORD Reserved;\r
-    };\r
-  };\r
-  struct _IP_ADAPTER_GATEWAY_ADDRESS  *Next;\r
-  SOCKET_ADDRESS                     Address;\r
-} IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH;\r
-\r
-typedef UINT32 NET_IF_COMPARTMENT_ID;\r
-typedef GUID NET_IF_NETWORK_GUID;\r
-\r
-typedef enum _NET_IF_CONNECTION_TYPE {\r
-  NET_IF_CONNECTION_DEDICATED   = 1,\r
-  NET_IF_CONNECTION_PASSIVE,\r
-  NET_IF_CONNECTION_DEMAND,\r
-  NET_IF_CONNECTION_MAXIMUM \r
-} NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE;\r
-\r
-typedef enum  {\r
-  TUNNEL_TYPE_NONE      = 0,\r
-  TUNNEL_TYPE_OTHER,\r
-  TUNNEL_TYPE_DIRECT,\r
-  TUNNEL_TYPE_6TO4,\r
-  TUNNEL_TYPE_ISATAP,\r
-  TUNNEL_TYPE_TEREDO,\r
-  TUNNEL_TYPE_IPHTTPS \r
-} TUNNEL_TYPE, *PTUNNEL_TYPE;\r
-\r
-/*\r
-A DUID consists of a two-octet type code represented in network byte\r
-   order, followed by a variable number of octets that make up the\r
-   actual identifier.  A DUID can be no more than 128 octets long (not\r
-   including the type code).\r
-*/\r
-#define MAX_DHCPV6_DUID_LENGTH 130\r
-\r
-typedef union _NET_LUID {\r
-  ULONG64 Value;\r
-  struct {\r
-    ULONG64 Reserved  :24;\r
-    ULONG64 NetLuidIndex  :24;\r
-    ULONG64 IfType  :16;\r
-  } Info;\r
-} NET_LUID, *PNET_LUID, IF_LUID;\r
-\r
-#define MAX_DNS_SUFFIX_STRING_LENGTH 246\r
-\r
-typedef struct _IP_ADAPTER_DNS_SUFFIX {\r
-  struct _IP_ADAPTER_DNS_SUFFIX  *Next;\r
-  WCHAR                         String[MAX_DNS_SUFFIX_STRING_LENGTH];\r
-} IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX;\r
-\r
-\r
-\r
-#define _IP_ADAPTER_ADDRESSES_HEAD \\r
-  union { \\r
-    ULONGLONG Alignment; \\r
-    struct { \\r
-      ULONG Length; \\r
-      DWORD IfIndex; \\r
-    }; \\r
-  };\r
-\r
-#define _IP_ADAPTER_ADDRESSES_BASE \\r
-  PCHAR                              AdapterName; \\r
-  PIP_ADAPTER_UNICAST_ADDRESS        FirstUnicastAddress; \\r
-  PIP_ADAPTER_ANYCAST_ADDRESS        FirstAnycastAddress; \\r
-  PIP_ADAPTER_MULTICAST_ADDRESS      FirstMulticastAddress; \\r
-  PIP_ADAPTER_DNS_SERVER_ADDRESS     FirstDnsServerAddress; \\r
-  PWCHAR                             DnsSuffix; \\r
-  PWCHAR                             Description; \\r
-  PWCHAR                             FriendlyName; \\r
-  BYTE                               PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \\r
-  DWORD                              PhysicalAddressLength; \\r
-  DWORD                              Flags; \\r
-  DWORD                              Mtu; \\r
-  DWORD                              IfType; \\r
-  IF_OPER_STATUS                     OperStatus;\r
-\r
-#define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \\r
-  DWORD                              Ipv6IfIndex; \\r
-  DWORD                              ZoneIndices[16]; \\r
-  PIP_ADAPTER_PREFIX                 FirstPrefix; \\r
-\r
-\r
-#define _IP_ADAPTER_ADDRESSES_ADD_VISTA \\r
-  _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \\r
-  ULONG64                            TransmitLinkSpeed; \\r
-  ULONG64                            ReceiveLinkSpeed; \\r
-  PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \\r
-  PIP_ADAPTER_GATEWAY_ADDRESS_LH     FirstGatewayAddress; \\r
-  ULONG                              Ipv4Metric; \\r
-  ULONG                              Ipv6Metric; \\r
-  IF_LUID                            Luid; \\r
-  SOCKET_ADDRESS                     Dhcpv4Server; \\r
-  NET_IF_COMPARTMENT_ID              CompartmentId; \\r
-  NET_IF_NETWORK_GUID                NetworkGuid; \\r
-  NET_IF_CONNECTION_TYPE             ConnectionType; \\r
-  TUNNEL_TYPE                        TunnelType; \\r
-  SOCKET_ADDRESS                     Dhcpv6Server; \\r
-  BYTE                               Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \\r
-  ULONG                              Dhcpv6ClientDuidLength; \\r
-  ULONG                              Dhcpv6Iaid;\r
-\r
-#define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \\r
-  _IP_ADAPTER_ADDRESSES_ADD_VISTA \\r
-  PIP_ADAPTER_DNS_SUFFIX             FirstDnsSuffix;\r
-\r
-#define _IP_ADAPTER_ADDRESSES_DEFINE(suffix,addition) \\r
-typedef struct _IP_ADAPTER_ADDRESSES##suffix { \\r
-  _IP_ADAPTER_ADDRESSES_HEAD \\r
-  struct _IP_ADAPTER_ADDRESSES##suffix *Next; \\r
-  _IP_ADAPTER_ADDRESSES_BASE \\r
-  addition \\r
-} IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix;\r
-  \r
-\r
-/* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */\r
-_IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1,_IP_ADAPTER_ADDRESSES_ADD_XPSP1)\r
-_IP_ADAPTER_ADDRESSES_DEFINE(_VISTA,_IP_ADAPTER_ADDRESSES_ADD_VISTA)\r
-_IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1,_IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1)\r
-\r
-static int\r
-EnumNICs_IPv6_get_ifs_count (SOCKET s)\r
-{\r
-  DWORD dwret = 0, err;\r
-  int iret;\r
-  iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0,\r
-      &dwret, NULL, NULL);\r
-  err = GetLastError ();\r
-  if (iret == SOCKET_ERROR && err == WSAEFAULT)\r
-    return dwret;\r
-  else if (iret == 0)\r
-    return 0;\r
-  return GNUNET_SYSERR;\r
-}\r
-\r
-static int\r
-EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size)\r
-{\r
-  int iret;\r
-  DWORD dwret = 0;\r
-  iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size,\r
-      &dwret, NULL, NULL);\r
-\r
-  if (iret != 0 || dwret != size)\r
-  {\r
-    /* It's supposed to succeed! And size should be the same */\r
-    return GNUNET_SYSERR;\r
-  }\r
-  return GNUNET_OK;\r
-}\r
-\r
-#undef GNUNET_malloc\r
-#define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \\r
-    HEAP_GENERATE_EXCEPTIONS, a)\r
-\r
-#undef GNUNET_free\r
-#define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a)\r
-\r
-#undef GNUNET_free_non_null\r
-#define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0)\r
-\r
-static int\r
-EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size)\r
-{\r
-  int iret;\r
-  DWORD dwret = 0;\r
-  DWORD error;\r
-  INTERFACE_INFO *ii = NULL;\r
-  DWORD ii_size = sizeof (INTERFACE_INFO) * 15;\r
-  while (TRUE)\r
-  {\r
-    if (ii_size >= sizeof (INTERFACE_INFO) * 1000)\r
-      return GNUNET_SYSERR;\r
-    ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size);\r
-    dwret = 0;\r
-    iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size,\r
-        &dwret, NULL, NULL);\r
-    error = GetLastError ();\r
-    if (iret == SOCKET_ERROR)\r
-    {\r
-      if (error == WSAEFAULT)\r
-      {\r
-        GNUNET_free (ii);\r
-        ii_size *= 2;\r
-        continue;\r
-      }\r
-      GNUNET_free (ii);\r
-      return GNUNET_SYSERR;\r
-    }\r
-    else\r
-    {\r
-      *inf = ii;\r
-      *size = dwret;\r
-      return GNUNET_OK;\r
-    }\r
-  }\r
-  return GNUNET_SYSERR;\r
-}\r
-\r
-int\r
-EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6)\r
-{\r
-  int result = 0;\r
-  SOCKET s4 = INVALID_SOCKET, s6 = INVALID_SOCKET;\r
-  DWORD dwret1 = 0, dwret2;\r
-  DWORD err1, err2;\r
-  int ifs4len = 0, ifs6len = 0;\r
-  INTERFACE_INFO *interfaces4 = NULL;\r
-  SOCKET_ADDRESS_LIST *interfaces6 = NULL;\r
-  SetLastError (0);\r
-  s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
-  err1 = GetLastError ();\r
-  SetLastError (0);\r
-  s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);\r
-  err2 = GetLastError ();\r
-  if (s6 != INVALID_SOCKET)\r
-  {\r
-    ifs6len = EnumNICs_IPv6_get_ifs_count (s6);\r
-    if (ifs6len > 0)\r
-    {\r
-      interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);\r
-      result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;\r
-    }\r
-    closesocket (s6);\r
-    s6 = INVALID_SOCKET;\r
-  }\r
-\r
-  if (s4 != INVALID_SOCKET)\r
-  {\r
-    result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;\r
-    closesocket (s4);\r
-    s4 = INVALID_SOCKET;\r
-  }\r
-  if (ifs6len + ifs4len == 0)\r
-    goto error;\r
-\r
-  if (!result)\r
-  {\r
-    *ifs4 = interfaces4;\r
-    *ifs4_len = ifs4len;\r
-    *ifs6 = interfaces6;\r
-    return GNUNET_OK;\r
-  }\r
-error:\r
-  if (interfaces4 != NULL)\r
-    GNUNET_free (interfaces4);\r
-  if (interfaces6 != NULL)\r
-    GNUNET_free (interfaces6);\r
-  if (s4 != INVALID_SOCKET)\r
-    closesocket (s4);\r
-  if (s6 != INVALID_SOCKET)\r
-    closesocket (s6);\r
-  return GNUNET_SYSERR;\r
-}\r
-\r
-/**\r
- * Returns GNUNET_OK on OK, GNUNET_SYSERR on error\r
- */\r
-int\r
-EnumNICs3 (struct EnumNICs3_results **results, int *results_count)\r
-{\r
-  DWORD dwRetVal = 0;\r
-  int count = 0;\r
-  ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |\r
-      GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;\r
-  struct sockaddr_in6 examplecom6;\r
-  IPAddr examplecom;\r
-  DWORD best_interface = 0;\r
-  DWORD best_interface6 = 0;\r
-\r
-  int use_enum2 = 0;\r
-  INTERFACE_INFO *interfaces4 = NULL;\r
-  int interfaces4_len = 0;\r
-  SOCKET_ADDRESS_LIST *interfaces6 = NULL;\r
-\r
-  unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);\r
-  IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;\r
-  IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);\r
-\r
-  if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)\r
-      == ERROR_BUFFER_OVERFLOW)\r
-  {\r
-    GNUNET_free (pAddresses);\r
-    pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);\r
-  }\r
-\r
-  dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);\r
-\r
-  if (dwRetVal != NO_ERROR)\r
-  {\r
-    GNUNET_free (pAddresses);\r
-    return GNUNET_SYSERR;\r
-  }\r
-\r
-  if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))\r
-  {\r
-    use_enum2 = 1;\r
-\r
-    /* Enumerate NICs using WSAIoctl() */\r
-    if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))\r
-    {\r
-      GNUNET_free (pAddresses);\r
-      return GNUNET_SYSERR;\r
-    }\r
-  }\r
-\r
-  examplecom = inet_addr("192.0.34.166"); /* www.example.com */\r
-  if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)\r
-    best_interface = 0;\r
-\r
-  if (GNGetBestInterfaceEx != NULL)\r
-  {\r
-    examplecom6.sin6_family = AF_INET6;\r
-    examplecom6.sin6_port = 0;\r
-    examplecom6.sin6_flowinfo = 0;\r
-    examplecom6.sin6_scope_id = 0;\r
-    inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",\r
-        (struct sockaddr *) &examplecom6.sin6_addr);\r
-    dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,\r
-        &best_interface6);\r
-    if (dwRetVal != NO_ERROR)\r
-      best_interface6 = 0;\r
-  }\r
-\r
-  /* Give IPv6 a priority */\r
-  if (best_interface6 != 0)\r
-    best_interface = best_interface6;\r
-\r
-  count = 0;\r
-  for (pCurrentAddress = pAddresses;\r
-      pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)\r
-  {\r
-    if (pCurrentAddress->OperStatus == IfOperStatusUp)\r
-    {\r
-      IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;\r
-      for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;\r
-          unicast = unicast->Next)\r
-      {\r
-        if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||\r
-            unicast->Address.lpSockaddr->sa_family == AF_INET6) &&\r
-            (unicast->DadState == IpDadStateDeprecated ||\r
-            unicast->DadState == IpDadStatePreferred))\r
-          count += 1;\r
-      }\r
-    }\r
-  }\r
-\r
-  if (count == 0)\r
-  {\r
-    *results = NULL;\r
-    *results_count = 0;\r
-    GNUNET_free (pAddresses);\r
-    GNUNET_free_non_null (interfaces4);\r
-    GNUNET_free_non_null (interfaces6);\r
-    return GNUNET_OK;\r
-  }\r
-\r
-  *results = (struct EnumNICs3_results *) GNUNET_malloc (\r
-      sizeof (struct EnumNICs3_results) * count);\r
-  *results_count = count;\r
-\r
-  count = 0;\r
-  for (pCurrentAddress = pAddresses;\r
-      pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)\r
-  {\r
-    struct EnumNICs3_results *r;\r
-    IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;\r
-    if (pCurrentAddress->OperStatus != IfOperStatusUp)\r
-      continue;\r
-    for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;\r
-        unicast = unicast->Next)\r
-    {\r
-      int i, j;\r
-      int mask_length = -1;\r
-      char dst[INET6_ADDRSTRLEN + 1];\r
-\r
-      if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&\r
-          unicast->Address.lpSockaddr->sa_family != AF_INET6) ||\r
-          (unicast->DadState != IpDadStateDeprecated &&\r
-          unicast->DadState != IpDadStatePreferred))\r
-        continue;\r
-\r
-      r = &(*results)[count];\r
-      r->flags = 0;\r
-      if (pCurrentAddress->IfIndex > 0 &&\r
-          pCurrentAddress->IfIndex == best_interface &&\r
-          unicast->Address.lpSockaddr->sa_family == AF_INET)\r
-        r->is_default = 1;\r
-      else if (pCurrentAddress->Ipv6IfIndex > 0 &&\r
-          pCurrentAddress->Ipv6IfIndex == best_interface6 &&\r
-          unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
-        r->is_default = 1;\r
-      else\r
-        r->is_default = 0;\r
-\r
-      /* Don't choose default interface twice */\r
-      if (r->is_default)\r
-        best_interface = best_interface6 = 0;\r
-\r
-      if (!use_enum2)\r
-      {\r
-        memcpy (&r->address, unicast->Address.lpSockaddr,\r
-            unicast->Address.iSockaddrLength);\r
-        memset (&r->mask, 0, sizeof (struct sockaddr));\r
-        mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->\r
-              OnLinkPrefixLength;\r
-        /* OnLinkPrefixLength is the number of leading 1s in the mask.\r
-         * OnLinkPrefixLength is available on Vista and later (hence use_enum2).\r
-         */\r
-        if (unicast->Address.lpSockaddr->sa_family == AF_INET)\r
-        {\r
-          struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;\r
-          for (i = 0; i < mask_length; i++)\r
-              ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);\r
-        }\r
-        else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
-        {\r
-          struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;\r
-          struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;\r
-          for (i = 0; i < mask_length; i++)\r
-            ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);\r
-          memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);\r
-          for (i = mask_length; i < 128; i++)\r
-            ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);\r
-        }\r
-        r->flags |= ENUMNICS3_MASK_OK;\r
-      }\r
-      else\r
-      {\r
-        int found = 0;\r
-        if (unicast->Address.lpSockaddr->sa_family == AF_INET)\r
-        {\r
-          for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)\r
-          {\r
-            struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;\r
-            if (memcpy (&interfaces4[i].iiAddress.Address,\r
-                unicast->Address.lpSockaddr,\r
-                unicast->Address.iSockaddrLength) != 0)\r
-              continue;\r
-            found = 1;\r
-            memcpy (&r->address, &interfaces4[i].iiAddress.Address,\r
-                sizeof (struct sockaddr_in));\r
-            memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,\r
-                sizeof (struct sockaddr_in));\r
-            for (mask_length = 0;\r
-                ((unsigned char *) &m->sin_addr)[mask_length / 8] &\r
-                0x80 >> (mask_length % 8); mask_length++)\r
-            {\r
-            }\r
-            r->flags |= ENUMNICS3_MASK_OK;\r
-          }\r
-        }\r
-        else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
-        {\r
-          for (i = 0;\r
-              interfaces6 != NULL && !found && i < interfaces6->iAddressCount;\r
-              i++)\r
-          {\r
-            if (memcpy (interfaces6->Address[i].lpSockaddr,\r
-                unicast->Address.lpSockaddr,\r
-                unicast->Address.iSockaddrLength) != 0)\r
-              continue;\r
-            found = 1;\r
-            memcpy (&r->address, interfaces6->Address[i].lpSockaddr,\r
-                sizeof (struct sockaddr_in6));\r
-            /* TODO: Find a way to reliably get network mask for IPv6 on XP */\r
-            memset (&r->mask, 0, sizeof (struct sockaddr));\r
-            r->flags &= ~ENUMNICS3_MASK_OK;\r
-          }\r
-        }\r
-        if (!found)\r
-        {\r
-          DebugBreak ();\r
-        }\r
-      }\r
-      if (unicast->Address.lpSockaddr->sa_family == AF_INET)\r
-      {\r
-        struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;\r
-        struct sockaddr_in *a = (struct sockaddr_in *) &r->address;\r
-        /* copy address to broadcast, then flip all the trailing bits not\r
-         * falling under netmask to 1,\r
-         * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.\r
-         */\r
-        memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);\r
-        for (i = mask_length; i < 32; i++)\r
-          ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);\r
-        r->flags |= ENUMNICS3_BCAST_OK;\r
-        r->addr_size = sizeof (struct sockaddr_in);\r
-        inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);\r
-      }\r
-      else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
-      {\r
-        struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;\r
-        /* for IPv6 broadcast is not defined, zero it down */\r
-        memset (&r->broadcast, 0, sizeof (struct sockaddr));\r
-        r->flags &= ~ENUMNICS3_BCAST_OK;\r
-        r->addr_size = sizeof (struct sockaddr_in6);\r
-        inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);\r
-      }\r
-\r
-      i = 0;\r
-      i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,\r
-          "%S (%s", pCurrentAddress->FriendlyName, dst);\r
-      for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)\r
-        i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,\r
-            "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);\r
-      i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");\r
-      r->pretty_name[1000] = '\0';\r
-      count += 1;\r
-    }\r
-  }\r
-\r
-  if (use_enum2)\r
-  {\r
-    GNUNET_free_non_null (interfaces4);\r
-    GNUNET_free_non_null (interfaces6);\r
-  }\r
-\r
-  GNUNET_free (pAddresses);\r
-  return GNUNET_OK;\r
-}\r
-\r
-void\r
-EnumNICs3_free (struct EnumNICs3_results *r)\r
-{\r
-  GNUNET_free_non_null (r);\r
-}\r
-\r
-\r
-/**\r
- * Lists all network interfaces in a combo box\r
- * Used by the basic GTK configurator\r
- *\r
- * @param callback function to call for each NIC\r
- * @param callback_cls closure for callback\r
- */\r
-int\r
-ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)\r
-{\r
-  int r;\r
-  int i;\r
-  struct EnumNICs3_results *results = NULL;\r
-  int results_count;\r
-\r
-  r = EnumNICs3 (&results, &results_count);\r
-  if (r != GNUNET_OK)\r
-    return GNUNET_NO;\r
-\r
-  for (i = 0; i < results_count; i++)\r
-    callback (callback_cls, results[i].pretty_name, results[i].is_default);\r
-  GNUNET_free_non_null (results);\r
-  return GNUNET_YES;\r
-}\r
-\r
-/**\r
- * @brief Installs the Windows service\r
- * @param servicename name of the service as diplayed by the SCM\r
- * @param application path to the application binary\r
- * @param username the name of the service's user account\r
- * @returns 0 on success\r
- *          1 if the Windows version doesn't support services\r
- *          2 if the SCM could not be opened\r
- *          3 if the service could not be created\r
- */\r
-int InstallAsService(char *servicename, char *application, char *username)\r
-{\r
-  SC_HANDLE hManager, hService;\r
-  char szEXE[_MAX_PATH + 17] = "\"";\r
-  char *user = NULL;\r
-\r
-  if (! GNOpenSCManager)\r
-    return 1;\r
-\r
-  plibc_conv_to_win_path(application, szEXE + 1);\r
-  strcat(szEXE, "\" --win-service");\r
-  hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);\r
-  if (! hManager)\r
-    return 2;\r
-\r
-  if (username)\r
-  {\r
-       user = (char *) malloc(strlen(username) + 3);\r
-       sprintf(user, ".\\%s", username);\r
-  }\r
-\r
-  hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,\r
-    SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,\r
-    NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);\r
-\r
-  if (user)\r
-    free(user);\r
-\r
-  if (! hService)\r
-    return 3;\r
-\r
-  GNCloseServiceHandle(hService);\r
-\r
-  return 0;\r
-}\r
-\r
-/**\r
- * @brief Uninstall Windows service\r
- * @param servicename name of the service to delete\r
- * @returns 0 on success\r
- *          1 if the Windows version doesn't support services\r
- *          2 if the SCM could not be openend\r
- *          3 if the service cannot be accessed\r
- *          4 if the service cannot be deleted\r
- */\r
-int UninstallService(char *servicename)\r
-{\r
-  SC_HANDLE hManager, hService;\r
-\r
-  if (! GNOpenSCManager)\r
-    return 1;\r
-\r
-  hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\r
-  if (! hManager)\r
-    return 2;\r
-\r
-  if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))\r
-    if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)\r
-      return 3;\r
-     else\r
-       goto closeSCM;\r
-\r
-  if (! GNDeleteService(hService))\r
-    if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)\r
-      return 4;\r
-\r
-closeSCM:\r
-  GNCloseServiceHandle(hService);\r
-\r
-  return 0;\r
-}\r
-\r
-/**\r
- * @author Scott Field, Microsoft\r
- * @see http://support.microsoft.com/?scid=kb;en-us;132958\r
- * @date 12-Jul-95\r
- */\r
-void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)\r
-{\r
-  DWORD StringLength;\r
-\r
-  if(String == NULL)\r
-  {\r
-    LsaString->Buffer = NULL;\r
-    LsaString->Length = 0;\r
-    LsaString->MaximumLength = 0;\r
-    return;\r
-  }\r
-\r
-  StringLength = wcslen(String);\r
-  LsaString->Buffer = String;\r
-  LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);\r
-  LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);\r
-}\r
-\r
-\r
-/**\r
- * @author Scott Field, Microsoft\r
- * @see http://support.microsoft.com/?scid=kb;en-us;132958\r
- * @date 12-Jul-95\r
- */\r
-NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)\r
-{\r
-  LSA_OBJECT_ATTRIBUTES ObjectAttributes;\r
-  LSA_UNICODE_STRING ServerString;\r
-  PLSA_UNICODE_STRING Server = NULL;\r
-\r
-  /* Always initialize the object attributes to all zeroes. */\r
-  ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));\r
-\r
-  if(ServerName != NULL)\r
-  {\r
-    /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */\r
-    _InitLsaString(&ServerString, ServerName);\r
-    Server = &ServerString;\r
-  }\r
-\r
-  /* Attempt to open the policy. */\r
-  return GNLsaOpenPolicy(Server,\r
-                       &ObjectAttributes, DesiredAccess, PolicyHandle);\r
-}\r
-\r
-/**\r
- * @brief Obtain a SID representing the supplied account on the supplied system\r
- * @return TRUE on success, FALSE on failure\r
- * @author Scott Field, Microsoft\r
- * @date 12-Jul-95\r
- * @remarks A buffer is allocated which contains the SID representing the\r
- *          supplied account. This buffer should be freed when it is no longer\r
- *          needed by calling\n\r
- *            HeapFree(GetProcessHeap(), 0, buffer)\r
- * @remarks Call GetLastError() to obtain extended error information.\r
- * @see http://support.microsoft.com/?scid=kb;en-us;132958\r
- */\r
-BOOL _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)\r
-{\r
-  LPTSTR ReferencedDomain = NULL;\r
-  DWORD cbSid = 128;                                                   /* initial allocation attempt */\r
-  DWORD cchReferencedDomain = 16;      /* initial allocation size */\r
-  SID_NAME_USE peUse;\r
-  BOOL bSuccess = FALSE;                                       /* assume this function will fail */\r
-\r
-  /* initial memory allocations */\r
-  if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)\r
-       return FALSE;\r
-\r
-  if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),\r
-                                   0,\r
-                                   cchReferencedDomain *\r
-                                   sizeof (TCHAR))) == NULL)\r
-       return FALSE;\r
-\r
-    /* Obtain the SID of the specified account on the specified system. */\r
-       while (!GNLookupAccountName(SystemName, /* machine to lookup account on */\r
-                  AccountName,                                                                                         /* account to lookup */\r
-                  *Sid,                                                                                                                        /* SID of interest */\r
-                  &cbSid,                                                                                                              /* size of SID */\r
-                  ReferencedDomain,                                                                    /* domain account was found on */\r
-                  &cchReferencedDomain, &peUse))\r
-       {\r
-               if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)\r
-               {\r
-                       /* reallocate memory */\r
-                       if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)\r
-                               return FALSE;\r
-\r
-                       if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),\r
-                                             0,\r
-                                             ReferencedDomain,\r
-                                             cchReferencedDomain\r
-                                             * sizeof (TCHAR))) == NULL)\r
-                               return FALSE;\r
-      }\r
-      else\r
-        goto end;\r
-  }\r
-\r
-  /* Indicate success. */\r
-  bSuccess = TRUE;\r
-\r
-end:\r
-  /* Cleanup and indicate failure, if appropriate. */\r
-  HeapFree (GetProcessHeap (), 0, ReferencedDomain);\r
-\r
-  if (!bSuccess)\r
-  {\r
-    if (*Sid != NULL)\r
-    {\r
-               HeapFree (GetProcessHeap (), 0, *Sid);\r
-               *Sid = NULL;\r
-    }\r
-  }\r
-\r
-  return bSuccess;\r
-}\r
-\r
-/**\r
- * @author Scott Field, Microsoft\r
- * @see http://support.microsoft.com/?scid=kb;en-us;132958\r
- * @date 12-Jul-95\r
- */\r
-NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */\r
-                               PSID AccountSid,                        /* SID to grant privilege to */\r
-                               LPWSTR PrivilegeName,   /* privilege to grant (Unicode) */\r
-                               BOOL bEnable                                            /* enable or disable */\r
-  )\r
-{\r
-  LSA_UNICODE_STRING PrivilegeString;\r
-\r
-  /* Create a LSA_UNICODE_STRING for the privilege name. */\r
-  _InitLsaString(&PrivilegeString, PrivilegeName);\r
-\r
-  /* grant or revoke the privilege, accordingly */\r
-  if(bEnable)\r
-  {\r
-    NTSTATUS i;\r
-\r
-    i = GNLsaAddAccountRights(PolicyHandle,                            /* open policy handle */\r
-                               AccountSid,                             /* target SID */\r
-                               &PrivilegeString,        /* privileges */\r
-                               1                                                                                       /* privilege count */\r
-      );\r
-  }\r
-  else\r
-  {\r
-    return GNLsaRemoveAccountRights(PolicyHandle,                      /* open policy handle */\r
-                                  AccountSid,                          /* target SID */\r
-                                  FALSE,                                                       /* do not disable all rights */\r
-                                  &PrivilegeString,            /* privileges */\r
-                                  1                                                                            /* privilege count */\r
-      );\r
-  }\r
-}\r
-\r
-/**\r
- * @brief Create a Windows service account\r
- * @return 0 on success, > 0 otherwise\r
- * @param pszName the name of the account\r
- * @param pszDesc description of the account\r
- */\r
-int CreateServiceAccount(const char *pszName, const char *pszDesc)\r
-{\r
-  USER_INFO_1 ui;\r
-  USER_INFO_1008 ui2;\r
-  NET_API_STATUS nStatus;\r
-  wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];\r
-  DWORD dwErr;\r
-  LSA_HANDLE hPolicy;\r
-  PSID pSID;\r
-\r
-  if (! GNNetUserAdd)\r
-       return 1;\r
-  mbstowcs(wszName, pszName, strlen(pszName) + 1);\r
-  mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);\r
-\r
-  memset(&ui, 0, sizeof(ui));\r
-  ui.usri1_name = wszName;\r
-  ui.usri1_password = wszName; /* account is locked anyway */\r
-  ui.usri1_priv = USER_PRIV_USER;\r
-  ui.usri1_comment = wszDesc;\r
-  ui.usri1_flags = UF_SCRIPT;\r
-\r
-  nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);\r
-\r
-  if (nStatus != NERR_Success && nStatus != NERR_UserExists)\r
-       return 2;\r
-\r
-  ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;\r
-  GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);\r
-\r
-  if (_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy) !=\r
-                                                                               STATUS_SUCCESS)\r
-       return 3;\r
-\r
-  _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);\r
-\r
-  if (_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE) != STATUS_SUCCESS)\r
-       return 4;\r
-\r
-  _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);\r
-  _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);\r
-  _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);\r
-\r
-  GNLsaClose(hPolicy);\r
-\r
-  return 0;\r
-}\r
-\r
-/**\r
- * @brief Grant permission to a file\r
- * @param lpszFileName the name of the file or directory\r
- * @param lpszAccountName the user account\r
- * @param dwAccessMask the desired access (e.g. GENERIC_ALL)\r
- * @return TRUE on success\r
- * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&\r
- */\r
-BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,\r
-      DWORD dwAccessMask)\r
-{\r
-  /* SID variables. */\r
-  SID_NAME_USE   snuType;\r
-  TCHAR *        szDomain       = NULL;\r
-  DWORD          cbDomain       = 0;\r
-  LPVOID         pUserSID       = NULL;\r
-  DWORD          cbUserSID      = 0;\r
-\r
-  /* File SD variables. */\r
-  PSECURITY_DESCRIPTOR pFileSD  = NULL;\r
-  DWORD          cbFileSD       = 0;\r
-\r
-  /* New SD variables. */\r
-  SECURITY_DESCRIPTOR  newSD;\r
-\r
-  /* ACL variables. */\r
-  PACL           pACL           = NULL;\r
-  BOOL           fDaclPresent;\r
-  BOOL           fDaclDefaulted;\r
-  ACL_SIZE_INFORMATION AclInfo;\r
-\r
-  /* New ACL variables. */\r
-  PACL           pNewACL        = NULL;\r
-  DWORD          cbNewACL       = 0;\r
-\r
-  /* Temporary ACE. */\r
-  LPVOID         pTempAce       = NULL;\r
-  UINT           CurrentAceIndex = 0;\r
-\r
-  UINT           newAceIndex = 0;\r
-\r
-  /* Assume function will fail. */\r
-  BOOL           fResult        = FALSE;\r
-  BOOL           fAPISuccess;\r
-\r
-  SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;\r
-\r
-  /**\r
-   * STEP 1: Get SID of the account name specified.\r
-   */\r
-  fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,\r
-        pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);\r
-\r
-  /* API should have failed with insufficient buffer. */\r
-  if (fAPISuccess)\r
-     goto end;\r
-  else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {\r
-     goto end;\r
-  }\r
-\r
-  pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);\r
-  if (!pUserSID) {\r
-     goto end;\r
-  }\r
-\r
-  szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));\r
-  if (!szDomain) {\r
-     goto end;\r
-  }\r
-\r
-  fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,\r
-        pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);\r
-  if (!fAPISuccess) {\r
-     goto end;\r
-  }\r
-\r
-  /**\r
-   *  STEP 2: Get security descriptor (SD) of the file specified.\r
-   */\r
-  fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,\r
-        secInfo, pFileSD, 0, &cbFileSD);\r
-\r
-  /* API should have failed with insufficient buffer. */\r
-  if (fAPISuccess)\r
-     goto end;\r
-  else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {\r
-     goto end;\r
-  }\r
-\r
-  pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,\r
-       cbFileSD);\r
-  if (!pFileSD) {\r
-     goto end;\r
-  }\r
-\r
-  fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,\r
-        secInfo, pFileSD, cbFileSD, &cbFileSD);\r
-  if (!fAPISuccess) {\r
-     goto end;\r
-  }\r
-\r
-  /**\r
-   * STEP 3: Initialize new SD.\r
-   */\r
-  if (!GNInitializeSecurityDescriptor(&newSD,\r
-        SECURITY_DESCRIPTOR_REVISION)) {\r
-     goto end;\r
-  }\r
-\r
-  /**\r
-   * STEP 4: Get DACL from the old SD.\r
-   */\r
-  if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,\r
-        &fDaclDefaulted)) {\r
-     goto end;\r
-  }\r
-\r
-  /**\r
-   * STEP 5: Get size information for DACL.\r
-   */\r
-  AclInfo.AceCount = 0; // Assume NULL DACL.\r
-  AclInfo.AclBytesFree = 0;\r
-  AclInfo.AclBytesInUse = sizeof(ACL);\r
-\r
-  if (pACL == NULL)\r
-     fDaclPresent = FALSE;\r
-\r
-  /* If not NULL DACL, gather size information from DACL. */\r
-  if (fDaclPresent) {\r
-\r
-     if (!GNGetAclInformation(pACL, &AclInfo,\r
-           sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {\r
-        goto end;\r
-     }\r
-  }\r
-\r
-  /**\r
-   * STEP 6: Compute size needed for the new ACL.\r
-   */\r
-  cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)\r
-        + GetLengthSid(pUserSID) - sizeof(DWORD);\r
-\r
-  /**\r
-   * STEP 7: Allocate memory for new ACL.\r
-   */\r
-  pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);\r
-  if (!pNewACL) {\r
-     goto end;\r
-  }\r
-\r
-  /**\r
-   * STEP 8: Initialize the new ACL.\r
-   */\r
-  if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {\r
-     goto end;\r
-  }\r
-\r
-  /**\r
-   * STEP 9 If DACL is present, copy all the ACEs from the old DACL\r
-   * to the new DACL.\r
-   *\r
-   * The following code assumes that the old DACL is\r
-   * already in Windows 2000 preferred order.  To conform\r
-   * to the new Windows 2000 preferred order, first we will\r
-   * copy all non-inherited ACEs from the old DACL to the\r
-   * new DACL, irrespective of the ACE type.\r
-   */\r
-\r
-  newAceIndex = 0;\r
-\r
-  if (fDaclPresent && AclInfo.AceCount) {\r
-\r
-     for (CurrentAceIndex = 0;\r
-           CurrentAceIndex < AclInfo.AceCount;\r
-           CurrentAceIndex++) {\r
-\r
-        /**\r
-         * TEP 10: Get an ACE.\r
-         */\r
-        if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {\r
-           goto end;\r
-        }\r
-\r
-        /**\r
-         * STEP 11: Check if it is a non-inherited ACE.\r
-         * If it is an inherited ACE, break from the loop so\r
-         * that the new access allowed non-inherited ACE can\r
-         * be added in the correct position, immediately after\r
-         * all non-inherited ACEs.\r
-         */\r
-        if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags\r
-           & INHERITED_ACE)\r
-           break;\r
-\r
-        /**\r
-         * STEP 12: Skip adding the ACE, if the SID matches\r
-         * with the account specified, as we are going to\r
-         * add an access allowed ACE with a different access\r
-         * mask.\r
-         */\r
-        if (GNEqualSid(pUserSID,\r
-           &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))\r
-           continue;\r
-\r
-        /**\r
-         * STEP 13: Add the ACE to the new ACL.\r
-         */\r
-        if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,\r
-              ((PACE_HEADER) pTempAce)->AceSize)) {\r
-           goto end;\r
-        }\r
-\r
-        newAceIndex++;\r
-     }\r
-  }\r
-\r
-  /**\r
-   * STEP 14: Add the access-allowed ACE to the new DACL.\r
-   * The new ACE added here will be in the correct position,\r
-   * immediately after all existing non-inherited ACEs.\r
-   */\r
-  if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,\r
-        pUserSID)) {\r
-     goto end;\r
-  }\r
-\r
-  /**\r
-   * STEP 14.5: Make new ACE inheritable\r
-   */\r
-  if (!GetAce(pNewACL, newAceIndex, &pTempAce))\r
-    goto end;\r
-  ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=\r
-    (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);\r
-\r
-  /**\r
-   * STEP 15: To conform to the new Windows 2000 preferred order,\r
-   * we will now copy the rest of inherited ACEs from the\r
-   * old DACL to the new DACL.\r
-   */\r
-  if (fDaclPresent && AclInfo.AceCount) {\r
-\r
-     for (;\r
-          CurrentAceIndex < AclInfo.AceCount;\r
-          CurrentAceIndex++) {\r
-\r
-        /**\r
-         * STEP 16: Get an ACE.\r
-         */\r
-        if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {\r
-           goto end;\r
-        }\r
-\r
-        /**\r
-         * STEP 17: Add the ACE to the new ACL.\r
-         */\r
-        if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,\r
-              ((PACE_HEADER) pTempAce)->AceSize)) {\r
-           goto end;\r
-        }\r
-     }\r
-  }\r
-\r
-  /**\r
-   * STEP 18: Set permissions\r
-   */\r
-  if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,\r
-    DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {\r
-       goto end;\r
-  }\r
-\r
-  fResult = TRUE;\r
-\r
-end:\r
-\r
-  /**\r
-   * STEP 19: Free allocated memory\r
-   */\r
-  if (pUserSID)\r
-     HeapFree(GetProcessHeap(), 0, pUserSID);\r
-\r
-  if (szDomain)\r
-     HeapFree(GetProcessHeap(), 0, szDomain);\r
-\r
-  if (pFileSD)\r
-     HeapFree(GetProcessHeap(), 0, pFileSD);\r
-\r
-  if (pNewACL)\r
-     HeapFree(GetProcessHeap(), 0, pNewACL);\r
-\r
-  return fResult;\r
-}\r
-\r
-char *winErrorStr(const char *prefix, int dwErr)\r
-{\r
-  char *err, *ret;\r
-  int mem;\r
-\r
-  if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,\r
-    NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,\r
-    0, NULL ))\r
-  {\r
-    err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);\r
-  }\r
-\r
-  mem = strlen(err) + strlen(prefix) + 20;\r
-  ret = (char *) malloc(mem);\r
-\r
-  snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);\r
-\r
-  LocalFree(err);\r
-\r
-  return ret;\r
-}\r
-\r
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/win.c
+ * @brief Helper functions for MS Windows in C++
+ * @author Nils Durner
+ */
+
+#ifndef _WIN_C
+#define _WIN_C
+
+#include "winproc.h"
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_common.h"
+#include "gnunet_connection_lib.h"
+
+#include <ntdef.h>
+#ifndef INHERITED_ACE
+#define INHERITED_ACE 0x10
+#endif
+
+int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);
+
+#define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \
+  union { \
+    struct { \
+      ULONG Length; \
+      DWORD Flags; \
+    }; \
+  };
+
+#define _IP_ADAPTER_UNICAST_ADDRESS_BASE \
+  SOCKET_ADDRESS                     Address; \
+  IP_PREFIX_ORIGIN                   PrefixOrigin; \
+  IP_SUFFIX_ORIGIN                   SuffixOrigin; \
+  IP_DAD_STATE                       DadState; \
+  ULONG                              ValidLifetime; \
+  ULONG                              PreferredLifetime; \
+  ULONG                              LeaseLifetime;
+
+#define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \
+  UINT8                              OnLinkPrefixLength;
+
+
+#define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix,addition) \
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS##suffix { \
+  _IP_ADAPTER_UNICAST_ADDRESS_HEAD \
+  struct _IP_ADAPTER_UNICAST_ADDRESS##suffix *Next; \
+  _IP_ADAPTER_UNICAST_ADDRESS_BASE \
+  addition \
+} IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix;
+
+/* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */
+_IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA)
+
+
+#ifndef __MINGW64_VERSION_MAJOR
+typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS {
+  union {
+    ULONGLONG Alignment;
+    struct {
+      ULONG Length;
+      DWORD Reserved;
+    };
+  };
+  struct _IP_ADAPTER_WINS_SERVER_ADDRESS  *Next;
+  SOCKET_ADDRESS                         Address;
+} IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH;
+
+typedef struct _IP_ADAPTER_GATEWAY_ADDRESS {
+  union {
+    ULONGLONG Alignment;
+    struct {
+      ULONG Length;
+      DWORD Reserved;
+    };
+  };
+  struct _IP_ADAPTER_GATEWAY_ADDRESS  *Next;
+  SOCKET_ADDRESS                     Address;
+} IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH;
+#endif
+
+typedef UINT32 NET_IF_COMPARTMENT_ID;
+typedef GUID NET_IF_NETWORK_GUID;
+
+#ifndef __MINGW64_VERSION_MAJOR
+typedef enum _NET_IF_CONNECTION_TYPE {
+  NET_IF_CONNECTION_DEDICATED   = 1,
+  NET_IF_CONNECTION_PASSIVE,
+  NET_IF_CONNECTION_DEMAND,
+  NET_IF_CONNECTION_MAXIMUM
+} NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE;
+
+typedef enum  {
+  TUNNEL_TYPE_NONE      = 0,
+  TUNNEL_TYPE_OTHER,
+  TUNNEL_TYPE_DIRECT,
+  TUNNEL_TYPE_6TO4,
+  TUNNEL_TYPE_ISATAP,
+  TUNNEL_TYPE_TEREDO,
+  TUNNEL_TYPE_IPHTTPS
+} TUNNEL_TYPE, *PTUNNEL_TYPE;
+#endif
+
+/*
+A DUID consists of a two-octet type code represented in network byte
+   order, followed by a variable number of octets that make up the
+   actual identifier.  A DUID can be no more than 128 octets long (not
+   including the type code).
+*/
+#define MAX_DHCPV6_DUID_LENGTH 130
+
+#ifndef __MINGW64_VERSION_MAJOR
+typedef union _NET_LUID {
+  ULONG64 Value;
+  struct {
+    ULONG64 Reserved  :24;
+    ULONG64 NetLuidIndex  :24;
+    ULONG64 IfType  :16;
+  } Info;
+} NET_LUID, *PNET_LUID, IF_LUID;
+
+#define MAX_DNS_SUFFIX_STRING_LENGTH 246
+
+typedef struct _IP_ADAPTER_DNS_SUFFIX {
+  struct _IP_ADAPTER_DNS_SUFFIX  *Next;
+  WCHAR                         String[MAX_DNS_SUFFIX_STRING_LENGTH];
+} IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX;
+#endif
+
+
+
+#define _IP_ADAPTER_ADDRESSES_HEAD \
+  union { \
+    ULONGLONG Alignment; \
+    struct { \
+      ULONG Length; \
+      DWORD IfIndex; \
+    }; \
+  };
+
+#define _IP_ADAPTER_ADDRESSES_BASE \
+  PCHAR                              AdapterName; \
+  PIP_ADAPTER_UNICAST_ADDRESS        FirstUnicastAddress; \
+  PIP_ADAPTER_ANYCAST_ADDRESS        FirstAnycastAddress; \
+  PIP_ADAPTER_MULTICAST_ADDRESS      FirstMulticastAddress; \
+  PIP_ADAPTER_DNS_SERVER_ADDRESS     FirstDnsServerAddress; \
+  PWCHAR                             DnsSuffix; \
+  PWCHAR                             Description; \
+  PWCHAR                             FriendlyName; \
+  BYTE                               PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \
+  DWORD                              PhysicalAddressLength; \
+  DWORD                              Flags; \
+  DWORD                              Mtu; \
+  DWORD                              IfType; \
+  IF_OPER_STATUS                     OperStatus;
+
+#define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \
+  DWORD                              Ipv6IfIndex; \
+  DWORD                              ZoneIndices[16]; \
+  PIP_ADAPTER_PREFIX                 FirstPrefix; \
+
+
+#define _IP_ADAPTER_ADDRESSES_ADD_VISTA \
+  _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \
+  ULONG64                            TransmitLinkSpeed; \
+  ULONG64                            ReceiveLinkSpeed; \
+  PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \
+  PIP_ADAPTER_GATEWAY_ADDRESS_LH     FirstGatewayAddress; \
+  ULONG                              Ipv4Metric; \
+  ULONG                              Ipv6Metric; \
+  IF_LUID                            Luid; \
+  SOCKET_ADDRESS                     Dhcpv4Server; \
+  NET_IF_COMPARTMENT_ID              CompartmentId; \
+  NET_IF_NETWORK_GUID                NetworkGuid; \
+  NET_IF_CONNECTION_TYPE             ConnectionType; \
+  TUNNEL_TYPE                        TunnelType; \
+  SOCKET_ADDRESS                     Dhcpv6Server; \
+  BYTE                               Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \
+  ULONG                              Dhcpv6ClientDuidLength; \
+  ULONG                              Dhcpv6Iaid;
+
+#define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \
+  _IP_ADAPTER_ADDRESSES_ADD_VISTA \
+  PIP_ADAPTER_DNS_SUFFIX             FirstDnsSuffix;
+
+#define _IP_ADAPTER_ADDRESSES_DEFINE(suffix,addition) \
+typedef struct _IP_ADAPTER_ADDRESSES##suffix { \
+  _IP_ADAPTER_ADDRESSES_HEAD \
+  struct _IP_ADAPTER_ADDRESSES##suffix *Next; \
+  _IP_ADAPTER_ADDRESSES_BASE \
+  addition \
+} IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix;
+
+
+/* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */
+_IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1,_IP_ADAPTER_ADDRESSES_ADD_XPSP1)
+_IP_ADAPTER_ADDRESSES_DEFINE(_VISTA,_IP_ADAPTER_ADDRESSES_ADD_VISTA)
+_IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1,_IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1)
+
+static int
+EnumNICs_IPv6_get_ifs_count (SOCKET s)
+{
+  DWORD dwret = 0, err;
+  int iret;
+  iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0,
+      &dwret, NULL, NULL);
+  err = GetLastError ();
+  if (iret == SOCKET_ERROR && err == WSAEFAULT)
+    return dwret;
+  else if (iret == 0)
+    return 0;
+  return GNUNET_SYSERR;
+}
+
+static int
+EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size)
+{
+  int iret;
+  DWORD dwret = 0;
+  iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size,
+      &dwret, NULL, NULL);
+
+  if (iret != 0 || dwret != size)
+  {
+    /* It's supposed to succeed! And size should be the same */
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+#undef GNUNET_malloc
+#define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \
+    HEAP_GENERATE_EXCEPTIONS, a)
+
+#undef GNUNET_free
+#define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a)
+
+#undef GNUNET_free_non_null
+#define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0)
+
+static int
+EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size)
+{
+  int iret;
+  DWORD dwret = 0;
+  DWORD error;
+  INTERFACE_INFO *ii = NULL;
+  DWORD ii_size = sizeof (INTERFACE_INFO) * 15;
+  while (TRUE)
+  {
+    if (ii_size >= sizeof (INTERFACE_INFO) * 1000)
+      return GNUNET_SYSERR;
+    ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size);
+    dwret = 0;
+    iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size,
+        &dwret, NULL, NULL);
+    error = GetLastError ();
+    if (iret == SOCKET_ERROR)
+    {
+      if (error == WSAEFAULT)
+      {
+        GNUNET_free (ii);
+        ii_size *= 2;
+        continue;
+      }
+      GNUNET_free (ii);
+      return GNUNET_SYSERR;
+    }
+    else
+    {
+      *inf = ii;
+      *size = dwret;
+      return GNUNET_OK;
+    }
+  }
+  return GNUNET_SYSERR;
+}
+
+int
+EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6)
+{
+  int result = 0;
+  SOCKET s4;
+  SOCKET s6;
+  int ifs4len = 0;
+  int ifs6len = 0;
+  INTERFACE_INFO *interfaces4 = NULL;
+  SOCKET_ADDRESS_LIST *interfaces6 = NULL;
+
+  SetLastError (0);
+  s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  (void) GetLastError ();
+  SetLastError (0);
+  s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+  (void) GetLastError ();
+  if (s6 != INVALID_SOCKET)
+  {
+    ifs6len = EnumNICs_IPv6_get_ifs_count (s6);
+    if (ifs6len > 0)
+    {
+      interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);
+      result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;
+    }
+    closesocket (s6);
+    s6 = INVALID_SOCKET;
+  }
+
+  if (s4 != INVALID_SOCKET)
+  {
+    result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;
+    closesocket (s4);
+    s4 = INVALID_SOCKET;
+  }
+  if (ifs6len + ifs4len == 0)
+    goto error;
+
+  if (!result)
+  {
+    *ifs4 = interfaces4;
+    *ifs4_len = ifs4len;
+    *ifs6 = interfaces6;
+    return GNUNET_OK;
+  }
+error:
+  if (interfaces4 != NULL)
+    GNUNET_free (interfaces4);
+  if (interfaces6 != NULL)
+    GNUNET_free (interfaces6);
+  if (s4 != INVALID_SOCKET)
+    closesocket (s4);
+  if (s6 != INVALID_SOCKET)
+    closesocket (s6);
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * @returns #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+EnumNICs3 (struct EnumNICs3_results **results, int *results_count)
+{
+  DWORD dwRetVal = 0;
+  int count = 0;
+  ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |
+      GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
+  struct sockaddr_in6 examplecom6;
+  IPAddr examplecom;
+  DWORD best_interface = 0;
+  DWORD best_interface6 = 0;
+
+  int use_enum2 = 0;
+  INTERFACE_INFO *interfaces4 = NULL;
+  int interfaces4_len = 0;
+  SOCKET_ADDRESS_LIST *interfaces6 = NULL;
+
+  unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
+  IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;
+  IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
+
+  if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)
+      == ERROR_BUFFER_OVERFLOW)
+  {
+    GNUNET_free (pAddresses);
+    pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
+  }
+
+  dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);
+
+  if (dwRetVal != NO_ERROR)
+  {
+    GNUNET_free (pAddresses);
+    return GNUNET_SYSERR;
+  }
+
+  if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))
+  {
+    use_enum2 = 1;
+
+    /* Enumerate NICs using WSAIoctl() */
+    if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))
+    {
+      GNUNET_free (pAddresses);
+      return GNUNET_SYSERR;
+    }
+  }
+
+  examplecom = inet_addr("192.0.34.166"); /* www.example.com */
+  if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)
+    best_interface = 0;
+
+  if (GNGetBestInterfaceEx != NULL)
+  {
+    examplecom6.sin6_family = AF_INET6;
+    examplecom6.sin6_port = 0;
+    examplecom6.sin6_flowinfo = 0;
+    examplecom6.sin6_scope_id = 0;
+    inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",
+        (struct sockaddr *) &examplecom6.sin6_addr);
+    dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,
+        &best_interface6);
+    if (dwRetVal != NO_ERROR)
+      best_interface6 = 0;
+  }
+
+  /* Give IPv6 a priority */
+  if (best_interface6 != 0)
+    best_interface = best_interface6;
+
+  count = 0;
+  for (pCurrentAddress = pAddresses;
+      pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
+  {
+    if (pCurrentAddress->OperStatus == IfOperStatusUp)
+    {
+      IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
+      for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
+          unicast = unicast->Next)
+      {
+        if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||
+            unicast->Address.lpSockaddr->sa_family == AF_INET6) &&
+            (unicast->DadState == IpDadStateDeprecated ||
+            unicast->DadState == IpDadStatePreferred))
+          count += 1;
+      }
+    }
+  }
+
+  if (count == 0)
+  {
+    *results = NULL;
+    *results_count = 0;
+    GNUNET_free (pAddresses);
+    GNUNET_free_non_null (interfaces4);
+    GNUNET_free_non_null (interfaces6);
+    return GNUNET_OK;
+  }
+
+  *results = (struct EnumNICs3_results *) GNUNET_malloc (
+      sizeof (struct EnumNICs3_results) * count);
+  *results_count = count;
+
+  count = 0;
+  for (pCurrentAddress = pAddresses;
+      pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
+  {
+    struct EnumNICs3_results *r;
+    IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
+    if (pCurrentAddress->OperStatus != IfOperStatusUp)
+      continue;
+    for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
+        unicast = unicast->Next)
+    {
+      int i, j;
+      int mask_length = -1;
+      char dst[INET6_ADDRSTRLEN + 1];
+
+      if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&
+          unicast->Address.lpSockaddr->sa_family != AF_INET6) ||
+          (unicast->DadState != IpDadStateDeprecated &&
+          unicast->DadState != IpDadStatePreferred))
+        continue;
+
+      r = &(*results)[count];
+      r->flags = 0;
+      if (pCurrentAddress->IfIndex > 0 &&
+          pCurrentAddress->IfIndex == best_interface &&
+          unicast->Address.lpSockaddr->sa_family == AF_INET)
+        r->is_default = 1;
+      else if (pCurrentAddress->Ipv6IfIndex > 0 &&
+          pCurrentAddress->Ipv6IfIndex == best_interface6 &&
+          unicast->Address.lpSockaddr->sa_family == AF_INET6)
+        r->is_default = 1;
+      else
+        r->is_default = 0;
+
+      /* Don't choose default interface twice */
+      if (r->is_default)
+        best_interface = best_interface6 = 0;
+
+      if (!use_enum2)
+      {
+        GNUNET_memcpy (&r->address, unicast->Address.lpSockaddr,
+            unicast->Address.iSockaddrLength);
+        memset (&r->mask, 0, sizeof (struct sockaddr));
+        mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->
+              OnLinkPrefixLength;
+        /* OnLinkPrefixLength is the number of leading 1s in the mask.
+         * OnLinkPrefixLength is available on Vista and later (hence use_enum2).
+         */
+        if (unicast->Address.lpSockaddr->sa_family == AF_INET)
+        {
+          struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
+          for (i = 0; i < mask_length; i++)
+              ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
+        }
+        else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
+        {
+          struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;
+          struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;
+          for (i = 0; i < mask_length; i++)
+            ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
+          GNUNET_memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
+          for (i = mask_length; i < 128; i++)
+            ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
+        }
+        r->flags |= ENUMNICS3_MASK_OK;
+      }
+      else
+      {
+        int found = 0;
+        if (unicast->Address.lpSockaddr->sa_family == AF_INET)
+        {
+          for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)
+          {
+            struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
+            GNUNET_memcpy (&interfaces4[i].iiAddress.Address,
+                unicast->Address.lpSockaddr,
+                unicast->Address.iSockaddrLength);
+            found = 1;
+            GNUNET_memcpy (&r->address, &interfaces4[i].iiAddress.Address,
+                sizeof (struct sockaddr_in));
+            GNUNET_memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,
+                sizeof (struct sockaddr_in));
+            for (mask_length = 0;
+                ((unsigned char *) &m->sin_addr)[mask_length / 8] &
+                0x80 >> (mask_length % 8); mask_length++)
+            {
+            }
+            r->flags |= ENUMNICS3_MASK_OK;
+          }
+        }
+        else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
+        {
+          for (i = 0;
+              interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
+              i++)
+          {
+            GNUNET_memcpy (interfaces6->Address[i].lpSockaddr,
+                unicast->Address.lpSockaddr,
+                unicast->Address.iSockaddrLength);
+            found = 1;
+            GNUNET_memcpy (&r->address, interfaces6->Address[i].lpSockaddr,
+                sizeof (struct sockaddr_in6));
+            /* TODO: Find a way to reliably get network mask for IPv6 on XP */
+            memset (&r->mask, 0, sizeof (struct sockaddr));
+            r->flags &= ~ENUMNICS3_MASK_OK;
+          }
+        }
+        if (!found)
+        {
+          DebugBreak ();
+        }
+      }
+      if (unicast->Address.lpSockaddr->sa_family == AF_INET)
+      {
+        struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
+        struct sockaddr_in *a = (struct sockaddr_in *) &r->address;
+        /* copy address to broadcast, then flip all the trailing bits not
+         * falling under netmask to 1,
+         * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.
+         */
+        GNUNET_memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
+        for (i = mask_length; i < 32; i++)
+          ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
+        r->flags |= ENUMNICS3_BCAST_OK;
+        r->addr_size = sizeof (struct sockaddr_in);
+        inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);
+      }
+      else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
+      {
+        struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;
+        /* for IPv6 broadcast is not defined, zero it down */
+        memset (&r->broadcast, 0, sizeof (struct sockaddr));
+        r->flags &= ~ENUMNICS3_BCAST_OK;
+        r->addr_size = sizeof (struct sockaddr_in6);
+        inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);
+      }
+
+      i = 0;
+      i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
+          "%S (%s", pCurrentAddress->FriendlyName, dst);
+      for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)
+        i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
+            "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);
+      i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");
+      r->pretty_name[1000] = '\0';
+      count += 1;
+    }
+  }
+
+  if (use_enum2)
+  {
+    GNUNET_free_non_null (interfaces4);
+    GNUNET_free_non_null (interfaces6);
+  }
+
+  GNUNET_free (pAddresses);
+  return GNUNET_OK;
+}
+
+void
+EnumNICs3_free (struct EnumNICs3_results *r)
+{
+  GNUNET_free_non_null (r);
+}
+
+
+/**
+ * Lists all network interfaces in a combo box
+ * Used by the basic GTK configurator
+ *
+ * @param callback function to call for each NIC
+ * @param callback_cls closure for callback
+ */
+int
+ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)
+{
+  int r;
+  int i;
+  struct EnumNICs3_results *results = NULL;
+  int results_count;
+
+  r = EnumNICs3 (&results, &results_count);
+  if (r != GNUNET_OK)
+    return GNUNET_NO;
+
+  for (i = 0; i < results_count; i++)
+    callback (callback_cls, results[i].pretty_name, results[i].is_default);
+  GNUNET_free_non_null (results);
+  return GNUNET_YES;
+}
+
+/**
+ * @brief Installs the Windows service
+ * @param servicename name of the service as diplayed by the SCM
+ * @param application path to the application binary
+ * @param username the name of the service's user account
+ * @returns 0 on success
+ *          1 if the Windows version doesn't support services
+ *          2 if the SCM could not be opened
+ *          3 if the service could not be created
+ */
+int InstallAsService(char *servicename, char *application, char *username)
+{
+  SC_HANDLE hManager, hService;
+  char szEXE[_MAX_PATH + 17] = "\"";
+  char *user = NULL;
+
+  if (! GNOpenSCManager)
+    return 1;
+
+  plibc_conv_to_win_path(application, szEXE + 1);
+  strcat(szEXE, "\" --win-service");
+  hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
+  if (! hManager)
+    return 2;
+
+  if (username)
+  {
+       user = (char *) malloc(strlen(username) + 3);
+       sprintf(user, ".\\%s", username);
+  }
+
+  hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
+    SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
+    NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
+
+  if (user)
+    free(user);
+
+  if (! hService)
+    return 3;
+
+  GNCloseServiceHandle(hService);
+
+  return 0;
+}
+
+
+/**
+ * @brief Uninstall Windows service
+ * @param servicename name of the service to delete
+ * @returns 0 on success
+ *          1 if the Windows version doesn't support services
+ *          2 if the SCM could not be openend
+ *          3 if the service cannot be accessed
+ *          4 if the service cannot be deleted
+ */
+int
+UninstallService(char *servicename)
+{
+  SC_HANDLE hManager, hService;
+
+  if (! GNOpenSCManager)
+    return 1;
+
+  hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+  if (! hManager)
+    return 2;
+
+  if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
+  {
+    if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
+      return 3;
+    else
+      goto closeSCM;
+  }
+
+  if (! GNDeleteService(hService))
+    if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
+      return 4;
+
+closeSCM:
+  GNCloseServiceHandle(hService);
+
+  return 0;
+}
+
+/**
+ * @author Scott Field, Microsoft
+ * @see http://support.microsoft.com/?scid=kb;en-us;132958
+ * @date 12-Jul-95
+ */
+void
+_InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
+{
+  DWORD StringLength;
+
+  if(String == NULL)
+  {
+    LsaString->Buffer = NULL;
+    LsaString->Length = 0;
+    LsaString->MaximumLength = 0;
+    return;
+  }
+
+  StringLength = wcslen(String);
+  LsaString->Buffer = String;
+  LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
+  LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
+}
+
+
+/**
+ * @author Scott Field, Microsoft
+ * @see http://support.microsoft.com/?scid=kb;en-us;132958
+ * @date 12-Jul-95
+ */
+NTSTATUS
+_OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
+{
+  LSA_OBJECT_ATTRIBUTES ObjectAttributes;
+  LSA_UNICODE_STRING ServerString;
+  PLSA_UNICODE_STRING Server = NULL;
+
+  /* Always initialize the object attributes to all zeroes. */
+  ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
+
+  if(ServerName != NULL)
+  {
+    /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
+    _InitLsaString(&ServerString, ServerName);
+    Server = &ServerString;
+  }
+
+  /* Attempt to open the policy. */
+  return GNLsaOpenPolicy(Server,
+                       &ObjectAttributes, DesiredAccess, PolicyHandle);
+}
+
+/**
+ * @brief Obtain a SID representing the supplied account on the supplied system
+ * @return TRUE on success, FALSE on failure
+ * @author Scott Field, Microsoft
+ * @date 12-Jul-95
+ * @remarks A buffer is allocated which contains the SID representing the
+ *          supplied account. This buffer should be freed when it is no longer
+ *          needed by calling\n
+ *            HeapFree(GetProcessHeap(), 0, buffer)
+ * @remarks Call GetLastError() to obtain extended error information.
+ * @see http://support.microsoft.com/?scid=kb;en-us;132958
+ */
+BOOL
+_GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)
+{
+  LPTSTR ReferencedDomain = NULL;
+  DWORD cbSid = 128;                                                   /* initial allocation attempt */
+  DWORD cchReferencedDomain = 16;      /* initial allocation size */
+  SID_NAME_USE peUse;
+  BOOL bSuccess = FALSE;                                       /* assume this function will fail */
+
+  /* initial memory allocations */
+  if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
+       return FALSE;
+
+  if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
+                                   0,
+                                   cchReferencedDomain *
+                                   sizeof (TCHAR))) == NULL)
+       return FALSE;
+
+    /* Obtain the SID of the specified account on the specified system. */
+       while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
+                  AccountName,                                                                                         /* account to lookup */
+                  *Sid,                                                                                                                        /* SID of interest */
+                  &cbSid,                                                                                                              /* size of SID */
+                  ReferencedDomain,                                                                    /* domain account was found on */
+                  &cchReferencedDomain, &peUse))
+       {
+               if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+               {
+                       /* reallocate memory */
+                       if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
+                               return FALSE;
+
+                       if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
+                                             0,
+                                             ReferencedDomain,
+                                             cchReferencedDomain
+                                             * sizeof (TCHAR))) == NULL)
+                               return FALSE;
+      }
+      else
+        goto end;
+  }
+
+  /* Indicate success. */
+  bSuccess = TRUE;
+
+end:
+  /* Cleanup and indicate failure, if appropriate. */
+  HeapFree (GetProcessHeap (), 0, ReferencedDomain);
+
+  if (!bSuccess)
+  {
+    if (*Sid != NULL)
+    {
+               HeapFree (GetProcessHeap (), 0, *Sid);
+               *Sid = NULL;
+    }
+  }
+
+  return bSuccess;
+}
+
+/**
+ * @author Scott Field, Microsoft
+ * @see http://support.microsoft.com/?scid=kb;en-us;132958
+ * @date 12-Jul-95
+ */
+NTSTATUS
+_SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
+                       PSID AccountSid,                        /* SID to grant privilege to */
+                       LPWSTR PrivilegeName,   /* privilege to grant (Unicode) */
+                       BOOL bEnable                                            /* enable or disable */
+  )
+{
+  LSA_UNICODE_STRING PrivilegeString;
+
+  /* Create a LSA_UNICODE_STRING for the privilege name. */
+  _InitLsaString(&PrivilegeString, PrivilegeName);
+
+  /* grant or revoke the privilege, accordingly */
+  if(bEnable)
+  {
+    NTSTATUS i;
+
+    i = GNLsaAddAccountRights(PolicyHandle,                            /* open policy handle */
+                               AccountSid,                             /* target SID */
+                               &PrivilegeString,        /* privileges */
+                               1                                                                                       /* privilege count */
+      );
+    return i;
+  }
+  else
+  {
+    return GNLsaRemoveAccountRights(PolicyHandle,                      /* open policy handle */
+                                  AccountSid,                          /* target SID */
+                                  FALSE,                                                       /* do not disable all rights */
+                                  &PrivilegeString,            /* privileges */
+                                  1                                                                            /* privilege count */
+      );
+  }
+}
+
+/**
+ * @brief Create a Windows service account
+ * @return 0 on success, > 0 otherwise
+ * @param pszName the name of the account
+ * @param pszDesc description of the account
+ */
+int
+CreateServiceAccount(const char *pszName,
+                     const char *pszDesc)
+{
+  USER_INFO_1 ui;
+  USER_INFO_1008 ui2;
+  NET_API_STATUS nStatus;
+  wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
+  LSA_HANDLE hPolicy;
+  PSID pSID;
+
+  if (! GNNetUserAdd)
+       return 1;
+  mbstowcs(wszName, pszName, strlen(pszName) + 1);
+  mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
+
+  memset(&ui, 0, sizeof(ui));
+  ui.usri1_name = wszName;
+  ui.usri1_password = wszName; /* account is locked anyway */
+  ui.usri1_priv = USER_PRIV_USER;
+  ui.usri1_comment = wszDesc;
+  ui.usri1_flags = UF_SCRIPT;
+
+  nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
+
+  if (nStatus != NERR_Success && nStatus != NERR_UserExists)
+       return 2;
+
+  ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
+  GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
+
+  if (!NT_SUCCESS(_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy)))
+       return 3;
+
+  _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);
+
+  if (!NT_SUCCESS(_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE)))
+       return 4;
+
+  _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);
+  _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);
+  _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);
+
+  GNLsaClose(hPolicy);
+
+  return 0;
+}
+
+/**
+ * @brief Grant permission to a file
+ * @param lpszFileName the name of the file or directory
+ * @param lpszAccountName the user account
+ * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
+ * @return TRUE on success
+ * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
+ */
+BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
+      DWORD dwAccessMask)
+{
+  /* SID variables. */
+  SID_NAME_USE   snuType;
+  TCHAR *        szDomain       = NULL;
+  DWORD          cbDomain       = 0;
+  LPVOID         pUserSID       = NULL;
+  DWORD          cbUserSID      = 0;
+
+  /* File SD variables. */
+  PSECURITY_DESCRIPTOR pFileSD  = NULL;
+  DWORD          cbFileSD       = 0;
+
+  /* New SD variables. */
+  SECURITY_DESCRIPTOR  newSD;
+
+  /* ACL variables. */
+  PACL           pACL           = NULL;
+  BOOL           fDaclPresent;
+  BOOL           fDaclDefaulted;
+  ACL_SIZE_INFORMATION AclInfo;
+
+  /* New ACL variables. */
+  PACL           pNewACL        = NULL;
+  DWORD          cbNewACL       = 0;
+
+  /* Temporary ACE. */
+  LPVOID         pTempAce       = NULL;
+  UINT           CurrentAceIndex = 0;
+
+  UINT           newAceIndex = 0;
+
+  /* Assume function will fail. */
+  BOOL           fResult        = FALSE;
+  BOOL           fAPISuccess;
+
+  SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
+
+  /**
+   * STEP 1: Get SID of the account name specified.
+   */
+  fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
+        pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
+
+  /* API should have failed with insufficient buffer. */
+  if (fAPISuccess)
+     goto end;
+  else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+     goto end;
+  }
+
+  pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
+  if (!pUserSID) {
+     goto end;
+  }
+
+  szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
+  if (!szDomain) {
+     goto end;
+  }
+
+  fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
+        pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
+  if (!fAPISuccess) {
+     goto end;
+  }
+
+  /**
+   *  STEP 2: Get security descriptor (SD) of the file specified.
+   */
+  fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
+        secInfo, pFileSD, 0, &cbFileSD);
+
+  /* API should have failed with insufficient buffer. */
+  if (fAPISuccess)
+     goto end;
+  else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+     goto end;
+  }
+
+  pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+       cbFileSD);
+  if (!pFileSD) {
+     goto end;
+  }
+
+  fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
+        secInfo, pFileSD, cbFileSD, &cbFileSD);
+  if (!fAPISuccess) {
+     goto end;
+  }
+
+  /**
+   * STEP 3: Initialize new SD.
+   */
+  if (!GNInitializeSecurityDescriptor(&newSD,
+        SECURITY_DESCRIPTOR_REVISION)) {
+     goto end;
+  }
+
+  /**
+   * STEP 4: Get DACL from the old SD.
+   */
+  if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
+        &fDaclDefaulted)) {
+     goto end;
+  }
+
+  /**
+   * STEP 5: Get size information for DACL.
+   */
+  AclInfo.AceCount = 0; // Assume NULL DACL.
+  AclInfo.AclBytesFree = 0;
+  AclInfo.AclBytesInUse = sizeof(ACL);
+
+  if (pACL == NULL)
+     fDaclPresent = FALSE;
+
+  /* If not NULL DACL, gather size information from DACL. */
+  if (fDaclPresent) {
+
+     if (!GNGetAclInformation(pACL, &AclInfo,
+           sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
+        goto end;
+     }
+  }
+
+  /**
+   * STEP 6: Compute size needed for the new ACL.
+   */
+  cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
+        + GetLengthSid(pUserSID) - sizeof(DWORD);
+
+  /**
+   * STEP 7: Allocate memory for new ACL.
+   */
+  pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
+  if (!pNewACL) {
+     goto end;
+  }
+
+  /**
+   * STEP 8: Initialize the new ACL.
+   */
+  if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
+     goto end;
+  }
+
+  /**
+   * STEP 9 If DACL is present, copy all the ACEs from the old DACL
+   * to the new DACL.
+   *
+   * The following code assumes that the old DACL is
+   * already in Windows 2000 preferred order.  To conform
+   * to the new Windows 2000 preferred order, first we will
+   * copy all non-inherited ACEs from the old DACL to the
+   * new DACL, irrespective of the ACE type.
+   */
+
+  newAceIndex = 0;
+
+  if (fDaclPresent && AclInfo.AceCount) {
+
+     for (CurrentAceIndex = 0;
+           CurrentAceIndex < AclInfo.AceCount;
+           CurrentAceIndex++) {
+
+        /**
+         * TEP 10: Get an ACE.
+         */
+        if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
+           goto end;
+        }
+
+        /**
+         * STEP 11: Check if it is a non-inherited ACE.
+         * If it is an inherited ACE, break from the loop so
+         * that the new access allowed non-inherited ACE can
+         * be added in the correct position, immediately after
+         * all non-inherited ACEs.
+         */
+        if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
+           & INHERITED_ACE)
+           break;
+
+        /**
+         * STEP 12: Skip adding the ACE, if the SID matches
+         * with the account specified, as we are going to
+         * add an access allowed ACE with a different access
+         * mask.
+         */
+        if (GNEqualSid(pUserSID,
+           &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
+           continue;
+
+        /**
+         * STEP 13: Add the ACE to the new ACL.
+         */
+        if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
+              ((PACE_HEADER) pTempAce)->AceSize)) {
+           goto end;
+        }
+
+        newAceIndex++;
+     }
+  }
+
+  /**
+   * STEP 14: Add the access-allowed ACE to the new DACL.
+   * The new ACE added here will be in the correct position,
+   * immediately after all existing non-inherited ACEs.
+   */
+  if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
+        pUserSID)) {
+     goto end;
+  }
+
+  /**
+   * STEP 14.5: Make new ACE inheritable
+   */
+  if (!GetAce(pNewACL, newAceIndex, &pTempAce))
+    goto end;
+  ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
+    (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
+
+  /**
+   * STEP 15: To conform to the new Windows 2000 preferred order,
+   * we will now copy the rest of inherited ACEs from the
+   * old DACL to the new DACL.
+   */
+  if (fDaclPresent && AclInfo.AceCount) {
+
+     for (;
+          CurrentAceIndex < AclInfo.AceCount;
+          CurrentAceIndex++) {
+
+        /**
+         * STEP 16: Get an ACE.
+         */
+        if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
+           goto end;
+        }
+
+        /**
+         * STEP 17: Add the ACE to the new ACL.
+         */
+        if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
+              ((PACE_HEADER) pTempAce)->AceSize)) {
+           goto end;
+        }
+     }
+  }
+
+  /**
+   * STEP 18: Set permissions
+   */
+  if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
+    DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
+       goto end;
+  }
+
+  fResult = TRUE;
+
+end:
+
+  /**
+   * STEP 19: Free allocated memory
+   */
+  if (pUserSID)
+     HeapFree(GetProcessHeap(), 0, pUserSID);
+
+  if (szDomain)
+     HeapFree(GetProcessHeap(), 0, szDomain);
+
+  if (pFileSD)
+     HeapFree(GetProcessHeap(), 0, pFileSD);
+
+  if (pNewACL)
+     HeapFree(GetProcessHeap(), 0, pNewACL);
+
+  return fResult;
+}
+
+char *winErrorStr(const char *prefix, int dwErr)
+{
+  char *err, *ret;
+  int mem;
+
+  if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+    NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
+    0, NULL ))
+  {
+    err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);
+  }
+
+  mem = strlen(err) + strlen(prefix) + 20;
+  ret = (char *) malloc(mem);
+
+  snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
+
+  LocalFree(err);
+
+  return ret;
+}
+
 /**
  * Terminate a process by creating a remote thread within it,
  * which proceeds to call ExitProcess() inside that process.
@@ -1269,61 +1284,61 @@ char *winErrorStr(const char *prefix, int dwErr)
  * @param dwTimeout number of ms to wait for the process to terminate
  * @return TRUE on success, FALSE on failure (check last error for the code)
  */
-BOOL\r
-SafeTerminateProcess (HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)\r
-{\r
-  DWORD dwTID, dwCode, dwErr = 0;\r
-  HANDLE hProcessDup = INVALID_HANDLE_VALUE;\r
-  HANDLE hRT = NULL;\r
-  HINSTANCE hKernel = GetModuleHandle ("Kernel32");\r
-  BOOL bSuccess = FALSE;\r
-\r
-  BOOL bDup = DuplicateHandle (GetCurrentProcess (), hProcess,\r
-      GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS,\r
-      FALSE, 0);\r
-\r
-  /* Detect the special case where the process is\r
-   * already dead...\r
-   */\r
-  if (GetExitCodeProcess (bDup ? hProcessDup : hProcess, &dwCode) &&\r
-      (STILL_ACTIVE ==  dwCode))\r
-  {\r
-    FARPROC pfnExitProc;\r
-\r
-    pfnExitProc = GetProcAddress (hKernel, "ExitProcess");\r
-\r
-    hRT = CreateRemoteThread ((bDup) ? hProcessDup : hProcess, NULL, 0,\r
-        (LPTHREAD_START_ROUTINE) pfnExitProc, (PVOID) uExitCode, 0, &dwTID);\r
-\r
-    dwErr = GetLastError ();\r
-  }\r
-  else\r
-  {\r
-    dwErr = ERROR_PROCESS_ABORTED;\r
-  }\r
-\r
-  if (hRT)\r
-  {\r
-    /* Must wait process to terminate to\r
-     * guarantee that it has exited...\r
-     */\r
-    DWORD dwWaitResult = WaitForSingleObject ((bDup) ? hProcessDup : hProcess,\r
-        dwTimeout);\r
-    if (dwWaitResult == WAIT_TIMEOUT)\r
-      dwErr = WAIT_TIMEOUT;\r
-    else\r
-      dwErr = GetLastError ();\r
-\r
-    CloseHandle (hRT);\r
-    bSuccess = dwErr == NO_ERROR;\r
-  }\r
-\r
-  if (bDup)\r
-    CloseHandle (hProcessDup);\r
-\r
-  SetLastError (dwErr);\r
-\r
-  return bSuccess;\r
+BOOL
+SafeTerminateProcess (HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)
+{
+  DWORD dwTID, dwCode, dwErr = 0;
+  HANDLE hProcessDup = INVALID_HANDLE_VALUE;
+  HANDLE hRT = NULL;
+  HINSTANCE hKernel = GetModuleHandle ("Kernel32");
+  BOOL bSuccess = FALSE;
+
+  BOOL bDup = DuplicateHandle (GetCurrentProcess (), hProcess,
+      GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS,
+      FALSE, 0);
+
+  /* Detect the special case where the process is
+   * already dead...
+   */
+  if (GetExitCodeProcess (bDup ? hProcessDup : hProcess, &dwCode) &&
+      (STILL_ACTIVE ==  dwCode))
+  {
+    FARPROC pfnExitProc;
+
+    pfnExitProc = GetProcAddress (hKernel, "ExitProcess");
+
+    hRT = CreateRemoteThread ((bDup) ? hProcessDup : hProcess, NULL, 0,
+        (LPTHREAD_START_ROUTINE) pfnExitProc, (PVOID) uExitCode, 0, &dwTID);
+
+    dwErr = GetLastError ();
+  }
+  else
+  {
+    dwErr = ERROR_PROCESS_ABORTED;
+  }
+
+  if (hRT)
+  {
+    /* Must wait process to terminate to
+     * guarantee that it has exited...
+     */
+    DWORD dwWaitResult = WaitForSingleObject ((bDup) ? hProcessDup : hProcess,
+        dwTimeout);
+    if (dwWaitResult == WAIT_TIMEOUT)
+      dwErr = WAIT_TIMEOUT;
+    else
+      dwErr = GetLastError ();
+
+    CloseHandle (hRT);
+    bSuccess = dwErr == NO_ERROR;
+  }
+
+  if (bDup)
+    CloseHandle (hProcessDup);
+
+  SetLastError (dwErr);
+
+  return bSuccess;
 }
-\r
-#endif\r
+
+#endif