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.

487 lines
14 KiB

  1. /*
  2. ** p r o p c r y p . c p p
  3. **
  4. ** Purpose:
  5. ** Functions to provide blob-level access to the pstore
  6. **
  7. ** History
  8. ** 3/04/97: (t-erikne) support for non-pstore systems
  9. ** 2/15/97: (t-erikne) rewritten for pstore
  10. ** 12/04/96: (sbailey) created
  11. **
  12. ** Copyright (C) Microsoft Corp. 1996, 1997.
  13. */
  14. #include "pch.hxx"
  15. #include "propcryp.h"
  16. #include <imnact.h>
  17. #include <demand.h>
  18. ///////////////////////////////////////////////////////////////////////////
  19. //
  20. // Structures, definitions
  21. //
  22. #define OBFUSCATOR 0x14151875;
  23. #define PROT_SIZEOF_HEADER 0x02 // 2 bytes in the header
  24. #define PROT_SIZEOF_XORHEADER (PROT_SIZEOF_HEADER+sizeof(DWORD))
  25. #define PROT_VERSION_1 0x01
  26. #define PROT_PASS_XOR 0x01
  27. #define PROT_PASS_PST 0x02
  28. // Layout of registry data (v0)
  29. //
  30. // /--------------------------------
  31. // | protected store name, a LPWSTR
  32. // \--------------------------------
  33. //
  34. //
  35. // Layout of registry data (v1)
  36. //
  37. // /----------------------------------------------------------------------
  38. // | version (1 b) =0x01 | type (1 b) =PROT_PASS_* | data (see below)
  39. // \----------------------------------------------------------------------
  40. //
  41. // data for PROT_PASS_PST
  42. // struct _data
  43. // { LPWSTR szPSTItemName; }
  44. // data for PROT_PASS_XOR
  45. // struct _data
  46. // { DWORD cb; BYTE pb[cb]; }
  47. //
  48. ///////////////////////////////////////////////////////////////////////////
  49. //
  50. // Prototypes
  51. //
  52. static inline BOOL FDataIsValidV0(BLOB *pblob);
  53. static BOOL FDataIsValidV1(BYTE *pb);
  54. static inline BOOL FDataIsPST(BYTE *pb);
  55. static HRESULT XOREncodeProp(const BLOB *const pClear, BLOB *const pEncoded);
  56. static HRESULT XORDecodeProp(const BLOB *const pEncoded, BLOB *const pClear);
  57. ///////////////////////////////////////////////////////////////////////////
  58. //
  59. // Admin functions (init, addref, release, ctor, dtor)
  60. //
  61. HRESULT HrCreatePropCrypt(CPropCrypt **ppPropCrypt)
  62. {
  63. *ppPropCrypt = new CPropCrypt();
  64. if (NULL == *ppPropCrypt)
  65. return TRAPHR(E_OUTOFMEMORY);
  66. return (*ppPropCrypt)->HrInit();
  67. }
  68. CPropCrypt::CPropCrypt(void) : m_cRef(1), m_fInit(FALSE),
  69. m_pISecProv(NULL)
  70. { }
  71. CPropCrypt::~CPropCrypt(void)
  72. {
  73. ReleaseObj(m_pISecProv);
  74. }
  75. ULONG CPropCrypt::AddRef(void)
  76. { return ++m_cRef; }
  77. ULONG CPropCrypt::Release(void)
  78. {
  79. if (0 != --m_cRef)
  80. return m_cRef;
  81. delete this;
  82. return 0;
  83. }
  84. HRESULT CPropCrypt::HrInit(void)
  85. {
  86. HRESULT hr;
  87. PST_PROVIDERID provId = MS_BASE_PSTPROVIDER_ID;
  88. Assert(!m_pISecProv);
  89. if (FAILED(hr = PStoreCreateInstance(&m_pISecProv, &provId, NULL, 0)))
  90. {
  91. // this is true because we will now handle
  92. // all transactions without the protected store
  93. m_fInit = TRUE;
  94. hr = S_OK;
  95. }
  96. else if (SUCCEEDED(hr = PSTCreateTypeSubType_NoUI(
  97. m_pISecProv,
  98. &PST_IDENT_TYPE_GUID,
  99. PST_IDENT_TYPE_STRING,
  100. &PST_IMNACCT_SUBTYPE_GUID,
  101. PST_IMNACCT_SUBTYPE_STRING)))
  102. {
  103. m_fInit = TRUE;
  104. }
  105. return hr;
  106. }
  107. ///////////////////////////////////////////////////////////////////////////
  108. //
  109. // Public encode/decode/delete functions
  110. //
  111. ///////////////////////////////////////////////////////////////////////////
  112. HRESULT CPropCrypt::HrEncodeNewProp(LPSTR szAccountName, BLOB *pClear, BLOB *pEncoded)
  113. {
  114. HRESULT hr = S_OK;
  115. const int cchFastbuf = 50;
  116. WCHAR szWfast[cchFastbuf];
  117. LPWSTR szWalloc = NULL;
  118. LPWSTR wszCookie = NULL;
  119. BLOB blob;
  120. DWORD dwErr;
  121. int cchW;
  122. AssertSz (pClear && pEncoded, "Null Parameter");
  123. pEncoded->pBlobData = NULL;
  124. if (m_fInit == FALSE)
  125. return TRAPHR(E_FAIL);
  126. if (!m_pISecProv)
  127. {
  128. // protected store does not exist
  129. hr = XOREncodeProp(pClear, pEncoded);
  130. goto exit;
  131. }
  132. if (szAccountName)
  133. {
  134. if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szAccountName, -1,
  135. szWfast, cchFastbuf))
  136. {
  137. dwErr = GetLastError();
  138. if (ERROR_INSUFFICIENT_BUFFER == dwErr)
  139. {
  140. // get proper size and alloc buffer
  141. cchW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  142. szAccountName, -1, NULL, 0);
  143. if (FAILED(hr = HrAlloc((LPVOID *)&szWalloc, cchW*sizeof(WCHAR))))
  144. goto exit;
  145. if (!(MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  146. szAccountName, -1, szWalloc, cchW)))
  147. {
  148. hr = GetLastError();
  149. goto exit;
  150. }
  151. }
  152. else
  153. {
  154. hr = dwErr;
  155. goto exit;
  156. }
  157. }
  158. }
  159. else
  160. {
  161. szWfast[0] = '\000';
  162. }
  163. if (SUCCEEDED(hr = PSTSetNewData(m_pISecProv, &PST_IDENT_TYPE_GUID,
  164. &PST_IMNACCT_SUBTYPE_GUID, szWalloc?szWalloc:szWfast, pClear, pEncoded)))
  165. {
  166. BYTE *pb = pEncoded->pBlobData;
  167. DWORD sz = pEncoded->cbSize;
  168. Assert(pb);
  169. pEncoded->cbSize += PROT_SIZEOF_HEADER;
  170. //N This realloc is annoying. If we assume the memory allocator used
  171. //N by the PST function, we could be smarter....
  172. if (FAILED(hr = HrAlloc((LPVOID *)&pEncoded->pBlobData, pEncoded->cbSize)))
  173. goto exit;
  174. pEncoded->pBlobData[0] = PROT_VERSION_1;
  175. pEncoded->pBlobData[1] = PROT_PASS_PST;
  176. Assert(2 == PROT_SIZEOF_HEADER);
  177. CopyMemory(&pEncoded->pBlobData[PROT_SIZEOF_HEADER], pb, sz);
  178. PSTFreeHandle(pb);
  179. }
  180. exit:
  181. if (szWalloc)
  182. MemFree(szWalloc);
  183. if (FAILED(hr) && pEncoded->pBlobData)
  184. MemFree(pEncoded->pBlobData);
  185. return hr;
  186. }
  187. HRESULT CPropCrypt::HrEncode(BLOB *pClear, BLOB *pEncoded)
  188. {
  189. HRESULT hr;
  190. PST_PROMPTINFO PromptInfo = { sizeof(PST_PROMPTINFO), 0, NULL, L""};
  191. AssertSz (pClear && pEncoded &&
  192. pClear->pBlobData && pClear->cbSize, "Null Parameter");
  193. if (m_fInit == FALSE)
  194. return TRAPHR(E_FAIL);
  195. if (m_pISecProv)
  196. {
  197. if (FDataIsValidV1(pEncoded->pBlobData) && FDataIsPST(pEncoded->pBlobData))
  198. {
  199. Assert(pEncoded->cbSize-PROT_SIZEOF_HEADER ==
  200. (lstrlenW((LPWSTR)(pEncoded->pBlobData+PROT_SIZEOF_HEADER))+1)*sizeof(WCHAR));
  201. tryagain:
  202. hr = m_pISecProv->WriteItem(
  203. PST_KEY_CURRENT_USER,
  204. &PST_IDENT_TYPE_GUID,
  205. &PST_IMNACCT_SUBTYPE_GUID,
  206. (LPCWSTR)&pEncoded->pBlobData[PROT_SIZEOF_HEADER],
  207. (DWORD)pClear->cbSize,
  208. pClear->pBlobData,
  209. &PromptInfo,
  210. PST_CF_NONE,
  211. 0);
  212. if (PST_E_TYPE_NO_EXISTS == hr)
  213. {
  214. DOUTL(DOUTL_CPROP, "PropCryp: somebody ruined my type or subtype");
  215. hr = PSTCreateTypeSubType_NoUI(
  216. m_pISecProv,
  217. &PST_IDENT_TYPE_GUID,
  218. PST_IDENT_TYPE_STRING,
  219. &PST_IMNACCT_SUBTYPE_GUID,
  220. PST_IMNACCT_SUBTYPE_STRING);
  221. if (SUCCEEDED(hr))
  222. goto tryagain;
  223. }
  224. }
  225. else
  226. {
  227. #ifdef DEBUG
  228. if (FDataIsValidV0(pEncoded))
  229. DOUTL(DOUTL_CPROP, "PropCryp: V0 to V1 upgrade");
  230. else if (!FDataIsValidV1(pEncoded->pBlobData))
  231. DOUTL(DOUTL_CPROP, "PropCryp: invalid data on save");
  232. #endif
  233. // now we have XOR data in a PST environment
  234. hr = HrEncodeNewProp(NULL, pClear, pEncoded);
  235. }
  236. }
  237. else
  238. {
  239. // protected store does not exist
  240. hr = XOREncodeProp(pClear, pEncoded);
  241. }
  242. return TrapError(hr);
  243. }
  244. /* HrDecode:
  245. **
  246. ** Purpose:
  247. ** Uses the protstor functions to retrieve a piece of secure data
  248. ** unless the data is not pstore, then it maps to the XOR function
  249. ** Takes:
  250. ** IN pEncoded - blob containing name to pass to PSTGetData
  251. ** OUT pClear - blob containing property data
  252. ** Notes:
  253. ** pBlobData in pClear must be freed with a call to CoTaskMemFree()
  254. ** Returns:
  255. ** hresult
  256. */
  257. HRESULT CPropCrypt::HrDecode(BLOB *pEncoded, BLOB *pClear)
  258. {
  259. HRESULT hr;
  260. AssertSz(pEncoded && pEncoded->pBlobData && pClear, TEXT("Null Parameter"));
  261. pClear->pBlobData = NULL;
  262. if (m_fInit == FALSE)
  263. return TRAPHR(E_FAIL);
  264. if (!FDataIsValidV1(pEncoded->pBlobData))
  265. {
  266. if (FDataIsValidV0(pEncoded))
  267. {
  268. DOUTL(DOUTL_CPROP, "PropCryp: obtaining v0 value");
  269. // looks like we might have a v0 blob: the name string
  270. hr = PSTGetData(m_pISecProv, &PST_IDENT_TYPE_GUID, &PST_IMNACCT_SUBTYPE_GUID,
  271. (LPCWSTR)pEncoded->pBlobData, pClear);
  272. }
  273. else
  274. hr = E_InvalidValue;
  275. }
  276. else if (FDataIsPST(pEncoded->pBlobData))
  277. {
  278. Assert(pEncoded->cbSize-PROT_SIZEOF_HEADER ==
  279. (lstrlenW((LPWSTR)(pEncoded->pBlobData+PROT_SIZEOF_HEADER))+1)*sizeof(WCHAR));
  280. hr = PSTGetData(m_pISecProv, &PST_IDENT_TYPE_GUID, &PST_IMNACCT_SUBTYPE_GUID,
  281. (LPCWSTR)&pEncoded->pBlobData[PROT_SIZEOF_HEADER], pClear);
  282. }
  283. else
  284. {
  285. hr = XORDecodeProp(pEncoded, pClear);
  286. }
  287. return hr;
  288. }
  289. HRESULT CPropCrypt::HrDelete(BLOB *pProp)
  290. {
  291. HRESULT hr;
  292. PST_PROMPTINFO PromptInfo = { sizeof(PST_PROMPTINFO), 0, NULL, L""};
  293. if (m_fInit == FALSE)
  294. return TRAPHR(E_FAIL);
  295. if (m_pISecProv && FDataIsValidV1(pProp->pBlobData) && FDataIsPST(pProp->pBlobData))
  296. {
  297. Assert(pProp->cbSize-PROT_SIZEOF_HEADER ==
  298. (lstrlenW((LPWSTR)(pProp->pBlobData+PROT_SIZEOF_HEADER))+1)*sizeof(WCHAR));
  299. hr = m_pISecProv->DeleteItem(
  300. PST_KEY_CURRENT_USER,
  301. &PST_IDENT_TYPE_GUID,
  302. &PST_IMNACCT_SUBTYPE_GUID,
  303. (LPCWSTR)&pProp->pBlobData[PROT_SIZEOF_HEADER],
  304. &PromptInfo,
  305. 0);
  306. }
  307. else
  308. // nothing to do
  309. hr = S_OK;
  310. return hr;
  311. }
  312. ///////////////////////////////////////////////////////////////////////////
  313. //
  314. // XOR functions
  315. //
  316. ///////////////////////////////////////////////////////////////////////////
  317. HRESULT XOREncodeProp(const BLOB *const pClear, BLOB *const pEncoded)
  318. {
  319. DWORD dwSize;
  320. DWORD last, last2;
  321. DWORD *pdwCypher;
  322. DWORD dex;
  323. pEncoded->cbSize = pClear->cbSize+PROT_SIZEOF_XORHEADER;
  324. if (!MemAlloc((LPVOID *)&pEncoded->pBlobData, pEncoded->cbSize))
  325. return E_OUTOFMEMORY;
  326. // set up header data
  327. Assert(2 == PROT_SIZEOF_HEADER);
  328. pEncoded->pBlobData[0] = PROT_VERSION_1;
  329. pEncoded->pBlobData[1] = PROT_PASS_XOR;
  330. *((DWORD *)&(pEncoded->pBlobData[2])) = pClear->cbSize;
  331. // nevermind that the pointer is offset by the header size, this is
  332. // where we start to write out the modified password
  333. pdwCypher = (DWORD *)&(pEncoded->pBlobData[PROT_SIZEOF_XORHEADER]);
  334. dex = 0;
  335. last = OBFUSCATOR; // 0' = 0 ^ ob
  336. if (dwSize = pClear->cbSize / sizeof(DWORD))
  337. {
  338. // case where data is >= 4 bytes
  339. for (; dex < dwSize; dex++)
  340. {
  341. last2 = ((DWORD *)pClear->pBlobData)[dex]; // 1
  342. pdwCypher[dex] = last2 ^ last; // 1' = 1 ^ 0
  343. last = last2; // save 1 for the 2 round
  344. }
  345. }
  346. // if we have bits left over
  347. // note that dwSize is computed now in bits
  348. if (dwSize = (pClear->cbSize % sizeof(DWORD))*8)
  349. {
  350. // need to not munge memory that isn't ours
  351. last >>= sizeof(DWORD)*8-dwSize;
  352. pdwCypher[dex] &= ((DWORD)-1) << dwSize;
  353. pdwCypher[dex] |=
  354. ((((DWORD *)pClear->pBlobData)[dex] & (((DWORD)-1) >> (sizeof(DWORD)*8-dwSize))) ^ last);
  355. }
  356. return S_OK;
  357. }
  358. HRESULT XORDecodeProp(const BLOB *const pEncoded, BLOB *const pClear)
  359. {
  360. DWORD dwSize;
  361. DWORD last;
  362. DWORD *pdwCypher;
  363. DWORD dex;
  364. // we use CoTaskMemAlloc to be in line with the PST implementation
  365. pClear->cbSize = pEncoded->pBlobData[2];
  366. if (!(pClear->pBlobData = (BYTE *)CoTaskMemAlloc(pClear->cbSize)))
  367. return E_OUTOFMEMORY;
  368. // should have been tested by now
  369. Assert(FDataIsValidV1(pEncoded->pBlobData));
  370. Assert(!FDataIsPST(pEncoded->pBlobData));
  371. // nevermind that the pointer is offset by the header size, this is
  372. // where the password starts
  373. pdwCypher = (DWORD *)&(pEncoded->pBlobData[PROT_SIZEOF_XORHEADER]);
  374. dex = 0;
  375. last = OBFUSCATOR;
  376. if (dwSize = pClear->cbSize / sizeof(DWORD))
  377. {
  378. // case where data is >= 4 bytes
  379. for (; dex < dwSize; dex++)
  380. last = ((DWORD *)pClear->pBlobData)[dex] = pdwCypher[dex] ^ last;
  381. }
  382. // if we have bits left over
  383. if (dwSize = (pClear->cbSize % sizeof(DWORD))*8)
  384. {
  385. // need to not munge memory that isn't ours
  386. last >>= sizeof(DWORD)*8-dwSize;
  387. ((DWORD *)pClear->pBlobData)[dex] &= ((DWORD)-1) << dwSize;
  388. ((DWORD *)pClear->pBlobData)[dex] |=
  389. ((pdwCypher[dex] & (((DWORD)-1) >> (sizeof(DWORD)*8-dwSize))) ^ last);
  390. }
  391. return S_OK;
  392. }
  393. ///////////////////////////////////////////////////////////////////////////
  394. //
  395. // Other static functions
  396. //
  397. ///////////////////////////////////////////////////////////////////////////
  398. BOOL FDataIsValidV1(BYTE *pb)
  399. { return pb && pb[0] == PROT_VERSION_1 && (pb[1] == PROT_PASS_XOR || pb[1] == PROT_PASS_PST); }
  400. BOOL FDataIsValidV0(BLOB *pblob)
  401. { return ((lstrlenW((LPWSTR)pblob->pBlobData)+1)*sizeof(WCHAR) == pblob->cbSize); }
  402. BOOL FDataIsPST(BYTE *pb)
  403. #ifdef DEBUG
  404. {
  405. if (pb)
  406. if (pb[1] == PROT_PASS_PST)
  407. {
  408. DOUTL(DOUTL_CPROP, "PropCryp: Data is PST");
  409. return TRUE;
  410. }
  411. else
  412. {
  413. DOUTL(DOUTL_CPROP, "PropCryp: Data is XOR");
  414. return FALSE;
  415. }
  416. else
  417. return FALSE;
  418. }
  419. #else
  420. { return pb && pb[1] == PROT_PASS_PST; }
  421. #endif