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.

3429 lines
83 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. srvhandl.c
  5. Abstract:
  6. This module implements all file descriptor oriented APIs.
  7. Author:
  8. Mark Lucovsky (markl) 30-Mar-1989
  9. Ellen Aycock-Wright (ellena) Nov-1990
  10. Revision History:
  11. --*/
  12. #include <sys/stat.h>
  13. #include "psxsrv.h"
  14. #define NTPSX_ONLY
  15. #include "sesport.h"
  16. void
  17. FindOwnerModeFile(
  18. IN HANDLE FileHandle,
  19. OUT struct stat *StatBuf
  20. );
  21. PSID
  22. GetLoginGroupSid(
  23. IN PPSX_PROCESS p
  24. );
  25. static PVOID pvInitSDMem[10];
  26. ULONG OflagToDesiredAccess[8] = {
  27. FILE_READ_DATA,
  28. FILE_WRITE_DATA,
  29. FILE_READ_DATA | FILE_WRITE_DATA,
  30. 0,
  31. 0,
  32. 0,
  33. 0,
  34. 0
  35. };
  36. PSID MakeSid();
  37. static BOOLEAN IsUserInGroup(
  38. PPSX_PROCESS p,
  39. PSID Group
  40. );
  41. BOOLEAN Open(
  42. PPSX_PROCESS p,
  43. PPSX_API_MSG m,
  44. PUNICODE_STRING Path,
  45. ULONG,
  46. mode_t,
  47. PULONG pRetVal,
  48. PULONG Error
  49. );
  50. BOOLEAN
  51. PsxOpen(
  52. IN PPSX_PROCESS p,
  53. IN OUT PPSX_API_MSG m
  54. )
  55. /*++
  56. Routine Description:
  57. This procedure implements POSIX Open.
  58. Arguments:
  59. p - Supplies the address of the process making the call.
  60. m - Supplies the address of the message associated with the open request.
  61. Return Value:
  62. TRUE - The contents of *m should be used to generate a reply.
  63. --*/
  64. {
  65. PPSX_OPEN_MSG args;
  66. NTSTATUS Status;
  67. BOOLEAN r;
  68. args = &m->u.Open;
  69. //
  70. // Check validity of pathname pointer
  71. //
  72. if (!ISPOINTERVALID_CLIENT(p, args->Path_U.Buffer,
  73. args->Path_U.Length)) {
  74. KdPrint(("Invalid pointer to open: 0x%x\n",
  75. args->Path_U.Buffer));
  76. m->Error = EINVAL;
  77. return TRUE;
  78. }
  79. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  80. if (!NT_SUCCESS(Status)) {
  81. m->Error = PsxStatusToErrno(Status);
  82. return TRUE;
  83. }
  84. r = Open(p, m, &args->Path_U, args->Flags, args->Mode, &m->ReturnValue,
  85. &m->Error);
  86. EndImpersonation();
  87. return r;
  88. }
  89. //
  90. // Internal support routine
  91. //
  92. BOOLEAN
  93. Open(
  94. IN PPSX_PROCESS p,
  95. IN PPSX_API_MSG m,
  96. IN PUNICODE_STRING Path,
  97. IN ULONG Flags,
  98. IN mode_t Mode,
  99. OUT PULONG pRetVal,
  100. OUT PULONG pError
  101. )
  102. {
  103. HANDLE FileHandle;
  104. NTSTATUS Status;
  105. PFILEDESCRIPTOR Fd;
  106. ULONG FdIndex;
  107. ULONG DesiredAccess;
  108. IO_STATUS_BLOCK Iosb;
  109. ULONG Options;
  110. FILE_INTERNAL_INFORMATION SerialNumber;
  111. OBJECT_ATTRIBUTES ObjA;
  112. ULONG FileClass;
  113. FILE_ALLOCATION_INFORMATION AllocationInfo;
  114. FILE_BASIC_INFORMATION BasicInfo;
  115. struct stat StatBuf;
  116. ULONG PosixTime;
  117. ULONG len;
  118. Fd = AllocateFd(p, 0, &FdIndex);
  119. if (NULL == Fd) {
  120. // No file descriptors are available.
  121. *pError = EMFILE;
  122. return TRUE;
  123. }
  124. DesiredAccess = OflagToDesiredAccess[Flags & O_ACCMODE];
  125. //
  126. // Whenever a file is opened, its ownership, protection, file type
  127. // information is available. This implies that to view a file from
  128. // posix, the following access rights are required:
  129. //
  130. // READ_CONTROL - to derive owner and mode
  131. // FILE_READ_ATTRIBUTES - to read control bit to see if what we
  132. // got was a pipe
  133. // FILE_READ_EA - to read EA's that determine object type
  134. // SYNCHRONIZE - to do syncronous IO
  135. //
  136. DesiredAccess |= (SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES |
  137. FILE_READ_EA);
  138. Options = FILE_SYNCHRONOUS_IO_NONALERT;
  139. //
  140. // If the pathname is /dev/tty, make the fd be open
  141. // on the process console.
  142. //
  143. {
  144. UNICODE_STRING U;
  145. PSX_GET_STRLEN(DOSDEVICE_X2_A,len);
  146. PSX_GET_SESSION_OBJECT_NAME(&U, DEV_TTY);
  147. if (Path->Length == U.Length &&
  148. 0 == wcsncmp(&Path->Buffer[len], &U.Buffer[len], 8)) {
  149. *pRetVal = FdIndex;
  150. *pError = OpenTty(p, Fd, DesiredAccess, Flags, TRUE);
  151. return TRUE;
  152. }
  153. }
  154. //
  155. // If the pathname is /dev/null, make the fd be open
  156. // on the corresponding special device.
  157. //
  158. {
  159. UNICODE_STRING U;
  160. PSX_GET_STRLEN(DOSDEVICE_X2_A,len);
  161. PSX_GET_SESSION_OBJECT_NAME(&U, DEV_NULL);
  162. if (Path->Length == U.Length &&
  163. 0 == wcsncmp(&Path->Buffer[len], &U.Buffer[len], 8)) {
  164. *pRetVal = FdIndex;
  165. *pError = OpenDevNull(p, Fd, DesiredAccess, Flags);
  166. return TRUE;
  167. }
  168. }
  169. //
  170. // We ask for delete access when we open the file, and if we
  171. // can't get it we try without. If the file is unlinked while
  172. // it's open, it gets moved to the junkyard, and when the last
  173. // close occurs we use the delete access to remove it.
  174. //
  175. DesiredAccess |= DELETE;
  176. if (Flags & O_CREAT) {
  177. CHAR buf[SECURITY_DESCRIPTOR_MIN_LENGTH];
  178. PSECURITY_DESCRIPTOR pSD = (PVOID)buf;
  179. Status = InitSecurityDescriptor(pSD, Path, p->Process,
  180. (Mode & _S_PROT) & ~p->FileModeCreationMask,
  181. pvInitSDMem);
  182. if (!NT_SUCCESS(Status)) {
  183. *pError = PsxStatusToErrno(Status);
  184. return TRUE;
  185. }
  186. InitializeObjectAttributes(&ObjA, Path, 0, NULL, pSD);
  187. Status = NtCreateFile(&FileHandle, DesiredAccess, &ObjA, &Iosb,
  188. NULL, FILE_ATTRIBUTE_NORMAL, SHARE_ALL,
  189. (Flags & O_EXCL) ? FILE_CREATE : FILE_OPEN_IF,
  190. Options, NULL, 0);
  191. if (STATUS_ACCESS_DENIED == Status ||
  192. STATUS_SHARING_VIOLATION == Status) {
  193. DesiredAccess &= ~DELETE;
  194. Status = NtCreateFile(&FileHandle, DesiredAccess,
  195. &ObjA, &Iosb,
  196. NULL, FILE_ATTRIBUTE_NORMAL, SHARE_ALL,
  197. (Flags & O_EXCL) ? FILE_CREATE : FILE_OPEN_IF,
  198. Options, NULL, 0);
  199. }
  200. DeInitSecurityDescriptor(pSD, pvInitSDMem);
  201. } else {
  202. InitializeObjectAttributes(&ObjA, Path, 0, NULL, NULL);
  203. Status = NtOpenFile(&FileHandle, DesiredAccess, &ObjA, &Iosb,
  204. SHARE_ALL, Options);
  205. if (STATUS_ACCESS_DENIED == Status ||
  206. STATUS_SHARING_VIOLATION == Status) {
  207. DesiredAccess &= ~DELETE;
  208. Status = NtOpenFile(&FileHandle, DesiredAccess, &ObjA, &Iosb,
  209. SHARE_ALL, Options);
  210. }
  211. }
  212. if (!NT_SUCCESS(Status)) {
  213. if (Status == STATUS_OBJECT_PATH_NOT_FOUND) {
  214. *pError = PsxStatusToErrnoPath(Path);
  215. return TRUE;
  216. }
  217. *pError = PsxStatusToErrno(Status);
  218. return TRUE;
  219. }
  220. //
  221. // Determine what type of file we have here.
  222. //
  223. FileClass = PsxDetermineFileClass(FileHandle);
  224. if (S_IFDIR == FileClass &&
  225. (DesiredAccess & FILE_WRITE_DATA)) {
  226. //
  227. // 1003.1-90 (5.3.1.4): the open() function shall return
  228. // -1 and set errno...
  229. // [EISDIR] The named file is a directory, and
  230. // the oflag argument specifies write
  231. // or read/write access.
  232. NtClose(FileHandle);
  233. *pError = EISDIR;
  234. return TRUE;
  235. }
  236. if ((Flags & O_TRUNC) && FileClass != S_IFIFO &&
  237. (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
  238. AllocationInfo.AllocationSize = RtlConvertLongToLargeInteger(0);
  239. Status = NtSetInformationFile(FileHandle, &Iosb,
  240. &AllocationInfo, sizeof(AllocationInfo), FileAllocationInformation);
  241. if (!NT_SUCCESS(Status)) {
  242. NtClose(FileHandle);
  243. *pError = PsxStatusToErrno(Status);
  244. return TRUE;
  245. }
  246. }
  247. Fd->SystemOpenFileDesc = AllocateSystemOpenFile();
  248. if (! Fd->SystemOpenFileDesc) {
  249. NtClose(FileHandle);
  250. *pError = ENOMEM;
  251. return TRUE;
  252. }
  253. Fd->SystemOpenFileDesc->NtIoHandle = FileHandle;
  254. if (DesiredAccess & FILE_READ_DATA) {
  255. Fd->SystemOpenFileDesc->Flags |= PSX_FD_READ;
  256. }
  257. if (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
  258. Fd->SystemOpenFileDesc->Flags |= PSX_FD_WRITE;
  259. }
  260. if (Flags & O_NONBLOCK) {
  261. Fd->SystemOpenFileDesc->Flags |= PSX_FD_NOBLOCK;
  262. }
  263. if (Flags & O_APPEND) {
  264. Fd->SystemOpenFileDesc->Flags |= PSX_FD_APPEND;
  265. }
  266. //
  267. // Get serial numbers.
  268. //
  269. Status = NtQueryInformationFile(FileHandle, &Iosb, &SerialNumber,
  270. sizeof(SerialNumber), FileInternalInformation);
  271. if (!NT_SUCCESS(Status)) {
  272. NtClose(FileHandle);
  273. *pError = PsxStatusToErrno(Status);
  274. return TRUE;
  275. }
  276. if (ReferenceOrCreateIoNode(GetFileDeviceNumber(Path),
  277. (ino_t)SerialNumber.IndexNumber.LowPart,
  278. FALSE, &Fd->SystemOpenFileDesc->IoNode)) {
  279. //
  280. // Existing Node Minimal Init
  281. //
  282. RtlLeaveCriticalSection(
  283. &Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
  284. *pRetVal = FdIndex;
  285. return IoOpenNewHandle(p, Fd, m);
  286. }
  287. if (! Fd->SystemOpenFileDesc->IoNode) {
  288. NtClose(FileHandle);
  289. *pError = ENOMEM;
  290. return TRUE;
  291. }
  292. //
  293. // New IoNode; lots of initialization
  294. //
  295. if (FileClass == S_IFIFO) {
  296. Fd->SystemOpenFileDesc->IoNode->IoVectors = &NamedPipeVectors;
  297. Fd->SystemOpenFileDesc->IoNode->Context =
  298. RtlAllocateHeap(PsxHeap, 0, sizeof(LOCAL_PIPE));
  299. InitializeLocalPipe(
  300. (PLOCAL_PIPE)Fd->SystemOpenFileDesc->IoNode->Context);
  301. } else {
  302. Fd->SystemOpenFileDesc->IoNode->IoVectors = &FileVectors;
  303. }
  304. PSX_GET_STRLEN("/DosDevices/X:",len);
  305. Fd->SystemOpenFileDesc->IoNode->PathLength = Path->Length/2 - len;
  306. StatBuf.st_mode = FileClass;
  307. FindOwnerModeFile(FileHandle, &StatBuf);
  308. Fd->SystemOpenFileDesc->IoNode->Mode =
  309. StatBuf.st_mode & ~(p->FileModeCreationMask);
  310. Fd->SystemOpenFileDesc->IoNode->OwnerId = StatBuf.st_uid;
  311. Fd->SystemOpenFileDesc->IoNode->GroupId = StatBuf.st_gid;
  312. //
  313. // Get the file timestamps, convert to Posix format, and stash
  314. // them away in the IoNode.
  315. //
  316. Status = NtQueryInformationFile(FileHandle, &Iosb, (PVOID)&BasicInfo,
  317. sizeof(BasicInfo), FileBasicInformation);
  318. if (!NT_SUCCESS(Status)) {
  319. *pError = PsxStatusToErrno(Status);
  320. return TRUE;
  321. }
  322. if (!RtlTimeToSecondsSince1970(&BasicInfo.LastAccessTime, &PosixTime)) {
  323. PosixTime = 0;
  324. }
  325. Fd->SystemOpenFileDesc->IoNode->AccessDataTime = PosixTime;
  326. if (!RtlTimeToSecondsSince1970(&BasicInfo.LastWriteTime, &PosixTime)) {
  327. PosixTime = 0;
  328. }
  329. Fd->SystemOpenFileDesc->IoNode->ModifyDataTime = PosixTime;
  330. if (!RtlTimeToSecondsSince1970(&BasicInfo.ChangeTime, &PosixTime)) {
  331. PosixTime = 0;
  332. }
  333. Fd->SystemOpenFileDesc->IoNode->ModifyIoNodeTime = PosixTime;
  334. RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
  335. *pRetVal = FdIndex;
  336. return IoOpenNewHandle(p, Fd, m);
  337. }
  338. BOOLEAN
  339. PsxClose (
  340. IN PPSX_PROCESS p,
  341. IN OUT PPSX_API_MSG m
  342. )
  343. /*++
  344. Routine Description:
  345. This procedure implements POSIX Close.
  346. Arguments:
  347. p - Supplies the address of the process making the call.
  348. m - Supplies the address of the message associated with the close request.
  349. Return Value:
  350. TRUE - The contents of *m should be used to generate a reply.
  351. --*/
  352. {
  353. PPSX_CLOSE_MSG args;
  354. ULONG FdIndex;
  355. args = &m->u.Close;
  356. FdIndex = args->FileDes;
  357. if (!ISFILEDESINRANGE(FdIndex)) {
  358. m->Error = EBADF;
  359. return TRUE;
  360. }
  361. if (!DeallocateFd(p, FdIndex)) {
  362. //
  363. // Bad File Descriptor
  364. //
  365. m->Error = EBADF;
  366. return TRUE;
  367. }
  368. m->ReturnValue = 0;
  369. return TRUE;
  370. }
  371. BOOLEAN
  372. PsxPipe (
  373. IN PPSX_PROCESS p,
  374. IN OUT PPSX_API_MSG m
  375. )
  376. /*++
  377. Routine Description:
  378. This procedure implements POSIX Pipe.
  379. Arguments:
  380. p - Supplies the address of the process making the call.
  381. m - Supplies the address of the message associated with the pipe request.
  382. Return Value:
  383. TRUE - The contents of *m should be used to generate a reply.
  384. --*/
  385. {
  386. PPSX_PIPE_MSG args;
  387. PFILEDESCRIPTOR ReadFd,WriteFd;
  388. ULONG ReadFdIndex,WriteFdIndex;
  389. PLOCAL_PIPE Pipe;
  390. PIONODE IoNode;
  391. LARGE_INTEGER Time;
  392. ULONG PosixTime;
  393. args = &m->u.Pipe;
  394. //
  395. // Allocate two file descriptors. One for read, and one
  396. // for write.
  397. //
  398. ReadFd = AllocateFd(p, 0, &ReadFdIndex);
  399. if (NULL == ReadFd) {
  400. //
  401. // No file descriptors available
  402. //
  403. m->Error = EMFILE;
  404. return TRUE;
  405. }
  406. //
  407. // Set FileDesc field so next allocate wont bump in to it
  408. //
  409. ReadFd->SystemOpenFileDesc = (PSYSTEMOPENFILE)1;
  410. WriteFd = AllocateFd(p, 0, &WriteFdIndex);
  411. if (NULL == WriteFd) {
  412. //
  413. // No file descriptors available
  414. //
  415. ReadFd->SystemOpenFileDesc = (PSYSTEMOPENFILE)NULL;
  416. m->Error = EMFILE;
  417. return TRUE;
  418. }
  419. Pipe = RtlAllocateHeap(PsxHeap, 0, sizeof(LOCAL_PIPE));
  420. if (NULL == Pipe) {
  421. DeallocateFd(p, ReadFdIndex);
  422. DeallocateFd(p, WriteFdIndex);
  423. m->Error = ENOMEM;
  424. return TRUE;
  425. }
  426. ReadFd->SystemOpenFileDesc = AllocateSystemOpenFile();
  427. if (! ReadFd->SystemOpenFileDesc) {
  428. DeallocateFd(p, ReadFdIndex);
  429. DeallocateFd(p, WriteFdIndex);
  430. RtlFreeHeap(PsxHeap, 0, Pipe);
  431. m->Error = ENOMEM;
  432. return TRUE;
  433. }
  434. ReadFd->SystemOpenFileDesc->Flags = PSX_FD_READ;
  435. ReadFd->SystemOpenFileDesc->NtIoHandle = (HANDLE)NULL;
  436. WriteFd->SystemOpenFileDesc = AllocateSystemOpenFile();
  437. if (! WriteFd->SystemOpenFileDesc) {
  438. DeallocateSystemOpenFile(p, ReadFd->SystemOpenFileDesc);
  439. DeallocateFd(p, ReadFdIndex);
  440. DeallocateFd(p, WriteFdIndex);
  441. RtlFreeHeap(PsxHeap, 0, Pipe);
  442. m->Error = ENOMEM;
  443. return TRUE;
  444. }
  445. WriteFd->SystemOpenFileDesc->Flags = PSX_FD_WRITE;
  446. WriteFd->SystemOpenFileDesc->NtIoHandle = (HANDLE)NULL;
  447. if (ReferenceOrCreateIoNode((dev_t)PSX_LOCAL_PIPE, (ULONG_PTR)Pipe,
  448. FALSE, &ReadFd->SystemOpenFileDesc->IoNode)) {
  449. Panic("PsxPipe: Existing IONODE ?\n");
  450. } else {
  451. DeallocateSystemOpenFile(p, ReadFd->SystemOpenFileDesc);
  452. DeallocateSystemOpenFile(p, WriteFd->SystemOpenFileDesc);
  453. DeallocateFd(p, ReadFdIndex);
  454. DeallocateFd(p, WriteFdIndex);
  455. RtlFreeHeap(PsxHeap, 0, Pipe);
  456. m->Error = ENOMEM;
  457. return TRUE;
  458. }
  459. WriteFd->SystemOpenFileDesc->IoNode = ReadFd->SystemOpenFileDesc->IoNode;
  460. WriteFd->SystemOpenFileDesc->IoNode->ReferenceCount++;
  461. if (! ReferenceOrCreateIoNode((dev_t)PSX_LOCAL_PIPE,
  462. (ULONG_PTR)Pipe,
  463. FALSE,
  464. &WriteFd->SystemOpenFileDesc->IoNode)) {
  465. // We don't bother to leave the ReadFd critsec because
  466. // DereferenceIoNode will just destroy it anyway, and it's not
  467. // like this code really cares about leaving the IoNode
  468. // critsec properly anyway,, since it only releases it once
  469. // later (which *does* work, but...).
  470. DereferenceIoNode(ReadFd->SystemOpenFileDesc->IoNode);
  471. DeallocateSystemOpenFile(p, ReadFd->SystemOpenFileDesc);
  472. DeallocateSystemOpenFile(p, WriteFd->SystemOpenFileDesc);
  473. DeallocateFd(p, ReadFdIndex);
  474. DeallocateFd(p, WriteFdIndex);
  475. RtlFreeHeap(PsxHeap, 0, Pipe);
  476. m->Error = ENOMEM;
  477. return TRUE;
  478. }
  479. IoNode = ReadFd->SystemOpenFileDesc->IoNode;
  480. IoNode->Context = (PVOID)Pipe;
  481. IoNode->IoVectors = &LocalPipeVectors;
  482. IoNode->PathLength = 0;
  483. //
  484. // Note that all the following fields are 'implementation dependent' for
  485. // local pipes except the times fields.
  486. //
  487. IoNode->Mode = (mode_t)0;
  488. IoNode->OwnerId = p->EffectiveUid;
  489. IoNode->GroupId = p->EffectiveGid;
  490. NtQuerySystemTime(&Time);
  491. if (!RtlTimeToSecondsSince1970(&Time, &PosixTime)) {
  492. PosixTime = 0L; // Time not within range of 1970 - 2105
  493. }
  494. IoNode->AccessDataTime = IoNode->ModifyDataTime = IoNode->ModifyIoNodeTime =
  495. PosixTime;
  496. InitializeLocalPipe(Pipe);
  497. RtlLeaveCriticalSection(&IoNode->IoNodeLock);
  498. //
  499. // call new handle routines
  500. //
  501. IoNewHandle(p, ReadFd);
  502. IoNewHandle(p, WriteFd);
  503. args->FileDes0 = ReadFdIndex;
  504. args->FileDes1 = WriteFdIndex;
  505. m->ReturnValue = 0;
  506. return TRUE;
  507. }
  508. BOOLEAN
  509. PsxWrite(
  510. IN PPSX_PROCESS p,
  511. IN PPSX_API_MSG m
  512. )
  513. /*++
  514. Routine Description:
  515. This procedure implements POSIX write()
  516. Arguments:
  517. p - Supplies the address of the process making the call.
  518. m - Supplies the address of the message associated with the write request.
  519. Return Value:
  520. TRUE - The contents of *m should be used to generate a reply.
  521. --*/
  522. {
  523. PPSX_WRITE_MSG args;
  524. PFILEDESCRIPTOR Fd;
  525. args = &m->u.Write;
  526. args->Command = IO_COMMAND_DONE;
  527. Fd = FdIndexToFd(p,args->FileDes);
  528. if (NULL == Fd) {
  529. m->Error = EBADF;
  530. return TRUE;
  531. }
  532. if (!(Fd->SystemOpenFileDesc->Flags & PSX_FD_WRITE)) {
  533. m->Error = EBADF;
  534. return TRUE;
  535. }
  536. if (0 == args->Nbytes) {
  537. m->ReturnValue = 0;
  538. return TRUE;
  539. }
  540. args->Scratch1 = args->Scratch2 = 0;
  541. return (Fd->SystemOpenFileDesc->IoNode->IoVectors->WriteRoutine)(p, m, Fd);
  542. }
  543. BOOLEAN
  544. PsxRead(
  545. IN PPSX_PROCESS p,
  546. IN PPSX_API_MSG m
  547. )
  548. /*++
  549. Routine Description:
  550. This procedure implements POSIX read()
  551. Arguments:
  552. p - Supplies the address of the process making the call.
  553. m - Supplies the address of the message associated with the read request.
  554. Return Value:
  555. TRUE - The contents of *m should be used to generate a reply.
  556. --*/
  557. {
  558. PPSX_READ_MSG args;
  559. PFILEDESCRIPTOR Fd;
  560. args = &m->u.Read;
  561. args->Command = IO_COMMAND_DONE;
  562. Fd = FdIndexToFd(p, args->FileDes);
  563. if (NULL == Fd) {
  564. m->Error = EBADF;
  565. return TRUE;
  566. }
  567. if (!(Fd->SystemOpenFileDesc->Flags & PSX_FD_READ)) {
  568. m->Error = EBADF;
  569. return TRUE;
  570. }
  571. if (0 == args->Nbytes) {
  572. m->ReturnValue = 0;
  573. return TRUE;
  574. }
  575. args->Scratch1 = args->Scratch2 = 0;
  576. return (Fd->SystemOpenFileDesc->IoNode->IoVectors->ReadRoutine)(p, m, Fd);
  577. }
  578. BOOLEAN
  579. PsxReadDir(
  580. IN PPSX_PROCESS p,
  581. IN PPSX_API_MSG m
  582. )
  583. /*++
  584. Routine Description:
  585. This procedure implements POSIX read()
  586. Arguments:
  587. p - Supplies the address of the process making the call.
  588. m - Supplies the address of the message associated with the read request.
  589. Return Value:
  590. TRUE - The contents of *m should be used to generate a reply.
  591. --*/
  592. {
  593. PPSX_READDIR_MSG args;
  594. PFILEDESCRIPTOR Fd;
  595. args = &m->u.ReadDir;
  596. Fd = FdIndexToFd(p, args->FileDes);
  597. if (NULL == Fd) {
  598. m->Error = EBADF;
  599. return TRUE;
  600. }
  601. if (!(Fd->SystemOpenFileDesc->Flags & PSX_FD_READ)) {
  602. m->Error = EBADF;
  603. return TRUE;
  604. }
  605. if (0 == args->Nbytes) {
  606. m->ReturnValue = 0;
  607. return TRUE;
  608. }
  609. return (Fd->SystemOpenFileDesc->IoNode->IoVectors->ReadRoutine)(p, m, Fd);
  610. }
  611. BOOLEAN
  612. PsxDup(
  613. IN PPSX_PROCESS p,
  614. IN PPSX_API_MSG m
  615. )
  616. /*++
  617. Routine Description:
  618. This procedure implements POSIX dup()
  619. Arguments:
  620. p - Supplies the address of the process making the call.
  621. m - Supplies the address of the message associated with the request.
  622. Return Value:
  623. TRUE - The contents of *m should be used to generate a reply.
  624. --*/
  625. {
  626. PPSX_DUP_MSG args;
  627. PFILEDESCRIPTOR Fd, FdDup;
  628. ULONG FdIndex;
  629. BOOLEAN RetVal;
  630. args = &m->u.Dup;
  631. Fd = FdIndexToFd(p, args->FileDes);
  632. if (!Fd) {
  633. m->Error = EBADF;
  634. return TRUE;
  635. }
  636. FdDup = AllocateFd(p, 0, &FdIndex);
  637. if (!Fd) {
  638. //
  639. // No file descriptors available
  640. //
  641. m->Error = EMFILE;
  642. return TRUE;
  643. }
  644. RetVal = (Fd->SystemOpenFileDesc->IoNode->IoVectors->DupRoutine)
  645. (p, m, Fd, FdDup);
  646. m->ReturnValue = FdIndex;
  647. return RetVal;
  648. }
  649. BOOLEAN
  650. PsxDup2(
  651. IN PPSX_PROCESS p,
  652. IN PPSX_API_MSG m
  653. )
  654. /*++
  655. Routine Description:
  656. This procedure implements POSIX dup2()
  657. Arguments:
  658. p - Supplies the address of the process making the call.
  659. m - Supplies the address of the message associated with the request.
  660. Return Value:
  661. TRUE - The contents of *m should be used to generate a reply.
  662. --*/
  663. {
  664. PPSX_DUP2_MSG args;
  665. PFILEDESCRIPTOR Fd, Fd2;
  666. ULONG FdIndex, FdIndex2;
  667. BOOLEAN RetVal;
  668. args = &m->u.Dup2;
  669. //
  670. // If FileDes is not valid, or FileDes2 is out of range, return EBADF
  671. //
  672. Fd = FdIndexToFd(p, args->FileDes);
  673. FdIndex = args->FileDes;
  674. FdIndex2 = args->FileDes2;
  675. if (!Fd || !ISFILEDESINRANGE(FdIndex2)) {
  676. m->Error = EBADF;
  677. return TRUE;
  678. }
  679. //
  680. // If FileDes is valid and == FileDes2, just return FileDes2
  681. //
  682. if (FdIndex == FdIndex2) {
  683. m->ReturnValue = FdIndex2;
  684. return TRUE;
  685. }
  686. //
  687. // Close FileDes2 (FdIndex2)
  688. //
  689. DeallocateFd(p, FdIndex2);
  690. //
  691. // Set Fd2 to file table entry just deallocated
  692. //
  693. Fd2 = &p->ProcessFileTable[FdIndex2];
  694. // Call Dup Routine to do the work
  695. RetVal = (Fd->SystemOpenFileDesc->IoNode->IoVectors->DupRoutine)
  696. (p, m, Fd, Fd2);
  697. m->ReturnValue = FdIndex2;
  698. return RetVal;
  699. }
  700. BOOLEAN
  701. PsxLseek(
  702. IN PPSX_PROCESS p,
  703. IN PPSX_API_MSG m
  704. )
  705. /*++
  706. Routine Description:
  707. This procedure implements POSIX lseek()
  708. Arguments:
  709. p - Supplies the address of the process making the call.
  710. m - Supplies the address of the message associated with the request.
  711. Return Value:
  712. TRUE - The contents of *m should be used to generate a reply.
  713. --*/
  714. {
  715. PPSX_LSEEK_MSG args;
  716. PFILEDESCRIPTOR Fd;
  717. args = &m->u.Lseek;
  718. Fd = FdIndexToFd(p, args->FileDes);
  719. if (!Fd) {
  720. m->Error = EBADF;
  721. return TRUE;
  722. }
  723. //
  724. // Lseek is not allowed on FIFOs or local pipes
  725. //
  726. if (S_ISFIFO(Fd->SystemOpenFileDesc->IoNode->Mode) ||
  727. Fd->SystemOpenFileDesc->IoNode->DeviceSerialNumber == PSX_LOCAL_PIPE) {
  728. m->Error = ESPIPE;
  729. return TRUE;
  730. }
  731. switch (args->Whence) {
  732. case SEEK_SET:
  733. case SEEK_CUR:
  734. case SEEK_END:
  735. break;
  736. default:
  737. m->Error = EINVAL;
  738. return TRUE;
  739. }
  740. return (Fd->SystemOpenFileDesc->IoNode->IoVectors->LseekRoutine)(p, m, Fd);
  741. }
  742. BOOLEAN
  743. PsxUmask(
  744. IN PPSX_PROCESS p,
  745. IN PPSX_API_MSG m
  746. )
  747. /*++
  748. Routine Description:
  749. This procedure implements POSIX umask.
  750. Arguments:
  751. p - Supplies the address of the process making the call.
  752. m - Supplies the address of the message associated with the umask request.
  753. Return Value:
  754. TRUE - The contents of *m should be used to generate a reply.
  755. --*/
  756. {
  757. PPSX_UMASK_MSG args;
  758. mode_t NewMask;
  759. args = &m->u.Umask;
  760. // Save old creation mode mask to return
  761. m->ReturnValue = (mode_t) (p->FileModeCreationMask);
  762. // Mask off all but the permission bits in Cmask
  763. NewMask = args->Cmask & _S_PROT;
  764. // Zero old permission bits in Mode mask
  765. p->FileModeCreationMask &= (!_S_PROT);
  766. // Or in new permission bits
  767. p->FileModeCreationMask |= NewMask;
  768. return TRUE;
  769. }
  770. BOOLEAN
  771. PsxMkDir(
  772. IN PPSX_PROCESS p,
  773. IN OUT PPSX_API_MSG m
  774. )
  775. /*++
  776. Routine Description:
  777. This procedure implements POSIX mkdir.
  778. Arguments:
  779. p - Supplies the address of the process making the call.
  780. m - Supplies the address of the message associated with the mkdir request.
  781. Return Value:
  782. TRUE - The contents of *m should be used to generate a reply.
  783. --*/
  784. {
  785. PPSX_MKDIR_MSG args;
  786. HANDLE FileHandle;
  787. NTSTATUS Status;
  788. IO_STATUS_BLOCK Iosb;
  789. OBJECT_ATTRIBUTES ObjA;
  790. UNICODE_STRING Path_U;
  791. ULONG DesiredAccess;
  792. CHAR buf[SECURITY_DESCRIPTOR_MIN_LENGTH];
  793. PSECURITY_DESCRIPTOR pSD = (PVOID)buf;
  794. args = &m->u.MkDir;
  795. //
  796. // Check validity of pathname pointer
  797. //
  798. if (!ISPOINTERVALID_CLIENT(p,args->Path_U.Buffer,args->Path_U.Length)) {
  799. KdPrint(("Invalid pointer to mkdir %lx \n",
  800. args->Path_U.Buffer));
  801. m->Error = EINVAL;
  802. return TRUE;
  803. }
  804. Path_U = args->Path_U;
  805. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  806. if (!NT_SUCCESS(Status)) {
  807. m->Error = PsxStatusToErrno(Status);
  808. return TRUE;
  809. }
  810. Status = InitSecurityDescriptor(pSD, &args->Path_U, p->Process,
  811. (args->Mode & _S_PROT) & ~p->FileModeCreationMask,
  812. pvInitSDMem);
  813. if (!NT_SUCCESS(Status)) {
  814. EndImpersonation();
  815. m->Error = PsxStatusToErrno(Status);
  816. return TRUE;
  817. }
  818. InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, pSD);
  819. DesiredAccess = WRITE_OWNER | WRITE_DAC;
  820. Status = NtCreateFile(&FileHandle, DesiredAccess, &ObjA, &Iosb, NULL,
  821. FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE,
  822. FILE_DIRECTORY_FILE, NULL, 0);
  823. EndImpersonation();
  824. DeInitSecurityDescriptor(pSD, pvInitSDMem);
  825. if (!NT_SUCCESS(Status)) {
  826. (void)NtClose(FileHandle);
  827. if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
  828. m->Error = PsxStatusToErrnoPath(&Path_U);
  829. return TRUE;
  830. }
  831. m->Error = PsxStatusToErrno(Status);
  832. return TRUE;
  833. }
  834. Status = NtClose(FileHandle);
  835. ASSERT(NT_SUCCESS(Status));
  836. return TRUE;
  837. }
  838. BOOLEAN
  839. PsxMkFifo(
  840. IN PPSX_PROCESS p,
  841. IN OUT PPSX_API_MSG m
  842. )
  843. /*++
  844. Routine Description:
  845. This procedure implements POSIX mkfifo.
  846. Arguments:
  847. p - Supplies the address of the process making the call.
  848. m - Supplies the address of the message associated with the mkfifo request.
  849. Return Value:
  850. TRUE - The contents of *m should be used to generate a reply.
  851. --*/
  852. {
  853. PPSX_MKFIFO_MSG args;
  854. HANDLE FileHandle;
  855. NTSTATUS Status;
  856. IO_STATUS_BLOCK Iosb;
  857. OBJECT_ATTRIBUTES ObjA;
  858. UNICODE_STRING Path_U;
  859. ULONG DesiredAccess;
  860. CHAR buf[SECURITY_DESCRIPTOR_MIN_LENGTH];
  861. PSECURITY_DESCRIPTOR pSD = (PVOID)buf;
  862. args = &m->u.MkFifo;
  863. //
  864. // Check validity of pathname pointer
  865. //
  866. if (!ISPOINTERVALID_CLIENT(p,args->Path_U.Buffer,args->Path_U.Length)) {
  867. KdPrint(("Invalid pointer to mkfifo %lx\n",
  868. args->Path_U.Buffer));
  869. m->Error = EINVAL;
  870. return TRUE;
  871. }
  872. Path_U = args->Path_U;
  873. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  874. if (!NT_SUCCESS(Status)) {
  875. m->Error = PsxStatusToErrno(Status);
  876. return TRUE;
  877. }
  878. Status = InitSecurityDescriptor(pSD, &args->Path_U, p->Process,
  879. (args->Mode & _S_PROT) & ~p->FileModeCreationMask,
  880. pvInitSDMem);
  881. if (!NT_SUCCESS(Status)) {
  882. EndImpersonation();
  883. m->Error = PsxStatusToErrno(Status);
  884. return TRUE;
  885. }
  886. InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, pSD);
  887. DesiredAccess = FILE_READ_DATA | WRITE_DAC | WRITE_OWNER;
  888. Status = NtCreateFile(&FileHandle, DesiredAccess, &ObjA, &Iosb,
  889. NULL, FILE_ATTRIBUTE_SYSTEM, 0, FILE_CREATE, 0L,
  890. NULL,
  891. 0);
  892. EndImpersonation();
  893. DeInitSecurityDescriptor(pSD, pvInitSDMem);
  894. if (!NT_SUCCESS(Status)) {
  895. if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
  896. m->Error = PsxStatusToErrnoPath(&Path_U);
  897. return TRUE;
  898. }
  899. m->Error = PsxStatusToErrno(Status);
  900. return TRUE;
  901. }
  902. Status = NtClose(FileHandle);
  903. ASSERT(NT_SUCCESS(Status));
  904. return TRUE;
  905. }
  906. BOOLEAN
  907. PsxStat(
  908. IN PPSX_PROCESS p,
  909. IN OUT PPSX_API_MSG m
  910. )
  911. /*++
  912. Routine Description:
  913. This procedure implements POSIX stat.
  914. Arguments:
  915. p - Supplies the address of the process making the call.
  916. m - Supplies the address of the message associated with the stat request.
  917. Return Value:
  918. TRUE - The contents of *m should be used to generate a reply.
  919. --*/
  920. {
  921. PPSX_STAT_MSG args;
  922. HANDLE FileHandle;
  923. NTSTATUS Status;
  924. IO_STATUS_BLOCK Iosb;
  925. OBJECT_ATTRIBUTES ObjA;
  926. UNICODE_STRING Path_U;
  927. PIONODE IoNode;
  928. FILE_INTERNAL_INFORMATION SerialNumber;
  929. BOOLEAN RetVal;
  930. args = &m->u.Stat;
  931. //
  932. // Check validity of pathname
  933. //
  934. if (!ISPOINTERVALID_CLIENT(p, args->Path_U.Buffer, args->Path_U.Length)) {
  935. KdPrint(("Invalid pointer to stat %lx \n", args->Path_U.Buffer));
  936. m->Error = EINVAL;
  937. return TRUE;
  938. }
  939. if (!ISPOINTERVALID_CLIENT(p, args->StatBuf, sizeof(struct stat))) {
  940. m->Error = EINVAL;
  941. return TRUE;
  942. }
  943. Path_U = args->Path_U;
  944. InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, NULL);
  945. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  946. if (NT_SUCCESS(Status)) {
  947. // Open the file to obtain file handle.
  948. Status = NtOpenFile(&FileHandle,
  949. SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES |
  950. FILE_READ_EA, &ObjA, &Iosb,
  951. SHARE_ALL,
  952. FILE_SYNCHRONOUS_IO_NONALERT);
  953. EndImpersonation();
  954. }
  955. //
  956. // Convert error code if open was not successful
  957. //
  958. if (!NT_SUCCESS(Status)) {
  959. if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
  960. m->Error = PsxStatusToErrnoPath(&Path_U);
  961. return TRUE;
  962. }
  963. m->Error = PsxStatusToErrno(Status);
  964. return TRUE;
  965. }
  966. //
  967. // Get file serial numbers...
  968. //
  969. Status = NtQueryInformationFile(FileHandle, &Iosb, &SerialNumber,
  970. sizeof(SerialNumber),
  971. FileInternalInformation);
  972. if (!NT_SUCCESS(Status)) {
  973. KdPrint(("PSXSS: NtQueryInfoFile failed: 0x%x\n", Status));
  974. }
  975. ASSERT(NT_SUCCESS(Status));
  976. //
  977. // Find the Ionode associated with this file.
  978. //
  979. if (ReferenceOrCreateIoNode(GetFileDeviceNumber(&Path_U),
  980. (ino_t)SerialNumber.IndexNumber.LowPart, TRUE, &IoNode)) {
  981. RetVal = (IoNode->IoVectors->StatRoutine)(IoNode,
  982. FileHandle, args->StatBuf, &Status);
  983. RtlLeaveCriticalSection(&IoNode->IoNodeLock);
  984. } else {
  985. //
  986. // Ionode doesn't exist. Not currently open or NonPosix file.
  987. //
  988. RetVal = (FileVectors.StatRoutine)(NULL, FileHandle,
  989. args->StatBuf, &Status);
  990. args->StatBuf->st_dev = GetFileDeviceNumber(&Path_U);
  991. }
  992. EndImpersonation();
  993. NtClose(FileHandle);
  994. if (!NT_SUCCESS(Status)) {
  995. m->Error = PsxStatusToErrno(Status);
  996. return TRUE;
  997. }
  998. return RetVal;
  999. }
  1000. BOOLEAN
  1001. PsxFStat(
  1002. IN PPSX_PROCESS p,
  1003. IN OUT PPSX_API_MSG m
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This procedure implements POSIX fstat.
  1008. Arguments:
  1009. p - Supplies the address of the process making the call.
  1010. m - Supplies the address of the message associated with the fstat request.
  1011. Return Value:
  1012. TRUE - The contents of *m should be used to generate a reply.
  1013. --*/
  1014. {
  1015. PPSX_FSTAT_MSG args;
  1016. PFILEDESCRIPTOR Fd;
  1017. NTSTATUS Status;
  1018. BOOLEAN RetVal;
  1019. args = &m->u.FStat;
  1020. if (!ISPOINTERVALID_CLIENT(p, args->StatBuf, sizeof(struct stat))) {
  1021. m->Error = EINVAL;
  1022. return TRUE;
  1023. }
  1024. Fd = FdIndexToFd(p, args->FileDes);
  1025. if (!Fd) {
  1026. m->Error = EBADF;
  1027. return TRUE;
  1028. }
  1029. RtlEnterCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
  1030. RetVal = (Fd->SystemOpenFileDesc->IoNode->IoVectors->StatRoutine)
  1031. (Fd->SystemOpenFileDesc->IoNode,
  1032. Fd->SystemOpenFileDesc->NtIoHandle,
  1033. args->StatBuf, &Status);
  1034. RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
  1035. if (!NT_SUCCESS(Status)) {
  1036. m->Error = PsxStatusToErrno(Status);
  1037. }
  1038. return RetVal;
  1039. }
  1040. BOOLEAN
  1041. PsxPathConf(
  1042. IN PPSX_PROCESS p,
  1043. IN OUT PPSX_API_MSG m
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. This procedure implements POSIX pathconf.
  1048. Arguments:
  1049. p - Supplies the address of the process making the call.
  1050. m - Supplies the address of the message associated with
  1051. the pathconf request.
  1052. Return Value:
  1053. TRUE - The contents of *m should be used to generate a reply.
  1054. --*/
  1055. {
  1056. PPSX_PATHCONF_MSG args;
  1057. HANDLE FileHandle;
  1058. NTSTATUS Status;
  1059. IO_STATUS_BLOCK IoStatusBlock;
  1060. OBJECT_ATTRIBUTES ObjA;
  1061. UNICODE_STRING Path;
  1062. ULONG Length;
  1063. PFILE_FS_ATTRIBUTE_INFORMATION pFSInfo;
  1064. unsigned char buf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION)+
  1065. 128*sizeof(WCHAR)];
  1066. args = &m->u.PathConf;
  1067. pFSInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)buf;
  1068. //
  1069. // Check validity of pathname
  1070. //
  1071. if (!ISPOINTERVALID_CLIENT(p, args->Path.Buffer, args->Path.Length)) {
  1072. KdPrint(("Invalid pointer to pathconf: %lx \n", args->Path.Buffer));
  1073. m->Error = EINVAL;
  1074. return TRUE;
  1075. }
  1076. Path = args->Path;
  1077. InitializeObjectAttributes(&ObjA, &Path, 0, NULL, NULL);
  1078. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1079. if (NT_SUCCESS(Status)) {
  1080. //
  1081. // Open the file to obtain file handle.
  1082. //
  1083. Status = NtOpenFile(&FileHandle,
  1084. SYNCHRONIZE | READ_CONTROL |
  1085. FILE_READ_ATTRIBUTES | FILE_READ_EA,
  1086. &ObjA,
  1087. &IoStatusBlock,
  1088. SHARE_ALL,
  1089. FILE_SYNCHRONOUS_IO_NONALERT);
  1090. EndImpersonation();
  1091. }
  1092. //
  1093. // Convert error code if open was not successful
  1094. //
  1095. if (!NT_SUCCESS(Status)) {
  1096. if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
  1097. m->Error = PsxStatusToErrnoPath(&Path);
  1098. return TRUE;
  1099. }
  1100. m->Error = PsxStatusToErrno(Status);
  1101. return TRUE;
  1102. }
  1103. //
  1104. // Figure out pathconf return value.
  1105. //
  1106. switch(args->Name) {
  1107. case _PC_LINK_MAX:
  1108. Status = NtQueryVolumeInformationFile(FileHandle,
  1109. &IoStatusBlock,
  1110. buf,
  1111. sizeof(buf),
  1112. FileFsAttributeInformation);
  1113. ASSERT(NT_SUCCESS(Status));
  1114. if (pFSInfo->FileSystemNameLength > (sizeof(buf)-sizeof(WCHAR))) {
  1115. KdPrint(("PSXSS: File System Name too long in PsxPathConf\n"));
  1116. m->Error = EINVAL;
  1117. return TRUE;
  1118. }
  1119. pFSInfo->FileSystemName[pFSInfo->FileSystemNameLength/2] = L'\0';
  1120. if (0 == wcscmp(L"NTFS", pFSInfo->FileSystemName) ||
  1121. 0 == wcscmp(L"OFS", pFSInfo->FileSystemName)) {
  1122. m->ReturnValue = (ULONG)LINK_MAX;
  1123. } else {
  1124. m->ReturnValue = 1;
  1125. }
  1126. break;
  1127. case _PC_NAME_MAX:
  1128. Status = NtQueryVolumeInformationFile(FileHandle,
  1129. &IoStatusBlock,
  1130. buf,
  1131. sizeof(buf),
  1132. FileFsAttributeInformation);
  1133. ASSERT(NT_SUCCESS(Status));
  1134. m->ReturnValue = pFSInfo->MaximumComponentNameLength;
  1135. break;
  1136. case _PC_PIPE_BUF:
  1137. m->ReturnValue = _POSIX_PIPE_BUF;
  1138. break;
  1139. case _PC_CHOWN_RESTRICTED:
  1140. m->ReturnValue = _POSIX_CHOWN_RESTRICTED;
  1141. break;
  1142. case _PC_NO_TRUNC:
  1143. m->ReturnValue = _POSIX_NO_TRUNC;
  1144. break;
  1145. case _PC_PATH_MAX:
  1146. m->ReturnValue = PATH_MAX;
  1147. break;
  1148. case _PC_MAX_CANON:
  1149. case _PC_MAX_INPUT:
  1150. case _PC_VDISABLE:
  1151. //
  1152. // No limit associated with file descriptor for these variables
  1153. //
  1154. m->Error = EINVAL;
  1155. break;
  1156. default:
  1157. m->Error = EINVAL;
  1158. }
  1159. Status = NtClose(FileHandle);
  1160. return TRUE;
  1161. }
  1162. BOOLEAN
  1163. PsxFPathConf(
  1164. IN PPSX_PROCESS p,
  1165. IN OUT PPSX_API_MSG m
  1166. )
  1167. /*++
  1168. Routine Description:
  1169. This procedure implements POSIX fpathconf.
  1170. Arguments:
  1171. p - Supplies the address of the process making the call.
  1172. m - Supplies the address of the message associated with
  1173. the fpathconf request.
  1174. Return Value:
  1175. TRUE - The contents of *m should be used to generate a reply.
  1176. --*/
  1177. {
  1178. PPSX_FPATHCONF_MSG args;
  1179. PFILEDESCRIPTOR Fd;
  1180. NTSTATUS Status;
  1181. IO_STATUS_BLOCK IoStatusBlock;
  1182. ULONG Length;
  1183. PFILE_FS_ATTRIBUTE_INFORMATION pFSInfo;
  1184. unsigned char buf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION)+
  1185. 128*sizeof(WCHAR)];
  1186. args = &m->u.FPathConf;
  1187. pFSInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)buf;
  1188. Fd = FdIndexToFd(p, args->FileDes);
  1189. if (!Fd) {
  1190. m->Error = EBADF;
  1191. return TRUE;
  1192. }
  1193. switch(args->Name) {
  1194. case _PC_LINK_MAX:
  1195. if (&FileVectors != Fd->SystemOpenFileDesc->IoNode->IoVectors) {
  1196. //
  1197. // The file descriptor is not open on a file.
  1198. //
  1199. m->Error = EINVAL;
  1200. return TRUE;
  1201. }
  1202. Status = NtQueryVolumeInformationFile(
  1203. Fd->SystemOpenFileDesc->NtIoHandle,
  1204. &IoStatusBlock,
  1205. buf,
  1206. sizeof(buf),
  1207. FileFsAttributeInformation);
  1208. if (!NT_SUCCESS(Status)) {
  1209. KdPrint(("PSXSS: NtqueryVolumeInformationFile failed: 0x%x\n", Status));
  1210. m->Error = PsxStatusToErrno(Status);
  1211. return TRUE;
  1212. }
  1213. if (pFSInfo->FileSystemNameLength > (sizeof(buf)-sizeof(WCHAR))) {
  1214. KdPrint(("PSXSS: File System Name too long in PsxPathConf\n"));
  1215. m->Error = EINVAL;
  1216. return TRUE;
  1217. }
  1218. pFSInfo->FileSystemName[pFSInfo->FileSystemNameLength/2] = L'\0';
  1219. if (0 == wcscmp(L"NTFS", pFSInfo->FileSystemName) ||
  1220. 0 == wcscmp(L"OFS", pFSInfo->FileSystemName)) {
  1221. m->ReturnValue = (ULONG)(LINK_MAX); //
  1222. } else {
  1223. m->ReturnValue = 1;
  1224. }
  1225. break;
  1226. case _PC_NAME_MAX:
  1227. if (&FileVectors != Fd->SystemOpenFileDesc->IoNode->IoVectors) {
  1228. //
  1229. // The file descriptor is not open on a file.
  1230. //
  1231. m->Error = EINVAL;
  1232. return TRUE;
  1233. }
  1234. Status = NtQueryVolumeInformationFile(
  1235. Fd->SystemOpenFileDesc->NtIoHandle,
  1236. &IoStatusBlock,
  1237. buf,
  1238. sizeof(buf),
  1239. FileFsAttributeInformation);
  1240. if (!NT_SUCCESS(Status)) {
  1241. KdPrint(("PSXSS: NtqueryVolumeInformationFile failed: 0x%x\n", Status));
  1242. m->Error = PsxStatusToErrno(Status);
  1243. return TRUE;
  1244. }
  1245. m->ReturnValue = pFSInfo->MaximumComponentNameLength;
  1246. break;
  1247. case _PC_PIPE_BUF:
  1248. m->ReturnValue = _POSIX_PIPE_BUF;
  1249. break;
  1250. case _PC_CHOWN_RESTRICTED:
  1251. m->ReturnValue = _POSIX_CHOWN_RESTRICTED;
  1252. break;
  1253. case _PC_NO_TRUNC:
  1254. m->ReturnValue = _POSIX_NO_TRUNC;
  1255. break;
  1256. case _PC_PATH_MAX:
  1257. m->ReturnValue = PATH_MAX;
  1258. break;
  1259. case _PC_MAX_CANON:
  1260. case _PC_MAX_INPUT:
  1261. case _PC_VDISABLE:
  1262. //
  1263. // No limit associated with file descriptor for these variables
  1264. //
  1265. m->Error = EINVAL;
  1266. break;
  1267. default:
  1268. m->Error = EINVAL;
  1269. }
  1270. return TRUE;
  1271. }
  1272. BOOLEAN
  1273. PsxChmod(
  1274. IN PPSX_PROCESS p,
  1275. IN PPSX_API_MSG m
  1276. )
  1277. /*++
  1278. Routine Description:
  1279. This procedure implements POSIX chmod.
  1280. Arguments:
  1281. p - Supplies the address of the process making the call.
  1282. m - Supplies the address of the message associated with the chmod request.
  1283. Return Value:
  1284. TRUE - The contents of *m should be used to generate a reply.
  1285. --*/
  1286. {
  1287. PPSX_CHMOD_MSG args;
  1288. HANDLE FileHandle;
  1289. NTSTATUS Status;
  1290. IO_STATUS_BLOCK
  1291. Iosb;
  1292. OBJECT_ATTRIBUTES
  1293. ObjA;
  1294. UNICODE_STRING
  1295. Path_U;
  1296. SECURITY_INFORMATION
  1297. SecurityInformation;
  1298. PSECURITY_DESCRIPTOR
  1299. SecurityDescriptor = NULL;
  1300. PACL pDacl = NULL;
  1301. ULONG DaclSize; // the size of the Dacl
  1302. PSID NtOwner, NtGroup;
  1303. BOOLEAN OwnerDefaulted, GroupDefaulted;
  1304. BOOLEAN DaclPresent, DaclDefaulted;
  1305. ACCESS_MASK
  1306. UserAccess, GroupAccess, OtherAccess;
  1307. ULONG LengthNeeded,
  1308. Revision, // Security Desc revision
  1309. SdSize; // Size for Security Desc
  1310. SECURITY_DESCRIPTOR_CONTROL
  1311. Control;
  1312. // Pointers for a manufactured absolute-format security descriptor.
  1313. PACL pAbsDacl = NULL,
  1314. pAbsSacl = NULL;
  1315. PSID pAbsOwner = NULL,
  1316. pAbsGroup = NULL;
  1317. args = &m->u.Chmod;
  1318. if (!ISPOINTERVALID_CLIENT(p, args->Path_U.Buffer,
  1319. args->Path_U.Length)) {
  1320. KdPrint(("Invalid pointer to chmod: %lx\n", args->Path_U.Buffer));
  1321. m->Error = EINVAL;
  1322. return TRUE;
  1323. }
  1324. Path_U = args->Path_U;
  1325. InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, NULL);
  1326. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1327. if (!NT_SUCCESS(Status)) {
  1328. m->Error = PsxStatusToErrno(Status);
  1329. return TRUE;
  1330. }
  1331. Status = NtOpenFile(&FileHandle, SYNCHRONIZE | WRITE_DAC | READ_CONTROL,
  1332. &ObjA, &Iosb,
  1333. SHARE_ALL,
  1334. FILE_SYNCHRONOUS_IO_NONALERT);
  1335. if (!NT_SUCCESS(Status)) {
  1336. NTSTATUS st;
  1337. //
  1338. // 1003.1-90: EPERM when the euid does not match the
  1339. // owner of the file. We try to open the file with null
  1340. // access, if we can't do that then search permission is
  1341. // denied or somesuch. Otherwise, we give EPERM.
  1342. //
  1343. st = NtOpenFile(&FileHandle, SYNCHRONIZE | READ_CONTROL,
  1344. &ObjA, &Iosb,
  1345. SHARE_ALL,
  1346. FILE_SYNCHRONOUS_IO_NONALERT);
  1347. EndImpersonation();
  1348. if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
  1349. m->Error = PsxStatusToErrnoPath(&Path_U);
  1350. return TRUE;
  1351. }
  1352. if (!NT_SUCCESS(st)) {
  1353. m->Error = PsxStatusToErrno(st);
  1354. return TRUE;
  1355. }
  1356. NtClose(FileHandle);
  1357. m->Error = EPERM;
  1358. return TRUE;
  1359. }
  1360. EndImpersonation();
  1361. //
  1362. // Get the security descriptor for the file.
  1363. //
  1364. SecurityInformation = OWNER_SECURITY_INFORMATION |
  1365. GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
  1366. Status = NtQuerySecurityObject(FileHandle, SecurityInformation,
  1367. NULL, 0, &SdSize);
  1368. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  1369. SecurityDescriptor = RtlAllocateHeap(PsxHeap, 0, SdSize);
  1370. if (NULL == SecurityDescriptor) {
  1371. m->Error = ENOMEM;
  1372. goto out;
  1373. }
  1374. Status = NtQuerySecurityObject(FileHandle, SecurityInformation,
  1375. SecurityDescriptor, SdSize, &SdSize);
  1376. ASSERT(NT_SUCCESS(Status));
  1377. Status = RtlGetControlSecurityDescriptor(SecurityDescriptor,
  1378. &Control, &Revision);
  1379. ASSERT(NT_SUCCESS(Status));
  1380. ASSERT(SECURITY_DESCRIPTOR_REVISION == Revision);
  1381. if (Control & SE_SELF_RELATIVE) {
  1382. PSECURITY_DESCRIPTOR
  1383. AbsSD; // SD in absolute format.
  1384. ULONG AbsSdSize = 0,
  1385. DaclSize = 0,
  1386. SaclSize = 0,
  1387. OwnerSize = 0,
  1388. GroupSize = 0;
  1389. //
  1390. // This security descriptor needs to be converted to absolute
  1391. // format.
  1392. //
  1393. Status = RtlSelfRelativeToAbsoluteSD(SecurityDescriptor,
  1394. NULL, &AbsSdSize, NULL, &DaclSize, NULL, &SaclSize,
  1395. NULL, &OwnerSize, NULL, &GroupSize);
  1396. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  1397. AbsSD = RtlAllocateHeap(PsxHeap, 0, AbsSdSize);
  1398. pAbsDacl = RtlAllocateHeap(PsxHeap, 0, DaclSize);
  1399. pAbsSacl = RtlAllocateHeap(PsxHeap, 0, SaclSize);
  1400. pAbsOwner = RtlAllocateHeap(PsxHeap, 0, OwnerSize);
  1401. pAbsGroup = RtlAllocateHeap(PsxHeap, 0, GroupSize);
  1402. if (NULL == AbsSD || NULL == pAbsDacl || NULL == pAbsSacl
  1403. || NULL == pAbsOwner || NULL == pAbsGroup) {
  1404. m->Error = ENOMEM;
  1405. goto out;
  1406. }
  1407. Status = RtlSelfRelativeToAbsoluteSD(SecurityDescriptor,
  1408. AbsSD, &AbsSdSize, pAbsDacl, &DaclSize, pAbsSacl,
  1409. &SaclSize, pAbsOwner, &OwnerSize, pAbsGroup,
  1410. &GroupSize);
  1411. ASSERT(NT_SUCCESS(Status));
  1412. // RtlFreeHeap(PsxHeap, 0, SecurityDescriptor);
  1413. SecurityDescriptor = AbsSD;
  1414. AbsSD = NULL; // so it won't be freed later
  1415. }
  1416. //
  1417. // Get the owner and group from the security descriptor
  1418. //
  1419. Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
  1420. &NtOwner, &OwnerDefaulted);
  1421. ASSERT(NT_SUCCESS(Status));
  1422. Status = RtlGetGroupSecurityDescriptor(SecurityDescriptor,
  1423. &NtGroup, &GroupDefaulted);
  1424. ASSERT(NT_SUCCESS(Status));
  1425. if (NULL == NtOwner || NULL == NtGroup) {
  1426. //
  1427. // We need an owner and group to change the modes; fail.
  1428. //
  1429. KdPrint(("PsxChmod: No owner or no group\n"));
  1430. m->Error = EPERM;
  1431. goto out;
  1432. }
  1433. Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
  1434. &DaclPresent, &pDacl, &DaclDefaulted);
  1435. ASSERT(NT_SUCCESS(Status));
  1436. ModeToAccessMask(args->Mode, &UserAccess, &GroupAccess, &OtherAccess);
  1437. Status = RtlMakePosixAcl(ACL_REVISION2, NtOwner, NtGroup, UserAccess,
  1438. GroupAccess, OtherAccess, 0, NULL, &LengthNeeded);
  1439. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  1440. pDacl = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  1441. if (NULL == pDacl) {
  1442. m->Error = ENOMEM;
  1443. return TRUE;
  1444. }
  1445. Status = RtlMakePosixAcl(ACL_REVISION2, NtOwner, NtGroup, UserAccess,
  1446. GroupAccess, OtherAccess, LengthNeeded, pDacl, &DaclSize);
  1447. ASSERT(NT_SUCCESS(Status));
  1448. Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE,
  1449. pDacl, FALSE);
  1450. if (!NT_SUCCESS(Status)) {
  1451. KdPrint(("PSXSS: RtlSetDacl: 0x%x\n", Status));
  1452. m->Error = EPERM;
  1453. return TRUE;
  1454. }
  1455. SecurityInformation = DACL_SECURITY_INFORMATION;
  1456. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1457. if (NT_SUCCESS(Status))
  1458. {
  1459. Status = NtSetSecurityObject(FileHandle, SecurityInformation,
  1460. SecurityDescriptor);
  1461. EndImpersonation();
  1462. }
  1463. if (!NT_SUCCESS(Status)) {
  1464. m->Error = PsxStatusToErrno(Status);
  1465. }
  1466. out:
  1467. NtClose(FileHandle);
  1468. if (NULL != pAbsDacl) {
  1469. RtlFreeHeap(PsxHeap, 0, pAbsDacl);
  1470. }
  1471. if (NULL != pAbsSacl) {
  1472. RtlFreeHeap(PsxHeap, 0, pAbsSacl);
  1473. }
  1474. if (NULL != pAbsOwner) {
  1475. RtlFreeHeap(PsxHeap, 0, pAbsOwner);
  1476. }
  1477. if (NULL != pAbsGroup) {
  1478. RtlFreeHeap(PsxHeap, 0, pAbsGroup);
  1479. }
  1480. if (NULL != SecurityDescriptor) {
  1481. RtlFreeHeap(PsxHeap, 0, SecurityDescriptor);
  1482. }
  1483. if (NULL != pDacl) {
  1484. RtlFreeHeap(PsxHeap, 0, pDacl);
  1485. }
  1486. return TRUE;
  1487. }
  1488. BOOLEAN
  1489. PsxChown(
  1490. IN PPSX_PROCESS p,
  1491. IN PPSX_API_MSG m
  1492. )
  1493. /*++
  1494. Routine Description:
  1495. This procedure implements POSIX chown.
  1496. Arguments:
  1497. p - Supplies the address of the process making the call.
  1498. m - Supplies the address of the message associated with the chown request.
  1499. Return Value:
  1500. TRUE - The contents of *m should be used to generate a reply.
  1501. --*/
  1502. {
  1503. PPSX_CHOWN_MSG args;
  1504. HANDLE FileHandle;
  1505. NTSTATUS Status;
  1506. IO_STATUS_BLOCK Iosb;
  1507. OBJECT_ATTRIBUTES ObjA;
  1508. UNICODE_STRING Path_U;
  1509. PIONODE IoNode;
  1510. SECURITY_INFORMATION SecurityInformation;
  1511. PSECURITY_DESCRIPTOR
  1512. SecurityDescriptor = NULL,
  1513. pFreeSD = NULL;
  1514. ACCESS_MASK UserAccess, GroupAccess, OtherAccess;
  1515. ULONG LengthNeeded;
  1516. PSID NtOwner, // owner from existing SD
  1517. NtGroup, // group from existing SD
  1518. DomainSid, // domain goes with new gid
  1519. NewGroup = NULL, // new group from DomainSid+gid
  1520. NewUser = NULL; // new user
  1521. BOOLEAN OwnerDefaulted, GroupDefaulted, DaclPresent, DaclDefaulted;
  1522. PACL pDacl = NULL, pDacl2 = NULL;
  1523. ULONG Revision; // Security Desc revision
  1524. SECURITY_DESCRIPTOR_CONTROL
  1525. Control;
  1526. FILE_INTERNAL_INFORMATION
  1527. SerialNumber;
  1528. // Pointers for a manufactured absolute-format security descriptor.
  1529. PACL pAbsDacl = NULL,
  1530. pAbsSacl = NULL;
  1531. PSID pAbsOwner = NULL,
  1532. pAbsGroup = NULL;
  1533. args = &m->u.Chown;
  1534. if (!ISPOINTERVALID_CLIENT(p, args->Path_U.Buffer,
  1535. args->Path_U.Length)) {
  1536. KdPrint(("Invalid pointer to chown: %lx\n",
  1537. args->Path_U.Buffer));
  1538. m->Error = EINVAL;
  1539. return TRUE;
  1540. }
  1541. Path_U = args->Path_U;
  1542. InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, NULL);
  1543. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1544. if (!NT_SUCCESS(Status)) {
  1545. m->Error = PsxStatusToErrno(Status);
  1546. return TRUE;
  1547. }
  1548. Status = NtOpenFile(&FileHandle,
  1549. SYNCHRONIZE | READ_CONTROL | WRITE_OWNER | WRITE_DAC,
  1550. &ObjA, &Iosb,
  1551. SHARE_ALL,
  1552. FILE_SYNCHRONOUS_IO_NONALERT);
  1553. EndImpersonation();
  1554. if (!NT_SUCCESS(Status)) {
  1555. //
  1556. // 1003.1-90 (5.6.5.4): EPERM when the caller does not have
  1557. // permission to change the owner. We check this by opening
  1558. // the file with the same mode, except without WRITE_OWNER.
  1559. //
  1560. if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
  1561. m->Error = PsxStatusToErrnoPath(&Path_U);
  1562. } else {
  1563. m->Error = PsxStatusToErrno(Status);
  1564. }
  1565. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1566. if (!NT_SUCCESS(Status)) {
  1567. m->Error = PsxStatusToErrno(Status);
  1568. return TRUE;
  1569. }
  1570. Status = NtOpenFile(&FileHandle,
  1571. SYNCHRONIZE | READ_CONTROL,
  1572. &ObjA, &Iosb,
  1573. SHARE_ALL,
  1574. FILE_SYNCHRONOUS_IO_NONALERT);
  1575. EndImpersonation();
  1576. if (NT_SUCCESS(Status)) {
  1577. m->Error = EPERM;
  1578. NtClose(FileHandle);
  1579. }
  1580. return TRUE;
  1581. }
  1582. //
  1583. // Get serial numbers.
  1584. //
  1585. Status = NtQueryInformationFile(FileHandle, &Iosb, &SerialNumber,
  1586. sizeof(SerialNumber), FileInternalInformation);
  1587. ASSERT(NT_SUCCESS(Status));
  1588. if (ReferenceOrCreateIoNode(GetFileDeviceNumber(&Path_U),
  1589. (ino_t)SerialNumber.IndexNumber.LowPart, TRUE, &IoNode)) {
  1590. // File already is open.
  1591. } else {
  1592. IoNode = NULL;
  1593. }
  1594. //
  1595. // Get SecurityInformation for the file.
  1596. //
  1597. SecurityInformation = OWNER_SECURITY_INFORMATION |
  1598. GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
  1599. Status = NtQuerySecurityObject(FileHandle, SecurityInformation,
  1600. NULL, 0, &LengthNeeded);
  1601. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  1602. SecurityDescriptor = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  1603. if (NULL == SecurityDescriptor) {
  1604. m->Error = ENOMEM;
  1605. goto out;
  1606. }
  1607. Status = NtQuerySecurityObject(FileHandle, SecurityInformation,
  1608. SecurityDescriptor, LengthNeeded, &LengthNeeded);
  1609. ASSERT(NT_SUCCESS(Status));
  1610. Status = RtlGetControlSecurityDescriptor(SecurityDescriptor,
  1611. &Control, &Revision);
  1612. ASSERT(NT_SUCCESS(Status));
  1613. ASSERT(SECURITY_DESCRIPTOR_REVISION == Revision);
  1614. if (Control & SE_SELF_RELATIVE) {
  1615. PSECURITY_DESCRIPTOR
  1616. AbsSD; // SD in absolute format.
  1617. ULONG AbsSdSize = 0,
  1618. DaclSize = 0, SaclSize = 0,
  1619. OwnerSize = 0, GroupSize = 0;
  1620. //
  1621. // This security descriptor needs to be converted to absolute
  1622. // format.
  1623. //
  1624. Status = RtlSelfRelativeToAbsoluteSD(SecurityDescriptor,
  1625. NULL, &AbsSdSize, NULL, &DaclSize, NULL, &SaclSize,
  1626. NULL, &OwnerSize, NULL, &GroupSize);
  1627. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  1628. AbsSD = RtlAllocateHeap(PsxHeap, 0, AbsSdSize);
  1629. pAbsSacl = RtlAllocateHeap(PsxHeap, 0, SaclSize);
  1630. pAbsOwner = RtlAllocateHeap(PsxHeap, 0, OwnerSize);
  1631. pAbsGroup = RtlAllocateHeap(PsxHeap, 0, GroupSize);
  1632. pAbsDacl = RtlAllocateHeap(PsxHeap, 0, DaclSize);
  1633. if (NULL == AbsSD || NULL == pAbsDacl || NULL == pAbsSacl
  1634. || NULL == pAbsOwner || NULL == pAbsGroup) {
  1635. m->Error = ENOMEM;
  1636. goto out;
  1637. }
  1638. Status = RtlSelfRelativeToAbsoluteSD(SecurityDescriptor,
  1639. AbsSD, &AbsSdSize, pAbsDacl, &DaclSize, pAbsSacl,
  1640. &SaclSize, pAbsOwner, &OwnerSize, pAbsGroup,
  1641. &GroupSize);
  1642. ASSERT(NT_SUCCESS(Status));
  1643. pFreeSD = SecurityDescriptor;
  1644. SecurityDescriptor = AbsSD;
  1645. }
  1646. //
  1647. // Get the owner and group from the security descriptor
  1648. //
  1649. Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
  1650. &NtOwner, &OwnerDefaulted);
  1651. ASSERT(NT_SUCCESS(Status));
  1652. Status = RtlGetGroupSecurityDescriptor(SecurityDescriptor,
  1653. &NtGroup, &GroupDefaulted);
  1654. ASSERT(NT_SUCCESS(Status));
  1655. if (NULL == NtOwner || NULL == NtGroup) {
  1656. //
  1657. // Seems like this file doesn't have an owner or a
  1658. // group, which means that we can't change it's group.
  1659. //
  1660. // XXX.mjb: ideally, would make the file owned by us if
  1661. // possible.
  1662. //
  1663. KdPrint(("PSXSS: PsxChown: no owner or no group\n"));
  1664. m->Error = EPERM;
  1665. goto out;
  1666. }
  1667. Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
  1668. &DaclPresent, &pDacl, &DaclDefaulted);
  1669. ASSERT(NT_SUCCESS(Status));
  1670. if (!DaclPresent || (DaclPresent && NULL == pDacl)) {
  1671. //
  1672. // All access is allowed to this file. We attach a Posix-
  1673. // type acl that allows all access.
  1674. //
  1675. ModeToAccessMask(0777, &UserAccess, &GroupAccess, &OtherAccess);
  1676. } else {
  1677. Status = RtlInterpretPosixAcl(ACL_REVISION2, NtOwner, NtGroup,
  1678. pDacl, &UserAccess, &GroupAccess, &OtherAccess);
  1679. if (STATUS_COULD_NOT_INTERPRET == Status) {
  1680. //
  1681. // There is an acl, but it is not in the Posix form.
  1682. // Ideally, we'd like to leave the resulting file
  1683. // with an ACL approximating the one we've foud there,
  1684. // but that's hard so we'll just do the easy thing.
  1685. //
  1686. ModeToAccessMask(0777, &UserAccess, &GroupAccess,
  1687. &OtherAccess);
  1688. } else if (!NT_SUCCESS(Status)) {
  1689. KdPrint(("PSXSS: RtlInterpretPosixAcl: 0x%x\n", Status));
  1690. m->Error = EPERM;
  1691. goto out;
  1692. }
  1693. }
  1694. if (0xFFF == args->Group) {
  1695. //
  1696. // The login group is treated specially here.
  1697. //
  1698. NewGroup = GetLoginGroupSid(p);
  1699. if (NULL == NewGroup) {
  1700. m->Error = ENOMEM;
  1701. goto out;
  1702. }
  1703. } else {
  1704. DomainSid = GetSidByOffset(args->Group & 0xFFFF0000);
  1705. if (NULL == DomainSid) {
  1706. //
  1707. // Either we can't get to the domain, or the user
  1708. // specified an invalid group. Bad.
  1709. //
  1710. m->Error = EINVAL;
  1711. goto out;
  1712. }
  1713. NewGroup = MakeSid(DomainSid, args->Group & 0xFFFF);
  1714. if (NULL == NewGroup) {
  1715. m->Error = ENOMEM;
  1716. goto out;
  1717. }
  1718. }
  1719. DomainSid = GetSidByOffset(args->Owner & 0xFFFF0000);
  1720. if (NULL == DomainSid) {
  1721. m->Error = EINVAL;
  1722. goto out;
  1723. }
  1724. NewUser = MakeSid(DomainSid, args->Owner & 0xFFFF);
  1725. if (NULL == NewUser) {
  1726. m->Error = ENOMEM;
  1727. goto out;
  1728. }
  1729. Status = RtlMakePosixAcl(ACL_REVISION2, NewUser, NewGroup,
  1730. UserAccess, GroupAccess, OtherAccess, 0, NULL, &LengthNeeded);
  1731. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  1732. pDacl2 = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  1733. if (NULL == pDacl2) {
  1734. m->Error = ENOMEM;
  1735. goto out;
  1736. }
  1737. Status = RtlMakePosixAcl(ACL_REVISION2, NewUser, NewGroup,
  1738. UserAccess, GroupAccess, OtherAccess, LengthNeeded, pDacl2,
  1739. &LengthNeeded);
  1740. ASSERT(NT_SUCCESS(Status));
  1741. Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE,
  1742. pDacl2, FALSE);
  1743. if (!NT_SUCCESS(Status)) {
  1744. KdPrint(("PSXSS: PsxChown: RtlSetDacl: 0x%x\n", Status));
  1745. m->Error = EPERM;
  1746. goto out;
  1747. }
  1748. Status = RtlSetGroupSecurityDescriptor(SecurityDescriptor, NewGroup, FALSE);
  1749. ASSERT(NT_SUCCESS(Status));
  1750. Status = RtlSetOwnerSecurityDescriptor(SecurityDescriptor, NewUser, FALSE);
  1751. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1752. if (NT_SUCCESS(Status))
  1753. {
  1754. Status = NtSetSecurityObject(FileHandle, SecurityInformation,
  1755. SecurityDescriptor);
  1756. EndImpersonation();
  1757. }
  1758. if (!NT_SUCCESS(Status)) {
  1759. m->Error = PsxStatusToErrno(Status);
  1760. goto out;
  1761. }
  1762. if (NULL != IoNode) {
  1763. IoNode->GroupId = args->Group;
  1764. }
  1765. out:
  1766. NtClose(FileHandle);
  1767. if (NULL != SecurityDescriptor) {
  1768. RtlFreeHeap(PsxHeap, 0, SecurityDescriptor);
  1769. }
  1770. if (NULL != NewGroup) {
  1771. RtlFreeHeap(PsxHeap, 0, NewGroup);
  1772. }
  1773. if (NULL != NewUser) {
  1774. RtlFreeHeap(PsxHeap, 0, NewUser);
  1775. }
  1776. if (NULL != pDacl2) {
  1777. RtlFreeHeap(PsxHeap, 0, pDacl2);
  1778. }
  1779. if (NULL != pAbsDacl) {
  1780. RtlFreeHeap(PsxHeap, 0, pAbsDacl);
  1781. }
  1782. if (NULL != pAbsSacl) {
  1783. RtlFreeHeap(PsxHeap, 0, pAbsSacl);
  1784. }
  1785. if (NULL != pAbsOwner) {
  1786. RtlFreeHeap(PsxHeap, 0, pAbsOwner);
  1787. }
  1788. if (NULL != pAbsGroup) {
  1789. RtlFreeHeap(PsxHeap, 0, pAbsGroup);
  1790. }
  1791. if (NULL != pFreeSD) {
  1792. RtlFreeHeap(PsxHeap, 0, pFreeSD);
  1793. }
  1794. return TRUE;
  1795. }
  1796. BOOLEAN
  1797. PsxUtime(
  1798. IN PPSX_PROCESS p,
  1799. IN PPSX_API_MSG m
  1800. )
  1801. /*++
  1802. Routine Description:
  1803. This procedure implements POSIX utime.
  1804. Arguments:
  1805. p - Supplies the address of the process making the call.
  1806. m - Supplies the address of the message associated with the utime request.
  1807. Return Value:
  1808. TRUE - The contents of *m should be used to generate a reply.
  1809. --*/
  1810. {
  1811. PPSX_UTIME_MSG args;
  1812. HANDLE FileHandle;
  1813. NTSTATUS Status;
  1814. IO_STATUS_BLOCK Iosb;
  1815. OBJECT_ATTRIBUTES ObjA;
  1816. UNICODE_STRING Path_U;
  1817. FILE_BASIC_INFORMATION BasicInfo;
  1818. LARGE_INTEGER Time;
  1819. args = &m->u.Utime;
  1820. if (!ISPOINTERVALID_CLIENT(p,args->Path_U.Buffer,args->Path_U.Length)) {
  1821. KdPrint(("Invalid pointer to utime %lx\n",
  1822. args->Path_U.Buffer));
  1823. m->Error = EINVAL;
  1824. return TRUE;
  1825. }
  1826. Path_U = args->Path_U;
  1827. InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, NULL);
  1828. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1829. if (NT_SUCCESS(Status)) {
  1830. Status = NtOpenFile(&FileHandle,
  1831. SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES,
  1832. &ObjA, &Iosb, SHARE_ALL, FILE_SYNCHRONOUS_IO_NONALERT);
  1833. if (!NT_SUCCESS(Status)) {
  1834. EndImpersonation();
  1835. }
  1836. }
  1837. if (!NT_SUCCESS(Status)) {
  1838. if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
  1839. m->Error = PsxStatusToErrnoPath(&Path_U);
  1840. return TRUE;
  1841. }
  1842. m->Error = PsxStatusToErrno(Status);
  1843. return TRUE;
  1844. }
  1845. //
  1846. // 1003.1-1990: EPERM when the /times/ argument is not
  1847. // NULL, the calling process has write access to the file,
  1848. // but is not the owner of the file. Here we're denying
  1849. // access to the file that NT would grant.
  1850. //
  1851. if (NULL != args->TimesSpecified) {
  1852. struct stat StatBuf;
  1853. StatBuf.st_uid = 0; // in case FindOwnerModeFile fails
  1854. FindOwnerModeFile(FileHandle, &StatBuf);
  1855. if (StatBuf.st_uid != p->EffectiveUid) {
  1856. UCHAR buf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) +
  1857. 128 * sizeof(WCHAR)];
  1858. PFILE_FS_ATTRIBUTE_INFORMATION pFSInfo = (PVOID)buf;
  1859. // We ignore this test for all but NTFS
  1860. Status = NtQueryVolumeInformationFile(FileHandle,
  1861. &Iosb, buf, sizeof(buf),
  1862. FileFsAttributeInformation);
  1863. ASSERT(NT_SUCCESS(Status));
  1864. pFSInfo->FileSystemName[pFSInfo->FileSystemNameLength/2] = 0;
  1865. if (0 == wcscmp(L"NTFS", pFSInfo->FileSystemName) ||
  1866. 0 == wcscmp(L"OFS", pFSInfo->FileSystemName)) {
  1867. NtClose(FileHandle);
  1868. m->Error = EPERM;
  1869. EndImpersonation();
  1870. return TRUE;
  1871. }
  1872. }
  1873. }
  1874. EndImpersonation();
  1875. RtlZeroMemory(&Time, sizeof(Time));
  1876. BasicInfo.CreationTime = Time;
  1877. BasicInfo.ChangeTime = Time;
  1878. BasicInfo.FileAttributes = 0;
  1879. //
  1880. // If the utimbuf is NULL, we're to set the file times to the current
  1881. // time. The owner and anyone else with write permission on the file
  1882. // should be able to perform this operation. If times are specified
  1883. // via a utimbuf, only the owner should be able to perform the
  1884. // operation.
  1885. //
  1886. if (args->TimesSpecified == NULL) {
  1887. NtQuerySystemTime(&Time);
  1888. BasicInfo.LastAccessTime = Time;
  1889. BasicInfo.LastWriteTime = Time;
  1890. } else {
  1891. RtlSecondsSince1970ToTime((ULONG)(args->Times.actime), &Time);
  1892. BasicInfo.LastAccessTime = Time;
  1893. RtlSecondsSince1970ToTime((ULONG)(args->Times.modtime), &Time);
  1894. BasicInfo.LastWriteTime = Time;
  1895. }
  1896. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1897. if (NT_SUCCESS(Status)) {
  1898. Status = NtSetInformationFile(FileHandle, &Iosb, &BasicInfo,
  1899. sizeof(BasicInfo), FileBasicInformation);
  1900. EndImpersonation();
  1901. }
  1902. if (!NT_SUCCESS(Status)) {
  1903. m->Error = PsxStatusToErrno(Status);
  1904. //FALL OUT
  1905. }
  1906. NtClose(FileHandle);
  1907. return TRUE;
  1908. }
  1909. BOOLEAN
  1910. PsxFcntl(
  1911. IN PPSX_PROCESS p,
  1912. IN PPSX_API_MSG m
  1913. )
  1914. /*++
  1915. Routine Description:
  1916. This procedure implements POSIX fcntl().
  1917. Arguments:
  1918. p - Supplies the address of the process making the call.
  1919. m - Supplies the address of the message associated with the request.
  1920. Return Value:
  1921. TRUE - The contents of *m should be used to generate a reply.
  1922. FALSE - No reply should be sent, for the case in which the process
  1923. was blocked (as in F_SETLKW).
  1924. --*/
  1925. {
  1926. PPSX_FCNTL_MSG args;
  1927. PFILEDESCRIPTOR pFd, pFdDup;
  1928. NTSTATUS Status;
  1929. BOOLEAN b;
  1930. int error;
  1931. args = &m->u.Fcntl;
  1932. pFd = FdIndexToFd(p, args->FileDes);
  1933. if (NULL == pFd) {
  1934. m->Error = EBADF;
  1935. return TRUE;
  1936. }
  1937. switch (args->Command) {
  1938. case F_DUPFD:
  1939. if (!ISFILEDESINRANGE(args->u.i)) {
  1940. m->Error = EINVAL;
  1941. return TRUE;
  1942. }
  1943. pFdDup = AllocateFd(p, args->u.i, &m->ReturnValue);
  1944. if (NULL == pFdDup) {
  1945. // no descriptors are available
  1946. m->Error = EMFILE;
  1947. return TRUE;
  1948. }
  1949. ASSERT(NULL != pFd->SystemOpenFileDesc->IoNode->IoVectors->DupRoutine);
  1950. return (pFd->SystemOpenFileDesc->IoNode->IoVectors->DupRoutine)
  1951. (p, m, pFd, pFdDup);
  1952. case F_GETFD:
  1953. //
  1954. // File descriptor flags
  1955. //
  1956. m->ReturnValue = 0;
  1957. if (pFd->Flags & PSX_FD_CLOSE_ON_EXEC) {
  1958. m->ReturnValue |= FD_CLOEXEC;
  1959. }
  1960. return TRUE;
  1961. case F_SETFD:
  1962. pFd->Flags = 0;
  1963. if (args->u.i & FD_CLOEXEC) {
  1964. pFd->Flags |= PSX_FD_CLOSE_ON_EXEC;
  1965. }
  1966. m->ReturnValue = 0;
  1967. return TRUE;
  1968. case F_GETFL:
  1969. //
  1970. // Get file description flags
  1971. //
  1972. if ((pFd->SystemOpenFileDesc->Flags &
  1973. (PSX_FD_READ | PSX_FD_WRITE))
  1974. == (PSX_FD_READ | PSX_FD_WRITE)) {
  1975. m->ReturnValue |= O_RDWR;
  1976. } else if (pFd->SystemOpenFileDesc->Flags & PSX_FD_READ) {
  1977. m->ReturnValue |= O_RDONLY;
  1978. } else if (pFd->SystemOpenFileDesc->Flags & PSX_FD_WRITE) {
  1979. m->ReturnValue |= O_WRONLY;
  1980. }
  1981. if (pFd->SystemOpenFileDesc->Flags & PSX_FD_NOBLOCK) {
  1982. m->ReturnValue |= O_NONBLOCK;
  1983. }
  1984. if (pFd->SystemOpenFileDesc->Flags & PSX_FD_APPEND) {
  1985. m->ReturnValue |= O_APPEND;
  1986. }
  1987. return TRUE;
  1988. case F_SETFL:
  1989. pFd->SystemOpenFileDesc->Flags &= ~(PSX_FD_APPEND | PSX_FD_NOBLOCK);
  1990. if (args->u.i & O_APPEND) {
  1991. pFd->SystemOpenFileDesc->Flags |= PSX_FD_APPEND;
  1992. }
  1993. if (args->u.i & O_NONBLOCK) {
  1994. pFd->SystemOpenFileDesc->Flags |= PSX_FD_NOBLOCK;
  1995. }
  1996. m->ReturnValue = 0;
  1997. return TRUE;
  1998. case F_SETLK:
  1999. case F_SETLKW:
  2000. //
  2001. // 1003.1-90 (6.5.2.4): EBADF if F_SETLK or F_SETLKW and
  2002. // l_type is F_RDLCK and fildes is not ... open for reading.
  2003. //
  2004. if (F_RDLCK == args->u.pf->l_type &&
  2005. !(pFd->SystemOpenFileDesc->Flags & PSX_FD_READ)) {
  2006. m->Error = EBADF;
  2007. m->ReturnValue = (ULONG)(-1);
  2008. return TRUE;
  2009. }
  2010. //
  2011. // ... EBADF if F_SETLK or F_SETLKW and l_type is F_WRLCK
  2012. // and fildes is not ... open for writing.
  2013. //
  2014. if (F_WRLCK == args->u.pf->l_type &&
  2015. !(pFd->SystemOpenFileDesc->Flags & PSX_FD_WRITE)) {
  2016. m->Error = EBADF;
  2017. m->ReturnValue = (ULONG)(-1);
  2018. return TRUE;
  2019. }
  2020. //FALLTHROUGH
  2021. case F_GETLK:
  2022. if (!(pFd->SystemOpenFileDesc->IoNode->Mode & S_IFREG)) {
  2023. //
  2024. // flocks only work on regular files
  2025. //
  2026. m->Error = EINVAL;
  2027. m->ReturnValue = (ULONG)(-1);
  2028. }
  2029. RtlEnterCriticalSection(&pFd->SystemOpenFileDesc->IoNode->IoNodeLock);
  2030. b = DoFlockStuff(p, m, args->Command, pFd,
  2031. args->u.pf, &error);
  2032. if (b) {
  2033. RtlLeaveCriticalSection(&pFd->SystemOpenFileDesc->IoNode->IoNodeLock);
  2034. }
  2035. m->Error = error;
  2036. if (error == 0) {
  2037. m->ReturnValue = 0;
  2038. } else {
  2039. m->ReturnValue = (ULONG)(-1);
  2040. }
  2041. //
  2042. // DoFlockStuff returns FALSE if the process was
  2043. // blocked and no reply should be sent.
  2044. //
  2045. return b;
  2046. #if DBG
  2047. case 99:
  2048. DumpFlockList(pFd->SystemOpenFileDesc->IoNode);
  2049. break;
  2050. #endif
  2051. default:
  2052. // This shouldn't happen; the client checks for valid
  2053. // command arguments.
  2054. ASSERT(0);
  2055. }
  2056. return TRUE;
  2057. }
  2058. BOOLEAN
  2059. PsxIsatty(
  2060. IN PPSX_PROCESS p,
  2061. IN OUT PPSX_API_MSG m
  2062. )
  2063. {
  2064. PPSX_ISATTY_MSG args;
  2065. NTSTATUS Status;
  2066. PFILEDESCRIPTOR Fd;
  2067. args = &m->u.Isatty;
  2068. Fd = FdIndexToFd(p, args->FileDes);
  2069. if (!Fd) {
  2070. m->Error = EBADF;
  2071. return TRUE;
  2072. }
  2073. if (&ConVectors == Fd->SystemOpenFileDesc->IoNode->IoVectors) {
  2074. //
  2075. // If the fd is open on the console, it's not
  2076. // necessarily a tty, since the console session manager
  2077. // could have redirected the output. The dll will send
  2078. // a message to posix.exe, asking whether it's redirected
  2079. // or not.
  2080. //
  2081. args->Command = IO_COMMAND_DO_CONSIO;
  2082. args->FileDes = HandleToUlong(Fd->SystemOpenFileDesc->NtIoHandle);
  2083. return TRUE;
  2084. }
  2085. args->Command = IO_COMMAND_DONE;
  2086. m->ReturnValue = FALSE; // not a tty
  2087. return TRUE;
  2088. }
  2089. BOOLEAN
  2090. PsxFtruncate(
  2091. IN PPSX_PROCESS p,
  2092. IN PPSX_API_MSG m
  2093. )
  2094. /*++
  2095. Routine Description:
  2096. This procedure implements POSIX ftruncate().
  2097. Arguments:
  2098. p - Supplies the address of the process making the call.
  2099. m - Supplies the address of the message associated with the request.
  2100. Return Value:
  2101. TRUE - The contents of *m should be used to generate a reply.
  2102. --*/
  2103. {
  2104. PPSX_FTRUNCATE_MSG args;
  2105. PFILEDESCRIPTOR Fd;
  2106. FILE_END_OF_FILE_INFORMATION EofInfo;
  2107. NTSTATUS Status;
  2108. IO_STATUS_BLOCK iosb;
  2109. args = &m->u.Ftruncate;
  2110. Fd = FdIndexToFd(p, args->FileDes);
  2111. if (!Fd) {
  2112. m->Error = EBADF;
  2113. return TRUE;
  2114. }
  2115. //
  2116. // Ftruncate is only allowed on regular files.
  2117. //
  2118. if (S_ISFIFO(Fd->SystemOpenFileDesc->IoNode->Mode) ||
  2119. Fd->SystemOpenFileDesc->IoNode->DeviceSerialNumber == PSX_LOCAL_PIPE) {
  2120. m->Error = ESPIPE;
  2121. return TRUE;
  2122. }
  2123. if (&FileVectors != Fd->SystemOpenFileDesc->IoNode->IoVectors) {
  2124. m->Error = EBADF;
  2125. return TRUE;
  2126. }
  2127. EofInfo.EndOfFile.QuadPart = args->Length;
  2128. Status = NtSetInformationFile(
  2129. Fd->SystemOpenFileDesc->NtIoHandle,
  2130. &iosb,
  2131. (PVOID)&EofInfo,
  2132. sizeof(EofInfo),
  2133. FileEndOfFileInformation
  2134. );
  2135. if (!NT_SUCCESS(Status)) {
  2136. m->Error = PsxStatusToErrno(Status);
  2137. }
  2138. return TRUE;
  2139. }
  2140. //
  2141. // Internal support routine
  2142. //
  2143. // InitSecurityDescriptor -- to be called when a new file is created. Sets
  2144. // up the security descriptor appropriately.
  2145. //
  2146. // The filename is used only to get the name of the parent direcotory,
  2147. // which we use to set the group in the security descriptor.
  2148. //
  2149. NTSTATUS
  2150. InitSecurityDescriptor(
  2151. PSECURITY_DESCRIPTOR pSD,
  2152. PUNICODE_STRING pFileName,
  2153. IN HANDLE Process,
  2154. IN mode_t Mode,
  2155. OUT PVOID *pvMem
  2156. )
  2157. {
  2158. PSID_AND_ATTRIBUTES
  2159. pSA;
  2160. HANDLE TokenHandle;
  2161. ULONG Length, LengthNeeded;
  2162. NTSTATUS
  2163. Status;
  2164. PACL pDacl;
  2165. ACCESS_MASK
  2166. UserAccess,
  2167. GroupAccess,
  2168. OtherAccess;
  2169. ANSI_STRING File_A;
  2170. UNICODE_STRING ParentDir_U;
  2171. OBJECT_ATTRIBUTES Obj;
  2172. HANDLE DirHandle;
  2173. PSID DirGroup;
  2174. PCHAR pch;
  2175. IO_STATUS_BLOCK Iosb;
  2176. SECURITY_INFORMATION SecurityInformation;
  2177. PSECURITY_DESCRIPTOR pDirSD = NULL;
  2178. PTOKEN_PRIMARY_GROUP pGroup = NULL;
  2179. BOOLEAN Defaulted;
  2180. int i;
  2181. Status = RtlUnicodeStringToAnsiString(&File_A, pFileName, TRUE);
  2182. if (!NT_SUCCESS(Status)) {
  2183. return STATUS_NO_MEMORY;
  2184. }
  2185. //
  2186. // Open the parent directory and get its group owner.
  2187. //
  2188. pch = strrchr(File_A.Buffer, '\\') + 1;
  2189. if (pch == NULL)
  2190. return STATUS_OBJECT_PATH_SYNTAX_BAD;
  2191. *pch = '\0';
  2192. File_A.Length = (USHORT)strlen(File_A.Buffer);
  2193. Status = RtlAnsiStringToUnicodeString(&ParentDir_U, &File_A, TRUE);
  2194. RtlFreeAnsiString(&File_A);
  2195. if (!NT_SUCCESS(Status)) {
  2196. return STATUS_NO_MEMORY;
  2197. }
  2198. InitializeObjectAttributes(&Obj, &ParentDir_U, 0, NULL, NULL);
  2199. Status = NtOpenFile(&DirHandle,
  2200. SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES |
  2201. FILE_READ_EA, &Obj, &Iosb,
  2202. SHARE_ALL,
  2203. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
  2204. RtlFreeUnicodeString(&ParentDir_U);
  2205. if (!NT_SUCCESS(Status)) {
  2206. return Status;
  2207. }
  2208. Status = NtOpenProcessToken(Process, GENERIC_READ, &TokenHandle);
  2209. if (!NT_SUCCESS(Status)) {
  2210. NtClose(DirHandle);
  2211. return Status;
  2212. }
  2213. SecurityInformation = GROUP_SECURITY_INFORMATION;
  2214. Status = NtQuerySecurityObject(DirHandle, SecurityInformation,
  2215. NULL, 0, &LengthNeeded);
  2216. if (STATUS_INVALID_PARAMETER == Status) {
  2217. //
  2218. // Can't get the group from parent dir, use primary group
  2219. // instead.
  2220. //
  2221. Status = NtQueryInformationToken(TokenHandle, TokenPrimaryGroup,
  2222. NULL, 0, &LengthNeeded);
  2223. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  2224. pGroup = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  2225. if (NULL == pGroup) {
  2226. NtClose(TokenHandle);
  2227. return STATUS_NO_MEMORY;
  2228. }
  2229. Status = NtQueryInformationToken(TokenHandle, TokenPrimaryGroup,
  2230. pGroup, LengthNeeded, &LengthNeeded);
  2231. ASSERT(NT_SUCCESS(Status));
  2232. DirGroup = pGroup->PrimaryGroup;
  2233. } else if (!NT_SUCCESS(Status)) {
  2234. static int _status;
  2235. _status = Status;
  2236. if (STATUS_BUFFER_TOO_SMALL != _status || 0 == LengthNeeded) {
  2237. KdPrint(("PSXSS: NtQSObject returned unexpected %x, %x\n",
  2238. _status, LengthNeeded));
  2239. return _status;
  2240. }
  2241. ASSERT(STATUS_BUFFER_TOO_SMALL == _status);
  2242. pDirSD = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  2243. if (NULL == pDirSD) {
  2244. NtClose(DirHandle);
  2245. return STATUS_NO_MEMORY;
  2246. }
  2247. Status = NtQuerySecurityObject(DirHandle, SecurityInformation,
  2248. pDirSD, LengthNeeded, &Length);
  2249. if (!NT_SUCCESS(Status)) {
  2250. KdPrint(("PSXSS: NtQSD: 0x%x\n", Status));
  2251. KdPrint(("PSXSS: NtQSD: %d vs. %d\n", LengthNeeded, Length));
  2252. return Status;
  2253. }
  2254. NtClose(DirHandle);
  2255. Status = RtlGetGroupSecurityDescriptor(pDirSD, &DirGroup,
  2256. &Defaulted);
  2257. ASSERT(NT_SUCCESS(Status));
  2258. }
  2259. Status = RtlCreateSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
  2260. ASSERT(NT_SUCCESS(Status));
  2261. Status = NtQueryInformationToken(TokenHandle, TokenUser, NULL,
  2262. 0, &LengthNeeded);
  2263. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  2264. pSA = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  2265. if (NULL == pSA) {
  2266. NtClose(TokenHandle);
  2267. return STATUS_NO_MEMORY;
  2268. }
  2269. Status = NtQueryInformationToken(TokenHandle, TokenUser, pSA,
  2270. LengthNeeded, &LengthNeeded);
  2271. if (!NT_SUCCESS(Status)) {
  2272. KdPrint(("PSXSS: NtQueryInfoToken: 0x%x\n", Status));
  2273. }
  2274. ASSERT(NT_SUCCESS(Status));
  2275. Status = RtlSetOwnerSecurityDescriptor(pSD, pSA->Sid, FALSE);
  2276. ASSERT(NT_SUCCESS(Status));
  2277. Status = RtlSetGroupSecurityDescriptor(pSD, DirGroup, FALSE);
  2278. ASSERT(NT_SUCCESS(Status));
  2279. ModeToAccessMask(Mode, &UserAccess, &GroupAccess, &OtherAccess);
  2280. Status = RtlMakePosixAcl(ACL_REVISION2, pSA->Sid, DirGroup,
  2281. UserAccess, GroupAccess, OtherAccess, 0, NULL, &LengthNeeded);
  2282. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  2283. pDacl = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  2284. if (NULL == pDacl) {
  2285. // XXX.mjb: better cleanup needed
  2286. NtClose(TokenHandle);
  2287. return STATUS_NO_MEMORY;
  2288. }
  2289. Status = RtlMakePosixAcl(ACL_REVISION2, pSA->Sid, DirGroup,
  2290. UserAccess, GroupAccess, OtherAccess, LengthNeeded, pDacl,
  2291. &LengthNeeded);
  2292. ASSERT(NT_SUCCESS(Status));
  2293. Status = RtlSetDaclSecurityDescriptor(pSD,
  2294. TRUE, pDacl, FALSE);
  2295. ASSERT(NT_SUCCESS(Status));
  2296. //
  2297. // The pointers we stick into pvMem will be freed in DeInitSD.
  2298. //
  2299. i = 0;
  2300. pvMem[i++] = pDacl;
  2301. pvMem[i++] = pSA;
  2302. if (NULL != pDirSD) {
  2303. pvMem[i++] = pDirSD;
  2304. }
  2305. if (NULL != pGroup) {
  2306. pvMem[i++] = pGroup;
  2307. }
  2308. pvMem[i++] = NULL;
  2309. NtClose(TokenHandle);
  2310. ASSERT(RtlValidSecurityDescriptor(pSD));
  2311. return STATUS_SUCCESS;
  2312. }
  2313. //
  2314. // Internal support routine
  2315. //
  2316. // This routine should only be called on SD's initialized with
  2317. // InitSecurityDescriptor(). It frees memory that was allocated
  2318. // there.
  2319. //
  2320. VOID
  2321. DeInitSecurityDescriptor(
  2322. PSECURITY_DESCRIPTOR pSD,
  2323. PVOID *pvMem
  2324. )
  2325. {
  2326. PACL pDacl;
  2327. NTSTATUS Status;
  2328. BOOLEAN b;
  2329. int i;
  2330. for (i = 0; NULL != pvMem[i]; ++i)
  2331. RtlFreeHeap(PsxHeap, 0, pvMem[i]);
  2332. #if 0
  2333. Status = RtlGetDaclSecurityDescriptor(pSD, &b, &pDacl, &b);
  2334. ASSERT(NT_SUCCESS(Status));
  2335. ASSERT(NULL != pDacl);
  2336. RtlFreeHeap(PsxHeap, 0, pDacl);
  2337. #endif
  2338. }
  2339. //
  2340. // Internal support routine
  2341. //
  2342. // See if the given group is one that the owner of this process belongs
  2343. // to.
  2344. //
  2345. static BOOLEAN
  2346. IsUserInGroup(
  2347. PPSX_PROCESS p,
  2348. PSID Group
  2349. )
  2350. {
  2351. HANDLE TokenHandle;
  2352. TOKEN_GROUPS *pGroups;
  2353. ULONG LengthNeeded;
  2354. NTSTATUS Status;
  2355. BOOLEAN RetVal = FALSE;
  2356. ULONG i;
  2357. Status = NtOpenProcessToken(p->Process, GENERIC_READ, &TokenHandle);
  2358. ASSERT(NT_SUCCESS(Status));
  2359. Status = NtQueryInformationToken(TokenHandle, TokenGroups, NULL,
  2360. 0, &LengthNeeded);
  2361. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  2362. pGroups = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  2363. if (NULL == pGroups) {
  2364. NtClose(TokenHandle);
  2365. return FALSE;
  2366. }
  2367. Status = NtQueryInformationToken(TokenHandle, TokenGroups, pGroups,
  2368. LengthNeeded, &LengthNeeded);
  2369. ASSERT(NT_SUCCESS(Status));
  2370. for (i = 0; i < pGroups->GroupCount; ++i) {
  2371. if (RtlEqualSid(pGroups->Groups[i].Sid, Group)) {
  2372. RetVal = TRUE;
  2373. break;
  2374. }
  2375. }
  2376. RtlFreeHeap(PsxHeap, 0, pGroups);
  2377. NtClose(TokenHandle);
  2378. return RetVal;
  2379. }
  2380. //
  2381. // Internal support routine
  2382. //
  2383. PSID
  2384. GetLoginGroupSid(
  2385. IN PPSX_PROCESS p
  2386. )
  2387. /*++
  2388. Get the logon group Sid from the supplementary group list. The
  2389. returned Sid is allocated from PsxHeap, and should be freed by
  2390. the caller when he's done with it.
  2391. Returns NULL upon failure.
  2392. --*/
  2393. {
  2394. HANDLE TokenHandle;
  2395. NTSTATUS Status;
  2396. PSID NewSid;
  2397. ULONG outlen, i;
  2398. TOKEN_GROUPS *pGroups;
  2399. Status = NtOpenProcessToken(p->Process, GENERIC_READ,
  2400. &TokenHandle);
  2401. if (!NT_SUCCESS(Status)) {
  2402. return NULL;
  2403. }
  2404. Status = NtQueryInformationToken(TokenHandle, TokenGroups,
  2405. NULL, 0, &outlen);
  2406. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  2407. pGroups = RtlAllocateHeap(PsxHeap, 0, outlen);
  2408. if (NULL == pGroups) {
  2409. NtClose(TokenHandle);
  2410. return NULL;
  2411. }
  2412. Status = NtQueryInformationToken(TokenHandle, TokenGroups,
  2413. pGroups, outlen, &outlen);
  2414. if (!NT_SUCCESS(Status)) {
  2415. RtlFreeHeap(PsxHeap, 0, pGroups);
  2416. NtClose(TokenHandle);
  2417. return NULL;
  2418. }
  2419. for (i = 0; i < pGroups->GroupCount; ++i) {
  2420. PSID Sid = pGroups->Groups[i].Sid;
  2421. if (0xFFF == MakePosixId(Sid)) {
  2422. // This is the login group sid, copy it and return.
  2423. NewSid = RtlAllocateHeap(PsxHeap, 0,
  2424. RtlLengthSid(Sid));
  2425. if (NULL == NewSid)
  2426. return NULL;
  2427. Status = RtlCopySid(RtlLengthSid(Sid), NewSid, Sid);
  2428. ASSERT(NT_SUCCESS(Status));
  2429. RtlFreeHeap(PsxHeap, 0, pGroups);
  2430. NtClose(TokenHandle);
  2431. return NewSid;
  2432. }
  2433. }
  2434. RtlFreeHeap(PsxHeap, 0, pGroups);
  2435. NtClose(TokenHandle);
  2436. return NULL;
  2437. }
  2438. //
  2439. // Internal support routine
  2440. //
  2441. ULONG
  2442. OpenTty(
  2443. PPSX_PROCESS p,
  2444. PFILEDESCRIPTOR Fd,
  2445. ULONG DesiredAccess,
  2446. ULONG Flags,
  2447. BOOLEAN NewOpen
  2448. )
  2449. /*++
  2450. Routine Description:
  2451. This routine is called to implement an open on the file /dev/tty.
  2452. Arguments:
  2453. p - The process on whose behalf the open is performed.
  2454. Fd - The file descriptor to receive the handle.
  2455. DesiredAccess - The access requested on the file.
  2456. Flags -
  2457. NewOpen - FALSE if the file is already open in the console session
  2458. manager. This will be the case for stdin, stdout, and
  2459. stderr. If NewOepn is TRUE, we're opening /dev/tty an
  2460. additional time, and we want the console sess mgr to open
  2461. con: again, to go along.
  2462. Return Value:
  2463. A posix error status, or 0 if successful.
  2464. --*/
  2465. {
  2466. SCREQUESTMSG Request;
  2467. NTSTATUS Status;
  2468. Fd->SystemOpenFileDesc = AllocateSystemOpenFile();
  2469. if (NULL == Fd->SystemOpenFileDesc) {
  2470. return ENOMEM;
  2471. }
  2472. if (DesiredAccess & FILE_READ_DATA) {
  2473. Fd->SystemOpenFileDesc->Flags |= PSX_FD_READ;
  2474. }
  2475. if (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
  2476. Fd->SystemOpenFileDesc->Flags |= PSX_FD_WRITE;
  2477. }
  2478. if (Flags & O_NONBLOCK) {
  2479. Fd->SystemOpenFileDesc->Flags |= PSX_FD_NOBLOCK;
  2480. }
  2481. if (Flags & O_APPEND) {
  2482. Fd->SystemOpenFileDesc->Flags |= PSX_FD_APPEND;
  2483. }
  2484. if (ReferenceOrCreateIoNode(PSX_CONSOLE_DEV,
  2485. (ULONG_PTR)p->PsxSession->Terminal->ConsolePort, FALSE,
  2486. &Fd->SystemOpenFileDesc->IoNode)) {
  2487. // null
  2488. } else {
  2489. if (! Fd->SystemOpenFileDesc->IoNode) {
  2490. DeallocateSystemOpenFile(p, Fd->SystemOpenFileDesc);
  2491. return ENOMEM;
  2492. }
  2493. Fd->SystemOpenFileDesc->IoNode->IoVectors = &ConVectors;
  2494. Fd->SystemOpenFileDesc->IoNode->Mode = S_IFCHR | 0700;
  2495. Fd->SystemOpenFileDesc->IoNode->OwnerId = p->EffectiveUid;
  2496. Fd->SystemOpenFileDesc->IoNode->GroupId = p->EffectiveGid;
  2497. }
  2498. RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
  2499. (void)IoOpenNewHandle(p, Fd, NULL);
  2500. Fd->SystemOpenFileDesc->Terminal = p->PsxSession->Terminal;
  2501. //
  2502. // Add a reference to the terminal (there is an additional
  2503. // file descriptor open on it).
  2504. //
  2505. ++Fd->SystemOpenFileDesc->Terminal->ReferenceCount;
  2506. if (!NewOpen) {
  2507. return 0;
  2508. }
  2509. //
  2510. // Send a message to posix.exe, asking him to open the
  2511. // console again.
  2512. //
  2513. Request.Request = ConRequest;
  2514. Request.d.Con.Request = ScOpenFile;
  2515. if (DesiredAccess & FILE_WRITE_DATA) {
  2516. Request.d.Con.d.IoBuf.Flags = O_WRONLY;
  2517. } else {
  2518. Request.d.Con.d.IoBuf.Flags = O_RDONLY;
  2519. }
  2520. PORT_MSG_TOTAL_LENGTH(Request) = sizeof(SCREQUESTMSG);
  2521. PORT_MSG_DATA_LENGTH(Request) = sizeof(SCREQUESTMSG) -
  2522. sizeof(PORT_MESSAGE);
  2523. PORT_MSG_ZERO_INIT(Request) = 0;
  2524. // XXX.mjb: hold session mgr lock
  2525. Status = NtRequestWaitReplyPort(p->PsxSession->Terminal->ConsolePort,
  2526. (PPORT_MESSAGE)&Request, (PPORT_MESSAGE)&Request);
  2527. if (!NT_SUCCESS(Status)) {
  2528. KdPrint(("PSXSS: NtRequest: 0x%x\n", Status));
  2529. }
  2530. ASSERT(NT_SUCCESS(Status));
  2531. // XXX.mjb: release session mgr lock
  2532. Fd->SystemOpenFileDesc->NtIoHandle = Request.d.Con.d.IoBuf.Handle;
  2533. return 0;
  2534. }
  2535. //
  2536. // Internal support routine
  2537. //
  2538. ULONG
  2539. OpenDevNull(
  2540. PPSX_PROCESS p,
  2541. PFILEDESCRIPTOR Fd,
  2542. ULONG DesiredAccess,
  2543. ULONG Flags
  2544. )
  2545. /*++
  2546. Routine Description:
  2547. This routine is called to implement an open on the file /dev/null.
  2548. Arguments:
  2549. p - The process on whose behalf the open is performed.
  2550. Fd - The file descriptor to receive the handle.
  2551. DesiredAccess - The access requested on the file.
  2552. Flags -
  2553. NewOpen - FALSE if the file is already open in the console session
  2554. manager. This will be the case for stdin, stdout, and
  2555. stderr. If NewOepn is TRUE, we're opening /dev/tty an
  2556. additional time, and we want the console sess mgr to open
  2557. con: again, to go along.
  2558. Return Value:
  2559. A posix error status, or 0 if successful.
  2560. --*/
  2561. {
  2562. NTSTATUS Status;
  2563. Fd->SystemOpenFileDesc = AllocateSystemOpenFile();
  2564. if (NULL == Fd->SystemOpenFileDesc) {
  2565. return ENOMEM;
  2566. }
  2567. if (DesiredAccess & FILE_READ_DATA) {
  2568. Fd->SystemOpenFileDesc->Flags |= PSX_FD_READ;
  2569. }
  2570. if (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
  2571. Fd->SystemOpenFileDesc->Flags |= PSX_FD_WRITE;
  2572. }
  2573. if (Flags & O_NONBLOCK) {
  2574. Fd->SystemOpenFileDesc->Flags |= PSX_FD_NOBLOCK;
  2575. }
  2576. if (Flags & O_APPEND) {
  2577. Fd->SystemOpenFileDesc->Flags |= PSX_FD_APPEND;
  2578. }
  2579. if (ReferenceOrCreateIoNode(PSX_NULL_DEV,
  2580. (ino_t)0, FALSE, &Fd->SystemOpenFileDesc->IoNode)) {
  2581. // null
  2582. } else {
  2583. if (! Fd->SystemOpenFileDesc->IoNode) {
  2584. DeallocateSystemOpenFile(p, Fd->SystemOpenFileDesc);
  2585. return ENOMEM;
  2586. }
  2587. Fd->SystemOpenFileDesc->IoNode->IoVectors = &NullVectors;
  2588. Fd->SystemOpenFileDesc->IoNode->Mode = S_IFCHR | 0666;
  2589. Fd->SystemOpenFileDesc->IoNode->OwnerId = p->EffectiveUid;
  2590. Fd->SystemOpenFileDesc->IoNode->GroupId = p->EffectiveGid;
  2591. }
  2592. RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
  2593. (void)IoOpenNewHandle(p, Fd, NULL);
  2594. Fd->SystemOpenFileDesc->Terminal = NULL;
  2595. return 0;
  2596. }
  2597. //
  2598. // Internal support routine
  2599. //
  2600. dev_t
  2601. GetFileDeviceNumber(
  2602. PUNICODE_STRING Path
  2603. )
  2604. /*++
  2605. Routine Description:
  2606. Takes a path, like \DosDevices\X:\foo\bar, and returns
  2607. the device number, which in this case is 'X'.
  2608. Arguments:
  2609. Path - the path.
  2610. Return Value:
  2611. The device number.
  2612. --*/
  2613. {
  2614. wchar_t ch;
  2615. if (NtCurrentPeb()->SessionId) {
  2616. ULONG len;
  2617. PSX_GET_STRLEN(DOSDEVICE_X_A,len);
  2618. ch = Path->Buffer[len-3];
  2619. }else{
  2620. ch = Path->Buffer[12];
  2621. }
  2622. return (dev_t)ch;
  2623. }