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

651 lines
17 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. Rxconfig.c
  5. Abstract:
  6. Redirector configuration routines for DRT
  7. Author:
  8. Balan Sethu Raman -- Created from the workstation service code
  9. --*/
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <ntlsa.h>
  14. #include <windows.h>
  15. #include "rxdrt.h"
  16. #include "rxdevice.h"
  17. #include "rxconfig.h"
  18. #include "malloc.h"
  19. #define PRIVILEGE_BUF_SIZE 512
  20. #define WS_LINKAGE_REGISTRY_PATH L"LanmanWorkstation\\Linkage"
  21. #define WS_BIND_VALUE_NAME L"Bind"
  22. extern NTSTATUS
  23. RxBindATransport(
  24. IN PWSTR ValueName,
  25. IN ULONG ValueType,
  26. IN PVOID ValueData,
  27. IN ULONG ValueLength,
  28. IN PVOID Context,
  29. IN PVOID EntryContext
  30. );
  31. //
  32. // For specifying the importance of a transport when binding to it.
  33. // The higher the number means that the transport will be searched
  34. // first.
  35. //
  36. STATIC DWORD QualityOfService = 65536;
  37. NTSTATUS
  38. RxGetDomainName(
  39. IN PULONG pBufferLengthInBytes,
  40. IN PWCHAR Buffer, // alloc and set ptr (free with NetApiBufferFree)
  41. OUT PBOOLEAN IsWorkgroupName
  42. )
  43. /*++
  44. Routine Description:
  45. Returns the name of the domain or workgroup this machine belongs to.
  46. Arguments:
  47. DomainNamePtr - The name of the domain or workgroup
  48. IsWorkgroupName - Returns TRUE if the name is a workgroup name.
  49. Returns FALSE if the name is a domain name.
  50. Return Value:
  51. NERR_Success - Success.
  52. NERR_CfgCompNotFound - There was an error determining the domain name
  53. --*/
  54. {
  55. NTSTATUS ntstatus;
  56. LSA_HANDLE PolicyHandle;
  57. PPOLICY_ACCOUNT_DOMAIN_INFO PrimaryDomainInfo;
  58. OBJECT_ATTRIBUTES ObjAttributes;
  59. //
  60. // Open a handle to the local security policy. Initialize the
  61. // objects attributes structure first.
  62. //
  63. InitializeObjectAttributes(
  64. &ObjAttributes,
  65. NULL,
  66. 0L,
  67. NULL,
  68. NULL
  69. );
  70. ntstatus = LsaOpenPolicy(
  71. NULL,
  72. &ObjAttributes,
  73. POLICY_VIEW_LOCAL_INFORMATION,
  74. &PolicyHandle
  75. );
  76. if (! NT_SUCCESS(ntstatus)) {
  77. return ntstatus;
  78. }
  79. //
  80. // Get the name of the primary domain from LSA
  81. //
  82. ntstatus = LsaQueryInformationPolicy(
  83. PolicyHandle,
  84. PolicyPrimaryDomainInformation,
  85. (PVOID *) &PrimaryDomainInfo
  86. );
  87. if (! NT_SUCCESS(ntstatus)) {
  88. (void) LsaClose(PolicyHandle);
  89. return ntstatus;
  90. }
  91. (void) LsaClose(PolicyHandle);
  92. if (PrimaryDomainInfo->DomainName.Length + sizeof(WCHAR) > *pBufferLengthInBytes) {
  93. ntstatus = STATUS_BUFFER_OVERFLOW;
  94. } else {
  95. *pBufferLengthInBytes = PrimaryDomainInfo->DomainName.Length;
  96. RtlZeroMemory(
  97. Buffer,
  98. PrimaryDomainInfo->DomainName.Length + sizeof(WCHAR)
  99. );
  100. memcpy(
  101. Buffer,
  102. PrimaryDomainInfo->DomainName.Buffer,
  103. PrimaryDomainInfo->DomainName.Length
  104. );
  105. }
  106. *IsWorkgroupName = (PrimaryDomainInfo->DomainSid == NULL);
  107. (void) LsaFreeMemory((PVOID) PrimaryDomainInfo);
  108. return STATUS_SUCCESS;
  109. }
  110. NTSTATUS
  111. RxStartRedirector(
  112. VOID
  113. )
  114. {
  115. NTSTATUS status;
  116. WCHAR NameBuffer[MAX_PATH];
  117. ULONG Length;
  118. WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  119. ULONG ComputerNameLengthInBytes;
  120. WCHAR DomainName[DNLEN + 1];
  121. ULONG DomainNameLengthInBytes;
  122. DWORD version;
  123. WKSTA_INFO_502 WkstaInfo;
  124. UNICODE_STRING InputString;
  125. UNICODE_STRING OutputString;
  126. BOOLEAN IsWorkGroup;
  127. BYTE Buffer[max(sizeof(LMR_REQUEST_PACKET) + (CNLEN + 1) * sizeof(WCHAR) +
  128. (DNLEN + 1) * sizeof(WCHAR),
  129. sizeof(LMDR_REQUEST_PACKET))];
  130. PLMR_REQUEST_PACKET Rrp = (PLMR_REQUEST_PACKET) Buffer;
  131. PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) Buffer;
  132. // Obtain the computer name.
  133. Length = MAX_PATH;
  134. status = GetComputerName(NameBuffer,&Length);
  135. ASSERT(Length <= MAX_COMPUTERNAME_LENGTH);
  136. // Canonicalize the name. ( Upcase conversion )
  137. InputString.Length = InputString.MaximumLength = (USHORT)((Length + 1) * sizeof(WCHAR));
  138. InputString.Buffer = NameBuffer;
  139. OutputString.Length = OutputString.MaximumLength = (USHORT)((Length + 1) * sizeof(WCHAR));
  140. OutputString.Buffer = ComputerName;
  141. ComputerNameLengthInBytes = Length * sizeof(WCHAR);
  142. RtlUpcaseUnicodeString(&OutputString,&InputString,FALSE);
  143. // Get the primary domain name from the configuration file
  144. DomainNameLengthInBytes = sizeof(WCHAR) * (DNLEN + 1);
  145. status = RxGetDomainName(&DomainNameLengthInBytes,DomainName,&IsWorkGroup);
  146. if (NT_SUCCESS(status)) {
  147. // Initialize redirector configuration
  148. Rrp->Type = ConfigInformation;
  149. Rrp->Version = REQUEST_PACKET_VERSION;
  150. wcscpy(Rrp->Parameters.Start.RedirectorName,
  151. ComputerName);
  152. Rrp->Parameters.Start.RedirectorNameLength = ComputerNameLengthInBytes;
  153. Rrp->Parameters.Start.DomainNameLength = DomainNameLengthInBytes;
  154. wcscpy((Rrp->Parameters.Start.RedirectorName+ComputerNameLengthInBytes),
  155. DomainName);
  156. status = RxRedirFsControl(
  157. RxRedirDeviceHandle,
  158. FSCTL_LMR_START,
  159. Rrp,
  160. sizeof(LMR_REQUEST_PACKET) +
  161. Rrp->Parameters.Start.RedirectorNameLength+
  162. Rrp->Parameters.Start.DomainNameLength,
  163. (LPBYTE) &WkstaInfo,
  164. sizeof(WKSTA_INFO_502),
  165. NULL
  166. );
  167. }
  168. return status;
  169. }
  170. NTSTATUS
  171. RxBindToTransports(
  172. VOID
  173. )
  174. /*++
  175. Routine Description:
  176. This function binds the transports specified in the registry to the
  177. redirector. The order of priority for the transports follows the order
  178. they are listed by the "Bind=" valuename.
  179. Arguments:
  180. None.
  181. Return Value:
  182. NTSTATUS - Success or reason for failure.
  183. --*/
  184. {
  185. NTSTATUS status;
  186. NTSTATUS tempStatus;
  187. NTSTATUS ntstatus;
  188. DWORD transportsBound;
  189. PRTL_QUERY_REGISTRY_TABLE queryTable;
  190. LIST_ENTRY header;
  191. PLIST_ENTRY pListEntry;
  192. PRX_BIND pBind;
  193. //
  194. // Ask the RTL to call us back for each subvalue in the MULTI_SZ
  195. // value \LanmanWorkstation\Linkage\Bind.
  196. //
  197. queryTable = (PVOID)malloc(sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
  198. if (queryTable == NULL) {
  199. return ERROR_NOT_ENOUGH_MEMORY;
  200. }
  201. InitializeListHead( &header);
  202. queryTable[0].QueryRoutine = RxBindATransport;
  203. queryTable[0].Flags = 0;
  204. queryTable[0].Name = WS_BIND_VALUE_NAME;
  205. queryTable[0].EntryContext = NULL;
  206. queryTable[0].DefaultType = REG_NONE;
  207. queryTable[0].DefaultData = NULL;
  208. queryTable[0].DefaultLength = 0;
  209. queryTable[1].QueryRoutine = NULL;
  210. queryTable[1].Flags = 0;
  211. queryTable[1].Name = NULL;
  212. ntstatus = RtlQueryRegistryValues(
  213. RTL_REGISTRY_SERVICES, // path relative to ...
  214. WS_LINKAGE_REGISTRY_PATH,
  215. queryTable,
  216. (PVOID) &header, // context
  217. NULL
  218. );
  219. //
  220. // First process all the data, then clean up.
  221. //
  222. for ( pListEntry = header.Flink;
  223. pListEntry != &header;
  224. pListEntry = pListEntry->Flink) {
  225. pBind = CONTAINING_RECORD(
  226. pListEntry,
  227. RX_BIND,
  228. ListEntry
  229. );
  230. tempStatus = NO_ERROR;
  231. if ( pBind->Redir->EventHandle != INVALID_HANDLE_VALUE) {
  232. WaitForSingleObject(
  233. pBind->Redir->EventHandle,
  234. INFINITE
  235. );
  236. pBind->Redir->Bound = (tempStatus == NO_ERROR);
  237. if (tempStatus == ERROR_DUP_NAME) {
  238. status = tempStatus;
  239. }
  240. }
  241. if ( pBind->Dgrec->EventHandle != INVALID_HANDLE_VALUE) {
  242. WaitForSingleObject(
  243. pBind->Dgrec->EventHandle,
  244. INFINITE
  245. );
  246. pBind->Dgrec->Bound = (tempStatus == NO_ERROR);
  247. if (tempStatus == ERROR_DUP_NAME) {
  248. status = tempStatus;
  249. }
  250. }
  251. //
  252. // If one is installed but the other is not, clean up the other.
  253. //
  254. if ( pBind->Dgrec->Bound != pBind->Redir->Bound) {
  255. RxUnbindTransport2( pBind);
  256. }
  257. }
  258. if (NT_SUCCESS(ntstatus)) {
  259. for ( pListEntry = header.Flink;
  260. pListEntry != &header;
  261. pListEntry = pListEntry->Flink) {
  262. pBind = CONTAINING_RECORD(
  263. pListEntry,
  264. RX_BIND,
  265. ListEntry
  266. );
  267. RxUnbindTransport2( pBind);
  268. }
  269. }
  270. for ( transportsBound = 0;
  271. IsListEmpty( &header) == FALSE;
  272. LocalFree((HLOCAL) pBind)) {
  273. pListEntry = RemoveHeadList( &header);
  274. pBind = CONTAINING_RECORD(
  275. pListEntry,
  276. RX_BIND,
  277. ListEntry
  278. );
  279. if ( pBind->Redir->EventHandle != INVALID_HANDLE_VALUE) {
  280. CloseHandle( pBind->Redir->EventHandle);
  281. }
  282. if ( pBind->Redir->Bound == TRUE) {
  283. transportsBound++;
  284. }
  285. if ( pBind->Dgrec->EventHandle != INVALID_HANDLE_VALUE) {
  286. CloseHandle( pBind->Dgrec->EventHandle);
  287. }
  288. }
  289. (void) free((HLOCAL) queryTable);
  290. if ( RxRedirAsyncDeviceHandle != NULL) {
  291. (VOID)NtClose( RxRedirAsyncDeviceHandle);
  292. RxRedirAsyncDeviceHandle = NULL;
  293. }
  294. if ( RxDgrecAsyncDeviceHandle != NULL) {
  295. (VOID)NtClose( RxDgrecAsyncDeviceHandle);
  296. RxDgrecAsyncDeviceHandle = NULL;
  297. }
  298. return ntstatus;
  299. }
  300. NTSTATUS
  301. RxBindATransport(
  302. IN PWSTR ValueName,
  303. IN ULONG ValueType,
  304. IN PVOID ValueData,
  305. IN ULONG ValueLength,
  306. IN PVOID Context,
  307. IN PVOID EntryContext
  308. )
  309. /*++
  310. This routine always returns SUCCESS because we want all transports
  311. to be processed fully.
  312. --*/
  313. {
  314. NTSTATUS status;
  315. DBG_UNREFERENCED_PARAMETER( ValueName);
  316. DBG_UNREFERENCED_PARAMETER( ValueLength);
  317. DBG_UNREFERENCED_PARAMETER( EntryContext);
  318. //
  319. // Bind transport
  320. //
  321. status = RxAsyncBindTransport(
  322. ValueData, // name of transport device object
  323. --QualityOfService,
  324. (PLIST_ENTRY)Context);
  325. return STATUS_SUCCESS;
  326. }
  327. DWORD
  328. RxGetPrivilege(
  329. IN DWORD numPrivileges,
  330. IN PULONG pulPrivileges
  331. )
  332. /*++
  333. Routine Description:
  334. This function alters the privilege level for the current thread.
  335. It does this by duplicating the token for the current thread, and then
  336. applying the new privileges to that new token, then the current thread
  337. impersonates with that new token.
  338. Privileges can be relinquished by calling NetpReleasePrivilege().
  339. Arguments:
  340. numPrivileges - This is a count of the number of privileges in the
  341. array of privileges.
  342. pulPrivileges - This is a pointer to the array of privileges that are
  343. desired. This is an array of ULONGs.
  344. Return Value:
  345. NO_ERROR - If the operation was completely successful.
  346. Otherwise, it returns mapped return codes from the various NT
  347. functions that are called.
  348. --*/
  349. {
  350. DWORD status;
  351. NTSTATUS ntStatus;
  352. HANDLE ourToken;
  353. HANDLE newToken;
  354. OBJECT_ATTRIBUTES Obja;
  355. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  356. ULONG bufLen;
  357. ULONG returnLen;
  358. PTOKEN_PRIVILEGES pPreviousState;
  359. PTOKEN_PRIVILEGES pTokenPrivilege = NULL;
  360. DWORD i;
  361. //
  362. // Initialize the Privileges Structure
  363. //
  364. pTokenPrivilege = LocalAlloc(LMEM_FIXED, sizeof(TOKEN_PRIVILEGES) +
  365. (sizeof(LUID_AND_ATTRIBUTES) * numPrivileges));
  366. if (pTokenPrivilege == NULL) {
  367. status = GetLastError();
  368. return(status);
  369. }
  370. pTokenPrivilege->PrivilegeCount = numPrivileges;
  371. for (i=0; i<numPrivileges ;i++ ) {
  372. pTokenPrivilege->Privileges[i].Luid = RtlConvertLongToLargeInteger(
  373. pulPrivileges[i]);
  374. pTokenPrivilege->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
  375. }
  376. //
  377. // Initialize Object Attribute Structure.
  378. //
  379. InitializeObjectAttributes(&Obja,NULL,0L,NULL,NULL);
  380. //
  381. // Initialize Security Quality Of Service Structure
  382. //
  383. SecurityQofS.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  384. SecurityQofS.ImpersonationLevel = SecurityImpersonation;
  385. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  386. SecurityQofS.EffectiveOnly = FALSE;
  387. Obja.SecurityQualityOfService = &SecurityQofS;
  388. //
  389. // Allocate storage for the structure that will hold the Previous State
  390. // information.
  391. //
  392. pPreviousState = LocalAlloc(LMEM_FIXED, PRIVILEGE_BUF_SIZE);
  393. if (pPreviousState == NULL) {
  394. status = GetLastError();
  395. LocalFree(pTokenPrivilege);
  396. return(status);
  397. }
  398. //
  399. // Open our own Token
  400. //
  401. ntStatus = NtOpenProcessToken(
  402. NtCurrentProcess(),
  403. TOKEN_DUPLICATE,
  404. &ourToken);
  405. if (!NT_SUCCESS(ntStatus)) {
  406. LocalFree(pPreviousState);
  407. LocalFree(pTokenPrivilege);
  408. return(RtlNtStatusToDosError(ntStatus));
  409. }
  410. //
  411. // Duplicate that Token
  412. //
  413. ntStatus = NtDuplicateToken(
  414. ourToken,
  415. TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  416. &Obja,
  417. FALSE, // Duplicate the entire token
  418. TokenImpersonation, // TokenType
  419. &newToken); // Duplicate token
  420. if (!NT_SUCCESS(ntStatus)) {
  421. LocalFree(pPreviousState);
  422. LocalFree(pTokenPrivilege);
  423. NtClose(ourToken);
  424. return(RtlNtStatusToDosError(ntStatus));
  425. }
  426. //
  427. // Add new privileges
  428. //
  429. bufLen = PRIVILEGE_BUF_SIZE;
  430. ntStatus = NtAdjustPrivilegesToken(
  431. newToken, // TokenHandle
  432. FALSE, // DisableAllPrivileges
  433. pTokenPrivilege, // NewState
  434. bufLen, // bufferSize for previous state
  435. pPreviousState, // pointer to previous state info
  436. &returnLen); // numBytes required for buffer.
  437. if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
  438. LocalFree(pPreviousState);
  439. bufLen = returnLen;
  440. pPreviousState = LocalAlloc(LMEM_FIXED, bufLen);
  441. ntStatus = NtAdjustPrivilegesToken(
  442. newToken, // TokenHandle
  443. FALSE, // DisableAllPrivileges
  444. pTokenPrivilege, // NewState
  445. bufLen, // bufferSize for previous state
  446. pPreviousState, // pointer to previous state info
  447. &returnLen); // numBytes required for buffer.
  448. }
  449. if (!NT_SUCCESS(ntStatus)) {
  450. LocalFree(pPreviousState);
  451. LocalFree(pTokenPrivilege);
  452. NtClose(ourToken);
  453. NtClose(newToken);
  454. return(RtlNtStatusToDosError(ntStatus));
  455. }
  456. //
  457. // Begin impersonating with the new token
  458. //
  459. ntStatus = NtSetInformationThread(
  460. NtCurrentThread(),
  461. ThreadImpersonationToken,
  462. (PVOID)&newToken,
  463. (ULONG)sizeof(HANDLE));
  464. if (!NT_SUCCESS(ntStatus)) {
  465. LocalFree(pPreviousState);
  466. LocalFree(pTokenPrivilege);
  467. NtClose(ourToken);
  468. NtClose(newToken);
  469. return(RtlNtStatusToDosError(ntStatus));
  470. }
  471. LocalFree(pPreviousState);
  472. LocalFree(pTokenPrivilege);
  473. NtClose(ourToken);
  474. NtClose(newToken);
  475. return(NO_ERROR);
  476. }
  477. DWORD
  478. RxReleasePrivilege(
  479. VOID
  480. )
  481. /*++
  482. Routine Description:
  483. This function relinquishes privileges obtained by calling NetpGetPrivilege().
  484. Arguments:
  485. none
  486. Return Value:
  487. NO_ERROR - If the operation was completely successful.
  488. Otherwise, it returns mapped return codes from the various NT
  489. functions that are called.
  490. --*/
  491. {
  492. NTSTATUS ntStatus;
  493. HANDLE NewToken;
  494. //
  495. // Revert To Self.
  496. //
  497. NewToken = NULL;
  498. ntStatus = NtSetInformationThread(
  499. NtCurrentThread(),
  500. ThreadImpersonationToken,
  501. (PVOID)&NewToken,
  502. (ULONG)sizeof(HANDLE));
  503. if ( !NT_SUCCESS(ntStatus) ) {
  504. return(RtlNtStatusToDosError(ntStatus));
  505. }
  506. return(NO_ERROR);
  507. }
  508.