2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 GNUnet e.V.
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 3, or (at your
8 option) any later version.
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.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
23 * @brief Helper functions for MS Windows in C++
32 #include "gnunet_crypto_lib.h"
33 #include "gnunet_common.h"
34 #include "gnunet_connection_lib.h"
38 #define INHERITED_ACE 0x10
41 int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);
43 #define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \
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; \
60 #define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \
61 UINT8 OnLinkPrefixLength;
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 \
70 } IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix;
72 /* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */
73 _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA)
76 #ifndef __MINGW64_VERSION_MAJOR
77 typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS {
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;
89 typedef struct _IP_ADAPTER_GATEWAY_ADDRESS {
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;
102 typedef UINT32 NET_IF_COMPARTMENT_ID;
103 typedef GUID NET_IF_NETWORK_GUID;
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;
114 TUNNEL_TYPE_NONE = 0,
121 } TUNNEL_TYPE, *PTUNNEL_TYPE;
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).
130 #define MAX_DHCPV6_DUID_LENGTH 130
132 #ifndef __MINGW64_VERSION_MAJOR
133 typedef union _NET_LUID {
136 ULONG64 Reserved :24;
137 ULONG64 NetLuidIndex :24;
140 } NET_LUID, *PNET_LUID, IF_LUID;
142 #define MAX_DNS_SUFFIX_STRING_LENGTH 246
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;
152 #define _IP_ADAPTER_ADDRESSES_HEAD \
154 ULONGLONG Alignment; \
161 #define _IP_ADAPTER_ADDRESSES_BASE \
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; \
168 PWCHAR Description; \
169 PWCHAR FriendlyName; \
170 BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \
171 DWORD PhysicalAddressLength; \
175 IF_OPER_STATUS OperStatus;
177 #define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \
179 DWORD ZoneIndices[16]; \
180 PIP_ADAPTER_PREFIX FirstPrefix; \
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; \
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; \
202 #define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \
203 _IP_ADAPTER_ADDRESSES_ADD_VISTA \
204 PIP_ADAPTER_DNS_SUFFIX FirstDnsSuffix;
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 \
212 } IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix;
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)
221 EnumNICs_IPv6_get_ifs_count (SOCKET s)
223 DWORD dwret = 0, err;
225 iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0,
227 err = GetLastError ();
228 if (iret == SOCKET_ERROR && err == WSAEFAULT)
232 return GNUNET_SYSERR;
236 EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size)
240 iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size,
243 if (iret != 0 || dwret != size)
245 /* It's supposed to succeed! And size should be the same */
246 return GNUNET_SYSERR;
252 #define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \
253 HEAP_GENERATE_EXCEPTIONS, a)
256 #define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a)
258 #undef GNUNET_free_non_null
259 #define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0)
262 EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size)
267 INTERFACE_INFO *ii = NULL;
268 DWORD ii_size = sizeof (INTERFACE_INFO) * 15;
271 if (ii_size >= sizeof (INTERFACE_INFO) * 1000)
272 return GNUNET_SYSERR;
273 ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size);
275 iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size,
277 error = GetLastError ();
278 if (iret == SOCKET_ERROR)
280 if (error == WSAEFAULT)
287 return GNUNET_SYSERR;
296 return GNUNET_SYSERR;
300 EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6)
307 INTERFACE_INFO *interfaces4 = NULL;
308 SOCKET_ADDRESS_LIST *interfaces6 = NULL;
311 s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
312 (void) GetLastError ();
314 s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
315 (void) GetLastError ();
316 if (s6 != INVALID_SOCKET)
318 ifs6len = EnumNICs_IPv6_get_ifs_count (s6);
321 interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);
322 result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;
328 if (s4 != INVALID_SOCKET)
330 result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;
334 if (ifs6len + ifs4len == 0)
345 if (interfaces4 != NULL)
346 GNUNET_free (interfaces4);
347 if (interfaces6 != NULL)
348 GNUNET_free (interfaces6);
349 if (s4 != INVALID_SOCKET)
351 if (s6 != INVALID_SOCKET)
353 return GNUNET_SYSERR;
358 * @returns #GNUNET_OK on success, #GNUNET_SYSERR on error
361 EnumNICs3 (struct EnumNICs3_results **results, int *results_count)
365 ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |
366 GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
367 struct sockaddr_in6 examplecom6;
369 DWORD best_interface = 0;
370 DWORD best_interface6 = 0;
373 INTERFACE_INFO *interfaces4 = NULL;
374 int interfaces4_len = 0;
375 SOCKET_ADDRESS_LIST *interfaces6 = NULL;
377 unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
378 IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;
379 IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
381 if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)
382 == ERROR_BUFFER_OVERFLOW)
384 GNUNET_free (pAddresses);
385 pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
388 dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);
390 if (dwRetVal != NO_ERROR)
392 GNUNET_free (pAddresses);
393 return GNUNET_SYSERR;
396 if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))
400 /* Enumerate NICs using WSAIoctl() */
401 if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))
403 GNUNET_free (pAddresses);
404 return GNUNET_SYSERR;
408 examplecom = inet_addr("192.0.34.166"); /* www.example.com */
409 if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)
412 if (GNGetBestInterfaceEx != NULL)
414 examplecom6.sin6_family = AF_INET6;
415 examplecom6.sin6_port = 0;
416 examplecom6.sin6_flowinfo = 0;
417 examplecom6.sin6_scope_id = 0;
418 inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",
419 (struct sockaddr *) &examplecom6.sin6_addr);
420 dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,
422 if (dwRetVal != NO_ERROR)
426 /* Give IPv6 a priority */
427 if (best_interface6 != 0)
428 best_interface = best_interface6;
431 for (pCurrentAddress = pAddresses;
432 pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
434 if (pCurrentAddress->OperStatus == IfOperStatusUp)
436 IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
437 for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
438 unicast = unicast->Next)
440 if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||
441 unicast->Address.lpSockaddr->sa_family == AF_INET6) &&
442 (unicast->DadState == IpDadStateDeprecated ||
443 unicast->DadState == IpDadStatePreferred))
453 GNUNET_free (pAddresses);
454 GNUNET_free_non_null (interfaces4);
455 GNUNET_free_non_null (interfaces6);
459 *results = (struct EnumNICs3_results *) GNUNET_malloc (
460 sizeof (struct EnumNICs3_results) * count);
461 *results_count = count;
464 for (pCurrentAddress = pAddresses;
465 pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
467 struct EnumNICs3_results *r;
468 IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
469 if (pCurrentAddress->OperStatus != IfOperStatusUp)
471 for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
472 unicast = unicast->Next)
475 int mask_length = -1;
476 char dst[INET6_ADDRSTRLEN + 1];
478 if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&
479 unicast->Address.lpSockaddr->sa_family != AF_INET6) ||
480 (unicast->DadState != IpDadStateDeprecated &&
481 unicast->DadState != IpDadStatePreferred))
484 r = &(*results)[count];
486 if (pCurrentAddress->IfIndex > 0 &&
487 pCurrentAddress->IfIndex == best_interface &&
488 unicast->Address.lpSockaddr->sa_family == AF_INET)
490 else if (pCurrentAddress->Ipv6IfIndex > 0 &&
491 pCurrentAddress->Ipv6IfIndex == best_interface6 &&
492 unicast->Address.lpSockaddr->sa_family == AF_INET6)
497 /* Don't choose default interface twice */
499 best_interface = best_interface6 = 0;
503 memcpy (&r->address, unicast->Address.lpSockaddr,
504 unicast->Address.iSockaddrLength);
505 memset (&r->mask, 0, sizeof (struct sockaddr));
506 mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->
508 /* OnLinkPrefixLength is the number of leading 1s in the mask.
509 * OnLinkPrefixLength is available on Vista and later (hence use_enum2).
511 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
513 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
514 for (i = 0; i < mask_length; i++)
515 ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
517 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
519 struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;
520 struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;
521 for (i = 0; i < mask_length; i++)
522 ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
523 memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
524 for (i = mask_length; i < 128; i++)
525 ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
527 r->flags |= ENUMNICS3_MASK_OK;
532 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
534 for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)
536 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
537 if (memcpy (&interfaces4[i].iiAddress.Address,
538 unicast->Address.lpSockaddr,
539 unicast->Address.iSockaddrLength) != 0)
542 memcpy (&r->address, &interfaces4[i].iiAddress.Address,
543 sizeof (struct sockaddr_in));
544 memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,
545 sizeof (struct sockaddr_in));
546 for (mask_length = 0;
547 ((unsigned char *) &m->sin_addr)[mask_length / 8] &
548 0x80 >> (mask_length % 8); mask_length++)
551 r->flags |= ENUMNICS3_MASK_OK;
554 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
557 interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
560 if (memcpy (interfaces6->Address[i].lpSockaddr,
561 unicast->Address.lpSockaddr,
562 unicast->Address.iSockaddrLength) != 0)
565 memcpy (&r->address, interfaces6->Address[i].lpSockaddr,
566 sizeof (struct sockaddr_in6));
567 /* TODO: Find a way to reliably get network mask for IPv6 on XP */
568 memset (&r->mask, 0, sizeof (struct sockaddr));
569 r->flags &= ~ENUMNICS3_MASK_OK;
577 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
579 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
580 struct sockaddr_in *a = (struct sockaddr_in *) &r->address;
581 /* copy address to broadcast, then flip all the trailing bits not
582 * falling under netmask to 1,
583 * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.
585 memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
586 for (i = mask_length; i < 32; i++)
587 ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
588 r->flags |= ENUMNICS3_BCAST_OK;
589 r->addr_size = sizeof (struct sockaddr_in);
590 inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);
592 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
594 struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;
595 /* for IPv6 broadcast is not defined, zero it down */
596 memset (&r->broadcast, 0, sizeof (struct sockaddr));
597 r->flags &= ~ENUMNICS3_BCAST_OK;
598 r->addr_size = sizeof (struct sockaddr_in6);
599 inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);
603 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
604 "%S (%s", pCurrentAddress->FriendlyName, dst);
605 for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)
606 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
607 "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);
608 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");
609 r->pretty_name[1000] = '\0';
616 GNUNET_free_non_null (interfaces4);
617 GNUNET_free_non_null (interfaces6);
620 GNUNET_free (pAddresses);
625 EnumNICs3_free (struct EnumNICs3_results *r)
627 GNUNET_free_non_null (r);
632 * Lists all network interfaces in a combo box
633 * Used by the basic GTK configurator
635 * @param callback function to call for each NIC
636 * @param callback_cls closure for callback
639 ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)
643 struct EnumNICs3_results *results = NULL;
646 r = EnumNICs3 (&results, &results_count);
650 for (i = 0; i < results_count; i++)
651 callback (callback_cls, results[i].pretty_name, results[i].is_default);
652 GNUNET_free_non_null (results);
657 * @brief Installs the Windows service
658 * @param servicename name of the service as diplayed by the SCM
659 * @param application path to the application binary
660 * @param username the name of the service's user account
661 * @returns 0 on success
662 * 1 if the Windows version doesn't support services
663 * 2 if the SCM could not be opened
664 * 3 if the service could not be created
666 int InstallAsService(char *servicename, char *application, char *username)
668 SC_HANDLE hManager, hService;
669 char szEXE[_MAX_PATH + 17] = "\"";
672 if (! GNOpenSCManager)
675 plibc_conv_to_win_path(application, szEXE + 1);
676 strcat(szEXE, "\" --win-service");
677 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
683 user = (char *) malloc(strlen(username) + 3);
684 sprintf(user, ".\\%s", username);
687 hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
688 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
689 NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
697 GNCloseServiceHandle(hService);
704 * @brief Uninstall Windows service
705 * @param servicename name of the service to delete
706 * @returns 0 on success
707 * 1 if the Windows version doesn't support services
708 * 2 if the SCM could not be openend
709 * 3 if the service cannot be accessed
710 * 4 if the service cannot be deleted
713 UninstallService(char *servicename)
715 SC_HANDLE hManager, hService;
717 if (! GNOpenSCManager)
720 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
724 if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
726 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
732 if (! GNDeleteService(hService))
733 if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
737 GNCloseServiceHandle(hService);
743 * @author Scott Field, Microsoft
744 * @see http://support.microsoft.com/?scid=kb;en-us;132958
748 _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
754 LsaString->Buffer = NULL;
755 LsaString->Length = 0;
756 LsaString->MaximumLength = 0;
760 StringLength = wcslen(String);
761 LsaString->Buffer = String;
762 LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
763 LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
768 * @author Scott Field, Microsoft
769 * @see http://support.microsoft.com/?scid=kb;en-us;132958
773 _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
775 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
776 LSA_UNICODE_STRING ServerString;
777 PLSA_UNICODE_STRING Server = NULL;
779 /* Always initialize the object attributes to all zeroes. */
780 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
782 if(ServerName != NULL)
784 /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
785 _InitLsaString(&ServerString, ServerName);
786 Server = &ServerString;
789 /* Attempt to open the policy. */
790 return GNLsaOpenPolicy(Server,
791 &ObjectAttributes, DesiredAccess, PolicyHandle);
795 * @brief Obtain a SID representing the supplied account on the supplied system
796 * @return TRUE on success, FALSE on failure
797 * @author Scott Field, Microsoft
799 * @remarks A buffer is allocated which contains the SID representing the
800 * supplied account. This buffer should be freed when it is no longer
801 * needed by calling\n
802 * HeapFree(GetProcessHeap(), 0, buffer)
803 * @remarks Call GetLastError() to obtain extended error information.
804 * @see http://support.microsoft.com/?scid=kb;en-us;132958
807 _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)
809 LPTSTR ReferencedDomain = NULL;
810 DWORD cbSid = 128; /* initial allocation attempt */
811 DWORD cchReferencedDomain = 16; /* initial allocation size */
813 BOOL bSuccess = FALSE; /* assume this function will fail */
815 /* initial memory allocations */
816 if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
819 if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
821 cchReferencedDomain *
822 sizeof (TCHAR))) == NULL)
825 /* Obtain the SID of the specified account on the specified system. */
826 while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
827 AccountName, /* account to lookup */
828 *Sid, /* SID of interest */
829 &cbSid, /* size of SID */
830 ReferencedDomain, /* domain account was found on */
831 &cchReferencedDomain, &peUse))
833 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
835 /* reallocate memory */
836 if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
839 if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
843 * sizeof (TCHAR))) == NULL)
850 /* Indicate success. */
854 /* Cleanup and indicate failure, if appropriate. */
855 HeapFree (GetProcessHeap (), 0, ReferencedDomain);
861 HeapFree (GetProcessHeap (), 0, *Sid);
870 * @author Scott Field, Microsoft
871 * @see http://support.microsoft.com/?scid=kb;en-us;132958
875 _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
876 PSID AccountSid, /* SID to grant privilege to */
877 LPWSTR PrivilegeName, /* privilege to grant (Unicode) */
878 BOOL bEnable /* enable or disable */
881 LSA_UNICODE_STRING PrivilegeString;
883 /* Create a LSA_UNICODE_STRING for the privilege name. */
884 _InitLsaString(&PrivilegeString, PrivilegeName);
886 /* grant or revoke the privilege, accordingly */
891 i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */
892 AccountSid, /* target SID */
893 &PrivilegeString, /* privileges */
894 1 /* privilege count */
900 return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */
901 AccountSid, /* target SID */
902 FALSE, /* do not disable all rights */
903 &PrivilegeString, /* privileges */
904 1 /* privilege count */
910 * @brief Create a Windows service account
911 * @return 0 on success, > 0 otherwise
912 * @param pszName the name of the account
913 * @param pszDesc description of the account
916 CreateServiceAccount(const char *pszName,
921 NET_API_STATUS nStatus;
922 wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
928 mbstowcs(wszName, pszName, strlen(pszName) + 1);
929 mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
931 memset(&ui, 0, sizeof(ui));
932 ui.usri1_name = wszName;
933 ui.usri1_password = wszName; /* account is locked anyway */
934 ui.usri1_priv = USER_PRIV_USER;
935 ui.usri1_comment = wszDesc;
936 ui.usri1_flags = UF_SCRIPT;
938 nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
940 if (nStatus != NERR_Success && nStatus != NERR_UserExists)
943 ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
944 GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
946 if (!NT_SUCCESS(_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy)))
949 _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);
951 if (!NT_SUCCESS(_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE)))
954 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);
955 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);
956 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);
964 * @brief Grant permission to a file
965 * @param lpszFileName the name of the file or directory
966 * @param lpszAccountName the user account
967 * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
968 * @return TRUE on success
969 * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
971 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
975 SID_NAME_USE snuType;
976 TCHAR * szDomain = NULL;
978 LPVOID pUserSID = NULL;
981 /* File SD variables. */
982 PSECURITY_DESCRIPTOR pFileSD = NULL;
985 /* New SD variables. */
986 SECURITY_DESCRIPTOR newSD;
992 ACL_SIZE_INFORMATION AclInfo;
994 /* New ACL variables. */
999 LPVOID pTempAce = NULL;
1000 UINT CurrentAceIndex = 0;
1002 UINT newAceIndex = 0;
1004 /* Assume function will fail. */
1005 BOOL fResult = FALSE;
1008 SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
1011 * STEP 1: Get SID of the account name specified.
1013 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1014 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1016 /* API should have failed with insufficient buffer. */
1019 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1023 pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
1028 szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
1033 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1034 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1040 * STEP 2: Get security descriptor (SD) of the file specified.
1042 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1043 secInfo, pFileSD, 0, &cbFileSD);
1045 /* API should have failed with insufficient buffer. */
1048 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1052 pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1058 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1059 secInfo, pFileSD, cbFileSD, &cbFileSD);
1065 * STEP 3: Initialize new SD.
1067 if (!GNInitializeSecurityDescriptor(&newSD,
1068 SECURITY_DESCRIPTOR_REVISION)) {
1073 * STEP 4: Get DACL from the old SD.
1075 if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
1081 * STEP 5: Get size information for DACL.
1083 AclInfo.AceCount = 0; // Assume NULL DACL.
1084 AclInfo.AclBytesFree = 0;
1085 AclInfo.AclBytesInUse = sizeof(ACL);
1088 fDaclPresent = FALSE;
1090 /* If not NULL DACL, gather size information from DACL. */
1093 if (!GNGetAclInformation(pACL, &AclInfo,
1094 sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
1100 * STEP 6: Compute size needed for the new ACL.
1102 cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
1103 + GetLengthSid(pUserSID) - sizeof(DWORD);
1106 * STEP 7: Allocate memory for new ACL.
1108 pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
1114 * STEP 8: Initialize the new ACL.
1116 if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
1121 * STEP 9 If DACL is present, copy all the ACEs from the old DACL
1124 * The following code assumes that the old DACL is
1125 * already in Windows 2000 preferred order. To conform
1126 * to the new Windows 2000 preferred order, first we will
1127 * copy all non-inherited ACEs from the old DACL to the
1128 * new DACL, irrespective of the ACE type.
1133 if (fDaclPresent && AclInfo.AceCount) {
1135 for (CurrentAceIndex = 0;
1136 CurrentAceIndex < AclInfo.AceCount;
1137 CurrentAceIndex++) {
1140 * TEP 10: Get an ACE.
1142 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1147 * STEP 11: Check if it is a non-inherited ACE.
1148 * If it is an inherited ACE, break from the loop so
1149 * that the new access allowed non-inherited ACE can
1150 * be added in the correct position, immediately after
1151 * all non-inherited ACEs.
1153 if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
1158 * STEP 12: Skip adding the ACE, if the SID matches
1159 * with the account specified, as we are going to
1160 * add an access allowed ACE with a different access
1163 if (GNEqualSid(pUserSID,
1164 &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
1168 * STEP 13: Add the ACE to the new ACL.
1170 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1171 ((PACE_HEADER) pTempAce)->AceSize)) {
1180 * STEP 14: Add the access-allowed ACE to the new DACL.
1181 * The new ACE added here will be in the correct position,
1182 * immediately after all existing non-inherited ACEs.
1184 if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
1190 * STEP 14.5: Make new ACE inheritable
1192 if (!GetAce(pNewACL, newAceIndex, &pTempAce))
1194 ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
1195 (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
1198 * STEP 15: To conform to the new Windows 2000 preferred order,
1199 * we will now copy the rest of inherited ACEs from the
1200 * old DACL to the new DACL.
1202 if (fDaclPresent && AclInfo.AceCount) {
1205 CurrentAceIndex < AclInfo.AceCount;
1206 CurrentAceIndex++) {
1209 * STEP 16: Get an ACE.
1211 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1216 * STEP 17: Add the ACE to the new ACL.
1218 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1219 ((PACE_HEADER) pTempAce)->AceSize)) {
1226 * STEP 18: Set permissions
1228 if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
1229 DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
1238 * STEP 19: Free allocated memory
1241 HeapFree(GetProcessHeap(), 0, pUserSID);
1244 HeapFree(GetProcessHeap(), 0, szDomain);
1247 HeapFree(GetProcessHeap(), 0, pFileSD);
1250 HeapFree(GetProcessHeap(), 0, pNewACL);
1255 char *winErrorStr(const char *prefix, int dwErr)
1260 if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1261 NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
1264 err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);
1267 mem = strlen(err) + strlen(prefix) + 20;
1268 ret = (char *) malloc(mem);
1270 snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
1278 * Terminate a process by creating a remote thread within it,
1279 * which proceeds to call ExitProcess() inside that process.
1280 * Safer than TerminateProcess ().
1282 * Code is from From http://private-storm.de/2009/08/11/case-terminateprocess/
1284 * @param hProcess handle of a process to terminate
1285 * @param uExitCode exit code to use for ExitProcess()
1286 * @param dwTimeout number of ms to wait for the process to terminate
1287 * @return TRUE on success, FALSE on failure (check last error for the code)
1290 SafeTerminateProcess (HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)
1292 DWORD dwTID, dwCode, dwErr = 0;
1293 HANDLE hProcessDup = INVALID_HANDLE_VALUE;
1295 HINSTANCE hKernel = GetModuleHandle ("Kernel32");
1296 BOOL bSuccess = FALSE;
1298 BOOL bDup = DuplicateHandle (GetCurrentProcess (), hProcess,
1299 GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS,
1302 /* Detect the special case where the process is
1305 if (GetExitCodeProcess (bDup ? hProcessDup : hProcess, &dwCode) &&
1306 (STILL_ACTIVE == dwCode))
1308 FARPROC pfnExitProc;
1310 pfnExitProc = GetProcAddress (hKernel, "ExitProcess");
1312 hRT = CreateRemoteThread ((bDup) ? hProcessDup : hProcess, NULL, 0,
1313 (LPTHREAD_START_ROUTINE) pfnExitProc, (PVOID) uExitCode, 0, &dwTID);
1315 dwErr = GetLastError ();
1319 dwErr = ERROR_PROCESS_ABORTED;
1324 /* Must wait process to terminate to
1325 * guarantee that it has exited...
1327 DWORD dwWaitResult = WaitForSingleObject ((bDup) ? hProcessDup : hProcess,
1329 if (dwWaitResult == WAIT_TIMEOUT)
1330 dwErr = WAIT_TIMEOUT;
1332 dwErr = GetLastError ();
1335 bSuccess = dwErr == NO_ERROR;
1339 CloseHandle (hProcessDup);
1341 SetLastError (dwErr);