//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // File : OSACHECK.CPP // // Synopsis: Tools to check OSATTR(s) of catalog file(s). // // History: DSIE - January 30, 2001 // // Microsoft Corporation (c) Copy Rights 2001. // #include #include #include #include #include #include #include #include #include #include #include //////////////////// // // macros // #define ASSERT(x) _ASSERT(x) #define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) //////////////////// // // Global variables // _TCHAR * g_pszFilePath = _T(""); // Pointer to catalog file path. BOOL g_bCatalogOSAttrOnly = FALSE; // OSAttr listing only flag. BOOL g_bIncludeSubDir = FALSE; // Inlcude sub-dir flag. BOOL g_bIgnoreError = FALSE; // Ignore error flag. BOOL g_bVerbose = FALSE; // Verbose flag. BOOL g_bViewCatalog = FALSE; // Display catalog dialog flag. //------------------------------------------------------------------------------ // // Function: DebugTrace // //------------------------------------------------------------------------------ #ifdef PKIDEBUG BOOL g_bUseOutputDebugString = FALSE; // Use OutputDebugString flag. void DebugTrace (char * pszFormat, ...) { char szMessage[512] = ""; va_list arglist; va_start(arglist, pszFormat); _vsnprintf(szMessage, ARRAYSIZE(szMessage), pszFormat, arglist); if (g_bUseOutputDebugString) { OutputDebugString(szMessage); } else { fprintf(stderr, szMessage); } va_end(arglist); return; } #else inline void DebugTrace (char * pszFormat, ...) {} #endif //------------------------------------------------------------------------------ // // Function: DisplayHelp // //------------------------------------------------------------------------------ void DisplayHelp (_TCHAR * pszFullExePath, BOOL bExtraHelp) { _TCHAR szDrive[_MAX_DRIVE] = _T(""); _TCHAR szDir[_MAX_DIR] = _T(""); _TCHAR szFName[_MAX_FNAME] = _T(""); _TCHAR szExt[_MAX_EXT] = _T(""); _TCHAR * pszExeName = _T("OSACheck"); if (pszFullExePath) { _splitpath(pszFullExePath, szDrive, szDir, szFName, szExt); pszExeName = szFName; } _ftprintf(stderr, _T("Usage: %s [drive:][path][filename] [options]\n"), pszExeName); _ftprintf(stderr, _T("\n")); _ftprintf(stderr, _T(" [drive:][path][filename]\n")); _ftprintf(stderr, _T(" Specifies drive, directory, and/or catalog files to scan.\n")); _ftprintf(stderr, _T("\n")); _ftprintf(stderr, _T(" [options]\n")); _ftprintf(stderr, _T(" -c List only catalog OSAttrs (no file listing).\n")); _ftprintf(stderr, _T(" -s Scan catalog files in specified directory and all subdirectories.\n")); _ftprintf(stderr, _T(" -i Ignore error and continue with next catalog file.\n")); _ftprintf(stderr, _T(" -v Verbose.\n")); if (bExtraHelp) { #ifdef PKIDEBUG _ftprintf(stderr, _T(" ~d Display catalog dialog.\n")); _ftprintf(stderr, _T(" ~o Use OutputDebugString() for debug trace.\n")); #endif _ftprintf(stderr, _T(" ~h This help screen.\n")); } else { _ftprintf(stderr, _T(" -h This help screen.\n")); } _ftprintf(stderr, _T("\n")); _ftprintf(stderr, _T("Note: If filename is not provided, *.CAT is assumed.\n")); _ftprintf(stderr, _T("\n")); return; } //------------------------------------------------------------------------------ // // Function: ParseCommandLine // //------------------------------------------------------------------------------ int ParseCommandLine (int argc, _TCHAR * argv[]) { int nResult = 0; BOOL bDisplayHelp = FALSE; BOOL bExtraHelp = FALSE; ASSERT(argc); for (int i = 1; i < argc; i++) { ASSERT(argv[i]); if (_T('-') == argv[i][0] || _T('/') == argv[i][0]) { switch (toupper(argv[i][1])) { case _T('C'): { g_bCatalogOSAttrOnly = TRUE; break; } case _T('I'): { g_bIgnoreError = TRUE; break; } case _T('S'): { g_bIncludeSubDir = TRUE; break; } case _T('V'): { g_bVerbose = TRUE; break; } case _T('?'): case _T('H'): default: { nResult = -1; bDisplayHelp = TRUE; break; } } } else if (_T('~') == argv[i][0]) { switch (toupper(argv[i][1])) { case _T('D'): { g_bViewCatalog = TRUE; break; } #ifdef PKIDEBUG case _T('O'): { g_bUseOutputDebugString = TRUE; break; } #endif case _T('?'): case _T('H'): default: { nResult = -1; bExtraHelp = TRUE; bDisplayHelp = TRUE; break; } } } else if (0 == _tcslen(g_pszFilePath)) { g_pszFilePath = argv[i]; if (NULL == _tcschr(g_pszFilePath, _T('*')) && NULL == strchr(g_pszFilePath, _T('?'))) { long hFile; struct _finddata_t fd; if (-1 != (hFile = _tfindfirst(g_pszFilePath, &fd))) { if (_A_SUBDIR & fd.attrib) { if (_T('\\') != g_pszFilePath[_tcslen(g_pszFilePath) - 1]) { if (g_pszFilePath = (_TCHAR *) malloc((_tcslen(g_pszFilePath) + _tcslen(_T("\\")) + 1) * sizeof(_TCHAR))) { _tcscpy(g_pszFilePath, argv[i]); _tcscat(g_pszFilePath, _T("\\")); } else { nResult = -2; } } } _findclose(hFile); } } } else { nResult = -3; bDisplayHelp = TRUE; } if (bDisplayHelp) { DisplayHelp(argv[0], bExtraHelp); break; } } return nResult; } //------------------------------------------------------------------------------ // // Function: ViewCatalog // //------------------------------------------------------------------------------ int ViewCatalog (PCCTL_CONTEXT pCTLContext) { CRYPTUI_VIEWCTL_STRUCT ViewCTLStruct; ASSERT(pCTLContext); memset(&ViewCTLStruct, 0, sizeof(ViewCTLStruct)); ViewCTLStruct.dwSize = sizeof(ViewCTLStruct); ViewCTLStruct.pCTLContext = pCTLContext; CryptUIDlgViewCTL(&ViewCTLStruct); return 0; } //------------------------------------------------------------------------------ // // Function: DecodeObject // //------------------------------------------------------------------------------ int DecodeObject (LPCSTR pszStructType, BYTE * pbEncoded, DWORD cbEncoded, CRYPT_DATA_BLOB * pDecodedBlob) { int nResult = 0; DWORD cbDecoded = 0; BYTE * pbDecoded = NULL; ASSERT(pszStructType); ASSERT(pbEncoded); ASSERT(pDecodedBlob); __try { pDecodedBlob->cbData = 0; pDecodedBlob->pbData = NULL; if (!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pszStructType, (const BYTE *) pbEncoded, cbEncoded, 0, NULL, &cbDecoded)) { nResult = GetLastError(); DebugTrace("\nError [%#x]: CryptDecodeObject() failed.\n", nResult); __leave; } if (!(pbDecoded = (BYTE *) malloc(cbDecoded))) { nResult = E_OUTOFMEMORY; DebugTrace("\nError: out of memory.\n"); __leave; } if (!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pszStructType, (const BYTE *) pbEncoded, cbEncoded, 0, pbDecoded, &cbDecoded)) { nResult = GetLastError(); DebugTrace("\nError [%#x]: CryptDecodeObject() failed.\n", nResult); __leave; } pDecodedBlob->cbData = cbDecoded; pDecodedBlob->pbData = pbDecoded; } __finally { if (nResult && pbDecoded) { free(pbDecoded); } } return nResult; } //------------------------------------------------------------------------------ // // Function: ProcessFileOSAttr // //------------------------------------------------------------------------------ int ProcessFileOSAttr (PCTL_INFO pCTLInfo) { int nResult = 0; ASSERT(pCTLInfo); for (DWORD i = 0; i < pCTLInfo->cCTLEntry; i++) { DWORD cOSAttr = 0; DWORD cFiles = 0; PCTL_ENTRY pCTLEntry = &pCTLInfo->rgCTLEntry[i]; if (i) { if (g_bVerbose) { _ftprintf(stdout, _T("\n%-10s"), _T("")); } else { _ftprintf(stdout, _T("\n%-14s"), _T("")); } } _ftprintf(stdout, _T("%-40S "), pCTLEntry->SubjectIdentifier.pbData); for (DWORD j = 0; j < pCTLEntry->cAttribute; j++) { PCRYPT_ATTRIBUTE pAttribute = &pCTLEntry->rgAttribute[j]; CRYPT_DATA_BLOB DataBlob = {0, NULL}; PCAT_NAMEVALUE pCATNameValue = NULL; if (0 != strcmp(pAttribute->pszObjId, CAT_NAMEVALUE_OBJID)) { continue; } if (0 != (nResult = DecodeObject(CAT_NAMEVALUE_STRUCT, pAttribute->rgValue[0].pbData, pAttribute->rgValue[0].cbData, &DataBlob))) { return nResult; } pCATNameValue = (PCAT_NAMEVALUE) DataBlob.pbData; if (0 == wcscmp(L"File", pCATNameValue->pwszTag)) { j = pCTLEntry->cAttribute; _ftprintf(stdout, _T("%-15S "), pCATNameValue->Value.pbData); cFiles++; } free(DataBlob.pbData); } if (0 == cFiles) { _ftprintf(stdout, _T("%-15s "), ""); } for (j = 0; j < pCTLEntry->cAttribute; j++) { PCRYPT_ATTRIBUTE pAttribute = &pCTLEntry->rgAttribute[j]; CRYPT_DATA_BLOB DataBlob = {0, NULL}; PCAT_NAMEVALUE pCATNameValue = NULL; if (0 != strcmp(pAttribute->pszObjId, CAT_NAMEVALUE_OBJID)) { continue; } if (0 != (nResult = DecodeObject(CAT_NAMEVALUE_STRUCT, pAttribute->rgValue[0].pbData, pAttribute->rgValue[0].cbData, &DataBlob))) { return nResult; } pCATNameValue = (PCAT_NAMEVALUE) DataBlob.pbData; if (0 == wcscmp(L"OSAttr", pCATNameValue->pwszTag)) { j = pCTLEntry->cAttribute; _ftprintf(stdout, _T("%S "), pCATNameValue->Value.pbData); cOSAttr++; } free(DataBlob.pbData); } } return nResult; } //------------------------------------------------------------------------------ // // Function: ProcessCatalogOSAttr // //------------------------------------------------------------------------------ int ProcessCatalogOSAttr (PCTL_INFO pCTLInfo) { int nResult = 0; DWORD cOSAttr = 0; ASSERT(pCTLInfo); for (DWORD i = 0; i < pCTLInfo->cExtension; i++) { PCERT_EXTENSION pExtension = &pCTLInfo->rgExtension[i]; if (0 == strcmp(CAT_NAMEVALUE_OBJID, pExtension->pszObjId)) { BOOL bDuplicate = TRUE; CRYPT_DATA_BLOB DataBlob = {0, NULL}; PCAT_NAMEVALUE pCATNameValue = NULL; if (0 != (nResult = DecodeObject(CAT_NAMEVALUE_STRUCT, pExtension->Value.pbData, pExtension->Value.cbData, &DataBlob))) { return nResult; } pCATNameValue = (PCAT_NAMEVALUE) DataBlob.pbData; if (0 == wcscmp(L"OSAttr", pCATNameValue->pwszTag)) { i = pCTLInfo->cExtension; _ftprintf(stdout, _T("%S"), pCATNameValue->Value.pbData); cOSAttr++; } free(DataBlob.pbData); } } if (0 == cOSAttr) { _ftprintf(stdout, _T("None")); } return nResult; } //------------------------------------------------------------------------------ // // Function: ProcessCatalog // //------------------------------------------------------------------------------ int ProcessCatalog (_TCHAR * pszFileName) { int nResult = 0; PCCTL_CONTEXT pCTLContext = NULL; ASSERT(pszFileName); __try { USES_CONVERSION; WCHAR * pwszFileName = NULL; if (g_bVerbose) { _TCHAR szCWD[_MAX_PATH] = _T(""); if (_tgetcwd(szCWD, ARRAYSIZE(szCWD))) { if (szCWD[_tcslen(szCWD) - 1] != _T('\\')) { szCWD[_tcslen(szCWD) + 1] = _T('\0'); szCWD[_tcslen(szCWD)] = _T('\\'); } _ftprintf(stdout, _T("-------------------------------------------------------------------------------\n")); _ftprintf(stdout, _T("Catalog = %s%s\n"), szCWD, pszFileName); } } else { _ftprintf(stdout, _T("%-14s"), pszFileName); } if (NULL == (pwszFileName = T2W(pszFileName))) { nResult = E_OUTOFMEMORY; DebugTrace(_T("Error: out of memory.\n")); __leave; } if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE, pwszFileName, CERT_QUERY_CONTENT_FLAG_CTL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, NULL, NULL, NULL, (const void **) &pCTLContext)) { nResult = GetLastError(); DebugTrace(_T("Error [%#x]: CryptQueryObject() failed.\n"), nResult); __leave; } if (g_bVerbose) { _ftprintf(stdout, _T("Entries = %d\n"), pCTLContext->pCtlInfo->cCTLEntry); if (g_bCatalogOSAttrOnly) { _ftprintf(stdout, _T("OSAttrs = ")); } else { _ftprintf(stdout, _T("Details = ")); } } if (g_bCatalogOSAttrOnly) { nResult = ProcessCatalogOSAttr(pCTLContext->pCtlInfo); } else { nResult = ProcessFileOSAttr(pCTLContext->pCtlInfo); } _ftprintf(stdout, _T("\n")); if (0 != nResult) { __leave; } if (g_bViewCatalog) { ViewCatalog(pCTLContext); } } __finally { if (pCTLContext) { CertFreeCTLContext(pCTLContext); } } return nResult; } //------------------------------------------------------------------------------ // // Function: ProcessCatalogs // //------------------------------------------------------------------------------ int ProcessCatalogs (_TCHAR * pszFilePath, BOOL bIncludeSubDir) { int nResult = 0; long hFile = -1; TCHAR szFilePath[_MAX_PATH] = _T(""); ASSERT(pszFilePath); __try { DWORD cDirs = 0; struct _finddata_t fd; if (0 == _tcslen(pszFilePath)) { _tcscpy(szFilePath, _T("*.cat")); } else { _tcscpy(szFilePath, pszFilePath); } if (-1 != (hFile = _tfindfirst(szFilePath, &fd))) { do { if (_A_SUBDIR & fd.attrib) { if (_tcscmp(_T("."), fd.name) && _tcscmp(_T(".."), fd.name)) { cDirs++; } } else { if (0 != (nResult = ProcessCatalog(fd.name))) { if (g_bIgnoreError) { nResult = 0; } else { __leave; } } } } while (0 == _tfindnext(hFile, &fd)); _findclose(hFile); hFile = -1; } if (bIncludeSubDir) { if (0 == cDirs) { _tcscpy(szFilePath, _T("*.*")); } if (-1 != (hFile = _tfindfirst(szFilePath, &fd))) { do { if ((_A_SUBDIR & fd.attrib) && _tcscmp(_T("."), fd.name) && _tcscmp(_T(".."), fd.name)) { _TCHAR szCWD[_MAX_PATH] = _T(""); if (_tgetcwd(szCWD, ARRAYSIZE(szCWD))) { _tchdir(fd.name); nResult = ProcessCatalogs(pszFilePath, bIncludeSubDir); _tchdir(szCWD); } else { nResult = errno; DebugTrace(_T("\nError [%#x]: _tgetcwd() failed.\n"), errno); } if (0 != nResult) { if (g_bIgnoreError) { nResult = 0; } else { __leave; } } } } while (0 == _tfindnext(hFile, &fd)); _findclose(hFile); hFile = -1; } } } __finally { if (-1 != hFile) { _findclose(hFile); } } return nResult; } //------------------------------------------------------------------------------ // // Function: main // //------------------------------------------------------------------------------ int __cdecl _tmain (int argc, _TCHAR * argv[]) { int nResult = 0; int CurrentDrive = _getdrive(); _TCHAR szCWD[_MAX_PATH] = _T(""); _tgetcwd(szCWD, sizeof(szCWD) / sizeof(szCWD[0])); __try { _TCHAR szDrive[_MAX_DRIVE] = _T(""); _TCHAR szDir[_MAX_DIR] = _T(""); _TCHAR szFName[_MAX_FNAME] = _T(""); _TCHAR szExt[_MAX_EXT] = _T(""); _TCHAR szFilePath[_MAX_PATH] = _T(""); if (0 != (nResult = ParseCommandLine(argc, argv))) { __leave; } if (g_bVerbose) { _ftprintf(stdout, _T("Current drive = %c:\n"), CurrentDrive - 1 + _T('A')); _ftprintf(stdout, _T("Current directory = %s\n"), szCWD); _ftprintf(stdout, _T("Command line =")); for (int i = 0; i < argc; i++) { _ftprintf(stdout, _T(" %s"), argv[i]); } _ftprintf(stdout, _T("\n")); } _splitpath(g_pszFilePath, szDrive, szDir, szFName, szExt); if (_tcslen(szDrive)) { if (0 != _chdrive(toupper(szDrive[0]) - _T('A') + 1)) { nResult = ENOENT; _ftprintf(stdout, _T("Error: _chdrive() to %s failed.\n"), szDrive); __leave; } } if (_tcslen(szDir)) { if (0 != _tchdir(szDir)) { nResult = ENOENT; _ftprintf(stdout, _T("Error: _tchdir() to %s failed.\n"), szDir); __leave; } } _tcscpy(szFilePath, szFName); _tcscat(szFilePath, szExt); nResult = ProcessCatalogs(szFilePath, g_bIncludeSubDir); } __finally { _chdrive(CurrentDrive); _tchdir(szCWD); } return nResult; }