#include #include #include "resource.h" #include #include #include #include #include "util.h" #include "parser.h" #include "mmcmgmt.h" const TCHAR gszUserDNFmt[] = TEXT("WinNT://%s/%s,user"); // Unicode to Unicode void Convert (LPWSTR wszIn, LPWSTR * pwszOut) { if (NULL == wszIn) { * pwszOut = NULL; return; } *pwszOut = new WCHAR [ wcslen (wszIn) + 1 ]; if (*pwszOut) { wcscpy (*pwszOut, wszIn); } return; } // Ansi to Unicode void Convert (LPSTR szIn, LPWSTR * pwszOut) { if (NULL == szIn) { * pwszOut = NULL; return; } *pwszOut = new WCHAR [ strlen (szIn) + 1 ]; if (*pwszOut) { if (0 == MultiByteToWideChar( CP_ACP, 0, szIn, -1, *pwszOut, strlen (szIn) + 1 ) ) { // the conversion failed delete [] *pwszOut; *pwszOut = NULL; } } return; } void UnicodeToOEM (LPWSTR wszIn, LPSTR *pszOut) { int iSize; if (NULL == wszIn) { * pszOut = NULL; return; } // get the required buffer size iSize = WideCharToMultiByte( CP_OEMCP, 0, wszIn, -1, NULL, 0, NULL, NULL ); if (0 == iSize) { *pszOut = NULL; } else { *pszOut = new char [ iSize ]; if (*pszOut) { if ( 0 == WideCharToMultiByte( CP_OEMCP, 0, wszIn, -1, *pszOut, iSize, NULL, NULL ) ) { // the conversion failed delete [] *pszOut; *pszOut = NULL; } } } return; } int MessagePrint( LPTSTR szText, LPTSTR szTitle ) { LPTSTR szOutput = NULL; LPWSTR wszOutput = NULL; LPSTR szOemOutput = NULL; // make it one TCHAR string szOutput = new TCHAR [ _tcslen(szText) + _tcslen(szTitle) + 3 ]; if (!szOutput) return -1; _stprintf ( szOutput, _T("%s\n%s\n"), szTitle, szText ); // convert the string to unicode Convert (szOutput, &wszOutput); delete [] szOutput; if (!wszOutput) return -1; // convert to OEM for printing UnicodeToOEM (wszOutput, &szOemOutput); delete [] wszOutput; if (!szOemOutput) return -1; // now print printf ("%s", szOemOutput); delete [] szOemOutput; return 0; } int MessagePrintIds ( int idsText ) { CIds IdsTitle (IDS_PRODUCTNAME); CIds IdsText ( idsText ); if ( IdsTitle.StringFound () && IdsText.StringFound () ) { return MessagePrint ( IdsText.GetString (), IdsTitle.GetString () ); } return 0; } // // Report an error resource string with one %s in it // void ReportSz1 ( HANDLE hLogFile, UINT idsError, LPTSTR szParam ) { TCHAR szText[256]; TCHAR szBuf2[128]; CIds IdsError (idsError); CIds IdsTitle (IDS_PRODUCTNAME); if ( IdsError.StringFound () && IdsTitle.StringFound () ) { _tcsncpy (szBuf2, szParam, sizeof(szBuf2) / sizeof(TCHAR)); szBuf2[sizeof(szBuf2) / sizeof(TCHAR) - 1] = 0; wsprintf (szText, IdsError.GetString (), szBuf2); if (hLogFile != NULL && hLogFile != INVALID_HANDLE_VALUE) { char szAnsiBuf[256]; DWORD dwNumOfBytesWritten; WideCharToMultiByte ( CP_ACP, 0, szText, -1, szAnsiBuf, sizeof(szAnsiBuf), NULL, NULL ); lstrcatA (szAnsiBuf, "\n"); WriteFile ( hLogFile, szAnsiBuf, lstrlenA (szAnsiBuf), &dwNumOfBytesWritten, NULL ); } else { MessagePrint (szText, IdsTitle.GetString ()); } } } // // IsValidDomainUser // Check if a domain user like redmond\jonsmith specified in szDomainUser // is valid or not. returns S_FALSE if it is invalid, S_OK for valid user. // // szFullName ---- To return the user's full name // cch ---- count of characters pointed to by szFullName // // if szFullName is NULL or cch is zero, no full name is returned // HRESULT IsValidDomainUser ( LPCTSTR szDomainUser, LPTSTR szFullName, DWORD cch ) { HRESULT hr = S_OK; TCHAR szDN[256]; TCHAR szDomain[256]; LPTSTR szSep; LPCTSTR szUser; DWORD dw; IADsUser * pUser = NULL; BSTR bstrFullName = NULL; // Sanity check if (szDomainUser == NULL || szDomainUser[0] == 0) { hr = S_FALSE; goto ExitHere; } // // Construct the user DN as // szSep = _tcschr (szDomainUser, TEXT('\\')); if (szSep == NULL) { // No '\' is given, assume a local user ,domain is local computer szUser = szDomainUser; dw = sizeof(szDomain)/sizeof(TCHAR); if (GetComputerName (szDomain, &dw) == 0) { hr = HRESULT_FROM_WIN32 (GetLastError ()); goto ExitHere; } } else { // assume invalid domain name if longer than 255 if (szSep - szDomainUser >= sizeof(szDomain)/sizeof(TCHAR)) { hr = S_FALSE; goto ExitHere; } _tcsncpy (szDomain, szDomainUser, szSep - szDomainUser); szDomain[szSep - szDomainUser] = 0; szUser = szSep + 1; } if (_tcslen (gszUserDNFmt) + _tcslen (szDomain) + _tcslen (szUser) > sizeof(szDN) / sizeof(TCHAR)) { hr = S_FALSE; goto ExitHere; } wsprintf (szDN, gszUserDNFmt, szDomain, szUser); // // Try to bind to the user object // hr = ADsGetObject (szDN, IID_IADsUser, (void **)&pUser); if (FAILED(hr)) { if (hr == E_ADS_INVALID_USER_OBJECT || hr == E_ADS_UNKNOWN_OBJECT || hr == E_ADS_BAD_PATHNAME || HRESULT_CODE(hr) == NERR_UserNotFound) { hr = S_FALSE; // The user does not exist } goto ExitHere; } // // If the user exists, get its full name // if (cch > 0) { hr = pUser->get_FullName (&bstrFullName); szFullName[0] = 0; if (hr == S_OK) { _tcsncpy (szFullName, bstrFullName, cch); szFullName[cch - 1] = 0; } } ExitHere: if (pUser) { pUser->Release(); } if (bstrFullName) { SysFreeString (bstrFullName); } return hr; } LPTSTR AppendStringAndFree (LPTSTR szOld, LPTSTR szToAppend) { LPTSTR szNew; DWORD dwLen; dwLen = ((szOld == NULL) ? 0 : _tcslen (szOld)) + _tcslen (szToAppend) + 1; szNew = new TCHAR[dwLen * sizeof(TCHAR)]; if (szNew == NULL) { goto ExitHere; } if (szOld) { _tcscpy (szNew, szOld); _tcscat (szNew, szToAppend); } else { _tcscpy (szNew, szToAppend); } ExitHere: if (szOld) { delete [] szOld; } return szNew; } void TsecCommandLine::ParseCommandLine (LPTSTR szCommand) { if (szCommand == NULL) { goto ExitHere; } // // Skip the first segment which is the executable itself // if (*szCommand == TEXT('\"')) { ++szCommand; while (*szCommand && *szCommand != TEXT('\"')) { ++szCommand; } if (*szCommand == TEXT('\"')) { ++szCommand; } } else { while ( *szCommand && *szCommand != TEXT(' ') && *szCommand != TEXT('\t') && *szCommand != 0x0a && *szCommand != 0x0d) { ++szCommand; } } while (*szCommand) { // // Search for / or - as the start of option // while (*szCommand && *szCommand != TEXT('/') && *szCommand != TEXT('-') ) { szCommand++; } if (*szCommand == 0) { break; } ++szCommand; // // -h, -H, -? means help // if (*szCommand == TEXT('h') || *szCommand == TEXT('H') || *szCommand == TEXT('?')) { ++szCommand; if (*szCommand == TEXT(' ') || *szCommand == TEXT('\t') || *szCommand == 0x0a || *szCommand == 0x0 || *szCommand == 0x0d) { m_fShowHelp = TRUE; } else { m_fError = TRUE; m_fShowHelp = TRUE; } } // // -v or -V followed by white space means validating only // else if (*szCommand == TEXT('v') || *szCommand == TEXT('V')) { ++szCommand; if (*szCommand == TEXT(' ') || *szCommand == TEXT('\t') || *szCommand == 0x0a || *szCommand == 0x0 || *szCommand == 0x0d) { m_fValidateOnly = TRUE; } else { m_fError = TRUE; m_fShowHelp = TRUE; } } // // -u, -U means to validate domain user account // else if (*szCommand == TEXT('u') || *szCommand == TEXT('U')) { ++szCommand; if (*szCommand == TEXT(' ') || *szCommand == TEXT('\t') || *szCommand == 0x0a || *szCommand == 0x0 || *szCommand == 0x0d) { m_fValidateDU = TRUE; } else { m_fError = TRUE; m_fShowHelp = TRUE; } } // // -d or -D followed by white space means dump current configuration // else if (*szCommand == TEXT('d') || *szCommand == TEXT('D')) { ++szCommand; if (*szCommand == TEXT(' ') || *szCommand == TEXT('\t') || *szCommand == 0x0a || *szCommand == 0x0 || *szCommand == 0x0d) { m_fDumpConfig = TRUE; } else { m_fError = TRUE; m_fShowHelp = TRUE; } } // // -f is followed by a xml file name // else if (*szCommand == TEXT('f') || *szCommand == TEXT('F')) { ++szCommand; // skip white spaces while (*szCommand != 0 && ( *szCommand == TEXT(' ') || *szCommand == TEXT('\t') || *szCommand == 0x0a || *szCommand == 0x0d)) { ++szCommand; } if (*szCommand == 0) { // no file name specified for -f, error m_fError = TRUE; } else { LPTSTR szBeg; int cch; szBeg = szCommand; cch = 0; // A quote means file name might contain space // search until the matchint quote of end if (*szCommand == TEXT('\"')) { ++szCommand; while (*szCommand != 0 && *szCommand != TEXT('\"')) { ++szCommand; ++cch; } } else { while (*szCommand != 0 && *szCommand != TEXT(' ') && *szCommand != TEXT('\t') && *szCommand != TEXT('\r') && *szCommand != TEXT('\n')) { ++szCommand; ++cch; } } if (cch == 0) { m_fError = TRUE; } else { m_szInFile = new TCHAR[cch+1]; if (m_szInFile != NULL) { memcpy (m_szInFile, szBeg, cch * sizeof(TCHAR)); m_szInFile[cch] = 0; } } } } else if(*szCommand) { m_fError = TRUE; ++szCommand; } } ExitHere: return; } int _cdecl wmain( void ) { HRESULT hr = S_OK; BOOL bUninit = FALSE; CXMLParser parser; CXMLUser * pCurUser = NULL, *pNextUser; CMMCManagement * pMmc = NULL; BOOL bNoMerge, bRemove, bPID; TCHAR szBufDU[256]; TCHAR szBufFN[256]; TCHAR szBufAddr[128]; DWORD dwPID; HWND hwndDump = NULL; HANDLE hLogFile = INVALID_HANDLE_VALUE; BOOL bRecordedError = FALSE, bValidUser; TsecCommandLine cmd (GetCommandLine ()); CXMLLine * pCurLine = NULL, * pNextLine; // // Create a dump window so that tlist.exe will report a title // if (LoadString ( GetModuleHandle(NULL), IDS_PRODUCTNAME, szBufFN, sizeof(szBufFN)/sizeof(TCHAR))) { hwndDump = CreateWindow ( TEXT("STATIC"), szBufFN, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL ); } // // Check the command line options // if (cmd.FError () || cmd.FShowHelp () || !cmd.FDumpConfig () && !cmd.FHasFile () || cmd.FDumpConfig () && cmd.FHasFile () || ( cmd.FValidateOnly () || cmd.FValidateUser () ) && !cmd.FHasFile () ) { cmd.PrintUsage(); goto ExitHere; } hr = CoInitializeEx ( NULL, COINIT_MULTITHREADED ); if (FAILED (hr)) { goto ExitHere; } bUninit = TRUE; // // Prepare the MMC component // pMmc = new CMMCManagement (); if (pMmc == NULL) { hr = TSECERR_NOMEM; goto ExitHere; } hr = pMmc->GetMMCData (); if (FAILED(hr)) { goto ExitHere; } // // Dump the current config if this option was present // if ( cmd.FDumpConfig() ) { hr = pMmc->DisplayMMCData (); goto ExitHere; } // // Set the XML file name and parse it, report error if any // hr = parser.SetXMLFile (cmd.GetInFileName ()); if (FAILED (hr)) { goto ExitHere; } hr = parser.Parse (); // Report parsing error if any if (hr == TSECERR_INVALFILEFORMAT) { hr = parser.ReportParsingError (); goto ExitHere; } if (FAILED (hr)) { goto ExitHere; } // // Create the log file for reporting errors during // MMC processing // hLogFile = CreateFile ( _T("tsecimp.log"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hLogFile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } // // Loop through each user and device, based on the user's // request, add or remove lines // hr = parser.GetFirstUser (&pCurUser); if (FAILED(hr)) { goto ExitHere; } while (pCurUser != NULL) { if (FAILED(hr = pCurUser->GetDomainUser( szBufDU, sizeof(szBufDU)/sizeof(TCHAR))) || FAILED(hr = pCurUser->GetFriendlyName( szBufFN, sizeof(szBufFN)/sizeof(TCHAR)))) { goto ExitHere; } bValidUser = TRUE; if (cmd.FValidateUser()) { hr = IsValidDomainUser( szBufDU, szBufAddr, // Borrowing szBufAddr for returning full name sizeof(szBufAddr) / sizeof(TCHAR) ); if (FAILED(hr)) { goto ExitHere; } // Not a valid domain user, report it if (hr == S_FALSE) { // domain user <%s> is invalid ReportSz1 (hLogFile, IDS_INVALIDUSER, szBufDU); bRecordedError = TRUE; bValidUser = FALSE; } if (szBufFN[0] == 0) { if (szBufAddr[0] != 0) { // Got a friendly name from DS, use it _tcscpy (szBufFN, szBufAddr); } } } // Still got no friendly name? use the domain user name if (szBufFN[0] == 0) { _tcscpy (szBufFN, szBufDU); } hr = pCurUser->IsNoMerge (&bNoMerge); if (FAILED(hr)) { goto ExitHere; } if (bNoMerge && !cmd.FValidateOnly()) { hr = pMmc->RemoveLinesForUser(szBufDU); if (FAILED(hr)) { goto ExitHere; } } // // Loop through each line, add or remove the device // if (pCurLine) { delete pCurLine; } hr = pCurUser->GetFirstLine (&pCurLine); if (FAILED(hr)) { goto ExitHere; } while (pCurLine != NULL) { if (FAILED(hr = pCurLine->IsRemove(&bRemove)) || FAILED(hr = pCurLine->IsPermanentID(&bPID))) { goto ExitHere; } if (bPID) { hr = pCurLine->GetPermanentID(&dwPID); } else { hr = pCurLine->GetAddress( szBufAddr, sizeof(szBufAddr)/sizeof(TCHAR) ); } if (FAILED(hr)) { goto ExitHere; } if (!cmd.FValidateOnly() && bValidUser) { if (bRemove) { if (bPID) { hr = pMmc->RemoveLinePIDForUser ( dwPID, szBufDU ); } else { hr = pMmc->RemoveLineAddrForUser ( szBufAddr, szBufDU ); } } else { if (bPID) { hr = pMmc->AddLinePIDForUser ( dwPID, szBufDU, szBufFN ); } else { hr = pMmc->AddLineAddrForUser ( szBufAddr, szBufDU, szBufFN ); } } } else { if (bPID) { hr = pMmc->IsValidPID (dwPID); } else { hr = pMmc->IsValidAddress (szBufAddr); } } if( hr == S_FALSE || hr == TSECERR_DEVLOCALONLY) { // An invalid permanent ID or address is given // report the error and quit TCHAR szText[256]; CIds IdsTitle (IDS_PRODUCTNAME); if ( IdsTitle.StringFound () ) { szText[0] = 0; if (bPID) { CIds IdsError (TSECERR_DEVLOCALONLY ? IDS_LOCALONLYPID : IDS_INVALPID); if ( IdsError.StringFound () ) { wsprintf (szText, IdsError.GetString (), dwPID); } } else if (!bPID) { CIds IdsError (TSECERR_DEVLOCALONLY ? IDS_LOCALONLYADDR : IDS_INVALADDR); if ( IdsError.StringFound () ) { wsprintf (szText, IdsError.GetString (), szBufAddr); } } if (hLogFile != NULL && hLogFile != INVALID_HANDLE_VALUE) { char szAnsiBuf[256]; DWORD dwNumOfBytesWritten; WideCharToMultiByte ( CP_ACP, 0, szText, -1, szAnsiBuf, sizeof(szAnsiBuf), NULL, NULL ); lstrcatA (szAnsiBuf, "\n"); WriteFile ( hLogFile, szAnsiBuf, lstrlenA (szAnsiBuf), &dwNumOfBytesWritten, NULL ); } else { MessagePrint (szText, IdsTitle.GetString ()); } } bRecordedError = TRUE; hr = S_OK; } else if(FAILED(hr)) { goto ExitHere; } hr = pCurLine->GetNextLine (&pNextLine); if (FAILED(hr)) { goto ExitHere; } delete pCurLine; pCurLine = pNextLine; } hr = pCurUser->GetNextUser (&pNextUser); if (FAILED(hr)) { goto ExitHere; } delete pCurUser; pCurUser = pNextUser; } // If error happend, we aready exited, reset warnings hr = S_OK; // We are done if we are asked to do validating only if (bRecordedError) { MessagePrintIds (IDS_HASERROR); } else if (cmd.FValidateOnly()) { MessagePrintIds (IDS_VALIDSUCCESS); } else { MessagePrintIds (IDS_FINSUCCESS); } ExitHere: // // Report error if any here // if(FAILED(hr)) { ReportError (NULL, hr); } if (hwndDump) { DestroyWindow (hwndDump); } if (hLogFile != INVALID_HANDLE_VALUE) { CloseHandle (hLogFile); } if (pCurLine) { delete pCurLine; } if (pCurUser) { delete pCurUser; } if (pMmc) { delete pMmc; } parser.Release(); if (bUninit) { CoUninitialize (); } return 0; } void ReportError ( HANDLE hFile, HRESULT hr ) { TCHAR szTitle[128]; TCHAR szBuf[512]; HINSTANCE hModule = GetModuleHandle (NULL); if (LoadString ( hModule, IDS_PRODUCTNAME, szTitle, sizeof(szTitle)/sizeof(TCHAR) ) == 0) { goto ExitHere; } // Is this our own error if (HRESULT_FACILITY(hr) == FACILITY_TSEC_CODE) { if (FormatMessage ( FORMAT_MESSAGE_FROM_HMODULE, hModule, HRESULT_CODE(hr), 0, szBuf, sizeof(szBuf)/sizeof(TCHAR), NULL ) == 0) { goto ExitHere; } } // Is this TAPI error? else if ((hr < 0 && hr > -100) || HRESULT_FACILITY(hr) == 0) { hModule = LoadLibrary (TEXT("TAPIUI.DLL")); if (hModule == NULL) { goto ExitHere; } if (FormatMessage ( FORMAT_MESSAGE_FROM_HMODULE, hModule, TAPIERROR_FORMATMESSAGE(hr), 0, szBuf, sizeof(szBuf)/sizeof(TCHAR), NULL ) == 0) { FreeLibrary (hModule); goto ExitHere; } FreeLibrary (hModule); } // Assume system error else { if (FormatMessage ( FORMAT_MESSAGE_FROM_SYSTEM, NULL, HRESULT_CODE(hr), 0, szBuf, sizeof(szBuf)/sizeof(TCHAR), NULL ) == 0) { goto ExitHere; } } if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) { MessagePrint (szBuf, szTitle); } else { char szAnsiBuf[1024]; DWORD dwNumOfBytesWritten; WideCharToMultiByte ( CP_ACP, 0, szBuf, -1, szAnsiBuf, sizeof(szAnsiBuf), NULL, NULL ); lstrcatA (szAnsiBuf, "\n"); WriteFile ( hFile, szAnsiBuf, lstrlenA (szAnsiBuf), &dwNumOfBytesWritten, NULL ); } ExitHere: return; }