Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4254 lines
119 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. vrnetapi.c
  5. Abstract:
  6. This module contains routines which support Vdm Redir lanman APIs and
  7. private functions:
  8. VrGetCDNames
  9. VrGetComputerName
  10. VrGetDomainName
  11. VrGetLogonServer
  12. VrGetUserName
  13. VrNetGetDCName
  14. VrNetMessageBufferSend
  15. VrNetNullTransactApi
  16. VrNetRemoteApi
  17. OemToUppercaseUnicode
  18. VrNetServiceControl
  19. VrNetServiceEnum
  20. VrNetServerEnum
  21. VrNetTransactApi
  22. VrNetUseAdd
  23. VrNetUseDel
  24. VrNetUseEnum
  25. VrNetUseGetInfo
  26. VrNetWkstaGetInfo
  27. (DumpWkstaInfo)
  28. VrNetWkstaSetInfo
  29. VrReturnAssignMode
  30. VrSetAssignMode
  31. VrGetAssignListEntry
  32. VrDefineMacro
  33. VrBreakMacro
  34. (VrpTransactVdm)
  35. EncryptPassword
  36. Author:
  37. Richard L Firth (rfirth) 21-Oct-1991
  38. Revision History:
  39. 21-Oct-1991 rfirth
  40. Created
  41. 02-May-1994 rfirth
  42. Upped password limit (& path length limit) to LM20_ values for
  43. VrDefineMacro
  44. --*/
  45. #include <nt.h>
  46. #include <ntrtl.h> // ASSERT, DbgPrint
  47. #include <nturtl.h>
  48. #include <windows.h>
  49. #include <softpc.h> // x86 virtual machine definitions
  50. #include <vrdlctab.h>
  51. #include <vdmredir.h> // common Vdm Redir stuff
  52. #include <lmcons.h> // LM20_PATHLEN
  53. #include <lmerr.h> // lan manager error codes
  54. #include <lmuse.h> // USE_LOTS_OF_FORCE
  55. #include <lmwksta.h> // NetWkstaGetInfo
  56. #include <lmserver.h> // SV_TYPE_ALL
  57. #include <lmapibuf.h> // NetApiBufferFree
  58. #include <vrnetapi.h> // prototypes
  59. #include <vrremote.h> // VrRemoteApi prototypes
  60. #include <packon.h> // structures in apistruc.h are not dword-only
  61. #include <apistruc.h> // tr_packet
  62. #include <packoff.h> // switch back on structure packing
  63. #include <apinums.h> // remotable API numbers
  64. #include <remdef.h> // remotable API descriptors
  65. #include <remtypes.h> // remotable API descriptor characters
  66. #include <rxp.h> // RxpTransactSmb
  67. #include <apiparam.h> // XS_NET_USE_ADD
  68. #include <xstypes.h> // XS_PARAMETER_HEADER
  69. #include <xsprocs.h> // XsNetUseAdd etc
  70. #include <string.h> // Dos still dealing with ASCII
  71. #include <netlibnt.h> // NetpNtStatusToApiStatus()
  72. #include "vrputil.h" // VrpMapDosError()
  73. #include "vrdebug.h" // VrDebugFlags etc
  74. #include "dlstruct.h" // down-level structures
  75. #include <rxuser.h> // RxNetUser...
  76. #include <lmaccess.h> // USER_PASSWORD_PARMNUM
  77. #include <crypt.h> // Needed by NetUserPasswordSet
  78. //
  79. // private routine prototypes
  80. //
  81. #if DBG
  82. VOID
  83. DumpWkstaInfo(
  84. IN DWORD Level,
  85. IN LPBYTE Buffer
  86. );
  87. #endif
  88. NET_API_STATUS
  89. VrpTransactVdm(
  90. IN BOOL NullSessionFlag
  91. );
  92. #if DBG
  93. PRIVATE
  94. VOID
  95. DumpTransactionPacket(
  96. IN struct tr_packet* TransactionPacket,
  97. IN BOOL IsInput,
  98. IN BOOL DumpData
  99. );
  100. #endif
  101. //
  102. // external functions
  103. //
  104. NET_API_STATUS
  105. GetLanmanSessionKey(
  106. IN LPWSTR ServerName,
  107. OUT LPBYTE pSessionKey
  108. );
  109. //
  110. // internal functions (not necessarily private)
  111. //
  112. BOOL
  113. OemToUppercaseUnicode(
  114. IN LPSTR AnsiStringPointer,
  115. OUT LPWSTR UnicodeStringPointer,
  116. IN DWORD MaxLength
  117. );
  118. BOOL
  119. EncryptPassword(
  120. IN LPWSTR ServerName,
  121. IN OUT LPBYTE Password
  122. );
  123. //
  124. // public routines
  125. //
  126. //
  127. // net APIs now unicode
  128. //
  129. #define NET_UNICODE
  130. VOID
  131. VrGetCDNames(
  132. VOID
  133. )
  134. /*++
  135. Routine Description:
  136. Performs the private redir function to get the computer and domain names.
  137. These are usually stored in the redir after they are read out of lanman.ini
  138. NOTE:
  139. This code assumes that the pointers are valid and point to valid,
  140. writable memory which has enough reserved space for the types of
  141. strings to be written
  142. Arguments:
  143. None. All arguments are extracted from the Vdm context registers/memory
  144. The dos redir gets passed a buffer in es:di which contains 3 far pointers
  145. to:
  146. place to store computer name
  147. place to store primary domain controller name
  148. place to store logon domain name
  149. Return Value:
  150. None. Results returned via VDM registers or in VDM memory, according to
  151. request
  152. Note that in the dos redir function, there is no return code, so if this
  153. routine fails the results will be unpredictable
  154. --*/
  155. {
  156. struct I_CDNames* structurePointer;
  157. LPSTR stringPointer;
  158. LPWSTR infoString;
  159. NET_API_STATUS rc1;
  160. NET_API_STATUS rc2;
  161. ANSI_STRING ansiString;
  162. UNICODE_STRING unicodeString;
  163. LPWKSTA_INFO_100 wkstaInfo = NULL;
  164. LPWKSTA_USER_INFO_1 userInfo = NULL;
  165. CHAR ansiBuf[LM20_CNLEN+1];
  166. NTSTATUS status;
  167. register DWORD len;
  168. #if DBG
  169. IF_DEBUG(NETAPI) {
  170. DbgPrint("VrGetCDNames\n");
  171. IF_DEBUG(BREAKPOINT) {
  172. DbgBreakPoint();
  173. }
  174. }
  175. #endif
  176. rc1 = NetWkstaGetInfo(NULL, 100, (LPBYTE*)&wkstaInfo);
  177. rc2 = NetWkstaUserGetInfo(0, 1, (LPBYTE*)&userInfo);
  178. ansiString.MaximumLength = sizeof(ansiBuf);
  179. ansiString.Length = 0;
  180. ansiString.Buffer = ansiBuf;
  181. structurePointer = (struct I_CDNames*)POINTER_FROM_WORDS(getES(), getDI());
  182. stringPointer = POINTER_FROM_POINTER(&structurePointer->CDN_pszComputer);
  183. if (stringPointer) {
  184. *stringPointer = 0;
  185. if (rc1 == NERR_Success) {
  186. infoString = (LPWSTR)wkstaInfo->wki100_computername;
  187. len = wcslen(infoString);
  188. if (len <= LM20_CNLEN) {
  189. RtlInitUnicodeString(&unicodeString, infoString);
  190. status = RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, FALSE);
  191. if (NT_SUCCESS(status)) {
  192. RtlCopyMemory(stringPointer, ansiBuf, len+1);
  193. _strupr(stringPointer);
  194. }
  195. }
  196. }
  197. }
  198. stringPointer = POINTER_FROM_POINTER(&structurePointer->CDN_pszPrimaryDomain);
  199. if (stringPointer) {
  200. *stringPointer = 0;
  201. if (rc1 == NERR_Success) {
  202. infoString = (LPWSTR)wkstaInfo->wki100_langroup;
  203. len = wcslen(infoString);
  204. if (len <= LM20_CNLEN) {
  205. RtlInitUnicodeString(&unicodeString, infoString);
  206. status = RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, FALSE);
  207. if (NT_SUCCESS(status)) {
  208. RtlCopyMemory(stringPointer, ansiBuf, len+1);
  209. _strupr(stringPointer);
  210. }
  211. }
  212. }
  213. }
  214. stringPointer = POINTER_FROM_POINTER(&structurePointer->CDN_pszLogonDomain);
  215. if (stringPointer) {
  216. *stringPointer = 0;
  217. if (rc2 == NERR_Success) {
  218. infoString = (LPWSTR)userInfo->wkui1_logon_domain;
  219. len = wcslen(infoString);
  220. if (len <= LM20_CNLEN) {
  221. RtlInitUnicodeString(&unicodeString, infoString);
  222. status = RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, FALSE);
  223. if (NT_SUCCESS(status)) {
  224. RtlCopyMemory(stringPointer, ansiBuf, len+1);
  225. _strupr(stringPointer);
  226. }
  227. }
  228. }
  229. }
  230. if (wkstaInfo) {
  231. NetApiBufferFree((LPVOID)wkstaInfo);
  232. }
  233. if (userInfo) {
  234. NetApiBufferFree((LPVOID)userInfo);
  235. }
  236. #if DBG
  237. IF_DEBUG(NETAPI) {
  238. DbgPrint("VrGetCDNames: computername=%s, PDCname=%s, logon domain=%s\n\n",
  239. POINTER_FROM_POINTER(&structurePointer->CDN_pszComputer)
  240. ? POINTER_FROM_POINTER(&structurePointer->CDN_pszComputer)
  241. : "",
  242. POINTER_FROM_POINTER(&structurePointer->CDN_pszPrimaryDomain)
  243. ? POINTER_FROM_POINTER(&structurePointer->CDN_pszPrimaryDomain)
  244. : "",
  245. POINTER_FROM_POINTER(&structurePointer->CDN_pszLogonDomain)
  246. ? POINTER_FROM_POINTER(&structurePointer->CDN_pszLogonDomain)
  247. : ""
  248. );
  249. }
  250. #endif
  251. }
  252. VOID
  253. VrGetComputerName(
  254. VOID
  255. )
  256. /*++
  257. Routine Description:
  258. Performs the private redir function to return the computer name stored in
  259. the redir
  260. Arguments:
  261. ENTRY ES:DI = buffer to copy computer name into
  262. Return Value:
  263. None.
  264. --*/
  265. {
  266. BOOL ok;
  267. CHAR nameBuf[MAX_COMPUTERNAME_LENGTH+1];
  268. DWORD nameLen;
  269. #if DBG
  270. IF_DEBUG(NETAPI) {
  271. DbgPrint("VrGetComputerName\n");
  272. }
  273. #endif
  274. nameLen = sizeof(nameBuf)-1;
  275. ok = GetComputerName(nameBuf, &nameLen);
  276. if (!ok) {
  277. SET_ERROR(ERROR_NOT_SUPPORTED);
  278. } else {
  279. if (nameLen > LM20_CNLEN) {
  280. SET_ERROR(NERR_BufTooSmall);
  281. #if DBG
  282. IF_DEBUG(NETAPI) {
  283. DbgPrint("VrGetComputerName returning ERROR %d!\n", getAX());
  284. }
  285. #endif
  286. } else {
  287. strcpy(LPSTR_FROM_WORDS(getES(), getDI()), nameBuf);
  288. setAX(0);
  289. setCF(0);
  290. #if DBG
  291. IF_DEBUG(NETAPI) {
  292. DbgPrint("VrGetComputerName returning %s\n", nameBuf);
  293. }
  294. #endif
  295. }
  296. }
  297. }
  298. VOID
  299. VrGetDomainName(
  300. VOID
  301. )
  302. /*++
  303. Routine Description:
  304. Performs the private redir function to return the primary domain name.
  305. This info is stored in the redir after being read from lanman.ini at
  306. configuration time
  307. Arguments:
  308. None. All arguments are extracted from the Vdm context registers/memory
  309. Return Value:
  310. None. Results returned via VDM registers or in VDM memory, according to
  311. request
  312. --*/
  313. {
  314. #if DBG
  315. IF_DEBUG(NETAPI) {
  316. DbgPrint("VrGetDomainName\n");
  317. IF_DEBUG(BREAKPOINT) {
  318. DbgBreakPoint();
  319. }
  320. }
  321. #endif
  322. #if DBG
  323. IF_DEBUG(NETAPI) {
  324. DbgPrint("VrGetDomainName - unsupported SVC\n");
  325. }
  326. #endif
  327. SET_ERROR(ERROR_NOT_SUPPORTED);
  328. }
  329. VOID
  330. VrGetLogonServer(
  331. VOID
  332. )
  333. /*++
  334. Routine Description:
  335. Performs the private redir function to return the name of the computer
  336. which logged this user onto the network
  337. Arguments:
  338. None. All arguments are extracted from the Vdm context registers/memory
  339. Return Value:
  340. None. Results returned via VDM registers or in VDM memory, according to
  341. request
  342. --*/
  343. {
  344. #if DBG
  345. IF_DEBUG(NETAPI) {
  346. DbgPrint("VrGetLogonServer\n");
  347. IF_DEBUG(BREAKPOINT) {
  348. DbgBreakPoint();
  349. }
  350. }
  351. #endif
  352. #if DBG
  353. IF_DEBUG(NETAPI) {
  354. DbgPrint("VrGetLogonServer - unsupported SVC\n");
  355. }
  356. #endif
  357. SET_ERROR(ERROR_NOT_SUPPORTED);
  358. }
  359. VOID
  360. VrGetUserName(
  361. VOID
  362. )
  363. /*++
  364. Routine Description:
  365. Performs the private redir function to return the logged on user name
  366. which is normally stored in the redir
  367. Arguments:
  368. ENTRY BX = 0 call doesn't care about buffer length (NetGetEnumInfo)
  369. BX = 1 call is for NetGetUserName, which does care about buffer length
  370. CX = buffer length, if BX = 1
  371. ES:DI = buffer
  372. Return Value:
  373. None.
  374. --*/
  375. {
  376. NET_API_STATUS status;
  377. LPBYTE buffer;
  378. LPWKSTA_USER_INFO_0 pInfo;
  379. BOOL itFits;
  380. DWORD len;
  381. #if DBG
  382. IF_DEBUG(NETAPI) {
  383. DbgPrint("VrGetUserName\n");
  384. IF_DEBUG(BREAKPOINT) {
  385. DbgBreakPoint();
  386. }
  387. }
  388. #endif
  389. status = NetWkstaUserGetInfo(NULL, 0, &buffer);
  390. if (status == NERR_Success) {
  391. pInfo = (LPWKSTA_USER_INFO_0)buffer;
  392. #ifdef DBCS /*fix for DBCS char sets*/
  393. len = (DWORD)NetpUnicodeToDBCSLen(pInfo->wkui0_username);
  394. #else // !DBCS
  395. len = (DWORD)wcslen(pInfo->wkui0_username);
  396. #endif // !DBCS
  397. if (getBX()) {
  398. itFits = (len) <= (DWORD)getCX()-1;
  399. if (itFits) {
  400. SET_SUCCESS();
  401. } else {
  402. SET_ERROR(NERR_BufTooSmall);
  403. }
  404. } else {
  405. itFits = TRUE;
  406. }
  407. if (itFits) {
  408. #ifdef DBCS /*fix for DBCS charsets*/
  409. NetpCopyWStrToStrDBCS(LPSTR_FROM_WORDS(getES(), getDI()),
  410. pInfo->wkui0_username);
  411. #else // !DBCS
  412. NetpCopyWStrToStr(LPSTR_FROM_WORDS(getES(), getDI()), pInfo->wkui0_username);
  413. #endif // !DBCS
  414. }
  415. NetApiBufferFree(buffer);
  416. } else {
  417. SET_ERROR((WORD)status);
  418. }
  419. }
  420. VOID
  421. VrNetGetDCName(
  422. VOID
  423. )
  424. /*++
  425. Routine Description:
  426. Performs local NetGetDCName on behalf of the Vdm client
  427. Arguments:
  428. None. All arguments are extracted from the Vdm context registers/memory
  429. Return Value:
  430. None. Results returned via VDM registers or in VDM memory, according to
  431. request
  432. --*/
  433. {
  434. #if DBG
  435. IF_DEBUG(NETAPI) {
  436. DbgPrint("VrGetDCName\n");
  437. IF_DEBUG(BREAKPOINT) {
  438. DbgBreakPoint();
  439. }
  440. }
  441. #endif
  442. #if DBG
  443. IF_DEBUG(NETAPI) {
  444. DbgPrint("VrNetGetDCName - unsupported SVC\n");
  445. }
  446. #endif
  447. SET_ERROR(ERROR_NOT_SUPPORTED);
  448. }
  449. VOID
  450. VrNetMessageBufferSend(
  451. VOID
  452. )
  453. /*++
  454. Routine Description:
  455. Performs local NetMessageBufferSend on behalf of the Vdm client
  456. Arguments:
  457. Function 5F40h
  458. ENTRY DS:DX = NetMessageBufferSendStruc:
  459. char far* NMBSS_NetName;
  460. char far* NMBSS_Buffer;
  461. unsigned int NMBSS_BufSize;
  462. Return Value:
  463. None. Results returned via VDM registers:
  464. CF = 0
  465. Success
  466. CF = 1
  467. AX = Error code
  468. --*/
  469. {
  470. NTSTATUS ntstatus;
  471. NET_API_STATUS status;
  472. XS_PARAMETER_HEADER header;
  473. XS_NET_MESSAGE_BUFFER_SEND parameters;
  474. struct NetMessageBufferSendStruc* structurePointer;
  475. #if DBG
  476. IF_DEBUG(NETAPI) {
  477. DbgPrint("VrNetMessageBufferSend\n");
  478. IF_DEBUG(BREAKPOINT) {
  479. DbgBreakPoint();
  480. }
  481. }
  482. #endif
  483. structurePointer = (struct NetMessageBufferSendStruc*)
  484. POINTER_FROM_WORDS(getDS(), getDX());
  485. parameters.Recipient = LPSTR_FROM_POINTER(&structurePointer->NMBSS_NetName);
  486. parameters.Buffer = LPBYTE_FROM_POINTER(&structurePointer->NMBSS_Buffer);
  487. parameters.BufLen = READ_WORD(&structurePointer->NMBSS_BufSize);
  488. header.Status = 0;
  489. header.ClientMachineName = NULL;
  490. header.ClientTransportName = NULL;
  491. ntstatus = XsNetMessageBufferSend(&header, &parameters, NULL, NULL);
  492. if (ntstatus != STATUS_SUCCESS) {
  493. status = NetpNtStatusToApiStatus(ntstatus);
  494. } else {
  495. status = header.Status;
  496. }
  497. if (status) {
  498. SET_ERROR(VrpMapDosError(status));
  499. #if DBG
  500. IF_DEBUG(NETAPI) {
  501. DbgPrint("VrNetMessageBufferSend: returning %d\n", status);
  502. }
  503. #endif
  504. } else {
  505. setCF(0);
  506. }
  507. }
  508. VOID
  509. VrNetNullTransactApi(
  510. VOID
  511. )
  512. /*++
  513. Routine Description:
  514. Performs a transaction IOCTL using the NULL session for a Vdm client
  515. Arguments:
  516. None. All arguments are extracted from the Vdm context registers/memory
  517. Return Value:
  518. None. Results returned via VDM registers or in VDM memory, according to
  519. request
  520. --*/
  521. {
  522. DWORD status;
  523. #if DBG
  524. IF_DEBUG(NETAPI) {
  525. DbgPrint("VrNetNullTransactApi\n");
  526. IF_DEBUG(BREAKPOINT) {
  527. DbgBreakPoint();
  528. }
  529. }
  530. #endif
  531. status = VrpTransactVdm(TRUE);
  532. if (status) {
  533. SET_ERROR((WORD)status);
  534. } else {
  535. setCF(0);
  536. }
  537. }
  538. VOID
  539. VrNetRemoteApi(
  540. VOID
  541. )
  542. /*++
  543. Routine Description:
  544. This routine is invoked when a dos program in a Vdm makes a lanman API
  545. call which in turn calls the redir NetIRemoteAPI function to send the
  546. request to a lanman server
  547. Arguments:
  548. None. All arguments are extracted from the Vdm context registers/memory
  549. Return Value:
  550. None. Results returned via VDM registers or in VDM memory, according to
  551. request
  552. --*/
  553. {
  554. DWORD ApiNumber;
  555. BOOL NullSessionFlag;
  556. NET_API_STATUS status;
  557. LPBYTE ServerNamePointer = LPBYTE_FROM_WORDS(getES(), getBX());
  558. #define ParameterDescriptor LPSTR_FROM_WORDS(getDS(), getSI())
  559. #define DataDescriptor LPSTR_FROM_WORDS(getDS(), getDI())
  560. #define AuxDescriptor LPSTR_FROM_WORDS(getDS(), getDX())
  561. ApiNumber = (DWORD)getCX();
  562. NullSessionFlag = ApiNumber & USE_NULL_SESSION_FLAG;
  563. ApiNumber &= ~USE_NULL_SESSION_FLAG;
  564. //
  565. // get pointers to the various descriptors which are readable from 32-bit
  566. // context and call the routine to perform the 16-bit remote api function
  567. //
  568. #if DBG
  569. IF_DEBUG(NETAPI) {
  570. DbgPrint("VrNetRemoteApi: ApiNumber=%d, ServerName=%s\n"
  571. "ParmDesc=%s, DataDesc=%s, AuxDesc=%s\n",
  572. ApiNumber,
  573. LPSTR_FROM_POINTER(ServerNamePointer),
  574. ParameterDescriptor,
  575. DataDescriptor,
  576. AuxDescriptor
  577. );
  578. }
  579. #endif
  580. //
  581. // RLF 04/21/93
  582. //
  583. // Yikes! It looks like passwords entered in DOS programs are not getting
  584. // encrypted. What a security hole. Let's block it-
  585. //
  586. // if this is a NetUserPasswordSet2 then we call the RxNetUserPasswordSet
  587. // function to remotely change the password. This function takes care of
  588. // correctly encrypting the password and sending the request over the NULL
  589. // session. In this case, ServerNamePointer points at the server name
  590. // parameter in the following PASCAL calling convention stack frame in DOS
  591. // memory:
  592. //
  593. // tos: far pointer to new password (OEM string)
  594. // far pointer to old password (OEM string)
  595. // far pointer to user name (OEM string)
  596. // far pointer to server name (OEM string) <- ServerNamePointer
  597. //
  598. if (ApiNumber == API_WUserPasswordSet2) {
  599. WCHAR uServerName[LM20_UNCLEN + 1];
  600. WCHAR uUserName[LM20_UNLEN + 1];
  601. WCHAR uOldPassword[LM20_PWLEN + 1];
  602. WCHAR uNewPassword[LM20_PWLEN + 1];
  603. NTSTATUS ntStatus;
  604. DWORD length;
  605. LPSTR ansiStringPointer;
  606. ansiStringPointer = LPSTR_FROM_POINTER(ServerNamePointer);
  607. ntStatus = RtlOemToUnicodeN(uServerName,
  608. sizeof(uServerName) - sizeof(uServerName[0]),
  609. &length,
  610. ansiStringPointer,
  611. strlen(ansiStringPointer)
  612. );
  613. if (NT_SUCCESS(ntStatus)) {
  614. uServerName[length/sizeof(uServerName[0])] = 0;
  615. } else {
  616. status = ERROR_INVALID_PARAMETER;
  617. goto VrNetRemoteApi_exit;
  618. }
  619. //
  620. // copy, upper case and convert to UNICODE, user name
  621. //
  622. ServerNamePointer -= sizeof(LPSTR);
  623. ansiStringPointer = LPSTR_FROM_POINTER(ServerNamePointer);
  624. if (!OemToUppercaseUnicode(ansiStringPointer,
  625. uUserName,
  626. ARRAY_ELEMENTS(uUserName) - 1)) {
  627. status = ERROR_INVALID_PARAMETER;
  628. goto VrNetRemoteApi_exit;
  629. }
  630. //
  631. // copy, upper case and convert to UNICODE, old password
  632. //
  633. ServerNamePointer -= sizeof(LPSTR);
  634. ansiStringPointer = LPSTR_FROM_POINTER(ServerNamePointer);
  635. if (!OemToUppercaseUnicode(ansiStringPointer,
  636. uOldPassword,
  637. ARRAY_ELEMENTS(uOldPassword) - 1)) {
  638. status = ERROR_INVALID_PARAMETER;
  639. goto VrNetRemoteApi_exit;
  640. }
  641. //
  642. // copy, upper case and convert to UNICODE, new password
  643. //
  644. ServerNamePointer -= sizeof(LPSTR);
  645. ansiStringPointer = LPSTR_FROM_POINTER(ServerNamePointer);
  646. if (!OemToUppercaseUnicode(ansiStringPointer,
  647. uNewPassword,
  648. ARRAY_ELEMENTS(uNewPassword) - 1)) {
  649. status = ERROR_INVALID_PARAMETER;
  650. goto VrNetRemoteApi_exit;
  651. }
  652. //
  653. // make the call to the down-level password set function
  654. //
  655. status = RxNetUserPasswordSet((LPTSTR)uServerName,
  656. (LPTSTR)uUserName,
  657. (LPTSTR)uOldPassword,
  658. (LPTSTR)uNewPassword
  659. );
  660. } else {
  661. CHAR aPassword[ENCRYPTED_PWLEN];
  662. LPBYTE parameterPointer;
  663. LPBYTE passwordPointer = NULL;
  664. DWORD passwordEncrypted;
  665. DWORD passwordLength;
  666. //
  667. // we are going to remote the API as requested. However, if the request
  668. // is NetUserAdd2 or NetUserSetInfo2 then we check to see if a password
  669. // is being sent over the wire. We may need to encrypt the password on
  670. // behalf of the DOS app
  671. //
  672. if (ApiNumber == API_WUserAdd2 || ApiNumber == API_WUserSetInfo2) {
  673. //
  674. // API request is to add a user or set a user's info. The former will
  675. // contain a password which needs to be encrypted, the latter MAY
  676. // contain a password which needs to be encrypted if the request is
  677. // to set all the information, or just the password
  678. //
  679. DWORD level;
  680. DWORD parmNum = PARMNUM_ALL;
  681. LPBYTE dataLengthPointer;
  682. //
  683. // in the case of NetUserAdd2, the stack frame in DOS memory looks like
  684. // this:
  685. //
  686. // tos: original password length
  687. // password encryption flag
  688. // buffer length
  689. // far pointer to buffer containing user_info_1 or user_info_2
  690. // info level
  691. // far pointer to server name <- ServerNamePointer
  692. //
  693. // and the NetUserSetInfo2 stack looks like this:
  694. //
  695. // tos: original password length
  696. // password encryption flag
  697. // parameter number
  698. // buffer length
  699. // far pointer to user_info_1 or user_info_2 or single parameter
  700. // info level
  701. // far pointer to user name
  702. // far pointer to server name <- ServerNamePointer
  703. //
  704. parameterPointer = ServerNamePointer;
  705. if (ApiNumber == API_WUserSetInfo2) {
  706. //
  707. // for SetInfo: bump the stack parameter pointer past the user
  708. // name pointer
  709. //
  710. parameterPointer -= sizeof(LPSTR);
  711. }
  712. //
  713. // bump the stack parameter pointer to the level parameter and
  714. // retrieve it
  715. //
  716. parameterPointer -= sizeof(WORD);
  717. level = (DWORD)READ_WORD(parameterPointer);
  718. //
  719. // bump the stack parameter pointer to point to the buffer address
  720. //
  721. parameterPointer -= sizeof(LPBYTE);
  722. passwordPointer = parameterPointer;
  723. //
  724. // move the stack parameter pointer to the password encryption flag
  725. // in the case of UserAdd2 or the parmNum parameter in the case of
  726. // SetInfo2. If SetInfo2, retrieve the parmNum parameter and move
  727. // the parameterPointer to point at the password encryption flag
  728. //
  729. parameterPointer -= sizeof(WORD);
  730. if (ApiNumber == API_WUserSetInfo2) {
  731. dataLengthPointer = parameterPointer;
  732. }
  733. parameterPointer -= sizeof(WORD);
  734. if (ApiNumber == API_WUserSetInfo2) {
  735. parmNum = (DWORD)READ_WORD(parameterPointer);
  736. parameterPointer -= sizeof(WORD);
  737. }
  738. //
  739. // get the password encryption flag and cleartext password length
  740. // from the DOS stack frame. Leave the stack frame pointer pointing
  741. // at the location for the encryption flag: we'll need to replace
  742. // this with TRUE and restore it before we return control
  743. //
  744. passwordEncrypted = (DWORD)READ_WORD(parameterPointer);
  745. passwordLength = (DWORD)READ_WORD(parameterPointer - sizeof(WORD));
  746. //
  747. // if the DOS app has already encrypted the password (how'd it do that?)
  748. // then we'll leave the password alone. Otherwise, we need to read
  749. // out the cleartext password from the user_info_1 or _2 structure
  750. // or SetInfo buffer, encrypt it and write back the encrypted
  751. // password, submit the request, then replace the encrypted password
  752. // in DOS memory with the original cleartext password.
  753. //
  754. // Note: passwordEncrypted might be 0 because this is a SetInfo2
  755. // call which is NOT setting the password
  756. //
  757. if (!passwordEncrypted
  758. && (parmNum == PARMNUM_ALL || parmNum == USER_PASSWORD_PARMNUM)
  759. && (level == 1 || level == 2)) {
  760. LM_OWF_PASSWORD lmOwfPassword;
  761. LM_SESSION_KEY lanmanKey;
  762. ENCRYPTED_LM_OWF_PASSWORD encryptedLmOwfPassword;
  763. NTSTATUS ntStatus;
  764. WCHAR uServerName[LM20_CNLEN + 1];
  765. DWORD length;
  766. LPSTR lpServerName;
  767. //
  768. // get into passwordPointer the address of the buffer. If UserAdd2
  769. // or SetInfo2 with PARMNUM_ALL, this is the address of a
  770. // user_info_1 or _2 structure, and we need to bump the pointer
  771. // again to be the address of the password field within the
  772. // structure.
  773. //
  774. // If the request is SetInfo2 with USER_PASSWORD_PARMNUM then
  775. // the buffer is the address of the password to set.
  776. //
  777. // Otherwise, this is a SetInfo2 call which is not setting a
  778. // password, so we don't have anything left to do
  779. //
  780. // if this is a SetInfo2 call with USER_PASSWORD_PARMNUM then
  781. // we have a slight kludge to perform. We need to encrypt the
  782. // password in 16-bit memory space, but if we just copy over
  783. // the cleartext password then we risk blatting over whatever
  784. // is in memory after the password. We have reserved a 16-byte
  785. // buffer in REDIR.EXE at CS:AX for this very purpose
  786. //
  787. if (parmNum == USER_PASSWORD_PARMNUM) {
  788. RtlCopyMemory(POINTER_FROM_WORDS(getCS(), getAX()),
  789. LPBYTE_FROM_POINTER(passwordPointer),
  790. ENCRYPTED_PWLEN
  791. );
  792. //
  793. // set the address of the buffer in the stack to point to
  794. // the encryption buffer in REDIR.EXE
  795. //
  796. WRITE_WORD(passwordPointer, getAX());
  797. WRITE_WORD(passwordPointer+2, getCS());
  798. passwordPointer = POINTER_FROM_WORDS(getCS(), getAX());
  799. } else {
  800. passwordPointer = LPBYTE_FROM_POINTER(passwordPointer);
  801. }
  802. //
  803. // BUGBUG - I have no idea (currently) if we ever get a NULL
  804. // pointer, but I think it is wrong. If we do, just
  805. // skip ahead and remote the function - let the
  806. // server handle it
  807. //
  808. if (!passwordPointer) {
  809. goto VrNetRemoteApi_do_remote;
  810. }
  811. //
  812. // if passwordPointer currently points at a user_info_1 or
  813. // user_info_2 structure, bump it to point at the password
  814. // field within the structure
  815. //
  816. if (parmNum == PARMNUM_ALL) {
  817. passwordPointer += (DWORD)&((struct user_info_1*)0)->usri1_password[0];
  818. }
  819. //
  820. // if the password is NULL_USERSETINFO_PASSWD (14 spaces and
  821. // terminating 0) there is nothing to do
  822. //
  823. if (!strcmp(passwordPointer, NULL_USERSETINFO_PASSWD)) {
  824. passwordPointer = NULL;
  825. goto VrNetRemoteApi_do_remote;
  826. }
  827. //
  828. // okay, let's do some encryption (exciting isn't it?)
  829. //
  830. RtlCopyMemory(aPassword,
  831. passwordPointer,
  832. sizeof(((struct user_info_1*)0)->usri1_password)
  833. );
  834. //
  835. // BUGBUG, this isn't necessarily the correct upper-case function
  836. //
  837. _strupr(aPassword);
  838. //
  839. // convert the ANSI server name to UNICODE for GetLanmanSessionKey
  840. //
  841. lpServerName = LPSTR_FROM_POINTER(ServerNamePointer);
  842. ntStatus = RtlOemToUnicodeN(uServerName,
  843. sizeof(uServerName) - sizeof(uServerName[0]),
  844. &length,
  845. lpServerName,
  846. strlen(lpServerName)
  847. );
  848. if (NT_SUCCESS(ntStatus)) {
  849. uServerName[length/sizeof(uServerName[0])] = 0;
  850. } else {
  851. status = ERROR_INVALID_PARAMETER;
  852. goto VrNetRemoteApi_exit;
  853. }
  854. ntStatus = RtlCalculateLmOwfPassword(aPassword, &lmOwfPassword);
  855. if (NT_SUCCESS(ntStatus)) {
  856. ntStatus = GetLanmanSessionKey((LPWSTR)uServerName, (LPBYTE)&lanmanKey);
  857. if (NT_SUCCESS(ntStatus)) {
  858. ntStatus = RtlEncryptLmOwfPwdWithLmSesKey(&lmOwfPassword,
  859. &lanmanKey,
  860. &encryptedLmOwfPassword
  861. );
  862. if (NT_SUCCESS(ntStatus)) {
  863. RtlCopyMemory(passwordPointer,
  864. &encryptedLmOwfPassword,
  865. sizeof(encryptedLmOwfPassword)
  866. );
  867. //
  868. // fake it
  869. //
  870. WRITE_WORD(parameterPointer, 1);
  871. //
  872. // if this is SetInfo2 with USER_PASSWORD_PARMNUM
  873. // then we don't need to copy back the cleartext
  874. // password because we have not modified the
  875. // original buffer in the app's space
  876. //
  877. // We also have to change the size of data being
  878. // passed in to the size of the encrypted password
  879. //
  880. if (parmNum == USER_PASSWORD_PARMNUM) {
  881. WRITE_WORD(dataLengthPointer, ENCRYPTED_PWLEN);
  882. passwordPointer = NULL;
  883. }
  884. }
  885. }
  886. }
  887. //
  888. // if we fell by the wayside, quit out
  889. //
  890. if (!NT_SUCCESS(ntStatus)) {
  891. status = RtlNtStatusToDosError(ntStatus);
  892. goto VrNetRemoteApi_exit;
  893. }
  894. } else {
  895. //
  896. // we are not encrypting the password - set the pointer back
  897. // to NULL. Used as a flag after call to VrRemoteApi
  898. //
  899. passwordPointer = NULL;
  900. }
  901. }
  902. //
  903. // build a transaction request from the caller's parameters
  904. //
  905. VrNetRemoteApi_do_remote:
  906. status = VrRemoteApi(ApiNumber,
  907. ServerNamePointer,
  908. ParameterDescriptor,
  909. DataDescriptor,
  910. AuxDescriptor,
  911. NullSessionFlag
  912. );
  913. //
  914. // if we replaced a cleartext password with an encrypted password in
  915. // DOS memory, then undo the change before giving control back to DOS
  916. //
  917. if (passwordPointer) {
  918. RtlCopyMemory(passwordPointer,
  919. aPassword,
  920. sizeof(((struct user_info_1*)0)->usri1_password)
  921. );
  922. WRITE_WORD(parameterPointer, 0);
  923. }
  924. }
  925. VrNetRemoteApi_exit:
  926. if (status != NERR_Success) {
  927. SET_ERROR((WORD)status);
  928. #if DBG
  929. IF_DEBUG(NETAPI) {
  930. DbgPrint("Error: VrNetRemoteApi returning %u\n", (DWORD)getAX());
  931. }
  932. #endif
  933. } else {
  934. setCF(0);
  935. }
  936. }
  937. BOOL
  938. OemToUppercaseUnicode(
  939. IN LPSTR AnsiStringPointer,
  940. OUT LPWSTR UnicodeStringPointer,
  941. IN DWORD MaxLength
  942. )
  943. /*++
  944. Routine Description:
  945. given a string in OEM character set, upper cases it then converts it to
  946. UNICODE
  947. Arguments:
  948. AnsiStringPointer - pointer to 8-bit string to convert
  949. UnicodeStringPointer - pointer to resultant 16-bit (UNICODE) string
  950. MaxLength - maximum output buffer length in # of characters,
  951. NOT including terminating NUL
  952. Return Value:
  953. BOOL
  954. TRUE - string converted
  955. FALSE - failed for some reason (string too long, Rtl function failed)
  956. --*/
  957. {
  958. DWORD stringLength;
  959. char scratchpad[UNLEN + 1]; // UNLEN is the largest type of string we'll get
  960. NTSTATUS ntStatus;
  961. DWORD length;
  962. stringLength = strlen(AnsiStringPointer);
  963. if (stringLength > MaxLength) {
  964. return FALSE;
  965. }
  966. strcpy(scratchpad, AnsiStringPointer);
  967. //
  968. // BUGBUG - this is not necessarily the correct upper-case function
  969. //
  970. _strupr(scratchpad);
  971. ntStatus = RtlOemToUnicodeN(UnicodeStringPointer,
  972. MaxLength * sizeof(*UnicodeStringPointer),
  973. &length,
  974. scratchpad,
  975. stringLength
  976. );
  977. if (NT_SUCCESS(ntStatus)) {
  978. UnicodeStringPointer[length/sizeof(*UnicodeStringPointer)] = 0;
  979. return TRUE;
  980. } else {
  981. return FALSE;
  982. }
  983. }
  984. VOID
  985. VrNetServerEnum(
  986. VOID
  987. )
  988. /*++
  989. Routine Description:
  990. Handles NetServerEnum and NetServerEnum2
  991. Arguments:
  992. NetServerEnum
  993. ENTRY AL = 4Ch
  994. BL = level (0 or 1)
  995. CX = size of buffer
  996. ES:DI = buffer
  997. EXIT CF = 1
  998. AX = Error code:
  999. NERR_BufTooSmall
  1000. ERROR_MORE_DATA
  1001. CF = 0
  1002. BX = entries read
  1003. CX = total available
  1004. NetServerEnum2
  1005. ENTRY AL = 53h
  1006. DS:SI = NetServerEnum2Struct:
  1007. DW Level
  1008. DD Buffer
  1009. DW Buflen
  1010. DD Type
  1011. DD Domain
  1012. EXIT CF = 1
  1013. AX = Error code:
  1014. NERR_BufTooSmall
  1015. ERROR_MORE_DATA
  1016. CF = 0
  1017. BX = entries read
  1018. CX = total available
  1019. Return Value:
  1020. None.
  1021. --*/
  1022. {
  1023. BYTE callType = getAL();
  1024. struct NetServerEnum2Struct* structPtr;
  1025. LPBYTE buffer;
  1026. WORD bufferSegment;
  1027. WORD bufferOffset;
  1028. LPDESC descriptor;
  1029. WORD level;
  1030. WORD buflen;
  1031. DWORD serverType;
  1032. LPSTR domain;
  1033. XS_NET_SERVER_ENUM_2 parameters;
  1034. XS_PARAMETER_HEADER header;
  1035. NTSTATUS ntstatus;
  1036. NET_API_STATUS status;
  1037. // LPBYTE enumPtr;
  1038. // DWORD nRead;
  1039. // DWORD nAvail;
  1040. #if DBG
  1041. IF_DEBUG(NETAPI) {
  1042. DbgPrint("VrNetServerEnum: type=0x%02x\n", callType);
  1043. IF_DEBUG(BREAKPOINT) {
  1044. DbgBreakPoint();
  1045. }
  1046. }
  1047. #endif
  1048. if (callType == 0x4c) {
  1049. //
  1050. // call is NetServerEnum
  1051. //
  1052. bufferSegment = getES();
  1053. bufferOffset = getDI();
  1054. buffer = LPBYTE_FROM_WORDS(bufferSegment, bufferOffset);
  1055. buflen = (WORD)getCX();
  1056. level = (WORD)getBL();
  1057. serverType = SV_TYPE_ALL;
  1058. domain = NULL;
  1059. } else {
  1060. //
  1061. // call is NetServerEnum2
  1062. //
  1063. structPtr = (struct NetServerEnum2Struct*)POINTER_FROM_WORDS(getDS(), getSI());
  1064. bufferSegment = GET_SEGMENT(&structPtr->NSE_buf);
  1065. bufferOffset = GET_OFFSET(&structPtr->NSE_buf);
  1066. buffer = POINTER_FROM_WORDS(bufferSegment, bufferOffset);
  1067. buflen = READ_WORD(&structPtr->NSE_buflen);
  1068. level = READ_WORD(&structPtr->NSE_level);
  1069. serverType = READ_DWORD(&structPtr->NSE_type);
  1070. domain = LPSTR_FROM_POINTER(&structPtr->NSE_domain);
  1071. }
  1072. //
  1073. // set the returned EntriesRead (BX) and TotalAvail (CX) to zero here for
  1074. // the benefit of the 16-bit Windows NETAPI.DLL!NetServerEnum2
  1075. // This function tries to unpack BX entries from the enum buffer as
  1076. // soon as control is returned after the call to the redir via DoIntx. BUT
  1077. // IT DOESN'T LOOK AT THE RETURN CODE FIRST. As Sam Kinnison used to say
  1078. // AAAAAAAAAAAAAAARRRRRGH AAAAAAARGHH AAAAAAARGHHHHHHH!!!!!!!
  1079. //
  1080. setBX(0);
  1081. setCX(0);
  1082. //
  1083. // first, check level - both types only handle 0 or 1
  1084. //
  1085. switch (level) {
  1086. case 0:
  1087. descriptor = REM16_server_info_0;
  1088. break;
  1089. case 1:
  1090. descriptor = REM16_server_info_1;
  1091. break;
  1092. //
  1093. // levels 2 & 3 not used in enum
  1094. //
  1095. default:
  1096. #if DBG
  1097. IF_DEBUG(NETAPI) {
  1098. DbgPrint("VrNetServerEnum - invalid level %d. Returning early\n", level);
  1099. }
  1100. #endif
  1101. SET_ERROR(ERROR_INVALID_LEVEL);
  1102. return;
  1103. }
  1104. parameters.Level = level;
  1105. parameters.Buffer = buffer;
  1106. parameters.BufLen = buflen;
  1107. parameters.ServerType = serverType;
  1108. parameters.Domain = domain;
  1109. #if DBG
  1110. IF_DEBUG(NETAPI) {
  1111. DbgPrint("buffer @%04x:%04x, length=%d, level=%d, type=0x%08x, domain=%s\n",
  1112. bufferSegment, bufferOffset, parameters.BufLen, level,
  1113. parameters.ServerType, parameters.Domain
  1114. );
  1115. }
  1116. #endif
  1117. // //
  1118. // // I_BrowserServerEnum which XsNetServerEnum2 calls requires a transport
  1119. // // name. If we don't give it one, it'll return ERROR_INVALID_PARAMETER
  1120. // //
  1121. //
  1122. // status = NetWkstaTransportEnum(NULL,
  1123. // 0,
  1124. // &enumPtr,
  1125. // -1L, // we'll take everything
  1126. // &nRead, // number returned
  1127. // &nAvail, // total available
  1128. // NULL // no resume handle
  1129. // );
  1130. // if (status != NERR_Success) {
  1131. //
  1132. //#if DBG
  1133. // IF_DEBUG(NETAPI) {
  1134. // DbgPrint("VrNetServerEnum: Error: NetWkstaTransportEnum returns %d\n", status);
  1135. // }
  1136. //#endif
  1137. //
  1138. // SET_ERROR(status);
  1139. // return;
  1140. // }
  1141. header.Status = 0;
  1142. header.ClientMachineName = NULL;
  1143. //
  1144. // use the first enumerated transport name
  1145. //
  1146. // header.ClientTransportName = ((LPWKSTA_TRANSPORT_INFO_0)enumPtr)->wkti0_transport_name;
  1147. header.ClientTransportName = NULL;
  1148. ntstatus = XsNetServerEnum2(&header, &parameters, descriptor, NULL);
  1149. if (!NT_SUCCESS(ntstatus)) {
  1150. status = NetpNtStatusToApiStatus(ntstatus);
  1151. } else {
  1152. status = (NET_API_STATUS)header.Status;
  1153. }
  1154. if (status == NERR_Success) {
  1155. SET_SUCCESS();
  1156. } else {
  1157. SET_ERROR((WORD)status);
  1158. }
  1159. if (status == NERR_Success || status == ERROR_MORE_DATA) {
  1160. if (parameters.EntriesRead) {
  1161. VrpConvertReceiveBuffer(buffer,
  1162. bufferSegment,
  1163. bufferOffset,
  1164. header.Converter,
  1165. parameters.EntriesRead,
  1166. descriptor,
  1167. NULL
  1168. );
  1169. }
  1170. setBX(parameters.EntriesRead);
  1171. setCX(parameters.TotalAvail);
  1172. }
  1173. #if DBG
  1174. IF_DEBUG(NETAPI) {
  1175. DbgPrint("VrNetServerEnum: returning %d for NetServerEnum2\n", getAX());
  1176. if (getAX() == NERR_Success || getAX() == ERROR_MORE_DATA) {
  1177. DbgPrint("EntriesRead=%d, TotalAvail=%d\n",
  1178. parameters.EntriesRead,
  1179. parameters.TotalAvail
  1180. );
  1181. }
  1182. }
  1183. #endif
  1184. // //
  1185. // // free up the buffer returned by NetWkstaTransportEnum
  1186. // //
  1187. //
  1188. // NetApiBufferFree(enumPtr);
  1189. }
  1190. VOID
  1191. VrNetServiceControl(
  1192. VOID
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. We allow the interrogate function for specific services. The other functions
  1197. are pause, continue and stop (uninstall) which we disallow
  1198. Arguments:
  1199. Function 5F42
  1200. DL = opcode:
  1201. 0 = interrogate SUPPORTED
  1202. 1 = pause service * NOT SUPPORTED *
  1203. 2 = continue service * NOT SUPPORTED *
  1204. 3 = uninstall service * NOT SUPPORTED *
  1205. 4 - 127 = reserved
  1206. 127 - 255 = OEM defined
  1207. DH = OEM defined argument
  1208. ES:BX = NetServiceControl structure:
  1209. char far* service name
  1210. unsigned short buffer length
  1211. char far* buffer
  1212. Return Value:
  1213. None.
  1214. --*/
  1215. {
  1216. BYTE opcode = getDL();
  1217. BYTE oemArg = getDH();
  1218. struct NetServiceControlStruc* structPtr = (struct NetServiceControlStruc*)
  1219. POINTER_FROM_WORDS(getES(), getBX());
  1220. LPSTR serviceName = READ_FAR_POINTER(&structPtr->NSCS_Service);
  1221. WORD buflen = READ_WORD(&structPtr->NSCS_BufLen);
  1222. LPSTR buffer = READ_FAR_POINTER(&structPtr->NSCS_BufferAddr);
  1223. WORD seg = GET_SEGMENT(&structPtr->NSCS_BufferAddr);
  1224. WORD off = GET_OFFSET(&structPtr->NSCS_BufferAddr);
  1225. XS_NET_SERVICE_CONTROL parameters;
  1226. XS_PARAMETER_HEADER header;
  1227. NTSTATUS ntstatus;
  1228. NET_API_STATUS status;
  1229. #if DBG
  1230. IF_DEBUG(NETAPI) {
  1231. DbgPrint("VrNetServiceControl: Service=%s, Opcode=%d, OemArg=%d, Buffer @%04x:%04x, len=%d\n",
  1232. serviceName,
  1233. opcode,
  1234. oemArg,
  1235. seg,
  1236. off,
  1237. buflen
  1238. );
  1239. }
  1240. #endif
  1241. if (opcode > 4) {
  1242. SET_ERROR(NERR_ServiceCtlNotValid);
  1243. return;
  1244. }
  1245. //
  1246. // we are disallowing anything other than 0 (interrogate) by returning
  1247. // ERROR_INVALID_PARAMETER, which may be a new error code
  1248. //
  1249. if (opcode) {
  1250. SET_ERROR(ERROR_INVALID_PARAMETER);
  1251. return;
  1252. }
  1253. //
  1254. // KLUDGE - if the service name is NETPOPUP then we return NERR_ServiceNotInstalled.
  1255. // LANMAN.DRV checks to see if this service is loaded. If it is then
  1256. // it sticks Load=WinPopUp in WIN.INI. We don't want it to do this
  1257. //
  1258. if (!_stricmp(serviceName, NETPOPUP_SERVICE)) {
  1259. //
  1260. // roll our own service_info_2 structure
  1261. //
  1262. if (buflen >= sizeof(struct service_info_2)) {
  1263. SET_ERROR(NERR_ServiceNotInstalled);
  1264. } else {
  1265. SET_ERROR(NERR_BufTooSmall);
  1266. }
  1267. return;
  1268. }
  1269. //
  1270. // leave the work to XsNetServiceControl
  1271. //
  1272. parameters.Service = serviceName;
  1273. parameters.OpCode = opcode;
  1274. parameters.Arg = oemArg;
  1275. parameters.Buffer = buffer;
  1276. parameters.BufLen = buflen;
  1277. header.Status = 0;
  1278. header.ClientMachineName = NULL;
  1279. header.ClientTransportName = NULL;
  1280. ntstatus = XsNetServiceControl(&header, &parameters, REM16_service_info_2, NULL);
  1281. if (!NT_SUCCESS(ntstatus)) {
  1282. status = NetpNtStatusToApiStatus(ntstatus);
  1283. } else {
  1284. status = (NET_API_STATUS)header.Status;
  1285. }
  1286. #if DBG
  1287. IF_DEBUG(NETAPI) {
  1288. DbgPrint("VrNetServiceControl: returning %d\n", status);
  1289. }
  1290. #endif
  1291. if (status == NERR_Success || status == ERROR_MORE_DATA) {
  1292. //
  1293. // there are no pointers in a service_info_2 structure, so there is
  1294. // no need to call VrpConvertReceiveBuffer. Also, we are not going to
  1295. // allow the DOS process to pause, continue, start or stop any of our
  1296. // 32-bit services, so we must tell the DOS app that the service
  1297. // cannot accept these controls: zero out bit 4
  1298. // (SERVICE_NOT_UNINSTALLABLE) and bit 5 (SERVICE_NOT_PAUSABLE)
  1299. //
  1300. ((struct service_info_2*)buffer)->svci2_status &= 0xff0f;
  1301. SET_OK((WORD)status);
  1302. } else {
  1303. SET_ERROR((WORD)status);
  1304. }
  1305. }
  1306. VOID
  1307. VrNetServiceEnum(
  1308. VOID
  1309. )
  1310. /*++
  1311. Routine Description:
  1312. description-of-function.
  1313. Arguments:
  1314. None.
  1315. Return Value:
  1316. None.
  1317. --*/
  1318. {
  1319. SET_ERROR(ERROR_NOT_SUPPORTED);
  1320. }
  1321. VOID
  1322. VrNetTransactApi(
  1323. VOID
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. Performs a transaction on behalf of the Vdm
  1328. Arguments:
  1329. None. All arguments are extracted from the Vdm context registers/memory
  1330. Return Value:
  1331. None. Results returned via VDM registers or in VDM memory, according to
  1332. request
  1333. --*/
  1334. {
  1335. DWORD status;
  1336. #if DBG
  1337. IF_DEBUG(NETAPI) {
  1338. DbgPrint("VrNetTransactApi\n");
  1339. IF_DEBUG(BREAKPOINT) {
  1340. DbgBreakPoint();
  1341. }
  1342. }
  1343. #endif
  1344. status = VrpTransactVdm(FALSE);
  1345. if (status) {
  1346. SET_ERROR((WORD)status);
  1347. } else {
  1348. setCF(0);
  1349. }
  1350. }
  1351. VOID
  1352. VrNetUseAdd(
  1353. VOID
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. Performs local NetUseAdd on behalf of the Vdm client
  1358. Arguments:
  1359. Function 5F47h
  1360. ENTRY BX = level
  1361. CX = buffer length
  1362. DS:SI = server name for remote call (MBZ)
  1363. ES:DI = buffer containing use_info_1 structure
  1364. Return Value:
  1365. None.
  1366. --*/
  1367. {
  1368. NET_API_STATUS status;
  1369. XS_NET_USE_ADD parameters;
  1370. XS_PARAMETER_HEADER header;
  1371. NTSTATUS ntstatus;
  1372. LPSTR computerName;
  1373. LPBYTE buffer;
  1374. WORD level;
  1375. BOOL allocated;
  1376. DWORD buflen;
  1377. DWORD auxOffset;
  1378. char myDescriptor[sizeof(REM16_use_info_1)];
  1379. char myDataBuffer[sizeof(struct use_info_1) + LM20_PWLEN + 1];
  1380. #if DBG
  1381. IF_DEBUG(NETAPI) {
  1382. DbgPrint("VrNetUseAdd\n");
  1383. IF_DEBUG(BREAKPOINT) {
  1384. DbgBreakPoint();
  1385. }
  1386. }
  1387. #endif
  1388. //
  1389. // ensure the computer name designates the local machine (NULL)
  1390. //
  1391. computerName = LPSTR_FROM_WORDS(getDS(), getSI());
  1392. level = (WORD)getBX();
  1393. if (level != 1) {
  1394. //
  1395. // level must be 1 for an add
  1396. //
  1397. SET_ERROR(ERROR_INVALID_LEVEL);
  1398. return;
  1399. }
  1400. //
  1401. // preset the modifiable descriptor string
  1402. //
  1403. strcpy(myDescriptor, REM16_use_info_1);
  1404. //
  1405. // pack the use_info_1 buffer as if we were getting ready to ship it over
  1406. // the net. Return errors
  1407. //
  1408. buffer = LPBYTE_FROM_WORDS(getES(), getDI());
  1409. buflen = (DWORD)getCX();
  1410. //
  1411. // copy the DOS buffer to 32-bit memory. Do this to avoid irritating problem
  1412. // of getting an already packed buffer from the client, and not being able
  1413. // to do anything with it
  1414. //
  1415. RtlCopyMemory(myDataBuffer, buffer, sizeof(struct use_info_1));
  1416. buffer = myDataBuffer;
  1417. buflen = sizeof(myDataBuffer);
  1418. status = VrpPackSendBuffer(&buffer,
  1419. &buflen,
  1420. &allocated,
  1421. myDescriptor, // modifiable descriptor
  1422. NULL, // AuxDescriptor
  1423. VrpGetStructureSize(REM16_use_info_1, &auxOffset),
  1424. (DWORD)-1, // AuxOffset (-1 means there is no aux char 'N')
  1425. 0, // AuxSize
  1426. FALSE, // not a SetInfo call
  1427. TRUE // OkToModifyDescriptor
  1428. );
  1429. if (status) {
  1430. SET_ERROR(VrpMapDosError(status));
  1431. return;
  1432. }
  1433. parameters.Level = level;
  1434. parameters.Buffer = buffer;
  1435. parameters.BufLen = (WORD)buflen;
  1436. header.Status = 0;
  1437. header.ClientMachineName = NULL;
  1438. header.ClientTransportName = NULL;
  1439. ntstatus = XsNetUseAdd(&header, &parameters, myDescriptor, NULL);
  1440. if (ntstatus != STATUS_SUCCESS) {
  1441. status = NetpNtStatusToApiStatus(ntstatus);
  1442. } else {
  1443. //
  1444. // no error generated in XsNetUseAdd. Get the status of the NetUseAdd
  1445. // proper from the header
  1446. //
  1447. status = (NET_API_STATUS)header.Status;
  1448. }
  1449. if (status != NERR_Success) {
  1450. #if DBG
  1451. IF_DEBUG(NETAPI) {
  1452. DbgPrint("Error: VrNetUseAdd: XsNetUseAdd returns %u\n", status);
  1453. }
  1454. #endif
  1455. SET_ERROR((WORD)status);
  1456. } else {
  1457. setCF(0);
  1458. }
  1459. //
  1460. // if VrpPackSendBuffer allocated a new buffer then free it
  1461. //
  1462. if (allocated) {
  1463. LocalFree(buffer);
  1464. }
  1465. }
  1466. VOID
  1467. VrNetUseDel(
  1468. VOID
  1469. )
  1470. /*++
  1471. Routine Description:
  1472. Performs local NetUseDel on behalf of the Vdm client
  1473. Arguments:
  1474. Function 5F48h
  1475. ENTRY BX = force flag
  1476. DS:SI = server name for remote call (MBZ)
  1477. ES:DI = use name
  1478. Return Value:
  1479. None.
  1480. --*/
  1481. {
  1482. NTSTATUS ntstatus;
  1483. NET_API_STATUS status;
  1484. WORD force;
  1485. LPSTR name;
  1486. XS_NET_USE_DEL parameters;
  1487. XS_PARAMETER_HEADER header;
  1488. #if DBG
  1489. IF_DEBUG(NETAPI) {
  1490. DbgPrint("VrNetUseDel\n");
  1491. IF_DEBUG(BREAKPOINT) {
  1492. DbgBreakPoint();
  1493. }
  1494. }
  1495. #endif
  1496. force = (WORD)getBX();
  1497. if (force > USE_LOTS_OF_FORCE) {
  1498. SET_ERROR(ERROR_INVALID_PARAMETER);
  1499. return;
  1500. }
  1501. name = LPSTR_FROM_WORDS(getDS(), getSI());
  1502. //
  1503. // make sure name is local
  1504. //
  1505. name = LPSTR_FROM_WORDS(getES(), getDI());
  1506. parameters.UseName = name;
  1507. parameters.Force = force;
  1508. header.Status = 0;
  1509. header.ClientMachineName = NULL;
  1510. header.ClientTransportName = NULL;
  1511. ntstatus = XsNetUseDel(&header, &parameters, NULL, NULL);
  1512. //
  1513. // if XsNetUseDel failed then map the NT error returned into a Net error
  1514. // else get the result of the NetUseDel proper from the header structure
  1515. //
  1516. if (ntstatus != STATUS_SUCCESS) {
  1517. status = NetpNtStatusToApiStatus(ntstatus);
  1518. } else {
  1519. status = (NET_API_STATUS)header.Status;
  1520. }
  1521. if (status != NERR_Success) {
  1522. SET_ERROR(VrpMapDosError(status));
  1523. } else {
  1524. setCF(0);
  1525. }
  1526. }
  1527. VOID
  1528. VrNetUseEnum(
  1529. VOID
  1530. )
  1531. /*++
  1532. Routine Description:
  1533. Performs local NetUseEnum on behalf of the Vdm client
  1534. Arguments:
  1535. Function 5F46h
  1536. ENTRY BX = level of info required - 0 or 1
  1537. CX = buffer length
  1538. ES:DI = buffer for enum info
  1539. Return Value:
  1540. None.
  1541. --*/
  1542. {
  1543. NTSTATUS ntstatus;
  1544. NET_API_STATUS status;
  1545. WORD level = getBX();
  1546. XS_NET_USE_ENUM parameters;
  1547. XS_PARAMETER_HEADER header;
  1548. LPDESC dataDesc;
  1549. LPBYTE receiveBuffer;
  1550. #if DBG
  1551. IF_DEBUG(NETAPI) {
  1552. DbgPrint("VrNetUseEnum\n");
  1553. IF_DEBUG(BREAKPOINT) {
  1554. DbgBreakPoint();
  1555. }
  1556. }
  1557. #endif
  1558. if (level <= 1) {
  1559. dataDesc = (level == 1) ? REM16_use_info_1 : REM16_use_info_0;
  1560. parameters.Level = level;
  1561. receiveBuffer = POINTER_FROM_WORDS(getES(), getDI());
  1562. parameters.Buffer = receiveBuffer;
  1563. parameters.BufLen = getCX();
  1564. header.Status = 0;
  1565. header.ClientMachineName = NULL;
  1566. header.ClientTransportName = NULL;
  1567. ntstatus = XsNetUseEnum(&header, &parameters, dataDesc, NULL);
  1568. //
  1569. // if XsNetUseEnum didn't have any problems, convert the actual status
  1570. // code to that returned in the header
  1571. //
  1572. if (ntstatus != STATUS_SUCCESS) {
  1573. status = NetpNtStatusToApiStatus(ntstatus);
  1574. } else {
  1575. status = (DWORD)header.Status;
  1576. }
  1577. } else {
  1578. status = ERROR_INVALID_LEVEL;
  1579. }
  1580. //
  1581. // NetUseEnum sets these even in the event of failure. We do the same
  1582. //
  1583. setCX(parameters.EntriesRead);
  1584. setDX(parameters.TotalAvail);
  1585. //
  1586. // if we're returning data, convert the pointer offsets to something
  1587. // meaningful
  1588. //
  1589. if (((status == NERR_Success) || (status == ERROR_MORE_DATA))
  1590. && parameters.EntriesRead) {
  1591. VrpConvertReceiveBuffer(receiveBuffer,
  1592. (WORD)getES(),
  1593. (WORD)getDI(),
  1594. (WORD)header.Converter,
  1595. parameters.EntriesRead,
  1596. dataDesc,
  1597. NULL
  1598. );
  1599. }
  1600. //
  1601. // only return carry clear if no error occurred. Even if ERROR_MORE_DATA
  1602. // set CF
  1603. //
  1604. if (status) {
  1605. SET_ERROR(VrpMapDosError(status));
  1606. } else {
  1607. setCF(0);
  1608. }
  1609. }
  1610. VOID
  1611. VrNetUseGetInfo(
  1612. VOID
  1613. )
  1614. /*++
  1615. Routine Description:
  1616. Performs local NetUseGetInfo on behalf of the Vdm client
  1617. Arguments:
  1618. Function 5F49h
  1619. ENTRY DS:DX = NetUseGetInfoStruc:
  1620. const char FAR* NUGI_usename;
  1621. short NUGI_level;
  1622. char FAR* NUGI_buffer;
  1623. unsigned short NUGI_buflen;
  1624. Return Value:
  1625. None.
  1626. --*/
  1627. {
  1628. NTSTATUS ntstatus;
  1629. NET_API_STATUS status;
  1630. XS_NET_USE_GET_INFO parameters;
  1631. XS_PARAMETER_HEADER header;
  1632. struct NetUseGetInfoStruc* structurePointer;
  1633. WORD level;
  1634. LPDESC dataDesc;
  1635. LPBYTE receiveBuffer;
  1636. #if DBG
  1637. IF_DEBUG(NETAPI) {
  1638. DbgPrint("VrNetUseGetInfo\n");
  1639. IF_DEBUG(BREAKPOINT) {
  1640. DbgBreakPoint();
  1641. }
  1642. }
  1643. #endif
  1644. //
  1645. // pull info out of Vdm context
  1646. //
  1647. structurePointer = (struct NetUseGetInfoStruc*)
  1648. POINTER_FROM_WORDS(getDS(), getDX());
  1649. level = structurePointer->NUGI_level;
  1650. //
  1651. // level can be 0 or 1
  1652. //
  1653. if (level <= 1) {
  1654. dataDesc = (level == 1) ? REM16_use_info_1 : REM16_use_info_0;
  1655. #if DBG
  1656. IF_DEBUG(NETAPI) {
  1657. DbgPrint("VrNetUseGetInfo: dataDesc=%s\n", dataDesc);
  1658. }
  1659. #endif
  1660. parameters.UseName= POINTER_FROM_POINTER(&(structurePointer->NUGI_usename));
  1661. #if DBG
  1662. IF_DEBUG(NETAPI) {
  1663. DbgPrint("VrNetUseGetInfo: UseName=%s\n", parameters.UseName);
  1664. }
  1665. #endif
  1666. parameters.Level = level;
  1667. #if DBG
  1668. IF_DEBUG(NETAPI) {
  1669. DbgPrint("VrNetUseGetInfo: level=%d\n", level);
  1670. }
  1671. #endif
  1672. receiveBuffer = POINTER_FROM_POINTER(&(structurePointer->NUGI_buffer));
  1673. #if DBG
  1674. IF_DEBUG(NETAPI) {
  1675. DbgPrint("VrNetUseGetInfo: receiveBuffer=%x\n", receiveBuffer);
  1676. }
  1677. #endif
  1678. parameters.Buffer = receiveBuffer;
  1679. parameters.BufLen = READ_WORD(&structurePointer->NUGI_buflen);
  1680. #if DBG
  1681. IF_DEBUG(NETAPI) {
  1682. DbgPrint("VrNetUseGetInfo: BufLen=%d\n", parameters.BufLen);
  1683. }
  1684. #endif
  1685. header.Status = 0;
  1686. header.ClientMachineName = NULL;
  1687. header.ClientTransportName = NULL;
  1688. ntstatus = XsNetUseGetInfo(&header, &parameters, dataDesc, NULL);
  1689. if (ntstatus != STATUS_SUCCESS) {
  1690. status = NetpNtStatusToApiStatus(ntstatus);
  1691. } else {
  1692. status = header.Status;
  1693. }
  1694. } else {
  1695. status = ERROR_INVALID_LEVEL;
  1696. }
  1697. if ((status == NERR_Success)
  1698. || (status == ERROR_MORE_DATA)
  1699. || (status == NERR_BufTooSmall)
  1700. ) {
  1701. setDX(parameters.TotalAvail);
  1702. #if DBG
  1703. IF_DEBUG(NETAPI) {
  1704. DbgPrint("VrNetUseGetInfo: TotalAvail=%d\n", parameters.TotalAvail);
  1705. }
  1706. #endif
  1707. if ((status == NERR_Success) || (status == ERROR_MORE_DATA)) {
  1708. VrpConvertReceiveBuffer(
  1709. receiveBuffer,
  1710. GET_SELECTOR(&(structurePointer->NUGI_buffer)),
  1711. GET_OFFSET(&(structurePointer->NUGI_buffer)),
  1712. (WORD)header.Converter,
  1713. 1,
  1714. dataDesc,
  1715. NULL
  1716. );
  1717. }
  1718. } else {
  1719. //
  1720. // the first thing NetUseGetInfo does is set the returned total available
  1721. // count to 0. Lets be compatible!
  1722. //
  1723. setDX(0);
  1724. }
  1725. if (status) {
  1726. SET_ERROR(VrpMapDosError(status));
  1727. } else {
  1728. setCF(0);
  1729. }
  1730. }
  1731. VOID
  1732. VrNetWkstaGetInfo(
  1733. VOID
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. Performs local NetWkstaGetInfo on behalf of the Vdm client
  1738. Arguments:
  1739. Function 5F44h
  1740. ENTRY BX = level (0, 1 or 10)
  1741. CX = size of caller's buffer
  1742. DS:SI = computer name for remote call (IGNORED)
  1743. ES:DI = caller's buffer
  1744. Return Value:
  1745. CF = 0
  1746. DX = size of buffer required to honour request
  1747. CF = 1
  1748. AX = error code
  1749. --*/
  1750. {
  1751. DWORD level;
  1752. DWORD bufLen;
  1753. LPBYTE buffer;
  1754. LPDESC dataDesc;
  1755. NET_API_STATUS status;
  1756. NTSTATUS ntStatus;
  1757. XS_PARAMETER_HEADER header;
  1758. XS_NET_WKSTA_GET_INFO parameters;
  1759. WORD bufferSegment;
  1760. WORD bufferOffset;
  1761. INT bufferLeft;
  1762. DWORD totalAvail;
  1763. #if DBG
  1764. IF_DEBUG(NETAPI) {
  1765. DbgPrint("\nVrNetWkstaGetInfo\n");
  1766. IF_DEBUG(BREAKPOINT) {
  1767. DbgBreakPoint();
  1768. }
  1769. }
  1770. #endif
  1771. level = (DWORD)getBX();
  1772. switch (level) {
  1773. case 0:
  1774. dataDesc = REMSmb_wksta_info_0;
  1775. break;
  1776. case 1:
  1777. dataDesc = REMSmb_wksta_info_1;
  1778. break;
  1779. case 10:
  1780. dataDesc = REMSmb_wksta_info_10;
  1781. break;
  1782. default:
  1783. SET_ERROR(ERROR_INVALID_LEVEL);
  1784. #if DBG
  1785. IF_DEBUG(NETAPI) {
  1786. DbgPrint("VrNetWkstaGetInfo: Error: returning %d for level %d\n",
  1787. getAX(),
  1788. level
  1789. );
  1790. }
  1791. #endif
  1792. return;
  1793. }
  1794. bufLen = (DWORD)getCX();
  1795. bufferSegment = getES();
  1796. bufferOffset = getDI();
  1797. buffer = LPBYTE_FROM_WORDS(bufferSegment, bufferOffset);
  1798. if (bufLen && !buffer) {
  1799. SET_ERROR(ERROR_INVALID_PARAMETER);
  1800. #if DBG
  1801. IF_DEBUG(NETAPI) {
  1802. DbgPrint("VrNetWkstaGetInfo: Error: buffer=NULL, buflen=%d\n", bufLen);
  1803. }
  1804. #endif
  1805. return;
  1806. }
  1807. //
  1808. // clear out the caller's buffer - just in case XsNetWkstaGetInfo forgets
  1809. // to fill in some fields
  1810. //
  1811. if (bufLen) {
  1812. RtlZeroMemory(buffer, bufLen);
  1813. }
  1814. #if DBG
  1815. IF_DEBUG(NETAPI) {
  1816. DbgPrint("VrNetWkstaGetInfo: level=%d, bufLen = %d (0x%x), buffer = %x:%x\n",
  1817. level, bufLen, bufLen, bufferSegment, bufferOffset
  1818. );
  1819. }
  1820. #endif
  1821. parameters.Level = (WORD)level;
  1822. parameters.Buffer = buffer;
  1823. parameters.BufLen = (WORD)bufLen;
  1824. header.Status = 0;
  1825. header.Converter = 0;
  1826. header.ClientMachineName = NULL;
  1827. header.ClientTransportName = NULL;
  1828. header.EncryptionKey = NULL;
  1829. ntStatus = XsNetWkstaGetInfo(&header, &parameters, dataDesc, NULL);
  1830. if (!NT_SUCCESS(ntStatus)) {
  1831. status = NetpNtStatusToApiStatus(ntStatus);
  1832. } else {
  1833. status = (NET_API_STATUS)header.Status;
  1834. }
  1835. if (status != NERR_Success) {
  1836. SET_ERROR((WORD)status);
  1837. } else {
  1838. setCF(0);
  1839. setAX((WORD)status);
  1840. }
  1841. #if DBG
  1842. IF_DEBUG(NETAPI) {
  1843. DbgPrint("VrNetWkstaGetInfo: status after XsNetWkstaGetInfo=%d, TotalAvail=%d\n",
  1844. status,
  1845. parameters.TotalAvail
  1846. );
  1847. // DumpWkstaInfo(level, buffer);
  1848. }
  1849. #endif
  1850. //
  1851. // This next bit of code will add the per-user information only if there
  1852. // is space to add all of it - XsNetWkstaGetInfo returns either all the
  1853. // variable data, or none of it. This is incorrect, but we'll play along.
  1854. //
  1855. // Assumes that the variable data is packed into the buffer starting at
  1856. // the end of the fixed structure + 1
  1857. //
  1858. // Irrespective of whether data is returned, we have to update the
  1859. // TotalAvail parameter to reflect the adjusted amount of data
  1860. //
  1861. totalAvail = parameters.TotalAvail;
  1862. bufferLeft = (INT)(bufLen - totalAvail);
  1863. if ((status == NERR_Success)
  1864. || (status == ERROR_MORE_DATA)
  1865. || (status == NERR_BufTooSmall)) {
  1866. //
  1867. // because of NT's ability to instantaneously support more than one
  1868. // user, XsNetWkstaGetInfo no longer returns information pertinent to
  1869. // the current user. Thus, we have to furnish the information from
  1870. // this user's context:
  1871. //
  1872. // field\level 0 1 10
  1873. // ------------------------
  1874. // user name x x x
  1875. // logon server x x
  1876. // logon domain x x
  1877. // other domains x x
  1878. //
  1879. // all this info is returned from NetWkstaUserGetInfo, level 1
  1880. //
  1881. LPBYTE info;
  1882. NET_API_STATUS net_status;
  1883. char username[LM20_UNLEN + 1];
  1884. char logonServer[LM20_UNCLEN + 1];
  1885. char logonDomain[LM20_DNLEN + 1];
  1886. char otherDomains[512]; // arbitrary
  1887. DWORD len;
  1888. LPWSTR UNALIGNED str;
  1889. //BOOL nullPointer;
  1890. BOOL addSlashes;
  1891. //// TEST_DATA
  1892. // static INT testindex = 0;
  1893. // static WCHAR* testnames[] = {
  1894. // NULL,
  1895. // NULL,
  1896. // L"",
  1897. // L"",
  1898. // L"A",
  1899. // L"A",
  1900. // L"AB",
  1901. // L"AB",
  1902. // L"ABC",
  1903. // L"ABC",
  1904. // L"ABCDEFGHIJKLMNO",
  1905. // L"ABCDEFGHIJKLMNO",
  1906. // L"\\\\",
  1907. // L"\\\\",
  1908. // L"\\\\A",
  1909. // L"\\\\A",
  1910. // L"\\\\AB",
  1911. // L"\\\\AB",
  1912. // L"\\\\ABC",
  1913. // L"\\\\ABC",
  1914. // L"\\\\ABCDEFGHIJKLMNO",
  1915. // L"\\\\ABCDEFGHIJKLMNO"
  1916. // };
  1917. //// TEST_DATA
  1918. //
  1919. // first off, modify the pointers for any data returned by
  1920. // XsNetWkstaGetInfo
  1921. //
  1922. if (status == NERR_Success) {
  1923. //#if DBG
  1924. // IF_DEBUG(NETAPI) {
  1925. // DbgPrint("VrNetWkstaGetInfo: calling VrpConvertReceiveBuffer: Converter=%04x\n",
  1926. // header.Converter
  1927. // );
  1928. // }
  1929. //#endif
  1930. VrpConvertReceiveBuffer(
  1931. buffer,
  1932. bufferSegment,
  1933. bufferOffset,
  1934. (WORD)header.Converter,
  1935. 1,
  1936. dataDesc,
  1937. NULL
  1938. );
  1939. }
  1940. //
  1941. // get the per-user information
  1942. //
  1943. net_status = NetWkstaUserGetInfo(NULL, 1, &info);
  1944. if (net_status == NERR_Success) {
  1945. //#if DBG
  1946. // IF_DEBUG(NETAPI) {
  1947. // DbgPrint("NetWkstaUserGetInfo:\n"
  1948. // "user name %ws\n"
  1949. // "logon domain %ws\n"
  1950. // "other domains %ws\n"
  1951. // "logon server %ws\n"
  1952. // "\n",
  1953. // ((PWKSTA_USER_INFO_1)info)->wkui1_username,
  1954. // ((PWKSTA_USER_INFO_1)info)->wkui1_logon_domain,
  1955. // ((PWKSTA_USER_INFO_1)info)->wkui1_oth_domains,
  1956. // ((PWKSTA_USER_INFO_1)info)->wkui1_logon_server
  1957. // );
  1958. // }
  1959. //#endif
  1960. //
  1961. // username for all levels
  1962. //
  1963. str = (LPWSTR)((PWKSTA_USER_INFO_1)info)->wkui1_username;
  1964. if (!str) {
  1965. str = L"";
  1966. }
  1967. //nullPointer = ((level == 10)
  1968. // ? ((struct wksta_info_10*)buffer)->wki10_username
  1969. // : ((struct wksta_info_0*)buffer)->wki0_username
  1970. // ) == NULL;
  1971. //len = wcslen(str) + nullPointer ? 1 : 0;
  1972. #ifdef DBCS /*fix for DBCS char sets*/
  1973. len = (DWORD)NetpUnicodeToDBCSLen(str) + 1;
  1974. #else // !DBCS
  1975. len = wcslen(str) + 1;
  1976. #endif // !DBCS
  1977. bufferLeft -= len;
  1978. totalAvail += len;
  1979. if (len <= sizeof(username)) {
  1980. #ifdef DBCS /*fix for DBCS char sets*/
  1981. NetpCopyWStrToStrDBCS(username, str);
  1982. #else // !DBCS
  1983. NetpCopyWStrToStr(username, str);
  1984. #endif // !DBCS
  1985. } else {
  1986. username[0] = 0;
  1987. }
  1988. //
  1989. // logon_server for levels 0 & 1
  1990. //
  1991. if (level <= 1) {
  1992. str = (LPWSTR)((PWKSTA_USER_INFO_1)info)->wkui1_logon_server;
  1993. //// TEST_CODE
  1994. // if (testindex < sizeof(testnames)/sizeof(testnames[0])) {
  1995. // str = testnames[testindex++];
  1996. // }
  1997. //// TEST_CODE
  1998. if (!str) {
  1999. str = L"";
  2000. }
  2001. #ifdef DBCS /*fix for DBCS char sets*/
  2002. len = (DWORD)NetpUnicodeToDBCSLen(str) + 1;
  2003. #else // !DBCS
  2004. len = wcslen(str) + 1;
  2005. #endif // !DBCS
  2006. //
  2007. // DOS returns "\\logon_server" whereas NT returns "logon_server".
  2008. // We need to account for the extra backslashes (but only if not
  2009. // NULL string)
  2010. // At this time, len includes +1 for terminating \0, so even a
  2011. // NULL string has length 1
  2012. //
  2013. addSlashes = TRUE;
  2014. if (len >= 3 && IS_PATH_SEPARATOR(str[0]) && IS_PATH_SEPARATOR(str[1])) {
  2015. addSlashes = FALSE;
  2016. } else if (len == 1) { // NULL string
  2017. addSlashes = FALSE;
  2018. }
  2019. if (addSlashes) {
  2020. len += 2;
  2021. }
  2022. bufferLeft -= len;
  2023. totalAvail += len;
  2024. if (len <= sizeof(logonServer)) {
  2025. INT offset = 0;
  2026. if (addSlashes) {
  2027. logonServer[0] = logonServer[1] = '\\';
  2028. offset = 2;
  2029. }
  2030. #ifdef DBCS /*fix for DBCS char sets*/
  2031. NetpCopyWStrToStrDBCS(&logonServer[offset], str);
  2032. #else // !DBCS
  2033. NetpCopyWStrToStr(&logonServer[offset], str);
  2034. #endif // !DBCS
  2035. } else {
  2036. logonServer[0] = 0;
  2037. }
  2038. }
  2039. //
  2040. // logon_domain and oth_domains for levels 1 & 10
  2041. //
  2042. if (level >= 1) {
  2043. str = (LPWSTR)((PWKSTA_USER_INFO_1)info)->wkui1_logon_domain;
  2044. if (!str) {
  2045. str = L"";
  2046. }
  2047. #ifdef DBCS /*fix for DBCS char sets*/
  2048. len = (DWORD)NetpUnicodeToDBCSLen(str) + 1;
  2049. #else // !DBCS
  2050. len = wcslen(str) + 1;
  2051. #endif // !DBCS
  2052. bufferLeft -= len;
  2053. totalAvail += len;
  2054. if (len <= sizeof(logonDomain)) {
  2055. #ifdef DBCS /*fix for DBCS char sets*/
  2056. NetpCopyWStrToStrDBCS(logonDomain, str);
  2057. #else // !DBCS
  2058. NetpCopyWStrToStr(logonDomain, str);
  2059. #endif // !DBCS
  2060. } else {
  2061. logonDomain[0] = 0;
  2062. }
  2063. str = (LPWSTR)((PWKSTA_USER_INFO_1)info)->wkui1_oth_domains;
  2064. if (!str) {
  2065. str = L"";
  2066. }
  2067. #ifdef DBCS /*fix for DBCS char sets*/
  2068. len = (DWORD)NetpUnicodeToDBCSLen(str) + 1;
  2069. #else // !DBCS
  2070. len = wcslen(str) + 1;
  2071. #endif // !DBCS
  2072. bufferLeft -= len;
  2073. totalAvail += len;
  2074. if (len <= sizeof(otherDomains)) {
  2075. #ifdef DBCS /*fix for DBCS char sets*/
  2076. NetpCopyWStrToStrDBCS(otherDomains, str);
  2077. #else // !DBCS
  2078. NetpCopyWStrToStr(otherDomains, str);
  2079. #endif // !DBCS
  2080. } else {
  2081. otherDomains[0] = 0;
  2082. }
  2083. }
  2084. //
  2085. // if there's enough space in the buffer then copy the strings
  2086. //
  2087. if (status == NERR_Success && bufferLeft >= 0) {
  2088. WORD offset = bufferOffset + parameters.TotalAvail;
  2089. LPSTR UNALIGNED ptr = POINTER_FROM_WORDS(bufferSegment, offset);
  2090. //
  2091. // username for all levels
  2092. //
  2093. strcpy(ptr, username);
  2094. len = strlen(username) + 1;
  2095. if (level <= 1) {
  2096. //
  2097. // levels 0 & 1 have username field at same offset
  2098. //
  2099. WRITE_WORD(&((struct wksta_info_1*)buffer)->wki1_username, offset);
  2100. WRITE_WORD((LPWORD)&((struct wksta_info_1*)buffer)->wki1_username+1, bufferSegment);
  2101. } else {
  2102. WRITE_WORD(&((struct wksta_info_10*)buffer)->wki10_username, offset);
  2103. WRITE_WORD((LPWORD)&((struct wksta_info_10*)buffer)->wki10_username+1, bufferSegment);
  2104. }
  2105. ptr += len;
  2106. offset += (WORD)len;
  2107. //
  2108. // logon_server for levels 0 & 1
  2109. //
  2110. if (level <= 1) {
  2111. strcpy(ptr, logonServer);
  2112. len = strlen(logonServer) + 1;
  2113. //
  2114. // levels 0 & 1 have logon_server field at same offset
  2115. //
  2116. WRITE_WORD(&((struct wksta_info_1*)buffer)->wki1_logon_server, offset);
  2117. WRITE_WORD((LPWORD)&((struct wksta_info_1*)buffer)->wki1_logon_server+1, bufferSegment);
  2118. ptr += len;
  2119. offset += (WORD)len;
  2120. }
  2121. //
  2122. // logon_domain and oth_domains for levels 1 & 10
  2123. //
  2124. if (level >= 1) {
  2125. if (level == 1) {
  2126. strcpy(ptr, logonDomain);
  2127. len = strlen(logonDomain) + 1;
  2128. WRITE_WORD(&((struct wksta_info_1*)buffer)->wki1_logon_domain, offset);
  2129. WRITE_WORD((LPWORD)&((struct wksta_info_1*)buffer)->wki1_logon_domain+1, bufferSegment);
  2130. ptr += len;
  2131. offset += (WORD)len;
  2132. strcpy(ptr, otherDomains);
  2133. WRITE_WORD(&((struct wksta_info_1*)buffer)->wki1_oth_domains, offset);
  2134. WRITE_WORD((LPWORD)&((struct wksta_info_1*)buffer)->wki1_oth_domains+1, bufferSegment);
  2135. } else {
  2136. strcpy(ptr, logonDomain);
  2137. len = strlen(logonDomain) + 1;
  2138. WRITE_WORD(&((struct wksta_info_10*)buffer)->wki10_logon_domain, offset);
  2139. WRITE_WORD((LPWORD)&((struct wksta_info_10*)buffer)->wki10_logon_domain+1, bufferSegment);
  2140. ptr += len;
  2141. offset += (WORD)len;
  2142. strcpy(ptr, otherDomains);
  2143. WRITE_WORD(&((struct wksta_info_10*)buffer)->wki10_oth_domains, offset);
  2144. WRITE_WORD((LPWORD)&((struct wksta_info_10*)buffer)->wki10_oth_domains+1, bufferSegment);
  2145. }
  2146. }
  2147. } else if (status == NERR_Success) {
  2148. //
  2149. // the additional data will overflow the caller's buffer:
  2150. // return ERROR_MORE_STATUS and NULL out any pointer fields
  2151. // that XsNetWkstaGetInfo managed to set
  2152. //
  2153. switch (level) {
  2154. case 1:
  2155. WRITE_FAR_POINTER(&((struct wksta_info_1*)buffer)->wki1_logon_domain, NULL);
  2156. WRITE_FAR_POINTER(&((struct wksta_info_1*)buffer)->wki1_oth_domains, NULL);
  2157. //
  2158. // FALL THROUGH TO LEVEL 0 FOR REST OF FIELDS
  2159. //
  2160. case 0:
  2161. WRITE_FAR_POINTER(&((struct wksta_info_0*)buffer)->wki0_root, NULL);
  2162. WRITE_FAR_POINTER(&((struct wksta_info_0*)buffer)->wki0_computername, NULL);
  2163. WRITE_FAR_POINTER(&((struct wksta_info_0*)buffer)->wki0_username, NULL);
  2164. WRITE_FAR_POINTER(&((struct wksta_info_0*)buffer)->wki0_langroup, NULL);
  2165. WRITE_FAR_POINTER(&((struct wksta_info_0*)buffer)->wki0_logon_server, NULL);
  2166. WRITE_FAR_POINTER(&((struct wksta_info_0*)buffer)->wki0_wrkheuristics, NULL);
  2167. break;
  2168. case 10:
  2169. WRITE_FAR_POINTER(&((struct wksta_info_10*)buffer)->wki10_computername, NULL);
  2170. WRITE_FAR_POINTER(&((struct wksta_info_10*)buffer)->wki10_username, NULL);
  2171. WRITE_FAR_POINTER(&((struct wksta_info_10*)buffer)->wki10_langroup, NULL);
  2172. WRITE_FAR_POINTER(&((struct wksta_info_10*)buffer)->wki10_logon_domain, NULL);
  2173. WRITE_FAR_POINTER(&((struct wksta_info_10*)buffer)->wki10_oth_domains, NULL);
  2174. break;
  2175. }
  2176. status = ERROR_MORE_DATA;
  2177. SET_ERROR((WORD)status);
  2178. }
  2179. //
  2180. // free the wksta user info buffer
  2181. //
  2182. NetApiBufferFree((LPVOID)info);
  2183. } else {
  2184. #if DBG
  2185. IF_DEBUG(NETAPI) {
  2186. DbgPrint("VrNetWkstaGetInfo: NetWkstaUserGetInfo returns %d\n", net_status);
  2187. }
  2188. #endif
  2189. }
  2190. //
  2191. // update the amount of data available when we return NERR_Success,
  2192. // ERROR_MORE_DATA or NERR_BufTooSmall
  2193. //
  2194. setDX((WORD)totalAvail);
  2195. #if DBG
  2196. IF_DEBUG(NETAPI) {
  2197. DbgPrint("VrNetWkstaGetInfo: TotalAvail=%d\n", getDX());
  2198. }
  2199. #endif
  2200. }
  2201. //
  2202. // if we got data back, then we must change the version number from
  2203. // 3.0 to 2.1 so lanman.drv thinks it is compatible with this version
  2204. // of LM
  2205. //
  2206. if (status == NERR_Success || status == ERROR_MORE_DATA) {
  2207. switch (level) {
  2208. case 0:
  2209. ((struct wksta_info_0*)buffer)->wki0_ver_major = LANMAN_EMULATION_MAJOR_VERSION;
  2210. ((struct wksta_info_0*)buffer)->wki0_ver_minor = LANMAN_EMULATION_MINOR_VERSION;
  2211. break;
  2212. case 1:
  2213. ((struct wksta_info_1*)buffer)->wki1_ver_major = LANMAN_EMULATION_MAJOR_VERSION;
  2214. ((struct wksta_info_1*)buffer)->wki1_ver_minor = LANMAN_EMULATION_MINOR_VERSION;
  2215. break;
  2216. case 10:
  2217. ((struct wksta_info_10*)buffer)->wki10_ver_major = LANMAN_EMULATION_MAJOR_VERSION;
  2218. ((struct wksta_info_10*)buffer)->wki10_ver_minor = LANMAN_EMULATION_MINOR_VERSION;
  2219. break;
  2220. }
  2221. }
  2222. #if DBG
  2223. IF_DEBUG(NETAPI) {
  2224. DbgPrint("VrNetWkstaGetInfo: return status=%d, TotalAvail=%d\n", getAX(), getDX());
  2225. }
  2226. if (status == NERR_Success || status == ERROR_MORE_DATA) {
  2227. IF_DEBUG(NETAPI) {
  2228. DumpWkstaInfo(level, buffer);
  2229. }
  2230. }
  2231. #endif
  2232. }
  2233. #if DBG
  2234. #define POSSIBLE_STRING(s) ((s) ? (s) : "")
  2235. VOID
  2236. DumpWkstaInfo(
  2237. IN DWORD level,
  2238. IN LPBYTE buffer
  2239. )
  2240. {
  2241. switch (level) {
  2242. case 0:
  2243. case 1:
  2244. //
  2245. // DbgPrint resets the test machine if we try it with this
  2246. // string & these args all at once!
  2247. //
  2248. DbgPrint( "reserved1 %04x\n",
  2249. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_reserved_1)
  2250. );
  2251. DbgPrint( "reserved2 %08x\n",
  2252. READ_DWORD(&((struct wksta_info_0*)buffer)->wki0_reserved_2)
  2253. );
  2254. DbgPrint( "lanroot %04x:%04x \"%s\"\n",
  2255. GET_SEGMENT(&((struct wksta_info_0*)buffer)->wki0_root),
  2256. GET_OFFSET(&((struct wksta_info_0*)buffer)->wki0_root),
  2257. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_0*)buffer)->wki0_root))
  2258. );
  2259. DbgPrint( "computername %04x:%04x \"%s\"\n",
  2260. GET_SEGMENT(&((struct wksta_info_0*)buffer)->wki0_computername),
  2261. GET_OFFSET(&((struct wksta_info_0*)buffer)->wki0_computername),
  2262. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_0*)buffer)->wki0_computername))
  2263. );
  2264. DbgPrint( "username %04x:%04x \"%s\"\n",
  2265. GET_SEGMENT(&((struct wksta_info_0*)buffer)->wki0_username),
  2266. GET_OFFSET(&((struct wksta_info_0*)buffer)->wki0_username),
  2267. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_0*)buffer)->wki0_username))
  2268. );
  2269. DbgPrint( "langroup %04x:%04x \"%s\"\n",
  2270. GET_SEGMENT(&((struct wksta_info_0*)buffer)->wki0_langroup),
  2271. GET_OFFSET(&((struct wksta_info_0*)buffer)->wki0_langroup),
  2272. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_0*)buffer)->wki0_langroup))
  2273. );
  2274. DbgPrint( "ver major %02x\n"
  2275. "ver minor %02x\n"
  2276. "reserved3 %08x\n"
  2277. "charwait %04x\n"
  2278. "chartime %08x\n"
  2279. "charcount %04x\n",
  2280. READ_BYTE(&((struct wksta_info_0*)buffer)->wki0_ver_major),
  2281. READ_BYTE(&((struct wksta_info_0*)buffer)->wki0_ver_minor),
  2282. READ_DWORD(&((struct wksta_info_0*)buffer)->wki0_reserved_3),
  2283. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_charwait),
  2284. READ_DWORD(&((struct wksta_info_0*)buffer)->wki0_chartime),
  2285. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_charcount)
  2286. );
  2287. DbgPrint( "reserved4 %04x\n"
  2288. "reserved5 %04x\n"
  2289. "keepconn %04x\n"
  2290. "keepsearch %04x\n"
  2291. "maxthreads %04x\n"
  2292. "maxcmds %04x\n",
  2293. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_reserved_4),
  2294. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_reserved_5),
  2295. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_keepconn),
  2296. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_keepsearch),
  2297. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_maxthreads),
  2298. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_maxcmds)
  2299. );
  2300. DbgPrint( "reserved6 %04x\n"
  2301. "numworkbuf %04x\n"
  2302. "sizworkbuf %04x\n"
  2303. "maxwrkcache %04x\n"
  2304. "sesstimeout %04x\n"
  2305. "sizerror %04x\n",
  2306. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_reserved_6),
  2307. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_numworkbuf),
  2308. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_sizworkbuf),
  2309. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_maxwrkcache),
  2310. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_sesstimeout),
  2311. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_sizerror)
  2312. );
  2313. DbgPrint( "numalerts %04x\n"
  2314. "numservices %04x\n"
  2315. "errlogsz %04x\n"
  2316. "printbuftime %04x\n"
  2317. "numcharbuf %04x\n"
  2318. "sizcharbuf %04x\n",
  2319. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_numalerts),
  2320. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_numservices),
  2321. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_errlogsz),
  2322. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_printbuftime),
  2323. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_numcharbuf),
  2324. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_sizcharbuf)
  2325. );
  2326. DbgPrint( "logon server %04x:%04x \"%s\"\n",
  2327. GET_SEGMENT(&((struct wksta_info_0*)buffer)->wki0_logon_server),
  2328. GET_OFFSET(&((struct wksta_info_0*)buffer)->wki0_logon_server),
  2329. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_0*)buffer)->wki0_logon_server))
  2330. );
  2331. DbgPrint( "wrkheuristics %04x:%04x \"%s\"\n",
  2332. GET_SEGMENT(&((struct wksta_info_0*)buffer)->wki0_wrkheuristics),
  2333. GET_OFFSET(&((struct wksta_info_0*)buffer)->wki0_wrkheuristics),
  2334. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_0*)buffer)->wki0_wrkheuristics))
  2335. );
  2336. DbgPrint( "mailslots %04x\n",
  2337. READ_WORD(&((struct wksta_info_0*)buffer)->wki0_mailslots)
  2338. );
  2339. if (level == 1) {
  2340. DbgPrint(
  2341. "logon domain %04x:%04x \"%s\"\n",
  2342. GET_SEGMENT(&((struct wksta_info_1*)buffer)->wki1_logon_domain),
  2343. GET_OFFSET(&((struct wksta_info_1*)buffer)->wki1_logon_domain),
  2344. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_1*)buffer)->wki1_logon_domain))
  2345. );
  2346. DbgPrint(
  2347. "other domains %04x:%04x \"%s\"\n",
  2348. GET_SEGMENT(&((struct wksta_info_1*)buffer)->wki1_oth_domains),
  2349. GET_OFFSET(&((struct wksta_info_1*)buffer)->wki1_oth_domains),
  2350. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_1*)buffer)->wki1_oth_domains))
  2351. );
  2352. DbgPrint(
  2353. "numdgrambuf %04x\n",
  2354. ((struct wksta_info_1*)buffer)->wki1_numdgrambuf
  2355. );
  2356. }
  2357. break;
  2358. case 10:
  2359. DbgPrint( "computername %04x:%04x \"%s\"\n",
  2360. GET_SEGMENT(&((struct wksta_info_10*)buffer)->wki10_computername),
  2361. GET_OFFSET(&((struct wksta_info_10*)buffer)->wki10_computername),
  2362. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_10*)buffer)->wki10_computername))
  2363. );
  2364. DbgPrint( "username %04x:%04x \"%s\"\n",
  2365. GET_SEGMENT(&((struct wksta_info_10*)buffer)->wki10_username),
  2366. GET_OFFSET(&((struct wksta_info_10*)buffer)->wki10_username),
  2367. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_10*)buffer)->wki10_username))
  2368. );
  2369. DbgPrint( "langroup %04x:%04x \"%s\"\n",
  2370. GET_SEGMENT(&((struct wksta_info_10*)buffer)->wki10_langroup),
  2371. GET_OFFSET(&((struct wksta_info_10*)buffer)->wki10_langroup),
  2372. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_10*)buffer)->wki10_langroup))
  2373. );
  2374. DbgPrint( "ver major %02x\n"
  2375. "ver minor %02x\n"
  2376. "logon domain %04x:%04x \"%s\"\n",
  2377. READ_BYTE(&((struct wksta_info_10*)buffer)->wki10_ver_major),
  2378. READ_BYTE(&((struct wksta_info_10*)buffer)->wki10_ver_minor),
  2379. GET_SEGMENT(&((struct wksta_info_10*)buffer)->wki10_logon_domain),
  2380. GET_OFFSET(&((struct wksta_info_10*)buffer)->wki10_logon_domain),
  2381. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_10*)buffer)->wki10_logon_domain))
  2382. );
  2383. DbgPrint( "other domains %04x:%04x \"%s\"\n",
  2384. GET_SEGMENT(&((struct wksta_info_10*)buffer)->wki10_oth_domains),
  2385. GET_OFFSET(&((struct wksta_info_10*)buffer)->wki10_oth_domains),
  2386. POSSIBLE_STRING(LPSTR_FROM_POINTER(&((struct wksta_info_10*)buffer)->wki10_oth_domains))
  2387. );
  2388. break;
  2389. }
  2390. DbgPrint("\n");
  2391. }
  2392. #endif
  2393. VOID
  2394. VrNetWkstaSetInfo(
  2395. VOID
  2396. )
  2397. /*++
  2398. Routine Description:
  2399. Performs local NetUseEnum on behalf of the Vdm client
  2400. Arguments:
  2401. None.
  2402. Return Value:
  2403. None.
  2404. --*/
  2405. {
  2406. #if DBG
  2407. IF_DEBUG(NETAPI) {
  2408. DbgPrint("VrNetWkstaSetInfo\n");
  2409. IF_DEBUG(BREAKPOINT) {
  2410. DbgBreakPoint();
  2411. }
  2412. }
  2413. #endif
  2414. #if DBG
  2415. IF_DEBUG(NETAPI) {
  2416. DbgPrint("VrNetWkstaSetInfo - unsupported SVC\n");
  2417. }
  2418. #endif
  2419. SET_ERROR(ERROR_NOT_SUPPORTED);
  2420. }
  2421. VOID
  2422. VrReturnAssignMode(
  2423. VOID
  2424. )
  2425. /*++
  2426. Routine Description:
  2427. Returns net pause/continue status
  2428. Arguments:
  2429. Function 5F00h
  2430. None. All arguments are extracted from the Vdm context registers/memory
  2431. Return Value:
  2432. None. Results returned via VDM registers or in VDM memory, according to
  2433. request
  2434. --*/
  2435. {
  2436. }
  2437. VOID
  2438. VrSetAssignMode(
  2439. VOID
  2440. )
  2441. /*++
  2442. Routine Description:
  2443. Pauses or continues net (drive/printer) redirection
  2444. Arguments:
  2445. Function 5F01h
  2446. None. All arguments are extracted from the Vdm context registers/memory
  2447. Return Value:
  2448. None. Results returned via VDM registers or in VDM memory, according to
  2449. request
  2450. --*/
  2451. {
  2452. }
  2453. //
  2454. // DefineMacroDriveUserWords - the old DefineMacro call (int 21h/ax=5f03h)
  2455. // allows the caller to associate a (16-bit) word value with the assignment.
  2456. // This value can be returned from GetAssignListEntry (int 21h/ax=5f02h).
  2457. // NetUse doesn't support this, so we fake it
  2458. //
  2459. // DefineMacroPrintUserWords - same idea for printers; we reserve 8 max
  2460. //
  2461. static WORD DefineMacroDriveUserWords[26];
  2462. static WORD DefineMacroPrintUserWords[8];
  2463. VOID
  2464. VrGetAssignListEntry(
  2465. VOID
  2466. )
  2467. /*++
  2468. Routine Description:
  2469. Old version of NetUseGetInfo. In DOS this function performs the following:
  2470. look along CDS list for entry # bx with IS_NET bit set
  2471. if found
  2472. return local device name and remote net name
  2473. else
  2474. look along list of printers for entry # bx
  2475. if found
  2476. return local device name and remote net name
  2477. endif
  2478. endif
  2479. Every time a drive entry is found with IS_NET set or a printer entry
  2480. found, bx is decremented. When bx reaches 0, then that's the entry to
  2481. return
  2482. NOTE: This function DOES NOT support UNC connections
  2483. Arguments:
  2484. Function 5F02h (GetAssignList)
  2485. Function 5F05h (GetAssignList2)
  2486. ENTRY BX = which item to return (starts @ 0)
  2487. DS:SI points to local redirection name
  2488. ES:DI points to remote redirection name
  2489. AL != 0 means return LSN in BP (GetAssignList2)?
  2490. Return Value:
  2491. CF = 0
  2492. BL = macro type (3 = printer, 4 = drive)
  2493. BH = 'interesting' bits ** UNSUPPORTED **
  2494. AX = net name ID ** UNSUPPORTED **
  2495. CX = user word
  2496. DX = max xmit size ** UNSUPPORTED **
  2497. BP = LSN if AL != 0 on entry ** UNSUPPORTED **
  2498. DS:SI has device name
  2499. ES:DI has net path
  2500. CF = 1
  2501. AX = ERROR_NO_MORE_FILES
  2502. --*/
  2503. {
  2504. NTSTATUS ntstatus;
  2505. NET_API_STATUS status;
  2506. XS_NET_USE_ENUM parameters;
  2507. XS_PARAMETER_HEADER header;
  2508. LPBYTE receiveBuffer;
  2509. DWORD entryNumber;
  2510. struct use_info_1* driveInfo[26];
  2511. struct use_info_1* printInfo[8]; // is overkill, 3 is more like it
  2512. struct use_info_1* infoPtr;
  2513. struct use_info_1* infoBase;
  2514. DWORD index;
  2515. DWORD i;
  2516. LPSTR remoteName;
  2517. WORD userWord;
  2518. DWORD converter;
  2519. WORD wstatus;
  2520. LPSTR dosPointer;
  2521. #if DBG
  2522. IF_DEBUG(NETAPI) {
  2523. DbgPrint("VrGetAssignListEntry\n");
  2524. VrDumpRealMode16BitRegisters(FALSE);
  2525. }
  2526. #endif
  2527. //
  2528. // maximum possible enumeration buffer size = 26 * (26 + 256 + 3) = 7410
  2529. // which we'll round to 8K, which is overkill. Decided to allocate 2K
  2530. //
  2531. #define ASSIGN_LIST_BUFFER_SIZE 2048
  2532. receiveBuffer = (LPBYTE)LocalAlloc(LMEM_FIXED, ASSIGN_LIST_BUFFER_SIZE);
  2533. if (receiveBuffer == NULL) {
  2534. //
  2535. // BUGBUG - possibly incompatible error code
  2536. //
  2537. SET_ERROR((WORD)ERROR_NOT_ENOUGH_MEMORY);
  2538. return;
  2539. }
  2540. parameters.Level = 1;
  2541. parameters.Buffer = receiveBuffer;
  2542. parameters.BufLen = ASSIGN_LIST_BUFFER_SIZE;
  2543. header.Status = 0;
  2544. header.ClientMachineName = NULL;
  2545. header.ClientTransportName = NULL;
  2546. ntstatus = XsNetUseEnum(&header, &parameters, REM16_use_info_1, NULL);
  2547. //
  2548. // if XsNetUseEnum didn't have any problems, convert the actual status
  2549. // code to that returned in the header
  2550. //
  2551. if (ntstatus != STATUS_SUCCESS) {
  2552. status = NetpNtStatusToApiStatus(ntstatus);
  2553. } else {
  2554. status = (DWORD)header.Status;
  2555. //
  2556. // we really want to brute-force this, so make sure we have all the
  2557. // data
  2558. //
  2559. #if DBG
  2560. IF_DEBUG(NETAPI) {
  2561. if (status != NERR_Success) {
  2562. DbgPrint("VrGetAssignListEntry: XsNetUseEnum returns header.Status == %d\n", status);
  2563. }
  2564. }
  2565. if (status == NERR_Success) {
  2566. ASSERT(parameters.EntriesRead == parameters.TotalAvail);
  2567. }
  2568. #endif
  2569. }
  2570. entryNumber = getBX();
  2571. if (status == NERR_Success) {
  2572. //
  2573. // only do the following if the bx'th entry is in the list
  2574. //
  2575. if (parameters.EntriesRead > entryNumber) {
  2576. //
  2577. // we need to emulate the action of the DOS Redirector: we need to
  2578. // sort the entries into ascending drive entries followed by
  2579. // ascending printer entries. There were no such things as UNC
  2580. // connections in the original (3.1) version of DOS, so we ignore
  2581. // any in our list. Also ignored are IPC connections and comms
  2582. // connections
  2583. //
  2584. RtlZeroMemory(driveInfo, sizeof(driveInfo));
  2585. RtlZeroMemory(printInfo, sizeof(printInfo));
  2586. infoPtr = (struct use_info_1*)receiveBuffer;
  2587. //
  2588. // XsNetUseEnum returns pointers in the structure as actual offsets
  2589. // from the start of the buffer + a converter word. We have to
  2590. // recalculate the actual pointers as
  2591. //
  2592. // start of enum buffer + (pointer offset - converter dword)
  2593. //
  2594. // we have to convert the 16-bit converter word to a dword for
  2595. // 32-bit pointer arithmetic
  2596. // driveInfo[index] = infoBase + ((DWORD)infoPtr->ui1_remote - converter);
  2597. //
  2598. infoBase = infoPtr;
  2599. converter = (DWORD)header.Converter;
  2600. for (i = 0; i < parameters.EntriesRead; ++i) {
  2601. //
  2602. // ignore UNCs - local name is NULL string (\0)
  2603. //
  2604. if (infoPtr->ui1_asg_type == USE_DISKDEV && infoPtr->ui1_local[0]) {
  2605. index = toupper(infoPtr->ui1_local[0])-'A';
  2606. driveInfo[index] = infoPtr;
  2607. #if DBG
  2608. IF_DEBUG(NETAPI) {
  2609. DbgPrint("Index=%d Drive=%s Netname=%s\n",
  2610. index,
  2611. infoPtr->ui1_local,
  2612. (LPSTR)infoBase + ((DWORD)infoPtr->ui1_remote - converter)
  2613. );
  2614. }
  2615. #endif
  2616. } else if (infoPtr->ui1_asg_type == USE_SPOOLDEV && infoPtr->ui1_local[0]) {
  2617. //
  2618. // NOTE: assume there was never, is not, and will never be
  2619. // such a thing as LPT0:
  2620. //
  2621. index = infoPtr->ui1_local[3] - '1';
  2622. printInfo[index] = infoPtr;
  2623. #if DBG
  2624. IF_DEBUG(NETAPI) {
  2625. DbgPrint("Index=%d Printer=%s Netname=%s\n",
  2626. index,
  2627. infoPtr->ui1_local,
  2628. (LPSTR)infoBase + ((DWORD)infoPtr->ui1_remote - converter)
  2629. );
  2630. }
  2631. #endif
  2632. }
  2633. ++infoPtr;
  2634. }
  2635. //
  2636. // now look along the list(s) for the bx'th (in entryNumber) entry
  2637. //
  2638. ++entryNumber;
  2639. for (i = 0; i < ARRAY_ELEMENTS(driveInfo); ++i) {
  2640. if (driveInfo[i]) {
  2641. --entryNumber;
  2642. if (!entryNumber) {
  2643. infoPtr = driveInfo[i];
  2644. userWord = DefineMacroDriveUserWords[i];
  2645. break;
  2646. }
  2647. }
  2648. }
  2649. //
  2650. // if entryNumber was not reduced to 0 then check the printers
  2651. //
  2652. if (entryNumber) {
  2653. for (i = 0; i < ARRAY_ELEMENTS(printInfo); ++i) {
  2654. if (printInfo[i]) {
  2655. --entryNumber;
  2656. if (!entryNumber) {
  2657. infoPtr = printInfo[i];
  2658. userWord = DefineMacroPrintUserWords[i];
  2659. break;
  2660. }
  2661. }
  2662. }
  2663. }
  2664. //
  2665. // if entryNumber is 0 then we found the bx'th entry. Return it.
  2666. //
  2667. if (!entryNumber) {
  2668. #if DBG
  2669. IF_DEBUG(NETAPI) {
  2670. DbgPrint("LocalName=%s, RemoteName=%s, UserWord=%04x\n",
  2671. infoPtr->ui1_local,
  2672. (LPSTR)infoBase + ((DWORD)infoPtr->ui1_remote - converter),
  2673. userWord
  2674. );
  2675. }
  2676. #endif
  2677. //
  2678. // copy the strings to DOS memory, making sure to upper case
  2679. // them and convert / to \.
  2680. //
  2681. strcpy(POINTER_FROM_WORDS(getDS(), getSI()), infoPtr->ui1_local);
  2682. dosPointer = LPSTR_FROM_WORDS(getES(), getDI());
  2683. remoteName = (LPSTR)infoBase + ((DWORD)infoPtr->ui1_remote - converter);
  2684. wstatus = VrpTranslateDosNetPath(&remoteName, &dosPointer);
  2685. #if DBG
  2686. IF_DEBUG(NETAPI) {
  2687. if (wstatus != 0) {
  2688. DbgPrint("VrGetAssignListEntry: wstatus == %d\n", wstatus);
  2689. }
  2690. }
  2691. #endif
  2692. setBL((BYTE)(infoPtr->ui1_asg_type == 0 ? 4 : 3));
  2693. setCX(userWord);
  2694. //
  2695. // return some innocuous (?!) values for the unsupported
  2696. // returned parameters
  2697. //
  2698. setBH((BYTE)(infoPtr->ui1_status ? 1 : 0)); // 'interesting' bits (?)
  2699. } else {
  2700. status = ERROR_NO_MORE_FILES;
  2701. }
  2702. } else {
  2703. status = ERROR_NO_MORE_FILES;
  2704. }
  2705. }
  2706. //
  2707. // only return carry clear if no error occurred. Even if ERROR_MORE_DATA
  2708. // set CF
  2709. //
  2710. if (status) {
  2711. SET_ERROR(VrpMapDosError(status));
  2712. } else {
  2713. setCF(0);
  2714. }
  2715. //
  2716. // free resources
  2717. //
  2718. LocalFree(receiveBuffer);
  2719. }
  2720. VOID
  2721. VrDefineMacro(
  2722. VOID
  2723. )
  2724. /*++
  2725. Routine Description:
  2726. Old version of NetUseAdd. Convert to NetUseAdd
  2727. Arguments:
  2728. Function 5F03h
  2729. ENTRY BL = device type
  2730. 3 = printer
  2731. 4 = drive
  2732. bit 7 on means use the wksta password when connecting ** UNSUPPORTED **
  2733. CX = user word
  2734. DS:SI = local device
  2735. Can be NUL device name, indicating UNC use
  2736. ES:DI = remote name
  2737. Return Value:
  2738. CF = 0
  2739. success
  2740. CF = 1
  2741. AX = ERROR_INVALID_PARAMETER (87)
  2742. ERROR_INVALID_PASSWORD (86)
  2743. ERROR_INVALID_DRIVE (15)
  2744. ERROR_ALREADY_ASSIGNED (85)
  2745. ERROR_PATH_NOT_FOUND (3)
  2746. ERROR_ACCESS_DENIED (5)
  2747. ERROR_NOT_ENOUGH_MEMORY (8)
  2748. ERROR_NO_MORE_FILES (18)
  2749. ERROR_REDIR_PAUSED (72)
  2750. --*/
  2751. {
  2752. NET_API_STATUS status;
  2753. XS_NET_USE_ADD parameters;
  2754. XS_PARAMETER_HEADER header;
  2755. NTSTATUS ntstatus;
  2756. BYTE bl;
  2757. LPSTR netStringPointer;
  2758. WORD index;
  2759. //
  2760. // modifiable descriptor string
  2761. //
  2762. char descriptor[sizeof(REM16_use_info_1)];
  2763. //
  2764. // buffer for use_info_1 plus remote string plus password
  2765. //
  2766. char useBuffer[sizeof(struct use_info_1) + LM20_PATHLEN + 1 + LM20_PWLEN + 1];
  2767. WORD wstatus;
  2768. LPBYTE variableData;
  2769. DWORD len;
  2770. LPSTR dosString;
  2771. #if DBG
  2772. IF_DEBUG(NETAPI) {
  2773. DbgPrint("VrDefineMacro \"%s\" == \"%s\"\n",
  2774. LPSTR_FROM_WORDS(getDS(), getSI()),
  2775. LPSTR_FROM_WORDS(getES(), getDI())
  2776. );
  2777. }
  2778. #endif
  2779. bl = getBL();
  2780. if (bl == 3) {
  2781. ((struct use_info_1*)useBuffer)->ui1_asg_type = 1; // USE_SPOOLDEV
  2782. } else if (bl == 4) {
  2783. ((struct use_info_1*)useBuffer)->ui1_asg_type = 0; // USE_DISKDEV
  2784. } else {
  2785. SET_ERROR(ERROR_INVALID_PARAMETER);
  2786. return;
  2787. }
  2788. //
  2789. // copy the standard 16-bit use_info_1 structure descriptor to the
  2790. // modifiable descriptor string: if we discover a NUL password then we
  2791. // set the ui1_password field to NULL and the corresponding descriptor
  2792. // character to 'O'
  2793. //
  2794. strcpy(descriptor, REM16_use_info_1);
  2795. //
  2796. // check the local name length
  2797. //
  2798. dosString = LPSTR_FROM_WORDS(getDS(), getSI());
  2799. if (dosString) {
  2800. if ((len = strlen(dosString) + 1) > LM20_DEVLEN + 1) {
  2801. SET_ERROR(ERROR_INVALID_PARAMETER);
  2802. return;
  2803. }
  2804. //
  2805. // copy the local device name into the use_info_1 structure
  2806. //
  2807. RtlCopyMemory(((struct use_info_1*)useBuffer)->ui1_local, dosString, len);
  2808. //
  2809. // BUGBUG - Code Page, Kanji, DBCS, Locale?
  2810. //
  2811. _strupr(((struct use_info_1*)useBuffer)->ui1_local);
  2812. } else {
  2813. ((struct use_info_1*)useBuffer)->ui1_local[0] = 0;
  2814. }
  2815. //
  2816. // copy the remote name to the end of the use_info_1 structure. If there's
  2817. // an error, return it
  2818. //
  2819. netStringPointer = POINTER_FROM_WORDS(getES(), getDI());
  2820. variableData = (LPBYTE)&((struct use_info_1*)useBuffer)[1];
  2821. ((struct use_info_1*)useBuffer)->ui1_remote = variableData;
  2822. wstatus = VrpTranslateDosNetPath(&netStringPointer, &variableData);
  2823. if (wstatus) {
  2824. SET_ERROR(wstatus);
  2825. return;
  2826. }
  2827. //
  2828. // if there was a password with this remote name, copy it to the end of
  2829. // the variable data area
  2830. //
  2831. if (*netStringPointer) {
  2832. if ((len = strlen(netStringPointer) + 1) > LM20_PWLEN + 1) {
  2833. SET_ERROR(ERROR_INVALID_PASSWORD);
  2834. return;
  2835. } else {
  2836. ((struct use_info_1*)useBuffer)->ui1_password = netStringPointer;
  2837. RtlCopyMemory(variableData, netStringPointer, len);
  2838. }
  2839. } else {
  2840. //
  2841. // there is no password - set the password pointer field to NULL and
  2842. // change the descriptor character for this field to 'O' signifying
  2843. // that there will be no string in the variable data for this field
  2844. //
  2845. ((struct use_info_1*)useBuffer)->ui1_password = NULL;
  2846. descriptor[4] = REM_NULL_PTR; // 'O'
  2847. }
  2848. parameters.Level = 1;
  2849. parameters.Buffer = useBuffer;
  2850. parameters.BufLen = sizeof(useBuffer);
  2851. header.Status = 0;
  2852. header.ClientMachineName = NULL;
  2853. header.ClientTransportName = NULL;
  2854. ntstatus = XsNetUseAdd(&header, &parameters, descriptor, NULL);
  2855. if (!NT_SUCCESS(ntstatus)) {
  2856. status = NetpNtStatusToApiStatus(ntstatus);
  2857. #if DBG
  2858. if (!NT_SUCCESS(ntstatus)) {
  2859. IF_DEBUG(NETAPI) {
  2860. DbgPrint("VrDefineMacro: Error: XsNetUseAdd returns %x\n", ntstatus);
  2861. }
  2862. }
  2863. #endif
  2864. } else {
  2865. //
  2866. // no error generated in XsNetUseAdd. Get the status of the NetUseAdd
  2867. // proper from the header
  2868. //
  2869. status = (NET_API_STATUS)header.Status;
  2870. }
  2871. if (status != NERR_Success) {
  2872. #if DBG
  2873. IF_DEBUG(NETAPI) {
  2874. DbgPrint("Error: VrDefineMacro: XsNetUseAdd returns %u\n", status);
  2875. }
  2876. #endif
  2877. SET_ERROR((WORD)status);
  2878. } else {
  2879. //
  2880. // set the user word in the appropriate list
  2881. //
  2882. if (bl == 3) {
  2883. index = ((struct use_info_1*)useBuffer)->ui1_local[3] - '0';
  2884. DefineMacroPrintUserWords[index] = getCX();
  2885. } else if (((struct use_info_1*)useBuffer)->ui1_local[0]) {
  2886. //
  2887. // note that we already upper-cased the device name
  2888. //
  2889. index = ((struct use_info_1*)useBuffer)->ui1_local[0] - 'A';
  2890. DefineMacroDriveUserWords[index] = getCX();
  2891. }
  2892. //
  2893. // BUGBUG - don't record user word for UNC connections????
  2894. //
  2895. setCF(0);
  2896. }
  2897. }
  2898. VOID
  2899. VrBreakMacro(
  2900. VOID
  2901. )
  2902. /*++
  2903. Routine Description:
  2904. Old version of NetUseDel. Convert to NetUseDel
  2905. Arguments:
  2906. Function 5F04h
  2907. ENTRY DS:SI = buffer containing device name of redirection to break
  2908. Return Value:
  2909. CF = 0
  2910. success
  2911. CF = 1
  2912. AX = ERROR_PATH_NOT_FOUND (3)
  2913. ERROR_ACCESS_DENIED (5)
  2914. ERROR_NOT_ENOUGH_MEMORY (8)
  2915. ERROR_REDIR_PAUSED (72)
  2916. ERROR_NO_MORE_FILES (18)
  2917. --*/
  2918. {
  2919. NTSTATUS ntstatus;
  2920. NET_API_STATUS status;
  2921. XS_NET_USE_DEL parameters;
  2922. XS_PARAMETER_HEADER header;
  2923. #if DBG
  2924. IF_DEBUG(NETAPI) {
  2925. DbgPrint("VrBreakMacro %s\n", LPSTR_FROM_WORDS(getDS(), getSI()));
  2926. }
  2927. #endif
  2928. parameters.UseName = LPSTR_FROM_WORDS(getDS(), getSI());
  2929. parameters.Force = USE_LOTS_OF_FORCE;
  2930. header.Status = 0;
  2931. header.ClientMachineName = NULL;
  2932. header.ClientTransportName = NULL;
  2933. ntstatus = XsNetUseDel(&header, &parameters, NULL, NULL);
  2934. //
  2935. // if XsNetUseDel failed then map the NT error returned into a Net error
  2936. // else get the result of the NetUseDel proper from the header structure
  2937. //
  2938. if (ntstatus != STATUS_SUCCESS) {
  2939. status = NetpNtStatusToApiStatus(ntstatus);
  2940. } else {
  2941. status = (NET_API_STATUS)header.Status;
  2942. if (status != NERR_Success) {
  2943. SET_ERROR(VrpMapDosError(status));
  2944. } else {
  2945. setCF(0);
  2946. }
  2947. }
  2948. }
  2949. //
  2950. // private routines
  2951. //
  2952. NET_API_STATUS
  2953. VrpTransactVdm(
  2954. IN BOOL NullSessionFlag
  2955. )
  2956. /*++
  2957. Routine Description:
  2958. Performs transaction request for NetTransactAPI and NetNullTransactAPI
  2959. Arguments:
  2960. NullSessionFlag - TRUE if the transaction request will use a NULL session
  2961. VDM DS:SI points at a transaction descriptor structure:
  2962. far pointer to transaction name (\\COMPUTER\PIPE\LANMAN)
  2963. far pointer to password for connection
  2964. far pointer to send parameter buffer
  2965. far pointer to send data buffer
  2966. far pointer to receive set-up buffer
  2967. far pointer to receive parameter buffer
  2968. far pointer to receive data buffer
  2969. unsigned short send parameter buffer length
  2970. unsigned short send data buffer length
  2971. unsigned short receive parameter buffer length
  2972. unsigned short receive data buffer length
  2973. unsigned short receive set-up buffer length
  2974. unsigned short flags
  2975. unsigned long timeout
  2976. unsigned short reserved
  2977. unsigned short send set-up buffer length
  2978. Return Value:
  2979. NET_API_STATUS
  2980. Success - NERR_Success
  2981. Failure - return code from RxpTransactSmb
  2982. --*/
  2983. {
  2984. struct tr_packet* transactionPacket;
  2985. DWORD receiveBufferLen;
  2986. NET_API_STATUS status;
  2987. char computerName[LM20_UNCLEN+1];
  2988. LPSTR pipeName;
  2989. DWORD i;
  2990. LPWSTR uncName;
  2991. UNICODE_STRING uString;
  2992. ANSI_STRING aString;
  2993. NTSTATUS ntstatus;
  2994. LPBYTE parameterBuffer;
  2995. LPBYTE pSendParameters;
  2996. LPBYTE pReceiveParameters;
  2997. WORD sendParameterLen;
  2998. WORD receiveParameterLen;
  2999. WORD apiNumber;
  3000. #if DBG
  3001. BOOL dumpRxData;
  3002. IF_DEBUG(NETAPI) {
  3003. DbgPrint("VrpTransactVdm: tr_packet @ %04x:%04x\n", getDS(), getSI());
  3004. }
  3005. #endif
  3006. transactionPacket = (struct tr_packet*)POINTER_FROM_WORDS(getDS(), getSI());
  3007. #if DBG
  3008. IF_DEBUG(NETAPI) {
  3009. DumpTransactionPacket(transactionPacket, TRUE, TRUE);
  3010. }
  3011. #endif
  3012. receiveBufferLen = (DWORD)READ_WORD(&transactionPacket->tr_rdlen);
  3013. //
  3014. // try to extract the UNC computer name from the pipe name
  3015. //
  3016. pipeName = LPSTR_FROM_POINTER(&transactionPacket->tr_name);
  3017. if (IS_ASCII_PATH_SEPARATOR(pipeName[0]) && IS_ASCII_PATH_SEPARATOR(pipeName[1])) {
  3018. computerName[0] = computerName[1] = '\\';
  3019. for (i = 2; i < sizeof(computerName)-1; ++i) {
  3020. if (IS_ASCII_PATH_SEPARATOR(pipeName[i])) {
  3021. break;
  3022. }
  3023. computerName[i] = pipeName[i];
  3024. }
  3025. if (IS_ASCII_PATH_SEPARATOR(pipeName[i])) {
  3026. computerName[i] = '\0';
  3027. pipeName = computerName;
  3028. }
  3029. }
  3030. RtlInitAnsiString(&aString, pipeName);
  3031. ntstatus = RtlAnsiStringToUnicodeString(&uString, &aString, (BOOLEAN)TRUE);
  3032. if (!NT_SUCCESS(ntstatus)) {
  3033. #if DBG
  3034. IF_DEBUG(NETAPI) {
  3035. DbgPrint("VrpTransactVdm: Unexpected situation: RtlAnsiStringToUnicodeString returns %x\n", ntstatus);
  3036. }
  3037. #endif
  3038. return ERROR_NOT_ENOUGH_MEMORY;
  3039. }
  3040. uncName = uString.Buffer;
  3041. #if DBG
  3042. IF_DEBUG(NETAPI) {
  3043. DbgPrint("VrpTransactVdm: UncName=%ws\n", uncName);
  3044. }
  3045. #endif
  3046. //
  3047. // if the app supplies different send and receive parameter buffer pointers
  3048. // we have to collapse them into the same buffer
  3049. //
  3050. pSendParameters = LPBYTE_FROM_POINTER(&transactionPacket->tr_spbuf);
  3051. pReceiveParameters = LPBYTE_FROM_POINTER(&transactionPacket->tr_rpbuf);
  3052. sendParameterLen = READ_WORD(&transactionPacket->tr_splen);
  3053. receiveParameterLen = READ_WORD(&transactionPacket->tr_rplen);
  3054. if (pSendParameters != pReceiveParameters) {
  3055. parameterBuffer = (LPBYTE)LocalAlloc(
  3056. LMEM_FIXED,
  3057. max(sendParameterLen, receiveParameterLen)
  3058. );
  3059. if (parameterBuffer == NULL) {
  3060. return ERROR_NOT_ENOUGH_MEMORY;
  3061. }
  3062. RtlMoveMemory(parameterBuffer, pSendParameters, sendParameterLen);
  3063. pSendParameters = pReceiveParameters = parameterBuffer;
  3064. } else {
  3065. parameterBuffer = NULL;
  3066. }
  3067. //
  3068. // in the case of remoted NetUserAdd2, NetUserPasswordSet2 and NetUserSetInfo2
  3069. // we have to encrypt any passwords if not already encrypted. We will change
  3070. // data in the parameter and send data buffer. Since we assume that this call
  3071. // is coming from the NET function library and not from the app, it should
  3072. // be okay to modify these buffers and not restore them before this function
  3073. // is complete
  3074. //
  3075. apiNumber = READ_WORD(pSendParameters);
  3076. if (apiNumber == API_WUserAdd2
  3077. || apiNumber == API_WUserPasswordSet2
  3078. || apiNumber == API_WUserSetInfo2) {
  3079. LPBYTE parameterPointer = pSendParameters + sizeof(WORD);
  3080. LPBYTE passwordPointer;
  3081. DWORD parmNum = PARMNUM_ALL;
  3082. //
  3083. // skip over parameter descriptor and data descriptor
  3084. //
  3085. parameterPointer += strlen(parameterPointer) + 1;
  3086. parameterPointer += strlen(parameterPointer) + 1;
  3087. //
  3088. // the next thing in the parameter buffer for SetInfo2 and PasswordSet2
  3089. // is the user name: skip it
  3090. //
  3091. if (apiNumber != API_WUserAdd2) {
  3092. parameterPointer += strlen(parameterPointer) + 1;
  3093. }
  3094. //
  3095. // if this is PasswordSet2 then parameterPointer is pointing at the
  3096. // old and new passwords. Remember this address and scan forward to
  3097. // the password encryption flag/new cleartext password length
  3098. //
  3099. // if this is AddUser2, we are pointing at the level which we are not
  3100. // interested in; skip forward to the encryption flag/cleartext password
  3101. // length
  3102. //
  3103. // if this is SetInfo2, we are pointing at the level which we are not
  3104. // interested in; skip forward to the parmnum. Record that. Then skip
  3105. // forward again to the encryption flag/cleartext password length
  3106. //
  3107. if (apiNumber == API_WUserPasswordSet2) {
  3108. passwordPointer = parameterPointer;
  3109. parameterPointer += ENCRYPTED_PWLEN * 2;
  3110. } else {
  3111. parameterPointer += sizeof(WORD);
  3112. if (apiNumber == API_WUserSetInfo2) {
  3113. parmNum = (DWORD)READ_WORD(parameterPointer);
  3114. parameterPointer += sizeof(WORD);
  3115. }
  3116. //
  3117. // in the case of NetUserAdd2 and NetUserSetInfo2, the data buffer
  3118. // contains the password. If the SetInfo2 is using PARMNUM_ALL then
  3119. // the password is in the same place as for AddUser2: in a user_info_1
  3120. // or user_info_2 structure. Luckily, the password is at the same
  3121. // offset for both structures.
  3122. //
  3123. // If this is SetInfo2 with USER_PASSWORD_PARMNUM then the send data
  3124. // pointer points at the password
  3125. //
  3126. passwordPointer = LPBYTE_FROM_POINTER(&transactionPacket->tr_sdbuf);
  3127. if (parmNum == PARMNUM_ALL) {
  3128. passwordPointer += (DWORD)&((struct user_info_1*)0)->usri1_password;
  3129. }
  3130. }
  3131. //
  3132. // only perform encryption if parmNum is PARMNUM_ALL or USER_PASSWORD_PARMNUM
  3133. //
  3134. if (parmNum == PARMNUM_ALL || parmNum == USER_PASSWORD_PARMNUM) {
  3135. //
  3136. // in all cases, parameterPointer points at the encryption flag
  3137. //
  3138. if (!READ_WORD(parameterPointer)) {
  3139. WORD cleartextLength;
  3140. //
  3141. // the password(s) is (are) not already encrypted (surprise!). We
  3142. // have to do it. If encryption fails for any reason, return an
  3143. // internal error. We do not want to fail-back to putting clear-text
  3144. // passwords on the wire in this case
  3145. //
  3146. cleartextLength = (WORD)strlen(passwordPointer);
  3147. //
  3148. // NetUserPasswordSet2 requires a different method than the
  3149. // other 2
  3150. //
  3151. if (apiNumber == API_WUserPasswordSet2) {
  3152. NTSTATUS ntStatus;
  3153. LPBYTE oldPasswordPointer = passwordPointer;
  3154. ENCRYPTED_LM_OWF_PASSWORD oldEncryptedWithNew;
  3155. ENCRYPTED_LM_OWF_PASSWORD newEncryptedWithOld;
  3156. ntStatus = RtlCalculateLmOwfPassword(
  3157. passwordPointer,
  3158. (PLM_OWF_PASSWORD)passwordPointer
  3159. );
  3160. if (!NT_SUCCESS(ntStatus)) {
  3161. status = NERR_InternalError;
  3162. goto VrpTransactVdm_exit;
  3163. }
  3164. passwordPointer += ENCRYPTED_PWLEN;
  3165. cleartextLength = (WORD)strlen(passwordPointer);
  3166. ntStatus = RtlCalculateLmOwfPassword(
  3167. passwordPointer,
  3168. (PLM_OWF_PASSWORD)passwordPointer
  3169. );
  3170. if (!NT_SUCCESS(ntStatus)) {
  3171. status = NERR_InternalError;
  3172. goto VrpTransactVdm_exit;
  3173. }
  3174. //
  3175. // for PasswordSet2, we need to double-encrypt the passwords
  3176. //
  3177. ntStatus = RtlEncryptLmOwfPwdWithLmOwfPwd(
  3178. (PLM_OWF_PASSWORD)oldPasswordPointer,
  3179. (PLM_OWF_PASSWORD)passwordPointer,
  3180. &oldEncryptedWithNew
  3181. );
  3182. if (!NT_SUCCESS(ntStatus)) {
  3183. status = NERR_InternalError;
  3184. goto VrpTransactVdm_exit;
  3185. }
  3186. ntStatus = RtlEncryptLmOwfPwdWithLmOwfPwd(
  3187. (PLM_OWF_PASSWORD)passwordPointer,
  3188. (PLM_OWF_PASSWORD)oldPasswordPointer,
  3189. &newEncryptedWithOld
  3190. );
  3191. if (!NT_SUCCESS(ntStatus)) {
  3192. status = NERR_InternalError;
  3193. goto VrpTransactVdm_exit;
  3194. }
  3195. RtlCopyMemory(oldPasswordPointer,
  3196. &oldEncryptedWithNew,
  3197. sizeof(oldEncryptedWithNew)
  3198. );
  3199. RtlCopyMemory(passwordPointer,
  3200. &newEncryptedWithOld,
  3201. sizeof(newEncryptedWithOld)
  3202. );
  3203. } else {
  3204. if (!EncryptPassword(uncName, passwordPointer)) {
  3205. status = NERR_InternalError;
  3206. goto VrpTransactVdm_exit;
  3207. }
  3208. }
  3209. //
  3210. // set the password encrypted flag in the parameter buffer
  3211. //
  3212. WRITE_WORD(parameterPointer, 1);
  3213. //
  3214. // record the length of the cleartext password (the new one in case
  3215. // of PasswordSet2)
  3216. //
  3217. WRITE_WORD(parameterPointer + sizeof(WORD), cleartextLength);
  3218. }
  3219. }
  3220. }
  3221. status = RxpTransactSmb(
  3222. (LPTSTR)uncName,
  3223. NULL, // transport name
  3224. pSendParameters,
  3225. (DWORD)sendParameterLen,
  3226. LPBYTE_FROM_POINTER(&transactionPacket->tr_sdbuf),
  3227. (DWORD)READ_WORD(&transactionPacket->tr_sdlen),
  3228. pReceiveParameters,
  3229. (DWORD)receiveParameterLen,
  3230. LPBYTE_FROM_POINTER(&transactionPacket->tr_rdbuf),
  3231. &receiveBufferLen,
  3232. NullSessionFlag
  3233. );
  3234. //
  3235. // if we received data, set the received data length in the structure
  3236. //
  3237. if (status == NERR_Success || status == ERROR_MORE_DATA) {
  3238. WRITE_WORD(&transactionPacket->tr_rdlen, receiveBufferLen);
  3239. }
  3240. //
  3241. // if we munged the parameter buffer then copy the returned parameters to
  3242. // the app's supplied buffer
  3243. //
  3244. if (parameterBuffer) {
  3245. RtlMoveMemory(LPBYTE_FROM_POINTER(&transactionPacket->tr_rpbuf),
  3246. pReceiveParameters,
  3247. receiveParameterLen
  3248. );
  3249. }
  3250. #if DBG
  3251. IF_DEBUG(NETAPI) {
  3252. DbgPrint("VrpTransactVdm: returning %d\n\n", status);
  3253. if (status == NERR_Success || status == ERROR_MORE_DATA) {
  3254. dumpRxData = TRUE;
  3255. } else {
  3256. dumpRxData = FALSE;
  3257. }
  3258. DumpTransactionPacket(transactionPacket, FALSE, dumpRxData);
  3259. }
  3260. #endif
  3261. VrpTransactVdm_exit:
  3262. RtlFreeUnicodeString(&uString);
  3263. if (parameterBuffer) {
  3264. LocalFree((HLOCAL)parameterBuffer);
  3265. }
  3266. return status;
  3267. }
  3268. BOOL
  3269. EncryptPassword(
  3270. IN LPWSTR ServerName,
  3271. IN OUT LPBYTE Password
  3272. )
  3273. /*++
  3274. Routine Description:
  3275. Encrypts an ANSI password
  3276. Arguments:
  3277. ServerName - pointer to UNICODE server name. Server is where we are going
  3278. to send the encrypted password
  3279. Password - pointer to buffer containing on input an ANSI password (<= 14
  3280. characters, plus NUL), and on output contains the 16-byte
  3281. encrypted password
  3282. Return Value:
  3283. BOOL
  3284. TRUE - Password has been encrypted
  3285. FALSE - couldn't encrypt password. Password is in unknown state
  3286. --*/
  3287. {
  3288. NTSTATUS ntStatus;
  3289. LM_OWF_PASSWORD lmOwfPassword;
  3290. LM_SESSION_KEY lanmanKey;
  3291. _strupr(Password);
  3292. ntStatus = RtlCalculateLmOwfPassword(Password, &lmOwfPassword);
  3293. if (NT_SUCCESS(ntStatus)) {
  3294. ntStatus = GetLanmanSessionKey(ServerName, (LPBYTE)&lanmanKey);
  3295. if (NT_SUCCESS(ntStatus)) {
  3296. ntStatus = RtlEncryptLmOwfPwdWithLmSesKey(&lmOwfPassword,
  3297. &lanmanKey,
  3298. (PENCRYPTED_LM_OWF_PASSWORD)Password
  3299. );
  3300. }
  3301. }
  3302. return NT_SUCCESS(ntStatus);
  3303. }
  3304. #if DBG
  3305. PRIVATE
  3306. VOID
  3307. DumpTransactionPacket(
  3308. IN struct tr_packet* TransactionPacket,
  3309. IN BOOL IsInput,
  3310. IN BOOL DumpData
  3311. )
  3312. {
  3313. LPBYTE password;
  3314. WORD parmSeg;
  3315. WORD parmOff;
  3316. WORD dataSeg;
  3317. WORD dataOff;
  3318. DWORD parmLen;
  3319. DWORD dataLen;
  3320. char passwordBuf[8*3+1];
  3321. password = LPBYTE_FROM_POINTER(&TransactionPacket->tr_passwd);
  3322. if (password) {
  3323. sprintf(passwordBuf, "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
  3324. password[0],
  3325. password[1],
  3326. password[2],
  3327. password[3],
  3328. password[4],
  3329. password[5],
  3330. password[6],
  3331. password[7]
  3332. );
  3333. } else {
  3334. passwordBuf[0] = 0;
  3335. }
  3336. DbgPrint( "DumpTransactionPacket(%08x)\n"
  3337. "name %04x:%04x \"%s\"\n"
  3338. "password %04x:%04x %s\n"
  3339. "send parm buffer %04x:%04x\n"
  3340. "send data buffer %04x:%04x\n"
  3341. "rcv setup buffer %04x:%04x\n"
  3342. "rcv parm buffer %04x:%04x\n"
  3343. "rcv data buffer %04x:%04x\n"
  3344. "send parm len %04x\n"
  3345. "send data len %04x\n"
  3346. "rcv parm len %04x\n"
  3347. "rcv data len %04x\n"
  3348. "rcv setup len %04x\n"
  3349. "flags %04x\n"
  3350. "timeout %08x (%d)\n"
  3351. "reserved %04x\n"
  3352. "send setup len %04x\n"
  3353. "\n",
  3354. TransactionPacket,
  3355. GET_SEGMENT(&TransactionPacket->tr_name),
  3356. GET_OFFSET(&TransactionPacket->tr_name),
  3357. LPSTR_FROM_POINTER(&TransactionPacket->tr_name),
  3358. GET_SEGMENT(&TransactionPacket->tr_passwd),
  3359. GET_OFFSET(&TransactionPacket->tr_passwd),
  3360. passwordBuf,
  3361. GET_SEGMENT(&TransactionPacket->tr_spbuf),
  3362. GET_OFFSET(&TransactionPacket->tr_spbuf),
  3363. GET_SEGMENT(&TransactionPacket->tr_sdbuf),
  3364. GET_OFFSET(&TransactionPacket->tr_sdbuf),
  3365. GET_SEGMENT(&TransactionPacket->tr_rsbuf),
  3366. GET_OFFSET(&TransactionPacket->tr_rsbuf),
  3367. GET_SEGMENT(&TransactionPacket->tr_rpbuf),
  3368. GET_OFFSET(&TransactionPacket->tr_rpbuf),
  3369. GET_SEGMENT(&TransactionPacket->tr_rdbuf),
  3370. GET_OFFSET(&TransactionPacket->tr_rdbuf),
  3371. READ_WORD(&TransactionPacket->tr_splen),
  3372. READ_WORD(&TransactionPacket->tr_sdlen),
  3373. READ_WORD(&TransactionPacket->tr_rplen),
  3374. READ_WORD(&TransactionPacket->tr_rdlen),
  3375. READ_WORD(&TransactionPacket->tr_rslen),
  3376. READ_WORD(&TransactionPacket->tr_flags),
  3377. READ_DWORD(&TransactionPacket->tr_timeout),
  3378. READ_DWORD(&TransactionPacket->tr_timeout),
  3379. READ_WORD(&TransactionPacket->tr_resvd),
  3380. READ_WORD(&TransactionPacket->tr_sslen)
  3381. );
  3382. if (IsInput) {
  3383. parmLen = (DWORD)READ_WORD(&TransactionPacket->tr_splen);
  3384. dataLen = (DWORD)READ_WORD(&TransactionPacket->tr_sdlen);
  3385. parmSeg = GET_SEGMENT(&TransactionPacket->tr_spbuf);
  3386. parmOff = GET_OFFSET(&TransactionPacket->tr_spbuf);
  3387. dataSeg = GET_SEGMENT(&TransactionPacket->tr_sdbuf);
  3388. dataOff = GET_OFFSET(&TransactionPacket->tr_sdbuf);
  3389. } else {
  3390. parmLen = (DWORD)READ_WORD(&TransactionPacket->tr_rplen);
  3391. dataLen = (DWORD)READ_WORD(&TransactionPacket->tr_rdlen);
  3392. parmSeg = GET_SEGMENT(&TransactionPacket->tr_rpbuf);
  3393. parmOff = GET_OFFSET(&TransactionPacket->tr_rpbuf);
  3394. dataSeg = GET_SEGMENT(&TransactionPacket->tr_rdbuf);
  3395. dataOff = GET_OFFSET(&TransactionPacket->tr_rdbuf);
  3396. }
  3397. if (DumpData) {
  3398. if (IsInput) {
  3399. IF_DEBUG(TRANSACT_TX) {
  3400. if (parmLen) {
  3401. DbgPrint("Send Parameters:\n");
  3402. VrDumpDosMemory('B', parmLen, parmSeg, parmOff);
  3403. }
  3404. if (dataLen) {
  3405. DbgPrint("Send Data:\n");
  3406. VrDumpDosMemory('B', dataLen, dataSeg, dataOff);
  3407. }
  3408. }
  3409. } else {
  3410. IF_DEBUG(TRANSACT_RX) {
  3411. if (parmLen) {
  3412. DbgPrint("Received Parameters:\n");
  3413. VrDumpDosMemory('B', parmLen, parmSeg, parmOff);
  3414. }
  3415. if (dataLen) {
  3416. DbgPrint("Received Data:\n");
  3417. VrDumpDosMemory('B', dataLen, dataSeg, dataOff);
  3418. }
  3419. }
  3420. }
  3421. }
  3422. }
  3423. #endif