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.

1390 lines
44 KiB

  1. //+------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1995, Microsoft Corporation.
  4. //
  5. // File: t2.cxx
  6. //
  7. // Contents:
  8. //
  9. // Classes:
  10. //
  11. // History: Nov-93 DaveMont Created.
  12. //
  13. //-------------------------------------------------------------------
  14. #include <t2.hxx>
  15. #include <filesec.hxx>
  16. #include <fileenum.hxx>
  17. #include <dumpsec.hxx>
  18. #include "caclsmsg.h"
  19. #include <locale.h>
  20. #include <string.h>
  21. #include <winnlsp.h>
  22. #include <tchar.h>
  23. #if DBG
  24. ULONG Debug;
  25. #endif
  26. //+----------------------------------------------------------------------------
  27. //
  28. // local prototypes
  29. //
  30. //+----------------------------------------------------------------------------
  31. BOOLEAN OpenToken(PHANDLE ph);
  32. void printfsid(SID *psid, ULONG *outputoffset);
  33. void printface(ACE_HEADER *paceh, BOOL fdir, ULONG outputoffset);
  34. void printfmask(ULONG mask, UCHAR acetype, BOOL fdir, ULONG outputoffset);
  35. WCHAR *mbstowcs(char *aname );
  36. BOOL GetUserAndAccess(TCHAR *arg, WCHAR **user, ULONG *access);
  37. #if DBG
  38. ULONG DebugEnumerate(TCHAR *filename, ULONG option);
  39. #endif
  40. ULONG DisplayAces(TCHAR *filename, ULONG option);
  41. ULONG ModifyAces(TCHAR *filename,
  42. MODE emode,
  43. ULONG option,
  44. TCHAR *argv[],
  45. LONG astart[], LONG aend[] );
  46. ULONG GetCmdLineArgs(INT argc, TCHAR *argv[],
  47. ULONG *option,
  48. LONG astart[], LONG aend[],
  49. MODE *emode
  50. #if DBG
  51. ,ULONG *debug
  52. #endif
  53. );
  54. ULONG
  55. __cdecl
  56. printmessage (FILE* fp, DWORD messageID, ...);
  57. //+----------------------------------------------------------------------------
  58. //
  59. // Function: vfcprintf
  60. //
  61. // Synopsis: prints formatted text to [pOut]. This function will call the
  62. // defulat c printf functions if it can not call WriteConsole().
  63. // We are calling WriteConsole() because it will display extended
  64. // characters, were as fprintf, printf ..., functions do not display
  65. // multi linguel strings.
  66. //
  67. // Arguments: [pOut] - Must be stdout, stderr, otherwise the function will just
  68. // call standard c functions.
  69. // [pszFormate] - Format string
  70. // [argList] - variable length argument list.
  71. //
  72. //----------------------------------------------------------------------------
  73. void vfcprintf(FILE *pOut, LPCTSTR pszFormat, va_list argList)
  74. {
  75. HANDLE handle;
  76. //
  77. // Get the standard handles for output. This assumes that the callers is calling with
  78. // either stdout or stderr, if it's anything else then just use normal sprintf.
  79. //
  80. TCHAR szText[2048];
  81. if(pOut == stdout){
  82. handle = GetStdHandle(STD_OUTPUT_HANDLE);
  83. } else if(pOut == stderr ){
  84. handle = GetStdHandle(STD_ERROR_HANDLE);
  85. } else {
  86. do_normal:
  87. #if defined(_UNICODE) || defined(UNICODE)
  88. vswprintf( szText, pszFormat, argList );
  89. fwprintf(pOut, szText );
  90. #else
  91. vsprintf( szText, pszFormat, argList );
  92. fprintf(pOut, szText );
  93. #endif
  94. return;
  95. }
  96. //
  97. // If we can't get the output handle then just send it to standard fprintf functions
  98. //
  99. if(INVALID_HANDLE_VALUE == handle){
  100. goto do_normal;
  101. }
  102. //
  103. // Format the text using standard C functions.
  104. //
  105. #if defined(_UNICODE) || defined(UNICODE)
  106. vswprintf( szText, pszFormat, argList );
  107. #else
  108. vsprintf( szText, pszFormat, argList );
  109. #endif
  110. DWORD cRead = 0;
  111. //
  112. // If we can't get the console mode from this handle, then it is being piped somewhere else
  113. // and we must use sprintf to write, because WriteConsole only works with a console
  114. // output handle.
  115. //
  116. if(!GetConsoleMode( handle, &cRead ))
  117. {
  118. DWORD cchBuffer = lstrlen(szText);
  119. LPSTR lpAnsiBuffer = (LPSTR) LocalAlloc(LMEM_FIXED, (cchBuffer+1)*sizeof(WCHAR));
  120. if (lpAnsiBuffer != NULL)
  121. {
  122. cchBuffer = WideCharToMultiByte(CP_OEMCP,
  123. 0,
  124. szText,
  125. cchBuffer + 1,
  126. lpAnsiBuffer,
  127. (cchBuffer +1) * sizeof(WCHAR),
  128. NULL,
  129. NULL);
  130. if (cchBuffer != 0)
  131. {
  132. fprintf(pOut,"%s",lpAnsiBuffer);
  133. }
  134. LocalFree(lpAnsiBuffer);
  135. }
  136. } else {
  137. WriteConsole( handle, szText, lstrlen(szText), &cRead, NULL);
  138. }
  139. }
  140. //+----------------------------------------------------------------------------
  141. //
  142. // Function: fcprintf
  143. //
  144. // synopsis: Same as fprintf, except this will call vfcprintf, which
  145. // prints to the console use WriteConsole.
  146. //
  147. // Arguments: [pOut] - FILE stream to output to.
  148. // [pszFormate] - Format string
  149. // [...] - variable length argument list.
  150. //
  151. //----------------------------------------------------------------------------
  152. void
  153. __cdecl
  154. fcprintf( FILE *pOut, LPCTSTR pszFormat, ...)
  155. {
  156. va_list marker;
  157. va_start(marker, pszFormat);
  158. vfcprintf( pOut, pszFormat, marker);
  159. va_end(marker);
  160. }
  161. //+----------------------------------------------------------------------------
  162. //
  163. // Function: fcprintf
  164. //
  165. // synopsis: Same as printf, except this will call vfcprintf, which
  166. // prints to the console use WriteConsole.
  167. //
  168. // Arguments: [pszFormate] - Format string
  169. // [...] - variable length argument list.
  170. //
  171. //----------------------------------------------------------------------------
  172. void
  173. __cdecl
  174. cprintf( LPCTSTR pszFormat, ...)
  175. {
  176. va_list marker;
  177. va_start(marker, pszFormat);
  178. vfcprintf( stdout, pszFormat, marker);
  179. va_end(marker);
  180. }
  181. //+----------------------------------------------------------------------------
  182. //
  183. // Function: Usage
  184. //
  185. // Synopsis: prints usage functionality
  186. //
  187. // Arguments: none
  188. //
  189. //----------------------------------------------------------------------------
  190. VOID usage()
  191. {
  192. printmessage(stdout, MSG_CACLS_USAGE, NULL);
  193. #if DBG
  194. if (Debug)
  195. {
  196. printf("\n /B deBug <[#]>\n");
  197. printf(" default is display error returned\n");
  198. printf(" in /B '#' is a mask: 1 display SIDS values\n");
  199. printf(" 2 display access masks\n");
  200. printf(" 4 display error returned\n");
  201. printf(" 8 display error location\n");
  202. printf(" 0x10 verbose\n");
  203. printf(" 0x20 verboser\n");
  204. printf(" 0x40 enumerate names\n");
  205. printf(" 0x80 enumerate failures\n");
  206. printf(" 0x100 enumerate starts and returns\n");
  207. printf(" 0x200 enumerate extra data\n");
  208. printf(" 0x400 size allocation data\n");
  209. printf(" 0x800 display enumeration of files\n");
  210. }
  211. #endif
  212. }
  213. BOOL
  214. IsAclSupported(LPCWSTR lpszFileName)
  215. {
  216. BOOL bReturn = TRUE;
  217. WCHAR szVolumePathName[MAX_PATH+1];
  218. if(GetVolumePathName(lpszFileName,
  219. szVolumePathName,
  220. MAX_PATH))
  221. {
  222. int nLen = wcslen(szVolumePathName);
  223. if((WCHAR)szVolumePathName[nLen -1] != L'\\')
  224. {
  225. szVolumePathName[nLen] = L'\\';
  226. szVolumePathName[nLen++] = L'\0';
  227. }
  228. DWORD dwFlags = 0;
  229. if(GetVolumeInformation(szVolumePathName,
  230. NULL,
  231. NULL,
  232. NULL,
  233. NULL,
  234. &dwFlags,
  235. NULL,
  236. 0))
  237. {
  238. if(!(FS_PERSISTENT_ACLS & dwFlags))
  239. {
  240. printmessage(stdout,MSG_CACLS_NOT_NTFS);
  241. return FALSE;
  242. }
  243. }
  244. }
  245. return bReturn;
  246. }
  247. //+----------------------------------------------------------------------------
  248. //
  249. // Function: Main, Public
  250. //
  251. // Synopsis: main!!
  252. //
  253. // Arguments: IN [argc] - cmdline arguement count
  254. // IN [argv] - input cmdline arguements
  255. //
  256. //----------------------------------------------------------------------------
  257. #if defined( __cplusplus )
  258. extern "C" {
  259. #endif
  260. VOID _cdecl wmain(int argc, wchar_t *argvw[])
  261. {
  262. char lBuf[6];
  263. //
  264. // Set the local to system OEM code page.
  265. //
  266. setlocale(LC_ALL, ".OCP" );
  267. SetThreadUILanguage(0);
  268. //
  269. // Convert the wide character set to string array.
  270. //
  271. LONG astart[MAX_OPTIONS], aend[MAX_OPTIONS];
  272. MODE emode;
  273. LONG ret = 0;
  274. ULONG option;
  275. if (ERROR_SUCCESS != (ret = GetCmdLineArgs(argc, argvw,
  276. &option,
  277. astart, aend,
  278. &emode
  279. #if DBG
  280. ,&Debug
  281. #endif
  282. )))
  283. {
  284. usage();
  285. exit(ret);
  286. }
  287. if(!IsAclSupported(argvw[1]))
  288. exit(1);
  289. switch (emode)
  290. {
  291. case MODE_DISPLAY:
  292. ret = DisplayAces(argvw[1], option);
  293. break;
  294. case MODE_REPLACE:
  295. case MODE_MODIFY:
  296. ret = ModifyAces(argvw[1], emode, option, argvw, astart, aend );
  297. break;
  298. #if DBG
  299. case MODE_DEBUG_ENUMERATE:
  300. ret = DebugEnumerate(argvw[1], option);
  301. break;
  302. #endif
  303. default:
  304. {
  305. usage();
  306. exit(1);
  307. }
  308. }
  309. if (ERROR_SUCCESS != ret)
  310. {
  311. LAST_ERROR((stderr, "Cacls failed, %ld\n",ret))
  312. if( ret == ERROR_BAD_ARGUMENTS )
  313. ret = MSG_CACLS_INVALID_ARGUMENT;
  314. printmessage(stderr, ret, NULL);
  315. if( ret == MSG_CACLS_INVALID_ARGUMENT )
  316. usage();
  317. }
  318. exit(ret);
  319. }
  320. #if defined( __cplusplus )
  321. }
  322. #endif
  323. //---------------------------------------------------------------------------
  324. //
  325. // Function: GetCmdLineArgs
  326. //
  327. // Synopsis: gets and parses command line arguments into commands
  328. // recognized by this program
  329. //
  330. // Arguments: IN [argc] - cmdline arguement count
  331. // IN [argv] - input cmdline arguements
  332. // OUT [option] - requested option
  333. // OUT [astart] - start of arguments for each option
  334. // OUT [aend] - end of arguments for each option
  335. // OUT [emode] - mode of operation
  336. // OUT [debug] - debug mask
  337. //
  338. //
  339. //----------------------------------------------------------------------------
  340. ULONG GetCmdLineArgs(INT argc, TCHAR *argv[],
  341. ULONG *option,
  342. LONG astart[], LONG aend[],
  343. MODE *emode
  344. #if DBG
  345. ,ULONG *debug
  346. #endif
  347. )
  348. {
  349. ARG_MODE_INDEX am = ARG_MODE_INDEX_NEED_OPTION;
  350. #if DBG
  351. *debug = 0;
  352. #endif
  353. *emode = MODE_DISPLAY;
  354. *option = 0;
  355. for (LONG j=0; j < MAX_OPTIONS ;j++ )
  356. {
  357. astart[j] = 0;
  358. aend[j] = 0;
  359. }
  360. if ( (argc < 2) || (argv[1][0] == '/') )
  361. {
  362. #if DBG
  363. // do this so debug args are printed out
  364. if (argc >= 2)
  365. {
  366. if ( (0 == lstrcmpi(&argv[1][1], TEXT("deBug"))) ||
  367. (0 == lstrcmpi(&argv[1][1], TEXT("b"))) )
  368. {
  369. *debug = DEBUG_LAST_ERROR;
  370. }
  371. }
  372. #endif
  373. return(ERROR_BAD_ARGUMENTS);
  374. }
  375. for (LONG k = 2; k < argc ; k++ )
  376. {
  377. if (argv[k][0] == '/')
  378. {
  379. switch (am)
  380. {
  381. case ARG_MODE_INDEX_NEED_OPTION:
  382. #if DBG
  383. case ARG_MODE_INDEX_DEBUG:
  384. #endif
  385. break;
  386. case ARG_MODE_INDEX_DENY:
  387. case ARG_MODE_INDEX_REVOKE:
  388. case ARG_MODE_INDEX_GRANT:
  389. case ARG_MODE_INDEX_REPLACE:
  390. if (astart[am] == k)
  391. return(ERROR_BAD_ARGUMENTS);
  392. break;
  393. default:
  394. return(ERROR_BAD_ARGUMENTS);
  395. }
  396. if ( (0 == lstrcmpi(&argv[k][1], TEXT("Tree"))) ||
  397. (0 == lstrcmpi(&argv[k][1], TEXT("t"))) )
  398. {
  399. if (*option & OPTION_TREE)
  400. return(ERROR_BAD_ARGUMENTS);
  401. *option |= OPTION_TREE;
  402. am = ARG_MODE_INDEX_NEED_OPTION;
  403. continue;
  404. }
  405. if ( (0 == lstrcmpi(&argv[k][1], TEXT("Continue"))) ||
  406. (0 == lstrcmpi(&argv[k][1], TEXT("c"))) )
  407. {
  408. if (*option & OPTION_CONTINUE_ON_ERROR)
  409. return(ERROR_BAD_ARGUMENTS);
  410. *option |= OPTION_CONTINUE_ON_ERROR;
  411. am = ARG_MODE_INDEX_NEED_OPTION;
  412. continue;
  413. }
  414. if ( (0 == lstrcmpi(&argv[k][1], TEXT("Edit"))) ||
  415. (0 == lstrcmpi(&argv[k][1], TEXT("E"))) )
  416. {
  417. if (*emode != MODE_DISPLAY)
  418. return(ERROR_BAD_ARGUMENTS);
  419. *emode = MODE_MODIFY;
  420. am = ARG_MODE_INDEX_NEED_OPTION;
  421. continue;
  422. }
  423. #if DBG
  424. if ( (0 == lstrcmpi(&argv[k][1], TEXT("deBug"))) ||
  425. (0 == lstrcmpi(&argv[k][1], TEXT("b"))) )
  426. {
  427. if (*debug)
  428. return(ERROR_BAD_ARGUMENTS);
  429. am = ARG_MODE_INDEX_DEBUG;
  430. *debug = DEBUG_LAST_ERROR;
  431. continue;
  432. }
  433. #endif
  434. if ( (0 == lstrcmpi(&argv[k][1], TEXT("Deny"))) ||
  435. (0 == lstrcmpi(&argv[k][1], TEXT("D"))) )
  436. {
  437. am = ARG_MODE_INDEX_DENY;
  438. *option |= OPTION_DENY;
  439. } else if ( (0 == lstrcmpi(&argv[k][1], TEXT("Revoke"))) ||
  440. (0 == lstrcmpi(&argv[k][1], TEXT("R"))) )
  441. {
  442. am = ARG_MODE_INDEX_REVOKE;
  443. *option |= OPTION_REVOKE;
  444. } else if ( (0 == lstrcmpi(&argv[k][1], TEXT("Grant"))) ||
  445. (0 == lstrcmpi(&argv[k][1], TEXT("G"))) )
  446. {
  447. am = ARG_MODE_INDEX_GRANT;
  448. *option |= OPTION_GRANT;
  449. } else if ( (0 == lstrcmpi(&argv[k][1], TEXT("rePlace"))) ||
  450. (0 == lstrcmpi(&argv[k][1], TEXT("P"))) )
  451. {
  452. *option |= OPTION_REPLACE;
  453. am = ARG_MODE_INDEX_REPLACE;
  454. } else
  455. return(ERROR_BAD_ARGUMENTS);
  456. if (astart[am] != 0)
  457. return(ERROR_BAD_ARGUMENTS);
  458. astart[am] = k+1;
  459. } else
  460. {
  461. switch (am)
  462. {
  463. case ARG_MODE_INDEX_NEED_OPTION:
  464. return(ERROR_BAD_ARGUMENTS);
  465. #if DBG
  466. case ARG_MODE_INDEX_DEBUG:
  467. *debug = _wtol(argv[k]);
  468. if (*debug & DEBUG_ENUMERATE)
  469. if (*emode == MODE_DISPLAY)
  470. *emode = MODE_DEBUG_ENUMERATE;
  471. else
  472. return(ERROR_BAD_ARGUMENTS);
  473. am = ARG_MODE_INDEX_NEED_OPTION;
  474. break;
  475. #endif
  476. case ARG_MODE_INDEX_DENY:
  477. case ARG_MODE_INDEX_REVOKE:
  478. case ARG_MODE_INDEX_GRANT:
  479. case ARG_MODE_INDEX_REPLACE:
  480. aend[am] = k+1;
  481. break;
  482. default:
  483. return(ERROR_BAD_ARGUMENTS);
  484. }
  485. }
  486. }
  487. if ( ( (*option & OPTION_DENY) && (aend[ARG_MODE_INDEX_DENY] == 0) ) ||
  488. ( (*option & OPTION_REVOKE) && (aend[ARG_MODE_INDEX_REVOKE] == 0) ) ||
  489. ( (*option & OPTION_GRANT) && (aend[ARG_MODE_INDEX_GRANT] == 0) ) ||
  490. ( (*option & OPTION_REPLACE) && (aend[ARG_MODE_INDEX_REPLACE] == 0) ) )
  491. {
  492. return(ERROR_BAD_ARGUMENTS);
  493. } else if ( (*option & OPTION_DENY) ||
  494. (*option & OPTION_REVOKE) ||
  495. (*option & OPTION_GRANT) ||
  496. (*option & OPTION_REPLACE) )
  497. {
  498. if (*emode == MODE_DISPLAY)
  499. {
  500. if (*option & OPTION_REVOKE)
  501. {
  502. return(ERROR_BAD_ARGUMENTS);
  503. }
  504. *emode = MODE_REPLACE;
  505. }
  506. }
  507. return(ERROR_SUCCESS);
  508. }
  509. //---------------------------------------------------------------------------
  510. //
  511. // Function: DisplayAces
  512. //
  513. // Synopsis: displays ACL from specified file
  514. //
  515. // Arguments: IN [filename] - file name
  516. // IN [option] - display option
  517. //
  518. //----------------------------------------------------------------------------
  519. ULONG DisplayAces(TCHAR *filename, ULONG option)
  520. {
  521. CFileEnumerate cfe(option & OPTION_TREE);
  522. WCHAR *pwfilename;
  523. BOOL fdir;
  524. ULONG ret;
  525. if (NO_ERROR == (ret = cfe.Init(filename, &pwfilename, &fdir)))
  526. {
  527. while ( (NO_ERROR == ret) ||
  528. ( ( (ERROR_ACCESS_DENIED == ret ) || (ERROR_SHARING_VIOLATION == ret) )&&
  529. (option & OPTION_CONTINUE_ON_ERROR) ) )
  530. {
  531. #if DBG
  532. if (fdir)
  533. DISPLAY((stderr, "processing file: "))
  534. else
  535. DISPLAY((stderr, "processing dir: "))
  536. #endif
  537. cprintf( TEXT("%s"), pwfilename);
  538. if (ERROR_ACCESS_DENIED == ret)
  539. {
  540. printmessage(stdout,MSG_CACLS_ACCESS_DENIED, NULL);
  541. } else if (ERROR_SHARING_VIOLATION == ret)
  542. {
  543. printmessage(stdout,MSG_CACLS_SHARING_VIOLATION, NULL);
  544. } else
  545. {
  546. DISPLAY((stderr, "\n"))
  547. VERBOSE((stderr, "\n"))
  548. CDumpSecurity cds(pwfilename);
  549. if (NO_ERROR == (ret = cds.Init()))
  550. {
  551. #if DBG
  552. if (Debug & DEBUG_VERBOSE)
  553. {
  554. SID *psid;
  555. ULONG oo;
  556. if (NO_ERROR == (ret = cds.GetSDOwner(&psid)))
  557. {
  558. printf(" Owner = ");
  559. printfsid(psid, &oo);
  560. if (NO_ERROR == (ret = cds.GetSDGroup(&psid)))
  561. {
  562. printf(" Group = ");
  563. printfsid(psid, &oo);
  564. }
  565. else
  566. ERRORS((stderr, "GetSDGroup failed, %d\n",ret))
  567. }
  568. else
  569. ERRORS((stderr, "GetSDOwner failed, %d\n",ret))
  570. }
  571. #endif
  572. ACE_HEADER *paceh;
  573. LONG retace;
  574. if (NO_ERROR == ret)
  575. for (retace = cds.GetNextAce(&paceh); retace >= 0; )
  576. {
  577. printface(paceh, fdir, wcslen(pwfilename));
  578. retace = cds.GetNextAce(&paceh);
  579. if (retace >= 0)
  580. printf("%*s",
  581. WideCharToMultiByte(CP_ACP, 0,
  582. pwfilename, -1,
  583. NULL, 0,
  584. NULL, NULL)-1," ");
  585. }
  586. }
  587. #if DBG
  588. else
  589. ERRORS((stderr, "cds.init failed, %d\n",ret))
  590. #endif
  591. }
  592. fprintf(stdout, "\n");
  593. if ( (NO_ERROR == ret) ||
  594. ( ( (ERROR_ACCESS_DENIED == ret ) || (ERROR_SHARING_VIOLATION == ret) )&&
  595. (option & OPTION_CONTINUE_ON_ERROR) ) )
  596. ret = cfe.Next(&pwfilename, &fdir);
  597. }
  598. switch (ret)
  599. {
  600. case ERROR_NO_MORE_FILES:
  601. ret = ERROR_SUCCESS;
  602. break;
  603. case ERROR_ACCESS_DENIED:
  604. case ERROR_SHARING_VIOLATION:
  605. break;
  606. case ERROR_SUCCESS:
  607. break;
  608. default:
  609. break;
  610. }
  611. } else
  612. {
  613. ERRORS((stderr, "cfe.init failed, %d\n",ret))
  614. }
  615. return(ret);
  616. }
  617. //---------------------------------------------------------------------------
  618. //
  619. // Function: ModifyAces
  620. //
  621. // Synopsis: modifies the aces for the specified file(s)
  622. //
  623. // Arguments: IN [filename] - name of file(s) to modify the aces on
  624. // IN [emode] - mode of operation
  625. // IN [option] - requested option
  626. // IN [astart] - start of arguments for each option
  627. // IN [aend] - end of arguments for each option
  628. //
  629. //----------------------------------------------------------------------------
  630. ULONG ModifyAces(TCHAR *filename,
  631. MODE emode,
  632. ULONG option,
  633. TCHAR *argv[],
  634. LONG astart[], LONG aend[])
  635. {
  636. CDaclWrap cdw;
  637. CFileEnumerate cfe(option & OPTION_TREE);
  638. WCHAR *user = NULL;
  639. ULONG access;
  640. ULONG ret = ERROR_SUCCESS;
  641. WCHAR *pwfilename;
  642. ULONG curoption;
  643. VERBOSERW((stderr, TEXT("user:permission pairs\n") ))
  644. // first proces the command line args to build up the new ace
  645. for (ULONG j = 0, k = 1;j < MAX_OPTIONS ; k <<= 1, j++ )
  646. {
  647. curoption = k;
  648. if (option & k)
  649. {
  650. for (LONG q = astart[j];
  651. q < aend[j] ; q++ )
  652. {
  653. VERBOSERW((stderr, TEXT(" %s\n"),argv[q] ))
  654. if ((k & OPTION_GRANT) || (k & OPTION_REPLACE))
  655. {
  656. if (!GetUserAndAccess(argv[q], &user, &access))
  657. {
  658. #if !defined(UNICODE) || !defined(_UNICODE)
  659. if (user)
  660. LocalFree(user);
  661. #endif
  662. return(ERROR_BAD_ARGUMENTS);
  663. }
  664. if (GENERIC_NONE == access)
  665. {
  666. if (!(k & OPTION_REPLACE))
  667. {
  668. #if !defined(UNICODE) || !defined(_UNICODE)
  669. if (user)
  670. LocalFree(user);
  671. #endif
  672. return(ERROR_BAD_ARGUMENTS);
  673. }
  674. }
  675. } else
  676. {
  677. #if !defined(UNICODE) || !defined(_UNICODE)
  678. user = mbstowcs(argv[q]);
  679. #else
  680. user = argv[q];
  681. #endif
  682. access = GENERIC_NONE;
  683. }
  684. VERBOSERW((stderr, TEXT("OPTION = %d, USER = %ws, ACCESS = %lx\n"),
  685. option,
  686. user,
  687. access))
  688. if (ERROR_SUCCESS != (ret = cdw.SetAccess(curoption,
  689. user,
  690. NULL,
  691. access)))
  692. {
  693. ERRORS((stderr, "SetAccess for %ws:%lx failed, %d\n",
  694. user,
  695. access,
  696. ret))
  697. #if !defined(UNICODE) || !defined(_UNICODE)
  698. LocalFree(user);
  699. #endif
  700. return(ret);
  701. }
  702. #if !defined(UNICODE) || !defined(_UNICODE)
  703. LocalFree(user);
  704. #endif
  705. user = NULL;
  706. }
  707. }
  708. }
  709. BOOL fdir;
  710. if (emode == MODE_REPLACE)
  711. {
  712. CHAR well[MAX_PATH];
  713. CHAR msgbuf[MAX_PATH];
  714. printmessage(stdout,MSG_CACLS_ARE_YOU_SURE, NULL);
  715. FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE, NULL, MSG_CACLS_Y, 0,
  716. msgbuf, MAX_PATH, NULL);
  717. fgets(well,MAX_PATH,stdin);
  718. // remove the trailing return
  719. if ('\n' == well[strlen(well) - sizeof(CHAR)])
  720. well[strlen(well) - sizeof(CHAR)] = '\0';
  721. if (0 != _stricmp(well, msgbuf))
  722. {
  723. FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE, NULL, MSG_CACLS_YES, 0,
  724. msgbuf, MAX_PATH, NULL);
  725. if (0 != _stricmp(well, msgbuf))
  726. return(ERROR_SUCCESS);
  727. }
  728. }
  729. if (NO_ERROR == (ret = cfe.Init(filename, &pwfilename, &fdir)))
  730. {
  731. while ( (NO_ERROR == ret) ||
  732. ( ( (ERROR_ACCESS_DENIED == ret ) || (ERROR_SHARING_VIOLATION == ret) )&&
  733. (option & OPTION_CONTINUE_ON_ERROR) ) )
  734. {
  735. CFileSecurity cfs(pwfilename);
  736. if (NO_ERROR == (ret = cfs.Init()))
  737. {
  738. if (NO_ERROR != (ret = cfs.SetFS(emode == MODE_REPLACE ? FALSE : TRUE, &cdw, fdir)))
  739. {
  740. if (!(((ERROR_ACCESS_DENIED == ret) || (ERROR_SHARING_VIOLATION == ret)) &&
  741. (option & OPTION_CONTINUE_ON_ERROR)))
  742. {
  743. ERRORS((stderr, "SetFS on %ws failed %ld\n",pwfilename, ret))
  744. return(ret);
  745. }
  746. }
  747. }
  748. else
  749. {
  750. //
  751. // If the error is access denied or sharing violation and we are to continue on error,
  752. // then keep going. Otherwise bail out here.
  753. //
  754. if (!(((ERROR_ACCESS_DENIED == ret) || (ERROR_SHARING_VIOLATION == ret)) &&
  755. (option & OPTION_CONTINUE_ON_ERROR))) {
  756. ERRORS((stderr, "init failed, %d\n",ret))
  757. return(ret);
  758. }
  759. }
  760. if (NO_ERROR == ret)
  761. {
  762. if (fdir)
  763. {
  764. printmessage(stdout, MSG_CACLS_PROCESSED_DIR, NULL);
  765. cprintf(L"%s\n", pwfilename);
  766. }
  767. else
  768. {
  769. printmessage(stdout, MSG_CACLS_PROCESSED_FILE, NULL);
  770. cprintf(L"%s\n", pwfilename);
  771. }
  772. }
  773. else if (ERROR_ACCESS_DENIED == ret)
  774. {
  775. printmessage(stdout, MSG_CACLS_ACCESS_DENIED, NULL);
  776. cprintf(L"%s\n", pwfilename);
  777. }
  778. else if (ret == ERROR_SHARING_VIOLATION)
  779. {
  780. printmessage(stdout, MSG_CACLS_SHARING_VIOLATION, NULL);
  781. cprintf(L"%s\n", pwfilename);
  782. }
  783. if ( (NO_ERROR == ret) ||
  784. ( ( (ERROR_ACCESS_DENIED == ret ) || (ERROR_SHARING_VIOLATION == ret) ) &&
  785. (option & OPTION_CONTINUE_ON_ERROR) ) )
  786. ret = cfe.Next(&pwfilename, &fdir);
  787. }
  788. switch (ret)
  789. {
  790. case ERROR_NO_MORE_FILES:
  791. ret = ERROR_SUCCESS;
  792. break;
  793. case ERROR_ACCESS_DENIED:
  794. case ERROR_SHARING_VIOLATION:
  795. break;
  796. case ERROR_SUCCESS:
  797. break;
  798. default:
  799. DISPLAY((stderr, "%ws failed: %d\n", pwfilename, ret))
  800. break;
  801. }
  802. } else
  803. ERRORS((stderr, "file enumeration failed to initialize %ws, %ld\n",pwfilename, ret))
  804. if (ret == ERROR_NO_MORE_FILES)
  805. {
  806. ret = ERROR_SUCCESS;
  807. }
  808. if (ret != ERROR_SUCCESS)
  809. {
  810. ERRORS((stderr, "Enumeration failed, %d\n",ret))
  811. }
  812. return(ret);
  813. }
  814. #if DBG
  815. //---------------------------------------------------------------------------
  816. //
  817. // Function: DebugEnumerate
  818. //
  819. // Synopsis: debug function
  820. //
  821. // Arguments: IN [filename] - file name
  822. // IN [option] - option
  823. //
  824. //----------------------------------------------------------------------------
  825. ULONG DebugEnumerate(TCHAR *filename, ULONG option)
  826. {
  827. CFileEnumerate cfe(option & OPTION_TREE);
  828. WCHAR *pwfilename;
  829. BOOL fdir;
  830. ULONG ret;
  831. ret = cfe.Init(filename, &pwfilename, &fdir);
  832. while ( (ERROR_SUCCESS == ret) ||
  833. ( (ERROR_ACCESS_DENIED == ret ) &&
  834. (option & OPTION_CONTINUE_ON_ERROR) ) )
  835. {
  836. if (fdir)
  837. printf("dir name = %ws%ws\n",pwfilename,
  838. ERROR_ACCESS_DENIED == ret ? L"ACCESS DENIED" : L"");
  839. else
  840. printf("file name = %ws%ws\n",pwfilename,
  841. ERROR_ACCESS_DENIED == ret ? L"ACCESS DENIED" : L"");
  842. ret = cfe.Next(&pwfilename, &fdir);
  843. }
  844. if (ret == ERROR_ACCESS_DENIED)
  845. {
  846. if (fdir)
  847. printf("dir name = %ws%ws\n",pwfilename,
  848. ERROR_ACCESS_DENIED == ret ? L"ACCESS DENIED" : L"");
  849. else
  850. printf("file name = %ws%ws\n",pwfilename,
  851. ERROR_ACCESS_DENIED == ret ? L"ACCESS DENIED" : L"");
  852. }
  853. if (ret != ERROR_NO_MORE_FILES)
  854. printf("Enumeration failed, %d\n",ret);
  855. return(ret);
  856. }
  857. #endif
  858. //---------------------------------------------------------------------------
  859. //
  860. // Function: GetUserAccess
  861. //
  862. // Synopsis: parses an input string for user:access
  863. //
  864. // Arguments: IN [arg] - input string to parse
  865. // OUT [user] - user if found
  866. // OUT [access] - access if found
  867. //
  868. //----------------------------------------------------------------------------
  869. BOOL GetUserAndAccess(TCHAR *arg, WCHAR **user, ULONG *access)
  870. {
  871. TCHAR *saccess = wcschr(arg,':');
  872. if (saccess)
  873. {
  874. *saccess = NULL;
  875. saccess++;
  876. if (wcschr(saccess,':'))
  877. return(FALSE);
  878. #if defined(UNICODE) || defined(_UNICODE)
  879. *user = arg;
  880. #else
  881. *user = mbstowcs(arg);
  882. #endif
  883. if (0 == lstrcmpi(saccess, TEXT("F") ))
  884. {
  885. *access = ( STANDARD_RIGHTS_ALL |
  886. FILE_READ_DATA |
  887. FILE_WRITE_DATA |
  888. FILE_APPEND_DATA |
  889. FILE_READ_EA |
  890. FILE_WRITE_EA |
  891. FILE_EXECUTE |
  892. FILE_DELETE_CHILD |
  893. FILE_READ_ATTRIBUTES |
  894. FILE_WRITE_ATTRIBUTES );
  895. }
  896. else if (0 == lstrcmpi(saccess,TEXT("R") ))
  897. {
  898. *access = FILE_GENERIC_READ | FILE_EXECUTE;
  899. }
  900. else if (0 == lstrcmpi(saccess, TEXT("C") ))
  901. {
  902. *access = FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_EXECUTE | DELETE;
  903. }
  904. else if (0 == lstrcmpi(saccess, TEXT("N") ))
  905. {
  906. *access = GENERIC_NONE;
  907. }
  908. else if (0 == lstrcmpi(saccess, TEXT("W") ))
  909. {
  910. *access = FILE_GENERIC_WRITE | FILE_EXECUTE;
  911. }
  912. else
  913. return(FALSE);
  914. return(TRUE);
  915. }
  916. return(FALSE);
  917. }
  918. //---------------------------------------------------------------------------
  919. //
  920. // Function: mbstowcs
  921. //
  922. // Synopsis: converts char to wchar, allocates space for wchar
  923. //
  924. // Arguments: IN [aname] - char string
  925. //
  926. //----------------------------------------------------------------------------
  927. WCHAR *mbstowcs(char *aname )
  928. {
  929. if (aname)
  930. {
  931. WCHAR *pwname = NULL;
  932. pwname = (WCHAR *)LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * (strlen(aname)+1));
  933. if (NULL == pwname)
  934. return(NULL);
  935. WCHAR *prwname = pwname;
  936. if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  937. aname, -1,
  938. prwname, sizeof(WCHAR)*(strlen(aname)+1)) == 0)
  939. return(NULL);
  940. return(pwname);
  941. } else
  942. return(NULL);
  943. }
  944. //----------------------------------------------------------------------------
  945. //
  946. // Function:
  947. //
  948. // Synopsis:
  949. //
  950. // Arguments:
  951. //
  952. //----------------------------------------------------------------------------
  953. BOOLEAN OpenToken(PHANDLE ph)
  954. {
  955. HANDLE hprocess;
  956. hprocess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
  957. if (hprocess == NULL)
  958. return(FALSE);
  959. if (OpenProcessToken(hprocess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ph))
  960. {
  961. CloseHandle(hprocess);
  962. return(TRUE);
  963. }
  964. CloseHandle(hprocess);
  965. return(FALSE);
  966. }
  967. //----------------------------------------------------------------------------
  968. //
  969. // Function: printfsid
  970. //
  971. // Synopsis: prints a NT SID
  972. //
  973. // Arguments: IN [psid] - pointer to the sid to print
  974. //
  975. //----------------------------------------------------------------------------
  976. void printfsid(SID *psid, ULONG *outputoffset)
  977. {
  978. #if DBG
  979. if ((Debug & DEBUG_VERBOSE) || (Debug & DEBUG_DISPLAY_SIDS))
  980. {
  981. printf("S-%lx",psid->Revision);
  982. if ( (psid->IdentifierAuthority.Value[0] != 0) ||
  983. (psid->IdentifierAuthority.Value[1] != 0) )
  984. {
  985. printf("0x%02hx%02hx%02hx%02hx%02hx%02hx",
  986. (USHORT)psid->IdentifierAuthority.Value[0],
  987. (USHORT)psid->IdentifierAuthority.Value[1],
  988. (USHORT)psid->IdentifierAuthority.Value[2],
  989. (USHORT)psid->IdentifierAuthority.Value[3],
  990. (USHORT)psid->IdentifierAuthority.Value[4],
  991. (USHORT)psid->IdentifierAuthority.Value[5] );
  992. } else
  993. {
  994. printf("-%lu",
  995. (ULONG)psid->IdentifierAuthority.Value[5] +
  996. (ULONG)(psid->IdentifierAuthority.Value[4] << 8) +
  997. (ULONG)(psid->IdentifierAuthority.Value[3] << 16) +
  998. (ULONG)(psid->IdentifierAuthority.Value[2] << 24) );
  999. }
  1000. if ( 0 < psid->SubAuthorityCount )
  1001. {
  1002. for (int k = 0; k < psid->SubAuthorityCount; k++ )
  1003. {
  1004. printf("-%d",psid->SubAuthority[k]);
  1005. }
  1006. }
  1007. }
  1008. #endif
  1009. ULONG ret;
  1010. CAccount ca(psid, NULL);
  1011. WCHAR *domain = NULL;
  1012. WCHAR *user;
  1013. if (NO_ERROR == ( ret = ca.GetAccountDomain(&domain) ) )
  1014. {
  1015. if ( (NULL == domain) || (0 == wcslen(domain)) )
  1016. {
  1017. fprintf(stdout, " ");
  1018. *outputoffset +=1;
  1019. }
  1020. else
  1021. {
  1022. fprintf(stdout, " ");
  1023. wprintf(L"%s", domain);
  1024. fprintf(stdout, "\\");
  1025. *outputoffset += 2 + wcslen( domain );;
  1026. }
  1027. if (NO_ERROR == ( ret = ca.GetAccountName(&user) ) )
  1028. {
  1029. wprintf(L"%s", user);
  1030. fprintf(stdout, ":");
  1031. *outputoffset += 1 + wcslen(user);
  1032. } else
  1033. {
  1034. *outputoffset += printmessage(stdout, MSG_CACLS_NAME_NOT_FOUND, NULL);
  1035. ERRORS((stderr, "(%lx)",ret))
  1036. }
  1037. } else
  1038. {
  1039. *outputoffset+= printmessage(stdout, MSG_CACLS_DOMAIN_NOT_FOUND, NULL);
  1040. ERRORS((stderr, "(%lx)",ret))
  1041. }
  1042. VERBOSE((stderr, "\n"))
  1043. }
  1044. //----------------------------------------------------------------------------
  1045. //
  1046. // Function: printface
  1047. //
  1048. // Synopsis: prints the specifed ace
  1049. //
  1050. // Arguments: IN [paceh] - input ace (header)
  1051. // IN [fdir] - TRUE = directory (different display options)
  1052. //
  1053. //----------------------------------------------------------------------------
  1054. void printface(ACE_HEADER *paceh, BOOL fdir, ULONG outputoffset)
  1055. {
  1056. VERBOSE((stderr, " "))
  1057. VERBOSER((stderr, "\npaceh->AceType = %x\n",paceh->AceType ))
  1058. VERBOSER((stderr, "paceh->AceFlags = %x\n",paceh->AceFlags ))
  1059. VERBOSER((stderr, "paceh->AceSize = %x\n",paceh->AceSize ))
  1060. ACCESS_ALLOWED_ACE *paaa = (ACCESS_ALLOWED_ACE *)paceh;
  1061. printfsid((SID *)&(paaa->SidStart),&outputoffset);
  1062. if (paceh->AceFlags & OBJECT_INHERIT_ACE )
  1063. {
  1064. outputoffset+= printmessage(stdout, MSG_CACLS_OBJECT_INHERIT, NULL);
  1065. }
  1066. if (paceh->AceFlags & CONTAINER_INHERIT_ACE )
  1067. {
  1068. outputoffset+= printmessage(stdout, MSG_CACLS_CONTAINER_INHERIT, NULL);
  1069. }
  1070. if (paceh->AceFlags & NO_PROPAGATE_INHERIT_ACE)
  1071. {
  1072. outputoffset+= printmessage(stdout, MSG_CACLS_NO_PROPAGATE_INHERIT, NULL);
  1073. }
  1074. if (paceh->AceFlags & INHERIT_ONLY_ACE )
  1075. {
  1076. outputoffset+= printmessage(stdout, MSG_CACLS_INHERIT_ONLY, NULL);
  1077. }
  1078. if (paceh->AceType == ACCESS_DENIED_ACE_TYPE)
  1079. {
  1080. DISPLAY_MASK((stderr, "(DENIED)"))
  1081. VERBOSE((stderr, "(DENIED)"))
  1082. }
  1083. printfmask(paaa->Mask, paceh->AceType, fdir, outputoffset);
  1084. fprintf(stdout, "\n");
  1085. }
  1086. //----------------------------------------------------------------------------
  1087. //
  1088. // Function: printfmask
  1089. //
  1090. // Synopsis: prints the access mask
  1091. //
  1092. // Arguments: IN [mask] - the access mask
  1093. // IN [acetype] - allowed/denied
  1094. // IN [fdir] - TRUE = directory
  1095. //
  1096. //----------------------------------------------------------------------------
  1097. CHAR *aRightsStr[] = { "STANDARD_RIGHTS_ALL",
  1098. "DELETE",
  1099. "READ_CONTROL",
  1100. "WRITE_DAC",
  1101. "WRITE_OWNER",
  1102. "SYNCHRONIZE",
  1103. "STANDARD_RIGHTS_REQUIRED",
  1104. "SPECIFIC_RIGHTS_ALL",
  1105. "ACCESS_SYSTEM_SECURITY",
  1106. "MAXIMUM_ALLOWED",
  1107. "GENERIC_READ",
  1108. "GENERIC_WRITE",
  1109. "GENERIC_EXECUTE",
  1110. "GENERIC_ALL",
  1111. "FILE_GENERIC_READ",
  1112. "FILE_GENERIC_WRITE",
  1113. "FILE_GENERIC_EXECUTE",
  1114. "FILE_READ_DATA",
  1115. //FILE_LIST_DIRECTORY
  1116. "FILE_WRITE_DATA",
  1117. //FILE_ADD_FILE
  1118. "FILE_APPEND_DATA",
  1119. //FILE_ADD_SUBDIRECTORY
  1120. "FILE_READ_EA",
  1121. "FILE_WRITE_EA",
  1122. "FILE_EXECUTE",
  1123. //FILE_TRAVERSE
  1124. "FILE_DELETE_CHILD",
  1125. "FILE_READ_ATTRIBUTES",
  1126. "FILE_WRITE_ATTRIBUTES" };
  1127. #define NUMRIGHTS 26
  1128. ULONG aRights[NUMRIGHTS] = { STANDARD_RIGHTS_ALL ,
  1129. DELETE ,
  1130. READ_CONTROL ,
  1131. WRITE_DAC ,
  1132. WRITE_OWNER ,
  1133. SYNCHRONIZE ,
  1134. STANDARD_RIGHTS_REQUIRED ,
  1135. SPECIFIC_RIGHTS_ALL ,
  1136. ACCESS_SYSTEM_SECURITY ,
  1137. MAXIMUM_ALLOWED ,
  1138. GENERIC_READ ,
  1139. GENERIC_WRITE ,
  1140. GENERIC_EXECUTE ,
  1141. GENERIC_ALL ,
  1142. FILE_GENERIC_READ ,
  1143. FILE_GENERIC_WRITE ,
  1144. FILE_GENERIC_EXECUTE ,
  1145. FILE_READ_DATA ,
  1146. //FILE_LIST_DIRECTORY ,
  1147. FILE_WRITE_DATA ,
  1148. //FILE_ADD_FILE ,
  1149. FILE_APPEND_DATA ,
  1150. //FILE_ADD_SUBDIRECTORY ,
  1151. FILE_READ_EA ,
  1152. FILE_WRITE_EA ,
  1153. FILE_EXECUTE ,
  1154. //FILE_TRAVERSE ,
  1155. FILE_DELETE_CHILD ,
  1156. FILE_READ_ATTRIBUTES ,
  1157. FILE_WRITE_ATTRIBUTES };
  1158. void printfmask(ULONG mask, UCHAR acetype, BOOL fdir, ULONG outputoffset)
  1159. {
  1160. ULONG savmask = mask;
  1161. VERBOSER((stderr, "mask = %08lx ", mask))
  1162. DISPLAY_MASK((stderr, "mask = %08lx\n", mask))
  1163. VERBOSE((stderr, " "))
  1164. #if DBG
  1165. if (!(Debug & (DEBUG_VERBOSE | DEBUG_DISPLAY_MASK)))
  1166. {
  1167. #endif
  1168. if ((acetype == ACCESS_ALLOWED_ACE_TYPE) &&
  1169. (mask == (FILE_GENERIC_READ | FILE_EXECUTE)))
  1170. {
  1171. printmessage(stdout, MSG_CACLS_READ, NULL);
  1172. } else if ((acetype == ACCESS_ALLOWED_ACE_TYPE) &&
  1173. (mask == (FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_EXECUTE | DELETE)))
  1174. {
  1175. printmessage(stdout, MSG_CACLS_CHANGE, NULL);
  1176. } else if ((acetype == ACCESS_ALLOWED_ACE_TYPE) &&
  1177. (mask == (GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE | DELETE)))
  1178. {
  1179. printmessage(stdout, MSG_CACLS_CHANGE, NULL);
  1180. } else if ((acetype == ACCESS_ALLOWED_ACE_TYPE) &&
  1181. (mask == ( STANDARD_RIGHTS_ALL |
  1182. FILE_READ_DATA |
  1183. FILE_WRITE_DATA |
  1184. FILE_APPEND_DATA |
  1185. FILE_READ_EA |
  1186. FILE_WRITE_EA |
  1187. FILE_EXECUTE |
  1188. FILE_DELETE_CHILD |
  1189. FILE_READ_ATTRIBUTES |
  1190. FILE_WRITE_ATTRIBUTES )) )
  1191. {
  1192. printmessage(stdout, MSG_CACLS_FULL_CONTROL, NULL);
  1193. } else if ((acetype == ACCESS_ALLOWED_ACE_TYPE) &&
  1194. (mask == GENERIC_ALL))
  1195. {
  1196. printmessage(stdout, MSG_CACLS_FULL_CONTROL, NULL);
  1197. } else if ((acetype == ACCESS_DENIED_ACE_TYPE) &&
  1198. (mask == GENERIC_ALL))
  1199. {
  1200. printmessage(stdout, MSG_CACLS_NONE, NULL);
  1201. } else if ((acetype == ACCESS_DENIED_ACE_TYPE) &&
  1202. (mask == ( STANDARD_RIGHTS_ALL |
  1203. FILE_READ_DATA |
  1204. FILE_WRITE_DATA |
  1205. FILE_APPEND_DATA |
  1206. FILE_READ_EA |
  1207. FILE_WRITE_EA |
  1208. FILE_EXECUTE |
  1209. FILE_DELETE_CHILD |
  1210. FILE_READ_ATTRIBUTES |
  1211. FILE_WRITE_ATTRIBUTES )) )
  1212. {
  1213. printmessage(stdout, MSG_CACLS_NONE, NULL);
  1214. } else
  1215. {
  1216. if (acetype == ACCESS_DENIED_ACE_TYPE)
  1217. printmessage(stdout, MSG_CACLS_DENY, NULL);
  1218. printmessage(stdout, MSG_CACLS_SPECIAL_ACCESS, NULL);
  1219. for (int k = 0; k<NUMRIGHTS ; k++ )
  1220. {
  1221. if ((mask & aRights[k]) == aRights[k])
  1222. {
  1223. fprintf(stdout, "%*s%s\n",outputoffset, " ", aRightsStr[k]);
  1224. }
  1225. if (mask == 0)
  1226. break;
  1227. }
  1228. }
  1229. #if DBG
  1230. } else
  1231. {
  1232. if (Debug & (DEBUG_DISPLAY_MASK | DEBUG_VERBOSE))
  1233. {
  1234. printf("\n");
  1235. for (int k = 0; k<NUMRIGHTS ; k++ )
  1236. {
  1237. if ((mask & aRights[k]) == aRights[k])
  1238. {
  1239. if (mask != savmask) printf(" |\n");
  1240. printf(" %s",aRightsStr[k]);
  1241. mask &= ~aRights[k];
  1242. }
  1243. if (mask == 0)
  1244. break;
  1245. }
  1246. }
  1247. VERBOSE((stderr, "=%x",mask))
  1248. if (mask != 0)
  1249. DISPLAY((stderr, "=%x/%x",mask,savmask))
  1250. }
  1251. #endif
  1252. fprintf(stdout, " ");
  1253. }
  1254. //----------------------------------------------------------------------------
  1255. //
  1256. // Function: printmessage
  1257. //
  1258. // Synopsis: prints a message, either from the local message file, or from the system
  1259. //
  1260. // Arguments: IN [fp] - stderr, stdio, etc.
  1261. // IN [messageID] - variable argument list
  1262. //
  1263. // Returns: length of the output buffer
  1264. //
  1265. //----------------------------------------------------------------------------
  1266. ULONG
  1267. __cdecl
  1268. printmessage (FILE* fp, DWORD messageID, ...)
  1269. {
  1270. WCHAR messagebuffer[4096];
  1271. va_list ap;
  1272. va_start(ap, messageID);
  1273. if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, NULL, messageID, 0,
  1274. messagebuffer, 4095, &ap))
  1275. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, messageID, 0,
  1276. messagebuffer, 4095, &ap);
  1277. CHAR achOem[2048];
  1278. WideCharToMultiByte(CP_OEMCP,
  1279. 0,
  1280. messagebuffer,
  1281. -1,
  1282. achOem,
  1283. sizeof(achOem),
  1284. NULL,
  1285. NULL);
  1286. fprintf(fp, achOem);
  1287. va_end(ap);
  1288. return(wcslen(messagebuffer));
  1289. }