Leaked source code of windows server 2003
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.

1338 lines
43 KiB

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