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.

566 lines
17 KiB

  1. /*---------------------------------------------------------------------------
  2. File: PwdSvc.cpp
  3. Comments: entry point functions and other exported functions for ADMT's
  4. password migration Lsa notification package.
  5. REVISION LOG ENTRY
  6. Revision By: Paul Thompson
  7. Revised on 09/06/00
  8. ---------------------------------------------------------------------------
  9. */
  10. #include "Pwd.h"
  11. #include "PwdSvc.h"
  12. #include "PwdSvc_s.c"
  13. // These global variables can be changed if required
  14. #define gsPwdProtoSeq TEXT("ncacn_np")
  15. #define gsPwdEndPoint TEXT("\\pipe\\PwdMigRpc")
  16. DWORD gPwdRpcMinThreads = 1;
  17. DWORD gPwdRpcMaxThreads = RPC_C_LISTEN_MAX_CALLS_DEFAULT;
  18. #ifndef STATUS_SUCCESS
  19. #define STATUS_SUCCESS ((NTSTATUS) 0x00000000L)
  20. #endif
  21. extern "C"
  22. {
  23. BOOL WINAPI _CRT_INIT( HANDLE hInstance, DWORD nReason, LPVOID pReserved );
  24. }
  25. RPC_STATUS RPC_ENTRY SecurityCallback(RPC_IF_HANDLE hInterface, void* pContext);
  26. namespace
  27. {
  28. //
  29. // Timer Class
  30. //
  31. class CTimer
  32. {
  33. public:
  34. CTimer() :
  35. m_hTimer(NULL)
  36. {
  37. }
  38. ~CTimer()
  39. {
  40. if (m_hTimer)
  41. {
  42. Close();
  43. }
  44. }
  45. DWORD Create()
  46. {
  47. ASSERT(m_hTimer == NULL);
  48. //
  49. // Create timer. Close timer first if already created.
  50. //
  51. if (m_hTimer)
  52. {
  53. Close();
  54. }
  55. m_hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
  56. return m_hTimer ? ERROR_SUCCESS : GetLastError();
  57. }
  58. DWORD Wait(int nTime)
  59. {
  60. ASSERT(m_hTimer != NULL);
  61. DWORD dwError = ERROR_SUCCESS;
  62. if (m_hTimer)
  63. {
  64. //
  65. // Convert elapsed time parameter from milliseconds
  66. // to relative due time in 100s of nanoseconds.
  67. //
  68. LARGE_INTEGER liDueTime;
  69. liDueTime.QuadPart = nTime * -10000i64;
  70. //
  71. // Set timer and wait for timer to be signaled.
  72. //
  73. if (SetWaitableTimer(m_hTimer, &liDueTime, 0, NULL, NULL, FALSE))
  74. {
  75. if (WaitForSingleObject(m_hTimer, INFINITE) == WAIT_FAILED)
  76. {
  77. dwError = GetLastError();
  78. }
  79. }
  80. else
  81. {
  82. dwError = GetLastError();
  83. }
  84. }
  85. else
  86. {
  87. dwError = ERROR_INVALID_HANDLE;
  88. }
  89. return dwError;
  90. }
  91. void Close()
  92. {
  93. ASSERT(m_hTimer != NULL);
  94. if (m_hTimer)
  95. {
  96. if (CloseHandle(m_hTimer) == FALSE)
  97. {
  98. DWORD dwError = GetLastError();
  99. ASSERT(dwError == ERROR_SUCCESS);
  100. }
  101. m_hTimer = NULL;
  102. }
  103. }
  104. protected:
  105. HANDLE m_hTimer;
  106. };
  107. }
  108. /******************************
  109. * RPC Registration Functions *
  110. ******************************/
  111. /*********************************************************************
  112. * *
  113. * Written by: Paul Thompson *
  114. * Date: 11 JUNE 2001 *
  115. * *
  116. * This function is called by a thread spawned from our *
  117. * "InitializeChangeNotify" password filter function to wait until *
  118. * SAM, and therefore RPC, is up and running. *
  119. * *
  120. * 04/17/02 MPO - rewritten to wait for SAM_SERVICE_STARTED event to *
  121. * be created first before waiting for this event to *
  122. * be signaled *
  123. *********************************************************************/
  124. //BEGIN PwdMigWaitForSamService
  125. DWORD __stdcall PwdMigWaitForSamService()
  126. {
  127. DWORD dwError = ERROR_SUCCESS;
  128. //
  129. // Attempt to open the SAM service started event object.
  130. //
  131. // Note that we must use the Nt APIs to open the event object
  132. // as the name begins with a \ character which is not valid
  133. // in the object name space used by the OpenEvent API.
  134. //
  135. HANDLE hEvent = NULL;
  136. UNICODE_STRING usEventName;
  137. RtlInitUnicodeString(&usEventName, L"\\SAM_SERVICE_STARTED");
  138. OBJECT_ATTRIBUTES oaEventAttributes;
  139. InitializeObjectAttributes(&oaEventAttributes, &usEventName, 0, 0, NULL);
  140. NTSTATUS ntStatus = NtOpenEvent(&hEvent, SYNCHRONIZE, &oaEventAttributes);
  141. if (NT_ERROR(ntStatus))
  142. {
  143. //
  144. // If the SAM service started event object has not been
  145. // created yet then wait until it has been created.
  146. //
  147. if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND)
  148. {
  149. //
  150. // Enter a loop which waits until the open event API returns
  151. // an error other than the event object not found. The loop
  152. // waits 15 sec between attempts to open object.
  153. //
  154. CTimer timer;
  155. dwError = timer.Create();
  156. if (dwError == ERROR_SUCCESS)
  157. {
  158. for (;;)
  159. {
  160. dwError = timer.Wait(15000);
  161. if (dwError != ERROR_SUCCESS)
  162. {
  163. break;
  164. }
  165. ntStatus = NtOpenEvent(&hEvent, SYNCHRONIZE, &oaEventAttributes);
  166. if (NT_SUCCESS(ntStatus))
  167. {
  168. break;
  169. }
  170. if (ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
  171. {
  172. dwError = LsaNtStatusToWinError(ntStatus);
  173. break;
  174. }
  175. }
  176. }
  177. }
  178. else
  179. {
  180. dwError = LsaNtStatusToWinError(ntStatus);
  181. }
  182. }
  183. //
  184. // If event has been opened then wait for it to be signalled.
  185. //
  186. if (hEvent != NULL)
  187. {
  188. NTSTATUS ntWaitStatus = NtWaitForSingleObject(hEvent, FALSE, NULL);
  189. NTSTATUS ntCloseStatus = NtClose(hEvent);
  190. ASSERT(NT_SUCCESS(ntCloseStatus));
  191. dwError = (ntWaitStatus == STATUS_WAIT_0) ? ERROR_SUCCESS : LsaNtStatusToWinError(ntWaitStatus);
  192. }
  193. return dwError;
  194. }
  195. //END PwdMigWaitForSamService
  196. /*********************************************************************
  197. * *
  198. * Written by: Paul Thompson *
  199. * Date: 11 JUNE 2001 *
  200. * *
  201. * This function is a spawned thread created by the *
  202. * "InitializeChangeNotify" password filter function to wait until *
  203. * SAM, and therefore RPC, is up and running and then register the *
  204. * ADMT Password Migration RPC interface. *
  205. * *
  206. * 04/17/02 MPO - rewritten to wait until critical section is *
  207. * initialized and to use a stronger authentication *
  208. * service when built for Windows 2000 or later *
  209. *********************************************************************/
  210. //BEGIN PwdMigRPCRegProc
  211. DWORD WINAPI PwdMigRPCRegProc(LPVOID lpParameter)
  212. {
  213. RPC_STATUS rc = RPC_S_OK;
  214. //
  215. // Wait for the SAM service to start before registering RPC interface.
  216. //
  217. if (PwdMigWaitForSamService() == ERROR_SUCCESS)
  218. {
  219. //
  220. // Initialize critical section used by PwdRpc interface
  221. // implementation.
  222. // Note that the critical section must be initialized before
  223. // registering RPC interface to prevent a race condition.
  224. //
  225. bool bCriticalSection = false;
  226. try
  227. {
  228. InitializeCriticalSection(&csADMTCriticalSection);
  229. bCriticalSection = true;
  230. }
  231. catch (...)
  232. {
  233. ;
  234. }
  235. if (bCriticalSection == false)
  236. {
  237. //
  238. // The initialize critical section API must
  239. // have thrown a STATUS_NO_MEMORY exception.
  240. //
  241. // Enter a loop which waits until the critical
  242. // section is initialized. The loop waits 15 sec
  243. // between attempts to initialize critical section.
  244. //
  245. CTimer timer;
  246. DWORD dwError = timer.Create();
  247. if (dwError == ERROR_SUCCESS)
  248. {
  249. while (bCriticalSection == false)
  250. {
  251. dwError = timer.Wait(15000);
  252. if (dwError != ERROR_SUCCESS)
  253. {
  254. break;
  255. }
  256. try
  257. {
  258. InitializeCriticalSection(&csADMTCriticalSection);
  259. bCriticalSection = true;
  260. }
  261. catch (...)
  262. {
  263. ;
  264. }
  265. }
  266. }
  267. if (dwError != ERROR_SUCCESS)
  268. {
  269. return dwError;
  270. }
  271. }
  272. // specify protocol sequence and endpoint
  273. // for receiving remote procedure calls
  274. rc = RpcServerUseProtseqEp(gsPwdProtoSeq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, gsPwdEndPoint, NULL);
  275. if (rc == RPC_S_OK)
  276. {
  277. //
  278. // Register PwdMigRpc interface with the RPC run-time library.
  279. // Only allow connections with an authorization level higher than
  280. // RPC_C_AUTHN_LEVEL_NONE. Also specifying security callback to
  281. // validate client before allowing access to interface.
  282. //
  283. rc = RpcServerRegisterIfEx(
  284. PwdMigRpc_ServerIfHandle,
  285. NULL,
  286. NULL,
  287. RPC_IF_ALLOW_SECURE_ONLY,
  288. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  289. SecurityCallback
  290. );
  291. if (rc == RPC_S_OK)
  292. {
  293. #ifdef PWD_W2KORLATER
  294. //
  295. // Register authentication information with RPC specifying
  296. // default principal name and specifying GSS negotiate.
  297. //
  298. PWCHAR pszPrincipalName = NULL;
  299. rc = RpcServerInqDefaultPrincName(RPC_C_AUTHN_GSS_NEGOTIATE, &pszPrincipalName);
  300. if (rc == RPC_S_OK)
  301. {
  302. ASSERT(pszPrincipalName && (wcslen(pszPrincipalName) != 0));
  303. //set the authenification for this RPC interface
  304. rc = RpcServerRegisterAuthInfo(pszPrincipalName, RPC_C_AUTHN_GSS_NEGOTIATE, NULL, NULL);
  305. RpcStringFree(&pszPrincipalName);
  306. }
  307. #else
  308. //set the authenification for this RPC interface
  309. rc = RpcServerRegisterAuthInfo(NULL, RPC_C_AUTHN_WINNT, NULL, NULL);
  310. #endif
  311. }
  312. }//end if set protocal sequence and end point set
  313. }//end if RPC service is ready
  314. return 0;
  315. }
  316. //END PwdMigRPCRegProc
  317. /*********************************************************************
  318. * *
  319. * Written by: Paul Thompson *
  320. * Date: 7 SEPT 2000 *
  321. * *
  322. * This function is called by Lsa when trying to load all *
  323. * registered Lsa password filter notification dlls. Here we will *
  324. * initialize the RPC run-time library to handle our ADMT password *
  325. * migration RPC interface and to begin looking for RPC calls. If we*
  326. * fail to successfully setup our RPC, we will return FALSE from this*
  327. * function which will cause Lsa not to load this password filter *
  328. * Dll. *
  329. * Note that the other two password filter dll functions: *
  330. * PasswordChangeNotify and PasswordFilter do nothing at this point *
  331. * in time. *
  332. * *
  333. *********************************************************************/
  334. //BEGIN InitializeChangeNotify
  335. BOOLEAN __stdcall InitializeChangeNotify()
  336. {
  337. /* local variables */
  338. BOOLEAN bSuccess = FALSE;
  339. /* function body */
  340. //spawn a seperate thread to register our RPC interface once RPC is up and running
  341. HANDLE h = CreateThread(NULL, 0, PwdMigRPCRegProc, NULL, 0, NULL);
  342. if (h != NULL)
  343. bSuccess = TRUE;;
  344. CloseHandle(h);
  345. return bSuccess;
  346. }
  347. //END InitializeChangeNotify
  348. /*********************************************************************
  349. * *
  350. * Written by: Paul Thompson *
  351. * Date: 7 SEPT 2000 *
  352. * *
  353. * This function is called by Lsa for all registered Lsa password*
  354. * filter notification dlls when a password in the domain has been *
  355. * modified. We will simply return STATUS_SUCCESS and do nothing. *
  356. * *
  357. *********************************************************************/
  358. //BEGIN PasswordChangeNotify
  359. NTSTATUS __stdcall PasswordChangeNotify(PUNICODE_STRING UserName, ULONG RelativeId,
  360. PUNICODE_STRING NewPassword)
  361. {
  362. return STATUS_SUCCESS;
  363. }
  364. /*********************************************************************
  365. * *
  366. * Written by: Paul Thompson *
  367. * Date: 7 SEPT 2000 *
  368. * *
  369. * This function is called by Lsa for all registered Lsa password*
  370. * filter notification dlls when a password in the domain is being *
  371. * modified. This function is designed to indicate to Lsa if the new*
  372. * password is acceptable. We will simply return TRUE (indicating it*
  373. * is acceptable) and do nothing. *
  374. * *
  375. *********************************************************************/
  376. //BEGIN PasswordFilter
  377. BOOLEAN __stdcall PasswordFilter(PUNICODE_STRING AccountName, PUNICODE_STRING FullName,
  378. PUNICODE_STRING Password, BOOLEAN SetOperation)
  379. {
  380. return TRUE;
  381. }
  382. //END PasswordFilter
  383. /***************************/
  384. /* Internal DLL functions. */
  385. /***************************/
  386. static BOOL Initialize(void)
  387. {
  388. return TRUE;
  389. }
  390. static BOOL Terminate(BOOL procterm)
  391. {
  392. if (!procterm)
  393. return TRUE;
  394. /* XXX Do stuff here */
  395. return TRUE;
  396. }
  397. BOOL WINAPI
  398. DllMain(HINSTANCE hinst, DWORD reason, VOID *rsvd)
  399. /*++
  400. Routine description:
  401. Dynamic link library entry point. Does nothing meaningful.
  402. Arguments:
  403. hinst = handle for the DLL
  404. reason = code indicating reason for call
  405. rsvd = for process attach: non-NULL => process startup
  406. for process detach: non-NULL => process termination
  407. Return value:
  408. status = success/failure
  409. Side effects:
  410. None
  411. --*/
  412. {
  413. switch (reason) {
  414. case DLL_PROCESS_ATTACH:
  415. {
  416. _CRT_INIT(hinst, reason, rsvd);
  417. DisableThreadLibraryCalls(hinst);
  418. return Initialize();
  419. break;
  420. }
  421. case DLL_PROCESS_DETACH:
  422. {
  423. BOOL bStat = Terminate(rsvd != NULL);
  424. _CRT_INIT(hinst, reason, rsvd);
  425. return bStat;
  426. break;
  427. }
  428. case DLL_THREAD_ATTACH:
  429. case DLL_THREAD_DETACH:
  430. return TRUE;
  431. default:
  432. return FALSE;
  433. }
  434. }
  435. ///////////////////////////////////////////////////////////////////////////////
  436. // Midl allocate memory
  437. ///////////////////////////////////////////////////////////////////////////////
  438. void __RPC_FAR * __RPC_USER
  439. midl_user_allocate(
  440. size_t len )
  441. {
  442. return new char[len];
  443. }
  444. ///////////////////////////////////////////////////////////////////////////////
  445. // Midl free memory
  446. ///////////////////////////////////////////////////////////////////////////////
  447. void __RPC_USER
  448. midl_user_free(
  449. void __RPC_FAR * ptr )
  450. {
  451. delete [] ptr;
  452. }