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.

678 lines
19 KiB

  1. // Users.cpp: implementation of the CUsers class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "efsadu.h"
  6. #include "Users.h"
  7. #include <wincrypt.h>
  8. #ifdef _DEBUG
  9. #undef THIS_FILE
  10. static char THIS_FILE[]=__FILE__;
  11. #define new DEBUG_NEW
  12. #endif
  13. //////////////////////////////////////////////////////////////////////
  14. // Construction/Destruction
  15. //////////////////////////////////////////////////////////////////////
  16. CUsers::CUsers()
  17. {
  18. m_UsersRoot = NULL;
  19. m_UserAddedCnt = 0;
  20. m_UserRemovedCnt = 0;
  21. }
  22. //////////////////////////////////////////////////////////////////////
  23. // Walk through the chain to free the memory
  24. //////////////////////////////////////////////////////////////////////
  25. CUsers::~CUsers()
  26. {
  27. Clear();
  28. }
  29. PUSERSONFILE
  30. CUsers::RemoveItemFromHead(void)
  31. {
  32. PUSERSONFILE PItem = m_UsersRoot;
  33. if (m_UsersRoot){
  34. m_UsersRoot = m_UsersRoot->Next;
  35. if ((PItem->Flag & USERADDED) && !(PItem->Flag & USERREMOVED)){
  36. m_UserAddedCnt--;
  37. }
  38. if ((PItem->Flag & USERINFILE) && (PItem->Flag & USERREMOVED)){
  39. m_UserRemovedCnt--;
  40. }
  41. }
  42. return PItem;
  43. }
  44. DWORD
  45. CUsers::Add( CUsers &NewUsers )
  46. {
  47. PUSERSONFILE NewItem;
  48. while (NewItem = NewUsers.RemoveItemFromHead()){
  49. PUSERSONFILE TmpItem = m_UsersRoot;
  50. while ( TmpItem ){
  51. if ((NewItem->UserName && TmpItem->UserName && !_tcsicmp(NewItem->UserName, TmpItem->UserName)) ||
  52. ((NULL == NewItem->UserName) && (TmpItem->UserName == NULL))){
  53. //
  54. // User exist
  55. //
  56. if ( TmpItem->Flag & USERREMOVED ){
  57. if ( TmpItem->Flag & USERADDED ){
  58. ASSERT(!(TmpItem->Flag & USERINFILE));
  59. //
  60. // User added and removed
  61. //
  62. m_UserAddedCnt++;
  63. } else if ( TmpItem->Flag & USERINFILE ){
  64. //
  65. // User added and removed
  66. //
  67. m_UserRemovedCnt--;
  68. }
  69. TmpItem->Flag &= ~USERREMOVED;
  70. }
  71. //
  72. // The caller will count on CUsers to release the memory
  73. //
  74. if (NewItem->UserName){
  75. delete [] NewItem->UserName;
  76. }
  77. if ( NewItem->Context ) {
  78. CertFreeCertificateContext((PCCERT_CONTEXT)NewItem->Context);
  79. }
  80. delete [] NewItem->Cert;
  81. if (NewItem->UserSid){
  82. delete [] NewItem->UserSid;
  83. }
  84. delete NewItem;
  85. NewItem = NULL;
  86. break;
  87. }
  88. TmpItem = TmpItem->Next;
  89. }
  90. if (NewItem ){
  91. //
  92. // New item. Insert into the head.
  93. //
  94. NewItem->Next = m_UsersRoot;
  95. m_UsersRoot = NewItem;
  96. m_UserAddedCnt++;
  97. }
  98. }
  99. return ERROR_SUCCESS;
  100. }
  101. DWORD
  102. CUsers::Add(
  103. LPTSTR UserName,
  104. PVOID UserCert,
  105. PSID UserSid, /* = NULL */
  106. DWORD Flag, /* = USERINFILE */
  107. PVOID Context /* = NULL */
  108. )
  109. //////////////////////////////////////////////////////////////////////
  110. // Routine Description:
  111. // Create an item for a user
  112. // Arguments:
  113. // UserName -- User's name
  114. // UserCert -- User's certificate blob or hash
  115. // UserSid -- User's ID. Can be NULL
  116. // Flag -- Indicate if the item is existing in the file, to be added or removed
  117. // Return Value:
  118. // NO_ERROR if succeed.
  119. // Will throw exception if memory allocation fails. ( From new.)
  120. //
  121. //////////////////////////////////////////////////////////////////////
  122. {
  123. PUSERSONFILE UserItem;
  124. PUSERSONFILE TmpUserItem = m_UsersRoot;
  125. PEFS_CERTIFICATE_BLOB CertBlob;
  126. PEFS_HASH_BLOB CertHashBlob;
  127. DWORD CertSize;
  128. DWORD SidSize;
  129. if ( !UserCert ){
  130. return ERROR_INVALID_PARAMETER;
  131. }
  132. ASSERT ( (( Flag & USERADDED ) || ( Flag & USERINFILE )) &&
  133. ( (Flag & (USERADDED | USERINFILE)) != (USERADDED | USERINFILE)));
  134. //
  135. // If the user already in the memory, no new item is to be created except for unknown user
  136. //
  137. while ( TmpUserItem ){
  138. if ( (UserName && TmpUserItem->UserName && !_tcsicmp(UserName, TmpUserItem->UserName)) ||
  139. ((NULL == UserName) && (TmpUserItem->UserName == NULL))){
  140. //
  141. // User exist
  142. //
  143. if ( TmpUserItem->Flag & USERREMOVED ){
  144. if ( TmpUserItem->Flag & USERADDED ){
  145. ASSERT(!(TmpUserItem->Flag & USERINFILE));
  146. //
  147. // User added and removed
  148. //
  149. m_UserAddedCnt++;
  150. } else if ( TmpUserItem->Flag & USERINFILE ){
  151. //
  152. // User added and removed
  153. //
  154. m_UserRemovedCnt--;
  155. }
  156. TmpUserItem->Flag &= ~USERREMOVED;
  157. }
  158. //
  159. // The caller will count on CUsers to release
  160. // the context if the call returns CRYPT_E_EXISTS. This is just for
  161. // performance reason.
  162. //
  163. /*
  164. if (UserName){
  165. delete [] UserName;
  166. }
  167. */
  168. if ( Context ) {
  169. CertFreeCertificateContext((PCCERT_CONTEXT)Context);
  170. Context = NULL;
  171. }
  172. return CRYPT_E_EXISTS;
  173. }
  174. TmpUserItem = TmpUserItem->Next;
  175. }
  176. try {
  177. UserItem = new USERSONFILE;
  178. if ( NULL == UserItem ){
  179. AfxThrowMemoryException( );
  180. }
  181. UserItem->Next = NULL;
  182. //
  183. // In case exception raised, we can call delete.
  184. // Delete NULL is OK, but random data is not OK.
  185. //
  186. UserItem->UserSid = NULL;
  187. UserItem->Cert = NULL;
  188. UserItem->Context = NULL;
  189. if ( UserSid ){
  190. SidSize = GetLengthSid( UserSid );
  191. if ( SidSize > 0 ){
  192. UserItem->UserSid = new BYTE[SidSize];
  193. if ( NULL == UserItem->UserSid ){
  194. AfxThrowMemoryException( );
  195. }
  196. if ( !CopySid(SidSize, UserItem->UserSid, UserSid)){
  197. delete [] UserItem->UserSid;
  198. delete UserItem;
  199. return GetLastError();
  200. }
  201. } else {
  202. delete UserItem;
  203. return GetLastError();
  204. }
  205. } else {
  206. UserItem->UserSid = NULL;
  207. }
  208. if ( Flag & USERINFILE ){
  209. //
  210. // The info is from the file. Use the hash structure
  211. //
  212. CertHashBlob = ( PEFS_HASH_BLOB ) UserCert;
  213. CertSize = sizeof(EFS_HASH_BLOB) + CertHashBlob->cbData;
  214. UserItem->Cert = new BYTE[CertSize];
  215. if ( NULL == UserItem->Cert ){
  216. AfxThrowMemoryException( );
  217. }
  218. ((PEFS_HASH_BLOB)UserItem->Cert)->cbData = CertHashBlob->cbData;
  219. ((PEFS_HASH_BLOB)UserItem->Cert)->pbData = (PBYTE)(UserItem->Cert) + sizeof(EFS_HASH_BLOB);
  220. memcpy(((PEFS_HASH_BLOB)UserItem->Cert)->pbData,
  221. CertHashBlob->pbData,
  222. CertHashBlob->cbData
  223. );
  224. } else {
  225. //
  226. // The info is from the user picked cert. Use Cert Blob structure
  227. //
  228. CertBlob = ( PEFS_CERTIFICATE_BLOB ) UserCert;
  229. CertSize = sizeof(EFS_CERTIFICATE_BLOB) + CertBlob->cbData;
  230. UserItem->Cert = new BYTE[CertSize];
  231. if ( NULL == UserItem->Cert ){
  232. AfxThrowMemoryException( );
  233. }
  234. ((PEFS_CERTIFICATE_BLOB)UserItem->Cert)->cbData = CertBlob->cbData;
  235. ((PEFS_CERTIFICATE_BLOB)UserItem->Cert)->dwCertEncodingType = CertBlob->dwCertEncodingType;
  236. ((PEFS_CERTIFICATE_BLOB)UserItem->Cert)->pbData = (PBYTE)(UserItem->Cert) + sizeof(EFS_CERTIFICATE_BLOB);
  237. memcpy(((PEFS_CERTIFICATE_BLOB)UserItem->Cert)->pbData,
  238. CertBlob->pbData,
  239. CertBlob->cbData
  240. );
  241. }
  242. UserItem->UserName = UserName;
  243. UserItem->Context = Context;
  244. UserItem->Flag = Flag;
  245. if ( Flag & USERADDED ){
  246. m_UserAddedCnt ++;
  247. }
  248. }
  249. catch (...) {
  250. delete [] UserItem->UserSid;
  251. delete [] UserItem->Cert;
  252. delete UserItem;
  253. AfxThrowMemoryException( );
  254. return ERROR_NOT_ENOUGH_MEMORY;
  255. }
  256. //
  257. // Add to the head
  258. //
  259. if ( NULL != m_UsersRoot ){
  260. UserItem->Next = m_UsersRoot;
  261. }
  262. m_UsersRoot = UserItem;
  263. return NO_ERROR;
  264. }
  265. DWORD
  266. CUsers::Remove(
  267. LPCTSTR UserName
  268. )
  269. //////////////////////////////////////////////////////////////////////
  270. // Routine Description:
  271. // Remove a user from the list. Actually just mark for remove.
  272. // Arguments:
  273. // UserName -- User's name
  274. // Return Value:
  275. // NO_ERROR if succeed.
  276. // ERROR_NOT_FOUND if the user cannot be found.
  277. //
  278. //////////////////////////////////////////////////////////////////////
  279. {
  280. PUSERSONFILE TmpUserItem = m_UsersRoot;
  281. BOOL UserMatched =FALSE;
  282. while ( TmpUserItem ){
  283. if (((NULL==UserName) && ( NULL == TmpUserItem->UserName)) ||
  284. ( UserName && TmpUserItem->UserName && !_tcsicmp(UserName, TmpUserItem->UserName))){
  285. //
  286. // User exist, mark it for remove
  287. //
  288. if ( TmpUserItem->Flag & USERINFILE ){
  289. m_UserRemovedCnt++;
  290. } else if ( TmpUserItem->Flag & USERADDED ) {
  291. m_UserAddedCnt--;
  292. }
  293. TmpUserItem->Flag |= USERREMOVED;
  294. return NO_ERROR;
  295. }
  296. TmpUserItem = TmpUserItem->Next;
  297. }
  298. return ERROR_NOT_FOUND;
  299. }
  300. DWORD
  301. CUsers::GetCertInfo(
  302. LPCTSTR UserName,
  303. PVOID *CertData,
  304. PVOID *CertContext
  305. )
  306. //////////////////////////////////////////////////////////////////////
  307. // Routine Description:
  308. // Get user's cert related value
  309. // Arguments:
  310. // UserName -- User's name whose cert is to be found
  311. // CertData -- Certificate Thumbprinter or cert blob
  312. // CertContext -- Cert context
  313. // Return Value:
  314. // Win32 Error
  315. //
  316. //////////////////////////////////////////////////////////////////////
  317. {
  318. PUSERSONFILE TmpUserItem = m_UsersRoot;
  319. BOOL UserMatched =FALSE;
  320. if ((CertData == NULL) || (CertContext == NULL) ) {
  321. return ERROR_INVALID_PARAMETER;
  322. }
  323. while ( TmpUserItem ){
  324. if (((NULL==UserName) && ( NULL == TmpUserItem->UserName)) ||
  325. ( UserName && TmpUserItem->UserName && !_tcsicmp(UserName, TmpUserItem->UserName))){
  326. //
  327. // User exist, return the interested data
  328. //
  329. *CertData = TmpUserItem->Cert;
  330. *CertContext = TmpUserItem->Context;
  331. return ERROR_SUCCESS;
  332. }
  333. TmpUserItem = TmpUserItem->Next;
  334. }
  335. return ERROR_NOT_FOUND;
  336. }
  337. PVOID
  338. CUsers::StartEnum()
  339. //////////////////////////////////////////////////////////////////////
  340. // Routine Description:
  341. // Prepare for GetNextUser
  342. // Arguments:
  343. //
  344. // Return Value:
  345. // A pointer used for GetNextUser
  346. //
  347. //////////////////////////////////////////////////////////////////////
  348. {
  349. return ((PVOID)m_UsersRoot);
  350. }
  351. PVOID
  352. CUsers::GetNextUser(
  353. PVOID Token,
  354. CString &UserName,
  355. CString &CertHash
  356. )
  357. //////////////////////////////////////////////////////////////////////
  358. // Routine Description:
  359. // Get next user in the list.(Not removed).
  360. // Arguments:
  361. // UserName -- Next User's name
  362. // CertHash -- Certificate Thumbprinter
  363. // Token -- A pointer returned by previous GetNextUser or StartEnum.
  364. // Return Value:
  365. // A pointer for GetNextUser()
  366. //
  367. //////////////////////////////////////////////////////////////////////
  368. {
  369. PUSERSONFILE TmpItem = (PUSERSONFILE) Token;
  370. PVOID RetPointer = NULL;
  371. while ( TmpItem ){
  372. if ( TmpItem->Flag & USERREMOVED ){
  373. TmpItem = TmpItem->Next;
  374. continue;
  375. }
  376. try{
  377. LPWSTR HashString = NULL;
  378. UserName = TmpItem->UserName;
  379. if (TmpItem->Flag & USERINFILE){
  380. PEFS_HASH_BLOB UserHashBlob;
  381. UserHashBlob = (PEFS_HASH_BLOB)TmpItem->Cert;
  382. HashString = new WCHAR[((((UserHashBlob->cbData + 1)/2) * 5) + 1)];
  383. if (HashString) {
  384. ConvertHashToStr(UserHashBlob->pbData, UserHashBlob->cbData, HashString);
  385. }
  386. } else if ( TmpItem->Context ){
  387. DWORD cbHash;
  388. PBYTE pbHash;
  389. if (CertGetCertificateContextProperty(
  390. (PCCERT_CONTEXT)TmpItem->Context,
  391. CERT_HASH_PROP_ID,
  392. NULL,
  393. &cbHash
  394. )) {
  395. pbHash = (PBYTE)new BYTE[cbHash];
  396. if (pbHash != NULL) {
  397. if (CertGetCertificateContextProperty(
  398. (PCCERT_CONTEXT)TmpItem->Context,
  399. CERT_HASH_PROP_ID,
  400. pbHash,
  401. &cbHash
  402. )) {
  403. HashString = new WCHAR[((((cbHash + 1)/2) * 5) + 1)];
  404. if (HashString) {
  405. ConvertHashToStr(pbHash, cbHash, HashString);
  406. }
  407. }
  408. delete [] pbHash;
  409. }
  410. }
  411. }
  412. CertHash = HashString;
  413. if (HashString){
  414. delete [] HashString;
  415. }
  416. RetPointer = TmpItem->Next;
  417. }
  418. catch (...){
  419. //
  420. // Out of memory
  421. //
  422. TmpItem = NULL;
  423. RetPointer = NULL;
  424. }
  425. break;
  426. }
  427. if ( NULL == TmpItem ){
  428. UserName.Empty();
  429. CertHash.Empty();
  430. }
  431. return RetPointer;
  432. }
  433. DWORD CUsers::GetUserAddedCnt()
  434. {
  435. return m_UserAddedCnt;
  436. }
  437. DWORD CUsers::GetUserRemovedCnt()
  438. {
  439. return m_UserRemovedCnt;
  440. }
  441. PVOID
  442. CUsers::GetNextChangedUser(
  443. PVOID Token,
  444. LPTSTR * UserName,
  445. PSID * UserSid,
  446. PVOID * CertData,
  447. DWORD * Flag
  448. )
  449. //////////////////////////////////////////////////////////////////////
  450. // Routine Description:
  451. // Get the info for changed users. This method is not well behaved in the
  452. // sense of OOP. It exposes internal pointers to the ouside world. The gain
  453. // is performance. At this moment, CUsers is a supporting class and used only
  454. // by USERLIST and CAddSheet (single thread). We can make USERLIST a
  455. // friend of CUsers if such concerns are raised in the future or reimplement this.
  456. // The same issue applies to the enumerate methods.
  457. //
  458. // Arguments:
  459. // Token -- A pointer to the item returned in previous GetNextChangedUser or StartEnum.
  460. // UserName -- User's name
  461. // CertData -- User's certificate blob or hash
  462. // UserSid -- User's ID. Can be NULL
  463. // Flag -- Indicate if the item is existing in the file, to be added or removed
  464. // Return Value:
  465. // Next item pointer.
  466. //
  467. //////////////////////////////////////////////////////////////////////
  468. {
  469. BOOL ChangedUserFound = FALSE;
  470. while ( Token ){
  471. *Flag = ((PUSERSONFILE) Token)->Flag;
  472. if ( ( *Flag & USERADDED ) && !( *Flag & USERREMOVED )){
  473. //
  474. // The user is to to be added to the file
  475. //
  476. *Flag = USERADDED;
  477. ChangedUserFound = TRUE;
  478. } else if ( ( *Flag & USERREMOVED ) && ( *Flag & USERINFILE)){
  479. //
  480. // The user is to be removed from the file
  481. //
  482. *Flag = USERREMOVED;
  483. ChangedUserFound = TRUE;
  484. }
  485. if ( ChangedUserFound ){
  486. *UserName = ((PUSERSONFILE) Token)->UserName;
  487. *UserSid = ((PUSERSONFILE) Token)->UserSid;
  488. *CertData = ((PUSERSONFILE) Token)->Cert;
  489. return ((PUSERSONFILE) Token)->Next;
  490. } else {
  491. Token = ((PUSERSONFILE) Token)->Next;
  492. }
  493. }
  494. *UserName = NULL;
  495. *UserSid = NULL;
  496. *CertData = NULL;
  497. *Flag = 0;
  498. return NULL;
  499. }
  500. void CUsers::Clear()
  501. {
  502. PUSERSONFILE TmpUserItem = m_UsersRoot;
  503. while (TmpUserItem){
  504. m_UsersRoot = TmpUserItem->Next;
  505. delete [] TmpUserItem->UserName;
  506. delete [] TmpUserItem->Cert;
  507. if (TmpUserItem->UserSid){
  508. delete [] TmpUserItem->UserSid;
  509. }
  510. if (TmpUserItem->Context){
  511. CertFreeCertificateContext((PCCERT_CONTEXT)TmpUserItem->Context);
  512. }
  513. delete TmpUserItem;
  514. TmpUserItem = m_UsersRoot;
  515. }
  516. m_UsersRoot = NULL;
  517. m_UserAddedCnt = 0;
  518. m_UserRemovedCnt = 0;
  519. }
  520. void CUsers::ConvertHashToStr(
  521. PBYTE pHashData,
  522. DWORD cbData,
  523. LPWSTR OutHashStr
  524. )
  525. {
  526. DWORD Index = 0;
  527. BOOLEAN NoLastZero = FALSE;
  528. for (; Index < cbData; Index+=2) {
  529. BYTE HashByteLow = pHashData[Index] & 0x0f;
  530. BYTE HashByteHigh = (pHashData[Index] & 0xf0) >> 4;
  531. OutHashStr[Index * 5/2] = HashByteHigh > 9 ? (WCHAR)(HashByteHigh - 9 + 0x40): (WCHAR)(HashByteHigh + 0x30);
  532. OutHashStr[Index * 5/2 + 1] = HashByteLow > 9 ? (WCHAR)(HashByteLow - 9 + 0x40): (WCHAR)(HashByteLow + 0x30);
  533. if (Index + 1 < cbData) {
  534. HashByteLow = pHashData[Index+1] & 0x0f;
  535. HashByteHigh = (pHashData[Index+1] & 0xf0) >> 4;
  536. OutHashStr[Index * 5/2 + 2] = HashByteHigh > 9 ? (WCHAR)(HashByteHigh - 9 + 0x40): (WCHAR)(HashByteHigh + 0x30);
  537. OutHashStr[Index * 5/2 + 3] = HashByteLow > 9 ? (WCHAR)(HashByteLow - 9 + 0x40): (WCHAR)(HashByteLow + 0x30);
  538. OutHashStr[Index * 5/2 + 4] = L' ';
  539. } else {
  540. OutHashStr[Index * 5/2 + 2] = 0;
  541. NoLastZero = TRUE;
  542. }
  543. }
  544. if (!NoLastZero) {
  545. OutHashStr[Index*5/2] = 0;
  546. }
  547. }