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.

706 lines
17 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. passrec.c
  5. Abstract:
  6. This module contains client side code to handle the local key recovery case.
  7. Author:
  8. Pete Skelly (petesk) May 9, 2000
  9. --*/
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. #include <lm.h>
  15. #include <rpc.h>
  16. #include <shlobj.h>
  17. #include <userenv.h>
  18. #include <wincrypt.h>
  19. #include "passrecp.h"
  20. #include "dpapiprv.h"
  21. #include "pasrec.h"
  22. #include "passrec.h"
  23. #define FILETIME_TICKS_PER_SECOND 10000000
  24. #define RECOVERYKEY_LIFETIME (60*60*24*365*5) // 5 Years
  25. DWORD
  26. PRRecoverPassword(
  27. IN LPWSTR pszUsername,
  28. IN PBYTE pbRecoveryPrivate,
  29. IN DWORD cbRecoveryPrivate,
  30. IN LPWSTR pszNewPassword)
  31. {
  32. DWORD dwError = ERROR_SUCCESS;
  33. RPC_BINDING_HANDLE h;
  34. unsigned short *pszBinding;
  35. if((NULL == pszUsername) ||
  36. (NULL == pbRecoveryPrivate) ||
  37. (NULL == pszNewPassword))
  38. {
  39. return ERROR_INVALID_PARAMETER;
  40. }
  41. dwError = RpcStringBindingComposeW(
  42. NULL,
  43. (unsigned short*)DPAPI_LOCAL_PROT_SEQ,
  44. NULL,
  45. (unsigned short*)DPAPI_LOCAL_ENDPOINT,
  46. NULL,
  47. &pszBinding
  48. );
  49. if (RPC_S_OK != dwError)
  50. {
  51. return(dwError);
  52. }
  53. dwError = RpcBindingFromStringBindingW(pszBinding, &h);
  54. if (RPC_S_OK != dwError)
  55. {
  56. goto error;
  57. }
  58. dwError = RpcEpResolveBinding(
  59. h,
  60. PasswordRecovery_v1_0_c_ifspec);
  61. if (RPC_S_OK != dwError)
  62. {
  63. goto error;
  64. }
  65. __try
  66. {
  67. dwError = SSRecoverPassword(h,
  68. (PBYTE)pszUsername,
  69. (wcslen(pszUsername) + 1) * sizeof(WCHAR),
  70. pbRecoveryPrivate,
  71. cbRecoveryPrivate,
  72. (PBYTE)pszNewPassword,
  73. (wcslen(pszNewPassword) + 1) * sizeof(WCHAR));
  74. }
  75. __except ( EXCEPTION_EXECUTE_HANDLER )
  76. {
  77. dwError = _exception_code();
  78. }
  79. error:
  80. if(pszBinding)
  81. {
  82. RpcStringFreeW(&pszBinding);
  83. }
  84. if(h)
  85. {
  86. RpcBindingFree(&h);
  87. }
  88. return dwError;
  89. }
  90. DWORD
  91. PRQueryStatus(
  92. IN OPTIONAL LPWSTR pszDomain,
  93. IN OPTIONAL LPWSTR pszUserName,
  94. OUT DWORD *pdwStatus)
  95. {
  96. DWORD dwError = ERROR_SUCCESS;
  97. RPC_BINDING_HANDLE h;
  98. WCHAR *pszBinding;
  99. WCHAR szUserName[UNLEN + 1];
  100. DWORD cchUserName;
  101. if(NULL == pdwStatus)
  102. {
  103. return ERROR_INVALID_PARAMETER;
  104. }
  105. //
  106. // If the caller didn't specify a username, then use the
  107. // username of the calling thread.
  108. //
  109. if(pszUserName == NULL)
  110. {
  111. pszUserName = szUserName;
  112. cchUserName = sizeof(szUserName) / sizeof(WCHAR);
  113. if(!GetUserNameW(szUserName, &cchUserName))
  114. {
  115. return GetLastError();
  116. }
  117. }
  118. dwError = RpcStringBindingComposeW(
  119. NULL,
  120. (unsigned short*)DPAPI_LOCAL_PROT_SEQ,
  121. NULL,
  122. (unsigned short*)DPAPI_LOCAL_ENDPOINT,
  123. NULL,
  124. &pszBinding
  125. );
  126. if (RPC_S_OK != dwError)
  127. {
  128. return(dwError);
  129. }
  130. dwError = RpcBindingFromStringBindingW(pszBinding, &h);
  131. if (RPC_S_OK != dwError)
  132. {
  133. goto error;
  134. }
  135. dwError = RpcEpResolveBinding(
  136. h,
  137. PasswordRecovery_v1_0_c_ifspec);
  138. if (RPC_S_OK != dwError)
  139. {
  140. goto error;
  141. }
  142. __try
  143. {
  144. dwError = SSRecoverQueryStatus(
  145. h,
  146. (PBYTE)pszUserName,
  147. (wcslen(pszUserName) + 1) * sizeof(WCHAR),
  148. pdwStatus);
  149. }
  150. __except ( EXCEPTION_EXECUTE_HANDLER )
  151. {
  152. dwError = _exception_code();
  153. }
  154. error:
  155. if(pszBinding)
  156. {
  157. RpcStringFreeW(&pszBinding);
  158. }
  159. if(h)
  160. {
  161. RpcBindingFree(&h);
  162. }
  163. return dwError;
  164. }
  165. DWORD
  166. PRImportRecoveryKey(
  167. IN LPWSTR pszUsername,
  168. IN LPWSTR pszCurrentPassword,
  169. IN BYTE* pbRecoveryPublic,
  170. IN DWORD cbRecoveryPublic)
  171. {
  172. DWORD dwError = ERROR_SUCCESS;
  173. RPC_BINDING_HANDLE h;
  174. unsigned short *pszBinding;
  175. if((NULL == pbRecoveryPublic) ||
  176. (0 == cbRecoveryPublic) ||
  177. (NULL == pszUsername) ||
  178. (NULL == pszCurrentPassword))
  179. {
  180. return ERROR_INVALID_PARAMETER;
  181. }
  182. dwError = RpcStringBindingComposeW(
  183. NULL,
  184. (unsigned short*)DPAPI_LOCAL_PROT_SEQ,
  185. NULL,
  186. (unsigned short*)DPAPI_LOCAL_ENDPOINT,
  187. NULL,
  188. &pszBinding
  189. );
  190. if (RPC_S_OK != dwError)
  191. {
  192. return(dwError);
  193. }
  194. dwError = RpcBindingFromStringBindingW(pszBinding, &h);
  195. if (RPC_S_OK != dwError)
  196. {
  197. goto error;
  198. }
  199. dwError = RpcEpResolveBinding(
  200. h,
  201. PasswordRecovery_v1_0_c_ifspec);
  202. if (RPC_S_OK != dwError)
  203. {
  204. goto error;
  205. }
  206. __try
  207. {
  208. dwError = SSRecoverImportRecoveryKey(
  209. h,
  210. (PBYTE)pszUsername,
  211. (wcslen(pszUsername) + 1) * sizeof(WCHAR),
  212. (PBYTE)pszCurrentPassword,
  213. (wcslen(pszCurrentPassword) + 1) * sizeof(WCHAR),
  214. pbRecoveryPublic,
  215. cbRecoveryPublic);
  216. }
  217. __except ( EXCEPTION_EXECUTE_HANDLER )
  218. {
  219. dwError = _exception_code();
  220. }
  221. error:
  222. if(pszBinding)
  223. {
  224. RpcStringFreeW(&pszBinding);
  225. }
  226. if(h)
  227. {
  228. RpcBindingFree(&h);
  229. }
  230. return dwError;
  231. }
  232. DWORD GenerateRecoveryCert(HCRYPTPROV hCryptProv,
  233. HCRYPTKEY hCryptKey,
  234. LPWSTR pszUsername,
  235. PSID pSid,
  236. PBYTE *ppbPublicExportData,
  237. DWORD *pcbPublicExportLength)
  238. {
  239. DWORD dwError = ERROR_SUCCESS;
  240. CERT_INFO CertInfo;
  241. CERT_PUBLIC_KEY_INFO *pKeyInfo = NULL;
  242. DWORD cbKeyInfo = 0;
  243. CERT_NAME_BLOB CertName;
  244. CERT_RDN_ATTR RDNAttributes[1];
  245. CERT_RDN CertRDN[] = {1, RDNAttributes} ;
  246. CERT_NAME_INFO NameInfo = {1, CertRDN};
  247. PCCERT_CONTEXT pCertContext = NULL;
  248. GUID GuidKey;
  249. CertName.pbData = NULL;
  250. CertName.cbData = 0;
  251. RDNAttributes[0].Value.pbData = NULL;
  252. RDNAttributes[0].Value.cbData = 0;
  253. DWORD cbCertSize = 0;
  254. PBYTE pbCert = NULL;
  255. DWORD cSize = 0;
  256. dwError = UuidCreate( &GuidKey );
  257. if(ERROR_SUCCESS != dwError)
  258. {
  259. goto error;
  260. }
  261. // Generate a self-signed cert structure
  262. RDNAttributes[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
  263. RDNAttributes[0].pszObjId = szOID_COMMON_NAME;
  264. RDNAttributes[0].Value.cbData = wcslen(pszUsername) * sizeof(WCHAR);
  265. RDNAttributes[0].Value.pbData = (PBYTE)pszUsername;
  266. //
  267. // Get the actual public key info from the key
  268. //
  269. if(!CryptExportPublicKeyInfo(hCryptProv,
  270. AT_KEYEXCHANGE,
  271. X509_ASN_ENCODING,
  272. NULL,
  273. &cbKeyInfo))
  274. {
  275. dwError = GetLastError();
  276. goto error;
  277. }
  278. pKeyInfo = (CERT_PUBLIC_KEY_INFO *)midl_user_allocate(cbKeyInfo);
  279. if(NULL == pKeyInfo)
  280. {
  281. dwError = ERROR_NOT_ENOUGH_MEMORY;
  282. goto error;
  283. }
  284. if(!CryptExportPublicKeyInfo(hCryptProv,
  285. AT_KEYEXCHANGE,
  286. X509_ASN_ENCODING,
  287. pKeyInfo,
  288. &cbKeyInfo))
  289. {
  290. dwError = GetLastError();
  291. goto error;
  292. }
  293. //
  294. // Generate the certificate name
  295. //
  296. if(!CryptEncodeObject(X509_ASN_ENCODING,
  297. X509_NAME,
  298. &NameInfo,
  299. NULL,
  300. &CertName.cbData))
  301. {
  302. dwError = GetLastError();
  303. goto error;
  304. }
  305. CertName.pbData = (PBYTE)midl_user_allocate(CertName.cbData);
  306. if(NULL == CertName.pbData)
  307. {
  308. dwError = ERROR_NOT_ENOUGH_MEMORY;
  309. goto error;
  310. }
  311. if(!CryptEncodeObject(X509_ASN_ENCODING,
  312. X509_NAME,
  313. &NameInfo,
  314. CertName.pbData,
  315. &CertName.cbData))
  316. {
  317. dwError = GetLastError();
  318. goto error;
  319. }
  320. CertInfo.dwVersion = CERT_V3;
  321. CertInfo.SerialNumber.pbData = (PBYTE)&GuidKey;
  322. CertInfo.SerialNumber.cbData = sizeof(GUID);
  323. CertInfo.SignatureAlgorithm.pszObjId = szOID_OIWSEC_sha1RSASign;
  324. CertInfo.SignatureAlgorithm.Parameters.cbData = 0;
  325. CertInfo.SignatureAlgorithm.Parameters.pbData = NULL;
  326. CertInfo.Issuer.pbData = CertName.pbData;
  327. CertInfo.Issuer.cbData = CertName.cbData;
  328. GetSystemTimeAsFileTime(&CertInfo.NotBefore);
  329. CertInfo.NotAfter = CertInfo.NotBefore;
  330. ((LARGE_INTEGER * )&CertInfo.NotAfter)->QuadPart +=
  331. Int32x32To64(FILETIME_TICKS_PER_SECOND, RECOVERYKEY_LIFETIME);
  332. CertInfo.Subject.pbData = CertName.pbData;
  333. CertInfo.Subject.cbData = CertName.cbData;
  334. CertInfo.SubjectPublicKeyInfo = *pKeyInfo;
  335. CertInfo.SubjectUniqueId.pbData = (PBYTE)pSid;
  336. CertInfo.SubjectUniqueId.cbData = GetLengthSid(pSid);
  337. CertInfo.SubjectUniqueId.cUnusedBits = 0;
  338. CertInfo.IssuerUniqueId.pbData = (PBYTE)pSid;
  339. CertInfo.IssuerUniqueId.cbData = GetLengthSid(pSid);
  340. CertInfo.IssuerUniqueId.cUnusedBits = 0;
  341. CertInfo.cExtension = 0;
  342. CertInfo.rgExtension = NULL;
  343. if(!CryptSignAndEncodeCertificate(hCryptProv,
  344. AT_KEYEXCHANGE,
  345. X509_ASN_ENCODING,
  346. X509_CERT_TO_BE_SIGNED,
  347. &CertInfo,
  348. &CertInfo.SignatureAlgorithm,
  349. NULL,
  350. NULL,
  351. &cbCertSize))
  352. {
  353. dwError = GetLastError();
  354. goto error;
  355. }
  356. pbCert = (PBYTE)midl_user_allocate(cbCertSize);
  357. if(NULL == pbCert)
  358. {
  359. dwError = ERROR_NOT_ENOUGH_MEMORY;
  360. goto error;
  361. }
  362. if(!CryptSignAndEncodeCertificate(hCryptProv,
  363. AT_KEYEXCHANGE,
  364. X509_ASN_ENCODING,
  365. X509_CERT_TO_BE_SIGNED,
  366. &CertInfo,
  367. &CertInfo.SignatureAlgorithm,
  368. NULL,
  369. pbCert,
  370. &cbCertSize))
  371. {
  372. dwError = GetLastError();
  373. goto error;
  374. }
  375. *pcbPublicExportLength = cbCertSize;
  376. *ppbPublicExportData = pbCert;
  377. // Double-check to make sure certificate is valid
  378. pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCertSize);
  379. if(pCertContext == NULL)
  380. {
  381. dwError = GetLastError();
  382. goto error;
  383. }
  384. else
  385. {
  386. CertFreeCertificateContext(pCertContext);
  387. }
  388. pbCert = NULL;
  389. error:
  390. if(pbCert)
  391. {
  392. midl_user_free(pbCert);
  393. }
  394. if(pKeyInfo)
  395. {
  396. midl_user_free(pKeyInfo);
  397. }
  398. if(CertName.pbData)
  399. {
  400. midl_user_free(CertName.pbData);
  401. }
  402. return dwError;
  403. }
  404. DWORD
  405. PRGenerateRecoveryKey(
  406. IN LPWSTR pszUsername,
  407. IN LPWSTR pszCurrentPassword,
  408. OUT PBYTE *ppbRecoveryPrivate,
  409. OUT DWORD *pcbRecoveryPrivate)
  410. {
  411. DWORD dwError = 0;
  412. HCRYPTPROV hProv = 0;
  413. HCRYPTKEY hKey = 0;
  414. DWORD dwDefaultKeySize = 2048;
  415. DWORD cbPrivateExportLength = 0;
  416. DWORD cbPublic = 0;
  417. PBYTE pbPublic = NULL;
  418. PBYTE pbRecoveryPrivate = NULL;
  419. DWORD cbRecoveryPrivate = 0;
  420. PSID pSid = NULL;
  421. DWORD cbSid;
  422. WCHAR szDomain[MAX_COMPUTERNAME_LENGTH + 1];
  423. DWORD cchDomain;
  424. SID_NAME_USE AcctType;
  425. //
  426. // Obtain SID of current user.
  427. //
  428. cchDomain = MAX_COMPUTERNAME_LENGTH + 1;
  429. if(!GetComputerNameW(szDomain, &cchDomain))
  430. {
  431. dwError = GetLastError();
  432. goto error;
  433. }
  434. if(!LookupAccountNameW(szDomain,
  435. pszUsername,
  436. NULL,
  437. &cbSid,
  438. NULL,
  439. &cchDomain,
  440. &AcctType))
  441. {
  442. dwError = GetLastError();
  443. if(dwError != ERROR_INSUFFICIENT_BUFFER)
  444. {
  445. goto error;
  446. }
  447. }
  448. pSid = (PBYTE)LocalAlloc(LPTR, cbSid);
  449. if(pSid == NULL)
  450. {
  451. dwError = ERROR_NOT_ENOUGH_MEMORY;
  452. goto error;
  453. }
  454. if(cchDomain > MAX_COMPUTERNAME_LENGTH + 1)
  455. {
  456. dwError = ERROR_NOT_ENOUGH_MEMORY;
  457. goto error;
  458. }
  459. if(!LookupAccountNameW(szDomain,
  460. pszUsername,
  461. pSid,
  462. &cbSid,
  463. szDomain,
  464. &cchDomain,
  465. &AcctType))
  466. {
  467. dwError = GetLastError();
  468. goto error;
  469. }
  470. //
  471. // Create recovery private key.
  472. //
  473. if(!CryptAcquireContext(&hProv,
  474. NULL,
  475. MS_STRONG_PROV,
  476. PROV_RSA_FULL,
  477. CRYPT_VERIFYCONTEXT))
  478. {
  479. dwError = GetLastError();
  480. goto error;
  481. }
  482. if(!CryptGenKey(hProv,
  483. AT_KEYEXCHANGE,
  484. CRYPT_EXPORTABLE | (dwDefaultKeySize << 16),
  485. &hKey))
  486. {
  487. dwError = GetLastError();
  488. goto error;
  489. }
  490. dwError = GenerateRecoveryCert(hProv,
  491. hKey,
  492. pszUsername,
  493. pSid,
  494. &pbPublic,
  495. &cbPublic);
  496. if(ERROR_SUCCESS != dwError)
  497. {
  498. goto error;
  499. }
  500. //
  501. // Get the private key size
  502. //
  503. if(!CryptExportKey(hKey,
  504. NULL,
  505. PRIVATEKEYBLOB,
  506. 0,
  507. NULL,
  508. &cbPrivateExportLength))
  509. {
  510. dwError = GetLastError();
  511. goto error;
  512. }
  513. cbRecoveryPrivate = 2*sizeof(DWORD) + cbPrivateExportLength;
  514. pbRecoveryPrivate = (PBYTE)LocalAlloc(LMEM_FIXED, cbRecoveryPrivate);
  515. if(NULL == pbRecoveryPrivate)
  516. {
  517. dwError = ERROR_NOT_ENOUGH_MEMORY;
  518. goto error;
  519. }
  520. *(DWORD *)pbRecoveryPrivate = RECOVERY_BLOB_MAGIC;
  521. *(DWORD *)(pbRecoveryPrivate + sizeof(DWORD)) = RECOVERY_BLOB_VERSION;
  522. //
  523. // Export the private key
  524. //
  525. if(!CryptExportKey(hKey,
  526. NULL,
  527. PRIVATEKEYBLOB,
  528. 0,
  529. pbRecoveryPrivate + 2*sizeof(DWORD),
  530. &cbPrivateExportLength))
  531. {
  532. dwError = GetLastError();
  533. goto error;
  534. }
  535. dwError = PRImportRecoveryKey(
  536. pszUsername,
  537. pszCurrentPassword,
  538. pbPublic,
  539. cbPublic);
  540. if(ERROR_SUCCESS != dwError)
  541. {
  542. goto error;
  543. }
  544. *ppbRecoveryPrivate = pbRecoveryPrivate;
  545. *pcbRecoveryPrivate = cbRecoveryPrivate;
  546. pbRecoveryPrivate = NULL;
  547. error:
  548. if(pbRecoveryPrivate)
  549. {
  550. RtlSecureZeroMemory(pbRecoveryPrivate, cbRecoveryPrivate);
  551. LocalFree(pbRecoveryPrivate);
  552. }
  553. if(pbPublic)
  554. {
  555. LocalFree(pbPublic);
  556. }
  557. if(hKey)
  558. {
  559. CryptDestroyKey(hKey);
  560. }
  561. if(hProv)
  562. {
  563. CryptReleaseContext(hProv, 0);
  564. }
  565. if(pSid)
  566. {
  567. LocalFree(pSid);
  568. }
  569. return dwError;
  570. }