2 This file is part of GNUnet.
3 (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 * @brief Helper functions for MS Windows in C++
32 #include "gnunet_common.h"
33 #include "gnunet_connection_lib.h"
37 #define INHERITED_ACE 0x10
40 int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);
42 #define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \
50 #define _IP_ADAPTER_UNICAST_ADDRESS_BASE \
51 SOCKET_ADDRESS Address; \
52 IP_PREFIX_ORIGIN PrefixOrigin; \
53 IP_SUFFIX_ORIGIN SuffixOrigin; \
54 IP_DAD_STATE DadState; \
55 ULONG ValidLifetime; \
56 ULONG PreferredLifetime; \
59 #define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \
60 UINT8 OnLinkPrefixLength;
63 #define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix,addition) \
64 typedef struct _IP_ADAPTER_UNICAST_ADDRESS##suffix { \
65 _IP_ADAPTER_UNICAST_ADDRESS_HEAD \
66 struct _IP_ADAPTER_UNICAST_ADDRESS##suffix *Next; \
67 _IP_ADAPTER_UNICAST_ADDRESS_BASE \
69 } IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix;
71 /* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */
72 _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA)
75 #ifndef __MINGW64_VERSION_MAJOR
76 typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS {
84 struct _IP_ADAPTER_WINS_SERVER_ADDRESS *Next;
85 SOCKET_ADDRESS Address;
86 } IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH;
88 typedef struct _IP_ADAPTER_GATEWAY_ADDRESS {
96 struct _IP_ADAPTER_GATEWAY_ADDRESS *Next;
97 SOCKET_ADDRESS Address;
98 } IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH;
101 typedef UINT32 NET_IF_COMPARTMENT_ID;
102 typedef GUID NET_IF_NETWORK_GUID;
104 #ifndef __MINGW64_VERSION_MAJOR
105 typedef enum _NET_IF_CONNECTION_TYPE {
106 NET_IF_CONNECTION_DEDICATED = 1,
107 NET_IF_CONNECTION_PASSIVE,
108 NET_IF_CONNECTION_DEMAND,
109 NET_IF_CONNECTION_MAXIMUM
110 } NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE;
113 TUNNEL_TYPE_NONE = 0,
120 } TUNNEL_TYPE, *PTUNNEL_TYPE;
124 A DUID consists of a two-octet type code represented in network byte
125 order, followed by a variable number of octets that make up the
126 actual identifier. A DUID can be no more than 128 octets long (not
127 including the type code).
129 #define MAX_DHCPV6_DUID_LENGTH 130
131 #ifndef __MINGW64_VERSION_MAJOR
132 typedef union _NET_LUID {
135 ULONG64 Reserved :24;
136 ULONG64 NetLuidIndex :24;
139 } NET_LUID, *PNET_LUID, IF_LUID;
141 #define MAX_DNS_SUFFIX_STRING_LENGTH 246
143 typedef struct _IP_ADAPTER_DNS_SUFFIX {
144 struct _IP_ADAPTER_DNS_SUFFIX *Next;
145 WCHAR String[MAX_DNS_SUFFIX_STRING_LENGTH];
146 } IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX;
151 #define _IP_ADAPTER_ADDRESSES_HEAD \
153 ULONGLONG Alignment; \
160 #define _IP_ADAPTER_ADDRESSES_BASE \
162 PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress; \
163 PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress; \
164 PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress; \
165 PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress; \
167 PWCHAR Description; \
168 PWCHAR FriendlyName; \
169 BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \
170 DWORD PhysicalAddressLength; \
174 IF_OPER_STATUS OperStatus;
176 #define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \
178 DWORD ZoneIndices[16]; \
179 PIP_ADAPTER_PREFIX FirstPrefix; \
182 #define _IP_ADAPTER_ADDRESSES_ADD_VISTA \
183 _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \
184 ULONG64 TransmitLinkSpeed; \
185 ULONG64 ReceiveLinkSpeed; \
186 PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \
187 PIP_ADAPTER_GATEWAY_ADDRESS_LH FirstGatewayAddress; \
191 SOCKET_ADDRESS Dhcpv4Server; \
192 NET_IF_COMPARTMENT_ID CompartmentId; \
193 NET_IF_NETWORK_GUID NetworkGuid; \
194 NET_IF_CONNECTION_TYPE ConnectionType; \
195 TUNNEL_TYPE TunnelType; \
196 SOCKET_ADDRESS Dhcpv6Server; \
197 BYTE Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \
198 ULONG Dhcpv6ClientDuidLength; \
201 #define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \
202 _IP_ADAPTER_ADDRESSES_ADD_VISTA \
203 PIP_ADAPTER_DNS_SUFFIX FirstDnsSuffix;
205 #define _IP_ADAPTER_ADDRESSES_DEFINE(suffix,addition) \
206 typedef struct _IP_ADAPTER_ADDRESSES##suffix { \
207 _IP_ADAPTER_ADDRESSES_HEAD \
208 struct _IP_ADAPTER_ADDRESSES##suffix *Next; \
209 _IP_ADAPTER_ADDRESSES_BASE \
211 } IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix;
214 /* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */
215 _IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1,_IP_ADAPTER_ADDRESSES_ADD_XPSP1)
216 _IP_ADAPTER_ADDRESSES_DEFINE(_VISTA,_IP_ADAPTER_ADDRESSES_ADD_VISTA)
217 _IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1,_IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1)
220 EnumNICs_IPv6_get_ifs_count (SOCKET s)
222 DWORD dwret = 0, err;
224 iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0,
226 err = GetLastError ();
227 if (iret == SOCKET_ERROR && err == WSAEFAULT)
231 return GNUNET_SYSERR;
235 EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size)
239 iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size,
242 if (iret != 0 || dwret != size)
244 /* It's supposed to succeed! And size should be the same */
245 return GNUNET_SYSERR;
251 #define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \
252 HEAP_GENERATE_EXCEPTIONS, a)
255 #define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a)
257 #undef GNUNET_free_non_null
258 #define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0)
261 EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size)
266 INTERFACE_INFO *ii = NULL;
267 DWORD ii_size = sizeof (INTERFACE_INFO) * 15;
270 if (ii_size >= sizeof (INTERFACE_INFO) * 1000)
271 return GNUNET_SYSERR;
272 ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size);
274 iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size,
276 error = GetLastError ();
277 if (iret == SOCKET_ERROR)
279 if (error == WSAEFAULT)
286 return GNUNET_SYSERR;
295 return GNUNET_SYSERR;
299 EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6)
302 SOCKET s4 = INVALID_SOCKET, s6 = INVALID_SOCKET;
303 DWORD dwret1 = 0, dwret2;
305 int ifs4len = 0, ifs6len = 0;
306 INTERFACE_INFO *interfaces4 = NULL;
307 SOCKET_ADDRESS_LIST *interfaces6 = NULL;
309 s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
310 err1 = GetLastError ();
312 s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
313 err2 = GetLastError ();
314 if (s6 != INVALID_SOCKET)
316 ifs6len = EnumNICs_IPv6_get_ifs_count (s6);
319 interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);
320 result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;
326 if (s4 != INVALID_SOCKET)
328 result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;
332 if (ifs6len + ifs4len == 0)
343 if (interfaces4 != NULL)
344 GNUNET_free (interfaces4);
345 if (interfaces6 != NULL)
346 GNUNET_free (interfaces6);
347 if (s4 != INVALID_SOCKET)
349 if (s6 != INVALID_SOCKET)
351 return GNUNET_SYSERR;
355 * Returns GNUNET_OK on OK, GNUNET_SYSERR on error
358 EnumNICs3 (struct EnumNICs3_results **results, int *results_count)
362 ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |
363 GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
364 struct sockaddr_in6 examplecom6;
366 DWORD best_interface = 0;
367 DWORD best_interface6 = 0;
370 INTERFACE_INFO *interfaces4 = NULL;
371 int interfaces4_len = 0;
372 SOCKET_ADDRESS_LIST *interfaces6 = NULL;
374 unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
375 IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;
376 IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
378 if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)
379 == ERROR_BUFFER_OVERFLOW)
381 GNUNET_free (pAddresses);
382 pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
385 dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);
387 if (dwRetVal != NO_ERROR)
389 GNUNET_free (pAddresses);
390 return GNUNET_SYSERR;
393 if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))
397 /* Enumerate NICs using WSAIoctl() */
398 if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))
400 GNUNET_free (pAddresses);
401 return GNUNET_SYSERR;
405 examplecom = inet_addr("192.0.34.166"); /* www.example.com */
406 if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)
409 if (GNGetBestInterfaceEx != NULL)
411 examplecom6.sin6_family = AF_INET6;
412 examplecom6.sin6_port = 0;
413 examplecom6.sin6_flowinfo = 0;
414 examplecom6.sin6_scope_id = 0;
415 inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",
416 (struct sockaddr *) &examplecom6.sin6_addr);
417 dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,
419 if (dwRetVal != NO_ERROR)
423 /* Give IPv6 a priority */
424 if (best_interface6 != 0)
425 best_interface = best_interface6;
428 for (pCurrentAddress = pAddresses;
429 pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
431 if (pCurrentAddress->OperStatus == IfOperStatusUp)
433 IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
434 for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
435 unicast = unicast->Next)
437 if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||
438 unicast->Address.lpSockaddr->sa_family == AF_INET6) &&
439 (unicast->DadState == IpDadStateDeprecated ||
440 unicast->DadState == IpDadStatePreferred))
450 GNUNET_free (pAddresses);
451 GNUNET_free_non_null (interfaces4);
452 GNUNET_free_non_null (interfaces6);
456 *results = (struct EnumNICs3_results *) GNUNET_malloc (
457 sizeof (struct EnumNICs3_results) * count);
458 *results_count = count;
461 for (pCurrentAddress = pAddresses;
462 pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
464 struct EnumNICs3_results *r;
465 IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
466 if (pCurrentAddress->OperStatus != IfOperStatusUp)
468 for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
469 unicast = unicast->Next)
472 int mask_length = -1;
473 char dst[INET6_ADDRSTRLEN + 1];
475 if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&
476 unicast->Address.lpSockaddr->sa_family != AF_INET6) ||
477 (unicast->DadState != IpDadStateDeprecated &&
478 unicast->DadState != IpDadStatePreferred))
481 r = &(*results)[count];
483 if (pCurrentAddress->IfIndex > 0 &&
484 pCurrentAddress->IfIndex == best_interface &&
485 unicast->Address.lpSockaddr->sa_family == AF_INET)
487 else if (pCurrentAddress->Ipv6IfIndex > 0 &&
488 pCurrentAddress->Ipv6IfIndex == best_interface6 &&
489 unicast->Address.lpSockaddr->sa_family == AF_INET6)
494 /* Don't choose default interface twice */
496 best_interface = best_interface6 = 0;
500 memcpy (&r->address, unicast->Address.lpSockaddr,
501 unicast->Address.iSockaddrLength);
502 memset (&r->mask, 0, sizeof (struct sockaddr));
503 mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->
505 /* OnLinkPrefixLength is the number of leading 1s in the mask.
506 * OnLinkPrefixLength is available on Vista and later (hence use_enum2).
508 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
510 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
511 for (i = 0; i < mask_length; i++)
512 ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
514 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
516 struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;
517 struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;
518 for (i = 0; i < mask_length; i++)
519 ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
520 memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
521 for (i = mask_length; i < 128; i++)
522 ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
524 r->flags |= ENUMNICS3_MASK_OK;
529 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
531 for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)
533 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
534 if (memcpy (&interfaces4[i].iiAddress.Address,
535 unicast->Address.lpSockaddr,
536 unicast->Address.iSockaddrLength) != 0)
539 memcpy (&r->address, &interfaces4[i].iiAddress.Address,
540 sizeof (struct sockaddr_in));
541 memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,
542 sizeof (struct sockaddr_in));
543 for (mask_length = 0;
544 ((unsigned char *) &m->sin_addr)[mask_length / 8] &
545 0x80 >> (mask_length % 8); mask_length++)
548 r->flags |= ENUMNICS3_MASK_OK;
551 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
554 interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
557 if (memcpy (interfaces6->Address[i].lpSockaddr,
558 unicast->Address.lpSockaddr,
559 unicast->Address.iSockaddrLength) != 0)
562 memcpy (&r->address, interfaces6->Address[i].lpSockaddr,
563 sizeof (struct sockaddr_in6));
564 /* TODO: Find a way to reliably get network mask for IPv6 on XP */
565 memset (&r->mask, 0, sizeof (struct sockaddr));
566 r->flags &= ~ENUMNICS3_MASK_OK;
574 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
576 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
577 struct sockaddr_in *a = (struct sockaddr_in *) &r->address;
578 /* copy address to broadcast, then flip all the trailing bits not
579 * falling under netmask to 1,
580 * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.
582 memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
583 for (i = mask_length; i < 32; i++)
584 ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
585 r->flags |= ENUMNICS3_BCAST_OK;
586 r->addr_size = sizeof (struct sockaddr_in);
587 inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);
589 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
591 struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;
592 /* for IPv6 broadcast is not defined, zero it down */
593 memset (&r->broadcast, 0, sizeof (struct sockaddr));
594 r->flags &= ~ENUMNICS3_BCAST_OK;
595 r->addr_size = sizeof (struct sockaddr_in6);
596 inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);
600 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
601 "%S (%s", pCurrentAddress->FriendlyName, dst);
602 for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)
603 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,
604 "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);
605 i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");
606 r->pretty_name[1000] = '\0';
613 GNUNET_free_non_null (interfaces4);
614 GNUNET_free_non_null (interfaces6);
617 GNUNET_free (pAddresses);
622 EnumNICs3_free (struct EnumNICs3_results *r)
624 GNUNET_free_non_null (r);
629 * Lists all network interfaces in a combo box
630 * Used by the basic GTK configurator
632 * @param callback function to call for each NIC
633 * @param callback_cls closure for callback
636 ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)
640 struct EnumNICs3_results *results = NULL;
643 r = EnumNICs3 (&results, &results_count);
647 for (i = 0; i < results_count; i++)
648 callback (callback_cls, results[i].pretty_name, results[i].is_default);
649 GNUNET_free_non_null (results);
654 * @brief Installs the Windows service
655 * @param servicename name of the service as diplayed by the SCM
656 * @param application path to the application binary
657 * @param username the name of the service's user account
658 * @returns 0 on success
659 * 1 if the Windows version doesn't support services
660 * 2 if the SCM could not be opened
661 * 3 if the service could not be created
663 int InstallAsService(char *servicename, char *application, char *username)
665 SC_HANDLE hManager, hService;
666 char szEXE[_MAX_PATH + 17] = "\"";
669 if (! GNOpenSCManager)
672 plibc_conv_to_win_path(application, szEXE + 1);
673 strcat(szEXE, "\" --win-service");
674 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
680 user = (char *) malloc(strlen(username) + 3);
681 sprintf(user, ".\\%s", username);
684 hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
685 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
686 NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
694 GNCloseServiceHandle(hService);
700 * @brief Uninstall Windows service
701 * @param servicename name of the service to delete
702 * @returns 0 on success
703 * 1 if the Windows version doesn't support services
704 * 2 if the SCM could not be openend
705 * 3 if the service cannot be accessed
706 * 4 if the service cannot be deleted
708 int UninstallService(char *servicename)
710 SC_HANDLE hManager, hService;
712 if (! GNOpenSCManager)
715 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
719 if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
721 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
727 if (! GNDeleteService(hService))
728 if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
732 GNCloseServiceHandle(hService);
738 * @author Scott Field, Microsoft
739 * @see http://support.microsoft.com/?scid=kb;en-us;132958
742 void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
748 LsaString->Buffer = NULL;
749 LsaString->Length = 0;
750 LsaString->MaximumLength = 0;
754 StringLength = wcslen(String);
755 LsaString->Buffer = String;
756 LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
757 LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
762 * @author Scott Field, Microsoft
763 * @see http://support.microsoft.com/?scid=kb;en-us;132958
766 NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
768 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
769 LSA_UNICODE_STRING ServerString;
770 PLSA_UNICODE_STRING Server = NULL;
772 /* Always initialize the object attributes to all zeroes. */
773 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
775 if(ServerName != NULL)
777 /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
778 _InitLsaString(&ServerString, ServerName);
779 Server = &ServerString;
782 /* Attempt to open the policy. */
783 return GNLsaOpenPolicy(Server,
784 &ObjectAttributes, DesiredAccess, PolicyHandle);
788 * @brief Obtain a SID representing the supplied account on the supplied system
789 * @return TRUE on success, FALSE on failure
790 * @author Scott Field, Microsoft
792 * @remarks A buffer is allocated which contains the SID representing the
793 * supplied account. This buffer should be freed when it is no longer
794 * needed by calling\n
795 * HeapFree(GetProcessHeap(), 0, buffer)
796 * @remarks Call GetLastError() to obtain extended error information.
797 * @see http://support.microsoft.com/?scid=kb;en-us;132958
799 BOOL _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)
801 LPTSTR ReferencedDomain = NULL;
802 DWORD cbSid = 128; /* initial allocation attempt */
803 DWORD cchReferencedDomain = 16; /* initial allocation size */
805 BOOL bSuccess = FALSE; /* assume this function will fail */
807 /* initial memory allocations */
808 if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
811 if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
813 cchReferencedDomain *
814 sizeof (TCHAR))) == NULL)
817 /* Obtain the SID of the specified account on the specified system. */
818 while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
819 AccountName, /* account to lookup */
820 *Sid, /* SID of interest */
821 &cbSid, /* size of SID */
822 ReferencedDomain, /* domain account was found on */
823 &cchReferencedDomain, &peUse))
825 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
827 /* reallocate memory */
828 if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
831 if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
835 * sizeof (TCHAR))) == NULL)
842 /* Indicate success. */
846 /* Cleanup and indicate failure, if appropriate. */
847 HeapFree (GetProcessHeap (), 0, ReferencedDomain);
853 HeapFree (GetProcessHeap (), 0, *Sid);
862 * @author Scott Field, Microsoft
863 * @see http://support.microsoft.com/?scid=kb;en-us;132958
866 NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
867 PSID AccountSid, /* SID to grant privilege to */
868 LPWSTR PrivilegeName, /* privilege to grant (Unicode) */
869 BOOL bEnable /* enable or disable */
872 LSA_UNICODE_STRING PrivilegeString;
874 /* Create a LSA_UNICODE_STRING for the privilege name. */
875 _InitLsaString(&PrivilegeString, PrivilegeName);
877 /* grant or revoke the privilege, accordingly */
882 i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */
883 AccountSid, /* target SID */
884 &PrivilegeString, /* privileges */
885 1 /* privilege count */
891 return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */
892 AccountSid, /* target SID */
893 FALSE, /* do not disable all rights */
894 &PrivilegeString, /* privileges */
895 1 /* privilege count */
901 * @brief Create a Windows service account
902 * @return 0 on success, > 0 otherwise
903 * @param pszName the name of the account
904 * @param pszDesc description of the account
906 int CreateServiceAccount(const char *pszName, const char *pszDesc)
910 NET_API_STATUS nStatus;
911 wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
918 mbstowcs(wszName, pszName, strlen(pszName) + 1);
919 mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
921 memset(&ui, 0, sizeof(ui));
922 ui.usri1_name = wszName;
923 ui.usri1_password = wszName; /* account is locked anyway */
924 ui.usri1_priv = USER_PRIV_USER;
925 ui.usri1_comment = wszDesc;
926 ui.usri1_flags = UF_SCRIPT;
928 nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
930 if (nStatus != NERR_Success && nStatus != NERR_UserExists)
933 ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
934 GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
936 if (!NT_SUCCESS(_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy)))
939 _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);
941 if (!NT_SUCCESS(_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE)))
944 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);
945 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);
946 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);
954 * @brief Grant permission to a file
955 * @param lpszFileName the name of the file or directory
956 * @param lpszAccountName the user account
957 * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
958 * @return TRUE on success
959 * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
961 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
965 SID_NAME_USE snuType;
966 TCHAR * szDomain = NULL;
968 LPVOID pUserSID = NULL;
971 /* File SD variables. */
972 PSECURITY_DESCRIPTOR pFileSD = NULL;
975 /* New SD variables. */
976 SECURITY_DESCRIPTOR newSD;
982 ACL_SIZE_INFORMATION AclInfo;
984 /* New ACL variables. */
989 LPVOID pTempAce = NULL;
990 UINT CurrentAceIndex = 0;
992 UINT newAceIndex = 0;
994 /* Assume function will fail. */
995 BOOL fResult = FALSE;
998 SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
1001 * STEP 1: Get SID of the account name specified.
1003 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1004 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1006 /* API should have failed with insufficient buffer. */
1009 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1013 pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
1018 szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
1023 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1024 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1030 * STEP 2: Get security descriptor (SD) of the file specified.
1032 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1033 secInfo, pFileSD, 0, &cbFileSD);
1035 /* API should have failed with insufficient buffer. */
1038 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1042 pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1048 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1049 secInfo, pFileSD, cbFileSD, &cbFileSD);
1055 * STEP 3: Initialize new SD.
1057 if (!GNInitializeSecurityDescriptor(&newSD,
1058 SECURITY_DESCRIPTOR_REVISION)) {
1063 * STEP 4: Get DACL from the old SD.
1065 if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
1071 * STEP 5: Get size information for DACL.
1073 AclInfo.AceCount = 0; // Assume NULL DACL.
1074 AclInfo.AclBytesFree = 0;
1075 AclInfo.AclBytesInUse = sizeof(ACL);
1078 fDaclPresent = FALSE;
1080 /* If not NULL DACL, gather size information from DACL. */
1083 if (!GNGetAclInformation(pACL, &AclInfo,
1084 sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
1090 * STEP 6: Compute size needed for the new ACL.
1092 cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
1093 + GetLengthSid(pUserSID) - sizeof(DWORD);
1096 * STEP 7: Allocate memory for new ACL.
1098 pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
1104 * STEP 8: Initialize the new ACL.
1106 if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
1111 * STEP 9 If DACL is present, copy all the ACEs from the old DACL
1114 * The following code assumes that the old DACL is
1115 * already in Windows 2000 preferred order. To conform
1116 * to the new Windows 2000 preferred order, first we will
1117 * copy all non-inherited ACEs from the old DACL to the
1118 * new DACL, irrespective of the ACE type.
1123 if (fDaclPresent && AclInfo.AceCount) {
1125 for (CurrentAceIndex = 0;
1126 CurrentAceIndex < AclInfo.AceCount;
1127 CurrentAceIndex++) {
1130 * TEP 10: Get an ACE.
1132 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1137 * STEP 11: Check if it is a non-inherited ACE.
1138 * If it is an inherited ACE, break from the loop so
1139 * that the new access allowed non-inherited ACE can
1140 * be added in the correct position, immediately after
1141 * all non-inherited ACEs.
1143 if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
1148 * STEP 12: Skip adding the ACE, if the SID matches
1149 * with the account specified, as we are going to
1150 * add an access allowed ACE with a different access
1153 if (GNEqualSid(pUserSID,
1154 &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
1158 * STEP 13: Add the ACE to the new ACL.
1160 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1161 ((PACE_HEADER) pTempAce)->AceSize)) {
1170 * STEP 14: Add the access-allowed ACE to the new DACL.
1171 * The new ACE added here will be in the correct position,
1172 * immediately after all existing non-inherited ACEs.
1174 if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
1180 * STEP 14.5: Make new ACE inheritable
1182 if (!GetAce(pNewACL, newAceIndex, &pTempAce))
1184 ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
1185 (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
1188 * STEP 15: To conform to the new Windows 2000 preferred order,
1189 * we will now copy the rest of inherited ACEs from the
1190 * old DACL to the new DACL.
1192 if (fDaclPresent && AclInfo.AceCount) {
1195 CurrentAceIndex < AclInfo.AceCount;
1196 CurrentAceIndex++) {
1199 * STEP 16: Get an ACE.
1201 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1206 * STEP 17: Add the ACE to the new ACL.
1208 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1209 ((PACE_HEADER) pTempAce)->AceSize)) {
1216 * STEP 18: Set permissions
1218 if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
1219 DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
1228 * STEP 19: Free allocated memory
1231 HeapFree(GetProcessHeap(), 0, pUserSID);
1234 HeapFree(GetProcessHeap(), 0, szDomain);
1237 HeapFree(GetProcessHeap(), 0, pFileSD);
1240 HeapFree(GetProcessHeap(), 0, pNewACL);
1245 char *winErrorStr(const char *prefix, int dwErr)
1250 if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1251 NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
1254 err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);
1257 mem = strlen(err) + strlen(prefix) + 20;
1258 ret = (char *) malloc(mem);
1260 snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
1268 * Terminate a process by creating a remote thread within it,
1269 * which proceeds to call ExitProcess() inside that process.
1270 * Safer than TerminateProcess ().
1272 * Code is from From http://private-storm.de/2009/08/11/case-terminateprocess/
1274 * @param hProcess handle of a process to terminate
1275 * @param uExitCode exit code to use for ExitProcess()
1276 * @param dwTimeout number of ms to wait for the process to terminate
1277 * @return TRUE on success, FALSE on failure (check last error for the code)
1280 SafeTerminateProcess (HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)
1282 DWORD dwTID, dwCode, dwErr = 0;
1283 HANDLE hProcessDup = INVALID_HANDLE_VALUE;
1285 HINSTANCE hKernel = GetModuleHandle ("Kernel32");
1286 BOOL bSuccess = FALSE;
1288 BOOL bDup = DuplicateHandle (GetCurrentProcess (), hProcess,
1289 GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS,
1292 /* Detect the special case where the process is
1295 if (GetExitCodeProcess (bDup ? hProcessDup : hProcess, &dwCode) &&
1296 (STILL_ACTIVE == dwCode))
1298 FARPROC pfnExitProc;
1300 pfnExitProc = GetProcAddress (hKernel, "ExitProcess");
1302 hRT = CreateRemoteThread ((bDup) ? hProcessDup : hProcess, NULL, 0,
1303 (LPTHREAD_START_ROUTINE) pfnExitProc, (PVOID) uExitCode, 0, &dwTID);
1305 dwErr = GetLastError ();
1309 dwErr = ERROR_PROCESS_ABORTED;
1314 /* Must wait process to terminate to
1315 * guarantee that it has exited...
1317 DWORD dwWaitResult = WaitForSingleObject ((bDup) ? hProcessDup : hProcess,
1319 if (dwWaitResult == WAIT_TIMEOUT)
1320 dwErr = WAIT_TIMEOUT;
1322 dwErr = GetLastError ();
1325 bSuccess = dwErr == NO_ERROR;
1329 CloseHandle (hProcessDup);
1331 SetLastError (dwErr);