void CreateDatabasesUnitTests::Test_CreateDatabases_SQLServer() { AppSecInc::Msi::MsiShim hInstall; std::wstring testdatapath = AppSecInc::File::GetModuleDirectoryW() + L"\\TestData_DataSourceUnitTests"; for each(const std::wstring& idtfile in AppSecInc::File::GetFiles(testdatapath, L"*.idt")) { std::wstring idtfile_name = AppSecInc::File::GetFileNameW(idtfile); std::wcout << std::endl << L" Importing \"" << idtfile_name << L"\""; hInstall.Import(testdatapath, idtfile_name); } AppSecInc::Msi::MsiInstall msiInstall(hInstall); std::wstring databasename = AppSecInc::Com::GenerateGUIDStringW(); AppSecInc::StringUtils::lrtrim(databasename, L"{}"); std::wcout << std::endl << L"Database: " << databasename; msiInstall.SetProperty(L"MSSQL_DATABASE_NAME", databasename); msiInstall.SetProperty(L"INSTALLLOCATION", AppSecInc::File::GetSpecialFolderPath(CSIDL_COMMON_APPDATA) + L"\\"); AppSecInc::Xml::XmlDocument xml; CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"DataSource.dll", L"CreateDatabases_SQLServer_Immediate")); xml.LoadXml(msiInstall.GetProperty(L"CreateDatabases_SQLServer_Deferred_Install")); // two databases, both have create actions, one is checkIfExists CPPUNIT_ASSERT(2 == xml.SelectNodes(L"/MSSQLDatabases/MSSQLDatabase")->length); CPPUNIT_ASSERT(2 == xml.SelectNodes(L"/MSSQLDatabases/MSSQLDatabase[@actions='create']")->length); CPPUNIT_ASSERT(1 == xml.SelectNodes(L"/MSSQLDatabases/MSSQLDatabase[@checkIfExists='false']")->length); CPPUNIT_ASSERT(1 == xml.SelectNodes(L"/MSSQLDatabases/MSSQLDatabase[@checkIfExists='true']")->length); // only the first database has options, but each have two file specs CPPUNIT_ASSERT(1 == xml.SelectNodes(L"/MSSQLDatabases/MSSQLDatabase/MSSQLDatabaseOptions/MSSQLDatabaseOption")->length); CPPUNIT_ASSERT(4 == xml.SelectNodes(L"/MSSQLDatabases/MSSQLDatabase/MSSQLDatabaseFileSpecs/MSSQLDatabaseFileSpec")->length); // connection strings must be encrypted MSXML2::IXMLDOMNodeListPtr connectionStrings = xml.SelectNodes(L"/MSSQLDatabases/MSSQLDatabase/ConnectionString/text()"); for (int i = 0; i < connectionStrings->length; i++) { std::wstring encrypted = StringUtils::mb2wc(StringUtils::bstr2mb(connectionStrings->item[i]->text)); AppSecInc::Crypt::DPAPIImpl::UnProtect(encrypted); // Fails if input string is not encrypted } // create the databases msiInstall.SetProperty(L"CustomActionData", msiInstall.GetProperty(L"CreateDatabases_SQLServer_Deferred_Install")); CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"DataSource.dll", L"CreateDatabases_SQLServer_Deferred")); // check that both databases exist AppSecInc::Databases::MSSQL::MSSQLConnectionInfo connection_info; connection_info.SetIPAddress(L"localhost"); AppSecInc::Databases::MSSQL::MSSQLDatabase database(connection_info); database.Connect(); // check the first database database.SetName(databasename); CPPUNIT_ASSERT(database.Exists()); // check the second database database.SetName(databasename + L"2"); CPPUNIT_ASSERT(database.Exists()); // drop the created databases MSXML2::IXMLDOMNodePtr mssqldatabase_node; MSXML2::IXMLDOMNodeListPtr mssqldatabase_nodes = xml.SelectNodes(L"/MSSQLDatabases/MSSQLDatabase"); while(NULL != (mssqldatabase_node = mssqldatabase_nodes->nextNode())) xml.SetAttribute(L"actions", L"drop", mssqldatabase_node); msiInstall.SetProperty(L"CustomActionData", xml.GetXml()); CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"DataSource.dll", L"CreateDatabases_SQLServer_Deferred")); }
CA_API UINT __stdcall TemplateFiles_Deferred(MSIHANDLE hInstall) { MSI_EXCEPTION_HANDLER_PROLOG; MsiInstall msiInstall(hInstall); AppSecInc::Xml::XmlDocument xmlDocument; xmlDocument.LoadXml(msiInstall.GetActionData()); MSXML2::IXMLDOMNodeListPtr rows = xmlDocument.SelectNodes(L"//TemplateFile[@execute='true']"); // \todo //Row[@rollback='false'] MSXML2::IXMLDOMNodePtr row = NULL; while (NULL != (row = rows->nextNode())) { std::wstring id = xmlDocument.GetAttributeValue(L"id", row); std::wstring source = xmlDocument.GetNodeValue(L"Source", row); std::wstring target = xmlDocument.GetNodeValue(L"Target", row, source); msiInstall.LogInfo(L"TemplateFiles_Deferred", source + L" => " + target); std::map<std::wstring, std::wstring> properties; { MSXML2::IXMLDOMNodeListPtr property_rows = xmlDocument.SelectNodes(L"Properties/Property", row); MSXML2::IXMLDOMNodePtr property_row = NULL; while (NULL != (property_row = property_rows->nextNode())) { std::wstring name = xmlDocument.GetAttributeValue(L"name", property_row); std::wstring value = xmlDocument.GetAttributeValue(L"value", property_row); long escape = AppSecInc::StringUtils::stringToLong(xmlDocument.GetAttributeValue(L"escape", property_row, L"0")); properties[name] = escape == 1 ? AppSecInc::StringUtils::escape(value) : value; } } std::wstring data; bool utf8 = AppSecInc::File::ReadAndConvertToEnd(source, data); data = AppSecInc::Formatter::FormatTemplate(data, properties); std::string char_data; if (utf8) { char_data = AppSecInc::StringUtils::wc2utf8(data); char_data.insert(0, std::string(reinterpret_cast<char *>(AppSecInc::File::utf8_bom))); } else { char_data = AppSecInc::StringUtils::wc2mb(data); } std::vector<char> binary_data; binary_data.assign(char_data.begin(), char_data.end()); AppSecInc::File::FileWrite(target, binary_data); } MSI_EXCEPTION_HANDLER_EPILOG; return ERROR_SUCCESS; }
void XmlDocumentUnitTests::testSelectNodes() { struct testSelectNodes_TestData { LPCWSTR xpath; long count; }; testSelectNodes_TestData testdata[] = { { L"/bookstore", 1 }, { L"/bookstore/book", 2 } }; std::wstring xmlfile = GetLocalFileLocation(L"store.xml"); std::wcout << std::endl << L"Xml: " << xmlfile; AppSecInc::Xml::XmlDocument xml; xml.Load(xmlfile, CLSID_DOMDocument); for (int i = 0; i < ARRAYSIZE(testdata); i++) { MSXML2::IXMLDOMNodeListPtr nodes = xml.SelectNodes(testdata[i].xpath); std::wcout << std::endl << testdata[i].xpath << L": " << nodes->length; CPPUNIT_ASSERT(testdata[i].count == nodes->length); } }
void CreateDatabasesUnitTests::Test_CreateDatabases_Access() { AppSecInc::Msi::MsiShim hInstall; std::wstring testdatapath = AppSecInc::File::GetModuleDirectoryW() + L"\\TestData_DataSourceUnitTests"; for each(const std::wstring& idtfile in AppSecInc::File::GetFiles(testdatapath, L"*.idt")) { std::wstring idtfile_name = AppSecInc::File::GetFileNameW(idtfile); std::wcout << std::endl << L" Importing \"" << idtfile_name << L"\""; hInstall.Import(testdatapath, idtfile_name); } AppSecInc::Msi::MsiInstall msiInstall(hInstall); std::wstring dbq = AppSecInc::File::DirectoryCombine( AppSecInc::File::GetTemporaryDirectoryW(), AppSecInc::Com::GenerateGUIDStringW() + L".dbq"); std::wcout << std::endl << L"DBQ: " << dbq; msiInstall.SetProperty(L"ACCESS_DATABASE_DBQ", dbq); msiInstall.SetProperty(L"INSTALLLOCATION", AppSecInc::File::GetSpecialFolderPath(CSIDL_COMMON_APPDATA) + L"\\"); AppSecInc::Xml::XmlDocument xml; CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"DataSource.dll", L"CreateDatabases_Access_Immediate")); xml.LoadXml(msiInstall.GetProperty(L"CreateDatabases_Access_Deferred_Install")); // two databases, both have create actions, one is checkIfExists CPPUNIT_ASSERT(1 == xml.SelectNodes(L"/AccessDatabases/AccessDatabase")->length); CPPUNIT_ASSERT(1 == xml.SelectNodes(L"/AccessDatabases/AccessDatabase[@actions='create']")->length); CPPUNIT_ASSERT(1 == xml.SelectNodes(L"/AccessDatabases/AccessDatabase[@checkIfExists='false']")->length); CPPUNIT_ASSERT(0 == xml.SelectNodes(L"/AccessDatabases/AccessDatabase[@checkIfExists='true']")->length); // connection strings must be encrypted MSXML2::IXMLDOMNodeListPtr connectionStrings = xml.SelectNodes(L"/AccessDatabases/AccessDatabase/ConnectionString/text()"); for (int i = 0; i < connectionStrings->length; i++) { std::wstring encrypted = StringUtils::mb2wc(StringUtils::bstr2mb(connectionStrings->item[i]->text)); AppSecInc::Crypt::DPAPIImpl::UnProtect(encrypted); // Fails if input string is not encrypted } // create the databases msiInstall.SetProperty(L"CustomActionData", msiInstall.GetProperty(L"CreateDatabases_Access_Deferred_Install")); CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"DataSource.dll", L"CreateDatabases_Access_Deferred")); // check that the database exists AppSecInc::Databases::Access::AccessDatabase database; database.SetDBQ(dbq); CPPUNIT_ASSERT(database.Exists()); // drop the created databases MSXML2::IXMLDOMNodePtr Accessdatabase_node; MSXML2::IXMLDOMNodeListPtr Accessdatabase_nodes = xml.SelectNodes(L"/AccessDatabases/AccessDatabase"); while(NULL != (Accessdatabase_node = Accessdatabase_nodes->nextNode())) xml.SetAttribute(L"actions", L"drop", Accessdatabase_node); msiInstall.SetProperty(L"CustomActionData", xml.GetXml()); CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"DataSource.dll", L"CreateDatabases_Access_Deferred")); }
CA_API UINT __stdcall TemplateFiles_Immediate(MSIHANDLE hInstall) { MSI_EXCEPTION_HANDLER_PROLOG; MsiInstall msiInstall(hInstall); // combined xml document AppSecInc::Xml::XmlDocument combined_xml_document; combined_xml_document.Create(); MSXML2::IXMLDOMNodePtr combined_xml_root = combined_xml_document.AppendChild(L"TemplateFiles"); std::wstring xml = msiInstall.GetViewData(L"SELECT * FROM `TemplateFiles`"); AppSecInc::Xml::XmlDocument xmlDocument; xmlDocument.LoadXml(xml); { MSXML2::IXMLDOMNodeListPtr rows = xmlDocument.SelectNodes(L"//Row"); MSXML2::IXMLDOMNodePtr row = NULL; while (NULL != (row = rows->nextNode())) { // id std::wstring templatefile_id = xmlDocument.GetNodeValue(L"Data[@Column=\"Id\"]", row, L""); // component id std::wstring component_id = xmlDocument.GetNodeValue(L"Data[@Column=\"ComponentId\"]", row, L""); // node condition std::wstring condition = xmlDocument.GetNodeValue(L"Data[@Column=\"Condition\"]", row); // operational attributes long attributes = AppSecInc::StringUtils::stringToLong(xmlDocument.GetNodeValue(L"Data[@Column=\"Attributes\"]", row)); // no condition (executes by default) or condition evaluates to true bool execute_per_condition = condition.empty() || msiInstall.EvaluateCondition(condition); if (! condition.empty()) { // set the evaluated value for debugging purposes xmlDocument.SelectNode(L"Data[@Column=\"Condition\"]", row)->text = _bstr_t(execute_per_condition ? L"1" : L"0"); } // execute on install bool execute_per_component_install = (component_id.empty() || msiInstall.IsComponentInstalling(component_id)); // execute on uninstall bool execute_per_component_uninstall = (component_id.empty() || msiInstall.IsComponentUnInstalling(component_id)); // execute on reinstall bool execute_per_component_reinstall = (component_id.empty() || msiInstall.IsComponentReInstalling(component_id)); bool execute = execute_per_condition && ( (execute_per_component_install && (attributes & ExecuteOnInstall) && msiInstall.IsInstalling()) || (execute_per_component_uninstall && (attributes & ExecuteOnUnInstall) && msiInstall.IsUnInstalling()) || (execute_per_component_reinstall && (attributes & ExecuteOnReInstall) && msiInstall.IsReInstalling()) ); MSXML2::IXMLDOMNodePtr templatefile_node = combined_xml_document.AppendChild(L"TemplateFile", combined_xml_root); combined_xml_document.SetAttribute(L"id", templatefile_id, templatefile_node); std::wstring source = xmlDocument.GetNodeValue(L"Data[@Column=\"Source\"]", row); std::wstring target = xmlDocument.GetNodeValue(L"Data[@Column=\"Target\"]", row, source); combined_xml_document.AppendChild(L"Source", templatefile_node)->text = _bstr_t(source.c_str()); combined_xml_document.AppendChild(L"Target", templatefile_node)->text = _bstr_t(target.c_str()); combined_xml_document.SetAttribute(L"execute", execute ? L"true" : L"false", templatefile_node); MSXML2::IXMLDOMNodePtr properties_node = combined_xml_document.AppendChild(L"Properties", templatefile_node); // append built-in properties { AppSecInc::Xml::XmlDocument xmlPropertiesDocument; xmlPropertiesDocument.LoadXml(msiInstall.GetViewData(L"SELECT * FROM `Property`")); MSXML2::IXMLDOMNodeListPtr property_rows = xmlPropertiesDocument.SelectNodes(L"//Row"); MSXML2::IXMLDOMNodePtr property_row = NULL; while (NULL != (property_row = property_rows->nextNode())) { std::wstring name = xmlPropertiesDocument.GetNodeValue(L"Data[@Column=\"Property\"]", property_row); std::wstring value = xmlPropertiesDocument.GetNodeValue(L"Data[@Column=\"Value\"]", property_row); MSXML2::IXMLDOMNodePtr property_node = combined_xml_document.AppendChild(L"Property", properties_node); combined_xml_document.SetAttribute(L"name", name, property_node); combined_xml_document.SetAttribute(L"value", value, property_node); } } // append properties from this TemplateFile { AppSecInc::Xml::XmlDocument xmlPropertiesDocument; xmlPropertiesDocument.LoadXml(msiInstall.GetViewData(L"SELECT * FROM `TemplateFileProperties`")); MSXML2::IXMLDOMNodeListPtr property_rows = xmlPropertiesDocument.SelectNodes(L"//Row"); MSXML2::IXMLDOMNodePtr property_row = NULL; while (NULL != (property_row = property_rows->nextNode())) { // \todo Change XPATH to fetch only rows that match ID std::wstring id = xmlPropertiesDocument.GetNodeValue(L"Data[@Column=\"TemplateFileId\"]", property_row); if (id != templatefile_id) continue; std::wstring name = xmlPropertiesDocument.GetNodeValue(L"Data[@Column=\"Name\"]", property_row); std::wstring value = xmlPropertiesDocument.GetNodeValue(L"Data[@Column=\"Value\"]", property_row); std::wstring escape = xmlPropertiesDocument.GetNodeValue(L"Data[@Column=\"Escape\"]", property_row); MSXML2::IXMLDOMNodePtr property_node = combined_xml_document.AppendChild(L"Property", properties_node); combined_xml_document.SetAttribute(L"name", name, property_node); combined_xml_document.SetAttribute(L"value", value, property_node); combined_xml_document.SetAttribute(L"escape", escape, property_node); } } } } msiInstall.SetActionData(L"TemplateFiles_Deferred", combined_xml_document.GetXml()); MSI_EXCEPTION_HANDLER_EPILOG; return ERROR_SUCCESS; }
CA_API UINT __stdcall LocalGroupMembers_Deferred(MSIHANDLE hInstall) { MSI_EXCEPTION_HANDLER_PROLOG; MsiInstall msiInstall(hInstall); AppSecInc::Xml::XmlDocument xmlDocument; xmlDocument.LoadXml(msiInstall.GetActionData()); MSXML2::IXMLDOMNodeListPtr rows = xmlDocument.SelectNodes(L"/LocalGroupMembers/LocalGroupMember"); MSXML2::IXMLDOMNodePtr row = NULL; while (NULL != (row = rows->nextNode())) { std::wstring id = xmlDocument.GetAttributeValue(L"id", row); std::wstring username = xmlDocument.GetNodeValue(L"Username", row); std::wstring groupname = xmlDocument.GetNodeValue(L"Group", row, L""); bool add_member = xmlDocument.GetAttributeBoolValue(L"add", row); bool remove_member = xmlDocument.GetAttributeBoolValue(L"remove", row); bool check = xmlDocument.GetAttributeBoolValue(L"check", row); if (remove_member && (! check || AppSecInc::LSA::LocalGroup::IsMember(groupname, username))) { msiInstall.LogInfo(_T(__FUNCTION__), L"Removing \"" + username + L"\" from \"" + groupname + L"\""); AppSecInc::LSA::LocalGroup::DeleteMember(groupname, username); } if (add_member && (! check || ! AppSecInc::LSA::LocalGroup::IsMember(groupname, username))) { msiInstall.LogInfo(_T(__FUNCTION__), L"Adding \"" + username + L"\" to \"" + groupname + L"\""); AppSecInc::LSA::LocalGroup::AddMember(groupname, username); } } MSI_EXCEPTION_HANDLER_EPILOG; return ERROR_SUCCESS; }