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_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)
303 SOCKET s4 = INVALID_SOCKET, s6 = INVALID_SOCKET;
304 DWORD dwret1 = 0, dwret2;
306 int ifs4len = 0, ifs6len = 0;
307 INTERFACE_INFO *interfaces4 = NULL;
308 SOCKET_ADDRESS_LIST *interfaces6 = NULL;
310 s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
311 err1 = GetLastError ();
313 s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
314 err2 = GetLastError ();
315 if (s6 != INVALID_SOCKET)
317 ifs6len = EnumNICs_IPv6_get_ifs_count (s6);
320 interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);
321 result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;
327 if (s4 != INVALID_SOCKET)
329 result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;
333 if (ifs6len + ifs4len == 0)
344 if (interfaces4 != NULL)
345 GNUNET_free (interfaces4);
346 if (interfaces6 != NULL)
347 GNUNET_free (interfaces6);
348 if (s4 != INVALID_SOCKET)
350 if (s6 != INVALID_SOCKET)
352 return GNUNET_SYSERR;
356 * Returns GNUNET_OK on OK, GNUNET_SYSERR on error
359 EnumNICs3 (struct EnumNICs3_results **results, int *results_count)
363 ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |
364 GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
365 struct sockaddr_in6 examplecom6;
367 DWORD best_interface = 0;
368 DWORD best_interface6 = 0;
371 INTERFACE_INFO *interfaces4 = NULL;
372 int interfaces4_len = 0;
373 SOCKET_ADDRESS_LIST *interfaces6 = NULL;
375 unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
376 IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;
377 IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
379 if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)
380 == ERROR_BUFFER_OVERFLOW)
382 GNUNET_free (pAddresses);
383 pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);
386 dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);
388 if (dwRetVal != NO_ERROR)
390 GNUNET_free (pAddresses);
391 return GNUNET_SYSERR;
394 if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))
398 /* Enumerate NICs using WSAIoctl() */
399 if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))
401 GNUNET_free (pAddresses);
402 return GNUNET_SYSERR;
406 examplecom = inet_addr("192.0.34.166"); /* www.example.com */
407 if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)
410 if (GNGetBestInterfaceEx != NULL)
412 examplecom6.sin6_family = AF_INET6;
413 examplecom6.sin6_port = 0;
414 examplecom6.sin6_flowinfo = 0;
415 examplecom6.sin6_scope_id = 0;
416 inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",
417 (struct sockaddr *) &examplecom6.sin6_addr);
418 dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,
420 if (dwRetVal != NO_ERROR)
424 /* Give IPv6 a priority */
425 if (best_interface6 != 0)
426 best_interface = best_interface6;
429 for (pCurrentAddress = pAddresses;
430 pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
432 if (pCurrentAddress->OperStatus == IfOperStatusUp)
434 IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
435 for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
436 unicast = unicast->Next)
438 if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||
439 unicast->Address.lpSockaddr->sa_family == AF_INET6) &&
440 (unicast->DadState == IpDadStateDeprecated ||
441 unicast->DadState == IpDadStatePreferred))
451 GNUNET_free (pAddresses);
452 GNUNET_free_non_null (interfaces4);
453 GNUNET_free_non_null (interfaces6);
457 *results = (struct EnumNICs3_results *) GNUNET_malloc (
458 sizeof (struct EnumNICs3_results) * count);
459 *results_count = count;
462 for (pCurrentAddress = pAddresses;
463 pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)
465 struct EnumNICs3_results *r;
466 IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;
467 if (pCurrentAddress->OperStatus != IfOperStatusUp)
469 for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;
470 unicast = unicast->Next)
473 int mask_length = -1;
474 char dst[INET6_ADDRSTRLEN + 1];
476 if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&
477 unicast->Address.lpSockaddr->sa_family != AF_INET6) ||
478 (unicast->DadState != IpDadStateDeprecated &&
479 unicast->DadState != IpDadStatePreferred))
482 r = &(*results)[count];
484 if (pCurrentAddress->IfIndex > 0 &&
485 pCurrentAddress->IfIndex == best_interface &&
486 unicast->Address.lpSockaddr->sa_family == AF_INET)
488 else if (pCurrentAddress->Ipv6IfIndex > 0 &&
489 pCurrentAddress->Ipv6IfIndex == best_interface6 &&
490 unicast->Address.lpSockaddr->sa_family == AF_INET6)
495 /* Don't choose default interface twice */
497 best_interface = best_interface6 = 0;
501 memcpy (&r->address, unicast->Address.lpSockaddr,
502 unicast->Address.iSockaddrLength);
503 memset (&r->mask, 0, sizeof (struct sockaddr));
504 mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->
506 /* OnLinkPrefixLength is the number of leading 1s in the mask.
507 * OnLinkPrefixLength is available on Vista and later (hence use_enum2).
509 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
511 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
512 for (i = 0; i < mask_length; i++)
513 ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);
515 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
517 struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;
518 struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;
519 for (i = 0; i < mask_length; i++)
520 ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
521 memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);
522 for (i = mask_length; i < 128; i++)
523 ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);
525 r->flags |= ENUMNICS3_MASK_OK;
530 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
532 for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)
534 struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;
535 if (memcpy (&interfaces4[i].iiAddress.Address,
536 unicast->Address.lpSockaddr,
537 unicast->Address.iSockaddrLength) != 0)
540 memcpy (&r->address, &interfaces4[i].iiAddress.Address,
541 sizeof (struct sockaddr_in));
542 memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,
543 sizeof (struct sockaddr_in));
544 for (mask_length = 0;
545 ((unsigned char *) &m->sin_addr)[mask_length / 8] &
546 0x80 >> (mask_length % 8); mask_length++)
549 r->flags |= ENUMNICS3_MASK_OK;
552 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)
555 interfaces6 != NULL && !found && i < interfaces6->iAddressCount;
558 if (memcpy (interfaces6->Address[i].lpSockaddr,
559 unicast->Address.lpSockaddr,
560 unicast->Address.iSockaddrLength) != 0)
563 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 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);
701 * @brief Uninstall Windows service
702 * @param servicename name of the service to delete
703 * @returns 0 on success
704 * 1 if the Windows version doesn't support services
705 * 2 if the SCM could not be openend
706 * 3 if the service cannot be accessed
707 * 4 if the service cannot be deleted
709 int UninstallService(char *servicename)
711 SC_HANDLE hManager, hService;
713 if (! GNOpenSCManager)
716 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
720 if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
722 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
728 if (! GNDeleteService(hService))
729 if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
733 GNCloseServiceHandle(hService);
739 * @author Scott Field, Microsoft
740 * @see http://support.microsoft.com/?scid=kb;en-us;132958
743 void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
749 LsaString->Buffer = NULL;
750 LsaString->Length = 0;
751 LsaString->MaximumLength = 0;
755 StringLength = wcslen(String);
756 LsaString->Buffer = String;
757 LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
758 LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
763 * @author Scott Field, Microsoft
764 * @see http://support.microsoft.com/?scid=kb;en-us;132958
767 NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
769 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
770 LSA_UNICODE_STRING ServerString;
771 PLSA_UNICODE_STRING Server = NULL;
773 /* Always initialize the object attributes to all zeroes. */
774 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
776 if(ServerName != NULL)
778 /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
779 _InitLsaString(&ServerString, ServerName);
780 Server = &ServerString;
783 /* Attempt to open the policy. */
784 return GNLsaOpenPolicy(Server,
785 &ObjectAttributes, DesiredAccess, PolicyHandle);
789 * @brief Obtain a SID representing the supplied account on the supplied system
790 * @return TRUE on success, FALSE on failure
791 * @author Scott Field, Microsoft
793 * @remarks A buffer is allocated which contains the SID representing the
794 * supplied account. This buffer should be freed when it is no longer
795 * needed by calling\n
796 * HeapFree(GetProcessHeap(), 0, buffer)
797 * @remarks Call GetLastError() to obtain extended error information.
798 * @see http://support.microsoft.com/?scid=kb;en-us;132958
800 BOOL _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)
802 LPTSTR ReferencedDomain = NULL;
803 DWORD cbSid = 128; /* initial allocation attempt */
804 DWORD cchReferencedDomain = 16; /* initial allocation size */
806 BOOL bSuccess = FALSE; /* assume this function will fail */
808 /* initial memory allocations */
809 if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
812 if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
814 cchReferencedDomain *
815 sizeof (TCHAR))) == NULL)
818 /* Obtain the SID of the specified account on the specified system. */
819 while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
820 AccountName, /* account to lookup */
821 *Sid, /* SID of interest */
822 &cbSid, /* size of SID */
823 ReferencedDomain, /* domain account was found on */
824 &cchReferencedDomain, &peUse))
826 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
828 /* reallocate memory */
829 if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
832 if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
836 * sizeof (TCHAR))) == NULL)
843 /* Indicate success. */
847 /* Cleanup and indicate failure, if appropriate. */
848 HeapFree (GetProcessHeap (), 0, ReferencedDomain);
854 HeapFree (GetProcessHeap (), 0, *Sid);
863 * @author Scott Field, Microsoft
864 * @see http://support.microsoft.com/?scid=kb;en-us;132958
867 NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
868 PSID AccountSid, /* SID to grant privilege to */
869 LPWSTR PrivilegeName, /* privilege to grant (Unicode) */
870 BOOL bEnable /* enable or disable */
873 LSA_UNICODE_STRING PrivilegeString;
875 /* Create a LSA_UNICODE_STRING for the privilege name. */
876 _InitLsaString(&PrivilegeString, PrivilegeName);
878 /* grant or revoke the privilege, accordingly */
883 i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */
884 AccountSid, /* target SID */
885 &PrivilegeString, /* privileges */
886 1 /* privilege count */
892 return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */
893 AccountSid, /* target SID */
894 FALSE, /* do not disable all rights */
895 &PrivilegeString, /* privileges */
896 1 /* privilege count */
902 * @brief Create a Windows service account
903 * @return 0 on success, > 0 otherwise
904 * @param pszName the name of the account
905 * @param pszDesc description of the account
907 int CreateServiceAccount(const char *pszName, const char *pszDesc)
911 NET_API_STATUS nStatus;
912 wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
919 mbstowcs(wszName, pszName, strlen(pszName) + 1);
920 mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
922 memset(&ui, 0, sizeof(ui));
923 ui.usri1_name = wszName;
924 ui.usri1_password = wszName; /* account is locked anyway */
925 ui.usri1_priv = USER_PRIV_USER;
926 ui.usri1_comment = wszDesc;
927 ui.usri1_flags = UF_SCRIPT;
929 nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
931 if (nStatus != NERR_Success && nStatus != NERR_UserExists)
934 ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
935 GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
937 if (!NT_SUCCESS(_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy)))
940 _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);
942 if (!NT_SUCCESS(_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE)))
945 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);
946 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);
947 _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);
955 * @brief Grant permission to a file
956 * @param lpszFileName the name of the file or directory
957 * @param lpszAccountName the user account
958 * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
959 * @return TRUE on success
960 * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
962 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
966 SID_NAME_USE snuType;
967 TCHAR * szDomain = NULL;
969 LPVOID pUserSID = NULL;
972 /* File SD variables. */
973 PSECURITY_DESCRIPTOR pFileSD = NULL;
976 /* New SD variables. */
977 SECURITY_DESCRIPTOR newSD;
983 ACL_SIZE_INFORMATION AclInfo;
985 /* New ACL variables. */
990 LPVOID pTempAce = NULL;
991 UINT CurrentAceIndex = 0;
993 UINT newAceIndex = 0;
995 /* Assume function will fail. */
996 BOOL fResult = FALSE;
999 SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
1002 * STEP 1: Get SID of the account name specified.
1004 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1005 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1007 /* API should have failed with insufficient buffer. */
1010 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1014 pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
1019 szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
1024 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
1025 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
1031 * STEP 2: Get security descriptor (SD) of the file specified.
1033 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1034 secInfo, pFileSD, 0, &cbFileSD);
1036 /* API should have failed with insufficient buffer. */
1039 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1043 pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1049 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
1050 secInfo, pFileSD, cbFileSD, &cbFileSD);
1056 * STEP 3: Initialize new SD.
1058 if (!GNInitializeSecurityDescriptor(&newSD,
1059 SECURITY_DESCRIPTOR_REVISION)) {
1064 * STEP 4: Get DACL from the old SD.
1066 if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
1072 * STEP 5: Get size information for DACL.
1074 AclInfo.AceCount = 0; // Assume NULL DACL.
1075 AclInfo.AclBytesFree = 0;
1076 AclInfo.AclBytesInUse = sizeof(ACL);
1079 fDaclPresent = FALSE;
1081 /* If not NULL DACL, gather size information from DACL. */
1084 if (!GNGetAclInformation(pACL, &AclInfo,
1085 sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
1091 * STEP 6: Compute size needed for the new ACL.
1093 cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
1094 + GetLengthSid(pUserSID) - sizeof(DWORD);
1097 * STEP 7: Allocate memory for new ACL.
1099 pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
1105 * STEP 8: Initialize the new ACL.
1107 if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
1112 * STEP 9 If DACL is present, copy all the ACEs from the old DACL
1115 * The following code assumes that the old DACL is
1116 * already in Windows 2000 preferred order. To conform
1117 * to the new Windows 2000 preferred order, first we will
1118 * copy all non-inherited ACEs from the old DACL to the
1119 * new DACL, irrespective of the ACE type.
1124 if (fDaclPresent && AclInfo.AceCount) {
1126 for (CurrentAceIndex = 0;
1127 CurrentAceIndex < AclInfo.AceCount;
1128 CurrentAceIndex++) {
1131 * TEP 10: Get an ACE.
1133 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1138 * STEP 11: Check if it is a non-inherited ACE.
1139 * If it is an inherited ACE, break from the loop so
1140 * that the new access allowed non-inherited ACE can
1141 * be added in the correct position, immediately after
1142 * all non-inherited ACEs.
1144 if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
1149 * STEP 12: Skip adding the ACE, if the SID matches
1150 * with the account specified, as we are going to
1151 * add an access allowed ACE with a different access
1154 if (GNEqualSid(pUserSID,
1155 &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
1159 * STEP 13: Add the ACE to the new ACL.
1161 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1162 ((PACE_HEADER) pTempAce)->AceSize)) {
1171 * STEP 14: Add the access-allowed ACE to the new DACL.
1172 * The new ACE added here will be in the correct position,
1173 * immediately after all existing non-inherited ACEs.
1175 if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
1181 * STEP 14.5: Make new ACE inheritable
1183 if (!GetAce(pNewACL, newAceIndex, &pTempAce))
1185 ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
1186 (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
1189 * STEP 15: To conform to the new Windows 2000 preferred order,
1190 * we will now copy the rest of inherited ACEs from the
1191 * old DACL to the new DACL.
1193 if (fDaclPresent && AclInfo.AceCount) {
1196 CurrentAceIndex < AclInfo.AceCount;
1197 CurrentAceIndex++) {
1200 * STEP 16: Get an ACE.
1202 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
1207 * STEP 17: Add the ACE to the new ACL.
1209 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
1210 ((PACE_HEADER) pTempAce)->AceSize)) {
1217 * STEP 18: Set permissions
1219 if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
1220 DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
1229 * STEP 19: Free allocated memory
1232 HeapFree(GetProcessHeap(), 0, pUserSID);
1235 HeapFree(GetProcessHeap(), 0, szDomain);
1238 HeapFree(GetProcessHeap(), 0, pFileSD);
1241 HeapFree(GetProcessHeap(), 0, pNewACL);
1246 char *winErrorStr(const char *prefix, int dwErr)
1251 if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1252 NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
1255 err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);
1258 mem = strlen(err) + strlen(prefix) + 20;
1259 ret = (char *) malloc(mem);
1261 snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
1269 * Terminate a process by creating a remote thread within it,
1270 * which proceeds to call ExitProcess() inside that process.
1271 * Safer than TerminateProcess ().
1273 * Code is from From http://private-storm.de/2009/08/11/case-terminateprocess/
1275 * @param hProcess handle of a process to terminate
1276 * @param uExitCode exit code to use for ExitProcess()
1277 * @param dwTimeout number of ms to wait for the process to terminate
1278 * @return TRUE on success, FALSE on failure (check last error for the code)
1281 SafeTerminateProcess (HANDLE hProcess, UINT uExitCode, DWORD dwTimeout)
1283 DWORD dwTID, dwCode, dwErr = 0;
1284 HANDLE hProcessDup = INVALID_HANDLE_VALUE;
1286 HINSTANCE hKernel = GetModuleHandle ("Kernel32");
1287 BOOL bSuccess = FALSE;
1289 BOOL bDup = DuplicateHandle (GetCurrentProcess (), hProcess,
1290 GetCurrentProcess (), &hProcessDup, PROCESS_ALL_ACCESS,
1293 /* Detect the special case where the process is
1296 if (GetExitCodeProcess (bDup ? hProcessDup : hProcess, &dwCode) &&
1297 (STILL_ACTIVE == dwCode))
1299 FARPROC pfnExitProc;
1301 pfnExitProc = GetProcAddress (hKernel, "ExitProcess");
1303 hRT = CreateRemoteThread ((bDup) ? hProcessDup : hProcess, NULL, 0,
1304 (LPTHREAD_START_ROUTINE) pfnExitProc, (PVOID) uExitCode, 0, &dwTID);
1306 dwErr = GetLastError ();
1310 dwErr = ERROR_PROCESS_ABORTED;
1315 /* Must wait process to terminate to
1316 * guarantee that it has exited...
1318 DWORD dwWaitResult = WaitForSingleObject ((bDup) ? hProcessDup : hProcess,
1320 if (dwWaitResult == WAIT_TIMEOUT)
1321 dwErr = WAIT_TIMEOUT;
1323 dwErr = GetLastError ();
1326 bSuccess = dwErr == NO_ERROR;
1330 CloseHandle (hProcessDup);
1332 SetLastError (dwErr);