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