first try raw, unexpanded name
[oweals/gnunet.git] / src / util / win.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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;
304   SOCKET s6;
305   int ifs4len = 0;
306   int ifs6len = 0;
307   INTERFACE_INFO *interfaces4 = NULL;
308   SOCKET_ADDRESS_LIST *interfaces6 = NULL;
309
310   SetLastError (0);
311   s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
312   (void) GetLastError ();
313   SetLastError (0);
314   s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
315   (void) GetLastError ();
316   if (s6 != INVALID_SOCKET)
317   {
318     ifs6len = EnumNICs_IPv6_get_ifs_count (s6);
319     if (ifs6len > 0)
320     {
321       interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);
322       result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;
323     }
324     closesocket (s6);
325     s6 = INVALID_SOCKET;
326   }
327
328   if (s4 != INVALID_SOCKET)
329   {
330     result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;
331     closesocket (s4);
332     s4 = INVALID_SOCKET;
333   }
334   if (ifs6len + ifs4len == 0)
335     goto error;
336
337   if (!result)
338   {
339     *ifs4 = interfaces4;
340     *ifs4_len = ifs4len;
341     *ifs6 = interfaces6;
342     return GNUNET_OK;
343   }
344 error:
345   if (interfaces4 != NULL)
346     GNUNET_free (interfaces4);
347   if (interfaces6 != NULL)
348     GNUNET_free (interfaces6);
349   if (s4 != INVALID_SOCKET)
350     closesocket (s4);
351   if (s6 != INVALID_SOCKET)
352     closesocket (s6);
353   return GNUNET_SYSERR;
354 }
355
356
357 /**
358  * @returns #GNUNET_OK on success, #GNUNET_SYSERR on error
359  */
360 int
361 EnumNICs3 (struct EnumNICs3_results **results, int *results_count)
362 {
363   DWORD dwRetVal = 0;
364   int count = 0;
365   ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |
366       GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
367   struct sockaddr_in6 examplecom6;
368   IPAddr examplecom;
369   DWORD best_interface = 0;
370   DWORD best_interface6 = 0;
371
372   int use_enum2 = 0;
373   INTERFACE_INFO *interfaces4 = NULL;
374   int interfaces4_len = 0;
375   SOCKET_ADDRESS_LIST *interfaces6 = NULL;
376
377   unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
378   IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;
379   IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
380
381   if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)
382       == ERROR_BUFFER_OVERFLOW)
383   {
384     GNUNET_free (pAddresses);
385     pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
386   }
387
388   dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);
389
390   if (dwRetVal != NO_ERROR)
391   {
392     GNUNET_free (pAddresses);
393     return GNUNET_SYSERR;
394   }
395
396   if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))
397   {
398     use_enum2 = 1;
399
400     /* Enumerate NICs using WSAIoctl() */
401     if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))
402     {
403       GNUNET_free (pAddresses);
404       return GNUNET_SYSERR;
405     }
406   }
407
408   examplecom = inet_addr("192.0.34.166"); /* www.example.com */
409   if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)
410     best_interface = 0;
411
412   if (GNGetBestInterfaceEx != NULL)
413   {
414     examplecom6.sin6_family = AF_INET6;
415     examplecom6.sin6_port = 0;
416     examplecom6.sin6_flowinfo = 0;
417     examplecom6.sin6_scope_id = 0;
418     inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",
419         (struct sockaddr *) &examplecom6.sin6_addr);
420     dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,
421         &best_interface6);
422     if (dwRetVal != NO_ERROR)
423       best_interface6 = 0;
424   }
425
426   /* Give IPv6 a priority */
427   if (best_interface6 != 0)
428     best_interface = best_interface6;
429
430   count = 0;
431   for (pCurrentAddress = pAddresses;
432       pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
433   {
434     if (pCurrentAddress->OperStatus == IfOperStatusUp)
435     {
436       IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
437       for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
438           unicast = unicast->Next)
439       {
440         if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||
441             unicast->Address.lpSockaddr->sa_family == AF_INET6) &&
442             (unicast->DadState == IpDadStateDeprecated ||
443             unicast->DadState == IpDadStatePreferred))
444           count += 1;
445       }
446     }
447   }
448
449   if (count == 0)
450   {
451     *results = NULL;
452     *results_count = 0;
453     GNUNET_free (pAddresses);
454     GNUNET_free_non_null (interfaces4);
455     GNUNET_free_non_null (interfaces6);
456     return GNUNET_OK;
457   }
458
459   *results = (struct EnumNICs3_results *) GNUNET_malloc (
460       sizeof (struct EnumNICs3_results) * count);
461   *results_count = count;
462
463   count = 0;
464   for (pCurrentAddress = pAddresses;
465       pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
466   {
467     struct EnumNICs3_results *r;
468     IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
469     if (pCurrentAddress->OperStatus != IfOperStatusUp)
470       continue;
471     for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
472         unicast = unicast->Next)
473     {
474       int i, j;
475       int mask_length = -1;
476       char dst[INET6_ADDRSTRLEN + 1];
477
478       if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&
479           unicast->Address.lpSockaddr->sa_family != AF_INET6) ||
480           (unicast->DadState != IpDadStateDeprecated &&
481           unicast->DadState != IpDadStatePreferred))
482         continue;
483
484       r = &(*results)[count];
485       r->flags = 0;
486       if (pCurrentAddress->IfIndex > 0 &&
487           pCurrentAddress->IfIndex == best_interface &&
488           unicast->Address.lpSockaddr->sa_family == AF_INET)
489         r->is_default = 1;
490       else if (pCurrentAddress->Ipv6IfIndex > 0 &&
491           pCurrentAddress->Ipv6IfIndex == best_interface6 &&
492           unicast->Address.lpSockaddr->sa_family == AF_INET6)
493         r->is_default = 1;
494       else
495         r->is_default = 0;
496
497       /* Don't choose default interface twice */
498       if (r->is_default)
499         best_interface = best_interface6 = 0;
500
501       if (!use_enum2)
502       {
503         GNUNET_memcpy (&r->address, unicast->Address.lpSockaddr,
504             unicast->Address.iSockaddrLength);
505         memset (&r->mask, 0, sizeof (struct sockaddr));
506         mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->
507               OnLinkPrefixLength;
508         /* OnLinkPrefixLength is the number of leading 1s in the mask.
509          * OnLinkPrefixLength is available on Vista and later (hence use_enum2).
510          */
511         if (unicast->Address.lpSockaddr->sa_family == AF_INET)
512         {
513           struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
514           for (i = 0; i < mask_length; i++)
515               ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
516         }
517         else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
518         {
519           struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;
520           struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;
521           for (i = 0; i < mask_length; i++)
522             ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
523           GNUNET_memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
524           for (i = mask_length; i < 128; i++)
525             ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
526         }
527         r->flags |= ENUMNICS3_MASK_OK;
528       }
529       else
530       {
531         int found = 0;
532         if (unicast->Address.lpSockaddr->sa_family == AF_INET)
533         {
534           for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)
535           {
536             struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
537             GNUNET_memcpy (&interfaces4[i].iiAddress.Address,
538                 unicast->Address.lpSockaddr,
539                 unicast->Address.iSockaddrLength);
540             found = 1;
541             GNUNET_memcpy (&r->address, &interfaces4[i].iiAddress.Address,
542                 sizeof (struct sockaddr_in));
543             GNUNET_memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,
544                 sizeof (struct sockaddr_in));
545             for (mask_length = 0;
546                 ((unsigned char *) &m->sin_addr)[mask_length / 8] &
547                 0x80 >> (mask_length % 8); mask_length++)
548             {
549             }
550             r->flags |= ENUMNICS3_MASK_OK;
551           }
552         }
553         else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
554         {
555           for (i = 0;
556               interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
557               i++)
558           {
559             GNUNET_memcpy (interfaces6->Address[i].lpSockaddr,
560                 unicast->Address.lpSockaddr,
561                 unicast->Address.iSockaddrLength);
562             found = 1;
563             GNUNET_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         GNUNET_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 /**
702  * @brief Uninstall Windows service
703  * @param servicename name of the service to delete
704  * @returns 0 on success
705  *          1 if the Windows version doesn't support services
706  *          2 if the SCM could not be openend
707  *          3 if the service cannot be accessed
708  *          4 if the service cannot be deleted
709  */
710 int
711 UninstallService(char *servicename)
712 {
713   SC_HANDLE hManager, hService;
714
715   if (! GNOpenSCManager)
716     return 1;
717
718   hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
719   if (! hManager)
720     return 2;
721
722   if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
723   {
724     if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
725       return 3;
726     else
727       goto closeSCM;
728   }
729
730   if (! GNDeleteService(hService))
731     if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
732       return 4;
733
734 closeSCM:
735   GNCloseServiceHandle(hService);
736
737   return 0;
738 }
739
740 /**
741  * @author Scott Field, Microsoft
742  * @see http://support.microsoft.com/?scid=kb;en-us;132958
743  * @date 12-Jul-95
744  */
745 void
746 _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
747 {
748   DWORD StringLength;
749
750   if(String == NULL)
751   {
752     LsaString->Buffer = NULL;
753     LsaString->Length = 0;
754     LsaString->MaximumLength = 0;
755     return;
756   }
757
758   StringLength = wcslen(String);
759   LsaString->Buffer = String;
760   LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
761   LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
762 }
763
764
765 /**
766  * @author Scott Field, Microsoft
767  * @see http://support.microsoft.com/?scid=kb;en-us;132958
768  * @date 12-Jul-95
769  */
770 NTSTATUS
771 _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
772 {
773   LSA_OBJECT_ATTRIBUTES ObjectAttributes;
774   LSA_UNICODE_STRING ServerString;
775   PLSA_UNICODE_STRING Server = NULL;
776
777   /* Always initialize the object attributes to all zeroes. */
778   ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
779
780   if(ServerName != NULL)
781   {
782     /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
783     _InitLsaString(&ServerString, ServerName);
784     Server = &ServerString;
785   }
786
787   /* Attempt to open the policy. */
788   return GNLsaOpenPolicy(Server,
789                        &ObjectAttributes, DesiredAccess, PolicyHandle);
790 }
791
792 /**
793  * @brief Obtain a SID representing the supplied account on the supplied system
794  * @return TRUE on success, FALSE on failure
795  * @author Scott Field, Microsoft
796  * @date 12-Jul-95
797  * @remarks A buffer is allocated which contains the SID representing the
798  *          supplied account. This buffer should be freed when it is no longer
799  *          needed by calling\n
800  *            HeapFree(GetProcessHeap(), 0, buffer)
801  * @remarks Call GetLastError() to obtain extended error information.
802  * @see http://support.microsoft.com/?scid=kb;en-us;132958
803  */
804 BOOL
805 _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)
806 {
807   LPTSTR ReferencedDomain = NULL;
808   DWORD cbSid = 128;                                                    /* initial allocation attempt */
809   DWORD cchReferencedDomain = 16;       /* initial allocation size */
810   SID_NAME_USE peUse;
811   BOOL bSuccess = FALSE;                                        /* assume this function will fail */
812
813   /* initial memory allocations */
814   if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
815         return FALSE;
816
817   if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
818                                     0,
819                                     cchReferencedDomain *
820                                     sizeof (TCHAR))) == NULL)
821         return FALSE;
822
823     /* Obtain the SID of the specified account on the specified system. */
824         while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
825                    AccountName,                                                                                         /* account to lookup */
826                    *Sid,                                                                                                                        /* SID of interest */
827                    &cbSid,                                                                                                              /* size of SID */
828                    ReferencedDomain,                                                                    /* domain account was found on */
829                    &cchReferencedDomain, &peUse))
830         {
831                 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
832                 {
833                         /* reallocate memory */
834                         if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
835                                 return FALSE;
836
837                         if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
838                                               0,
839                                               ReferencedDomain,
840                                               cchReferencedDomain
841                                               * sizeof (TCHAR))) == NULL)
842                                 return FALSE;
843       }
844       else
845         goto end;
846   }
847
848   /* Indicate success. */
849   bSuccess = TRUE;
850
851 end:
852   /* Cleanup and indicate failure, if appropriate. */
853   HeapFree (GetProcessHeap (), 0, ReferencedDomain);
854
855   if (!bSuccess)
856   {
857     if (*Sid != NULL)
858     {
859                 HeapFree (GetProcessHeap (), 0, *Sid);
860                 *Sid = NULL;
861     }
862   }
863
864   return bSuccess;
865 }
866
867 /**
868  * @author Scott Field, Microsoft
869  * @see http://support.microsoft.com/?scid=kb;en-us;132958
870  * @date 12-Jul-95
871  */
872 NTSTATUS
873 _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
874                        PSID AccountSid,                         /* SID to grant privilege to */
875                        LPWSTR PrivilegeName,    /* privilege to grant (Unicode) */
876                        BOOL bEnable                                             /* enable or disable */
877   )
878 {
879   LSA_UNICODE_STRING PrivilegeString;
880
881   /* Create a LSA_UNICODE_STRING for the privilege name. */
882   _InitLsaString(&PrivilegeString, PrivilegeName);
883
884   /* grant or revoke the privilege, accordingly */
885   if(bEnable)
886   {
887     NTSTATUS i;
888
889     i = GNLsaAddAccountRights(PolicyHandle,                             /* open policy handle */
890                                AccountSid,                              /* target SID */
891                                &PrivilegeString,        /* privileges */
892                                1                                                                                        /* privilege count */
893       );
894     return i;
895   }
896   else
897   {
898     return GNLsaRemoveAccountRights(PolicyHandle,                       /* open policy handle */
899                                   AccountSid,                           /* target SID */
900                                   FALSE,                                                        /* do not disable all rights */
901                                   &PrivilegeString,             /* privileges */
902                                   1                                                                             /* privilege count */
903       );
904   }
905 }
906
907 /**
908  * @brief Create a Windows service account
909  * @return 0 on success, > 0 otherwise
910  * @param pszName the name of the account
911  * @param pszDesc description of the account
912  */
913 int
914 CreateServiceAccount(const char *pszName,
915                      const char *pszDesc)
916 {
917   USER_INFO_1 ui;
918   USER_INFO_1008 ui2;
919   NET_API_STATUS nStatus;
920   wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
921   LSA_HANDLE hPolicy;
922   PSID pSID;
923
924   if (! GNNetUserAdd)
925         return 1;
926   mbstowcs(wszName, pszName, strlen(pszName) + 1);
927   mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
928
929   memset(&ui, 0, sizeof(ui));
930   ui.usri1_name = wszName;
931   ui.usri1_password = wszName; /* account is locked anyway */
932   ui.usri1_priv = USER_PRIV_USER;
933   ui.usri1_comment = wszDesc;
934   ui.usri1_flags = UF_SCRIPT;
935
936   nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
937
938   if (nStatus != NERR_Success && nStatus != NERR_UserExists)
939         return 2;
940
941   ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
942   GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
943
944   if (!NT_SUCCESS(_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy)))
945         return 3;
946
947   _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);
948
949   if (!NT_SUCCESS(_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE)))
950         return 4;
951
952   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);
953   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);
954   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);
955
956   GNLsaClose(hPolicy);
957
958   return 0;
959 }
960
961 /**
962  * @brief Grant permission to a file
963  * @param lpszFileName the name of the file or directory
964  * @param lpszAccountName the user account
965  * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
966  * @return TRUE on success
967  * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
968  */
969 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
970       DWORD dwAccessMask)
971 {
972   /* SID variables. */
973   SID_NAME_USE   snuType;
974   TCHAR *        szDomain       = NULL;
975   DWORD          cbDomain       = 0;
976   LPVOID         pUserSID       = NULL;
977   DWORD          cbUserSID      = 0;
978
979   /* File SD variables. */
980   PSECURITY_DESCRIPTOR pFileSD  = NULL;
981   DWORD          cbFileSD       = 0;
982
983   /* New SD variables. */
984   SECURITY_DESCRIPTOR  newSD;
985
986   /* ACL variables. */
987   PACL           pACL           = NULL;
988   BOOL           fDaclPresent;
989   BOOL           fDaclDefaulted;
990   ACL_SIZE_INFORMATION AclInfo;
991
992   /* New ACL variables. */
993   PACL           pNewACL        = NULL;
994   DWORD          cbNewACL       = 0;
995
996   /* Temporary ACE. */
997   LPVOID         pTempAce       = NULL;
998   UINT           CurrentAceIndex = 0;
999
1000   UINT           newAceIndex = 0;
1001
1002   /* Assume function will fail. */
1003   BOOL           fResult        = FALSE;
1004   BOOL           fAPISuccess;
1005
1006   SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
1007
1008   /**
1009    * STEP 1: Get SID of the account name specified.
1010    */
1011   fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1012         pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1013
1014   /* API should have failed with insufficient buffer. */
1015   if (fAPISuccess)
1016      goto end;
1017   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1018      goto end;
1019   }
1020
1021   pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
1022   if (!pUserSID) {
1023      goto end;
1024   }
1025
1026   szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
1027   if (!szDomain) {
1028      goto end;
1029   }
1030
1031   fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1032         pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1033   if (!fAPISuccess) {
1034      goto end;
1035   }
1036
1037   /**
1038    *  STEP 2: Get security descriptor (SD) of the file specified.
1039    */
1040   fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1041         secInfo, pFileSD, 0, &cbFileSD);
1042
1043   /* API should have failed with insufficient buffer. */
1044   if (fAPISuccess)
1045      goto end;
1046   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1047      goto end;
1048   }
1049
1050   pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1051         cbFileSD);
1052   if (!pFileSD) {
1053      goto end;
1054   }
1055
1056   fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1057         secInfo, pFileSD, cbFileSD, &cbFileSD);
1058   if (!fAPISuccess) {
1059      goto end;
1060   }
1061
1062   /**
1063    * STEP 3: Initialize new SD.
1064    */
1065   if (!GNInitializeSecurityDescriptor(&newSD,
1066         SECURITY_DESCRIPTOR_REVISION)) {
1067      goto end;
1068   }
1069
1070   /**
1071    * STEP 4: Get DACL from the old SD.
1072    */
1073   if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
1074         &fDaclDefaulted)) {
1075      goto end;
1076   }
1077
1078   /**
1079    * STEP 5: Get size information for DACL.
1080    */
1081   AclInfo.AceCount = 0; // Assume NULL DACL.
1082   AclInfo.AclBytesFree = 0;
1083   AclInfo.AclBytesInUse = sizeof(ACL);
1084
1085   if (pACL == NULL)
1086      fDaclPresent = FALSE;
1087
1088   /* If not NULL DACL, gather size information from DACL. */
1089   if (fDaclPresent) {
1090
1091      if (!GNGetAclInformation(pACL, &AclInfo,
1092            sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
1093         goto end;
1094      }
1095   }
1096
1097   /**
1098    * STEP 6: Compute size needed for the new ACL.
1099    */
1100   cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
1101         + GetLengthSid(pUserSID) - sizeof(DWORD);
1102
1103   /**
1104    * STEP 7: Allocate memory for new ACL.
1105    */
1106   pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
1107   if (!pNewACL) {
1108      goto end;
1109   }
1110
1111   /**
1112    * STEP 8: Initialize the new ACL.
1113    */
1114   if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
1115      goto end;
1116   }
1117
1118   /**
1119    * STEP 9 If DACL is present, copy all the ACEs from the old DACL
1120    * to the new DACL.
1121    *
1122    * The following code assumes that the old DACL is
1123    * already in Windows 2000 preferred order.  To conform
1124    * to the new Windows 2000 preferred order, first we will
1125    * copy all non-inherited ACEs from the old DACL to the
1126    * new DACL, irrespective of the ACE type.
1127    */
1128
1129   newAceIndex = 0;
1130
1131   if (fDaclPresent && AclInfo.AceCount) {
1132
1133      for (CurrentAceIndex = 0;
1134            CurrentAceIndex < AclInfo.AceCount;
1135            CurrentAceIndex++) {
1136
1137         /**
1138          * TEP 10: Get an ACE.
1139          */
1140         if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1141            goto end;
1142         }
1143
1144         /**
1145          * STEP 11: Check if it is a non-inherited ACE.
1146          * If it is an inherited ACE, break from the loop so
1147          * that the new access allowed non-inherited ACE can
1148          * be added in the correct position, immediately after
1149          * all non-inherited ACEs.
1150          */
1151         if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
1152            & INHERITED_ACE)
1153            break;
1154
1155         /**
1156          * STEP 12: Skip adding the ACE, if the SID matches
1157          * with the account specified, as we are going to
1158          * add an access allowed ACE with a different access
1159          * mask.
1160          */
1161         if (GNEqualSid(pUserSID,
1162            &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
1163            continue;
1164
1165         /**
1166          * STEP 13: Add the ACE to the new ACL.
1167          */
1168         if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1169               ((PACE_HEADER) pTempAce)->AceSize)) {
1170            goto end;
1171         }
1172
1173         newAceIndex++;
1174      }
1175   }
1176
1177   /**
1178    * STEP 14: Add the access-allowed ACE to the new DACL.
1179    * The new ACE added here will be in the correct position,
1180    * immediately after all existing non-inherited ACEs.
1181    */
1182   if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
1183         pUserSID)) {
1184      goto end;
1185   }
1186
1187   /**
1188    * STEP 14.5: Make new ACE inheritable
1189    */
1190   if (!GetAce(pNewACL, newAceIndex, &pTempAce))
1191     goto end;
1192   ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
1193     (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
1194
1195   /**
1196    * STEP 15: To conform to the new Windows 2000 preferred order,
1197    * we will now copy the rest of inherited ACEs from the
1198    * old DACL to the new DACL.
1199    */
1200   if (fDaclPresent && AclInfo.AceCount) {
1201
1202      for (;
1203           CurrentAceIndex < AclInfo.AceCount;
1204           CurrentAceIndex++) {
1205
1206         /**
1207          * STEP 16: Get an ACE.
1208          */
1209         if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1210            goto end;
1211         }
1212
1213         /**
1214          * STEP 17: Add the ACE to the new ACL.
1215          */
1216         if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1217               ((PACE_HEADER) pTempAce)->AceSize)) {
1218            goto end;
1219         }
1220      }
1221   }
1222
1223   /**
1224    * STEP 18: Set permissions
1225    */
1226   if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
1227     DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
1228         goto end;
1229   }
1230
1231   fResult = TRUE;
1232
1233 end:
1234
1235   /**
1236    * STEP 19: Free allocated memory
1237    */
1238   if (pUserSID)
1239      HeapFree(GetProcessHeap(), 0, pUserSID);
1240
1241   if (szDomain)
1242      HeapFree(GetProcessHeap(), 0, szDomain);
1243
1244   if (pFileSD)
1245      HeapFree(GetProcessHeap(), 0, pFileSD);
1246
1247   if (pNewACL)
1248      HeapFree(GetProcessHeap(), 0, pNewACL);
1249
1250   return fResult;
1251 }
1252
1253 char *winErrorStr(const char *prefix, int dwErr)
1254 {
1255   char *err, *ret;
1256   int mem;
1257
1258   if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1259     NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
1260     0, NULL ))
1261   {
1262     err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);
1263   }
1264
1265   mem = strlen(err) + strlen(prefix) + 20;
1266   ret = (char *) malloc(mem);
1267
1268   snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
1269
1270   LocalFree(err);
1271
1272   return ret;
1273 }
1274
1275 /**
1276  * Terminate a process by creating a remote thread within it,
1277  * which proceeds to call ExitProcess() inside that process.
1278  * Safer than TerminateProcess ().
1279  *
1280  * Code is from From http://private-storm.de/2009/08/11/case-terminateprocess/
1281  *
1282  * @param hProcess handle of a process to terminate
1283  * @param uExitCode exit code to use for ExitProcess()
1284  * @param dwTimeout number of ms to wait for the process to terminate
1285  * @return TRUE on success, FALSE on failure (check last error for the code)
1286  */
1287 BOOL
1288 SafeTerminateProcess (HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)
1289 {
1290   DWORD dwTID, dwCode, dwErr = 0;
1291   HANDLE hProcessDup = INVALID_HANDLE_VALUE;
1292   HANDLE hRT = NULL;
1293   HINSTANCE hKernel = GetModuleHandle ("Kernel32");
1294   BOOL bSuccess = FALSE;
1295
1296   BOOL bDup = DuplicateHandle (GetCurrentProcess (), hProcess,
1297       GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS,
1298       FALSE, 0);
1299
1300   /* Detect the special case where the process is
1301    * already dead...
1302    */
1303   if (GetExitCodeProcess (bDup ? hProcessDup : hProcess, &dwCode) &&
1304       (STILL_ACTIVE ==  dwCode))
1305   {
1306     FARPROC pfnExitProc;
1307
1308     pfnExitProc = GetProcAddress (hKernel, "ExitProcess");
1309
1310     hRT = CreateRemoteThread ((bDup) ? hProcessDup : hProcess, NULL, 0,
1311         (LPTHREAD_START_ROUTINE) pfnExitProc, (PVOID) uExitCode, 0, &dwTID);
1312
1313     dwErr = GetLastError ();
1314   }
1315   else
1316   {
1317     dwErr = ERROR_PROCESS_ABORTED;
1318   }
1319
1320   if (hRT)
1321   {
1322     /* Must wait process to terminate to
1323      * guarantee that it has exited...
1324      */
1325     DWORD dwWaitResult = WaitForSingleObject ((bDup) ? hProcessDup : hProcess,
1326         dwTimeout);
1327     if (dwWaitResult == WAIT_TIMEOUT)
1328       dwErr = WAIT_TIMEOUT;
1329     else
1330       dwErr = GetLastError ();
1331
1332     CloseHandle (hRT);
1333     bSuccess = dwErr == NO_ERROR;
1334   }
1335
1336   if (bDup)
1337     CloseHandle (hProcessDup);
1338
1339   SetLastError (dwErr);
1340
1341   return bSuccess;
1342 }
1343
1344 #endif