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.

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