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.

944 lines
24 KiB

  1. /*--
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. calcscom.c
  5. Abstract:
  6. Support routines for dacls/sacls exes
  7. Author:
  8. 14-Dec-1996 (macm)
  9. Environment:
  10. User mode only.
  11. Requires ANSI C extensions: slash-slash comments, long external names.
  12. Revision History:
  13. --*/
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <caclscom.h>
  19. #include <dsysdbg.h>
  20. #include <aclapi.h>
  21. #include <stdio.h>
  22. #include <wcstr.h>
  23. #include <seopaque.h>
  24. #include <sertlp.h>
  25. DWORD
  26. ConvertCmdlineRights(
  27. IN PSTR pszCmdline,
  28. IN PCACLS_STR_RIGHTS pRightsTable,
  29. IN INT cRights,
  30. OUT DWORD *pConvertedRights
  31. )
  32. /*++
  33. Routine Description:
  34. Parses the given command line string that corresponds to a given rights
  35. list. The individual righs entry are looked up in the rights table and
  36. added to the list of converted rights
  37. Arguments:
  38. pszCmdline - The list of string rights to convert
  39. pRightsTable - The mapping from the string rights to the new win32 rights.
  40. It is expected that the rights table string tags will all be in upper
  41. case upon function entry.
  42. cRights - The number of items in the rights table
  43. pConvertedRights - Where the converted access mask is returned
  44. Return Value:
  45. ERROR_SUCCESS -- Success
  46. ERROR_INVALID_PARAMETER -- An unexpected string right was encountered
  47. --*/
  48. {
  49. DWORD dwErr = ERROR_SUCCESS;
  50. PSTR pszCurrent = pszCmdline;
  51. INT i;
  52. #if DBG
  53. INT j;
  54. #endif
  55. *pConvertedRights = 0;
  56. //
  57. // Allow empty lists
  58. //
  59. if (pszCurrent == NULL) {
  60. return(ERROR_SUCCESS);
  61. }
  62. //
  63. // Assert that the table is upper case as expected
  64. //
  65. #if DBG
  66. for (i = 0; i < cRights; i++) {
  67. for (j = 0; j < 2; j++) {
  68. if(toupper(pRightsTable[i].szRightsTag[j]) != pRightsTable[i].szRightsTag[j]) {
  69. dwErr = ERROR_INVALID_PARAMETER;
  70. break;
  71. }
  72. }
  73. }
  74. #endif
  75. while (dwErr == ERROR_SUCCESS && *pszCurrent != '\0') {
  76. dwErr = ERROR_INVALID_PARAMETER;
  77. for (i = 0; i < cRights; i++ ) {
  78. if (pRightsTable[i].szRightsTag[0] ==
  79. toupper(*pszCurrent) &&
  80. pRightsTable[i].szRightsTag[1] ==
  81. toupper(*(pszCurrent + 1))) {
  82. dwErr = ERROR_SUCCESS;
  83. *pConvertedRights |= pRightsTable[i].Right;
  84. break;
  85. }
  86. }
  87. pszCurrent++;
  88. if (*pszCurrent != '\0') {
  89. pszCurrent++;
  90. }
  91. }
  92. return(dwErr);
  93. }
  94. DWORD
  95. ParseCmdline (
  96. IN PSTR *ppszArgs,
  97. IN INT cArgs,
  98. IN INT cSkip,
  99. IN PCACLS_CMDLINE pCmdValues,
  100. IN INT cCmdValues
  101. )
  102. /*++
  103. Routine Description:
  104. Parses the command line against the given cmd values.
  105. Arguments:
  106. ppszArgs - The argument list
  107. cArgs - Count of arguments in the list
  108. cSkip - Number of initial arguments to skip
  109. pCmdValues - Command values list to process the command line against
  110. cCmdValues - Number of command values in the list
  111. Return Value:
  112. ERROR_SUCCESS -- Success
  113. ERROR_INVALID_PARAMETER -- An unexpected command line value was found
  114. --*/
  115. {
  116. DWORD dwErr = ERROR_SUCCESS;
  117. INT i,j;
  118. i = cSkip;
  119. while (i < cArgs && dwErr == ERROR_SUCCESS) {
  120. if( *ppszArgs[i] == '/' || *ppszArgs[i] == '-') {
  121. for (j = 0; j < cCmdValues; j++) {
  122. if (_stricmp(ppszArgs[i] + 1, pCmdValues[j].pszSwitch) == 0) {
  123. if (pCmdValues[j].iIndex != -1) {
  124. dwErr = ERROR_INVALID_PARAMETER;
  125. } else {
  126. pCmdValues[j].iIndex = i;
  127. //
  128. // See if we need to skip some number of values
  129. //
  130. if (pCmdValues[j].fFindNextSwitch == TRUE ) {
  131. pCmdValues[j].cValues = 0;
  132. while (i + 1 < cArgs) {
  133. if (*ppszArgs[i + 1] != '/' &&
  134. *ppszArgs[i + 1] != '-') {
  135. pCmdValues[j].cValues++;
  136. i++;
  137. } else {
  138. break;
  139. }
  140. }
  141. }
  142. }
  143. break;
  144. }
  145. }
  146. if (j == cCmdValues) {
  147. dwErr = ERROR_INVALID_PARAMETER;
  148. break;
  149. }
  150. } else {
  151. dwErr = ERROR_INVALID_PARAMETER;
  152. }
  153. i++;
  154. }
  155. return(dwErr);
  156. }
  157. DWORD
  158. ProcessOperation (
  159. IN PSTR *ppszCmdline,
  160. IN PCACLS_CMDLINE pCmdInfo,
  161. IN ACCESS_MODE AccessMode,
  162. IN PCACLS_STR_RIGHTS pRightsTable,
  163. IN INT cRights,
  164. IN DWORD fInherit,
  165. IN PACL pOldAcl OPTIONAL,
  166. OUT PACL *ppNewAcl
  167. )
  168. /*++
  169. Routine Description:
  170. Performs an "operation", such as Grant, Revoke, Deny. It parses the given command values
  171. into User/Permission pairs, and then creates a new security descriptor. The returned
  172. security descriptor needs to be freed via LocalFree.
  173. Arguments:
  174. ppszCmdline - The command line argument list
  175. pCmdInfo - Information about where this operation lives in the comand line
  176. AccessMode - Type of operation (Grant/Revoke/Deny) to do
  177. pRightsTable - The mapping from the string rights to the new win32 rights.
  178. It is expected that the rights table string tags will all be in upper
  179. case upon function entry.
  180. cRights - The number of items in the rights table
  181. fInherit - Inheritance flags to apply
  182. pOldAcl - Optional. If present, this is the ACL off of the object in the edit case.
  183. ppNewAcl - Where the new ACL is returned.
  184. Return Value:
  185. ERROR_SUCCESS -- Success
  186. ERROR_INVALID_PARAMETER -- The switch was specified, but no user/perms pairs were found
  187. ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed.
  188. --*/
  189. {
  190. DWORD dwErr = ERROR_SUCCESS;
  191. PEXPLICIT_ACCESS_A pNewAccess = NULL;
  192. PSTR pszRights;
  193. INT i;
  194. DWORD dwRights;
  195. //
  196. // Make sure we have valid parameters
  197. //
  198. if (pCmdInfo->iIndex != -1 && pCmdInfo->cValues == 0) {
  199. return(ERROR_INVALID_PARAMETER);
  200. }
  201. pNewAccess = (PEXPLICIT_ACCESS_A)LocalAlloc(LMEM_FIXED,
  202. sizeof(EXPLICIT_ACCESS_A) * pCmdInfo->cValues);
  203. if (pNewAccess == NULL) {
  204. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  205. }
  206. //
  207. // Otherwise, start parsing and converting...
  208. //
  209. for (i = 0; i < (INT)pCmdInfo->cValues && dwErr == ERROR_SUCCESS; i++) {
  210. pszRights = strchr(ppszCmdline[pCmdInfo->iIndex + i + 1], ':');
  211. if (pszRights == NULL && AccessMode != REVOKE_ACCESS) {
  212. dwErr = ERROR_INVALID_PARAMETER;
  213. } else {
  214. if (pszRights != NULL) {
  215. *pszRights = '\0';
  216. pszRights++;
  217. }
  218. dwErr = ConvertCmdlineRights(pszRights,
  219. pRightsTable,
  220. cRights,
  221. &dwRights);
  222. if (dwErr == ERROR_SUCCESS) {
  223. BuildExplicitAccessWithNameA(&pNewAccess[i],
  224. ppszCmdline[pCmdInfo->iIndex + i + 1],
  225. dwRights,
  226. AccessMode,
  227. fInherit);
  228. }
  229. }
  230. }
  231. //
  232. // If all of that worked, we'll apply it to the new security descriptor
  233. //
  234. if (dwErr == ERROR_SUCCESS) {
  235. dwErr = SetEntriesInAclA(pCmdInfo->cValues,
  236. pNewAccess,
  237. pOldAcl,
  238. ppNewAcl);
  239. }
  240. LocalFree(pNewAccess);
  241. return(dwErr);
  242. }
  243. DWORD
  244. SetAndPropagateFileRights (
  245. IN PSTR pszFilePath,
  246. IN PACL pAcl,
  247. IN SECURITY_INFORMATION SeInfo,
  248. IN BOOL fPropagate,
  249. IN BOOL fContinueOnDenied,
  250. IN BOOL fBreadthFirst,
  251. IN DWORD fInherit
  252. )
  253. /*++
  254. Routine Description:
  255. This function will set [and propagate] the given acl to the specified path and optionally all
  256. of its children. In the event of an access denied error, this function may or may not
  257. terminate, depending on the state of the fContinueOnDenied flag. This function does a depth
  258. first search with a write on return. This function is recursive.
  259. Arguments:
  260. pszFilePath - The file path to set the ACL on
  261. pAcl - The acl to set
  262. SeInfo - Whether the DACL or SACL is being set
  263. fPropagate - Determines whether the function should propagate or not
  264. fContinueOnDenied - Determines the behavior when an access denied is encountered.
  265. fBreadthFirst - If TRUE, do a breadth first propagation. Otherwise, do a depth first
  266. fInherit - Optional inheritance flags to apply
  267. Return Value:
  268. ERROR_SUCCESS -- Success
  269. ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed.
  270. --*/
  271. {
  272. DWORD dwErr = ERROR_SUCCESS;
  273. PSTR pszFullPath = NULL;
  274. PSTR pszSearchPath = NULL;
  275. HANDLE hFind = INVALID_HANDLE_VALUE;
  276. DWORD cPathLen = 0;
  277. WIN32_FIND_DATAA FindData;
  278. BOOL fRestoreWhack = FALSE;
  279. PACE_HEADER pAce;
  280. DWORD iAce;
  281. if ( fInherit != 0 ) {
  282. pAce = (PACE_HEADER)FirstAce(pAcl);
  283. for ( iAce = 0;
  284. iAce < pAcl->AceCount && dwErr == ERROR_SUCCESS;
  285. iAce++, pAce = (PACE_HEADER)NextAce(pAce) ) {
  286. pAce->AceFlags |= (UCHAR)fInherit;
  287. }
  288. }
  289. //
  290. // If we're doing a breadth first propagation, set the security first
  291. //
  292. if ( fBreadthFirst == TRUE ) {
  293. dwErr = SetNamedSecurityInfoA(pszFilePath, SE_FILE_OBJECT, SeInfo, NULL, NULL,
  294. SeInfo == DACL_SECURITY_INFORMATION ?
  295. pAcl :
  296. NULL,
  297. SeInfo == SACL_SECURITY_INFORMATION ?
  298. pAcl :
  299. NULL);
  300. }
  301. if (fPropagate == TRUE) {
  302. cPathLen = strlen(pszFilePath);
  303. pszSearchPath = (PSTR)LocalAlloc(LMEM_FIXED, cPathLen + 1 + 4);
  304. if (pszSearchPath == NULL) {
  305. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  306. } else {
  307. if (pszFilePath[cPathLen - 1] == '\\') {
  308. pszFilePath[cPathLen - 1] = '\0';
  309. cPathLen--;
  310. fRestoreWhack = TRUE;
  311. }
  312. sprintf(pszSearchPath, "%s\\%s", pszFilePath, "*.*");
  313. hFind = FindFirstFileA(pszSearchPath,
  314. &FindData);
  315. if (hFind == INVALID_HANDLE_VALUE) {
  316. dwErr = GetLastError();
  317. }
  318. }
  319. //
  320. // Start processing all the files
  321. //
  322. while (dwErr == ERROR_SUCCESS) {
  323. //
  324. // Ignore the . and ..
  325. //
  326. if (strcmp(FindData.cFileName, ".") != 0 &&
  327. strcmp(FindData.cFileName, "..") != 0) {
  328. //
  329. // Now, build the full path...
  330. //
  331. pszFullPath = (PSTR)LocalAlloc(LMEM_FIXED,
  332. cPathLen + 1 + strlen(FindData.cFileName) + 1);
  333. if (pszFullPath == NULL) {
  334. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  335. } else {
  336. sprintf(pszFullPath, "%s\\%s", pszFilePath, FindData.cFileName);
  337. //
  338. // Call ourselves
  339. //
  340. dwErr = SetAndPropagateFileRights(pszFullPath, pAcl, SeInfo,
  341. fPropagate, fContinueOnDenied, fBreadthFirst,
  342. fInherit);
  343. if (dwErr == ERROR_ACCESS_DENIED && fContinueOnDenied == TRUE) {
  344. dwErr = ERROR_SUCCESS;
  345. }
  346. }
  347. }
  348. if (dwErr == ERROR_SUCCESS && FindNextFile(hFind, &FindData) == FALSE) {
  349. dwErr = GetLastError();
  350. }
  351. }
  352. if(dwErr == ERROR_NO_MORE_FILES)
  353. {
  354. dwErr = ERROR_SUCCESS;
  355. }
  356. }
  357. //
  358. // Cover the case where it is a file
  359. //
  360. if (dwErr == ERROR_DIRECTORY) {
  361. dwErr = ERROR_SUCCESS;
  362. }
  363. //
  364. // Now, do the set
  365. //
  366. if (dwErr == ERROR_SUCCESS && fBreadthFirst == FALSE) {
  367. dwErr = SetNamedSecurityInfoA(pszFilePath, SE_FILE_OBJECT, SeInfo, NULL, NULL,
  368. SeInfo == DACL_SECURITY_INFORMATION ?
  369. pAcl :
  370. NULL,
  371. SeInfo == SACL_SECURITY_INFORMATION ?
  372. pAcl :
  373. NULL);
  374. }
  375. if (fRestoreWhack == TRUE) {
  376. pszFilePath[cPathLen - 1] = '\\';
  377. pszFilePath[cPathLen] = '\0';
  378. }
  379. //
  380. // If necessary, restore the inheritance flags
  381. //
  382. if ( fInherit != 0 ) {
  383. pAce = (PACE_HEADER)FirstAce(pAcl);
  384. for ( iAce = 0;
  385. iAce < pAcl->AceCount && dwErr == ERROR_SUCCESS;
  386. iAce++, pAce = (PACE_HEADER)NextAce(pAce) ) {
  387. pAce->AceFlags &= (UCHAR)~fInherit;
  388. }
  389. }
  390. return(dwErr);
  391. }
  392. DWORD
  393. DisplayAcl (
  394. IN PSTR pszPath,
  395. IN PACL pAcl,
  396. IN PCACLS_STR_RIGHTS pRightsTable,
  397. IN INT cRights
  398. )
  399. /*++
  400. Routine Description:
  401. This function will display the given acl to the screen
  402. Arguments:
  403. pszPath - The file path to be displayed
  404. pAcl - The Acl to display
  405. pRightsTable - List of available rights
  406. cRights - Number of rights in the list
  407. Return Value:
  408. ERROR_SUCCESS -- Success
  409. --*/
  410. {
  411. DWORD dwErr = ERROR_SUCCESS;
  412. ACL_SIZE_INFORMATION AclSize;
  413. ACL_REVISION_INFORMATION AclRev;
  414. PKNOWN_ACE pAce;
  415. PSID pSid;
  416. DWORD iIndex;
  417. PSTR pszName;
  418. INT i,cPathLen, iSkip, j;
  419. PSTR pszAceTypes[] = {"ACCESS_ALLOWED_ACE_TYPE",
  420. "ACCESS_DENIED_ACE_TYPE",
  421. "SYSTEM_AUDIT_ACE_TYPE",
  422. "SYSTEM_ALARM_ACE_TYPE",
  423. "ACCESS_ALLOWED_COMPOUND_ACE_TYPE",
  424. "ACCESS_ALLOWED_OBJECT_ACE_TYPE",
  425. "ACCESS_DENIED_OBJECT_ACE_TYPE",
  426. "SYSTEM_AUDIT_OBJECT_ACE_TYPE",
  427. "SYSTEM_ALARM_OBJECT_ACE_TYPE"};
  428. PSTR pszInherit[] = {"OBJECT_INHERIT_ACE",
  429. "CONTAINER_INHERIT_ACE",
  430. "NO_PROPAGATE_INHERIT_ACE",
  431. "INHERIT_ONLY_ACE",
  432. "INHERITED_ACE"};
  433. fprintf(stdout, "%s: ", pszPath);
  434. cPathLen = strlen(pszPath) + 2;
  435. if (pAcl == NULL) {
  436. fprintf(stdout, "NULL acl\n");
  437. } else {
  438. if (GetAclInformation(pAcl, &AclRev, sizeof(ACL_REVISION_INFORMATION),
  439. AclRevisionInformation) == FALSE) {
  440. return(GetLastError());
  441. }
  442. if(GetAclInformation(pAcl, &AclSize, sizeof(ACL_SIZE_INFORMATION),
  443. AclSizeInformation) == FALSE) {
  444. return(GetLastError());
  445. }
  446. fprintf(stdout, "AclRevision: %lu\n", AclRev.AclRevision);
  447. fprintf(stdout, "%*sAceCount: %lu\n", cPathLen, " ", AclSize.AceCount);
  448. fprintf(stdout, "%*sInUse: %lu\n", cPathLen, " ", AclSize.AclBytesInUse);
  449. fprintf(stdout, "%*sFree: %lu\n", cPathLen, " ", AclSize.AclBytesFree);
  450. fprintf(stdout, "%*sFlags: %lu\n", cPathLen, " ", pAcl->Sbz1);
  451. //
  452. // Now, dump all of the aces
  453. //
  454. pAce = FirstAce(pAcl);
  455. for(iIndex = 0; iIndex < pAcl->AceCount; iIndex++) {
  456. cPathLen = strlen(pszPath) + 2;
  457. fprintf(stdout, " %*sAce [%3lu]: ", cPathLen, " ", iIndex);
  458. cPathLen += 13;
  459. fprintf(stdout, "Type: %s\n", pAce->Header.AceType > ACCESS_MAX_MS_ACE_TYPE ?
  460. "UNKNOWN ACE TYPE" :
  461. pszAceTypes[pAce->Header.AceType]);
  462. fprintf(stdout, "%*sFlags: ", cPathLen, " ");
  463. if ( pAce->Header.AceFlags == 0 ) {
  464. fprintf(stdout, "0\n");
  465. } else {
  466. if (( pAce->Header.AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) != 0 ) {
  467. fprintf( stdout,"SUCCESSFUL_ACCESS_ACE_FLAG " );
  468. }
  469. if (( pAce->Header.AceFlags & FAILED_ACCESS_ACE_FLAG) != 0 ) {
  470. if (( pAce->Header.AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) != 0 ) {
  471. fprintf( stdout, "| " );
  472. }
  473. fprintf( stdout,"FAILED_ACCESS_ACE_FLAG" );
  474. }
  475. iSkip = 0;
  476. if ( ( pAce->Header.AceFlags &
  477. (FAILED_ACCESS_ACE_FLAG | SUCCESSFUL_ACCESS_ACE_FLAG)) != 0 &&
  478. ( pAce->Header.AceFlags & VALID_INHERIT_FLAGS) != 0 ) {
  479. iSkip = cPathLen + 7;
  480. }
  481. //
  482. // Now, the inheritance flags
  483. //
  484. for (j = 0; j < sizeof(pszInherit) / sizeof(PSTR) ; j++) {
  485. if ((pAce->Header.AceFlags & (1 << j)) != 0 ) {
  486. if (iSkip != 0) {
  487. fprintf(stdout, " | \n");
  488. fprintf(stdout, "%*s", iSkip, " ");
  489. }
  490. fprintf(stdout, "%s", pszInherit[j]);
  491. if (iSkip == 0) {
  492. iSkip = cPathLen + 7;
  493. }
  494. }
  495. }
  496. fprintf( stdout,"\n" );
  497. }
  498. fprintf(stdout, "%*sSize: 0x%lx\n", cPathLen, " ", pAce->Header.AceSize);
  499. fprintf(stdout, "%*sMask: ", cPathLen, " ");
  500. if (pAce->Mask == 0) {
  501. fprintf(stdout, "%*sNo access\n", cPathLen, " ");
  502. } else {
  503. iSkip = 0;
  504. for (i = 1 ;i < cRights ;i++ ) {
  505. if ((pAce->Mask & pRightsTable[i].Right) != 0) {
  506. if (iSkip != 0) {
  507. fprintf(stdout, "%*s", iSkip, " ");
  508. } else {
  509. iSkip = cPathLen + 7;
  510. }
  511. fprintf(stdout, "%s\n", pRightsTable[i].pszDisplayTag);
  512. }
  513. }
  514. }
  515. //
  516. // Lookup the account name and return it...
  517. //
  518. //
  519. // If it's an object ace, dump the guids
  520. //
  521. dwErr = TranslateAccountName((PSID)&(pAce->SidStart), &pszName);
  522. if (dwErr == ERROR_SUCCESS) {
  523. fprintf(stdout, "%*sUser: %s\n", cPathLen, " ", pszName);
  524. LocalFree(pszName);
  525. }
  526. fprintf( stdout, "\n" );
  527. pAce = NextAce(pAce);
  528. }
  529. }
  530. return(dwErr);
  531. }
  532. DWORD
  533. TranslateAccountName (
  534. IN PSID pSid,
  535. OUT PSTR *ppszName
  536. )
  537. /*++
  538. Routine Description:
  539. This function will "translate" a sid into a name by doing a LookupAccountSid on the sid
  540. Arguments:
  541. pSid - The sid to convert to a name
  542. ppszName - Where the name is returned. Must be freed via a call to LocalFree.
  543. Return Value:
  544. ERROR_SUCCESS -- Success
  545. ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  546. --*/
  547. {
  548. DWORD dwErr = ERROR_SUCCESS;
  549. SID_NAME_USE esidtype;
  550. LPSTR pszDomain = NULL;
  551. LPSTR pszName = NULL;
  552. ULONG cName = 0;
  553. ULONG cDomain = 0;
  554. if (LookupAccountSidA(NULL, pSid, NULL, &cName, NULL, &cDomain, &esidtype) == FALSE) {
  555. dwErr = GetLastError();
  556. if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
  557. dwErr = ERROR_SUCCESS;
  558. //
  559. // Allocate for the name and the domain
  560. //
  561. pszName = (PSTR)LocalAlloc(LMEM_FIXED, cName);
  562. if (pszName != NULL) {
  563. pszDomain = (PSTR)LocalAlloc(LMEM_FIXED, cDomain);
  564. if (pszDomain == NULL) {
  565. LocalFree(pszName);
  566. pszName = NULL;
  567. }
  568. }
  569. if (pszName == NULL) {
  570. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  571. }
  572. if (dwErr == ERROR_SUCCESS) {
  573. if(LookupAccountSidA(NULL, pSid, pszName, &cName, pszDomain, &cDomain,
  574. &esidtype) == FALSE) {
  575. dwErr = GetLastError();
  576. LocalFree(pszName);
  577. LocalFree(pszDomain);
  578. }
  579. }
  580. } else if (dwErr == ERROR_NONE_MAPPED) {
  581. UCHAR String[256];
  582. UNICODE_STRING SidStr;
  583. NTSTATUS Status;
  584. dwErr = ERROR_SUCCESS;
  585. pszName = NULL;
  586. //
  587. // Ok, return the sid as a name
  588. //
  589. SidStr.Buffer = (PWSTR)String;
  590. SidStr.Length = SidStr.MaximumLength = 256;
  591. Status = RtlConvertSidToUnicodeString(&SidStr, pSid, FALSE);
  592. if (NT_SUCCESS(Status)) {
  593. pszName = (PSTR)LocalAlloc(LMEM_FIXED,
  594. wcstombs(NULL, SidStr.Buffer,
  595. wcslen(SidStr.Buffer) + 1) + 1);
  596. if (pszName == NULL) {
  597. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  598. } else {
  599. wcstombs(pszName, SidStr.Buffer, wcslen(SidStr.Buffer) + 1);
  600. }
  601. } else {
  602. dwErr = RtlNtStatusToDosError(Status);
  603. }
  604. }
  605. }
  606. if(dwErr == ERROR_SUCCESS)
  607. {
  608. ULONG cLen;
  609. if(pszDomain != NULL && *pszDomain != '\0')
  610. {
  611. cLen = strlen(pszDomain) + 1;
  612. cLen += strlen(pszName) + 1;
  613. *ppszName = (PSTR)LocalAlloc(LMEM_FIXED, cLen);
  614. if (*ppszName == NULL) {
  615. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  616. } else {
  617. sprintf(*ppszName, "%s\\%s", pszDomain, pszName);
  618. }
  619. } else {
  620. *ppszName = pszName;
  621. pszName = NULL;
  622. }
  623. }
  624. LocalFree(pszDomain);
  625. LocalFree(pszName);
  626. return(dwErr);
  627. }