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.

1256 lines
27 KiB

  1. /*--
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. sysdb.c
  5. Abstract:
  6. System database access routines.
  7. Author:
  8. Matthew Bradburn (mattbr) 04-Mar-1992
  9. Revision History:
  10. --*/
  11. #include "psxsrv.h"
  12. #include "psxmsg.h"
  13. #include <pwd.h>
  14. #include <grp.h>
  15. #include <ntsam.h>
  16. #include <ntlsa.h>
  17. #include <seposix.h>
  18. #include <ctype.h>
  19. #define UNICODE
  20. #include <windef.h>
  21. #include <winbase.h>
  22. static NTSTATUS
  23. PutUserInfo(
  24. PSID DomainSid,
  25. SAM_HANDLE DomainHandle,
  26. ULONG UserId,
  27. PCHAR DataDest,
  28. OUT int *pLength
  29. );
  30. static VOID
  31. PutSpecialUserInfo(
  32. PUNICODE_STRING Name,
  33. PCHAR DataDest,
  34. uid_t Uid,
  35. OUT int *pLength
  36. );
  37. static NTSTATUS
  38. PutGroupInfo(
  39. PSID DomainSid,
  40. SAM_HANDLE DomainHandle,
  41. ULONG GroupId,
  42. PCHAR DataDest,
  43. IN SID_NAME_USE Type,
  44. OUT int *pLength
  45. );
  46. static VOID
  47. PutSpecialGroupInfo(
  48. PUNICODE_STRING Name,
  49. PCHAR DataDest,
  50. gid_t Gid,
  51. OUT int *pLength
  52. );
  53. static BOOLEAN
  54. ConvertPathToPsx(
  55. ANSI_STRING *A
  56. );
  57. PSID
  58. GetSpecialSid(
  59. uid_t Uid
  60. );
  61. NTSTATUS
  62. MySamConnect(
  63. IN PSID DomainSid, // NULL if domain unknown
  64. OUT PSAM_HANDLE ServerHandle
  65. )
  66. {
  67. SECURITY_QUALITY_OF_SERVICE
  68. SecurityQoS;
  69. OBJECT_ATTRIBUTES
  70. Obj;
  71. NTSTATUS
  72. Status;
  73. LSA_HANDLE
  74. TrustedDomainHandle,
  75. PolicyHandle;
  76. PTRUSTED_CONTROLLERS_INFO
  77. pBuf;
  78. ULONG i;
  79. SecurityQoS.ImpersonationLevel = SecurityIdentification;
  80. SecurityQoS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  81. SecurityQoS.EffectiveOnly = TRUE;
  82. InitializeObjectAttributes(&Obj, NULL, 0, NULL, NULL);
  83. Obj.SecurityQualityOfService = &SecurityQoS;
  84. if (NULL == DomainSid) {
  85. Status = SamConnect(NULL, ServerHandle,
  86. GENERIC_READ | GENERIC_EXECUTE, &Obj);
  87. if (!NT_SUCCESS(Status)) {
  88. KdPrint(("PSXSS: Can't connect to SAM: 0x%x\n",
  89. Status));
  90. }
  91. return Status;
  92. }
  93. Status = LsaOpenPolicy(NULL, &Obj, GENERIC_EXECUTE, &PolicyHandle);
  94. if (!NT_SUCCESS(Status)) {
  95. KdPrint(("PSXSS: MySamConnect: LsaOpenPolicy: 0x%x\n", Status));
  96. return Status;
  97. }
  98. Status = LsaOpenTrustedDomain(PolicyHandle, DomainSid,
  99. GENERIC_READ | GENERIC_EXECUTE,
  100. &TrustedDomainHandle);
  101. if (!NT_SUCCESS(Status)) {
  102. LsaClose(PolicyHandle);
  103. Status = SamConnect(NULL, ServerHandle,
  104. GENERIC_READ | GENERIC_EXECUTE, &Obj);
  105. if (!NT_SUCCESS(Status)) {
  106. KdPrint(("PSXSS: Can't connect to SAM: 0x%x\n",
  107. Status));
  108. }
  109. return Status;
  110. }
  111. Status = LsaQueryInfoTrustedDomain(TrustedDomainHandle,
  112. TrustedControllersInformation, (PVOID *)&pBuf);
  113. LsaClose(PolicyHandle);
  114. LsaClose(TrustedDomainHandle);
  115. if (!NT_SUCCESS(Status)) {
  116. KdPrint(("PSXSS: MySamConnect: LsaQueryInfoTrusted: 0x%x\n",
  117. Status));
  118. return Status;
  119. }
  120. for (i = 0; i < pBuf->Entries; ++i) {
  121. if (0 == pBuf->Names[i].Length) {
  122. // the null string signifies domain controller unknown
  123. continue;
  124. }
  125. Status = SamConnect(&pBuf->Names[i], ServerHandle,
  126. GENERIC_READ | GENERIC_EXECUTE, &Obj);
  127. if (NT_SUCCESS(Status)) {
  128. // found an acceptable choice
  129. LsaFreeMemory(pBuf);
  130. return Status;
  131. }
  132. }
  133. LsaFreeMemory(pBuf);
  134. //
  135. // If there were no acceptable domain controllers, we try the
  136. // machine domain
  137. //
  138. Status = SamConnect(NULL, ServerHandle, GENERIC_EXECUTE, &Obj);
  139. if (!NT_SUCCESS(Status)) {
  140. KdPrint(("PSXSS: Can't connect to SAM: 0x%x\n", Status));
  141. }
  142. return Status;
  143. }
  144. NTSTATUS
  145. GetMyAccountDomainName(
  146. PUNICODE_STRING Domain_U
  147. )
  148. {
  149. NTSTATUS Status;
  150. OBJECT_ATTRIBUTES Obj;
  151. SECURITY_QUALITY_OF_SERVICE SecurityQoS;
  152. LSA_HANDLE PolicyHandle;
  153. PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo;
  154. SecurityQoS.ImpersonationLevel = SecurityIdentification;
  155. SecurityQoS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  156. SecurityQoS.EffectiveOnly = TRUE;
  157. InitializeObjectAttributes(&Obj, NULL, 0, NULL, NULL);
  158. Obj.SecurityQualityOfService = &SecurityQoS;
  159. Status = LsaOpenPolicy(NULL, &Obj, GENERIC_EXECUTE, &PolicyHandle);
  160. if (!NT_SUCCESS(Status)) {
  161. return Status;
  162. }
  163. Status = LsaQueryInformationPolicy(PolicyHandle,
  164. PolicyAccountDomainInformation, (PVOID *)&AccountDomainInfo);
  165. if (!NT_SUCCESS(Status)) {
  166. LsaClose(PolicyHandle);
  167. return Status;
  168. }
  169. LsaClose(PolicyHandle);
  170. Domain_U->MaximumLength = AccountDomainInfo->DomainName.MaximumLength;
  171. Domain_U->Buffer = RtlAllocateHeap(PsxHeap, 0,
  172. Domain_U->MaximumLength);
  173. if (NULL == Domain_U->Buffer) {
  174. return STATUS_NO_MEMORY;
  175. }
  176. RtlCopyUnicodeString(Domain_U, &AccountDomainInfo->DomainName);
  177. LsaFreeMemory(AccountDomainInfo);
  178. return STATUS_SUCCESS;
  179. }
  180. BOOLEAN
  181. PsxGetPwUid(
  182. IN PPSX_PROCESS p,
  183. IN PPSX_API_MSG m
  184. )
  185. {
  186. NTSTATUS Status;
  187. PPSX_GETPWUID_MSG args;
  188. PSID DomainSid;
  189. SAM_HANDLE
  190. ServerHandle = NULL,
  191. DomainHandle = NULL;
  192. LSA_HANDLE
  193. PolicyHandle = NULL;
  194. PSID Sid = NULL;
  195. OBJECT_ATTRIBUTES Obj;
  196. SECURITY_QUALITY_OF_SERVICE SecurityQoS;
  197. PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains;
  198. PLSA_TRANSLATED_NAME Names;
  199. args = &m->u.GetPwUid;
  200. if (SE_NULL_POSIX_ID == (args->Uid & 0xFFFF0000)) {
  201. // Special case for universal well-known sids and nt
  202. // ... well-known sids.
  203. Sid = GetSpecialSid(args->Uid);
  204. if (NULL == Sid) {
  205. m->Error = 1;
  206. return TRUE;
  207. }
  208. goto TryLsa;
  209. }
  210. DomainSid = GetSidByOffset(args->Uid & 0xFFFF0000);
  211. if (NULL == DomainSid) {
  212. m->Error = 1;
  213. return TRUE;
  214. }
  215. Status = MySamConnect(DomainSid, &ServerHandle);
  216. if (!NT_SUCCESS(Status)) {
  217. m->Error = 1;
  218. return TRUE;
  219. }
  220. Status = SamOpenDomain(ServerHandle, GENERIC_EXECUTE, DomainSid,
  221. &DomainHandle);
  222. if (NT_SUCCESS(Status)) {
  223. Status = PutUserInfo(DomainSid, DomainHandle,
  224. args->Uid & 0xFFFF,
  225. (PCHAR)args->PwBuf, &args->Length);
  226. if (NT_SUCCESS(Status)) {
  227. goto out;
  228. }
  229. }
  230. //
  231. // SAM can't find the name, so we'll try the LSA.
  232. //
  233. Sid = MakeSid(DomainSid, args->Uid & 0x0000FFFF);
  234. TryLsa:
  235. SecurityQoS.ImpersonationLevel = SecurityIdentification;
  236. SecurityQoS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  237. SecurityQoS.EffectiveOnly = TRUE;
  238. InitializeObjectAttributes(&Obj, NULL, 0, NULL, NULL);
  239. Obj.SecurityQualityOfService = &SecurityQoS;
  240. Status = LsaOpenPolicy(NULL, &Obj, GENERIC_EXECUTE, &PolicyHandle);
  241. if (!NT_SUCCESS(Status)) {
  242. m->Error = PsxStatusToErrno(Status);
  243. goto out;
  244. }
  245. Status = LsaLookupSids(PolicyHandle, 1, &Sid, &ReferencedDomains,
  246. &Names);
  247. if (NT_SUCCESS(Status)) {
  248. LsaFreeMemory((PVOID)ReferencedDomains);
  249. PutSpecialUserInfo(&Names->Name, (PCHAR)args->PwBuf,
  250. args->Uid, &args->Length);
  251. LsaFreeMemory((PVOID)Names);
  252. } else {
  253. UNICODE_STRING U;
  254. RtlConvertSidToUnicodeString(&U, Sid, TRUE);
  255. PutSpecialUserInfo(&U, (PCHAR)args->PwBuf, args->Uid,
  256. &args->Length);
  257. RtlFreeUnicodeString(&U);
  258. }
  259. out:
  260. if (NULL != Sid) RtlFreeHeap(PsxHeap, 0, (PVOID)Sid);
  261. if (NULL != ServerHandle) SamCloseHandle(ServerHandle);
  262. if (NULL != DomainHandle) SamCloseHandle(DomainHandle);
  263. if (NULL != PolicyHandle) LsaClose(PolicyHandle);
  264. return TRUE;
  265. }
  266. BOOLEAN
  267. PsxGetPwNam(
  268. IN PPSX_PROCESS p,
  269. IN PPSX_API_MSG m
  270. )
  271. {
  272. PPSX_GETPWNAM_MSG args;
  273. NTSTATUS Status;
  274. UNICODE_STRING
  275. Name_U, // the user's name in unicode
  276. Domain_U; // the name of the account domain
  277. ANSI_STRING
  278. Name_A; // the user's name in Ansi
  279. PULONG pUserId = NULL; // the relative offset for the user
  280. SAM_HANDLE
  281. ServerHandle = NULL,
  282. DomainHandle = NULL;
  283. PSID_NAME_USE
  284. pUse;
  285. PSID DomainSid = NULL;
  286. WCHAR ComputerNameBuf[32 + 1];
  287. ULONG Len = 32 + 1;
  288. Name_U.Buffer = NULL;
  289. args = &m->u.GetPwNam;
  290. Status = MySamConnect(DomainSid, &ServerHandle);
  291. if (!NT_SUCCESS(Status)) {
  292. m->Error = 1;
  293. return TRUE;
  294. }
  295. //
  296. // Find the name of the local machine -- we look there for
  297. // the name being requested.
  298. //
  299. if (!GetComputerName(ComputerNameBuf, &Len)) {
  300. KdPrint(("PSXSS: GetComputerName: 0x%x\n", GetLastError()));
  301. m->Error = 1;
  302. goto out;
  303. }
  304. RtlInitUnicodeString(&Domain_U, ComputerNameBuf);
  305. Status = SamLookupDomainInSamServer(ServerHandle, &Domain_U,
  306. &DomainSid);
  307. if (!NT_SUCCESS(Status)) {
  308. KdPrint(("PSXSS: Can't lookup domain: 0x%x\n", Status));
  309. //
  310. // If the "machinename" domain didn't work, try the
  311. // account domain.
  312. //
  313. Status = GetMyAccountDomainName(&Domain_U);
  314. if (!NT_SUCCESS(Status)) {
  315. m->Error = 1;
  316. goto out;
  317. }
  318. Status = SamLookupDomainInSamServer(ServerHandle, &Domain_U,
  319. &DomainSid);
  320. RtlFreeHeap(PsxHeap, 0, (PVOID)Domain_U.Buffer);
  321. if (!NT_SUCCESS(Status)) {
  322. KdPrint(("PSXSS: Can't lookup acct domain: 0x%x\n", Status));
  323. m->Error = 1;
  324. goto out;
  325. }
  326. }
  327. Status = SamOpenDomain(ServerHandle, GENERIC_EXECUTE, DomainSid,
  328. &DomainHandle);
  329. if (!NT_SUCCESS(Status)) {
  330. m->Error = 1;
  331. goto out;
  332. }
  333. RtlInitAnsiString(&Name_A, args->Name);
  334. Status = RtlAnsiStringToUnicodeString(&Name_U, &Name_A, TRUE);
  335. if (!NT_SUCCESS(Status)) {
  336. m->Error = ENOMEM;
  337. goto out;
  338. }
  339. Status = SamLookupNamesInDomain(DomainHandle, 1, &Name_U, &pUserId,
  340. &pUse);
  341. if (!NT_SUCCESS(Status)) {
  342. m->Error = ENOENT;
  343. goto out;
  344. }
  345. // Make sure the name is a user name.
  346. if (*pUse != SidTypeUser) {
  347. SamFreeMemory(pUse);
  348. KdPrint(("PSXSS: Group name is type %d\n", *pUse));
  349. m->Error = 1;
  350. goto out;
  351. }
  352. SamFreeMemory(pUse);
  353. Status = PutUserInfo(DomainSid, DomainHandle, *pUserId,
  354. (PCHAR)args->PwBuf, &args->Length);
  355. if (!NT_SUCCESS(Status)) {
  356. m->Error = 1;
  357. }
  358. out:
  359. if (NULL != ServerHandle) {
  360. SamCloseHandle(ServerHandle);
  361. }
  362. if (NULL != DomainHandle) {
  363. SamCloseHandle(DomainHandle);
  364. }
  365. if (NULL != Name_U.Buffer) {
  366. RtlFreeUnicodeString(&Name_U);
  367. }
  368. if (NULL != pUserId) {
  369. SamFreeMemory(pUserId);
  370. }
  371. if (NULL != DomainSid) {
  372. SamFreeMemory(DomainSid);
  373. }
  374. return TRUE;
  375. }
  376. static VOID
  377. PutSpecialUserInfo(
  378. PUNICODE_STRING Name,
  379. PCHAR DataDest,
  380. uid_t Uid,
  381. OUT int *pLength
  382. )
  383. {
  384. PCHAR pch;
  385. struct passwd *pwd;
  386. ANSI_STRING A;
  387. pwd = (struct passwd *)DataDest;
  388. pwd->pw_uid = Uid;
  389. // Don't know what the gid should be, we use the uid.
  390. pwd->pw_gid = Uid;
  391. pch = DataDest + sizeof(struct passwd);
  392. pwd->pw_name = pch - (ULONG_PTR)DataDest;
  393. A.Buffer = pch;
  394. A.MaximumLength = NAME_MAX;
  395. RtlUnicodeStringToAnsiString(&A, Name, FALSE);
  396. pch += strlen(pch) + 1;
  397. pwd->pw_dir = pch - (ULONG_PTR)DataDest;
  398. strcpy(pch, "/");
  399. pch += strlen(pch) + 1;
  400. pwd->pw_shell = pch - (ULONG_PTR)DataDest;
  401. strcpy(pch, "noshell");
  402. pch += strlen(pch) + 1;
  403. *pLength = (int)((ULONG_PTR)pch - (ULONG_PTR)DataDest);
  404. }
  405. //
  406. // PutUserInfo -- place password database information about the user at
  407. // the specified data destination address.
  408. //
  409. static NTSTATUS
  410. PutUserInfo(
  411. PSID DomainSid,
  412. SAM_HANDLE DomainHandle,
  413. ULONG UserId,
  414. PCHAR DataDest,
  415. int *pLength
  416. )
  417. {
  418. SAM_HANDLE
  419. UserHandle = NULL;
  420. PUSER_ACCOUNT_INFORMATION
  421. AccountInfo = NULL;
  422. PSID Sid; // User Sid
  423. ULONG SpaceLeft;
  424. struct passwd *pwd;
  425. PCHAR pch;
  426. NTSTATUS Status;
  427. ANSI_STRING A;
  428. PCHAR pchPsxDir;
  429. Status = SamOpenUser(DomainHandle, GENERIC_READ | GENERIC_EXECUTE,
  430. UserId, &UserHandle);
  431. if (!NT_SUCCESS(Status)) {
  432. goto out;
  433. }
  434. Status = SamQueryInformationUser(UserHandle, UserAccountInformation,
  435. (PVOID *)&AccountInfo);
  436. if (!NT_SUCCESS(Status)) {
  437. KdPrint(("PSXSS: Can't query info user: 0x%x\n", Status));
  438. goto out;
  439. }
  440. pwd = (struct passwd *)DataDest;
  441. Sid = MakeSid(DomainSid, AccountInfo->UserId);
  442. if (NULL == Sid) {
  443. goto out;
  444. }
  445. pwd->pw_uid = MakePosixId(Sid);
  446. RtlFreeHeap(PsxHeap, 0, (PVOID)Sid);
  447. Sid = MakeSid(DomainSid, AccountInfo->PrimaryGroupId);
  448. if (NULL == Sid) {
  449. goto out;
  450. }
  451. pwd->pw_gid = MakePosixId(Sid);
  452. RtlFreeHeap(PsxHeap, 0, (PVOID)Sid);
  453. SpaceLeft = ARG_MAX - sizeof(struct passwd);
  454. pch = DataDest + sizeof(struct passwd);
  455. pwd->pw_name = pch - (ULONG_PTR)DataDest;
  456. A.Buffer = pch;
  457. A.MaximumLength = (USHORT)SpaceLeft;
  458. Status = RtlUnicodeStringToAnsiString(&A, &AccountInfo->UserName,
  459. FALSE);
  460. if (!NT_SUCCESS(Status)) {
  461. goto out;
  462. }
  463. SpaceLeft -= A.Length;
  464. pch = pch + A.Length + 1;
  465. pwd->pw_dir = pch - (ULONG_PTR)DataDest;
  466. A.Buffer = pch;
  467. A.MaximumLength = (USHORT)SpaceLeft;
  468. Status = RtlUnicodeStringToAnsiString(&A, &AccountInfo->HomeDirectory,
  469. FALSE);
  470. if (!NT_SUCCESS(Status)) {
  471. goto out;
  472. }
  473. if (!ConvertPathToPsx(&A)) {
  474. goto out;
  475. }
  476. SpaceLeft -= A.Length;
  477. if (SpaceLeft <= strlen("noshell")) {
  478. goto out;
  479. }
  480. pch = pch + A.Length + 1;
  481. pwd->pw_shell = pch - (ULONG_PTR)DataDest;
  482. strcpy(pch, "noshell");
  483. pch += strlen(pch) + 1;
  484. *pLength = (int)((ULONG_PTR)pch - (ULONG_PTR)DataDest);
  485. out:
  486. if (NULL != UserHandle) {
  487. SamCloseHandle(UserHandle);
  488. }
  489. if (NULL != AccountInfo) {
  490. SamFreeMemory(AccountInfo);
  491. }
  492. return Status;
  493. }
  494. BOOLEAN
  495. PsxGetGrGid(
  496. IN PPSX_PROCESS p,
  497. IN PPSX_API_MSG m
  498. )
  499. {
  500. NTSTATUS Status;
  501. PPSX_GETGRGID_MSG args;
  502. ULONG Gid;
  503. PSID DomainSid, GroupSid;
  504. SAM_HANDLE
  505. ServerHandle = NULL,
  506. DomainHandle = NULL;
  507. PLSA_REFERENCED_DOMAIN_LIST
  508. ReferencedDomains = NULL;
  509. PLSA_TRANSLATED_NAME
  510. Names = NULL;
  511. LSA_HANDLE PolicyHandle = NULL;
  512. OBJECT_ATTRIBUTES Obj;
  513. SECURITY_QUALITY_OF_SERVICE SecurityQoS;
  514. PSID Sid = NULL;
  515. args = &m->u.GetGrGid;
  516. Gid = args->Gid;
  517. if (0xFFF == Gid) {
  518. UNICODE_STRING U;
  519. //
  520. // This is a login group, which we'll just translate to
  521. // S-1-5-5-0-0
  522. //
  523. RtlInitUnicodeString(&U, L"S-1-5-5-0-0");
  524. PutSpecialGroupInfo(&U, (PCHAR)args->GrBuf, Gid,
  525. &args->Length);
  526. return TRUE;
  527. }
  528. if (SE_NULL_POSIX_ID == (Gid & 0xFFFF0000)) {
  529. // Special case for universal well-known sids and nt
  530. // ... well-known sids.
  531. Sid = GetSpecialSid(Gid);
  532. if (NULL == Sid) {
  533. m->Error = 1;
  534. return TRUE;
  535. }
  536. goto TryLsa;
  537. }
  538. DomainSid = GetSidByOffset(Gid & 0xFFFF0000);
  539. if (NULL == DomainSid) {
  540. m->Error = 1;
  541. return TRUE;
  542. }
  543. Status = MySamConnect(DomainSid, &ServerHandle);
  544. if (!NT_SUCCESS(Status)) {
  545. m->Error = 1;
  546. return TRUE;
  547. }
  548. Status = SamOpenDomain(ServerHandle, GENERIC_READ | GENERIC_EXECUTE,
  549. DomainSid, &DomainHandle);
  550. if (NT_SUCCESS(Status)) {
  551. //
  552. // Look for a group
  553. //
  554. Status = PutGroupInfo(DomainSid, DomainHandle, Gid & 0xFFFF,
  555. (PCHAR)args->GrBuf, SidTypeGroup,
  556. &args->Length);
  557. if (NT_SUCCESS(Status)) {
  558. goto out;
  559. }
  560. //
  561. // Try again, except look for an alias
  562. //
  563. Status = PutGroupInfo(DomainSid, DomainHandle, Gid & 0xFFFF,
  564. (PCHAR)args->GrBuf, SidTypeAlias, &args->Length);
  565. if (NT_SUCCESS(Status)) {
  566. goto out;
  567. }
  568. }
  569. //
  570. // Give up looking in SAM, ask LSA to identify.
  571. //
  572. Sid = MakeSid(DomainSid, Gid & 0x0000FFFF);
  573. TryLsa:
  574. SecurityQoS.ImpersonationLevel = SecurityIdentification;
  575. SecurityQoS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  576. SecurityQoS.EffectiveOnly = TRUE;
  577. InitializeObjectAttributes(&Obj, NULL, 0, NULL, NULL);
  578. Obj.SecurityQualityOfService = &SecurityQoS;
  579. Status = LsaOpenPolicy(NULL, &Obj, GENERIC_EXECUTE, &PolicyHandle);
  580. if (!NT_SUCCESS(Status)) {
  581. m->Error = PsxStatusToErrno(Status);
  582. goto out;
  583. }
  584. Status = LsaLookupSids(PolicyHandle, 1, &Sid, &ReferencedDomains,
  585. &Names);
  586. if (NT_SUCCESS(Status)) {
  587. LsaFreeMemory((PVOID)ReferencedDomains);
  588. PutSpecialGroupInfo(&Names->Name, (PCHAR)args->GrBuf, Gid,
  589. &args->Length);
  590. LsaFreeMemory((PVOID)Names);
  591. goto out;
  592. } else {
  593. UNICODE_STRING U;
  594. RtlConvertSidToUnicodeString(&U, Sid, TRUE);
  595. PutSpecialGroupInfo(&U, (PCHAR)args->GrBuf, Gid,
  596. &args->Length);
  597. RtlFreeUnicodeString(&U);
  598. goto out;
  599. }
  600. out:
  601. if (NULL != PolicyHandle) LsaClose(PolicyHandle);
  602. if (NULL != ServerHandle) SamCloseHandle(ServerHandle);
  603. if (NULL != DomainHandle) SamCloseHandle(DomainHandle);
  604. if (NULL != Sid) RtlFreeHeap(PsxHeap, 0, (PVOID)Sid);
  605. return TRUE;
  606. }
  607. BOOLEAN
  608. PsxGetGrNam(
  609. IN PPSX_PROCESS p,
  610. IN PPSX_API_MSG m
  611. )
  612. {
  613. PPSX_GETGRNAM_MSG args;
  614. NTSTATUS Status;
  615. UNICODE_STRING
  616. Name_U, // the group name in unicode
  617. Domain_U; // the name of the account domain
  618. ANSI_STRING
  619. Name_A; // the group name in Ansi
  620. PULONG pGroupId = NULL; // the relative offset for the group
  621. SAM_HANDLE
  622. ServerHandle = NULL,
  623. DomainHandle = NULL;
  624. PSID_NAME_USE
  625. pUse;
  626. PSID DomainSid = NULL,
  627. Sid = NULL;
  628. WCHAR ComputerNameBuf[32 + 1];
  629. ULONG Len = 32 + 1;
  630. SID_NAME_USE Type;
  631. Name_U.Buffer = NULL;
  632. args = &m->u.GetGrNam;
  633. Status = MySamConnect(DomainSid, &ServerHandle);
  634. if (!NT_SUCCESS(Status)) {
  635. m->Error = 1;
  636. return TRUE;
  637. }
  638. //
  639. // Find the name of the local machine -- we look here for
  640. // the name being requested.
  641. //
  642. if (!GetComputerName(ComputerNameBuf, &Len)) {
  643. KdPrint(("PSXSS: GetComputerName: 0x%x\n", GetLastError()));
  644. m->Error = 1;
  645. goto out;
  646. }
  647. RtlInitUnicodeString(&Domain_U, ComputerNameBuf);
  648. Status = SamLookupDomainInSamServer(ServerHandle, &Domain_U,
  649. &DomainSid);
  650. if (!NT_SUCCESS(Status)) {
  651. //
  652. // If the "machinename" domain didn't work, try the
  653. // account domain.
  654. //
  655. Status = GetMyAccountDomainName(&Domain_U);
  656. if (!NT_SUCCESS(Status)) {
  657. m->Error = 1;
  658. goto out;
  659. }
  660. Status = SamLookupDomainInSamServer(ServerHandle, &Domain_U,
  661. &DomainSid);
  662. RtlFreeHeap(PsxHeap, 0, (PVOID)Domain_U.Buffer);
  663. if (!NT_SUCCESS(Status)) {
  664. KdPrint(("PSXSS: Can't lookup acct domain: 0x%x\n", Status));
  665. m->Error = 1;
  666. goto out;
  667. }
  668. }
  669. Status = SamOpenDomain(ServerHandle, GENERIC_READ | GENERIC_EXECUTE,
  670. DomainSid, &DomainHandle);
  671. if (!NT_SUCCESS(Status)) {
  672. KdPrint(("PSXSS: Can't open domain: 0x%x\n", Status));
  673. m->Error = 1;
  674. goto out;
  675. }
  676. RtlInitAnsiString(&Name_A, args->Name);
  677. Status = RtlAnsiStringToUnicodeString(&Name_U, &Name_A, TRUE);
  678. if (!NT_SUCCESS(Status)) {
  679. m->Error = ENOMEM;
  680. goto out;
  681. }
  682. Status = SamLookupNamesInDomain(DomainHandle, 1, &Name_U, &pGroupId,
  683. &pUse);
  684. if (!NT_SUCCESS(Status)) {
  685. KdPrint(("PSXSS: Can't lookup name: 0x%x\n", Status));
  686. m->Error = 1;
  687. goto out;
  688. }
  689. // Make sure the name is a group name.
  690. Type = *pUse;
  691. SamFreeMemory(pUse);
  692. if (Type != SidTypeGroup && Type != SidTypeAlias) {
  693. m->Error = EINVAL;
  694. goto out;
  695. }
  696. Status = PutGroupInfo(DomainSid, DomainHandle, *pGroupId,
  697. (PCHAR)args->GrBuf, Type, &args->Length);
  698. out:
  699. if (NULL != ServerHandle) {
  700. SamCloseHandle(ServerHandle);
  701. }
  702. if (NULL != DomainHandle) {
  703. SamCloseHandle(DomainHandle);
  704. }
  705. if (NULL != Name_U.Buffer) {
  706. RtlFreeUnicodeString(&Name_U);
  707. }
  708. if (NULL != pGroupId) {
  709. SamFreeMemory(pGroupId);
  710. }
  711. if (NULL != DomainSid) {
  712. SamFreeMemory(DomainSid);
  713. }
  714. return TRUE;
  715. }
  716. static VOID
  717. PutSpecialGroupInfo(
  718. PUNICODE_STRING Name,
  719. PCHAR DataDest,
  720. gid_t Gid,
  721. OUT int *pLength
  722. )
  723. {
  724. struct group *grp;
  725. PCHAR pch, *ppchMem;
  726. ANSI_STRING A;
  727. //
  728. // The struct group goes at the beginning of the view memory,
  729. // followed by the array of member name pointers.
  730. //
  731. grp = (struct group *)DataDest;
  732. ppchMem = (PCHAR *)((PCHAR)DataDest + sizeof(struct group));
  733. grp->gr_mem = (PCHAR *)((PCHAR)ppchMem - (ULONG_PTR)DataDest);
  734. grp->gr_gid = Gid;
  735. // No members.
  736. ppchMem[0] = NULL;
  737. pch = (PCHAR)(ppchMem + 1);
  738. grp->gr_name = pch - (ULONG_PTR)DataDest;
  739. A.Buffer = pch;
  740. A.MaximumLength = NAME_MAX;
  741. RtlUnicodeStringToAnsiString(&A, Name, FALSE);
  742. pch += strlen(pch) + 1;
  743. *pLength = (int)((ULONG_PTR)(pch - (ULONG_PTR)DataDest));
  744. }
  745. NTSTATUS
  746. GetUserNameFromSid(
  747. PSID Sid,
  748. PANSI_STRING pA)
  749. {
  750. ULONG SubAuthCount;
  751. ULONG RelativeId;
  752. PSID DomainSid = NULL;
  753. SAM_HANDLE
  754. ServerHandle = NULL,
  755. DomainHandle = NULL,
  756. UserHandle = NULL;
  757. PUSER_ACCOUNT_INFORMATION
  758. AccountInfo = NULL;
  759. NTSTATUS Status = STATUS_SUCCESS;
  760. SubAuthCount = *RtlSubAuthorityCountSid(Sid);
  761. RelativeId = *RtlSubAuthoritySid(Sid, SubAuthCount - 1);
  762. DomainSid = RtlAllocateHeap(PsxHeap, 0, RtlLengthSid(Sid));
  763. if (NULL == DomainSid) {
  764. goto out;
  765. }
  766. Status = RtlCopySid(RtlLengthSid(Sid), DomainSid, Sid);
  767. ASSERT(NT_SUCCESS(Status));
  768. --*RtlSubAuthorityCountSid(DomainSid);
  769. Status = MySamConnect(DomainSid, &ServerHandle);
  770. if (!NT_SUCCESS(Status)) {
  771. goto out;
  772. }
  773. Status = SamOpenDomain(ServerHandle, GENERIC_EXECUTE,
  774. DomainSid, &DomainHandle);
  775. if (!NT_SUCCESS(Status)) {
  776. goto out;
  777. }
  778. Status = SamOpenUser(DomainHandle, GENERIC_READ | GENERIC_EXECUTE,
  779. RelativeId, &UserHandle);
  780. if (!NT_SUCCESS(Status)) {
  781. goto out;
  782. }
  783. Status = SamQueryInformationUser(UserHandle, UserAccountInformation,
  784. (PVOID *)&AccountInfo);
  785. if (!NT_SUCCESS(Status)) {
  786. goto out;
  787. }
  788. Status = RtlUnicodeStringToAnsiString(pA, &AccountInfo->UserName, FALSE);
  789. out:
  790. if (NULL != DomainSid) RtlFreeHeap(PsxHeap, 0, DomainSid);
  791. if (NULL != ServerHandle) SamCloseHandle(ServerHandle);
  792. if (NULL != DomainHandle) SamCloseHandle(DomainHandle);
  793. if (NULL != UserHandle) SamCloseHandle(UserHandle);
  794. if (NULL != AccountInfo) SamFreeMemory(AccountInfo);
  795. return Status;
  796. }
  797. static NTSTATUS
  798. PutGroupInfo(
  799. PSID DomainSid,
  800. SAM_HANDLE DomainHandle,
  801. ULONG GroupId,
  802. PCHAR DataDest,
  803. IN SID_NAME_USE Type,
  804. OUT int *pLength
  805. )
  806. {
  807. ANSI_STRING
  808. A; // misc. ansi strings
  809. PGROUP_NAME_INFORMATION
  810. NameInfo = NULL;
  811. ULONG SpaceLeft,
  812. count,
  813. i;
  814. struct group *grp;
  815. PCHAR pch, *ppchMem;
  816. PSID Sid;
  817. NTSTATUS Status;
  818. SAM_HANDLE GroupHandle = NULL;
  819. PULONG
  820. puGroupMem = NULL, // array of group members' relative id's
  821. puAttr = NULL; // array of group members' attributes
  822. PSID
  823. *ppsGroupMem = NULL; // array of alias members' relative id's
  824. //
  825. // The struct group goes at the beginning of the view memory,
  826. // followed by the array of member name pointers.
  827. //
  828. grp = (struct group *)DataDest;
  829. ppchMem = (PCHAR *)((PCHAR)DataDest + sizeof(struct group));
  830. grp->gr_mem = (PCHAR *)((PCHAR)ppchMem - (ULONG_PTR)DataDest);
  831. Sid = MakeSid(DomainSid, GroupId);
  832. if (NULL == Sid) {
  833. goto out;
  834. }
  835. grp->gr_gid = MakePosixId(Sid);
  836. RtlFreeHeap(PsxHeap, 0, Sid);
  837. if (SidTypeGroup == Type) {
  838. Status = SamOpenGroup(DomainHandle,
  839. GENERIC_READ | GENERIC_EXECUTE,
  840. GroupId, &GroupHandle);
  841. if (!NT_SUCCESS(Status)) {
  842. goto out;
  843. }
  844. Status = SamGetMembersInGroup(GroupHandle, &puGroupMem,
  845. &puAttr, &count);
  846. if (!NT_SUCCESS(Status)) {
  847. goto out;
  848. }
  849. Status = SamQueryInformationGroup(GroupHandle,
  850. GroupNameInformation, (PVOID *)&NameInfo);
  851. if (!NT_SUCCESS(Status)) {
  852. KdPrint(("PSXSS: Can't query info group: 0x%x\n",
  853. Status));
  854. goto out;
  855. }
  856. } else {
  857. Status = SamOpenAlias(DomainHandle,
  858. GENERIC_READ | GENERIC_EXECUTE,
  859. GroupId, &GroupHandle);
  860. if (!NT_SUCCESS(Status)) {
  861. goto out;
  862. }
  863. Status = SamGetMembersInAlias(GroupHandle, &ppsGroupMem,
  864. &count);
  865. if (!NT_SUCCESS(Status)) {
  866. goto out;
  867. }
  868. Status = SamQueryInformationAlias(GroupHandle,
  869. AliasNameInformation, (PVOID *)&NameInfo);
  870. if (!NT_SUCCESS(Status)) {
  871. KdPrint(("PSXSS: Can't query info alias: 0x%x\n",
  872. Status));
  873. goto out;
  874. }
  875. }
  876. //
  877. // The strings start after the member name pointer array. We leave
  878. // an extra member name pointer for the null-terminator.
  879. //
  880. pch = (PCHAR)(ppchMem + 1 + count);
  881. SpaceLeft = (ULONG)(PSX_CLIENT_PORT_MEMORY_SIZE -
  882. (ULONG_PTR)(pch - (ULONG_PTR)DataDest));
  883. grp->gr_name = pch - (ULONG_PTR)DataDest;
  884. A.Buffer = pch;
  885. A.MaximumLength = (USHORT)SpaceLeft;
  886. Status = RtlUnicodeStringToAnsiString(&A, &NameInfo->Name, FALSE);
  887. if (!NT_SUCCESS(Status)) {
  888. goto out;
  889. }
  890. SpaceLeft -= A.Length;
  891. pch = pch + A.Length + 1;
  892. for (i = 0; i < count; ++i) {
  893. SAM_HANDLE UserHandle;
  894. PUSER_ACCOUNT_NAME_INFORMATION pUserInfo;
  895. ppchMem[i] = pch - (ULONG_PTR)DataDest;
  896. A.Buffer = pch;
  897. A.MaximumLength = (USHORT)SpaceLeft;
  898. if (Type == SidTypeGroup) {
  899. Status = SamOpenUser(DomainHandle,
  900. GENERIC_READ | GENERIC_EXECUTE,
  901. puGroupMem[i], &UserHandle);
  902. if (!NT_SUCCESS(Status)) {
  903. KdPrint(("PSXSS: SamOpenUser: 0x%x\n", Status));
  904. continue;
  905. }
  906. Status = SamQueryInformationUser(UserHandle,
  907. UserAccountNameInformation,
  908. (PVOID *)&pUserInfo);
  909. if (!NT_SUCCESS(Status)) {
  910. KdPrint(("PSXSS: SamQueryInfoUser: 0x%x\n",
  911. Status));
  912. }
  913. ASSERT(NT_SUCCESS(Status));
  914. Status = SamCloseHandle(UserHandle);
  915. if (!NT_SUCCESS(Status)) {
  916. KdPrint(("PSXSS: SamCloseHandle: 0x%x\n",
  917. Status));
  918. }
  919. ASSERT(NT_SUCCESS(Status));
  920. RtlUnicodeStringToAnsiString(&A,
  921. &pUserInfo->UserName, FALSE);
  922. SamFreeMemory(pUserInfo);
  923. } else {
  924. Status = GetUserNameFromSid(ppsGroupMem[i], &A);
  925. if (!NT_SUCCESS(Status)) {
  926. continue;
  927. }
  928. }
  929. SpaceLeft -= A.Length;
  930. pch = pch + A.Length + 1;
  931. }
  932. ppchMem[i] = NULL;
  933. *pLength = (int)((ULONG_PTR)(pch - (ULONG_PTR)DataDest));
  934. SamCloseHandle(GroupHandle);
  935. return STATUS_SUCCESS;
  936. out:
  937. if (NULL != GroupHandle) {
  938. SamCloseHandle(GroupHandle);
  939. }
  940. if (NULL != puGroupMem) {
  941. SamFreeMemory(puGroupMem);
  942. }
  943. if (NULL != ppsGroupMem) {
  944. SamFreeMemory(ppsGroupMem);
  945. }
  946. if (NULL != puAttr) {
  947. SamFreeMemory(puAttr);
  948. }
  949. if (NULL != NameInfo) {
  950. SamFreeMemory(NameInfo);
  951. }
  952. return STATUS_BUFFER_TOO_SMALL;
  953. }
  954. //
  955. // MakeSid -- Attach the given relative id to the given Domain Sid to
  956. // make a new Sid, and return it. That new sid must be freed with
  957. // RtlFreeHeap.
  958. //
  959. PSID
  960. MakeSid(
  961. PSID DomainSid,
  962. ULONG RelativeId
  963. )
  964. {
  965. PSID NewSid;
  966. NTSTATUS Status;
  967. UCHAR AuthCount;
  968. int i;
  969. AuthCount = *RtlSubAuthorityCountSid(DomainSid) + 1;
  970. NewSid = RtlAllocateHeap(PsxHeap, 0, RtlLengthRequiredSid(AuthCount));
  971. if (NULL == NewSid) {
  972. return NULL;
  973. }
  974. Status = RtlInitializeSid(NewSid, RtlIdentifierAuthoritySid(DomainSid),
  975. AuthCount);
  976. if (!NT_SUCCESS(Status)) {
  977. KdPrint(("PSXSS: 0x%x\n", Status));
  978. }
  979. ASSERT(NT_SUCCESS(Status));
  980. //
  981. // Copy the Domain Sid.
  982. //
  983. for (i = 0; i < AuthCount - 1; ++i) {
  984. *RtlSubAuthoritySid(NewSid, i) = *RtlSubAuthoritySid(DomainSid,
  985. i);
  986. }
  987. //
  988. // Append the Relative Id.
  989. //
  990. *RtlSubAuthoritySid(NewSid, AuthCount - 1) = RelativeId;
  991. return NewSid;
  992. }
  993. //
  994. // ConvertPathToPsx -- Converts an ANSI_STRING representation of
  995. // a path to a posix format path. The ANSI_STRING's buffer is assumed
  996. // to point to a section of the ClientView memory, and the MaximumLength
  997. // member of the ANSI_STRING is assumed to be set to the maximum length
  998. // of the final path string. This function will modify the Buffer and
  999. // Length members of the input ANSI_STRING. This function will return
  1000. // false if a working buffer cannot be allocated in the PsxHeap heap.
  1001. //
  1002. static BOOLEAN
  1003. ConvertPathToPsx (
  1004. ANSI_STRING *A
  1005. )
  1006. {
  1007. PCHAR TmpBuff;
  1008. PCHAR InRover;
  1009. PCHAR OutRover;
  1010. TmpBuff = RtlAllocateHeap(PsxHeap, 0, A->Length*2);
  1011. if (NULL == TmpBuff) {
  1012. return(FALSE);
  1013. }
  1014. if (*(A->Buffer) == '\0') {
  1015. strcpy(TmpBuff, "//C/" );
  1016. } else {
  1017. for (InRover = A->Buffer, OutRover = TmpBuff;
  1018. *InRover != '\0';
  1019. ++InRover) {
  1020. if (';' == *InRover) {
  1021. // semis become colons
  1022. *OutRover++ = ':';
  1023. } else if ('\\' == *InRover) {
  1024. // back-slashes become forward-slashes
  1025. *OutRover++ = '/';
  1026. } else if (':' == *(InRover + 1)) {
  1027. // "X:" becomes "//X" - drive letter must be uppercase
  1028. *OutRover++ = '/';
  1029. *OutRover++ = '/';
  1030. *OutRover++ = (CHAR)toupper(*InRover);
  1031. ++InRover; // skip the colon
  1032. } else {
  1033. *OutRover++ = *InRover;
  1034. }
  1035. }
  1036. *OutRover = '\0';
  1037. }
  1038. strcpy(A->Buffer, TmpBuff);
  1039. A->Length = (USHORT)strlen(A->Buffer);
  1040. RtlFreeHeap(PsxHeap, 0, (PVOID)TmpBuff);
  1041. return (TRUE);
  1042. }
  1043. PSID
  1044. GetSpecialSid(
  1045. uid_t Uid
  1046. )
  1047. {
  1048. PSID Sid;
  1049. NTSTATUS Status;
  1050. SID_IDENTIFIER_AUTHORITY Auth = SECURITY_NULL_SID_AUTHORITY;
  1051. UCHAR uc;
  1052. ULONG ul;
  1053. Sid = RtlAllocateHeap(PsxHeap, 0, RtlLengthRequiredSid(1));
  1054. if (NULL == Sid)
  1055. return NULL;
  1056. Status = RtlInitializeSid(Sid, &Auth, 1);
  1057. ASSERT(NT_SUCCESS(Status));
  1058. uc = (UCHAR)((Uid & 0xFFF) >> 8);
  1059. RtlIdentifierAuthoritySid(Sid)->Value[5] = uc;
  1060. ul = Uid & 0xF;
  1061. *RtlSubAuthoritySid(Sid, 0) = ul;
  1062. return Sid;
  1063. }