Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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