2 This file is part of GNUnet.
\r
3 (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors)
\r
5 GNUnet is free software; you can redistribute it and/or modify
\r
6 it under the terms of the GNU General Public License as published
\r
7 by the Free Software Foundation; either version 2, or (at your
\r
8 option) any later version.
\r
10 GNUnet is distributed in the hope that it will be useful, but
\r
11 WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
13 General Public License for more details.
\r
15 You should have received a copy of the GNU General Public License
\r
16 along with GNUnet; see the file COPYING. If not, write to the
\r
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
\r
18 Boston, MA 02111-1307, USA.
\r
23 * @brief Helper functions for MS Windows in C++
\r
24 * @author Nils Durner
\r
30 #include "winproc.h"
\r
31 #include "platform.h"
\r
32 #include "gnunet_common.h"
\r
33 #include "gnunet_connection_lib.h"
\r
36 using namespace std;
\r
39 #ifndef INHERITED_ACE
\r
40 #define INHERITED_ACE 0x10
\r
45 int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);
\r
47 #define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \
\r
55 #define _IP_ADAPTER_UNICAST_ADDRESS_BASE \
\r
56 SOCKET_ADDRESS Address; \
\r
57 IP_PREFIX_ORIGIN PrefixOrigin; \
\r
58 IP_SUFFIX_ORIGIN SuffixOrigin; \
\r
59 IP_DAD_STATE DadState; \
\r
60 ULONG ValidLifetime; \
\r
61 ULONG PreferredLifetime; \
\r
62 ULONG LeaseLifetime;
\r
64 #define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \
\r
65 UINT8 OnLinkPrefixLength;
\r
68 #define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix,addition) \
\r
69 typedef struct _IP_ADAPTER_UNICAST_ADDRESS##suffix { \
\r
70 _IP_ADAPTER_UNICAST_ADDRESS_HEAD \
\r
71 struct _IP_ADAPTER_UNICAST_ADDRESS##suffix *Next; \
\r
72 _IP_ADAPTER_UNICAST_ADDRESS_BASE \
\r
74 } IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix;
\r
76 /* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */
\r
77 _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA)
\r
80 typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS {
\r
82 ULONGLONG Alignment;
\r
88 struct _IP_ADAPTER_WINS_SERVER_ADDRESS *Next;
\r
89 SOCKET_ADDRESS Address;
\r
90 } IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH;
\r
92 typedef struct _IP_ADAPTER_GATEWAY_ADDRESS {
\r
94 ULONGLONG Alignment;
\r
100 struct _IP_ADAPTER_GATEWAY_ADDRESS *Next;
\r
101 SOCKET_ADDRESS Address;
\r
102 } IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH;
\r
104 typedef UINT32 NET_IF_COMPARTMENT_ID;
\r
105 typedef GUID NET_IF_NETWORK_GUID;
\r
107 typedef enum _NET_IF_CONNECTION_TYPE {
\r
108 NET_IF_CONNECTION_DEDICATED = 1,
\r
109 NET_IF_CONNECTION_PASSIVE,
\r
110 NET_IF_CONNECTION_DEMAND,
\r
111 NET_IF_CONNECTION_MAXIMUM
\r
112 } NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE;
\r
115 TUNNEL_TYPE_NONE = 0,
\r
117 TUNNEL_TYPE_DIRECT,
\r
119 TUNNEL_TYPE_ISATAP,
\r
120 TUNNEL_TYPE_TEREDO,
\r
121 TUNNEL_TYPE_IPHTTPS
\r
122 } TUNNEL_TYPE, *PTUNNEL_TYPE;
\r
125 A DUID consists of a two-octet type code represented in network byte
\r
126 order, followed by a variable number of octets that make up the
\r
127 actual identifier. A DUID can be no more than 128 octets long (not
\r
128 including the type code).
\r
130 #define MAX_DHCPV6_DUID_LENGTH 130
\r
132 typedef union _NET_LUID {
\r
135 ULONG64 Reserved :24;
\r
136 ULONG64 NetLuidIndex :24;
\r
137 ULONG64 IfType :16;
\r
139 } NET_LUID, *PNET_LUID, IF_LUID;
\r
141 #define MAX_DNS_SUFFIX_STRING_LENGTH 246
\r
143 typedef struct _IP_ADAPTER_DNS_SUFFIX {
\r
144 struct _IP_ADAPTER_DNS_SUFFIX *Next;
\r
145 WCHAR String[MAX_DNS_SUFFIX_STRING_LENGTH];
\r
146 } IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX;
\r
150 #define _IP_ADAPTER_ADDRESSES_HEAD \
\r
152 ULONGLONG Alignment; \
\r
159 #define _IP_ADAPTER_ADDRESSES_BASE \
\r
160 PCHAR AdapterName; \
\r
161 PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress; \
\r
162 PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress; \
\r
163 PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress; \
\r
164 PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress; \
\r
165 PWCHAR DnsSuffix; \
\r
166 PWCHAR Description; \
\r
167 PWCHAR FriendlyName; \
\r
168 BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \
\r
169 DWORD PhysicalAddressLength; \
\r
173 IF_OPER_STATUS OperStatus;
\r
175 #define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \
\r
176 DWORD Ipv6IfIndex; \
\r
177 DWORD ZoneIndices[16]; \
\r
178 PIP_ADAPTER_PREFIX FirstPrefix; \
\r
181 #define _IP_ADAPTER_ADDRESSES_ADD_VISTA \
\r
182 _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \
\r
183 ULONG64 TransmitLinkSpeed; \
\r
184 ULONG64 ReceiveLinkSpeed; \
\r
185 PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \
\r
186 PIP_ADAPTER_GATEWAY_ADDRESS_LH FirstGatewayAddress; \
\r
187 ULONG Ipv4Metric; \
\r
188 ULONG Ipv6Metric; \
\r
190 SOCKET_ADDRESS Dhcpv4Server; \
\r
191 NET_IF_COMPARTMENT_ID CompartmentId; \
\r
192 NET_IF_NETWORK_GUID NetworkGuid; \
\r
193 NET_IF_CONNECTION_TYPE ConnectionType; \
\r
194 TUNNEL_TYPE TunnelType; \
\r
195 SOCKET_ADDRESS Dhcpv6Server; \
\r
196 BYTE Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \
\r
197 ULONG Dhcpv6ClientDuidLength; \
\r
200 #define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \
\r
201 _IP_ADAPTER_ADDRESSES_ADD_VISTA \
\r
202 PIP_ADAPTER_DNS_SUFFIX FirstDnsSuffix;
\r
204 #define _IP_ADAPTER_ADDRESSES_DEFINE(suffix,addition) \
\r
205 typedef struct _IP_ADAPTER_ADDRESSES##suffix { \
\r
206 _IP_ADAPTER_ADDRESSES_HEAD \
\r
207 struct _IP_ADAPTER_ADDRESSES##suffix *Next; \
\r
208 _IP_ADAPTER_ADDRESSES_BASE \
\r
210 } IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix;
\r
213 /* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */
\r
214 _IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1,_IP_ADAPTER_ADDRESSES_ADD_XPSP1)
\r
215 _IP_ADAPTER_ADDRESSES_DEFINE(_VISTA,_IP_ADAPTER_ADDRESSES_ADD_VISTA)
\r
216 _IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1,_IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1)
\r
219 EnumNICs_IPv6_get_ifs_count (SOCKET s)
\r
221 DWORD dwret = 0, err;
\r
223 iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0,
\r
224 &dwret, NULL, NULL);
\r
225 err = GetLastError ();
\r
226 if (iret == SOCKET_ERROR && err == WSAEFAULT)
\r
228 else if (iret == 0)
\r
230 return GNUNET_SYSERR;
\r
234 EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size)
\r
238 iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size,
\r
239 &dwret, NULL, NULL);
\r
241 if (iret != 0 || dwret != size)
\r
243 /* It's supposed to succeed! And size should be the same */
\r
244 return GNUNET_SYSERR;
\r
249 #undef GNUNET_malloc
\r
250 #define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \
\r
251 HEAP_GENERATE_EXCEPTIONS, a)
\r
254 #define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a)
\r
256 #undef GNUNET_free_non_null
\r
257 #define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0)
\r
260 EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size)
\r
265 INTERFACE_INFO *ii = NULL;
\r
266 DWORD ii_size = sizeof (INTERFACE_INFO) * 15;
\r
269 if (ii_size >= sizeof (INTERFACE_INFO) * 1000)
\r
270 return GNUNET_SYSERR;
\r
271 ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size);
\r
273 iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size,
\r
274 &dwret, NULL, NULL);
\r
275 error = GetLastError ();
\r
276 if (iret == SOCKET_ERROR)
\r
278 if (error == WSAEFAULT)
\r
285 return GNUNET_SYSERR;
\r
294 return GNUNET_SYSERR;
\r
298 EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6)
\r
301 SOCKET s4 = INVALID_SOCKET, s6 = INVALID_SOCKET;
\r
302 DWORD dwret1 = 0, dwret2;
\r
304 int ifs4len = 0, ifs6len = 0;
\r
305 INTERFACE_INFO *interfaces4 = NULL;
\r
306 SOCKET_ADDRESS_LIST *interfaces6 = NULL;
\r
308 s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
\r
309 err1 = GetLastError ();
\r
311 s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
\r
312 err2 = GetLastError ();
\r
313 if (s6 != INVALID_SOCKET)
\r
315 ifs6len = EnumNICs_IPv6_get_ifs_count (s6);
\r
318 interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);
\r
319 result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;
\r
322 s6 = INVALID_SOCKET;
\r
325 if (s4 != INVALID_SOCKET)
\r
327 result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;
\r
329 s4 = INVALID_SOCKET;
\r
331 if (ifs6len + ifs4len == 0)
\r
336 *ifs4 = interfaces4;
\r
337 *ifs4_len = ifs4len;
\r
338 *ifs6 = interfaces6;
\r
342 if (interfaces4 != NULL)
\r
343 GNUNET_free (interfaces4);
\r
344 if (interfaces6 != NULL)
\r
345 GNUNET_free (interfaces6);
\r
346 if (s4 != INVALID_SOCKET)
\r
348 if (s6 != INVALID_SOCKET)
\r
350 return GNUNET_SYSERR;
\r
354 * Returns GNUNET_OK on OK, GNUNET_SYSERR on error
\r
357 EnumNICs3 (struct EnumNICs3_results **results, int *results_count)
\r
359 DWORD dwRetVal = 0;
\r
361 ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |
\r
362 GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
\r
363 struct sockaddr_in6 examplecom6;
\r
365 DWORD best_interface = 0;
\r
366 DWORD best_interface6 = 0;
\r
369 INTERFACE_INFO *interfaces4 = NULL;
\r
370 int interfaces4_len = 0;
\r
371 SOCKET_ADDRESS_LIST *interfaces6 = NULL;
\r
373 unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
\r
374 IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;
\r
375 IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
\r
377 if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)
\r
378 == ERROR_BUFFER_OVERFLOW)
\r
380 GNUNET_free (pAddresses);
\r
381 pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
\r
384 dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);
\r
386 if (dwRetVal != NO_ERROR)
\r
388 GNUNET_free (pAddresses);
\r
389 return GNUNET_SYSERR;
\r
392 if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))
\r
396 /* Enumerate NICs using WSAIoctl() */
\r
397 if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))
\r
399 GNUNET_free (pAddresses);
\r
400 return GNUNET_SYSERR;
\r
404 examplecom = inet_addr("192.0.34.166"); /* www.example.com */
\r
405 if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)
\r
406 best_interface = 0;
\r
408 if (GNGetBestInterfaceEx != NULL)
\r
410 examplecom6.sin6_family = AF_INET6;
\r
411 examplecom6.sin6_port = 0;
\r
412 examplecom6.sin6_flowinfo = 0;
\r
413 examplecom6.sin6_scope_id = 0;
\r
414 inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",
\r
415 (struct sockaddr *) &examplecom6.sin6_addr);
\r
416 dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,
\r
418 if (dwRetVal != NO_ERROR)
\r
419 best_interface6 = 0;
\r
422 /* Give IPv6 a priority */
\r
423 if (best_interface6 != 0)
\r
424 best_interface = best_interface6;
\r
427 for (pCurrentAddress = pAddresses;
\r
428 pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
\r
430 if (pCurrentAddress->OperStatus == IfOperStatusUp)
\r
432 IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
\r
433 for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
\r
434 unicast = unicast->Next)
\r
436 if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||
\r
437 unicast->Address.lpSockaddr->sa_family == AF_INET6) &&
\r
438 (unicast->DadState == IpDadStateDeprecated ||
\r
439 unicast->DadState == IpDadStatePreferred))
\r
448 *results_count = 0;
\r
449 GNUNET_free (pAddresses);
\r
450 GNUNET_free_non_null (interfaces4);
\r
451 GNUNET_free_non_null (interfaces6);
\r
455 *results = (struct EnumNICs3_results *) GNUNET_malloc (
\r
456 sizeof (struct EnumNICs3_results) * count);
\r
457 *results_count = count;
\r
460 for (pCurrentAddress = pAddresses;
\r
461 pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
\r
463 struct EnumNICs3_results *r;
\r
464 IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
\r
465 if (pCurrentAddress->OperStatus != IfOperStatusUp)
\r
467 for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
\r
468 unicast = unicast->Next)
\r
471 int mask_length = -1;
\r
472 char dst[INET6_ADDRSTRLEN + 1];
\r
474 if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&
\r
475 unicast->Address.lpSockaddr->sa_family != AF_INET6) ||
\r
476 (unicast->DadState != IpDadStateDeprecated &&
\r
477 unicast->DadState != IpDadStatePreferred))
\r
480 r = &(*results)[count];
\r
482 if (pCurrentAddress->IfIndex > 0 &&
\r
483 pCurrentAddress->IfIndex == best_interface &&
\r
484 unicast->Address.lpSockaddr->sa_family == AF_INET)
\r
486 else if (pCurrentAddress->Ipv6IfIndex > 0 &&
\r
487 pCurrentAddress->Ipv6IfIndex == best_interface6 &&
\r
488 unicast->Address.lpSockaddr->sa_family == AF_INET6)
\r
493 /* Don't choose default interface twice */
\r
495 best_interface = best_interface6 = 0;
\r
499 memcpy (&r->address, unicast->Address.lpSockaddr,
\r
500 unicast->Address.iSockaddrLength);
\r
501 memset (&r->mask, 0, sizeof (struct sockaddr));
\r
502 mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->
\r
503 OnLinkPrefixLength;
\r
504 /* OnLinkPrefixLength is the number of leading 1s in the mask.
\r
505 * OnLinkPrefixLength is available on Vista and later (hence use_enum2).
\r
507 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
\r
509 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
\r
510 for (i = 0; i < mask_length; i++)
\r
511 ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
\r
513 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
\r
515 struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;
\r
516 struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;
\r
517 for (i = 0; i < mask_length; i++)
\r
518 ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
\r
519 memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
\r
520 for (i = mask_length; i < 128; i++)
\r
521 ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
\r
523 r->flags |= ENUMNICS3_MASK_OK;
\r
528 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
\r
530 for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)
\r
532 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
\r
533 if (memcpy (&interfaces4[i].iiAddress.Address,
\r
534 unicast->Address.lpSockaddr,
\r
535 unicast->Address.iSockaddrLength) != 0)
\r
538 memcpy (&r->address, &interfaces4[i].iiAddress.Address,
\r
539 sizeof (struct sockaddr_in));
\r
540 memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,
\r
541 sizeof (struct sockaddr_in));
\r
542 for (mask_length = 0;
\r
543 ((unsigned char *) &m->sin_addr)[mask_length / 8] &
\r
544 0x80 >> (mask_length % 8); mask_length++)
\r
547 r->flags |= ENUMNICS3_MASK_OK;
\r
550 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
\r
553 interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
\r
556 if (memcpy (interfaces6->Address[i].lpSockaddr,
\r
557 unicast->Address.lpSockaddr,
\r
558 unicast->Address.iSockaddrLength) != 0)
\r
561 memcpy (&r->address, interfaces6->Address[i].lpSockaddr,
\r
562 sizeof (struct sockaddr_in6));
\r
563 /* TODO: Find a way to reliably get network mask for IPv6 on XP */
\r
564 memset (&r->mask, 0, sizeof (struct sockaddr));
\r
565 r->flags &= ~ENUMNICS3_MASK_OK;
\r
573 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
\r
575 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
\r
576 struct sockaddr_in *a = (struct sockaddr_in *) &r->address;
\r
577 /* copy address to broadcast, then flip all the trailing bits not
\r
578 * falling under netmask to 1,
\r
579 * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.
\r
581 memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
\r
582 for (i = mask_length; i < 32; i++)
\r
583 ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
\r
584 r->flags |= ENUMNICS3_BCAST_OK;
\r
585 r->addr_size = sizeof (struct sockaddr_in);
\r
586 inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);
\r
588 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
\r
590 struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;
\r
591 /* for IPv6 broadcast is not defined, zero it down */
\r
592 memset (&r->broadcast, 0, sizeof (struct sockaddr));
\r
593 r->flags &= ~ENUMNICS3_BCAST_OK;
\r
594 r->addr_size = sizeof (struct sockaddr_in6);
\r
595 inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);
\r
599 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
\r
600 "%S (%s", pCurrentAddress->FriendlyName, dst);
\r
601 for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)
\r
602 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
\r
603 "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);
\r
604 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");
\r
605 r->pretty_name[1000] = '\0';
\r
612 GNUNET_free_non_null (interfaces4);
\r
613 GNUNET_free_non_null (interfaces6);
\r
616 GNUNET_free (pAddresses);
\r
621 EnumNICs3_free (struct EnumNICs3_results *r)
\r
623 GNUNET_free_non_null (r);
\r
628 * Lists all network interfaces in a combo box
\r
629 * Used by the basic GTK configurator
\r
631 * @param callback function to call for each NIC
\r
632 * @param callback_cls closure for callback
\r
635 ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)
\r
639 struct EnumNICs3_results *results = NULL;
\r
642 r = EnumNICs3 (&results, &results_count);
\r
643 if (r != GNUNET_OK)
\r
646 for (i = 0; i < results_count; i++)
\r
647 callback (callback_cls, results[i].pretty_name, results[i].is_default);
\r
648 GNUNET_free_non_null (results);
\r
653 * @brief Installs the Windows service
\r
654 * @param servicename name of the service as diplayed by the SCM
\r
655 * @param application path to the application binary
\r
656 * @param username the name of the service's user account
\r
657 * @returns 0 on success
\r
658 * 1 if the Windows version doesn't support services
\r
659 * 2 if the SCM could not be opened
\r
660 * 3 if the service could not be created
\r
662 int InstallAsService(char *servicename, char *application, char *username)
\r
664 SC_HANDLE hManager, hService;
\r
665 char szEXE[_MAX_PATH + 17] = "\"";
\r
668 if (! GNOpenSCManager)
\r
671 plibc_conv_to_win_path(application, szEXE + 1);
\r
672 strcat(szEXE, "\" --win-service");
\r
673 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
\r
679 user = (char *) malloc(strlen(username) + 3);
\r
680 sprintf(user, ".\\%s", username);
\r
683 hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
\r
684 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
\r
685 NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
\r
693 GNCloseServiceHandle(hService);
\r
699 * @brief Uninstall Windows service
\r
700 * @param servicename name of the service to delete
\r
701 * @returns 0 on success
\r
702 * 1 if the Windows version doesn't support services
\r
703 * 2 if the SCM could not be openend
\r
704 * 3 if the service cannot be accessed
\r
705 * 4 if the service cannot be deleted
\r
707 int UninstallService(char *servicename)
\r
709 SC_HANDLE hManager, hService;
\r
711 if (! GNOpenSCManager)
\r
714 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
\r
718 if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
\r
719 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
\r
724 if (! GNDeleteService(hService))
\r
725 if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
\r
729 GNCloseServiceHandle(hService);
\r
735 * @author Scott Field, Microsoft
\r
736 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
739 void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
\r
741 DWORD StringLength;
\r
745 LsaString->Buffer = NULL;
\r
746 LsaString->Length = 0;
\r
747 LsaString->MaximumLength = 0;
\r
751 StringLength = wcslen(String);
\r
752 LsaString->Buffer = String;
\r
753 LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
\r
754 LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
\r
759 * @author Scott Field, Microsoft
\r
760 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
763 NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
\r
765 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
\r
766 LSA_UNICODE_STRING ServerString;
\r
767 PLSA_UNICODE_STRING Server = NULL;
\r
769 /* Always initialize the object attributes to all zeroes. */
\r
770 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
\r
772 if(ServerName != NULL)
\r
774 /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
\r
775 _InitLsaString(&ServerString, ServerName);
\r
776 Server = &ServerString;
\r
779 /* Attempt to open the policy. */
\r
780 return GNLsaOpenPolicy(Server,
\r
781 &ObjectAttributes, DesiredAccess, PolicyHandle);
\r
785 * @brief Obtain a SID representing the supplied account on the supplied system
\r
786 * @return TRUE on success, FALSE on failure
\r
787 * @author Scott Field, Microsoft
\r
789 * @remarks A buffer is allocated which contains the SID representing the
\r
790 * supplied account. This buffer should be freed when it is no longer
\r
791 * needed by calling\n
\r
792 * HeapFree(GetProcessHeap(), 0, buffer)
\r
793 * @remarks Call GetLastError() to obtain extended error information.
\r
794 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
796 BOOL _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)
\r
798 LPTSTR ReferencedDomain = NULL;
\r
799 DWORD cbSid = 128; /* initial allocation attempt */
\r
800 DWORD cchReferencedDomain = 16; /* initial allocation size */
\r
801 SID_NAME_USE peUse;
\r
802 BOOL bSuccess = FALSE; /* assume this function will fail */
\r
804 /* initial memory allocations */
\r
805 if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
\r
808 if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
\r
810 cchReferencedDomain *
\r
811 sizeof (TCHAR))) == NULL)
\r
814 /* Obtain the SID of the specified account on the specified system. */
\r
815 while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
\r
816 AccountName, /* account to lookup */
\r
817 *Sid, /* SID of interest */
\r
818 &cbSid, /* size of SID */
\r
819 ReferencedDomain, /* domain account was found on */
\r
820 &cchReferencedDomain, &peUse))
\r
822 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
\r
824 /* reallocate memory */
\r
825 if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
\r
828 if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
\r
831 cchReferencedDomain
\r
832 * sizeof (TCHAR))) == NULL)
\r
839 /* Indicate success. */
\r
843 /* Cleanup and indicate failure, if appropriate. */
\r
844 HeapFree (GetProcessHeap (), 0, ReferencedDomain);
\r
850 HeapFree (GetProcessHeap (), 0, *Sid);
\r
859 * @author Scott Field, Microsoft
\r
860 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
863 NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
\r
864 PSID AccountSid, /* SID to grant privilege to */
\r
865 LPWSTR PrivilegeName, /* privilege to grant (Unicode) */
\r
866 BOOL bEnable /* enable or disable */
\r
869 LSA_UNICODE_STRING PrivilegeString;
\r
871 /* Create a LSA_UNICODE_STRING for the privilege name. */
\r
872 _InitLsaString(&PrivilegeString, PrivilegeName);
\r
874 /* grant or revoke the privilege, accordingly */
\r
879 i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */
\r
880 AccountSid, /* target SID */
\r
881 &PrivilegeString, /* privileges */
\r
882 1 /* privilege count */
\r
887 return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */
\r
888 AccountSid, /* target SID */
\r
889 FALSE, /* do not disable all rights */
\r
890 &PrivilegeString, /* privileges */
\r
891 1 /* privilege count */
\r
897 * @brief Create a Windows service account
\r
898 * @return 0 on success, > 0 otherwise
\r
899 * @param pszName the name of the account
\r
900 * @param pszDesc description of the account
\r
902 int CreateServiceAccount(const char *pszName, const char *pszDesc)
\r
905 USER_INFO_1008 ui2;
\r
906 NET_API_STATUS nStatus;
\r
907 wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
\r
909 LSA_HANDLE hPolicy;
\r
912 if (! GNNetUserAdd)
\r
914 mbstowcs(wszName, pszName, strlen(pszName) + 1);
\r
915 mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
\r
917 memset(&ui, 0, sizeof(ui));
\r
918 ui.usri1_name = wszName;
\r
919 ui.usri1_password = wszName; /* account is locked anyway */
\r
920 ui.usri1_priv = USER_PRIV_USER;
\r
921 ui.usri1_comment = wszDesc;
\r
922 ui.usri1_flags = UF_SCRIPT;
\r
924 nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
\r
926 if (nStatus != NERR_Success && nStatus != NERR_UserExists)
\r
929 ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
\r
930 GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
\r
932 if (_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy) !=
\r
936 _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);
\r
938 if (_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE) != STATUS_SUCCESS)
\r
941 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);
\r
942 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);
\r
943 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);
\r
945 GNLsaClose(hPolicy);
\r
951 * @brief Grant permission to a file
\r
952 * @param lpszFileName the name of the file or directory
\r
953 * @param lpszAccountName the user account
\r
954 * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
\r
955 * @return TRUE on success
\r
956 * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
\r
958 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
\r
959 DWORD dwAccessMask)
\r
961 /* SID variables. */
\r
962 SID_NAME_USE snuType;
\r
963 TCHAR * szDomain = NULL;
\r
964 DWORD cbDomain = 0;
\r
965 LPVOID pUserSID = NULL;
\r
966 DWORD cbUserSID = 0;
\r
968 /* File SD variables. */
\r
969 PSECURITY_DESCRIPTOR pFileSD = NULL;
\r
970 DWORD cbFileSD = 0;
\r
972 /* New SD variables. */
\r
973 SECURITY_DESCRIPTOR newSD;
\r
975 /* ACL variables. */
\r
978 BOOL fDaclDefaulted;
\r
979 ACL_SIZE_INFORMATION AclInfo;
\r
981 /* New ACL variables. */
\r
982 PACL pNewACL = NULL;
\r
983 DWORD cbNewACL = 0;
\r
985 /* Temporary ACE. */
\r
986 LPVOID pTempAce = NULL;
\r
987 UINT CurrentAceIndex = 0;
\r
989 UINT newAceIndex = 0;
\r
991 /* Assume function will fail. */
\r
992 BOOL fResult = FALSE;
\r
995 SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
\r
998 * STEP 1: Get SID of the account name specified.
\r
1000 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
\r
1001 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
\r
1003 /* API should have failed with insufficient buffer. */
\r
1006 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
\r
1010 pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
\r
1015 szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
\r
1020 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
\r
1021 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
\r
1022 if (!fAPISuccess) {
\r
1027 * STEP 2: Get security descriptor (SD) of the file specified.
\r
1029 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
\r
1030 secInfo, pFileSD, 0, &cbFileSD);
\r
1032 /* API should have failed with insufficient buffer. */
\r
1035 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
\r
1039 pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
\r
1045 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
\r
1046 secInfo, pFileSD, cbFileSD, &cbFileSD);
\r
1047 if (!fAPISuccess) {
\r
1052 * STEP 3: Initialize new SD.
\r
1054 if (!GNInitializeSecurityDescriptor(&newSD,
\r
1055 SECURITY_DESCRIPTOR_REVISION)) {
\r
1060 * STEP 4: Get DACL from the old SD.
\r
1062 if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
\r
1063 &fDaclDefaulted)) {
\r
1068 * STEP 5: Get size information for DACL.
\r
1070 AclInfo.AceCount = 0; // Assume NULL DACL.
\r
1071 AclInfo.AclBytesFree = 0;
\r
1072 AclInfo.AclBytesInUse = sizeof(ACL);
\r
1075 fDaclPresent = FALSE;
\r
1077 /* If not NULL DACL, gather size information from DACL. */
\r
1078 if (fDaclPresent) {
\r
1080 if (!GNGetAclInformation(pACL, &AclInfo,
\r
1081 sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
\r
1087 * STEP 6: Compute size needed for the new ACL.
\r
1089 cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
\r
1090 + GetLengthSid(pUserSID) - sizeof(DWORD);
\r
1093 * STEP 7: Allocate memory for new ACL.
\r
1095 pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
\r
1101 * STEP 8: Initialize the new ACL.
\r
1103 if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
\r
1108 * STEP 9 If DACL is present, copy all the ACEs from the old DACL
\r
1109 * to the new DACL.
\r
1111 * The following code assumes that the old DACL is
\r
1112 * already in Windows 2000 preferred order. To conform
\r
1113 * to the new Windows 2000 preferred order, first we will
\r
1114 * copy all non-inherited ACEs from the old DACL to the
\r
1115 * new DACL, irrespective of the ACE type.
\r
1120 if (fDaclPresent && AclInfo.AceCount) {
\r
1122 for (CurrentAceIndex = 0;
\r
1123 CurrentAceIndex < AclInfo.AceCount;
\r
1124 CurrentAceIndex++) {
\r
1127 * TEP 10: Get an ACE.
\r
1129 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
\r
1134 * STEP 11: Check if it is a non-inherited ACE.
\r
1135 * If it is an inherited ACE, break from the loop so
\r
1136 * that the new access allowed non-inherited ACE can
\r
1137 * be added in the correct position, immediately after
\r
1138 * all non-inherited ACEs.
\r
1140 if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
\r
1145 * STEP 12: Skip adding the ACE, if the SID matches
\r
1146 * with the account specified, as we are going to
\r
1147 * add an access allowed ACE with a different access
\r
1150 if (GNEqualSid(pUserSID,
\r
1151 &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
\r
1155 * STEP 13: Add the ACE to the new ACL.
\r
1157 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
\r
1158 ((PACE_HEADER) pTempAce)->AceSize)) {
\r
1167 * STEP 14: Add the access-allowed ACE to the new DACL.
\r
1168 * The new ACE added here will be in the correct position,
\r
1169 * immediately after all existing non-inherited ACEs.
\r
1171 if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
\r
1177 * STEP 14.5: Make new ACE inheritable
\r
1179 if (!GetAce(pNewACL, newAceIndex, &pTempAce))
\r
1181 ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
\r
1182 (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
\r
1185 * STEP 15: To conform to the new Windows 2000 preferred order,
\r
1186 * we will now copy the rest of inherited ACEs from the
\r
1187 * old DACL to the new DACL.
\r
1189 if (fDaclPresent && AclInfo.AceCount) {
\r
1192 CurrentAceIndex < AclInfo.AceCount;
\r
1193 CurrentAceIndex++) {
\r
1196 * STEP 16: Get an ACE.
\r
1198 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
\r
1203 * STEP 17: Add the ACE to the new ACL.
\r
1205 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
\r
1206 ((PACE_HEADER) pTempAce)->AceSize)) {
\r
1213 * STEP 18: Set permissions
\r
1215 if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
\r
1216 DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
\r
1225 * STEP 19: Free allocated memory
\r
1228 HeapFree(GetProcessHeap(), 0, pUserSID);
\r
1231 HeapFree(GetProcessHeap(), 0, szDomain);
\r
1234 HeapFree(GetProcessHeap(), 0, pFileSD);
\r
1237 HeapFree(GetProcessHeap(), 0, pNewACL);
\r
1242 char *winErrorStr(const char *prefix, int dwErr)
\r
1247 if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
\r
1248 NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
\r
1251 err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);
\r
1254 mem = strlen(err) + strlen(prefix) + 20;
\r
1255 ret = (char *) malloc(mem);
\r
1257 snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
\r
1264 } /* extern "C" */
\r