Source code of Windows XP (NT5)
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.

740 lines
20 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. client.c
  5. Abstract:
  6. This module contains the client impersonation code.
  7. Author:
  8. Jameel Hyder (microsoft!jameelh)
  9. Revision History:
  10. 16 Jun 1992 Initial Version
  11. Notes: Tab stop: 4
  12. --*/
  13. #define FILENUM FILE_CLIENT
  14. #include <afp.h>
  15. #include <client.h>
  16. #include <access.h>
  17. #include <secutil.h>
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text( PAGE, AfpImpersonateClient)
  20. #pragma alloc_text( PAGE, AfpRevertBack)
  21. #pragma alloc_text( PAGE, AfpGetChallenge)
  22. #pragma alloc_text( PAGE, AfpLogonUser)
  23. #endif
  24. /*** AfpImpersonateClient
  25. *
  26. * Impersonates the remote client. The token representing the remote client
  27. * is available in the SDA. If the SDA is NULL (i.e. server context) then
  28. * impersonate the token that we have created for ourselves.
  29. */
  30. VOID
  31. AfpImpersonateClient(
  32. IN PSDA pSda OPTIONAL
  33. )
  34. {
  35. NTSTATUS Status = STATUS_SUCCESS;
  36. HANDLE Token;
  37. PAGED_CODE( );
  38. if (pSda != NULL)
  39. {
  40. Token = pSda->sda_UserToken;
  41. }
  42. else Token = AfpFspToken;
  43. ASSERT(Token != NULL);
  44. Status = NtSetInformationThread(NtCurrentThread(),
  45. ThreadImpersonationToken,
  46. (PVOID)&Token,
  47. sizeof(Token));
  48. ASSERT(NT_SUCCESS(Status));
  49. }
  50. /*** AfpRevertBack
  51. *
  52. * Revert back to the default thread context.
  53. */
  54. VOID
  55. AfpRevertBack(
  56. VOID
  57. )
  58. {
  59. NTSTATUS Status = STATUS_SUCCESS;
  60. HANDLE Handle = NULL;
  61. PAGED_CODE( );
  62. Status = NtSetInformationThread(NtCurrentThread(),
  63. ThreadImpersonationToken,
  64. (PVOID)&Handle,
  65. sizeof(Handle));
  66. ASSERT(NT_SUCCESS(Status));
  67. }
  68. /*** AfpGetChallenge
  69. *
  70. * Obtain a challenge token from the MSV1_0 package. This token is used by
  71. * AfpLogin call.
  72. *
  73. * The following function modified so that we generate the challenge ourselves
  74. * instead of making a call. This routine borrowed almost verbatim from
  75. * the LM server code.
  76. */
  77. PBYTE
  78. AfpGetChallenge(
  79. IN VOID
  80. )
  81. {
  82. PMSV1_0_LM20_CHALLENGE_REQUEST ChallengeRequest;
  83. PMSV1_0_LM20_CHALLENGE_RESPONSE ChallengeResponse;
  84. ULONG Length;
  85. PBYTE pRetBuf;
  86. NTSTATUS Status, StatusX;
  87. union
  88. {
  89. LARGE_INTEGER time;
  90. UCHAR bytes[8];
  91. } u;
  92. ULONG seed;
  93. ULONG challenge[2];
  94. ULONG result3;
  95. PAGED_CODE( );
  96. ChallengeRequest = NULL;
  97. //
  98. // Create a pseudo-random 8-byte number by munging the system time
  99. // for use as a random number seed.
  100. //
  101. // Start by getting the system time.
  102. //
  103. ASSERT( MSV1_0_CHALLENGE_LENGTH == 2 * sizeof(ULONG) );
  104. KeQuerySystemTime( &u.time );
  105. //
  106. // To ensure that we don't use the same system time twice, add in the
  107. // count of the number of times this routine has been called. Then
  108. // increment the counter.
  109. //
  110. // *** Since we don't use the low byte of the system time (it doesn't
  111. // take on enough different values, because of the timer
  112. // resolution), we increment the counter by 0x100.
  113. //
  114. // *** We don't interlock the counter because we don't really care
  115. // if it's not 100% accurate.
  116. //
  117. u.time.LowPart += EncryptionKeyCount;
  118. EncryptionKeyCount += 0x100;
  119. //
  120. // Now use parts of the system time as a seed for the random
  121. // number generator.
  122. //
  123. // *** Because the middle two bytes of the low part of the system
  124. // time change most rapidly, we use those in forming the seed.
  125. //
  126. seed = ((u.bytes[1] + 1) << 0) |
  127. ((u.bytes[2] + 0) << 8) |
  128. ((u.bytes[2] - 1) << 16) |
  129. ((u.bytes[1] + 0) << 24);
  130. //
  131. // Now get two random numbers. RtlRandom does not return negative
  132. // numbers, so we pseudo-randomly negate them.
  133. //
  134. challenge[0] = RtlRandom( &seed );
  135. challenge[1] = RtlRandom( &seed );
  136. result3 = RtlRandom( &seed );
  137. if ( (result3 & 0x1) != 0 )
  138. {
  139. challenge[0] |= 0x80000000;
  140. }
  141. if ( (result3 & 0x2) != 0 )
  142. {
  143. challenge[1] |= 0x80000000;
  144. }
  145. // Allocate a buffer to hold the challenge and copy it in
  146. if ((pRetBuf = AfpAllocNonPagedMemory(MSV1_0_CHALLENGE_LENGTH)) != NULL)
  147. {
  148. RtlCopyMemory(pRetBuf, challenge, MSV1_0_CHALLENGE_LENGTH);
  149. }
  150. return (pRetBuf);
  151. }
  152. /*** AfpLogonUser
  153. *
  154. * Attempt to login the user. The password is either encrypted or cleartext
  155. * based on the UAM used. The UserName and domain is extracted out of the Sda.
  156. *
  157. * LOCKS: AfpStatisticsLock (SPIN)
  158. */
  159. AFPSTATUS
  160. AfpLogonUser(
  161. IN PSDA pSda,
  162. IN PANSI_STRING UserPasswd
  163. )
  164. {
  165. NTSTATUS Status, SubStatus;
  166. PUNICODE_STRING WSName;
  167. ULONG ulUnused;
  168. ULONG NtlmInTokenSize;
  169. PNTLM_AUTHENTICATE_MESSAGE NtlmInToken = NULL;
  170. PAUTHENTICATE_MESSAGE InToken = NULL;
  171. ULONG InTokenSize;
  172. PNTLM_ACCEPT_RESPONSE OutToken = NULL;
  173. ULONG OutTokenSize;
  174. SIZE_T AllocateSize;
  175. SecBufferDesc InputToken;
  176. SecBuffer InputBuffers[2];
  177. SecBufferDesc OutputToken;
  178. SecBuffer OutputBuffer;
  179. CtxtHandle hNewContext;
  180. TimeStamp Expiry;
  181. ULONG BufferOffset;
  182. PCHAR pTmp;
  183. PRAS_SUBAUTH_INFO pRasSubAuthInfo;
  184. PARAP_SUBAUTH_REQ pSfmSubAuthInfo;
  185. PARAP_SUBAUTH_RESP pSfmResp;
  186. DWORD ResponseHigh;
  187. DWORD ResponseLow;
  188. DWORD dwTmpLen;
  189. PAGED_CODE( );
  190. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  191. #ifdef OPTIMIZE_GUEST_LOGONS
  192. // 11/28/94 SueA: Now that there is a License Service to track the number
  193. // of sessions via LsaLogonUser, we can no longer fake the guest tokens.
  194. // Optimization for subsequent guest logons
  195. // After the first guest logon, we save the token and do not free it till the
  196. // server stops. All subsequent guest logons 'share' that token.
  197. if (pSda->sda_ClientType == SDA_CLIENT_GUEST)
  198. {
  199. AfpSwmrAcquireExclusive(&AfpEtcMapLock);
  200. if (AfpGuestToken != NULL)
  201. {
  202. pSda->sda_UserToken = AfpGuestToken;
  203. pSda->sda_UserSid = &AfpSidWorld;
  204. pSda->sda_GroupSid = &AfpSidWorld; // Primary group of Guest is also 'World'
  205. #ifdef INHERIT_DIRECTORY_PERMS
  206. pSda->sda_UID = AfpIdWorld;
  207. pSda->sda_GID = AfpIdWorld;
  208. #else
  209. ASSERT (AfpGuestSecDesc != NULL);
  210. pSda->sda_pSecDesc = AfpGuestSecDesc;
  211. #endif
  212. AfpSwmrRelease(&AfpEtcMapLock);
  213. return AFP_ERR_NONE;
  214. }
  215. else
  216. {
  217. AfpSwmrRelease(&AfpEtcMapLock);
  218. }
  219. }
  220. #endif // OPTIMIZE_GUEST_LOGONS
  221. WSName = &AfpDefaultWksta;
  222. if (pSda->sda_WSName.Length != 0)
  223. WSName = &pSda->sda_WSName;
  224. //
  225. // Figure out how big a buffer we need. We put all the messages
  226. // in one buffer for efficiency's sake.
  227. //
  228. NtlmInTokenSize = sizeof(NTLM_AUTHENTICATE_MESSAGE);
  229. // alignment needs to be correct based on 32/64 bit addressing!!!
  230. NtlmInTokenSize = (NtlmInTokenSize + 7) & 0xfffffff8;
  231. InTokenSize = sizeof(AUTHENTICATE_MESSAGE) +
  232. pSda->sda_UserName.Length +
  233. WSName->Length +
  234. (sizeof(RAS_SUBAUTH_INFO) + sizeof(ARAP_SUBAUTH_REQ)) +
  235. pSda->sda_DomainName.Length +
  236. UserPasswd->Length +
  237. 24; // extra for byte aligning
  238. InTokenSize = (InTokenSize + 7) & 0xfffffff8;
  239. OutTokenSize = sizeof(NTLM_ACCEPT_RESPONSE);
  240. OutTokenSize = (OutTokenSize + 7) & 0xfffffff8;
  241. //
  242. // Round this up to 8 byte boundary becaus the out token needs to be
  243. // quad word aligned for the LARGE_INTEGER.
  244. //
  245. AllocateSize = ((NtlmInTokenSize + InTokenSize + 7) & 0xfffffff8) + OutTokenSize;
  246. Status = NtAllocateVirtualMemory(NtCurrentProcess(),
  247. &InToken,
  248. 0L,
  249. &AllocateSize,
  250. MEM_COMMIT,
  251. PAGE_READWRITE);
  252. if (!NT_SUCCESS(Status))
  253. {
  254. AFPLOG_ERROR(AFPSRVMSG_PAGED_POOL, Status, &AllocateSize,sizeof(AllocateSize), NULL);
  255. #if DBG
  256. DbgBreakPoint();
  257. #endif
  258. return(AFP_ERR_MISC);
  259. }
  260. NtlmInToken = (PNTLM_AUTHENTICATE_MESSAGE) ((PUCHAR) InToken + InTokenSize);
  261. OutToken = (PNTLM_ACCEPT_RESPONSE) ((PUCHAR)NtlmInToken + ((NtlmInTokenSize + 7) & 0xfffffff8));
  262. RtlZeroMemory(InToken, InTokenSize + NtlmInTokenSize);
  263. //
  264. // set up the NtlmInToken first
  265. //
  266. if (pSda->sda_Challenge)
  267. {
  268. RtlCopyMemory(NtlmInToken->ChallengeToClient,
  269. pSda->sda_Challenge,
  270. MSV1_0_CHALLENGE_LENGTH );
  271. }
  272. if ((pSda->sda_ClientType == SDA_CLIENT_RANDNUM) ||
  273. (pSda->sda_ClientType == SDA_CLIENT_TWOWAY))
  274. {
  275. NtlmInToken->ParameterControl = (MSV1_0_SUBAUTHENTICATION_DLL_RAS << 24);
  276. }
  277. else
  278. {
  279. NtlmInToken->ParameterControl = 0;
  280. }
  281. //
  282. // Okay, now for the tought part - marshalling the AUTHENTICATE_MESSAGE
  283. //
  284. RtlCopyMemory(InToken->Signature,
  285. NTLMSSP_SIGNATURE,
  286. sizeof(NTLMSSP_SIGNATURE) );
  287. InToken->MessageType = NtLmAuthenticate;
  288. BufferOffset = sizeof(AUTHENTICATE_MESSAGE);
  289. //
  290. // LM password - case insensitive
  291. //
  292. pTmp = (PBYTE)InToken + BufferOffset;
  293. *(LPWSTR)pTmp = L'\0';
  294. InToken->LmChallengeResponse.Buffer = BufferOffset;
  295. InToken->LmChallengeResponse.Length = 1;
  296. InToken->LmChallengeResponse.MaximumLength = sizeof(WCHAR);
  297. InToken->NtChallengeResponse.Buffer = BufferOffset;
  298. InToken->NtChallengeResponse.Length = 0;
  299. InToken->NtChallengeResponse.MaximumLength = sizeof(WCHAR);
  300. InToken->DomainName.Buffer = BufferOffset;
  301. InToken->DomainName.Length = 0;
  302. InToken->DomainName.MaximumLength = sizeof(WCHAR);
  303. InToken->Workstation.Buffer = BufferOffset;
  304. InToken->Workstation.Length = 0;
  305. InToken->Workstation.MaximumLength = sizeof(WCHAR);
  306. InToken->UserName.Buffer = BufferOffset;
  307. InToken->UserName.Length = 0;
  308. InToken->UserName.MaximumLength = sizeof(WCHAR);
  309. if (pSda->sda_UserName.Length != 0)
  310. {
  311. if (pSda->sda_DomainName.Length != 0)
  312. {
  313. InToken->DomainName.Length = pSda->sda_DomainName.Length;
  314. InToken->DomainName.MaximumLength = pSda->sda_DomainName.MaximumLength;
  315. InToken->DomainName.Buffer = BufferOffset;
  316. RtlCopyMemory((PBYTE)InToken + BufferOffset,
  317. (PBYTE)pSda->sda_DomainName.Buffer,
  318. pSda->sda_DomainName.Length);
  319. BufferOffset += pSda->sda_DomainName.Length;
  320. BufferOffset = (BufferOffset + 3) & 0xfffffffc; // dword align it
  321. }
  322. InToken->LmChallengeResponse.Buffer = BufferOffset;
  323. //
  324. // is he using native Apple UAM? setup buffers differently!
  325. //
  326. if ((pSda->sda_ClientType == SDA_CLIENT_RANDNUM) ||
  327. (pSda->sda_ClientType == SDA_CLIENT_TWOWAY))
  328. {
  329. pRasSubAuthInfo =
  330. (PRAS_SUBAUTH_INFO)((PBYTE)InToken + BufferOffset);
  331. pRasSubAuthInfo->ProtocolType = RAS_SUBAUTH_PROTO_ARAP;
  332. pRasSubAuthInfo->DataSize = sizeof(ARAP_SUBAUTH_REQ);
  333. pSfmSubAuthInfo = (PARAP_SUBAUTH_REQ)&pRasSubAuthInfo->Data[0];
  334. if (pSda->sda_ClientType == SDA_CLIENT_RANDNUM)
  335. {
  336. pSfmSubAuthInfo->PacketType = SFM_SUBAUTH_LOGON_PKT;
  337. }
  338. else
  339. {
  340. pSfmSubAuthInfo->PacketType = SFM_2WAY_SUBAUTH_LOGON_PKT;
  341. }
  342. pSfmSubAuthInfo->Logon.fGuestLogon = FALSE;
  343. ASSERT(pSda->sda_Challenge != NULL);
  344. // put the 2 dwords of challenge that we gave the Mac
  345. pTmp = pSda->sda_Challenge;
  346. GETDWORD2DWORD_NOCONV((PBYTE)&pSfmSubAuthInfo->Logon.NTChallenge1,pTmp);
  347. pTmp += sizeof(DWORD);
  348. GETDWORD2DWORD_NOCONV((PBYTE)&pSfmSubAuthInfo->Logon.NTChallenge2,pTmp);
  349. // put the 2 dwords of response that the Mac gave us
  350. pTmp = UserPasswd->Buffer;
  351. GETDWORD2DWORD_NOCONV((PBYTE)&pSfmSubAuthInfo->Logon.MacResponse1,pTmp);
  352. pTmp += sizeof(DWORD);
  353. GETDWORD2DWORD_NOCONV((PBYTE)&pSfmSubAuthInfo->Logon.MacResponse2,pTmp);
  354. // 2-way guy sends his own challenge: doesn't trust us!
  355. if (pSda->sda_ClientType == SDA_CLIENT_TWOWAY)
  356. {
  357. pTmp += sizeof(DWORD);
  358. GETDWORD2DWORD_NOCONV((PBYTE)&pSfmSubAuthInfo->Logon.MacChallenge1,pTmp);
  359. pTmp += sizeof(DWORD);
  360. GETDWORD2DWORD_NOCONV((PBYTE)&pSfmSubAuthInfo->Logon.MacChallenge2,pTmp);
  361. }
  362. dwTmpLen = (sizeof(RAS_SUBAUTH_INFO) + sizeof(ARAP_SUBAUTH_REQ));
  363. InToken->LmChallengeResponse.Length = (USHORT)dwTmpLen;
  364. InToken->LmChallengeResponse.MaximumLength = (USHORT)dwTmpLen;
  365. BufferOffset += dwTmpLen;
  366. }
  367. //
  368. // this client is using MS-UAM or Apple's cleartext
  369. //
  370. else
  371. {
  372. InToken->LmChallengeResponse.Length = UserPasswd->Length;
  373. InToken->LmChallengeResponse.MaximumLength = UserPasswd->MaximumLength;
  374. RtlCopyMemory( (PBYTE)InToken + BufferOffset,
  375. UserPasswd->Buffer,
  376. UserPasswd->Length );
  377. BufferOffset += UserPasswd->Length;
  378. }
  379. BufferOffset = (BufferOffset + 3) & 0xfffffffc; // dword align it
  380. //
  381. // Workstation Name
  382. //
  383. InToken->Workstation.Buffer = BufferOffset;
  384. InToken->Workstation.Length = WSName->Length;
  385. InToken->Workstation.MaximumLength = WSName->MaximumLength;
  386. RtlCopyMemory((PBYTE)InToken + BufferOffset,
  387. WSName->Buffer,
  388. WSName->Length);
  389. BufferOffset += WSName->Length;
  390. BufferOffset = (BufferOffset + 3) & 0xfffffffc; // dword align it
  391. //
  392. // User Name
  393. //
  394. InToken->UserName.Buffer = BufferOffset;
  395. InToken->UserName.Length = pSda->sda_UserName.Length;
  396. InToken->UserName.MaximumLength = pSda->sda_UserName.MaximumLength;
  397. RtlCopyMemory((PBYTE)InToken + BufferOffset,
  398. pSda->sda_UserName.Buffer,
  399. pSda->sda_UserName.Length);
  400. BufferOffset += pSda->sda_UserName.Length;
  401. }
  402. InputToken.pBuffers = InputBuffers;
  403. InputToken.cBuffers = 2;
  404. InputToken.ulVersion = 0;
  405. InputBuffers[0].pvBuffer = InToken;
  406. InputBuffers[0].cbBuffer = InTokenSize;
  407. InputBuffers[0].BufferType = SECBUFFER_TOKEN;
  408. InputBuffers[1].pvBuffer = NtlmInToken;
  409. InputBuffers[1].cbBuffer = NtlmInTokenSize;
  410. InputBuffers[1].BufferType = SECBUFFER_TOKEN;
  411. OutputToken.pBuffers = &OutputBuffer;
  412. OutputToken.cBuffers = 1;
  413. OutputToken.ulVersion = 0;
  414. OutputBuffer.pvBuffer = OutToken;
  415. OutputBuffer.cbBuffer = OutTokenSize;
  416. OutputBuffer.BufferType = SECBUFFER_TOKEN;
  417. Status = AcceptSecurityContext(&AfpSecHandle,
  418. NULL,
  419. &InputToken,
  420. ASC_REQ_LICENSING,
  421. SECURITY_NATIVE_DREP,
  422. &hNewContext,
  423. &OutputToken,
  424. &ulUnused,
  425. &Expiry );
  426. if (NT_SUCCESS(Status))
  427. {
  428. AFPTIME CurrentTime;
  429. NTSTATUS SecStatus;
  430. if (pSda->sda_ClientType != SDA_CLIENT_GUEST)
  431. {
  432. SecPkgContext_PasswordExpiry PasswordExpires;
  433. // Get the kickoff time from the profile buffer. Round this to
  434. // even # of SESSION_CHECK_TIME units
  435. SecStatus = QueryContextAttributes(
  436. &hNewContext,
  437. SECPKG_ATTR_PASSWORD_EXPIRY,
  438. &PasswordExpires
  439. );
  440. if( SecStatus == NO_ERROR )
  441. {
  442. AfpGetCurrentTimeInMacFormat(&CurrentTime);
  443. pSda->sda_tTillKickOff = (DWORD)
  444. ( AfpConvertTimeToMacFormat(&PasswordExpires.tsPasswordExpires) -
  445. CurrentTime );
  446. pSda->sda_tTillKickOff -= pSda->sda_tTillKickOff % SESSION_CHECK_TIME;
  447. }
  448. else
  449. {
  450. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  451. ("AfpLogonUser: QueryContextAttributes failed %lx\n",SecStatus));
  452. }
  453. }
  454. // return stuff from subauth
  455. pSfmResp = (PARAP_SUBAUTH_RESP)&OutToken->UserSessionKey[0];
  456. ResponseHigh = pSfmResp->Response.high;
  457. ResponseLow = pSfmResp->Response.low;
  458. SubStatus = NtFreeVirtualMemory(NtCurrentProcess( ),
  459. (PVOID *)&InToken,
  460. &AllocateSize,
  461. MEM_RELEASE);
  462. ASSERT(NT_SUCCESS(SubStatus));
  463. //
  464. // 2-Way authentication? client expects us to send a response to
  465. // the challenge that it sent
  466. //
  467. if (pSda->sda_ClientType == SDA_CLIENT_TWOWAY)
  468. {
  469. pSda->sda_ReplySize = RANDNUM_RESP_LEN;
  470. if (AfpAllocReplyBuf(pSda) != AFP_ERR_NONE)
  471. {
  472. return(AFP_ERR_USER_NOT_AUTH);
  473. }
  474. pTmp = pSda->sda_ReplyBuf;
  475. PUTBYTE42BYTE4(pTmp, (PBYTE)&ResponseHigh);
  476. pTmp += sizeof(DWORD);
  477. PUTBYTE42BYTE4(pTmp, (PBYTE)&ResponseLow);
  478. }
  479. else if (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V2)
  480. {
  481. pSda->sda_ReplySize = sizeof(DWORD);
  482. if (AfpAllocReplyBuf(pSda) != AFP_ERR_NONE)
  483. {
  484. return(AFP_ERR_USER_NOT_AUTH);
  485. }
  486. pTmp = pSda->sda_ReplyBuf;
  487. PUTBYTE42BYTE4(pTmp, (PBYTE)&pSda->sda_tTillKickOff);
  488. }
  489. }
  490. else // if (NT_SUCCESS(Status) != NO_ERROR)
  491. {
  492. NTSTATUS ExtErrCode = Status;
  493. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  494. ("AfpLogonUser: AcceptSecurityContext() failed with %X\n", Status));
  495. SubStatus = NtFreeVirtualMemory(NtCurrentProcess(),
  496. (PVOID *)&InToken,
  497. &AllocateSize,
  498. MEM_RELEASE );
  499. ASSERT(NT_SUCCESS(SubStatus));
  500. // Set extended error codes here if using custom UAM or AFP 2.1
  501. Status = AFP_ERR_USER_NOT_AUTH; // default
  502. // The mac will map this to a session error dialog for each UAM.
  503. // The dialog may be a little different for different versions of
  504. // the mac OS and each UAM, but will always have something to do
  505. // with getting the message across about no more sessions available.
  506. if (ExtErrCode == STATUS_LICENSE_QUOTA_EXCEEDED)
  507. {
  508. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  509. ("AfpLogonUser: License Quota Exceeded: returning ASP_SERVER_BUSY\n"));
  510. return (ASP_SERVER_BUSY);
  511. }
  512. if ((pSda->sda_ClientVersion >= AFP_VER_21) &&
  513. (pSda->sda_ClientType != SDA_CLIENT_MSUAM_V2) &&
  514. (pSda->sda_ClientType != SDA_CLIENT_MSUAM_V2))
  515. {
  516. if ((ExtErrCode == STATUS_PASSWORD_EXPIRED) ||
  517. (ExtErrCode == STATUS_PASSWORD_MUST_CHANGE))
  518. Status = AFP_ERR_PWD_EXPIRED;
  519. }
  520. else if ((pSda->sda_ClientType == SDA_CLIENT_MSUAM_V1) ||
  521. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V2))
  522. {
  523. if ((ExtErrCode == STATUS_PASSWORD_EXPIRED) ||
  524. (ExtErrCode == STATUS_PASSWORD_MUST_CHANGE))
  525. Status = AFP_ERR_PASSWORD_EXPIRED;
  526. else if ((ExtErrCode == STATUS_ACCOUNT_DISABLED) ||
  527. (ExtErrCode == STATUS_ACCOUNT_LOCKED_OUT))
  528. Status = AFP_ERR_ACCOUNT_DISABLED;
  529. else if (ExtErrCode == STATUS_INVALID_LOGON_HOURS)
  530. Status = AFP_ERR_INVALID_LOGON_HOURS;
  531. else if (ExtErrCode == STATUS_INVALID_WORKSTATION)
  532. Status = AFP_ERR_INVALID_WORKSTATION;
  533. }
  534. return( Status );
  535. }
  536. //
  537. // get the token out using the context
  538. //
  539. Status = QuerySecurityContextToken( &hNewContext, &pSda->sda_UserToken );
  540. if (!NT_SUCCESS(Status))
  541. {
  542. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  543. ("AfpLogonUser: QuerySecurityContextToken() failed with %X\n", Status));
  544. pSda->sda_UserToken = NULL; // just paranoia
  545. return(Status);
  546. }
  547. Status = DeleteSecurityContext( &hNewContext );
  548. if (!NT_SUCCESS(Status))
  549. {
  550. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  551. ("AfpLogonUser: DeleteSecurityContext() failed with %X\n", Status));
  552. }
  553. Status = AfpGetUserAndPrimaryGroupSids(pSda);
  554. if (!NT_SUCCESS(Status))
  555. {
  556. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  557. ("AfpLogonUser: AfpGetUserAndPrimaryGroupSids() failed with %X\n", Status));
  558. AFPLOG_ERROR(AFPSRVMSG_LOGON, Status, NULL, 0, NULL);
  559. return( Status );
  560. }
  561. #ifdef INHERIT_DIRECTORY_PERMS
  562. // Convert the user and group sids to IDs
  563. AfpSidToMacId(pSda->sda_UserSid, &pSda->sda_UID);
  564. AfpSidToMacId(pSda->sda_GroupSid, &pSda->sda_GID);
  565. #else
  566. // Make a security descriptor for user
  567. Status = AfpMakeSecurityDescriptorForUser(pSda->sda_UserSid,
  568. pSda->sda_GroupSid,
  569. &pSda->sda_pSecDesc);
  570. #endif
  571. #ifdef OPTIMIZE_GUEST_LOGONS
  572. if (pSda->sda_ClientType == SDA_CLIENT_GUEST)
  573. {
  574. // Save the guest login token and security descriptor
  575. AfpSwmrAcquireExclusive(&AfpEtcMapLock);
  576. AfpGuestToken = pSda->sda_UserToken;
  577. #ifdef INHERIT_DIRECTORY_PERMS
  578. AfpSidToMacId(&AfpSidWorld, &AfpIdWorld);
  579. #else
  580. AfpGuestSecDesc = pSda->sda_pSecDesc;
  581. #endif
  582. AfpSwmrRelease(&AfpEtcMapLock);
  583. }
  584. #endif // OPTIMIZE_GUEST_LOGONS
  585. return Status;
  586. }