diff options
Diffstat (limited to 'src/util/win.c')
-rw-r--r-- | src/util/win.c | 1365 |
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 | |||
41 | int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows); | ||
42 | |||
43 | #define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \ | ||
44 | union { \ | ||
45 | struct { \ | ||
46 | ULONG Length; \ | ||
47 | DWORD Flags; \ | ||
48 | }; \ | ||
49 | }; | ||
50 | |||
51 | #define _IP_ADAPTER_UNICAST_ADDRESS_BASE \ | ||
52 | SOCKET_ADDRESS Address; \ | ||
53 | IP_PREFIX_ORIGIN PrefixOrigin; \ | ||
54 | IP_SUFFIX_ORIGIN SuffixOrigin; \ | ||
55 | IP_DAD_STATE DadState; \ | ||
56 | ULONG ValidLifetime; \ | ||
57 | ULONG PreferredLifetime; \ | ||
58 | ULONG LeaseLifetime; | ||
59 | |||
60 | #define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \ | ||
61 | UINT8 OnLinkPrefixLength; | ||
62 | |||
63 | |||
64 | #define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix, addition) \ | ||
65 | typedef struct _IP_ADAPTER_UNICAST_ADDRESS ## suffix { \ | ||
66 | _IP_ADAPTER_UNICAST_ADDRESS_HEAD \ | ||
67 | struct _IP_ADAPTER_UNICAST_ADDRESS ## suffix *Next; \ | ||
68 | _IP_ADAPTER_UNICAST_ADDRESS_BASE \ | ||
69 | addition \ | ||
70 | } IP_ADAPTER_UNICAST_ADDRESS ## suffix, *PIP_ADAPTER_UNICAST_ADDRESS ## suffix; | ||
71 | |||
72 | /* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */ | ||
73 | _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA, _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA) | ||
74 | |||
75 | |||
76 | #ifndef __MINGW64_VERSION_MAJOR | ||
77 | typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS { | ||
78 | union { | ||
79 | ULONGLONG Alignment; | ||
80 | struct { | ||
81 | ULONG Length; | ||
82 | DWORD Reserved; | ||
83 | }; | ||
84 | }; | ||
85 | struct _IP_ADAPTER_WINS_SERVER_ADDRESS *Next; | ||
86 | SOCKET_ADDRESS Address; | ||
87 | } IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH; | ||
88 | |||
89 | typedef struct _IP_ADAPTER_GATEWAY_ADDRESS { | ||
90 | union { | ||
91 | ULONGLONG Alignment; | ||
92 | struct { | ||
93 | ULONG Length; | ||
94 | DWORD Reserved; | ||
95 | }; | ||
96 | }; | ||
97 | struct _IP_ADAPTER_GATEWAY_ADDRESS *Next; | ||
98 | SOCKET_ADDRESS Address; | ||
99 | } IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH; | ||
100 | #endif | ||
101 | |||
102 | typedef UINT32 NET_IF_COMPARTMENT_ID; | ||
103 | typedef GUID NET_IF_NETWORK_GUID; | ||
104 | |||
105 | #ifndef __MINGW64_VERSION_MAJOR | ||
106 | typedef enum _NET_IF_CONNECTION_TYPE { | ||
107 | NET_IF_CONNECTION_DEDICATED = 1, | ||
108 | NET_IF_CONNECTION_PASSIVE, | ||
109 | NET_IF_CONNECTION_DEMAND, | ||
110 | NET_IF_CONNECTION_MAXIMUM | ||
111 | } NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE; | ||
112 | |||
113 | typedef enum { | ||
114 | TUNNEL_TYPE_NONE = 0, | ||
115 | TUNNEL_TYPE_OTHER, | ||
116 | TUNNEL_TYPE_DIRECT, | ||
117 | TUNNEL_TYPE_6TO4, | ||
118 | TUNNEL_TYPE_ISATAP, | ||
119 | TUNNEL_TYPE_TEREDO, | ||
120 | TUNNEL_TYPE_IPHTTPS | ||
121 | } TUNNEL_TYPE, *PTUNNEL_TYPE; | ||
122 | #endif | ||
123 | |||
124 | /* | ||
125 | A DUID consists of a two-octet type code represented in network byte | ||
126 | order, followed by a variable number of octets that make up the | ||
127 | actual identifier. A DUID can be no more than 128 octets long (not | ||
128 | including the type code). | ||
129 | */ | ||
130 | #define MAX_DHCPV6_DUID_LENGTH 130 | ||
131 | |||
132 | #ifndef __MINGW64_VERSION_MAJOR | ||
133 | typedef union _NET_LUID { | ||
134 | ULONG64 Value; | ||
135 | struct { | ||
136 | ULONG64 Reserved : 24; | ||
137 | ULONG64 NetLuidIndex : 24; | ||
138 | ULONG64 IfType : 16; | ||
139 | } Info; | ||
140 | } NET_LUID, *PNET_LUID, IF_LUID; | ||
141 | |||
142 | #define MAX_DNS_SUFFIX_STRING_LENGTH 246 | ||
143 | |||
144 | typedef struct _IP_ADAPTER_DNS_SUFFIX { | ||
145 | struct _IP_ADAPTER_DNS_SUFFIX *Next; | ||
146 | WCHAR String[MAX_DNS_SUFFIX_STRING_LENGTH]; | ||
147 | } IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX; | ||
148 | #endif | ||
149 | |||
150 | |||
151 | |||
152 | #define _IP_ADAPTER_ADDRESSES_HEAD \ | ||
153 | union { \ | ||
154 | ULONGLONG Alignment; \ | ||
155 | struct { \ | ||
156 | ULONG Length; \ | ||
157 | DWORD IfIndex; \ | ||
158 | }; \ | ||
159 | }; | ||
160 | |||
161 | #define _IP_ADAPTER_ADDRESSES_BASE \ | ||
162 | PCHAR AdapterName; \ | ||
163 | PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress; \ | ||
164 | PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress; \ | ||
165 | PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress; \ | ||
166 | PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress; \ | ||
167 | PWCHAR DnsSuffix; \ | ||
168 | PWCHAR Description; \ | ||
169 | PWCHAR FriendlyName; \ | ||
170 | BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \ | ||
171 | DWORD PhysicalAddressLength; \ | ||
172 | DWORD Flags; \ | ||
173 | DWORD Mtu; \ | ||
174 | DWORD IfType; \ | ||
175 | IF_OPER_STATUS OperStatus; | ||
176 | |||
177 | #define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \ | ||
178 | DWORD Ipv6IfIndex; \ | ||
179 | DWORD ZoneIndices[16]; \ | ||
180 | PIP_ADAPTER_PREFIX FirstPrefix; \ | ||
181 | |||
182 | |||
183 | #define _IP_ADAPTER_ADDRESSES_ADD_VISTA \ | ||
184 | _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \ | ||
185 | ULONG64 TransmitLinkSpeed; \ | ||
186 | ULONG64 ReceiveLinkSpeed; \ | ||
187 | PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \ | ||
188 | PIP_ADAPTER_GATEWAY_ADDRESS_LH FirstGatewayAddress; \ | ||
189 | ULONG Ipv4Metric; \ | ||
190 | ULONG Ipv6Metric; \ | ||
191 | IF_LUID Luid; \ | ||
192 | SOCKET_ADDRESS Dhcpv4Server; \ | ||
193 | NET_IF_COMPARTMENT_ID CompartmentId; \ | ||
194 | NET_IF_NETWORK_GUID NetworkGuid; \ | ||
195 | NET_IF_CONNECTION_TYPE ConnectionType; \ | ||
196 | TUNNEL_TYPE TunnelType; \ | ||
197 | SOCKET_ADDRESS Dhcpv6Server; \ | ||
198 | BYTE Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \ | ||
199 | ULONG Dhcpv6ClientDuidLength; \ | ||
200 | ULONG Dhcpv6Iaid; | ||
201 | |||
202 | #define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \ | ||
203 | _IP_ADAPTER_ADDRESSES_ADD_VISTA \ | ||
204 | PIP_ADAPTER_DNS_SUFFIX FirstDnsSuffix; | ||
205 | |||
206 | #define _IP_ADAPTER_ADDRESSES_DEFINE(suffix, addition) \ | ||
207 | typedef struct _IP_ADAPTER_ADDRESSES ## suffix { \ | ||
208 | _IP_ADAPTER_ADDRESSES_HEAD \ | ||
209 | struct _IP_ADAPTER_ADDRESSES ## suffix *Next; \ | ||
210 | _IP_ADAPTER_ADDRESSES_BASE \ | ||
211 | addition \ | ||
212 | } IP_ADAPTER_ADDRESSES ## suffix, *PIP_ADAPTER_ADDRESSES ## suffix; | ||
213 | |||
214 | |||
215 | /* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */ | ||
216 | _IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1, _IP_ADAPTER_ADDRESSES_ADD_XPSP1) | ||
217 | _IP_ADAPTER_ADDRESSES_DEFINE(_VISTA, _IP_ADAPTER_ADDRESSES_ADD_VISTA) | ||
218 | _IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1, _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1) | ||
219 | |||
220 | static int | ||
221 | EnumNICs_IPv6_get_ifs_count(_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 | |||
236 | static int | ||
237 | EnumNICs_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 | |||
263 | static int | ||
264 | EnumNICs_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 | |||
302 | int | ||
303 | EnumNICs2(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 | } | ||
347 | error: | ||
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 | */ | ||
363 | int | ||
364 | EnumNICs3(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 | |||
625 | void | ||
626 | EnumNICs3_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 | */ | ||
639 | int | ||
640 | ListNICs(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 | */ | ||
667 | int 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 | */ | ||
713 | int | ||
714 | UninstallService(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 | |||
737 | closeSCM: | ||
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 | */ | ||
748 | void | ||
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 | */ | ||
773 | NTSTATUS | ||
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 | */ | ||
807 | BOOL | ||
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 | |||
854 | end: | ||
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 | */ | ||
875 | NTSTATUS | ||
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 | */ | ||
916 | int | ||
917 | CreateServiceAccount(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 | */ | ||
972 | BOOL 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 | |||
1254 | end: | ||
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 | |||
1274 | char *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 | */ | ||
1308 | BOOL | ||
1309 | SafeTerminateProcess(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 | ||