aboutsummaryrefslogtreecommitdiff
path: root/src/util/win.c
diff options
context:
space:
mode:
authorLRN <lrn1986@gmail.com>2012-09-27 22:55:39 +0000
committerLRN <lrn1986@gmail.com>2012-09-27 22:55:39 +0000
commita202cf2498161dae7e2060d7b8251303b1c06a38 (patch)
tree0e5365e90c6f4b2005f0ff15e0e489d95714e864 /src/util/win.c
parent222046dfeacea9876ec30f6d2c88de0acf62632b (diff)
downloadgnunet-a202cf2498161dae7e2060d7b8251303b1c06a38.tar.gz
gnunet-a202cf2498161dae7e2060d7b8251303b1c06a38.zip
W32-specific platform stuff is now pure C
Diffstat (limited to 'src/util/win.c')
-rw-r--r--src/util/win.c1329
1 files changed, 1329 insertions, 0 deletions
diff --git a/src/util/win.c b/src/util/win.c
new file mode 100644
index 000000000..18e3e80c0
--- /dev/null
+++ b/src/util/win.c
@@ -0,0 +1,1329 @@
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
41int 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) \
65typedef 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
76typedef 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
88typedef 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
100typedef UINT32 NET_IF_COMPARTMENT_ID;
101typedef GUID NET_IF_NETWORK_GUID;
102
103typedef 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
110typedef 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/*
121A 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
128typedef 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
139typedef 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) \
201typedef 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
214static int
215EnumNICs_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
229static int
230EnumNICs_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
255static int
256EnumNICs_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
293int
294EnumNICs2 (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 }
337error:
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 */
352int
353EnumNICs3 (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
616void
617EnumNICs3_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 */
630int
631ListNICs (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 */
658int 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 */
703int 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
724closeSCM:
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 */
735void _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 */
759NTSTATUS _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 */
792BOOL _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
838end:
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 */
859NTSTATUS _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 */
898int 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 */
954BOOL 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
1218end:
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
1238char *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 */
1272BOOL
1273SafeTerminateProcess (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