2 This file is part of GNUnet.
\r
3 (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors)
\r
5 GNUnet is free software; you can redistribute it and/or modify
\r
6 it under the terms of the GNU General Public License as published
\r
7 by the Free Software Foundation; either version 2, or (at your
\r
8 option) any later version.
\r
10 GNUnet is distributed in the hope that it will be useful, but
\r
11 WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
13 General Public License for more details.
\r
15 You should have received a copy of the GNU General Public License
\r
16 along with GNUnet; see the file COPYING. If not, write to the
\r
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
\r
18 Boston, MA 02111-1307, USA.
\r
23 * @brief Helper functions for MS Windows in C++
\r
24 * @author Nils Durner
\r
30 #include "winproc.h"
\r
31 #include "platform.h"
\r
32 #include "gnunet_common.h"
\r
33 #include "gnunet_connection_lib.h"
\r
36 using namespace std;
\r
39 #ifndef INHERITED_ACE
\r
40 #define INHERITED_ACE 0x10
\r
45 int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);
\r
48 * Enumerate all network adapters
\r
50 void EnumNICs(PMIB_IFTABLE *pIfTable, PMIB_IPADDRTABLE *pAddrTable)
\r
52 DWORD dwSize, dwRet;
\r
63 *pIfTable = (MIB_IFTABLE *) GlobalAlloc(GPTR, sizeof(MIB_IFTABLE));
\r
65 /* Get size of table */
\r
66 if (GNGetIfTable(*pIfTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
\r
68 GlobalFree(*pIfTable);
\r
69 *pIfTable = (MIB_IFTABLE *) GlobalAlloc(GPTR, dwSize);
\r
72 if ((dwRet = GNGetIfTable(*pIfTable, &dwSize, 0)) == NO_ERROR &&
\r
75 DWORD dwIfIdx, dwSize = sizeof(MIB_IPADDRTABLE);
\r
76 *pAddrTable = (MIB_IPADDRTABLE *) GlobalAlloc(GPTR, dwSize);
\r
78 /* Make an initial call to GetIpAddrTable to get the
\r
80 if (GNGetIpAddrTable(*pAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
\r
82 GlobalFree(*pAddrTable);
\r
83 *pAddrTable = (MIB_IPADDRTABLE *) GlobalAlloc(GPTR, dwSize);
\r
85 GNGetIpAddrTable(*pAddrTable, &dwSize, 0);
\r
91 * Lists all network interfaces in a combo box
\r
92 * Used by the basic GTK configurator
\r
94 * @param callback function to call for each NIC
\r
95 * @param callback_cls closure for callback
\r
97 int ListNICs(void (*callback) (void *, const char *, int), void * callback_cls)
\r
99 PMIB_IFTABLE pTable;
\r
100 PMIB_IPADDRTABLE pAddrTable;
\r
101 DWORD dwIfIdx, dwExternalNIC;
\r
104 /* Determine our external NIC */
\r
105 theIP = inet_addr("192.0.34.166"); /* www.example.com */
\r
106 if ((! GNGetBestInterface) ||
\r
107 (GNGetBestInterface(theIP, &dwExternalNIC) != NO_ERROR))
\r
112 /* Enumerate NICs */
\r
113 EnumNICs(&pTable, &pAddrTable);
\r
117 for(dwIfIdx=0; dwIfIdx <= pTable->dwNumEntries; dwIfIdx++)
\r
119 char szEntry[1001];
\r
122 PIP_ADAPTER_INFO pAdapterInfo;
\r
123 PIP_ADAPTER_INFO pAdapter = NULL;
\r
124 DWORD dwRetVal = 0;
\r
126 /* Get IP-Address */
\r
128 for(i = 0; i < pAddrTable->dwNumEntries; i++)
\r
130 if (pAddrTable->table[i].dwIndex == pTable->table[dwIfIdx].dwIndex)
\r
132 dwIP = pAddrTable->table[i].dwAddr;
\r
139 BYTE bPhysAddr[MAXLEN_PHYSADDR];
\r
140 char *pszIfName = NULL;
\r
141 char dst[INET_ADDRSTRLEN];
\r
143 /* Get friendly interface name */
\r
144 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
\r
145 ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
\r
147 /* Make an initial call to GetAdaptersInfo to get
\r
148 the necessary size into the ulOutBufLen variable */
\r
149 if (GGetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
\r
150 free(pAdapterInfo);
\r
151 pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
\r
154 if ((dwRetVal = GGetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
\r
155 pAdapter = pAdapterInfo;
\r
157 if (pTable->table[dwIfIdx].dwIndex == pAdapter->Index)
\r
162 sprintf(szKey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
\r
163 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection",
\r
164 pAdapter->AdapterName);
\r
165 pszIfName = (char *) malloc(251);
\r
166 if (QueryRegistry(HKEY_LOCAL_MACHINE, szKey, "Name", pszIfName,
\r
167 &lLen) != ERROR_SUCCESS)
\r
173 pAdapter = pAdapter->Next;
\r
176 free(pAdapterInfo);
\r
179 memset(bPhysAddr, 0, MAXLEN_PHYSADDR);
\r
181 pTable->table[dwIfIdx].bPhysAddr,
\r
182 pTable->table[dwIfIdx].dwPhysAddrLen);
\r
184 snprintf(szEntry, 1000, "%s (%s - %I64u)",
\r
185 pszIfName ? pszIfName : (char *) pTable->table[dwIfIdx].bDescr,
\r
186 inet_ntop (AF_INET, &dwIP, dst, INET_ADDRSTRLEN),
\r
187 *((unsigned long long *) bPhysAddr));
\r
193 callback(callback_cls,
\r
195 pAddrTable->table[dwIfIdx].dwIndex == dwExternalNIC);
\r
198 GlobalFree(pAddrTable);
\r
199 GlobalFree(pTable);
\r
206 * @brief Installs the Windows service
\r
207 * @param servicename name of the service as diplayed by the SCM
\r
208 * @param application path to the application binary
\r
209 * @param username the name of the service's user account
\r
210 * @returns 0 on success
\r
211 * 1 if the Windows version doesn't support services
\r
212 * 2 if the SCM could not be opened
\r
213 * 3 if the service could not be created
\r
215 int InstallAsService(char *servicename, char *application, char *username)
\r
217 SC_HANDLE hManager, hService;
\r
218 char szEXE[_MAX_PATH + 17] = "\"";
\r
221 if (! GNOpenSCManager)
\r
224 plibc_conv_to_win_path(application, szEXE + 1);
\r
225 strcat(szEXE, "\" --win-service");
\r
226 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
\r
232 user = (char *) malloc(strlen(username) + 3);
\r
233 sprintf(user, ".\\%s", username);
\r
236 hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
\r
237 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
\r
238 NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
\r
246 GNCloseServiceHandle(hService);
\r
252 * @brief Uninstall Windows service
\r
253 * @param servicename name of the service to delete
\r
254 * @returns 0 on success
\r
255 * 1 if the Windows version doesn't support services
\r
256 * 2 if the SCM could not be openend
\r
257 * 3 if the service cannot be accessed
\r
258 * 4 if the service cannot be deleted
\r
260 int UninstallService(char *servicename)
\r
262 SC_HANDLE hManager, hService;
\r
264 if (! GNOpenSCManager)
\r
267 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
\r
271 if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
\r
272 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
\r
277 if (! GNDeleteService(hService))
\r
278 if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
\r
282 GNCloseServiceHandle(hService);
\r
288 * @author Scott Field, Microsoft
\r
289 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
292 void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
\r
294 DWORD StringLength;
\r
298 LsaString->Buffer = NULL;
\r
299 LsaString->Length = 0;
\r
300 LsaString->MaximumLength = 0;
\r
304 StringLength = wcslen(String);
\r
305 LsaString->Buffer = String;
\r
306 LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
\r
307 LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
\r
312 * @author Scott Field, Microsoft
\r
313 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
316 NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
\r
318 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
\r
319 LSA_UNICODE_STRING ServerString;
\r
320 PLSA_UNICODE_STRING Server = NULL;
\r
322 /* Always initialize the object attributes to all zeroes. */
\r
323 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
\r
325 if(ServerName != NULL)
\r
327 /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
\r
328 _InitLsaString(&ServerString, ServerName);
\r
329 Server = &ServerString;
\r
332 /* Attempt to open the policy. */
\r
333 return GNLsaOpenPolicy(Server,
\r
334 &ObjectAttributes, DesiredAccess, PolicyHandle);
\r
338 * @brief Obtain a SID representing the supplied account on the supplied system
\r
339 * @return TRUE on success, FALSE on failure
\r
340 * @author Scott Field, Microsoft
\r
342 * @remarks A buffer is allocated which contains the SID representing the
\r
343 * supplied account. This buffer should be freed when it is no longer
\r
344 * needed by calling\n
\r
345 * HeapFree(GetProcessHeap(), 0, buffer)
\r
346 * @remarks Call GetLastError() to obtain extended error information.
\r
347 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
349 BOOL _GetAccountSid(LPTSTR SystemName, LPTSTR AccountName, PSID * Sid)
\r
351 LPTSTR ReferencedDomain = NULL;
\r
352 DWORD cbSid = 128; /* initial allocation attempt */
\r
353 DWORD cchReferencedDomain = 16; /* initial allocation size */
\r
354 SID_NAME_USE peUse;
\r
355 BOOL bSuccess = FALSE; /* assume this function will fail */
\r
357 /* initial memory allocations */
\r
358 if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
\r
361 if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
\r
363 cchReferencedDomain *
\r
364 sizeof (TCHAR))) == NULL)
\r
367 /* Obtain the SID of the specified account on the specified system. */
\r
368 while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
\r
369 AccountName, /* account to lookup */
\r
370 *Sid, /* SID of interest */
\r
371 &cbSid, /* size of SID */
\r
372 ReferencedDomain, /* domain account was found on */
\r
373 &cchReferencedDomain, &peUse))
\r
375 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
\r
377 /* reallocate memory */
\r
378 if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
\r
381 if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
\r
384 cchReferencedDomain
\r
385 * sizeof (TCHAR))) == NULL)
\r
392 /* Indicate success. */
\r
396 /* Cleanup and indicate failure, if appropriate. */
\r
397 HeapFree (GetProcessHeap (), 0, ReferencedDomain);
\r
403 HeapFree (GetProcessHeap (), 0, *Sid);
\r
412 * @author Scott Field, Microsoft
\r
413 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
416 NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
\r
417 PSID AccountSid, /* SID to grant privilege to */
\r
418 LPWSTR PrivilegeName, /* privilege to grant (Unicode) */
\r
419 BOOL bEnable /* enable or disable */
\r
422 LSA_UNICODE_STRING PrivilegeString;
\r
424 /* Create a LSA_UNICODE_STRING for the privilege name. */
\r
425 _InitLsaString(&PrivilegeString, PrivilegeName);
\r
427 /* grant or revoke the privilege, accordingly */
\r
432 i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */
\r
433 AccountSid, /* target SID */
\r
434 &PrivilegeString, /* privileges */
\r
435 1 /* privilege count */
\r
440 return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */
\r
441 AccountSid, /* target SID */
\r
442 FALSE, /* do not disable all rights */
\r
443 &PrivilegeString, /* privileges */
\r
444 1 /* privilege count */
\r
450 * @brief Create a Windows service account
\r
451 * @return 0 on success, > 0 otherwise
\r
452 * @param pszName the name of the account
\r
453 * @param pszDesc description of the account
\r
455 int CreateServiceAccount(char *pszName, char *pszDesc)
\r
458 USER_INFO_1008 ui2;
\r
459 NET_API_STATUS nStatus;
\r
460 wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
\r
462 LSA_HANDLE hPolicy;
\r
465 if (! GNNetUserAdd)
\r
467 mbstowcs(wszName, pszName, strlen(pszName) + 1);
\r
468 mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
\r
470 memset(&ui, 0, sizeof(ui));
\r
471 ui.usri1_name = wszName;
\r
472 ui.usri1_password = wszName; /* account is locked anyway */
\r
473 ui.usri1_priv = USER_PRIV_USER;
\r
474 ui.usri1_comment = wszDesc;
\r
475 ui.usri1_flags = UF_SCRIPT;
\r
477 nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
\r
479 if (nStatus != NERR_Success && nStatus != NERR_UserExists)
\r
482 ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
\r
483 GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
\r
485 if (_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy) !=
\r
489 _GetAccountSid(NULL, (LPTSTR) pszName, &pSID);
\r
491 if (_SetPrivilegeOnAccount(hPolicy, pSID, L"SeServiceLogonRight", TRUE) != STATUS_SUCCESS)
\r
494 _SetPrivilegeOnAccount(hPolicy, pSID, L"SeDenyInteractiveLogonRight", TRUE);
\r
495 _SetPrivilegeOnAccount(hPolicy, pSID, L"SeDenyBatchLogonRight", TRUE);
\r
496 _SetPrivilegeOnAccount(hPolicy, pSID, L"SeDenyNetworkLogonRight", TRUE);
\r
498 GNLsaClose(hPolicy);
\r
504 * @brief Grant permission to a file
\r
505 * @param lpszFileName the name of the file or directory
\r
506 * @param lpszAccountName the user account
\r
507 * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
\r
508 * @return TRUE on success
\r
509 * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
\r
511 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
\r
512 DWORD dwAccessMask)
\r
514 /* SID variables. */
\r
515 SID_NAME_USE snuType;
\r
516 TCHAR * szDomain = NULL;
\r
517 DWORD cbDomain = 0;
\r
518 LPVOID pUserSID = NULL;
\r
519 DWORD cbUserSID = 0;
\r
521 /* File SD variables. */
\r
522 PSECURITY_DESCRIPTOR pFileSD = NULL;
\r
523 DWORD cbFileSD = 0;
\r
525 /* New SD variables. */
\r
526 SECURITY_DESCRIPTOR newSD;
\r
528 /* ACL variables. */
\r
531 BOOL fDaclDefaulted;
\r
532 ACL_SIZE_INFORMATION AclInfo;
\r
534 /* New ACL variables. */
\r
535 PACL pNewACL = NULL;
\r
536 DWORD cbNewACL = 0;
\r
538 /* Temporary ACE. */
\r
539 LPVOID pTempAce = NULL;
\r
540 UINT CurrentAceIndex = 0;
\r
542 UINT newAceIndex = 0;
\r
544 /* Assume function will fail. */
\r
545 BOOL fResult = FALSE;
\r
548 SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
\r
551 * STEP 1: Get SID of the account name specified.
\r
553 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
\r
554 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
\r
556 /* API should have failed with insufficient buffer. */
\r
559 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
\r
563 pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
\r
568 szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
\r
573 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
\r
574 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
\r
575 if (!fAPISuccess) {
\r
580 * STEP 2: Get security descriptor (SD) of the file specified.
\r
582 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
\r
583 secInfo, pFileSD, 0, &cbFileSD);
\r
585 /* API should have failed with insufficient buffer. */
\r
588 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
\r
592 pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
\r
598 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
\r
599 secInfo, pFileSD, cbFileSD, &cbFileSD);
\r
600 if (!fAPISuccess) {
\r
605 * STEP 3: Initialize new SD.
\r
607 if (!GNInitializeSecurityDescriptor(&newSD,
\r
608 SECURITY_DESCRIPTOR_REVISION)) {
\r
613 * STEP 4: Get DACL from the old SD.
\r
615 if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
\r
616 &fDaclDefaulted)) {
\r
621 * STEP 5: Get size information for DACL.
\r
623 AclInfo.AceCount = 0; // Assume NULL DACL.
\r
624 AclInfo.AclBytesFree = 0;
\r
625 AclInfo.AclBytesInUse = sizeof(ACL);
\r
628 fDaclPresent = FALSE;
\r
630 /* If not NULL DACL, gather size information from DACL. */
\r
631 if (fDaclPresent) {
\r
633 if (!GNGetAclInformation(pACL, &AclInfo,
\r
634 sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
\r
640 * STEP 6: Compute size needed for the new ACL.
\r
642 cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
\r
643 + GetLengthSid(pUserSID) - sizeof(DWORD);
\r
646 * STEP 7: Allocate memory for new ACL.
\r
648 pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
\r
654 * STEP 8: Initialize the new ACL.
\r
656 if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
\r
661 * STEP 9 If DACL is present, copy all the ACEs from the old DACL
\r
664 * The following code assumes that the old DACL is
\r
665 * already in Windows 2000 preferred order. To conform
\r
666 * to the new Windows 2000 preferred order, first we will
\r
667 * copy all non-inherited ACEs from the old DACL to the
\r
668 * new DACL, irrespective of the ACE type.
\r
673 if (fDaclPresent && AclInfo.AceCount) {
\r
675 for (CurrentAceIndex = 0;
\r
676 CurrentAceIndex < AclInfo.AceCount;
\r
677 CurrentAceIndex++) {
\r
680 * TEP 10: Get an ACE.
\r
682 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
\r
687 * STEP 11: Check if it is a non-inherited ACE.
\r
688 * If it is an inherited ACE, break from the loop so
\r
689 * that the new access allowed non-inherited ACE can
\r
690 * be added in the correct position, immediately after
\r
691 * all non-inherited ACEs.
\r
693 if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
\r
698 * STEP 12: Skip adding the ACE, if the SID matches
\r
699 * with the account specified, as we are going to
\r
700 * add an access allowed ACE with a different access
\r
703 if (GNEqualSid(pUserSID,
\r
704 &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
\r
708 * STEP 13: Add the ACE to the new ACL.
\r
710 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
\r
711 ((PACE_HEADER) pTempAce)->AceSize)) {
\r
720 * STEP 14: Add the access-allowed ACE to the new DACL.
\r
721 * The new ACE added here will be in the correct position,
\r
722 * immediately after all existing non-inherited ACEs.
\r
724 if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
\r
730 * STEP 14.5: Make new ACE inheritable
\r
732 if (!GetAce(pNewACL, newAceIndex, &pTempAce))
\r
734 ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
\r
735 (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
\r
738 * STEP 15: To conform to the new Windows 2000 preferred order,
\r
739 * we will now copy the rest of inherited ACEs from the
\r
740 * old DACL to the new DACL.
\r
742 if (fDaclPresent && AclInfo.AceCount) {
\r
745 CurrentAceIndex < AclInfo.AceCount;
\r
746 CurrentAceIndex++) {
\r
749 * STEP 16: Get an ACE.
\r
751 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
\r
756 * STEP 17: Add the ACE to the new ACL.
\r
758 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
\r
759 ((PACE_HEADER) pTempAce)->AceSize)) {
\r
766 * STEP 18: Set permissions
\r
768 if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
\r
769 DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
\r
778 * STEP 19: Free allocated memory
\r
781 HeapFree(GetProcessHeap(), 0, pUserSID);
\r
784 HeapFree(GetProcessHeap(), 0, szDomain);
\r
787 HeapFree(GetProcessHeap(), 0, pFileSD);
\r
790 HeapFree(GetProcessHeap(), 0, pNewACL);
\r
795 char *winErrorStr(const char *prefix, int dwErr)
\r
800 if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
\r
801 NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
\r
807 mem = strlen(err) + strlen(prefix) + 20;
\r
808 ret = (char *) malloc(mem);
\r
810 snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
\r