/*************************************************************************/ /* Copyright (C) 1999 Microsoft Corporation */ /* File: MSDVDAdm.cpp */ /* Description: DImplementation of CMSDVDAdm */ /* Author: Fang Wang */ /*************************************************************************/ #include "stdafx.h" #include "MSWebDVD.h" #include "MSDVDAdm.h" #include "iso3166.h" #include #include #include const TCHAR g_szRegistryKey[] = TEXT("Software\\Microsoft\\Multimedia\\DVD"); const TCHAR g_szPassword[] = TEXT("DVDAdmin.password"); const TCHAR g_szSalt[] = TEXT("DVDAdmin.ps"); // password salt const TCHAR g_szUserSalt[] = TEXT("DVDAdmin.us"); // username salt const TCHAR g_szUsername[] = TEXT("DVDAdmin.username"); const TCHAR g_szPlayerLevel[] = TEXT("DVDAdmin.playerLevel"); const TCHAR g_szPlayerCountry[] = TEXT("DVDAdmin.playerCountry"); const TCHAR g_szDisableScrnSvr[] = TEXT("DVDAdmin.disableScreenSaver"); const TCHAR g_szBookmarkOnClose[] = TEXT("DVDAdmin.bookmarkOnClose"); const TCHAR g_szBookmarkOnStop[] = TEXT("DVDAdmin.bookmarkOnStop"); const TCHAR g_szDefaultAudio[] = TEXT("DVDAdmin.defaultAudioLCID"); const TCHAR g_szDefaultSP[] = TEXT("DVDAdmin.defaultSPLCID"); const TCHAR g_szDefaultMenu[] = TEXT("DVDAdmin.defaultMenuLCID"); /*************************************************************/ /* Helper functions */ /*************************************************************/ /*************************************************************/ /* Function: LoadStringFromRes */ /* Description: load a string from resource */ /*************************************************************/ LPTSTR LoadStringFromRes(DWORD redId){ TCHAR *string = new TCHAR[MAX_PATH]; if(NULL == string){ return(NULL); } ::ZeroMemory(string, sizeof(TCHAR) * MAX_PATH); ::LoadString(_Module.GetModuleInstance(), redId, string, MAX_PATH); return string; }/* end of if statement */ /*************************************************************/ /* Function: lstrlenWInternal */ /*************************************************************/ int WINAPI lstrlenWInternal(LPCWSTR lpString){ int length = 0; while (*lpString++ != L'\0') length++; return length; }/* end of function lstrlenWInternal */ /*************************************************************/ /* Name: GetRegistryDword /* Description: /*************************************************************/ BOOL GetRegistryDword(const TCHAR *pKey, DWORD* dwRet, DWORD dwDefault) { HKEY hKey; LONG lRet; *dwRet = dwDefault; lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_szRegistryKey, 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) { DWORD dwType, dwLen; dwLen = sizeof(DWORD); if (ERROR_SUCCESS != RegQueryValueEx(hKey, pKey, NULL, &dwType, (LPBYTE)dwRet, &dwLen)){ *dwRet = dwDefault; RegCloseKey(hKey); return FALSE; } RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: SetRegistryDword /* Description: /*************************************************************/ BOOL SetRegistryDword(const TCHAR *pKey, DWORD dwRet) { HKEY hKey; LONG lRet; lRet = RegCreateKey(HKEY_LOCAL_MACHINE, g_szRegistryKey, &hKey); if (lRet == ERROR_SUCCESS) { lRet = RegSetValueEx(hKey, pKey, NULL, REG_DWORD, (LPBYTE)&dwRet, sizeof(dwRet)); RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: GetRegistryString /* Description: /*************************************************************/ BOOL GetRegistryString(const TCHAR *pKey, TCHAR* szRet, DWORD* dwLen, TCHAR* szDefault) { HKEY hKey; LONG lRet; DWORD dwTempLen = 0; lstrcpyn(szRet, szDefault, *dwLen); lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_szRegistryKey, 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) { DWORD dwType; dwTempLen = (*dwLen) * sizeof(TCHAR); if (ERROR_SUCCESS != RegQueryValueEx(hKey, pKey, NULL, &dwType, (LPBYTE)szRet, &dwTempLen)) { lstrcpyn(szRet, szDefault, *dwLen); *dwLen = 0; } *dwLen = dwTempLen/sizeof(TCHAR); RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: SetRegistryString /* Description: /*************************************************************/ BOOL SetRegistryString(const TCHAR *pKey, TCHAR *szString, DWORD dwLen) { HKEY hKey; LONG lRet; lRet = RegCreateKey(HKEY_LOCAL_MACHINE, g_szRegistryKey, &hKey); if (lRet == ERROR_SUCCESS) { lRet = RegSetValueEx(hKey, pKey, NULL, REG_SZ, (LPBYTE)szString, dwLen*sizeof(TCHAR)); RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: GetRegistryByte /* Description: /*************************************************************/ BOOL GetRegistryBytes(const TCHAR *pKey, BYTE* szRet, DWORD* dwLen) { HKEY hKey; LONG lRet; lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_szRegistryKey, 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) { DWORD dwType; if (ERROR_SUCCESS != RegQueryValueEx(hKey, pKey, NULL, &dwType, (LPBYTE)szRet, dwLen)) { *dwLen = 0; } RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: SetRegistryBytes /* Description: /*************************************************************/ BOOL SetRegistryBytes(const TCHAR *pKey, BYTE *szString, DWORD dwLen) { HKEY hKey; LONG lRet; lRet = RegCreateKey(HKEY_LOCAL_MACHINE, g_szRegistryKey, &hKey); BOOL bRet = TRUE; if (lRet == ERROR_SUCCESS) { if (szString == NULL) { lRet = RegDeleteValue(hKey, pKey); bRet = (lRet == ERROR_SUCCESS) || (lRet == ERROR_FILE_NOT_FOUND); } else { lRet = RegSetValueEx(hKey, pKey, NULL, REG_BINARY, (LPBYTE)szString, dwLen); bRet = (lRet == ERROR_SUCCESS); } RegCloseKey(hKey); } return (bRet); } // Start not so lame functions /*************************************************************/ /* Name: GetRegistryDwordCU /* Description: /*************************************************************/ BOOL GetRegistryDwordCU(const TCHAR *pKey, DWORD* dwRet, DWORD dwDefault) { HKEY hKey; LONG lRet; *dwRet = dwDefault; lRet = RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegistryKey, 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) { DWORD dwType, dwLen; dwLen = sizeof(DWORD); if (ERROR_SUCCESS != RegQueryValueEx(hKey, pKey, NULL, &dwType, (LPBYTE)dwRet, &dwLen)){ *dwRet = dwDefault; RegCloseKey(hKey); return FALSE; } RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: SetRegistryDwordCU /* Description: /*************************************************************/ BOOL SetRegistryDwordCU(const TCHAR *pKey, DWORD dwRet) { HKEY hKey; LONG lRet; lRet = RegCreateKey(HKEY_CURRENT_USER, g_szRegistryKey, &hKey); if (lRet == ERROR_SUCCESS) { lRet = RegSetValueEx(hKey, pKey, NULL, REG_DWORD, (LPBYTE)&dwRet, sizeof(dwRet)); RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: GetRegistryStringCU /* Description: /*************************************************************/ BOOL GetRegistryStringCU(const TCHAR *pKey, TCHAR* szRet, DWORD* dwLen, TCHAR* szDefault) { HKEY hKey; LONG lRet; DWORD dwTempLen = 0; lstrcpyn(szRet, szDefault, *dwLen); lRet = RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegistryKey, 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) { DWORD dwType; dwTempLen = (*dwLen) * sizeof(TCHAR); if (ERROR_SUCCESS != RegQueryValueEx(hKey, pKey, NULL, &dwType, (LPBYTE)szRet, &dwTempLen)) { lstrcpyn(szRet, szDefault, sizeof(szRet) / sizeof(szRet[0])); *dwLen = 0; } *dwLen = dwTempLen/sizeof(TCHAR); RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: SetRegistryStringCU /* Description: /*************************************************************/ BOOL SetRegistryStringCU(const TCHAR *pKey, TCHAR *szString, DWORD dwLen) { HKEY hKey; LONG lRet; lRet = RegCreateKey(HKEY_CURRENT_USER, g_szRegistryKey, &hKey); if (lRet == ERROR_SUCCESS) { lRet = RegSetValueEx(hKey, pKey, NULL, REG_SZ, (LPBYTE)szString, dwLen*sizeof(TCHAR)); RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: GetRegistryByteCU /* Description: /*************************************************************/ BOOL GetRegistryBytesCU(const TCHAR *pKey, BYTE* szRet, DWORD* dwLen) { HKEY hKey; LONG lRet; lRet = RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegistryKey, 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) { DWORD dwType; if (ERROR_SUCCESS != RegQueryValueEx(hKey, pKey, NULL, &dwType, (LPBYTE)szRet, dwLen)) { *dwLen = 0; } RegCloseKey(hKey); } return (lRet == ERROR_SUCCESS); } /*************************************************************/ /* Name: SetRegistryBytesCU /* Description: /*************************************************************/ BOOL SetRegistryBytesCU(const TCHAR *pKey, BYTE *szString, DWORD dwLen) { HKEY hKey; LONG lRet; lRet = RegCreateKey(HKEY_CURRENT_USER, g_szRegistryKey, &hKey); BOOL bRet = TRUE; if (lRet == ERROR_SUCCESS) { if (szString == NULL) { lRet = RegDeleteValue(hKey, pKey); bRet = (lRet == ERROR_SUCCESS) || (lRet == ERROR_FILE_NOT_FOUND); } else { lRet = RegSetValueEx(hKey, pKey, NULL, REG_BINARY, (LPBYTE)szString, dwLen); bRet = (lRet == ERROR_SUCCESS); } RegCloseKey(hKey); } return (bRet); } // end not so lame functions /*************************************************************/ /* Function: CMSDVDAdm */ /*************************************************************/ CMSDVDAdm::CMSDVDAdm(){ DWORD temp; GetRegistryDword(g_szPlayerLevel, &temp, (DWORD)LEVEL_ADULT); m_lParentctrlLevel = temp; GetRegistryDword(g_szPlayerCountry, &temp, (DWORD)0); m_lParentctrlCountry = temp; GetRegistryDword(g_szDisableScrnSvr, &temp, (DWORD)VARIANT_TRUE); m_fDisableScreenSaver = (VARIANT_BOOL)temp; SaveScreenSaver(); if (m_fDisableScreenSaver != VARIANT_FALSE) DisableScreenSaver(); GetRegistryDword(g_szBookmarkOnStop, &temp, (DWORD)VARIANT_FALSE); m_fBookmarkOnStop = (VARIANT_BOOL)temp; GetRegistryDword(g_szBookmarkOnClose, &temp, (DWORD)VARIANT_TRUE); m_fBookmarkOnClose = (VARIANT_BOOL)temp; }/* end of function CMSDVDAdm */ /*************************************************************/ /* Function: ~CMSDVDAdm */ /*************************************************************/ CMSDVDAdm::~CMSDVDAdm(){ RestoreScreenSaver(); }/* end of function ~CMSDVDAdm */ /*************************************************************/ /* Name: EncryptPassword */ /* Description: Hash the password */ /* Params: */ /* lpPassword: password to hash */ /* lpAssaultedHash: hashed password, */ /* allocated by this fucntion, released by caller */ /* p_dwAssault: salt, save with hash; or salt passed in */ /* genAssault: TRUE = generate salt; FALSE = salt passed in */ /*************************************************************/ HRESULT CMSDVDAdm::EncryptPassword(LPTSTR lpPassword, BYTE **lpAssaultedHash, DWORD *p_dwCryptLen, DWORD *p_dwAssault, BOOL genAssault){ if(!lpPassword || !lpAssaultedHash || !p_dwAssault || !p_dwCryptLen){ return E_POINTER; } if( lstrlen(lpPassword) > MAX_PASSWD){ return E_INVALIDARG; } HCRYPTPROV hProv = NULL; // Handle to Crypto Context HCRYPTHASH hHash = NULL; // Handle to Hash Function DWORD dwAssault = 0; // As(Sa)u(lt) for hash DWORD dwAssaultedHash = 0; // Length of Assaulted hash // Init Crypto Context if(!CryptAcquireContext(&hProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){ return E_UNEXPECTED; } // Store the Salt in dwAssault, either generate it or copy the user passed value if(genAssault){ if(!CryptGenRandom(hProv, sizeof(DWORD), reinterpret_cast(&dwAssault))){ if(hProv) CryptReleaseContext(hProv, 0); return E_UNEXPECTED; } *p_dwAssault = dwAssault; } else{ dwAssault = *p_dwAssault; } // Create the handle to the Hash function if(!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)){ if(hProv) CryptReleaseContext(hProv, 0); if(hHash) CryptDestroyHash(hHash); return E_UNEXPECTED; } // Hash the password if(!CryptHashData(hHash, reinterpret_cast(lpPassword), lstrlen(lpPassword)*sizeof(lpPassword[0]), 0)){ if(hProv) CryptReleaseContext(hProv, 0); if(hHash) CryptDestroyHash(hHash); return E_UNEXPECTED; } // Add the salt if(!CryptHashData(hHash, reinterpret_cast(&dwAssault), sizeof(DWORD), 0)){ if(hProv) CryptReleaseContext(hProv, 0); if(hHash) CryptDestroyHash(hHash); return E_UNEXPECTED; } // Get the size of the hashed data if(!CryptGetHashParam(hHash, HP_HASHVAL, 0, &dwAssaultedHash, 0)){ if(hProv) CryptReleaseContext(hProv, 0); if(hHash) CryptDestroyHash(hHash); return E_UNEXPECTED; } // Allocate a string large enough to hold the hash data and a null *lpAssaultedHash = new BYTE[dwAssaultedHash]; if(!lpAssaultedHash){ if(hProv) CryptReleaseContext(hProv, 0); if(hHash) CryptDestroyHash(hHash); return E_UNEXPECTED; } // Zero the string ZeroMemory(*lpAssaultedHash, dwAssaultedHash); // Copy length of Encrypted bytes to return value *p_dwCryptLen = dwAssaultedHash; // Get the hash data and store it in a string if(!CryptGetHashParam(hHash, HP_HASHVAL, *lpAssaultedHash, &dwAssaultedHash, 0)){ if(hProv) CryptReleaseContext(hProv, 0); if(hHash) CryptDestroyHash(hHash); if(lpAssaultedHash){ delete[] *lpAssaultedHash; *lpAssaultedHash = NULL; } return E_UNEXPECTED; } // Clean up if(hProv) CryptReleaseContext(hProv, 0); if(hHash) CryptDestroyHash(hHash); return S_OK; }/* end of function EncryptPassword */ /*************************************************************/ /* Function: ConfirmPassword */ /* Description: */ /* There is no need for a user to confirm passwords unless */ /* they are hacking the password. */ /* ConfirmPassword always fails (and waits five seconds) */ /*************************************************************/ STDMETHODIMP CMSDVDAdm::ConfirmPassword(BSTR strUserName, BSTR strPassword, VARIANT_BOOL *pVal){ Sleep(1000); return E_FAIL; } /*************************************************************/ /* Function: _ConfirmPassword */ /* Description: comfired a password with the one saved */ /*************************************************************/ STDMETHODIMP CMSDVDAdm::_ConfirmPassword(BSTR /*strUserName*/, BSTR strPassword, VARIANT_BOOL *fRight){ HRESULT hr = S_OK; try { USES_CONVERSION; if(!strPassword || !fRight){ throw E_POINTER; } UINT bStrLen = lstrlen(strPassword); if(bStrLen >= MAX_PASSWD){ throw E_INVALIDARG; } LPTSTR szPassword = OLE2T(strPassword); BYTE szSavedPasswd[MAX_PASSWD]; DWORD dwLen = MAX_PASSWD; BOOL bFound = GetRegistryBytes(g_szPassword, szSavedPasswd, &dwLen); // if no password has been set yet if (!bFound || dwLen == 0) { // so in this case accept only an empty string if(lstrlen(szPassword) <= 0){ *fRight = VARIANT_TRUE; } else { *fRight = VARIANT_FALSE; } throw (hr); } DWORD dwAssault = 0; bFound = GetRegistryDword(g_szSalt, &dwAssault, 0); if(!bFound ){ // Old style password since there is no salt // ignore current password until it is reset *fRight = VARIANT_TRUE; throw(hr); } // if password is 0 len and password is set don't even try to encrypt just return false if(lstrlen(szPassword) <= 0){ *fRight = VARIANT_FALSE; throw(hr); } // Encrypt the password with the salt from the registry BYTE *pszEncrypted = NULL; DWORD dwCryptLen = 0; hr = EncryptPassword(szPassword, &pszEncrypted, &dwCryptLen, &dwAssault, FALSE); if(FAILED(hr)){ throw (hr); } // Compare the Encrypted input password with the saved password if(memcmp(pszEncrypted, szSavedPasswd, (dwAssault <= dwLen?dwAssault:dwLen) ) == 0) *fRight = VARIANT_TRUE; else *fRight = VARIANT_FALSE; delete[] pszEncrypted; } catch(HRESULT hrTmp){ hr = hrTmp; } catch(...){ hr = E_UNEXPECTED; } if(FAILED(hr)){ Sleep(1000); } return (HandleError(hr)); }/* end of function ConfirmPassword */ /*************************************************************/ /* Function: ChangePassword */ /* Description: password change requested */ /*************************************************************/ STDMETHODIMP CMSDVDAdm::ChangePassword(BSTR strUserName, BSTR strOldPassword, BSTR strNewPassword){ HRESULT hr = S_OK; try { USES_CONVERSION; if(!strUserName || !strOldPassword || !strNewPassword){ return E_POINTER; } // check the size of the string so we do not overwrite // or write a very big chunk into registry if(lstrlen(strNewPassword) >= MAX_PASSWD){ throw(E_FAIL); } LPTSTR szNewPassword = OLE2T(strNewPassword); // Confirm old password first VARIANT_BOOL temp; _ConfirmPassword(strUserName, strOldPassword, &temp); if (temp == VARIANT_FALSE){ throw E_ACCESSDENIED; } DWORD dwAssault = 0; DWORD dwCryptLen = 0; BYTE *pszEncrypted = NULL; hr = EncryptPassword(szNewPassword, &pszEncrypted, &dwCryptLen, &dwAssault, TRUE); if(FAILED(hr)){ throw E_FAIL; } BOOL bSuccess = SetRegistryBytes(g_szPassword, pszEncrypted, dwCryptLen); if (!bSuccess){ hr = E_FAIL; } delete[] pszEncrypted; // If storing the password hash failed, don't store the salt if(SUCCEEDED(hr)){ bSuccess = SetRegistryDword(g_szSalt, dwAssault); if (!bSuccess){ hr = E_FAIL; } } } catch(HRESULT hrTmp){ hr = hrTmp; } catch(...){ hr = E_UNEXPECTED; } return HandleError(hr); }/* end of function ChangePassword */ /*************************************************************/ /* Function: SaveParentalLevel */ /*************************************************************/ STDMETHODIMP CMSDVDAdm::SaveParentalLevel(long lParentalLevel, BSTR strUserName, BSTR strPassword){ HRESULT hr = S_OK; try { if (lParentalLevel != LEVEL_DISABLED && (lParentalLevel < LEVEL_G || lParentalLevel > LEVEL_ADULT)) { throw (E_INVALIDARG); } /* end of if statement */ if (m_lParentctrlLevel != lParentalLevel) { // Confirm password first VARIANT_BOOL temp; _ConfirmPassword(strUserName, strPassword, &temp); if (temp == VARIANT_FALSE) throw (E_ACCESSDENIED); } BOOL bSuccess = SetRegistryDword(g_szPlayerLevel, (DWORD) lParentalLevel); if (!bSuccess){ throw E_FAIL; } m_lParentctrlLevel = lParentalLevel; } catch(HRESULT hrTmp){ hr = hrTmp; } catch(...){ hr = E_UNEXPECTED; } return HandleError(hr); }/* end of function SaveParentalLevel */ /*************************************************************/ /* Name: SaveParentalCountry */ /*************************************************************/ STDMETHODIMP CMSDVDAdm::SaveParentalCountry(long lCountry, BSTR strUserName,BSTR strPassword){ HRESULT hr = S_OK; try { if(lCountry < 0 && lCountry > 0xffff){ throw(E_INVALIDARG); }/* end of if statement */ BYTE bCountryCode[2]; bCountryCode[0] = BYTE(lCountry>>8); bCountryCode[1] = BYTE(lCountry); // convert the input country code to upper case by applying ToUpper to each letter WORD wCountry = ISO3166::PackCode( (char *)bCountryCode ); BOOL bFound = FALSE; for( unsigned i=0; i