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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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 GNUNET_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 GNUNET_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 GNUNET_memcpy (&interfaces4[i].iiAddress.Address,
538 unicast->Address.lpSockaddr,
539 unicast->Address.iSockaddrLength);
541 GNUNET_memcpy (&r->address, &interfaces4[i].iiAddress.Address,
542 sizeof (struct sockaddr_in));
543 GNUNET_memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,
544 sizeof (struct sockaddr_in));
545 for (mask_length = 0;
546 ((unsigned char *) &m->sin_addr)[mask_length / 8] &
547 0x80 >> (mask_length % 8); mask_length++)
550 r->flags |= ENUMNICS3_MASK_OK;
553 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
556 interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
559 GNUNET_memcpy (interfaces6->Address[i].lpSockaddr,
560 unicast->Address.lpSockaddr,
561 unicast->Address.iSockaddrLength);
563 GNUNET_memcpy (&r->address, interfaces6->Address[i].lpSockaddr,
564 sizeof (struct sockaddr_in6));
565 /* TODO: Find a way to reliably get network mask for IPv6 on XP */
566 memset (&r->mask, 0, sizeof (struct sockaddr));
567 r->flags &= ~ENUMNICS3_MASK_OK;
575 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
577 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
578 struct sockaddr_in *a = (struct sockaddr_in *) &r->address;
579 /* copy address to broadcast, then flip all the trailing bits not
580 * falling under netmask to 1,
581 * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.
583 GNUNET_memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
584 for (i = mask_length; i < 32; i++)
585 ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
586 r->flags |= ENUMNICS3_BCAST_OK;
587 r->addr_size = sizeof (struct sockaddr_in);
588 inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);
590 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
592 struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;
593 /* for IPv6 broadcast is not defined, zero it down */
594 memset (&r->broadcast, 0, sizeof (struct sockaddr));
595 r->flags &= ~ENUMNICS3_BCAST_OK;
596 r->addr_size = sizeof (struct sockaddr_in6);
597 inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);
601 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
602 "%S (%s", pCurrentAddress->FriendlyName, dst);
603 for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)
604 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
605 "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);
606 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");
607 r->pretty_name[1000] = '\0';
614 GNUNET_free_non_null (interfaces4);
615 GNUNET_free_non_null (interfaces6);
618 GNUNET_free (pAddresses);
623 EnumNICs3_free (struct EnumNICs3_results *r)
625 GNUNET_free_non_null (r);
630 * Lists all network interfaces in a combo box
631 * Used by the basic GTK configurator
633 * @param callback function to call for each NIC
634 * @param callback_cls closure for callback
637 ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)
641 struct EnumNICs3_results *results = NULL;
644 r = EnumNICs3 (&results, &results_count);
648 for (i = 0; i < results_count; i++)
649 callback (callback_cls, results[i].pretty_name, results[i].is_default);
650 GNUNET_free_non_null (results);
655 * @brief Installs the Windows service
656 * @param servicename name of the service as diplayed by the SCM
657 * @param application path to the application binary
658 * @param username the name of the service's user account
659 * @returns 0 on success
660 * 1 if the Windows version doesn't support services
661 * 2 if the SCM could not be opened
662 * 3 if the service could not be created
664 int InstallAsService(char *servicename, char *application, char *username)
666 SC_HANDLE hManager, hService;
667 char szEXE[_MAX_PATH + 17] = "\"";
670 if (! GNOpenSCManager)
673 plibc_conv_to_win_path(application, szEXE + 1);
674 strcat(szEXE, "\" --win-service");
675 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
681 user = (char *) malloc(strlen(username) + 3);
682 sprintf(user, ".\\%s", username);
685 hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
686 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
687 NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
695 GNCloseServiceHandle(hService);
702 * @brief Uninstall Windows service
703 * @param servicename name of the service to delete
704 * @returns 0 on success
705 * 1 if the Windows version doesn't support services
706 * 2 if the SCM could not be openend
707 * 3 if the service cannot be accessed
708 * 4 if the service cannot be deleted
711 UninstallService(char *servicename)
713 SC_HANDLE hManager, hService;
715 if (! GNOpenSCManager)
718 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
722 if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
724 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
730 if (! GNDeleteService(hService))
731 if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
735 GNCloseServiceHandle(hService);
741 * @author Scott Field, Microsoft
742 * @see http://support.microsoft.com/?scid=kb;en-us;132958
746 _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
752 LsaString->Buffer = NULL;
753 LsaString->Length = 0;
754 LsaString->MaximumLength = 0;
758 StringLength = wcslen(String);
759 LsaString->Buffer = String;
760 LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
761 LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
766 * @author Scott Field, Microsoft
767 * @see http://support.microsoft.com/?scid=kb;en-us;132958
771 _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
773 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
774 LSA_UNICODE_STRING ServerString;
775 PLSA_UNICODE_STRING Server = NULL;
777 /* Always initialize the object attributes to all zeroes. */
778 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
780 if(ServerName != NULL)
782 /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
783 _InitLsaString(&ServerString, ServerName);
784 Server = &ServerString;
787 /* Attempt to open the policy. */
788 return GNLsaOpenPolicy(Server,
789 &ObjectAttributes, DesiredAccess, PolicyHandle);
793 * @brief Obtain a SID representing the supplied account on the supplied system
794 * @return TRUE on success, FALSE on failure
795 * @author Scott Field, Microsoft
797 * @remarks A buffer is allocated which contains the SID representing the
798 * supplied account. This buffer should be freed when it is no longer
799 * needed by calling\n
800 * HeapFree(GetProcessHeap(), 0, buffer)
801 * @remarks Call GetLastError() to obtain extended error information.
802 * @see http://support.microsoft.com/?scid=kb;en-us;132958
805 _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)
807 LPTSTR ReferencedDomain = NULL;
808 DWORD cbSid = 128; /* initial allocation attempt */
809 DWORD cchReferencedDomain = 16; /* initial allocation size */
811 BOOL bSuccess = FALSE; /* assume this function will fail */
813 /* initial memory allocations */
814 if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
817 if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
819 cchReferencedDomain *
820 sizeof (TCHAR))) == NULL)
823 /* Obtain the SID of the specified account on the specified system. */
824 while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
825 AccountName, /* account to lookup */
826 *Sid, /* SID of interest */
827 &cbSid, /* size of SID */
828 ReferencedDomain, /* domain account was found on */
829 &cchReferencedDomain, &peUse))
831 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
833 /* reallocate memory */
834 if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
837 if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
841 * sizeof (TCHAR))) == NULL)
848 /* Indicate success. */
852 /* Cleanup and indicate failure, if appropriate. */
853 HeapFree (GetProcessHeap (), 0, ReferencedDomain);
859 HeapFree (GetProcessHeap (), 0, *Sid);
868 * @author Scott Field, Microsoft
869 * @see http://support.microsoft.com/?scid=kb;en-us;132958
873 _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
874 PSID AccountSid, /* SID to grant privilege to */
875 LPWSTR PrivilegeName, /* privilege to grant (Unicode) */
876 BOOL bEnable /* enable or disable */
879 LSA_UNICODE_STRING PrivilegeString;
881 /* Create a LSA_UNICODE_STRING for the privilege name. */
882 _InitLsaString(&PrivilegeString, PrivilegeName);
884 /* grant or revoke the privilege, accordingly */
889 i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */
890 AccountSid, /* target SID */
891 &PrivilegeString, /* privileges */
892 1 /* privilege count */
898 return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */
899 AccountSid, /* target SID */
900 FALSE, /* do not disable all rights */
901 &PrivilegeString, /* privileges */
902 1 /* privilege count */
908 * @brief Create a Windows service account
909 * @return 0 on success, > 0 otherwise
910 * @param pszName the name of the account
911 * @param pszDesc description of the account
914 CreateServiceAccount(const char *pszName,
919 NET_API_STATUS nStatus;
920 wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
926 mbstowcs(wszName, pszName, strlen(pszName) + 1);
927 mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
929 memset(&ui, 0, sizeof(ui));
930 ui.usri1_name = wszName;
931 ui.usri1_password = wszName; /* account is locked anyway */
932 ui.usri1_priv = USER_PRIV_USER;
933 ui.usri1_comment = wszDesc;
934 ui.usri1_flags = UF_SCRIPT;
936 nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
938 if (nStatus != NERR_Success && nStatus != NERR_UserExists)
941 ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
942 GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
944 if (!NT_SUCCESS(_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy)))
947 _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);
949 if (!NT_SUCCESS(_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE)))
952 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);
953 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);
954 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);
962 * @brief Grant permission to a file
963 * @param lpszFileName the name of the file or directory
964 * @param lpszAccountName the user account
965 * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
966 * @return TRUE on success
967 * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
969 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
973 SID_NAME_USE snuType;
974 TCHAR * szDomain = NULL;
976 LPVOID pUserSID = NULL;
979 /* File SD variables. */
980 PSECURITY_DESCRIPTOR pFileSD = NULL;
983 /* New SD variables. */
984 SECURITY_DESCRIPTOR newSD;
990 ACL_SIZE_INFORMATION AclInfo;
992 /* New ACL variables. */
997 LPVOID pTempAce = NULL;
998 UINT CurrentAceIndex = 0;
1000 UINT newAceIndex = 0;
1002 /* Assume function will fail. */
1003 BOOL fResult = FALSE;
1006 SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
1009 * STEP 1: Get SID of the account name specified.
1011 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1012 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1014 /* API should have failed with insufficient buffer. */
1017 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1021 pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
1026 szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
1031 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1032 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1038 * STEP 2: Get security descriptor (SD) of the file specified.
1040 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1041 secInfo, pFileSD, 0, &cbFileSD);
1043 /* API should have failed with insufficient buffer. */
1046 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1050 pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1056 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1057 secInfo, pFileSD, cbFileSD, &cbFileSD);
1063 * STEP 3: Initialize new SD.
1065 if (!GNInitializeSecurityDescriptor(&newSD,
1066 SECURITY_DESCRIPTOR_REVISION)) {
1071 * STEP 4: Get DACL from the old SD.
1073 if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
1079 * STEP 5: Get size information for DACL.
1081 AclInfo.AceCount = 0; // Assume NULL DACL.
1082 AclInfo.AclBytesFree = 0;
1083 AclInfo.AclBytesInUse = sizeof(ACL);
1086 fDaclPresent = FALSE;
1088 /* If not NULL DACL, gather size information from DACL. */
1091 if (!GNGetAclInformation(pACL, &AclInfo,
1092 sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
1098 * STEP 6: Compute size needed for the new ACL.
1100 cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
1101 + GetLengthSid(pUserSID) - sizeof(DWORD);
1104 * STEP 7: Allocate memory for new ACL.
1106 pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
1112 * STEP 8: Initialize the new ACL.
1114 if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
1119 * STEP 9 If DACL is present, copy all the ACEs from the old DACL
1122 * The following code assumes that the old DACL is
1123 * already in Windows 2000 preferred order. To conform
1124 * to the new Windows 2000 preferred order, first we will
1125 * copy all non-inherited ACEs from the old DACL to the
1126 * new DACL, irrespective of the ACE type.
1131 if (fDaclPresent && AclInfo.AceCount) {
1133 for (CurrentAceIndex = 0;
1134 CurrentAceIndex < AclInfo.AceCount;
1135 CurrentAceIndex++) {
1138 * TEP 10: Get an ACE.
1140 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1145 * STEP 11: Check if it is a non-inherited ACE.
1146 * If it is an inherited ACE, break from the loop so
1147 * that the new access allowed non-inherited ACE can
1148 * be added in the correct position, immediately after
1149 * all non-inherited ACEs.
1151 if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
1156 * STEP 12: Skip adding the ACE, if the SID matches
1157 * with the account specified, as we are going to
1158 * add an access allowed ACE with a different access
1161 if (GNEqualSid(pUserSID,
1162 &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
1166 * STEP 13: Add the ACE to the new ACL.
1168 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1169 ((PACE_HEADER) pTempAce)->AceSize)) {
1178 * STEP 14: Add the access-allowed ACE to the new DACL.
1179 * The new ACE added here will be in the correct position,
1180 * immediately after all existing non-inherited ACEs.
1182 if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
1188 * STEP 14.5: Make new ACE inheritable
1190 if (!GetAce(pNewACL, newAceIndex, &pTempAce))
1192 ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
1193 (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
1196 * STEP 15: To conform to the new Windows 2000 preferred order,
1197 * we will now copy the rest of inherited ACEs from the
1198 * old DACL to the new DACL.
1200 if (fDaclPresent && AclInfo.AceCount) {
1203 CurrentAceIndex < AclInfo.AceCount;
1204 CurrentAceIndex++) {
1207 * STEP 16: Get an ACE.
1209 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1214 * STEP 17: Add the ACE to the new ACL.
1216 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1217 ((PACE_HEADER) pTempAce)->AceSize)) {
1224 * STEP 18: Set permissions
1226 if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
1227 DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
1236 * STEP 19: Free allocated memory
1239 HeapFree(GetProcessHeap(), 0, pUserSID);
1242 HeapFree(GetProcessHeap(), 0, szDomain);
1245 HeapFree(GetProcessHeap(), 0, pFileSD);
1248 HeapFree(GetProcessHeap(), 0, pNewACL);
1253 char *winErrorStr(const char *prefix, int dwErr)
1258 if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1259 NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
1262 err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);
1265 mem = strlen(err) + strlen(prefix) + 20;
1266 ret = (char *) malloc(mem);
1268 snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
1276 * Terminate a process by creating a remote thread within it,
1277 * which proceeds to call ExitProcess() inside that process.
1278 * Safer than TerminateProcess ().
1280 * Code is from From http://private-storm.de/2009/08/11/case-terminateprocess/
1282 * @param hProcess handle of a process to terminate
1283 * @param uExitCode exit code to use for ExitProcess()
1284 * @param dwTimeout number of ms to wait for the process to terminate
1285 * @return TRUE on success, FALSE on failure (check last error for the code)
1288 SafeTerminateProcess (HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)
1290 DWORD dwTID, dwCode, dwErr = 0;
1291 HANDLE hProcessDup = INVALID_HANDLE_VALUE;
1293 HINSTANCE hKernel = GetModuleHandle ("Kernel32");
1294 BOOL bSuccess = FALSE;
1296 BOOL bDup = DuplicateHandle (GetCurrentProcess (), hProcess,
1297 GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS,
1300 /* Detect the special case where the process is
1303 if (GetExitCodeProcess (bDup ? hProcessDup : hProcess, &dwCode) &&
1304 (STILL_ACTIVE == dwCode))
1306 FARPROC pfnExitProc;
1308 pfnExitProc = GetProcAddress (hKernel, "ExitProcess");
1310 hRT = CreateRemoteThread ((bDup) ? hProcessDup : hProcess, NULL, 0,
1311 (LPTHREAD_START_ROUTINE) pfnExitProc, (PVOID) uExitCode, 0, &dwTID);
1313 dwErr = GetLastError ();
1317 dwErr = ERROR_PROCESS_ABORTED;
1322 /* Must wait process to terminate to
1323 * guarantee that it has exited...
1325 DWORD dwWaitResult = WaitForSingleObject ((bDup) ? hProcessDup : hProcess,
1327 if (dwWaitResult == WAIT_TIMEOUT)
1328 dwErr = WAIT_TIMEOUT;
1330 dwErr = GetLastError ();
1333 bSuccess = dwErr == NO_ERROR;
1337 CloseHandle (hProcessDup);
1339 SetLastError (dwErr);