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.

1429 lines
48 KiB

  1. /*---------------------------------------------------------------------------
  2. File: PwdRpc.cpp
  3. Comments: RPC interface for Password Migration Lsa Notification Package
  4. and other internal functions.
  5. REVISION LOG ENTRY
  6. Revision By: Paul Thompson
  7. Revised on 09/04/00
  8. ---------------------------------------------------------------------------
  9. */
  10. #include "Pwd.h"
  11. #include <lmcons.h>
  12. #include <comdef.h>
  13. #include <malloc.h>
  14. #include "PwdSvc.h"
  15. #include "McsDmMsg.h"
  16. #include "AdmtCrypt2.h"
  17. #include "pwdfuncs.h"
  18. #include "TReg.hpp"
  19. #include "IsAdmin.hpp"
  20. #include "ResStr.h"
  21. #include "TxtSid.h"
  22. #include "resource.h"
  23. #include <MsPwdMig.h>
  24. /* global definitions */
  25. #define STATUS_NULL_LM_PASSWORD ((NTSTATUS)0x4000000DL)
  26. #define LM_BUFFER_LENGTH (LM20_PWLEN + 1)
  27. typedef NTSTATUS (CALLBACK * LSAIWRITEAUDITEVENT)(PSE_ADT_PARAMETER_ARRAY, ULONG);
  28. typedef NTSTATUS (* PLSAIAUDITPASSWORDACCESSEVENT)(USHORT EventType, PCWSTR pszTargetUserName, PCWSTR pszTargetUserDomain);
  29. #ifndef SECURITY_MAX_SID_SIZE
  30. #define SECURITY_MAX_SID_SIZE (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES * sizeof(DWORD)))
  31. #endif
  32. /* global variables */
  33. CRITICAL_SECTION csADMTCriticalSection; //critical sectio to protect concurrent first-time access
  34. SAMPR_HANDLE hgDomainHandle = NULL; //domain handle used in password calls
  35. LM_OWF_PASSWORD NullLmOwfPassword; //NULL representation of an LM Owf Password
  36. NT_OWF_PASSWORD NullNtOwfPassword; //NULL representation of an NT Owf Password
  37. HCRYPTPROV g_hProvider = 0;
  38. HCRYPTKEY g_hSessionKey = 0;
  39. HANDLE hEventSource;
  40. HMODULE hLsaDLL = NULL;
  41. LSAIWRITEAUDITEVENT LsaIWriteAuditEvent = NULL;
  42. PLSAIAUDITPASSWORDACCESSEVENT LsaIAuditPasswordAccessEvent = NULL;
  43. PWCHAR pDomain = NULL;
  44. BOOL LsapCrashOnAuditFail = TRUE;
  45. int nOSVer = 4;
  46. BOOL bWhistlerDC = FALSE;
  47. static const WCHAR PASSWORD_AUDIT_TEXT_ENGLISH[] = L"Password Hash Audit Event. Password of the following user accessed: Target User Name: %s Target User Domain: %s By user: Caller SID: %s";
  48. /* Checks if this machine is running Whistler OS or something even newer and the OS major verison number, sets global variables accordingly */
  49. void GetOS()
  50. {
  51. /* local constants */
  52. const int WINDOWS_2000_BUILD_NUMBER = 2195;
  53. /* local variables */
  54. TRegKey verKey, regComputer;
  55. DWORD rc = 0;
  56. WCHAR sBuildNum[MAX_PATH];
  57. /* function body */
  58. //connect to the DC's HKLM registry key
  59. rc = regComputer.Connect(HKEY_LOCAL_MACHINE, NULL);
  60. if (rc == ERROR_SUCCESS)
  61. {
  62. //see if this machine is running Windows XP or newer by checking the
  63. //build number in the registry. If not, then we don't need to check
  64. //for the new security option
  65. rc = verKey.OpenRead(L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",&regComputer);
  66. if (rc == ERROR_SUCCESS)
  67. {
  68. //get the CurrentBuildNumber string
  69. rc = verKey.ValueGetStr(L"CurrentBuildNumber", sBuildNum, MAX_PATH);
  70. if (rc == ERROR_SUCCESS)
  71. {
  72. int nBuild = _wtoi(sBuildNum);
  73. if (nBuild <= WINDOWS_2000_BUILD_NUMBER)
  74. bWhistlerDC = FALSE;
  75. else
  76. bWhistlerDC = TRUE;
  77. }
  78. //get the Version Number
  79. rc = verKey.ValueGetStr(L"CurrentVersion", sBuildNum, MAX_PATH);
  80. if (rc == ERROR_SUCCESS)
  81. nOSVer = _wtoi(sBuildNum);
  82. }
  83. }
  84. return;
  85. }
  86. _bstr_t GetString(DWORD dwID)
  87. {
  88. /* local variables */
  89. HINSTANCE m_hInstance = NULL;
  90. WCHAR sBuffer[1000];
  91. _bstr_t bstrRet;
  92. /* function body */
  93. m_hInstance = LoadLibrary(L"PwMig.dll");
  94. if (m_hInstance)
  95. {
  96. if (LoadString(m_hInstance, dwID, sBuffer, 1000) > 0)
  97. {
  98. // prevent uncaught exception due to low memory condition
  99. try
  100. {
  101. bstrRet = sBuffer;
  102. }
  103. catch (...)
  104. {
  105. ;
  106. }
  107. }
  108. FreeLibrary(m_hInstance);
  109. }
  110. return bstrRet;
  111. }
  112. /***************************
  113. * Event Logging Functions *
  114. ***************************/
  115. /*++
  116. Routine Description:
  117. Implements current policy of how to deal with a failed audit.
  118. Arguments:
  119. None.
  120. Return Value:
  121. None.
  122. --*/
  123. void LsapAuditFailed(NTSTATUS AuditStatus)
  124. {
  125. /* local variables */
  126. NTSTATUS Status;
  127. ULONG Response;
  128. ULONG_PTR HardErrorParam;
  129. BOOLEAN PrivWasEnabled;
  130. TRegKey verKey, regComputer;
  131. DWORD rc = 0;
  132. WCHAR sBuildNum[MAX_PATH];
  133. DWORD crashVal;
  134. BOOL bRaiseError = FALSE;
  135. /* function body */
  136. //connect to this machine's HKLM registry key
  137. rc = regComputer.Connect(HKEY_LOCAL_MACHINE, NULL);
  138. if (rc == ERROR_SUCCESS)
  139. {
  140. //open the LSA key and see if crash on audit failed is turned on
  141. rc = verKey.Open(L"SYSTEM\\CurrentControlSet\\Control\\Lsa",&regComputer);
  142. if (rc == ERROR_SUCCESS)
  143. {
  144. //get the CrashOnAuditFail value
  145. rc = verKey.ValueGetDWORD(CRASH_ON_AUDIT_FAIL_VALUE, &crashVal);
  146. if (rc == ERROR_SUCCESS)
  147. {
  148. //if crash on audit fail is set, turn off the flag
  149. if (crashVal == LSAP_CRASH_ON_AUDIT_FAIL)
  150. {
  151. bRaiseError = TRUE; //set flag to raise hard error
  152. rc = verKey.ValueSetDWORD(CRASH_ON_AUDIT_FAIL_VALUE, LSAP_ALLOW_ADIMIN_LOGONS_ONLY);
  153. if (rc == ERROR_SUCCESS)
  154. {
  155. //flush the key to disk
  156. do
  157. {
  158. Status = NtFlushKey(verKey.KeyGet());
  159. } while ((Status == STATUS_INSUFFICIENT_RESOURCES) || (Status == STATUS_NO_MEMORY));
  160. ASSERT(NT_SUCCESS(Status));
  161. }
  162. }
  163. }
  164. }
  165. }
  166. //if needed, raise a hard error
  167. if (bRaiseError)
  168. {
  169. HardErrorParam = AuditStatus;
  170. // enable the shutdown privilege so that we can bugcheck
  171. Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &PrivWasEnabled);
  172. Status = NtRaiseHardError(
  173. STATUS_AUDIT_FAILED,
  174. 1,
  175. 0,
  176. &HardErrorParam,
  177. OptionShutdownSystem,
  178. &Response);
  179. }
  180. return;
  181. }
  182. /*Routine Description:
  183. Find out if auditing is enabled for a certain event category and
  184. event success/failure case.
  185. Arguments:
  186. AuditCategory - Category of event to be audited.
  187. e.g. AuditCategoryPolicyChange
  188. AuditEventType - status type of event
  189. e.g. EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE
  190. Return Value:
  191. TRUE or FALSE
  192. */
  193. BOOL LsapAdtIsAuditingEnabledForCategory(POLICY_AUDIT_EVENT_TYPE AuditCategory,
  194. UINT AuditEventType)
  195. {
  196. BOOL bSuccess = FALSE;
  197. LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  198. NTSTATUS status = 0;
  199. LSA_HANDLE hPolicy;
  200. ASSERT((AuditEventType == EVENTLOG_AUDIT_SUCCESS) ||
  201. (AuditEventType == EVENTLOG_AUDIT_FAILURE));
  202. //attempt to open the policy.
  203. ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));//object attributes are reserved, so initalize to zeroes.
  204. status = LsaOpenPolicy( NULL,
  205. &ObjectAttributes,
  206. POLICY_READ,
  207. &hPolicy); //recieves the policy handle
  208. if (NT_SUCCESS(status))
  209. {
  210. //ask for audit event policy information
  211. PPOLICY_AUDIT_EVENTS_INFO info;
  212. status = LsaQueryInformationPolicy(hPolicy, PolicyAuditEventsInformation, (PVOID *)&info);
  213. if (NT_SUCCESS(status))
  214. {
  215. //if auditing is enabled, see if enable for this type
  216. if (info->AuditingMode)
  217. {
  218. POLICY_AUDIT_EVENT_OPTIONS EventAuditingOptions;
  219. EventAuditingOptions = info->EventAuditingOptions[AuditCategory];
  220. bSuccess = (AuditEventType == EVENTLOG_AUDIT_SUCCESS) ?
  221. (BOOL) (EventAuditingOptions & POLICY_AUDIT_EVENT_SUCCESS):
  222. (BOOL) (EventAuditingOptions & POLICY_AUDIT_EVENT_FAILURE);
  223. }
  224. LsaFreeMemory((PVOID) info); //free policy info structure
  225. }
  226. LsaClose(hPolicy); //Freeing the policy object handle
  227. }
  228. return bSuccess;
  229. }
  230. /*++
  231. Routine Description:
  232. This routine impersonates our client, opens the thread token, and
  233. extracts the User Sid. It puts the Sid in memory allocated via
  234. LsapAllocateLsaHeap, which must be freed by the caller.
  235. Arguments:
  236. None.
  237. Return Value:
  238. Returns a pointer to heap memory containing a copy of the Sid, or
  239. NULL.
  240. --*/
  241. NTSTATUS LsapQueryClientInfo(PTOKEN_USER *UserSid, PLUID AuthenticationId)
  242. {
  243. NTSTATUS Status = STATUS_SUCCESS;
  244. HANDLE TokenHandle;
  245. ULONG ReturnLength;
  246. TOKEN_STATISTICS TokenStats;
  247. //impersonate the caller
  248. Status = I_RpcMapWin32Status(RpcImpersonateClient(NULL));
  249. if (!NT_SUCCESS(Status))
  250. return( Status );
  251. //open the thread token
  252. Status = NtOpenThreadToken(
  253. NtCurrentThread(),
  254. TOKEN_QUERY,
  255. TRUE, // OpenAsSelf
  256. &TokenHandle);
  257. if (!NT_SUCCESS(Status))
  258. {
  259. I_RpcMapWin32Status(RpcRevertToSelf());
  260. return( Status );
  261. }
  262. //revert to self
  263. Status = I_RpcMapWin32Status(RpcRevertToSelf());
  264. ASSERT(NT_SUCCESS(Status));
  265. //get the size of the token information
  266. Status = NtQueryInformationToken (
  267. TokenHandle,
  268. TokenUser,
  269. NULL,
  270. 0,
  271. &ReturnLength);
  272. if (Status != STATUS_BUFFER_TOO_SMALL)
  273. {
  274. NtClose(TokenHandle);
  275. return( Status );
  276. }
  277. //allocate memory to hold the token info
  278. *UserSid = (PTOKEN_USER)malloc(ReturnLength);
  279. if (*UserSid == NULL)
  280. {
  281. NtClose(TokenHandle);
  282. return( STATUS_INSUFFICIENT_RESOURCES );
  283. }
  284. //get the token info
  285. Status = NtQueryInformationToken (
  286. TokenHandle,
  287. TokenUser,
  288. *UserSid,
  289. ReturnLength,
  290. &ReturnLength);
  291. if (!NT_SUCCESS(Status))
  292. {
  293. NtClose(TokenHandle);
  294. free(*UserSid);
  295. *UserSid = NULL;
  296. return( Status );
  297. }
  298. //get the authentication ID
  299. ReturnLength = 0;
  300. Status = NtQueryInformationToken (
  301. TokenHandle,
  302. TokenStatistics,
  303. (PVOID)&TokenStats,
  304. sizeof(TOKEN_STATISTICS),
  305. &ReturnLength);
  306. NtClose(TokenHandle);
  307. if (!NT_SUCCESS(Status))
  308. {
  309. free(*UserSid);
  310. *UserSid = NULL;
  311. return( Status );
  312. }
  313. *AuthenticationId = TokenStats.AuthenticationId;
  314. return Status;
  315. }
  316. /*********************************************************************
  317. * *
  318. * Written by: Paul Thompson *
  319. * Date: 23 APR 2001 *
  320. * *
  321. * This function is responsible for generating a *
  322. * SE_AUDITID_PASSWORD_HASH_ACCESS event in the security log. This *
  323. * function is called to generate that message when a user password *
  324. * hash is retrieved by the ADMT password filter DLL. *
  325. * All these event logging functions are copied and modified from LSA*
  326. * code written by others. *
  327. * *
  328. * Parameters: *
  329. * EventType - EVENTLOG_AUDIT_SUCCESS or EVENTLOG_AUDIT_FAILURE *
  330. * pszTargetUserName - name of user whose password is being retrieved*
  331. * pszTargetUserDomain - domain of user whose password is being *
  332. * retrieved *
  333. * *
  334. * Return Value: *
  335. * HRESULT - Standard Return Result *
  336. * *
  337. *********************************************************************/
  338. //BEGIN LsaAuditPasswordAccessEvent
  339. HRESULT LsaAuditPasswordAccessEvent(USHORT EventType,
  340. PCWSTR pszTargetUserName,
  341. PCWSTR pszTargetUserDomain)
  342. {
  343. /* local constants */
  344. const int W2K_VERSION_NUMBER = 5;
  345. /* local variables */
  346. HRESULT hr = S_OK;
  347. NTSTATUS Status = STATUS_SUCCESS;
  348. LUID ClientAuthenticationId;
  349. PTOKEN_USER TokenUserInformation=NULL;
  350. SE_ADT_PARAMETER_ARRAY AuditParameters = { 0 };
  351. PSE_ADT_PARAMETER_ARRAY_ENTRY Parameter;
  352. UNICODE_STRING TargetUser;
  353. UNICODE_STRING TargetDomain;
  354. UNICODE_STRING SubsystemName;
  355. UNICODE_STRING Explanation;
  356. _bstr_t sExplainText;
  357. /* function body */
  358. //if parameters are invalid, return
  359. if ( !((EventType == EVENTLOG_AUDIT_SUCCESS) ||
  360. (EventType == EVENTLOG_AUDIT_FAILURE)) ||
  361. !pszTargetUserName || !pszTargetUserDomain ||
  362. !*pszTargetUserName || !*pszTargetUserDomain )
  363. {
  364. return (HRESULT_FROM_WIN32(LsaNtStatusToWinError(STATUS_INVALID_PARAMETER)));
  365. }
  366. //If audit password access event function is available
  367. if (LsaIAuditPasswordAccessEvent)
  368. {
  369. Status = LsaIAuditPasswordAccessEvent(EventType, pszTargetUserName, pszTargetUserDomain);
  370. }
  371. else if (LsaIWriteAuditEvent)
  372. {
  373. //if auditing is not enabled, return asap
  374. if (!LsapAdtIsAuditingEnabledForCategory(AuditCategoryAccountManagement, EventType))
  375. return S_OK;
  376. // get caller info from the thread token
  377. Status = LsapQueryClientInfo( &TokenUserInformation, &ClientAuthenticationId );
  378. if (!NT_SUCCESS( Status ))
  379. {
  380. LsapAuditFailed(Status);
  381. return (HRESULT_FROM_WIN32(LsaNtStatusToWinError(Status)));
  382. }
  383. //init UNICODE_STRINGS
  384. RtlInitUnicodeString(&TargetUser, pszTargetUserName);
  385. RtlInitUnicodeString(&TargetDomain, pszTargetUserDomain);
  386. RtlInitUnicodeString(&SubsystemName, L"Security");
  387. //if not Whistler the audit message will be vague as to its intent, therefore we will add some
  388. //explanation text
  389. sExplainText = GetString(IDS_EVENT_PWD_HASH_W2K_EXPLAIN);
  390. RtlInitUnicodeString(&Explanation, (WCHAR*)sExplainText);
  391. //set the audit paramter header information
  392. RtlZeroMemory((PVOID) &AuditParameters, sizeof(AuditParameters));
  393. AuditParameters.CategoryId = SE_CATEGID_ACCOUNT_MANAGEMENT;
  394. AuditParameters.AuditId = SE_AUDITID_PASSWORD_HASH_ACCESS;
  395. AuditParameters.Type = EventType;
  396. //now set the audit parameters for this OS. Parameters are added to the structure using macros
  397. //defined in LsaParamMacros.h
  398. AuditParameters.ParameterCount = 0;
  399. LsapSetParmTypeSid(AuditParameters, AuditParameters.ParameterCount, TokenUserInformation->User.Sid);
  400. AuditParameters.ParameterCount++;
  401. LsapSetParmTypeString(AuditParameters, AuditParameters.ParameterCount, &SubsystemName);
  402. AuditParameters.ParameterCount++;
  403. LsapSetParmTypeString(AuditParameters, AuditParameters.ParameterCount, &TargetUser);
  404. AuditParameters.ParameterCount++;
  405. LsapSetParmTypeString(AuditParameters, AuditParameters.ParameterCount, &TargetDomain);
  406. AuditParameters.ParameterCount++;
  407. LsapSetParmTypeLogonId(AuditParameters, AuditParameters.ParameterCount, ClientAuthenticationId);
  408. AuditParameters.ParameterCount++;
  409. LsapSetParmTypeString(AuditParameters, AuditParameters.ParameterCount, &Explanation);
  410. AuditParameters.ParameterCount++;
  411. //Write to the security log
  412. Status = LsaIWriteAuditEvent(&AuditParameters, 0);
  413. if (!NT_SUCCESS(Status))
  414. LsapAuditFailed(Status);
  415. }//end if Whistler
  416. if (TokenUserInformation != NULL)
  417. free(TokenUserInformation);
  418. return (HRESULT_FROM_WIN32(LsaNtStatusToWinError(Status)));
  419. }
  420. /*********************************************************************
  421. * *
  422. * Written by: Paul Thompson *
  423. * Date: 8 SEPT 2000 *
  424. * *
  425. * This function is responsible for retrieving the caller's sid. *
  426. * We will use this prior to logging an event log. *
  427. * *
  428. *********************************************************************/
  429. //BEGIN GetCallerSid
  430. DWORD GetCallerSid(PSID pCallerSid, DWORD dwLength)
  431. {
  432. /* local variables */
  433. DWORD rc;
  434. HANDLE hToken = NULL;
  435. TOKEN_USER tUser[10];
  436. ULONG len;
  437. /* function body */
  438. rc = (DWORD)RpcImpersonateClient(NULL);
  439. if (!rc)
  440. {
  441. if ( OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken) )
  442. {
  443. if ( GetTokenInformation(hToken,TokenUser,tUser,10*(sizeof TOKEN_USER),&len) )
  444. CopySid(dwLength, pCallerSid, tUser[0].User.Sid);
  445. else
  446. rc = GetLastError();
  447. CloseHandle(hToken);
  448. }
  449. else
  450. rc = GetLastError();
  451. RPC_STATUS statusRevertToSelf = RpcRevertToSelf();
  452. ASSERT(statusRevertToSelf == RPC_S_OK);
  453. }
  454. return rc;
  455. }
  456. //END GetCallerSid
  457. /*********************************************************************
  458. * *
  459. * Written by: Paul Thompson *
  460. * Date: 19 SEPT 2000 *
  461. * *
  462. * This function is responsible for logging major events in Event*
  463. * Viewer. *
  464. * *
  465. *********************************************************************/
  466. //BEGIN LogEvent
  467. void LogPwdEvent(const WCHAR* srcName, bool bAuditSuccess)
  468. {
  469. /* local variables */
  470. USHORT wType;
  471. DWORD rc = 0;
  472. BOOL rcBool;
  473. /* function body */
  474. if (bAuditSuccess)
  475. wType = EVENTLOG_AUDIT_SUCCESS;
  476. else
  477. wType = EVENTLOG_AUDIT_FAILURE;
  478. //if NT4.0, write to the Security Event Log as you would any log
  479. if (nOSVer == 4)
  480. {
  481. //get the caller's SID
  482. BYTE byteSid[SECURITY_MAX_SID_SIZE];
  483. PSID pCallerSid = (PSID)byteSid;
  484. if (hEventSource && (GetCallerSid(pCallerSid, SECURITY_MAX_SID_SIZE) == ERROR_SUCCESS))
  485. {
  486. LPTSTR pStringArray[1];
  487. WCHAR msg[2000];
  488. WCHAR txtSid[MAX_PATH];
  489. DWORD lenTxt = MAX_PATH;
  490. //prepare the msg to display
  491. if (!GetTextualSid(pCallerSid,txtSid,&lenTxt))
  492. wcscpy(txtSid, L"");
  493. //retrieve audit text
  494. //note that hard-coded English string is used if string retrieval fails
  495. _bstr_t strFormat = GetString(IDS_EVENT_PWD_HASH_RETRIEVAL);
  496. LPCWSTR pszFormat = strFormat;
  497. if (pszFormat == NULL)
  498. {
  499. pszFormat = PASSWORD_AUDIT_TEXT_ENGLISH;
  500. }
  501. _snwprintf(msg, sizeof(msg) / sizeof(msg[0]), pszFormat, srcName, pDomain, txtSid);
  502. msg[sizeof(msg) / sizeof(msg[0]) - 1] = L'\0';
  503. pStringArray[0] = msg;
  504. //log the event
  505. rcBool = ReportEventW(hEventSource, // handle of event source
  506. wType, // event type
  507. SE_CATEGID_ACCOUNT_MANAGEMENT,// event category
  508. SE_AUDITID_PASSWORD_HASH_ACCESS,// event ID
  509. pCallerSid, // current user's SID
  510. 1, // strings in lpszStrings
  511. 0, // no bytes of raw data
  512. (LPCTSTR *)pStringArray, // array of error strings
  513. NULL ); // no raw data
  514. if ( !rcBool )
  515. rc = GetLastError();
  516. }
  517. }
  518. else //else write the event by requesting LSA to do it for us
  519. {
  520. //if not already done, late bind to LsaIWriteAuditEvent since it is not present on an NT 4.0 box
  521. if (!LsaIWriteAuditEvent)
  522. {
  523. hLsaDLL = LoadLibrary(L"LsaSrv.dll");
  524. if ( hLsaDLL )
  525. {
  526. LsaIWriteAuditEvent = (LSAIWRITEAUDITEVENT)GetProcAddress(hLsaDLL, "LsaIWriteAuditEvent");
  527. LsaIAuditPasswordAccessEvent = (PLSAIAUDITPASSWORDACCESSEVENT)GetProcAddress(hLsaDLL, "LsaIAuditPasswordAccessEvent");
  528. }
  529. }
  530. if (LsaIWriteAuditEvent)
  531. LsaAuditPasswordAccessEvent(wType, srcName, pDomain);
  532. }
  533. }
  534. //END LogEvent
  535. /*******************************
  536. * Event Logging Functions End *
  537. *******************************/
  538. /*********************************************************************
  539. * *
  540. * Written by: Paul Thompson *
  541. * Date: 8 SEPT 2000 *
  542. * *
  543. * This function is responsible for obtaining the account domain *
  544. * sid. This sid will be later used to Open the domain via SAM. *
  545. * *
  546. *********************************************************************/
  547. //BEGIN GetDomainSid
  548. NTSTATUS GetDomainSid(PSID * pDomainSid)
  549. {
  550. /* local variables */
  551. LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  552. NTSTATUS status = 0;
  553. LSA_HANDLE hPolicy;
  554. HRESULT hr = 0;
  555. /* function body */
  556. //object attributes are reserved, so initalize to zeroes.
  557. ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
  558. //attempt to open the policy.
  559. status = LsaOpenPolicy(
  560. NULL,
  561. &ObjectAttributes,
  562. POLICY_EXECUTE,
  563. &hPolicy //recieves the policy handle
  564. );
  565. if (NT_SUCCESS(status))
  566. {
  567. //ask for account domain policy information
  568. PPOLICY_ACCOUNT_DOMAIN_INFO info;
  569. status = LsaQueryInformationPolicy(hPolicy, PolicyAccountDomainInformation, (PVOID *)&info);
  570. if (NT_SUCCESS(status))
  571. {
  572. //save the domain sid
  573. *pDomainSid = SafeCopySid(info->DomainSid);
  574. if (*pDomainSid == NULL)
  575. status = STATUS_INSUFFICIENT_RESOURCES;
  576. //save the domain name
  577. USHORT uLen = info->DomainName.Length / sizeof(WCHAR);
  578. pDomain = new WCHAR[uLen + sizeof(WCHAR)];
  579. if (pDomain)
  580. {
  581. wcsncpy(pDomain, info->DomainName.Buffer, uLen);
  582. pDomain[uLen] = L'\0';
  583. }
  584. //free policy info structure
  585. LsaFreeMemory((PVOID) info);
  586. }
  587. //Freeing the policy object handle
  588. LsaClose(hPolicy);
  589. }
  590. return status;
  591. }
  592. //END GetDomainSid
  593. /*********************************************************************
  594. * *
  595. * Written by: Paul Thompson *
  596. * Date: 8 SEPT 2000 *
  597. * *
  598. * This function is responsible for obtaining a domain handle *
  599. * used repeatedly by our interface function CopyPassword. *
  600. * For optimization, this function should only be called once per*
  601. * the life of this dll. *
  602. * This function also gets an Event Handle to the event log. *
  603. * *
  604. *********************************************************************/
  605. //BEGIN GetDomainHandle
  606. NTSTATUS GetDomainHandle(SAMPR_HANDLE *pDomainHandle)
  607. {
  608. /* local variables */
  609. PSID pDomainSid;
  610. NTSTATUS status;
  611. SAMPR_HANDLE hServerHandle;
  612. SAMPR_HANDLE hDomainHandle;
  613. /* function body */
  614. //get the account domain sid
  615. status = GetDomainSid(&pDomainSid);
  616. if (NT_SUCCESS(status))
  617. {
  618. //connect to the Sam and get a server handle
  619. status = SamIConnect(NULL,
  620. &hServerHandle,
  621. SAM_SERVER_ALL_ACCESS,
  622. TRUE);
  623. if (NT_SUCCESS(status))
  624. {
  625. //get the account domain handle
  626. status = SamrOpenDomain(hServerHandle,
  627. DOMAIN_ALL_ACCESS,
  628. (PRPC_SID)pDomainSid,
  629. &hDomainHandle);
  630. if (NT_SUCCESS(status))
  631. *pDomainHandle = hDomainHandle;
  632. //close the SamIConnect server handle
  633. SamrCloseHandle(&hServerHandle);
  634. }
  635. FreeSid(pDomainSid);
  636. }
  637. return status;
  638. }
  639. //END GetDomainHandle
  640. /*********************************************************************
  641. * *
  642. * Written by: Paul Thompson *
  643. * Date: 8 SEPT 2000 *
  644. * *
  645. * This function is responsible for retrieving the global domain *
  646. * handle. If we don't have the handle yet, it calls the externally *
  647. * defined GetDomainHandle funtion to get the handle. The handle *
  648. * retrieval code is placed in a critical section. Subsequent *
  649. * calls to this functin merely return the handle. *
  650. * I will also use this function to fill the global NULL *
  651. * LmOwfPassword structure for possible use. This should be done *
  652. * one time only. *
  653. * *
  654. *********************************************************************/
  655. //BEGIN RetrieveDomainHandle
  656. HRESULT RetrieveDomainHandle(SAMPR_HANDLE *pDomainHandle)
  657. {
  658. /* local constants */
  659. const WCHAR * svcName = L"Security";
  660. /* local variables */
  661. NTSTATUS status = 0;
  662. HRESULT hr = ERROR_SUCCESS;
  663. BOOL bInCritSec = FALSE;
  664. /* function body */
  665. try
  666. {
  667. //enter the critical section
  668. EnterCriticalSection(&csADMTCriticalSection);
  669. bInCritSec = TRUE;
  670. //if not yet retrieved, get the global handle and fill the NULL
  671. //LmOwfPassword structure
  672. if (hgDomainHandle == NULL)
  673. {
  674. //get the domain handle
  675. status = GetDomainHandle(&hgDomainHandle);
  676. if (NT_SUCCESS(status))
  677. pDomainHandle = &hgDomainHandle;
  678. GetOS(); //set global variable as to whether this DC's OS
  679. //if NT4.0 OS on this DC, then set the event handle for logging events
  680. if (nOSVer == 4)
  681. {
  682. NTSTATUS Status;
  683. BOOLEAN PrivWasEnabled;
  684. //make sure we have audit and debug privileges
  685. RtlAdjustPrivilege( SE_SECURITY_PRIVILEGE, TRUE, FALSE, &PrivWasEnabled );
  686. RtlAdjustPrivilege( SE_DEBUG_PRIVILEGE, TRUE, FALSE, &PrivWasEnabled );
  687. RtlAdjustPrivilege( SE_AUDIT_PRIVILEGE, TRUE, FALSE, &PrivWasEnabled );
  688. //register this dll with the eventlog, get a handle, and store globally
  689. hEventSource = RegisterEventSourceW(NULL, svcName);
  690. if (!hEventSource)
  691. {
  692. LeaveCriticalSection(&csADMTCriticalSection); // Release ownership of the critical section
  693. return HRESULT_FROM_WIN32(GetLastError());
  694. }
  695. }
  696. //fill a global NULL LmOwfPassword in case we need it later
  697. WCHAR sNtPwd[MAX_PATH] = L"";
  698. UNICODE_STRING UnicodePwd;
  699. ANSI_STRING LmPassword;
  700. CHAR sBuf[LM_BUFFER_LENGTH];
  701. RtlInitUnicodeString(&UnicodePwd, sNtPwd);
  702. //fill LmOwf NULL password
  703. LmPassword.Buffer = sBuf;
  704. LmPassword.MaximumLength = LmPassword.Length = LM_BUFFER_LENGTH;
  705. RtlZeroMemory( LmPassword.Buffer, LM_BUFFER_LENGTH );
  706. status = RtlUpcaseUnicodeStringToOemString( &LmPassword, &UnicodePwd, FALSE );
  707. if ( !NT_SUCCESS(status) )
  708. {
  709. //the password is longer than the max LM password length
  710. status = STATUS_NULL_LM_PASSWORD;
  711. RtlZeroMemory( LmPassword.Buffer, LM_BUFFER_LENGTH );
  712. RtlCalculateLmOwfPassword((PLM_PASSWORD)&LmPassword, &NullLmOwfPassword);
  713. }
  714. else
  715. {
  716. RtlCalculateLmOwfPassword((PLM_PASSWORD)&LmPassword, &NullLmOwfPassword);
  717. }
  718. //fill NtOwf NULL password
  719. RtlCalculateNtOwfPassword((PNT_PASSWORD)&UnicodePwd, &NullNtOwfPassword);
  720. }
  721. LeaveCriticalSection(&csADMTCriticalSection); // Release ownership of the critical section
  722. }
  723. catch(...)
  724. {
  725. if (bInCritSec)
  726. {
  727. LeaveCriticalSection(&csADMTCriticalSection); // Release ownership of the critical section
  728. status = STATUS_UNSUCCESSFUL;
  729. }
  730. else
  731. {
  732. // EnterCriticalSection may raise a STATUS_INVALID_HANDLE under low memory conditions
  733. status = STATUS_INVALID_HANDLE;
  734. }
  735. }
  736. //convert any error to a win error
  737. if (!NT_SUCCESS(status))
  738. hr = LsaNtStatusToWinError(status);
  739. return hr;
  740. }
  741. //END RetrieveDomainHandle
  742. /*********************************************************************
  743. * *
  744. * Written by: Paul Thompson *
  745. * Date: 11 SEPT 2000 *
  746. * *
  747. * This function is responsible for retrieving the passwords for *
  748. * the given user's source domain account. We use SAM APIs to *
  749. * retrieve the LmOwf and NtOwf formats of the password. *
  750. * *
  751. *********************************************************************/
  752. //BEGIN RetrieveEncrytedSourcePasswords
  753. HRESULT RetrieveEncrytedSourcePasswords(const WCHAR* srcName,
  754. PLM_OWF_PASSWORD pSrcLmOwfPwd,
  755. PNT_OWF_PASSWORD pSrcNtOwfPwd)
  756. {
  757. /* local variables */
  758. NTSTATUS status = 0;
  759. HRESULT hr = ERROR_SUCCESS;
  760. SAMPR_HANDLE hUserHandle = NULL;
  761. ULONG ulCount = 1;
  762. ULONG userID;
  763. RPC_UNICODE_STRING sNames[1];
  764. SAMPR_ULONG_ARRAY ulIDs;
  765. SAMPR_ULONG_ARRAY ulUse;
  766. PSAMPR_USER_INFO_BUFFER pInfoBuf = NULL;
  767. WCHAR * pName;
  768. /* function body */
  769. pName = new WCHAR[wcslen(srcName)+1];
  770. if (!pName)
  771. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  772. //get the user's ID
  773. sNames[0].Length = sNames[0].MaximumLength = (USHORT)((wcslen(srcName)) * sizeof(WCHAR));
  774. wcscpy(pName, srcName);
  775. sNames[0].Buffer = pName;
  776. ulIDs.Element = NULL;
  777. ulUse.Element = NULL;
  778. status = SamrLookupNamesInDomain(hgDomainHandle,
  779. ulCount,
  780. sNames,
  781. &ulIDs,
  782. &ulUse);
  783. delete [] pName;
  784. if (!NT_SUCCESS(status))
  785. return HRESULT_FROM_WIN32(LsaNtStatusToWinError(status));
  786. userID = *(ulIDs.Element);
  787. //get a user handle
  788. status = SamrOpenUser(hgDomainHandle,
  789. USER_READ,
  790. userID,
  791. &hUserHandle);
  792. if (!NT_SUCCESS(status))
  793. {
  794. SamIFree_SAMPR_ULONG_ARRAY(&ulIDs);
  795. SamIFree_SAMPR_ULONG_ARRAY(&ulUse);
  796. return HRESULT_FROM_WIN32(LsaNtStatusToWinError(status));
  797. }
  798. //get the user's password
  799. status = SamrQueryInformationUser(hUserHandle,
  800. UserInternal3Information,
  801. &pInfoBuf);
  802. if (NT_SUCCESS(status)) //if success, get LmOwf and NtOwf versions of the password
  803. {
  804. if (pInfoBuf->Internal3.I1.NtPasswordPresent)
  805. memcpy(pSrcNtOwfPwd, pInfoBuf->Internal3.I1.NtOwfPassword.Buffer, sizeof(NT_OWF_PASSWORD));
  806. else
  807. memcpy(pSrcNtOwfPwd, &NullNtOwfPassword, sizeof(NT_OWF_PASSWORD));
  808. if (pInfoBuf->Internal3.I1.LmPasswordPresent)
  809. memcpy(pSrcLmOwfPwd, pInfoBuf->Internal3.I1.LmOwfPassword.Buffer, sizeof(LM_OWF_PASSWORD));
  810. else //else we need to use the global NULL LmOwfPassword
  811. memcpy(pSrcLmOwfPwd, &NullLmOwfPassword, sizeof(LM_OWF_PASSWORD));
  812. SamIFree_SAMPR_USER_INFO_BUFFER (pInfoBuf, UserInternal3Information);
  813. LogPwdEvent(srcName, true);
  814. }
  815. else
  816. LogPwdEvent(srcName, false);
  817. SamIFree_SAMPR_ULONG_ARRAY(&ulIDs);
  818. SamIFree_SAMPR_ULONG_ARRAY(&ulUse);
  819. SamrCloseHandle(&hUserHandle);
  820. if (!NT_SUCCESS(status))
  821. hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(status));
  822. return hr;
  823. }
  824. //END RetrieveEncrytedSourcePasswords
  825. /*********************************************************************
  826. * *
  827. * Written by: Paul Thompson *
  828. * Date: 11 SEPT 2000 *
  829. * *
  830. * This function is responsible for using the MSCHAP dll to *
  831. * change the given target user's password. *
  832. * *
  833. *********************************************************************/
  834. //BEGIN SetTargetPassword
  835. HRESULT SetTargetPassword(handle_t hBinding, const WCHAR* tgtServer,
  836. const WCHAR* tgtName, WCHAR* currentPwd,
  837. LM_OWF_PASSWORD newLmOwfPwd, NT_OWF_PASSWORD newNtOwfPwd)
  838. {
  839. /* local variables */
  840. NTSTATUS status;
  841. HRESULT hr = ERROR_SUCCESS;
  842. RPC_STATUS rcpStatus;
  843. UNICODE_STRING UnicodePwd;
  844. OEM_STRING oemString;
  845. LM_OWF_PASSWORD OldLmOwfPassword;
  846. NT_OWF_PASSWORD OldNtOwfPassword;
  847. BOOLEAN LmOldPresent = TRUE;
  848. int nConvert;
  849. WCHAR * pTemp;
  850. /* function body */
  851. pTemp = new WCHAR[wcslen(currentPwd)+1];
  852. if (!pTemp)
  853. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  854. //convert the old LmOwf password
  855. wcscpy(pTemp, currentPwd);
  856. _wcsupr(pTemp);
  857. RtlInitUnicodeString(&UnicodePwd, pTemp);
  858. status = RtlUpcaseUnicodeStringToOemString(&oemString, &UnicodePwd, TRUE);
  859. RtlSecureZeroMemory(pTemp, (wcslen(currentPwd)+1)*sizeof(WCHAR));
  860. delete [] pTemp;
  861. if (NT_SUCCESS(status))
  862. {
  863. if (status == STATUS_NULL_LM_PASSWORD)
  864. LmOldPresent = FALSE;
  865. else
  866. {
  867. status = RtlCalculateLmOwfPassword(oemString.Buffer, &OldLmOwfPassword);
  868. }
  869. RtlSecureZeroMemory(oemString.Buffer, oemString.Length);
  870. RtlFreeOemString(&oemString);
  871. }
  872. //convert the old NtOwf password
  873. RtlInitUnicodeString(&UnicodePwd, currentPwd);
  874. status = RtlCalculateNtOwfPassword(&UnicodePwd, &OldNtOwfPassword);
  875. if (!NT_SUCCESS(status)) //if failed, leave
  876. {
  877. hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(status));
  878. goto exit;
  879. }
  880. //impersonate the caller when setting the password, if failed, leave
  881. rcpStatus = RpcImpersonateClient(hBinding);
  882. if (rcpStatus != RPC_S_OK)
  883. {
  884. hr = HRESULT_FROM_WIN32(rcpStatus);
  885. goto exit;
  886. }
  887. //change the Password!
  888. status = MSChapSrvChangePassword(const_cast<WCHAR*>(tgtServer),
  889. const_cast<WCHAR*>(tgtName),
  890. LmOldPresent,
  891. &OldLmOwfPassword,
  892. &newLmOwfPwd,
  893. &OldNtOwfPassword,
  894. &newNtOwfPwd);
  895. rcpStatus = RpcRevertToSelf();
  896. if (rcpStatus != RPC_S_OK)
  897. hr = HRESULT_FROM_WIN32(rcpStatus);
  898. if (!NT_SUCCESS(status))
  899. hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(status));
  900. exit:
  901. RtlSecureZeroMemory(&OldLmOwfPassword, sizeof(LM_OWF_PASSWORD));
  902. RtlSecureZeroMemory(&OldNtOwfPassword, sizeof(NT_OWF_PASSWORD));
  903. return hr;
  904. }
  905. //END SetTargetPassword
  906. /*********************************************************************
  907. * *
  908. * Written by: Paul Thompson *
  909. * Date: 8 SEPT 2000 *
  910. * *
  911. * This function is responsible for checking to make sure that *
  912. * the calling client has the proper access on this machine and *
  913. * domain to change someone's password. We use a helper function to *
  914. * do the actual check. *
  915. * *
  916. *********************************************************************/
  917. //BEGIN AuthenticateClient
  918. DWORD
  919. AuthenticateClient(
  920. handle_t hBinding // in - binding for client call
  921. )
  922. {
  923. /* local variables */
  924. DWORD rc;
  925. /* function body */
  926. rc = (DWORD)RpcImpersonateClient(hBinding);
  927. if (!rc)
  928. {
  929. rc = IsAdminLocal();
  930. RPC_STATUS statusRevertToSelf = RpcRevertToSelfEx(hBinding);
  931. ASSERT(statusRevertToSelf == RPC_S_OK);
  932. }
  933. return rc;
  934. }
  935. //END AuthenticateClient
  936. /*********************************************************************
  937. * *
  938. * Written by: Paul Thompson *
  939. * Date: 6 SEPT 2000 *
  940. * *
  941. * This function is responsible for migrating the given user's *
  942. * password from the source domain, in which this dll is running, to *
  943. * the given migrated target domain account. We will retrieve the *
  944. * old user's current password and set the new user's password to *
  945. * match. *
  946. * *
  947. *********************************************************************/
  948. //BEGIN CopyPassword
  949. DWORD __stdcall
  950. CopyPassword(
  951. /* [in] */ handle_t hBinding,
  952. /* [string][in] */ const WCHAR __RPC_FAR *tgtServer,
  953. /* [string][in] */ const WCHAR __RPC_FAR *srcName,
  954. /* [string][in] */ const WCHAR __RPC_FAR *tgtName,
  955. /* [in] */ unsigned long dwPwd,
  956. /* [size_is][in] */const char __RPC_FAR *currentPwd
  957. )
  958. {
  959. HRESULT hr = ERROR_SUCCESS;
  960. SAMPR_HANDLE hDomain = NULL;
  961. LM_OWF_PASSWORD NewLmOwfPassword;
  962. NT_OWF_PASSWORD NewNtOwfPassword;
  963. NTSTATUS status;
  964. DWORD rc=0;
  965. PSID pCallerSid = NULL;
  966. _variant_t varPwd;
  967. _bstr_t bstrPwd;
  968. BOOL bInCritSec = FALSE;
  969. // validate parameters
  970. if ((tgtServer == NULL) || (srcName == NULL) || (tgtName == NULL) ||
  971. (currentPwd == NULL) || (dwPwd <= 0))
  972. {
  973. return E_INVALIDARG;
  974. }
  975. //validate the buffer and the reported size
  976. if (IsBadReadPtr(currentPwd, dwPwd))
  977. return E_INVALIDARG;
  978. try
  979. {
  980. //convert the incoming byte array into a variant
  981. varPwd = SetVariantWithBinaryArray(const_cast<char*>(currentPwd), dwPwd);
  982. if ((varPwd.vt != (VT_UI1|VT_ARRAY)) || (varPwd.parray == NULL))
  983. return E_INVALIDARG;
  984. //enter the critical section
  985. EnterCriticalSection(&csADMTCriticalSection);
  986. bInCritSec = TRUE; //set flag that tells we need to leave the critical section
  987. //try to decrypt the password
  988. ASSERT(g_hSessionKey != NULL);
  989. bstrPwd = AdmtDecrypt(g_hSessionKey, varPwd);
  990. LeaveCriticalSection(&csADMTCriticalSection); // Release ownership of the critical section
  991. bInCritSec = FALSE;
  992. if (!bstrPwd)
  993. {
  994. rc = GetLastError();
  995. return HRESULT_FROM_WIN32(rc);
  996. }
  997. }
  998. catch (_com_error& ce)
  999. {
  1000. if (bInCritSec)
  1001. LeaveCriticalSection(&csADMTCriticalSection); // Release ownership of the critical section
  1002. return ce.Error();
  1003. }
  1004. catch (...)
  1005. {
  1006. if (bInCritSec)
  1007. LeaveCriticalSection(&csADMTCriticalSection); // Release ownership of the critical section
  1008. return E_FAIL;
  1009. }
  1010. //get the domain handle
  1011. hr = RetrieveDomainHandle(&hDomain);
  1012. if (hr == ERROR_SUCCESS)
  1013. {
  1014. //get the user's password from the source domain
  1015. hr = RetrieveEncrytedSourcePasswords(srcName, &NewLmOwfPassword, &NewNtOwfPassword);
  1016. if (hr == ERROR_SUCCESS)
  1017. {
  1018. //set the target user's password to the source user's
  1019. hr = SetTargetPassword(hBinding, tgtServer, tgtName, (WCHAR*)bstrPwd,
  1020. NewLmOwfPassword, NewNtOwfPassword);
  1021. }
  1022. }
  1023. if ((WCHAR*)bstrPwd)
  1024. RtlSecureZeroMemory((WCHAR*)bstrPwd, wcslen((WCHAR*)bstrPwd)*sizeof(WCHAR));
  1025. RtlSecureZeroMemory(&NewLmOwfPassword, sizeof(LM_OWF_PASSWORD));
  1026. RtlSecureZeroMemory(&NewNtOwfPassword, sizeof(NT_OWF_PASSWORD));
  1027. return hr;
  1028. }
  1029. //END CopyPassword
  1030. /*********************************************************************
  1031. * *
  1032. * Written by: Paul Thompson *
  1033. * Date: 6 SEPT 2000 *
  1034. * *
  1035. * This function is responsible for checking a registry value to *
  1036. * make sure that the ADMT password migration Lsa notification *
  1037. * package is installed, running, and ready to migrate passwords. *
  1038. * *
  1039. *********************************************************************/
  1040. //BEGIN CheckConfig
  1041. DWORD __stdcall
  1042. CheckConfig(
  1043. /* [in] */ handle_t hBinding,
  1044. /* [in] */ unsigned long dwSession,
  1045. /* [size_is][in] */const char __RPC_FAR *aSession,
  1046. /* [in] */ unsigned long dwPwd,
  1047. /* [size_is][in] */const char __RPC_FAR *aTestPwd,
  1048. /* [out] */ WCHAR __RPC_FAR tempPwd[PASSWORD_BUFFER_SIZE]
  1049. )
  1050. {
  1051. DWORD rc;
  1052. DWORD rval;
  1053. DWORD type; // type of value
  1054. DWORD len = sizeof rval; // value length
  1055. HKEY hKey;
  1056. _variant_t varPwd;
  1057. _variant_t varSession;
  1058. _bstr_t bstrPwd = L"";
  1059. BOOL bInCritSec = FALSE;
  1060. // validate parameters
  1061. if ((aSession == NULL) || (aTestPwd == NULL) || (tempPwd == NULL) ||
  1062. (dwSession <= 0) || (dwPwd <= 0))
  1063. {
  1064. return E_INVALIDARG;
  1065. }
  1066. //validate the buffer and the reported size
  1067. if ((IsBadReadPtr(aSession, dwSession)) || (IsBadReadPtr(aTestPwd, dwPwd)) ||
  1068. (IsBadWritePtr((LPVOID)tempPwd, PASSWORD_BUFFER_SIZE * sizeof(WCHAR))))
  1069. {
  1070. return E_INVALIDARG;
  1071. }
  1072. //make sure the registry value is set for password migration
  1073. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1074. L"System\\CurrentControlSet\\Control\\Lsa",
  1075. 0,
  1076. KEY_READ,
  1077. &hKey);
  1078. if (rc == ERROR_SUCCESS)
  1079. {
  1080. rc = RegQueryValueEx(hKey, L"AllowPasswordExport", NULL, &type, (BYTE *)&rval, &len);
  1081. RegCloseKey(hKey);
  1082. if ((rc == ERROR_SUCCESS) && (type == REG_DWORD) && (rval == 1))
  1083. rc = ERROR_SUCCESS;
  1084. else
  1085. return PM_E_PASSWORD_MIGRATION_NOT_ENABLED;
  1086. }
  1087. else
  1088. return HRESULT_FROM_WIN32(rc);
  1089. try
  1090. {
  1091. //convert the incoming byte arrays into variants
  1092. varSession = SetVariantWithBinaryArray(const_cast<char*>(aSession), dwSession);
  1093. varPwd = SetVariantWithBinaryArray(const_cast<char*>(aTestPwd), dwPwd);
  1094. if ((varSession.vt != (VT_UI1|VT_ARRAY)) || (varSession.parray == NULL) ||
  1095. (varPwd.vt != (VT_UI1|VT_ARRAY)) || (varPwd.parray == NULL))
  1096. return E_INVALIDARG;
  1097. // acquire cryptographic service provider context
  1098. //enter the critical section
  1099. EnterCriticalSection(&csADMTCriticalSection);
  1100. bInCritSec = TRUE; //set flag that tells we need to leave the critical section
  1101. if (g_hProvider == 0)
  1102. {
  1103. g_hProvider = AdmtAcquireContext();
  1104. }
  1105. if (g_hProvider)
  1106. {
  1107. // import new session key
  1108. HCRYPTKEY hSessionKey = AdmtImportSessionKey(g_hProvider, varSession);
  1109. // decrypt password
  1110. if (hSessionKey)
  1111. {
  1112. // destroy any existing session key
  1113. if (g_hSessionKey)
  1114. {
  1115. AdmtDestroyKey(g_hSessionKey);
  1116. }
  1117. g_hSessionKey = hSessionKey;
  1118. bstrPwd = AdmtDecrypt(g_hSessionKey, varPwd);
  1119. if (!bstrPwd)
  1120. rc = GetLastError();
  1121. }
  1122. else
  1123. rc = GetLastError();
  1124. }
  1125. else
  1126. {
  1127. rc = GetLastError();
  1128. }
  1129. LeaveCriticalSection(&csADMTCriticalSection); // Release ownership of the critical section
  1130. bInCritSec = FALSE;
  1131. //send back the decrypted password
  1132. if (bstrPwd.length() > 0)
  1133. {
  1134. wcsncpy(tempPwd, bstrPwd, PASSWORD_BUFFER_SIZE);
  1135. tempPwd[PASSWORD_BUFFER_SIZE - 1] = L'\0';
  1136. }
  1137. else
  1138. {
  1139. tempPwd[0] = L'\0';
  1140. }
  1141. }
  1142. catch (_com_error& ce)
  1143. {
  1144. if (bInCritSec)
  1145. LeaveCriticalSection(&csADMTCriticalSection); // Release ownership of the critical section
  1146. return ce.Error();
  1147. }
  1148. catch (...)
  1149. {
  1150. if (bInCritSec)
  1151. LeaveCriticalSection(&csADMTCriticalSection); // Release ownership of the critical section
  1152. return E_FAIL;
  1153. }
  1154. return HRESULT_FROM_WIN32(rc);
  1155. }
  1156. //END CheckConfig
  1157. //----------------------------------------------------------------------------
  1158. // Security Callback Function
  1159. //
  1160. // Validates client access to PwdMigRpc interface.
  1161. //
  1162. // Arguments
  1163. // hInterface - interface handle (not used in this implementation)
  1164. // pContext - the context is the client binding handle
  1165. //
  1166. // Return Value
  1167. // A returned value of RPC_OK means allow access whereas any other value
  1168. // means deny access. This implementation returns ERROR_ACCESS_DENIED to
  1169. // indicate that access should be denied to client.
  1170. //----------------------------------------------------------------------------
  1171. RPC_STATUS RPC_ENTRY SecurityCallback(RPC_IF_HANDLE hInterface, void* pContext)
  1172. {
  1173. RPC_STATUS rpcStatusReturn = ERROR_ACCESS_DENIED;
  1174. if (pContext)
  1175. {
  1176. //
  1177. // Retrieve privilege attributes of client making call.
  1178. //
  1179. RPC_AUTHZ_HANDLE hPrivs;
  1180. DWORD dwAuthnLevel;
  1181. RPC_STATUS status = RpcBindingInqAuthClient(
  1182. pContext,
  1183. &hPrivs,
  1184. NULL,
  1185. &dwAuthnLevel,
  1186. NULL,
  1187. NULL
  1188. );
  1189. if (status == RPC_S_OK)
  1190. {
  1191. //
  1192. // Verify authentication level is packet privacy.
  1193. //
  1194. if (dwAuthnLevel >= RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
  1195. {
  1196. //
  1197. // Verify the client is an administrator on the local machine.
  1198. //
  1199. status = AuthenticateClient(pContext);
  1200. //
  1201. // If all checks have passed then allow client access.
  1202. //
  1203. if (status == RPC_S_OK)
  1204. {
  1205. rpcStatusReturn = RPC_S_OK;
  1206. }
  1207. }
  1208. }
  1209. }
  1210. return rpcStatusReturn;
  1211. }