Fix perf_crypto_rsa.c after various changes
[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
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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;
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         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           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             if (memcpy (&interfaces4[i].iiAddress.Address,
538                 unicast->Address.lpSockaddr,
539                 unicast->Address.iSockaddrLength) != 0)
540               continue;
541             found = 1;
542             memcpy (&r->address, &interfaces4[i].iiAddress.Address,
543                 sizeof (struct sockaddr_in));
544             memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,
545                 sizeof (struct sockaddr_in));
546             for (mask_length = 0;
547                 ((unsigned char *) &m->sin_addr)[mask_length / 8] &
548                 0x80 >> (mask_length % 8); mask_length++)
549             {
550             }
551             r->flags |= ENUMNICS3_MASK_OK;
552           }
553         }
554         else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
555         {
556           for (i = 0;
557               interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
558               i++)
559           {
560             if (memcpy (interfaces6->Address[i].lpSockaddr,
561                 unicast->Address.lpSockaddr,
562                 unicast->Address.iSockaddrLength) != 0)
563               continue;
564             found = 1;
565             memcpy (&r->address, interfaces6->Address[i].lpSockaddr,
566                 sizeof (struct sockaddr_in6));
567             /* TODO: Find a way to reliably get network mask for IPv6 on XP */
568             memset (&r->mask, 0, sizeof (struct sockaddr));
569             r->flags &= ~ENUMNICS3_MASK_OK;
570           }
571         }
572         if (!found)
573         {
574           DebugBreak ();
575         }
576       }
577       if (unicast->Address.lpSockaddr->sa_family == AF_INET)
578       {
579         struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
580         struct sockaddr_in *a = (struct sockaddr_in *) &r->address;
581         /* copy address to broadcast, then flip all the trailing bits not
582          * falling under netmask to 1,
583          * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.
584          */
585         memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
586         for (i = mask_length; i < 32; i++)
587           ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
588         r->flags |= ENUMNICS3_BCAST_OK;
589         r->addr_size = sizeof (struct sockaddr_in);
590         inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);
591       }
592       else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
593       {
594         struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;
595         /* for IPv6 broadcast is not defined, zero it down */
596         memset (&r->broadcast, 0, sizeof (struct sockaddr));
597         r->flags &= ~ENUMNICS3_BCAST_OK;
598         r->addr_size = sizeof (struct sockaddr_in6);
599         inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);
600       }
601
602       i = 0;
603       i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
604           "%S (%s", pCurrentAddress->FriendlyName, dst);
605       for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)
606         i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
607             "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);
608       i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");
609       r->pretty_name[1000] = '\0';
610       count += 1;
611     }
612   }
613
614   if (use_enum2)
615   {
616     GNUNET_free_non_null (interfaces4);
617     GNUNET_free_non_null (interfaces6);
618   }
619
620   GNUNET_free (pAddresses);
621   return GNUNET_OK;
622 }
623
624 void
625 EnumNICs3_free (struct EnumNICs3_results *r)
626 {
627   GNUNET_free_non_null (r);
628 }
629
630
631 /**
632  * Lists all network interfaces in a combo box
633  * Used by the basic GTK configurator
634  *
635  * @param callback function to call for each NIC
636  * @param callback_cls closure for callback
637  */
638 int
639 ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)
640 {
641   int r;
642   int i;
643   struct EnumNICs3_results *results = NULL;
644   int results_count;
645
646   r = EnumNICs3 (&results, &results_count);
647   if (r != GNUNET_OK)
648     return GNUNET_NO;
649
650   for (i = 0; i < results_count; i++)
651     callback (callback_cls, results[i].pretty_name, results[i].is_default);
652   GNUNET_free_non_null (results);
653   return GNUNET_YES;
654 }
655
656 /**
657  * @brief Installs the Windows service
658  * @param servicename name of the service as diplayed by the SCM
659  * @param application path to the application binary
660  * @param username the name of the service's user account
661  * @returns 0 on success
662  *          1 if the Windows version doesn't support services
663  *          2 if the SCM could not be opened
664  *          3 if the service could not be created
665  */
666 int InstallAsService(char *servicename, char *application, char *username)
667 {
668   SC_HANDLE hManager, hService;
669   char szEXE[_MAX_PATH + 17] = "\"";
670   char *user = NULL;
671
672   if (! GNOpenSCManager)
673     return 1;
674
675   plibc_conv_to_win_path(application, szEXE + 1);
676   strcat(szEXE, "\" --win-service");
677   hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
678   if (! hManager)
679     return 2;
680
681   if (username)
682   {
683         user = (char *) malloc(strlen(username) + 3);
684         sprintf(user, ".\\%s", username);
685   }
686
687   hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
688     SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
689     NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
690
691   if (user)
692     free(user);
693
694   if (! hService)
695     return 3;
696
697   GNCloseServiceHandle(hService);
698
699   return 0;
700 }
701
702
703 /**
704  * @brief Uninstall Windows service
705  * @param servicename name of the service to delete
706  * @returns 0 on success
707  *          1 if the Windows version doesn't support services
708  *          2 if the SCM could not be openend
709  *          3 if the service cannot be accessed
710  *          4 if the service cannot be deleted
711  */
712 int
713 UninstallService(char *servicename)
714 {
715   SC_HANDLE hManager, hService;
716
717   if (! GNOpenSCManager)
718     return 1;
719
720   hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
721   if (! hManager)
722     return 2;
723
724   if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
725   {
726     if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
727       return 3;
728     else
729       goto closeSCM;
730   }
731
732   if (! GNDeleteService(hService))
733     if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
734       return 4;
735
736 closeSCM:
737   GNCloseServiceHandle(hService);
738
739   return 0;
740 }
741
742 /**
743  * @author Scott Field, Microsoft
744  * @see http://support.microsoft.com/?scid=kb;en-us;132958
745  * @date 12-Jul-95
746  */
747 void
748 _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
749 {
750   DWORD StringLength;
751
752   if(String == NULL)
753   {
754     LsaString->Buffer = NULL;
755     LsaString->Length = 0;
756     LsaString->MaximumLength = 0;
757     return;
758   }
759
760   StringLength = wcslen(String);
761   LsaString->Buffer = String;
762   LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
763   LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
764 }
765
766
767 /**
768  * @author Scott Field, Microsoft
769  * @see http://support.microsoft.com/?scid=kb;en-us;132958
770  * @date 12-Jul-95
771  */
772 NTSTATUS
773 _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
774 {
775   LSA_OBJECT_ATTRIBUTES ObjectAttributes;
776   LSA_UNICODE_STRING ServerString;
777   PLSA_UNICODE_STRING Server = NULL;
778
779   /* Always initialize the object attributes to all zeroes. */
780   ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
781
782   if(ServerName != NULL)
783   {
784     /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
785     _InitLsaString(&ServerString, ServerName);
786     Server = &ServerString;
787   }
788
789   /* Attempt to open the policy. */
790   return GNLsaOpenPolicy(Server,
791                        &ObjectAttributes, DesiredAccess, PolicyHandle);
792 }
793
794 /**
795  * @brief Obtain a SID representing the supplied account on the supplied system
796  * @return TRUE on success, FALSE on failure
797  * @author Scott Field, Microsoft
798  * @date 12-Jul-95
799  * @remarks A buffer is allocated which contains the SID representing the
800  *          supplied account. This buffer should be freed when it is no longer
801  *          needed by calling\n
802  *            HeapFree(GetProcessHeap(), 0, buffer)
803  * @remarks Call GetLastError() to obtain extended error information.
804  * @see http://support.microsoft.com/?scid=kb;en-us;132958
805  */
806 BOOL
807 _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)
808 {
809   LPTSTR ReferencedDomain = NULL;
810   DWORD cbSid = 128;                                                    /* initial allocation attempt */
811   DWORD cchReferencedDomain = 16;       /* initial allocation size */
812   SID_NAME_USE peUse;
813   BOOL bSuccess = FALSE;                                        /* assume this function will fail */
814
815   /* initial memory allocations */
816   if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
817         return FALSE;
818
819   if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
820                                     0,
821                                     cchReferencedDomain *
822                                     sizeof (TCHAR))) == NULL)
823         return FALSE;
824
825     /* Obtain the SID of the specified account on the specified system. */
826         while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
827                    AccountName,                                                                                         /* account to lookup */
828                    *Sid,                                                                                                                        /* SID of interest */
829                    &cbSid,                                                                                                              /* size of SID */
830                    ReferencedDomain,                                                                    /* domain account was found on */
831                    &cchReferencedDomain, &peUse))
832         {
833                 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
834                 {
835                         /* reallocate memory */
836                         if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
837                                 return FALSE;
838
839                         if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
840                                               0,
841                                               ReferencedDomain,
842                                               cchReferencedDomain
843                                               * sizeof (TCHAR))) == NULL)
844                                 return FALSE;
845       }
846       else
847         goto end;
848   }
849
850   /* Indicate success. */
851   bSuccess = TRUE;
852
853 end:
854   /* Cleanup and indicate failure, if appropriate. */
855   HeapFree (GetProcessHeap (), 0, ReferencedDomain);
856
857   if (!bSuccess)
858   {
859     if (*Sid != NULL)
860     {
861                 HeapFree (GetProcessHeap (), 0, *Sid);
862                 *Sid = NULL;
863     }
864   }
865
866   return bSuccess;
867 }
868
869 /**
870  * @author Scott Field, Microsoft
871  * @see http://support.microsoft.com/?scid=kb;en-us;132958
872  * @date 12-Jul-95
873  */
874 NTSTATUS
875 _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
876                        PSID AccountSid,                         /* SID to grant privilege to */
877                        LPWSTR PrivilegeName,    /* privilege to grant (Unicode) */
878                        BOOL bEnable                                             /* enable or disable */
879   )
880 {
881   LSA_UNICODE_STRING PrivilegeString;
882
883   /* Create a LSA_UNICODE_STRING for the privilege name. */
884   _InitLsaString(&PrivilegeString, PrivilegeName);
885
886   /* grant or revoke the privilege, accordingly */
887   if(bEnable)
888   {
889     NTSTATUS i;
890
891     i = GNLsaAddAccountRights(PolicyHandle,                             /* open policy handle */
892                                AccountSid,                              /* target SID */
893                                &PrivilegeString,        /* privileges */
894                                1                                                                                        /* privilege count */
895       );
896     return i;
897   }
898   else
899   {
900     return GNLsaRemoveAccountRights(PolicyHandle,                       /* open policy handle */
901                                   AccountSid,                           /* target SID */
902                                   FALSE,                                                        /* do not disable all rights */
903                                   &PrivilegeString,             /* privileges */
904                                   1                                                                             /* privilege count */
905       );
906   }
907 }
908
909 /**
910  * @brief Create a Windows service account
911  * @return 0 on success, > 0 otherwise
912  * @param pszName the name of the account
913  * @param pszDesc description of the account
914  */
915 int
916 CreateServiceAccount(const char *pszName,
917                      const char *pszDesc)
918 {
919   USER_INFO_1 ui;
920   USER_INFO_1008 ui2;
921   NET_API_STATUS nStatus;
922   wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
923   LSA_HANDLE hPolicy;
924   PSID pSID;
925
926   if (! GNNetUserAdd)
927         return 1;
928   mbstowcs(wszName, pszName, strlen(pszName) + 1);
929   mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
930
931   memset(&ui, 0, sizeof(ui));
932   ui.usri1_name = wszName;
933   ui.usri1_password = wszName; /* account is locked anyway */
934   ui.usri1_priv = USER_PRIV_USER;
935   ui.usri1_comment = wszDesc;
936   ui.usri1_flags = UF_SCRIPT;
937
938   nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
939
940   if (nStatus != NERR_Success && nStatus != NERR_UserExists)
941         return 2;
942
943   ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
944   GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
945
946   if (!NT_SUCCESS(_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy)))
947         return 3;
948
949   _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);
950
951   if (!NT_SUCCESS(_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE)))
952         return 4;
953
954   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);
955   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);
956   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);
957
958   GNLsaClose(hPolicy);
959
960   return 0;
961 }
962
963 /**
964  * @brief Grant permission to a file
965  * @param lpszFileName the name of the file or directory
966  * @param lpszAccountName the user account
967  * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
968  * @return TRUE on success
969  * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
970  */
971 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
972       DWORD dwAccessMask)
973 {
974   /* SID variables. */
975   SID_NAME_USE   snuType;
976   TCHAR *        szDomain       = NULL;
977   DWORD          cbDomain       = 0;
978   LPVOID         pUserSID       = NULL;
979   DWORD          cbUserSID      = 0;
980
981   /* File SD variables. */
982   PSECURITY_DESCRIPTOR pFileSD  = NULL;
983   DWORD          cbFileSD       = 0;
984
985   /* New SD variables. */
986   SECURITY_DESCRIPTOR  newSD;
987
988   /* ACL variables. */
989   PACL           pACL           = NULL;
990   BOOL           fDaclPresent;
991   BOOL           fDaclDefaulted;
992   ACL_SIZE_INFORMATION AclInfo;
993
994   /* New ACL variables. */
995   PACL           pNewACL        = NULL;
996   DWORD          cbNewACL       = 0;
997
998   /* Temporary ACE. */
999   LPVOID         pTempAce       = NULL;
1000   UINT           CurrentAceIndex = 0;
1001
1002   UINT           newAceIndex = 0;
1003
1004   /* Assume function will fail. */
1005   BOOL           fResult        = FALSE;
1006   BOOL           fAPISuccess;
1007
1008   SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
1009
1010   /**
1011    * STEP 1: Get SID of the account name specified.
1012    */
1013   fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1014         pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1015
1016   /* API should have failed with insufficient buffer. */
1017   if (fAPISuccess)
1018      goto end;
1019   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1020      goto end;
1021   }
1022
1023   pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
1024   if (!pUserSID) {
1025      goto end;
1026   }
1027
1028   szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
1029   if (!szDomain) {
1030      goto end;
1031   }
1032
1033   fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1034         pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1035   if (!fAPISuccess) {
1036      goto end;
1037   }
1038
1039   /**
1040    *  STEP 2: Get security descriptor (SD) of the file specified.
1041    */
1042   fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1043         secInfo, pFileSD, 0, &cbFileSD);
1044
1045   /* API should have failed with insufficient buffer. */
1046   if (fAPISuccess)
1047      goto end;
1048   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1049      goto end;
1050   }
1051
1052   pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1053         cbFileSD);
1054   if (!pFileSD) {
1055      goto end;
1056   }
1057
1058   fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1059         secInfo, pFileSD, cbFileSD, &cbFileSD);
1060   if (!fAPISuccess) {
1061      goto end;
1062   }
1063
1064   /**
1065    * STEP 3: Initialize new SD.
1066    */
1067   if (!GNInitializeSecurityDescriptor(&newSD,
1068         SECURITY_DESCRIPTOR_REVISION)) {
1069      goto end;
1070   }
1071
1072   /**
1073    * STEP 4: Get DACL from the old SD.
1074    */
1075   if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
1076         &fDaclDefaulted)) {
1077      goto end;
1078   }
1079
1080   /**
1081    * STEP 5: Get size information for DACL.
1082    */
1083   AclInfo.AceCount = 0; // Assume NULL DACL.
1084   AclInfo.AclBytesFree = 0;
1085   AclInfo.AclBytesInUse = sizeof(ACL);
1086
1087   if (pACL == NULL)
1088      fDaclPresent = FALSE;
1089
1090   /* If not NULL DACL, gather size information from DACL. */
1091   if (fDaclPresent) {
1092
1093      if (!GNGetAclInformation(pACL, &AclInfo,
1094            sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
1095         goto end;
1096      }
1097   }
1098
1099   /**
1100    * STEP 6: Compute size needed for the new ACL.
1101    */
1102   cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
1103         + GetLengthSid(pUserSID) - sizeof(DWORD);
1104
1105   /**
1106    * STEP 7: Allocate memory for new ACL.
1107    */
1108   pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
1109   if (!pNewACL) {
1110      goto end;
1111   }
1112
1113   /**
1114    * STEP 8: Initialize the new ACL.
1115    */
1116   if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
1117      goto end;
1118   }
1119
1120   /**
1121    * STEP 9 If DACL is present, copy all the ACEs from the old DACL
1122    * to the new DACL.
1123    *
1124    * The following code assumes that the old DACL is
1125    * already in Windows 2000 preferred order.  To conform
1126    * to the new Windows 2000 preferred order, first we will
1127    * copy all non-inherited ACEs from the old DACL to the
1128    * new DACL, irrespective of the ACE type.
1129    */
1130
1131   newAceIndex = 0;
1132
1133   if (fDaclPresent && AclInfo.AceCount) {
1134
1135      for (CurrentAceIndex = 0;
1136            CurrentAceIndex < AclInfo.AceCount;
1137            CurrentAceIndex++) {
1138
1139         /**
1140          * TEP 10: Get an ACE.
1141          */
1142         if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1143            goto end;
1144         }
1145
1146         /**
1147          * STEP 11: Check if it is a non-inherited ACE.
1148          * If it is an inherited ACE, break from the loop so
1149          * that the new access allowed non-inherited ACE can
1150          * be added in the correct position, immediately after
1151          * all non-inherited ACEs.
1152          */
1153         if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
1154            & INHERITED_ACE)
1155            break;
1156
1157         /**
1158          * STEP 12: Skip adding the ACE, if the SID matches
1159          * with the account specified, as we are going to
1160          * add an access allowed ACE with a different access
1161          * mask.
1162          */
1163         if (GNEqualSid(pUserSID,
1164            &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
1165            continue;
1166
1167         /**
1168          * STEP 13: Add the ACE to the new ACL.
1169          */
1170         if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1171               ((PACE_HEADER) pTempAce)->AceSize)) {
1172            goto end;
1173         }
1174
1175         newAceIndex++;
1176      }
1177   }
1178
1179   /**
1180    * STEP 14: Add the access-allowed ACE to the new DACL.
1181    * The new ACE added here will be in the correct position,
1182    * immediately after all existing non-inherited ACEs.
1183    */
1184   if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
1185         pUserSID)) {
1186      goto end;
1187   }
1188
1189   /**
1190    * STEP 14.5: Make new ACE inheritable
1191    */
1192   if (!GetAce(pNewACL, newAceIndex, &pTempAce))
1193     goto end;
1194   ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
1195     (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
1196
1197   /**
1198    * STEP 15: To conform to the new Windows 2000 preferred order,
1199    * we will now copy the rest of inherited ACEs from the
1200    * old DACL to the new DACL.
1201    */
1202   if (fDaclPresent && AclInfo.AceCount) {
1203
1204      for (;
1205           CurrentAceIndex < AclInfo.AceCount;
1206           CurrentAceIndex++) {
1207
1208         /**
1209          * STEP 16: Get an ACE.
1210          */
1211         if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1212            goto end;
1213         }
1214
1215         /**
1216          * STEP 17: Add the ACE to the new ACL.
1217          */
1218         if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1219               ((PACE_HEADER) pTempAce)->AceSize)) {
1220            goto end;
1221         }
1222      }
1223   }
1224
1225   /**
1226    * STEP 18: Set permissions
1227    */
1228   if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
1229     DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
1230         goto end;
1231   }
1232
1233   fResult = TRUE;
1234
1235 end:
1236
1237   /**
1238    * STEP 19: Free allocated memory
1239    */
1240   if (pUserSID)
1241      HeapFree(GetProcessHeap(), 0, pUserSID);
1242
1243   if (szDomain)
1244      HeapFree(GetProcessHeap(), 0, szDomain);
1245
1246   if (pFileSD)
1247      HeapFree(GetProcessHeap(), 0, pFileSD);
1248
1249   if (pNewACL)
1250      HeapFree(GetProcessHeap(), 0, pNewACL);
1251
1252   return fResult;
1253 }
1254
1255 char *winErrorStr(const char *prefix, int dwErr)
1256 {
1257   char *err, *ret;
1258   int mem;
1259
1260   if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1261     NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
1262     0, NULL ))
1263   {
1264     err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);
1265   }
1266
1267   mem = strlen(err) + strlen(prefix) + 20;
1268   ret = (char *) malloc(mem);
1269
1270   snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
1271
1272   LocalFree(err);
1273
1274   return ret;
1275 }
1276
1277 /**
1278  * Terminate a process by creating a remote thread within it,
1279  * which proceeds to call ExitProcess() inside that process.
1280  * Safer than TerminateProcess ().
1281  *
1282  * Code is from From http://private-storm.de/2009/08/11/case-terminateprocess/
1283  *
1284  * @param hProcess handle of a process to terminate
1285  * @param uExitCode exit code to use for ExitProcess()
1286  * @param dwTimeout number of ms to wait for the process to terminate
1287  * @return TRUE on success, FALSE on failure (check last error for the code)
1288  */
1289 BOOL
1290 SafeTerminateProcess (HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)
1291 {
1292   DWORD dwTID, dwCode, dwErr = 0;
1293   HANDLE hProcessDup = INVALID_HANDLE_VALUE;
1294   HANDLE hRT = NULL;
1295   HINSTANCE hKernel = GetModuleHandle ("Kernel32");
1296   BOOL bSuccess = FALSE;
1297
1298   BOOL bDup = DuplicateHandle (GetCurrentProcess (), hProcess,
1299       GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS,
1300       FALSE, 0);
1301
1302   /* Detect the special case where the process is
1303    * already dead...
1304    */
1305   if (GetExitCodeProcess (bDup ? hProcessDup : hProcess, &dwCode) &&
1306       (STILL_ACTIVE ==  dwCode))
1307   {
1308     FARPROC pfnExitProc;
1309
1310     pfnExitProc = GetProcAddress (hKernel, "ExitProcess");
1311
1312     hRT = CreateRemoteThread ((bDup) ? hProcessDup : hProcess, NULL, 0,
1313         (LPTHREAD_START_ROUTINE) pfnExitProc, (PVOID) uExitCode, 0, &dwTID);
1314
1315     dwErr = GetLastError ();
1316   }
1317   else
1318   {
1319     dwErr = ERROR_PROCESS_ABORTED;
1320   }
1321
1322   if (hRT)
1323   {
1324     /* Must wait process to terminate to
1325      * guarantee that it has exited...
1326      */
1327     DWORD dwWaitResult = WaitForSingleObject ((bDup) ? hProcessDup : hProcess,
1328         dwTimeout);
1329     if (dwWaitResult == WAIT_TIMEOUT)
1330       dwErr = WAIT_TIMEOUT;
1331     else
1332       dwErr = GetLastError ();
1333
1334     CloseHandle (hRT);
1335     bSuccess = dwErr == NO_ERROR;
1336   }
1337
1338   if (bDup)
1339     CloseHandle (hProcessDup);
1340
1341   SetLastError (dwErr);
1342
1343   return bSuccess;
1344 }
1345
1346 #endif