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.

694 lines
17 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract:
  6. This module implements all utility functions.
  7. Author:
  8. Wesley Witt (wesw) 21-Oct-1998
  9. Revision History:
  10. --*/
  11. #include "cmdcons.h"
  12. #pragma hdrstop
  13. #include "remboot.h"
  14. HANDLE NetUseHandles[26] = { NULL };
  15. BOOLEAN RdrIsInKernelMode = FALSE;
  16. RC_ALLOWED_DIRECTORY AllowedDirs[] = {
  17. { FALSE, L"$WIN_NT$.~BT" },
  18. { FALSE, L"$WIN_NT$.~LS" },
  19. { FALSE, L"CMDCONS" },
  20. { TRUE, L"SYSTEM VOLUME INFORMATION" }
  21. };
  22. BOOLEAN
  23. RcIsPathNameAllowed(
  24. IN LPCWSTR FullPath,
  25. IN BOOLEAN RemovableMediaOk,
  26. IN BOOLEAN Mkdir
  27. )
  28. /*++
  29. Routine Description:
  30. This routine verifies that the specified path name is
  31. allowed based on the security context that the console
  32. user is logged into.
  33. Arguments:
  34. FullPath - specifies the full path to be verified.
  35. Return Value:
  36. FALSE if failure, indicating the path is not allowed.
  37. TRUE otherwise.
  38. --*/
  39. {
  40. WCHAR TempBuf[MAX_PATH*2];
  41. UNICODE_STRING UnicodeString;
  42. OBJECT_ATTRIBUTES Obja;
  43. HANDLE Handle;
  44. IO_STATUS_BLOCK IoStatusBlock;
  45. NTSTATUS Status;
  46. BOOL isDirectory = TRUE;
  47. //
  48. // should we bypass security?
  49. //
  50. if (AllowAllPaths) {
  51. return TRUE;
  52. }
  53. //
  54. // some special processing for dos paths
  55. // we must make sure that only the root and %systemdir% are allowed.
  56. //
  57. if (FullPath[1] == L':' && FullPath[2] == L'\\' && FullPath[3] == 0) {
  58. //
  59. // root directory is ok.
  60. //
  61. return TRUE;
  62. }
  63. SpStringToUpper((PWSTR)FullPath);
  64. if (!RcGetNTFileName((PWSTR)FullPath,TempBuf))
  65. return FALSE;
  66. INIT_OBJA(&Obja,&UnicodeString,TempBuf);
  67. Status = ZwOpenFile(
  68. &Handle,
  69. FILE_READ_ATTRIBUTES,
  70. &Obja,
  71. &IoStatusBlock,
  72. FILE_SHARE_READ | FILE_SHARE_WRITE,
  73. FILE_DIRECTORY_FILE
  74. );
  75. if( !NT_SUCCESS(Status) ) {
  76. isDirectory = FALSE;
  77. } else {
  78. ZwClose( Handle );
  79. }
  80. if (isDirectory == FALSE && wcsrchr( FullPath, L'\\' ) == ( &FullPath[2] )) {
  81. //
  82. // if the cannonicalized path has only one slash the user is trying to do something
  83. // to the files in the root, which we allow.
  84. //
  85. // however we do not allow users to mess with directories at the root
  86. //
  87. if (Mkdir) {
  88. return FALSE;
  89. } else {
  90. return TRUE;
  91. }
  92. }
  93. ASSERT(SelectedInstall != NULL);
  94. if(SelectedInstall != NULL) {
  95. //
  96. // Get the length of the first element in the path
  97. //
  98. PCWSTR sz;
  99. DWORD Len;
  100. DWORD i;
  101. WCHAR SelectedInstallDrive;
  102. sz = wcschr(FullPath + 3, L'\\');
  103. if(NULL == sz) {
  104. sz = FullPath + wcslen(FullPath);
  105. }
  106. Len = (DWORD) ((sz - FullPath) - 3);
  107. SelectedInstallDrive = RcToUpper(SelectedInstall->DriveLetter);
  108. //
  109. // See if path begins with the install path
  110. //
  111. if(FullPath[0] == SelectedInstallDrive && 0 == _wcsnicmp(FullPath + 3, SelectedInstall->Path, Len)) {
  112. return TRUE;
  113. }
  114. //
  115. // See if the path begins with an allowed dir
  116. //
  117. for(i = 0; i < sizeof(AllowedDirs) / sizeof(AllowedDirs[0]); ++i) {
  118. if((!AllowedDirs[i].MustBeOnInstallDrive || FullPath[0] == SelectedInstallDrive) &&
  119. 0 == _wcsnicmp(FullPath + 3, AllowedDirs[i].Directory, Len)) {
  120. return TRUE;
  121. }
  122. }
  123. }
  124. if (RcIsFileOnRemovableMedia(TempBuf) == STATUS_SUCCESS) {
  125. if (RemovableMediaOk) {
  126. return TRUE;
  127. }
  128. }
  129. if (RcIsNetworkDrive(TempBuf) == STATUS_SUCCESS) {
  130. //
  131. // Context that was used for connection will do appropriate security checking.
  132. //
  133. return TRUE;
  134. }
  135. return FALSE;
  136. }
  137. BOOLEAN
  138. RcDoesPathHaveWildCards(
  139. IN LPCWSTR FullPath
  140. )
  141. /*++
  142. Routine Description:
  143. This routine verifies that the specified path name is
  144. allowed based on the security context that the console
  145. user is logged into.
  146. Arguments:
  147. FullPath - specifies the full path to be verified.
  148. Return Value:
  149. FALSE if failure, indicating the path is not allowed.
  150. TRUE otherwise.
  151. --*/
  152. {
  153. if (wcsrchr( FullPath, L'*' )) {
  154. return TRUE;
  155. }
  156. if (wcsrchr( FullPath, L'?' )) {
  157. return TRUE;
  158. }
  159. return FALSE;
  160. }
  161. NTSTATUS
  162. RcIsNetworkDrive(
  163. IN PWSTR FileName
  164. )
  165. /*++
  166. Routine Description:
  167. This routine returns if the FileName given is a network path.
  168. Arguments:
  169. FileName - specifies the full path to be checked.
  170. Return Value:
  171. Any other than STATUS_SUCCESS if failure, indicating the path is not on the network,
  172. STATUS_SUCCESS otherwise.
  173. --*/
  174. {
  175. NTSTATUS Status;
  176. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  177. PWSTR BaseNtName;
  178. if (wcsncmp(FileName, L"\\DosDevice", wcslen(L"\\DosDevice")) == 0) {
  179. Status = GetDriveLetterLinkTarget( FileName, &BaseNtName );
  180. if (!NT_SUCCESS(Status)) {
  181. return Status;
  182. }
  183. } else {
  184. BaseNtName = FileName;
  185. }
  186. Status = pRcGetDeviceInfo( BaseNtName, &DeviceInfo );
  187. if(NT_SUCCESS(Status)) {
  188. if (DeviceInfo.DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM) {
  189. Status = STATUS_NO_MEDIA;
  190. }
  191. }
  192. return Status;
  193. }
  194. NTSTATUS
  195. RcDoNetUse(
  196. PWSTR Share,
  197. PWSTR User,
  198. PWSTR Password,
  199. PWSTR Drive
  200. )
  201. /*++
  202. Routine Description:
  203. This routine attempts to make a connection using the redirector to the remote server.
  204. Arguments:
  205. Share - A string of the form "\\server\share"
  206. User - A string of the form "domain\user"
  207. Password - A string containing the password information.
  208. Drive - Filled in with a string of the form "X", where X is the drive letter the share
  209. has been mapped to.
  210. Return Value:
  211. STATUS_SUCCESS if successful, indicating Drive contains the mapped drive letter,
  212. otherwise the appropriate error code.
  213. --*/
  214. {
  215. NTSTATUS Status;
  216. PWSTR NtDeviceName;
  217. ULONG ShareLength;
  218. WCHAR DriveLetter;
  219. WCHAR temporaryBuffer[128];
  220. PWCHAR Temp, Temp2;
  221. HANDLE Handle;
  222. ULONG EaBufferLength;
  223. PWSTR UserName;
  224. PWSTR DomainName;
  225. PVOID EaBuffer;
  226. UNICODE_STRING UnicodeString;
  227. UNICODE_STRING UnicodeString2;
  228. OBJECT_ATTRIBUTES ObjectAttributes;
  229. IO_STATUS_BLOCK IoStatusBlock;
  230. PFILE_FULL_EA_INFORMATION FullEaInfo;
  231. //
  232. // Switch the redirector to kernel-mode security if it is not.
  233. //
  234. if (!RdrIsInKernelMode) {
  235. Status = PutRdrInKernelMode();
  236. if (!NT_SUCCESS(Status)) {
  237. return Status;
  238. }
  239. RdrIsInKernelMode = TRUE;
  240. }
  241. //
  242. // Search for an open drive letter, starting at D: and working up.
  243. //
  244. wcscpy(temporaryBuffer, L"\\DosDevices\\D:");
  245. Temp = wcsstr(temporaryBuffer, L"D:");
  246. for (DriveLetter = L'D'; (Temp && (DriveLetter <= L'Z')); DriveLetter++) {
  247. *Temp = DriveLetter;
  248. Status = GetDriveLetterLinkTarget( temporaryBuffer, &Temp2 );
  249. if (!NT_SUCCESS(Status)) {
  250. break;
  251. }
  252. }
  253. if (DriveLetter > L'Z') {
  254. return STATUS_OBJECT_NAME_INVALID;
  255. }
  256. //
  257. // Build the NT device name.
  258. //
  259. ShareLength = wcslen(Share);
  260. NtDeviceName = SpMemAlloc(ShareLength * sizeof(WCHAR) + sizeof(L"\\Device\\LanmanRedirector\\;X:0"));
  261. if (NtDeviceName == NULL) {
  262. return STATUS_NO_MEMORY;
  263. }
  264. wcscpy(NtDeviceName, L"\\Device\\LanmanRedirector\\;");
  265. temporaryBuffer[0] = DriveLetter;
  266. temporaryBuffer[1] = UNICODE_NULL;
  267. wcscat(NtDeviceName, temporaryBuffer);
  268. wcscat(NtDeviceName, L":0");
  269. wcscat(NtDeviceName, Share + 1);
  270. //
  271. // Chop the username and domainname into individual values.
  272. //
  273. wcscpy(temporaryBuffer, User);
  274. DomainName = temporaryBuffer;
  275. UserName = wcsstr(temporaryBuffer, L"\\");
  276. if (UserName == NULL) {
  277. SpMemFree(NtDeviceName);
  278. return STATUS_OBJECT_NAME_INVALID;
  279. }
  280. *UserName = UNICODE_NULL;
  281. UserName++;
  282. //
  283. // Create buffer with user credentials
  284. //
  285. EaBufferLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]);
  286. EaBufferLength += sizeof(EA_NAME_DOMAIN);
  287. EaBufferLength += (wcslen(DomainName) * sizeof(WCHAR));
  288. if (EaBufferLength & (sizeof(ULONG) - 1)) {
  289. //
  290. // Long align the next entry
  291. //
  292. EaBufferLength += (sizeof(ULONG) - (EaBufferLength & (sizeof(ULONG) - 1)));
  293. }
  294. EaBufferLength += FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]);
  295. EaBufferLength += sizeof(EA_NAME_USERNAME);
  296. EaBufferLength += (wcslen(UserName) * sizeof(WCHAR));
  297. if (EaBufferLength & (sizeof(ULONG) - 1)) {
  298. //
  299. // Long align the next entry
  300. //
  301. EaBufferLength += (sizeof(ULONG) - (EaBufferLength & (sizeof(ULONG) - 1)));
  302. }
  303. EaBufferLength += FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]);
  304. EaBufferLength += sizeof(EA_NAME_PASSWORD);
  305. EaBufferLength += (wcslen(Password) * sizeof(WCHAR));
  306. EaBuffer = SpMemAlloc(EaBufferLength);
  307. if (EaBuffer == NULL) {
  308. SpMemFree(NtDeviceName);
  309. return STATUS_NO_MEMORY;
  310. }
  311. FullEaInfo = (PFILE_FULL_EA_INFORMATION)EaBuffer;
  312. FullEaInfo->Flags = 0;
  313. FullEaInfo->EaNameLength = sizeof(EA_NAME_DOMAIN) - 1;
  314. FullEaInfo->EaValueLength = (wcslen(DomainName)) * sizeof(WCHAR);
  315. strcpy(&(FullEaInfo->EaName[0]), EA_NAME_DOMAIN);
  316. memcpy(&(FullEaInfo->EaName[FullEaInfo->EaNameLength + 1]), DomainName, FullEaInfo->EaValueLength);
  317. FullEaInfo->NextEntryOffset = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  318. FullEaInfo->EaNameLength + 1 +
  319. FullEaInfo->EaValueLength;
  320. if (FullEaInfo->NextEntryOffset & (sizeof(ULONG) - 1)) {
  321. FullEaInfo->NextEntryOffset += (sizeof(ULONG) -
  322. (FullEaInfo->NextEntryOffset &
  323. (sizeof(ULONG) - 1)));
  324. }
  325. FullEaInfo = (PFILE_FULL_EA_INFORMATION)(((char *)FullEaInfo) + FullEaInfo->NextEntryOffset);
  326. FullEaInfo->Flags = 0;
  327. FullEaInfo->EaNameLength = sizeof(EA_NAME_USERNAME) - 1;
  328. FullEaInfo->EaValueLength = (wcslen(UserName)) * sizeof(WCHAR);
  329. strcpy(&(FullEaInfo->EaName[0]), EA_NAME_USERNAME);
  330. memcpy(&(FullEaInfo->EaName[FullEaInfo->EaNameLength + 1]), UserName, FullEaInfo->EaValueLength);
  331. FullEaInfo->NextEntryOffset = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  332. FullEaInfo->EaNameLength + 1 +
  333. FullEaInfo->EaValueLength;
  334. if (FullEaInfo->NextEntryOffset & (sizeof(ULONG) - 1)) {
  335. FullEaInfo->NextEntryOffset += (sizeof(ULONG) -
  336. (FullEaInfo->NextEntryOffset &
  337. (sizeof(ULONG) - 1)));
  338. }
  339. FullEaInfo = (PFILE_FULL_EA_INFORMATION)(((char *)FullEaInfo) + FullEaInfo->NextEntryOffset);
  340. FullEaInfo->Flags = 0;
  341. FullEaInfo->EaNameLength = sizeof(EA_NAME_PASSWORD) - 1;
  342. FullEaInfo->EaValueLength = (wcslen(Password)) * sizeof(WCHAR);
  343. strcpy(&(FullEaInfo->EaName[0]), EA_NAME_PASSWORD);
  344. memcpy(&(FullEaInfo->EaName[FullEaInfo->EaNameLength + 1]), Password, FullEaInfo->EaValueLength);
  345. FullEaInfo->NextEntryOffset = 0;
  346. //
  347. // Now make the connection
  348. //
  349. RtlInitUnicodeString(&UnicodeString, NtDeviceName);
  350. InitializeObjectAttributes(&ObjectAttributes,
  351. &UnicodeString,
  352. OBJ_CASE_INSENSITIVE,
  353. NULL,
  354. NULL
  355. );
  356. Status = ZwCreateFile(&Handle,
  357. SYNCHRONIZE,
  358. &ObjectAttributes,
  359. &IoStatusBlock,
  360. NULL,
  361. FILE_ATTRIBUTE_NORMAL,
  362. FILE_SHARE_READ,
  363. FILE_OPEN_IF,
  364. (FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
  365. EaBuffer,
  366. EaBufferLength
  367. );
  368. if (NT_SUCCESS(Status) && NT_SUCCESS(IoStatusBlock.Status)) {
  369. //
  370. // Save off the handle so we can close it later if need be
  371. //
  372. NetUseHandles[DriveLetter - L'A'] = Handle;
  373. Drive[0] = DriveLetter;
  374. Drive[1] = L':';
  375. Drive[2] = UNICODE_NULL;
  376. //
  377. // Now create a symbolic link from the dos drive letter to the redirector
  378. //
  379. wcscpy(temporaryBuffer, L"\\DosDevices\\");
  380. wcscat(temporaryBuffer, Drive);
  381. RtlInitUnicodeString(&UnicodeString2, temporaryBuffer);
  382. Status = IoCreateSymbolicLink(&UnicodeString2, &UnicodeString);
  383. if (!NT_SUCCESS(Status)) {
  384. ZwClose(Handle);
  385. NetUseHandles[DriveLetter - L'A'] = NULL;
  386. } else {
  387. RcAddDrive(DriveLetter);
  388. }
  389. }
  390. SpMemFree(NtDeviceName);
  391. return Status;
  392. }
  393. NTSTATUS
  394. RcNetUnuse(
  395. PWSTR Drive
  396. )
  397. /*++
  398. Routine Description:
  399. This routine closes a network connection.
  400. Arguments:
  401. Drive - A string of the form "X:", where X is the drive letter returned by a previous call to
  402. NetDoNetUse().
  403. Return Value:
  404. STATUS_SUCCESS if successful, indicating the drive letter has been unmapped,
  405. otherwise the appropriate error code.
  406. --*/
  407. {
  408. NTSTATUS Status;
  409. WCHAR DriveLetter;
  410. WCHAR temporaryBuffer[128];
  411. UNICODE_STRING UnicodeString;
  412. DriveLetter = *Drive;
  413. if ((DriveLetter >= L'a') && (DriveLetter <= L'z')) {
  414. DriveLetter = L'A' + (DriveLetter - L'a');
  415. }
  416. if ((DriveLetter < L'A') | (DriveLetter > L'Z')) {
  417. return STATUS_OBJECT_NAME_INVALID;
  418. }
  419. if (NetUseHandles[DriveLetter - L'A'] == NULL) {
  420. return STATUS_OBJECT_NAME_INVALID;
  421. }
  422. if (RcGetCurrentDriveLetter() == DriveLetter) {
  423. return STATUS_CONNECTION_IN_USE;
  424. }
  425. wcscpy(temporaryBuffer, L"\\DosDevices\\");
  426. wcscat(temporaryBuffer, Drive);
  427. RtlInitUnicodeString(&UnicodeString, temporaryBuffer);
  428. Status = IoDeleteSymbolicLink(&UnicodeString);
  429. if (NT_SUCCESS(Status)) {
  430. ZwClose(NetUseHandles[DriveLetter - L'A']);
  431. NetUseHandles[DriveLetter - L'A'] = NULL;
  432. RcRemoveDrive(DriveLetter);
  433. }
  434. return Status;
  435. }
  436. NTSTATUS
  437. PutRdrInKernelMode(
  438. VOID
  439. )
  440. /*++
  441. Routine Description:
  442. This routine IOCTLs down to the rdr to force it to use kernel-mode security.
  443. Arguments:
  444. None.
  445. Return Value:
  446. STATUS_SUCCESS if successful, otherwise the appropriate error code.
  447. --*/
  448. {
  449. OBJECT_ATTRIBUTES ObjectAttributes;
  450. UNICODE_STRING UnicodeString;
  451. IO_STATUS_BLOCK IoStatusBlock;
  452. NTSTATUS Status;
  453. HANDLE Handle;
  454. RtlInitUnicodeString(&UnicodeString, DD_NFS_DEVICE_NAME_U);
  455. InitializeObjectAttributes(
  456. &ObjectAttributes,
  457. &UnicodeString,
  458. OBJ_CASE_INSENSITIVE,
  459. NULL,
  460. NULL
  461. );
  462. Status = ZwCreateFile(
  463. &Handle,
  464. GENERIC_READ | GENERIC_WRITE,
  465. &ObjectAttributes,
  466. &IoStatusBlock,
  467. NULL,
  468. 0,
  469. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  470. FILE_OPEN,
  471. FILE_SYNCHRONOUS_IO_NONALERT,
  472. NULL,
  473. 0
  474. );
  475. if (!NT_SUCCESS(Status)) {
  476. KdPrint(("SPCMDCON: Unable to open redirector. %x\n", Status));
  477. return Status;
  478. }
  479. Status = ZwDeviceIoControlFile(Handle,
  480. NULL,
  481. NULL,
  482. NULL,
  483. &IoStatusBlock,
  484. IOCTL_LMMR_USEKERNELSEC,
  485. NULL,
  486. 0,
  487. NULL,
  488. 0
  489. );
  490. if (NT_SUCCESS(Status)) {
  491. Status = IoStatusBlock.Status;
  492. }
  493. ZwClose(Handle);
  494. return Status;
  495. }
  496. BOOLEAN
  497. RcIsArc(
  498. VOID
  499. )
  500. /*++
  501. Routine Description:
  502. Run time check to determine if this is an Arc system. We attempt to read an
  503. Arc variable using the Hal. This will fail for Bios based systems.
  504. Arguments:
  505. None
  506. Return Value:
  507. True = This is an Arc system.
  508. --*/
  509. {
  510. #ifdef _X86_
  511. ARC_STATUS ArcStatus = EBADF;
  512. //
  513. // Get the env var into the temp buffer.
  514. //
  515. UCHAR wbuff[130];
  516. //
  517. // Get the env var into the temp buffer.
  518. //
  519. ArcStatus = HalGetEnvironmentVariable(
  520. "OsLoader",
  521. sizeof(wbuff),
  522. wbuff
  523. );
  524. return((ArcStatus == ESUCCESS) ? TRUE: FALSE);
  525. #else
  526. return TRUE;
  527. #endif
  528. }