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.

1596 lines
53 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. fsp_srv.c
  5. Abstract:
  6. This module contains the entry points for the AFP server APIs queued to
  7. the FSP. These are all callable from FSP Only.
  8. Author:
  9. Jameel Hyder (microsoft!jameelh)
  10. Revision History:
  11. 25 Apr 1992 Initial Version
  12. Notes: Tab stop: 4
  13. --*/
  14. #define FILENUM FILE_FSP_SRV
  15. #include <afp.h>
  16. #include <gendisp.h>
  17. #include <client.h>
  18. #include <scavengr.h>
  19. #include <secutil.h>
  20. LOCAL BOOLEAN
  21. afpGetUserNameAndPwdOrWSName(
  22. IN PANSI_STRING Block,
  23. IN BOOLEAN Password,
  24. OUT PUNICODE_STRING pUserName,
  25. OUT PUNICODE_STRING pDomainName,
  26. OUT PVOID pParm
  27. );
  28. LOCAL BOOLEAN
  29. afpGetNameAndDomain(
  30. IN PANSI_STRING pDomainNUser,
  31. OUT PUNICODE_STRING pUserName,
  32. OUT PUNICODE_STRING pDomainName
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text( PAGE, AfpFspDispLogin)
  36. #pragma alloc_text( PAGE, AfpFspDispLoginCont)
  37. #pragma alloc_text( PAGE, AfpFspDispLogout)
  38. #pragma alloc_text( PAGE, AfpFspDispChangePassword)
  39. #pragma alloc_text( PAGE, AfpFspDispMapName)
  40. #pragma alloc_text( PAGE, AfpFspDispMapId)
  41. #pragma alloc_text( PAGE, AfpFspDispGetUserInfo)
  42. #pragma alloc_text( PAGE, afpGetUserNameAndPwdOrWSName)
  43. #pragma alloc_text( PAGE, afpGetNameAndDomain)
  44. #endif
  45. /*** AfpFspDispLogin
  46. *
  47. * This is the worker routine for the AfpLogin API.
  48. *
  49. * The request packet is represented below.
  50. *
  51. * sda_Name1 ANSI_STRING AFP Version
  52. * sda_Name2 ANSI_STRING UAM String
  53. * sda_Name3 BLOCK Depends on the UAM used
  54. * NO_USER_AUTHENT Not used
  55. * CLEAR_TEXT_AUTHENT User Name & Password string
  56. * CUSTOM_UAM User Name & Machine Name
  57. * Both the ClearText and the Custom UAM case are treated identically
  58. * except for validation.
  59. *
  60. * LOCKS: sda_Lock (SPIN)
  61. */
  62. AFPSTATUS FASTCALL
  63. AfpFspDispLogin(
  64. IN PSDA pSda
  65. )
  66. {
  67. LONG i;
  68. ANSI_STRING UserPasswd;
  69. PSID GuestSid = NULL;
  70. BOOLEAN fGuestLogon = FALSE;
  71. BOOLEAN fKillSession = FALSE;
  72. AFPSTATUS Status = AFP_ERR_NONE;
  73. IPADDRESS IpAddress;
  74. struct _AppleUamRespPacket
  75. {
  76. BYTE _LogonId[2];
  77. BYTE _ChallengeToClient[1];
  78. };
  79. struct _AppleUamRespPacket *pAppleUamRespPacket;
  80. struct _ResponsePacket
  81. {
  82. BYTE _ChallengeToClient[MSV1_0_CHALLENGE_LENGTH];
  83. BYTE _TranslationTable[1];
  84. };
  85. PAGED_CODE( );
  86. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
  87. ("AfpFspDispLogin: Entered\n"));
  88. UserPasswd.Length = 0;
  89. UserPasswd.MaximumLength = 0;
  90. UserPasswd.Buffer = NULL;
  91. AfpSetEmptyAnsiString(&UserPasswd, 0, NULL);
  92. do
  93. {
  94. // First validate whether the call is allowed at this time. If a user
  95. // is either already logged on OR if we are awaiting a response after
  96. // a challenge has already been given, then this goes no further.
  97. if ((pSda->sda_Flags & SDA_LOGIN_MASK) != SDA_USER_NOT_LOGGEDIN)
  98. {
  99. Status = AFP_ERR_MISC;
  100. break;
  101. }
  102. // Validate the AFP Version
  103. for (i = 0; i < AFP_NUM_VERSIONS; i++)
  104. {
  105. if (RtlEqualString(&pSda->sda_Name1, &AfpVersions[i], True))
  106. {
  107. pSda->sda_ClientVersion = (BYTE)i;
  108. break;
  109. }
  110. }
  111. if (i == AFP_NUM_VERSIONS)
  112. {
  113. Status = AFP_ERR_BAD_VERSION;
  114. break;
  115. }
  116. #if DBG
  117. if (pSda->sda_Flags & SDA_SESSION_OVER_TCP)
  118. {
  119. PTCPCONN pTcpConn;
  120. pTcpConn = (PTCPCONN)(pSda->sda_SessHandle);
  121. IpAddress = pTcpConn->con_DestIpAddr;
  122. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  123. ("AFP/TCP: Mac client version 2.%d (%d.%d.%d.%d) connected (%lx)\n",
  124. pTcpConn->con_pSda->sda_ClientVersion,(IpAddress>>24)&0xFF,
  125. (IpAddress>>16)&0xFF,(IpAddress>>8)&0xFF,IpAddress&0xFF,pTcpConn));
  126. }
  127. else if (pSda->sda_ClientVersion >= AFP_VER_22)
  128. {
  129. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  130. ("AFP/Appletalk: Mac client version 2.%d connected\n",
  131. pSda->sda_ClientVersion));
  132. }
  133. #endif
  134. // Validate the UAM string
  135. for (i = 0; i < AFP_NUM_UAMS; i++)
  136. {
  137. if (RtlEqualString(&pSda->sda_Name2, &AfpUamStrings[i], True))
  138. {
  139. pSda->sda_ClientType = (BYTE)i;
  140. break;
  141. }
  142. }
  143. if (i == AFP_NUM_UAMS)
  144. {
  145. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  146. ("AfpFspDispLogin: unknown UAM, ignoring!\n"));
  147. Status = AFP_ERR_BAD_UAM;
  148. break;
  149. }
  150. // All seems OK so far. Handle the simple GUEST logon case first.
  151. pSda->sda_DomainName.Length = 0;
  152. pSda->sda_DomainName.Buffer = NULL;
  153. if (pSda->sda_ClientType == SDA_CLIENT_GUEST)
  154. {
  155. if (!(AfpServerOptions & AFP_SRVROPT_GUESTLOGONALLOWED))
  156. {
  157. Status = AFP_ERR_BAD_UAM;
  158. break;
  159. }
  160. // Lookup the current Guest account name
  161. {
  162. ULONG64 TempBuffer[16];
  163. ULONG GuestSidSize = 0;
  164. ULONG NameSize;
  165. ULONG DomainSize;
  166. UNICODE_STRING Name;
  167. UNICODE_STRING Domain;
  168. SID_NAME_USE NameUse;
  169. WCHAR NameString[UNLEN+1];
  170. WCHAR DomainString[DNLEN+1];
  171. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  172. NTSTATUS TempStatus = STATUS_SUCCESS;
  173. TempStatus = SecLookupWellKnownSid (
  174. WinAccountGuestSid,
  175. NULL,
  176. 0,
  177. &GuestSidSize
  178. );
  179. if (TempStatus == STATUS_BUFFER_TOO_SMALL)
  180. {
  181. if ((GuestSid = (PSID)AfpAllocPagedMemory (GuestSidSize)) == NULL)
  182. {
  183. Status = AFP_ERR_MISC;
  184. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  185. ("AfpFspDispLogin: AfpAllocPagedMemory failed to allocate memory"));
  186. break;
  187. }
  188. TempStatus = STATUS_SUCCESS;
  189. TempStatus = SecLookupWellKnownSid (
  190. WinAccountGuestSid,
  191. GuestSid,
  192. GuestSidSize,
  193. &GuestSidSize
  194. );
  195. if (TempStatus != STATUS_SUCCESS)
  196. {
  197. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  198. ("AfpFspDispLogin: SecLookupWellKnownSid 2 failed with error %ld\n",
  199. TempStatus));
  200. Status = AFP_ERR_MISC;
  201. break;
  202. }
  203. }
  204. else
  205. {
  206. if (TempStatus != STATUS_SUCCESS)
  207. {
  208. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  209. ("AfpFspDispLogin: SecLookupWellKnownSid 1 failed with error %ld\n",
  210. TempStatus));
  211. Status = AFP_ERR_MISC;
  212. break;
  213. }
  214. }
  215. Name.Buffer = NameString;
  216. Name.Length = sizeof (NameString);
  217. Name.MaximumLength = Name.Length;
  218. Domain.Buffer = DomainString;
  219. Domain.Length = sizeof (DomainString);
  220. Domain.MaximumLength = Domain.Length;
  221. TempStatus = SecLookupAccountSid (
  222. GuestSid,
  223. &NameSize,
  224. &Name,
  225. &DomainSize,
  226. &Domain,
  227. &NameUse
  228. );
  229. if (TempStatus != STATUS_SUCCESS)
  230. {
  231. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  232. ("AfpFspDispLogin: SecLookupAccountSid failed with error %ld\n",
  233. TempStatus));
  234. Status = AFP_ERR_MISC;
  235. break;
  236. }
  237. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  238. ("AfpFspDispLogin: SecLookupAccountSid returned GuestName = %Z, Guestname Size = %d\n",
  239. &Name, Name.Length));
  240. if ((pSda->sda_UserName.Buffer =
  241. (PWSTR)AfpAllocNonPagedMemory(Name.Length)) == NULL)
  242. {
  243. Status = AFP_ERR_MISC;
  244. break;
  245. }
  246. memcpy ((BYTE *)(pSda->sda_UserName.Buffer), (BYTE *)Name.Buffer,
  247. Name.Length);
  248. pSda->sda_UserName.Length = Name.Length;
  249. pSda->sda_UserName.MaximumLength = Name.Length;
  250. }
  251. // Consider the guest as a cleartext client from this point on
  252. // with NULL password
  253. fGuestLogon = TRUE;
  254. pSda->sda_ClientType = SDA_CLIENT_CLEARTEXT;
  255. Status = AfpLogonUser(pSda, &UserPasswd);
  256. break;
  257. }
  258. // Take apart the sda_Name3 block. The block looks as follows. We have
  259. // already eliminated the possibility of a GUEST login.
  260. // 1. ClearText/Custom UAM PASCALSTR - UserName (+DomainName)
  261. // 2. ClearText PASCALSTR - Password
  262. // Custom UAM PASCALSTR - MachineName
  263. if (pSda->sda_ClientType == SDA_CLIENT_CLEARTEXT)
  264. {
  265. if (!(AfpServerOptions & AFP_SRVROPT_CLEARTEXTLOGONALLOWED))
  266. {
  267. Status = AFP_ERR_BAD_UAM;
  268. break;
  269. }
  270. }
  271. if (!afpGetUserNameAndPwdOrWSName(&pSda->sda_Name3,
  272. pSda->sda_ClientType,
  273. &pSda->sda_UserName,
  274. &pSda->sda_DomainName,
  275. (pSda->sda_ClientType == SDA_CLIENT_CLEARTEXT) ?
  276. (PVOID)&UserPasswd : (PVOID)&pSda->sda_WSName))
  277. {
  278. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  279. ("AfpFspDispLogin: afpGetUserNameAndPwdOrWSName failed\n"));
  280. Status = AFP_ERR_USER_NOT_AUTH;
  281. break;
  282. }
  283. // Attempt to logon user for Cleartext case
  284. if (pSda->sda_ClientType == SDA_CLIENT_CLEARTEXT)
  285. {
  286. // The user password as we have it is potentially padded with nulls
  287. // if it is less than 8 chars. Get the length right
  288. UserPasswd.Length = strlen(UserPasswd.Buffer) + 1;
  289. Status = AfpLogonUser(pSda, &UserPasswd);
  290. // Free the buffer for the password
  291. AfpFreeMemory(UserPasswd.Buffer);
  292. break;
  293. }
  294. else
  295. {
  296. // Using the custom UAM, ship the challenge token
  297. pSda->sda_ReplySize = MSV1_0_CHALLENGE_LENGTH;
  298. // is this MS-UAM client? if so, need room for translation table
  299. if ((pSda->sda_ClientType == SDA_CLIENT_MSUAM_V1) ||
  300. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V2) ||
  301. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V3))
  302. {
  303. pSda->sda_ReplySize += AFP_XLAT_TABLE_SIZE;
  304. }
  305. else
  306. {
  307. pSda->sda_ReplySize += sizeof(USHORT); // space for LogonId
  308. }
  309. if (AfpAllocReplyBuf(pSda) != AFP_ERR_NONE)
  310. {
  311. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  312. ("AfpFspDispLogin: AfpAllocReplyBuf failed\n"));
  313. Status = AFP_ERR_USER_NOT_AUTH;
  314. break;
  315. }
  316. if ((pSda->sda_Challenge = AfpGetChallenge()) == NULL)
  317. {
  318. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  319. ("AfpFspDispLogin: AfpGetChallenge failed\n"));
  320. Status = AFP_ERR_USER_NOT_AUTH;
  321. AfpFreeReplyBuf(pSda, FALSE);
  322. break;
  323. }
  324. Status = AFP_ERR_AUTH_CONTINUE;
  325. // MS-UAM client? copy challenge and translation table
  326. if ((pSda->sda_ClientType == SDA_CLIENT_MSUAM_V1) ||
  327. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V2) ||
  328. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V3))
  329. {
  330. RtlCopyMemory(pRspPkt->_ChallengeToClient, pSda->sda_Challenge,
  331. MSV1_0_CHALLENGE_LENGTH);
  332. RtlCopyMemory(pRspPkt->_TranslationTable,
  333. AfpTranslationTable+AFP_XLAT_TABLE_SIZE,
  334. AFP_XLAT_TABLE_SIZE);
  335. }
  336. else
  337. {
  338. pAppleUamRespPacket = (struct _AppleUamRespPacket *)(pSda->sda_ReplyBuf);
  339. // copy the LogonId (make one up, using the sda pointer itself!)
  340. //*(USHORT *)(&pAppleUamRespPacket->_LogonId[0]) = (USHORT)pSda;
  341. pAppleUamRespPacket->_LogonId[0] = 0;
  342. pAppleUamRespPacket->_LogonId[1] = 0;
  343. // copy the challenge
  344. RtlCopyMemory(&pAppleUamRespPacket->_ChallengeToClient[0],
  345. pSda->sda_Challenge,
  346. MSV1_0_CHALLENGE_LENGTH);
  347. }
  348. }
  349. } while (False);
  350. if (GuestSid != NULL)
  351. {
  352. AfpFreeMemory(GuestSid);
  353. }
  354. // Set the SDA in the right state
  355. if (Status == AFP_ERR_NONE)
  356. {
  357. // Cancel the scavenger event for checking this user's kickoff time
  358. // IF ANY
  359. AfpScavengerKillEvent(AfpSdaCheckSession,
  360. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)));
  361. if (fGuestLogon)
  362. {
  363. AfpInterlockedSetDword(&pSda->sda_Flags,
  364. SDA_GUEST_LOGIN,
  365. &pSda->sda_Lock);
  366. }
  367. AfpInterlockedSetNClearDword(&pSda->sda_Flags,
  368. SDA_USER_LOGGEDIN,
  369. SDA_LOGIN_FAILED,
  370. &pSda->sda_Lock);
  371. pSda->sda_WSName.Length = 0;
  372. pSda->sda_WSName.MaximumLength = 0;
  373. pSda->sda_WSName.Buffer = NULL;
  374. if (pSda->sda_tTillKickOff < MAXLONG)
  375. AfpScavengerScheduleEvent(
  376. AfpSdaCheckSession,
  377. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)),
  378. (pSda->sda_tTillKickOff > SESSION_WARN_TIME) ?
  379. (pSda->sda_tTillKickOff - SESSION_WARN_TIME) :
  380. SESSION_CHECK_TIME,
  381. True);
  382. }
  383. else if (Status == AFP_ERR_AUTH_CONTINUE)
  384. {
  385. // Login is half-way done. Set to receive a FPLoginCont call
  386. AfpInterlockedSetDword(&pSda->sda_Flags,
  387. SDA_USER_LOGIN_PARTIAL,
  388. &pSda->sda_Lock);
  389. }
  390. else if (Status == AFP_ERR_PWD_EXPIRED)
  391. {
  392. AfpInterlockedSetDword(&pSda->sda_Flags,
  393. SDA_LOGIN_FAILED,
  394. &pSda->sda_Lock);
  395. Status = AFP_ERR_NONE;
  396. fKillSession = True;
  397. }
  398. else
  399. {
  400. fKillSession = True;
  401. }
  402. if (fKillSession)
  403. {
  404. // Cancel the scavenger event for checking this user's kickoff time
  405. // IF ANY
  406. AfpScavengerKillEvent(AfpSdaCheckSession,
  407. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)));
  408. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  409. ("AfpFspDispLogin: Logon failed: Scheduling session to be killed in (%ld) seconds\n", SESSION_KILL_TIME));
  410. pSda->sda_tTillKickOff = SESSION_KILL_TIME;
  411. AfpScavengerScheduleEvent(
  412. AfpSdaCheckSession,
  413. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)),
  414. (pSda->sda_tTillKickOff > SESSION_WARN_TIME) ?
  415. (pSda->sda_tTillKickOff - SESSION_WARN_TIME) :
  416. SESSION_CHECK_TIME,
  417. True);
  418. }
  419. return Status;
  420. }
  421. /*** AfpFspDispLoginCont
  422. *
  423. * This is the worker routine for the AfpLoginCont API.
  424. *
  425. * The request packet is represented below.
  426. *
  427. * sda_Name1 BLOCK Response to challenge (24 bytes)
  428. */
  429. AFPSTATUS FASTCALL
  430. AfpFspDispLoginCont(
  431. IN PSDA pSda
  432. )
  433. {
  434. AFPSTATUS Status = AFP_ERR_NONE;
  435. ANSI_STRING Passwd;
  436. struct _AppleUamReqPkt
  437. {
  438. BYTE _LogonId[2];
  439. BYTE _ChallengeResponse[1];
  440. };
  441. struct _AppleUamReqPkt *pAppleUamReqPkt;
  442. struct _RequestPacket
  443. {
  444. DWORD _ChallengeResponse[1];
  445. };
  446. PAGED_CODE( );
  447. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
  448. ("AfpFspDispLoginCont: Entered\n"));
  449. if ((pSda->sda_Flags & SDA_LOGIN_MASK) != SDA_USER_LOGIN_PARTIAL)
  450. {
  451. Status = AFP_ERR_USER_NOT_AUTH;
  452. }
  453. else
  454. {
  455. if ((pSda->sda_ClientType == SDA_CLIENT_MSUAM_V1) ||
  456. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V2) ||
  457. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V3))
  458. {
  459. Passwd.Length = Passwd.MaximumLength = LM_RESPONSE_LENGTH;
  460. Passwd.Buffer = (PBYTE)&pReqPkt->_ChallengeResponse[0];
  461. }
  462. else
  463. {
  464. pAppleUamReqPkt = (struct _AppleUamReqPkt *)(pSda->sda_ReqBlock);
  465. Passwd.Buffer = (PBYTE)&pAppleUamReqPkt->_ChallengeResponse[0];
  466. if (pSda->sda_ClientType == SDA_CLIENT_RANDNUM)
  467. {
  468. Passwd.Length = Passwd.MaximumLength = RANDNUM_RESP_LEN;
  469. }
  470. else
  471. {
  472. Passwd.Length = Passwd.MaximumLength = TWOWAY_RESP_LEN;
  473. }
  474. }
  475. ASSERT (pSda->sda_Challenge != NULL);
  476. Status = AfpLogonUser(pSda, &Passwd);
  477. AfpFreeMemory(pSda->sda_Challenge);
  478. pSda->sda_Challenge = NULL;
  479. }
  480. // Set the SDA in the right state
  481. if (Status == AFP_ERR_NONE)
  482. {
  483. // Cancel the scavenger event for checking this user's kickoff time
  484. // IF ANY
  485. AfpScavengerKillEvent(AfpSdaCheckSession,
  486. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)));
  487. AfpInterlockedSetNClearDword(&pSda->sda_Flags,
  488. SDA_USER_LOGGEDIN,
  489. SDA_USER_LOGIN_PARTIAL,
  490. &pSda->sda_Lock);
  491. if (pSda->sda_tTillKickOff < MAXLONG)
  492. AfpScavengerScheduleEvent(
  493. AfpSdaCheckSession,
  494. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)),
  495. (pSda->sda_tTillKickOff > SESSION_WARN_TIME) ?
  496. (pSda->sda_tTillKickOff - SESSION_WARN_TIME) :
  497. SESSION_CHECK_TIME,
  498. True);
  499. }
  500. else
  501. {
  502. // Cancel the scavenger event for checking this user's kickoff time
  503. // IF ANY
  504. AfpScavengerKillEvent(AfpSdaCheckSession,
  505. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)));
  506. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  507. ("AfpFspDispLoginCont: Logon failed: Scheduling session to be killed in (%ld) seconds\n"));
  508. pSda->sda_tTillKickOff = SESSION_KILL_TIME;
  509. AfpScavengerScheduleEvent(
  510. AfpSdaCheckSession,
  511. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)),
  512. (pSda->sda_tTillKickOff > SESSION_WARN_TIME) ?
  513. (pSda->sda_tTillKickOff - SESSION_WARN_TIME) :
  514. SESSION_CHECK_TIME,
  515. True);
  516. }
  517. return Status;
  518. }
  519. /*** AfpFspDispLogout
  520. *
  521. * This is the worker routine for the AfpLogout API.
  522. *
  523. * There is no request packet for this API.
  524. */
  525. AFPSTATUS FASTCALL
  526. AfpFspDispLogout(
  527. IN PSDA pSda
  528. )
  529. {
  530. AFP_SESSION_INFO SessInfo;
  531. PAGED_CODE( );
  532. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
  533. ("AfpFspDispLogout: Entered\n"));
  534. AfpInterlockedClearDword(&pSda->sda_Flags, SDA_LOGIN_MASK, &pSda->sda_Lock);
  535. return AFP_ERR_NONE;
  536. }
  537. /*** AfpFspDispChangePassword
  538. *
  539. * This is the worker routine for the AfpChangePassword API.
  540. *
  541. * The request packet is represented below.
  542. *
  543. * sda_AfpSubFunc BYTE New password length - UAM
  544. * sda_Name1 ANSI_STRING UAM String
  545. * sda_Name2 ANSI_STRING User Name [and domain]
  546. * sda_Name3 BLOCK Old and New passwords
  547. * Format depends on the UAM
  548. * ClearText Old Password (8 bytes, 0 padded)
  549. * New Password (8 bytes, 0 padded)
  550. * Encrypted Old Password LM_OWF_PASSWORD (16)
  551. * New Password LM_OWF_PASSWORD (16)
  552. *
  553. * All we do here is package the user name, domain name, old and new password
  554. * and give it up to user mode to attempt the password change since we cannot
  555. * do it in kernel mode.
  556. */
  557. AFPSTATUS FASTCALL
  558. AfpFspDispChangePassword(
  559. IN PSDA pSda
  560. )
  561. {
  562. AFPSTATUS Status;
  563. PAFP_PASSWORD_DESC pPwdDesc=NULL;
  564. ANSI_STRING NewPwd;
  565. UNICODE_STRING UNewPwd;
  566. UNICODE_STRING UserName;
  567. UNICODE_STRING DomainName;
  568. BYTE Method;
  569. struct _ResponsePacket
  570. {
  571. BYTE __ExtendedErrorCode[4];
  572. };
  573. PAGED_CODE( );
  574. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
  575. ("AfpFspDispChangePassword: Entered\n"));
  576. if ((pPwdDesc =
  577. (PAFP_PASSWORD_DESC)AfpAllocPagedMemory(sizeof(AFP_PASSWORD_DESC))) == NULL)
  578. {
  579. return AFP_ERR_MISC;
  580. }
  581. AfpSetEmptyUnicodeString(&DomainName,
  582. sizeof(pPwdDesc->DomainName),
  583. pPwdDesc->DomainName);
  584. AfpSetEmptyUnicodeString(&UserName,
  585. sizeof(pPwdDesc->UserName),
  586. pPwdDesc->UserName);
  587. do
  588. {
  589. Status = AFP_ERR_BAD_UAM; // Default
  590. // Validate the UAM string, cannot be 'No User Authent'
  591. for (Method = CLEAR_TEXT_AUTHENT; Method < AFP_NUM_UAMS; Method++)
  592. {
  593. if (RtlEqualString(&pSda->sda_Name1,
  594. &AfpUamStrings[Method],
  595. True))
  596. {
  597. if (pSda->sda_Flags & SDA_USER_LOGGEDIN)
  598. {
  599. // if the client is logged in using TWOWAY_EXCHANGE, the
  600. // UAM specified in password change is still RANDNUM_EXCHANGE
  601. // so, hack it, so rest of our logic works!
  602. //
  603. if ((Method == RANDNUM_EXCHANGE) &&
  604. (pSda->sda_ClientType == TWOWAY_EXCHANGE))
  605. {
  606. Method = TWOWAY_EXCHANGE;
  607. }
  608. if (pSda->sda_ClientType == Method)
  609. {
  610. Status = AFP_ERR_NONE;
  611. }
  612. else
  613. {
  614. Status = AFP_ERR_PARAM;
  615. }
  616. }
  617. else
  618. {
  619. pSda->sda_ClientType = Method;
  620. Status = AFP_ERR_NONE;
  621. }
  622. break;
  623. }
  624. }
  625. if ((Status != AFP_ERR_NONE) ||
  626. ((Method == CLEAR_TEXT_AUTHENT) &&
  627. !(AfpServerOptions & AFP_SRVROPT_CLEARTEXTLOGONALLOWED)))
  628. {
  629. break;
  630. }
  631. Status = AFP_ERR_PARAM; // Assume failure
  632. RtlZeroMemory(pPwdDesc, sizeof(AFP_PASSWORD_DESC));
  633. // Validate and Convert user name to unicode. If the user is already
  634. // logged in, make sure the user name matches what we already know
  635. if (!afpGetNameAndDomain(&pSda->sda_Name2,
  636. &UserName,
  637. &DomainName) ||
  638. !RtlEqualUnicodeString(&UserName,
  639. &pSda->sda_UserName,
  640. True) ||
  641. !RtlEqualUnicodeString(&DomainName,
  642. &pSda->sda_DomainName,
  643. True))
  644. {
  645. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  646. ("AfpFspDispChangePassword: afpGetNameAndDomain failed\n"));
  647. break;
  648. }
  649. pPwdDesc->AuthentMode = Method;
  650. if (Method == CLEAR_TEXT_AUTHENT)
  651. {
  652. ANSI_STRING ATmpPwd;
  653. UNICODE_STRING UOldPwd;
  654. // Make sure the old and new passwords are atleast the min. size
  655. if (pSda->sda_Name3.Length < (2 * sizeof(AFP_MAXPWDSIZE)))
  656. break;
  657. // Translate both passwords to host ansi (upper case)
  658. ATmpPwd.Buffer = pSda->sda_Name3.Buffer;
  659. ATmpPwd.Length = AFP_MAXPWDSIZE;
  660. ATmpPwd.MaximumLength = AFP_MAXPWDSIZE;
  661. UOldPwd.Buffer = (PWCHAR)pPwdDesc->OldPassword;
  662. UOldPwd.Length = sizeof(pPwdDesc->OldPassword);
  663. UOldPwd.MaximumLength = sizeof(pPwdDesc->OldPassword);
  664. if (!NT_SUCCESS(AfpConvertPasswordStringToUnicode(&ATmpPwd, &UOldPwd)))
  665. {
  666. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  667. ("AfpFspDispChangePassword: AfpConvertPasswordStringToUnicode 1 failed\n"));
  668. break;
  669. }
  670. pPwdDesc->OldPasswordLen = AFP_MAXPWDSIZE*sizeof(WCHAR);
  671. if (wcslen(UOldPwd.Buffer) < AFP_MAXPWDSIZE)
  672. {
  673. pPwdDesc->OldPasswordLen = wcslen(UOldPwd.Buffer)*sizeof(WCHAR);
  674. }
  675. ATmpPwd.Buffer = pSda->sda_Name3.Buffer+AFP_MAXPWDSIZE;
  676. ATmpPwd.Length = AFP_MAXPWDSIZE;
  677. ATmpPwd.MaximumLength = AFP_MAXPWDSIZE;
  678. UNewPwd.Buffer = (PWCHAR)pPwdDesc->NewPassword;
  679. UNewPwd.Length = sizeof(pPwdDesc->NewPassword);
  680. UNewPwd.MaximumLength = sizeof(pPwdDesc->NewPassword);
  681. if (!NT_SUCCESS(AfpConvertPasswordStringToUnicode(&ATmpPwd, &UNewPwd)))
  682. {
  683. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  684. ("AfpFspDispChangePassword: AfpConvertPasswordStringToUnicode 2 failed\n"));
  685. break;
  686. }
  687. pPwdDesc->NewPasswordLen = AFP_MAXPWDSIZE*sizeof(WCHAR);
  688. if (wcslen(UNewPwd.Buffer) < AFP_MAXPWDSIZE)
  689. {
  690. pPwdDesc->NewPasswordLen = wcslen(UNewPwd.Buffer)*sizeof(WCHAR);
  691. }
  692. #if 0
  693. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  694. ("AfpFspDispChangePassword: OldPwd=(%Z), NewPwd=(%Z)\n",
  695. &UOldPwd, &UNewPwd));
  696. #endif
  697. }
  698. //
  699. // if this is a client using Apple's native UAM, parms are different!
  700. //
  701. else if ((Method == RANDNUM_EXCHANGE) ||
  702. (Method == TWOWAY_EXCHANGE))
  703. {
  704. // Make sure the old and new passwords are atleast the min. size
  705. if (pSda->sda_Name3.Length < (2 * MAX_MAC_PWD_LEN))
  706. {
  707. ASSERT(0);
  708. break;
  709. }
  710. RtlCopyMemory(pPwdDesc->OldPassword,
  711. pSda->sda_Name3.Buffer,
  712. MAX_MAC_PWD_LEN);
  713. RtlCopyMemory(pPwdDesc->NewPassword,
  714. pSda->sda_Name3.Buffer + RANDNUM_RESP_LEN,
  715. MAX_MAC_PWD_LEN);
  716. }
  717. else if (Method == SDA_CLIENT_MSUAM_V1)
  718. {
  719. // Make sure the old and new passwords are atleast the min. size
  720. if (pSda->sda_Name3.Length < (2 * LM_OWF_PASSWORD_LENGTH))
  721. {
  722. break;
  723. }
  724. pPwdDesc->bPasswordLength = pSda->sda_AfpSubFunc;
  725. RtlCopyMemory(pPwdDesc->OldPassword,
  726. pSda->sda_Name3.Buffer,
  727. LM_OWF_PASSWORD_LENGTH);
  728. RtlCopyMemory(pPwdDesc->NewPassword,
  729. pSda->sda_Name3.Buffer + LM_OWF_PASSWORD_LENGTH,
  730. LM_OWF_PASSWORD_LENGTH);
  731. }
  732. else if (Method == SDA_CLIENT_MSUAM_V2)
  733. {
  734. // the data expected here is large (532 bytes) here
  735. try {
  736. RtlCopyMemory(pPwdDesc->OldPassword,
  737. pSda->sda_Name3.Buffer,
  738. LM_OWF_PASSWORD_LENGTH);
  739. RtlCopyMemory(pPwdDesc->NewPassword,
  740. pSda->sda_Name3.Buffer + LM_OWF_PASSWORD_LENGTH,
  741. (SAM_MAX_PASSWORD_LENGTH * 2) + 4);
  742. } except( EXCEPTION_EXECUTE_HANDLER ) {
  743. ASSERT(0);
  744. break;
  745. }
  746. }
  747. else if (Method == SDA_CLIENT_MSUAM_V3)
  748. {
  749. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
  750. ("AfpFspDispChangePassword: SDA_CLIENT_MSUAM_V3\n"));
  751. // the data expected here is large
  752. try
  753. {
  754. RtlCopyMemory(&pPwdDesc->NtEncryptedBuff.Ciphers,
  755. pSda->sda_Name3.Buffer,
  756. sizeof(SFM_PASSWORD_CHANGE_MESSAGE_HEADER));
  757. if (!strcmp(pPwdDesc->NtEncryptedBuff.Ciphers.h.Signature, SFM_CHANGE_PASSWORD_SIGNATURE)
  758. && (pPwdDesc->NtEncryptedBuff.Ciphers.h.Version == 1))
  759. {
  760. if (pPwdDesc->NtEncryptedBuff.Ciphers.h.cbMessage == sizeof(SFM_PASSWORD_CHANGE_MESSAGE_1))
  761. {
  762. RtlCopyMemory(&pPwdDesc->NtEncryptedBuff.Ciphers,
  763. pSda->sda_Name3.Buffer,
  764. pPwdDesc->NtEncryptedBuff.Ciphers.h.cbMessage);
  765. }
  766. else if (pPwdDesc->NtEncryptedBuff.Ciphers.h.cbMessage == sizeof(SFM_PASSWORD_CHANGE_MESSAGE_1_SHORT))
  767. {
  768. RtlCopyMemory(
  769. ((UCHAR*)&pPwdDesc->NtEncryptedBuff.Ciphers.m1)
  770. + sizeof(pPwdDesc->NtEncryptedBuff.Ciphers.m1) - sizeof(SFM_PASSWORD_CHANGE_MESSAGE_1_SHORT) + 2, // trailing byte of 2
  771. pSda->sda_Name3.Buffer,
  772. pPwdDesc->NtEncryptedBuff.Ciphers.h.cbMessage);
  773. }
  774. else
  775. {
  776. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  777. ("AfpFspDispChangePassword: unexpected cbMessage\n"));
  778. break;
  779. }
  780. }
  781. else
  782. {
  783. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  784. ("AfpFspDispChangePassword: unexpected cipher\n"));
  785. break;
  786. }
  787. } except( EXCEPTION_EXECUTE_HANDLER ) {
  788. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  789. ("AfpFspDispChangePassword: exception\n"));
  790. ASSERT(0);
  791. break;
  792. }
  793. }
  794. else
  795. {
  796. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  797. ("AfpFspDispChangePassword: unknown method %d\n",Method));
  798. ASSERT(0);
  799. }
  800. Status = AfpChangePassword(pSda, pPwdDesc);
  801. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  802. ("AfpFspDispChangePassword: AfpChangePassword returned %lx\n",
  803. Status));
  804. } while (False);
  805. if (NT_SUCCESS(Status))
  806. {
  807. // Check if we are here because the login returned password expired.
  808. // If this is Afp 2.1 chooser, we also need to logon this fella
  809. if (pSda->sda_Flags & SDA_LOGIN_FAILED)
  810. {
  811. AfpInterlockedClearDword(&pSda->sda_Flags,
  812. SDA_LOGIN_FAILED,
  813. &pSda->sda_Lock);
  814. NewPwd.Buffer = pPwdDesc->NewPassword;
  815. NewPwd.Length = sizeof(pPwdDesc->NewPassword);
  816. NewPwd.MaximumLength = sizeof(pPwdDesc->NewPassword);
  817. RtlCopyMemory(pPwdDesc->NewPassword,
  818. pSda->sda_Name3.Buffer+AFP_MAXPWDSIZE,
  819. AFP_MAXPWDSIZE);
  820. if (AfpConvertMacAnsiToHostAnsi(&NewPwd) != AFP_ERR_NONE)
  821. {
  822. // break;
  823. }
  824. // The user password as we have it is potentially padded with nulls
  825. // if it is less than 8 chars. Get the length right
  826. NewPwd.Length = strlen(NewPwd.Buffer) + 1;
  827. Status = AfpLogonUser(pSda, &NewPwd);
  828. if (Status == AFP_ERR_NONE)
  829. {
  830. AfpInterlockedSetDword(&pSda->sda_Flags,
  831. SDA_USER_LOGGEDIN,
  832. &pSda->sda_Lock);
  833. pSda->sda_WSName.Length = 0;
  834. pSda->sda_WSName.MaximumLength = 0;
  835. pSda->sda_WSName.Buffer = NULL;
  836. if (pSda->sda_tTillKickOff < MAXLONG)
  837. AfpScavengerScheduleEvent(
  838. AfpSdaCheckSession,
  839. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)),
  840. (pSda->sda_tTillKickOff > SESSION_WARN_TIME) ?
  841. (pSda->sda_tTillKickOff - SESSION_WARN_TIME) :
  842. SESSION_CHECK_TIME,
  843. True);
  844. }
  845. }
  846. }
  847. else // Failure - convert to right status code
  848. {
  849. {
  850. // Cancel the scavenger event for checking this user's kickoff time
  851. // IF ANY
  852. AfpScavengerKillEvent(AfpSdaCheckSession,
  853. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)));
  854. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  855. ("AfpFspDispChangePassword: Chgpwd/Logon failed: Scheduling session to be killed in (%ld) seconds\n"));
  856. pSda->sda_tTillKickOff = SESSION_KILL_TIME;
  857. AfpScavengerScheduleEvent(
  858. AfpSdaCheckSession,
  859. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)),
  860. (pSda->sda_tTillKickOff > SESSION_WARN_TIME) ?
  861. (pSda->sda_tTillKickOff - SESSION_WARN_TIME) :
  862. SESSION_CHECK_TIME,
  863. True);
  864. }
  865. if ((pSda->sda_ClientType == SDA_CLIENT_MSUAM_V1) ||
  866. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V2) ||
  867. (pSda->sda_ClientType == SDA_CLIENT_MSUAM_V3))
  868. {
  869. if (Status == STATUS_PASSWORD_EXPIRED)
  870. Status = AFP_ERR_PASSWORD_EXPIRED;
  871. else if (Status == STATUS_ACCOUNT_DISABLED)
  872. Status = AFP_ERR_ACCOUNT_DISABLED;
  873. else if (Status == STATUS_INVALID_LOGON_HOURS)
  874. Status = AFP_ERR_INVALID_LOGON_HOURS;
  875. else if (Status == STATUS_INVALID_WORKSTATION)
  876. Status = AFP_ERR_INVALID_WORKSTATION;
  877. else if (Status == STATUS_PASSWORD_RESTRICTION)
  878. Status = AFP_ERR_PASSWORD_RESTRICTED;
  879. else if (Status == STATUS_PWD_TOO_SHORT)
  880. Status = AFP_ERR_PASSWORD_TOO_SHORT;
  881. else if (Status == STATUS_ACCOUNT_RESTRICTION)
  882. Status = AFP_ERR_ACCOUNT_RESTRICTED;
  883. else if (Status == STATUS_ACCESS_DENIED)
  884. Status = AFP_ERR_PASSWORD_CANT_CHANGE;
  885. else if ((Status != AFP_ERR_BAD_UAM) &&
  886. (Status != AFP_ERR_PARAM))
  887. Status = AFP_ERR_MISC;
  888. }
  889. else
  890. {
  891. if (Status == STATUS_WRONG_PASSWORD)
  892. Status = AFP_ERR_USER_NOT_AUTH;
  893. else if ((Status == STATUS_PASSWORD_RESTRICTION) ||
  894. (Status == STATUS_ACCOUNT_DISABLED))
  895. Status = AFP_ERR_ACCESS_DENIED;
  896. else if (Status == STATUS_PWD_TOO_SHORT)
  897. {
  898. if ((pSda->sda_Flags & SDA_USER_LOGGEDIN) &&
  899. (pSda->sda_ClientVersion >= AFP_VER_21))
  900. {
  901. Status = AFP_ERR_PWD_TOO_SHORT;
  902. }
  903. else
  904. Status = AFP_ERR_ACCESS_DENIED;
  905. }
  906. else if ((Status == STATUS_NONE_MAPPED) ||
  907. (Status == STATUS_NO_SUCH_USER))
  908. Status = AFP_ERR_PARAM;
  909. else if ((Status != AFP_ERR_BAD_UAM) &&
  910. (Status != AFP_ERR_PARAM))
  911. Status = AFP_ERR_MISC;
  912. }
  913. }
  914. if (pPwdDesc)
  915. {
  916. AfpFreeMemory(pPwdDesc);
  917. }
  918. return Status;
  919. }
  920. /*** AfpFspDispMapName
  921. *
  922. * This is the worker routine for the AfpMapName API.
  923. *
  924. * The request packet is represented below.
  925. *
  926. * sda_SubFunc BYTE User/Group Flag
  927. * sda_Name1 ANSI_STRING Name of user/group
  928. */
  929. AFPSTATUS FASTCALL
  930. AfpFspDispMapName(
  931. IN PSDA pSda
  932. )
  933. {
  934. AFPSTATUS Status = AFP_ERR_NONE;
  935. UNICODE_STRING Us;
  936. DWORD UserOrGroupId = 0;
  937. struct _ResponsePacket
  938. {
  939. BYTE __UserOrGroupId[4];
  940. };
  941. PAGED_CODE( );
  942. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
  943. ("AfpFspDispMapName: Entered\n"));
  944. if ((pSda->sda_AfpSubFunc != MAP_USER_NAME) &&
  945. (pSda->sda_AfpSubFunc != MAP_GROUP_NAME))
  946. return AFP_ERR_PARAM;
  947. AfpSetEmptyUnicodeString(&Us, 0, NULL);
  948. // If this is the first time we are asking for the name to be translated.
  949. if ((pSda->sda_Name1.Length != 0) &&
  950. (pSda->sda_SecUtilSid == NULL) &&
  951. (NT_SUCCESS(pSda->sda_SecUtilResult)))
  952. {
  953. Us.MaximumLength = (pSda->sda_Name1.Length + 1) * sizeof(WCHAR);
  954. if ((Us.Buffer = (LPWSTR)AfpAllocPagedMemory(Us.MaximumLength)) == NULL)
  955. {
  956. return AFP_ERR_MISC;
  957. }
  958. if (!NT_SUCCESS(Status = AfpConvertStringToUnicode(&pSda->sda_Name1, &Us)))
  959. {
  960. AfpFreeMemory(Us.Buffer);
  961. return AFP_ERR_MISC;
  962. }
  963. Status = AfpNameToSid( pSda, &Us );
  964. AfpFreeMemory(Us.Buffer);
  965. if (!NT_SUCCESS(Status))
  966. {
  967. if (Status != AFP_ERR_EXTENDED)
  968. Status = AFP_ERR_MISC;
  969. }
  970. return Status;
  971. }
  972. // If we have successfully translated the name
  973. if (pSda->sda_Name1.Length != 0)
  974. {
  975. if ((pSda->sda_SecUtilSid != NULL) &&
  976. (NT_SUCCESS( pSda->sda_SecUtilResult)))
  977. Status = AfpSidToMacId(pSda->sda_SecUtilSid, &UserOrGroupId);
  978. else Status = AFP_ERR_ITEM_NOT_FOUND;
  979. }
  980. if (NT_SUCCESS(Status))
  981. {
  982. pSda->sda_ReplySize = SIZE_RESPPKT;
  983. if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
  984. {
  985. PUTDWORD2DWORD(pRspPkt->__UserOrGroupId, UserOrGroupId);
  986. }
  987. }
  988. if (pSda->sda_SecUtilSid != NULL)
  989. {
  990. AfpFreeMemory(pSda->sda_SecUtilSid);
  991. pSda->sda_SecUtilSid = NULL;
  992. }
  993. return Status;
  994. }
  995. /*** AfpFspDispMapId
  996. *
  997. * This is the worker routine for the AfpMapId API.
  998. *
  999. * The request packet is represented below.
  1000. *
  1001. * sda_SubFunc BYTE User/Group Flag
  1002. * sda_ReqBlock DWORD UserId
  1003. *
  1004. * We do not use the UserId field since it is invalid anyway !!
  1005. */
  1006. AFPSTATUS FASTCALL
  1007. AfpFspDispMapId(
  1008. IN PSDA pSda
  1009. )
  1010. {
  1011. AFPSTATUS Status = AFP_ERR_NONE;
  1012. PAFP_SID_NAME pSidName = NULL;
  1013. PSID pSid; // Sid of user or group
  1014. struct _RequestPacket
  1015. {
  1016. DWORD _UserOrGroupId;
  1017. };
  1018. struct _ResponsePacket
  1019. {
  1020. BYTE __NameLength[1];
  1021. BYTE __Name[1];
  1022. };
  1023. PAGED_CODE( );
  1024. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
  1025. ("AfpFspDispMapId: Entered\n"));
  1026. if ((pSda->sda_AfpSubFunc != MAP_USER_ID) &&
  1027. (pSda->sda_AfpSubFunc != MAP_GROUP_ID))
  1028. return AFP_ERR_PARAM;
  1029. Status = AFP_ERR_ITEM_NOT_FOUND; // Assume failure
  1030. if (NT_SUCCESS(pSda->sda_SecUtilResult)) do
  1031. {
  1032. ANSI_STRING As;
  1033. As.Length = 0;
  1034. As.MaximumLength = 1;
  1035. As.Buffer = "";
  1036. if (pReqPkt->_UserOrGroupId != 0)
  1037. {
  1038. Status = AfpMacIdToSid(pReqPkt->_UserOrGroupId, &pSid);
  1039. if (!NT_SUCCESS(Status))
  1040. {
  1041. Status = AFP_ERR_ITEM_NOT_FOUND;
  1042. break;
  1043. }
  1044. Status = AfpSidToName(pSda, pSid, &pSidName);
  1045. if (!NT_SUCCESS(Status))
  1046. {
  1047. if (Status != AFP_ERR_EXTENDED)
  1048. Status = AFP_ERR_MISC;
  1049. break;
  1050. }
  1051. /* MSKK hideyukn, Unicode char length not eqaul to ansi byte length in DBCS, 08/07/95 */
  1052. #ifdef DBCS
  1053. pSda->sda_ReplySize = pSidName->Name.Length + SIZE_RESPPKT;
  1054. #else
  1055. pSda->sda_ReplySize = pSidName->Name.Length/sizeof(WCHAR) + SIZE_RESPPKT;
  1056. #endif // DBCS
  1057. }
  1058. else pSda->sda_ReplySize = SIZE_RESPPKT; // For an id of 0
  1059. if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
  1060. {
  1061. if (pSidName != NULL)
  1062. {
  1063. As.MaximumLength = pSda->sda_ReplySize - 1;
  1064. As.Buffer = pRspPkt->__Name;
  1065. if ((Status = AfpConvertStringToAnsi(&pSidName->Name, &As)) != AFP_ERR_NONE)
  1066. {
  1067. AfpFreeReplyBuf(pSda, FALSE);
  1068. }
  1069. PUTBYTE2BYTE(pRspPkt->__NameLength, As.Length);
  1070. }
  1071. else PUTBYTE2BYTE(pRspPkt->__NameLength, 0);
  1072. }
  1073. } while (False);
  1074. return Status;
  1075. }
  1076. /*** AfpFspDispGetUserInfo
  1077. *
  1078. * This routine implements the AfpGetUserInfo API.
  1079. *
  1080. * The request packet is represented below.
  1081. *
  1082. * sda_AfpSubFunc BYTE ThisUser flag
  1083. * sda_ReqBlock DWORD UserId
  1084. * sda_ReqBlock DWORD Bitmap
  1085. *
  1086. * We do not use the UserId field since it is invalid anyway !!
  1087. */
  1088. AFPSTATUS FASTCALL
  1089. AfpFspDispGetUserInfo(
  1090. IN PSDA pSda
  1091. )
  1092. {
  1093. DWORD Bitmap;
  1094. PBYTE pTemp;
  1095. AFPSTATUS Status = AFP_ERR_PARAM;
  1096. DWORD Uid, Gid;
  1097. struct _RequestPacket
  1098. {
  1099. DWORD _UserId;
  1100. DWORD _Bitmap;
  1101. };
  1102. struct _ResponsePacket
  1103. {
  1104. BYTE __Bitmap[2];
  1105. BYTE __Id1[4];
  1106. BYTE __Id2[4];
  1107. };
  1108. PAGED_CODE( );
  1109. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
  1110. ("AfpFspDispGetUserInfo: Entered\n"));
  1111. do
  1112. {
  1113. if (!(pSda->sda_AfpSubFunc & USERINFO_THISUSER))
  1114. break;
  1115. Bitmap = pReqPkt->_Bitmap;
  1116. if (Bitmap & ~(USERINFO_BITMAP_USERID | USERINFO_BITMAP_PRIGID))
  1117. {
  1118. Status = AFP_ERR_BITMAP;
  1119. break;
  1120. }
  1121. if (Bitmap & USERINFO_BITMAP_USERID)
  1122. {
  1123. if (!NT_SUCCESS(Status = AfpSidToMacId(pSda->sda_UserSid, &Uid)))
  1124. {
  1125. Status = AFP_ERR_MISC;
  1126. break;
  1127. }
  1128. }
  1129. if (Bitmap & USERINFO_BITMAP_PRIGID)
  1130. {
  1131. if (!NT_SUCCESS(Status = AfpSidToMacId(pSda->sda_GroupSid, &Gid)))
  1132. {
  1133. Status = AFP_ERR_MISC;
  1134. break;
  1135. }
  1136. }
  1137. pSda->sda_ReplySize = SIZE_RESPPKT;
  1138. if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
  1139. {
  1140. PUTSHORT2SHORT(pRspPkt->__Bitmap, Bitmap);
  1141. pTemp = pRspPkt->__Id1;
  1142. if (Bitmap & USERINFO_BITMAP_USERID)
  1143. {
  1144. PUTDWORD2DWORD(pTemp, Uid);
  1145. pTemp = pRspPkt->__Id2;
  1146. }
  1147. else pSda->sda_ReplySize -= sizeof(DWORD);
  1148. if (Bitmap & USERINFO_BITMAP_PRIGID)
  1149. {
  1150. PUTDWORD2DWORD(pTemp, Gid);
  1151. }
  1152. else pSda->sda_ReplySize -= sizeof(DWORD);
  1153. }
  1154. } while (False);
  1155. return Status;
  1156. }
  1157. /*** afpGetUserNameAndPwdOrWSName
  1158. *
  1159. * Unmarshall the block containing UserName and either password or WS Name
  1160. * into unicode/ansi strings. Allocate memory for the output strings.
  1161. *
  1162. * The layout of the Buffer is as follows:
  1163. * User Name and an optional pad
  1164. * Workstation name or user password depending on the UAM.
  1165. *
  1166. * The optional pad is not directly determined since this buffer has been
  1167. * copied and we do not know at this point whether this started at an odd
  1168. * or an even boundary. We get to it indirectly from the size.
  1169. */
  1170. LOCAL BOOLEAN
  1171. afpGetUserNameAndPwdOrWSName(
  1172. IN PANSI_STRING Block,
  1173. IN BYTE ClientType,
  1174. OUT PUNICODE_STRING pUserName,
  1175. OUT PUNICODE_STRING pDomainName,
  1176. OUT PVOID pParm // Either password or WSName
  1177. )
  1178. {
  1179. ANSI_STRING UserName;
  1180. #define pPwd ((PANSI_STRING)pParm)
  1181. #define pWS ((PUNICODE_STRING)pParm)
  1182. PBYTE pTmp;
  1183. BOOLEAN RetCode = False;
  1184. PAGED_CODE( );
  1185. do
  1186. {
  1187. pPwd->Buffer = NULL;
  1188. pPwd->Length = 0;
  1189. pUserName->Buffer = NULL;
  1190. if (Block->Buffer == NULL)
  1191. {
  1192. ASSERT(0);
  1193. return(False);
  1194. }
  1195. pTmp = Block->Buffer;
  1196. UserName.Length = (USHORT)*pTmp;
  1197. UserName.Buffer = ++pTmp;
  1198. // Sanity check
  1199. if ((USHORT)(UserName.Length + 1) > Block->Length)
  1200. break;
  1201. pTmp += UserName.Length;
  1202. // make sure we are within bounds!
  1203. if (pTmp <= (Block->Buffer + Block->Length))
  1204. {
  1205. // If there is a NULL pad, go past it.
  1206. if (*pTmp == '\0')
  1207. pTmp++;
  1208. }
  1209. pUserName->Buffer = NULL; // Force allocation
  1210. pDomainName->Buffer = NULL; // Force allocation
  1211. if (!afpGetNameAndDomain(&UserName, pUserName, pDomainName))
  1212. break;
  1213. // Make sure we do not have a name of the form "DOMAIN\" i.e. a
  1214. // valid domain name and a NULL user name, disallow that explicitly
  1215. // so that we don't logon such users with a NULL session
  1216. if (pUserName->Length == 0)
  1217. {
  1218. if (pUserName->Buffer != NULL)
  1219. {
  1220. AfpFreeMemory(pUserName->Buffer);
  1221. pUserName->Buffer = NULL;
  1222. }
  1223. if (pDomainName->Buffer != NULL)
  1224. {
  1225. AfpFreeMemory(pDomainName->Buffer);
  1226. pDomainName->Buffer = NULL;
  1227. }
  1228. return False;
  1229. }
  1230. // The balance of the buffer is the block, if it is a password. Else
  1231. // it is the machine name string which is a PASCALSTR.
  1232. pPwd->MaximumLength = (USHORT)(Block->Length - (pTmp - Block->Buffer) + 1);
  1233. if (ClientType != SDA_CLIENT_CLEARTEXT)
  1234. {
  1235. // in case of Apple UAM (scrambled or 2-way), machine name won't
  1236. // be present, so check only for MS-UAM
  1237. //
  1238. if (((ClientType == SDA_CLIENT_MSUAM_V1) ||
  1239. (ClientType == SDA_CLIENT_MSUAM_V2) ||
  1240. (ClientType == SDA_CLIENT_MSUAM_V3)) &&
  1241. (pTmp < (Block->Buffer + Block->Length - 1)))
  1242. {
  1243. pWS->MaximumLength = (USHORT)((*pTmp + 1) * sizeof(WCHAR));
  1244. if (pWS->MaximumLength < (USHORT)((Block->Length -
  1245. (pTmp - Block->Buffer + 1)) *sizeof(WCHAR)))
  1246. {
  1247. return False;
  1248. }
  1249. }
  1250. else
  1251. {
  1252. pWS->MaximumLength = (sizeof(AFP_DEFAULT_WORKSTATION_A) *
  1253. sizeof(WCHAR));
  1254. }
  1255. }
  1256. if ((pPwd->Buffer = AfpAllocNonPagedMemory(pPwd->MaximumLength)) == NULL)
  1257. break;
  1258. if (ClientType == SDA_CLIENT_CLEARTEXT)
  1259. {
  1260. // We are dealing with a clear text password
  1261. pPwd->Length = pPwd->MaximumLength - 1;
  1262. RtlCopyMemory(pPwd->Buffer, pTmp, pPwd->Length);
  1263. if (AfpConvertMacAnsiToHostAnsi(pPwd) != AFP_ERR_NONE)
  1264. break;
  1265. pPwd->Buffer[pPwd->Length] = 0;
  1266. }
  1267. else
  1268. {
  1269. ANSI_STRING AS;
  1270. if (((ClientType == SDA_CLIENT_MSUAM_V1) ||
  1271. (ClientType == SDA_CLIENT_MSUAM_V2) ||
  1272. (ClientType == SDA_CLIENT_MSUAM_V3)) &&
  1273. (pTmp < (Block->Buffer + Block->Length - 1)))
  1274. {
  1275. AS.Buffer = ++pTmp;
  1276. AS.MaximumLength = pWS->MaximumLength/sizeof(WCHAR);
  1277. AS.Length = AS.MaximumLength - 1;
  1278. }
  1279. //
  1280. // for scrambled and 2-way exchange, use default wksta name since
  1281. // we don't know what it is
  1282. //
  1283. else
  1284. {
  1285. AS.Buffer = AFP_DEFAULT_WORKSTATION_A;
  1286. AS.MaximumLength = pWS->MaximumLength/sizeof(WCHAR);
  1287. AS.Length = AS.MaximumLength - 1;
  1288. }
  1289. // We have potentially a workstation name here. Since this is a
  1290. // pascal string, adjust the length etc.
  1291. AfpConvertStringToUnicode(&AS, pWS);
  1292. pWS->Buffer[pWS->Length/sizeof(WCHAR)] = L'\0';
  1293. }
  1294. RetCode = True;
  1295. } while (False);
  1296. if (!RetCode)
  1297. {
  1298. if (pUserName->Buffer != NULL)
  1299. {
  1300. AfpFreeMemory(pUserName->Buffer);
  1301. pUserName->Buffer = NULL;
  1302. }
  1303. if (pPwd->Buffer != NULL)
  1304. {
  1305. AfpFreeMemory(pPwd->Buffer);
  1306. pPwd->Buffer = NULL;
  1307. }
  1308. if (pDomainName->Buffer != NULL)
  1309. {
  1310. AfpFreeMemory(pDomainName->Buffer);
  1311. pDomainName->Buffer = NULL;
  1312. }
  1313. }
  1314. return RetCode;
  1315. }
  1316. /*** afpGetNameAndDomain
  1317. *
  1318. * Extract the name and domain from a string formed as DOMAIN\NAME.
  1319. */
  1320. BOOLEAN
  1321. afpGetNameAndDomain(
  1322. IN PANSI_STRING pDomainNUser,
  1323. OUT PUNICODE_STRING pUserName,
  1324. OUT PUNICODE_STRING pDomainName
  1325. )
  1326. {
  1327. BYTE c;
  1328. ANSI_STRING User, Domain;
  1329. BOOLEAN fDomainBuffAlloc=FALSE;
  1330. // Check if the user name has a '\' character in it. If it does,
  1331. // seperate the domain name from user name. The Username string is
  1332. // not ASCIIZ. Before we search for a '\', make it ASCIIZ w/o trashing
  1333. // whatever is there.
  1334. PAGED_CODE( );
  1335. User.Buffer = AfpStrChr(pDomainNUser->Buffer, pDomainNUser->Length, '\\');
  1336. if (User.Buffer != NULL)
  1337. {
  1338. (User.Buffer) ++; // Past the '\'
  1339. Domain.Buffer = pDomainNUser->Buffer;
  1340. Domain.Length = (USHORT)(User.Buffer - Domain.Buffer - 1);
  1341. User.Length = pDomainNUser->Length - Domain.Length - 1;
  1342. if (Domain.Length > DNLEN)
  1343. {
  1344. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  1345. ("afpGetNameAndDomain: domain name too long (%d vs. max %d): rejecting\n",
  1346. Domain.Length, DNLEN));
  1347. return(False);
  1348. }
  1349. Domain.MaximumLength = Domain.Length + 1;
  1350. pDomainName->MaximumLength = Domain.MaximumLength * sizeof(WCHAR);
  1351. if (pDomainName->Buffer == NULL)
  1352. {
  1353. if ((pDomainName->Buffer =
  1354. (PWSTR)AfpAllocNonPagedMemory(pDomainName->MaximumLength)) == NULL)
  1355. {
  1356. return False;
  1357. }
  1358. fDomainBuffAlloc = TRUE;
  1359. }
  1360. AfpConvertStringToUnicode(&Domain, pDomainName);
  1361. }
  1362. else User = *pDomainNUser;
  1363. if (User.Length > LM20_UNLEN)
  1364. {
  1365. DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_ERR,
  1366. ("afpGetNameAndDomain: user name too long (%d vs. max %d): rejecting\n",
  1367. User.Length,LM20_UNLEN));
  1368. return(False);
  1369. }
  1370. User.MaximumLength = User.Length + 1;
  1371. pUserName->MaximumLength = User.MaximumLength * sizeof(WCHAR);
  1372. if ((pUserName->Buffer == NULL) &&
  1373. (pUserName->Buffer =
  1374. (PWSTR)AfpAllocNonPagedMemory(pUserName->MaximumLength)) == NULL)
  1375. {
  1376. if (fDomainBuffAlloc)
  1377. {
  1378. AfpFreeMemory(pDomainName->Buffer);
  1379. pDomainName->Buffer = NULL;
  1380. }
  1381. return False;
  1382. }
  1383. AfpConvertStringToUnicode(&User, pUserName);
  1384. return True;
  1385. }