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.

650 lines
22 KiB

  1. extern "C"
  2. {
  3. // include NT and SAM headers here,
  4. // order of these files DOES matter
  5. #include <nt.h>
  6. #include <ntrtl.h>
  7. #include <nturtl.h>
  8. #include <rpc.h>
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <assert.h>
  12. #include <samrpc.h>
  13. #include <ntlsa.h>
  14. #define SECURITY_WIN32
  15. #define SECURITY_PACKAGE
  16. #include <security.h>
  17. #include <secint.h>
  18. #include <samisrv.h>
  19. #include <lsarpc.h>
  20. #include <lsaisrv.h>
  21. #include <ntsam.h>
  22. #include <ntsamp.h>
  23. #include <netlib.h>
  24. #include <windows.h>
  25. #include <lmerr.h>
  26. #include <lmcons.h>
  27. #include <netlib.h>
  28. #include <ntdef.h>
  29. }
  30. #ifndef OEM_STRING
  31. typedef STRING OEM_STRING;
  32. #endif
  33. #include "main.h"
  34. #include "Clogger.h"
  35. #include "DSREvents.h"
  36. static WCHAR g_wszLSAKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Lsa";
  37. static WCHAR g_wszNotPac[] = L"Notification Packages";
  38. static WCHAR g_wszName[] = L"dsrestor";
  39. static WCHAR g_wszEventLog[] = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application";
  40. static WCHAR g_wszEventFileName[] = L"EventMessageFile";
  41. static WCHAR g_wszTypesSupported[] = L"TypesSupported";
  42. static WCHAR g_wszEventFilePath[] = L"%SystemRoot%\\System32\\DSREvt.dll";
  43. static DWORD g_dwTypesSupported = 0x7;
  44. //For comparison of OLD_LARGE_INTEGER
  45. BOOL operator > ( OLD_LARGE_INTEGER li1, OLD_LARGE_INTEGER li2 )
  46. {
  47. return( li1.HighPart > li2.HighPart ||
  48. ( li1.HighPart ==li2.HighPart && li1.LowPart > li2.LowPart ) );
  49. }
  50. //Generate Domain Admin Sid based on Domain Sid
  51. NTSTATUS CreateDomainAdminSid(PSID *ppDomainAdminSid, //[Out] return Domain Admin Sid
  52. PSID pDomainSid) //[in] Domain Sid
  53. {
  54. NTSTATUS NtStatus = STATUS_SUCCESS;
  55. UCHAR AccountSubAuthorityCount;
  56. ULONG AccountSidLength;
  57. PULONG RidLocation;
  58. if (!ppDomainAdminSid || !pDomainSid)
  59. return STATUS_INSUFFICIENT_RESOURCES;
  60. // Calculate the size of the new sid
  61. AccountSubAuthorityCount = *RtlSubAuthorityCountSid(pDomainSid) + (UCHAR)1;
  62. AccountSidLength = RtlLengthRequiredSid(AccountSubAuthorityCount);
  63. // Allocate space for the account sid
  64. *ppDomainAdminSid = RtlAllocateHeap(RtlProcessHeap(), 0, AccountSidLength);
  65. if (*ppDomainAdminSid == NULL)
  66. {
  67. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  68. }
  69. else
  70. {
  71. // Copy the domain sid into the first part of the account sid
  72. NTSTATUS IgnoreStatus = RtlCopySid(AccountSidLength, *ppDomainAdminSid, pDomainSid);
  73. // Increment the account sid sub-authority count
  74. if (RtlSubAuthorityCountSid(*ppDomainAdminSid))
  75. *RtlSubAuthorityCountSid(*ppDomainAdminSid) = AccountSubAuthorityCount;
  76. // Add the rid as the final sub-authority
  77. RidLocation = RtlSubAuthoritySid(*ppDomainAdminSid, AccountSubAuthorityCount-1);
  78. if (RidLocation)
  79. *RidLocation = DOMAIN_USER_RID_ADMIN;
  80. NtStatus = STATUS_SUCCESS;
  81. }
  82. return NtStatus;
  83. }
  84. // Create a thread to run PassCheck()
  85. BOOL NTAPI InitializeChangeNotify( void )
  86. {
  87. ULONG ulID = 0;
  88. HANDLE hThread = CreateThread( NULL, 0, PassCheck, NULL, 0, &ulID );
  89. if (hThread && (hThread != INVALID_HANDLE_VALUE))
  90. CloseHandle( hThread );
  91. return TRUE;
  92. }
  93. NTSTATUS NTAPI PasswordChangeNotify( PUNICODE_STRING UserName,
  94. ULONG RelativeId,
  95. PUNICODE_STRING NewPassword )
  96. {
  97. return STATUS_SUCCESS;
  98. }
  99. BOOL NTAPI PasswordFilter( PUNICODE_STRING AccountName,
  100. PUNICODE_STRING FullName,
  101. PUNICODE_STRING Password,
  102. BOOLEAN SetOperation )
  103. {
  104. return TRUE;
  105. }
  106. // Get Password for DSRestoreMode and DomainAdmin and set to same if not already
  107. // then sleep for 30 minutes
  108. DWORD WINAPI PassCheck( LPVOID lpParameter )
  109. {
  110. CEventLogger EventLogger;
  111. DWORD dwRt=0; //Return Value
  112. DWORD dwSleepTime = 30*60*1000;
  113. // 30 min * 60 sec * 1000 msec
  114. NTSTATUS RtVal = STATUS_SUCCESS;
  115. OLD_LARGE_INTEGER liPasswordLastSet = {0,0};
  116. SAMPR_HANDLE hSAMPR = NULL;
  117. PSAMPR_SERVER_NAME pSvrName = NULL;
  118. SAMPR_HANDLE hServerHandle = NULL;
  119. SAMPR_HANDLE hDomainHandle = NULL;
  120. PSAMPR_USER_INFO_BUFFER pUserBuffer = NULL;
  121. LSA_HANDLE hPolicyHd = NULL;
  122. LSA_OBJECT_ATTRIBUTES ObjAttr;
  123. PPOLICY_PRIMARY_DOMAIN_INFO pDomainInfo=NULL;
  124. WCHAR szSvrName[MAX_COMPUTERNAME_LENGTH + 1];
  125. DWORD dwSvrName = MAX_COMPUTERNAME_LENGTH + 1;
  126. LSA_UNICODE_STRING ServerName;
  127. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  128. PSID pDomainAdminSid = NULL;
  129. NT_OWF_PASSWORD Password;
  130. SID_AND_ATTRIBUTES_LIST GroupMembership;
  131. SAMPR_HANDLE UserHandle = NULL;
  132. UNICODE_STRING PsudoUserName;
  133. //Get ready for event logging
  134. EventLogger.InitEventLog(g_wszName ,0, LOGGING_LEVEL_3);
  135. EventLogger.LogEvent(LOGTYPE_INFORMATION,
  136. EVENTDSR_FILTER_STARTED);
  137. //Required by LsaOpenPolicy
  138. ZeroMemory(&ObjAttr,sizeof(LSA_OBJECT_ATTRIBUTES));
  139. ServerName.MaximumLength=sizeof(WCHAR)*(MAX_COMPUTERNAME_LENGTH + 1);
  140. GroupMembership.Count = 0;
  141. GroupMembership.SidAndAttributes = NULL;
  142. // First get the local server name
  143. if( !GetComputerName(szSvrName, &dwSvrName))
  144. {
  145. dwRt = GetLastError();
  146. EventLogger.LogEvent(LOGTYPE_FORCE_ERROR,
  147. EVENTDSR_FILTER_NO_HOST_NAME,
  148. dwRt);
  149. goto EXIT;
  150. }
  151. ServerName.Buffer=szSvrName;
  152. ServerName.Length=(USHORT)(sizeof(WCHAR)*dwSvrName);
  153. // To get the Policy Handle
  154. if( STATUS_SUCCESS != (RtVal=LsaOpenPolicy(
  155. &ServerName,
  156. &ObjAttr,
  157. POLICY_VIEW_LOCAL_INFORMATION,
  158. &hPolicyHd
  159. )) )
  160. {
  161. //Error output RtVal
  162. dwRt = GetLastError();
  163. EventLogger.LogEvent(LOGTYPE_FORCE_ERROR,
  164. EVENTDSR_FILTER_NO_LOCAL_POLICY,
  165. dwRt);
  166. goto EXIT;
  167. }
  168. // Get the Primary Domain information
  169. if( STATUS_SUCCESS != (RtVal=LsaQueryInformationPolicy(
  170. hPolicyHd,
  171. PolicyPrimaryDomainInformation,
  172. reinterpret_cast<PVOID *> (&pDomainInfo) ) ))
  173. {
  174. //Error, log return value RtVal
  175. EventLogger.LogEvent(LOGTYPE_FORCE_ERROR,
  176. EVENTDSR_FILTER_NO_DOMAIN_INFO,
  177. RtVal);
  178. goto EXIT;
  179. }
  180. if( NULL == pDomainInfo->Sid )
  181. {
  182. // If we are running in the DS Restore mode, the Domain sid will be NULL
  183. // No need to run in this case.
  184. goto EXIT;
  185. }
  186. //Build the sid for domain admin
  187. if( STATUS_SUCCESS != CreateDomainAdminSid(&pDomainAdminSid, pDomainInfo->Sid) )
  188. {
  189. //Error output RtVal
  190. dwRt = GetLastError();
  191. EventLogger.LogEvent(LOGTYPE_FORCE_ERROR,
  192. EVENTDSR_FILTER_NO_ADMIN_SID,
  193. dwRt);
  194. goto EXIT;
  195. }
  196. //Check if the domain admin Sid just generated is valid
  197. if(! IsValidSid( pDomainAdminSid ))
  198. {
  199. dwRt = GetLastError();
  200. EventLogger.LogEvent(LOGTYPE_FORCE_ERROR,
  201. EVENTDSR_FILTER_NO_ADMIN_SID,
  202. dwRt);
  203. goto EXIT;
  204. }
  205. // Starting the loop of polling domain admin password
  206. while( TRUE )
  207. {
  208. //Get the server handle
  209. if(STATUS_SUCCESS != SamIConnect(
  210. pSvrName,
  211. &hServerHandle,
  212. POLICY_ALL_ACCESS,
  213. TRUE) )
  214. {
  215. dwRt = GetLastError();
  216. EventLogger.LogEvent(LOGTYPE_FORCE_ERROR,
  217. EVENTDSR_FILTER_CONNECT_SAM_FAIL,
  218. dwRt);
  219. break;
  220. }
  221. // Get the domain handle
  222. if(STATUS_SUCCESS != SamrOpenDomain(
  223. hServerHandle,
  224. POLICY_ALL_ACCESS,
  225. (PRPC_SID)(pDomainInfo->Sid),
  226. //PSID and PRPC_SID are basically the same
  227. &hDomainHandle) )
  228. {
  229. dwRt = GetLastError();
  230. EventLogger.LogEvent(LOGTYPE_FORCE_ERROR,
  231. EVENTDSR_FILTER_CONNECT_DOMAIN_FAIL,
  232. dwRt);
  233. break;
  234. }
  235. PsudoUserName.Buffer = reinterpret_cast<PWSTR> (pDomainAdminSid);
  236. PsudoUserName.Length = (USHORT)GetLengthSid(pDomainAdminSid);
  237. PsudoUserName.MaximumLength = PsudoUserName.Length;
  238. //Get accout info for Domain Admin
  239. if(STATUS_SUCCESS != ( RtVal= SamIGetUserLogonInformation(
  240. hDomainHandle,
  241. SAM_OPEN_BY_SID,
  242. &PsudoUserName,
  243. &pUserBuffer,
  244. &GroupMembership,
  245. &UserHandle) ) )
  246. {
  247. dwRt = GetLastError();
  248. EventLogger.LogEvent(LOGTYPE_FORCE_ERROR,
  249. EVENTDSR_FILTER_NO_DOMAIN_ADMIN_INFO,
  250. dwRt);
  251. break;
  252. }
  253. // Check if the password of the Domain Admin was changed in
  254. // the last sleep period.
  255. // The first time, always set the password.
  256. if( pUserBuffer->All.PasswordLastSet > liPasswordLastSet )
  257. {
  258. RtlCopyMemory(
  259. &Password,
  260. pUserBuffer->All.NtOwfPassword.Buffer,
  261. NT_OWF_PASSWORD_LENGTH);
  262. if(STATUS_SUCCESS != SamiSetDSRMPasswordOWF(
  263. &ServerName,
  264. DOMAIN_USER_RID_ADMIN,
  265. &Password
  266. ) )
  267. {
  268. dwRt = GetLastError();
  269. EventLogger.LogEvent(LOGTYPE_FORCE_ERROR,
  270. EVENTDSR_FILTER_SET_PAWD_FAIL,
  271. dwRt);
  272. break;
  273. }
  274. liPasswordLastSet=pUserBuffer->All.PasswordLastSet;
  275. }
  276. // Clean up for next loop
  277. SamIFree_SAMPR_USER_INFO_BUFFER(pUserBuffer, UserAllInformation);
  278. RtlZeroMemory(&Password, NT_OWF_PASSWORD_LENGTH);
  279. SamrCloseHandle(&hServerHandle);
  280. SamrCloseHandle(&hDomainHandle);
  281. pUserBuffer = NULL;
  282. hServerHandle=NULL;
  283. hDomainHandle=NULL;
  284. // Sleep 30 minutes
  285. Sleep( dwSleepTime );
  286. }
  287. EXIT:
  288. //Clean up
  289. if( NULL != pUserBuffer )
  290. {
  291. SamIFree_SAMPR_USER_INFO_BUFFER(
  292. pUserBuffer, UserAllInformation);
  293. }
  294. if( NULL != hServerHandle )
  295. {
  296. SamrCloseHandle(&hServerHandle);
  297. }
  298. if( NULL != hDomainHandle )
  299. {
  300. SamrCloseHandle(&hDomainHandle);
  301. }
  302. if( NULL != pDomainAdminSid )
  303. {
  304. RtlFreeHeap( RtlProcessHeap(), 0, (PVOID)pDomainAdminSid);
  305. }
  306. if( NULL != pDomainInfo )
  307. {
  308. LsaFreeMemory(pDomainInfo);
  309. }
  310. if( NULL != hPolicyHd )
  311. {
  312. LsaClose(hPolicyHd);
  313. }
  314. return dwRt;
  315. }
  316. HRESULT NTAPI RegisterFilter( void )
  317. {
  318. DWORD dwType = 0;
  319. DWORD dwcbSize = 0;
  320. HKEY hLSAKey = NULL;
  321. HKEY hEventLogKey = NULL;
  322. HKEY hDSEvtKey = NULL;
  323. BOOL bSuccess = FALSE;
  324. BOOL bRegistered = FALSE;
  325. LONG lRetVal = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  326. g_wszLSAKey,
  327. 0,
  328. KEY_ALL_ACCESS,
  329. &hLSAKey );
  330. if (ERROR_SUCCESS == lRetVal)
  331. {
  332. ULONG ulStrLen = wcslen( g_wszName );
  333. lRetVal = RegQueryValueEx( hLSAKey,
  334. g_wszNotPac,
  335. NULL,
  336. &dwType,
  337. NULL,
  338. &dwcbSize );
  339. if (ERROR_SUCCESS == lRetVal) // Key exists, must add my value to the end
  340. {
  341. WCHAR *pwsz = NULL;
  342. DWORD dwBufSize = dwcbSize + (ulStrLen+1)*sizeof(WCHAR);
  343. BYTE *pbyVal = new BYTE[dwBufSize];
  344. if (NULL != pbyVal)
  345. {
  346. lRetVal = RegQueryValueEx( hLSAKey,
  347. g_wszNotPac,
  348. NULL,
  349. &dwType,
  350. pbyVal,
  351. &dwcbSize );
  352. if (ERROR_SUCCESS == lRetVal)
  353. {
  354. //First, check if we have already registered
  355. pwsz = (WCHAR *)pbyVal;
  356. while( *pwsz != 0 )
  357. {
  358. if (0 == wcscmp( pwsz, g_wszName ))
  359. {
  360. //It is already registered
  361. bRegistered = TRUE;
  362. bSuccess = TRUE;
  363. break;
  364. }
  365. pwsz += (wcslen( pwsz ) + 1);
  366. }
  367. if(! bRegistered)
  368. {
  369. // Got the value, now I need to add myself to the end
  370. pwsz = (WCHAR *)&(pbyVal[dwcbSize - 2]);
  371. wcscpy( pwsz, g_wszName );
  372. // Make sure we're termintate by 2 UNICODE NULLs (REG_MULTI_SZ)
  373. pwsz += ulStrLen + 1;
  374. *pwsz = 0;
  375. lRetVal = RegSetValueEx( hLSAKey,
  376. g_wszNotPac,
  377. 0,
  378. (DWORD)REG_MULTI_SZ,
  379. pbyVal,
  380. dwBufSize );
  381. if (ERROR_SUCCESS == lRetVal)
  382. bSuccess = TRUE;
  383. }
  384. }
  385. delete[] pbyVal;
  386. }
  387. }
  388. else // Key doesn't exist. Have to create it
  389. {
  390. DWORD dwBufSize=(ulStrLen+2)*sizeof(WCHAR);
  391. BYTE *rgbyVal= new BYTE[dwBufSize];
  392. if( NULL != rgbyVal )
  393. {
  394. WCHAR *pwsz = (WCHAR *)rgbyVal;
  395. wcscpy( pwsz, g_wszName );
  396. // Make sure we're terminated by two UNICODE NULLs (REG_MULTI_SZ)
  397. pwsz += ulStrLen + 1;
  398. *pwsz = 0;
  399. lRetVal = RegSetValueEx( hLSAKey,
  400. g_wszNotPac,
  401. 0,
  402. (DWORD)REG_MULTI_SZ,
  403. rgbyVal,
  404. dwBufSize );
  405. if (ERROR_SUCCESS == lRetVal)
  406. bSuccess = TRUE;
  407. delete[] rgbyVal;
  408. }
  409. }
  410. RegCloseKey( hLSAKey );
  411. }
  412. if( bSuccess )
  413. {
  414. lRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  415. g_wszEventLog,
  416. 0,
  417. KEY_ALL_ACCESS,
  418. &hEventLogKey);
  419. if ( ERROR_SUCCESS == lRetVal )
  420. {
  421. //Create the Reg Key for eventlogging
  422. lRetVal = RegCreateKeyEx(hEventLogKey,
  423. g_wszName,
  424. 0,
  425. NULL,
  426. 0,
  427. KEY_ALL_ACCESS,
  428. NULL,
  429. &hDSEvtKey,
  430. NULL);
  431. if ( ERROR_SUCCESS == lRetVal )
  432. {
  433. lRetVal = RegSetValueEx(hDSEvtKey,
  434. g_wszEventFileName,
  435. 0,
  436. REG_SZ,
  437. reinterpret_cast<CONST BYTE*>(g_wszEventFilePath),
  438. sizeof(WCHAR)*wcslen(g_wszEventFilePath));
  439. if (ERROR_SUCCESS == lRetVal )
  440. {
  441. lRetVal = RegSetValueEx(hDSEvtKey,
  442. g_wszTypesSupported,
  443. 0,
  444. REG_DWORD,
  445. reinterpret_cast<CONST BYTE*>(&g_dwTypesSupported),
  446. sizeof(DWORD));
  447. }
  448. RegCloseKey(hDSEvtKey);
  449. }
  450. if (ERROR_SUCCESS != lRetVal)
  451. {
  452. bSuccess = FALSE;
  453. }
  454. }
  455. RegCloseKey(hEventLogKey);
  456. }
  457. return bSuccess ? (bRegistered ? S_FALSE : S_OK ) : E_FAIL;
  458. }
  459. HRESULT NTAPI UnRegisterFilter( void )
  460. {
  461. DWORD dwType = 0;
  462. DWORD dwcbSize = 0;
  463. HKEY hLSAKey = NULL;
  464. HKEY hEventLogKey =NULL;
  465. BOOL bSuccess = FALSE;
  466. LONG lRetVal = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  467. g_wszLSAKey,
  468. 0,
  469. KEY_ALL_ACCESS,
  470. &hLSAKey );
  471. if (ERROR_SUCCESS == lRetVal)
  472. {
  473. lRetVal = RegQueryValueEx( hLSAKey,
  474. g_wszNotPac,
  475. NULL,
  476. &dwType,
  477. NULL,
  478. &dwcbSize );
  479. // Key exists, must delete my value from the end
  480. if (ERROR_SUCCESS == lRetVal)
  481. {
  482. ULONG ulStrLen = wcslen( g_wszName );
  483. BYTE *pbyVal = new BYTE[dwcbSize];
  484. if (pbyVal)
  485. {
  486. lRetVal = RegQueryValueEx( hLSAKey,
  487. g_wszNotPac,
  488. NULL,
  489. &dwType,
  490. pbyVal,
  491. &dwcbSize );
  492. if (ERROR_SUCCESS == lRetVal)
  493. {
  494. // Got the old key,
  495. // now step through and remove my part of the key
  496. WCHAR *pwsz = (WCHAR *)pbyVal;
  497. WCHAR *wszNewRegVal = new WCHAR[dwcbSize];
  498. WCHAR *pwszNewVal = wszNewRegVal;
  499. DWORD dwLen = 0;
  500. if (wszNewRegVal)
  501. {
  502. *pwszNewVal = 0;
  503. while( *pwsz != 0 )
  504. {
  505. if (wcscmp( pwsz, g_wszName ))
  506. {
  507. wcscpy( pwszNewVal, pwsz );
  508. dwLen += wcslen( pwsz ) + 1;
  509. pwszNewVal += (wcslen( pwsz ) + 1);
  510. }
  511. pwsz += (wcslen( pwsz ) + 1);
  512. }
  513. // if we got here and there's nothing in the buffer,
  514. // we were the only one installed,
  515. // now we must delete the key, else set it to the old value
  516. wszNewRegVal[dwLen] = 0; // add the last NULL
  517. dwLen++; // account for that last NULL
  518. lRetVal = RegSetValueEx(hLSAKey,
  519. g_wszNotPac,
  520. 0,
  521. (DWORD)REG_MULTI_SZ,
  522. reinterpret_cast<CONST BYTE*>(wszNewRegVal),
  523. dwLen*sizeof(WCHAR));
  524. if (ERROR_SUCCESS == lRetVal)
  525. bSuccess = TRUE;
  526. delete[] wszNewRegVal;
  527. }
  528. }
  529. delete[] pbyVal;
  530. }
  531. // NTRAID#NTBUG9-655545-2002/07/05-artm
  532. RegCloseKey( hLSAKey );
  533. }
  534. }
  535. if( bSuccess )
  536. {
  537. //Delete the Reg Key for eventlogging
  538. lRetVal=RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  539. g_wszEventLog,
  540. 0,
  541. KEY_ALL_ACCESS,
  542. &hEventLogKey);
  543. if (ERROR_SUCCESS == lRetVal)
  544. {
  545. RegDeleteKey(hEventLogKey, g_wszName );
  546. if( ERROR_SUCCESS != lRetVal &&
  547. ERROR_FILE_NOT_FOUND != lRetVal )
  548. // If the key does not exist, ERROR_FILE_NOT_FOUND wii be returened
  549. {
  550. bSuccess = FALSE;
  551. }
  552. RegCloseKey( hEventLogKey );
  553. }
  554. else
  555. {
  556. bSuccess = FALSE;
  557. }
  558. }
  559. return bSuccess ? S_OK : E_FAIL;
  560. }