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.

853 lines
20 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. psxsup.c
  5. Abstract:
  6. PSX Support Routines
  7. Author:
  8. Mark Lucovsky (markl) 27-Nov-1989
  9. Revision History:
  10. --*/
  11. #include "psxsrv.h"
  12. #include <ntlsa.h>
  13. #include <ntsam.h>
  14. #include <ntseapi.h>
  15. #include "sesport.h"
  16. #include "seposix.h"
  17. #define UNICODE
  18. #include <windows.h>
  19. #include <lm.h>
  20. #include <lmaccess.h>
  21. #include <sys/stat.h>
  22. //
  23. // This number will never be returned in the PosixOffset field of
  24. // a trusted domain query.
  25. //
  26. #define INVALID_POSIX_OFFSET 1
  27. ULONG
  28. PsxStatusToErrno(
  29. IN NTSTATUS Status
  30. )
  31. /*++
  32. Routine Description:
  33. This procedure converts an NT status code to an
  34. equivalent errno value.
  35. The conversion is a function of the status code class.
  36. Arguments:
  37. Class - Supplies the status code class to use.
  38. Status - Supplies the status code to convert.
  39. Return Value:
  40. Returns an equivalent error code to the supplied status code.
  41. --*/
  42. {
  43. ULONG Error;
  44. switch (Status) {
  45. case STATUS_INVALID_PARAMETER:
  46. Error = EINVAL;
  47. break;
  48. case STATUS_DIRECTORY_NOT_EMPTY:
  49. // Error = ENOTEMPTY;
  50. Error = EEXIST;
  51. break;
  52. case STATUS_OBJECT_PATH_INVALID:
  53. case STATUS_OBJECT_PATH_SYNTAX_BAD:
  54. case STATUS_NOT_A_DIRECTORY:
  55. Error = ENOTDIR;
  56. break;
  57. case STATUS_OBJECT_NAME_COLLISION:
  58. Error = EEXIST;
  59. break;
  60. case STATUS_OBJECT_PATH_NOT_FOUND:
  61. case STATUS_OBJECT_NAME_NOT_FOUND:
  62. case STATUS_DELETE_PENDING:
  63. case STATUS_NO_SUCH_FILE:
  64. Error = ENOENT;
  65. break;
  66. case STATUS_NO_MEMORY:
  67. case STATUS_INSUFFICIENT_RESOURCES:
  68. Error = ENOMEM;
  69. break;
  70. case STATUS_CANNOT_DELETE:
  71. Error = ETXTBUSY;
  72. break;
  73. case STATUS_DISK_FULL:
  74. Error = ENOSPC;
  75. break;
  76. case STATUS_MEDIA_WRITE_PROTECTED:
  77. Error = EROFS;
  78. break;
  79. case STATUS_OBJECT_NAME_INVALID:
  80. Error = ENAMETOOLONG;
  81. break;
  82. case STATUS_FILE_IS_A_DIRECTORY:
  83. Error = EISDIR;
  84. break;
  85. case STATUS_NOT_SAME_DEVICE:
  86. Error = EXDEV;
  87. break;
  88. case STATUS_INVALID_OWNER:
  89. Error = EPERM;
  90. break;
  91. case STATUS_INVALID_IMAGE_FORMAT:
  92. case STATUS_INVALID_IMAGE_LE_FORMAT:
  93. case STATUS_INVALID_IMAGE_NOT_MZ:
  94. case STATUS_INVALID_IMAGE_PROTECT:
  95. case STATUS_INVALID_IMAGE_WIN_16:
  96. Error = ENOEXEC;
  97. break;
  98. case STATUS_NOT_IMPLEMENTED:
  99. Error = ENOSYS;
  100. break;
  101. case STATUS_TOO_MANY_LINKS:
  102. Error = EMLINK;
  103. break;
  104. default:
  105. Error = EACCES;
  106. }
  107. return Error;
  108. }
  109. ULONG
  110. PsxStatusToErrnoPath(
  111. IN PUNICODE_STRING Path
  112. )
  113. /*++
  114. Routine Description:
  115. This procedure is called when an NtOpenFile returns
  116. STATUS_OBJECT_PATH_NOT_FOUND; this routine is to
  117. distinguish the following too cases:
  118. /file.c/foo, where file.c exists (ENOTDIR)
  119. /noent/foo, where noent doesn't exist (ENOENT)
  120. (NtOpenFile returns OBJECT_PATH_NOT_FOUND for both cases).
  121. Arguments:
  122. Path - Supplies the path that was given to NtOpenFile. The
  123. path string is destroyed by this function.
  124. Return Value:
  125. Returns an equivalent error code to the supplied status code.
  126. --*/
  127. {
  128. NTSTATUS Status;
  129. OBJECT_ATTRIBUTES Obj;
  130. HANDLE FileHandle;
  131. ULONG DesiredAccess;
  132. IO_STATUS_BLOCK Iosb;
  133. ULONG Options;
  134. PWCHAR pwc, pwcSav;
  135. ULONG MinLen;
  136. PSX_GET_SIZEOF(DOSDEVICE_X_W,MinLen);
  137. DesiredAccess = SYNCHRONIZE;
  138. Options = FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE;
  139. pwcSav = NULL;
  140. for (;;) {
  141. //
  142. // Remove a trailing component.
  143. //
  144. pwc = wcsrchr(Path->Buffer, L'\\');
  145. if (pwcSav)
  146. *pwcSav = L'\\';
  147. if (NULL == pwc) {
  148. break;
  149. }
  150. *pwc = UNICODE_NULL;
  151. pwcSav = pwc;
  152. Path->Length = wcslen(Path->Buffer) * sizeof(WCHAR);
  153. if (Path->Length <= MinLen) {
  154. *pwcSav = L'\\';
  155. break;
  156. }
  157. InitializeObjectAttributes(&Obj, Path, 0, NULL, NULL);
  158. Status = NtOpenFile(&FileHandle, DesiredAccess, &Obj,
  159. &Iosb, SHARE_ALL, Options);
  160. if (NT_SUCCESS(Status)) {
  161. NtClose(FileHandle);
  162. }
  163. if (STATUS_NOT_A_DIRECTORY == Status) {
  164. *pwcSav = L'\\';
  165. Path->Length = wcslen(Path->Buffer) * sizeof(WCHAR);
  166. return ENOTDIR;
  167. }
  168. }
  169. Path->Length = wcslen(Path->Buffer) * sizeof(WCHAR);
  170. return ENOENT;
  171. }
  172. ULONG
  173. PsxDetermineFileClass(
  174. IN HANDLE FileHandle
  175. )
  176. /*++
  177. Routine Description:
  178. This function examines a file handle and returns its FileClass
  179. Arguments:
  180. FileHandle - Supplies a handle to an open file whose class is to be
  181. determined.
  182. Return Value:
  183. The file class of the specified file. Defined in <sys/stat.h>.
  184. --*/
  185. {
  186. NTSTATUS st;
  187. IO_STATUS_BLOCK Iosb;
  188. FILE_BASIC_INFORMATION BasicInfo;
  189. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  190. //
  191. // Call NtQueryFile to get device type and attributes
  192. //
  193. st = NtQueryInformationFile(
  194. FileHandle,
  195. &Iosb,
  196. &BasicInfo,
  197. sizeof(BasicInfo),
  198. FileBasicInformation
  199. );
  200. if (!NT_SUCCESS(st)) {
  201. // XXX.mjb: Sometimes fails on HPFS
  202. KdPrint(("PSXS: PsxDetermineFileClass: NtQueryInfoFile: 0x%x\n", st));
  203. return S_IFREG;
  204. }
  205. st = NtQueryVolumeInformationFile(
  206. FileHandle,
  207. &Iosb,
  208. &DeviceInfo,
  209. sizeof(DeviceInfo),
  210. FileFsDeviceInformation
  211. );
  212. ASSERT(NT_SUCCESS(st));
  213. switch (DeviceInfo.DeviceType) {
  214. case FILE_DEVICE_DATALINK:
  215. case FILE_DEVICE_KEYBOARD:
  216. case FILE_DEVICE_MOUSE:
  217. case FILE_DEVICE_NETWORK:
  218. case FILE_DEVICE_NULL:
  219. case FILE_DEVICE_PHYSICAL_NETCARD:
  220. case FILE_DEVICE_PARALLEL_PORT:
  221. case FILE_DEVICE_PRINTER:
  222. case FILE_DEVICE_SOUND:
  223. case FILE_DEVICE_SCREEN:
  224. case FILE_DEVICE_SERIAL_PORT:
  225. case FILE_DEVICE_TRANSPORT:
  226. return S_IFCHR;
  227. case FILE_DEVICE_DFS:
  228. case FILE_DEVICE_DISK_FILE_SYSTEM:
  229. case FILE_DEVICE_NETWORK_FILE_SYSTEM:
  230. return S_IFBLK;
  231. case FILE_DEVICE_DISK:
  232. case FILE_DEVICE_VIRTUAL_DISK:
  233. case FILE_DEVICE_TAPE:
  234. break;
  235. default:
  236. break;
  237. // return 0;
  238. }
  239. //
  240. // The only thing left is RegularFile class. Now
  241. // determine if this is a directory, named pipe,
  242. // or regular file.
  243. //
  244. if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  245. return S_IFDIR;
  246. }
  247. //
  248. // For now, anything marked as a system file is a named pipe.
  249. // In the future, this will involve checking to see if file
  250. // has the Object Bit and has the appropriate EA (named pipe
  251. // class id).
  252. //
  253. if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_SYSTEM) {
  254. return S_IFIFO;
  255. }
  256. return S_IFREG;
  257. }
  258. VOID
  259. EndImpersonation(
  260. VOID
  261. )
  262. {
  263. HANDLE Handle;
  264. NTSTATUS Status;
  265. Handle = NULL;
  266. Status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken,
  267. (PVOID)&Handle, sizeof(HANDLE));
  268. ASSERT(NT_SUCCESS(Status));
  269. }
  270. //
  271. // MakePosixId -- convert the given SID into a Posix Id. This basically
  272. // means find the Posix Offset and add it to the last sub-authority
  273. // in the SID. The Posix Id is returned.
  274. //
  275. uid_t
  276. MakePosixId(PSID Sid)
  277. {
  278. NTSTATUS Status;
  279. LSA_HANDLE
  280. PolicyHandle,
  281. TrustedDomainHandle;
  282. PTRUSTED_POSIX_OFFSET_INFO
  283. pPosixOff;
  284. OBJECT_ATTRIBUTES
  285. Obj;
  286. SECURITY_QUALITY_OF_SERVICE
  287. SecurityQoS;
  288. CHAR buf[SECURITY_DESCRIPTOR_MIN_LENGTH];
  289. PSECURITY_DESCRIPTOR
  290. SecurityDescriptor = (PVOID)buf;
  291. PSID DomainSid;
  292. ULONG RelativeId, offset;
  293. UNICODE_STRING
  294. DCName,
  295. Domain_U;
  296. PPOLICY_ACCOUNT_DOMAIN_INFO
  297. AccountDomainInfo;
  298. PPOLICY_PRIMARY_DOMAIN_INFO
  299. PrimaryDomainInfo;
  300. UCHAR SubAuthCount;
  301. LPBYTE netbuf;
  302. ULONG i;
  303. SubAuthCount = *RtlSubAuthorityCountSid(Sid);
  304. RelativeId = *RtlSubAuthoritySid(Sid, SubAuthCount - 1);
  305. //
  306. // Map S-1-5-5-X-Y to Id 0xFFF
  307. //
  308. if (3 == SubAuthCount &&
  309. 5 == RtlIdentifierAuthoritySid(Sid)->Value[5] &&
  310. 5 == *RtlSubAuthoritySid(Sid, 0)) {
  311. return 0xFFF;
  312. }
  313. //
  314. // First copy the given Sid to a Sid for that domain.
  315. //
  316. DomainSid = RtlAllocateHeap(PsxHeap, 0, RtlLengthSid(Sid));
  317. if (NULL == DomainSid) {
  318. KdPrint(("PSXSS: MakePosixId: no memory\n"));
  319. return 0;
  320. }
  321. Status = RtlCopySid(RtlLengthSid(Sid), DomainSid, Sid);
  322. ASSERT(NT_SUCCESS(Status));
  323. --*RtlSubAuthorityCountSid(DomainSid);
  324. //
  325. // See if the offset for the domain is already known.
  326. //
  327. if (INVALID_POSIX_OFFSET != (offset = GetOffsetBySid(DomainSid))) {
  328. // XXX.mjb: close handles, free memory.
  329. RtlFreeHeap(PsxHeap, 0, (PVOID)DomainSid);
  330. return (offset | RelativeId);
  331. }
  332. //
  333. // If the Domain part of the passed-in Sid is our account domain,
  334. // then the offset is known.
  335. //
  336. SecurityQoS.ImpersonationLevel = SecurityIdentification;
  337. SecurityQoS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  338. SecurityQoS.EffectiveOnly = TRUE;
  339. InitializeObjectAttributes(&Obj, NULL, 0, NULL, NULL);
  340. Obj.SecurityQualityOfService = &SecurityQoS;
  341. Status = LsaOpenPolicy(NULL, &Obj, GENERIC_EXECUTE, &PolicyHandle);
  342. if (!NT_SUCCESS(Status)) {
  343. KdPrint(("PSXSS: Can't open policy: 0x%x\n", Status));
  344. RtlFreeHeap(PsxHeap, 0, (PVOID)DomainSid);
  345. return 0;
  346. }
  347. Status = LsaQueryInformationPolicy(PolicyHandle,
  348. PolicyAccountDomainInformation, (PVOID *)&AccountDomainInfo);
  349. if (!NT_SUCCESS(Status)) {
  350. KdPrint(("PSXSS: Can't query info policy: 0x%x\n", Status));
  351. return 0;
  352. }
  353. ASSERT(NULL != AccountDomainInfo->DomainSid);
  354. if (RtlEqualSid(AccountDomainInfo->DomainSid, DomainSid)) {
  355. MapSidToOffset(DomainSid, SE_ACCOUNT_DOMAIN_POSIX_OFFSET);
  356. LsaFreeMemory(AccountDomainInfo);
  357. LsaClose(PolicyHandle);
  358. return RelativeId | SE_ACCOUNT_DOMAIN_POSIX_OFFSET;
  359. }
  360. LsaFreeMemory(AccountDomainInfo);
  361. Status = LsaQueryInformationPolicy(PolicyHandle,
  362. PolicyPrimaryDomainInformation, (PVOID *)&PrimaryDomainInfo);
  363. ASSERT(NT_SUCCESS(Status));
  364. if (NULL == PrimaryDomainInfo->Sid) {
  365. //
  366. // This machine does not have a primary domain, and the
  367. // sid we're mapping does not belong to the account domain
  368. // and is not a well-known sid.
  369. //
  370. RtlFreeHeap(PsxHeap, 0, (PVOID)DomainSid);
  371. LsaFreeMemory(PrimaryDomainInfo);
  372. LsaClose(PolicyHandle);
  373. return RelativeId;
  374. }
  375. if (NULL != PrimaryDomainInfo->Sid &&
  376. RtlEqualSid(PrimaryDomainInfo->Sid, DomainSid)) {
  377. MapSidToOffset(DomainSid, SE_PRIMARY_DOMAIN_POSIX_OFFSET);
  378. LsaFreeMemory(PrimaryDomainInfo);
  379. LsaClose(PolicyHandle);
  380. return RelativeId | SE_PRIMARY_DOMAIN_POSIX_OFFSET;
  381. }
  382. Status = NetGetAnyDCName(NULL,
  383. PrimaryDomainInfo->Name.Buffer,
  384. &netbuf);
  385. if (Status != ERROR_SUCCESS) {
  386. RtlFreeHeap(PsxHeap, 0, (PVOID)DomainSid);
  387. LsaFreeMemory(PrimaryDomainInfo);
  388. LsaClose(PolicyHandle);
  389. return RelativeId;
  390. }
  391. DCName.Buffer = (PVOID)netbuf;
  392. NetApiBufferSize(netbuf, (LPDWORD)&DCName.MaximumLength);
  393. DCName.Length = wcslen((PWCHAR)netbuf) * sizeof(WCHAR);
  394. LsaClose(PolicyHandle);
  395. Status = LsaOpenPolicy(&DCName, &Obj, GENERIC_EXECUTE, &PolicyHandle);
  396. if (!NT_SUCCESS(Status)) {
  397. KdPrint(("PSXSS: Can't open policy on DC %wZ: 0x%x\n", &DCName,
  398. Status));
  399. LsaFreeMemory(PrimaryDomainInfo);
  400. RtlFreeHeap(PsxHeap, 0, (PVOID)DomainSid);
  401. return RelativeId;
  402. }
  403. NetApiBufferFree(netbuf);
  404. LsaFreeMemory(PrimaryDomainInfo);
  405. Status = LsaOpenTrustedDomain(PolicyHandle, DomainSid, GENERIC_EXECUTE,
  406. &TrustedDomainHandle);
  407. if (!NT_SUCCESS(Status)) {
  408. KdPrint(("PSXSS: Can't open trusted domain\n"));
  409. RtlFreeHeap(PsxHeap, 0, (PVOID)DomainSid);
  410. return RelativeId;
  411. }
  412. Status = LsaQueryInfoTrustedDomain(TrustedDomainHandle,
  413. TrustedPosixOffsetInformation,
  414. (PVOID)&pPosixOff);
  415. if (!NT_SUCCESS(Status)) {
  416. KdPrint(("PSXSS: Can't query Posix offset info: 0x%x\n",
  417. Status));
  418. LsaClose(PolicyHandle);
  419. LsaClose(TrustedDomainHandle);
  420. RtlFreeHeap(PsxHeap, 0, (PVOID)DomainSid);
  421. return RelativeId;
  422. }
  423. offset = pPosixOff->Offset;
  424. LsaFreeMemory(pPosixOff);
  425. if (offset & 0xFFFF) {
  426. KdPrint(("PSXSS: bad PsxOffset 0x%x\n", offset));
  427. RtlFreeHeap(PsxHeap, 0, (PVOID)DomainSid);
  428. LsaClose(TrustedDomainHandle);
  429. LsaClose(PolicyHandle);
  430. offset = 0;
  431. }
  432. ASSERT(INVALID_POSIX_OFFSET != offset);
  433. MapSidToOffset(DomainSid, offset);
  434. //
  435. // Do not free DomainSid -- there is still a reference to it in
  436. // the Sid-Offset cache (put there by MapSidToOffset).
  437. //
  438. LsaClose(PolicyHandle);
  439. LsaClose(TrustedDomainHandle);
  440. return offset | RelativeId;
  441. }
  442. typedef struct _SID_AND_OFFSET {
  443. LIST_ENTRY Links;
  444. PSID Sid;
  445. ULONG Offset;
  446. } SID_AND_OFFSET, *PSID_AND_OFFSET;
  447. LIST_ENTRY SidList;
  448. RTL_CRITICAL_SECTION SidListMutex;
  449. //
  450. // GetOffsetBySid -- search the SidList for the given Sid. If we've
  451. // encountered this domain before, we'll know the Posix offset,
  452. // which is returned. If not, INVALID_POSIX_OFFSET is returned.
  453. //
  454. ULONG
  455. GetOffsetBySid(PSID Sid)
  456. {
  457. PSID_AND_OFFSET pSO;
  458. ULONG Offset = INVALID_POSIX_OFFSET;
  459. RtlEnterCriticalSection(&SidListMutex);
  460. for (pSO = (PSID_AND_OFFSET)SidList.Flink;
  461. pSO != (PSID_AND_OFFSET)&SidList;
  462. pSO = (PSID_AND_OFFSET)pSO->Links.Flink) {
  463. if (RtlEqualSid(Sid, pSO->Sid)) {
  464. Offset = pSO->Offset;
  465. break;
  466. }
  467. }
  468. RtlLeaveCriticalSection(&SidListMutex);
  469. return Offset;
  470. }
  471. //
  472. // GetSidByOffset -- search the SidList for the given offset. Called in
  473. // the process of converting a uid or gid to a Sid, as in getpwuid().
  474. //
  475. PSID
  476. GetSidByOffset(ULONG Offset)
  477. {
  478. PSID_AND_OFFSET pSO;
  479. PSID Sid = NULL;
  480. RtlEnterCriticalSection(&SidListMutex);
  481. for (pSO = (PSID_AND_OFFSET)SidList.Flink;
  482. pSO != (PSID_AND_OFFSET)&SidList;
  483. pSO = (PSID_AND_OFFSET)pSO->Links.Flink) {
  484. if (Offset == pSO->Offset) {
  485. Sid = pSO->Sid;
  486. break;
  487. }
  488. }
  489. RtlLeaveCriticalSection(&SidListMutex);
  490. return Sid;
  491. }
  492. //
  493. // MapSidToOffset -- add the given sid and offset to the cache. If there's
  494. // an error, like no memory, it's simply dropped on the floor.
  495. //
  496. VOID
  497. MapSidToOffset(PSID Sid, ULONG Offset)
  498. {
  499. PSID_AND_OFFSET pSO;
  500. pSO = RtlAllocateHeap(PsxHeap, 0, sizeof(*pSO));
  501. if (NULL == pSO) {
  502. return;
  503. }
  504. pSO->Sid = Sid;
  505. pSO->Offset = Offset;
  506. RtlEnterCriticalSection(&SidListMutex);
  507. InsertHeadList(&SidList, &pSO->Links);
  508. RtlLeaveCriticalSection(&SidListMutex);
  509. }
  510. //
  511. // InitSidList -- do initialization, including mapping special Sids to
  512. // their appropriate offsets. No locking is done, assumed to be
  513. // called in a single-threaded way.
  514. //
  515. VOID
  516. InitSidList(VOID)
  517. {
  518. NTSTATUS Status;
  519. PSID Sid;
  520. SID_IDENTIFIER_AUTHORITY
  521. AuthSec = SECURITY_NT_AUTHORITY,
  522. Auth0 = SECURITY_NULL_SID_AUTHORITY,
  523. Auth1 = SECURITY_WORLD_SID_AUTHORITY,
  524. Auth2 = SECURITY_LOCAL_SID_AUTHORITY,
  525. Auth3 = SECURITY_CREATOR_SID_AUTHORITY,
  526. Auth4 = SECURITY_NON_UNIQUE_AUTHORITY,
  527. Auth5 = SECURITY_NT_AUTHORITY;
  528. RtlInitializeCriticalSection(&SidListMutex);
  529. InitializeListHead(&SidList);
  530. Status = RtlAllocateAndInitializeSid(&Auth0, 0,
  531. 0, 0, 0, 0, 0, 0, 0, 0, &Sid);
  532. ASSERT(NT_SUCCESS(Status));
  533. MapSidToOffset(Sid, SE_NULL_POSIX_ID);
  534. Status = RtlAllocateAndInitializeSid(&Auth1, 0,
  535. 0, 0, 0, 0, 0, 0, 0, 0, &Sid);
  536. ASSERT(NT_SUCCESS(Status));
  537. MapSidToOffset(Sid, SE_WORLD_POSIX_ID);
  538. Status = RtlAllocateAndInitializeSid(&Auth2, 0,
  539. 0, 0, 0, 0, 0, 0, 0, 0, &Sid);
  540. ASSERT(NT_SUCCESS(Status));
  541. MapSidToOffset(Sid, SE_LOCAL_POSIX_ID);
  542. Status = RtlAllocateAndInitializeSid(&Auth3, 0,
  543. 0, 0, 0, 0, 0, 0, 0, 0, &Sid);
  544. ASSERT(NT_SUCCESS(Status));
  545. MapSidToOffset(Sid, SE_CREATOR_OWNER_POSIX_ID);
  546. Status = RtlAllocateAndInitializeSid(&Auth4, 0,
  547. 0, 0, 0, 0, 0, 0, 0, 0, &Sid);
  548. ASSERT(NT_SUCCESS(Status));
  549. MapSidToOffset(Sid, SE_NON_UNIQUE_POSIX_ID);
  550. Status = RtlAllocateAndInitializeSid(&Auth5, 0,
  551. 0, 0, 0, 0, 0, 0, 0, 0, &Sid);
  552. ASSERT(NT_SUCCESS(Status));
  553. MapSidToOffset(Sid, SE_AUTHORITY_POSIX_ID);
  554. //
  555. // "Builtin" domain has known offset.
  556. //
  557. Status = RtlAllocateAndInitializeSid(&AuthSec, 1,
  558. SECURITY_BUILTIN_DOMAIN_RID, 0, 0, 0, 0, 0, 0, 0, &Sid);
  559. ASSERT(NT_SUCCESS(Status));
  560. MapSidToOffset(Sid, SE_BUILT_IN_DOMAIN_POSIX_OFFSET);
  561. }
  562. //
  563. // AccessMaskToMode -- convert a set of NT ACCESS_MASKS to the POSIX
  564. // mode_t.
  565. //
  566. mode_t
  567. AccessMaskToMode(
  568. ACCESS_MASK UserAccess,
  569. ACCESS_MASK GroupAccess,
  570. ACCESS_MASK OtherAccess
  571. )
  572. {
  573. mode_t Mode = 0;
  574. int i;
  575. PACCESS_MASK pAM;
  576. //
  577. // Make sure that if a GENERIC_ACCESS is set, we notice that
  578. // the mask implies FILE_GENERIC_ACCESS.
  579. //
  580. for (i = 0; i < 3; ++i) {
  581. switch (i) {
  582. case 0:
  583. pAM = &UserAccess;
  584. break;
  585. case 1:
  586. pAM = &GroupAccess;
  587. break;
  588. case 2:
  589. pAM = &OtherAccess;
  590. break;
  591. }
  592. if (*pAM & GENERIC_READ) {
  593. *pAM |= FILE_GENERIC_READ;
  594. }
  595. if (*pAM & GENERIC_WRITE) {
  596. *pAM |= FILE_GENERIC_WRITE;
  597. }
  598. if (*pAM & GENERIC_EXECUTE) {
  599. *pAM |= FILE_GENERIC_EXECUTE;
  600. }
  601. if (*pAM & GENERIC_ALL) {
  602. *pAM |= FILE_ALL_ACCESS;
  603. }
  604. }
  605. if (UserAccess & FILE_READ_DATA) {
  606. Mode |= S_IRUSR;
  607. }
  608. if ((UserAccess & FILE_WRITE_DATA) &&
  609. (UserAccess & FILE_APPEND_DATA)) {
  610. Mode |= S_IWUSR;
  611. }
  612. if (UserAccess & FILE_EXECUTE) {
  613. Mode |= S_IXUSR;
  614. }
  615. if (GroupAccess & FILE_READ_DATA) {
  616. Mode |= S_IRGRP;
  617. }
  618. if ((GroupAccess & FILE_WRITE_DATA) &&
  619. (GroupAccess & FILE_APPEND_DATA)) {
  620. Mode |= S_IWGRP;
  621. }
  622. if (GroupAccess & FILE_EXECUTE) {
  623. Mode |= S_IXGRP;
  624. }
  625. if (OtherAccess & FILE_READ_DATA) {
  626. Mode |= S_IROTH;
  627. }
  628. if ((OtherAccess & FILE_WRITE_DATA) &&
  629. (OtherAccess & FILE_APPEND_DATA)) {
  630. Mode |= S_IWOTH;
  631. }
  632. if (OtherAccess & FILE_EXECUTE) {
  633. Mode |= S_IXOTH;
  634. }
  635. return Mode;
  636. }
  637. void
  638. ModeToAccessMask(
  639. mode_t Mode,
  640. PACCESS_MASK pUserAccess,
  641. PACCESS_MASK pGroupAccess,
  642. PACCESS_MASK pOtherAccess
  643. )
  644. {
  645. //
  646. // All ACL's have these standard permissions:
  647. // READ_ATTR and READ_EA so anybody can access() any file.
  648. //
  649. *pUserAccess = SYNCHRONIZE |
  650. READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA;
  651. *pGroupAccess = *pOtherAccess = *pUserAccess;
  652. //
  653. // The owner always gets WRITE_DAC (for chmod), FILE_WRITE_ATTR
  654. // (for utimes), and WRITE_OWNER (for chgrp).
  655. //
  656. *pUserAccess |= (WRITE_DAC | WRITE_OWNER | FILE_WRITE_ATTRIBUTES);
  657. if (Mode & S_IRUSR) {
  658. *pUserAccess |= FILE_GENERIC_READ | FILE_LIST_DIRECTORY;
  659. }
  660. if (Mode & S_IWUSR) {
  661. *pUserAccess |= FILE_GENERIC_WRITE | FILE_DELETE_CHILD;
  662. }
  663. if (Mode & S_IXUSR) {
  664. *pUserAccess |= FILE_GENERIC_EXECUTE;
  665. }
  666. if (Mode & S_IRGRP) {
  667. *pGroupAccess |= FILE_GENERIC_READ | FILE_LIST_DIRECTORY;
  668. }
  669. if (Mode & S_IWGRP) {
  670. *pGroupAccess |= FILE_GENERIC_WRITE | FILE_DELETE_CHILD;
  671. }
  672. if (Mode & S_IXGRP) {
  673. *pGroupAccess |= FILE_GENERIC_EXECUTE;
  674. }
  675. if (Mode & S_IROTH) {
  676. *pOtherAccess |= FILE_GENERIC_READ | FILE_LIST_DIRECTORY;
  677. }
  678. if (Mode & S_IWOTH) {
  679. *pOtherAccess |= FILE_GENERIC_WRITE | FILE_DELETE_CHILD;
  680. }
  681. if (Mode & S_IXOTH) {
  682. *pOtherAccess |= FILE_GENERIC_EXECUTE;
  683. }
  684. }