-fix time assertion introduce in last patch
[oweals/gnunet.git] / src / util / win.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file util/win.c
23  * @brief Helper functions for MS Windows in C++
24  * @author Nils Durner
25  */
26
27 #ifndef _WIN_C
28 #define _WIN_C
29
30 #include "winproc.h"
31 #include "platform.h"
32 #include "gnunet_crypto_lib.h"
33 #include "gnunet_common.h"
34 #include "gnunet_connection_lib.h"
35
36 #include <ntdef.h>
37 #ifndef INHERITED_ACE
38 #define INHERITED_ACE 0x10
39 #endif
40
41 int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);
42
43 #define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \
44   union { \
45     struct { \
46       ULONG Length; \
47       DWORD Flags; \
48     }; \
49   };
50
51 #define _IP_ADAPTER_UNICAST_ADDRESS_BASE \
52   SOCKET_ADDRESS                     Address; \
53   IP_PREFIX_ORIGIN                   PrefixOrigin; \
54   IP_SUFFIX_ORIGIN                   SuffixOrigin; \
55   IP_DAD_STATE                       DadState; \
56   ULONG                              ValidLifetime; \
57   ULONG                              PreferredLifetime; \
58   ULONG                              LeaseLifetime;
59
60 #define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \
61   UINT8                              OnLinkPrefixLength;
62
63
64 #define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix,addition) \
65 typedef struct _IP_ADAPTER_UNICAST_ADDRESS##suffix { \
66   _IP_ADAPTER_UNICAST_ADDRESS_HEAD \
67   struct _IP_ADAPTER_UNICAST_ADDRESS##suffix *Next; \
68   _IP_ADAPTER_UNICAST_ADDRESS_BASE \
69   addition \
70 } IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix;
71
72 /* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */
73 _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA)
74
75
76 #ifndef __MINGW64_VERSION_MAJOR
77 typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS {
78   union {
79     ULONGLONG Alignment;
80     struct {
81       ULONG Length;
82       DWORD Reserved;
83     };
84   };
85   struct _IP_ADAPTER_WINS_SERVER_ADDRESS  *Next;
86   SOCKET_ADDRESS                         Address;
87 } IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH;
88
89 typedef struct _IP_ADAPTER_GATEWAY_ADDRESS {
90   union {
91     ULONGLONG Alignment;
92     struct {
93       ULONG Length;
94       DWORD Reserved;
95     };
96   };
97   struct _IP_ADAPTER_GATEWAY_ADDRESS  *Next;
98   SOCKET_ADDRESS                     Address;
99 } IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH;
100 #endif
101
102 typedef UINT32 NET_IF_COMPARTMENT_ID;
103 typedef GUID NET_IF_NETWORK_GUID;
104
105 #ifndef __MINGW64_VERSION_MAJOR
106 typedef enum _NET_IF_CONNECTION_TYPE {
107   NET_IF_CONNECTION_DEDICATED   = 1,
108   NET_IF_CONNECTION_PASSIVE,
109   NET_IF_CONNECTION_DEMAND,
110   NET_IF_CONNECTION_MAXIMUM
111 } NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE;
112
113 typedef enum  {
114   TUNNEL_TYPE_NONE      = 0,
115   TUNNEL_TYPE_OTHER,
116   TUNNEL_TYPE_DIRECT,
117   TUNNEL_TYPE_6TO4,
118   TUNNEL_TYPE_ISATAP,
119   TUNNEL_TYPE_TEREDO,
120   TUNNEL_TYPE_IPHTTPS
121 } TUNNEL_TYPE, *PTUNNEL_TYPE;
122 #endif
123
124 /*
125 A DUID consists of a two-octet type code represented in network byte
126    order, followed by a variable number of octets that make up the
127    actual identifier.  A DUID can be no more than 128 octets long (not
128    including the type code).
129 */
130 #define MAX_DHCPV6_DUID_LENGTH 130
131
132 #ifndef __MINGW64_VERSION_MAJOR
133 typedef union _NET_LUID {
134   ULONG64 Value;
135   struct {
136     ULONG64 Reserved  :24;
137     ULONG64 NetLuidIndex  :24;
138     ULONG64 IfType  :16;
139   } Info;
140 } NET_LUID, *PNET_LUID, IF_LUID;
141
142 #define MAX_DNS_SUFFIX_STRING_LENGTH 246
143
144 typedef struct _IP_ADAPTER_DNS_SUFFIX {
145   struct _IP_ADAPTER_DNS_SUFFIX  *Next;
146   WCHAR                         String[MAX_DNS_SUFFIX_STRING_LENGTH];
147 } IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX;
148 #endif
149
150
151
152 #define _IP_ADAPTER_ADDRESSES_HEAD \
153   union { \
154     ULONGLONG Alignment; \
155     struct { \
156       ULONG Length; \
157       DWORD IfIndex; \
158     }; \
159   };
160
161 #define _IP_ADAPTER_ADDRESSES_BASE \
162   PCHAR                              AdapterName; \
163   PIP_ADAPTER_UNICAST_ADDRESS        FirstUnicastAddress; \
164   PIP_ADAPTER_ANYCAST_ADDRESS        FirstAnycastAddress; \
165   PIP_ADAPTER_MULTICAST_ADDRESS      FirstMulticastAddress; \
166   PIP_ADAPTER_DNS_SERVER_ADDRESS     FirstDnsServerAddress; \
167   PWCHAR                             DnsSuffix; \
168   PWCHAR                             Description; \
169   PWCHAR                             FriendlyName; \
170   BYTE                               PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \
171   DWORD                              PhysicalAddressLength; \
172   DWORD                              Flags; \
173   DWORD                              Mtu; \
174   DWORD                              IfType; \
175   IF_OPER_STATUS                     OperStatus;
176
177 #define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \
178   DWORD                              Ipv6IfIndex; \
179   DWORD                              ZoneIndices[16]; \
180   PIP_ADAPTER_PREFIX                 FirstPrefix; \
181
182
183 #define _IP_ADAPTER_ADDRESSES_ADD_VISTA \
184   _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \
185   ULONG64                            TransmitLinkSpeed; \
186   ULONG64                            ReceiveLinkSpeed; \
187   PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \
188   PIP_ADAPTER_GATEWAY_ADDRESS_LH     FirstGatewayAddress; \
189   ULONG                              Ipv4Metric; \
190   ULONG                              Ipv6Metric; \
191   IF_LUID                            Luid; \
192   SOCKET_ADDRESS                     Dhcpv4Server; \
193   NET_IF_COMPARTMENT_ID              CompartmentId; \
194   NET_IF_NETWORK_GUID                NetworkGuid; \
195   NET_IF_CONNECTION_TYPE             ConnectionType; \
196   TUNNEL_TYPE                        TunnelType; \
197   SOCKET_ADDRESS                     Dhcpv6Server; \
198   BYTE                               Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \
199   ULONG                              Dhcpv6ClientDuidLength; \
200   ULONG                              Dhcpv6Iaid;
201
202 #define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \
203   _IP_ADAPTER_ADDRESSES_ADD_VISTA \
204   PIP_ADAPTER_DNS_SUFFIX             FirstDnsSuffix;
205
206 #define _IP_ADAPTER_ADDRESSES_DEFINE(suffix,addition) \
207 typedef struct _IP_ADAPTER_ADDRESSES##suffix { \
208   _IP_ADAPTER_ADDRESSES_HEAD \
209   struct _IP_ADAPTER_ADDRESSES##suffix *Next; \
210   _IP_ADAPTER_ADDRESSES_BASE \
211   addition \
212 } IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix;
213
214
215 /* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */
216 _IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1,_IP_ADAPTER_ADDRESSES_ADD_XPSP1)
217 _IP_ADAPTER_ADDRESSES_DEFINE(_VISTA,_IP_ADAPTER_ADDRESSES_ADD_VISTA)
218 _IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1,_IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1)
219
220 static int
221 EnumNICs_IPv6_get_ifs_count (SOCKET s)
222 {
223   DWORD dwret = 0, err;
224   int iret;
225   iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0,
226       &dwret, NULL, NULL);
227   err = GetLastError ();
228   if (iret == SOCKET_ERROR && err == WSAEFAULT)
229     return dwret;
230   else if (iret == 0)
231     return 0;
232   return GNUNET_SYSERR;
233 }
234
235 static int
236 EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size)
237 {
238   int iret;
239   DWORD dwret = 0;
240   iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size,
241       &dwret, NULL, NULL);
242
243   if (iret != 0 || dwret != size)
244   {
245     /* It's supposed to succeed! And size should be the same */
246     return GNUNET_SYSERR;
247   }
248   return GNUNET_OK;
249 }
250
251 #undef GNUNET_malloc
252 #define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \
253     HEAP_GENERATE_EXCEPTIONS, a)
254
255 #undef GNUNET_free
256 #define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a)
257
258 #undef GNUNET_free_non_null
259 #define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0)
260
261 static int
262 EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size)
263 {
264   int iret;
265   DWORD dwret = 0;
266   DWORD error;
267   INTERFACE_INFO *ii = NULL;
268   DWORD ii_size = sizeof (INTERFACE_INFO) * 15;
269   while (TRUE)
270   {
271     if (ii_size >= sizeof (INTERFACE_INFO) * 1000)
272       return GNUNET_SYSERR;
273     ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size);
274     dwret = 0;
275     iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size,
276         &dwret, NULL, NULL);
277     error = GetLastError ();
278     if (iret == SOCKET_ERROR)
279     {
280       if (error == WSAEFAULT)
281       {
282         GNUNET_free (ii);
283         ii_size *= 2;
284         continue;
285       }
286       GNUNET_free (ii);
287       return GNUNET_SYSERR;
288     }
289     else
290     {
291       *inf = ii;
292       *size = dwret;
293       return GNUNET_OK;
294     }
295   }
296   return GNUNET_SYSERR;
297 }
298
299 int
300 EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6)
301 {
302   int result = 0;
303   SOCKET s4 = INVALID_SOCKET, s6 = INVALID_SOCKET;
304   DWORD dwret1 = 0, dwret2;
305   DWORD err1, err2;
306   int ifs4len = 0, ifs6len = 0;
307   INTERFACE_INFO *interfaces4 = NULL;
308   SOCKET_ADDRESS_LIST *interfaces6 = NULL;
309   SetLastError (0);
310   s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
311   err1 = GetLastError ();
312   SetLastError (0);
313   s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
314   err2 = GetLastError ();
315   if (s6 != INVALID_SOCKET)
316   {
317     ifs6len = EnumNICs_IPv6_get_ifs_count (s6);
318     if (ifs6len > 0)
319     {
320       interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);
321       result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;
322     }
323     closesocket (s6);
324     s6 = INVALID_SOCKET;
325   }
326
327   if (s4 != INVALID_SOCKET)
328   {
329     result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;
330     closesocket (s4);
331     s4 = INVALID_SOCKET;
332   }
333   if (ifs6len + ifs4len == 0)
334     goto error;
335
336   if (!result)
337   {
338     *ifs4 = interfaces4;
339     *ifs4_len = ifs4len;
340     *ifs6 = interfaces6;
341     return GNUNET_OK;
342   }
343 error:
344   if (interfaces4 != NULL)
345     GNUNET_free (interfaces4);
346   if (interfaces6 != NULL)
347     GNUNET_free (interfaces6);
348   if (s4 != INVALID_SOCKET)
349     closesocket (s4);
350   if (s6 != INVALID_SOCKET)
351     closesocket (s6);
352   return GNUNET_SYSERR;
353 }
354
355 /**
356  * Returns GNUNET_OK on OK, GNUNET_SYSERR on error
357  */
358 int
359 EnumNICs3 (struct EnumNICs3_results **results, int *results_count)
360 {
361   DWORD dwRetVal = 0;
362   int count = 0;
363   ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |
364       GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
365   struct sockaddr_in6 examplecom6;
366   IPAddr examplecom;
367   DWORD best_interface = 0;
368   DWORD best_interface6 = 0;
369
370   int use_enum2 = 0;
371   INTERFACE_INFO *interfaces4 = NULL;
372   int interfaces4_len = 0;
373   SOCKET_ADDRESS_LIST *interfaces6 = NULL;
374
375   unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
376   IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;
377   IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
378
379   if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)
380       == ERROR_BUFFER_OVERFLOW)
381   {
382     GNUNET_free (pAddresses);
383     pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
384   }
385
386   dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);
387
388   if (dwRetVal != NO_ERROR)
389   {
390     GNUNET_free (pAddresses);
391     return GNUNET_SYSERR;
392   }
393
394   if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))
395   {
396     use_enum2 = 1;
397
398     /* Enumerate NICs using WSAIoctl() */
399     if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))
400     {
401       GNUNET_free (pAddresses);
402       return GNUNET_SYSERR;
403     }
404   }
405
406   examplecom = inet_addr("192.0.34.166"); /* www.example.com */
407   if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)
408     best_interface = 0;
409
410   if (GNGetBestInterfaceEx != NULL)
411   {
412     examplecom6.sin6_family = AF_INET6;
413     examplecom6.sin6_port = 0;
414     examplecom6.sin6_flowinfo = 0;
415     examplecom6.sin6_scope_id = 0;
416     inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",
417         (struct sockaddr *) &examplecom6.sin6_addr);
418     dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,
419         &best_interface6);
420     if (dwRetVal != NO_ERROR)
421       best_interface6 = 0;
422   }
423
424   /* Give IPv6 a priority */
425   if (best_interface6 != 0)
426     best_interface = best_interface6;
427
428   count = 0;
429   for (pCurrentAddress = pAddresses;
430       pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
431   {
432     if (pCurrentAddress->OperStatus == IfOperStatusUp)
433     {
434       IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
435       for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
436           unicast = unicast->Next)
437       {
438         if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||
439             unicast->Address.lpSockaddr->sa_family == AF_INET6) &&
440             (unicast->DadState == IpDadStateDeprecated ||
441             unicast->DadState == IpDadStatePreferred))
442           count += 1;
443       }
444     }
445   }
446
447   if (count == 0)
448   {
449     *results = NULL;
450     *results_count = 0;
451     GNUNET_free (pAddresses);
452     GNUNET_free_non_null (interfaces4);
453     GNUNET_free_non_null (interfaces6);
454     return GNUNET_OK;
455   }
456
457   *results = (struct EnumNICs3_results *) GNUNET_malloc (
458       sizeof (struct EnumNICs3_results) * count);
459   *results_count = count;
460
461   count = 0;
462   for (pCurrentAddress = pAddresses;
463       pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
464   {
465     struct EnumNICs3_results *r;
466     IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
467     if (pCurrentAddress->OperStatus != IfOperStatusUp)
468       continue;
469     for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
470         unicast = unicast->Next)
471     {
472       int i, j;
473       int mask_length = -1;
474       char dst[INET6_ADDRSTRLEN + 1];
475
476       if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&
477           unicast->Address.lpSockaddr->sa_family != AF_INET6) ||
478           (unicast->DadState != IpDadStateDeprecated &&
479           unicast->DadState != IpDadStatePreferred))
480         continue;
481
482       r = &(*results)[count];
483       r->flags = 0;
484       if (pCurrentAddress->IfIndex > 0 &&
485           pCurrentAddress->IfIndex == best_interface &&
486           unicast->Address.lpSockaddr->sa_family == AF_INET)
487         r->is_default = 1;
488       else if (pCurrentAddress->Ipv6IfIndex > 0 &&
489           pCurrentAddress->Ipv6IfIndex == best_interface6 &&
490           unicast->Address.lpSockaddr->sa_family == AF_INET6)
491         r->is_default = 1;
492       else
493         r->is_default = 0;
494
495       /* Don't choose default interface twice */
496       if (r->is_default)
497         best_interface = best_interface6 = 0;
498
499       if (!use_enum2)
500       {
501         memcpy (&r->address, unicast->Address.lpSockaddr,
502             unicast->Address.iSockaddrLength);
503         memset (&r->mask, 0, sizeof (struct sockaddr));
504         mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->
505               OnLinkPrefixLength;
506         /* OnLinkPrefixLength is the number of leading 1s in the mask.
507          * OnLinkPrefixLength is available on Vista and later (hence use_enum2).
508          */
509         if (unicast->Address.lpSockaddr->sa_family == AF_INET)
510         {
511           struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
512           for (i = 0; i < mask_length; i++)
513               ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
514         }
515         else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
516         {
517           struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;
518           struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;
519           for (i = 0; i < mask_length; i++)
520             ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
521           memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
522           for (i = mask_length; i < 128; i++)
523             ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
524         }
525         r->flags |= ENUMNICS3_MASK_OK;
526       }
527       else
528       {
529         int found = 0;
530         if (unicast->Address.lpSockaddr->sa_family == AF_INET)
531         {
532           for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)
533           {
534             struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
535             if (memcpy (&interfaces4[i].iiAddress.Address,
536                 unicast->Address.lpSockaddr,
537                 unicast->Address.iSockaddrLength) != 0)
538               continue;
539             found = 1;
540             memcpy (&r->address, &interfaces4[i].iiAddress.Address,
541                 sizeof (struct sockaddr_in));
542             memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,
543                 sizeof (struct sockaddr_in));
544             for (mask_length = 0;
545                 ((unsigned char *) &m->sin_addr)[mask_length / 8] &
546                 0x80 >> (mask_length % 8); mask_length++)
547             {
548             }
549             r->flags |= ENUMNICS3_MASK_OK;
550           }
551         }
552         else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
553         {
554           for (i = 0;
555               interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
556               i++)
557           {
558             if (memcpy (interfaces6->Address[i].lpSockaddr,
559                 unicast->Address.lpSockaddr,
560                 unicast->Address.iSockaddrLength) != 0)
561               continue;
562             found = 1;
563             memcpy (&r->address, interfaces6->Address[i].lpSockaddr,
564                 sizeof (struct sockaddr_in6));
565             /* TODO: Find a way to reliably get network mask for IPv6 on XP */
566             memset (&r->mask, 0, sizeof (struct sockaddr));
567             r->flags &= ~ENUMNICS3_MASK_OK;
568           }
569         }
570         if (!found)
571         {
572           DebugBreak ();
573         }
574       }
575       if (unicast->Address.lpSockaddr->sa_family == AF_INET)
576       {
577         struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
578         struct sockaddr_in *a = (struct sockaddr_in *) &r->address;
579         /* copy address to broadcast, then flip all the trailing bits not
580          * falling under netmask to 1,
581          * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.
582          */
583         memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
584         for (i = mask_length; i < 32; i++)
585           ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
586         r->flags |= ENUMNICS3_BCAST_OK;
587         r->addr_size = sizeof (struct sockaddr_in);
588         inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);
589       }
590       else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
591       {
592         struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;
593         /* for IPv6 broadcast is not defined, zero it down */
594         memset (&r->broadcast, 0, sizeof (struct sockaddr));
595         r->flags &= ~ENUMNICS3_BCAST_OK;
596         r->addr_size = sizeof (struct sockaddr_in6);
597         inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);
598       }
599
600       i = 0;
601       i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
602           "%S (%s", pCurrentAddress->FriendlyName, dst);
603       for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)
604         i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
605             "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);
606       i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");
607       r->pretty_name[1000] = '\0';
608       count += 1;
609     }
610   }
611
612   if (use_enum2)
613   {
614     GNUNET_free_non_null (interfaces4);
615     GNUNET_free_non_null (interfaces6);
616   }
617
618   GNUNET_free (pAddresses);
619   return GNUNET_OK;
620 }
621
622 void
623 EnumNICs3_free (struct EnumNICs3_results *r)
624 {
625   GNUNET_free_non_null (r);
626 }
627
628
629 /**
630  * Lists all network interfaces in a combo box
631  * Used by the basic GTK configurator
632  *
633  * @param callback function to call for each NIC
634  * @param callback_cls closure for callback
635  */
636 int
637 ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)
638 {
639   int r;
640   int i;
641   struct EnumNICs3_results *results = NULL;
642   int results_count;
643
644   r = EnumNICs3 (&results, &results_count);
645   if (r != GNUNET_OK)
646     return GNUNET_NO;
647
648   for (i = 0; i < results_count; i++)
649     callback (callback_cls, results[i].pretty_name, results[i].is_default);
650   GNUNET_free_non_null (results);
651   return GNUNET_YES;
652 }
653
654 /**
655  * @brief Installs the Windows service
656  * @param servicename name of the service as diplayed by the SCM
657  * @param application path to the application binary
658  * @param username the name of the service's user account
659  * @returns 0 on success
660  *          1 if the Windows version doesn't support services
661  *          2 if the SCM could not be opened
662  *          3 if the service could not be created
663  */
664 int InstallAsService(char *servicename, char *application, char *username)
665 {
666   SC_HANDLE hManager, hService;
667   char szEXE[_MAX_PATH + 17] = "\"";
668   char *user = NULL;
669
670   if (! GNOpenSCManager)
671     return 1;
672
673   plibc_conv_to_win_path(application, szEXE + 1);
674   strcat(szEXE, "\" --win-service");
675   hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
676   if (! hManager)
677     return 2;
678
679   if (username)
680   {
681         user = (char *) malloc(strlen(username) + 3);
682         sprintf(user, ".\\%s", username);
683   }
684
685   hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
686     SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
687     NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
688
689   if (user)
690     free(user);
691
692   if (! hService)
693     return 3;
694
695   GNCloseServiceHandle(hService);
696
697   return 0;
698 }
699
700 /**
701  * @brief Uninstall Windows service
702  * @param servicename name of the service to delete
703  * @returns 0 on success
704  *          1 if the Windows version doesn't support services
705  *          2 if the SCM could not be openend
706  *          3 if the service cannot be accessed
707  *          4 if the service cannot be deleted
708  */
709 int UninstallService(char *servicename)
710 {
711   SC_HANDLE hManager, hService;
712
713   if (! GNOpenSCManager)
714     return 1;
715
716   hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
717   if (! hManager)
718     return 2;
719
720   if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
721   {
722     if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
723       return 3;
724     else
725       goto closeSCM;
726   }
727
728   if (! GNDeleteService(hService))
729     if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
730       return 4;
731
732 closeSCM:
733   GNCloseServiceHandle(hService);
734
735   return 0;
736 }
737
738 /**
739  * @author Scott Field, Microsoft
740  * @see http://support.microsoft.com/?scid=kb;en-us;132958
741  * @date 12-Jul-95
742  */
743 void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
744 {
745   DWORD StringLength;
746
747   if(String == NULL)
748   {
749     LsaString->Buffer = NULL;
750     LsaString->Length = 0;
751     LsaString->MaximumLength = 0;
752     return;
753   }
754
755   StringLength = wcslen(String);
756   LsaString->Buffer = String;
757   LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
758   LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
759 }
760
761
762 /**
763  * @author Scott Field, Microsoft
764  * @see http://support.microsoft.com/?scid=kb;en-us;132958
765  * @date 12-Jul-95
766  */
767 NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
768 {
769   LSA_OBJECT_ATTRIBUTES ObjectAttributes;
770   LSA_UNICODE_STRING ServerString;
771   PLSA_UNICODE_STRING Server = NULL;
772
773   /* Always initialize the object attributes to all zeroes. */
774   ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
775
776   if(ServerName != NULL)
777   {
778     /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
779     _InitLsaString(&ServerString, ServerName);
780     Server = &ServerString;
781   }
782
783   /* Attempt to open the policy. */
784   return GNLsaOpenPolicy(Server,
785                        &ObjectAttributes, DesiredAccess, PolicyHandle);
786 }
787
788 /**
789  * @brief Obtain a SID representing the supplied account on the supplied system
790  * @return TRUE on success, FALSE on failure
791  * @author Scott Field, Microsoft
792  * @date 12-Jul-95
793  * @remarks A buffer is allocated which contains the SID representing the
794  *          supplied account. This buffer should be freed when it is no longer
795  *          needed by calling\n
796  *            HeapFree(GetProcessHeap(), 0, buffer)
797  * @remarks Call GetLastError() to obtain extended error information.
798  * @see http://support.microsoft.com/?scid=kb;en-us;132958
799  */
800 BOOL _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)
801 {
802   LPTSTR ReferencedDomain = NULL;
803   DWORD cbSid = 128;                                                    /* initial allocation attempt */
804   DWORD cchReferencedDomain = 16;       /* initial allocation size */
805   SID_NAME_USE peUse;
806   BOOL bSuccess = FALSE;                                        /* assume this function will fail */
807
808   /* initial memory allocations */
809   if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
810         return FALSE;
811
812   if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
813                                     0,
814                                     cchReferencedDomain *
815                                     sizeof (TCHAR))) == NULL)
816         return FALSE;
817
818     /* Obtain the SID of the specified account on the specified system. */
819         while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
820                    AccountName,                                                                                         /* account to lookup */
821                    *Sid,                                                                                                                        /* SID of interest */
822                    &cbSid,                                                                                                              /* size of SID */
823                    ReferencedDomain,                                                                    /* domain account was found on */
824                    &cchReferencedDomain, &peUse))
825         {
826                 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
827                 {
828                         /* reallocate memory */
829                         if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
830                                 return FALSE;
831
832                         if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
833                                               0,
834                                               ReferencedDomain,
835                                               cchReferencedDomain
836                                               * sizeof (TCHAR))) == NULL)
837                                 return FALSE;
838       }
839       else
840         goto end;
841   }
842
843   /* Indicate success. */
844   bSuccess = TRUE;
845
846 end:
847   /* Cleanup and indicate failure, if appropriate. */
848   HeapFree (GetProcessHeap (), 0, ReferencedDomain);
849
850   if (!bSuccess)
851   {
852     if (*Sid != NULL)
853     {
854                 HeapFree (GetProcessHeap (), 0, *Sid);
855                 *Sid = NULL;
856     }
857   }
858
859   return bSuccess;
860 }
861
862 /**
863  * @author Scott Field, Microsoft
864  * @see http://support.microsoft.com/?scid=kb;en-us;132958
865  * @date 12-Jul-95
866  */
867 NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
868                                PSID AccountSid,                         /* SID to grant privilege to */
869                                LPWSTR PrivilegeName,    /* privilege to grant (Unicode) */
870                                BOOL bEnable                                             /* enable or disable */
871   )
872 {
873   LSA_UNICODE_STRING PrivilegeString;
874
875   /* Create a LSA_UNICODE_STRING for the privilege name. */
876   _InitLsaString(&PrivilegeString, PrivilegeName);
877
878   /* grant or revoke the privilege, accordingly */
879   if(bEnable)
880   {
881     NTSTATUS i;
882
883     i = GNLsaAddAccountRights(PolicyHandle,                             /* open policy handle */
884                                AccountSid,                              /* target SID */
885                                &PrivilegeString,        /* privileges */
886                                1                                                                                        /* privilege count */
887       );
888     return i;
889   }
890   else
891   {
892     return GNLsaRemoveAccountRights(PolicyHandle,                       /* open policy handle */
893                                   AccountSid,                           /* target SID */
894                                   FALSE,                                                        /* do not disable all rights */
895                                   &PrivilegeString,             /* privileges */
896                                   1                                                                             /* privilege count */
897       );
898   }
899 }
900
901 /**
902  * @brief Create a Windows service account
903  * @return 0 on success, > 0 otherwise
904  * @param pszName the name of the account
905  * @param pszDesc description of the account
906  */
907 int CreateServiceAccount(const char *pszName, const char *pszDesc)
908 {
909   USER_INFO_1 ui;
910   USER_INFO_1008 ui2;
911   NET_API_STATUS nStatus;
912   wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
913   DWORD dwErr;
914   LSA_HANDLE hPolicy;
915   PSID pSID;
916
917   if (! GNNetUserAdd)
918         return 1;
919   mbstowcs(wszName, pszName, strlen(pszName) + 1);
920   mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
921
922   memset(&ui, 0, sizeof(ui));
923   ui.usri1_name = wszName;
924   ui.usri1_password = wszName; /* account is locked anyway */
925   ui.usri1_priv = USER_PRIV_USER;
926   ui.usri1_comment = wszDesc;
927   ui.usri1_flags = UF_SCRIPT;
928
929   nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
930
931   if (nStatus != NERR_Success && nStatus != NERR_UserExists)
932         return 2;
933
934   ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
935   GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
936
937   if (!NT_SUCCESS(_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy)))
938         return 3;
939
940   _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);
941
942   if (!NT_SUCCESS(_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE)))
943         return 4;
944
945   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);
946   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);
947   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);
948
949   GNLsaClose(hPolicy);
950
951   return 0;
952 }
953
954 /**
955  * @brief Grant permission to a file
956  * @param lpszFileName the name of the file or directory
957  * @param lpszAccountName the user account
958  * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
959  * @return TRUE on success
960  * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
961  */
962 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
963       DWORD dwAccessMask)
964 {
965   /* SID variables. */
966   SID_NAME_USE   snuType;
967   TCHAR *        szDomain       = NULL;
968   DWORD          cbDomain       = 0;
969   LPVOID         pUserSID       = NULL;
970   DWORD          cbUserSID      = 0;
971
972   /* File SD variables. */
973   PSECURITY_DESCRIPTOR pFileSD  = NULL;
974   DWORD          cbFileSD       = 0;
975
976   /* New SD variables. */
977   SECURITY_DESCRIPTOR  newSD;
978
979   /* ACL variables. */
980   PACL           pACL           = NULL;
981   BOOL           fDaclPresent;
982   BOOL           fDaclDefaulted;
983   ACL_SIZE_INFORMATION AclInfo;
984
985   /* New ACL variables. */
986   PACL           pNewACL        = NULL;
987   DWORD          cbNewACL       = 0;
988
989   /* Temporary ACE. */
990   LPVOID         pTempAce       = NULL;
991   UINT           CurrentAceIndex = 0;
992
993   UINT           newAceIndex = 0;
994
995   /* Assume function will fail. */
996   BOOL           fResult        = FALSE;
997   BOOL           fAPISuccess;
998
999   SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
1000
1001   /**
1002    * STEP 1: Get SID of the account name specified.
1003    */
1004   fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1005         pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1006
1007   /* API should have failed with insufficient buffer. */
1008   if (fAPISuccess)
1009      goto end;
1010   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1011      goto end;
1012   }
1013
1014   pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
1015   if (!pUserSID) {
1016      goto end;
1017   }
1018
1019   szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
1020   if (!szDomain) {
1021      goto end;
1022   }
1023
1024   fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1025         pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1026   if (!fAPISuccess) {
1027      goto end;
1028   }
1029
1030   /**
1031    *  STEP 2: Get security descriptor (SD) of the file specified.
1032    */
1033   fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1034         secInfo, pFileSD, 0, &cbFileSD);
1035
1036   /* API should have failed with insufficient buffer. */
1037   if (fAPISuccess)
1038      goto end;
1039   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1040      goto end;
1041   }
1042
1043   pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1044         cbFileSD);
1045   if (!pFileSD) {
1046      goto end;
1047   }
1048
1049   fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1050         secInfo, pFileSD, cbFileSD, &cbFileSD);
1051   if (!fAPISuccess) {
1052      goto end;
1053   }
1054
1055   /**
1056    * STEP 3: Initialize new SD.
1057    */
1058   if (!GNInitializeSecurityDescriptor(&newSD,
1059         SECURITY_DESCRIPTOR_REVISION)) {
1060      goto end;
1061   }
1062
1063   /**
1064    * STEP 4: Get DACL from the old SD.
1065    */
1066   if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
1067         &fDaclDefaulted)) {
1068      goto end;
1069   }
1070
1071   /**
1072    * STEP 5: Get size information for DACL.
1073    */
1074   AclInfo.AceCount = 0; // Assume NULL DACL.
1075   AclInfo.AclBytesFree = 0;
1076   AclInfo.AclBytesInUse = sizeof(ACL);
1077
1078   if (pACL == NULL)
1079      fDaclPresent = FALSE;
1080
1081   /* If not NULL DACL, gather size information from DACL. */
1082   if (fDaclPresent) {
1083
1084      if (!GNGetAclInformation(pACL, &AclInfo,
1085            sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
1086         goto end;
1087      }
1088   }
1089
1090   /**
1091    * STEP 6: Compute size needed for the new ACL.
1092    */
1093   cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
1094         + GetLengthSid(pUserSID) - sizeof(DWORD);
1095
1096   /**
1097    * STEP 7: Allocate memory for new ACL.
1098    */
1099   pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
1100   if (!pNewACL) {
1101      goto end;
1102   }
1103
1104   /**
1105    * STEP 8: Initialize the new ACL.
1106    */
1107   if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
1108      goto end;
1109   }
1110
1111   /**
1112    * STEP 9 If DACL is present, copy all the ACEs from the old DACL
1113    * to the new DACL.
1114    *
1115    * The following code assumes that the old DACL is
1116    * already in Windows 2000 preferred order.  To conform
1117    * to the new Windows 2000 preferred order, first we will
1118    * copy all non-inherited ACEs from the old DACL to the
1119    * new DACL, irrespective of the ACE type.
1120    */
1121
1122   newAceIndex = 0;
1123
1124   if (fDaclPresent && AclInfo.AceCount) {
1125
1126      for (CurrentAceIndex = 0;
1127            CurrentAceIndex < AclInfo.AceCount;
1128            CurrentAceIndex++) {
1129
1130         /**
1131          * TEP 10: Get an ACE.
1132          */
1133         if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1134            goto end;
1135         }
1136
1137         /**
1138          * STEP 11: Check if it is a non-inherited ACE.
1139          * If it is an inherited ACE, break from the loop so
1140          * that the new access allowed non-inherited ACE can
1141          * be added in the correct position, immediately after
1142          * all non-inherited ACEs.
1143          */
1144         if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
1145            & INHERITED_ACE)
1146            break;
1147
1148         /**
1149          * STEP 12: Skip adding the ACE, if the SID matches
1150          * with the account specified, as we are going to
1151          * add an access allowed ACE with a different access
1152          * mask.
1153          */
1154         if (GNEqualSid(pUserSID,
1155            &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
1156            continue;
1157
1158         /**
1159          * STEP 13: Add the ACE to the new ACL.
1160          */
1161         if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1162               ((PACE_HEADER) pTempAce)->AceSize)) {
1163            goto end;
1164         }
1165
1166         newAceIndex++;
1167      }
1168   }
1169
1170   /**
1171    * STEP 14: Add the access-allowed ACE to the new DACL.
1172    * The new ACE added here will be in the correct position,
1173    * immediately after all existing non-inherited ACEs.
1174    */
1175   if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
1176         pUserSID)) {
1177      goto end;
1178   }
1179
1180   /**
1181    * STEP 14.5: Make new ACE inheritable
1182    */
1183   if (!GetAce(pNewACL, newAceIndex, &pTempAce))
1184     goto end;
1185   ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
1186     (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
1187
1188   /**
1189    * STEP 15: To conform to the new Windows 2000 preferred order,
1190    * we will now copy the rest of inherited ACEs from the
1191    * old DACL to the new DACL.
1192    */
1193   if (fDaclPresent && AclInfo.AceCount) {
1194
1195      for (;
1196           CurrentAceIndex < AclInfo.AceCount;
1197           CurrentAceIndex++) {
1198
1199         /**
1200          * STEP 16: Get an ACE.
1201          */
1202         if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1203            goto end;
1204         }
1205
1206         /**
1207          * STEP 17: Add the ACE to the new ACL.
1208          */
1209         if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1210               ((PACE_HEADER) pTempAce)->AceSize)) {
1211            goto end;
1212         }
1213      }
1214   }
1215
1216   /**
1217    * STEP 18: Set permissions
1218    */
1219   if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
1220     DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
1221         goto end;
1222   }
1223
1224   fResult = TRUE;
1225
1226 end:
1227
1228   /**
1229    * STEP 19: Free allocated memory
1230    */
1231   if (pUserSID)
1232      HeapFree(GetProcessHeap(), 0, pUserSID);
1233
1234   if (szDomain)
1235      HeapFree(GetProcessHeap(), 0, szDomain);
1236
1237   if (pFileSD)
1238      HeapFree(GetProcessHeap(), 0, pFileSD);
1239
1240   if (pNewACL)
1241      HeapFree(GetProcessHeap(), 0, pNewACL);
1242
1243   return fResult;
1244 }
1245
1246 char *winErrorStr(const char *prefix, int dwErr)
1247 {
1248   char *err, *ret;
1249   int mem;
1250
1251   if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1252     NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
1253     0, NULL ))
1254   {
1255     err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);
1256   }
1257
1258   mem = strlen(err) + strlen(prefix) + 20;
1259   ret = (char *) malloc(mem);
1260
1261   snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
1262
1263   LocalFree(err);
1264
1265   return ret;
1266 }
1267
1268 /**
1269  * Terminate a process by creating a remote thread within it,
1270  * which proceeds to call ExitProcess() inside that process.
1271  * Safer than TerminateProcess ().
1272  *
1273  * Code is from From http://private-storm.de/2009/08/11/case-terminateprocess/
1274  *
1275  * @param hProcess handle of a process to terminate
1276  * @param uExitCode exit code to use for ExitProcess()
1277  * @param dwTimeout number of ms to wait for the process to terminate
1278  * @return TRUE on success, FALSE on failure (check last error for the code)
1279  */
1280 BOOL
1281 SafeTerminateProcess (HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)
1282 {
1283   DWORD dwTID, dwCode, dwErr = 0;
1284   HANDLE hProcessDup = INVALID_HANDLE_VALUE;
1285   HANDLE hRT = NULL;
1286   HINSTANCE hKernel = GetModuleHandle ("Kernel32");
1287   BOOL bSuccess = FALSE;
1288
1289   BOOL bDup = DuplicateHandle (GetCurrentProcess (), hProcess,
1290       GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS,
1291       FALSE, 0);
1292
1293   /* Detect the special case where the process is
1294    * already dead...
1295    */
1296   if (GetExitCodeProcess (bDup ? hProcessDup : hProcess, &dwCode) &&
1297       (STILL_ACTIVE ==  dwCode))
1298   {
1299     FARPROC pfnExitProc;
1300
1301     pfnExitProc = GetProcAddress (hKernel, "ExitProcess");
1302
1303     hRT = CreateRemoteThread ((bDup) ? hProcessDup : hProcess, NULL, 0,
1304         (LPTHREAD_START_ROUTINE) pfnExitProc, (PVOID) uExitCode, 0, &dwTID);
1305
1306     dwErr = GetLastError ();
1307   }
1308   else
1309   {
1310     dwErr = ERROR_PROCESS_ABORTED;
1311   }
1312
1313   if (hRT)
1314   {
1315     /* Must wait process to terminate to
1316      * guarantee that it has exited...
1317      */
1318     DWORD dwWaitResult = WaitForSingleObject ((bDup) ? hProcessDup : hProcess,
1319         dwTimeout);
1320     if (dwWaitResult == WAIT_TIMEOUT)
1321       dwErr = WAIT_TIMEOUT;
1322     else
1323       dwErr = GetLastError ();
1324
1325     CloseHandle (hRT);
1326     bSuccess = dwErr == NO_ERROR;
1327   }
1328
1329   if (bDup)
1330     CloseHandle (hProcessDup);
1331
1332   SetLastError (dwErr);
1333
1334   return bSuccess;
1335 }
1336
1337 #endif