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 typedef list<WSAOVERLAPPED *> TOLList;
\r
47 static HANDLE hOLLock;
\r
48 static TOLList lstOL;
\r
50 int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);
\r
52 void __attribute__ ((constructor)) gnunet_win_init() {
\r
53 hOLLock = CreateMutex(NULL, FALSE, NULL);
\r
56 void __attribute__ ((destructor)) gnunet_win_fini() {
\r
57 CloseHandle(hOLLock);
\r
61 * Enumerate all network adapters
\r
63 void EnumNICs(PMIB_IFTABLE *pIfTable, PMIB_IPADDRTABLE *pAddrTable)
\r
65 DWORD dwSize, dwRet;
\r
76 *pIfTable = (MIB_IFTABLE *) GlobalAlloc(GPTR, sizeof(MIB_IFTABLE));
\r
78 /* Get size of table */
\r
79 if (GNGetIfTable(*pIfTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
\r
81 GlobalFree(*pIfTable);
\r
82 *pIfTable = (MIB_IFTABLE *) GlobalAlloc(GPTR, dwSize);
\r
85 if ((dwRet = GNGetIfTable(*pIfTable, &dwSize, 0)) == NO_ERROR &&
\r
88 DWORD dwIfIdx, dwSize = sizeof(MIB_IPADDRTABLE);
\r
89 *pAddrTable = (MIB_IPADDRTABLE *) GlobalAlloc(GPTR, dwSize);
\r
91 /* Make an initial call to GetIpAddrTable to get the
\r
93 if (GNGetIpAddrTable(*pAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
\r
95 GlobalFree(*pAddrTable);
\r
96 *pAddrTable = (MIB_IPADDRTABLE *) GlobalAlloc(GPTR, dwSize);
\r
98 GNGetIpAddrTable(*pAddrTable, &dwSize, 0);
\r
104 * Lists all network interfaces in a combo box
\r
105 * Used by the basic GTK configurator
\r
108 int ListNICs(void (*callback) (const char *, int, void *), void * cls)
\r
110 PMIB_IFTABLE pTable;
\r
111 PMIB_IPADDRTABLE pAddrTable;
\r
112 DWORD dwIfIdx, dwExternalNIC;
\r
115 /* Determine our external NIC */
\r
116 theIP = inet_addr("192.0.34.166"); /* www.example.com */
\r
117 if ((! GNGetBestInterface) ||
\r
118 (GNGetBestInterface(theIP, &dwExternalNIC) != NO_ERROR))
\r
123 /* Enumerate NICs */
\r
124 EnumNICs(&pTable, &pAddrTable);
\r
128 for(dwIfIdx=0; dwIfIdx <= pTable->dwNumEntries; dwIfIdx++)
\r
130 char szEntry[1001];
\r
133 PIP_ADAPTER_INFO pAdapterInfo;
\r
134 PIP_ADAPTER_INFO pAdapter = NULL;
\r
135 DWORD dwRetVal = 0;
\r
137 /* Get IP-Address */
\r
139 for(i = 0; i < pAddrTable->dwNumEntries; i++)
\r
141 if (pAddrTable->table[i].dwIndex == pTable->table[dwIfIdx].dwIndex)
\r
143 dwIP = pAddrTable->table[i].dwAddr;
\r
150 BYTE bPhysAddr[MAXLEN_PHYSADDR];
\r
151 char *pszIfName = NULL;
\r
152 char dst[INET_ADDRSTRLEN];
\r
154 /* Get friendly interface name */
\r
155 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
\r
156 ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
\r
158 /* Make an initial call to GetAdaptersInfo to get
\r
159 the necessary size into the ulOutBufLen variable */
\r
160 if (GGetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
\r
161 free(pAdapterInfo);
\r
162 pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
\r
165 if ((dwRetVal = GGetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
\r
166 pAdapter = pAdapterInfo;
\r
168 if (pTable->table[dwIfIdx].dwIndex == pAdapter->Index)
\r
173 sprintf(szKey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
\r
174 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection",
\r
175 pAdapter->AdapterName);
\r
176 pszIfName = (char *) malloc(251);
\r
177 if (QueryRegistry(HKEY_LOCAL_MACHINE, szKey, "Name", pszIfName,
\r
178 &lLen) != ERROR_SUCCESS)
\r
184 pAdapter = pAdapter->Next;
\r
187 free(pAdapterInfo);
\r
190 memset(bPhysAddr, 0, MAXLEN_PHYSADDR);
\r
192 pTable->table[dwIfIdx].bPhysAddr,
\r
193 pTable->table[dwIfIdx].dwPhysAddrLen);
\r
195 snprintf(szEntry, 1000, "%s (%s - %I64u)",
\r
196 pszIfName ? pszIfName : (char *) pTable->table[dwIfIdx].bDescr,
\r
197 inet_ntop (AF_INET, &dwIP, dst, INET_ADDRSTRLEN),
\r
198 *((unsigned long long *) bPhysAddr));
\r
204 callback(szEntry, pAddrTable->table[dwIfIdx].dwIndex == dwExternalNIC, cls);
\r
207 GlobalFree(pAddrTable);
\r
208 GlobalFree(pTable);
\r
215 * @brief Installs the Windows service
\r
216 * @param servicename name of the service as diplayed by the SCM
\r
217 * @param application path to the application binary
\r
218 * @param username the name of the service's user account
\r
219 * @returns 0 on success
\r
220 * 1 if the Windows version doesn't support services
\r
221 * 2 if the SCM could not be opened
\r
222 * 3 if the service could not be created
\r
224 int InstallAsService(char *servicename, char *application, char *username)
\r
226 SC_HANDLE hManager, hService;
\r
227 char szEXE[_MAX_PATH + 17] = "\"";
\r
230 if (! GNOpenSCManager)
\r
233 plibc_conv_to_win_path(application, szEXE + 1);
\r
234 strcat(szEXE, "\" --win-service");
\r
235 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
\r
241 user = (char *) malloc(strlen(username) + 3);
\r
242 sprintf(user, ".\\%s", username);
\r
245 hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
\r
246 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
\r
247 NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
\r
255 GNCloseServiceHandle(hService);
\r
261 * @brief Uninstall Windows service
\r
262 * @param servicename name of the service to delete
\r
263 * @returns 0 on success
\r
264 * 1 if the Windows version doesn't support services
\r
265 * 2 if the SCM could not be openend
\r
266 * 3 if the service cannot be accessed
\r
267 * 4 if the service cannot be deleted
\r
269 int UninstallService(char *servicename)
\r
271 SC_HANDLE hManager, hService;
\r
273 if (! GNOpenSCManager)
\r
276 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
\r
280 if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
\r
281 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
\r
286 if (! GNDeleteService(hService))
\r
287 if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
\r
291 GNCloseServiceHandle(hService);
\r
297 * @author Scott Field, Microsoft
\r
298 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
301 void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
\r
303 DWORD StringLength;
\r
307 LsaString->Buffer = NULL;
\r
308 LsaString->Length = 0;
\r
309 LsaString->MaximumLength = 0;
\r
313 StringLength = wcslen(String);
\r
314 LsaString->Buffer = String;
\r
315 LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
\r
316 LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
\r
321 * @author Scott Field, Microsoft
\r
322 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
325 NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
\r
327 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
\r
328 LSA_UNICODE_STRING ServerString;
\r
329 PLSA_UNICODE_STRING Server = NULL;
\r
331 /* Always initialize the object attributes to all zeroes. */
\r
332 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
\r
334 if(ServerName != NULL)
\r
336 /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
\r
337 _InitLsaString(&ServerString, ServerName);
\r
338 Server = &ServerString;
\r
341 /* Attempt to open the policy. */
\r
342 return GNLsaOpenPolicy(Server,
\r
343 &ObjectAttributes, DesiredAccess, PolicyHandle);
\r
347 * @brief Obtain a SID representing the supplied account on the supplied system
\r
348 * @return TRUE on success, FALSE on failure
\r
349 * @author Scott Field, Microsoft
\r
351 * @remarks A buffer is allocated which contains the SID representing the
\r
352 * supplied account. This buffer should be freed when it is no longer
\r
353 * needed by calling\n
\r
354 * HeapFree(GetProcessHeap(), 0, buffer)
\r
355 * @remarks Call GetLastError() to obtain extended error information.
\r
356 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
358 BOOL _GetAccountSid(LPTSTR SystemName, LPTSTR AccountName, PSID * Sid)
\r
360 LPTSTR ReferencedDomain = NULL;
\r
361 DWORD cbSid = 128; /* initial allocation attempt */
\r
362 DWORD cchReferencedDomain = 16; /* initial allocation size */
\r
363 SID_NAME_USE peUse;
\r
364 BOOL bSuccess = FALSE; /* assume this function will fail */
\r
366 /* initial memory allocations */
\r
367 if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
\r
370 if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
\r
372 cchReferencedDomain *
\r
373 sizeof (TCHAR))) == NULL)
\r
376 /* Obtain the SID of the specified account on the specified system. */
\r
377 while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
\r
378 AccountName, /* account to lookup */
\r
379 *Sid, /* SID of interest */
\r
380 &cbSid, /* size of SID */
\r
381 ReferencedDomain, /* domain account was found on */
\r
382 &cchReferencedDomain, &peUse))
\r
384 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
\r
386 /* reallocate memory */
\r
387 if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
\r
390 if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
\r
393 cchReferencedDomain
\r
394 * sizeof (TCHAR))) == NULL)
\r
401 /* Indicate success. */
\r
405 /* Cleanup and indicate failure, if appropriate. */
\r
406 HeapFree (GetProcessHeap (), 0, ReferencedDomain);
\r
412 HeapFree (GetProcessHeap (), 0, *Sid);
\r
421 * @author Scott Field, Microsoft
\r
422 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
425 NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
\r
426 PSID AccountSid, /* SID to grant privilege to */
\r
427 LPWSTR PrivilegeName, /* privilege to grant (Unicode) */
\r
428 BOOL bEnable /* enable or disable */
\r
431 LSA_UNICODE_STRING PrivilegeString;
\r
433 /* Create a LSA_UNICODE_STRING for the privilege name. */
\r
434 _InitLsaString(&PrivilegeString, PrivilegeName);
\r
436 /* grant or revoke the privilege, accordingly */
\r
441 i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */
\r
442 AccountSid, /* target SID */
\r
443 &PrivilegeString, /* privileges */
\r
444 1 /* privilege count */
\r
449 return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */
\r
450 AccountSid, /* target SID */
\r
451 FALSE, /* do not disable all rights */
\r
452 &PrivilegeString, /* privileges */
\r
453 1 /* privilege count */
\r
459 * @brief Create a Windows service account
\r
460 * @return 0 on success, > 0 otherwise
\r
461 * @param pszName the name of the account
\r
462 * @param pszDesc description of the account
\r
464 int CreateServiceAccount(char *pszName, char *pszDesc)
\r
467 USER_INFO_1008 ui2;
\r
468 NET_API_STATUS nStatus;
\r
469 wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
\r
471 LSA_HANDLE hPolicy;
\r
474 if (! GNNetUserAdd)
\r
476 mbstowcs(wszName, pszName, strlen(pszName) + 1);
\r
477 mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
\r
479 memset(&ui, 0, sizeof(ui));
\r
480 ui.usri1_name = wszName;
\r
481 ui.usri1_password = wszName; /* account is locked anyway */
\r
482 ui.usri1_priv = USER_PRIV_USER;
\r
483 ui.usri1_comment = wszDesc;
\r
484 ui.usri1_flags = UF_SCRIPT;
\r
486 nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
\r
488 if (nStatus != NERR_Success && nStatus != NERR_UserExists)
\r
491 ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
\r
492 GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
\r
494 if (_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy) !=
\r
498 _GetAccountSid(NULL, (LPTSTR) pszName, &pSID);
\r
500 if (_SetPrivilegeOnAccount(hPolicy, pSID, L"SeServiceLogonRight", TRUE) != STATUS_SUCCESS)
\r
503 _SetPrivilegeOnAccount(hPolicy, pSID, L"SeDenyInteractiveLogonRight", TRUE);
\r
504 _SetPrivilegeOnAccount(hPolicy, pSID, L"SeDenyBatchLogonRight", TRUE);
\r
505 _SetPrivilegeOnAccount(hPolicy, pSID, L"SeDenyNetworkLogonRight", TRUE);
\r
507 GNLsaClose(hPolicy);
\r
513 * @brief Grant permission to a file
\r
514 * @param lpszFileName the name of the file or directory
\r
515 * @param lpszAccountName the user account
\r
516 * @param the desired access (e.g. GENERIC_ALL)
\r
517 * @return TRUE on success
\r
518 * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
\r
520 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
\r
521 DWORD dwAccessMask)
\r
523 /* SID variables. */
\r
524 SID_NAME_USE snuType;
\r
525 TCHAR * szDomain = NULL;
\r
526 DWORD cbDomain = 0;
\r
527 LPVOID pUserSID = NULL;
\r
528 DWORD cbUserSID = 0;
\r
530 /* File SD variables. */
\r
531 PSECURITY_DESCRIPTOR pFileSD = NULL;
\r
532 DWORD cbFileSD = 0;
\r
534 /* New SD variables. */
\r
535 SECURITY_DESCRIPTOR newSD;
\r
537 /* ACL variables. */
\r
540 BOOL fDaclDefaulted;
\r
541 ACL_SIZE_INFORMATION AclInfo;
\r
543 /* New ACL variables. */
\r
544 PACL pNewACL = NULL;
\r
545 DWORD cbNewACL = 0;
\r
547 /* Temporary ACE. */
\r
548 LPVOID pTempAce = NULL;
\r
549 UINT CurrentAceIndex = 0;
\r
551 UINT newAceIndex = 0;
\r
553 /* Assume function will fail. */
\r
554 BOOL fResult = FALSE;
\r
557 SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
\r
560 * STEP 1: Get SID of the account name specified.
\r
562 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
\r
563 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
\r
565 /* API should have failed with insufficient buffer. */
\r
568 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
\r
572 pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
\r
577 szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
\r
582 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
\r
583 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
\r
584 if (!fAPISuccess) {
\r
589 * STEP 2: Get security descriptor (SD) of the file specified.
\r
591 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
\r
592 secInfo, pFileSD, 0, &cbFileSD);
\r
594 /* API should have failed with insufficient buffer. */
\r
597 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
\r
601 pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
\r
607 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
\r
608 secInfo, pFileSD, cbFileSD, &cbFileSD);
\r
609 if (!fAPISuccess) {
\r
614 * STEP 3: Initialize new SD.
\r
616 if (!GNInitializeSecurityDescriptor(&newSD,
\r
617 SECURITY_DESCRIPTOR_REVISION)) {
\r
622 * STEP 4: Get DACL from the old SD.
\r
624 if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
\r
625 &fDaclDefaulted)) {
\r
630 * STEP 5: Get size information for DACL.
\r
632 AclInfo.AceCount = 0; // Assume NULL DACL.
\r
633 AclInfo.AclBytesFree = 0;
\r
634 AclInfo.AclBytesInUse = sizeof(ACL);
\r
637 fDaclPresent = FALSE;
\r
639 /* If not NULL DACL, gather size information from DACL. */
\r
640 if (fDaclPresent) {
\r
642 if (!GNGetAclInformation(pACL, &AclInfo,
\r
643 sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
\r
649 * STEP 6: Compute size needed for the new ACL.
\r
651 cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
\r
652 + GetLengthSid(pUserSID) - sizeof(DWORD);
\r
655 * STEP 7: Allocate memory for new ACL.
\r
657 pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
\r
663 * STEP 8: Initialize the new ACL.
\r
665 if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
\r
670 * STEP 9 If DACL is present, copy all the ACEs from the old DACL
\r
673 * The following code assumes that the old DACL is
\r
674 * already in Windows 2000 preferred order. To conform
\r
675 * to the new Windows 2000 preferred order, first we will
\r
676 * copy all non-inherited ACEs from the old DACL to the
\r
677 * new DACL, irrespective of the ACE type.
\r
682 if (fDaclPresent && AclInfo.AceCount) {
\r
684 for (CurrentAceIndex = 0;
\r
685 CurrentAceIndex < AclInfo.AceCount;
\r
686 CurrentAceIndex++) {
\r
689 * TEP 10: Get an ACE.
\r
691 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
\r
696 * STEP 11: Check if it is a non-inherited ACE.
\r
697 * If it is an inherited ACE, break from the loop so
\r
698 * that the new access allowed non-inherited ACE can
\r
699 * be added in the correct position, immediately after
\r
700 * all non-inherited ACEs.
\r
702 if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
\r
707 * STEP 12: Skip adding the ACE, if the SID matches
\r
708 * with the account specified, as we are going to
\r
709 * add an access allowed ACE with a different access
\r
712 if (GNEqualSid(pUserSID,
\r
713 &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
\r
717 * STEP 13: Add the ACE to the new ACL.
\r
719 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
\r
720 ((PACE_HEADER) pTempAce)->AceSize)) {
\r
729 * STEP 14: Add the access-allowed ACE to the new DACL.
\r
730 * The new ACE added here will be in the correct position,
\r
731 * immediately after all existing non-inherited ACEs.
\r
733 if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
\r
739 * STEP 14.5: Make new ACE inheritable
\r
741 if (!GetAce(pNewACL, newAceIndex, &pTempAce))
\r
743 ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
\r
744 (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
\r
747 * STEP 15: To conform to the new Windows 2000 preferred order,
\r
748 * we will now copy the rest of inherited ACEs from the
\r
749 * old DACL to the new DACL.
\r
751 if (fDaclPresent && AclInfo.AceCount) {
\r
754 CurrentAceIndex < AclInfo.AceCount;
\r
755 CurrentAceIndex++) {
\r
758 * STEP 16: Get an ACE.
\r
760 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
\r
765 * STEP 17: Add the ACE to the new ACL.
\r
767 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
\r
768 ((PACE_HEADER) pTempAce)->AceSize)) {
\r
775 * STEP 18: Set permissions
\r
777 if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
\r
778 DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
\r
787 * STEP 19: Free allocated memory
\r
790 HeapFree(GetProcessHeap(), 0, pUserSID);
\r
793 HeapFree(GetProcessHeap(), 0, szDomain);
\r
796 HeapFree(GetProcessHeap(), 0, pFileSD);
\r
799 HeapFree(GetProcessHeap(), 0, pNewACL);
\r
804 char *winErrorStr(const char *prefix, int dwErr)
\r
809 if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
\r
810 NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
\r
816 mem = strlen(err) + strlen(prefix) + 20;
\r
817 ret = (char *) malloc(mem);
\r
819 snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
\r