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