Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

663 lines
17 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1999 **
  4. //*********************************************************************
  5. //
  6. // PID.CPP - Header for the implementation of CProductID
  7. //
  8. // HISTORY:
  9. //
  10. // 1/27/99 a-jaswed Created.
  11. //
  12. #include "pid.h"
  13. #include "appdefs.h"
  14. #include "dispids.h"
  15. #include "msobmain.h"
  16. #include "digpid.h"
  17. #define REG_VAL_PID2 L"PID2"
  18. #define REG_VAL_PID3 L"PID3"
  19. #define REG_VAL_PID3DATA L"PID3Data"
  20. #define REG_VAL_PRODUCTKEY L"ProductKey"
  21. #define SEC_KEY_VER L"Version"
  22. DISPATCHLIST ProductIDExternalInterface[] =
  23. {
  24. {L"get_PID", DISPID_PRODUCTID_GET_PID },
  25. {L"set_PID", DISPID_PRODUCTID_SET_PID },
  26. {L"get_PIDAcceptance", DISPID_PRODUCTID_GET_ACCEPTED },
  27. {L"ValidatePID", DISPID_PRODUCTID_VALIDATEPID },
  28. {L"get_CurrentPID2", DISPID_PRODUCTID_GET_CURRENT_PID2 }
  29. };
  30. /////////////////////////////////////////////////////////////
  31. // CProductID::CProductID
  32. CProductID::CProductID()
  33. {
  34. WCHAR szKeyName[] = REG_KEY_OOBE_TEMP,
  35. szKeyWindows[] = REG_KEY_WINDOWS,
  36. szPid3[256],
  37. szOemInfoFile[MAX_PATH] = L"\0";
  38. HKEY hKey;
  39. DWORD cb,
  40. dwType;
  41. BOOL bDontCare;
  42. BSTR bstrPid;
  43. // Init member vars
  44. m_cRef = 0;
  45. m_dwPidState = PID_STATE_UNKNOWN;
  46. // Init the data we are going to try to get from the registry.
  47. //
  48. m_szPID2[0] = L'\0';
  49. szPid3[0] = L'\0';
  50. ZeroMemory(&m_abPID3, sizeof(m_abPID3));
  51. if ( RegOpenKey(HKEY_LOCAL_MACHINE, szKeyName, &hKey) == ERROR_SUCCESS )
  52. {
  53. // Get the PID 2 from the registry.
  54. //
  55. cb = sizeof(m_szPID2);
  56. RegQueryValueEx(hKey, REG_VAL_PID2, NULL, &dwType, (LPBYTE) m_szPID2, &cb);
  57. // Get the PID 3 from the registry.
  58. //
  59. cb = sizeof(szPid3);
  60. RegQueryValueEx(hKey, REG_VAL_PID3, NULL, &dwType, (LPBYTE) szPid3, &cb);
  61. // Get the PID 3 data from the registry.
  62. //
  63. cb = sizeof(m_abPID3);
  64. RegQueryValueEx(hKey, REG_VAL_PID3DATA, NULL, &dwType, m_abPID3, &cb);
  65. RegCloseKey(hKey);
  66. }
  67. // If we don't already have a saved state PID3 string, we need to
  68. // try to read it from the places where the OEM can pre-populate it.
  69. //
  70. if ( ( szPid3[0] == L'\0' ) &&
  71. ( RegOpenKey(HKEY_LOCAL_MACHINE, szKeyWindows, &hKey) == ERROR_SUCCESS ) )
  72. {
  73. // First try the registry.
  74. //
  75. cb = sizeof(szPid3);
  76. if ( ( RegQueryValueEx(hKey, REG_VAL_PRODUCTKEY, NULL, &dwType, (LPBYTE) szPid3, &cb) != ERROR_SUCCESS ) ||
  77. ( szPid3[0] == L'\0' ) )
  78. {
  79. // Now try the INI file.
  80. //
  81. GetSystemDirectory(szOemInfoFile, MAX_CHARS_IN_BUFFER(szOemInfoFile));
  82. lstrcat(szOemInfoFile, OEMINFO_INI_FILENAME);
  83. GetPrivateProfileString(SEC_KEY_VER, REG_VAL_PRODUCTKEY, L"\0", szPid3, MAX_CHARS_IN_BUFFER(szPid3), szOemInfoFile);
  84. }
  85. RegCloseKey(hKey);
  86. }
  87. // We need to store the PID we retrieved as a BSTR in the object.
  88. //
  89. m_bstrPID = SysAllocString(szPid3);
  90. // We assume the PID was accepted if we have the PID 2 & 3 strings.
  91. //
  92. if ( m_szPID2[0] && szPid3[0] )
  93. m_dwPidState = PID_STATE_VALID;
  94. else if ( szPid3[0] )
  95. ValidatePID(&bDontCare);
  96. else
  97. m_dwPidState = PID_STATE_INVALID;
  98. // If the PID is invalid, we don't want it.
  99. //
  100. if ( m_dwPidState == PID_STATE_INVALID )
  101. {
  102. bstrPid = SysAllocString(L"\0");
  103. set_PID(bstrPid);
  104. SysFreeString(bstrPid);
  105. }
  106. m_szProdType[0] = L'\0';
  107. }
  108. /////////////////////////////////////////////////////////////
  109. // CProductID::~CProductID
  110. CProductID::~CProductID()
  111. {
  112. SysFreeString(m_bstrPID);
  113. assert(m_cRef == 0);
  114. }
  115. VOID CProductID::SaveState()
  116. {
  117. WCHAR szKeyName[] = REG_KEY_OOBE_TEMP;
  118. HKEY hKey;
  119. LPWSTR lpszPid3;
  120. if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS )
  121. {
  122. // Save the PID 2 to the registry.
  123. //
  124. if ( m_szPID2[0] )
  125. RegSetValueEx(hKey, REG_VAL_PID2, 0, REG_SZ, (LPBYTE) m_szPID2, BYTES_REQUIRED_BY_SZ(m_szPID2));
  126. else
  127. RegDeleteValue(hKey, REG_VAL_PID2);
  128. // Save the PID 3 to the registry.
  129. //
  130. lpszPid3 = m_bstrPID;
  131. if ( *lpszPid3 )
  132. RegSetValueEx(hKey, REG_VAL_PID3, 0, REG_SZ, (LPBYTE) lpszPid3, BYTES_REQUIRED_BY_SZ(lpszPid3));
  133. else
  134. RegDeleteValue(hKey, REG_VAL_PID3);
  135. // Save the PID 3 data from the registry.
  136. //
  137. if ( *((LPDWORD) m_abPID3) )
  138. RegSetValueEx(hKey, REG_VAL_PID3DATA, 0, REG_BINARY, m_abPID3, *((LPDWORD) m_abPID3));
  139. else
  140. RegDeleteValue(hKey, REG_VAL_PID3DATA);
  141. RegFlushKey(hKey);
  142. RegCloseKey(hKey);
  143. }
  144. }
  145. ////////////////////////////////////////////////
  146. ////////////////////////////////////////////////
  147. //// GET / SET :: PID
  148. ////
  149. HRESULT CProductID::set_PID(BSTR bstrVal)
  150. {
  151. LPWSTR lpszNew,
  152. lpszOld;
  153. lpszNew = bstrVal;
  154. lpszOld = m_bstrPID;
  155. // No need to set it if we alread have
  156. // the same string.
  157. //
  158. if ( CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpszNew, -1, lpszOld, -1) != CSTR_EQUAL )
  159. {
  160. m_dwPidState = PID_STATE_UNKNOWN;
  161. SysFreeString(m_bstrPID);
  162. m_bstrPID = SysAllocString(bstrVal);
  163. m_szPID2[0] = L'\0';
  164. ZeroMemory(&m_abPID3, sizeof(m_abPID3));
  165. SaveState();
  166. }
  167. return S_OK;
  168. }
  169. HRESULT CProductID::get_PID(BSTR* pbstrVal)
  170. {
  171. *pbstrVal = SysAllocString(m_bstrPID);
  172. return S_OK;
  173. }
  174. HRESULT CProductID::get_PID2(LPWSTR* lplpszPid2)
  175. {
  176. *lplpszPid2 = SysAllocString(m_szPID2);
  177. return S_OK;
  178. }
  179. HRESULT CProductID::get_PID3Data(LPBYTE* lplpabPid3Data)
  180. {
  181. *lplpabPid3Data = m_abPID3;
  182. return S_OK;
  183. }
  184. HRESULT CProductID::get_PIDAcceptance(BOOL* pbVal)
  185. {
  186. #if 0
  187. *pbVal = (m_dwPidState == PID_STATE_VALID);
  188. #endif // 0
  189. // BUGBUG: get_PIDAcceptance not implemented.
  190. *pbVal = TRUE;
  191. return S_OK;
  192. }
  193. HRESULT CProductID::get_ProductType(LPWSTR* lplpszProductType)
  194. {
  195. // BUGBUG: get_ProductType not implemented
  196. m_szProdType[0] = L'\0';
  197. *lplpszProductType = SysAllocString(m_szProdType);
  198. return S_OK;
  199. }
  200. HRESULT CProductID::ValidatePID(BOOL* pbIsValid)
  201. {
  202. BOOL bValid = FALSE;
  203. LPWSTR lpszPid3;
  204. WCHAR szOemId[5] = L"\0";
  205. DWORD dwSkuFlags = 0;
  206. // Don't need to check if we know it is already valid.
  207. //
  208. if ( m_dwPidState == PID_STATE_VALID )
  209. *pbIsValid = TRUE;
  210. else if ( m_dwPidState == PID_STATE_INVALID )
  211. *pbIsValid = FALSE;
  212. else
  213. {
  214. // Need to convert m_bstrPID to an ANSI string.
  215. //
  216. lpszPid3 = m_bstrPID;
  217. if ( ( lpszPid3 != NULL ) &&
  218. SetupGetProductType( m_szProdType, &dwSkuFlags ) &&
  219. SetupGetSetupInfo( NULL, 0, NULL, 0,
  220. szOemId, sizeof(szOemId), NULL ) )
  221. {
  222. // Validate the PID!
  223. //
  224. bValid = ( SetupPidGen3(
  225. lpszPid3,
  226. dwSkuFlags,
  227. szOemId,
  228. FALSE,
  229. m_szPID2,
  230. m_abPID3,
  231. NULL) == PID_VALID );
  232. }
  233. // Set the return value.
  234. //
  235. if ( *pbIsValid = bValid )
  236. m_dwPidState = PID_STATE_VALID;
  237. else
  238. {
  239. // Make sure we reset the buffers because the PID isn't valid.
  240. //
  241. m_dwPidState = PID_STATE_INVALID;
  242. m_szPID2[0] = L'\0';
  243. ZeroMemory(&m_abPID3, sizeof(m_abPID3));
  244. }
  245. // Make sure we commit the data to the registry.
  246. //
  247. SaveState();
  248. }
  249. return S_OK;
  250. }
  251. /*
  252. This function returns the PID 2.0 string from the registry. It is needed
  253. because get_PID2() returns an empty string if set_PID() has not been called.
  254. */
  255. HRESULT CProductID::get_CurrentPID2(LPWSTR* lplpszPid2)
  256. {
  257. HKEY hKey;
  258. DWORD cb;
  259. DWORD dwType;
  260. WCHAR szPID2[24] = L"\0";
  261. if ( RegOpenKey(HKEY_LOCAL_MACHINE, REG_KEY_WINDOWSNT, &hKey) == ERROR_SUCCESS )
  262. {
  263. // Get the PID 2 from the registry.
  264. //
  265. cb = sizeof(szPID2);
  266. RegQueryValueEx(hKey,
  267. REG_VAL_PRODUCTID,
  268. NULL,
  269. &dwType,
  270. (LPBYTE) szPID2,
  271. &cb
  272. );
  273. RegCloseKey(hKey);
  274. }
  275. *lplpszPid2 = SysAllocString(szPID2);
  276. return S_OK;
  277. }
  278. /////////////////////////////////////////////////////////////
  279. /////////////////////////////////////////////////////////////
  280. /////////////////////////////////////////////////////////////
  281. /////// IUnknown implementation
  282. ///////
  283. ///////
  284. /////////////////////////////////////////////////////////////
  285. // CProductID::QueryInterface
  286. STDMETHODIMP CProductID::QueryInterface(REFIID riid, LPVOID* ppvObj)
  287. {
  288. // must set out pointer parameters to NULL
  289. *ppvObj = NULL;
  290. if ( riid == IID_IUnknown)
  291. {
  292. AddRef();
  293. *ppvObj = (IUnknown*)this;
  294. return ResultFromScode(S_OK);
  295. }
  296. if (riid == IID_IDispatch)
  297. {
  298. AddRef();
  299. *ppvObj = (IDispatch*)this;
  300. return ResultFromScode(S_OK);
  301. }
  302. // Not a supported interface
  303. return ResultFromScode(E_NOINTERFACE);
  304. }
  305. /////////////////////////////////////////////////////////////
  306. // CProductID::AddRef
  307. STDMETHODIMP_(ULONG) CProductID::AddRef()
  308. {
  309. return ++m_cRef;
  310. }
  311. /////////////////////////////////////////////////////////////
  312. // CProductID::Release
  313. STDMETHODIMP_(ULONG) CProductID::Release()
  314. {
  315. return --m_cRef;
  316. }
  317. /////////////////////////////////////////////////////////////
  318. /////////////////////////////////////////////////////////////
  319. /////////////////////////////////////////////////////////////
  320. /////// IDispatch implementation
  321. ///////
  322. ///////
  323. /////////////////////////////////////////////////////////////
  324. // CProductID::GetTypeInfo
  325. STDMETHODIMP CProductID::GetTypeInfo(UINT, LCID, ITypeInfo**)
  326. {
  327. return E_NOTIMPL;
  328. }
  329. /////////////////////////////////////////////////////////////
  330. // CProductID::GetTypeInfoCount
  331. STDMETHODIMP CProductID::GetTypeInfoCount(UINT* pcInfo)
  332. {
  333. return E_NOTIMPL;
  334. }
  335. /////////////////////////////////////////////////////////////
  336. // CProductID::GetIDsOfNames
  337. STDMETHODIMP CProductID::GetIDsOfNames(REFIID riid,
  338. OLECHAR** rgszNames,
  339. UINT cNames,
  340. LCID lcid,
  341. DISPID* rgDispId)
  342. {
  343. HRESULT hr = DISP_E_UNKNOWNNAME;
  344. rgDispId[0] = DISPID_UNKNOWN;
  345. for (int iX = 0; iX < sizeof(ProductIDExternalInterface)/sizeof(DISPATCHLIST); iX ++)
  346. {
  347. if(lstrcmp(ProductIDExternalInterface[iX].szName, rgszNames[0]) == 0)
  348. {
  349. rgDispId[0] = ProductIDExternalInterface[iX].dwDispID;
  350. hr = NOERROR;
  351. break;
  352. }
  353. }
  354. // Set the disid's for the parameters
  355. if (cNames > 1)
  356. {
  357. // Set a DISPID for function parameters
  358. for (UINT i = 1; i < cNames ; i++)
  359. rgDispId[i] = DISPID_UNKNOWN;
  360. }
  361. return hr;
  362. }
  363. /////////////////////////////////////////////////////////////
  364. // CProductID::Invoke
  365. HRESULT CProductID::Invoke
  366. (
  367. DISPID dispidMember,
  368. REFIID riid,
  369. LCID lcid,
  370. WORD wFlags,
  371. DISPPARAMS* pdispparams,
  372. VARIANT* pvarResult,
  373. EXCEPINFO* pexcepinfo,
  374. UINT* puArgErr
  375. )
  376. {
  377. HRESULT hr = S_OK;
  378. switch(dispidMember)
  379. {
  380. case DISPID_PRODUCTID_GET_PID:
  381. {
  382. TRACE(L"DISPID_PRODUCTID_GET_PID\n");
  383. if(pvarResult)
  384. {
  385. VariantInit(pvarResult);
  386. V_VT(pvarResult) = VT_BSTR;
  387. get_PID(&(pvarResult->bstrVal));
  388. }
  389. break;
  390. }
  391. case DISPID_PRODUCTID_SET_PID:
  392. {
  393. TRACE(L"DISPID_PRODUCTID_SET_PID\n");
  394. if(pdispparams && &pdispparams[0].rgvarg[0])
  395. set_PID(pdispparams[0].rgvarg[0].bstrVal);
  396. break;
  397. }
  398. case DISPID_PRODUCTID_GET_ACCEPTED:
  399. {
  400. TRACE(L"DISPID_PRODUCTID_GET_ACCEPTED\n");
  401. if(pvarResult)
  402. {
  403. VariantInit(pvarResult);
  404. V_VT(pvarResult) = VT_BOOL;
  405. get_PIDAcceptance((BOOL*)&(pvarResult->boolVal));
  406. }
  407. break;
  408. }
  409. case DISPID_PRODUCTID_VALIDATEPID:
  410. {
  411. TRACE(L"DISPID_PRODUCTID_VALIDATEPID\n");
  412. if(pvarResult)
  413. {
  414. VariantInit(pvarResult);
  415. V_VT(pvarResult) = VT_BOOL;
  416. ValidatePID((BOOL*)&(pvarResult->boolVal));
  417. }
  418. break;
  419. }
  420. case DISPID_PRODUCTID_GET_CURRENT_PID2:
  421. {
  422. TRACE(L"DISPID_PRODUCTID_GET_CURRENT_PID2");
  423. if(pvarResult)
  424. {
  425. VariantInit(pvarResult);
  426. V_VT(pvarResult) = VT_BSTR;
  427. get_CurrentPID2(&(pvarResult->bstrVal));
  428. }
  429. break;
  430. }
  431. default:
  432. {
  433. hr = DISP_E_MEMBERNOTFOUND;
  434. break;
  435. }
  436. }
  437. return hr;
  438. }
  439. #ifdef PRERELEASE
  440. BOOL
  441. GetCdKey (
  442. OUT PBYTE CdKey
  443. )
  444. {
  445. DIGITALPID dpid;
  446. DWORD type;
  447. DWORD rc;
  448. HKEY key;
  449. DWORD size = sizeof (dpid);
  450. BOOL b = FALSE;
  451. rc = RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), &key);
  452. if (rc == ERROR_SUCCESS) {
  453. rc = RegQueryValueEx (key, TEXT("DigitalProductId"), NULL, &type, (LPBYTE)&dpid, &size);
  454. if (rc == ERROR_SUCCESS && type == REG_BINARY) {
  455. CopyMemory (CdKey, &dpid.abCdKey, sizeof (dpid.abCdKey));
  456. b = TRUE;
  457. }
  458. else
  459. {
  460. TRACE1(L"OOBE: GetDigitalID, RegQueryValueEx failed, errorcode = %d", rc);
  461. }
  462. RegCloseKey (key);
  463. }
  464. else
  465. {
  466. TRACE1(L"OOBE: GetDigitalID, RegOpenKey failed, errorcode = %d", rc);
  467. }
  468. return b;
  469. }
  470. const unsigned int iBase = 24;
  471. //
  472. // obtained from Jim Harkins 11/27/2000
  473. //
  474. void EncodePid3g(
  475. TCHAR *pchCDKey3Chars, // [OUT] pointer to 29+1 character Secure Product key
  476. LPBYTE pbCDKey3) // [IN] pointer to 15-byte binary Secure Product Key
  477. {
  478. // Given the binary PID 3.0 we need to encode
  479. // it into ASCII characters. We're only allowed to
  480. // use 24 characters so we need to do a base 2 to
  481. // base 24 conversion. It's just like any other
  482. // base conversion execpt the numbers are bigger
  483. // so we have to do the long division ourselves.
  484. const TCHAR achDigits[] = TEXT("BCDFGHJKMPQRTVWXY2346789");
  485. int iCDKey3Chars = 29;
  486. int cGroup = 0;
  487. pchCDKey3Chars[iCDKey3Chars--] = TEXT('\0');
  488. while (0 <= iCDKey3Chars)
  489. {
  490. unsigned int i = 0; // accumulator
  491. int iCDKey3;
  492. for (iCDKey3 = 15-1; 0 <= iCDKey3; --iCDKey3)
  493. {
  494. i = (i * 256) + pbCDKey3[iCDKey3];
  495. pbCDKey3[iCDKey3] = (BYTE)(i / iBase);
  496. i %= iBase;
  497. }
  498. // i now contains the remainder, which is the current digit
  499. pchCDKey3Chars[iCDKey3Chars--] = achDigits[i];
  500. // add '-' between groups of 5 chars
  501. if (++cGroup % 5 == 0 && iCDKey3Chars > 0)
  502. {
  503. pchCDKey3Chars[iCDKey3Chars--] = TEXT('-');
  504. }
  505. }
  506. return;
  507. }
  508. #endif
  509. void CheckDigitalID()
  510. {
  511. #ifdef PRERELEASE
  512. WCHAR WinntPath[MAX_PATH];
  513. BYTE abCdKey[16];
  514. TCHAR ProductId[64] = TEXT("\0"),
  515. szPid[32];
  516. if (GetCdKey (abCdKey))
  517. {
  518. EncodePid3g (ProductId, abCdKey);
  519. // Now compare this value with the productKey value from $winnt$.inf
  520. if(GetCanonicalizedPath(WinntPath, WINNT_INF_FILENAME))
  521. {
  522. if (GetPrivateProfileString(L"UserData",
  523. REG_VAL_PRODUCTKEY,
  524. L"\0",
  525. szPid, MAX_CHARS_IN_BUFFER(szPid),
  526. WinntPath) != 0)
  527. {
  528. if (lstrcmpi(szPid, ProductId) != 0)
  529. {
  530. TRACE1(L"CheckDigitalID: PID in registry and file are different. Registry has: %s",ProductId);
  531. }
  532. else
  533. {
  534. TRACE(L"CheckDigitalID checks out OK");
  535. }
  536. }
  537. else
  538. {
  539. TRACE1(L"CheckDigitalID:Could not get PID from File: %s", WinntPath);
  540. }
  541. }
  542. else
  543. {
  544. TRACE1(L"CheckDigitalID: Could not get path to %s", WINNT_INF_FILENAME);
  545. }
  546. }
  547. #endif
  548. return;
  549. }