Leaked source code of windows server 2003
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.

679 lines
20 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-1998
  5. //
  6. // File: findlost.cpp
  7. //
  8. // Contents:
  9. // Find lost license
  10. //
  11. // History:
  12. // Feb 4, 98 HueiWang Created
  13. //---------------------------------------------------------------------------
  14. #include "pch.cpp"
  15. #include "globals.h"
  16. #include "findlost.h"
  17. #include "misc.h"
  18. #include "db.h"
  19. #include "clilic.h"
  20. #include "keypack.h"
  21. #include "kp.h"
  22. #include "lkpdesc.h"
  23. #define STRSAFE_NO_DEPRECATE
  24. #include <strsafe.h>
  25. //++-------------------------------------------------------------------
  26. DWORD
  27. DBFindLicenseExact(
  28. IN PTLSDbWorkSpace pDbWkSpace,
  29. IN PLICENSEDPRODUCT pLicProduct,
  30. OUT LICENSEDCLIENT *pFoundLicense
  31. )
  32. /*++
  33. Abstract:
  34. Find license based on exact match of client HWID
  35. Parameter:
  36. pDbWkSpace : workspace handle.
  37. pLicProduct : product to request license.
  38. pFoundLicense: found license
  39. Returns:
  40. TLS_E_RECORD_NOTFOUND: HWID not found
  41. ++*/
  42. {
  43. DWORD dwStatus = ERROR_SUCCESS;
  44. BOOL bFound=FALSE;
  45. DWORD dwMatchHwidCount;
  46. LICENSEDCLIENT search_license;
  47. TLSLICENSEPACK search_keypack;
  48. TLSLICENSEPACK found_keypack;
  49. memset(&search_license, 0, sizeof(search_license));
  50. memset(pFoundLicense, 0, sizeof(LICENSEDCLIENT));
  51. search_license.dwSystemBiosChkSum = pLicProduct->Hwid.dwPlatformID;
  52. search_license.dwVideoBiosChkSum = pLicProduct->Hwid.Data1;
  53. search_license.dwFloppyBiosChkSum = pLicProduct->Hwid.Data2;
  54. search_license.dwHardDiskSize = pLicProduct->Hwid.Data3;
  55. search_license.dwRamSize = pLicProduct->Hwid.Data4;
  56. //
  57. // lock both tables -
  58. // Other threads might be in the process of allocating a temp. license
  59. // while this thread is searching
  60. //
  61. TLSDBLockKeyPackTable();
  62. TLSDBLockLicenseTable();
  63. dwStatus = TLSDBLicenseEnumBegin(
  64. pDbWkSpace,
  65. TRUE,
  66. LICENSE_COLUMN_SEARCH_HWID,
  67. &search_license
  68. );
  69. if(dwStatus != ERROR_SUCCESS)
  70. {
  71. goto cleanup;
  72. }
  73. while(bFound == FALSE)
  74. {
  75. dwStatus = TLSDBLicenseEnumNext(
  76. pDbWkSpace,
  77. pFoundLicense
  78. );
  79. if(dwStatus != ERROR_SUCCESS)
  80. {
  81. break;
  82. }
  83. //
  84. // Verify against client HWID
  85. //
  86. dwMatchHwidCount = 0;
  87. dwMatchHwidCount += (pFoundLicense->dwSystemBiosChkSum == pLicProduct->Hwid.dwPlatformID);
  88. dwMatchHwidCount += (pFoundLicense->dwVideoBiosChkSum == pLicProduct->Hwid.Data1);
  89. dwMatchHwidCount += (pFoundLicense->dwFloppyBiosChkSum == pLicProduct->Hwid.Data2);
  90. dwMatchHwidCount += (pFoundLicense->dwHardDiskSize == pLicProduct->Hwid.Data3);
  91. dwMatchHwidCount += (pFoundLicense->dwRamSize == pLicProduct->Hwid.Data4);
  92. if(dwMatchHwidCount != 5)
  93. {
  94. break;
  95. }
  96. //
  97. // See if this match our license pack
  98. //
  99. search_keypack.dwKeyPackId = pFoundLicense->dwKeyPackId;
  100. dwStatus = TLSDBKeyPackFind(
  101. pDbWkSpace,
  102. TRUE,
  103. LSKEYPACK_EXSEARCH_DWINTERNAL,
  104. &search_keypack,
  105. &found_keypack
  106. );
  107. if(dwStatus != ERROR_SUCCESS)
  108. {
  109. continue;
  110. }
  111. //
  112. // No actual license is issued for concurrent KeyPack.
  113. //
  114. if(found_keypack.ucAgreementType != LSKEYPACKTYPE_RETAIL &&
  115. found_keypack.ucAgreementType != LSKEYPACKTYPE_SELECT &&
  116. found_keypack.ucAgreementType != LSKEYPACKTYPE_OPEN &&
  117. found_keypack.ucAgreementType != LSKEYPACKTYPE_TEMPORARY &&
  118. found_keypack.ucAgreementType != LSKEYPACKTYPE_FREE )
  119. {
  120. continue;
  121. }
  122. UCHAR ucKeyPackStatus = found_keypack.ucKeyPackStatus & ~LSKEYPACKSTATUS_RESERVED;
  123. //
  124. // No license for pending activation key pack, use temporary license scheme.
  125. //
  126. if(ucKeyPackStatus != LSKEYPACKSTATUS_ACTIVE &&
  127. ucKeyPackStatus != LSKEYPACKSTATUS_TEMPORARY)
  128. {
  129. continue;
  130. }
  131. if(found_keypack.wMajorVersion != pLicProduct->pLicensedVersion->wMajorVersion ||
  132. found_keypack.wMinorVersion != pLicProduct->pLicensedVersion->wMinorVersion)
  133. {
  134. continue;
  135. }
  136. if(found_keypack.dwPlatformType != pLicProduct->LicensedProduct.dwPlatformID)
  137. {
  138. continue;
  139. }
  140. if(_tcsnicmp(found_keypack.szProductId,
  141. (LPTSTR)(pLicProduct->pbOrgProductID),
  142. ((pLicProduct->cbOrgProductID)/sizeof(TCHAR)) - 1)
  143. != 0)
  144. {
  145. continue;
  146. }
  147. //
  148. // Found our lost license.
  149. //
  150. bFound = TRUE;
  151. }
  152. TLSDBLicenseEnumEnd(pDbWkSpace);
  153. cleanup:
  154. if(dwStatus == TLS_I_NO_MORE_DATA)
  155. {
  156. SetLastError(dwStatus = TLS_E_RECORD_NOTFOUND);
  157. }
  158. TLSDBUnlockLicenseTable();
  159. TLSDBUnlockKeyPackTable();
  160. return dwStatus;
  161. }
  162. //++-------------------------------------------------------------------
  163. DWORD
  164. DBFindLostLicenseExact(
  165. IN PTLSDbWorkSpace pDbWkSpace,
  166. IN PTLSDBAllocateRequest pRequest, // ucKeyPackType not use
  167. // IN BOOL bMatchHwid,
  168. IN PHWID pHwid,
  169. IN OUT PTLSLICENSEPACK lpKeyPack,
  170. IN OUT PLICENSEDCLIENT lpLicense
  171. )
  172. /*++
  173. Abstract:
  174. Find lost license base on exact/closest match of client HWID
  175. Parameter:
  176. pDbWkSpace : workspace handle.
  177. pRequest : product to request license.
  178. bMatchHwid : TRUE if match HWID, FALSE otherwise.
  179. lpKeyPack : keyPack that license was issued from.
  180. lpLicense : Founded license record.
  181. Returns:
  182. ++*/
  183. {
  184. DWORD dwStatus = ERROR_SUCCESS;
  185. BOOL bFound=FALSE;
  186. DWORD dwMatchHwidCount;
  187. LICENSEDCLIENT search_license;
  188. LICENSEDCLIENT found_license;
  189. TLSLICENSEPACK search_keypack;
  190. TLSLICENSEPACK found_keypack;
  191. //
  192. // Ignore ucKeyPackType
  193. //
  194. pRequest->ucAgreementType = LSKEYPACKTYPE_FIRST;
  195. dwStatus = VerifyTLSDBAllocateRequest(pRequest);
  196. if(dwStatus != ERROR_SUCCESS)
  197. {
  198. return dwStatus;
  199. }
  200. memset(&search_license, 0, sizeof(search_license));
  201. memset(&found_license, 0, sizeof(found_license));
  202. search_license.dwSystemBiosChkSum = pHwid->dwPlatformID;
  203. search_license.dwVideoBiosChkSum = pHwid->Data1;
  204. search_license.dwFloppyBiosChkSum = pHwid->Data2;
  205. search_license.dwHardDiskSize = pHwid->Data3;
  206. search_license.dwRamSize = pHwid->Data4;
  207. //
  208. // lock both table -
  209. // Other thread might be in the process of allocating a temp. license while this
  210. // thread try to delete the temp. key pack.
  211. //
  212. TLSDBLockKeyPackTable();
  213. TLSDBLockLicenseTable();
  214. dwStatus = TLSDBLicenseEnumBegin(
  215. pDbWkSpace,
  216. TRUE,
  217. LICENSE_COLUMN_SEARCH_HWID,
  218. &search_license
  219. );
  220. if(dwStatus != ERROR_SUCCESS)
  221. {
  222. goto cleanup;
  223. }
  224. while(bFound == FALSE)
  225. {
  226. dwStatus = TLSDBLicenseEnumNext(
  227. pDbWkSpace,
  228. &found_license
  229. );
  230. if(dwStatus != ERROR_SUCCESS)
  231. {
  232. break;
  233. }
  234. //
  235. // Verify against client HWID
  236. //
  237. dwMatchHwidCount = 0;
  238. dwMatchHwidCount += (found_license.dwSystemBiosChkSum == pHwid->dwPlatformID);
  239. dwMatchHwidCount += (found_license.dwVideoBiosChkSum == pHwid->Data1);
  240. dwMatchHwidCount += (found_license.dwFloppyBiosChkSum == pHwid->Data2);
  241. dwMatchHwidCount += (found_license.dwHardDiskSize == pHwid->Data3);
  242. dwMatchHwidCount += (found_license.dwRamSize == pHwid->Data4);
  243. if(dwMatchHwidCount != 5)
  244. {
  245. break;
  246. }
  247. //
  248. // consider only valid license
  249. //
  250. if( found_license.ucLicenseStatus != LSLICENSE_STATUS_ACTIVE &&
  251. found_license.ucLicenseStatus != LSLICENSE_STATUS_PENDING &&
  252. found_license.ucLicenseStatus != LSLICENSE_STATUS_TEMPORARY)
  253. {
  254. continue;
  255. }
  256. //
  257. // See if this match our license pack
  258. //
  259. search_keypack.dwKeyPackId = found_license.dwKeyPackId;
  260. dwStatus = TLSDBKeyPackFind(
  261. pDbWkSpace,
  262. TRUE,
  263. LSKEYPACK_EXSEARCH_DWINTERNAL,
  264. &search_keypack,
  265. &found_keypack
  266. );
  267. if(dwStatus != ERROR_SUCCESS)
  268. {
  269. continue;
  270. }
  271. //
  272. // No actual license is issued for concurrent KeyPack.
  273. //
  274. if(found_keypack.ucAgreementType != LSKEYPACKTYPE_RETAIL &&
  275. found_keypack.ucAgreementType != LSKEYPACKTYPE_SELECT &&
  276. found_keypack.ucAgreementType != LSKEYPACKTYPE_OPEN &&
  277. found_keypack.ucAgreementType != LSKEYPACKTYPE_TEMPORARY &&
  278. found_keypack.ucAgreementType != LSKEYPACKTYPE_FREE )
  279. {
  280. continue;
  281. }
  282. UCHAR ucKeyPackStatus = found_keypack.ucKeyPackStatus & ~LSKEYPACKSTATUS_RESERVED;
  283. //
  284. // No license for pending activation key pack, use temporary license scheme.
  285. //
  286. if(ucKeyPackStatus != LSKEYPACKSTATUS_ACTIVE &&
  287. ucKeyPackStatus != LSKEYPACKSTATUS_TEMPORARY)
  288. {
  289. continue;
  290. }
  291. if(found_keypack.wMajorVersion != HIWORD(pRequest->dwVersion) ||
  292. found_keypack.wMinorVersion != LOWORD(pRequest->dwVersion) )
  293. {
  294. continue;
  295. }
  296. if(found_keypack.dwPlatformType != pRequest->dwPlatformId)
  297. {
  298. continue;
  299. }
  300. if(_tcscmp(found_keypack.szCompanyName, pRequest->szCompanyName) != 0)
  301. {
  302. continue;
  303. }
  304. if(_tcscmp(found_keypack.szProductId, pRequest->szProductId) != 0)
  305. {
  306. continue;
  307. }
  308. //
  309. // Found our lost license.
  310. //
  311. bFound = TRUE;
  312. *lpLicense = found_license;
  313. *lpKeyPack = found_keypack;
  314. }
  315. TLSDBLicenseEnumEnd(pDbWkSpace);
  316. cleanup:
  317. if(dwStatus == TLS_I_NO_MORE_DATA)
  318. {
  319. SetLastError(dwStatus = TLS_E_RECORD_NOTFOUND);
  320. }
  321. TLSDBUnlockLicenseTable();
  322. TLSDBUnlockKeyPackTable();
  323. return dwStatus;
  324. }
  325. //++--------------------------------------------------------------------
  326. DWORD
  327. TLSFindLicense(
  328. IN PLICENSEDPRODUCT pLicProduct,
  329. OUT PLICENSEDCLIENT pLicClient
  330. )
  331. {
  332. PTLSDbWorkSpace pDbWkSpace = NULL;
  333. DWORD status = ERROR_SUCCESS;
  334. pDbWkSpace = AllocateWorkSpace(g_EnumDbTimeout);
  335. if(pDbWkSpace == NULL)
  336. {
  337. status=TLS_E_ALLOCATE_HANDLE;
  338. goto cleanup;
  339. }
  340. status = DBFindLicenseExact(pDbWkSpace,pLicProduct,pLicClient);
  341. ReleaseWorkSpace(&pDbWkSpace);
  342. cleanup:
  343. return status;
  344. }
  345. //++--------------------------------------------------------------------
  346. DWORD
  347. TLSFindDbLicensedProduct(
  348. IN PTLSDBLICENSEDPRODUCT pDbLicProduct,
  349. OUT PLICENSEDCLIENT pLicClient
  350. )
  351. {
  352. PTLSDbWorkSpace pDbWkSpace = NULL;
  353. DWORD status = ERROR_SUCCESS;
  354. LICENSEDPRODUCT LicProduct;
  355. LICENSED_VERSION_INFO LicVerInfo;
  356. pDbWkSpace = AllocateWorkSpace(g_EnumDbTimeout);
  357. if(pDbWkSpace == NULL)
  358. {
  359. status=TLS_E_ALLOCATE_HANDLE;
  360. goto cleanup;
  361. }
  362. memcpy(&(LicProduct.Hwid), &(pDbLicProduct->ClientHwid), sizeof(HWID));
  363. LicVerInfo.wMajorVersion = HIWORD(pDbLicProduct->dwProductVersion);
  364. LicVerInfo.wMinorVersion = LOWORD(pDbLicProduct->dwProductVersion);
  365. LicProduct.pLicensedVersion = &LicVerInfo;
  366. LicProduct.LicensedProduct.dwPlatformID = pDbLicProduct->dwPlatformID;
  367. LicProduct.pbOrgProductID = (PBYTE)(pDbLicProduct->szLicensedProductId);
  368. LicProduct.cbOrgProductID = _tcslen(pDbLicProduct->szLicensedProductId) * sizeof(TCHAR);
  369. status = DBFindLicenseExact(pDbWkSpace,&LicProduct,pLicClient);
  370. ReleaseWorkSpace(&pDbWkSpace);
  371. cleanup:
  372. return status;
  373. }
  374. //++--------------------------------------------------------------------
  375. DWORD
  376. TLSDBFindLostLicense(
  377. IN PTLSDbWorkSpace pDbWkSpace,
  378. IN PTLSDBLICENSEREQUEST pLicenseRequest,
  379. IN PHWID pHwid,
  380. IN OUT PTLSDBLICENSEDPRODUCT pLicensedProduct,
  381. OUT PUCHAR pucMarked
  382. )
  383. /*++
  384. Abstract:
  385. Wrapper to DBFindLostLicense().
  386. See DBFindLostLicense.
  387. ++*/
  388. {
  389. DWORD dwStatus=ERROR_SUCCESS;
  390. TLSLICENSEPACK keypack;
  391. LICENSEDCLIENT License;
  392. ULARGE_INTEGER ulSerialNumber;
  393. FILETIME notBefore;
  394. FILETIME notAfter;
  395. PMGENERATELICENSE PolModGenLicense;
  396. PPMCERTEXTENSION pPolModCertExtension=NULL;
  397. PMLICENSEREQUEST PolRequest;
  398. TLSDBAllocateRequest AllocateRequest;
  399. DWORD dwRetCode=ERROR_SUCCESS;
  400. keypack.pbDomainSid = NULL;
  401. AllocateRequest.szCompanyName = (LPTSTR)pLicenseRequest->pszCompanyName;
  402. AllocateRequest.szProductId = (LPTSTR)pLicenseRequest->pszProductId;
  403. AllocateRequest.dwVersion = pLicenseRequest->dwProductVersion;
  404. AllocateRequest.dwPlatformId = pLicenseRequest->dwPlatformID;
  405. AllocateRequest.dwLangId = pLicenseRequest->dwLanguageID;
  406. AllocateRequest.dwNumLicenses = 1;
  407. dwStatus = DBFindLostLicenseExact(
  408. pDbWkSpace,
  409. &AllocateRequest,
  410. //TRUE,
  411. pHwid,
  412. &keypack,
  413. &License
  414. );
  415. #if 0
  416. //
  417. // TermSrv does not support matching, comment out for now
  418. //
  419. if(dwStatus == TLS_E_RECORD_NOTFOUND)
  420. {
  421. //
  422. // find by matching, very expensive operation
  423. //
  424. dwStatus = DBFindLostLicenseMatch(
  425. pDbWkSpace,
  426. &AllocateRequest,
  427. FALSE,
  428. pHwid,
  429. &keypack,
  430. &License
  431. );
  432. if(dwStatus == ERROR_SUCCESS)
  433. {
  434. dwRetCode = TLS_W_LICENSE_PROXIMATE;
  435. }
  436. }
  437. #endif
  438. if(dwStatus != ERROR_SUCCESS)
  439. {
  440. goto cleanup;
  441. }
  442. UnixTimeToFileTime(License.ftIssueDate, &notBefore);
  443. UnixTimeToFileTime(License.ftExpireDate, &notAfter);
  444. ulSerialNumber.LowPart = License.dwLicenseId;
  445. ulSerialNumber.HighPart = keypack.dwKeyPackId;
  446. PolRequest.dwProductVersion = MAKELONG(keypack.wMinorVersion, keypack.wMajorVersion);
  447. PolRequest.pszProductId = (LPTSTR)keypack.szProductId;
  448. PolRequest.pszCompanyName = (LPTSTR)keypack.szCompanyName;
  449. PolRequest.dwLanguageId = pLicenseRequest->dwLanguageID;
  450. PolRequest.dwPlatformId = keypack.dwPlatformType;
  451. PolRequest.pszMachineName = License.szMachineName;
  452. PolRequest.pszUserName = License.szUserName;
  453. //
  454. // Inform Policy Module of license generation.
  455. //
  456. PolModGenLicense.pLicenseRequest = &PolRequest;
  457. PolModGenLicense.dwKeyPackType = keypack.ucAgreementType;
  458. PolModGenLicense.dwKeyPackId = keypack.dwKeyPackId;
  459. PolModGenLicense.dwKeyPackLicenseId = License.dwKeyPackLicenseId;
  460. PolModGenLicense.ClientLicenseSerialNumber = ulSerialNumber;
  461. PolModGenLicense.ftNotBefore = notBefore;
  462. PolModGenLicense.ftNotAfter = notAfter;
  463. dwStatus = pLicenseRequest->pPolicy->PMLicenseRequest(
  464. pLicenseRequest->hClient,
  465. REQUEST_GENLICENSE,
  466. (PVOID)&PolModGenLicense,
  467. (PVOID *)&pPolModCertExtension
  468. );
  469. if(dwStatus != ERROR_SUCCESS)
  470. {
  471. //
  472. // Error in policy module
  473. //
  474. goto cleanup;
  475. }
  476. //
  477. // Check error return from policy module
  478. //
  479. if(pPolModCertExtension != NULL)
  480. {
  481. if(pPolModCertExtension->pbData != NULL && pPolModCertExtension->cbData == 0 ||
  482. pPolModCertExtension->pbData == NULL && pPolModCertExtension->cbData != 0 )
  483. {
  484. // assuming no extension data
  485. pPolModCertExtension->cbData = 0;
  486. pPolModCertExtension->pbData = NULL;
  487. }
  488. if(CompareFileTime(&(pPolModCertExtension->ftNotBefore), &(pPolModCertExtension->ftNotAfter)) > 0)
  489. {
  490. //
  491. // invalid data return from policy module
  492. //
  493. TLSLogEvent(
  494. EVENTLOG_ERROR_TYPE,
  495. TLS_E_GENERATECLIENTELICENSE,
  496. dwStatus = TLS_E_POLICYMODULEERROR,
  497. pLicenseRequest->pPolicy->GetCompanyName(),
  498. pLicenseRequest->pPolicy->GetProductId()
  499. );
  500. goto cleanup;
  501. }
  502. //
  503. // Ignore not before and not after
  504. //
  505. }
  506. if(keypack.ucAgreementType == LSKEYPACKTYPE_TEMPORARY)
  507. {
  508. //
  509. // we found a temporary license
  510. //
  511. dwRetCode = TLS_I_FOUND_TEMPORARY_LICENSE;
  512. }
  513. //
  514. // License expired
  515. //
  516. if(License.ftExpireDate < time(NULL))
  517. {
  518. dwRetCode = TLS_E_LICENSE_EXPIRED;
  519. }
  520. //
  521. // Return licensed product
  522. //
  523. pLicensedProduct->pSubjectPublicKeyInfo = NULL;
  524. pLicensedProduct->dwQuantity = License.dwNumLicenses;
  525. pLicensedProduct->ulSerialNumber = ulSerialNumber;
  526. pLicensedProduct->dwKeyPackId = keypack.dwKeyPackId;
  527. pLicensedProduct->dwLicenseId = License.dwLicenseId;
  528. pLicensedProduct->dwKeyPackLicenseId = License.dwKeyPackLicenseId;
  529. pLicensedProduct->ClientHwid.dwPlatformID = License.dwSystemBiosChkSum;
  530. pLicensedProduct->ClientHwid.Data1 = License.dwVideoBiosChkSum;
  531. pLicensedProduct->ClientHwid.Data2 = License.dwFloppyBiosChkSum;
  532. pLicensedProduct->ClientHwid.Data3 = License.dwHardDiskSize;
  533. pLicensedProduct->ClientHwid.Data4 = License.dwRamSize;
  534. pLicensedProduct->bTemp = (keypack.ucAgreementType == LSKEYPACKTYPE_TEMPORARY);
  535. pLicensedProduct->NotBefore = notBefore;
  536. pLicensedProduct->NotAfter = notAfter;
  537. pLicensedProduct->dwProductVersion = MAKELONG(keypack.wMinorVersion, keypack.wMajorVersion);
  538. _tcscpy(pLicensedProduct->szCompanyName, keypack.szCompanyName);
  539. _tcscpy(pLicensedProduct->szLicensedProductId, keypack.szProductId);
  540. StringCbCopy(pLicensedProduct->szRequestProductId, sizeof(pLicensedProduct->szRequestProductId), pLicenseRequest->pClientLicenseRequest->pszProductId);
  541. _tcscpy(pLicensedProduct->szUserName, License.szUserName);
  542. _tcscpy(pLicensedProduct->szMachineName, License.szMachineName);
  543. pLicensedProduct->dwLanguageID = pLicenseRequest->dwLanguageID;
  544. pLicensedProduct->dwPlatformID = pLicenseRequest->dwPlatformID;
  545. pLicensedProduct->pbPolicyData = (pPolModCertExtension) ? pPolModCertExtension->pbData : NULL;
  546. pLicensedProduct->cbPolicyData = (pPolModCertExtension) ? pPolModCertExtension->cbData : 0;
  547. if (NULL != pucMarked)
  548. {
  549. // this field is being reused for marking (e.g. user is authenticated)
  550. *pucMarked = License.ucEntryStatus;
  551. }
  552. cleanup:
  553. return (dwStatus == ERROR_SUCCESS) ? dwRetCode : dwStatus;
  554. }