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.

1602 lines
63 KiB

  1. /****************************************************************************/
  2. /* asmint.c */
  3. /* */
  4. /* Security Manager internal functions */
  5. /* */
  6. /* Copyright(C) Microsoft Corporation 1997-1999 */
  7. /****************************************************************************/
  8. #include <precomp.h>
  9. #pragma hdrstop
  10. #define TRC_FILE "asmint"
  11. #define pTRCWd (pRealSMHandle->pWDHandle)
  12. #include <adcg.h>
  13. #include <acomapi.h>
  14. #include <nwdwapi.h>
  15. #include <anmapi.h>
  16. #include <asmint.h>
  17. #include <tsremdsk.h>
  18. #define DC_INCLUDE_DATA
  19. #include <asmdata.c>
  20. #undef DC_INCLUDE_DATA
  21. /****************************************************************************/
  22. /* Code page based driver compatible Unicode translations */
  23. /****************************************************************************/
  24. // Note these are initialized and LastNlsTableBuffer is freed in ntdd.c
  25. // at driver entry and exit.
  26. FAST_MUTEX fmCodePage;
  27. ULONG LastCodePageTranslated; // I'm assuming 0 is not a valid codepage
  28. PVOID LastNlsTableBuffer;
  29. CPTABLEINFO LastCPTableInfo;
  30. UINT NlsTableUseCount;
  31. /****************************************************************************/
  32. /* Name: SMDecryptPacket */
  33. /* */
  34. /* Purpose: Decrypt a packet */
  35. /* */
  36. /* Returns: TRUE - decryption succeeded */
  37. /* FALSE - decryption failed */
  38. /* */
  39. /* Params: pRealSMHandle - SM Handle */
  40. /* pData - packet to decrypt */
  41. /* dataLen - length of packet to decrypt */
  42. /* fSecureChecksum - take the checksum of the encrypted bytes */
  43. /* */
  44. /****************************************************************************/
  45. BOOL RDPCALL SMDecryptPacket(PSM_HANDLE_DATA pRealSMHandle,
  46. PVOID pData,
  47. unsigned dataLen,
  48. BOOL fSecureChecksum)
  49. {
  50. BOOL rc = TRUE;
  51. PRNS_SECURITY_HEADER1_UA pSecHdr;
  52. PRNS_SECURITY_HEADER2_UA pSecHdr2;
  53. unsigned coreDataLen;
  54. PBYTE pCoreData;
  55. unsigned SecHdrLen;
  56. DC_BEGIN_FN("SMDecryptPacket");
  57. /************************************************************************/
  58. /* Check to see we are encryption is on for this session */
  59. /************************************************************************/
  60. TRC_ASSERT((pRealSMHandle->encrypting),
  61. (TB,"Decrypt called when we are not encrypting"));
  62. if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
  63. SecHdrLen = sizeof(RNS_SECURITY_HEADER2);
  64. pSecHdr2 = (PRNS_SECURITY_HEADER2_UA)pData;
  65. }
  66. else {
  67. SecHdrLen = sizeof(RNS_SECURITY_HEADER1);
  68. }
  69. /************************************************************************/
  70. /* Check if this packet is encrypted */
  71. /************************************************************************/
  72. if (dataLen >= SecHdrLen) {
  73. pSecHdr = (PRNS_SECURITY_HEADER1_UA)pData;
  74. TRC_ASSERT((pSecHdr->flags & RNS_SEC_ENCRYPT),
  75. (TB, "This packet is not encrypted"));
  76. }
  77. else {
  78. TRC_ERR((TB,"PDU len %u too short for security header1", dataLen));
  79. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  80. Log_RDP_SecurityDataTooShort, pData, dataLen);
  81. rc = FALSE;
  82. DC_QUIT;
  83. }
  84. /************************************************************************/
  85. /* Get interesting pointers and lengths */
  86. /************************************************************************/
  87. if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
  88. coreDataLen = dataLen - sizeof(RNS_SECURITY_HEADER2);
  89. pCoreData = (PBYTE)(pSecHdr) + sizeof(RNS_SECURITY_HEADER2);
  90. }
  91. else {
  92. coreDataLen = dataLen - sizeof(RNS_SECURITY_HEADER1);
  93. pCoreData = (PBYTE)(pSecHdr) + sizeof(RNS_SECURITY_HEADER1);
  94. }
  95. //
  96. // Debug verification, we always go with what the protocol header
  97. // says but verify it's consistent with the capabilities
  98. //
  99. if (fSecureChecksum !=
  100. ((pSecHdr->flags & RDP_SEC_SECURE_CHECKSUM) != 0)) {
  101. TRC_ERR((TB,
  102. "fSecureChecksum: 0x%x setting does not match protocol: 0x%x",
  103. fSecureChecksum,
  104. (pSecHdr->flags & RDP_SEC_SECURE_CHECKSUM)));
  105. }
  106. /************************************************************************/
  107. /* check to see we need to update the session key. */
  108. /************************************************************************/
  109. if (pRealSMHandle->decryptCount == UPDATE_SESSION_KEY_COUNT) {
  110. rc = TRUE;
  111. // Don't need to update the session key if using FIPS
  112. if (pRealSMHandle->encryptionMethodSelected != SM_FIPS_ENCRYPTION_FLAG) {
  113. rc = UpdateSessionKey(
  114. pRealSMHandle->startDecryptKey,
  115. pRealSMHandle->currentDecryptKey,
  116. pRealSMHandle->encryptionMethodSelected,
  117. pRealSMHandle->keyLength,
  118. &pRealSMHandle->rc4DecryptKey,
  119. pRealSMHandle->encryptionLevel );
  120. }
  121. if( !rc ) {
  122. TRC_ERR((TB, "SM failed to update session key"));
  123. /****************************************************************/
  124. /* Log an error and disconnect the Client */
  125. /****************************************************************/
  126. WDW_LogAndDisconnect(
  127. pRealSMHandle->pWDHandle, TRUE,
  128. Log_RDP_ENC_UpdateSessionKeyFailed,
  129. NULL,
  130. 0);
  131. rc = FALSE;
  132. DC_QUIT;
  133. }
  134. /********************************************************************/
  135. /* reset counter. */
  136. /********************************************************************/
  137. pRealSMHandle->decryptCount = 0;
  138. }
  139. TRC_DATA_DBG("Data buffer before decryption", pCoreData, coreDataLen);
  140. if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
  141. rc = TSFIPS_DecryptData(
  142. &(pRealSMHandle->FIPSData),
  143. pCoreData,
  144. coreDataLen,
  145. pSecHdr2->padlen,
  146. pSecHdr2->dataSignature,
  147. pRealSMHandle->totalDecryptCount);
  148. }
  149. else {
  150. rc = DecryptData(
  151. pRealSMHandle->encryptionLevel,
  152. pRealSMHandle->currentDecryptKey,
  153. &pRealSMHandle->rc4DecryptKey,
  154. pRealSMHandle->keyLength,
  155. pCoreData,
  156. coreDataLen,
  157. pRealSMHandle->macSaltKey,
  158. pSecHdr->dataSignature,
  159. (pSecHdr->flags & RDP_SEC_SECURE_CHECKSUM),
  160. pRealSMHandle->totalDecryptCount);
  161. }
  162. if (rc) {
  163. TRC_DBG((TB, "Data decrypted: %ld", coreDataLen));
  164. TRC_DATA_DBG("Data buffer after decryption", pCoreData, coreDataLen);
  165. /********************************************************************/
  166. /* successfully decrypted a packet, increment the decrption counter.*/
  167. /********************************************************************/
  168. pRealSMHandle->decryptCount++;
  169. pRealSMHandle->totalDecryptCount++;
  170. }
  171. else {
  172. TRC_ERR((TB, "SM failed to decrypt data: %ld", coreDataLen));
  173. /********************************************************************/
  174. /* Log an error and disconnect the Client */
  175. /********************************************************************/
  176. WDW_LogAndDisconnect(
  177. pRealSMHandle->pWDHandle, TRUE,
  178. Log_RDP_ENC_DecryptFailed,
  179. NULL,
  180. 0);
  181. rc = FALSE;
  182. }
  183. DC_EXIT_POINT:
  184. DC_END_FN();
  185. return rc;
  186. } /* SMDecryptPacket */
  187. /****************************************************************************/
  188. /* Name: SMContinueSecurityExchange */
  189. /* */
  190. /* Purpose: Continue a security exchange */
  191. /* */
  192. /* Returns: TRUE if successful, FALSE otherwise. */
  193. /* */
  194. /* Params: pRealSMHandle - SM Handle */
  195. /* pData - incoming security exchange packet */
  196. /* dataLen - length of incoming packet */
  197. /* */
  198. /****************************************************************************/
  199. BOOLEAN RDPCALL SMContinueSecurityExchange(
  200. PSM_HANDLE_DATA pRealSMHandle,
  201. PVOID pData,
  202. UINT32 dataLen)
  203. {
  204. BOOLEAN result = TRUE;
  205. PRNS_SECURITY_PACKET_UA pSecPkt = (PRNS_SECURITY_PACKET_UA) pData;
  206. DC_BEGIN_FN("SMContinueSecurityExchange");
  207. if (dataLen >= sizeof(RNS_SECURITY_PACKET)) {
  208. ULONG flags = ((PRNS_SECURITY_PACKET_UA)pData)->flags;
  209. if (flags & RNS_SEC_INFO_PKT)
  210. result = SMSecurityExchangeInfo(pRealSMHandle, pData, dataLen);
  211. else if (flags & RNS_SEC_EXCHANGE_PKT)
  212. result = SMSecurityExchangeKey(pRealSMHandle, pData, dataLen);
  213. else
  214. TRC_ERR((TB,"Unknown security exchange packet flag: %lx", flags));
  215. }
  216. else {
  217. TRC_ERR((TB,"Packet len %u too short for security packet", dataLen));
  218. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  219. Log_RDP_SecurityDataTooShort, pData, dataLen);
  220. result = FALSE;
  221. }
  222. DC_END_FN();
  223. return (result);
  224. } /* SMContinueSecurityExchange */
  225. /****************************************************************************/
  226. /* Name: SMSecurityExchangeInfo */
  227. /* */
  228. /* Purpose: Continue a security exchange */
  229. /* */
  230. /* Returns: TRUE if successful, FALSE otherwise. */
  231. /* */
  232. /* Params: pRealSMHandle - SM Handle */
  233. /* pData - incoming security exchange packet */
  234. /* dataLen - length of incoming packet */
  235. /* */
  236. /****************************************************************************/
  237. BOOLEAN RDPCALL SMSecurityExchangeInfo(PSM_HANDLE_DATA pRealSMHandle,
  238. PVOID pData,
  239. UINT32 dataLength)
  240. {
  241. BOOL rc;
  242. BOOLEAN result = TRUE;
  243. PRNS_INFO_PACKET_UA pInfoPkt;
  244. UINT cb;
  245. NTSTATUS Status;
  246. DC_BEGIN_FN("SMSecurityExchangeInfo");
  247. /************************************************************************/
  248. /* Decrypt the packet if necessary */
  249. /************************************************************************/
  250. if (pRealSMHandle->encrypting)
  251. {
  252. if (((PRNS_SECURITY_HEADER_UA)pData)->flags & RNS_SEC_ENCRYPT)
  253. {
  254. // Wait for session key creation. This can fail if
  255. // the client has sent bad security data (check
  256. // pTSWd->SessKeyCreationStatus) or we time out (which
  257. // indicates an early socket close by the client, since we're
  258. // using an infinite wait and the socket close returns
  259. // timeout). On a session key error we force a client disconnect
  260. // with an appropriate error in the log. Note that we do not
  261. // have an infinite wait deadlock here, since we have already
  262. // received the client data and are simply waiting for a
  263. // verdict from the WSX about whether the key is usable.
  264. TRC_DBG((TB, "About to wait for session key creation"));
  265. Status = WDW_WaitForConnectionEvent(pRealSMHandle->pWDHandle,
  266. (pRealSMHandle->pWDHandle)->pSessKeyEvent, -1);
  267. TRC_DBG((TB, "Back from wait for session key creation"));
  268. if (!((pRealSMHandle->pWDHandle)->dead) && Status == STATUS_SUCCESS &&
  269. NT_SUCCESS((pRealSMHandle->pWDHandle)->
  270. SessKeyCreationStatus)) {
  271. TRC_DBG((TB, "Decrypt the packet"));
  272. rc = SMDecryptPacket(pRealSMHandle,
  273. pData,
  274. dataLength,
  275. FALSE);
  276. if (!rc)
  277. {
  278. TRC_ERR((TB, "Failed to decrypt packet"));
  279. DC_QUIT;
  280. }
  281. }
  282. else {
  283. // We initiate an error log and disconnect only if we actually
  284. // get an error return from user mode in getting the client
  285. // random / session key. If we don't have an error in the
  286. // session key status, and we received a timeout, we
  287. // know the client disconnected because of the infinite
  288. // wait above.
  289. if ((pRealSMHandle->pWDHandle)->dead && Status == STATUS_TIMEOUT) {
  290. TRC_NRM((TB,"Client disconnected during sess key wait"));
  291. }
  292. else {
  293. TRC_ERR((TB,"Failed session key creation, "
  294. "wait status=%X, sess key status = %X", Status,
  295. (pRealSMHandle->pWDHandle)->
  296. SessKeyCreationStatus));
  297. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  298. Log_RDP_ENC_DecryptFailed, NULL, 0);
  299. result = FALSE;
  300. }
  301. DC_QUIT;
  302. }
  303. }
  304. else {
  305. if (pRealSMHandle->pWDHandle->bForceEncryptedCSPDU) {
  306. TRC_ASSERT((FALSE), (TB, "unencrypted data in encrypted protocol"));
  307. WDW_LogAndDisconnect(
  308. pRealSMHandle->pWDHandle, TRUE,
  309. Log_RDP_ENC_DecryptFailed, NULL, 0);
  310. result = FALSE;
  311. DC_QUIT;
  312. }
  313. }
  314. /********************************************************************/
  315. /* Adjust pointer and length */
  316. /********************************************************************/
  317. if (pRealSMHandle->encryptionMethodSelected == SM_FIPS_ENCRYPTION_FLAG) {
  318. (PBYTE)pData += sizeof(RNS_SECURITY_HEADER2);
  319. dataLength -= (sizeof(RNS_SECURITY_HEADER2) + ((PRNS_SECURITY_HEADER2_UA)pData)->padlen);
  320. }
  321. else {
  322. (PBYTE)pData += sizeof(RNS_SECURITY_HEADER1);
  323. dataLength -= sizeof(RNS_SECURITY_HEADER1);
  324. }
  325. }
  326. else
  327. {
  328. /********************************************************************/
  329. /* Adjust pointer and length */
  330. /********************************************************************/
  331. (PBYTE) pData += sizeof(RNS_SECURITY_HEADER);
  332. dataLength -= sizeof(RNS_SECURITY_HEADER);
  333. }
  334. {
  335. // Time zone information
  336. // initialization in case if no timezone information received
  337. //
  338. //This time zone information is invalid
  339. //using it we set BaseSrvpStaticServerData->TermsrvClientTimeZoneId to
  340. //TIME_ZONE_ID_INVALID!
  341. RDP_TIME_ZONE_INFORMATION InvalidTZ={0,L"",
  342. {0,10,0,6/*this number makes it invalid; day numbers >5 not allowed*/,0,0,0,0},0,L"",
  343. {0,4,0,6/*this number makes it invalid*/,0,0,0,0},0};
  344. memcpy(&(pRealSMHandle->pWDHandle->clientTimeZone), &InvalidTZ,
  345. sizeof(RDP_TIME_ZONE_INFORMATION));
  346. }
  347. // initialize the client sessionid to invalid in case there isn't
  348. // one in the packet
  349. pRealSMHandle->pWDHandle->clientSessionId = RNS_INFO_INVALID_SESSION_ID;
  350. /************************************************************************/
  351. /* Process the packet contents */
  352. /************************************************************************/
  353. if (dataLength >= FIELD_OFFSET(RNS_INFO_PACKET, Domain)) {
  354. // Big enough for the header, but the header promises more data.
  355. // Validate that we received a packet with all that data
  356. //
  357. // To conserve network bandwidth, the RNS_INFO_PACKET is collapsed down so
  358. // the strings are all adjacent before being sent. Read it in and put the
  359. // strings in the correct places
  360. //
  361. pInfoPkt = (PRNS_INFO_PACKET_UA)pData;
  362. cb = FIELD_OFFSET(RNS_INFO_PACKET, Domain) + pInfoPkt->cbDomain +
  363. pInfoPkt->cbUserName + pInfoPkt->cbPassword +
  364. pInfoPkt->cbAlternateShell + pInfoPkt->cbWorkingDir;
  365. // There's always 5 extra null terminations
  366. if (pInfoPkt->flags & RNS_INFO_UNICODE) {
  367. cb += sizeof(wchar_t) * 5;
  368. } else {
  369. cb += 5;
  370. }
  371. if (dataLength < cb) {
  372. TRC_ERR((TB,"Packet len %u too short for info packet data %u",
  373. dataLength, cb));
  374. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  375. Log_RDP_SecurityDataTooShort, pData, dataLength);
  376. result = FALSE;
  377. DC_QUIT;
  378. }
  379. } else {
  380. TRC_ERR((TB,"Packet len %u too short for info packet header",
  381. dataLength));
  382. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  383. Log_RDP_SecurityDataTooShort, pData, dataLength);
  384. result = FALSE;
  385. DC_QUIT;
  386. }
  387. if (pInfoPkt->flags & RNS_INFO_UNICODE) {
  388. // The client can handle Unicode logon information, so we don't have
  389. // to do the translation work
  390. PBYTE psz = &pInfoPkt->Domain[0];
  391. UINT size;
  392. //
  393. // The CodePage field in InfoPacket is overridden to mean
  394. // active input locale when the infopacket is UNICODE
  395. //
  396. pRealSMHandle->pWDHandle->activeInputLocale = pInfoPkt->CodePage;
  397. // Domain
  398. cb = pInfoPkt->cbDomain;
  399. if (cb > TS_MAX_DOMAIN_LENGTH - sizeof(wchar_t))
  400. cb = TS_MAX_DOMAIN_LENGTH - sizeof(wchar_t);
  401. pTRCWd->pInfoPkt->cbDomain = (UINT16)cb;
  402. memcpy(pTRCWd->pInfoPkt->Domain, psz, cb);
  403. TRC_NRM((TB, "Received Domain (len %d):'%S'", cb,
  404. pTRCWd->pInfoPkt->Domain));
  405. psz += pInfoPkt->cbDomain + sizeof(wchar_t);
  406. // Username, Salem Expert pass hardcoded HelpAssistant account
  407. // name. Remote Assistance login make uses of auto-logon feature
  408. // of TermSrv, if login is from HelpAssistant, we by-pass this
  409. // fDontDisplayLastUserName and TermSrv will disconnect client
  410. // if fail in RA security check.
  411. cb = pInfoPkt->cbUserName;
  412. if (cb > TS_MAX_USERNAME_LENGTH - sizeof(wchar_t))
  413. cb = TS_MAX_USERNAME_LENGTH - sizeof(wchar_t);
  414. pTRCWd->pInfoPkt->cbUserName = (UINT16)cb;
  415. memcpy(pTRCWd->pInfoPkt->UserName, psz, cb);
  416. TRC_NRM((TB, "Received UserName (len %d):'%S'", cb,
  417. pTRCWd->pInfoPkt->UserName));
  418. psz += pInfoPkt->cbUserName + sizeof(wchar_t);
  419. cb = pInfoPkt->cbPassword;
  420. if (cb > TS_MAX_PASSWORD_LENGTH - sizeof(wchar_t))
  421. cb = TS_MAX_PASSWORD_LENGTH - sizeof(wchar_t);
  422. pTRCWd->pInfoPkt->cbPassword = (UINT16)cb;
  423. memcpy(pTRCWd->pInfoPkt->Password, psz, cb);
  424. TRC_NRM((TB, "Received Password (len %d)", cb));
  425. psz += pInfoPkt->cbPassword + sizeof(wchar_t);
  426. // AlternateShell
  427. cb = pInfoPkt->cbAlternateShell;
  428. if (cb > TS_MAX_ALTERNATESHELL_LENGTH - sizeof(wchar_t))
  429. cb = TS_MAX_ALTERNATESHELL_LENGTH - sizeof(wchar_t);
  430. pTRCWd->pInfoPkt->cbAlternateShell = (UINT16)cb;
  431. memcpy(pTRCWd->pInfoPkt->AlternateShell, psz,
  432. cb);
  433. TRC_NRM((TB, "Received AlternateShell (len %d):'%S'", cb,
  434. pTRCWd->pInfoPkt->AlternateShell));
  435. psz += pInfoPkt->cbAlternateShell + sizeof(wchar_t);
  436. // WorkingDir
  437. cb = pInfoPkt->cbWorkingDir;
  438. if (cb > TS_MAX_WORKINGDIR_LENGTH - sizeof(wchar_t))
  439. cb = TS_MAX_WORKINGDIR_LENGTH - sizeof(wchar_t);
  440. pTRCWd->pInfoPkt->cbWorkingDir = (UINT16)cb;
  441. memcpy(pTRCWd->pInfoPkt->WorkingDir, psz, cb);
  442. TRC_NRM((TB, "Received WorkingDir (len %d):'%S'", cb,
  443. pTRCWd->pInfoPkt->WorkingDir));
  444. psz += pInfoPkt->cbWorkingDir + sizeof(wchar_t);
  445. // new info fields added post win2000 beta 3
  446. if ((UINT32)(psz - (PBYTE)pData) < dataLength) {
  447. int currentLen = (UINT32)(psz - (PBYTE)pData);
  448. if (currentLen + sizeof(UINT16) * 2 < dataLength) {
  449. // computer address family
  450. pRealSMHandle->pWDHandle->clientAddressFamily =
  451. *((PUINT16_UA)psz);
  452. psz += sizeof(UINT16);
  453. TRC_NRM((TB, "Client address family=%d",
  454. pRealSMHandle->pWDHandle->clientAddressFamily));
  455. // computer address length
  456. cb = *((PUINT16_UA)psz);
  457. psz += sizeof(UINT16);
  458. currentLen += sizeof(UINT16) * 2;
  459. }
  460. else {
  461. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  462. dataLength));
  463. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  464. Log_RDP_SecurityDataTooShort, pData, dataLength);
  465. result = FALSE;
  466. DC_QUIT;
  467. }
  468. if (cb) {
  469. if (currentLen + cb < dataLength) {
  470. // computer address
  471. if (cb < TS_MAX_CLIENTADDRESS_LENGTH)
  472. memcpy(&(pRealSMHandle->pWDHandle->clientAddress[0]),
  473. psz, cb);
  474. else
  475. memcpy(&(pRealSMHandle->pWDHandle->clientAddress[0]),
  476. psz, TS_MAX_CLIENTADDRESS_LENGTH - sizeof(wchar_t));
  477. psz += cb;
  478. TRC_NRM((TB, "Client address=%S", pRealSMHandle->pWDHandle->clientAddress));
  479. currentLen += cb;
  480. }
  481. else {
  482. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  483. dataLength));
  484. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  485. Log_RDP_SecurityDataTooShort, pData, dataLength);
  486. result = FALSE;
  487. DC_QUIT;
  488. }
  489. }
  490. // client dir length
  491. if (currentLen + sizeof(UINT16) < dataLength) {
  492. cb = *((PUINT16_UA)psz);
  493. psz += sizeof(UINT16);
  494. currentLen += sizeof(UINT16);
  495. }
  496. else {
  497. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  498. dataLength));
  499. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  500. Log_RDP_SecurityDataTooShort, pData, dataLength);
  501. result = FALSE;
  502. DC_QUIT;
  503. }
  504. if (cb) {
  505. // client dir
  506. if (currentLen + cb <= dataLength) {
  507. if (cb < TS_MAX_CLIENTDIR_LENGTH)
  508. memcpy(&(pRealSMHandle->pWDHandle->clientDir[0]),
  509. psz, cb);
  510. else
  511. memcpy(&(pRealSMHandle->pWDHandle->clientDir[0]),
  512. psz, TS_MAX_CLIENTDIR_LENGTH - sizeof(wchar_t));
  513. psz += cb;
  514. TRC_NRM((TB, "Client directory: %S", pRealSMHandle->pWDHandle->clientDir));
  515. currentLen += cb;
  516. }
  517. else {
  518. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  519. dataLength));
  520. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  521. Log_RDP_SecurityDataTooShort, pData, dataLength);
  522. result = FALSE;
  523. DC_QUIT;
  524. }
  525. }
  526. // is there something else? If yes it must be the time zone
  527. if ((UINT32)currentLen < dataLength)
  528. {
  529. //client time zone information
  530. cb = sizeof(RDP_TIME_ZONE_INFORMATION);
  531. if (currentLen + cb <= dataLength) {
  532. //time zone information received
  533. memcpy(&(pRealSMHandle->pWDHandle->clientTimeZone), psz, cb);
  534. psz += cb;
  535. currentLen += cb;
  536. }
  537. else {
  538. TRC_ERR((TB,"Packet len %u too short for time zone data", dataLength));
  539. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  540. Log_RDP_SecurityDataTooShort, pData, dataLength);
  541. result = FALSE;
  542. DC_QUIT;
  543. }
  544. }
  545. // is there something else? If yes it must be the client session id
  546. if ((UINT32)currentLen < dataLength)
  547. {
  548. //client session ID
  549. cb = sizeof(UINT32);
  550. if (currentLen + cb <= dataLength) {
  551. // session id of the client received
  552. pRealSMHandle->pWDHandle->clientSessionId = *((PUINT32_UA)psz);
  553. psz += cb;
  554. currentLen += cb;
  555. }
  556. else {
  557. TRC_ERR((TB,"Packet len %u too short for session id data", dataLength));
  558. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  559. Log_RDP_SecurityDataTooShort, pData, dataLength);
  560. result = FALSE;
  561. DC_QUIT;
  562. }
  563. }
  564. //
  565. // is there something else? If yes it must be the perf
  566. // disabled feature list
  567. //
  568. if ((UINT32)currentLen < dataLength)
  569. {
  570. //Disabled feature list
  571. cb = sizeof(UINT32);
  572. if (currentLen + cb <= dataLength) {
  573. // session id of the client received
  574. pRealSMHandle->pWDHandle->performanceFlags = *((PUINT32_UA)psz);
  575. psz += cb;
  576. currentLen += cb;
  577. }
  578. else {
  579. TRC_ERR((TB,"Packet len %u too short for session id data", dataLength));
  580. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  581. Log_RDP_SecurityDataTooShort, pData, dataLength);
  582. result = FALSE;
  583. DC_QUIT;
  584. }
  585. }
  586. // Autoreconnect info length
  587. pTRCWd->pInfoPkt->ExtraInfo.cbAutoReconnectLen = 0;
  588. //
  589. // Is there something else? If yes it must be the autoreconnect info
  590. //
  591. if ((UINT32)currentLen < dataLength)
  592. {
  593. if (currentLen + sizeof(UINT16) <= dataLength) {
  594. cb = *((PUINT16_UA)psz);
  595. psz += sizeof(UINT16);
  596. currentLen += sizeof(UINT16);
  597. }
  598. else {
  599. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  600. dataLength));
  601. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  602. Log_RDP_SecurityDataTooShort, pData, dataLength);
  603. result = FALSE;
  604. DC_QUIT;
  605. }
  606. //
  607. // Autoreconnect info is optional
  608. //
  609. if (cb) {
  610. // Variable length Autoreconnect info
  611. if (currentLen + cb <= dataLength) {
  612. if (cb <= TS_MAX_AUTORECONNECT_LEN) {
  613. pTRCWd->pInfoPkt->ExtraInfo.cbAutoReconnectLen = (UINT16)cb;
  614. memcpy(pTRCWd->pInfoPkt->ExtraInfo.autoReconnectCookie,
  615. psz, cb);
  616. psz += cb;
  617. currentLen += cb;
  618. }
  619. else {
  620. pTRCWd->pInfoPkt->ExtraInfo.cbAutoReconnectLen = (UINT16)0;
  621. memset(pTRCWd->pInfoPkt->ExtraInfo.autoReconnectCookie, 0,
  622. sizeof(pTRCWd->pInfoPkt->ExtraInfo.autoReconnectCookie));
  623. TRC_ERR((TB,"Autoreconnect info too long %d",cb));
  624. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  625. Log_RDP_SecurityDataTooShort, pData, dataLength);
  626. result = FALSE;
  627. DC_QUIT;
  628. }
  629. }
  630. else {
  631. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  632. dataLength));
  633. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  634. Log_RDP_SecurityDataTooShort, pData, dataLength);
  635. result = FALSE;
  636. DC_QUIT;
  637. }
  638. }
  639. }
  640. }
  641. // Flags
  642. pTRCWd->pInfoPkt->flags = pInfoPkt->flags;
  643. } else {
  644. // The client can't handle Unicode session information, so the server
  645. // needs to do the conversion. Most likely Win3.1 client.
  646. PSTR pszA;
  647. pszA = pInfoPkt->Domain;
  648. //
  649. // The CodePage field in InfoPacket is overridden to mean
  650. // active input locale when the infopacket is UNICODE.
  651. // Now that we are ansi we don't get any input locale info so
  652. // make sure it is zero'd out.
  653. //
  654. pRealSMHandle->pWDHandle->activeInputLocale = 0;
  655. // Domain
  656. cb = pInfoPkt->cbDomain;
  657. if (cb >= TS_MAX_DOMAIN_LENGTH)
  658. cb = TS_MAX_DOMAIN_LENGTH - 1;
  659. if (-1 == (cb = ConvertToAndFromWideChar(pRealSMHandle,
  660. pInfoPkt->CodePage, (LPWSTR)pTRCWd->pInfoPkt->Domain,
  661. sizeof(pTRCWd->pInfoPkt->Domain), pszA, cb, TRUE)))
  662. {
  663. TRC_ERR((TB, "Unable to convert domain name"));
  664. pTRCWd->pInfoPkt->cbDomain = 0;
  665. }
  666. else
  667. {
  668. pTRCWd->pInfoPkt->cbDomain = (UINT16)cb;
  669. }
  670. pszA += pInfoPkt->cbDomain + 1;
  671. cb = pInfoPkt->cbUserName;
  672. if (cb >= TS_MAX_USERNAME_LENGTH)
  673. cb = TS_MAX_USERNAME_LENGTH - 1;
  674. if (-1 == (cb = ConvertToAndFromWideChar(pRealSMHandle,
  675. pInfoPkt->CodePage, (LPWSTR)pTRCWd->pInfoPkt->UserName,
  676. sizeof(pTRCWd->pInfoPkt->UserName), pszA, cb, TRUE)))
  677. {
  678. TRC_ERR((TB, "Unable to convert UserName name"));
  679. pTRCWd->pInfoPkt->cbUserName = 0;
  680. }
  681. else
  682. {
  683. pTRCWd->pInfoPkt->cbUserName = (UINT16)cb;
  684. }
  685. pszA += pInfoPkt->cbUserName + 1;
  686. cb = pInfoPkt->cbPassword;
  687. if (cb >= TS_MAX_PASSWORD_LENGTH)
  688. cb = TS_MAX_PASSWORD_LENGTH - 1;
  689. if (-1 == (cb = ConvertToAndFromWideChar(pRealSMHandle,
  690. pInfoPkt->CodePage, (LPWSTR)pTRCWd->pInfoPkt->Password,
  691. sizeof(pTRCWd->pInfoPkt->Password), pszA, cb, TRUE)))
  692. {
  693. TRC_ERR((TB, "Unable to convert Password name"));
  694. pTRCWd->pInfoPkt->cbPassword = 0;
  695. }
  696. else
  697. {
  698. pTRCWd->pInfoPkt->cbPassword = (UINT16)cb;
  699. }
  700. pszA += pInfoPkt->cbPassword + 1;
  701. // AlternateShell
  702. cb = pInfoPkt->cbAlternateShell;
  703. if (cb >= TS_MAX_ALTERNATESHELL_LENGTH)
  704. cb = TS_MAX_ALTERNATESHELL_LENGTH - 1;
  705. if (-1 == (cb = ConvertToAndFromWideChar(pRealSMHandle,
  706. pInfoPkt->CodePage, (LPWSTR)pTRCWd->pInfoPkt->AlternateShell,
  707. sizeof(pTRCWd->pInfoPkt->AlternateShell), pszA, cb, TRUE)))
  708. {
  709. TRC_ERR((TB, "Unable to convert AlternateShell name"));
  710. pTRCWd->pInfoPkt->cbAlternateShell = 0;
  711. }
  712. else
  713. {
  714. pTRCWd->pInfoPkt->cbAlternateShell = (UINT16)cb;
  715. }
  716. pszA += pInfoPkt->cbAlternateShell + 1;
  717. // WorkingDir
  718. cb = pInfoPkt->cbWorkingDir;
  719. if (cb >= TS_MAX_WORKINGDIR_LENGTH)
  720. cb = TS_MAX_WORKINGDIR_LENGTH - 1;
  721. if (-1 == (cb = ConvertToAndFromWideChar(pRealSMHandle,
  722. pInfoPkt->CodePage, (LPWSTR)pTRCWd->pInfoPkt->WorkingDir,
  723. sizeof(pTRCWd->pInfoPkt->WorkingDir), pszA, cb, TRUE)))
  724. {
  725. TRC_ERR((TB, "Unable to convert WorkingDir name"));
  726. pTRCWd->pInfoPkt->cbWorkingDir = 0;
  727. }
  728. else
  729. {
  730. pTRCWd->pInfoPkt->cbWorkingDir = (UINT16)cb;
  731. }
  732. pszA += pInfoPkt->cbWorkingDir + 1;
  733. // new info fields added post win2000 beta 3
  734. if ((UINT32)(pszA - (PBYTE)pData) < dataLength) {
  735. int len, currentLen;
  736. currentLen = (UINT32)(pszA - (PBYTE)pData);
  737. if (currentLen + sizeof(UINT16) * 2 < dataLength) {
  738. // computer address family
  739. pRealSMHandle->pWDHandle->clientAddressFamily =
  740. *((PUINT16_UA)pszA);
  741. pszA += sizeof(UINT16);
  742. TRC_NRM((TB, "Client address family=%d",
  743. pRealSMHandle->pWDHandle->clientAddressFamily));
  744. // computer address length
  745. cb = *((PUINT16_UA)pszA);
  746. pszA += sizeof(UINT16);
  747. currentLen += sizeof(UINT16) * 2;
  748. }
  749. else {
  750. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  751. dataLength));
  752. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  753. Log_RDP_SecurityDataTooShort, pData, dataLength);
  754. result = FALSE;
  755. DC_QUIT;
  756. }
  757. if (cb) {
  758. // computer address
  759. if (currentLen + cb < dataLength) {
  760. len = min(cb, TS_MAX_CLIENTADDRESS_LENGTH - sizeof(wchar_t));
  761. if (-1 == (len = ConvertToAndFromWideChar(pRealSMHandle,
  762. pInfoPkt->CodePage, (LPWSTR)pRealSMHandle->pWDHandle->clientAddress,
  763. sizeof(pRealSMHandle->pWDHandle->clientAddress), pszA, len, TRUE)))
  764. {
  765. TRC_ERR((TB, "Unable to convert clientaddress"));
  766. pRealSMHandle->pWDHandle->clientAddress[0] = '\0';
  767. }
  768. pszA += cb;
  769. TRC_NRM((TB, "Client address: %S", pRealSMHandle->pWDHandle->clientAddress));
  770. currentLen += cb;
  771. }
  772. else {
  773. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  774. dataLength));
  775. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  776. Log_RDP_SecurityDataTooShort, pData, dataLength);
  777. result = FALSE;
  778. DC_QUIT;
  779. }
  780. }
  781. // client directory length
  782. if (currentLen + sizeof(UINT16) < dataLength) {
  783. cb = *((PUINT16_UA)pszA);
  784. pszA += sizeof(UINT16);
  785. currentLen += sizeof(UINT16);
  786. }
  787. else {
  788. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  789. dataLength));
  790. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  791. Log_RDP_SecurityDataTooShort, pData, dataLength);
  792. result = FALSE;
  793. DC_QUIT;
  794. }
  795. if (cb) {
  796. if (currentLen + cb <= dataLength) {
  797. len = min(cb, TS_MAX_CLIENTDIR_LENGTH);
  798. if (-1 == (len = ConvertToAndFromWideChar(pRealSMHandle,
  799. pInfoPkt->CodePage, (LPWSTR)pRealSMHandle->pWDHandle->clientDir,
  800. sizeof(pRealSMHandle->pWDHandle->clientDir), pszA, len, TRUE)))
  801. {
  802. TRC_ERR((TB, "Unable to convert clientaddress"));
  803. pRealSMHandle->pWDHandle->clientDir[0] = '\0';
  804. }
  805. pszA += cb;
  806. TRC_NRM((TB, "Client directory: %S", pRealSMHandle->pWDHandle->clientDir));
  807. currentLen += cb;
  808. }
  809. else {
  810. TRC_ERR((TB,"Packet len %u too short for extra info packet data",
  811. dataLength));
  812. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  813. Log_RDP_SecurityDataTooShort, pData, dataLength);
  814. result = FALSE;
  815. DC_QUIT;
  816. }
  817. }
  818. // is there something else? If yes it must be the time zone
  819. if ((UINT32)currentLen < dataLength)
  820. {
  821. //client time zone information
  822. cb = sizeof(RDP_TIME_ZONE_INFORMATION);
  823. if (currentLen + cb <= dataLength) {
  824. //timezone information received
  825. memcpy(&(pRealSMHandle->pWDHandle->clientTimeZone), pszA, cb);
  826. pszA += cb;
  827. currentLen += cb;
  828. }
  829. else {
  830. TRC_ERR((TB,"Packet len %u too short for time zone data", dataLength));
  831. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  832. Log_RDP_SecurityDataTooShort, pData, dataLength);
  833. result = FALSE;
  834. DC_QUIT;
  835. }
  836. }
  837. // is there something else? If yes it must be the client session id
  838. if ((UINT32)currentLen < dataLength)
  839. {
  840. //client time zone information
  841. cb = sizeof(UINT32);
  842. if (currentLen + cb <= dataLength) {
  843. // session id of the client received
  844. pRealSMHandle->pWDHandle->clientSessionId = *((PUINT32_UA)pszA);
  845. pszA += cb;
  846. currentLen += cb;
  847. }
  848. else {
  849. TRC_ERR((TB,"Packet len %u too short for session id data", dataLength));
  850. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  851. Log_RDP_SecurityDataTooShort, pData, dataLength);
  852. result = FALSE;
  853. DC_QUIT;
  854. }
  855. }
  856. }
  857. // Flags
  858. pTRCWd->pInfoPkt->flags = pInfoPkt->flags;
  859. pTRCWd->pInfoPkt->flags |= RNS_INFO_UNICODE;
  860. }
  861. //
  862. // Does client only send encrypted PDUs
  863. //
  864. pRealSMHandle->pWDHandle->bForceEncryptedCSPDU = (pInfoPkt->flags &
  865. RNS_INFO_FORCE_ENCRYPTED_CS_PDU) ? TRUE : FALSE;
  866. /************************************************************************/
  867. /* Update the state */
  868. /************************************************************************/
  869. #ifdef USE_LICENSE
  870. SM_SET_STATE(SM_STATE_LICENSING);
  871. #else
  872. SM_SET_STATE(SM_STATE_CONNECTED);
  873. #endif
  874. /************************************************************************/
  875. /* Tell WDW */
  876. /************************************************************************/
  877. WDW_OnSMConnected(pRealSMHandle->pWDHandle, NM_CB_CONN_OK);
  878. DC_EXIT_POINT:
  879. DC_END_FN();
  880. return (result);
  881. } /* SMSecurityExchangeInfo */
  882. /****************************************************************************/
  883. /* Name: SMSecurityExchangeKey */
  884. /* */
  885. /* Purpose: security key exchange */
  886. /* */
  887. /* Returns: TRUE if successful, FALSE otherwise. */
  888. /* */
  889. /* Params: pRealSMHandle - SM Handle */
  890. /* pData - incoming security exchange packet */
  891. /* dataLen - length of incoming packet */
  892. /* */
  893. /****************************************************************************/
  894. /****************************************************************************/
  895. /* Values for local variable rc */
  896. /****************************************************************************/
  897. #define SM_RC_DONE 0
  898. #define SM_RC_WAIT 1
  899. #define SM_RC_FAILED 2
  900. BOOLEAN RDPCALL SMSecurityExchangeKey(PSM_HANDLE_DATA pRealSMHandle,
  901. PVOID pData,
  902. UINT32 dataLen)
  903. {
  904. BOOLEAN result = TRUE;
  905. PRNS_SECURITY_PACKET_UA pSecPkt = (PRNS_SECURITY_PACKET_UA) pData;
  906. DC_BEGIN_FN("SMSecurityExchangeKey");
  907. /************************************************************************/
  908. /* check to see we are encrypting. */
  909. /************************************************************************/
  910. TRC_ASSERT((pRealSMHandle->encrypting == TRUE),
  911. (TB,"Recvd a security exchange pkg when we aren't encrypting"));
  912. if (pRealSMHandle->encrypting == FALSE)
  913. {
  914. DC_QUIT;
  915. }
  916. /************************************************************************/
  917. /* check to see we received a security exchange pkg. This pkt contains */
  918. /* a client random encrypted with the server's public key. */
  919. /************************************************************************/
  920. if (pSecPkt->flags & RNS_SEC_EXCHANGE_PKT) {
  921. /**********************************************************************/
  922. /* check to see we have not received a security exchange packet before*/
  923. /**********************************************************************/
  924. TRC_ASSERT((pRealSMHandle->recvdClientRandom == FALSE),
  925. (TB,"Client security packet is already received"));
  926. if( pRealSMHandle->recvdClientRandom == TRUE ) {
  927. DC_QUIT;
  928. }
  929. // Remember if the client can decrypt an encrypted license packet
  930. if (pSecPkt->flags & RDP_SEC_LICENSE_ENCRYPT_SC)
  931. pRealSMHandle->encryptingLicToClient = TRUE;
  932. else
  933. pRealSMHandle->encryptingLicToClient = FALSE;
  934. // Validate the data length
  935. if(sizeof(RNS_SECURITY_PACKET) + pSecPkt->length > dataLen)
  936. {
  937. TRC_ERR((TB, "Error: Security packet length %u too short", dataLen));
  938. WDW_LogAndDisconnect(pRealSMHandle->pWDHandle, TRUE,
  939. Log_RDP_SecurityDataTooShort, pData, dataLen);
  940. result = FALSE;
  941. DC_QUIT;
  942. }
  943. /********************************************************************/
  944. /* note the length of the security pkg. */
  945. /********************************************************************/
  946. pRealSMHandle->encClientRandomLen = pSecPkt->length;
  947. /********************************************************************/
  948. /* Allocate memory for the security info. */
  949. /********************************************************************/
  950. pRealSMHandle->pEncClientRandom =
  951. (PBYTE)COM_Malloc(pSecPkt->length);
  952. if( pRealSMHandle->pEncClientRandom == NULL ) {
  953. DC_QUIT;
  954. }
  955. /********************************************************************/
  956. /* copy the client random, set the appropriate flags and signal it. */
  957. /********************************************************************/
  958. memcpy(
  959. pRealSMHandle->pEncClientRandom,
  960. (PBYTE)(pSecPkt + 1),
  961. pSecPkt->length );
  962. pRealSMHandle->recvdClientRandom = TRUE;
  963. /********************************************************************/
  964. /* Shadow stacks go immediately to connected at this stage since */
  965. /* we don't have to wait for the normal initial prog, etc. to come */
  966. /* from the client. */
  967. /********************************************************************/
  968. if (pRealSMHandle->pWDHandle->StackClass == Stack_Shadow) {
  969. pRealSMHandle->pWDHandle->connected = TRUE;
  970. SM_SET_STATE(SM_STATE_CONNECTED);
  971. SM_SET_STATE(SM_STATE_SC_REGISTERED);
  972. SM_Dead(pRealSMHandle, FALSE);
  973. }
  974. KeSetEvent ((pRealSMHandle->pWDHandle)->pSecEvent, 0, FALSE);
  975. }
  976. else {
  977. TRC_ERR((TB, "Unknown security packet flags: %lx", pSecPkt->flags));
  978. }
  979. DC_EXIT_POINT:
  980. DC_END_FN();
  981. return (result);
  982. } /* SMSecurityExchangeKey */
  983. /****************************************************************************/
  984. /* Name: SMFreeInitResources */
  985. /* */
  986. /* Purpose: Free resources allocated at initialization */
  987. /****************************************************************************/
  988. void RDPCALL SMFreeInitResources(PSM_HANDLE_DATA pRealSMHandle)
  989. {
  990. DC_BEGIN_FN("SMFreeInitResources");
  991. /************************************************************************/
  992. /* nothing to free up here. */
  993. /************************************************************************/
  994. DC_END_FN();
  995. } /* SMFreeInitResources */
  996. /****************************************************************************/
  997. /* Name: SMFreeConnectResources */
  998. /* */
  999. /* Purpose: Free resources allocated when a Client connects */
  1000. /* */
  1001. /* Returns: none */
  1002. /* */
  1003. /* Params: pRealSMHandle - SM Handle */
  1004. /* */
  1005. /****************************************************************************/
  1006. void RDPCALL SMFreeConnectResources(PSM_HANDLE_DATA pRealSMHandle)
  1007. {
  1008. DC_BEGIN_FN("SMFreeConnectResources");
  1009. /************************************************************************/
  1010. /* Free the user data (if any) */
  1011. /************************************************************************/
  1012. if (pRealSMHandle->pUserData)
  1013. {
  1014. TRC_NRM((TB, "Free user data"));
  1015. COM_Free(pRealSMHandle->pUserData);
  1016. pRealSMHandle->pUserData = NULL;
  1017. }
  1018. if( pRealSMHandle->pEncClientRandom != NULL ) {
  1019. TRC_NRM((TB, "Free pEncClientRandom"));
  1020. COM_Free(pRealSMHandle->pEncClientRandom);
  1021. pRealSMHandle->pEncClientRandom = NULL;
  1022. }
  1023. DC_END_FN();
  1024. } /* SMFreeClientResources */
  1025. #define NLS_TABLE_KEY \
  1026. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\CodePage"
  1027. BOOL GetNlsTablePath(
  1028. PSM_HANDLE_DATA pRealSMHandle,
  1029. UINT CodePage,
  1030. PWCHAR PathBuffer
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. This routine takes a code page identifier, queries the registry to find the
  1035. appropriate NLS table for that code page, and then returns a path to the
  1036. table.
  1037. Arguments;
  1038. CodePage - specifies the code page to look for
  1039. PathBuffer - Specifies a buffer into which to copy the path of the NLS
  1040. file. This routine assumes that the size is at least MAX_PATH
  1041. Return Value:
  1042. TRUE if successful, FALSE otherwise.
  1043. Gerrit van Wingerden [gerritv] 1/22/96
  1044. -*/
  1045. {
  1046. NTSTATUS NtStatus;
  1047. BOOL Result = FALSE;
  1048. HANDLE RegistryKeyHandle;
  1049. OBJECT_ATTRIBUTES ObjectAttributes;
  1050. UNICODE_STRING UnicodeString;
  1051. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  1052. DC_BEGIN_FN("GetNlsTablePath");
  1053. RtlInitUnicodeString(&UnicodeString, NLS_TABLE_KEY);
  1054. InitializeObjectAttributes(&ObjectAttributes,
  1055. &UnicodeString,
  1056. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1057. NULL,
  1058. NULL);
  1059. NtStatus = ZwOpenKey(&RegistryKeyHandle, GENERIC_READ, &ObjectAttributes);
  1060. if(NT_SUCCESS(NtStatus))
  1061. {
  1062. WCHAR *ResultBuffer;
  1063. ULONG BufferSize = sizeof(WCHAR) * MAX_PATH +
  1064. sizeof(KEY_VALUE_FULL_INFORMATION);
  1065. ResultBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, (ULONG) 'slnG');
  1066. if(ResultBuffer)
  1067. {
  1068. ULONG ValueReturnedLength;
  1069. WCHAR CodePageStringBuffer[20];
  1070. RtlZeroMemory(ResultBuffer, BufferSize);
  1071. swprintf(CodePageStringBuffer, L"%d", CodePage);
  1072. RtlInitUnicodeString(&UnicodeString,CodePageStringBuffer);
  1073. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) ResultBuffer;
  1074. NtStatus = ZwQueryValueKey(RegistryKeyHandle,
  1075. &UnicodeString,
  1076. KeyValuePartialInformation,
  1077. KeyValueInformation,
  1078. BufferSize,
  1079. &BufferSize);
  1080. if(NT_SUCCESS(NtStatus))
  1081. {
  1082. swprintf(PathBuffer,L"\\SystemRoot\\System32\\%ws",
  1083. &(KeyValueInformation->Data[0]));
  1084. Result = TRUE;
  1085. }
  1086. else
  1087. {
  1088. TRC_ERR((TB, "GetNlsTablePath failed to get NLS table\n"));
  1089. }
  1090. ExFreePool((PVOID)ResultBuffer);
  1091. }
  1092. else
  1093. {
  1094. TRC_ERR((TB, "GetNlsTablePath out of memory\n"));
  1095. }
  1096. ZwClose(RegistryKeyHandle);
  1097. }
  1098. else
  1099. {
  1100. TRC_ERR((TB, "GetNlsTablePath failed to open NLS key\n"));
  1101. }
  1102. DC_END_FN();
  1103. return(Result);
  1104. }
  1105. INT ConvertToAndFromWideChar(
  1106. PSM_HANDLE_DATA pRealSMHandle,
  1107. UINT CodePage,
  1108. LPWSTR WideCharString,
  1109. INT BytesInWideCharString,
  1110. LPSTR MultiByteString,
  1111. INT BytesInMultiByteString,
  1112. BOOL ConvertToWideChar
  1113. )
  1114. /*++
  1115. Routine Description:
  1116. This routine converts a character string to or from a wide char string
  1117. assuming a specified code page. Most of the actual work is done inside
  1118. RtlCustomCPToUnicodeN, but this routine still needs to manage the loading
  1119. of the NLS files before passing them to the RtlRoutine. We will cache
  1120. the mapped NLS file for the most recently used code page which ought to
  1121. suffice for out purposes.
  1122. Arguments:
  1123. CodePage - the code page to use for doing the translation.
  1124. WideCharString - buffer the string is to be translated into.
  1125. BytesInWideCharString - number of bytes in the WideCharString buffer
  1126. if converting to wide char and the buffer isn't large enough then the
  1127. string in truncated and no error results.
  1128. MultiByteString - the multibyte string to be translated to Unicode.
  1129. BytesInMultiByteString - number of bytes in the multibyte string if
  1130. converting to multibyte and the buffer isn't large enough the string
  1131. is truncated and no error results
  1132. ConvertToWideChar - if TRUE then convert from multibyte to widechar
  1133. otherwise convert from wide char to multibyte
  1134. Return Value:
  1135. Success - The number of bytes in the converted WideCharString
  1136. Failure - -1
  1137. Gerrit van Wingerden [gerritv] 1/22/96
  1138. -*/
  1139. {
  1140. NTSTATUS NtStatus;
  1141. USHORT OemCodePage, AnsiCodePage;
  1142. CPTABLEINFO LocalTableInfo;
  1143. PCPTABLEINFO TableInfo = NULL;
  1144. PVOID LocalTableBase = NULL;
  1145. INT BytesConverted = 0;
  1146. DC_BEGIN_FN("ConvertToAndFromWideChar");
  1147. // Codepage 0 is not valid
  1148. if (0 == CodePage)
  1149. {
  1150. TRC_ERR((TB, "EngMultiByteToWideChar invalid code page\n"));
  1151. BytesConverted = -1;
  1152. DC_QUIT;
  1153. }
  1154. RtlGetDefaultCodePage(&AnsiCodePage,&OemCodePage);
  1155. // see if we can use the default translation routinte
  1156. if(AnsiCodePage == CodePage)
  1157. {
  1158. if(ConvertToWideChar)
  1159. {
  1160. NtStatus = RtlMultiByteToUnicodeN(WideCharString,
  1161. BytesInWideCharString,
  1162. &BytesConverted,
  1163. MultiByteString,
  1164. BytesInMultiByteString);
  1165. }
  1166. else
  1167. {
  1168. NtStatus = RtlUnicodeToMultiByteN(MultiByteString,
  1169. BytesInMultiByteString,
  1170. &BytesConverted,
  1171. WideCharString,
  1172. BytesInWideCharString);
  1173. }
  1174. if(NT_SUCCESS(NtStatus))
  1175. {
  1176. return(BytesConverted);
  1177. }
  1178. else
  1179. {
  1180. return(-1);
  1181. }
  1182. }
  1183. ExAcquireFastMutex(&fmCodePage);
  1184. if(CodePage == LastCodePageTranslated)
  1185. {
  1186. // we can use the cached code page information
  1187. TableInfo = &LastCPTableInfo;
  1188. NlsTableUseCount += 1;
  1189. }
  1190. ExReleaseFastMutex(&fmCodePage);
  1191. if(TableInfo == NULL)
  1192. {
  1193. // get a pointer to the path of the NLS table
  1194. WCHAR NlsTablePath[MAX_PATH];
  1195. if(GetNlsTablePath(pRealSMHandle, CodePage,NlsTablePath))
  1196. {
  1197. UNICODE_STRING UnicodeString;
  1198. IO_STATUS_BLOCK IoStatus;
  1199. HANDLE NtFileHandle;
  1200. OBJECT_ATTRIBUTES ObjectAttributes;
  1201. RtlInitUnicodeString(&UnicodeString,NlsTablePath);
  1202. InitializeObjectAttributes(&ObjectAttributes,
  1203. &UnicodeString,
  1204. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1205. NULL,
  1206. NULL);
  1207. NtStatus = ZwCreateFile(&NtFileHandle,
  1208. SYNCHRONIZE | FILE_READ_DATA,
  1209. &ObjectAttributes,
  1210. &IoStatus,
  1211. NULL,
  1212. 0,
  1213. FILE_SHARE_READ,
  1214. FILE_OPEN,
  1215. FILE_SYNCHRONOUS_IO_NONALERT,
  1216. NULL,
  1217. 0);
  1218. if(NT_SUCCESS(NtStatus))
  1219. {
  1220. FILE_STANDARD_INFORMATION StandardInfo;
  1221. // Query the object to determine its length.
  1222. NtStatus = ZwQueryInformationFile(NtFileHandle,
  1223. &IoStatus,
  1224. &StandardInfo,
  1225. sizeof(FILE_STANDARD_INFORMATION),
  1226. FileStandardInformation);
  1227. if(NT_SUCCESS(NtStatus))
  1228. {
  1229. UINT LengthOfFile = StandardInfo.EndOfFile.LowPart;
  1230. LocalTableBase = ExAllocatePoolWithTag(PagedPool, LengthOfFile,
  1231. (ULONG)'cwcG');
  1232. if(LocalTableBase)
  1233. {
  1234. RtlZeroMemory(LocalTableBase, LengthOfFile);
  1235. // Read the file into our buffer.
  1236. NtStatus = ZwReadFile(NtFileHandle,
  1237. NULL,
  1238. NULL,
  1239. NULL,
  1240. &IoStatus,
  1241. LocalTableBase,
  1242. LengthOfFile,
  1243. NULL,
  1244. NULL);
  1245. if(!NT_SUCCESS(NtStatus))
  1246. {
  1247. TRC_ERR((TB, "WDMultiByteToWideChar unable to read file\n"));
  1248. ExFreePool((PVOID)LocalTableBase);
  1249. LocalTableBase = NULL;
  1250. }
  1251. }
  1252. else
  1253. {
  1254. TRC_ERR((TB, "WDMultiByteToWideChar out of memory\n"));
  1255. }
  1256. }
  1257. else
  1258. {
  1259. TRC_ERR((TB, "WDMultiByteToWideChar unable query NLS file\n"));
  1260. }
  1261. ZwClose(NtFileHandle);
  1262. }
  1263. else
  1264. {
  1265. TRC_ERR((TB, "EngMultiByteToWideChar unable to open NLS file\n"));
  1266. }
  1267. }
  1268. else
  1269. {
  1270. TRC_ERR((TB, "EngMultiByteToWideChar get registry entry for NLS file failed\n"));
  1271. }
  1272. if(LocalTableBase == NULL)
  1273. {
  1274. return(-1);
  1275. }
  1276. // now that we've got the table use it to initialize the CodePage table
  1277. RtlInitCodePageTable(LocalTableBase,&LocalTableInfo);
  1278. TableInfo = &LocalTableInfo;
  1279. }
  1280. // Once we are here TableInfo points to the the CPTABLEINFO struct we want
  1281. if(ConvertToWideChar)
  1282. {
  1283. NtStatus = RtlCustomCPToUnicodeN(TableInfo,
  1284. WideCharString,
  1285. BytesInWideCharString,
  1286. &BytesConverted,
  1287. MultiByteString,
  1288. BytesInMultiByteString);
  1289. }
  1290. else
  1291. {
  1292. NtStatus = RtlUnicodeToCustomCPN(TableInfo,
  1293. MultiByteString,
  1294. BytesInMultiByteString,
  1295. &BytesConverted,
  1296. WideCharString,
  1297. BytesInWideCharString);
  1298. }
  1299. if(!NT_SUCCESS(NtStatus))
  1300. {
  1301. // signal failure
  1302. BytesConverted = -1;
  1303. }
  1304. // see if we need to update the cached CPTABLEINFO information
  1305. if(TableInfo != &LocalTableInfo)
  1306. {
  1307. // we must have used the cached CPTABLEINFO data for the conversion
  1308. // simple decrement the reference count
  1309. ExAcquireFastMutex(&fmCodePage);
  1310. NlsTableUseCount -= 1;
  1311. ExReleaseFastMutex(&fmCodePage);
  1312. }
  1313. else
  1314. {
  1315. PVOID FreeTable;
  1316. // we must have just allocated a new CPTABLE structure so cache it
  1317. // unless another thread is using current cached entry
  1318. ExAcquireFastMutex(&fmCodePage);
  1319. if(!NlsTableUseCount)
  1320. {
  1321. LastCodePageTranslated = CodePage;
  1322. RtlMoveMemory(&LastCPTableInfo, TableInfo, sizeof(CPTABLEINFO));
  1323. FreeTable = LastNlsTableBuffer;
  1324. LastNlsTableBuffer = LocalTableBase;
  1325. }
  1326. else
  1327. {
  1328. FreeTable = LocalTableBase;
  1329. }
  1330. ExReleaseFastMutex(&fmCodePage);
  1331. // Now free the memory for either the old table or the one we allocated
  1332. // depending on whether we update the cache. Note that if this is
  1333. // the first time we are adding a cached value to the local table, then
  1334. // FreeTable will be NULL since LastNlsTableBuffer will be NULL
  1335. if(FreeTable)
  1336. {
  1337. ExFreePool((PVOID)FreeTable);
  1338. }
  1339. }
  1340. // we are done
  1341. DC_EXIT_POINT:
  1342. DC_END_FN();
  1343. return(BytesConverted);
  1344. }