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
107 * @param callback function to call for each NIC
\r
108 * @param callback_cls closure for callback
\r
110 int ListNICs(void (*callback) (void *, const char *, int), void * callback_cls)
\r
112 PMIB_IFTABLE pTable;
\r
113 PMIB_IPADDRTABLE pAddrTable;
\r
114 DWORD dwIfIdx, dwExternalNIC;
\r
117 /* Determine our external NIC */
\r
118 theIP = inet_addr("192.0.34.166"); /* www.example.com */
\r
119 if ((! GNGetBestInterface) ||
\r
120 (GNGetBestInterface(theIP, &dwExternalNIC) != NO_ERROR))
\r
125 /* Enumerate NICs */
\r
126 EnumNICs(&pTable, &pAddrTable);
\r
130 for(dwIfIdx=0; dwIfIdx <= pTable->dwNumEntries; dwIfIdx++)
\r
132 char szEntry[1001];
\r
135 PIP_ADAPTER_INFO pAdapterInfo;
\r
136 PIP_ADAPTER_INFO pAdapter = NULL;
\r
137 DWORD dwRetVal = 0;
\r
139 /* Get IP-Address */
\r
141 for(i = 0; i < pAddrTable->dwNumEntries; i++)
\r
143 if (pAddrTable->table[i].dwIndex == pTable->table[dwIfIdx].dwIndex)
\r
145 dwIP = pAddrTable->table[i].dwAddr;
\r
152 BYTE bPhysAddr[MAXLEN_PHYSADDR];
\r
153 char *pszIfName = NULL;
\r
154 char dst[INET_ADDRSTRLEN];
\r
156 /* Get friendly interface name */
\r
157 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
\r
158 ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
\r
160 /* Make an initial call to GetAdaptersInfo to get
\r
161 the necessary size into the ulOutBufLen variable */
\r
162 if (GGetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
\r
163 free(pAdapterInfo);
\r
164 pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
\r
167 if ((dwRetVal = GGetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
\r
168 pAdapter = pAdapterInfo;
\r
170 if (pTable->table[dwIfIdx].dwIndex == pAdapter->Index)
\r
175 sprintf(szKey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
\r
176 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection",
\r
177 pAdapter->AdapterName);
\r
178 pszIfName = (char *) malloc(251);
\r
179 if (QueryRegistry(HKEY_LOCAL_MACHINE, szKey, "Name", pszIfName,
\r
180 &lLen) != ERROR_SUCCESS)
\r
186 pAdapter = pAdapter->Next;
\r
189 free(pAdapterInfo);
\r
192 memset(bPhysAddr, 0, MAXLEN_PHYSADDR);
\r
194 pTable->table[dwIfIdx].bPhysAddr,
\r
195 pTable->table[dwIfIdx].dwPhysAddrLen);
\r
197 snprintf(szEntry, 1000, "%s (%s - %I64u)",
\r
198 pszIfName ? pszIfName : (char *) pTable->table[dwIfIdx].bDescr,
\r
199 inet_ntop (AF_INET, &dwIP, dst, INET_ADDRSTRLEN),
\r
200 *((unsigned long long *) bPhysAddr));
\r
206 callback(callback_cls,
\r
208 pAddrTable->table[dwIfIdx].dwIndex == dwExternalNIC);
\r
211 GlobalFree(pAddrTable);
\r
212 GlobalFree(pTable);
\r
219 * @brief Installs the Windows service
\r
220 * @param servicename name of the service as diplayed by the SCM
\r
221 * @param application path to the application binary
\r
222 * @param username the name of the service's user account
\r
223 * @returns 0 on success
\r
224 * 1 if the Windows version doesn't support services
\r
225 * 2 if the SCM could not be opened
\r
226 * 3 if the service could not be created
\r
228 int InstallAsService(char *servicename, char *application, char *username)
\r
230 SC_HANDLE hManager, hService;
\r
231 char szEXE[_MAX_PATH + 17] = "\"";
\r
234 if (! GNOpenSCManager)
\r
237 plibc_conv_to_win_path(application, szEXE + 1);
\r
238 strcat(szEXE, "\" --win-service");
\r
239 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
\r
245 user = (char *) malloc(strlen(username) + 3);
\r
246 sprintf(user, ".\\%s", username);
\r
249 hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,
\r
250 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,
\r
251 NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);
\r
259 GNCloseServiceHandle(hService);
\r
265 * @brief Uninstall Windows service
\r
266 * @param servicename name of the service to delete
\r
267 * @returns 0 on success
\r
268 * 1 if the Windows version doesn't support services
\r
269 * 2 if the SCM could not be openend
\r
270 * 3 if the service cannot be accessed
\r
271 * 4 if the service cannot be deleted
\r
273 int UninstallService(char *servicename)
\r
275 SC_HANDLE hManager, hService;
\r
277 if (! GNOpenSCManager)
\r
280 hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
\r
284 if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))
\r
285 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
\r
290 if (! GNDeleteService(hService))
\r
291 if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
\r
295 GNCloseServiceHandle(hService);
\r
301 * @author Scott Field, Microsoft
\r
302 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
305 void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
\r
307 DWORD StringLength;
\r
311 LsaString->Buffer = NULL;
\r
312 LsaString->Length = 0;
\r
313 LsaString->MaximumLength = 0;
\r
317 StringLength = wcslen(String);
\r
318 LsaString->Buffer = String;
\r
319 LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);
\r
320 LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
\r
325 * @author Scott Field, Microsoft
\r
326 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
329 NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
\r
331 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
\r
332 LSA_UNICODE_STRING ServerString;
\r
333 PLSA_UNICODE_STRING Server = NULL;
\r
335 /* Always initialize the object attributes to all zeroes. */
\r
336 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
\r
338 if(ServerName != NULL)
\r
340 /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */
\r
341 _InitLsaString(&ServerString, ServerName);
\r
342 Server = &ServerString;
\r
345 /* Attempt to open the policy. */
\r
346 return GNLsaOpenPolicy(Server,
\r
347 &ObjectAttributes, DesiredAccess, PolicyHandle);
\r
351 * @brief Obtain a SID representing the supplied account on the supplied system
\r
352 * @return TRUE on success, FALSE on failure
\r
353 * @author Scott Field, Microsoft
\r
355 * @remarks A buffer is allocated which contains the SID representing the
\r
356 * supplied account. This buffer should be freed when it is no longer
\r
357 * needed by calling\n
\r
358 * HeapFree(GetProcessHeap(), 0, buffer)
\r
359 * @remarks Call GetLastError() to obtain extended error information.
\r
360 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
362 BOOL _GetAccountSid(LPTSTR SystemName, LPTSTR AccountName, PSID * Sid)
\r
364 LPTSTR ReferencedDomain = NULL;
\r
365 DWORD cbSid = 128; /* initial allocation attempt */
\r
366 DWORD cchReferencedDomain = 16; /* initial allocation size */
\r
367 SID_NAME_USE peUse;
\r
368 BOOL bSuccess = FALSE; /* assume this function will fail */
\r
370 /* initial memory allocations */
\r
371 if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)
\r
374 if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),
\r
376 cchReferencedDomain *
\r
377 sizeof (TCHAR))) == NULL)
\r
380 /* Obtain the SID of the specified account on the specified system. */
\r
381 while (!GNLookupAccountName(SystemName, /* machine to lookup account on */
\r
382 AccountName, /* account to lookup */
\r
383 *Sid, /* SID of interest */
\r
384 &cbSid, /* size of SID */
\r
385 ReferencedDomain, /* domain account was found on */
\r
386 &cchReferencedDomain, &peUse))
\r
388 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
\r
390 /* reallocate memory */
\r
391 if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)
\r
394 if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),
\r
397 cchReferencedDomain
\r
398 * sizeof (TCHAR))) == NULL)
\r
405 /* Indicate success. */
\r
409 /* Cleanup and indicate failure, if appropriate. */
\r
410 HeapFree (GetProcessHeap (), 0, ReferencedDomain);
\r
416 HeapFree (GetProcessHeap (), 0, *Sid);
\r
425 * @author Scott Field, Microsoft
\r
426 * @see http://support.microsoft.com/?scid=kb;en-us;132958
\r
429 NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */
\r
430 PSID AccountSid, /* SID to grant privilege to */
\r
431 LPWSTR PrivilegeName, /* privilege to grant (Unicode) */
\r
432 BOOL bEnable /* enable or disable */
\r
435 LSA_UNICODE_STRING PrivilegeString;
\r
437 /* Create a LSA_UNICODE_STRING for the privilege name. */
\r
438 _InitLsaString(&PrivilegeString, PrivilegeName);
\r
440 /* grant or revoke the privilege, accordingly */
\r
445 i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */
\r
446 AccountSid, /* target SID */
\r
447 &PrivilegeString, /* privileges */
\r
448 1 /* privilege count */
\r
453 return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */
\r
454 AccountSid, /* target SID */
\r
455 FALSE, /* do not disable all rights */
\r
456 &PrivilegeString, /* privileges */
\r
457 1 /* privilege count */
\r
463 * @brief Create a Windows service account
\r
464 * @return 0 on success, > 0 otherwise
\r
465 * @param pszName the name of the account
\r
466 * @param pszDesc description of the account
\r
468 int CreateServiceAccount(char *pszName, char *pszDesc)
\r
471 USER_INFO_1008 ui2;
\r
472 NET_API_STATUS nStatus;
\r
473 wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];
\r
475 LSA_HANDLE hPolicy;
\r
478 if (! GNNetUserAdd)
\r
480 mbstowcs(wszName, pszName, strlen(pszName) + 1);
\r
481 mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);
\r
483 memset(&ui, 0, sizeof(ui));
\r
484 ui.usri1_name = wszName;
\r
485 ui.usri1_password = wszName; /* account is locked anyway */
\r
486 ui.usri1_priv = USER_PRIV_USER;
\r
487 ui.usri1_comment = wszDesc;
\r
488 ui.usri1_flags = UF_SCRIPT;
\r
490 nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);
\r
492 if (nStatus != NERR_Success && nStatus != NERR_UserExists)
\r
495 ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
\r
496 GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);
\r
498 if (_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy) !=
\r
502 _GetAccountSid(NULL, (LPTSTR) pszName, &pSID);
\r
504 if (_SetPrivilegeOnAccount(hPolicy, pSID, L"SeServiceLogonRight", TRUE) != STATUS_SUCCESS)
\r
507 _SetPrivilegeOnAccount(hPolicy, pSID, L"SeDenyInteractiveLogonRight", TRUE);
\r
508 _SetPrivilegeOnAccount(hPolicy, pSID, L"SeDenyBatchLogonRight", TRUE);
\r
509 _SetPrivilegeOnAccount(hPolicy, pSID, L"SeDenyNetworkLogonRight", TRUE);
\r
511 GNLsaClose(hPolicy);
\r
517 * @brief Grant permission to a file
\r
518 * @param lpszFileName the name of the file or directory
\r
519 * @param lpszAccountName the user account
\r
520 * @param dwAccessMask the desired access (e.g. GENERIC_ALL)
\r
521 * @return TRUE on success
\r
522 * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&
\r
524 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,
\r
525 DWORD dwAccessMask)
\r
527 /* SID variables. */
\r
528 SID_NAME_USE snuType;
\r
529 TCHAR * szDomain = NULL;
\r
530 DWORD cbDomain = 0;
\r
531 LPVOID pUserSID = NULL;
\r
532 DWORD cbUserSID = 0;
\r
534 /* File SD variables. */
\r
535 PSECURITY_DESCRIPTOR pFileSD = NULL;
\r
536 DWORD cbFileSD = 0;
\r
538 /* New SD variables. */
\r
539 SECURITY_DESCRIPTOR newSD;
\r
541 /* ACL variables. */
\r
544 BOOL fDaclDefaulted;
\r
545 ACL_SIZE_INFORMATION AclInfo;
\r
547 /* New ACL variables. */
\r
548 PACL pNewACL = NULL;
\r
549 DWORD cbNewACL = 0;
\r
551 /* Temporary ACE. */
\r
552 LPVOID pTempAce = NULL;
\r
553 UINT CurrentAceIndex = 0;
\r
555 UINT newAceIndex = 0;
\r
557 /* Assume function will fail. */
\r
558 BOOL fResult = FALSE;
\r
561 SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
\r
564 * STEP 1: Get SID of the account name specified.
\r
566 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
\r
567 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
\r
569 /* API should have failed with insufficient buffer. */
\r
572 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
\r
576 pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);
\r
581 szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));
\r
586 fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,
\r
587 pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);
\r
588 if (!fAPISuccess) {
\r
593 * STEP 2: Get security descriptor (SD) of the file specified.
\r
595 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
\r
596 secInfo, pFileSD, 0, &cbFileSD);
\r
598 /* API should have failed with insufficient buffer. */
\r
601 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
\r
605 pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
\r
611 fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,
\r
612 secInfo, pFileSD, cbFileSD, &cbFileSD);
\r
613 if (!fAPISuccess) {
\r
618 * STEP 3: Initialize new SD.
\r
620 if (!GNInitializeSecurityDescriptor(&newSD,
\r
621 SECURITY_DESCRIPTOR_REVISION)) {
\r
626 * STEP 4: Get DACL from the old SD.
\r
628 if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
\r
629 &fDaclDefaulted)) {
\r
634 * STEP 5: Get size information for DACL.
\r
636 AclInfo.AceCount = 0; // Assume NULL DACL.
\r
637 AclInfo.AclBytesFree = 0;
\r
638 AclInfo.AclBytesInUse = sizeof(ACL);
\r
641 fDaclPresent = FALSE;
\r
643 /* If not NULL DACL, gather size information from DACL. */
\r
644 if (fDaclPresent) {
\r
646 if (!GNGetAclInformation(pACL, &AclInfo,
\r
647 sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
\r
653 * STEP 6: Compute size needed for the new ACL.
\r
655 cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)
\r
656 + GetLengthSid(pUserSID) - sizeof(DWORD);
\r
659 * STEP 7: Allocate memory for new ACL.
\r
661 pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);
\r
667 * STEP 8: Initialize the new ACL.
\r
669 if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
\r
674 * STEP 9 If DACL is present, copy all the ACEs from the old DACL
\r
677 * The following code assumes that the old DACL is
\r
678 * already in Windows 2000 preferred order. To conform
\r
679 * to the new Windows 2000 preferred order, first we will
\r
680 * copy all non-inherited ACEs from the old DACL to the
\r
681 * new DACL, irrespective of the ACE type.
\r
686 if (fDaclPresent && AclInfo.AceCount) {
\r
688 for (CurrentAceIndex = 0;
\r
689 CurrentAceIndex < AclInfo.AceCount;
\r
690 CurrentAceIndex++) {
\r
693 * TEP 10: Get an ACE.
\r
695 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
\r
700 * STEP 11: Check if it is a non-inherited ACE.
\r
701 * If it is an inherited ACE, break from the loop so
\r
702 * that the new access allowed non-inherited ACE can
\r
703 * be added in the correct position, immediately after
\r
704 * all non-inherited ACEs.
\r
706 if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
\r
711 * STEP 12: Skip adding the ACE, if the SID matches
\r
712 * with the account specified, as we are going to
\r
713 * add an access allowed ACE with a different access
\r
716 if (GNEqualSid(pUserSID,
\r
717 &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
\r
721 * STEP 13: Add the ACE to the new ACL.
\r
723 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
\r
724 ((PACE_HEADER) pTempAce)->AceSize)) {
\r
733 * STEP 14: Add the access-allowed ACE to the new DACL.
\r
734 * The new ACE added here will be in the correct position,
\r
735 * immediately after all existing non-inherited ACEs.
\r
737 if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
\r
743 * STEP 14.5: Make new ACE inheritable
\r
745 if (!GetAce(pNewACL, newAceIndex, &pTempAce))
\r
747 ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=
\r
748 (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
\r
751 * STEP 15: To conform to the new Windows 2000 preferred order,
\r
752 * we will now copy the rest of inherited ACEs from the
\r
753 * old DACL to the new DACL.
\r
755 if (fDaclPresent && AclInfo.AceCount) {
\r
758 CurrentAceIndex < AclInfo.AceCount;
\r
759 CurrentAceIndex++) {
\r
762 * STEP 16: Get an ACE.
\r
764 if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {
\r
769 * STEP 17: Add the ACE to the new ACL.
\r
771 if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
\r
772 ((PACE_HEADER) pTempAce)->AceSize)) {
\r
779 * STEP 18: Set permissions
\r
781 if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,
\r
782 DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {
\r
791 * STEP 19: Free allocated memory
\r
794 HeapFree(GetProcessHeap(), 0, pUserSID);
\r
797 HeapFree(GetProcessHeap(), 0, szDomain);
\r
800 HeapFree(GetProcessHeap(), 0, pFileSD);
\r
803 HeapFree(GetProcessHeap(), 0, pNewACL);
\r
808 char *winErrorStr(const char *prefix, int dwErr)
\r
813 if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
\r
814 NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,
\r
820 mem = strlen(err) + strlen(prefix) + 20;
\r
821 ret = (char *) malloc(mem);
\r
823 snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);
\r