最近两天在一家公司做兼职。刚去公司,老板就分配了一个任务。公司里有一个软件,在编辑自己产生的文件后,点击保存,文件就会自动上传到服务器进行备份,并立即删除本地的文件。给我的任务是:在Windows2000下,文件夹的属性中的安全选项卡是用户能够看到的。并且一般的用户都可以通过这个安全编辑对话框来更改文件夹的权限。问题是这样的:如果用户把文件夹的删除权限设置为拒绝,那么本地的文件只能上传到服务器,而本地的文件是删不掉的了。老板希望我想一个办法把文件夹的属性中的安全选项卡屏蔽掉。刚刚面试完,不敢说不会,只好满口答应,向老板保证,我一定会尽力去解决的。
在仔细研究了所面对的问题并上网查找了一些资料后,我觉得可以用一种变通的办法来达到同样的效果。那就是:当用户把删除权限设置为拒绝后,我就会检测到,然后再把它改过来。哈哈。不失为一种解决方案。在对Windows安全系统及编程接口完全不熟悉的情况下,我觉得能做到多少就努力做到多少吧。后来老板也很赞同我的想法。从他和我说话的表情和语气。^_^
下面就是我的代码。当然大量参考了Jeffrey Richter先生的宝书《Programming Server-Side Applications for Microsoft Windows 2000》。这是一本很好的书,可惜市面上已经买不到了。自古红颜多薄命,难道好书也像美人一样?幸好,我有英文电子版,可以解一时之急。讲解Win32安全编程机制的书也不多,这是其中的一本。
#include "stdafx.h"
#include
<windows.h>
#include
<Aclapi.h>
#include
<AccCtrl.h>
#include
<Sddl.h>
#include
<iostream>
using namespace
std; #define PSIDFromPACE(pACE) ((PSID)(&((pACE)->SidStart)))
typedef union _ACE_UNION
...
{ ACE_HEADER aceHeader; ACCESS_ALLOWED_ACE aceAllowed; ACCESS_DENIED_ACE aceDenied; SYSTEM_AUDIT_ACE aceAudit; }*
PACE_UNION; void
DumpACL(PACL pACL); DWORD DelAceAndSetACL(PACL pACL, PSID psid, TCHAR *
pszBuf); void GrantDeleteRight(TCHAR *pszBuf, PSID psid, PACL pOldDACL, PACL *
pNewDACL); ULONG CalculateACLSize(PACL pACLOld, PSID* ppSidArray, int nNumSids, PACE_UNION* ppACEs, int
nNumACEs); PACE_UNION AllocateACE(ULONG bACEType, ULONG bACEFlags, ULONG lAccessMask, PSID pSID); ULONG GetACEInsertionIndex(PACL pDACL, PACE_UNION pACENew); BOOL CopyACL( PACL pACLDestination, PACL pACLSource ); int
FindACEInACL( PACL pACL, PACE_UNION pACE ); BOOL IsEqualACE( PACE_UNION pACE1, PACE_UNION pACE2 ); LPVOID AllocateTokenInformation(HANDLE hToken, TOKEN_INFORMATION_CLASS tokenClass); struct...
{ BYTE lACEType; PTSTR pszTypeName; }aceTypes[6] = ...
{ ...{ACCESS_ALLOWED_ACE_TYPE, TEXT("ACCESS_ALLOWED_ACE_TYPE")}, ...{ACCESS_DENIED_ACE_TYPE, TEXT("ACCESS_DENIED_ACE_TYPE")}, ...{SYSTEM_AUDIT_ACE_TYPE, TEXT("SYSTEM_AUDIT_ACE_TYPE")}, ...{ACCESS_ALLOWED_OBJECT_ACE_TYPE, TEXT("ACCESS_ALLOWED_OBJECT_ACE_TYPE")}, ...{ACCESS_DENIED_OBJECT_ACE_TYPE, TEXT("ACCESS_DENIED_OBJECT_ACE_TYPE")}, ...{SYSTEM_AUDIT_OBJECT_ACE_TYPE, TEXT("SYSTEM_AUDIT_OBJECT_ACE_TYPE")}}
; struct...
{ ULONG lACEFlag; PTSTR pszFlagName; }aceFlags[7] = ...
{ ...{INHERITED_ACE, TEXT("INHERITED_ACE")}, ...{CONTAINER_INHERIT_ACE, TEXT("CONTAINER_INHERIT_ACE")}, ...{OBJECT_INHERIT_ACE, TEXT("OBJECT_INHERIT_ACE")}, ...{INHERIT_ONLY_ACE, TEXT("INHERIT_ONLY_ACE")}, ...{NO_PROPAGATE_INHERIT_ACE, TEXT("NO_PROPAGATE_INHERIT_ACE")}, ...{FAILED_ACCESS_ACE_FLAG, TEXT("FAILED_ACCESS_ACE_FLAG")}, ...{SUCCESSFUL_ACCESS_ACE_FLAG, TEXT("SUCCESSFUL_ACCESS_ACE_FLAG")}}
; int _tmain(int argc, _TCHAR*
argv[]) ...
{ SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; PSID psid = NULL; // 获得当前用户的SID和默认的DACL。 HANDLE hToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))...{ // Error _tprintf(_T("OpenProcessToken Failed.")); return 1; } TOKEN_USER* ptUser = (TOKEN_USER*)AllocateTokenInformation(hToken, TokenUser); if (ptUser != NULL)...{ psid = ptUser->User.Sid; } TOKEN_DEFAULT_DACL* ptDACL = (TOKEN_DEFAULT_DACL*)AllocateTokenInformation(hToken, TokenDefaultDacl); if (ptDACL != NULL)...{ DumpACL(ptDACL->DefaultDacl); } // 初始化sd。使用当前用户的默认DACL。 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, ptDACL->DefaultDacl, FALSE); // 初始化sa。 sa.nLength= sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = FALSE; sa.lpSecurityDescriptor = &sd; // 创建一个指定文件夹名和具有上面安全属性的文件夹。 TCHAR szPathBuf[MAX_PATH]; _tprintf(_T("Input the directory: ")); _tscanf(_T("%s"), szPathBuf); CreateDirectory(szPathBuf, &sa); DWORD dwRes = 0; PACL pOldDACL = NULL, pNewDACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; // Get a pointer to the existing DACL. dwRes = GetNamedSecurityInfo(szPathBuf, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD); if (ERROR_SUCCESS != dwRes) ...{ _tprintf(_T("GetNamedSecurityInfo Error %u "), dwRes); return 1; } DumpACL(pOldDACL); if (DelAceAndSetACL(pOldDACL, psid, szPathBuf) == ERROR_SUCCESS) ...{ GrantDeleteRight(szPathBuf, psid, pOldDACL, &pNewDACL); DumpACL(pNewDACL); } else ...{ GrantDeleteRight(szPathBuf, psid, pOldDACL, &pNewDACL); DumpACL(pNewDACL); } LocalFree(pSD); return 0; }
DWORD DelAceAndSetACL(PACL pACL, PSID psid, TCHAR
*
pszBuf) ...
{ DWORD dwRes = -1; __try ...{ ACL_SIZE_INFORMATION aclSize = ...{0}; if (!GetAclInformation(pACL, &aclSize, sizeof(aclSize), AclSizeInformation)) __leave; for (ULONG lIndex = 0; lIndex < aclSize.AceCount; lIndex++) ...{ ACCESS_ALLOWED_ACE* pACE; if (!GetAce(pACL, lIndex, (PVOID*)&pACE)) __leave; bool flag16 = false, flag26 = false; int cnt = 0; ULONG lIndex2 = (ULONG)1<<31; while (lIndex2) ...{ ++cnt; if (cnt == 16 && ((pACE->Mask & lIndex2) != 0)) ...{ flag16 = true; } if (cnt == 26 && ((pACE->Mask & lIndex2) != 0)) ...{ flag26 = true; } lIndex2 >>= 1; if (flag16 || flag26) break; } if ((flag16 || flag26) && pACE->Header.AceType == ACCESS_DENIED_ACE_TYPE) ...{ ::DeleteAce(pACL, lIndex); --lIndex; --aclSize.AceCount; dwRes = SetNamedSecurityInfo(pszBuf, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, psid, NULL, pACL, NULL); if (ERROR_SUCCESS != dwRes) printf("SetNamedSecurityInfo Error %u ", dwRes); flag16 = flag26 = false; } } }__finally ...{} return dwRes; }
void GrantDeleteRight(TCHAR *pszBuf, PSID psid, PACL pOldDACL, PACL *
pNewDACL) ...
{ PSID psidArray[1]; psidArray[0] = psid; // Get the size of the new ACL ULONG lACLSize = CalculateACLSize(pOldDACL, psidArray, 1, NULL, 1); if (lACLSize == 0)...{ // Error } // Allocate memory for the ACL *pNewDACL = (PACL)HeapAlloc(GetProcessHeap(), 0, lACLSize); if (pNewDACL == NULL) ...{ // Error } // Initialize the ACL if (!InitializeAcl(*pNewDACL, lACLSize, ACL_REVISION))...{ // Error } PACE_UNION pNewACE = AllocateACE( ACCESS_ALLOWED_ACE_TYPE, NULL, GENERIC_ALL | FILE_DELETE_CHILD | DELETE, psid ); // 如果ACL中有相同的ACE则返回。 if (FindACEInACL(*pNewDACL, pNewACE) != -1) return; CopyACL(*pNewDACL, pOldDACL); // Get location for new ACE ULONG lIndex = GetACEInsertionIndex(*pNewDACL, pNewACE); // Add the new ACE if (!AddAce(*pNewDACL, ACL_REVISION, lIndex, pNewACE, pNewACE->aceHeader.AceSize)) printf("Error!"); DWORD dwRes = SetNamedSecurityInfo(pszBuf, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, psid, NULL, *pNewDACL, NULL); if (ERROR_SUCCESS != dwRes) printf("SetNamedSecurityInfo Error %u ", dwRes); }
void DumpACL(PACL pACL)...
{ __try...{ if (pACL == NULL)...{ _tprintf(TEXT("NULL DACL ")); __leave; } ACL_SIZE_INFORMATION aclSize = ...{0}; if (!GetAclInformation(pACL, &aclSize, sizeof(aclSize), AclSizeInformation)) __leave; _tprintf(TEXT("ACL ACE count: %d "), aclSize.AceCount); for (ULONG lIndex = 0;lIndex < aclSize.AceCount;lIndex++)...{ ACCESS_ALLOWED_ACE* pACE; if (!GetAce(pACL, lIndex, (PVOID*)&pACE)) __leave; _tprintf(TEXT(" ACE #%d "), lIndex); ULONG lIndex2 = 6; PTSTR pszString = TEXT("Unknown ACE Type"); while (lIndex2--)...{ if(pACE->Header.AceType == aceTypes[lIndex2].lACEType) ...{ pszString = aceTypes[lIndex2].pszTypeName; } } _tprintf(TEXT(" ACE Type = %s "), pszString); _tprintf(TEXT(" ACE Flags = ")); lIndex2 = 7; while (lIndex2--) ...{ if ((pACE->Header.AceFlags & aceFlags[lIndex2].lACEFlag) != 0) _tprintf(TEXT(" %s "), aceFlags[lIndex2].pszFlagName); } _tprintf(TEXT(" ACE Mask (32->0) = ")); lIndex2 = (ULONG)1<<31; while (lIndex2) ...{ _tprintf(((pACE->Mask & lIndex2) != 0)?TEXT("1"):TEXT("0")); lIndex2>>=1; } TCHAR szName[1024]; TCHAR szDom[1024]; PSID pSID = PSIDFromPACE(pACE); SID_NAME_USE sidUse; ULONG lLen1 = 1024, lLen2 = 1024; if (!LookupAccountSid(NULL, pSID, szName, &lLen1, szDom, &lLen2, &sidUse)) lstrcpy(szName, TEXT("Unknown")); PTSTR pszSID; if (!ConvertSidToStringSid(pSID, &pszSID)) __leave; _tprintf(TEXT(" ACE SID = %s (%s) "), pszSID, szName); LocalFree(pszSID); } }__finally...{} }
LPVOID AllocateTokenInformation(HANDLE hToken, TOKEN_INFORMATION_CLASS tokenClass)
...
{ PVOID pvBuffer = NULL; __try...{ BOOL fSuccess; // Initial buffer size ULONG lSize = 0 ; do ...{ // Do we have a size yet? if (lSize != 0) ...{ // Do we already have a buffer? if (pvBuffer != NULL) LocalFree(pvBuffer);// Then free it // Allocate a new buffer pvBuffer = LocalAlloc(LPTR, lSize) ; if(pvBuffer == NULL) __leave; } // Try again fSuccess = GetTokenInformation( hToken, tokenClass, pvBuffer, lSize, &lSize ) ; // Still not enough buffer? }while( !fSuccess && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) ; // If we failed for some other reason, back out if(!fSuccess) ...{ if(pvBuffer) LocalFree(pvBuffer) ; pvBuffer = NULL; } }__finally...{} // Return locally allocated buffer return (pvBuffer) ; }
ULONG CalculateACLSize(PACL pACLOld, PSID
* ppSidArray, int nNumSids, PACE_UNION* ppACEs, int
nNumACEs) ...
{ ULONG lACLSize = 0; try...{ // If we are including an existing ACL, then find its size if (pACLOld != NULL)...{ ACL_SIZE_INFORMATION aclSize; if(!GetAclInformation(pACLOld, &aclSize, sizeof(aclSize), AclSizeInformation))...{ goto leave; } lACLSize = aclSize.AclBytesInUse; } if (ppSidArray != NULL)...{ // Step through each SID while (nNumSids--)...{ // If a SID isn't valid, then we bail if (!IsValidSid(ppSidArray[nNumSids]))...{ lACLSize = 0; goto leave; } // Get the SID's length lACLSize += GetLengthSid(ppSidArray[nNumSids]); // Add the ACE structure size, minus the // size of the SidStart member lACLSize += sizeof(ACCESS_ALLOWED_ACE) - sizeof(((ACCESS_ALLOWED_ACE*)0)->SidStart); } } if (ppACEs != NULL)...{ // Step through each ACE while (nNumACEs--)...{ // Get the SIDs length lACLSize += ppACEs[nNumACEs]->aceHeader.AceSize; } } // Add in the ACL structure itself lACLSize += sizeof(ACL); leave:; }catch(...)...{ // An exception means we fail the function lACLSize = 0; } return (lACLSize); }
BOOL CopyACL( PACL pACLDestination, PACL pACLSource )
...
{ BOOL fReturn = FALSE; try ...{ // Get the number of ACEs in the source ACL ACL_SIZE_INFORMATION aclSize; if (!GetAclInformation(pACLSource, &aclSize, sizeof(aclSize), AclSizeInformation))...{ goto leave; } // Use GetAce and AddAce to copy the ACEs for(ULONG lIndex=0;lIndex < aclSize.AceCount;lIndex++)...{ ACE_HEADER* pACE; if(!GetAce(pACLSource, lIndex, (PVOID*)&pACE)) goto leave; if(!AddAce(pACLDestination, ACL_REVISION, MAXDWORD, (PVOID*)pACE, pACE->AceSize)) goto leave; } fReturn = TRUE; leave:; }catch(...)...{ } return (fReturn); }
PACE_UNION AllocateACE(ULONG bACEType, ULONG bACEFlags, ULONG lAccessMask, PSID pSID)
...
{ PACE_UNION pReturnACE = NULL; PBYTE pbBuffer = NULL; try...{ // Get the offset of the SID in the ACE ULONG lSIDOffset = (ULONG)(&((ACCESS_ALLOWED_ACE*)0)->SidStart); // Get the size of the ACE without the SID ULONG lACEStructSize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(((ACCESS_ALLOWED_ACE*)0)->SidStart); // Get the length of the SID ULONG lSIDSize = GetLengthSid(pSID); // Allocate a buffer for the ACE pbBuffer = (PBYTE)LocalAlloc(LPTR, lACEStructSize + lSIDSize); if (pbBuffer == NULL) goto leave; // Copy the SID into the ACE if(!CopySid(lSIDSize, (PSID)(pbBuffer+lSIDOffset), pSID))...{ goto leave; } pReturnACE = (PACE_UNION) pbBuffer; pReturnACE->aceHeader.AceSize = (USHORT)(lACEStructSize + lSIDSize); pReturnACE->aceHeader.AceType = (BYTE)bACEType; pReturnACE->aceHeader.AceFlags = (BYTE)bACEFlags; pReturnACE->aceAllowed.Mask = lAccessMask; leave:; }catch(...)...{} // Free the buffer in an error case if (pbBuffer != (PBYTE)pReturnACE)...{ LocalFree(pbBuffer); } return (pReturnACE); }
ULONG GetACEInsertionIndex(PACL pDACL, PACE_UNION pACENew)
...
{ ULONG lIndex = (ULONG) -1; try...{ // ACE types by ACL order ULONG lFilterType[] = ...{ ACCESS_DENIED_ACE_TYPE, ACCESS_DENIED_OBJECT_ACE_TYPE, ACCESS_ALLOWED_ACE_TYPE, ACCESS_ALLOWED_OBJECT_ACE_TYPE}; // Determine which group the new ACE should belong to ULONG lNewAceGroup; for(lNewAceGroup = 0; lNewAceGroup<4 ; lNewAceGroup++)...{ if(pACENew->aceHeader.AceType == lFilterType[lNewAceGroup]) break; } // If group == 4, the ACE type is no good if(lNewAceGroup==4) goto leave; // If new ACE is an inherited ACE, then it goes after other ACEs if((pACENew->aceHeader.AceFlags & INHERITED_ACE) != 0) lNewAceGroup+=4; // Get ACE count ACL_SIZE_INFORMATION aclSize; if (!GetAclInformation(pDACL, &aclSize, sizeof(aclSize), AclSizeInformation))...{ goto leave; } // Iterate through ACEs lIndex = 0; for(lIndex = 0;lIndex < aclSize.AceCount;lIndex++)...{ ACE_HEADER* pACE; if(!GetAce(pDACL, lIndex, (PVOID*)&pACE)) goto leave; // Get the group of the ACL ACE ULONG lAceGroup; for(lAceGroup = 0; lAceGroup<4 ; lAceGroup++)...{ if(pACE->AceType == lFilterType[lAceGroup]) break; } // Test for bad ACE if(lAceGroup==4)...{ lIndex = (ULONG) -1; goto leave; } // Inherited adjustment if((pACE->AceFlags & INHERITED_ACE) != 0) lAceGroup+=4; // If this is the same group, then insertion point found if(lAceGroup>=lNewAceGroup) break; } leave: ; }catch(...)...{ } return (lIndex); }
BOOL IsEqualACE( PACE_UNION pACE1, PACE_UNION pACE2 )
...
{ BOOL fReturn = FALSE; try ...{ if(pACE1->aceHeader.AceType != pACE2->aceHeader.AceType) goto leave; // Get the offset of the SID in the ACE ULONG lSIDOffset = (ULONG)((&((ACCESS_ALLOWED_ACE*)0)->SidStart)); // Get the size of the ACE without the SID ULONG lACEStructSize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(((ACCESS_ALLOWED_ACE*)0)->SidStart); PBYTE pbACE1 = (PBYTE)pACE1; PBYTE pbACE2 = (PBYTE)pACE2; fReturn = TRUE; while(lACEStructSize--) fReturn = (fReturn && ((pbACE1[lACEStructSize] == pbACE2[lACEStructSize]))); // Check SIDs fReturn = fReturn && EqualSid((PSID)(pbACE1+lSIDOffset), (PSID)(pbACE2+lSIDOffset)); leave:; }catch(...)...{ } return (fReturn); }
int
FindACEInACL(PACL pACL, PACE_UNION pACE) ...
{ int nACEIndex = -1; try...{ ACL_SIZE_INFORMATION aclSize; if (!GetAclInformation(pACL, &aclSize, sizeof(aclSize), AclSizeInformation))...{ goto leave; } while (aclSize.AceCount--)...{ PACE_UNION pACETemp; if(!GetAce(pACL, aclSize.AceCount, (PVOID *)&pACETemp)) goto leave; if(IsEqualACE(pACETemp, pACE))...{ nACEIndex = (int)aclSize.AceCount; break; } } leave:; }catch(...)...{ } return (nACEIndex); }