/*++ Copyright (c) 2001 Microsoft Corporation Module Name : common.cxx Abstract: Class that are used to do a number of commonly needed things Author: Christopher Achille (cachille) Project: Internet Services Setup Revision History: August 2001: Created --*/ #include "stdafx.h" #include "common.hxx" #include "dcomperm.h" // function: VerifyParameters // // Verify the parameters are correct // // Parameters of ciParams // 0 params - The caller want to know if this is an upgrade, period // 2 params - The caller wants to know if this is an upgrade in the range from param(0) to param(1) (inclusive) // BOOL CIsUpgrade::VerifyParameters(CItemList &ciParams) { if ( ( ciParams.GetNumberOfItems() == 0 ) || ( ( ciParams.GetNumberOfItems() == 2 ) && ( ciParams.IsNumber(0) ) && ( ciParams.IsNumber(1) ) ) ) { return TRUE; } return FALSE; } // function: GetMethodName // // Returns the name of the CIsMetabase call // LPTSTR CIsUpgrade::GetMethodName() { return _T("IsUpgrade"); } // function: DoInternalWork // // Do the Verification of the upgrade // BOOL CIsUpgrade::DoInternalWork(CItemList &ciParams) { BOOL fRet = TRUE; DWORD dwUpgradeType = g_pTheApp->m_eUpgradeType; // Init return to installmode==upgrade fRet = g_pTheApp->m_eInstallMode == IM_UPGRADE; if (ciParams.GetNumberOfItems() == 0) { // We only wanted to know if it was an upgrade, so return return fRet; } // Check lower bound if (fRet) { DWORD dwMin = ciParams.GetNumber(0); switch ( dwUpgradeType ) { case UT_10: case UT_10_W95: fRet = dwMin <= 1; break; case UT_20: fRet = dwMin <= 2; break; case UT_30: case UT_351: fRet = dwMin <= 3; break; case UT_40: fRet = dwMin <= 4; break; case UT_50: case UT_51: fRet = dwMin <= 5; break; case UT_60: fRet = dwMin <= 6; break; default: fRet = FALSE; } } // Check upper bound if (fRet) { DWORD dwMax = ciParams.GetNumber(1); switch ( dwUpgradeType ) { case UT_10: case UT_10_W95: fRet = dwMax >= 1; break; case UT_20: fRet = dwMax >= 2; break; case UT_30: case UT_351: fRet = dwMax >= 3; break; case UT_40: fRet = dwMax >= 4; break; case UT_50: case UT_51: fRet = dwMax >= 5; break; case UT_60: fRet = dwMax >= 6; break; default: fRet = FALSE; } // switch } return fRet; } // function: AddAceToSD // // Add an ACE (Access Control List) to a Source Descriptor. // // Parameters: // hObject - Handle to the object // ObjectType - The type of object // pszTustee - The trustee for new ACE // TrusteeForm - The format of the trustee structure // dwAccessRights - Access Mask for the New ACE // AccessMode - Type of ACE // dwInderitance - Inheritance Flags for ACE // bAddToExisting - TRUE==add ace to existing ACL, FALSE==ignore existing ACL // // Return // TRUE - It was successful // FALSE - It failed BOOL CFileSys_Acl::AddAcetoSD( HANDLE hObject, // handle to object SE_OBJECT_TYPE ObjectType, // type of object LPTSTR pszTrustee, // trustee for new ACE TRUSTEE_FORM TrusteeForm, // format of TRUSTEE structure DWORD dwAccessRights, // access mask for new ACE ACCESS_MODE AccessMode, // type of ACE DWORD dwInheritance, // inheritance flags for new ACE BOOL bAddToExisting // add the new ace to the old SD, if not create a new SD ) { DWORD dwErr = ERROR_SUCCESS; PACL pNewDacl = NULL; PACL pOldDacl = NULL; EXPLICIT_ACCESS ea; PSECURITY_DESCRIPTOR pSD = NULL; if ( bAddToExisting ) { // If we are adding, then lets retrieve the old SD dwErr = GetSecurityInfo( hObject, ObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDacl, NULL, &pSD); if ( dwErr == ERROR_SUCCESS ) { // It is possible that we did not retrieve any acl's for this file, // so don't try to remove a user from them if ( pOldDacl ) { RemoveUserFromAcl( pOldDacl, pszTrustee); } } } // Create new SD with the new ACE if ( dwErr == ERROR_SUCCESS ) { ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); ea.grfAccessPermissions = dwAccessRights; ea.grfAccessMode = AccessMode; ea.grfInheritance = dwInheritance; ea.Trustee.TrusteeForm = TrusteeForm; ea.Trustee.ptstrName = pszTrustee; dwErr = SetEntriesInAcl(1, &ea, pOldDacl, &pNewDacl); } if ( ( dwErr == ERROR_SUCCESS ) && ( pNewDacl ) ) { dwErr = SetSecurityInfo( hObject, ObjectType, DACL_SECURITY_INFORMATION | ( bAddToExisting ? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION ), NULL, NULL, pNewDacl, NULL); } if ( pSD ) { LocalFree( pSD ); } if ( pNewDacl ) { LocalFree( pNewDacl ); } return dwErr == ERROR_SUCCESS; } // function: RemoveUserFromAcl // // Remove a User from the Acl // // Parameters // pAcl - A pointer to the Acl // szUserName - The user to remove BOOL CFileSys_Acl::RemoveUserFromAcl(PACL pAcl, LPTSTR szUserName) { BOOL bUserExisted; do { bUserExisted = FALSE; // Keep removing until all instances of that user are gone. } while ( ( RemovePrincipalFromACL(pAcl,szUserName,&bUserExisted) == ERROR_SUCCESS) && bUserExisted ); return TRUE; } // function: VerifyParameters // // Verify the parameters are correct // BOOL CFileSys_AddAcl::VerifyParameters(CItemList &ciParams) { if ( ( ciParams.GetNumberOfItems() == 6 ) && ciParams.IsNumber(3) && ciParams.IsNumber(4) && ciParams.IsNumber(5) ) { return TRUE; } return FALSE; } // function: GetMethodName // // Return the Method Name for this Class // LPTSTR CFileSys_AddAcl::GetMethodName() { return _T("FilSys_AddAcl"); } // function: CreateFullFileName // // Create the Full FileName from the Path with wildcards, and the filename // // Parameters: // buffFullFileName [out] - The FileName including the path // szFullPathwithWildCard [in] - The search path (ie. c:\winnt\system32\inetsrv\*.*) // szFileName [in] - The filename to append to the seach path (ie. asp.dll) // BOOL CFileSys_Acl::CreateFullFileName(BUFFER &buffFullFileName, LPTSTR szFullPathwithWildCard, LPTSTR szFileName) { LPTSTR szLastSlash; if ( !buffFullFileName.Resize( ( _tcslen(szFullPathwithWildCard) + _tcslen(szFileName) + 1 ) * sizeof(TCHAR) ) ) { // Could not allocate memory needed return FALSE; } // Copy the full path to the buffer _tcscpy( (LPTSTR) buffFullFileName.QueryPtr(), szFullPathwithWildCard); // Look for last part of path szLastSlash = _tcsrchr( (LPTSTR) buffFullFileName.QueryPtr(), L'\\' ); if (!szLastSlash) { return FALSE; } // Copy the filename on top of the end of the path _tcscpy( szLastSlash + 1, szFileName); return TRUE; } // function: SetFileAcl // // Add the file/directory acl // BOOL CFileSys_Acl::SetFileAcl(LPTSTR szFileName, LPTSTR szUserName, SE_OBJECT_TYPE ObjectType, DWORD dwAccessMask, BOOL bAllowAccess, DWORD dwInheritable, BOOL bAddAcetoOriginal) { HANDLE hFile; BOOL bRet; hFile = CreateFile( szFileName, WRITE_DAC|READ_CONTROL, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, NULL); if ( hFile == INVALID_HANDLE_VALUE ) { return FALSE; } bRet = AddAcetoSD( hFile, ObjectType, szUserName, TRUSTEE_IS_NAME, dwAccessMask, bAllowAccess ? SET_ACCESS: DENY_ACCESS, dwInheritable, bAddAcetoOriginal ); // bAllowAccess ? GRANT_ACCESS: DENY_ACCESS, dwInheritable); CloseHandle( hFile ); return bRet; } // function: RemoveUserAcl // // Remove a User's ACL from a file // BOOL CFileSys_Acl::RemoveUserAcl(LPTSTR szFile, LPTSTR szUserName) { HANDLE hFile; DWORD dwErr; PACL pDacl; PSECURITY_DESCRIPTOR pSD = NULL; hFile = CreateFile( szFile, WRITE_DAC|READ_CONTROL, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, NULL); if ( hFile == INVALID_HANDLE_VALUE ) { return FALSE; } dwErr = GetSecurityInfo( hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, NULL, &pSD); if ( ( dwErr == ERROR_SUCCESS ) && ( pDacl ) ) { RemoveUserFromAcl( pDacl, szUserName); dwErr = SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pDacl, NULL); } CloseHandle( hFile ); if ( pSD ) { LocalFree( pSD ); } return dwErr == ERROR_SUCCESS; } // function: DoSetAcl // // Set or remove an ACL on a file. // If it is Set, then we will either add or just set based on bIgnorePreviousAcls // // Parameters // bAdd - Add the ace. FALSE==remove the ace from the acl // bAddAcltoOrignial - TRUE==add ace, FALSE==do not add to old ace, just replace // // ciList - The list of the parameters from the inf file // 0 - A list of files (full paths) // 1 - The exclusion list, list of files to not be inclused (file names only) // 2 - The user(s) to have access for // the following are needed it bAdd is true... // 3 - Access Mask // 4 - bAllowAccess (FALSE==Denuy Access) // 5 - Inheritance Flags // BOOL CFileSys_Acl::DoAcling(CItemList &ciList, BOOL bAdd, BOOL bAddAcltoOriginal) { HANDLE hFileList; WIN32_FIND_DATA sFD; BUFFER BuffFullFileName; CItemList ciExclusionList; CItemList ciUserList; // Load exclusion list, and userlist if ( (!ciExclusionList.LoadSubList(ciList.GetItem(1))) || (!ciUserList.LoadSubList(ciList.GetItem(2))) ) { return FALSE; } if ( !_tcsstr( ciList.GetItem(0), _T("*")) ) { for (DWORD i = 0; i < ciUserList.GetNumberOfItems(); i++) { if ( bAdd ) { // It is only a single file, so only call it once SetFileAcl( (LPTSTR) ciList.GetItem(0), // FileName ciUserList.GetItem(i), // UserName SE_FILE_OBJECT, // The type of object ciList.GetNumber(3), // dwAccess Mask ciList.GetNumber(4), // bAllow access ciList.GetNumber(5), // bInhertance Flags bAddAcltoOriginal ); } else { RemoveUserAcl(ciList.GetItem(0),ciUserList.GetItem(i)); } } return TRUE; } hFileList = FindFirstFile( ciList.GetItem(0), &sFD ); if (hFileList == INVALID_HANDLE_VALUE) { return FALSE; } do { if ( ( !ciExclusionList.FindItem( sFD.cFileName, FALSE ) ) && ( _tcscmp( sFD.cFileName, _T(".") ) ) && ( _tcscmp( sFD.cFileName, _T("..") ) ) && ( CreateFullFileName( BuffFullFileName, ciList.GetItem(0), sFD.cFileName ) ) ) { for (DWORD i = 0; i < ciUserList.GetNumberOfItems(); i++) { if ( bAdd ) { SetFileAcl( (LPTSTR) BuffFullFileName.QueryPtr(), // FileName ciUserList.GetItem(i), // UserName SE_FILE_OBJECT, // The type of object ciList.GetNumber(3), // dwAccess Mask ciList.GetNumber(4), // bAllow access ciList.GetNumber(5), // bInhertance Flags bAddAcltoOriginal ); } else { RemoveUserAcl((LPTSTR) BuffFullFileName.QueryPtr(),ciUserList.GetItem(i)); } } } } while ( FindNextFile( hFileList, &sFD ) ); FindClose( hFileList ); return TRUE; } // function: DoInternalWork // // Add the Acl for the files specified // // Parameters // ciList - The list of the parameters from the inf file // 0 - A list of files (full paths) // 1 - The exclusion list, list of files to not be inclused (file names only) // 2 - The user(s) to have access for // 3 - Access Mask // 4 - bAllowAccess (FALSE==Denuy Access) // 5 - Inheritance Flags BOOL CFileSys_AddAcl::DoInternalWork(CItemList &ciList) { return DoAcling( ciList, TRUE, TRUE ); } // function: VerifyParameters // // Verify the parameters are correct // BOOL CFileSys_RemoveAcl::VerifyParameters(CItemList &ciParams) { return ciParams.GetNumberOfItems() == 3; } // function: GetMethodName // // Return the Method Name for this Class // LPTSTR CFileSys_RemoveAcl::GetMethodName() { return _T("FilSys_RemoveAcl"); } // function: DoInternalWork // // Remove an Acl for a specific user // // Parameters // ciList - The list of the parameters from the inf file // 0 - A list of files (full paths) // 1 - The exclusion list, list of files to not be inclused (file names only) // 2 - The user(s) to remove access for BOOL CFileSys_RemoveAcl::DoInternalWork(CItemList &ciList) { return DoAcling( ciList, FALSE ); } // function: VerifyParameters // // Verify the parameters are correct // BOOL CFileSys_SetAcl::VerifyParameters(CItemList &ciParams) { if ( ( ciParams.GetNumberOfItems() == 6 ) && ciParams.IsNumber(3) && ciParams.IsNumber(4) && ciParams.IsNumber(5) ) { return TRUE; } return FALSE; } // function: GetMethodName // // Return the Method Name for this Class // LPTSTR CFileSys_SetAcl::GetMethodName() { return _T("FilSys_SetAcl"); } // function: DoInternalWork // // Set the Acl for the files specified (ignoring previous acl's) // // Parameters // ciList - The list of the parameters from the inf file // 0 - A list of files (full paths) // 1 - The exclusion list, list of files to not be inclused (file names only) // 2 - The user(s) to have access for // 3 - Access Mask // 4 - bAllowAccess (FALSE==Denuy Access) // 5 - Inheritance Flags BOOL CFileSys_SetAcl::DoInternalWork(CItemList &ciList) { return DoAcling( ciList, TRUE, FALSE ); }