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.

1221 lines
35 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. rassfm.c
  5. Abstract:
  6. This module implements the subauthentication needed by the various RAS
  7. protocols (ARAP, MD5 etc.).
  8. It is adapted from the subauthentication sample from CliffV.
  9. Author:
  10. Shirish Koti 28-Feb-97
  11. Revisions:
  12. 06/02/97 Steve Cobb, Added MD5-CHAP support
  13. --*/
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <ntsam.h>
  18. #include <windows.h>
  19. #include <ntmsv1_0.h>
  20. #include <crypt.h>
  21. #include <samrpc.h>
  22. #include <lsarpc.h>
  23. #define SECURITY_WIN32
  24. #define SECURITY_PACKAGE
  25. #include <security.h>
  26. #include <secint.h>
  27. #include <samisrv.h>
  28. #include <lsaisrv.h>
  29. #include <ntlsa.h>
  30. #include <lmcons.h>
  31. #include <logonmsv.h>
  32. #include <macfile.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include "rasman.h"
  36. #include "rasfmsub.h"
  37. #include "arapio.h"
  38. #include "md5port.h"
  39. #include "cleartxt.h"
  40. #include "rassfm.h"
  41. // Private heap used by the RASSFM module.
  42. PVOID RasSfmPrivateHeap;
  43. // Empty OWF password.
  44. const NT_OWF_PASSWORD EMPTY_OWF_PASSWORD =
  45. {
  46. {
  47. { '\x31', '\xD6', '\xCF', '\xE0', '\xD1', '\x6A', '\xE9', '\x31' },
  48. { '\xB7', '\x3C', '\x59', '\xD7', '\xE0', '\xC0', '\x89', '\xC0' }
  49. }
  50. };
  51. BOOL
  52. RasSfmSubAuthEntry(
  53. IN HANDLE hinstDll,
  54. IN DWORD fdwReason,
  55. IN LPVOID lpReserved
  56. )
  57. /*++
  58. Routine Description:
  59. Entry point into the dll
  60. Arguments:
  61. hinstDll - handle
  62. fdwReason - why the entry
  63. lpReserved -
  64. Return Value:
  65. TRUE
  66. --*/
  67. {
  68. switch (fdwReason)
  69. {
  70. case DLL_PROCESS_ATTACH:
  71. RasSfmPrivateHeap = RtlCreateHeap(
  72. HEAP_GROWABLE,
  73. NULL,
  74. 0,
  75. 0,
  76. NULL,
  77. NULL
  78. );
  79. DisableThreadLibraryCalls( hinstDll );
  80. InitializeCriticalSection( &ArapDesLock );
  81. break;
  82. case DLL_PROCESS_DETACH:
  83. RtlDestroyHeap(RasSfmPrivateHeap);
  84. break;
  85. }
  86. return(TRUE);
  87. }
  88. NTSTATUS
  89. Msv1_0SubAuthenticationRoutineEx(
  90. IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
  91. IN PVOID LogonInformation,
  92. IN ULONG Flags,
  93. IN PUSER_ALL_INFORMATION UserAll,
  94. IN SAM_HANDLE UserHandle,
  95. IN OUT PMSV1_0_VALIDATION_INFO ValidationInfo,
  96. OUT PULONG ActionsPerformed
  97. )
  98. /*++
  99. Routine Description:
  100. This is the routine called in by the MSV package (if it was requested that
  101. the subauth package be called in), as a result of calling LsaLogonUser.
  102. This routine does RAS protocol specific authentication.
  103. In case of both ARAP and MD5 CHAP, the only thing we do in this routine is
  104. actual password authentication and leave everything else (logon hours, pwd
  105. expiry etc.) to the MSV package.
  106. Arguments:
  107. LogonLevel - we don't use it
  108. LogonInformation - contains the info our client side gave to us
  109. Flags - we don't use this flag
  110. UserAll - we get password creation,expiry times from this
  111. UserHandle - we get the clear text password using this
  112. ValidationInfo - set return info
  113. ActionsPerformed - we always set this to NTLM_SUBAUTH_PASSWORD to indicate
  114. to the package that all we did was check for password
  115. Return Value:
  116. STATUS_SUCCESS: if there was no error.
  117. STATUS_WRONG_PASSWORD: The password was invalid.
  118. --*/
  119. {
  120. NTSTATUS status;
  121. PNETLOGON_NETWORK_INFO pLogonNetworkInfo;
  122. PRAS_SUBAUTH_INFO pRasSubAuthInfo;
  123. USHORT bufferLength;
  124. pLogonNetworkInfo = (PNETLOGON_NETWORK_INFO) LogonInformation;
  125. pRasSubAuthInfo = (PRAS_SUBAUTH_INFO)
  126. pLogonNetworkInfo->NtChallengeResponse.Buffer;
  127. bufferLength = pLogonNetworkInfo->NtChallengeResponse.Length;
  128. if ( pRasSubAuthInfo == NULL || (bufferLength < sizeof(RAS_SUBAUTH_INFO)) )
  129. {
  130. return STATUS_INVALID_PARAMETER;
  131. }
  132. switch (pRasSubAuthInfo->ProtocolType)
  133. {
  134. //
  135. // do the ARAP-specific authentication
  136. //
  137. case RAS_SUBAUTH_PROTO_ARAP:
  138. status = ArapSubAuthentication(pLogonNetworkInfo,
  139. UserAll,
  140. UserHandle,
  141. ValidationInfo);
  142. ValidationInfo->Authoritative = TRUE;
  143. *ActionsPerformed = MSV1_0_SUBAUTH_PASSWORD;
  144. break;
  145. // MD5 CHAP subauthentication.
  146. //
  147. case RAS_SUBAUTH_PROTO_MD5CHAP:
  148. {
  149. // Subauthenticate the user account.
  150. //
  151. status = MD5ChapSubAuthentication(
  152. UserHandle,
  153. UserAll,
  154. pRasSubAuthInfo,
  155. bufferLength
  156. );
  157. // No validation information is returned. Might want to return a
  158. // session key here in the future.
  159. //
  160. ValidationInfo->WhichFields = 0;
  161. ValidationInfo->Authoritative = TRUE;
  162. *ActionsPerformed = MSV1_0_SUBAUTH_PASSWORD;
  163. break;
  164. }
  165. // MD5 CHAP Ex subauthentication.
  166. //
  167. case RAS_SUBAUTH_PROTO_MD5CHAP_EX:
  168. {
  169. // Subauthenticate the user account.
  170. //
  171. status = MD5ChapExSubAuthentication(
  172. UserHandle,
  173. UserAll,
  174. pRasSubAuthInfo,
  175. bufferLength
  176. );
  177. // No validation information is returned. Might want to return a
  178. // session key here in the future.
  179. //
  180. ValidationInfo->WhichFields = 0;
  181. ValidationInfo->Authoritative = TRUE;
  182. *ActionsPerformed = MSV1_0_SUBAUTH_PASSWORD;
  183. break;
  184. }
  185. default:
  186. DBGPRINT("RASSFM subauth pkg: bad protocol type %d\n",
  187. pRasSubAuthInfo->ProtocolType);
  188. status = STATUS_WRONG_PASSWORD;
  189. break;
  190. }
  191. return(status);
  192. }
  193. NTSTATUS
  194. Msv1_0SubAuthenticationRoutineGeneric(
  195. IN PVOID SubmitBuffer,
  196. IN ULONG SubmitBufferLength,
  197. OUT PULONG ReturnBufferLength,
  198. OUT PVOID *ReturnBuffer
  199. )
  200. /*++
  201. Routine Description:
  202. This is the routine called in by the MSV package (if it was requested that
  203. the subauth package be called in), as a result of calling
  204. LsaCallAuthenticationPackage. This routine does RAS protocol specific
  205. functions.
  206. In case of ARAP, we implement change password functionality in this routine.
  207. Arguments:
  208. SubmitBuffer - the buffer containing password change info
  209. SubmitBufferLength - length of this buffer
  210. ReturnBufferLength - we don't use it
  211. ReturnBuffer - we don't use it
  212. Return Value:
  213. STATUS_SUCCESS: if there was no error.
  214. --*/
  215. {
  216. PARAP_SUBAUTH_REQ pArapSubAuthInfo;
  217. PUNICODE_STRING pUserName;
  218. PUNICODE_STRING pDomainName;
  219. PRAS_SUBAUTH_INFO pRasSubAuthInfo;
  220. NTSTATUS status;
  221. pRasSubAuthInfo = (PRAS_SUBAUTH_INFO)SubmitBuffer;
  222. switch (pRasSubAuthInfo->ProtocolType)
  223. {
  224. //
  225. // do the ARAP-specific authentication
  226. //
  227. case RAS_SUBAUTH_PROTO_ARAP:
  228. status = ArapChangePassword(pRasSubAuthInfo,
  229. ReturnBufferLength,
  230. ReturnBuffer);
  231. break;
  232. default:
  233. DBGPRINT("Msv1_0SubAuthenticationRoutineGeneric: bad protocol type\n");
  234. ASSERT(0);
  235. status = STATUS_UNSUCCESSFUL;
  236. }
  237. return(status);
  238. }
  239. NTSTATUS
  240. ArapSubAuthentication(
  241. IN OUT PNETLOGON_NETWORK_INFO pLogonNetworkInfo,
  242. IN PUSER_ALL_INFORMATION UserAll,
  243. IN SAM_HANDLE UserHandle,
  244. IN OUT PMSV1_0_VALIDATION_INFO ValidationInfo
  245. )
  246. /*++
  247. Routine Description:
  248. This is the routine that does the actuall authentication. It retrieves
  249. the clear-text password, does the DES encryption of the challenge and
  250. compares with what the Mac client has sent to determine if authentication
  251. succeeded. Also, it returns a response to the challenge sent to us by
  252. the Mac.
  253. Arguments:
  254. pLogonNetworkInfo - ptr to the NETLOGON_NETWORK_INFO struct
  255. UserAll - ptr to the USER_ALL_INFORMATION struct
  256. UserHandle - sam handle for the user
  257. ValidationInfo - what we return to our caller
  258. Return Value:
  259. STATUS_SUCCESS: if authentication succeeded, appropriate error otherwise
  260. --*/
  261. {
  262. NTSTATUS status;
  263. PARAP_SUBAUTH_REQ pArapSubAuthInfo;
  264. ARAP_CHALLENGE Challenge;
  265. PARAP_SUBAUTH_RESP pArapResp;
  266. PUNICODE_STRING pUserName;
  267. PUNICODE_STRING pDomainName;
  268. UNICODE_STRING UnicodePassword;
  269. ANSI_STRING AnsiPassword;
  270. PRAS_SUBAUTH_INFO pRasSubAuthInfo;
  271. DWORD Response1;
  272. DWORD Response2;
  273. UCHAR ClearTextPassword[64];
  274. BOOLEAN fCallerIsArap;
  275. pRasSubAuthInfo = (PRAS_SUBAUTH_INFO)
  276. pLogonNetworkInfo->NtChallengeResponse.Buffer;
  277. pArapSubAuthInfo = (PARAP_SUBAUTH_REQ)&pRasSubAuthInfo->Data[0];
  278. //
  279. // NOTE: this is a quick-n-dirty workaround to returning a clean buffer
  280. // We use the KickoffTime,LogoffTime and SessionKey fields of ValidationInfo
  281. // The SessionKey is a 16 byte field. We use only 12 bytes, but be careful
  282. // not to exceed it!!
  283. ASSERT(sizeof(ARAP_SUBAUTH_RESP) <= sizeof(USER_SESSION_KEY));
  284. //
  285. // store the password create and expiry date: we need to send it to Mac
  286. //
  287. ValidationInfo->KickoffTime = UserAll->PasswordLastSet;
  288. ValidationInfo->LogoffTime = UserAll->PasswordMustChange;
  289. ValidationInfo->WhichFields = ( MSV1_0_VALIDATION_LOGOFF_TIME |
  290. MSV1_0_VALIDATION_KICKOFF_TIME |
  291. MSV1_0_VALIDATION_SESSION_KEY |
  292. MSV1_0_VALIDATION_USER_FLAGS );
  293. ValidationInfo->UserFlags = 0;
  294. pArapResp = (PARAP_SUBAUTH_RESP)&ValidationInfo->SessionKey;
  295. if ((pArapSubAuthInfo->PacketType != ARAP_SUBAUTH_LOGON_PKT) &&
  296. (pArapSubAuthInfo->PacketType != SFM_SUBAUTH_LOGON_PKT))
  297. {
  298. DBGPRINT("ARAPSubAuth: PacketType is not ARAP, returning failure\n");
  299. pArapResp->Result = ARAPERR_BAD_FORMAT;
  300. return(STATUS_UNSUCCESSFUL);
  301. }
  302. fCallerIsArap = (pArapSubAuthInfo->PacketType == ARAP_SUBAUTH_LOGON_PKT);
  303. //
  304. // presently no one calls with fGuestLogon. If in future, we need Guest logon,
  305. // then we will have to check if (Flags & MSV1_0_GUEST_LOGON) is set to allow
  306. // Guest logon. Right now, we fail the request.
  307. //
  308. if (pArapSubAuthInfo->Logon.fGuestLogon)
  309. {
  310. DBGPRINT("ARAPSubAuth: how come guest logon is reaching here??\n");
  311. ASSERT(0);
  312. pArapResp->Result = ARAPERR_AUTH_FAILURE;
  313. return(STATUS_UNSUCCESSFUL);
  314. }
  315. pUserName = &pLogonNetworkInfo->Identity.UserName;
  316. pDomainName = &pLogonNetworkInfo->Identity.LogonDomainName;
  317. status = RetrieveCleartextPassword(UserHandle, UserAll, &UnicodePassword);
  318. if (status != STATUS_SUCCESS)
  319. {
  320. DBGPRINT("ARAPSubAuth: RetrieveCleartextPassword failed %lx\n",status);
  321. pArapResp->Result = ARAPERR_PASSWD_NOT_AVAILABLE;
  322. return(STATUS_UNSUCCESSFUL);
  323. }
  324. SecureZeroMemory(ClearTextPassword, sizeof(ClearTextPassword));
  325. AnsiPassword.Length = AnsiPassword.MaximumLength = sizeof(ClearTextPassword);
  326. AnsiPassword.Buffer = ClearTextPassword;
  327. status = RtlUnicodeStringToAnsiString( &AnsiPassword, &UnicodePassword, FALSE );
  328. SecureZeroMemory(UnicodePassword.Buffer, UnicodePassword.Length);
  329. // we don't need the unicode password anymore
  330. RtlFreeUnicodeString(&UnicodePassword);
  331. if (!NT_SUCCESS(status))
  332. {
  333. DBGPRINT("ARAPSubAuth: RtlUnicodeStringToAnsiString failed %lx\n",status);
  334. pArapResp->Result = ARAPERR_PASSWD_NOT_AVAILABLE;
  335. return(STATUS_UNSUCCESSFUL);
  336. }
  337. //
  338. // Mac sends challenge to us as well: compute the response
  339. //
  340. Challenge.high = pArapSubAuthInfo->Logon.MacChallenge1;
  341. Challenge.low = pArapSubAuthInfo->Logon.MacChallenge2;
  342. EnterCriticalSection( &ArapDesLock );
  343. if (fCallerIsArap)
  344. {
  345. DoDesInit(ClearTextPassword, TRUE);
  346. }
  347. //
  348. // RandNum expects the low-bit of each byte (of password) to be cleared
  349. // during key-generation
  350. //
  351. else
  352. {
  353. DoDesInit(ClearTextPassword, FALSE);
  354. }
  355. DoTheDESEncrypt((PBYTE)&Challenge);
  356. //
  357. // copy the response that needs to be sent back to the Mac
  358. //
  359. pArapResp->Response = Challenge;
  360. //
  361. // encrypt the challenge that we sent to find out if this Mac is honest
  362. //
  363. Challenge.high = pArapSubAuthInfo->Logon.NTChallenge1;
  364. Challenge.low = pArapSubAuthInfo->Logon.NTChallenge2;
  365. DoTheDESEncrypt((PBYTE)&Challenge);
  366. Response1 = Challenge.high;
  367. Response2 = Challenge.low;
  368. DoDesEnd();
  369. LeaveCriticalSection( &ArapDesLock );
  370. //
  371. // zero the clear text password: we don't need it hanging around
  372. //
  373. SecureZeroMemory(ClearTextPassword, sizeof(ClearTextPassword));
  374. //
  375. // does the response returned by the Mac match ours?
  376. //
  377. if ((Response1 == pArapSubAuthInfo->Logon.MacResponse1) &&
  378. (Response2 == pArapSubAuthInfo->Logon.MacResponse2))
  379. {
  380. pArapResp->Result = ARAPERR_NO_ERROR;
  381. status = STATUS_SUCCESS;
  382. }
  383. else
  384. {
  385. DBGPRINT("ARAPSubAuth: our Challenge: %lx %lx\n",
  386. pArapSubAuthInfo->Logon.NTChallenge1,pArapSubAuthInfo->Logon.NTChallenge2);
  387. DBGPRINT("ARAPSubAuth: Response don't match! (ours %lx %lx vs. Mac's %lx %lx)\n",
  388. Response1,Response2,pArapSubAuthInfo->Logon.MacResponse1,
  389. pArapSubAuthInfo->Logon.MacResponse2);
  390. pArapResp->Response.high = 0;
  391. pArapResp->Response.low = 0;
  392. pArapResp->Result = ARAPERR_AUTH_FAILURE;
  393. status = STATUS_WRONG_PASSWORD;
  394. }
  395. return(status);
  396. }
  397. NTSTATUS
  398. ArapChangePassword(
  399. IN OUT PRAS_SUBAUTH_INFO pRasSubAuthInfo,
  400. OUT PULONG ReturnBufferLength,
  401. OUT PVOID *ReturnBuffer
  402. )
  403. /*++
  404. Routine Description:
  405. This routine is called to change the password of the user in question.
  406. It first retrieves the clear-text password, does the DES decryption of the
  407. munged old password and munged new password to get the clear-text old and
  408. new passwords; makes sure that the old password matches with what we have
  409. as the password and then finally, sets the new password.
  410. Arguments:
  411. pRasSubAuthInfo - ptr to RAS_SUBAUTH_INFO struct: input data
  412. ReturnBufferLength - how much are we returning
  413. ReturnBuffer - what we return: output data
  414. Return Value:
  415. STATUS_SUCCESS: if password change succeeded, appropriate error otherwise
  416. --*/
  417. {
  418. NTSTATUS status;
  419. PARAP_SUBAUTH_REQ pArapSubAuthInfo;
  420. PARAP_SUBAUTH_RESP pArapResp;
  421. UNICODE_STRING UserName;
  422. UNICODE_STRING PackageName;
  423. UNICODE_STRING UnicodePassword;
  424. ANSI_STRING AnsiPassword;
  425. USER_INFORMATION_CLASS UserInformationClass;
  426. USER_ALL_INFORMATION UserAllInfo;
  427. ARAP_CHALLENGE Challenge;
  428. USER_PARAMETERS_INFORMATION *oldParmInfo=NULL;
  429. PSAMPR_USER_ALL_INFORMATION UserParmInfo=NULL;
  430. UCHAR OldPwd[32];
  431. UCHAR NewPwd[32];
  432. UCHAR MacsOldPwd[32];
  433. WCHAR NtPassword[40];
  434. UCHAR NewPwdLen;
  435. UCHAR OldPwdLen;
  436. UCHAR MacOldPwdLen;
  437. SAMPR_HANDLE UserHandle;
  438. PVOID Credentials;
  439. DWORD CredentialSize;
  440. PUCHAR pBufPtr;
  441. BOOLEAN fCallerIsArap;
  442. UCHAR FirstByte;
  443. BOOLEAN fPasswordAvailable=TRUE;
  444. UCHAR i;
  445. *ReturnBuffer = MIDL_user_allocate( sizeof(ARAP_SUBAUTH_RESP) );
  446. if (*ReturnBuffer == NULL)
  447. {
  448. DBGPRINT("ARAPChgPwd: MIDL_alloc failed!\n");
  449. *ReturnBufferLength = 0;
  450. return(STATUS_INSUFFICIENT_RESOURCES);
  451. }
  452. *ReturnBufferLength = sizeof(ARAP_SUBAUTH_RESP);
  453. pArapResp = (PARAP_SUBAUTH_RESP)*ReturnBuffer;
  454. pArapSubAuthInfo = (PARAP_SUBAUTH_REQ)&pRasSubAuthInfo->Data[0];
  455. if ((pArapSubAuthInfo->PacketType != ARAP_SUBAUTH_CHGPWD_PKT) &&
  456. (pArapSubAuthInfo->PacketType != SFM_SUBAUTH_CHGPWD_PKT))
  457. {
  458. DBGPRINT("ARAPChgPwd: bad packet type %d!\n",pArapSubAuthInfo->PacketType);
  459. pArapResp->Result = ARAPERR_BAD_FORMAT;
  460. return(STATUS_UNSUCCESSFUL);
  461. }
  462. fCallerIsArap = (pArapSubAuthInfo->PacketType == ARAP_SUBAUTH_CHGPWD_PKT);
  463. UserName.Length = (sizeof(WCHAR) * wcslen(pArapSubAuthInfo->ChgPwd.UserName));
  464. UserName.MaximumLength = UserName.Length;
  465. UserName.Buffer = pArapSubAuthInfo->ChgPwd.UserName;
  466. status = ArapGetSamHandle(&UserHandle, &UserName);
  467. if (status != STATUS_SUCCESS)
  468. {
  469. DBGPRINT("Arap: ArapGetSamHandle failed with %lx\n", status);
  470. pArapResp->Result = ARAPERR_COULDNT_GET_SAMHANDLE;
  471. return(status);
  472. }
  473. SecureZeroMemory(OldPwd, sizeof(OldPwd));
  474. SecureZeroMemory(MacsOldPwd, sizeof(MacsOldPwd));
  475. SecureZeroMemory(NewPwd, sizeof(NewPwd));
  476. //
  477. // are we on a DS?
  478. //
  479. if (SampUsingDsData())
  480. {
  481. RtlInitUnicodeString( &PackageName, CLEAR_TEXT_PWD_PACKAGE );
  482. //
  483. // get the clear text password
  484. //
  485. status = SamIRetrievePrimaryCredentials( (PVOID)UserHandle,
  486. &PackageName,
  487. &Credentials,
  488. &CredentialSize );
  489. if (status != STATUS_SUCCESS)
  490. {
  491. DBGPRINT("ARAPSubAuth: SamI...Credentials failed %lx\n",status);
  492. pArapResp->Result = ARAPERR_PASSWD_NOT_AVAILABLE;
  493. SamrCloseHandle( &UserHandle );
  494. return(status);
  495. }
  496. //
  497. // if we are returned a null password, it could be that the password is really
  498. // null, or that cleartext password isn't available for this user. If it's
  499. // the latter, we need to bail out!
  500. //
  501. if (CredentialSize == 0)
  502. {
  503. // get the OWF for this user
  504. status = SamrQueryInformationUser( UserHandle,
  505. UserParametersInformation,
  506. (PSAMPR_USER_INFO_BUFFER*)&oldParmInfo);
  507. //
  508. // if the call failed, or if the user's password is not null, bail out!
  509. //
  510. if ( !NT_SUCCESS(status) ||
  511. (oldParmInfo->Parameters.Length != NT_OWF_PASSWORD_LENGTH) ||
  512. (memcmp(oldParmInfo->Parameters.Buffer,
  513. &EMPTY_OWF_PASSWORD,
  514. NT_OWF_PASSWORD_LENGTH)) )
  515. {
  516. fPasswordAvailable = FALSE;
  517. }
  518. if (NT_SUCCESS(status))
  519. {
  520. SamIFree_SAMPR_USER_INFO_BUFFER( (PSAMPR_USER_INFO_BUFFER)oldParmInfo,
  521. UserParametersInformation);
  522. }
  523. if (!fPasswordAvailable)
  524. {
  525. DBGPRINT("ArapChangePassword: password not available\n");
  526. pArapResp->Result = ARAPERR_PASSWD_NOT_AVAILABLE;
  527. LocalFree( Credentials );
  528. SamrCloseHandle( &UserHandle );
  529. return(status);
  530. }
  531. }
  532. // convert to wide-char size
  533. CredentialSize = (CredentialSize/sizeof(WCHAR));
  534. if (CredentialSize > sizeof(OldPwd))
  535. {
  536. DBGPRINT("ArapChangePassword: pwd too long (%d bytes)\n",CredentialSize);
  537. pArapResp->Result = ARAPERR_PASSWORD_TOO_LONG;
  538. LocalFree( Credentials );
  539. SamrCloseHandle( &UserHandle );
  540. return(STATUS_WRONG_PASSWORD);
  541. }
  542. wcstombs(OldPwd, Credentials, CredentialSize);
  543. SecureZeroMemory( Credentials, CredentialSize );
  544. LocalFree( Credentials );
  545. }
  546. //
  547. // we are not running on the DS, but on a Standalone (workgroup) box. We need to
  548. // retrieve the cleartext pwd differently
  549. //
  550. else
  551. {
  552. // get the user parms
  553. status = SamrQueryInformationUser( UserHandle,
  554. UserAllInformation,
  555. (PSAMPR_USER_INFO_BUFFER *)&UserParmInfo);
  556. if (!NT_SUCCESS(status))
  557. {
  558. DBGPRINT("ARAPSubAuth: SamrQueryInformationUser failed %lx\n",status);
  559. pArapResp->Result = ARAPERR_PASSWD_NOT_AVAILABLE;
  560. SamrCloseHandle( &UserHandle );
  561. return(status);
  562. }
  563. status = IASParmsGetUserPassword(UserParmInfo->Parameters.Buffer,
  564. &UnicodePassword.Buffer);
  565. SamIFree_SAMPR_USER_INFO_BUFFER((PSAMPR_USER_INFO_BUFFER)UserParmInfo,
  566. UserAllInformation);
  567. if ((status != STATUS_SUCCESS) || (UnicodePassword.Buffer == NULL))
  568. {
  569. DBGPRINT("ARAPSubAuth: IASParmsGetUserPassword failed %lx\n",status);
  570. pArapResp->Result = ARAPERR_PASSWD_NOT_AVAILABLE;
  571. SamrCloseHandle( &UserHandle );
  572. return(STATUS_WRONG_PASSWORD);
  573. }
  574. UnicodePassword.MaximumLength =
  575. UnicodePassword.Length = (USHORT)(wcslen(UnicodePassword.Buffer) * sizeof( WCHAR ));
  576. AnsiPassword.Length = AnsiPassword.MaximumLength = sizeof(OldPwd);
  577. AnsiPassword.Buffer = OldPwd;
  578. status = RtlUnicodeStringToAnsiString( &AnsiPassword, &UnicodePassword, FALSE );
  579. SecureZeroMemory(UnicodePassword.Buffer, UnicodePassword.Length);
  580. // we don't need the unicode password anymore
  581. RtlFreeUnicodeString(&UnicodePassword);
  582. if (!NT_SUCCESS(status))
  583. {
  584. DBGPRINT("ARAPSubAuth: RtlUnicodeStringToAnsiString failed %lx\n",status);
  585. pArapResp->Result = ARAPERR_PASSWD_NOT_AVAILABLE;
  586. SamrCloseHandle( &UserHandle );
  587. return(STATUS_UNSUCCESSFUL);
  588. }
  589. }
  590. //
  591. // password change happens differently for ARAP and SFM: in ARAP, the old pwd
  592. // as well as the new pwd are encrypted using the old pwd. In SFM, old pwd is
  593. // encrypted with the new pwd (the first 8 bytes in after username), and the
  594. // new pwd is encrypted with the old pwd (the next 8 bytes)
  595. //
  596. if (fCallerIsArap)
  597. {
  598. //
  599. // first, get the get the old password out (the way Mac knows it)
  600. //
  601. pBufPtr = &pArapSubAuthInfo->ChgPwd.OldMunge[0];
  602. EnterCriticalSection( &ArapDesLock );
  603. DoDesInit(OldPwd, TRUE);
  604. // first 8 bytes of mangled old password
  605. pBufPtr = &pArapSubAuthInfo->ChgPwd.OldMunge[0];
  606. Challenge.high = (*((DWORD *)(pBufPtr)));
  607. pBufPtr += 4;
  608. Challenge.low = (*((DWORD *)(pBufPtr)));
  609. DoTheDESDecrypt((PBYTE)&Challenge);
  610. RtlCopyMemory(MacsOldPwd, (PBYTE)&Challenge, 8);
  611. // next 8 bytes of mangled old password
  612. pBufPtr += 4;
  613. Challenge.high = (*((DWORD *)(pBufPtr)));
  614. pBufPtr += 4;
  615. Challenge.low = (*((DWORD *)(pBufPtr)));
  616. DoTheDESDecrypt((PBYTE)&Challenge);
  617. RtlCopyMemory(MacsOldPwd+8, (PBYTE)&Challenge, 8);
  618. //
  619. // now, get the new password
  620. //
  621. // first 8 bytes of the mangled new password
  622. pBufPtr = &pArapSubAuthInfo->ChgPwd.NewMunge[0];
  623. Challenge.high = (*((DWORD *)(pBufPtr)));
  624. pBufPtr += 4;
  625. Challenge.low = (*((DWORD *)(pBufPtr)));
  626. DoTheDESDecrypt((PBYTE)&Challenge);
  627. RtlCopyMemory(NewPwd, (PBYTE)&Challenge, 8);
  628. // next 8 bytes of the mangled new password
  629. pBufPtr += 4;
  630. Challenge.high = (*((DWORD *)(pBufPtr)));
  631. pBufPtr += 4;
  632. Challenge.low = (*((DWORD *)(pBufPtr)));
  633. DoTheDESDecrypt((PBYTE)&Challenge);
  634. RtlCopyMemory(NewPwd+8, (PBYTE)&Challenge, 8);
  635. DoDesEnd();
  636. LeaveCriticalSection( &ArapDesLock );
  637. MacOldPwdLen = MacsOldPwd[0];
  638. NewPwdLen = NewPwd[0];
  639. FirstByte = 1;
  640. }
  641. else
  642. {
  643. // using old pwd as the key, get the new pwd out
  644. EnterCriticalSection( &ArapDesLock );
  645. DoDesInit(OldPwd, FALSE); // clear low-bit
  646. pBufPtr = &pArapSubAuthInfo->ChgPwd.NewMunge[0];
  647. Challenge.high = (*((DWORD UNALIGNED *)(pBufPtr)));
  648. pBufPtr += 4;
  649. Challenge.low = (*((DWORD UNALIGNED *)(pBufPtr)));
  650. DoTheDESDecrypt((PBYTE)&Challenge);
  651. RtlCopyMemory(NewPwd, (PBYTE)&Challenge, 8);
  652. DoDesEnd();
  653. //
  654. // now, we need to get the old pwd out so that we can make sure the
  655. // guy really had the pwd to begin with
  656. //
  657. DoDesInit(NewPwd, FALSE); // clear low-bit
  658. pBufPtr = &pArapSubAuthInfo->ChgPwd.OldMunge[0];
  659. Challenge.high = (*((DWORD UNALIGNED *)(pBufPtr)));
  660. pBufPtr += 4;
  661. Challenge.low = (*((DWORD UNALIGNED *)(pBufPtr)));
  662. DoTheDESDecrypt((PBYTE)&Challenge);
  663. RtlCopyMemory(MacsOldPwd, (PBYTE)&Challenge, 8);
  664. DoDesEnd();
  665. LeaveCriticalSection( &ArapDesLock );
  666. MacOldPwdLen = (UCHAR)strlen((PBYTE)MacsOldPwd);
  667. NewPwdLen = (UCHAR)strlen((PBYTE)NewPwd);
  668. FirstByte = 0;
  669. }
  670. OldPwdLen = (UCHAR)strlen((PBYTE)OldPwd);
  671. if ((MacOldPwdLen != OldPwdLen) || (MacOldPwdLen > MAX_MAC_PWD_LEN))
  672. {
  673. DBGPRINT("ArapChangePassword: Length mismatch! old len %d, oldMacLen %d\n",
  674. OldPwdLen,MacOldPwdLen);
  675. pArapResp->Result = ARAPERR_PASSWORD_TOO_LONG;
  676. SamrCloseHandle( &UserHandle );
  677. SecureZeroMemory(OldPwd, sizeof(OldPwd));
  678. SecureZeroMemory(MacsOldPwd, sizeof(MacsOldPwd));
  679. SecureZeroMemory(NewPwd, sizeof(NewPwd));
  680. return(STATUS_LOGON_FAILURE);
  681. }
  682. //
  683. // make sure the guy really knew the password to begin with
  684. //
  685. for (i=0; i<MacOldPwdLen ; i++)
  686. {
  687. if (MacsOldPwd[FirstByte+i] != OldPwd[i])
  688. {
  689. // Use only when required
  690. #if 0
  691. DBGPRINT("ArapChgPwd: bad pwd: oldpwd=%s Mac's pwd=%s newpwd=%s\n",
  692. OldPwd,&MacsOldPwd[1],&NewPwd[1]);
  693. #endif
  694. pArapResp->Result = ARAPERR_BAD_PASSWORD;
  695. SamrCloseHandle( &UserHandle );
  696. SecureZeroMemory(OldPwd, sizeof(OldPwd));
  697. SecureZeroMemory(MacsOldPwd, sizeof(MacsOldPwd));
  698. SecureZeroMemory(NewPwd, sizeof(NewPwd));
  699. return(STATUS_LOGON_FAILURE);
  700. }
  701. }
  702. SecureZeroMemory(NtPassword, sizeof(NtPassword));
  703. //
  704. // convert the thing to unicode..
  705. // first byte in newpwd is length of the passwd
  706. //
  707. mbstowcs(NtPassword, &NewPwd[FirstByte], NewPwdLen);
  708. NtPassword[NewPwdLen] = 0;
  709. SecureZeroMemory( &UserAllInfo, sizeof(UserAllInfo) );
  710. UserAllInfo.UserName.Length = UserName.Length;
  711. UserAllInfo.UserName.MaximumLength = UserName.MaximumLength;
  712. UserAllInfo.UserName.Buffer = UserName.Buffer;
  713. UserAllInfo.WhichFields = USER_ALL_NTPASSWORDPRESENT;
  714. UserAllInfo.NtPassword.Length = wcslen(NtPassword) * sizeof(WCHAR);
  715. UserAllInfo.NtPassword.MaximumLength = wcslen(NtPassword) * sizeof(WCHAR);
  716. UserAllInfo.NtPassword.Buffer = NtPassword;
  717. status = SamrSetInformationUser( UserHandle,
  718. UserAllInformation,
  719. (PSAMPR_USER_INFO_BUFFER)&UserAllInfo);
  720. SamrCloseHandle( &UserHandle );
  721. //
  722. // wipe out all the clear-text passwords
  723. //
  724. SecureZeroMemory(OldPwd, sizeof(OldPwd));
  725. SecureZeroMemory(NewPwd, sizeof(NewPwd));
  726. SecureZeroMemory((PUCHAR)NtPassword, sizeof(NtPassword));
  727. if (status != STATUS_SUCCESS)
  728. {
  729. DBGPRINT("ARAPSubAuth: SamrSetInfo.. failed %lx\n",status);
  730. pArapResp->Result = ARAPERR_SET_PASSWD_FAILED;
  731. return(STATUS_UNSUCCESSFUL);
  732. }
  733. pArapResp->Result = ARAPERR_NO_ERROR;
  734. return(STATUS_SUCCESS);
  735. }
  736. NTSTATUS
  737. ArapGetSamHandle(
  738. IN PVOID *pUserHandle,
  739. IN PUNICODE_STRING pUserName
  740. )
  741. /*++
  742. Routine Description:
  743. This routine gets sam handle to the specified user (when we get into the
  744. subauth pkg for a password change, we don't have user's sam handle).
  745. Arguments:
  746. pUserHandle - sam handle, on return
  747. pUserName - name of the user in question
  748. Return Value:
  749. STATUS_SUCCESS: if handle retrieved successfully,
  750. appropriate error otherwise
  751. --*/
  752. {
  753. NTSTATUS status;
  754. PLSAPR_POLICY_INFORMATION PolicyInfo = NULL;
  755. SAMPR_HANDLE SamHandle = NULL;
  756. SAMPR_HANDLE DomainHandle = NULL;
  757. SAMPR_ULONG_ARRAY RidArray;
  758. SAMPR_ULONG_ARRAY UseArray;
  759. RidArray.Element = NULL;
  760. UseArray.Element = NULL;
  761. status = LsaIQueryInformationPolicyTrusted(
  762. PolicyAccountDomainInformation,
  763. &PolicyInfo);
  764. if (status != STATUS_SUCCESS)
  765. {
  766. DBGPRINT("ArapGetSamHandle: LsaI...Trusted failed with %lx\n", status);
  767. goto ArapGetSamHandle_Exit;
  768. }
  769. status = SamIConnect(
  770. NULL, // no server name
  771. &SamHandle,
  772. 0, // no desired access
  773. TRUE // trusted caller
  774. );
  775. if (status != STATUS_SUCCESS)
  776. {
  777. DBGPRINT("ArapGetSamHandle: SamIConnect failed with %lx\n", status);
  778. goto ArapGetSamHandle_Exit;
  779. }
  780. status = SamrOpenDomain(
  781. SamHandle,
  782. 0, // no desired access
  783. (PRPC_SID) PolicyInfo->PolicyAccountDomainInfo.DomainSid,
  784. &DomainHandle);
  785. if (status != STATUS_SUCCESS)
  786. {
  787. DBGPRINT("ArapGetSamHandle: SamrOpenDomain failed with %lx\n", status);
  788. goto ArapGetSamHandle_Exit;
  789. }
  790. status = SamrLookupNamesInDomain(
  791. DomainHandle,
  792. 1,
  793. (PRPC_UNICODE_STRING) pUserName,
  794. &RidArray,
  795. &UseArray);
  796. if (status != STATUS_SUCCESS)
  797. {
  798. DBGPRINT("ArapGetSamHandle: Samr..Domain failed with %lx\n", status);
  799. goto ArapGetSamHandle_Exit;
  800. }
  801. if (UseArray.Element[0] != SidTypeUser)
  802. {
  803. DBGPRINT("ArapGetSamHandle: didn't find our user\n");
  804. goto ArapGetSamHandle_Exit;
  805. }
  806. //
  807. // Finally open the user
  808. //
  809. status = SamrOpenUser(
  810. DomainHandle,
  811. 0, // no desired access,
  812. RidArray.Element[0],
  813. pUserHandle);
  814. if (status != STATUS_SUCCESS)
  815. {
  816. DBGPRINT("ArapGetSamHandle: SamrOpenUser failed with %lx\n", status);
  817. goto ArapGetSamHandle_Exit;
  818. }
  819. ArapGetSamHandle_Exit:
  820. if (DomainHandle != NULL)
  821. {
  822. SamrCloseHandle( &DomainHandle );
  823. }
  824. if (SamHandle != NULL)
  825. {
  826. SamrCloseHandle( &SamHandle );
  827. }
  828. if (PolicyInfo != NULL)
  829. {
  830. LsaIFree_LSAPR_POLICY_INFORMATION(
  831. PolicyAccountDomainInformation,
  832. PolicyInfo);
  833. }
  834. SamIFree_SAMPR_ULONG_ARRAY( &UseArray );
  835. SamIFree_SAMPR_ULONG_ARRAY( &RidArray );
  836. return(status);
  837. }
  838. NTSTATUS
  839. DeltaNotify(
  840. IN PSID DomainSid,
  841. IN SECURITY_DB_DELTA_TYPE DeltaType,
  842. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  843. IN ULONG ObjectRid,
  844. IN OPTIONAL PUNICODE_STRING ObjectName,
  845. IN PLARGE_INTEGER ModifiedCount,
  846. IN PSAM_DELTA_DATA DeltaData
  847. )
  848. {
  849. DWORD dwRetCode;
  850. AFP_SERVER_HANDLE hAfpServer;
  851. AFP_SERVER_INFO afpInfo;
  852. // ignore any changes other than those to user
  853. if (ObjectType != SecurityDbObjectSamUser)
  854. {
  855. return(STATUS_SUCCESS);
  856. }
  857. // we only care about guest account: ignore the notification for other users
  858. if (ObjectRid != DOMAIN_USER_RID_GUEST)
  859. {
  860. return(STATUS_SUCCESS);
  861. }
  862. // enable/disable of guest account is all that's interesting to us
  863. if (DeltaType != SecurityDbChange)
  864. {
  865. return(STATUS_SUCCESS);
  866. }
  867. // if there is no DeltaData, account enable/disable hasn't been affected
  868. if (!DeltaData)
  869. {
  870. return(STATUS_SUCCESS);
  871. }
  872. //
  873. // ok, looks like Guest account was enabled (or disabled). Connect to the
  874. // SFM service on this machine. If we fail, that means SFM is not started
  875. // In that case, ignore this change
  876. //
  877. dwRetCode = AfpAdminConnect(NULL, &hAfpServer);
  878. // if we couldn't connect, don't bother: just ignore this notification
  879. if (dwRetCode != NO_ERROR)
  880. {
  881. DBGPRINT("DeltaNotify: AfpAdminConnect failed, dwRetCode = %ld\n",dwRetCode);
  882. return(STATUS_SUCCESS);
  883. }
  884. SecureZeroMemory(&afpInfo, sizeof(AFP_SERVER_INFO));
  885. //
  886. // find out if the guest account is enabled or disabled and set the flag
  887. // appropriately
  888. //
  889. if (!(DeltaData->AccountControl & USER_ACCOUNT_DISABLED))
  890. {
  891. afpInfo.afpsrv_options = AFP_SRVROPT_GUESTLOGONALLOWED;
  892. }
  893. dwRetCode = AfpAdminServerSetInfo(hAfpServer,
  894. (LPBYTE)&afpInfo,
  895. AFP_SERVER_GUEST_ACCT_NOTIFY);
  896. AfpAdminDisconnect(hAfpServer);
  897. return(STATUS_SUCCESS);
  898. }