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