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