diff --git a/Engine.cpp b/Engine.cpp index 8832797..a2787be 100644 --- a/Engine.cpp +++ b/Engine.cpp @@ -23,6 +23,12 @@ pProcessDomain( _In_ BOOL bWriteTableInfo ); +BOOL +pGetFileVersion( + _Out_ wchar_t* szVersion, + _In_ size_t _BufferCount +); + BOOL Process ( _In_ PGLOBAL_CONFIG pGlobalConfig @@ -35,10 +41,14 @@ Process ( ROOTDSE_CONFIG RootDse = { 0 }; + DWORD dwStartTime, dwEndTime; + + dwStartTime = GetTickCount(); + // // Get server by DC Locator, if needed // - if (wcscmp(pGlobalConfig->szServer, L"[dsgetdc]") == 0) + if (wcscmp(pGlobalConfig->szServer, DC_LOCATOR_OPTION) == 0) { bResult = pLocateDc(NULL, &szServer); if (bResult == FALSE) @@ -79,13 +89,13 @@ Process ( } swprintf( - szDirectory, MAX_PATH, + pGlobalConfig->szFullOutDirectory, MAX_PATH, L"%s\\%s\\%s", pGlobalConfig->szOutDirectory, szRootDns, pGlobalConfig->szSystemTime ); - CreateDirectory(szDirectory, NULL); + CreateDirectory(pGlobalConfig->szFullOutDirectory, NULL); swprintf( szDirectory, MAX_PATH, @@ -190,7 +200,39 @@ Process ( { ROOTDSE_CONFIG pRootDse = { 0 }; - pProcessDomain(pGlobalConfig, &pRootDse, szDirectory, szServer, szRootDns, TRUE, TRUE); + pProcessDomain(pGlobalConfig, &pRootDse, szDirectory, szServer, szRootDns, TRUE, FALSE); + + // + // Process Forest domains + // + if (pGlobalConfig->szForestDomains != NULL) + { + LPWSTR szContext = NULL; + LPWSTR szOtherDomain = wcstok_s(pGlobalConfig->szForestDomains, L",", &szContext); + + while (szOtherDomain != NULL) + { + ROOTDSE_CONFIG pOtherRootDse = { 0 }; + bResult = pLocateDc(szOtherDomain, &szServer); + if (bResult != FALSE) + { + Log( + __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_INFORMATION, + "Processing extra domain in forest: %S", + szOtherDomain + ); + pProcessDomain(pGlobalConfig, &pOtherRootDse, szDirectory, szServer, szRootDns, TRUE, TRUE); + } + szOtherDomain = wcstok_s(NULL, L",", &szContext); + } + } + + // + // Write table infos into table file (FALSE, TRUE) + // Done only after all requests (TRUE, FALSE) to be sure to have max text size for all domains + // + pProcessDomain(pGlobalConfig, &pRootDse, szDirectory, szServer, szRootDns, FALSE, TRUE); + _SafeHeapRelease(szServer); } else @@ -257,10 +299,55 @@ Process ( bReturn = TRUE; End: - _SafeHeapRelease(szRootDns); + dwEndTime = GetTickCount() - dwStartTime; + if (pGlobalConfig->hTableFile != NULL) + { + // + // Write metatada table + // + BUFFER_DATA Buffer; + WCHAR szFilename[MAX_PATH]; + WCHAR szMetadata[1024]; + + swprintf( + szFilename, MAX_PATH, + L"%s\\%s\\%s\\metadata.tsv", + pGlobalConfig->szOutDirectory, + szRootDns, + pGlobalConfig->szSystemTime + ); + bResult = BufferInitialize(&Buffer, szFilename); + if (bResult != FALSE) + { + // Exe version + BufferWrite(&Buffer, (LPWSTR)L"oradad_version"); + BufferWriteTab(&Buffer); + pGetFileVersion(szMetadata, 1024); + BufferWrite(&Buffer, szMetadata); + BufferWriteLine(&Buffer); + // Process Time + BufferWrite(&Buffer, (LPWSTR)L"oradad_processtime"); + BufferWriteTab(&Buffer); + swprintf_s(szMetadata, 1024, L"%d", dwEndTime); + BufferWrite(&Buffer, szMetadata); + BufferWriteLine(&Buffer); + // Level + BufferWrite(&Buffer, (LPWSTR)L"oradad_level"); + BufferWriteTab(&Buffer); + swprintf_s(szMetadata, 1024, L"%d", pGlobalConfig->dwLevel); + BufferWrite(&Buffer, szMetadata); + BufferWriteLine(&Buffer); + + BufferClose(&Buffer); + + WriteTextFile(pGlobalConfig->hTableFile, "metadata.tsv\tmetadata\tmetadata\t2\tkey\tnvarchar(255)\tvalue\tnvarchar(1024)\n"); + } + CloseHandle(pGlobalConfig->hTableFile); + } + _SafeHeapRelease(szRootDns); return bReturn; } @@ -405,4 +492,42 @@ pProcessDomain ( _SafeHeapRelease(szDomainDns); return TRUE; +} + +BOOL +pGetFileVersion ( + _Out_ wchar_t* const szVersion, + _In_ size_t const _BufferCount +) +{ + WCHAR szFilename[MAX_PATH]; + + GetModuleFileNameW(NULL, szFilename, MAX_PATH); + DWORD dwHandle; + DWORD sz = GetFileVersionInfoSizeW(szFilename, &dwHandle); + if (0 == sz) + { + return FALSE; + } + PBYTE pbBuf = (PBYTE)_HeapAlloc(sz); + if (GetFileVersionInfoW(szFilename, dwHandle, sz, pbBuf) == FALSE) + { + _SafeHeapRelease(pbBuf); + return FALSE; + } + VS_FIXEDFILEINFO * pvi; + sz = sizeof(VS_FIXEDFILEINFO); + if (!VerQueryValueW(pbBuf, L"\\", (LPVOID*)&pvi, (unsigned int*)&sz)) + { + _SafeHeapRelease(pbBuf); + return FALSE; + } + swprintf(szVersion, _BufferCount, L"%d.%d.%d.%d", + pvi->dwProductVersionMS >> 16, + pvi->dwFileVersionMS & 0xFFFF, + pvi->dwFileVersionLS >> 16, + pvi->dwFileVersionLS & 0xFFFF + ); + _SafeHeapRelease(pbBuf); + return 0; } \ No newline at end of file diff --git a/LDAP.cpp b/LDAP.cpp index 7076c33..f574423 100644 --- a/LDAP.cpp +++ b/LDAP.cpp @@ -371,13 +371,14 @@ LdapProcessRequest ( berval *pBerVal = NULL; + DWORD dwObjectCount = 0; DWORD dwStartTime, dwEndTime; dwStartTime = GetTickCount(); Log( - __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_VERBOSE, - "Start dump '%S/%S/%S/%S'.", szRootDns, szPath1, szPath2, pRequest->szName + __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_INFORMATION, + "Dumping '%S/%S/%S/%S'.", szRootDns, szPath1, szPath2, pRequest->szName ); // @@ -772,10 +773,15 @@ LdapProcessRequest ( } else { - Log( - __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_WARNING, - "ldap_get_values(%S, %s) has no value but is not with range.", szDn, pAttribute - ); + // We exclude 'msDS-RevealedList' attribute which can be + // returned even null + if (wcscmp(pAttribute, L"msDS-RevealedList") != 0) + { + Log( + __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_WARNING, + "ldap_get_values(%S, %S) has no value but is not with range.", szDn, pAttribute + ); + } } } } @@ -1009,7 +1015,7 @@ LdapProcessRequest ( } BufferWriteLine(pBuffer); - + dwObjectCount++; ldap_memfree(szDn); } @@ -1090,12 +1096,15 @@ LdapProcessRequest ( BufferClose(&Buffer); dwEndTime = GetTickCount(); + dwEndTime = (dwEndTime - dwStartTime) / 1000; Log( __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_INFORMATION, - "Dump '%S/%S/%S/%S' finished (elapsed time: %u seconds).", - szRootDns, szPath1, szPath2, pRequest->szName, - (dwEndTime - dwStartTime) / 1000 + " Finished: elapsed time: %u second%s, %u object%s.", + dwEndTime, + dwEndTime > 1 ? "s" : "", + dwObjectCount, + dwObjectCount > 1 ? "s" : "" ); } @@ -1369,7 +1378,7 @@ pHasAttributeWithRange ( { Log( __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_VERBOSE, - "'%S' has attribute '%S' with range.", + "'%S' has at least one attribute with range ('%S').", szDn, szAttrName ); bReturn = TRUE; @@ -1496,4 +1505,30 @@ pGetRangedAttribute ( ldap_msgfree(pLdapMessage); return ppValue; -} \ No newline at end of file +} + +/* + BerElement* pBer = NULL; + + pAttribute = ldap_first_attribute( + pLdapHandle, // Session handle + pEntry, // Current entry + &pBer); // [out] Current BerElement + + while (pAttribute != NULL) + { + ldap_memfree(pAttribute); + + pAttribute = ldap_next_attribute( + pLdapHandle, // Session Handle + pEntry, // Current entry + pBer); // Current BerElement + } + } + + if (pBer != NULL) + { + ber_free(pBer, 0); + pBer = NULL; + } +*/ \ No newline at end of file diff --git a/Main.cpp b/Main.cpp index 70dcbf3..8742a80 100644 --- a/Main.cpp +++ b/Main.cpp @@ -1,18 +1,21 @@ #include #include #include +#include #include "ORADAD.h" #pragma comment(lib, "msxml6.lib") #pragma comment(lib, "wldap32.lib") #pragma comment(lib, "rpcrt4.lib") #pragma comment(lib, "NetApi32.lib") +#pragma comment(lib, "Mincore.lib") HANDLE g_hHeap = NULL; HANDLE g_hLogFile = NULL; GLOBAL_CONFIG g_GlobalConfig = { 0 }; +//__declspec(dllexport) int wmain ( int argc, @@ -22,6 +25,7 @@ wmain ( HRESULT hr; SYSTEMTIME st; IXMLDOMDocument2 *pXMLDoc = NULL; + TCHAR szPath[MAX_PATH]; // // Check command line parameters @@ -32,31 +36,37 @@ wmain ( return EXIT_FAILURE; } + // + // Initialization + // + g_hHeap = HeapCreate(0, 0, 0); + if (g_hHeap == NULL) + { + return EXIT_FAILURE; + } + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + // // Start logging // - g_hLogFile = CreateFile(TEXT("oradad.log"), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL); + DuplicateString(argv[1], &g_GlobalConfig.szOutDirectory); + _stprintf_s(szPath, MAX_PATH, TEXT("%s\\oradad.log"), g_GlobalConfig.szOutDirectory); + + g_hLogFile = CreateFile(szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); if (g_hLogFile == INVALID_HANDLE_VALUE) { fprintf_s(stderr, "[!] Unable to open log file. Exit.\n"); return EXIT_FAILURE; } - SetFilePointer(g_hLogFile, 0, 0, FILE_END); Log( __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_INFORMATION, "Starting." ); - - // - // Initialization - // - g_hHeap = HeapCreate(0, 0, 0); - if (g_hHeap == NULL) - { - return EXIT_FAILURE; - } - hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + Log( + __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_VERBOSE, + "Output directory is '%S'.", g_GlobalConfig.szOutDirectory + ); // // Read configuration @@ -68,13 +78,6 @@ wmain ( // // Main process // - DuplicateString(argv[1], &g_GlobalConfig.szOutDirectory); - - Log( - __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_VERBOSE, - "Output directory is '%S'.", g_GlobalConfig.szOutDirectory - ); - GetSystemTime(&st); swprintf_s( g_GlobalConfig.szSystemTime, 17, @@ -89,13 +92,26 @@ wmain ( // Release // End: + Log( + __FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_INFORMATION, + "End." + ); + CloseHandle(g_hLogFile); + + // Move log file to output directory + if (g_GlobalConfig.szFullOutDirectory[0] != 0) + { + TCHAR szFinalPath[MAX_PATH]; + + _stprintf_s(szFinalPath, MAX_PATH, TEXT("%s\\oradad.log"), g_GlobalConfig.szFullOutDirectory); + MoveFile(szPath, szFinalPath); + } + _SafeHeapRelease(g_GlobalConfig.szOutDirectory); HeapDestroy(g_hHeap); _SafeCOMRelease(pXMLDoc); CoUninitialize(); - CloseHandle(g_hLogFile); - return EXIT_SUCCESS; } \ No newline at end of file diff --git a/ORADAD.h b/ORADAD.h index 58a973c..60a100e 100644 --- a/ORADAD.h +++ b/ORADAD.h @@ -8,4 +8,9 @@ #define _SafeHeapRelease(x) { if (NULL != x) { HeapFree(g_hHeap, 0, x); x = NULL; } } #define _SafeCOMRelease(x) { if (NULL != x) { x->Release(); x = NULL; } } -#define _CallWriteAndGetMax(x, y) do { DWORD dwTempSizeResult; dwTempSizeResult = x; if (dwTempSizeResult>y) y=dwTempSizeResult; } while(FALSE) \ No newline at end of file +#define _CallWriteAndGetMax(x, y) do { DWORD dwTempSizeResult; dwTempSizeResult = x; if (dwTempSizeResult>y) y=dwTempSizeResult; } while(FALSE) + +// +// Defines +// +#define DC_LOCATOR_OPTION L"[dsgetdc]" diff --git a/ORADAD.rc b/ORADAD.rc index ea5f006..89d9b03 100644 Binary files a/ORADAD.rc and b/ORADAD.rc differ diff --git a/Structures.h b/Structures.h index 6ad23fd..6c86a47 100644 --- a/Structures.h +++ b/Structures.h @@ -146,6 +146,7 @@ typedef struct _GLOBAL_CONFIG WCHAR szSystemTime[17]; LPWSTR szOutDirectory; + WCHAR szFullOutDirectory[MAX_PATH]; HANDLE hTableFile; BOOL bWriteHeader; @@ -159,6 +160,8 @@ typedef struct _GLOBAL_CONFIG BOOL bAllDomainsInForest; BOOL dwSleepTime; + LPWSTR szForestDomains; + DWORD dwRequestCount; PREQUEST_CONFIG pRequests; diff --git a/XML.cpp b/XML.cpp index f2c9395..837463e 100644 --- a/XML.cpp +++ b/XML.cpp @@ -170,6 +170,8 @@ XmlReadConfigFile ( pGlobalConfig->szUserPassword = strNodeText; else if ((wcscmp(strNodeName, L"allDomainsInForest") == 0) && (wcslen(strNodeText) > 0)) pGlobalConfig->bAllDomainsInForest = pReadBoolean(strNodeText); + else if ((wcscmp(strNodeName, L"forestDomains") == 0) && (wcslen(strNodeText) > 0)) + pGlobalConfig->szForestDomains = strNodeText; else if ((wcscmp(strNodeName, L"level") == 0) && (wcslen(strNodeText) > 0)) pGlobalConfig->dwLevel = pReadUInteger(strNodeText); else if ((wcscmp(strNodeName, L"sleepTime") == 0) && (wcslen(strNodeText) > 0)) @@ -183,6 +185,16 @@ XmlReadConfigFile ( _SafeCOMRelease(pXMLNodeList); _SafeCOMRelease(pXMLNode); + + // + // Check attributes + // + // Find all domains in forest can only be done with DC locator option + if ((wcscmp(pGlobalConfig->szServer, DC_LOCATOR_OPTION) != 0) && (pGlobalConfig->bAllDomainsInForest == TRUE)) + { + pGlobalConfig->bAllDomainsInForest = FALSE; + } + // // Read Attributes // diff --git a/config-oradad.xml b/config-oradad.xml index 0b893fa..762b246 100644 --- a/config-oradad.xml +++ b/config-oradad.xml @@ -1,12 +1,13 @@ - [dsgetdc] - - + [dsgetdc] + + 1 + 2 0 0 @@ -93,43 +94,66 @@ + + + + + - - - - - + + + + + + + + + + - + + + + + + + + + + + + + + @@ -137,8 +161,6 @@ - - @@ -152,26 +174,41 @@ - + + + + + + - - + + + + + + + + + + + + @@ -180,17 +217,19 @@ + + + - @@ -199,17 +238,24 @@ + + + + + + + @@ -220,29 +266,39 @@ + + + - + + + + + + - + + + @@ -254,9 +310,11 @@ + + @@ -265,22 +323,25 @@ - - - - + - - + + + + + + + + @@ -289,19 +350,29 @@ + + + + + + + + + + - + @@ -310,23 +381,35 @@ + + + + + + + + + + + + - - + + @@ -334,87 +417,12 @@ + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -872,6 +880,15 @@ + + + + + + + + +