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.

7158 lines
159 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: db.cpp
  7. //
  8. // Contents: Cert Server Database interface implementation
  9. //
  10. //---------------------------------------------------------------------------
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. #include "csprop.h"
  14. #include "db.h"
  15. #include "column.h"
  16. #include "row.h"
  17. #include "view.h"
  18. #include "backup.h"
  19. #include "restore.h"
  20. #include "dbw.h"
  21. #include <mimeole.h>
  22. #define __dwFILE__ __dwFILE_CERTDB_DB_CPP__
  23. // Table and Index Density (in percent), for page splits:
  24. // Create tables and indexes with PCDENSITYSET.
  25. // Reset to PCDENSITYRESET if below PCDENSITYMIN or above PCDENSITYMAX.
  26. // Windows 2000 used 50% for indexes, 100% for tables (and primary indexes)!?!
  27. #define PCDENSITYSET 0 // use reasonable default (80%?)
  28. #define PCDENSITYMIN 60
  29. #define PCDENSITYRESET 80 // reset to 80% if out of range
  30. #define PCDENSITYMAX 95
  31. #define ULTABLEPAGES 4
  32. #define SEEKPOS_FIRST 0
  33. #define SEEKPOS_LAST 1
  34. #define SEEKPOS_INDEXFIRST 2
  35. #define SEEKPOS_INDEXLAST 3
  36. LONG g_cCertDB = 0;
  37. LONG g_cCertDBTotal = 0;
  38. LONG g_cXactCommit = 0;
  39. LONG g_cXactAbort = 0;
  40. LONG g_cXactTotal = 0;
  41. char *g_pszDBFile = NULL;
  42. typedef struct _DBJETPARM {
  43. DWORD paramid;
  44. DWORD lParam;
  45. char *pszParam;
  46. BOOL fString;
  47. } DBJETPARM;
  48. #define LANGID_DBFIXED MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) // 0x409
  49. #define CB_PROPFASTBUF 128
  50. DBJETPARM g_aParm[] = {
  51. #define JP_LOGPATH 0
  52. { JET_paramLogFilePath, 0, NULL, TRUE },
  53. #define JP_SYSTEMPATH 1
  54. { JET_paramSystemPath, 0, NULL, TRUE },
  55. #define JP_TEMPPATH 2
  56. { JET_paramTempPath, 0, NULL, TRUE },
  57. #define JP_EVENTSOURCE 3
  58. { JET_paramEventSource, 0, NULL, TRUE },
  59. #define JP_SESSIONMAX 4
  60. { JET_paramMaxSessions, 0, NULL, FALSE },
  61. #define JP_CACHESIZEMIN 5
  62. { JET_paramCacheSizeMin, 64, NULL, FALSE },
  63. #define JP_CACHESIZEMAX 6
  64. { JET_paramCacheSizeMax, 512, NULL, FALSE },
  65. #define JP_VERPAGESMAX 7
  66. #define VERPAGESMULTIPLIER 64 // 64 * 16k units ==> 1mb per session
  67. { JET_paramMaxVerPages, VERPAGESMULTIPLIER * DBSESSIONCOUNTDEFAULT, NULL, FALSE },
  68. #define JP_MAXCURSORS 8
  69. #define MAXCURSORSMULTIPLIER 20 // 5 per table * 4 tables per session ==> 20
  70. { JET_paramMaxCursors, 1024, NULL, FALSE },
  71. #define JP_LOGBUFFERS 9
  72. { JET_paramLogBuffers, 41, NULL, FALSE },
  73. #define JP_LOGFILESIZE 10
  74. { JET_paramLogFileSize, 1024, NULL, FALSE },
  75. { JET_paramRecovery, 0, "on", TRUE },
  76. { JET_paramMaxTemporaryTables, 5, NULL, FALSE },
  77. { JET_paramAssertAction, JET_AssertBreak, NULL, FALSE },
  78. { JET_paramBaseName, 0, szDBBASENAMEPARM, TRUE } // "edb"
  79. };
  80. #define CDBPARM (sizeof(g_aParm)/sizeof(g_aParm[0]))
  81. VOID
  82. DBFreeParms()
  83. {
  84. if (NULL != g_aParm[JP_LOGPATH].pszParam)
  85. {
  86. LocalFree(g_aParm[JP_LOGPATH].pszParam);
  87. g_aParm[JP_LOGPATH].pszParam = NULL;
  88. }
  89. if (NULL != g_aParm[JP_SYSTEMPATH].pszParam)
  90. {
  91. LocalFree(g_aParm[JP_SYSTEMPATH].pszParam);
  92. g_aParm[JP_SYSTEMPATH].pszParam = NULL;
  93. }
  94. if (NULL != g_aParm[JP_TEMPPATH].pszParam)
  95. {
  96. LocalFree(g_aParm[JP_TEMPPATH].pszParam);
  97. g_aParm[JP_TEMPPATH].pszParam = NULL;
  98. }
  99. if (NULL != g_aParm[JP_EVENTSOURCE].pszParam)
  100. {
  101. LocalFree(g_aParm[JP_EVENTSOURCE].pszParam);
  102. g_aParm[JP_EVENTSOURCE].pszParam = NULL;
  103. }
  104. }
  105. HRESULT
  106. DBInitParms(
  107. IN DWORD cSession,
  108. IN DWORD DBFlags,
  109. OPTIONAL IN WCHAR const *pwszEventSource,
  110. OPTIONAL IN WCHAR const *pwszLogDir,
  111. OPTIONAL IN WCHAR const *pwszSystemDir,
  112. OPTIONAL IN WCHAR const *pwszTempDir,
  113. OUT JET_INSTANCE *pInstance)
  114. {
  115. HRESULT hr = E_OUTOFMEMORY;
  116. HKEY hKey = NULL;
  117. DBJETPARM const *pjp;
  118. DWORD cwc;
  119. DWORD cwcT;
  120. WCHAR *pwszPath = NULL;
  121. WCHAR *pwszValueName = NULL;
  122. char *pszValue = NULL;
  123. BYTE *pbValue = NULL;
  124. DWORD i;
  125. DBFreeParms();
  126. cwc = 0;
  127. if (NULL != pwszLogDir)
  128. {
  129. cwcT = wcslen(pwszLogDir) + 1;
  130. if (cwc < cwcT)
  131. {
  132. cwc = cwcT;
  133. }
  134. }
  135. if (NULL != pwszSystemDir)
  136. {
  137. cwcT = wcslen(pwszSystemDir) + 1;
  138. if (cwc < cwcT)
  139. {
  140. cwc = cwcT;
  141. }
  142. }
  143. if (NULL != pwszTempDir)
  144. {
  145. cwcT = wcslen(pwszTempDir) + 1;
  146. if (cwc < cwcT)
  147. {
  148. cwc = cwcT;
  149. }
  150. }
  151. if (0 != cwc)
  152. {
  153. pwszPath = (WCHAR *) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * (cwc + 1));
  154. if (NULL == pwszPath)
  155. {
  156. hr = E_OUTOFMEMORY;
  157. _JumpError(hr, error, "LocalAlloc");
  158. }
  159. }
  160. if (NULL != pwszLogDir)
  161. {
  162. wcscpy(pwszPath, pwszLogDir);
  163. wcscat(pwszPath, L"\\");
  164. CSASSERT(wcslen(pwszPath) <= cwc);
  165. if (!ConvertWszToSz(&g_aParm[JP_LOGPATH].pszParam, pwszPath, -1))
  166. {
  167. _JumpError(hr, error, "ConvertWszToSz(LogDir)");
  168. }
  169. }
  170. if (NULL != pwszSystemDir)
  171. {
  172. wcscpy(pwszPath, pwszSystemDir);
  173. wcscat(pwszPath, L"\\");
  174. CSASSERT(wcslen(pwszPath) <= cwc);
  175. if (!ConvertWszToSz(&g_aParm[JP_SYSTEMPATH].pszParam, pwszPath, -1))
  176. {
  177. _JumpError(hr, error, "ConvertWszToSz(SystemDir)");
  178. }
  179. }
  180. if (NULL != pwszTempDir)
  181. {
  182. wcscpy(pwszPath, pwszTempDir);
  183. wcscat(pwszPath, L"\\");
  184. CSASSERT(wcslen(pwszPath) <= cwc);
  185. if (!ConvertWszToSz(&g_aParm[JP_TEMPPATH].pszParam, pwszPath, -1))
  186. {
  187. _JumpError(hr, error, "ConvertWszToSz(TempDir)");
  188. }
  189. }
  190. if (NULL != pwszEventSource)
  191. {
  192. if (!ConvertWszToSz(
  193. &g_aParm[JP_EVENTSOURCE].pszParam,
  194. pwszEventSource,
  195. -1))
  196. {
  197. _JumpError(hr, error, "ConvertWszToSz(EventSource)");
  198. }
  199. }
  200. g_aParm[JP_SESSIONMAX].lParam = cSession + 1;
  201. if (8 * cSession > g_aParm[JP_CACHESIZEMIN].lParam)
  202. {
  203. g_aParm[JP_CACHESIZEMIN].lParam = 8 * cSession;
  204. }
  205. if (8 * 8 * cSession > g_aParm[JP_CACHESIZEMAX].lParam)
  206. {
  207. g_aParm[JP_CACHESIZEMAX].lParam = 8 * 8 * cSession;
  208. }
  209. if (DBFLAGS_MAXCACHESIZEX100 & DBFlags)
  210. {
  211. // real fix is not to set this at all, but setting it to a large number
  212. // should suffice
  213. g_aParm[JP_CACHESIZEMAX].lParam *= 100;
  214. }
  215. if (VERPAGESMULTIPLIER * cSession > g_aParm[JP_VERPAGESMAX].lParam)
  216. {
  217. g_aParm[JP_VERPAGESMAX].lParam = VERPAGESMULTIPLIER * cSession;
  218. }
  219. if (MAXCURSORSMULTIPLIER * cSession > g_aParm[JP_MAXCURSORS].lParam)
  220. {
  221. g_aParm[JP_MAXCURSORS].lParam = MAXCURSORSMULTIPLIER * cSession;
  222. }
  223. if (DBFLAGS_LOGBUFFERSLARGE & DBFlags)
  224. {
  225. // default was 41
  226. g_aParm[JP_LOGBUFFERS].lParam = 256;
  227. }
  228. if (DBFLAGS_LOGBUFFERSHUGE & DBFlags)
  229. {
  230. // should be logfilesize (1024k) - 64k, specified in 512b units
  231. g_aParm[JP_LOGBUFFERS].lParam = 480;
  232. }
  233. if (DBFLAGS_LOGFILESIZE16MB & DBFlags)
  234. {
  235. // 16x the size we usually run with (16 * 1MB)
  236. g_aParm[JP_LOGFILESIZE].lParam = 16 * 1024;
  237. }
  238. for (pjp = g_aParm; pjp < &g_aParm[CDBPARM]; pjp++)
  239. {
  240. if (!pjp->fString || NULL != pjp->pszParam)
  241. {
  242. _dbgJetSetSystemParameter(
  243. pInstance,
  244. 0,
  245. pjp->paramid,
  246. pjp->lParam,
  247. pjp->pszParam);
  248. }
  249. }
  250. if (DBFLAGS_CIRCULARLOGGING & DBFlags)
  251. {
  252. DBGPRINT((DBG_SS_CERTDB, "JetSetSystemParameter(Circular Log)\n"));
  253. _dbgJetSetSystemParameter(
  254. pInstance,
  255. 0,
  256. JET_paramCircularLog,
  257. TRUE,
  258. NULL);
  259. }
  260. if (DBFLAGS_LAZYFLUSH & DBFlags)
  261. {
  262. DBGPRINT((DBG_SS_CERTDB, "JetSetSystemParameter(Lazy Flush)\n"));
  263. _dbgJetSetSystemParameter(
  264. pInstance,
  265. 0,
  266. JET_paramCommitDefault,
  267. JET_bitCommitLazyFlush,
  268. NULL);
  269. }
  270. if (DBFLAGS_CHECKPOINTDEPTH60MB & DBFlags)
  271. {
  272. // 60MB -- triple the size we usually run with (20MB)
  273. DBGPRINT((DBG_SS_CERTDB, "JetSetSystemParameter(CheckPoint Depth)\n"));
  274. _dbgJetSetSystemParameter(
  275. pInstance,
  276. 0,
  277. JET_paramCheckpointDepthMax,
  278. 60 * 1024 * 1024,
  279. NULL);
  280. }
  281. hr = RegOpenKeyEx(
  282. HKEY_LOCAL_MACHINE,
  283. wszREGKEYCONFIGPATH_BS wszREGKEYDBPARAMETERS,
  284. 0,
  285. KEY_READ,
  286. &hKey);
  287. _PrintIfErrorStr2(
  288. hr,
  289. "RegOpenKeyEx",
  290. wszREGKEYCONFIGPATH_BS wszREGKEYDBPARAMETERS,
  291. hr);
  292. if (S_OK == hr)
  293. {
  294. DWORD cValue;
  295. DWORD cwcValueNameLenMax;
  296. DWORD cbValueLenMax;
  297. #define CBPAD (2 * sizeof(WCHAR) - 1)
  298. hr = RegQueryInfoKey(
  299. hKey,
  300. NULL,
  301. NULL,
  302. NULL,
  303. NULL,
  304. NULL,
  305. NULL,
  306. &cValue,
  307. &cwcValueNameLenMax,
  308. &cbValueLenMax,
  309. NULL,
  310. NULL);
  311. _JumpIfError(hr, error, "RegQueryInfoKey");
  312. pwszValueName = (WCHAR *) LocalAlloc(
  313. LMEM_FIXED,
  314. sizeof(WCHAR) * (cwcValueNameLenMax + 1));
  315. if (NULL == pwszValueName)
  316. {
  317. hr = E_OUTOFMEMORY;
  318. _JumpError(hr, error, "LocalAlloc");
  319. }
  320. pbValue = (BYTE *) LocalAlloc(LMEM_FIXED, cbValueLenMax + CBPAD);
  321. if (NULL == pbValue)
  322. {
  323. hr = E_OUTOFMEMORY;
  324. _JumpError(hr, error, "LocalAlloc");
  325. }
  326. for (i = 0; i < cValue; i++)
  327. {
  328. DWORD dwType;
  329. DWORD cbValue;
  330. LONG ParamId;
  331. LONG lParam;
  332. BOOL fValid;
  333. cwc = cwcValueNameLenMax + 1;
  334. cbValue = cbValueLenMax;
  335. if (!RegEnumValue(
  336. hKey,
  337. i,
  338. pwszValueName,
  339. &cwc,
  340. NULL,
  341. &dwType,
  342. pbValue,
  343. &cbValue))
  344. {
  345. hr = myHLastError();
  346. _JumpIfError(hr, error, "VirtualAlloc");
  347. }
  348. ParamId = myWtoI(pwszValueName, &fValid);
  349. if (!fValid)
  350. {
  351. hr = E_INVALIDARG;
  352. _JumpErrorStr(hr, error, "fValid", pwszValueName);
  353. }
  354. lParam = 0;
  355. if (NULL != pszValue)
  356. {
  357. LocalFree(pszValue);
  358. pszValue = NULL;
  359. }
  360. switch (dwType)
  361. {
  362. case REG_DWORD:
  363. if (sizeof(lParam) != cbValue)
  364. {
  365. hr = E_INVALIDARG;
  366. _JumpErrorStr(hr, error, "cbValue", pwszValueName);
  367. }
  368. lParam = *(LONG *) pbValue;
  369. break;
  370. case REG_SZ:
  371. ZeroMemory(&pbValue[cbValue], CBPAD);
  372. if (!ConvertWszToSz(&pszValue, (WCHAR const *) pbValue, -1))
  373. {
  374. _JumpError(hr, error, "ConvertWszToSz");
  375. }
  376. break;
  377. default:
  378. hr = E_INVALIDARG;
  379. _JumpErrorStr(hr, error, "dwType", pwszValueName);
  380. }
  381. CONSOLEPRINT3((
  382. DBG_SS_CERTDB,
  383. "JetSetSystemParameter(%u, %u, %hs)\n",
  384. ParamId,
  385. lParam,
  386. pszValue));
  387. _dbgJetSetSystemParameter(
  388. pInstance,
  389. 0,
  390. ParamId,
  391. lParam,
  392. pszValue);
  393. }
  394. }
  395. hr = S_OK;
  396. error:
  397. if (NULL != hKey)
  398. {
  399. RegCloseKey(hKey);
  400. }
  401. if (NULL != pwszPath)
  402. {
  403. LocalFree(pwszPath);
  404. }
  405. if (NULL != pszValue)
  406. {
  407. LocalFree(pszValue);
  408. }
  409. if (NULL != pwszValueName)
  410. {
  411. LocalFree(pwszValueName);
  412. }
  413. if (NULL != pbValue)
  414. {
  415. LocalFree(pbValue);
  416. }
  417. return(hr);
  418. }
  419. #if DBG_CERTSRV
  420. WCHAR const *
  421. wszCSFFlags(
  422. IN LONG Flags)
  423. {
  424. static WCHAR s_awc[256];
  425. wsprintf(s_awc, L"{%x", Flags);
  426. if (CSF_INUSE & Flags) dbgcat(s_awc, L"InUse");
  427. if (CSF_READONLY & Flags) dbgcat(s_awc, L"ReadOnly");
  428. if (CSF_CREATE & Flags) dbgcat(s_awc, L"Create");
  429. if (CSF_VIEW & Flags) dbgcat(s_awc, L"View");
  430. if (CSF_VIEWRESET & Flags) dbgcat(s_awc, L"ViewReset");
  431. wcscat(s_awc, L"}");
  432. CSASSERT(wcslen(s_awc) < ARRAYSIZE(s_awc));
  433. return(s_awc);
  434. }
  435. WCHAR const *
  436. wszCSTFlags(
  437. IN LONG Flags)
  438. {
  439. static WCHAR s_awc[256];
  440. wsprintf(s_awc, L"{%x", Flags);
  441. if (CST_SEEKINDEXRANGE & Flags) dbgcat(s_awc, L"IndexRange");
  442. if (CST_SEEKNOTMOVE & Flags) dbgcat(s_awc, L"SeekNotMove");
  443. if (CST_SEEKUSECURRENT & Flags) dbgcat(s_awc, L"UseCurrent");
  444. if (0 == (CST_SEEKUSECURRENT & Flags)) dbgcat(s_awc, L"SkipCurrent");
  445. if (CST_SEEKASCEND & Flags) dbgcat(s_awc, L"Ascend");
  446. if (0 == (CST_SEEKASCEND & Flags)) dbgcat(s_awc, L"Descend");
  447. wcscat(s_awc, L"}");
  448. CSASSERT(wcslen(s_awc) < ARRAYSIZE(s_awc));
  449. return(s_awc);
  450. }
  451. WCHAR const *
  452. wszTable(
  453. IN DWORD dwTable)
  454. {
  455. WCHAR const *pwsz;
  456. switch (dwTable)
  457. {
  458. case TABLE_REQUESTS:
  459. pwsz = wszREQUESTTABLE;
  460. break;
  461. case TABLE_CERTIFICATES:
  462. pwsz = wszCERTIFICATETABLE;
  463. break;
  464. case TABLE_ATTRIBUTES:
  465. pwsz = wszREQUESTATTRIBUTETABLE;
  466. break;
  467. case TABLE_EXTENSIONS:
  468. pwsz = wszCERTIFICATEEXTENSIONTABLE;
  469. break;
  470. case TABLE_CRLS:
  471. pwsz = wszCRLTABLE;
  472. break;
  473. default:
  474. pwsz = L"???";
  475. break;
  476. }
  477. return(pwsz);
  478. }
  479. WCHAR const *
  480. wszSeekOperator(
  481. IN LONG SeekOperator)
  482. {
  483. WCHAR const *pwsz;
  484. static WCHAR s_wszBuf[10 + cwcDWORDSPRINTF];
  485. switch (CVR_SEEK_MASK & SeekOperator)
  486. {
  487. case CVR_SEEK_NONE: pwsz = L"None"; break;
  488. case CVR_SEEK_EQ: pwsz = L"=="; break;
  489. case CVR_SEEK_LT: pwsz = L"<"; break;
  490. case CVR_SEEK_LE: pwsz = L"<="; break;
  491. case CVR_SEEK_GE: pwsz = L">="; break;
  492. case CVR_SEEK_GT: pwsz = L">"; break;
  493. default:
  494. wsprintf(s_wszBuf, L"???=%x", SeekOperator);
  495. pwsz = s_wszBuf;
  496. break;
  497. }
  498. if (s_wszBuf != pwsz && (CVR_SEEK_NODELTA & SeekOperator))
  499. {
  500. wcscpy(s_wszBuf, pwsz);
  501. wcscat(s_wszBuf, L",NoDelta");
  502. pwsz = s_wszBuf;
  503. }
  504. return(pwsz);
  505. }
  506. WCHAR const *
  507. wszSortOperator(
  508. IN LONG SortOrder)
  509. {
  510. WCHAR const *pwsz;
  511. static WCHAR s_wszBuf[10 + cwcDWORDSPRINTF];
  512. switch (SortOrder)
  513. {
  514. case CVR_SORT_NONE: pwsz = L"None"; break;
  515. case CVR_SORT_ASCEND: pwsz = L"Ascend"; break;
  516. case CVR_SORT_DESCEND: pwsz = L"Descend"; break;
  517. default:
  518. wsprintf(s_wszBuf, L"???=%x", SortOrder);
  519. pwsz = s_wszBuf;
  520. break;
  521. }
  522. return(pwsz);
  523. }
  524. VOID
  525. dbDumpFileTime(
  526. IN DWORD dwSubSystemId,
  527. IN CHAR const *pszPrefix,
  528. IN FILETIME const *pft)
  529. {
  530. HRESULT hr;
  531. WCHAR *pwsz;
  532. hr = myGMTFileTimeToWszLocalTime(pft, TRUE, &pwsz);
  533. if (S_OK == hr)
  534. {
  535. DBGPRINT((dwSubSystemId, "%hs%ws\n", pszPrefix, pwsz));
  536. LocalFree(pwsz);
  537. }
  538. }
  539. VOID
  540. dbDumpValue(
  541. IN DWORD dwSubSystemId,
  542. OPTIONAL IN DBTABLE const *pdt,
  543. IN BYTE const *pbValue,
  544. IN DWORD cbValue)
  545. {
  546. if (NULL != pdt && NULL != pbValue && ISTEXTCOLTYP(pdt->dbcoltyp))
  547. {
  548. cbValue += sizeof(WCHAR);
  549. }
  550. if (JET_coltypDateTime == pdt->dbcoltyp && sizeof(FILETIME) == cbValue)
  551. {
  552. dbDumpFileTime(dwSubSystemId, "", (FILETIME const *) pbValue);
  553. }
  554. DBGDUMPHEX((dwSubSystemId, DH_NOADDRESS, pbValue, cbValue));
  555. }
  556. VOID
  557. CCertDB::DumpRestriction(
  558. IN DWORD dwSubSystemId,
  559. IN LONG i,
  560. IN CERTVIEWRESTRICTION const *pcvr)
  561. {
  562. HRESULT hr;
  563. WCHAR wszColumn[5 + cwcDWORDSPRINTF];
  564. DBTABLE const *pdt;
  565. WCHAR const *pwszTable = L"???";
  566. WCHAR const *pwszCol;
  567. hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
  568. if (S_OK != hr)
  569. {
  570. _PrintError(hr, "_MapPropIdIndex");
  571. wsprintf(wszColumn, L"???=%x", pcvr->ColumnIndex);
  572. pdt = NULL;
  573. pwszCol = wszColumn;
  574. }
  575. else
  576. {
  577. pwszCol = pdt->pwszPropName;
  578. pwszTable = wszTable(pdt->dwTable);
  579. }
  580. DBGPRINT((
  581. dwSubSystemId,
  582. "Restriction[%d]: Col=%ws.%ws\n"
  583. " Seek='%ws' Sort=%ws cb=%x, pb=%x\n",
  584. i,
  585. pwszTable,
  586. pwszCol,
  587. wszSeekOperator(pcvr->SeekOperator),
  588. wszSortOperator(pcvr->SortOrder),
  589. pcvr->cbValue,
  590. pcvr->pbValue));
  591. dbDumpValue(dwSubSystemId, pdt, pcvr->pbValue, pcvr->cbValue);
  592. }
  593. VOID
  594. dbDumpColumn(
  595. IN DWORD dwSubSystemId,
  596. IN DBTABLE const *pdt,
  597. IN BYTE const *pbValue,
  598. IN DWORD cbValue)
  599. {
  600. DBGPRINT((dwSubSystemId, "Column: cb=%x pb=%x\n", cbValue, pbValue));
  601. dbDumpValue(dwSubSystemId, pdt, pbValue, cbValue);
  602. }
  603. DBAUXDATA const *
  604. dbGetAuxTable(
  605. IN CERTSESSION *pcs,
  606. IN JET_TABLEID tableid)
  607. {
  608. DBAUXDATA const *pdbaux;
  609. CSASSERT(IsValidJetTableId(tableid));
  610. if (tableid == pcs->aTable[CSTI_CERTIFICATE].TableId)
  611. {
  612. pdbaux = &g_dbauxCertificates;
  613. }
  614. else if (tableid == pcs->aTable[CSTI_ATTRIBUTE].TableId)
  615. {
  616. pdbaux = &g_dbauxAttributes;
  617. }
  618. else if (tableid == pcs->aTable[CSTI_EXTENSION].TableId)
  619. {
  620. pdbaux = &g_dbauxExtensions;
  621. }
  622. else
  623. {
  624. CSASSERT(tableid == pcs->aTable[CSTI_PRIMARY].TableId);
  625. pdbaux = &g_dbauxRequests;
  626. switch (CSF_TABLEMASK & pcs->SesFlags)
  627. {
  628. case TABLE_CERTIFICATES:
  629. pdbaux = &g_dbauxCertificates;
  630. break;
  631. case TABLE_ATTRIBUTES:
  632. pdbaux = &g_dbauxAttributes;
  633. break;
  634. case TABLE_EXTENSIONS:
  635. pdbaux = &g_dbauxExtensions;
  636. break;
  637. case TABLE_CRLS:
  638. pdbaux = &g_dbauxCRLs;
  639. break;
  640. }
  641. }
  642. return(pdbaux);
  643. }
  644. HRESULT
  645. CCertDB::_DumpRowId(
  646. IN CHAR const *psz,
  647. IN CERTSESSION *pcs,
  648. IN JET_TABLEID tableid)
  649. {
  650. HRESULT hr;
  651. #define DBG_SS_DUMPREQUESTID DBG_SS_CERTDBI
  652. if (!IsValidJetTableId(tableid))
  653. {
  654. hr = E_HANDLE;
  655. _JumpError(hr, error, "tableid");
  656. }
  657. if (DbgIsSSActive(DBG_SS_DUMPREQUESTID))
  658. {
  659. DWORD cb;
  660. DWORD dwTmp;
  661. DBAUXDATA const *pdbaux = dbGetAuxTable(pcs, tableid);
  662. WCHAR awchr[cwcHRESULTSTRING];
  663. cb = sizeof(dwTmp);
  664. hr = _RetrieveColumn(
  665. pcs,
  666. tableid,
  667. pdbaux->pdtRowId,
  668. pdbaux->pdtRowId->dbcolumnid,
  669. NULL,
  670. &cb,
  671. (BYTE *) &dwTmp);
  672. if (S_OK != hr)
  673. {
  674. DBGPRINT((
  675. DBG_SS_DUMPREQUESTID,
  676. "%hs: %hs.RowId: pcs=%d: %ws\n",
  677. psz,
  678. pdbaux->pszTable,
  679. pcs->RowId,
  680. myHResultToString(awchr, hr)));
  681. _JumpError2(hr, error, "_RetrieveColumn", hr);
  682. }
  683. DBGPRINT((
  684. DBG_SS_DUMPREQUESTID,
  685. "%hs: %hs.RowId: pcs=%d dbcol=%d\n",
  686. psz,
  687. pdbaux->pszTable,
  688. pcs->RowId,
  689. dwTmp));
  690. }
  691. hr = S_OK;
  692. error:
  693. return(hr);
  694. }
  695. HRESULT
  696. CCertDB::_DumpColumn(
  697. IN CHAR const *psz,
  698. IN CERTSESSION *pcs,
  699. IN JET_TABLEID tableid,
  700. IN DBTABLE const *pdt,
  701. OPTIONAL IN ICertDBComputedColumn *pIComputedColumn)
  702. {
  703. HRESULT hr;
  704. BYTE rgbFastBuf[CB_PROPFASTBUF];
  705. DWORD cb;
  706. BYTE *pb = rgbFastBuf;
  707. if (!IsValidJetTableId(tableid))
  708. {
  709. hr = E_HANDLE;
  710. _JumpError(hr, error, "tableid");
  711. }
  712. CSASSERT(0 != pdt->dbcolumnid);
  713. if (DbgIsSSActive(DBG_SS_CERTDBI))
  714. {
  715. DBAUXDATA const *pdbaux = dbGetAuxTable(pcs, tableid);
  716. BOOL fIsText;
  717. cb = sizeof(rgbFastBuf);
  718. hr = _RetrieveColumn(
  719. pcs,
  720. tableid,
  721. pdt,
  722. pdt->dbcolumnid,
  723. pIComputedColumn,
  724. &cb,
  725. pb);
  726. if (S_OK != hr)
  727. {
  728. if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
  729. {
  730. _JumpError(hr, error, "_RetrieveColumn");
  731. }
  732. CSASSERT(sizeof(rgbFastBuf) < cb);
  733. pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
  734. if (NULL == pb)
  735. {
  736. hr = E_OUTOFMEMORY;
  737. _JumpError(hr, error, "LocalAlloc");
  738. }
  739. hr = _RetrieveColumn(
  740. pcs,
  741. tableid,
  742. pdt,
  743. pdt->dbcolumnid,
  744. pIComputedColumn,
  745. &cb,
  746. pb);
  747. _JumpIfError(hr, error, "_RetrieveColumn");
  748. }
  749. fIsText = ISTEXTCOLTYP(pdt->dbcoltyp);
  750. DBGPRINT((
  751. DBG_SS_CERTDBI,
  752. "%hs: _DumpColumn(%hs, %hs): Value:%hs%ws%hs\n",
  753. psz,
  754. pdbaux->pszTable,
  755. pdt->pszFieldName,
  756. fIsText? " '" : "",
  757. fIsText? (WCHAR *) pb : L"",
  758. fIsText? "'" : ""));
  759. dbDumpValue(DBG_SS_CERTDBI, pdt, pb, cb);
  760. }
  761. hr = S_OK;
  762. error:
  763. if (NULL != pb && rgbFastBuf != pb)
  764. {
  765. LocalFree(pb);
  766. }
  767. return(hr);
  768. }
  769. #endif // DBG_CERTSRV
  770. CCertDB::CCertDB()
  771. {
  772. HRESULT hr;
  773. InterlockedIncrement(&g_cCertDB);
  774. InterlockedIncrement(&g_cCertDBTotal);
  775. m_Instance = 0;
  776. m_fDBOpen = FALSE;
  777. m_fDBRestart = FALSE;
  778. m_fPendingShutDown = FALSE;
  779. m_fFoundOldColumns = FALSE;
  780. m_fAddedNewColumns = FALSE;
  781. m_aSession = NULL;
  782. m_cSession = 0;
  783. m_cbPage = 0;
  784. m_cCritSec = 0;
  785. __try
  786. {
  787. InitializeCriticalSection(&m_critsecSession);
  788. m_cCritSec++;
  789. InitializeCriticalSection(&m_critsecAutoIncTables);
  790. m_cCritSec++;
  791. }
  792. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  793. {
  794. }
  795. }
  796. CCertDB::~CCertDB()
  797. {
  798. ShutDown(0);
  799. if (0 < m_cCritSec)
  800. {
  801. DeleteCriticalSection(&m_critsecSession);
  802. if (1 < m_cCritSec)
  803. {
  804. DeleteCriticalSection(&m_critsecAutoIncTables);
  805. }
  806. }
  807. InterlockedDecrement(&g_cCertDB);
  808. }
  809. STDMETHODIMP
  810. CCertDB::Open(
  811. /* [in] */ DWORD DBFlags,
  812. /* [in] */ DWORD cSession,
  813. /* [in] */ WCHAR const *pwszEventSource,
  814. /* [in] */ WCHAR const *pwszDBFile,
  815. /* [in] */ WCHAR const *pwszLogDir,
  816. /* [in] */ WCHAR const *pwszSystemDir,
  817. /* [in] */ WCHAR const *pwszTempDir)
  818. {
  819. HRESULT hr;
  820. DWORD i;
  821. DBCREATETABLE const *pct;
  822. JET_GRBIT grbit;
  823. DWORD CreateFlags;
  824. CERTSESSION *pcs = NULL;
  825. if (NULL == pwszDBFile ||
  826. NULL == pwszLogDir ||
  827. NULL == pwszSystemDir ||
  828. NULL == pwszTempDir)
  829. {
  830. hr = E_POINTER;
  831. _JumpError(hr, error, "NULL parm");
  832. }
  833. if (0 == (DBFLAGS_DISABLESNAPSHOTBACKUP & DBFlags))
  834. {
  835. hr = InitGlobalWriterState();
  836. _JumpIfError(hr, error, "InitGlobalWriterState");
  837. }
  838. m_fDBOpen = FALSE;
  839. m_fDBRestart = FALSE;
  840. m_fDBReadOnly = (DBFLAGS_READONLY & DBFlags)? TRUE : FALSE;
  841. CSASSERT(NULL == m_aSession); // code assumes we do not have session
  842. m_cSession = 0;
  843. m_aSession = (CERTSESSION *) LocalAlloc(
  844. LMEM_FIXED | LMEM_ZEROINIT,
  845. cSession * sizeof(m_aSession[0]));
  846. hr = E_OUTOFMEMORY;
  847. if (NULL == m_aSession)
  848. {
  849. _JumpError(hr, error, "LocalAlloc(m_aSession)");
  850. }
  851. for (i = 0; i < cSession; i++)
  852. {
  853. m_aSession[i].SesId = MAXDWORD;
  854. m_aSession[i].DBId = MAXDWORD;
  855. }
  856. if (!ConvertWszToSz(&g_pszDBFile, pwszDBFile, -1))
  857. {
  858. _JumpError(hr, error, "ConvertWszToSz(DBFile)");
  859. }
  860. hr = DBInitParms(
  861. cSession,
  862. DBFlags,
  863. pwszEventSource,
  864. pwszLogDir,
  865. pwszSystemDir,
  866. pwszTempDir,
  867. &m_Instance);
  868. _JumpIfError(hr, error, "DBInitParms");
  869. hr = _dbgJetInit(&m_Instance);
  870. if ((HRESULT) JET_errLogFileSizeMismatchDatabasesConsistent == hr ||
  871. (HRESULT) JET_errLogFileSizeMismatch == hr)
  872. {
  873. _PrintError(hr, "JetInit(old log file size)");
  874. _dbgJetSetSystemParameter(
  875. &m_Instance,
  876. 0,
  877. JET_paramLogFileSize,
  878. 1000,
  879. NULL);
  880. hr = _dbgJetInit(&m_Instance);
  881. }
  882. _JumpIfError(
  883. hr,
  884. error,
  885. (HRESULT) JET_errFileAccessDenied == hr?
  886. "JetInit(Server already running?)" :
  887. "JetInit(JetSetSystemParameter problem?)");
  888. for (i = 0; i < cSession; i++)
  889. {
  890. hr = _dbgJetBeginSession(m_Instance, &m_aSession[i].SesId, NULL, NULL);
  891. _JumpIfError(hr, error, "_dbgJetBeginSession");
  892. m_cSession++;
  893. if (0 == i)
  894. {
  895. CreateFlags = 0;
  896. grbit = m_fDBReadOnly?
  897. JET_bitDbReadOnly : JET_bitDbDeleteCorruptIndexes;
  898. hr = _dbgJetAttachDatabase(
  899. m_aSession[i].SesId,
  900. g_pszDBFile,
  901. grbit);
  902. if ((HRESULT) JET_errFileNotFound == hr &&
  903. (DBFLAGS_CREATEIFNEEDED & DBFlags))
  904. {
  905. DBGPRINT((DBG_SS_CERTDB, "Creating Database\n"));
  906. CreateFlags |= CF_DATABASE;
  907. }
  908. else
  909. if ((HRESULT) JET_wrnCorruptIndexDeleted == hr)
  910. {
  911. // Rebuild deleted indexes over Unicode columns...
  912. DBGPRINT((DBG_SS_CERTDB, "Creating Database Indexes\n"));
  913. CreateFlags |= CF_MISSINGINDEXES;
  914. }
  915. else
  916. if ((HRESULT) JET_wrnDatabaseAttached != hr)
  917. {
  918. _JumpIfError(hr, error, "JetAttachDatabase");
  919. }
  920. if (m_fDBReadOnly)
  921. {
  922. if (CreateFlags)
  923. {
  924. hr = E_ACCESSDENIED;
  925. _JumpError(hr, error, "ReadOnly");
  926. }
  927. }
  928. else
  929. {
  930. CreateFlags |= CF_MISSINGTABLES | CF_MISSINGCOLUMNS;
  931. hr = _Create(CreateFlags, g_pszDBFile);
  932. _JumpIfError(hr, error, "_Create");
  933. }
  934. }
  935. hr = _dbgJetOpenDatabase(
  936. m_aSession[i].SesId,
  937. g_pszDBFile,
  938. NULL,
  939. &m_aSession[i].DBId,
  940. 0);
  941. _JumpIfError(hr, error, "JetOpenDatabase");
  942. }
  943. hr = _AllocateSession(&pcs);
  944. _JumpIfError(hr, error, "_AllocateSession");
  945. for (pct = g_actDataBase; NULL != pct->pszTableName; pct++)
  946. {
  947. hr = _BuildColumnIds(pcs, pct->pszTableName, pct->pdt);
  948. _JumpIfError(hr, error, "_BuildColumnIds");
  949. }
  950. if (!m_fDBReadOnly)
  951. {
  952. for (pct = g_actDataBase; NULL != pct->pszTableName; pct++)
  953. {
  954. hr = _ConvertOldColumnData(
  955. pcs,
  956. pct->pszTableName,
  957. pct->pdbaux,
  958. pct->pdt);
  959. _JumpIfError(hr, error, "_ConvertOldColumnData");
  960. }
  961. }
  962. m_fDBOpen = TRUE;
  963. error:
  964. if (NULL != pcs)
  965. {
  966. ReleaseSession(pcs);
  967. }
  968. hr = myJetHResult(hr);
  969. if (S_OK == hr && m_fDBRestart)
  970. {
  971. hr = S_FALSE; // Restart required for DB changes to take effect.
  972. _PrintError(hr, "m_fDBRestart");
  973. }
  974. return(hr);
  975. }
  976. STDMETHODIMP
  977. CCertDB::ShutDown(
  978. /* [in] */ DWORD dwFlags)
  979. {
  980. HRESULT hr;
  981. // Fix Jet failure after upgrade. When starting certsrv calls Open twice,
  982. // first to trigger the db upgrade, then the real open. m_fFoundOldColumns
  983. // doesn't get cleared so the second open attempts another upgrade and fails.
  984. m_fFoundOldColumns = FALSE;
  985. if (CDBSHUTDOWN_PENDING == dwFlags)
  986. {
  987. m_fPendingShutDown = TRUE;
  988. hr = _dbgJetStopService(); // fail all future Jet calls
  989. _PrintIfError(hr, "JetStopService");
  990. }
  991. else
  992. {
  993. hr = S_OK;
  994. if (NULL != m_aSession)
  995. {
  996. DBGPRINT((DBG_SS_CERTDB, "Database shutdown...\n"));
  997. #if 0 // Avoid useless thread context asserts
  998. DWORD i;
  999. for (i = 0; i < m_cSession; i++)
  1000. {
  1001. hr = _dbgJetEndSession(
  1002. m_aSession[i].SesId,
  1003. JET_bitForceSessionClosed);
  1004. _PrintIfError(hr, "JetEndSession");
  1005. }
  1006. #endif
  1007. hr = _dbgJetTerm2(m_Instance, JET_bitTermComplete);
  1008. if (S_OK != hr)
  1009. {
  1010. _PrintError(hr, "JetTerm2");
  1011. hr = _dbgJetTerm2(m_Instance, JET_bitTermAbrupt);
  1012. _PrintIfError(hr, "JetTerm2(Abrupt)");
  1013. }
  1014. DBGPRINT((DBG_SS_CERTDB, "Database shutdown complete\n"));
  1015. LocalFree(m_aSession);
  1016. m_aSession = NULL;
  1017. }
  1018. if (NULL != g_pszDBFile)
  1019. {
  1020. LocalFree(g_pszDBFile);
  1021. g_pszDBFile = NULL;
  1022. }
  1023. DBFreeParms();
  1024. UnInitGlobalWriterState();
  1025. }
  1026. //error:
  1027. return(myJetHResult(hr));
  1028. }
  1029. HRESULT
  1030. CCertDB::BeginTransaction(
  1031. IN CERTSESSION *pcs,
  1032. IN BOOL fPrepareUpdate)
  1033. {
  1034. HRESULT hr;
  1035. BOOL fTransacted = FALSE;
  1036. DWORD i;
  1037. if (NULL == pcs)
  1038. {
  1039. hr = E_POINTER;
  1040. _JumpError(hr, error, "NULL parm");
  1041. }
  1042. if (0 != pcs->cTransact)
  1043. {
  1044. hr = E_UNEXPECTED;
  1045. _JumpError(hr, error, "Nested transaction");
  1046. }
  1047. CSASSERTTHREAD(pcs);
  1048. hr = _dbgJetBeginTransaction(pcs->SesId);
  1049. _JumpIfError(hr, error, "JetBeginTransaction");
  1050. fTransacted = TRUE;
  1051. if (fPrepareUpdate)
  1052. {
  1053. CSASSERTTHREAD(pcs);
  1054. for (i = 0; i < CSTI_MAX; i++)
  1055. {
  1056. if (IsValidJetTableId(pcs->aTable[i].TableId))
  1057. {
  1058. hr = _dbgJetPrepareUpdate(
  1059. pcs->SesId,
  1060. pcs->aTable[i].TableId,
  1061. JET_prepReplace);
  1062. _JumpIfError(hr, error, "JetPrepareUpdate");
  1063. }
  1064. }
  1065. }
  1066. pcs->cTransact++;
  1067. InterlockedIncrement(&g_cXactTotal);
  1068. hr = S_OK;
  1069. error:
  1070. if (S_OK != hr && fTransacted)
  1071. {
  1072. HRESULT hr2;
  1073. CSASSERTTHREAD(pcs);
  1074. hr2 = _Rollback(pcs);
  1075. _PrintIfError(hr2, "_Rollback");
  1076. }
  1077. return(myJetHResult(hr));
  1078. }
  1079. HRESULT
  1080. CCertDB::CommitTransaction(
  1081. IN CERTSESSION *pcs,
  1082. IN BOOL fCommit,
  1083. IN BOOL fLazyFlush)
  1084. {
  1085. HRESULT hr;
  1086. DWORD i;
  1087. if (NULL == pcs)
  1088. {
  1089. hr = E_POINTER;
  1090. _JumpError(hr, error, "NULL parm");
  1091. }
  1092. CSASSERT(0 != pcs->cTransact);
  1093. if (fCommit)
  1094. {
  1095. if (0 == (CSF_DELETE & pcs->SesFlags))
  1096. {
  1097. for (i = 0; i < CSTI_MAXDIRECT; i++)
  1098. {
  1099. if (IsValidJetTableId(pcs->aTable[i].TableId))
  1100. {
  1101. hr = _UpdateTable(pcs, pcs->aTable[i].TableId);
  1102. _JumpIfError(hr, error, "_UpdateTable");
  1103. }
  1104. }
  1105. }
  1106. CSASSERTTHREAD(pcs);
  1107. hr = _dbgJetCommitTransaction(pcs->SesId, fLazyFlush?JET_bitCommitLazyFlush:0);
  1108. _JumpIfError(hr, error, "JetCommitTransaction");
  1109. }
  1110. else
  1111. {
  1112. hr = _Rollback(pcs);
  1113. _JumpIfError(hr, error, "_Rollback");
  1114. }
  1115. pcs->cTransact--;
  1116. if (fCommit)
  1117. {
  1118. InterlockedIncrement(&g_cXactCommit);
  1119. }
  1120. else
  1121. {
  1122. InterlockedIncrement(&g_cXactAbort);
  1123. }
  1124. error:
  1125. return(myJetHResult(hr));
  1126. }
  1127. HRESULT
  1128. CCertDB::_AllocateSession(
  1129. OUT CERTSESSION **ppcs)
  1130. {
  1131. HRESULT hr;
  1132. DWORD i;
  1133. BOOL fEnterCritSec = FALSE;
  1134. CSASSERT(NULL != ppcs);
  1135. *ppcs = NULL;
  1136. if (0 == m_cCritSec)
  1137. {
  1138. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  1139. _JumpError(hr, error, "InitializeCriticalSection failure");
  1140. }
  1141. EnterCriticalSection(&m_critsecSession);
  1142. fEnterCritSec = TRUE;
  1143. for (i = 0; 0 != m_aSession[i].SesFlags; i++)
  1144. {
  1145. if (i + 1 == m_cSession)
  1146. {
  1147. hr = CERTSRV_E_NO_DB_SESSIONS;
  1148. _JumpIfError(hr, error, "no more sessions");
  1149. }
  1150. }
  1151. *ppcs = &m_aSession[i];
  1152. CSASSERT(0 == (*ppcs)->RowId);
  1153. (*ppcs)->SesFlags = CSF_INUSE;
  1154. (*ppcs)->dwThreadId = GetCurrentThreadId();
  1155. ZeroMemory((*ppcs)->aTable, sizeof((*ppcs)->aTable));
  1156. hr = S_OK;
  1157. error:
  1158. if (fEnterCritSec)
  1159. {
  1160. LeaveCriticalSection(&m_critsecSession);
  1161. }
  1162. return(hr);
  1163. }
  1164. HRESULT
  1165. CCertDB::_OpenTableRow(
  1166. IN CERTSESSION *pcs,
  1167. IN DBAUXDATA const *pdbaux,
  1168. OPTIONAL IN CERTVIEWRESTRICTION const *pcvr,
  1169. OUT CERTSESSIONTABLE *pTable,
  1170. OUT DWORD *pdwRowIdMismatch)
  1171. {
  1172. HRESULT hr;
  1173. DWORD dwRowId;
  1174. DWORD cb;
  1175. CSASSERT(NULL == pTable->TableId);
  1176. CSASSERT(0 == pTable->TableFlags);
  1177. *pdwRowIdMismatch = 0;
  1178. if (CSF_CREATE & pcs->SesFlags)
  1179. {
  1180. CSASSERT(NULL == pcvr);
  1181. CSASSERTTHREAD(pcs);
  1182. hr = _dbgJetOpenTable(
  1183. pcs->SesId,
  1184. pcs->DBId,
  1185. pdbaux->pszTable,
  1186. NULL,
  1187. 0,
  1188. 0,
  1189. &pTable->TableId);
  1190. _JumpIfError(hr, error, "JetOpenTable");
  1191. }
  1192. else
  1193. {
  1194. if (NULL == pcvr)
  1195. {
  1196. hr = E_POINTER;
  1197. _JumpError(hr, error, "NULL parm");
  1198. }
  1199. hr = _OpenTable(pcs, pdbaux, pcvr, pTable);
  1200. if (S_FALSE == hr)
  1201. {
  1202. hr = CERTSRV_E_PROPERTY_EMPTY;
  1203. }
  1204. _JumpIfError2(hr, error, "_OpenTable", CERTSRV_E_PROPERTY_EMPTY);
  1205. }
  1206. if (!((CSF_READONLY | CSF_DELETE) & pcs->SesFlags))
  1207. {
  1208. CSASSERTTHREAD(pcs);
  1209. hr = _dbgJetPrepareUpdate(
  1210. pcs->SesId,
  1211. pTable->TableId,
  1212. (CSF_CREATE & pcs->SesFlags)?
  1213. JET_prepInsert : JET_prepReplace);
  1214. _JumpIfError(hr, error, "JetPrepareUpdate");
  1215. }
  1216. // Requests table RequestId column is JET_bitColumnAutoincrement.
  1217. // Certificates table RequestId column is manually initialized here.
  1218. //
  1219. // When creating a Certificates table row, the RequestId column must be
  1220. // set from pcs->RowId, which must already have been set by first creating
  1221. // the Requests table row.
  1222. //
  1223. // When opening an existing row in either table, just fetch the column.
  1224. CSASSERTTHREAD(pcs);
  1225. hr = _dbgJetRetrieveColumn(
  1226. pcs->SesId,
  1227. pTable->TableId,
  1228. pdbaux->pdtRowId->dbcolumnid,
  1229. &dwRowId,
  1230. sizeof(dwRowId),
  1231. &cb,
  1232. JET_bitRetrieveCopy,
  1233. NULL);
  1234. if ((HRESULT) JET_wrnColumnNull == hr)
  1235. {
  1236. hr = CERTSRV_E_PROPERTY_EMPTY;
  1237. }
  1238. _PrintIfError2(hr, "JetRetrieveColumn", CERTSRV_E_PROPERTY_EMPTY);
  1239. if (S_OK != hr || 0 == dwRowId)
  1240. {
  1241. CSASSERT(CSF_CREATE & pcs->SesFlags);
  1242. if (0 == (CSF_CREATE & pcs->SesFlags))
  1243. {
  1244. if (S_OK == hr)
  1245. {
  1246. hr = CERTSRV_E_PROPERTY_EMPTY;
  1247. }
  1248. _JumpError(hr, error, "JetRetrieveColumn");
  1249. }
  1250. dwRowId = pcs->RowId;
  1251. hr = _dbgJetSetColumn(
  1252. pcs->SesId,
  1253. pTable->TableId,
  1254. pdbaux->pdtRowId->dbcolumnid,
  1255. &dwRowId,
  1256. sizeof(dwRowId),
  1257. 0,
  1258. NULL);
  1259. _JumpIfError(hr, error, "JetSetColumn");
  1260. }
  1261. else if (0 == pcs->RowId)
  1262. {
  1263. pcs->RowId = dwRowId;
  1264. }
  1265. DBGPRINT((
  1266. DBG_SS_CERTDBI,
  1267. "_OpenTableRow:%hs %hs --> RowId=%d(dwRowId(RetrieveColumn)=%d)\n",
  1268. (CSF_CREATE & pcs->SesFlags)? " (Create)" : "",
  1269. pdbaux->pszTable,
  1270. pcs->RowId,
  1271. dwRowId));
  1272. CSASSERT(0 != pcs->RowId);
  1273. if (pcs->RowId > dwRowId)
  1274. {
  1275. *pdwRowIdMismatch = dwRowId;
  1276. hr = CERTSRV_E_PROPERTY_EMPTY;
  1277. _JumpError(hr, error, "Missing autoincrement RowId");
  1278. }
  1279. CSASSERT(pcs->RowId == dwRowId);
  1280. error:
  1281. if (S_OK != hr)
  1282. {
  1283. if (IsValidJetTableId(pTable->TableId))
  1284. {
  1285. HRESULT hr2;
  1286. CSASSERTTHREAD(pcs);
  1287. hr2 = _dbgJetCloseTable(pcs->SesId, pTable->TableId);
  1288. _PrintIfError(hr2, "JetCloseTable");
  1289. }
  1290. ZeroMemory(pTable, sizeof(*pTable));
  1291. }
  1292. return(myJetHResult(hr));
  1293. }
  1294. HRESULT
  1295. CCertDB::OpenTables(
  1296. IN CERTSESSION *pcs,
  1297. OPTIONAL IN CERTVIEWRESTRICTION const *pcvr)
  1298. {
  1299. HRESULT hr;
  1300. BOOL fCertTableFirst = FALSE;
  1301. BOOL fCertTableLast = FALSE;
  1302. CERTVIEWRESTRICTION cvrRowId;
  1303. CERTVIEWRESTRICTION const *pcvrPrimary;
  1304. CERTVIEWRESTRICTION const *pcvrCertificates;
  1305. BOOL fEnterCritSec = FALSE;
  1306. DBAUXDATA const *pdbauxPrimary;
  1307. if (NULL == pcs)
  1308. {
  1309. hr = E_POINTER;
  1310. _JumpError(hr, error, "NULL parm");
  1311. }
  1312. pcvrPrimary = pcvr;
  1313. pcvrCertificates = NULL;
  1314. pdbauxPrimary = &g_dbauxRequests;
  1315. if (TABLE_REQCERTS == (CSF_TABLEMASK & pcs->SesFlags))
  1316. {
  1317. fCertTableLast = TRUE;
  1318. if (NULL != pcvr)
  1319. {
  1320. cvrRowId.SeekOperator = CVR_SEEK_EQ;
  1321. cvrRowId.SortOrder = CVR_SORT_ASCEND;
  1322. cvrRowId.pbValue = (BYTE *) &pcs->RowId;
  1323. cvrRowId.cbValue = sizeof(pcs->RowId);
  1324. switch (DTI_TABLEMASK & pcvr->ColumnIndex)
  1325. {
  1326. case DTI_REQUESTTABLE:
  1327. pcvrCertificates = &cvrRowId;
  1328. cvrRowId.ColumnIndex = DTI_CERTIFICATETABLE | DTC_REQUESTID;
  1329. break;
  1330. case DTI_CERTIFICATETABLE:
  1331. fCertTableLast = FALSE;
  1332. fCertTableFirst = TRUE;
  1333. pcvrCertificates = pcvr;
  1334. pcvrPrimary = &cvrRowId;
  1335. cvrRowId.ColumnIndex = DTI_REQUESTTABLE | DTR_REQUESTID;
  1336. break;
  1337. default:
  1338. hr = E_INVALIDARG;
  1339. _JumpError(hr, error, "ColumnIndex Table");
  1340. }
  1341. }
  1342. }
  1343. else
  1344. {
  1345. switch (CSF_TABLEMASK & pcs->SesFlags)
  1346. {
  1347. case TABLE_ATTRIBUTES:
  1348. pdbauxPrimary = &g_dbauxAttributes;
  1349. break;
  1350. case TABLE_EXTENSIONS:
  1351. pdbauxPrimary = &g_dbauxExtensions;
  1352. break;
  1353. case TABLE_CRLS:
  1354. pdbauxPrimary = &g_dbauxCRLs;
  1355. break;
  1356. default:
  1357. hr = E_INVALIDARG;
  1358. _JumpError(hr, error, "bad table");
  1359. }
  1360. }
  1361. if (1 >= m_cCritSec)
  1362. {
  1363. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  1364. _JumpError(hr, error, "InitializeCriticalSection failure");
  1365. }
  1366. EnterCriticalSection(&m_critsecAutoIncTables);
  1367. fEnterCritSec = TRUE;
  1368. hr = S_OK;
  1369. __try
  1370. {
  1371. DWORD dwRowIdMismatch;
  1372. if (fCertTableFirst)
  1373. {
  1374. hr = _OpenTableRow(
  1375. pcs,
  1376. &g_dbauxCertificates,
  1377. pcvrCertificates,
  1378. &pcs->aTable[CSTI_CERTIFICATE],
  1379. &dwRowIdMismatch);
  1380. _LeaveIfError2(hr, "_OpenTableRow", CERTSRV_E_PROPERTY_EMPTY);
  1381. CSASSERT(0 != pcs->RowId);
  1382. CSASSERT(IsValidJetTableId(pcs->aTable[CSTI_CERTIFICATE].TableId));
  1383. DBGPRINT((
  1384. DBG_SS_CERTDBI,
  1385. "OpenTables: %hs: %ws\n",
  1386. g_dbauxCertificates.pszTable,
  1387. wszCSTFlags(pcs->aTable[CSTI_CERTIFICATE].TableFlags)));
  1388. }
  1389. hr = _OpenTableRow(
  1390. pcs,
  1391. pdbauxPrimary,
  1392. pcvrPrimary,
  1393. &pcs->aTable[CSTI_PRIMARY],
  1394. &dwRowIdMismatch);
  1395. _LeaveIfError2(hr, "_OpenTableRow", CERTSRV_E_PROPERTY_EMPTY);
  1396. CSASSERT(0 != pcs->RowId);
  1397. CSASSERT(IsValidJetTableId(pcs->aTable[CSTI_PRIMARY].TableId));
  1398. DBGPRINT((
  1399. DBG_SS_CERTDBI,
  1400. "OpenTables: %hs: %ws\n",
  1401. g_dbauxRequests.pszTable,
  1402. wszCSTFlags(pcs->aTable[CSTI_PRIMARY].TableFlags)));
  1403. if (fCertTableLast)
  1404. {
  1405. while (TRUE)
  1406. {
  1407. hr = _OpenTableRow(
  1408. pcs,
  1409. &g_dbauxCertificates,
  1410. pcvrCertificates,
  1411. &pcs->aTable[CSTI_CERTIFICATE],
  1412. &dwRowIdMismatch);
  1413. _PrintIfError(hr, "_OpenTableRow");
  1414. if (S_OK == hr || 0 == dwRowIdMismatch)
  1415. {
  1416. break;
  1417. }
  1418. }
  1419. _PrintIfError(hr, "_OpenTableRow");
  1420. if (S_OK == hr)
  1421. {
  1422. CSASSERT(IsValidJetTableId(pcs->aTable[CSTI_CERTIFICATE].TableId));
  1423. DBGPRINT((
  1424. DBG_SS_CERTDBI,
  1425. "OpenTables: %hs: %ws\n",
  1426. g_dbauxCertificates.pszTable,
  1427. wszCSTFlags(pcs->aTable[CSTI_CERTIFICATE].TableFlags)));
  1428. }
  1429. hr = S_OK;
  1430. }
  1431. }
  1432. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  1433. {
  1434. }
  1435. error:
  1436. if (S_OK != hr)
  1437. {
  1438. __try
  1439. {
  1440. HRESULT hr2;
  1441. DWORD i;
  1442. for (i = 0; i < CSTI_MAX; i++)
  1443. {
  1444. if (NULL != pcs)
  1445. {
  1446. CSASSERTTHREAD(pcs);
  1447. if (IsValidJetTableId(pcs->aTable[i].TableId))
  1448. {
  1449. hr2 = _dbgJetCloseTable(
  1450. pcs->SesId,
  1451. pcs->aTable[i].TableId);
  1452. _PrintIfError(hr2, "JetCloseTable");
  1453. }
  1454. ZeroMemory(&pcs->aTable[i], sizeof(pcs->aTable[i]));
  1455. }
  1456. }
  1457. }
  1458. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  1459. {
  1460. }
  1461. }
  1462. if (fEnterCritSec)
  1463. {
  1464. LeaveCriticalSection(&m_critsecAutoIncTables);
  1465. }
  1466. return(myJetHResult(hr));
  1467. }
  1468. HRESULT
  1469. CCertDB::CloseTables(
  1470. IN CERTSESSION *pcs)
  1471. {
  1472. HRESULT hr = S_OK;
  1473. HRESULT hr2;
  1474. DWORD i;
  1475. if (NULL == pcs)
  1476. {
  1477. hr = E_POINTER;
  1478. _JumpError(hr, error, "NULL parm");
  1479. }
  1480. for (i = 0; i < CSTI_MAX; i++)
  1481. {
  1482. if (IsValidJetTableId(pcs->aTable[i].TableId))
  1483. {
  1484. hr2 = CloseTable(pcs, pcs->aTable[i].TableId);
  1485. _PrintIfError(hr2, "CloseTable");
  1486. if (S_OK == hr)
  1487. {
  1488. hr = hr2;
  1489. }
  1490. }
  1491. }
  1492. error:
  1493. return(myJetHResult(hr));
  1494. }
  1495. HRESULT
  1496. CCertDB::Delete(
  1497. IN CERTSESSION *pcs)
  1498. {
  1499. HRESULT hr = S_OK;
  1500. HRESULT hr2;
  1501. DWORD i;
  1502. if (NULL == pcs)
  1503. {
  1504. hr = E_POINTER;
  1505. _JumpError(hr, error, "NULL parm");
  1506. }
  1507. for (i = 0; i < CSTI_MAXDIRECT; i++)
  1508. {
  1509. if (IsValidJetTableId(pcs->aTable[i].TableId))
  1510. {
  1511. hr2 = _dbgJetDelete(pcs->SesId, pcs->aTable[i].TableId);
  1512. _PrintIfError(hr2, "JetDelete");
  1513. if (S_OK == hr)
  1514. {
  1515. hr = hr2;
  1516. }
  1517. }
  1518. }
  1519. error:
  1520. return(myJetHResult(hr));
  1521. }
  1522. HRESULT
  1523. CCertDB::_UpdateTable(
  1524. IN CERTSESSION *pcs,
  1525. IN JET_TABLEID tableid)
  1526. {
  1527. HRESULT hr;
  1528. CSASSERT(IsValidJetTableId(tableid));
  1529. CSASSERTTHREAD(pcs);
  1530. hr = _dbgJetUpdate(pcs->SesId, tableid, NULL, 0, NULL);
  1531. _JumpIfError(hr, error, "JetUpdate");
  1532. error:
  1533. return(myJetHResult(hr));
  1534. }
  1535. HRESULT
  1536. CCertDB::CloseTable(
  1537. IN CERTSESSION *pcs,
  1538. IN JET_TABLEID tableid)
  1539. {
  1540. HRESULT hr;
  1541. if (NULL == pcs)
  1542. {
  1543. hr = E_POINTER;
  1544. _JumpError(hr, error, "NULL parm");
  1545. }
  1546. CSASSERT(IsValidJetTableId(tableid));
  1547. CSASSERTTHREAD(pcs);
  1548. hr = _dbgJetCloseTable(pcs->SesId, tableid);
  1549. _JumpIfError(hr, error, "JetCloseTable");
  1550. error:
  1551. return(myJetHResult(hr));
  1552. }
  1553. STDMETHODIMP
  1554. CCertDB::OpenRow(
  1555. /* [in] */ DWORD dwFlags,
  1556. /* [in] */ DWORD RowId,
  1557. /* [in] */ WCHAR const *pwszSerialNumberOrCertHash, // OPTIONAL
  1558. /* [out] */ ICertDBRow **pprow)
  1559. {
  1560. HRESULT hr;
  1561. ICertDBRow *prow = NULL;
  1562. DWORD SesFlags = 0;
  1563. CERTSESSION *pcs = NULL;
  1564. CERTVIEWRESTRICTION cvr;
  1565. CERTVIEWRESTRICTION *pcvr;
  1566. if (NULL == pprow)
  1567. {
  1568. hr = E_POINTER;
  1569. _JumpError(hr, error, "NULL parm");
  1570. }
  1571. *pprow = NULL;
  1572. switch (PROPTABLE_MASK & dwFlags)
  1573. {
  1574. case PROPTABLE_REQCERT:
  1575. SesFlags |= TABLE_REQCERTS;
  1576. cvr.ColumnIndex = DTI_REQUESTTABLE | DTC_REQUESTID;
  1577. break;
  1578. case PROPTABLE_ATTRIBUTE:
  1579. SesFlags |= TABLE_ATTRIBUTES;
  1580. cvr.ColumnIndex = DTI_ATTRIBUTETABLE | DTA_REQUESTID;
  1581. break;
  1582. case PROPTABLE_EXTENSION:
  1583. SesFlags |= TABLE_EXTENSIONS;
  1584. cvr.ColumnIndex = DTI_EXTENSIONTABLE | DTE_REQUESTID;
  1585. break;
  1586. case PROPTABLE_CRL:
  1587. SesFlags |= TABLE_CRLS;
  1588. cvr.ColumnIndex = DTI_CRLTABLE | DTL_ROWID;
  1589. break;
  1590. default:
  1591. hr = E_INVALIDARG;
  1592. _JumpError(hr, error, "bad table");
  1593. }
  1594. if ((PROPOPEN_CERTHASH & dwFlags) && NULL == pwszSerialNumberOrCertHash)
  1595. {
  1596. hr = E_INVALIDARG;
  1597. _JumpError(hr, error, "bad PROPOPEN_CERTHASH");
  1598. }
  1599. if (PROPTABLE_REQCERT != (PROPTABLE_MASK & dwFlags) &&
  1600. NULL != pwszSerialNumberOrCertHash)
  1601. {
  1602. hr = E_INVALIDARG;
  1603. _JumpError(hr, error, "bad pwszSerialNumberOrCertHash");
  1604. }
  1605. if ((PROPOPEN_READONLY | PROPOPEN_DELETE) ==
  1606. ((PROPOPEN_READONLY | PROPOPEN_DELETE) & dwFlags))
  1607. {
  1608. hr = E_INVALIDARG;
  1609. _JumpError(hr, error, "delete + read-only");
  1610. }
  1611. if (0 == RowId && NULL == pwszSerialNumberOrCertHash)
  1612. {
  1613. if ((PROPOPEN_READONLY | PROPOPEN_DELETE) & dwFlags)
  1614. {
  1615. hr = E_INVALIDARG;
  1616. _JumpError(hr, error, "OpenRow: create vs. delete or read-only");
  1617. }
  1618. SesFlags |= CSF_CREATE;
  1619. pcvr = NULL;
  1620. }
  1621. else
  1622. {
  1623. cvr.SeekOperator = CVR_SEEK_EQ;
  1624. cvr.SortOrder = CVR_SORT_ASCEND;
  1625. if (NULL != pwszSerialNumberOrCertHash)
  1626. {
  1627. cvr.ColumnIndex = (PROPOPEN_CERTHASH & dwFlags)?
  1628. (DTI_CERTIFICATETABLE | DTC_CERTIFICATEHASH) :
  1629. (DTI_CERTIFICATETABLE | DTC_CERTIFICATESERIALNUMBER);
  1630. cvr.cbValue = wcslen(pwszSerialNumberOrCertHash) * sizeof(WCHAR);
  1631. cvr.pbValue = (BYTE *) pwszSerialNumberOrCertHash;
  1632. }
  1633. else
  1634. {
  1635. cvr.cbValue = sizeof(RowId);
  1636. cvr.pbValue = (BYTE *) &RowId;
  1637. }
  1638. pcvr = &cvr;
  1639. }
  1640. if (PROPOPEN_READONLY & dwFlags)
  1641. {
  1642. SesFlags |= CSF_READONLY;
  1643. }
  1644. else
  1645. {
  1646. if (PROPOPEN_DELETE & dwFlags)
  1647. {
  1648. SesFlags |= CSF_DELETE;
  1649. }
  1650. if (m_fDBReadOnly)
  1651. {
  1652. hr = E_ACCESSDENIED;
  1653. _JumpError(hr, error, "OpenRow: read-only DB");
  1654. }
  1655. }
  1656. prow = new CCertDBRow;
  1657. if (NULL == prow)
  1658. {
  1659. hr = E_OUTOFMEMORY;
  1660. _JumpError(hr, error, "new CCertDBRow");
  1661. }
  1662. hr = _AllocateSession(&pcs);
  1663. _JumpIfError(hr, error, "_AllocateSession");
  1664. pcs->RowId = RowId;
  1665. pcs->SesFlags |= SesFlags;
  1666. pcs->prow = prow;
  1667. hr = ((CCertDBRow *) prow)->Open(pcs, this, pcvr);
  1668. _JumpIfError2(hr, error, "Open", CERTSRV_E_PROPERTY_EMPTY);
  1669. *pprow = prow;
  1670. prow = NULL;
  1671. pcs = NULL;
  1672. error:
  1673. if (NULL != prow)
  1674. {
  1675. prow->Release();
  1676. }
  1677. if (NULL != pcs)
  1678. {
  1679. ReleaseSession(pcs);
  1680. }
  1681. return(hr);
  1682. }
  1683. STDMETHODIMP
  1684. CCertDB::OpenView(
  1685. /* [in] */ DWORD ccvr,
  1686. /* [in] */ CERTVIEWRESTRICTION const *acvr,
  1687. /* [in] */ DWORD ccolOut,
  1688. /* [in] */ DWORD const *acolOut,
  1689. /* [in] */ DWORD const dwFlags,
  1690. /* [out] */ IEnumCERTDBRESULTROW **ppenum)
  1691. {
  1692. HRESULT hr;
  1693. IEnumCERTDBRESULTROW *penum = NULL;
  1694. CERTSESSION *pcs;
  1695. if ((NULL == acvr && 0 != ccvr) || NULL == acolOut || NULL == ppenum)
  1696. {
  1697. hr = E_POINTER;
  1698. _JumpError(hr, error, "NULL parm");
  1699. }
  1700. *ppenum = NULL;
  1701. penum = new CEnumCERTDBRESULTROW(0 != (CDBOPENVIEW_WORKERTHREAD & dwFlags));
  1702. if (NULL == penum)
  1703. {
  1704. hr = E_OUTOFMEMORY;
  1705. _JumpError(hr, error, "new CEnumCERTDBRESULTROW");
  1706. }
  1707. hr = _AllocateSession(&pcs);
  1708. _JumpIfError(hr, error, "_AllocateSession");
  1709. pcs->SesFlags |= CSF_READONLY | CSF_VIEW;
  1710. pcs->pview = penum;
  1711. hr = ((CEnumCERTDBRESULTROW *) penum)->Open(
  1712. pcs,
  1713. this,
  1714. ccvr,
  1715. acvr,
  1716. ccolOut,
  1717. acolOut);
  1718. _JumpIfError(hr, error, "Open");
  1719. *ppenum = penum;
  1720. penum = NULL;
  1721. error:
  1722. if (NULL != penum)
  1723. {
  1724. penum->Release();
  1725. }
  1726. return(hr);
  1727. }
  1728. HRESULT
  1729. CCertDB::OpenBackup(
  1730. /* [in] */ LONG grbitJet,
  1731. /* [out] */ ICertDBBackup **ppBackup)
  1732. {
  1733. HRESULT hr;
  1734. ICertDBBackup *pBackup = NULL;
  1735. CERTSESSION *pcs = NULL;
  1736. if (NULL == ppBackup)
  1737. {
  1738. hr = E_POINTER;
  1739. _JumpError(hr, error, "NULL parm");
  1740. }
  1741. *ppBackup = NULL;
  1742. pBackup = new CCertDBBackup;
  1743. if (NULL == pBackup)
  1744. {
  1745. hr = E_OUTOFMEMORY;
  1746. _JumpError(hr, error, "new CCertDBBackup");
  1747. }
  1748. hr = _AllocateSession(&pcs);
  1749. _JumpIfError(hr, error, "_AllocateSession");
  1750. hr = ((CCertDBBackup *) pBackup)->Open(grbitJet, pcs, this);
  1751. _JumpIfError(hr, error, "Open");
  1752. *ppBackup = pBackup;
  1753. pBackup = NULL;
  1754. pcs = NULL;
  1755. hr = S_OK;
  1756. error:
  1757. if (NULL != pBackup)
  1758. {
  1759. pBackup->Release();
  1760. }
  1761. if (NULL != pcs)
  1762. {
  1763. ReleaseSession(pcs);
  1764. }
  1765. return(hr);
  1766. }
  1767. HRESULT
  1768. CCertDB::ReleaseSession(
  1769. IN CERTSESSION *pcs)
  1770. {
  1771. HRESULT hr = S_OK;
  1772. HRESULT hr2;
  1773. if (NULL == pcs)
  1774. {
  1775. hr = E_POINTER;
  1776. _JumpError(hr, error, "NULL parm");
  1777. }
  1778. CSASSERT(CSF_INUSE & pcs->SesFlags);
  1779. while (0 != pcs->cTransact)
  1780. {
  1781. CSASSERTTHREAD(pcs);
  1782. hr2 = _dbgJetRollback(pcs->SesId, 0);
  1783. if (S_OK == hr)
  1784. {
  1785. hr = hr2;
  1786. }
  1787. _JumpIfError(hr2, loop, "JetRollback");
  1788. DBGPRINT((
  1789. (CSF_READONLY & pcs->SesFlags)? DBG_SS_CERTDBI : DBG_SS_CERTDB,
  1790. "ReleaseSession: Rollback transaction: %x\n",
  1791. pcs->cTransact));
  1792. loop:
  1793. CSASSERT(0 == pcs->cTransact);
  1794. pcs->cTransact--;
  1795. InterlockedIncrement(&g_cXactAbort);
  1796. }
  1797. //EnterCriticalSection(&m_critsecSession);
  1798. pcs->RowId = 0;
  1799. pcs->prow = NULL;
  1800. pcs->SesFlags = 0; // turn off CSF_INUSE -- must be LAST!
  1801. //LeaveCriticalSection(&m_critsecSession);
  1802. error:
  1803. return(myJetHResult(hr));
  1804. }
  1805. HRESULT
  1806. CCertDB::_Rollback(
  1807. IN CERTSESSION *pcs)
  1808. {
  1809. HRESULT hr = S_OK;
  1810. DWORD i;
  1811. if (NULL == pcs)
  1812. {
  1813. hr = E_POINTER;
  1814. _JumpError(hr, error, "NULL parm");
  1815. }
  1816. CSASSERT(CSF_INUSE & pcs->SesFlags);
  1817. for (i = 0; i < CSTI_MAX; i++)
  1818. {
  1819. pcs->aTable[i].TableId = 0;
  1820. }
  1821. CSASSERTTHREAD(pcs);
  1822. hr = _dbgJetRollback(pcs->SesId, 0);
  1823. _JumpIfError(hr, error, "JetRollback");
  1824. error:
  1825. return(myJetHResult(hr));
  1826. }
  1827. HRESULT
  1828. CCertDB::BackupBegin(
  1829. IN LONG grbitJet)
  1830. {
  1831. HRESULT hr;
  1832. hr = _dbgJetBeginExternalBackup(grbitJet);
  1833. _JumpIfError(hr, error, "JetBeginExternalBackup");
  1834. error:
  1835. return(myJetHResult(hr));
  1836. }
  1837. HRESULT
  1838. CCertDB::_BackupGetFileList(
  1839. IN BOOL fDBFiles,
  1840. IN OUT DWORD *pcwcList,
  1841. OUT WCHAR *pwszzList) // OPTIONAL
  1842. {
  1843. HRESULT hr;
  1844. CHAR buf[12];
  1845. CHAR *pszz = buf;
  1846. DWORD cbbuf = ARRAYSIZE(buf);
  1847. DWORD cbActual;
  1848. WCHAR *pwszz = NULL;
  1849. DWORD cwc;
  1850. WCHAR *pwsz;
  1851. while (TRUE)
  1852. {
  1853. if (fDBFiles)
  1854. {
  1855. hr = _dbgJetGetAttachInfo(pszz, cbbuf, &cbActual);
  1856. _JumpIfError(hr, error, "JetGetAttachInfo");
  1857. }
  1858. else
  1859. {
  1860. hr = _dbgJetGetLogInfo(pszz, cbbuf, &cbActual);
  1861. _JumpIfError(hr, error, "JetGetLogInfo");
  1862. }
  1863. if (cbbuf >= cbActual)
  1864. {
  1865. break;
  1866. }
  1867. CSASSERT(buf == pszz);
  1868. pszz = (CHAR *) LocalAlloc(LMEM_FIXED, cbActual);
  1869. if (NULL == pszz)
  1870. {
  1871. hr = E_OUTOFMEMORY;
  1872. _JumpError(hr, error, "LocalAlloc");
  1873. }
  1874. cbbuf = cbActual;
  1875. }
  1876. if (!ConvertSzToWsz(&pwszz, pszz, cbActual))
  1877. {
  1878. hr = E_OUTOFMEMORY;
  1879. _JumpError(hr, error, "ConvertSzToWsz");
  1880. }
  1881. pwsz = pwszz;
  1882. do
  1883. {
  1884. cwc = wcslen(pwsz);
  1885. pwsz += cwc + 1;
  1886. } while (0 != cwc);
  1887. cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszz); // includes double trailing L'\0's
  1888. if (NULL != pwszzList)
  1889. {
  1890. CopyMemory(pwszzList, pwszz, min(cwc, *pcwcList) * sizeof(WCHAR));
  1891. if (cwc > *pcwcList)
  1892. {
  1893. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  1894. }
  1895. }
  1896. *pcwcList = cwc;
  1897. _JumpIfError(hr, error, "Buffer Overflow");
  1898. error:
  1899. if (NULL != pszz && buf != pszz)
  1900. {
  1901. LocalFree(pszz);
  1902. }
  1903. if (NULL != pwszz)
  1904. {
  1905. LocalFree(pwszz);
  1906. }
  1907. return(myJetHResult(hr));
  1908. }
  1909. HRESULT
  1910. CCertDB::BackupGetDBFileList(
  1911. IN OUT DWORD *pcwcList,
  1912. OUT WCHAR *pwszzList) // OPTIONAL
  1913. {
  1914. HRESULT hr;
  1915. hr = _BackupGetFileList(TRUE, pcwcList, pwszzList);
  1916. _JumpIfError(hr, error, "_BackupGetFileList");
  1917. error:
  1918. return(hr);
  1919. }
  1920. HRESULT
  1921. CCertDB::BackupGetLogFileList(
  1922. IN OUT DWORD *pcwcList,
  1923. OUT WCHAR *pwszzList) // OPTIONAL
  1924. {
  1925. HRESULT hr;
  1926. hr = _BackupGetFileList(FALSE, pcwcList, pwszzList);
  1927. _JumpIfError(hr, error, "_BackupGetFileList");
  1928. error:
  1929. return(hr);
  1930. }
  1931. HRESULT
  1932. CCertDB::BackupOpenFile(
  1933. IN WCHAR const *pwszFile,
  1934. OUT JET_HANDLE *phFileDB,
  1935. OPTIONAL OUT ULARGE_INTEGER *pliSize)
  1936. {
  1937. HRESULT hr;
  1938. CHAR *pszFile = NULL;
  1939. if (!ConvertWszToSz(&pszFile, pwszFile, -1))
  1940. {
  1941. hr = E_OUTOFMEMORY;
  1942. _JumpError(hr, error, "ConvertWszToSz(pwszFile)");
  1943. }
  1944. hr = _dbgJetOpenFile(
  1945. pszFile,
  1946. phFileDB,
  1947. &pliSize->LowPart,
  1948. &pliSize->HighPart);
  1949. _JumpIfErrorStr(hr, error, "JetOpenFile", pwszFile);
  1950. error:
  1951. if (NULL != pszFile)
  1952. {
  1953. LocalFree(pszFile);
  1954. }
  1955. return(myJetHResult(hr));
  1956. }
  1957. HRESULT
  1958. CCertDB::BackupReadFile(
  1959. IN JET_HANDLE hFileDB,
  1960. OUT BYTE *pb,
  1961. IN DWORD cb,
  1962. OUT DWORD *pcb)
  1963. {
  1964. HRESULT hr;
  1965. BYTE *pbAlloc = NULL;
  1966. BYTE *pbRead;
  1967. if (0 == m_cbPage)
  1968. {
  1969. SYSTEM_INFO si;
  1970. GetSystemInfo(&si);
  1971. m_cbPage = si.dwPageSize;
  1972. }
  1973. if ((m_cbPage - 1) & cb)
  1974. {
  1975. hr = E_INVALIDARG;
  1976. _JumpError(hr, error, "bad read size");
  1977. }
  1978. pbRead = pb;
  1979. // If the caller's buffer is not page aligned, allocate an aligned buffer
  1980. // and copy the data.
  1981. if ((m_cbPage - 1) & (DWORD_PTR) pb)
  1982. {
  1983. pbAlloc = (BYTE *) VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_READWRITE);
  1984. if (NULL == pbAlloc)
  1985. {
  1986. hr = myHLastError();
  1987. _JumpIfError(hr, error, "VirtualAlloc");
  1988. }
  1989. pbRead = pbAlloc;
  1990. }
  1991. hr = _dbgJetReadFile(hFileDB, pbRead, cb, pcb);
  1992. _JumpIfError(hr, error, "JetReadFile");
  1993. if (NULL != pbAlloc)
  1994. {
  1995. CopyMemory(pb, pbAlloc, *pcb);
  1996. }
  1997. error:
  1998. if (NULL != pbAlloc)
  1999. {
  2000. VirtualFree(pbAlloc, 0, MEM_RELEASE);
  2001. }
  2002. return(myJetHResult(hr));
  2003. }
  2004. HRESULT
  2005. CCertDB::BackupCloseFile(
  2006. IN JET_HANDLE hFileDB)
  2007. {
  2008. HRESULT hr;
  2009. hr = _dbgJetCloseFile(hFileDB);
  2010. _JumpIfError(hr, error, "JetCloseFile");
  2011. error:
  2012. return(myJetHResult(hr));
  2013. }
  2014. HRESULT
  2015. CCertDB::BackupTruncateLog()
  2016. {
  2017. HRESULT hr;
  2018. hr = _dbgJetTruncateLog();
  2019. _JumpIfError(hr, error, "JetTruncateLog");
  2020. error:
  2021. return(myJetHResult(hr));
  2022. }
  2023. HRESULT
  2024. CCertDB::BackupEnd()
  2025. {
  2026. HRESULT hr;
  2027. hr = _dbgJetEndExternalBackup();
  2028. _JumpIfError(hr, error, "JetEndExternalBackup");
  2029. error:
  2030. return(myJetHResult(hr));
  2031. }
  2032. DBTABLE const *
  2033. CCertDB::_MapTable(
  2034. IN WCHAR const *pwszPropName,
  2035. IN DBTABLE const *pdt)
  2036. {
  2037. while (NULL != pdt->pwszPropName)
  2038. {
  2039. if (0 == (DBTF_MISSING & pdt->dwFlags) &&
  2040. (0 == mylstrcmpiS(pwszPropName, pdt->pwszPropName) ||
  2041. (NULL != pdt->pwszPropNameObjId &&
  2042. 0 == mylstrcmpiS(pwszPropName, pdt->pwszPropNameObjId))))
  2043. {
  2044. return(pdt);
  2045. }
  2046. pdt++;
  2047. }
  2048. return(NULL);
  2049. }
  2050. HRESULT
  2051. CCertDB::_MapPropIdIndex(
  2052. IN DWORD ColumnIndex,
  2053. OUT DBTABLE const **ppdt,
  2054. OPTIONAL OUT DWORD *pType)
  2055. {
  2056. HRESULT hr;
  2057. DBTABLE const *pdt = NULL;
  2058. DWORD iCol = DTI_COLUMNMASK & ColumnIndex;
  2059. switch (DTI_TABLEMASK & ColumnIndex)
  2060. {
  2061. case DTI_REQUESTTABLE:
  2062. if (DTR_MAX > iCol)
  2063. {
  2064. pdt = g_adtRequests;
  2065. }
  2066. break;
  2067. case DTI_CERTIFICATETABLE:
  2068. if (DTC_MAX > iCol)
  2069. {
  2070. pdt = g_adtCertificates;
  2071. }
  2072. break;
  2073. case DTI_ATTRIBUTETABLE:
  2074. if (DTA_MAX > iCol)
  2075. {
  2076. pdt = g_adtRequestAttributes;
  2077. }
  2078. break;
  2079. case DTI_EXTENSIONTABLE:
  2080. if (DTE_MAX > iCol)
  2081. {
  2082. pdt = g_adtCertExtensions;
  2083. }
  2084. break;
  2085. case DTI_CRLTABLE:
  2086. if (DTL_MAX > iCol)
  2087. {
  2088. pdt = g_adtCRLs;
  2089. }
  2090. break;
  2091. }
  2092. if (NULL == pdt)
  2093. {
  2094. hr = E_INVALIDARG;
  2095. DBGPRINT((
  2096. DBG_SS_CERTDB,
  2097. "_MapPropIdIndex(%x) -> %x\n",
  2098. ColumnIndex,
  2099. hr));
  2100. _JumpError(hr, error, "column index");
  2101. }
  2102. pdt += iCol;
  2103. if (NULL != pType)
  2104. {
  2105. switch (pdt->dbcoltyp)
  2106. {
  2107. case JET_coltypDateTime:
  2108. *pType = PROPTYPE_DATE;
  2109. break;
  2110. case JET_coltypLong:
  2111. *pType = PROPTYPE_LONG;
  2112. break;
  2113. case JET_coltypText:
  2114. case JET_coltypLongText:
  2115. *pType = PROPTYPE_STRING;
  2116. break;
  2117. case JET_coltypLongBinary:
  2118. default:
  2119. *pType = PROPTYPE_BINARY;
  2120. break;
  2121. }
  2122. if (NULL != pdt->pszIndexName &&
  2123. 0 == (DBTF_INDEXREQUESTID & pdt->dwFlags))
  2124. {
  2125. *pType |= PROPFLAGS_INDEXED;
  2126. }
  2127. }
  2128. DBGPRINT((
  2129. DBG_SS_CERTDBI,
  2130. "_MapPropIdIndex(%x) -> %ws.%ws\n",
  2131. ColumnIndex,
  2132. wszTable(pdt->dwTable),
  2133. pdt->pwszPropName));
  2134. hr = S_OK;
  2135. error:
  2136. *ppdt = pdt;
  2137. return(hr);
  2138. }
  2139. HRESULT
  2140. CCertDB::_MapTableToIndex(
  2141. IN DBTABLE const *pdt,
  2142. OUT DWORD *pColumnIndex)
  2143. {
  2144. HRESULT hr;
  2145. DBTABLE const *pdtBase;
  2146. DWORD Column;
  2147. DWORD cColumnMax;
  2148. DWORD iCol;
  2149. Column = 0;
  2150. switch (pdt->dwTable)
  2151. {
  2152. case TABLE_REQUESTS:
  2153. Column = DTI_REQUESTTABLE;
  2154. cColumnMax = DTR_MAX;
  2155. pdtBase = g_adtRequests;
  2156. break;
  2157. case TABLE_CERTIFICATES:
  2158. Column = DTI_CERTIFICATETABLE;
  2159. cColumnMax = DTC_MAX;
  2160. pdtBase = g_adtCertificates;
  2161. break;
  2162. case TABLE_ATTRIBUTES:
  2163. Column = DTI_ATTRIBUTETABLE;
  2164. cColumnMax = DTA_MAX;
  2165. pdtBase = g_adtRequestAttributes;
  2166. break;
  2167. case TABLE_EXTENSIONS:
  2168. Column = DTI_EXTENSIONTABLE;
  2169. cColumnMax = DTE_MAX;
  2170. pdtBase = g_adtCertExtensions;
  2171. break;
  2172. case TABLE_CRLS:
  2173. Column = DTI_CRLTABLE;
  2174. cColumnMax = DTL_MAX;
  2175. pdtBase = g_adtCRLs;
  2176. break;
  2177. default:
  2178. hr = E_INVALIDARG;
  2179. _JumpError(hr, error, "pdt->dwTable");
  2180. }
  2181. for (iCol = 0; ; iCol++)
  2182. {
  2183. if (iCol >= cColumnMax)
  2184. {
  2185. hr = E_INVALIDARG;
  2186. _JumpError(hr, error, "iCol");
  2187. }
  2188. if (pdt->pwszPropName == pdtBase[iCol].pwszPropName)
  2189. {
  2190. break;
  2191. }
  2192. }
  2193. Column |= iCol;
  2194. hr = S_OK;
  2195. error:
  2196. DBGPRINT((
  2197. DBG_SS_CERTDBI,
  2198. "_MapTableToIndex(%ws.%ws) -> col=%x, hr=%x\n",
  2199. wszTable(pdt->dwTable),
  2200. pdt->pwszPropName,
  2201. Column,
  2202. hr));
  2203. *pColumnIndex = Column;
  2204. return(hr);
  2205. }
  2206. HRESULT
  2207. CCertDB::MapPropId(
  2208. IN WCHAR const *pwszPropName,
  2209. IN DWORD dwFlags,
  2210. OUT DBTABLE *pdtOut)
  2211. {
  2212. DBTABLE const *pdt = NULL;
  2213. WCHAR wszPrefix[2 * (sizeof(wszPROPSUBJECTDOT) / sizeof(WCHAR))];
  2214. DWORD dwTable;
  2215. HRESULT hr = S_OK;
  2216. DBTABLE const *pdbTable;
  2217. WCHAR const *pwszStart;
  2218. BOOL fSubject = FALSE;
  2219. BOOL fRequest = FALSE;
  2220. if (NULL == pwszPropName || NULL == pdtOut)
  2221. {
  2222. hr = E_POINTER;
  2223. _JumpError(hr, error, "NULL parm");
  2224. }
  2225. dwTable = PROPTABLE_MASK & dwFlags;
  2226. CSASSERT(
  2227. PROPTABLE_REQUEST == dwTable ||
  2228. PROPTABLE_CERTIFICATE == dwTable ||
  2229. PROPTABLE_CRL == dwTable);
  2230. // Check to see if the request is for L"Subject.".
  2231. pwszStart = pwszPropName;
  2232. if (PROPTABLE_CRL != dwTable)
  2233. {
  2234. while (!fSubject)
  2235. {
  2236. WCHAR const *pwsz;
  2237. pwsz = wcschr(pwszStart, L'.');
  2238. if (NULL == pwsz ||
  2239. pwsz - pwszStart + 2 > sizeof(wszPrefix)/sizeof(WCHAR))
  2240. {
  2241. pwsz = pwszStart;
  2242. break;
  2243. }
  2244. pwsz++; // skip past L'.'
  2245. CopyMemory(
  2246. wszPrefix,
  2247. pwszStart,
  2248. (SAFE_SUBTRACT_POINTERS(pwsz, pwszStart) * sizeof(WCHAR)));
  2249. wszPrefix[pwsz - pwszStart] = L'\0';
  2250. if (!fSubject)
  2251. {
  2252. pwszStart = pwsz;
  2253. if (0 == LSTRCMPIS(wszPrefix, wszPROPSUBJECTDOT))
  2254. {
  2255. fSubject = TRUE;
  2256. continue;
  2257. }
  2258. else
  2259. if (!fRequest &&
  2260. PROPTABLE_REQUEST == dwTable &&
  2261. 0 == LSTRCMPIS(wszPrefix, wszPROPREQUESTDOT))
  2262. {
  2263. fRequest = TRUE;
  2264. continue;
  2265. }
  2266. }
  2267. hr = E_INVALIDARG;
  2268. _JumpErrorStr(hr, error, "Invalid prefix", pwszPropName);
  2269. }
  2270. }
  2271. pdbTable = NULL;
  2272. // Search the requested table for a matching property name or property
  2273. // objectid string.
  2274. switch (dwTable)
  2275. {
  2276. case PROPTABLE_REQUEST:
  2277. pdbTable = g_adtRequests;
  2278. break;
  2279. case PROPTABLE_CERTIFICATE:
  2280. pdbTable = g_adtCertificates;
  2281. break;
  2282. case PROPTABLE_CRL:
  2283. pdbTable = g_adtCRLs;
  2284. break;
  2285. }
  2286. CSASSERT(NULL != pdbTable);
  2287. pdt = _MapTable(pwszStart, pdbTable);
  2288. if (NULL == pdt || (fSubject && 0 == (DBTF_SUBJECT & pdt->dwFlags)))
  2289. {
  2290. hr = CERTSRV_E_PROPERTY_EMPTY;
  2291. _JumpErrorStr(
  2292. hr,
  2293. error,
  2294. PROPTABLE_REQUEST == dwTable?
  2295. "unknown Request property" :
  2296. PROPTABLE_CERTIFICATE == dwTable?
  2297. "unknown Certificate property" :
  2298. "unknown CRL property",
  2299. pwszPropName);
  2300. }
  2301. *pdtOut = *pdt; // structure copy
  2302. hr = S_OK;
  2303. error:
  2304. return(hr);
  2305. }
  2306. HRESULT
  2307. CCertDB::TestShutDownState()
  2308. {
  2309. HRESULT hr;
  2310. if (m_fPendingShutDown)
  2311. {
  2312. hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS);
  2313. _JumpError(hr, error, "m_fPendingShutDown");
  2314. }
  2315. hr = S_OK;
  2316. error:
  2317. return(hr);
  2318. }
  2319. HRESULT
  2320. CCertDB::SetProperty(
  2321. IN CERTSESSION *pcs,
  2322. IN DBTABLE const *pdt,
  2323. IN DWORD cbProp,
  2324. IN BYTE const *pbProp) // OPTIONAL
  2325. {
  2326. HRESULT hr;
  2327. JET_TABLEID tableid;
  2328. if (NULL == pcs ||
  2329. NULL == pdt ||
  2330. (NULL == pbProp && !ISTEXTCOLTYP(pdt->dbcoltyp)))
  2331. {
  2332. hr = E_POINTER;
  2333. _JumpError(hr, error, "NULL parm");
  2334. }
  2335. DBGPRINT((
  2336. DBG_SS_CERTDBI,
  2337. "SetProperty for %hs into table %d\n",
  2338. pdt->pszFieldName,
  2339. pdt->dwTable));
  2340. if (ISTEXTCOLTYP(pdt->dbcoltyp))
  2341. {
  2342. DBGPRINT((DBG_SS_CERTDBI, "SetProperty setting string %ws\n", pbProp));
  2343. }
  2344. if (JET_coltypDateTime == pdt->dbcoltyp)
  2345. {
  2346. DBGPRINT((
  2347. DBG_SS_CERTDBI,
  2348. "SetProperty setting date: %x:%x\n",
  2349. ((DWORD *) pbProp)[0],
  2350. ((DWORD *) pbProp)[1]));
  2351. }
  2352. switch (pdt->dwTable)
  2353. {
  2354. case TABLE_CRLS:
  2355. case TABLE_REQUESTS:
  2356. tableid = pcs->aTable[CSTI_PRIMARY].TableId;
  2357. break;
  2358. case TABLE_CERTIFICATES:
  2359. tableid = pcs->aTable[CSTI_CERTIFICATE].TableId;
  2360. break;
  2361. default:
  2362. hr = E_INVALIDARG;
  2363. _JumpError(hr, error, "unknown table type");
  2364. }
  2365. if (!IsValidJetTableId(tableid))
  2366. {
  2367. hr = E_HANDLE;
  2368. _JumpErrorStr(hr, error, "tableid", pdt->pwszPropName);
  2369. }
  2370. hr = _SetColumn(
  2371. pcs->SesId,
  2372. tableid,
  2373. pdt,
  2374. pdt->dbcolumnid,
  2375. cbProp,
  2376. pbProp);
  2377. _JumpIfErrorStr(hr, error, "_SetColumn", pdt->pwszPropName);
  2378. error:
  2379. return(myJetHResult(hr));
  2380. }
  2381. HRESULT
  2382. CCertDB::GetProperty(
  2383. IN CERTSESSION *pcs,
  2384. IN DBTABLE const *pdt,
  2385. OPTIONAL IN ICertDBComputedColumn *pIComputedColumn,
  2386. IN OUT DWORD *pcbProp,
  2387. OUT BYTE *pbProp) // OPTIONAL
  2388. {
  2389. HRESULT hr;
  2390. JET_TABLEID tableid;
  2391. if (NULL == pcs || NULL == pdt || NULL == pcbProp)
  2392. {
  2393. hr = E_POINTER;
  2394. _JumpError(hr, error, "NULL parm");
  2395. }
  2396. DBGPRINT((
  2397. DBG_SS_CERTDBI,
  2398. "GetProperty for %hs from table %d\n",
  2399. pdt->pszFieldName,
  2400. pdt->dwTable));
  2401. if ((CSF_TABLEMASK & pcs->SesFlags) != pdt->dwTable)
  2402. {
  2403. if (TABLE_REQCERTS != (CSF_TABLEMASK & pcs->SesFlags) ||
  2404. (TABLE_REQUESTS != pdt->dwTable &&
  2405. TABLE_CERTIFICATES != pdt->dwTable))
  2406. {
  2407. hr = E_INVALIDARG;
  2408. _JumpError(hr, error, "mismatched table");
  2409. }
  2410. }
  2411. if (TABLE_CERTIFICATES == pdt->dwTable)
  2412. {
  2413. tableid = pcs->aTable[CSTI_CERTIFICATE].TableId;
  2414. }
  2415. else
  2416. {
  2417. tableid = pcs->aTable[CSTI_PRIMARY].TableId;
  2418. }
  2419. if (!IsValidJetTableId(tableid))
  2420. {
  2421. hr = E_HANDLE;
  2422. _JumpErrorStr(hr, error, "tableid", pdt->pwszPropName);
  2423. }
  2424. hr = _RetrieveColumn(
  2425. pcs,
  2426. tableid,
  2427. pdt,
  2428. pdt->dbcolumnid,
  2429. pIComputedColumn,
  2430. pcbProp,
  2431. pbProp);
  2432. _JumpIfErrorStr3(
  2433. hr,
  2434. error,
  2435. "_RetrieveColumn",
  2436. pdt->pwszPropName,
  2437. CERTSRV_E_PROPERTY_EMPTY,
  2438. HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW));
  2439. if (ISTEXTCOLTYP(pdt->dbcoltyp))
  2440. {
  2441. DBGPRINT((DBG_SS_CERTDBI, "GetProperty returning string %ws\n", pbProp));
  2442. }
  2443. error:
  2444. return(myJetHResult(hr));
  2445. }
  2446. HRESULT
  2447. CCertDB::CopyRequestNames(
  2448. IN CERTSESSION *pcs)
  2449. {
  2450. HRESULT hr = S_OK;
  2451. DBTABLE dt;
  2452. DWORD cbProp;
  2453. BYTE *pbProp = NULL;
  2454. DWORD i;
  2455. BYTE rgbFastBuf[CB_PROPFASTBUF];
  2456. if (NULL == pcs)
  2457. {
  2458. hr = E_POINTER;
  2459. _JumpError(hr, error, "NULL parm");
  2460. }
  2461. for (i = 0; NULL != g_dntr[i].pszFieldName; i++)
  2462. {
  2463. hr = MapPropId(g_dntr[i].pwszPropName, PROPTABLE_REQUEST, &dt);
  2464. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  2465. {
  2466. hr = S_OK;
  2467. continue; // Optional column doesn't exist
  2468. }
  2469. _JumpIfError(hr, error, "MapPropId");
  2470. // re-point at fastbuf
  2471. pbProp = rgbFastBuf;
  2472. cbProp = sizeof(rgbFastBuf);
  2473. hr = GetProperty(pcs, &dt, NULL, &cbProp, pbProp);
  2474. if (S_OK != hr)
  2475. {
  2476. if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
  2477. {
  2478. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  2479. {
  2480. hr = S_OK;
  2481. continue;
  2482. }
  2483. _JumpIfError(hr, error, "GetProperty");
  2484. }
  2485. CSASSERT (ARRAYSIZE(rgbFastBuf) < cbProp);
  2486. DBGPRINT((
  2487. DBG_SS_CERTDB,
  2488. "FastBuf miss: CopyRequestNames(cbProp=%u)\n",
  2489. cbProp));
  2490. pbProp = (BYTE *) LocalAlloc(LMEM_FIXED, cbProp);
  2491. if (NULL == pbProp)
  2492. {
  2493. hr = E_OUTOFMEMORY;
  2494. _JumpError(hr, error, "LocalAlloc");
  2495. }
  2496. hr = GetProperty(pcs, &dt, NULL, &cbProp, pbProp);
  2497. _JumpIfError(hr, error, "GetProperty");
  2498. } // have data in hand
  2499. hr = MapPropId(g_dntr[i].pwszPropName, PROPTABLE_CERTIFICATE, &dt);
  2500. _JumpIfError(hr, error, "MapPropId");
  2501. hr = SetProperty(pcs, &dt, cbProp, pbProp);
  2502. _JumpIfError(hr, error, "SetProperty");
  2503. if (NULL != pbProp && rgbFastBuf != pbProp)
  2504. {
  2505. LocalFree(pbProp);
  2506. }
  2507. pbProp = NULL;
  2508. }
  2509. error:
  2510. if (NULL != pbProp && rgbFastBuf != pbProp)
  2511. {
  2512. LocalFree(pbProp);
  2513. }
  2514. return(hr);
  2515. }
  2516. STDMETHODIMP
  2517. CCertDB::EnumCertDBColumn(
  2518. /* [in] */ DWORD dwTable,
  2519. /* [out] */ IEnumCERTDBCOLUMN **ppenum)
  2520. {
  2521. HRESULT hr;
  2522. IEnumCERTDBCOLUMN *penum = NULL;
  2523. if (NULL == ppenum)
  2524. {
  2525. hr = E_POINTER;
  2526. _JumpError(hr, error, "NULL parm");
  2527. }
  2528. *ppenum = NULL;
  2529. penum = new CEnumCERTDBCOLUMN;
  2530. if (NULL == penum)
  2531. {
  2532. hr = E_OUTOFMEMORY;
  2533. _JumpError(hr, error, "new CEnumCERTDBCOLUMN");
  2534. }
  2535. hr = ((CEnumCERTDBCOLUMN *) penum)->Open(dwTable, this);
  2536. _JumpIfError(hr, error, "Open");
  2537. *ppenum = penum;
  2538. hr = S_OK;
  2539. error:
  2540. if (S_OK != hr && NULL != penum)
  2541. {
  2542. penum->Release();
  2543. }
  2544. return(hr);
  2545. }
  2546. STDMETHODIMP
  2547. CCertDB::GetDefaultColumnSet(
  2548. /* [in] */ DWORD iColumnSetDefault,
  2549. /* [in] */ DWORD cColumnIds,
  2550. /* [out] */ DWORD *pcColumnIds,
  2551. /* [out, ref] */ DWORD *pColumnIds) // OPTIONAL
  2552. {
  2553. HRESULT hr;
  2554. DWORD *pcol;
  2555. DWORD ccol;
  2556. if (NULL == pcColumnIds)
  2557. {
  2558. hr = E_POINTER;
  2559. _JumpError(hr, error, "NULL parm");
  2560. }
  2561. switch (iColumnSetDefault)
  2562. {
  2563. case CV_COLUMN_LOG_FAILED_DEFAULT:
  2564. case CV_COLUMN_QUEUE_DEFAULT:
  2565. pcol = g_aColumnViewQueue;
  2566. ccol = g_cColumnViewQueue;
  2567. break;
  2568. case CV_COLUMN_LOG_REVOKED_DEFAULT:
  2569. pcol = g_aColumnViewRevoked;
  2570. ccol = g_cColumnViewRevoked;
  2571. break;
  2572. case CV_COLUMN_LOG_DEFAULT:
  2573. pcol = g_aColumnViewLog;
  2574. ccol = g_cColumnViewLog;
  2575. break;
  2576. case CV_COLUMN_EXTENSION_DEFAULT:
  2577. pcol = g_aColumnViewExtension;
  2578. ccol = g_cColumnViewExtension;
  2579. break;
  2580. case CV_COLUMN_ATTRIBUTE_DEFAULT:
  2581. pcol = g_aColumnViewAttribute;
  2582. ccol = g_cColumnViewAttribute;
  2583. break;
  2584. case CV_COLUMN_CRL_DEFAULT:
  2585. pcol = g_aColumnViewCRL;
  2586. ccol = g_cColumnViewCRL;
  2587. break;
  2588. default:
  2589. hr = E_INVALIDARG;
  2590. _JumpError(hr, error, "iColumnSetDefault");
  2591. }
  2592. *pcColumnIds = ccol;
  2593. hr = S_OK;
  2594. if (NULL != pColumnIds)
  2595. {
  2596. if (ccol > cColumnIds)
  2597. {
  2598. ccol = cColumnIds;
  2599. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  2600. }
  2601. CopyMemory(pColumnIds, pcol, ccol * sizeof(*pColumnIds));
  2602. }
  2603. error:
  2604. return(hr);
  2605. }
  2606. HRESULT
  2607. CCertDB::GetColumnType(
  2608. IN LONG ColumnIndex,
  2609. OUT DWORD *pType)
  2610. {
  2611. HRESULT hr;
  2612. DBTABLE const *pdt;
  2613. if (NULL == pType)
  2614. {
  2615. hr = E_POINTER;
  2616. _JumpError(hr, error, "NULL parm");
  2617. }
  2618. hr = _MapPropIdIndex(ColumnIndex, &pdt, pType);
  2619. _JumpIfError(hr, error, "_MapPropIdIndex");
  2620. error:
  2621. return(hr);
  2622. }
  2623. HRESULT
  2624. CCertDB::EnumCertDBColumnNext(
  2625. IN DWORD dwTable, // CVRC_TABLE_*
  2626. IN ULONG ielt,
  2627. IN ULONG celt,
  2628. OUT CERTDBCOLUMN *rgelt,
  2629. OUT ULONG *pielt,
  2630. OUT ULONG *pceltFetched)
  2631. {
  2632. HRESULT hr;
  2633. ULONG ieltEnd;
  2634. ULONG ieltMax;
  2635. ULONG TableIndex;
  2636. CERTDBCOLUMN *pelt;
  2637. WCHAR const *pwszPrefix;
  2638. WCHAR const *pwszDisplayName;
  2639. if (NULL == rgelt || NULL == pielt || NULL == pceltFetched)
  2640. {
  2641. hr = E_POINTER;
  2642. _JumpError(hr, error, "NULL parm");
  2643. }
  2644. switch (dwTable)
  2645. {
  2646. case CVRC_TABLE_REQCERT:
  2647. TableIndex = DTI_REQUESTTABLE;
  2648. ieltMax = DTR_MAX + DTC_MAX;
  2649. break;
  2650. case CVRC_TABLE_EXTENSIONS:
  2651. TableIndex = DTI_EXTENSIONTABLE;
  2652. ieltMax = DTE_MAX;
  2653. break;
  2654. case CVRC_TABLE_ATTRIBUTES:
  2655. TableIndex = DTI_ATTRIBUTETABLE;
  2656. ieltMax = DTA_MAX;
  2657. break;
  2658. case CVRC_TABLE_CRL:
  2659. TableIndex = DTI_CRLTABLE;
  2660. ieltMax = DTL_MAX;
  2661. break;
  2662. default:
  2663. hr = E_INVALIDARG;
  2664. _JumpError(hr, error, "Bad table");
  2665. }
  2666. if (ieltMax + ielt < celt)
  2667. {
  2668. celt = ieltMax - ielt;
  2669. }
  2670. ieltEnd = ielt + celt;
  2671. ZeroMemory(rgelt, celt * sizeof(rgelt[0]));
  2672. hr = S_OK;
  2673. for (pelt = rgelt; pelt < &rgelt[celt]; ielt++, pelt++)
  2674. {
  2675. DBTABLE const *pdt;
  2676. ULONG ieltBase = 0;
  2677. if (ieltMax <= ielt)
  2678. {
  2679. if (pelt == rgelt)
  2680. {
  2681. hr = S_FALSE;
  2682. }
  2683. break;
  2684. }
  2685. pwszPrefix = NULL;
  2686. if (CVRC_TABLE_REQCERT == dwTable)
  2687. {
  2688. if (DTR_MAX > ielt)
  2689. {
  2690. pwszPrefix = wszPROPREQUESTDOT;
  2691. TableIndex = DTI_REQUESTTABLE;
  2692. }
  2693. else
  2694. {
  2695. ieltBase = DTR_MAX;
  2696. TableIndex = DTI_CERTIFICATETABLE;
  2697. }
  2698. }
  2699. pelt->Index = TableIndex | (ielt - ieltBase);
  2700. hr = _MapPropIdIndex(pelt->Index, &pdt, &pelt->Type);
  2701. _JumpIfError(hr, error, "_MapPropIdIndex");
  2702. pelt->cbMax = pdt->dwcbMax;
  2703. hr = _DupString(pwszPrefix, pdt->pwszPropName, &pelt->pwszName);
  2704. _JumpIfError(hr, error, "_DupString");
  2705. hr = myGetColumnDisplayName(pelt->pwszName, &pwszDisplayName);
  2706. _PrintIfError(hr, "myGetColumnDisplayName");
  2707. if (S_OK != hr)
  2708. {
  2709. pwszDisplayName = pelt->pwszName;
  2710. }
  2711. hr = _DupString(NULL, pwszDisplayName, &pelt->pwszDisplayName);
  2712. _JumpIfError(hr, error, "_DupString");
  2713. }
  2714. *pceltFetched = SAFE_SUBTRACT_POINTERS(pelt, rgelt);
  2715. *pielt = ielt;
  2716. error:
  2717. if (S_OK != hr && S_FALSE != hr)
  2718. {
  2719. if (NULL != rgelt)
  2720. {
  2721. for (pelt = rgelt; pelt < &rgelt[celt]; pelt++)
  2722. {
  2723. if (NULL != pelt->pwszName)
  2724. {
  2725. CoTaskMemFree(pelt->pwszName);
  2726. pelt->pwszName = NULL;
  2727. }
  2728. if (NULL != pelt->pwszDisplayName)
  2729. {
  2730. CoTaskMemFree(pelt->pwszDisplayName);
  2731. pelt->pwszDisplayName = NULL;
  2732. }
  2733. }
  2734. }
  2735. }
  2736. return(hr);
  2737. }
  2738. HRESULT
  2739. CCertDB::EnumCertDBResultRowNext(
  2740. IN CERTSESSION *pcs,
  2741. IN DWORD ccvr,
  2742. IN CERTVIEWRESTRICTION const *pcvr,
  2743. IN DWORD ccolOut,
  2744. IN DWORD const *acolOut,
  2745. IN LONG cskip,
  2746. OPTIONAL IN ICertDBComputedColumn *pIComputedColumn,
  2747. IN ULONG celt,
  2748. OUT CERTDBRESULTROW *rgelt,
  2749. OUT ULONG *pceltFetched,
  2750. OUT LONG *pcskipped)
  2751. {
  2752. HRESULT hr;
  2753. DWORD iRow;
  2754. LONG cskipped;
  2755. DBGPRINT((
  2756. DBG_SS_CERTDBI,
  2757. "EnumCertDBResultRowNext called: cskip: %d\n", cskip));
  2758. if (NULL == pcvr ||
  2759. NULL == acolOut ||
  2760. NULL == rgelt ||
  2761. NULL == pceltFetched ||
  2762. NULL == pcskipped)
  2763. {
  2764. hr = E_POINTER;
  2765. _JumpError(hr, error, "NULL parm");
  2766. }
  2767. *pcskipped = 0;
  2768. hr = S_OK;
  2769. for (iRow = 0; iRow < celt; iRow++)
  2770. {
  2771. hr = TestShutDownState();
  2772. _JumpIfError(hr, error, "TestShutDownState");
  2773. hr = _GetResultRow(
  2774. pcs,
  2775. ccvr,
  2776. pcvr,
  2777. cskip,
  2778. ccolOut,
  2779. acolOut,
  2780. pIComputedColumn,
  2781. &rgelt[iRow],
  2782. &cskipped);
  2783. if (S_FALSE == hr)
  2784. {
  2785. *pcskipped += cskipped;
  2786. break;
  2787. }
  2788. DBGPRINT((
  2789. DBG_SS_CERTDBI,
  2790. "EnumCertDBResultRowNext: rowid %u\n", rgelt[iRow].rowid));
  2791. _JumpIfError(hr, error, "_GetResultRow");
  2792. *pcskipped += cskipped;
  2793. cskip = 0;
  2794. }
  2795. *pceltFetched = iRow;
  2796. DBGPRINT((
  2797. DBG_SS_CERTDBI,
  2798. "EnumCertDBResultRowNext: %u rows, hr=%x\n",
  2799. *pceltFetched,
  2800. hr));
  2801. error:
  2802. if (S_OK != hr && S_FALSE != hr)
  2803. {
  2804. ReleaseResultRow(celt, rgelt);
  2805. }
  2806. return(hr);
  2807. }
  2808. HRESULT
  2809. CCertDB::_CompareColumnValue(
  2810. IN CERTSESSION *pcs,
  2811. IN CERTVIEWRESTRICTION const *pcvr,
  2812. OPTIONAL IN ICertDBComputedColumn *pIComputedColumn)
  2813. {
  2814. HRESULT hr;
  2815. JET_TABLEID tableid;
  2816. DBTABLE const *pdt;
  2817. WCHAR *pwszValue = NULL;
  2818. BOOL fMatch;
  2819. int r;
  2820. BYTE rgbFastBuf[256];
  2821. BYTE *pbProp = rgbFastBuf;
  2822. DWORD cb = sizeof(rgbFastBuf);
  2823. // if SEEK_NONE, short circuit tests
  2824. if (CVR_SEEK_NONE == (CVR_SEEK_MASK & pcvr->SeekOperator))
  2825. {
  2826. return S_OK;
  2827. }
  2828. hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
  2829. _JumpIfError(hr, error, "_MapPropIdIndex");
  2830. if (TABLE_CERTIFICATES == pdt->dwTable)
  2831. {
  2832. tableid = pcs->aTable[CSTI_CERTIFICATE].TableId;
  2833. }
  2834. else
  2835. {
  2836. tableid = pcs->aTable[CSTI_PRIMARY].TableId;
  2837. }
  2838. if (!IsValidJetTableId(tableid))
  2839. {
  2840. hr = E_HANDLE;
  2841. _JumpError(hr, error, "tableid");
  2842. }
  2843. hr = _RetrieveColumn(
  2844. pcs,
  2845. tableid,
  2846. pdt,
  2847. pdt->dbcolumnid,
  2848. pIComputedColumn,
  2849. &cb,
  2850. rgbFastBuf);
  2851. if (S_OK != hr)
  2852. {
  2853. if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
  2854. {
  2855. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  2856. {
  2857. _PrintError2(hr, "_RetrieveColumn", hr);
  2858. hr = S_FALSE;
  2859. }
  2860. _JumpError2(hr, error, "_RetrieveColumn", S_FALSE);
  2861. }
  2862. // buffer not big enough, dyn-alloc
  2863. CSASSERT(ARRAYSIZE(rgbFastBuf) < cb);
  2864. DBGPRINT((
  2865. DBG_SS_CERTDB,
  2866. "FastBuf miss: _CompareColumnValue(cbProp=%u)\n",
  2867. cb));
  2868. pbProp = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
  2869. if (NULL == pbProp)
  2870. {
  2871. hr = E_OUTOFMEMORY;
  2872. _JumpError(hr, error, "LocalAlloc");
  2873. }
  2874. hr = _RetrieveColumn(
  2875. pcs,
  2876. tableid,
  2877. pdt,
  2878. pdt->dbcolumnid,
  2879. pIComputedColumn,
  2880. &cb,
  2881. pbProp);
  2882. _JumpIfError(hr, error, "_RetrieveColumn");
  2883. } // we have data in-hand
  2884. #if DBG_CERTSRV
  2885. DumpRestriction(DBG_SS_CERTDBI, -1, pcvr);
  2886. dbDumpColumn(DBG_SS_CERTDBI, pdt, pbProp, cb);
  2887. #endif
  2888. fMatch = FALSE;
  2889. switch (pdt->dbcoltyp)
  2890. {
  2891. case JET_coltypLong:
  2892. if (cb == pcvr->cbValue && sizeof(LONG) == cb)
  2893. {
  2894. LONG lRestriction;
  2895. LONG lColumn;
  2896. lRestriction = *(LONG *) pcvr->pbValue;
  2897. lColumn = *(LONG *) pbProp;
  2898. switch (CVR_SEEK_MASK & pcvr->SeekOperator)
  2899. {
  2900. case CVR_SEEK_EQ:
  2901. fMatch = lColumn == lRestriction;
  2902. break;
  2903. case CVR_SEEK_LT:
  2904. fMatch = lColumn < lRestriction;
  2905. break;
  2906. case CVR_SEEK_LE:
  2907. fMatch = lColumn <= lRestriction;
  2908. break;
  2909. case CVR_SEEK_GE:
  2910. fMatch = lColumn >= lRestriction;
  2911. break;
  2912. case CVR_SEEK_GT:
  2913. fMatch = lColumn > lRestriction;
  2914. break;
  2915. }
  2916. DBGPRINT((
  2917. DBG_SS_CERTDBI,
  2918. "_CompareColumnValue(lColumn=%x %ws lRestriction=%x) -> fMatch=%x\n",
  2919. lColumn,
  2920. wszSeekOperator(pcvr->SeekOperator),
  2921. lRestriction,
  2922. fMatch));
  2923. }
  2924. break;
  2925. case JET_coltypDateTime:
  2926. if (cb == pcvr->cbValue && sizeof(FILETIME) == cb)
  2927. {
  2928. r = CompareFileTime(
  2929. (FILETIME *) pcvr->pbValue,
  2930. (FILETIME *) pbProp);
  2931. switch (CVR_SEEK_MASK & pcvr->SeekOperator)
  2932. {
  2933. case CVR_SEEK_EQ:
  2934. fMatch = 0 == r;
  2935. break;
  2936. case CVR_SEEK_LT:
  2937. fMatch = 0 < r;
  2938. break;
  2939. case CVR_SEEK_LE:
  2940. fMatch = 0 <= r;
  2941. break;
  2942. case CVR_SEEK_GE:
  2943. fMatch = 0 >= r;
  2944. break;
  2945. case CVR_SEEK_GT:
  2946. fMatch = 0 > r;
  2947. break;
  2948. }
  2949. #if DBG_CERTSRV
  2950. dbDumpFileTime(
  2951. DBG_SS_CERTDBI,
  2952. "Column: ",
  2953. (FILETIME const *) pbProp);
  2954. dbDumpFileTime(
  2955. DBG_SS_CERTDBI,
  2956. "Restriction: ",
  2957. (FILETIME const *) pcvr->pbValue);
  2958. #endif
  2959. DBGPRINT((
  2960. DBG_SS_CERTDBI,
  2961. "_CompareColumnValue(ftColumn=%08x:%08x %ws ftRestriction=%08x:%08x) -> r=%d, fMatch=%x\n",
  2962. ((LARGE_INTEGER *) pbProp)->HighPart,
  2963. ((LARGE_INTEGER *) pbProp)->LowPart,
  2964. wszSeekOperator(pcvr->SeekOperator),
  2965. ((LARGE_INTEGER *) pcvr->pbValue)->HighPart,
  2966. ((LARGE_INTEGER *) pcvr->pbValue)->LowPart,
  2967. r,
  2968. fMatch));
  2969. }
  2970. break;
  2971. case JET_coltypText:
  2972. case JET_coltypLongText:
  2973. CSASSERT(
  2974. (1 + wcslen((WCHAR const *) pcvr->pbValue)) * sizeof(WCHAR) ==
  2975. pcvr->cbValue);
  2976. CSASSERT(wcslen((WCHAR const *) pbProp) * sizeof(WCHAR) == cb);
  2977. r = mylstrcmpiL((WCHAR const *) pcvr->pbValue, (WCHAR const *) pbProp); //pwszValue
  2978. switch (CVR_SEEK_MASK & pcvr->SeekOperator)
  2979. {
  2980. case CVR_SEEK_EQ:
  2981. fMatch = 0 == r;
  2982. break;
  2983. case CVR_SEEK_LT:
  2984. fMatch = 0 < r;
  2985. break;
  2986. case CVR_SEEK_LE:
  2987. fMatch = 0 <= r;
  2988. break;
  2989. case CVR_SEEK_GE:
  2990. fMatch = 0 >= r;
  2991. break;
  2992. case CVR_SEEK_GT:
  2993. fMatch = 0 > r;
  2994. break;
  2995. }
  2996. DBGPRINT((
  2997. DBG_SS_CERTDBI,
  2998. "_CompareColumnValue(pwszColumn=%ws %ws pwszRestriction=%ws) -> r=%d, fMatch=%x\n",
  2999. pbProp, //pwszValue,
  3000. wszSeekOperator(pcvr->SeekOperator),
  3001. pcvr->pbValue,
  3002. r,
  3003. fMatch));
  3004. break;
  3005. case JET_coltypLongBinary:
  3006. if (CVR_SEEK_EQ != (CVR_SEEK_MASK & pcvr->SeekOperator))
  3007. {
  3008. hr = E_INVALIDARG;
  3009. _JumpError(hr, error, "Bad dbcoltyp");
  3010. }
  3011. fMatch = cb == pcvr->cbValue &&
  3012. 0 == memcmp(pcvr->pbValue, pbProp, cb);
  3013. break;
  3014. default:
  3015. hr = E_INVALIDARG;
  3016. _JumpError(hr, error, "Bad dbcoltyp");
  3017. }
  3018. if (!fMatch)
  3019. {
  3020. hr = S_FALSE;
  3021. _JumpError2(hr, error, "No match", S_FALSE);
  3022. }
  3023. error:
  3024. if (NULL != pwszValue)
  3025. {
  3026. LocalFree(pwszValue);
  3027. }
  3028. if (NULL != pbProp && rgbFastBuf != pbProp)
  3029. {
  3030. LocalFree(pbProp);
  3031. }
  3032. return(hr);
  3033. }
  3034. HRESULT
  3035. CCertDB::_MakeSeekKey(
  3036. IN CERTSESSION *pcs,
  3037. IN JET_TABLEID tableid,
  3038. IN DBTABLE const *pdt,
  3039. IN BYTE const *pbValue,
  3040. IN DWORD cbValue)
  3041. {
  3042. HRESULT hr;
  3043. JET_GRBIT grbitKey = JET_bitNewKey;
  3044. CSASSERT(IsValidJetTableId(tableid));
  3045. if (DBTF_INDEXREQUESTID & pdt->dwFlags)
  3046. {
  3047. CSASSERTTHREAD(pcs);
  3048. hr = _dbgJetMakeKey(
  3049. pcs->SesId,
  3050. tableid,
  3051. &pcs->RowId,
  3052. sizeof(pcs->RowId),
  3053. grbitKey);
  3054. _JumpIfError(hr, error, "JetMakeKey(RowId)");
  3055. DBGPRINT((DBG_SS_CERTDBI, "_MakeSeekKey key(RowId):\n"));
  3056. DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, (BYTE *) &pcs->RowId, sizeof(pcs->RowId)));
  3057. grbitKey = 0;
  3058. }
  3059. CSASSERTTHREAD(pcs);
  3060. hr = _dbgJetMakeKey(pcs->SesId, tableid, pbValue, cbValue, grbitKey);
  3061. _JumpIfErrorStr(hr, error, "JetMakeKey", pdt->pwszPropName);
  3062. DBGPRINT((DBG_SS_CERTDBI, "_MakeSeekKey key:\n"));
  3063. DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, pbValue, cbValue));
  3064. error:
  3065. return(myJetHResult(hr));
  3066. }
  3067. HRESULT
  3068. CCertDB::_SeekTable(
  3069. IN CERTSESSION *pcs,
  3070. IN JET_TABLEID tableid,
  3071. IN CERTVIEWRESTRICTION const *pcvr,
  3072. IN DBTABLE const *pdt,
  3073. OPTIONAL IN ICertDBComputedColumn *pIComputedColumn,
  3074. IN DWORD dwPosition,
  3075. OUT DWORD *pTableFlags
  3076. DBGPARM(IN DBAUXDATA const *pdbaux))
  3077. {
  3078. HRESULT hr;
  3079. DBSEEKDATA SeekData;
  3080. BYTE *pbValue;
  3081. DWORD cbValue;
  3082. BYTE abRangeKey[JET_cbKeyMost];
  3083. DWORD cbRangeKey;
  3084. *pTableFlags = 0;
  3085. if (!IsValidJetTableId(tableid))
  3086. {
  3087. hr = E_HANDLE;
  3088. _JumpError(hr, error, "tableid");
  3089. }
  3090. hr = _JetSeekFromRestriction(pcvr, dwPosition, &SeekData);
  3091. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  3092. {
  3093. hr = S_FALSE;
  3094. }
  3095. _JumpIfError2(hr, error, "_JetSeekFromRestriction", S_FALSE);
  3096. cbValue = pcvr->cbValue;
  3097. pbValue = pcvr->pbValue;
  3098. if (ISTEXTCOLTYP(pdt->dbcoltyp) &&
  3099. NULL != pbValue &&
  3100. cbValue == -1)
  3101. {
  3102. cbValue = wcslen((WCHAR const *) pbValue) * sizeof(WCHAR);
  3103. }
  3104. // If we need to set an index limit, seek to the limit location, and save
  3105. // a copy of the key until after the initial record is located.
  3106. if (CST_SEEKINDEXRANGE & SeekData.SeekFlags)
  3107. {
  3108. hr = _MakeSeekKey(pcs, tableid, pdt, pbValue, cbValue);
  3109. _JumpIfError(hr, error, "_MakeSeekKey");
  3110. CSASSERTTHREAD(pcs);
  3111. hr = _dbgJetSeek(pcs->SesId, tableid, SeekData.grbitSeekRange);
  3112. if ((HRESULT) JET_errRecordNotFound == hr)
  3113. {
  3114. // No record exists past the data we're interested in.
  3115. // Just use the end of the index as the limit.
  3116. _PrintError2(hr, "JetSeek(Range Limit): no key, index end is limit", hr);
  3117. SeekData.SeekFlags &= ~CST_SEEKINDEXRANGE;
  3118. hr = S_OK;
  3119. }
  3120. else if ((HRESULT) JET_wrnSeekNotEqual == hr)
  3121. {
  3122. _PrintError2(hr, "JetSeek(Range): ignoring key not equal", hr);
  3123. hr = S_OK; // Ignore inexact match when seeking >= or <=
  3124. }
  3125. //_JumpIfError2(hr, error, "JetSeek(IndexRange)", S_FALSE);
  3126. _JumpIfError(hr, error, "JetSeek(IndexRange)");
  3127. }
  3128. // If we found a valid key at the limit location, save it now.
  3129. cbRangeKey = 0;
  3130. if (CST_SEEKINDEXRANGE & SeekData.SeekFlags)
  3131. {
  3132. CSASSERTTHREAD(pcs);
  3133. hr = _dbgJetRetrieveKey(
  3134. pcs->SesId,
  3135. tableid,
  3136. abRangeKey,
  3137. ARRAYSIZE(abRangeKey),
  3138. &cbRangeKey,
  3139. 0);
  3140. _JumpIfError(hr, error, "JetRetrieveKey");
  3141. DBGPRINT((DBG_SS_CERTDBI, "RetrieveKey(Range):\n"));
  3142. DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, abRangeKey, cbRangeKey));
  3143. }
  3144. // Locate the initial record: seek to a key or move to one end of the index
  3145. if (CST_SEEKNOTMOVE & SeekData.SeekFlags)
  3146. {
  3147. hr = _MakeSeekKey(pcs, tableid, pdt, pbValue, cbValue);
  3148. _JumpIfError(hr, error, "_MakeSeekKey");
  3149. CSASSERTTHREAD(pcs);
  3150. hr = _dbgJetSeek(pcs->SesId, tableid, SeekData.grbitInitial);
  3151. if ((HRESULT) JET_errRecordNotFound == hr)
  3152. {
  3153. // Routine GetAttribute/Extension call:
  3154. _PrintError2(hr, "JetSeek: Property EMPTY", hr);
  3155. hr = S_FALSE;
  3156. }
  3157. else if ((HRESULT) JET_wrnSeekNotEqual == hr)
  3158. {
  3159. hr = S_OK; // Ignore inexact match when seeking >= or <=
  3160. }
  3161. _JumpIfError2(hr, error, "JetSeek(Initial)", S_FALSE);
  3162. }
  3163. else
  3164. {
  3165. // grbitInitial is a move count here, not a grbit
  3166. CSASSERTTHREAD(pcs);
  3167. hr = _dbgJetMove(pcs->SesId, tableid, SeekData.grbitInitial, 0);
  3168. if ((HRESULT) JET_errNoCurrentRecord == hr)
  3169. {
  3170. // Routine Enumerate call:
  3171. // _JumpIfError(hr, error, "JetMove: no more elements");
  3172. hr = S_FALSE;
  3173. }
  3174. _JumpIfError2(hr, error, "JetMove(End)", S_FALSE);
  3175. // If moving the cursor to the last element, we want to position
  3176. // ourselves to step over the end again (skip the last element).
  3177. //
  3178. // If moving to the first element, we want to position ourselves on the
  3179. // first element and use it before stepping
  3180. if (SEEKPOS_FIRST == dwPosition || SEEKPOS_INDEXFIRST == dwPosition)
  3181. {
  3182. SeekData.SeekFlags |= CST_SEEKUSECURRENT;
  3183. }
  3184. }
  3185. // We're done seeking around; set the index limit from the saved key.
  3186. if (CST_SEEKINDEXRANGE & SeekData.SeekFlags)
  3187. {
  3188. CSASSERTTHREAD(pcs);
  3189. hr = _dbgJetMakeKey(
  3190. pcs->SesId,
  3191. tableid,
  3192. abRangeKey,
  3193. cbRangeKey,
  3194. JET_bitNormalizedKey);
  3195. _JumpIfError(hr, error, "JetMakeKey");
  3196. DBGPRINT((DBG_SS_CERTDBI, "RangeKey:\n"));
  3197. DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, abRangeKey, cbRangeKey));
  3198. CSASSERTTHREAD(pcs);
  3199. hr = _dbgJetSetIndexRange(
  3200. pcs->SesId,
  3201. tableid,
  3202. SeekData.grbitRange);
  3203. if ((HRESULT) JET_errNoCurrentRecord == hr)
  3204. {
  3205. // No records to enumerate:
  3206. _PrintError2(hr, "JetSetIndexRange: no records to enumerate", hr);
  3207. hr = S_FALSE;
  3208. }
  3209. _JumpIfError2(hr, error, "JetSetIndexRange", S_FALSE);
  3210. }
  3211. DBGCODE(_DumpRowId("post-_SeekTable", pcs, tableid));
  3212. DBGCODE(_DumpColumn("post-_SeekTable", pcs, tableid, pdt, pIComputedColumn));
  3213. *pTableFlags = SeekData.SeekFlags;
  3214. error:
  3215. if (S_FALSE == hr)
  3216. {
  3217. DWORD dwPosition2 = dwPosition;
  3218. switch (dwPosition)
  3219. {
  3220. case SEEKPOS_FIRST:
  3221. dwPosition2 = SEEKPOS_INDEXFIRST;
  3222. break;
  3223. case SEEKPOS_LAST:
  3224. dwPosition2 = SEEKPOS_INDEXLAST;
  3225. break;
  3226. }
  3227. if (dwPosition2 != dwPosition)
  3228. {
  3229. hr = _SeekTable(
  3230. pcs,
  3231. tableid,
  3232. pcvr,
  3233. pdt,
  3234. pIComputedColumn,
  3235. dwPosition2,
  3236. pTableFlags
  3237. DBGPARM(pdbaux));
  3238. _PrintIfError2(hr, "_SeekTable: recurse on index first/last", S_FALSE);
  3239. }
  3240. }
  3241. #if DBG_CERTSRV
  3242. if (S_OK != hr)
  3243. {
  3244. DumpRestriction(DBG_SS_CERTDBI, 0, pcvr);
  3245. }
  3246. #endif
  3247. return(myJetHResult(hr));
  3248. }
  3249. HRESULT
  3250. CCertDB::_MoveTable(
  3251. IN CERTSESSION *pcs,
  3252. IN DWORD ccvr,
  3253. IN CERTVIEWRESTRICTION const *pcvr,
  3254. OPTIONAL IN ICertDBComputedColumn *pIComputedColumn,
  3255. IN LONG cskip,
  3256. OUT LONG *pcskipped)
  3257. {
  3258. HRESULT hr;
  3259. DWORD cb;
  3260. DBAUXDATA const *pdbaux;
  3261. DBTABLE const *pdt;
  3262. DWORD icvr;
  3263. LONG lSeek;
  3264. LONG skipIncrement;
  3265. LONG cskipRemain;
  3266. BOOL fHitEnd = FALSE;
  3267. LONG cskippeddummy;
  3268. CERTSESSIONTABLE *pTable;
  3269. CERTSESSIONTABLE *pTable2;
  3270. *pcskipped = 0;
  3271. DBGPRINT((
  3272. DBG_SS_CERTDBI,
  3273. "_MoveTable called(ccvr=%d, cskip=%d, flags=%ws)\n",
  3274. ccvr,
  3275. cskip,
  3276. wszCSFFlags(pcs->SesFlags)));
  3277. hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
  3278. _JumpIfError(hr, error, "_MapPropIdIndex");
  3279. pTable = &pcs->aTable[CSTI_PRIMARY];
  3280. pTable2 = NULL;
  3281. switch (DTI_TABLEMASK & pcvr->ColumnIndex)
  3282. {
  3283. case DTI_REQUESTTABLE:
  3284. pdbaux = &g_dbauxRequests;
  3285. pTable2 = &pcs->aTable[CSTI_CERTIFICATE];
  3286. break;
  3287. case DTI_CERTIFICATETABLE:
  3288. pdbaux = &g_dbauxCertificates;
  3289. pTable = &pcs->aTable[CSTI_CERTIFICATE];
  3290. pTable2 = &pcs->aTable[CSTI_PRIMARY];
  3291. break;
  3292. case DTI_EXTENSIONTABLE:
  3293. pdbaux = &g_dbauxExtensions;
  3294. break;
  3295. case DTI_ATTRIBUTETABLE:
  3296. pdbaux = &g_dbauxAttributes;
  3297. break;
  3298. case DTI_CRLTABLE:
  3299. pdbaux = &g_dbauxCRLs;
  3300. break;
  3301. default:
  3302. hr = E_INVALIDARG;
  3303. _JumpError(hr, error, "ColumnIndex Table");
  3304. }
  3305. DBGPRINT((
  3306. DBG_SS_CERTDBI,
  3307. "_MoveTable(Table=%hs, TableFlags=%ws)\n",
  3308. pdbaux->pszTable,
  3309. wszCSTFlags(pTable->TableFlags)));
  3310. if (NULL != pTable2 && IsValidJetTableId(pTable2->TableId))
  3311. {
  3312. DBGPRINT((
  3313. DBG_SS_CERTDBI,
  3314. "_MoveTable(Table2=%hs, TableFlags2=%ws)\n",
  3315. &g_dbauxCertificates == pdbaux?
  3316. g_dbauxRequests.pszTable :
  3317. g_dbauxCertificates.pszTable,
  3318. wszCSTFlags(pTable2->TableFlags)));
  3319. }
  3320. switch (pcvr->SortOrder)
  3321. {
  3322. case CVR_SORT_DESCEND:
  3323. lSeek = JET_MovePrevious;
  3324. break;
  3325. case CVR_SORT_NONE:
  3326. default:
  3327. CSASSERT(!"bad pcvr->SortOrder"); // shouldn't get this far
  3328. // FALL THROUGH
  3329. case CVR_SORT_ASCEND:
  3330. lSeek = JET_MoveNext;
  3331. break;
  3332. }
  3333. // Add one to the skip count for the implicit Next operation. Next
  3334. // always moves forward one, even when a negative skip count moves
  3335. // backward. The net result may be a forward or backward skip.
  3336. cskipRemain = cskip + 1;
  3337. skipIncrement = 1;
  3338. if (0 > cskipRemain)
  3339. {
  3340. CSASSERT(JET_MoveNext == -1 * JET_MovePrevious);
  3341. lSeek *= -1; // Seek in opposite direction
  3342. cskipRemain *= -1; // make the skip count positive
  3343. skipIncrement = -1;
  3344. }
  3345. CSASSERT(0 <= cskipRemain);
  3346. while (0 != cskipRemain)
  3347. {
  3348. DBGPRINT((
  3349. DBG_SS_CERTDBI,
  3350. "_MoveTable loop: ccvr=%d, cskipRemain=%d, lSeek=%d, flags=%ws\n",
  3351. ccvr,
  3352. cskipRemain,
  3353. lSeek,
  3354. wszCSFFlags(pcs->SesFlags)));
  3355. DBGCODE(_DumpRowId("_MoveTable(loop top)", pcs, pTable->TableId));
  3356. if (CSF_VIEW & pcs->SesFlags)
  3357. {
  3358. hr = TestShutDownState();
  3359. _JumpIfError(hr, error, "TestShutDownState");
  3360. }
  3361. if (CSF_VIEWRESET & pcs->SesFlags)
  3362. {
  3363. hr = _SeekTable(
  3364. pcs,
  3365. pTable->TableId,
  3366. pcvr,
  3367. pdt,
  3368. pIComputedColumn,
  3369. SEEKPOS_FIRST,
  3370. &pTable->TableFlags
  3371. DBGPARM(pdbaux));
  3372. _JumpIfError(hr, error, "_SeekTable");
  3373. pcs->SesFlags &= ~CSF_VIEWRESET;
  3374. }
  3375. if (0 == (CST_SEEKUSECURRENT & pTable->TableFlags))
  3376. {
  3377. CSASSERTTHREAD(pcs);
  3378. hr = _dbgJetMove(pcs->SesId, pTable->TableId, lSeek, 0);
  3379. if ((HRESULT) JET_errNoCurrentRecord == hr)
  3380. {
  3381. _PrintIfError2(hr, "JetMove: no more elements", hr);
  3382. if (fHitEnd)
  3383. {
  3384. // we hit the end trying to backstep! We're done
  3385. hr = S_FALSE;
  3386. _JumpError2(
  3387. hr,
  3388. error,
  3389. "JetMove: db backstep hit beginning",
  3390. hr);
  3391. }
  3392. fHitEnd = TRUE;
  3393. // NOTE: Tough case
  3394. //
  3395. // We just hit the end of the database index, which could be a
  3396. // virtual end or the real end. To recover, we call _SeekTable
  3397. // to position ourselves at the last legal element computed by
  3398. // the 1st restriction, then allow this routine to rewind until
  3399. // we position ourselves on the very last legal element as
  3400. // computed by 2nd through Nth restrictions.
  3401. // Routine Seek call to position at end of enumeration
  3402. hr = _SeekTable(
  3403. pcs,
  3404. pTable->TableId,
  3405. pcvr,
  3406. pdt,
  3407. pIComputedColumn,
  3408. SEEKPOS_LAST, // cursor at end
  3409. &pTable->TableFlags
  3410. DBGPARM(pdbaux));
  3411. _JumpIfError(hr, error, "_SeekTable moving to last elt");
  3412. // now fall through, allow other restrictions to test for 1st
  3413. // valid element
  3414. lSeek *= -1; // Seek in opposite direction
  3415. cskipRemain = 1; // one valid element
  3416. pcskipped = &cskippeddummy; // stop counting skipped rows
  3417. }
  3418. _JumpIfError2(hr, error, "JetMove", S_FALSE);
  3419. DBGCODE(_DumpRowId("_MoveTable(post-move)", pcs, pTable->TableId));
  3420. hr = _CompareColumnValue(pcs, pcvr, pIComputedColumn);
  3421. _JumpIfError2(hr, error, "_CompareColumnValue", S_FALSE);
  3422. }
  3423. pTable->TableFlags &= ~CST_SEEKUSECURRENT;
  3424. // Fetch RowId from the first table, form a key for the second
  3425. // table and seek to the corresponding record in the second table.
  3426. cb = sizeof(pcs->RowId);
  3427. hr = _RetrieveColumn(
  3428. pcs,
  3429. pTable->TableId,
  3430. pdbaux->pdtRowId,
  3431. pdbaux->pdtRowId->dbcolumnid,
  3432. NULL,
  3433. &cb,
  3434. (BYTE *) &pcs->RowId);
  3435. _JumpIfError(hr, error, "_RetrieveColumn");
  3436. DBGPRINT((
  3437. DBG_SS_CERTDBI,
  3438. "_MoveTable(Primary) %hs --> RowId=%d\n",
  3439. pdbaux->pszTable,
  3440. pcs->RowId));
  3441. if (NULL != pTable2 && IsValidJetTableId(pTable2->TableId))
  3442. {
  3443. CSASSERTTHREAD(pcs);
  3444. hr = _dbgJetMakeKey(
  3445. pcs->SesId,
  3446. pTable2->TableId,
  3447. &pcs->RowId,
  3448. sizeof(pcs->RowId),
  3449. JET_bitNewKey);
  3450. _JumpIfError(hr, error, "JetMakeKey");
  3451. hr = _dbgJetSeek(pcs->SesId, pTable2->TableId, JET_bitSeekEQ);
  3452. if ((HRESULT) JET_errRecordNotFound == hr)
  3453. {
  3454. // Database is inconsistent
  3455. hr = S_FALSE;
  3456. }
  3457. _JumpIfError2(hr, error, "JetSeek", S_FALSE);
  3458. DBGPRINT((
  3459. DBG_SS_CERTDBI,
  3460. "_MoveTable(Secondary) %hs --> RowId=%d\n",
  3461. &g_dbauxCertificates == pdbaux?
  3462. g_dbauxRequests.pszTable :
  3463. g_dbauxCertificates.pszTable,
  3464. pcs->RowId));
  3465. }
  3466. // Now verify that any addtional restrictions are satisfied
  3467. for (icvr = 1; icvr < ccvr; icvr++)
  3468. {
  3469. #if 0
  3470. printf(
  3471. "RowId=%u, cvr[%u]: seek=%x, *pb=%x\n",
  3472. pcs->RowId,
  3473. icvr,
  3474. pcvr[icvr].SeekOperator,
  3475. *(DWORD *) pcvr[icvr].pbValue);
  3476. #endif
  3477. hr = _CompareColumnValue(pcs, &pcvr[icvr], pIComputedColumn);
  3478. if (S_FALSE == hr)
  3479. {
  3480. break; // skip row silently
  3481. }
  3482. _JumpIfError(hr, error, "_CompareColumnValue");
  3483. }
  3484. if (icvr >= ccvr)
  3485. {
  3486. *pcskipped += skipIncrement;
  3487. cskipRemain--; // found a matching row
  3488. }
  3489. } // while (cskipRemain)
  3490. error:
  3491. // if we nailed the end and rewound, return failure
  3492. if (fHitEnd && S_OK == hr)
  3493. {
  3494. hr = S_FALSE;
  3495. }
  3496. return(myJetHResult(hr));
  3497. }
  3498. HRESULT
  3499. CCertDB::_GetResultRow(
  3500. IN CERTSESSION *pcs,
  3501. IN DWORD ccvr,
  3502. IN CERTVIEWRESTRICTION const *pcvr,
  3503. IN LONG cskip,
  3504. IN DWORD ccolOut,
  3505. IN DWORD const *acolOut,
  3506. OPTIONAL IN ICertDBComputedColumn *pIComputedColumn,
  3507. OUT CERTDBRESULTROW *pelt,
  3508. OUT LONG *pcskipped)
  3509. {
  3510. HRESULT hr;
  3511. DWORD iCol;
  3512. BYTE *pbProp = NULL;
  3513. BYTE *pbT;
  3514. DWORD cbAlloc = 0;
  3515. DWORD cbProp;
  3516. DBGPRINT((
  3517. DBG_SS_CERTDBI,
  3518. "_GetResultRow(ccvr=%d, ccolOut=%d, cskip=%d, flags=%ws)\n",
  3519. ccvr,
  3520. ccolOut,
  3521. cskip,
  3522. wszCSFFlags(pcs->SesFlags)));
  3523. // This may move past the end of the database index entries.
  3524. // In that case, we're positioned at the end of the index.
  3525. hr = _MoveTable(pcs, ccvr, pcvr, pIComputedColumn, cskip, pcskipped);
  3526. _JumpIfError2(hr, error, "_MoveTable", S_FALSE);
  3527. DBGPRINT((DBG_SS_CERTDBI, "_GetResultRow: RowId=%d\n", pcs->RowId));
  3528. pelt->acol = (CERTDBRESULTCOLUMN *) CoTaskMemAlloc(
  3529. ccolOut * sizeof(pelt->acol[0]));
  3530. if (NULL == pelt->acol)
  3531. {
  3532. hr = E_OUTOFMEMORY;
  3533. _JumpError(hr, error, "alloc acol");
  3534. }
  3535. ZeroMemory(pelt->acol, ccolOut * sizeof(pelt->acol[0]));
  3536. pelt->rowid = pcs->RowId;
  3537. pelt->ccol = ccolOut;
  3538. for (iCol = 0; iCol < ccolOut; iCol++)
  3539. {
  3540. DBTABLE const *pdt;
  3541. CERTDBRESULTCOLUMN *pCol;
  3542. pCol = &pelt->acol[iCol];
  3543. pCol->Index = acolOut[iCol];
  3544. hr = _MapPropIdIndex(pCol->Index, &pdt, &pCol->Type);
  3545. _JumpIfError(hr, error, "_MapPropIdIndex");
  3546. while (TRUE)
  3547. {
  3548. cbProp = cbAlloc;
  3549. hr = GetProperty(pcs, pdt, pIComputedColumn, &cbProp, pbProp);
  3550. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  3551. {
  3552. break; // leave 0 size, NULL pointer
  3553. }
  3554. if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
  3555. {
  3556. _JumpIfError(hr, error, "GetProperty");
  3557. }
  3558. if (cbAlloc >= cbProp)
  3559. {
  3560. CSASSERT(S_OK == hr);
  3561. CSASSERT(0 != cbProp && NULL != pbProp);
  3562. break; // property value is in cbProp, pbProp
  3563. }
  3564. // Property value is too large for the buffer -- grow it
  3565. if (NULL == pbProp)
  3566. {
  3567. pbT = (BYTE *) LocalAlloc(LMEM_FIXED, cbProp);
  3568. }
  3569. else
  3570. {
  3571. pbT = (BYTE *) LocalReAlloc(pbProp, cbProp, LMEM_MOVEABLE);
  3572. }
  3573. if (NULL == pbT)
  3574. {
  3575. hr = E_OUTOFMEMORY;
  3576. _JumpError(hr, error, "LocalAlloc/LocalReAlloc property");
  3577. }
  3578. pbProp = pbT;
  3579. cbAlloc = cbProp;
  3580. }
  3581. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  3582. {
  3583. BYTE const *pb = pbProp;
  3584. if (PROPTYPE_STRING == (PROPTYPE_MASK & pCol->Type))
  3585. {
  3586. CSASSERT(L'\0' == *(WCHAR *) &pbProp[cbProp]);
  3587. cbProp += sizeof(WCHAR); // include NULL term
  3588. }
  3589. pCol->cbValue = cbProp;
  3590. pCol->pbValue = (BYTE *) CoTaskMemAlloc(cbProp);
  3591. if (NULL == pCol->pbValue)
  3592. {
  3593. hr = E_OUTOFMEMORY;
  3594. _JumpError(hr, error, "CoTaskMemAlloc");
  3595. }
  3596. CopyMemory(pCol->pbValue, pb, pCol->cbValue);
  3597. }
  3598. DBGPRINT((
  3599. DBG_SS_CERTDBI,
  3600. "_GetResultRow: fetch %ws.%ws: type=%x cb=%x\n",
  3601. wszTable(pdt->dwTable),
  3602. pdt->pwszPropName,
  3603. pCol->Type,
  3604. pCol->cbValue));
  3605. }
  3606. hr = S_OK;
  3607. error:
  3608. if (NULL != pbProp)
  3609. {
  3610. LocalFree(pbProp);
  3611. }
  3612. return(hr);
  3613. }
  3614. HRESULT
  3615. CCertDB::ReleaseResultRow(
  3616. IN ULONG celt,
  3617. IN OUT CERTDBRESULTROW *rgelt)
  3618. {
  3619. HRESULT hr;
  3620. DWORD iRow;
  3621. DWORD iCol;
  3622. CERTDBRESULTROW *pResultRow;
  3623. if (NULL == rgelt)
  3624. {
  3625. hr = E_POINTER;
  3626. _JumpError(hr, error, "NULL parm");
  3627. }
  3628. for (iRow = 0; iRow < celt; iRow++)
  3629. {
  3630. pResultRow = &rgelt[iRow];
  3631. if (NULL != pResultRow->acol)
  3632. {
  3633. for (iCol = 0; iCol < pResultRow->ccol; iCol++)
  3634. {
  3635. if (NULL != pResultRow->acol[iCol].pbValue)
  3636. {
  3637. CoTaskMemFree(pResultRow->acol[iCol].pbValue);
  3638. pResultRow->acol[iCol].pbValue = NULL;
  3639. }
  3640. }
  3641. CoTaskMemFree(pResultRow->acol);
  3642. pResultRow->acol = NULL;
  3643. }
  3644. pResultRow->ccol = 0;
  3645. }
  3646. hr = S_OK;
  3647. error:
  3648. return(hr);
  3649. }
  3650. HRESULT
  3651. CCertDB::EnumerateSetup(
  3652. IN CERTSESSION *pcs,
  3653. IN OUT DWORD *pFlags,
  3654. OUT JET_TABLEID *ptableid)
  3655. {
  3656. HRESULT hr;
  3657. JET_TABLEID tableid = 0;
  3658. DBAUXDATA const *pdbaux;
  3659. if (NULL == pcs || NULL == ptableid)
  3660. {
  3661. hr = E_POINTER;
  3662. _JumpError(hr, error, "NULL parm");
  3663. }
  3664. switch (*pFlags)
  3665. {
  3666. case CIE_TABLE_ATTRIBUTES:
  3667. pdbaux = &g_dbauxAttributes;
  3668. break;
  3669. case CIE_TABLE_EXTENSIONS:
  3670. pdbaux = &g_dbauxExtensions;
  3671. break;
  3672. default:
  3673. hr = E_INVALIDARG;
  3674. _JumpError(hr, error, "*pFlags");
  3675. }
  3676. CSASSERTTHREAD(pcs);
  3677. hr = _dbgJetOpenTable(
  3678. pcs->SesId,
  3679. pcs->DBId,
  3680. pdbaux->pszTable,
  3681. NULL,
  3682. 0,
  3683. 0,
  3684. &tableid);
  3685. _JumpIfError(hr, error, "JetOpenTable");
  3686. CSASSERTTHREAD(pcs);
  3687. hr = _dbgJetSetCurrentIndex2(
  3688. pcs->SesId,
  3689. tableid,
  3690. pdbaux->pszRowIdIndex,
  3691. JET_bitMoveFirst);
  3692. _JumpIfError(hr, error, "JetSetCurrentIndex2");
  3693. CSASSERTTHREAD(pcs);
  3694. hr = _dbgJetMakeKey(
  3695. pcs->SesId,
  3696. tableid,
  3697. &pcs->RowId,
  3698. sizeof(pcs->RowId),
  3699. JET_bitNewKey);
  3700. _JumpIfError(hr, error, "JetMakeKey");
  3701. *pFlags |= CIE_RESET;
  3702. CSASSERT(IsValidJetTableId(tableid));
  3703. *ptableid = tableid;
  3704. tableid = 0;
  3705. error:
  3706. if (IsValidJetTableId(tableid))
  3707. {
  3708. CSASSERTTHREAD(pcs);
  3709. _dbgJetCloseTable(pcs->SesId, tableid);
  3710. }
  3711. return(myJetHResult(hr));
  3712. }
  3713. HRESULT
  3714. CCertDB::_EnumerateMove(
  3715. IN CERTSESSION *pcs,
  3716. IN OUT DWORD *pFlags,
  3717. IN DBAUXDATA const *pdbaux,
  3718. IN JET_TABLEID tableid,
  3719. IN LONG cskip)
  3720. {
  3721. HRESULT hr;
  3722. DWORD cb;
  3723. DWORD RowId;
  3724. LONG lSeek;
  3725. DBGPRINT((
  3726. DBG_SS_CERTDBI,
  3727. "_EnumerateMove(cskip=%d, flags=%x%hs)\n",
  3728. cskip,
  3729. *pFlags,
  3730. (CIE_RESET & *pFlags)? " Reset" : ""));
  3731. CSASSERT(IsValidJetTableId(tableid));
  3732. if (CIE_RESET & *pFlags)
  3733. {
  3734. CSASSERTTHREAD(pcs);
  3735. hr = _dbgJetSeek(pcs->SesId, tableid, JET_bitSeekEQ);
  3736. if ((HRESULT) JET_errRecordNotFound == hr)
  3737. {
  3738. hr = S_FALSE;
  3739. }
  3740. _JumpIfError2(hr, error, "JetSeek", S_FALSE);
  3741. *pFlags &= ~CIE_RESET;
  3742. }
  3743. else
  3744. {
  3745. // Add one to the skip count for the implicit Next operation. Next
  3746. // always moves forward one, even when a negative skip count moves
  3747. // backward. The net result may be a forward or backward skip.
  3748. cskip++;
  3749. }
  3750. if (0 != cskip)
  3751. {
  3752. lSeek = JET_MoveNext * cskip;
  3753. CSASSERT(JET_MoveNext == -1 * JET_MovePrevious);
  3754. CSASSERTTHREAD(pcs);
  3755. hr = _dbgJetMove(pcs->SesId, tableid, lSeek, 0);
  3756. if ((HRESULT) JET_errNoCurrentRecord == hr)
  3757. {
  3758. hr = S_FALSE;
  3759. }
  3760. _JumpIfError2(hr, error, "JetMove", S_FALSE);
  3761. // Make sure this entry is for the same request:
  3762. cb = sizeof(RowId);
  3763. hr = _RetrieveColumn(
  3764. pcs,
  3765. tableid,
  3766. pdbaux->pdtRowId,
  3767. pdbaux->pdtRowId->dbcolumnid,
  3768. NULL,
  3769. &cb,
  3770. (BYTE *) &RowId);
  3771. _JumpIfError(hr, error, "_RetrieveColumn");
  3772. if (RowId != pcs->RowId)
  3773. {
  3774. hr = S_FALSE;
  3775. goto error;
  3776. }
  3777. }
  3778. hr = S_OK;
  3779. error:
  3780. return(myJetHResult(hr));
  3781. }
  3782. HRESULT
  3783. CCertDB::EnumerateNext(
  3784. IN CERTSESSION *pcs,
  3785. IN OUT DWORD *pFlags,
  3786. IN JET_TABLEID tableid,
  3787. IN LONG cskip,
  3788. IN ULONG celt,
  3789. OUT CERTDBNAME *rgelt,
  3790. OUT ULONG *pceltFetched)
  3791. {
  3792. HRESULT hr;
  3793. DWORD cb;
  3794. CERTDBNAME *pelt;
  3795. WCHAR wszTmp[MAX_PATH];
  3796. DBAUXDATA const *pdbaux;
  3797. if (NULL == pcs || NULL == rgelt || NULL == pceltFetched)
  3798. {
  3799. hr = E_POINTER;
  3800. _JumpError(hr, error, "NULL parm");
  3801. }
  3802. ZeroMemory(rgelt, celt * sizeof(rgelt[0]));
  3803. if (!IsValidJetTableId(tableid))
  3804. {
  3805. hr = E_HANDLE;
  3806. _JumpError(hr, error, "tableid");
  3807. }
  3808. switch (CIE_TABLE_MASK & *pFlags)
  3809. {
  3810. case CIE_TABLE_ATTRIBUTES:
  3811. pdbaux = &g_dbauxAttributes;
  3812. break;
  3813. case CIE_TABLE_EXTENSIONS:
  3814. pdbaux = &g_dbauxExtensions;
  3815. break;
  3816. default:
  3817. hr = E_INVALIDARG;
  3818. _JumpError(hr, error, "*pFlags");
  3819. }
  3820. hr = S_OK;
  3821. for (pelt = rgelt; pelt < &rgelt[celt]; pelt++)
  3822. {
  3823. hr = _EnumerateMove(pcs, pFlags, pdbaux, tableid, cskip);
  3824. if (S_FALSE == hr)
  3825. {
  3826. break;
  3827. }
  3828. _JumpIfError(hr, error, "_EnumerateMove");
  3829. cskip = 0;
  3830. cb = sizeof(wszTmp);
  3831. hr = _RetrieveColumn(
  3832. pcs,
  3833. tableid,
  3834. pdbaux->pdtName,
  3835. pdbaux->pdtName->dbcolumnid,
  3836. NULL,
  3837. &cb,
  3838. (BYTE *) wszTmp);
  3839. _JumpIfError(hr, error, "_RetrieveColumn");
  3840. CSASSERT(0 == (cb % sizeof(WCHAR))); // integer # of wchars
  3841. CSASSERT(L'\0' == wszTmp[cb / sizeof(WCHAR)]); // zero term
  3842. hr = _DupString(NULL, wszTmp, &pelt->pwszName);
  3843. _JumpIfError(hr, error, "_DupString");
  3844. }
  3845. *pceltFetched = SAFE_SUBTRACT_POINTERS(pelt, rgelt);
  3846. error:
  3847. if (S_OK != hr && S_FALSE != hr)
  3848. {
  3849. if (NULL != rgelt)
  3850. {
  3851. for (pelt = rgelt; pelt < &rgelt[celt]; pelt++)
  3852. {
  3853. if (NULL != pelt->pwszName)
  3854. {
  3855. CoTaskMemFree(pelt->pwszName);
  3856. pelt->pwszName = NULL;
  3857. }
  3858. }
  3859. }
  3860. }
  3861. return(myJetHResult(hr));
  3862. }
  3863. HRESULT
  3864. CCertDB::EnumerateClose(
  3865. IN CERTSESSION *pcs,
  3866. IN JET_TABLEID tableid)
  3867. {
  3868. HRESULT hr;
  3869. if (NULL == pcs)
  3870. {
  3871. hr = E_POINTER;
  3872. _JumpError(hr, error, "NULL parm");
  3873. }
  3874. if (!IsValidJetTableId(tableid))
  3875. {
  3876. hr = E_HANDLE;
  3877. _JumpError(hr, error, "tableid");
  3878. }
  3879. CSASSERTTHREAD(pcs);
  3880. hr = _dbgJetCloseTable(pcs->SesId, tableid);
  3881. _JumpIfError(hr, error, "JetCloseTable");
  3882. error:
  3883. return(myJetHResult(hr));
  3884. }
  3885. HRESULT
  3886. CCertDB::_BuildColumnIds(
  3887. IN CERTSESSION *pcs,
  3888. IN CHAR const *pszTableName,
  3889. IN DBTABLE *pdt)
  3890. {
  3891. HRESULT hr;
  3892. JET_TABLEID tableid;
  3893. JET_COLUMNDEF columndef;
  3894. BOOL fOpen = FALSE;
  3895. hr = _dbgJetOpenTable(
  3896. pcs->SesId,
  3897. pcs->DBId,
  3898. pszTableName,
  3899. NULL,
  3900. 0,
  3901. 0,
  3902. &tableid);
  3903. _JumpIfError(hr, error, "JetOpenTable");
  3904. fOpen = TRUE;
  3905. CSASSERT(IsValidJetTableId(tableid));
  3906. for ( ; NULL != pdt->pwszPropName; pdt++)
  3907. {
  3908. if (DBTF_COMPUTED & pdt->dwFlags)
  3909. {
  3910. ZeroMemory(&columndef, sizeof(columndef));
  3911. columndef.cbStruct = sizeof(columndef);
  3912. //columndef.columnid = 0;
  3913. columndef.coltyp = JET_coltypLong;
  3914. columndef.cbMax = sizeof(LONG);
  3915. //columndef.grbit = 0;
  3916. }
  3917. else
  3918. {
  3919. hr = _dbgJetGetColumnInfo(
  3920. pcs->SesId,
  3921. pcs->DBId,
  3922. pszTableName,
  3923. pdt->pszFieldName,
  3924. &columndef,
  3925. sizeof(columndef),
  3926. JET_ColInfo);
  3927. if ((HRESULT) JET_errColumnNotFound == hr &&
  3928. (DBTF_SOFTFAIL & pdt->dwFlags))
  3929. {
  3930. pdt->dwFlags |= DBTF_MISSING;
  3931. pdt->dbcolumnid = MAXDWORD;
  3932. DBGPRINT((
  3933. DBG_SS_CERTDB,
  3934. "_BuildColumnIds: %hs.%hs Ignoring missing column\n",
  3935. pszTableName,
  3936. pdt->pszFieldName));
  3937. hr = S_OK;
  3938. continue;
  3939. }
  3940. _JumpIfError(hr, error, "JetGetColumnInfo");
  3941. }
  3942. pdt->dbcolumnid = columndef.columnid;
  3943. CSASSERT(
  3944. pdt->dbcoltyp == columndef.coltyp ||
  3945. (ISTEXTCOLTYP(pdt->dbcoltyp) && ISTEXTCOLTYP(columndef.coltyp)));
  3946. if (JET_coltypText == pdt->dbcoltyp)
  3947. {
  3948. CSASSERT(pdt->dwcbMax == pdt->dbcolumnMax);
  3949. CSASSERT(0 != pdt->dbcolumnMax);
  3950. CSASSERT(CB_DBMAXTEXT_MAXINTERNAL >= pdt->dbcolumnMax);
  3951. }
  3952. else if (JET_coltypLongText == pdt->dbcoltyp)
  3953. {
  3954. CSASSERT(pdt->dwcbMax == pdt->dbcolumnMax);
  3955. CSASSERT(CB_DBMAXTEXT_MAXINTERNAL < pdt->dbcolumnMax);
  3956. }
  3957. else if (JET_coltypLongBinary == pdt->dbcoltyp)
  3958. {
  3959. CSASSERT(pdt->dwcbMax == pdt->dbcolumnMax);
  3960. CSASSERT(0 != pdt->dbcolumnMax);
  3961. }
  3962. else if (JET_coltypDateTime == pdt->dbcoltyp)
  3963. {
  3964. CSASSERT(sizeof(DATE) == pdt->dwcbMax);
  3965. CSASSERT(0 == pdt->dbcolumnMax);
  3966. }
  3967. else if (JET_coltypLong == pdt->dbcoltyp)
  3968. {
  3969. CSASSERT(sizeof(LONG) == pdt->dwcbMax);
  3970. CSASSERT(0 == pdt->dbcolumnMax);
  3971. }
  3972. else
  3973. {
  3974. DBGPRINT((
  3975. DBG_SS_CERTDB,
  3976. "_BuildColumnIds: %hs.%hs Unknown column type %u\n",
  3977. pszTableName,
  3978. pdt->pszFieldName,
  3979. pdt->dbcoltyp));
  3980. CSASSERT(!"Unknown column type");
  3981. }
  3982. if (pdt->dwcbMax != columndef.cbMax)
  3983. {
  3984. DBGPRINT((
  3985. DBG_SS_CERTDB,
  3986. "_BuildColumnIds: %hs.%hs length %u, expected %u\n",
  3987. pszTableName,
  3988. pdt->pszFieldName,
  3989. columndef.cbMax,
  3990. pdt->dwcbMax));
  3991. // max size can only be increased...
  3992. if (pdt->dwcbMax > columndef.cbMax)
  3993. {
  3994. JET_DDLMAXCOLUMNSIZE jdmcs;
  3995. jdmcs.szTable = const_cast<char *>(pszTableName);
  3996. jdmcs.szColumn = const_cast<char *>(pdt->pszFieldName);
  3997. jdmcs.cbMax = pdt->dwcbMax;
  3998. hr = _dbgJetConvertDDL(
  3999. pcs->SesId,
  4000. pcs->DBId,
  4001. opDDLConvIncreaseMaxColumnSize,
  4002. &jdmcs,
  4003. sizeof(jdmcs));
  4004. _PrintIfError(hr, "JetConvertDDL");
  4005. if (S_OK == hr)
  4006. {
  4007. m_fDBRestart = TRUE;
  4008. DBGPRINT((
  4009. DBG_SS_CERTDB,
  4010. "Increased Column Size: %hs.%hs: %x->%x\n",
  4011. jdmcs.szTable,
  4012. jdmcs.szColumn,
  4013. columndef.cbMax,
  4014. jdmcs.cbMax));
  4015. }
  4016. }
  4017. }
  4018. pdt->dbcolumnidOld = MAXDWORD;
  4019. if (chTEXTPREFIX == *pdt->pszFieldName ||
  4020. (DBTF_COLUMNRENAMED & pdt->dwFlags))
  4021. {
  4022. char const *pszFieldName = &pdt->pszFieldName[1];
  4023. if (DBTF_COLUMNRENAMED & pdt->dwFlags)
  4024. {
  4025. pszFieldName += strlen(pszFieldName) + 1;
  4026. }
  4027. CSASSERT(
  4028. chTEXTPREFIX != *pszTableName ||
  4029. ISTEXTCOLTYP(columndef.coltyp));
  4030. hr = _dbgJetGetColumnInfo(
  4031. pcs->SesId,
  4032. pcs->DBId,
  4033. pszTableName,
  4034. pszFieldName,
  4035. &columndef,
  4036. sizeof(columndef),
  4037. JET_ColInfo);
  4038. if (S_OK == hr)
  4039. {
  4040. CSASSERT(
  4041. chTEXTPREFIX != *pszTableName ||
  4042. ISTEXTCOLTYP(columndef.coltyp));
  4043. DBGPRINT((
  4044. DBG_SS_CERTDB,
  4045. "Found Old Column: %hs.%hs: %x\n",
  4046. pszTableName,
  4047. pszFieldName,
  4048. columndef.columnid));
  4049. pdt->dwFlags |= DBTF_OLDCOLUMNID;
  4050. pdt->dbcolumnidOld = columndef.columnid;
  4051. m_fFoundOldColumns = TRUE;
  4052. }
  4053. hr = S_OK;
  4054. }
  4055. }
  4056. error:
  4057. if (fOpen)
  4058. {
  4059. HRESULT hr2;
  4060. hr2 = _dbgJetCloseTable(pcs->SesId, tableid);
  4061. _PrintIfError(hr2, "JetCloseTable");
  4062. if (S_OK == hr)
  4063. {
  4064. hr = hr2;
  4065. }
  4066. }
  4067. return(myJetHResult(hr));
  4068. }
  4069. HRESULT
  4070. CCertDB::_AddKeyLengthColumn(
  4071. IN CERTSESSION *pcs,
  4072. IN JET_TABLEID tableid,
  4073. IN DWORD DBGPARMREFERENCED(RowId),
  4074. IN DBTABLE const *pdtPublicKey,
  4075. IN DBTABLE const *pdtPublicKeyAlgorithm,
  4076. IN DBTABLE const *pdtPublicKeyParameters,
  4077. IN DBTABLE const *pdtPublicKeyLength,
  4078. IN DBAUXDATA const *DBGPARMREFERENCED(pdbaux),
  4079. IN OUT BYTE **ppbBuf,
  4080. IN OUT DWORD *pcbBuf)
  4081. {
  4082. HRESULT hr;
  4083. DWORD cb;
  4084. DWORD KeyLength;
  4085. CERT_PUBLIC_KEY_INFO PublicKeyInfo;
  4086. ZeroMemory(&PublicKeyInfo, sizeof(PublicKeyInfo));
  4087. DBGPRINT((
  4088. DBG_SS_CERTDBI,
  4089. "Computing %hs[%d].%hs\n",
  4090. pdbaux->pszTable,
  4091. RowId,
  4092. pdtPublicKeyLength->pszFieldName));
  4093. cb = sizeof(KeyLength);
  4094. hr = _RetrieveColumn(
  4095. pcs,
  4096. tableid,
  4097. pdtPublicKeyLength,
  4098. pdtPublicKeyLength->dbcolumnid,
  4099. NULL,
  4100. &cb,
  4101. (BYTE *) &KeyLength);
  4102. if (S_OK == hr)
  4103. {
  4104. goto error; // already set -- skip this column
  4105. }
  4106. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  4107. {
  4108. _JumpError(hr, error, "_RetrieveColumn");
  4109. }
  4110. // Fetch the public key algorithm ObjId & copy as ansi to alloc'd memory.
  4111. hr = _RetrieveColumnBuffer(
  4112. pcs,
  4113. tableid,
  4114. pdtPublicKeyAlgorithm,
  4115. pdtPublicKeyAlgorithm->dbcolumnid,
  4116. &cb,
  4117. ppbBuf,
  4118. pcbBuf);
  4119. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  4120. {
  4121. hr = S_OK;
  4122. goto error; // No old data -- skip this column
  4123. }
  4124. _JumpIfErrorStr(
  4125. hr,
  4126. error,
  4127. "_RetrieveColumnBuffer",
  4128. pdtPublicKeyAlgorithm->pwszPropName);
  4129. if (!ConvertWszToSz(
  4130. &PublicKeyInfo.Algorithm.pszObjId,
  4131. (WCHAR const *) *ppbBuf,
  4132. -1))
  4133. {
  4134. hr = E_OUTOFMEMORY;
  4135. _JumpError(hr, error, "ConvertWszToSz(LogDir)");
  4136. }
  4137. // Fetch the public key algorithm paramaters, and copy to alloc'd memory.
  4138. hr = _RetrieveColumnBuffer(
  4139. pcs,
  4140. tableid,
  4141. pdtPublicKeyParameters,
  4142. pdtPublicKeyParameters->dbcolumnid,
  4143. &PublicKeyInfo.Algorithm.Parameters.cbData,
  4144. ppbBuf,
  4145. pcbBuf);
  4146. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  4147. {
  4148. hr = S_OK;
  4149. goto error; // No old data -- skip this column
  4150. }
  4151. _JumpIfErrorStr(
  4152. hr,
  4153. error,
  4154. "_RetrieveColumnBuffer",
  4155. pdtPublicKeyParameters->pwszPropName);
  4156. PublicKeyInfo.Algorithm.Parameters.pbData = (BYTE *) LocalAlloc(
  4157. LMEM_FIXED,
  4158. PublicKeyInfo.Algorithm.Parameters.cbData);
  4159. if (NULL == PublicKeyInfo.Algorithm.Parameters.pbData)
  4160. {
  4161. hr = E_OUTOFMEMORY;
  4162. _JumpError(hr, error, "ConvertWszToSz(LogDir)");
  4163. }
  4164. CopyMemory(
  4165. PublicKeyInfo.Algorithm.Parameters.pbData,
  4166. *ppbBuf,
  4167. PublicKeyInfo.Algorithm.Parameters.cbData);
  4168. // Fetch the public key, and leave in dynamic buffer.
  4169. hr = _RetrieveColumnBuffer(
  4170. pcs,
  4171. tableid,
  4172. pdtPublicKey,
  4173. pdtPublicKey->dbcolumnid,
  4174. &PublicKeyInfo.PublicKey.cbData,
  4175. ppbBuf,
  4176. pcbBuf);
  4177. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  4178. {
  4179. hr = S_OK;
  4180. goto error; // No old data -- skip this column
  4181. }
  4182. _JumpIfErrorStr(
  4183. hr,
  4184. error,
  4185. "_RetrieveColumnBuffer",
  4186. pdtPublicKey->pwszPropName);
  4187. PublicKeyInfo.PublicKey.pbData = *ppbBuf;
  4188. KeyLength = CertGetPublicKeyLength(X509_ASN_ENCODING, &PublicKeyInfo);
  4189. // Store the key length in the new column
  4190. hr = _SetColumn(
  4191. pcs->SesId,
  4192. tableid,
  4193. pdtPublicKeyLength,
  4194. pdtPublicKeyLength->dbcolumnid,
  4195. sizeof(KeyLength),
  4196. (BYTE const *) &KeyLength);
  4197. _JumpIfErrorStr(hr, error, "_SetColumn", pdtPublicKeyLength->pwszPropName);
  4198. DBGPRINT((
  4199. DBG_SS_CERTDB,
  4200. "Computed %hs[%d].%hs: %u\n",
  4201. pdbaux->pszTable,
  4202. RowId,
  4203. pdtPublicKeyLength->pszFieldName,
  4204. KeyLength));
  4205. error:
  4206. if (NULL != PublicKeyInfo.Algorithm.pszObjId)
  4207. {
  4208. LocalFree(PublicKeyInfo.Algorithm.pszObjId);
  4209. }
  4210. if (NULL != PublicKeyInfo.Algorithm.Parameters.pbData)
  4211. {
  4212. LocalFree(PublicKeyInfo.Algorithm.Parameters.pbData);
  4213. }
  4214. return(hr);
  4215. }
  4216. HRESULT
  4217. CCertDB::_AddCallerName(
  4218. IN CERTSESSION *pcs,
  4219. IN JET_TABLEID tableid,
  4220. IN DWORD DBGPARMREFERENCED(RowId),
  4221. IN DBTABLE const *pdtCallerName,
  4222. IN DBTABLE const *pdtRequesterName,
  4223. IN DBAUXDATA const *DBGPARMREFERENCED(pdbaux),
  4224. IN OUT BYTE **ppbBuf,
  4225. IN OUT DWORD *pcbBuf)
  4226. {
  4227. HRESULT hr;
  4228. DWORD cb;
  4229. DBGPRINT((
  4230. DBG_SS_CERTDBI,
  4231. "Copying %hs[%d].%hs\n",
  4232. pdbaux->pszTable,
  4233. RowId,
  4234. pdtCallerName->pszFieldName));
  4235. cb = 0;
  4236. hr = _RetrieveColumn(
  4237. pcs,
  4238. tableid,
  4239. pdtCallerName,
  4240. pdtCallerName->dbcolumnid,
  4241. NULL,
  4242. &cb,
  4243. NULL);
  4244. if (S_OK == hr)
  4245. {
  4246. goto error; // already set -- skip this column
  4247. }
  4248. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  4249. {
  4250. _JumpError(hr, error, "_RetrieveColumn");
  4251. }
  4252. // Fetch the ReqesterName
  4253. hr = _RetrieveColumnBuffer(
  4254. pcs,
  4255. tableid,
  4256. pdtRequesterName,
  4257. pdtRequesterName->dbcolumnid,
  4258. &cb,
  4259. ppbBuf,
  4260. pcbBuf);
  4261. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  4262. {
  4263. hr = S_OK;
  4264. goto error; // No old data -- skip this column
  4265. }
  4266. _JumpIfErrorStr(
  4267. hr,
  4268. error,
  4269. "_RetrieveColumnBuffer",
  4270. pdtRequesterName->pwszPropName);
  4271. // Store the RequesterName as the CallerName in the new column
  4272. hr = _SetColumn(
  4273. pcs->SesId,
  4274. tableid,
  4275. pdtCallerName,
  4276. pdtCallerName->dbcolumnid,
  4277. cb,
  4278. *ppbBuf);
  4279. _JumpIfErrorStr(hr, error, "_SetColumn", pdtCallerName->pwszPropName);
  4280. DBGPRINT((
  4281. DBG_SS_CERTDB,
  4282. "Copied %hs[%d].%hs: %ws\n",
  4283. pdbaux->pszTable,
  4284. RowId,
  4285. pdtCallerName->pszFieldName,
  4286. *ppbBuf));
  4287. error:
  4288. return(hr);
  4289. }
  4290. HRESULT
  4291. CCertDB::_SetHashColumnIfEmpty(
  4292. IN CERTSESSION *pcs,
  4293. IN JET_TABLEID tableid,
  4294. IN DWORD DBGPARMREFERENCED(RowId),
  4295. IN DBTABLE const *pdtHash,
  4296. IN DBAUXDATA const *DBGPARMREFERENCED(pdbaux),
  4297. IN BYTE const *pbHash,
  4298. IN DWORD cbHash)
  4299. {
  4300. HRESULT hr;
  4301. DWORD cb;
  4302. BSTR strHash = NULL;
  4303. cb = 0;
  4304. hr = _RetrieveColumn(
  4305. pcs,
  4306. tableid,
  4307. pdtHash,
  4308. pdtHash->dbcolumnid,
  4309. NULL,
  4310. &cb,
  4311. NULL);
  4312. if (S_OK == hr)
  4313. {
  4314. goto error; // already set -- skip this column...
  4315. }
  4316. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  4317. {
  4318. _JumpError(hr, error, "_RetrieveColumn");
  4319. }
  4320. hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash);
  4321. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  4322. // Store the computed hash.
  4323. hr = _SetColumn(
  4324. pcs->SesId,
  4325. tableid,
  4326. pdtHash,
  4327. pdtHash->dbcolumnid,
  4328. wcslen(strHash) * sizeof(WCHAR),
  4329. (BYTE const *) strHash);
  4330. _JumpIfErrorStr(hr, error, "_SetColumn", pdtHash->pwszPropName);
  4331. DBGPRINT((
  4332. DBG_SS_CERTDB,
  4333. "Derived %hs[%d].%hs: %ws\n",
  4334. pdbaux->pszTable,
  4335. RowId,
  4336. pdtHash->pszFieldName,
  4337. strHash));
  4338. error:
  4339. if (NULL != strHash)
  4340. {
  4341. SysFreeString(strHash);
  4342. }
  4343. return(hr);
  4344. }
  4345. HRESULT
  4346. CCertDB::_AddCertColumns(
  4347. IN CERTSESSION *pcs,
  4348. IN JET_TABLEID tableid,
  4349. IN DWORD RowId,
  4350. IN DBTABLE const *pdtCertHash,
  4351. IN DBTABLE const *pdtSKI,
  4352. IN DBTABLE const *pdtCert,
  4353. IN DBAUXDATA const *pdbaux,
  4354. IN OUT BYTE **ppbBuf,
  4355. IN OUT DWORD *pcbBuf)
  4356. {
  4357. HRESULT hr;
  4358. CERT_CONTEXT const *pcc = NULL;
  4359. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  4360. DWORD cb;
  4361. BYTE *pbSKI = NULL;
  4362. DBGPRINT((
  4363. DBG_SS_CERTDBI,
  4364. "Deriving from %hs[%d].%hs\n",
  4365. pdbaux->pszTable,
  4366. RowId,
  4367. pdtCert->pszFieldName));
  4368. // Fetch the Cert
  4369. hr = _RetrieveColumnBuffer(
  4370. pcs,
  4371. tableid,
  4372. pdtCert,
  4373. pdtCert->dbcolumnid,
  4374. &cb,
  4375. ppbBuf,
  4376. pcbBuf);
  4377. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  4378. {
  4379. hr = S_OK;
  4380. goto error; // No old data -- skip this row
  4381. }
  4382. _JumpIfErrorStr(
  4383. hr,
  4384. error,
  4385. "_RetrieveColumnBuffer",
  4386. pdtCert->pwszPropName);
  4387. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, *ppbBuf, *pcbBuf);
  4388. if (NULL == pcc)
  4389. {
  4390. hr = myHLastError();
  4391. _JumpError(hr, error, "CertCreateCertificateContext");
  4392. }
  4393. if (NULL != pdtCertHash)
  4394. {
  4395. cb = sizeof(abHash);
  4396. if (!CertGetCertificateContextProperty(
  4397. pcc,
  4398. CERT_SHA1_HASH_PROP_ID,
  4399. abHash,
  4400. &cb))
  4401. {
  4402. hr = myHLastError();
  4403. _JumpError(hr, error, "CertGetCertificateContextProperty");
  4404. }
  4405. hr = _SetHashColumnIfEmpty(
  4406. pcs,
  4407. tableid,
  4408. RowId,
  4409. pdtCertHash,
  4410. pdbaux,
  4411. abHash,
  4412. cb);
  4413. _JumpIfError(hr, error, "_SetHashColumnIfEmpty");
  4414. }
  4415. if (NULL != pdtSKI)
  4416. {
  4417. hr = myGetPublicKeyHash(
  4418. pcc->pCertInfo,
  4419. &pcc->pCertInfo->SubjectPublicKeyInfo,
  4420. &pbSKI,
  4421. &cb);
  4422. _JumpIfError(hr, error, "myGetPublicKeyHash");
  4423. hr = _SetHashColumnIfEmpty(
  4424. pcs,
  4425. tableid,
  4426. RowId,
  4427. pdtSKI,
  4428. pdbaux,
  4429. pbSKI,
  4430. cb);
  4431. _JumpIfError(hr, error, "_SetHashColumnIfEmpty");
  4432. }
  4433. hr = S_OK;
  4434. error:
  4435. if (NULL != pcc)
  4436. {
  4437. CertFreeCertificateContext(pcc);
  4438. }
  4439. if (NULL != pbSKI)
  4440. {
  4441. LocalFree(pbSKI);
  4442. }
  4443. return(hr);
  4444. }
  4445. HRESULT
  4446. CCertDB::_ConvertColumnData(
  4447. IN CERTSESSION *pcs,
  4448. IN JET_TABLEID tableid,
  4449. IN DWORD DBGPARMREFERENCED(RowId),
  4450. IN DBTABLE const *pdt,
  4451. IN DBAUXDATA const *DBGPARMREFERENCED(pdbaux),
  4452. IN OUT BYTE **ppbBuf,
  4453. IN OUT DWORD *pcbBuf)
  4454. {
  4455. HRESULT hr;
  4456. WCHAR *pwszNew = NULL;
  4457. BYTE const *pbNew;
  4458. DWORD cb;
  4459. DBGPRINT((
  4460. DBG_SS_CERTDBI,
  4461. "Converting %hs[%d].%hs:\n",
  4462. pdbaux->pszTable,
  4463. RowId,
  4464. pdt->pszFieldName));
  4465. // Fetch old column. Grows the buffer if necessary.
  4466. hr = _RetrieveColumnBuffer(
  4467. pcs,
  4468. tableid,
  4469. pdt,
  4470. pdt->dbcolumnidOld,
  4471. &cb,
  4472. ppbBuf,
  4473. pcbBuf);
  4474. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  4475. {
  4476. hr = S_OK;
  4477. goto error; // No old data -- skip this column
  4478. }
  4479. _JumpIfErrorStr(hr, error, "_RetrieveColumnBuffer", pdt->pwszPropName);
  4480. if (DBTF_COLUMNRENAMED & pdt->dwFlags)
  4481. {
  4482. pbNew = *ppbBuf;
  4483. }
  4484. else
  4485. {
  4486. if (!ConvertSzToWsz(&pwszNew, (char *) *ppbBuf, -1))
  4487. {
  4488. hr = E_OUTOFMEMORY;
  4489. _JumpError(hr, error, "ConvertSzToWsz");
  4490. }
  4491. pbNew = (BYTE const *) pwszNew;
  4492. cb = wcslen(pwszNew) * sizeof(WCHAR);
  4493. }
  4494. // Store the converted string in the Unicode column
  4495. hr = _SetColumn(pcs->SesId, tableid, pdt, pdt->dbcolumnid, cb, pbNew);
  4496. _JumpIfErrorStr(hr, error, "_SetColumn", pdt->pwszPropName);
  4497. if (JET_coltypLong != pdt->dbcoltyp)
  4498. {
  4499. // Clear out the old column
  4500. hr = _SetColumn(pcs->SesId, tableid, pdt, pdt->dbcolumnidOld, 0, NULL);
  4501. _JumpIfErrorStr(hr, error, "_SetColumn(Clear old)", pdt->pwszPropName);
  4502. }
  4503. DBGPRINT((
  4504. DBG_SS_CERTDB,
  4505. "Converted %hs[%d].%hs: %ws\n",
  4506. pdbaux->pszTable,
  4507. RowId,
  4508. pdt->pszFieldName,
  4509. ISTEXTCOLTYP(pdt->dbcoltyp)? (WCHAR const *) pbNew : L""));
  4510. if (!ISTEXTCOLTYP(pdt->dbcoltyp))
  4511. {
  4512. DBGDUMPHEX((DBG_SS_CERTDB, DH_NOADDRESS, pbNew, cb));
  4513. }
  4514. error:
  4515. if (NULL != pwszNew)
  4516. {
  4517. LocalFree(pwszNew);
  4518. }
  4519. return(hr);
  4520. }
  4521. DBTABLE *
  4522. dbFindColumn(
  4523. IN DBTABLE *adt,
  4524. IN char const *pszFieldName)
  4525. {
  4526. DBTABLE *pdt;
  4527. DBTABLE *pdtRet = NULL;
  4528. for (pdt = adt; NULL != pdt->pwszPropName; pdt++)
  4529. {
  4530. if (0 == _stricmp(pszFieldName, pdt->pszFieldName))
  4531. {
  4532. pdtRet = pdt;
  4533. break;
  4534. }
  4535. }
  4536. return(pdtRet);
  4537. }
  4538. HRESULT
  4539. CCertDB::_ConvertOldColumnData(
  4540. IN CERTSESSION *pcs,
  4541. IN CHAR const *pszTableName,
  4542. IN DBAUXDATA const *pdbaux,
  4543. IN DBTABLE *adt)
  4544. {
  4545. HRESULT hr;
  4546. HRESULT hr2;
  4547. JET_TABLEID tableid;
  4548. BOOL fOpen = FALSE;
  4549. BOOL fTransacted = FALSE;
  4550. DBTABLE *pdt;
  4551. DWORD RowId;
  4552. DWORD cb;
  4553. BYTE *pbBuf = NULL;
  4554. DWORD cbBuf = 0;
  4555. BOOL fZeroIssuerNameId = FALSE;
  4556. DWORD IssuerNameId;
  4557. DBTABLE *pdtPublicKeyLength = NULL;
  4558. DBTABLE *pdtPublicKey = NULL;
  4559. DBTABLE *pdtPublicKeyAlgorithm = NULL;
  4560. DBTABLE *pdtPublicKeyParameters = NULL;
  4561. DBTABLE *pdtCallerName = NULL;
  4562. DBTABLE *pdtRequesterName;
  4563. DBTABLE *pdtCert = NULL;
  4564. DBTABLE *pdtCertHash;
  4565. DBTABLE *pdtSKI;
  4566. hr = _dbgJetOpenTable(
  4567. pcs->SesId,
  4568. pcs->DBId,
  4569. pszTableName,
  4570. NULL,
  4571. 0,
  4572. 0,
  4573. &tableid);
  4574. _JumpIfError(hr, error, "JetOpenTable");
  4575. fOpen = TRUE;
  4576. // Step through the RowId index for this table.
  4577. CSASSERT(IsValidJetTableId(tableid));
  4578. hr = _dbgJetSetCurrentIndex2(
  4579. pcs->SesId,
  4580. tableid,
  4581. pdbaux->pszRowIdIndex,
  4582. JET_bitMoveFirst);
  4583. _JumpIfError(hr, error, "JetSetCurrentIndex2");
  4584. if (NULL != pdbaux->pdtIssuerNameId)
  4585. {
  4586. cb = sizeof(IssuerNameId);
  4587. hr = _RetrieveColumn(
  4588. pcs,
  4589. tableid,
  4590. pdbaux->pdtIssuerNameId,
  4591. pdbaux->pdtIssuerNameId->dbcolumnid,
  4592. NULL,
  4593. &cb,
  4594. (BYTE *) &IssuerNameId);
  4595. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  4596. {
  4597. fZeroIssuerNameId = TRUE;
  4598. }
  4599. else
  4600. {
  4601. // swallow error if empty database
  4602. _PrintIfErrorStr2(
  4603. hr,
  4604. "_RetrieveColumn",
  4605. pdbaux->pdtIssuerNameId->pwszPropName,
  4606. myJetHResult(JET_errNoCurrentRecord));
  4607. }
  4608. }
  4609. pdtPublicKeyLength = dbFindColumn(adt, szPUBLICKEYLENGTH);
  4610. if (NULL != pdtPublicKeyLength)
  4611. {
  4612. pdtPublicKey = dbFindColumn(adt, szPUBLICKEY);
  4613. pdtPublicKeyAlgorithm = dbFindColumn(adt, szPUBLICKEYALGORITHM);
  4614. pdtPublicKeyParameters = dbFindColumn(adt, szPUBLICKEYPARAMS);
  4615. if (NULL == pdtPublicKey ||
  4616. NULL == pdtPublicKeyAlgorithm ||
  4617. NULL == pdtPublicKeyParameters)
  4618. {
  4619. pdtPublicKeyLength = NULL;
  4620. }
  4621. else
  4622. {
  4623. hr = _RetrieveColumn(
  4624. pcs,
  4625. tableid,
  4626. pdtPublicKeyLength,
  4627. pdtPublicKeyLength->dbcolumnid,
  4628. NULL,
  4629. &cb,
  4630. NULL);
  4631. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  4632. {
  4633. pdtPublicKeyLength = NULL;
  4634. }
  4635. }
  4636. }
  4637. pdtRequesterName = NULL;
  4638. pdtCallerName = dbFindColumn(adt, szCALLERNAME);
  4639. if (NULL != pdtCallerName)
  4640. {
  4641. DBTABLE *pdtDisposition;
  4642. pdtRequesterName = dbFindColumn(adt, szREQUESTERNAME);
  4643. pdtDisposition = dbFindColumn(adt, szDISPOSITION);
  4644. if (NULL == pdtRequesterName || NULL == pdtDisposition)
  4645. {
  4646. pdtCallerName = NULL;
  4647. }
  4648. else
  4649. {
  4650. // Find the first row containing a bonafide request:
  4651. for (;;)
  4652. {
  4653. BOOL fSkip;
  4654. LONG Disposition;
  4655. cb = sizeof(Disposition);
  4656. hr = _RetrieveColumn(
  4657. pcs,
  4658. tableid,
  4659. pdtDisposition,
  4660. pdtDisposition->dbcolumnid,
  4661. NULL,
  4662. &cb,
  4663. (BYTE *) &Disposition);
  4664. if (S_OK != hr)
  4665. {
  4666. _PrintError(hr, "_RetrieveColumn");
  4667. pdtCallerName = NULL;
  4668. break;
  4669. }
  4670. switch (Disposition)
  4671. {
  4672. case DB_DISP_PENDING:
  4673. case DB_DISP_DENIED:
  4674. case DB_DISP_ISSUED:
  4675. case DB_DISP_REVOKED:
  4676. fSkip = FALSE;
  4677. break;
  4678. default:
  4679. fSkip = TRUE;
  4680. break;
  4681. }
  4682. if (!fSkip)
  4683. {
  4684. break;
  4685. }
  4686. hr = _dbgJetMove(pcs->SesId, tableid, JET_MoveNext, 0);
  4687. if (S_OK != hr)
  4688. {
  4689. _PrintError(hr, "JetMove");
  4690. pdtCallerName = NULL;
  4691. break;
  4692. }
  4693. }
  4694. if (NULL != pdtCallerName)
  4695. {
  4696. // Update all rows only if this row's CallerName is empty
  4697. // and RequesterName is NOT empty.
  4698. hr = _RetrieveColumn(
  4699. pcs,
  4700. tableid,
  4701. pdtCallerName,
  4702. pdtCallerName->dbcolumnid,
  4703. NULL,
  4704. &cb,
  4705. NULL);
  4706. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  4707. {
  4708. pdtCallerName = NULL;
  4709. }
  4710. else
  4711. {
  4712. hr = _RetrieveColumn(
  4713. pcs,
  4714. tableid,
  4715. pdtRequesterName,
  4716. pdtRequesterName->dbcolumnid,
  4717. NULL,
  4718. &cb,
  4719. NULL);
  4720. if (S_OK != hr)
  4721. {
  4722. pdtCallerName = NULL;
  4723. }
  4724. }
  4725. }
  4726. hr = _dbgJetSetCurrentIndex2(
  4727. pcs->SesId,
  4728. tableid,
  4729. pdbaux->pszRowIdIndex,
  4730. JET_bitMoveFirst);
  4731. _JumpIfError(hr, error, "JetSetCurrentIndex2");
  4732. }
  4733. }
  4734. pdtCertHash = NULL;
  4735. pdtSKI = NULL;
  4736. pdtCert = dbFindColumn(adt, szRAWCERTIFICATE);
  4737. if (NULL != pdtCert)
  4738. {
  4739. pdtCertHash = dbFindColumn(adt, szCERTIFICATEHASH);
  4740. pdtSKI = dbFindColumn(adt, szSUBJECTKEYIDENTIFIER);
  4741. if (NULL == pdtCertHash || NULL == pdtSKI)
  4742. {
  4743. pdtCert = NULL;
  4744. }
  4745. else
  4746. {
  4747. // Update all rows only if the first row's CertHash is empty,
  4748. // and the first row's Cert column is NOT empty.
  4749. hr = _RetrieveColumn(
  4750. pcs,
  4751. tableid,
  4752. pdtCertHash,
  4753. pdtCertHash->dbcolumnid,
  4754. NULL,
  4755. &cb,
  4756. NULL);
  4757. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  4758. {
  4759. pdtCert = NULL;
  4760. }
  4761. else
  4762. {
  4763. hr = _RetrieveColumn(
  4764. pcs,
  4765. tableid,
  4766. pdtCert,
  4767. pdtCert->dbcolumnid,
  4768. NULL,
  4769. &cb,
  4770. NULL);
  4771. if (S_OK != hr)
  4772. {
  4773. pdtCert = NULL;
  4774. }
  4775. }
  4776. }
  4777. }
  4778. if (NULL != pdtPublicKeyLength ||
  4779. NULL != pdtCallerName ||
  4780. NULL != pdtCert ||
  4781. m_fFoundOldColumns ||
  4782. fZeroIssuerNameId)
  4783. {
  4784. DBGPRINT((DBG_SS_CERTDB, "Updating %hs table.\n", pdbaux->pszTable));
  4785. while (TRUE)
  4786. {
  4787. // Fetch RowId from the table.
  4788. cb = sizeof(pcs->RowId);
  4789. hr = _RetrieveColumn(
  4790. pcs,
  4791. tableid,
  4792. pdbaux->pdtRowId,
  4793. pdbaux->pdtRowId->dbcolumnid,
  4794. NULL,
  4795. &cb,
  4796. (BYTE *) &RowId);
  4797. if (S_OK != hr)
  4798. {
  4799. if (myJetHResult(JET_errNoCurrentRecord) == hr)
  4800. {
  4801. hr = S_OK; // Table is empty
  4802. break;
  4803. }
  4804. _JumpError(hr, error, "_RetrieveColumn");
  4805. }
  4806. hr = _dbgJetBeginTransaction(pcs->SesId);
  4807. _JumpIfError(hr, error, "JetBeginTransaction");
  4808. fTransacted = TRUE;
  4809. // Transact each row.
  4810. //
  4811. // If fZeroIssuerNameId, set EMPTY IssuerNameId columns to zero.
  4812. //
  4813. // if the first row's public key length column was empty
  4814. // Read the public key column, compute the size and store it
  4815. //
  4816. // if the first row's CallerName was empty
  4817. // Copy RequesterName to CallerName
  4818. //
  4819. // if m_fFoundOldColumns
  4820. // For each text column, do the following:
  4821. // Retrieve old string from the old column,
  4822. // Convert to Unicode (if old column was Ansi),
  4823. // Write the Unicode string to the new column,
  4824. // Set the old column to NULL.
  4825. hr = _dbgJetPrepareUpdate(
  4826. pcs->SesId,
  4827. tableid,
  4828. JET_prepReplace);
  4829. _JumpIfError(hr, error, "JetPrepareUpdate");
  4830. if (fZeroIssuerNameId)
  4831. {
  4832. cb = sizeof(IssuerNameId);
  4833. hr = _RetrieveColumn(
  4834. pcs,
  4835. tableid,
  4836. pdbaux->pdtIssuerNameId,
  4837. pdbaux->pdtIssuerNameId->dbcolumnid,
  4838. NULL,
  4839. &cb,
  4840. (BYTE *) &IssuerNameId);
  4841. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  4842. {
  4843. _JumpIfError(hr, error, "_RetrieveColumn");
  4844. }
  4845. else
  4846. {
  4847. // Only set EMPTY columns!
  4848. IssuerNameId = 0;
  4849. hr = _SetColumn(
  4850. pcs->SesId,
  4851. tableid,
  4852. pdbaux->pdtIssuerNameId,
  4853. pdbaux->pdtIssuerNameId->dbcolumnid,
  4854. sizeof(IssuerNameId),
  4855. (BYTE const *) &IssuerNameId);
  4856. _JumpIfError(hr, error, "_SetColumn");
  4857. }
  4858. }
  4859. // Convert old columns first.
  4860. if (m_fFoundOldColumns)
  4861. {
  4862. for (pdt = adt; NULL != pdt->pwszPropName; pdt++)
  4863. {
  4864. if (DBTF_OLDCOLUMNID & pdt->dwFlags)
  4865. {
  4866. hr = _ConvertColumnData(
  4867. pcs,
  4868. tableid,
  4869. RowId,
  4870. pdt,
  4871. pdbaux,
  4872. &pbBuf,
  4873. &cbBuf);
  4874. _JumpIfErrorStr(
  4875. hr,
  4876. error,
  4877. "_ConvertColumnData",
  4878. pdt->pwszPropName);
  4879. }
  4880. }
  4881. }
  4882. // Now compute new columns.
  4883. if (NULL != pdtPublicKeyLength)
  4884. {
  4885. hr = _AddKeyLengthColumn(
  4886. pcs,
  4887. tableid,
  4888. RowId,
  4889. pdtPublicKey,
  4890. pdtPublicKeyAlgorithm,
  4891. pdtPublicKeyParameters,
  4892. pdtPublicKeyLength,
  4893. pdbaux,
  4894. &pbBuf,
  4895. &cbBuf);
  4896. _JumpIfError(hr, error, "_AddKeyLengthColumn");
  4897. }
  4898. if (NULL != pdtCallerName)
  4899. {
  4900. hr = _AddCallerName(
  4901. pcs,
  4902. tableid,
  4903. RowId,
  4904. pdtCallerName,
  4905. pdtRequesterName,
  4906. pdbaux,
  4907. &pbBuf,
  4908. &cbBuf);
  4909. _JumpIfError(hr, error, "_AddCallerName");
  4910. }
  4911. if (NULL != pdtCert)
  4912. {
  4913. hr = _AddCertColumns(
  4914. pcs,
  4915. tableid,
  4916. RowId,
  4917. pdtCertHash,
  4918. pdtSKI,
  4919. pdtCert,
  4920. pdbaux,
  4921. &pbBuf,
  4922. &cbBuf);
  4923. _JumpIfError(hr, error, "_AddCertHash");
  4924. }
  4925. // Done with this row.
  4926. hr = _dbgJetUpdate(pcs->SesId, tableid, NULL, 0, NULL);
  4927. _JumpIfError(hr, error, "JetUpdate");
  4928. hr = _dbgJetCommitTransaction(pcs->SesId, 0);
  4929. _JumpIfError(hr, error, "JetCommitTransaction");
  4930. fTransacted = FALSE;
  4931. hr = _dbgJetMove(pcs->SesId, tableid, JET_MoveNext, 0);
  4932. if ((HRESULT) JET_errNoCurrentRecord == hr)
  4933. {
  4934. hr = S_OK;
  4935. break;
  4936. }
  4937. }
  4938. }
  4939. if (m_fFoundOldColumns)
  4940. {
  4941. hr = _dbgJetBeginTransaction(pcs->SesId);
  4942. _JumpIfError(hr, error, "JetBeginTransaction");
  4943. fTransacted = TRUE;
  4944. for (pdt = adt; NULL != pdt->pwszPropName; pdt++)
  4945. {
  4946. char const *pszFieldName;
  4947. if (0 == (DBTF_OLDCOLUMNID & pdt->dwFlags))
  4948. {
  4949. continue;
  4950. }
  4951. pszFieldName = &pdt->pszFieldName[1];
  4952. if (DBTF_COLUMNRENAMED & pdt->dwFlags)
  4953. {
  4954. pszFieldName += strlen(pszFieldName) + 1;
  4955. }
  4956. DBGPRINT((
  4957. DBG_SS_CERTDB,
  4958. "Deleting column %hs.%hs\n",
  4959. pdbaux->pszTable,
  4960. pszFieldName));
  4961. hr = _dbgJetDeleteColumn(pcs->SesId, tableid, pszFieldName);
  4962. _PrintIfError(hr, "JetDeleteColumn");
  4963. if ((HRESULT) JET_errColumnInUse == hr)
  4964. {
  4965. hr = S_OK; // we'll delete the column next time we restart
  4966. }
  4967. _JumpIfError(hr, error, "JetDeleteColumn");
  4968. }
  4969. hr = _dbgJetCommitTransaction(pcs->SesId, 0);
  4970. _JumpIfError(hr, error, "JetCommitTransaction");
  4971. fTransacted = FALSE;
  4972. }
  4973. hr = S_OK;
  4974. error:
  4975. if (NULL != pbBuf)
  4976. {
  4977. LocalFree(pbBuf);
  4978. }
  4979. if (fTransacted)
  4980. {
  4981. hr2 = _Rollback(pcs);
  4982. _PrintIfError(hr2, "_Rollback");
  4983. if (S_OK == hr)
  4984. {
  4985. hr = hr2;
  4986. }
  4987. }
  4988. if (fOpen)
  4989. {
  4990. hr2 = _dbgJetCloseTable(pcs->SesId, tableid);
  4991. _PrintIfError(hr2, "JetCloseTable");
  4992. if (S_OK == hr)
  4993. {
  4994. hr = hr2;
  4995. }
  4996. }
  4997. return(myJetHResult(hr));
  4998. }
  4999. HRESULT
  5000. CCertDB::_SetColumn(
  5001. IN JET_SESID SesId,
  5002. IN JET_TABLEID tableid,
  5003. IN DBTABLE const *pdt,
  5004. IN JET_COLUMNID columnid,
  5005. IN DWORD cbProp,
  5006. OPTIONAL IN BYTE const *pbProp)
  5007. {
  5008. HRESULT hr;
  5009. if (!IsValidJetTableId(tableid))
  5010. {
  5011. hr = E_HANDLE;
  5012. _JumpError(hr, error, "tableid");
  5013. }
  5014. if (DBTF_COMPUTED & pdt->dwFlags)
  5015. {
  5016. hr = E_ACCESSDENIED;
  5017. _JumpError(hr, error, "Computed");
  5018. }
  5019. hr = _dbgJetSetColumn(SesId, tableid, columnid, pbProp, cbProp, 0, NULL);
  5020. if ((HRESULT) JET_wrnColumnMaxTruncated == hr)
  5021. {
  5022. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  5023. }
  5024. _JumpIfError(hr, error, "JetSetColumn");
  5025. error:
  5026. return(myJetHResult(hr));
  5027. }
  5028. HRESULT
  5029. CCertDB::SetAttribute(
  5030. IN CERTSESSION *pcs,
  5031. IN WCHAR const *pwszAttributeName,
  5032. IN DWORD cbValue,
  5033. IN BYTE const *pbValue) // OPTIONAL
  5034. {
  5035. return(_SetIndirect(
  5036. pcs,
  5037. &pcs->aTable[CSTI_ATTRIBUTE],
  5038. pwszAttributeName,
  5039. NULL,
  5040. cbValue,
  5041. pbValue));
  5042. }
  5043. HRESULT
  5044. CCertDB::GetAttribute(
  5045. IN CERTSESSION *pcs,
  5046. IN WCHAR const *pwszAttributeName,
  5047. IN OUT DWORD *pcbValue,
  5048. OUT BYTE *pbValue) // OPTIONAL
  5049. {
  5050. return(_GetIndirect(
  5051. pcs,
  5052. &pcs->aTable[CSTI_ATTRIBUTE],
  5053. pwszAttributeName,
  5054. NULL,
  5055. pcbValue,
  5056. pbValue));
  5057. }
  5058. HRESULT
  5059. CCertDB::SetExtension(
  5060. IN CERTSESSION *pcs,
  5061. IN WCHAR const *pwszExtensionName,
  5062. IN DWORD dwExtFlags,
  5063. IN DWORD cbValue,
  5064. IN BYTE const *pbValue) // OPTIONAL
  5065. {
  5066. return(_SetIndirect(
  5067. pcs,
  5068. &pcs->aTable[CSTI_EXTENSION],
  5069. pwszExtensionName,
  5070. &dwExtFlags,
  5071. cbValue,
  5072. pbValue));
  5073. }
  5074. HRESULT
  5075. CCertDB::GetExtension(
  5076. IN CERTSESSION *pcs,
  5077. IN WCHAR const *pwszExtensionName,
  5078. OUT DWORD *pdwExtFlags,
  5079. IN OUT DWORD *pcbValue,
  5080. OUT BYTE *pbValue) // OPTIONAL
  5081. {
  5082. return(_GetIndirect(
  5083. pcs,
  5084. &pcs->aTable[CSTI_EXTENSION],
  5085. pwszExtensionName,
  5086. pdwExtFlags,
  5087. pcbValue,
  5088. pbValue));
  5089. }
  5090. HRESULT
  5091. CCertDB::_JetSeekFromRestriction(
  5092. IN CERTVIEWRESTRICTION const *pcvr,
  5093. IN DWORD dwPosition,
  5094. OUT DBSEEKDATA *pSeekData)
  5095. {
  5096. HRESULT hr;
  5097. BOOL fAscend;
  5098. DBSEEKDATA SeekFirst; // seek to first element matching restriction
  5099. DBSEEKDATA SeekLast; // seek to last element matching restriction
  5100. DBSEEKDATA SeekIndexFirst; // seek to first index element
  5101. DBSEEKDATA SeekIndexLast; // seek to last index element
  5102. DBSEEKDATA *pSeek;
  5103. BOOL fValid;
  5104. // SeekLast.SeekFlags: where to seek to retrieve end-of-range key
  5105. // SeekLast.grbitSeekRange: where to set the cursor initially: move or seek
  5106. // SeekLast.grbitRange: other flags to be ingested while setting range:
  5107. // (bitRange UpperLimit, Inclusive)
  5108. #if DBG_CERTSRV
  5109. DumpRestriction(DBG_SS_CERTDBI, 0, pcvr);
  5110. #endif
  5111. fAscend = (CVR_SORT_DESCEND != pcvr->SortOrder);
  5112. CSASSERT(
  5113. CVR_SORT_NONE == pcvr->SortOrder ||
  5114. CVR_SORT_ASCEND == pcvr->SortOrder ||
  5115. CVR_SORT_DESCEND == pcvr->SortOrder);
  5116. ZeroMemory(&SeekFirst, sizeof(SeekFirst));
  5117. ZeroMemory(&SeekLast, sizeof(SeekLast));
  5118. ZeroMemory(&SeekIndexFirst, sizeof(SeekIndexFirst));
  5119. ZeroMemory(&SeekIndexLast, sizeof(SeekIndexLast));
  5120. switch (CVR_SEEK_MASK & pcvr->SeekOperator)
  5121. {
  5122. case CVR_SEEK_EQ:
  5123. if (fAscend)
  5124. {
  5125. SeekFirst.SeekFlags = CST_SEEKUSECURRENT |
  5126. CST_SEEKNOTMOVE |
  5127. CST_SEEKINDEXRANGE;
  5128. SeekFirst.grbitSeekRange = JET_bitSeekEQ;
  5129. SeekFirst.grbitInitial = JET_bitSeekEQ;
  5130. SeekFirst.grbitRange = JET_bitRangeUpperLimit |
  5131. JET_bitRangeInclusive;
  5132. SeekLast.SeekFlags = CST_SEEKINDEXRANGE;
  5133. SeekLast.grbitSeekRange = JET_bitSeekGT;
  5134. SeekLast.grbitInitial = (JET_GRBIT) JET_MovePrevious;
  5135. SeekLast.grbitRange = JET_bitRangeUpperLimit;
  5136. }
  5137. else
  5138. {
  5139. SeekFirst.SeekFlags = CST_SEEKNOTMOVE | CST_SEEKINDEXRANGE;
  5140. SeekFirst.grbitSeekRange = JET_bitSeekEQ;
  5141. SeekFirst.grbitInitial = JET_bitSeekGT;
  5142. SeekFirst.grbitRange = JET_bitRangeInclusive;
  5143. SeekLast.SeekFlags = CST_SEEKINDEXRANGE;
  5144. SeekLast.grbitSeekRange = JET_bitSeekEQ;
  5145. SeekLast.grbitInitial = (JET_GRBIT) JET_MovePrevious;
  5146. SeekLast.grbitRange = JET_bitRangeInclusive;
  5147. }
  5148. break;
  5149. case CVR_SEEK_LT:
  5150. if (fAscend)
  5151. {
  5152. SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
  5153. SeekFirst.grbitSeekRange = JET_bitSeekGE;
  5154. SeekFirst.grbitInitial = JET_MoveFirst;
  5155. SeekFirst.grbitRange = JET_bitRangeUpperLimit;
  5156. SeekLast.SeekFlags = CST_SEEKINDEXRANGE;
  5157. SeekLast.grbitSeekRange = JET_bitSeekGE;
  5158. SeekLast.grbitInitial = (JET_GRBIT) JET_MovePrevious;
  5159. SeekLast.grbitRange = JET_bitRangeUpperLimit;
  5160. }
  5161. else
  5162. {
  5163. SeekFirst.SeekFlags = CST_SEEKNOTMOVE;
  5164. SeekFirst.grbitInitial = JET_bitSeekGE;
  5165. //SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
  5166. SeekLast.grbitInitial = JET_MoveFirst;
  5167. SeekIndexFirst.SeekFlags = CST_SEEKUSECURRENT;
  5168. SeekIndexFirst.grbitInitial = JET_MoveLast;
  5169. }
  5170. break;
  5171. case CVR_SEEK_LE:
  5172. if (fAscend)
  5173. {
  5174. SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
  5175. SeekFirst.grbitSeekRange = JET_bitSeekGT;
  5176. SeekFirst.grbitInitial = JET_MoveFirst;
  5177. SeekFirst.grbitRange = JET_bitRangeUpperLimit;
  5178. SeekLast.SeekFlags = CST_SEEKINDEXRANGE; // !CST_SEEKUSECURRENT
  5179. SeekLast.grbitSeekRange = JET_bitSeekGT;
  5180. SeekLast.grbitInitial = (JET_GRBIT) JET_MovePrevious;
  5181. SeekLast.grbitRange = JET_bitRangeUpperLimit;
  5182. }
  5183. else
  5184. {
  5185. SeekFirst.SeekFlags = CST_SEEKNOTMOVE;
  5186. SeekFirst.grbitInitial = JET_bitSeekGT;
  5187. //SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
  5188. SeekLast.grbitInitial = JET_MoveFirst;
  5189. SeekIndexFirst.SeekFlags = CST_SEEKUSECURRENT;
  5190. SeekIndexFirst.grbitInitial = JET_MoveLast;
  5191. }
  5192. break;
  5193. case CVR_SEEK_GE:
  5194. if (fAscend)
  5195. {
  5196. SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKNOTMOVE;
  5197. SeekFirst.grbitInitial = JET_bitSeekGE;
  5198. //SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
  5199. SeekLast.grbitInitial = JET_MoveLast;
  5200. }
  5201. else
  5202. {
  5203. SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
  5204. SeekFirst.grbitSeekRange = JET_bitSeekLT;
  5205. SeekFirst.grbitInitial = JET_MoveLast;
  5206. // Implied: SeekFirst.grbitRange = JET_bitRangeLowerLimit;
  5207. SeekLast.SeekFlags = CST_SEEKNOTMOVE;
  5208. SeekLast.grbitInitial = JET_bitSeekLT;
  5209. SeekIndexLast.SeekFlags = CST_SEEKUSECURRENT;
  5210. SeekIndexLast.grbitInitial = JET_MoveFirst;
  5211. }
  5212. break;
  5213. case CVR_SEEK_GT:
  5214. if (fAscend)
  5215. {
  5216. SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKNOTMOVE;
  5217. SeekFirst.grbitInitial = JET_bitSeekGT;
  5218. //SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
  5219. SeekLast.grbitInitial = JET_MoveLast;
  5220. }
  5221. else
  5222. {
  5223. SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
  5224. SeekFirst.grbitSeekRange = JET_bitSeekLE;
  5225. SeekFirst.grbitInitial = JET_MoveLast;
  5226. // Implied: SeekFirst.grbitRange = JET_bitRangeLowerLimit;
  5227. SeekLast.SeekFlags = CST_SEEKNOTMOVE;
  5228. SeekLast.grbitInitial = JET_bitSeekLE;
  5229. SeekIndexLast.SeekFlags = CST_SEEKUSECURRENT;
  5230. SeekIndexLast.grbitInitial = JET_MoveFirst;
  5231. }
  5232. break;
  5233. case CVR_SEEK_NONE:
  5234. if (fAscend)
  5235. {
  5236. SeekFirst.SeekFlags = CST_SEEKUSECURRENT;
  5237. SeekFirst.grbitInitial = JET_MoveFirst;
  5238. //SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
  5239. SeekLast.grbitInitial = JET_MoveLast;
  5240. }
  5241. else
  5242. {
  5243. SeekFirst.SeekFlags = CST_SEEKUSECURRENT;
  5244. SeekFirst.grbitInitial = JET_MoveLast;
  5245. //SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
  5246. SeekLast.grbitInitial = JET_MoveFirst;
  5247. }
  5248. break;
  5249. default:
  5250. CSASSERT(!"bad pcvr->SeekOperator"); // shouldn't get this far
  5251. hr = E_INVALIDARG;
  5252. _JumpError(hr, error, "Seek value");
  5253. }
  5254. fValid = TRUE;
  5255. switch (dwPosition)
  5256. {
  5257. case SEEKPOS_FIRST:
  5258. pSeek = &SeekFirst;
  5259. break;
  5260. case SEEKPOS_LAST:
  5261. pSeek = &SeekLast;
  5262. break;
  5263. case SEEKPOS_INDEXFIRST:
  5264. pSeek = &SeekIndexFirst;
  5265. fValid = 0 != pSeek->SeekFlags;
  5266. break;
  5267. case SEEKPOS_INDEXLAST:
  5268. pSeek = &SeekIndexLast;
  5269. fValid = 0 != pSeek->SeekFlags;
  5270. break;
  5271. default:
  5272. CSASSERT(!"bad dwPosition"); // shouldn't get this far
  5273. hr = E_INVALIDARG;
  5274. _JumpError(hr, error, "dwPosition value");
  5275. }
  5276. if (!fValid)
  5277. {
  5278. // For this SeekOperator, if seeking to the first or last matching
  5279. // restriction failed, there's no point in seeking to the index end.
  5280. hr = CERTSRV_E_PROPERTY_EMPTY;
  5281. _JumpError2(hr, error, "pSeek->SeekFlags", hr);
  5282. }
  5283. *pSeekData = *pSeek; // structure copy
  5284. if (fAscend)
  5285. {
  5286. pSeekData->SeekFlags |= CST_SEEKASCEND;
  5287. }
  5288. hr = S_OK;
  5289. DBGPRINT((
  5290. DBG_SS_CERTDBI,
  5291. "_JetSeekFromRestriction: SeekFlags=%ws, grbitStart=%ws\n",
  5292. wszCSTFlags(pSeekData->SeekFlags),
  5293. (CST_SEEKNOTMOVE & pSeekData->SeekFlags)?
  5294. wszSeekgrbit(pSeekData->grbitInitial) :
  5295. wszMovecrow(pSeekData->grbitInitial)));
  5296. if (CST_SEEKINDEXRANGE & pSeekData->SeekFlags)
  5297. {
  5298. DBGPRINT((
  5299. DBG_SS_CERTDBI,
  5300. "_JetSeekFromRestriction: grbitSeekRange=%ws, grbitRange=%ws\n",
  5301. wszSeekgrbit(pSeekData->grbitSeekRange),
  5302. wszSetIndexRangegrbit(pSeekData->grbitRange)));
  5303. }
  5304. error:
  5305. return(hr);
  5306. }
  5307. HRESULT
  5308. CCertDB::_OpenTable(
  5309. IN CERTSESSION *pcs,
  5310. IN DBAUXDATA const *pdbaux,
  5311. IN CERTVIEWRESTRICTION const *pcvr,
  5312. IN OUT CERTSESSIONTABLE *pTable)
  5313. {
  5314. HRESULT hr;
  5315. DBTABLE const *pdt;
  5316. BOOL fOpened = FALSE;
  5317. hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
  5318. _JumpIfError(hr, error, "_MapPropIdIndex");
  5319. if (NULL == pdt->pszIndexName)
  5320. {
  5321. hr = E_INVALIDARG;
  5322. _JumpError(hr, error, "Column not indexed");
  5323. }
  5324. if (!IsValidJetTableId(pTable->TableId))
  5325. {
  5326. CSASSERTTHREAD(pcs);
  5327. hr = _dbgJetOpenTable(
  5328. pcs->SesId,
  5329. pcs->DBId,
  5330. pdbaux->pszTable,
  5331. NULL,
  5332. 0,
  5333. 0,
  5334. &pTable->TableId);
  5335. _JumpIfError(hr, error, "JetOpenTable");
  5336. fOpened = TRUE;
  5337. // Find RowId and/or Named column.
  5338. // It's more efficient to pass NULL for primary index name.
  5339. CSASSERTTHREAD(pcs);
  5340. hr = _dbgJetSetCurrentIndex2(
  5341. pcs->SesId,
  5342. pTable->TableId,
  5343. (DBTF_INDEXPRIMARY & pdt->dwFlags)?
  5344. NULL : pdt->pszIndexName,
  5345. JET_bitMoveFirst);
  5346. _JumpIfError(hr, error, "JetSetCurrentIndex2");
  5347. DBGPRINT((
  5348. DBG_SS_CERTDBI,
  5349. "_OpenTable Table=%hs, Index=%hs\n",
  5350. pdbaux->pszTable,
  5351. pdt->pszIndexName));
  5352. }
  5353. hr = _SeekTable(
  5354. pcs,
  5355. pTable->TableId,
  5356. pcvr,
  5357. pdt,
  5358. NULL,
  5359. SEEKPOS_FIRST,
  5360. &pTable->TableFlags
  5361. DBGPARM(pdbaux));
  5362. _JumpIfError2(hr, error, "_SeekTable", S_FALSE);
  5363. error:
  5364. if (S_OK != hr && S_FALSE != hr && fOpened)
  5365. {
  5366. if (IsValidJetTableId(pTable->TableId))
  5367. {
  5368. HRESULT hr2;
  5369. CSASSERTTHREAD(pcs);
  5370. hr2 = _dbgJetCloseTable(pcs->SesId, pTable->TableId);
  5371. _PrintIfError(hr2, "JetCloseTable");
  5372. }
  5373. ZeroMemory(pTable, sizeof(*pTable));
  5374. }
  5375. return(myJetHResult(hr));
  5376. }
  5377. HRESULT
  5378. CCertDB::_SetIndirect(
  5379. IN CERTSESSION *pcs,
  5380. IN OUT CERTSESSIONTABLE *pTable,
  5381. IN WCHAR const *pwszNameValue,
  5382. OPTIONAL IN DWORD const *pdwExtFlags,
  5383. IN DWORD cbValue,
  5384. OPTIONAL IN BYTE const *pbValue)
  5385. {
  5386. HRESULT hr;
  5387. DBAUXDATA const *pdbaux;
  5388. BOOL fExisting = FALSE;
  5389. BOOL fDelete;
  5390. CERTVIEWRESTRICTION cvr;
  5391. if (NULL == pcs || NULL == pwszNameValue)
  5392. {
  5393. hr = E_POINTER;
  5394. _JumpError(hr, error, "NULL parm");
  5395. }
  5396. fDelete = NULL == pbValue;
  5397. if (NULL == pdwExtFlags)
  5398. {
  5399. pdbaux = &g_dbauxAttributes;
  5400. cvr.ColumnIndex = DTI_ATTRIBUTETABLE | DTA_ATTRIBUTENAME;
  5401. }
  5402. else
  5403. {
  5404. if (0 != *pdwExtFlags)
  5405. {
  5406. fDelete = FALSE;
  5407. }
  5408. pdbaux = &g_dbauxExtensions;
  5409. cvr.ColumnIndex = DTI_EXTENSIONTABLE | DTE_EXTENSIONNAME;
  5410. }
  5411. DBGPRINT((
  5412. DBG_SS_CERTDBI,
  5413. "IN: _SetIndirect(%hs.%ws) cb = %x%ws\n",
  5414. pdbaux->pszTable,
  5415. pwszNameValue,
  5416. cbValue,
  5417. fDelete? L" DELETE" : L""));
  5418. cvr.SeekOperator = CVR_SEEK_EQ;
  5419. cvr.SortOrder = CVR_SORT_NONE;
  5420. cvr.cbValue = wcslen(pwszNameValue) * sizeof(WCHAR);
  5421. cvr.pbValue = (BYTE *) pwszNameValue;
  5422. hr = _OpenTable(pcs, pdbaux, &cvr, pTable);
  5423. if (S_FALSE != hr)
  5424. {
  5425. _JumpIfError(hr, error, "_OpenTable");
  5426. fExisting = TRUE;
  5427. }
  5428. _PrintIfError2(hr, "_OpenTable", S_FALSE);
  5429. if (fDelete)
  5430. {
  5431. if (fExisting)
  5432. {
  5433. CSASSERTTHREAD(pcs);
  5434. hr = _dbgJetDelete(pcs->SesId, pTable->TableId);
  5435. _JumpIfError(hr, error, "JetDelete");
  5436. }
  5437. }
  5438. else
  5439. {
  5440. CSASSERTTHREAD(pcs);
  5441. hr = _dbgJetPrepareUpdate(
  5442. pcs->SesId,
  5443. pTable->TableId,
  5444. !fExisting? JET_prepInsert : JET_prepReplace);
  5445. _JumpIfError(hr, error, "JetPrepareUpdate");
  5446. if (!fExisting)
  5447. {
  5448. // No existing row -- insert a new one:
  5449. // Set RowId
  5450. hr = _SetColumn(
  5451. pcs->SesId,
  5452. pTable->TableId,
  5453. pdbaux->pdtRowId,
  5454. pdbaux->pdtRowId->dbcolumnid,
  5455. sizeof(pcs->RowId),
  5456. (BYTE const *) &pcs->RowId);
  5457. _JumpIfError(hr, error, "_SetColumn");
  5458. // Set row's name column
  5459. hr = _SetColumn(
  5460. pcs->SesId,
  5461. pTable->TableId,
  5462. pdbaux->pdtName,
  5463. pdbaux->pdtName->dbcolumnid,
  5464. wcslen(pwszNameValue) * sizeof(WCHAR), // cch
  5465. (BYTE const *) pwszNameValue /*szTmp*/);
  5466. _JumpIfError(hr, error, "_SetColumn");
  5467. }
  5468. if (NULL != pdwExtFlags)
  5469. {
  5470. // Set or update flags
  5471. hr = _SetColumn(
  5472. pcs->SesId,
  5473. pTable->TableId,
  5474. pdbaux->pdtFlags,
  5475. pdbaux->pdtFlags->dbcolumnid,
  5476. sizeof(*pdwExtFlags),
  5477. (BYTE const *) pdwExtFlags);
  5478. _JumpIfError(hr, error, "_SetColumn");
  5479. }
  5480. // Set or update value
  5481. hr = _SetColumn(
  5482. pcs->SesId,
  5483. pTable->TableId,
  5484. pdbaux->pdtValue,
  5485. pdbaux->pdtValue->dbcolumnid,
  5486. cbValue,
  5487. pbValue);
  5488. _JumpIfError(hr, error, "_SetColumn");
  5489. CSASSERTTHREAD(pcs);
  5490. hr = _dbgJetUpdate(pcs->SesId, pTable->TableId, NULL, 0, NULL);
  5491. _JumpIfError(hr, error, "JetUpdate");
  5492. }
  5493. error:
  5494. return(myJetHResult(hr));
  5495. }
  5496. HRESULT
  5497. CCertDB::_GetIndirect(
  5498. IN CERTSESSION *pcs,
  5499. IN OUT CERTSESSIONTABLE *pTable,
  5500. IN WCHAR const *pwszNameValue,
  5501. OPTIONAL OUT DWORD *pdwExtFlags,
  5502. IN OUT DWORD *pcbValue,
  5503. OPTIONAL OUT BYTE *pbValue)
  5504. {
  5505. HRESULT hr;
  5506. DBAUXDATA const *pdbaux;
  5507. CERTVIEWRESTRICTION cvr;
  5508. if (NULL == pcs || NULL == pwszNameValue || NULL == pcbValue)
  5509. {
  5510. hr = E_POINTER;
  5511. _JumpError(hr, error, "NULL parm");
  5512. }
  5513. if (NULL == pdwExtFlags)
  5514. {
  5515. pdbaux = &g_dbauxAttributes;
  5516. cvr.ColumnIndex = DTI_ATTRIBUTETABLE | DTA_ATTRIBUTENAME;
  5517. }
  5518. else
  5519. {
  5520. pdbaux = &g_dbauxExtensions;
  5521. cvr.ColumnIndex = DTI_EXTENSIONTABLE | DTE_EXTENSIONNAME;
  5522. }
  5523. DBGPRINT((
  5524. DBG_SS_CERTDBI,
  5525. "IN: _GetIndirect(%hs.%ws) cb = %x\n",
  5526. pdbaux->pszTable,
  5527. pwszNameValue,
  5528. *pcbValue));
  5529. cvr.SeekOperator = CVR_SEEK_EQ;
  5530. cvr.SortOrder = CVR_SORT_NONE;
  5531. cvr.cbValue = wcslen(pwszNameValue) * sizeof(WCHAR);
  5532. cvr.pbValue = (BYTE *) pwszNameValue;
  5533. hr = _OpenTable(pcs, pdbaux, &cvr, pTable);
  5534. if (S_FALSE == hr)
  5535. {
  5536. hr = CERTSRV_E_PROPERTY_EMPTY;
  5537. }
  5538. _JumpIfError2(hr, error, "_OpenTable", CERTSRV_E_PROPERTY_EMPTY);
  5539. if (NULL != pdwExtFlags)
  5540. {
  5541. DWORD cb;
  5542. // Get flags column
  5543. cb = sizeof(*pdwExtFlags);
  5544. hr = _RetrieveColumn(
  5545. pcs,
  5546. pTable->TableId,
  5547. pdbaux->pdtFlags,
  5548. pdbaux->pdtFlags->dbcolumnid,
  5549. NULL,
  5550. &cb,
  5551. (BYTE *) pdwExtFlags);
  5552. _JumpIfError(hr, error, "_RetrieveColumn");
  5553. DBGPRINT((
  5554. DBG_SS_CERTDBI,
  5555. "_GetIndirect(%hs): Flags = %x\n",
  5556. pdbaux->pszTable,
  5557. *pdwExtFlags));
  5558. }
  5559. // Get value column
  5560. hr = _RetrieveColumn(
  5561. pcs,
  5562. pTable->TableId,
  5563. pdbaux->pdtValue,
  5564. pdbaux->pdtValue->dbcolumnid,
  5565. NULL,
  5566. pcbValue,
  5567. pbValue);
  5568. if (CERTSRV_E_PROPERTY_EMPTY == hr && NULL != pdwExtFlags)
  5569. {
  5570. // return zero length property value and S_OK, so the caller can see
  5571. // the extension flags.
  5572. *pcbValue = 0;
  5573. hr = S_OK;
  5574. }
  5575. _JumpIfErrorStr(hr, error, "_RetrieveColumn", pwszNameValue);
  5576. DBGPRINT((
  5577. DBG_SS_CERTDBI,
  5578. "OUT: _GetIndirect(%hs.%ws) cb = %x\n",
  5579. pdbaux->pszTable,
  5580. pwszNameValue,
  5581. *pcbValue));
  5582. error:
  5583. return(myJetHResult(hr));
  5584. }
  5585. #define CB_FETCHDELTA 256
  5586. // Fetch a column. Loop if we have to grow the buffer.
  5587. HRESULT
  5588. CCertDB::_RetrieveColumnBuffer(
  5589. IN CERTSESSION *pcs,
  5590. IN JET_TABLEID tableid,
  5591. IN DBTABLE const *pdt,
  5592. IN JET_COLUMNID columnid,
  5593. OUT DWORD *pcbProp,
  5594. IN OUT BYTE **ppbBuf,
  5595. IN OUT DWORD *pcbBuf)
  5596. {
  5597. HRESULT hr;
  5598. BYTE *pbBuf = *ppbBuf;
  5599. DWORD cbBuf = *pcbBuf;
  5600. DWORD cb;
  5601. cb = cbBuf;
  5602. while (TRUE)
  5603. {
  5604. if (NULL == pbBuf)
  5605. {
  5606. // If cbBuf == 0, allocate CB_FETCHDELTA bytes.
  5607. // Otherwise, allocate column size *plus* CB_FETCHDELTA bytes.
  5608. // Ensures we make no more than two calls to _RetrieveColumn.
  5609. cb += CB_FETCHDELTA;
  5610. pbBuf = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
  5611. if (NULL == pbBuf)
  5612. {
  5613. hr = E_OUTOFMEMORY;
  5614. _JumpError(hr, error, "LocalAlloc");
  5615. }
  5616. DBGPRINT((
  5617. DBG_SS_CERTDBI,
  5618. "Grow buffer: %x --> %x\n", cbBuf, cb));
  5619. cbBuf = cb;
  5620. }
  5621. cb = cbBuf;
  5622. hr = _RetrieveColumn(
  5623. pcs,
  5624. tableid,
  5625. pdt,
  5626. columnid,
  5627. NULL,
  5628. &cb,
  5629. pbBuf);
  5630. if (S_OK == hr)
  5631. {
  5632. *pcbProp = cb;
  5633. break; // data fit in the buffer
  5634. }
  5635. if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
  5636. {
  5637. _JumpError2(hr, error, "_RetrieveColumn", CERTSRV_E_PROPERTY_EMPTY);
  5638. }
  5639. // Data won't fit. Grow the buffer.
  5640. CSASSERT(NULL != pbBuf);
  5641. LocalFree(pbBuf);
  5642. pbBuf = NULL;
  5643. }
  5644. CSASSERT(S_OK == hr);
  5645. error:
  5646. *ppbBuf = pbBuf;
  5647. *pcbBuf = cbBuf;
  5648. return(hr);
  5649. }
  5650. HRESULT
  5651. CCertDB::_RetrieveColumn(
  5652. IN CERTSESSION *pcs,
  5653. IN JET_TABLEID tableid,
  5654. IN DBTABLE const *pdt,
  5655. IN JET_COLUMNID columnid,
  5656. OPTIONAL IN ICertDBComputedColumn *pIComputedColumn,
  5657. IN OUT DWORD *pcbProp,
  5658. OPTIONAL OUT BYTE *pbProp)
  5659. {
  5660. HRESULT hr;
  5661. DWORD cbActual;
  5662. DWORD cbTotal;
  5663. DWORD ColumnIdComputed;
  5664. DWORD ColumnIdAlt;
  5665. DWORD PropTypeAlt;
  5666. BYTE *pbPropAltBuf = NULL;
  5667. DBTABLE const *pdtAlt = NULL;
  5668. if (!IsValidJetTableId(tableid))
  5669. {
  5670. hr = E_HANDLE;
  5671. _JumpError(hr, error, "tableid");
  5672. }
  5673. ColumnIdComputed = 0;
  5674. ColumnIdAlt = 0;
  5675. PropTypeAlt = 0;
  5676. if (DBTF_COMPUTED & pdt->dwFlags)
  5677. {
  5678. CSASSERT(JET_coltypLong == pdt->dbcoltyp);
  5679. CSASSERT(0 == columnid);
  5680. if (NULL == pIComputedColumn)
  5681. {
  5682. hr = (HRESULT) JET_wrnColumnNull;
  5683. cbActual = 0;
  5684. _PrintErrorStr(
  5685. CERTSRV_E_PROPERTY_EMPTY,
  5686. "pIComputedColumn NULL",
  5687. pdt->pwszPropName);
  5688. }
  5689. else
  5690. {
  5691. DWORD PropTypeT;
  5692. hr = _MapTableToIndex(pdt, &ColumnIdComputed);
  5693. _JumpIfError(hr, error, "_MapTableToIndex");
  5694. hr = pIComputedColumn->GetAlternateColumnId(
  5695. ColumnIdComputed,
  5696. &ColumnIdAlt,
  5697. &PropTypeAlt);
  5698. _JumpIfError(hr, error, "GetAlternateColumnId");
  5699. hr = _MapPropIdIndex(ColumnIdAlt, &pdtAlt, &PropTypeT);
  5700. _JumpIfError(hr, error, "_MapPropIdIndex");
  5701. if (pdt->dwTable != pdtAlt->dwTable)
  5702. {
  5703. hr = CERTSRV_E_PROPERTY_EMPTY;
  5704. _JumpError(hr, error, "pdtAlt->dwTable");
  5705. }
  5706. if (PropTypeAlt != (PROPTYPE_MASK & PropTypeT))
  5707. {
  5708. hr = CERTSRV_E_PROPERTY_EMPTY;
  5709. _JumpError(hr, error, "PropTypeAlt");
  5710. }
  5711. hr = (HRESULT) JET_wrnBufferTruncated;
  5712. cbActual = sizeof(LONG);
  5713. }
  5714. }
  5715. else
  5716. {
  5717. hr = _dbgJetRetrieveColumn(
  5718. pcs->SesId,
  5719. tableid,
  5720. columnid,
  5721. NULL,
  5722. 0,
  5723. &cbActual,
  5724. JET_bitRetrieveCopy,
  5725. NULL);
  5726. }
  5727. if ((HRESULT) JET_wrnColumnNull == hr)
  5728. {
  5729. // Routine GetProperty call:
  5730. // _JumpIfError(hr, error, "JetRetrieveColumn: Property EMPTY");
  5731. hr = CERTSRV_E_PROPERTY_EMPTY;
  5732. goto error;
  5733. }
  5734. if ((HRESULT) JET_wrnBufferTruncated != hr)
  5735. {
  5736. _JumpIfError2(hr, error, "JetRetrieveColumn", JET_errNoCurrentRecord);
  5737. }
  5738. if (cbActual == 0)
  5739. {
  5740. hr = CERTSRV_E_PROPERTY_EMPTY;
  5741. _JumpError(hr, error, "JetRetrieveColumn: cbActual=0: Property EMPTY");
  5742. }
  5743. cbTotal = cbActual;
  5744. if (ISTEXTCOLTYP(pdt->dbcoltyp))
  5745. {
  5746. DBGPRINT((DBG_SS_CERTDBI, "Size of text %d\n", cbActual));
  5747. cbTotal += sizeof(WCHAR);
  5748. }
  5749. if (NULL == pbProp || cbTotal > *pcbProp)
  5750. {
  5751. *pcbProp = cbTotal;
  5752. hr = S_OK;
  5753. if (NULL != pbProp)
  5754. {
  5755. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  5756. //_PrintError(hr, "output buffer too small");
  5757. }
  5758. goto error;
  5759. }
  5760. if (DBTF_COMPUTED & pdt->dwFlags)
  5761. {
  5762. DWORD cbPropAlt;
  5763. DWORD cbPropAltBuf = 0;
  5764. CSASSERT(JET_coltypLong == pdt->dbcoltyp);
  5765. CSASSERT(0 == columnid);
  5766. CSASSERT(NULL != pIComputedColumn);
  5767. // Fetch the alternate column
  5768. hr = _RetrieveColumnBuffer(
  5769. pcs,
  5770. tableid,
  5771. pdtAlt,
  5772. pdtAlt->dbcolumnid,
  5773. &cbPropAlt,
  5774. &pbPropAltBuf,
  5775. &cbPropAltBuf);
  5776. _JumpIfErrorStr(
  5777. hr,
  5778. error,
  5779. "_RetrieveColumnBuffer",
  5780. pdtAlt->pwszPropName);
  5781. hr = pIComputedColumn->ComputeColumnValue(
  5782. ColumnIdComputed,
  5783. ColumnIdAlt,
  5784. PropTypeAlt,
  5785. cbPropAlt,
  5786. pbPropAltBuf,
  5787. (DWORD *) pbProp);
  5788. _JumpIfError(hr, error, "ComputeColumnValue");
  5789. DBGCODE(_DumpRowId("ComputeColumnValue", pcs, tableid));
  5790. CSASSERT(sizeof(LONG) == cbActual);
  5791. hr = S_OK;
  5792. }
  5793. else
  5794. {
  5795. hr = _dbgJetRetrieveColumn(
  5796. pcs->SesId,
  5797. tableid,
  5798. columnid,
  5799. pbProp,
  5800. cbActual,
  5801. &cbActual,
  5802. JET_bitRetrieveCopy,
  5803. NULL);
  5804. _JumpIfError(hr, error, "JetRetrieveColumn");
  5805. }
  5806. *pcbProp = cbActual;
  5807. if (ISTEXTCOLTYP(pdt->dbcoltyp))
  5808. {
  5809. *(WCHAR *) &pbProp[cbActual] = L'\0';
  5810. }
  5811. error:
  5812. if (NULL != pbPropAltBuf)
  5813. {
  5814. LocalFree(pbPropAltBuf);
  5815. }
  5816. return(myJetHResult(hr));
  5817. }
  5818. HRESULT
  5819. CCertDB::_CreateIndex(
  5820. IN CERTSESSION *pcs,
  5821. IN JET_TABLEID tableid,
  5822. IN CHAR const *pszIndexName,
  5823. IN CHAR const *pchKey,
  5824. IN DWORD cbKey,
  5825. IN DWORD flags)
  5826. {
  5827. HRESULT hr;
  5828. CSASSERT(IsValidJetTableId(tableid));
  5829. hr = _dbgJetCreateIndex(
  5830. pcs->SesId,
  5831. tableid,
  5832. pszIndexName,
  5833. flags,
  5834. pchKey,
  5835. cbKey,
  5836. PCDENSITYSET);
  5837. _JumpIfError3(
  5838. hr,
  5839. error,
  5840. "JetCreateIndex",
  5841. (HRESULT) JET_errIndexDuplicate,
  5842. (HRESULT) JET_errIndexHasPrimary);
  5843. DBGPRINT((
  5844. DBG_SS_CERTDBI,
  5845. "CreateIndex: %x:%hs idx=%hs len=%x flags=%x\n",
  5846. tableid,
  5847. pszIndexName,
  5848. pchKey,
  5849. cbKey,
  5850. flags));
  5851. error:
  5852. return(myJetHResult(hr));
  5853. }
  5854. HRESULT
  5855. CCertDB::_AddColumn(
  5856. IN CERTSESSION *pcs,
  5857. IN JET_TABLEID tableid,
  5858. IN DBTABLE const *pdt)
  5859. {
  5860. HRESULT hr;
  5861. JET_COLUMNDEF columndef;
  5862. JET_COLUMNID columnid;
  5863. CSASSERT(IsValidJetTableId(tableid));
  5864. ZeroMemory(&columndef, sizeof(columndef));
  5865. columndef.cbStruct = sizeof(columndef);
  5866. columndef.cp = CP_UNICODE; // CP_UNICODE(1200) instead of CP_USASCII(1252)
  5867. columndef.langid = LANGID_DBFIXED;
  5868. columndef.wCountry = 1;
  5869. columndef.coltyp = pdt->dbcoltyp;
  5870. columndef.cbMax = pdt->dbcolumnMax;
  5871. columndef.grbit = pdt->dbgrbit;
  5872. DBGPRINT((
  5873. DBG_SS_CERTDBI,
  5874. "AddColumn: %x:%hs coltyp=%x cbMax=%x grbit=%x\n",
  5875. tableid,
  5876. pdt->pszFieldName,
  5877. pdt->dbcoltyp,
  5878. pdt->dbcolumnMax,
  5879. pdt->dbgrbit));
  5880. hr = _dbgJetAddColumn(
  5881. pcs->SesId,
  5882. tableid,
  5883. pdt->pszFieldName,
  5884. &columndef,
  5885. NULL,
  5886. 0,
  5887. &columnid);
  5888. CSASSERT((HRESULT) JET_wrnColumnMaxTruncated != hr);
  5889. _JumpIfErrorStr3(
  5890. hr,
  5891. error,
  5892. "JetAddColumn",
  5893. pdt->pwszPropName,
  5894. (HRESULT) JET_errColumnDuplicate,
  5895. (HRESULT) JET_errColumnRedundant);
  5896. error:
  5897. return(myJetHResult(hr));
  5898. }
  5899. HRESULT
  5900. CCertDB::_CreateTable(
  5901. IN DWORD CreateFlags, // CF_*
  5902. IN CERTSESSION *pcs,
  5903. IN DBCREATETABLE const *pct)
  5904. {
  5905. HRESULT hr;
  5906. JET_TABLEID tableid;
  5907. BOOL fTableOpen;
  5908. CHAR achCol[MAX_PATH];
  5909. DBTABLE const *pdt;
  5910. JET_DDLINDEXDENSITY IndexDensity;
  5911. DBGPRINT((
  5912. DBG_SS_CERTDBI,
  5913. "_CreateTable(%x, %hs)\n",
  5914. CreateFlags,
  5915. pct->pszTableName));
  5916. fTableOpen = FALSE;
  5917. if (CF_MISSINGTABLES & CreateFlags)
  5918. {
  5919. hr = _dbgJetCreateTable(
  5920. pcs->SesId,
  5921. pcs->DBId,
  5922. pct->pszTableName,
  5923. ULTABLEPAGES,
  5924. PCDENSITYSET,
  5925. &tableid);
  5926. if ((HRESULT) JET_errTableDuplicate != hr)
  5927. {
  5928. _JumpIfError(hr, error, "JetCreateTable");
  5929. if (!(CF_DATABASE & CreateFlags))
  5930. {
  5931. DBGPRINT((
  5932. DBG_SS_CERTDB,
  5933. "Created Missing Table: %hs:%x\n",
  5934. pct->pszTableName,
  5935. tableid));
  5936. }
  5937. hr = _dbgJetCloseTable(pcs->SesId, tableid);
  5938. _JumpIfError(hr, error, "JetCloseTable");
  5939. }
  5940. }
  5941. hr = _dbgJetOpenTable(
  5942. pcs->SesId,
  5943. pcs->DBId,
  5944. pct->pszTableName,
  5945. NULL, // pvParameters
  5946. 0, // cbParameters
  5947. JET_bitTableDenyRead, // grbit
  5948. &tableid);
  5949. _JumpIfError(hr, error, "JetOpenTable");
  5950. fTableOpen = TRUE;
  5951. CSASSERT(IsValidJetTableId(tableid));
  5952. DBGPRINT((DBG_SS_CERTDBI, "OpenTable: %hs: %x\n", pct->pszTableName, tableid));
  5953. if (CF_MISSINGTABLES & CreateFlags)
  5954. {
  5955. ULONG aulDensity[2];
  5956. hr = _dbgJetGetTableInfo(
  5957. pcs->SesId,
  5958. tableid,
  5959. aulDensity,
  5960. sizeof(aulDensity),
  5961. JET_TblInfoSpaceAlloc);
  5962. _JumpIfError(hr, error, "JetGetTableInfo");
  5963. DBGPRINT((
  5964. DBG_SS_CERTDBI,
  5965. "Table Density: %hs: %u\n",
  5966. pct->pszTableName,
  5967. aulDensity[1]));
  5968. #if 0
  5969. // Modifying the table density does not change the density returned by
  5970. // JetGetTableInfo. Instead, it modifies the primary index density,
  5971. // which has the same effect. There's no point in making this call,
  5972. // because it would modify the primary index density, so we wouldn't
  5973. // notice a restart is required when the primary index density is
  5974. // examined below.
  5975. if (PCDENSITYMIN > aulDensity[1] || PCDENSITYMAX < aulDensity[1])
  5976. {
  5977. IndexDensity.szTable = const_cast<char *>(pct->pszTableName);
  5978. IndexDensity.szIndex = NULL;
  5979. IndexDensity.ulDensity = PCDENSITYRESET;
  5980. // This call doesn't seem to modify the table density returned
  5981. // by JetGetTableInfo. Instead, it modifies the primary index
  5982. // density, which has the same effect.
  5983. // Make the call anyway, just in case there ever is a distinction.
  5984. hr = _dbgJetConvertDDL(
  5985. pcs->SesId,
  5986. pcs->DBId,
  5987. opDDLConvChangeIndexDensity,
  5988. &IndexDensity,
  5989. sizeof(IndexDensity));
  5990. _PrintIfError(hr, "JetConvertDDL");
  5991. if (S_OK == hr)
  5992. {
  5993. m_fDBRestart = TRUE;
  5994. DBGPRINT((
  5995. DBG_SS_CERTDB,
  5996. "Changed Table Density: %hs: %x->%x\n",
  5997. IndexDensity.szTable,
  5998. aulDensity[1],
  5999. IndexDensity.ulDensity));
  6000. }
  6001. }
  6002. #endif
  6003. }
  6004. if (NULL != pct->pdt)
  6005. {
  6006. HRESULT hrDuplicate;
  6007. HRESULT hrRedundant;
  6008. HRESULT hrHasPrimary;
  6009. if ((CF_DATABASE | CF_MISSINGTABLES | CF_MISSINGCOLUMNS) & CreateFlags)
  6010. {
  6011. hrDuplicate = myJetHResult(JET_errColumnDuplicate);
  6012. hrRedundant = myJetHResult(JET_errColumnRedundant);
  6013. for (pdt = pct->pdt; NULL != pdt->pwszPropName; pdt++)
  6014. {
  6015. if (0 == (DBTF_COMPUTED & pdt->dwFlags))
  6016. {
  6017. hr = _AddColumn(pcs, tableid, pdt);
  6018. if (hrDuplicate == hr || hrRedundant == hr)
  6019. {
  6020. _PrintError2(hr, "_AddColumn", hr);
  6021. hr = S_OK;
  6022. }
  6023. else
  6024. if (S_OK == hr && !(CF_DATABASE & CreateFlags))
  6025. {
  6026. m_fAddedNewColumns = TRUE;
  6027. DBGPRINT((
  6028. DBG_SS_CERTDB,
  6029. "Added Missing Column: %hs.%hs\n",
  6030. pct->pszTableName,
  6031. pdt->pszFieldName));
  6032. }
  6033. _JumpIfErrorStr(hr, error, "_AddColumn", pdt->pwszPropName);
  6034. }
  6035. }
  6036. }
  6037. if ((CF_DATABASE | CF_MISSINGTABLES | CF_MISSINGCOLUMNS | CF_MISSINGINDEXES) & CreateFlags)
  6038. {
  6039. hrDuplicate = myJetHResult(JET_errIndexDuplicate);
  6040. hrHasPrimary = myJetHResult(JET_errIndexHasPrimary);
  6041. for (pdt = pct->pdt; NULL != pdt->pwszPropName; pdt++)
  6042. {
  6043. if (NULL != pdt->pszIndexName)
  6044. {
  6045. DWORD dwCreateIndexFlags = 0;
  6046. char *psz = achCol;
  6047. ULONG ulDensity;
  6048. if (DBTF_INDEXPRIMARY & pdt->dwFlags)
  6049. {
  6050. dwCreateIndexFlags |= JET_bitIndexPrimary;
  6051. }
  6052. if (DBTF_INDEXUNIQUE & pdt->dwFlags)
  6053. {
  6054. dwCreateIndexFlags |= JET_bitIndexUnique;
  6055. }
  6056. if (DBTF_INDEXIGNORENULL & pdt->dwFlags)
  6057. {
  6058. dwCreateIndexFlags |= JET_bitIndexIgnoreNull;
  6059. }
  6060. if (DBTF_INDEXREQUESTID & pdt->dwFlags)
  6061. {
  6062. psz += sprintf(psz, "+%hs", szREQUESTID) + 1;
  6063. }
  6064. psz += sprintf(psz, "+%hs", pdt->pszFieldName) + 1;
  6065. *psz++ = '\0'; // double terminate
  6066. if (ISTEXTCOLTYP(pdt->dbcoltyp))
  6067. {
  6068. // if text field, include 2-byte langid
  6069. *(WORD UNALIGNED *) psz = LANGID_DBFIXED;
  6070. psz += sizeof(WORD);
  6071. *psz++ = '\0'; // double terminate
  6072. *psz++ = '\0'; // double terminate
  6073. }
  6074. hr = _CreateIndex(
  6075. pcs,
  6076. tableid,
  6077. pdt->pszIndexName,
  6078. achCol,
  6079. SAFE_SUBTRACT_POINTERS(psz, achCol),
  6080. dwCreateIndexFlags);
  6081. if (hrDuplicate == hr ||
  6082. (hrHasPrimary == hr &&
  6083. (DBTF_INDEXPRIMARY & pdt->dwFlags)))
  6084. {
  6085. _PrintError2(hr, "_CreateIndex", hr);
  6086. hr = S_OK;
  6087. }
  6088. else
  6089. if (S_OK == hr && !(CF_DATABASE & CreateFlags))
  6090. {
  6091. DBGPRINT((
  6092. DBG_SS_CERTDB,
  6093. "Added Missing Index: %hs.%hs\n",
  6094. pct->pszTableName,
  6095. pdt->pszIndexName));
  6096. if (chTEXTPREFIX == *pdt->pszIndexName ||
  6097. (DBTF_INDEXRENAMED & pdt->dwFlags))
  6098. {
  6099. char const *pszIndexName = &pdt->pszIndexName[1];
  6100. CSASSERTTHREAD(pcs);
  6101. if (DBTF_INDEXRENAMED & pdt->dwFlags)
  6102. {
  6103. pszIndexName += strlen(pszIndexName) + 1;
  6104. }
  6105. hr = _dbgJetDeleteIndex(
  6106. pcs->SesId,
  6107. tableid,
  6108. pszIndexName);
  6109. _PrintIfError2(hr, "JetDeleteIndex", hr);
  6110. if (S_OK == hr)
  6111. {
  6112. DBGPRINT((
  6113. DBG_SS_CERTDB,
  6114. "Deleted index %hs.%hs\n",
  6115. pct->pszTableName,
  6116. pszIndexName));
  6117. }
  6118. hr = S_OK;
  6119. }
  6120. }
  6121. _JumpIfError(hr, error, "_CreateIndex");
  6122. hr = _dbgJetGetIndexInfo(
  6123. pcs->SesId,
  6124. pcs->DBId,
  6125. pct->pszTableName,
  6126. pdt->pszIndexName,
  6127. &ulDensity,
  6128. sizeof(ulDensity),
  6129. JET_IdxInfoSpaceAlloc);
  6130. _JumpIfError(hr, error, "JetGetIndexInfo");
  6131. DBGPRINT((
  6132. DBG_SS_CERTDBI,
  6133. "Index Density: %hs.%hs: %u\n",
  6134. pct->pszTableName,
  6135. pdt->pszIndexName,
  6136. ulDensity));
  6137. if (PCDENSITYMIN > ulDensity || PCDENSITYMAX < ulDensity)
  6138. {
  6139. IndexDensity.szTable = const_cast<char *>(pct->pszTableName);
  6140. IndexDensity.szIndex = const_cast<char *>(pdt->pszIndexName);
  6141. IndexDensity.ulDensity = PCDENSITYRESET;
  6142. hr = _dbgJetConvertDDL(
  6143. pcs->SesId,
  6144. pcs->DBId,
  6145. opDDLConvChangeIndexDensity,
  6146. &IndexDensity,
  6147. sizeof(IndexDensity));
  6148. _PrintIfError(hr, "JetConvertDDL");
  6149. if (S_OK == hr)
  6150. {
  6151. m_fDBRestart = TRUE;
  6152. DBGPRINT((
  6153. DBG_SS_CERTDB,
  6154. "Changed Index Density: %hs.%hs: %x->%x\n",
  6155. IndexDensity.szTable,
  6156. IndexDensity.szIndex,
  6157. ulDensity,
  6158. IndexDensity.ulDensity));
  6159. }
  6160. }
  6161. }
  6162. }
  6163. }
  6164. }
  6165. hr = S_OK;
  6166. error:
  6167. if (fTableOpen)
  6168. {
  6169. HRESULT hr2;
  6170. hr2 = _dbgJetCloseTable(pcs->SesId, tableid);
  6171. if (S_OK == hr)
  6172. {
  6173. hr = hr2;
  6174. _JumpIfError(hr, error, "JetCloseTable");
  6175. }
  6176. }
  6177. return(myJetHResult(hr));
  6178. }
  6179. HRESULT
  6180. CCertDB::_Create(
  6181. IN DWORD CreateFlags, // CF_*
  6182. IN CHAR const *pszDataBaseName)
  6183. {
  6184. HRESULT hr;
  6185. DBCREATETABLE const *pct;
  6186. CERTSESSION *pcs = NULL;
  6187. DBGPRINT((
  6188. DBG_SS_CERTDBI,
  6189. "_Create(%x, %hs)\n",
  6190. CreateFlags,
  6191. pszDataBaseName));
  6192. hr = _AllocateSession(&pcs);
  6193. _JumpIfError(hr, error, "_AllocateSession");
  6194. if (CF_DATABASE & CreateFlags)
  6195. {
  6196. hr = _dbgJetCreateDatabase(
  6197. pcs->SesId,
  6198. pszDataBaseName,
  6199. NULL,
  6200. &pcs->DBId,
  6201. 0);
  6202. _JumpIfError(hr, error, "JetCreateDatabase");
  6203. hr = _dbgJetCloseDatabase(pcs->SesId, pcs->DBId, 0);
  6204. _JumpIfError(hr, error, "JetCloseDatabase");
  6205. }
  6206. hr = _dbgJetOpenDatabase(
  6207. pcs->SesId,
  6208. pszDataBaseName,
  6209. NULL,
  6210. &pcs->DBId,
  6211. JET_bitDbExclusive);
  6212. _JumpIfError(hr, error, "JetOpenDatabase");
  6213. hr = _dbgJetBeginTransaction(pcs->SesId);
  6214. _JumpIfError(hr, error, "JetBeginTransaction");
  6215. for (pct = g_actDataBase; NULL != pct->pszTableName; pct++)
  6216. {
  6217. hr = _CreateTable(CreateFlags, pcs, pct);
  6218. _JumpIfError(hr, error, "_CreateTable");
  6219. }
  6220. hr = _dbgJetCommitTransaction(pcs->SesId, 0);
  6221. _JumpIfError(hr, error, "JetCommitTransaction");
  6222. hr = _dbgJetCloseDatabase(pcs->SesId, pcs->DBId, 0);
  6223. _JumpIfError(hr, error, "JetCloseDatabase");
  6224. error:
  6225. if (NULL != pcs)
  6226. {
  6227. ReleaseSession(pcs);
  6228. }
  6229. return(myJetHResult(hr));
  6230. }
  6231. HRESULT
  6232. CCertDB::_DupString(
  6233. OPTIONAL IN WCHAR const *pwszPrefix,
  6234. IN WCHAR const *pwszIn,
  6235. OUT WCHAR **ppwszOut)
  6236. {
  6237. DWORD cbPrefix;
  6238. DWORD cb;
  6239. HRESULT hr;
  6240. cbPrefix = 0;
  6241. if (NULL != pwszPrefix)
  6242. {
  6243. cbPrefix = wcslen(pwszPrefix) * sizeof(WCHAR);
  6244. }
  6245. cb = (wcslen(pwszIn) + 1) * sizeof(WCHAR);
  6246. *ppwszOut = (WCHAR *) CoTaskMemAlloc(cbPrefix + cb);
  6247. if (NULL == *ppwszOut)
  6248. {
  6249. hr = E_OUTOFMEMORY;
  6250. _JumpError(hr, error, "CoTaskMemAlloc");
  6251. }
  6252. if (NULL != pwszPrefix)
  6253. {
  6254. CopyMemory(*ppwszOut, pwszPrefix, cbPrefix);
  6255. }
  6256. CopyMemory((BYTE *) *ppwszOut + cbPrefix, pwszIn, cb);
  6257. hr = S_OK;
  6258. error:
  6259. return(hr);
  6260. }