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.

4264 lines
109 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+============================================================================
  3. //
  4. // trklib.hxx
  5. //
  6. // Private classes and declarations shared between
  7. // Tracking (Workstation) Service and
  8. // Tracking (Server) Service.
  9. //
  10. //
  11. //+============================================================================
  12. #pragma once
  13. #include <cfiletim.hxx>
  14. #define ELEMENTS(x) (sizeof(x)/sizeof(x[0]))
  15. #define HIGH_WORD(dword) ( (WORD) (dword >> 16) )
  16. #define LO_WORD(dword) ( (WORD) (dword & 0xFFFF) )
  17. #define HIGH_BYTE(word) ( (BYTE) (word >> 8) )
  18. #define LO_BYTE(word) ( (BYTE) (word & 0xFF) )
  19. #define LINKDATA_AS_CLASS
  20. #include <linkdata.hxx>
  21. #include <trk.h>
  22. #include <rpcasync.h>
  23. #include <trkwks.h>
  24. #include <..\\common\\config.hxx>
  25. #include <disttrk.hxx>
  26. #include "debug.hxx"
  27. struct CDomainRelativeObjId;
  28. #if !DBG || defined(lint) || defined(_lint)
  29. #define DBGSTATIC static // hidden function
  30. #else
  31. #define DBGSTATIC // visible for use in debugger.
  32. #endif
  33. #ifdef TRKDATA_ALLOCATE
  34. #define EXTERN
  35. #define INIT( _x) = _x
  36. #else
  37. #define EXTERN extern
  38. #define INIT( _x)
  39. #endif
  40. const extern TCHAR s_tszKeyNameLinkTrack[];
  41. // RTL_SYSTEM_VOLUME_INFORMATION_FOLDER is "System Volume Information"
  42. const extern TCHAR s_tszSystemVolumeInformation[] INIT( RTL_SYSTEM_VOLUME_INFORMATION_FOLDER );
  43. const extern TCHAR s_tszLogFileName[] INIT( L"\\" RTL_SYSTEM_VOLUME_INFORMATION_FOLDER L"\\tracking.log" );
  44. const extern TCHAR s_tszOldLogFileName[] INIT(TEXT("\\~secure.nt\\tracking.log"));
  45. // ------------
  46. // Debug Levels
  47. // ------------
  48. //
  49. // The following defines are used to describe debug messages.
  50. // Each TrkLog call is categorized in one of three ways:
  51. // error - TRKDBG_ERROR
  52. // scenario - e.g. TRKDBG_MOVE
  53. // component - e.g. TRKDBG_SVR
  54. //
  55. //
  56. // Tracing based on classes:
  57. //
  58. #define TRKDBG_TIMER 0x10000000
  59. #define TRKDBG_IDT 0x08000000 // CIntraDomainTable
  60. #define TRKDBG_SVR 0x04000000 // CTrkSvrSvc
  61. #define TRKDBG_LOG 0x02000000 // CLog, CVolumeList
  62. #define TRKDBG_PORT 0x01000000 // CPort
  63. #define TRKDBG_WORKMAN 0x00800000 // CWorkMan
  64. #define TRKDBG_VOLTAB 0x00400000 // CVolumeTable
  65. #define TRKDBG_LDAP 0x00200000 // ldap_ calls
  66. #define TRKDBG_WKS 0x00100000 // CTrkWksSvc
  67. #define TRKDBG_VOLMAP 0x00080000 // CPersistentVolumeMap
  68. #define TRKDBG_ADMIN 0x00040000
  69. #define TRKDBG_RPC 0x00020000
  70. #define TRKDBG_VOL_REFCNT 0x00010000
  71. #define TRKDBG_DENIAL 0x00008000 // CDenialChecker
  72. #define TRKDBG_VOLCACHE 0x00004000
  73. #define TRKDBG_OBJID_DELETIONS 0x00002000
  74. #define TRKDBG_TUNNEL 0x00001000
  75. #define TRKDBG_QUOTA 0x00000800 // CQuotaTable
  76. #define TRKDBG_MISC 0x00000400 // Miscellaneous
  77. #define TRKDBG_VOLUME 0x00000200
  78. //
  79. // Tracing based on scenarios:
  80. //
  81. #define TRKDBG_MOVE 0x00000800 // move, volume synchronization
  82. #define TRKDBG_MEND 0x00000400 // mend
  83. #define TRKDBG_GARBAGE_COLLECT 0x00000200 // all garbage collection
  84. #define TRKDBG_VOLTAB_RESTORE 0x00000100 // volume table restore
  85. #define TRKDBG_CREATE 0x00000080 // create link
  86. // Composite debug messages
  87. #define TRKDBG_ERROR 0x80000000
  88. #define TRKDBG_WARNING 0x40000000
  89. //
  90. // Internal error codes (those that are used across
  91. // and RPC boundary are in trk.idl).
  92. //
  93. #define TRK_E_CORRUPT_LOG 0x8dead001
  94. #define TRK_E_TIMER_REGISTRY_CORRUPT 0x8dead002
  95. #define TRK_E_REGISTRY_REFRESH_CORRUPT 0x8dead003
  96. #define TRK_E_CORRUPT_IDT 0x8dead004
  97. #define TRK_E_DB_CONNECT_ERROR 0x8dead005
  98. #define TRK_E_DN_TOO_LONG 0x8dead006
  99. #define TRK_E_DOMAIN_COMPUTER_NAMES_TOO_LONG 0x8dead007
  100. #define TRK_E_BAD_USERNAME_NO_SLASH 0x8dead008
  101. #define TRK_E_UNKNOWN_SID 0x8dead009
  102. #define TRK_E_IMPERSONATED_COMPUTERNAME_TOO_LONG 0x8dead00a
  103. #define TRK_E_UNKNOWN_SVR_MESSAGE_TYPE 0x8dead00b
  104. #define TRK_E_FAIL_TEST 0x8dead00c
  105. #define TRK_E_DENIAL_OF_SERVICE_ATTACK 0x8dead00d
  106. #define TRK_E_SERVICE_NOT_RUNNING 0x8dead00e
  107. #define TRK_E_TOO_MANY_UNSHORTENED_NOTIFICATIONS 0x8dead00f
  108. #define TRK_E_CORRUPT_CLNTSYNC 0x8dead010
  109. #define TRK_E_COMPUTER_NAME_TOO_LONG 0x8dead011
  110. #define TRK_E_SERVICE_STOPPING 0x8dead012
  111. #define TRK_E_BIRTHIDS_DONT_MATCH 0x8dead013
  112. #define TRK_E_CORRUPT_VOLTAB 0x8dead014
  113. #define TRK_E_INTERNAL_ERROR 0x8dead015
  114. #define TRK_E_PATH_TOO_LONG 0x8dead016
  115. #define TRK_E_GET_MACHINE_NAME_FAIL 0x8dead017
  116. #define TRK_E_SET_VOLUME_STATE_FAIL 0x8dead018
  117. #define TRK_E_VOLUME_ACCESS_DENIED 0x8dead019
  118. #define TRK_E_NOT_FOUND 0x8dead01b
  119. #define TRK_E_VOLUME_QUOTA_EXCEEDED 0x8dead01c
  120. #define TRK_E_SERVER_TOO_BUSY 0x8dead01e
  121. #define TRK_E_INVALID_VOLUME_ID 0x8dead01f
  122. #define TRK_E_CALLER_NOT_MACHINE_ACCOUNT 0x8dead020
  123. #define TRK_E_VOLUME_NOT_DRIVE 0x8dead021
  124. #if DBG
  125. TCHAR * StringizeServiceControl( DWORD dwControl );
  126. const TCHAR * GetErrorString(HRESULT hr);
  127. #endif
  128. HRESULT MapTR2HR( HRESULT tr );
  129. // ------
  130. // Macros
  131. // ------
  132. #if DBG
  133. #define IFDBG(x) x
  134. #else
  135. #define IFDBG(x)
  136. #endif
  137. #define SECONDS_IN_DAY (60 * 60 * 24)
  138. // Num characters in a string-ized GUID, not including the null terminator.
  139. // E.g. "{48dad90c-51fb-11d0-8c59-00c04fd90f85}"
  140. #define CCH_GUID_STRING 38
  141. // Verify that TCHARs are WCHARs
  142. #define ASSERT_TCHAR_IS_WCHAR TrkAssert( sizeof(TCHAR) == sizeof(WCHAR) )
  143. #define TRK_MAX_DOMAINNAME 15
  144. #define TRK_MAX_USERNAME 15
  145. #define RELEASE_INTERFACE(punk) if( NULL != punk ) { punk->Release(); punk = NULL; }
  146. // This structure is used to map TRK_E error codes to HRESULTs, and
  147. // to strings for debug use.
  148. struct TrkEMap
  149. {
  150. HRESULT tr; // TRK_E_* codes
  151. HRESULT hr;
  152. #if DBG
  153. TCHAR *ptszDescription;
  154. #endif
  155. };
  156. // -------------------
  157. // Function Prototypes
  158. // -------------------
  159. FILETIME GetFileTimeNow();
  160. BOOL EnablePrivilege( const TCHAR *ptszPrivilegeName );
  161. extern BOOL g_fRestorePrivilegeEnabled INIT(FALSE);
  162. inline void EnableRestorePrivilege()
  163. {
  164. if( !g_fRestorePrivilegeEnabled )
  165. {
  166. g_fRestorePrivilegeEnabled = TRUE;
  167. EnablePrivilege( SE_RESTORE_NAME );
  168. }
  169. }
  170. BOOL RunningAsAdministratorHack();
  171. #if DBG
  172. typedef VOID (*PFNRtlCheckForOrphanedCriticalSections)( HANDLE hThread );
  173. inline void
  174. TrkRtlCheckForOrphanedCriticalSections( HANDLE hThread )
  175. {
  176. static PFNRtlCheckForOrphanedCriticalSections pfnRtlCheckForOrphanedCriticalSections = NULL;
  177. static BOOL fGetProcAddress = FALSE;
  178. if( !fGetProcAddress )
  179. {
  180. fGetProcAddress = TRUE;
  181. pfnRtlCheckForOrphanedCriticalSections
  182. = (PFNRtlCheckForOrphanedCriticalSections)
  183. GetProcAddress( GetModuleHandle(TEXT("ntdll.dll")), "RtlCheckForOrphanedCriticalSections" );
  184. }
  185. if( NULL != pfnRtlCheckForOrphanedCriticalSections )
  186. pfnRtlCheckForOrphanedCriticalSections( hThread );
  187. }
  188. #endif
  189. LONG _BreakOnDebuggableException(DWORD dwException, EXCEPTION_POINTERS* pException );
  190. #define BreakOnDebuggableException() \
  191. ( (GetExceptionCode() == STATUS_ACCESS_VIOLATION) || (GetExceptionCode() == STATUS_POSSIBLE_DEADLOCK) \
  192. ? _BreakThenReturn( EXCEPTION_EXECUTE_HANDLER, GetExceptionCode(), GetExceptionInformation() ) \
  193. : EXCEPTION_EXECUTE_HANDLER)
  194. // Break to debugger within an exception handler
  195. #define BREAK_THEN_RETURN( i ) \
  196. _BreakThenReturn( i, GetExceptionCode(), GetExceptionInformation() )
  197. inline int _BreakThenReturn( int i, DWORD dwException, EXCEPTION_POINTERS* pException )
  198. {
  199. #if DBG
  200. if( NULL != pException )
  201. {
  202. TrkLog(( TRKDBG_ERROR, TEXT("!cxr %p;!exr %p"),
  203. pException->ContextRecord, pException->ExceptionRecord ));
  204. }
  205. DebugBreak();
  206. #endif
  207. return( i );
  208. }
  209. TCHAR * wcstotcs(TCHAR *ptszBuf, const WCHAR *pwsz);
  210. CHAR * tcstombs(CHAR *pszBuf, const TCHAR *ptsz);
  211. WCHAR * tcstowcs(WCHAR *pwszBuf, const TCHAR *ptsz);
  212. TCHAR * mbstotcs(TCHAR *ptszBuf, const CHAR *psz);
  213. BOOL IsLocalObjectVolume(const TCHAR *pwszPath);
  214. BOOL IsLocalObjectVolume( ULONG iVolume );
  215. DWORD
  216. TrkTimeUnits(const SYSTEMTIME &st );
  217. DWORD
  218. TrkTimeUnits(const CFILETIME &cft );
  219. extern VOID
  220. SZToCLSID( LPCSTR szCLSID, CLSID *pclsid );
  221. #include <fileops.hxx>
  222. //+-------------------------------------------------------------------------
  223. //
  224. // Inline routines to raise exceptions
  225. //
  226. //--------------------------------------------------------------------------
  227. #if DBG
  228. #define TrkRaiseException(e) dbgRaiseException(e, __FILE__, __LINE__)
  229. #define TrkRaiseWin32Error(e) dbgRaiseWin32Error(e, __FILE__, __LINE__)
  230. #define TrkRaiseLastError() dbgRaiseLastError( __FILE__, __LINE__)
  231. #define TrkRaiseNtStatus(e) dbgRaiseNtStatus(e, __FILE__, __LINE__)
  232. inline void dbgRaiseException( HRESULT hr, const char * pszFile, int line )
  233. {
  234. TrkLog((TRKDBG_WARNING, TEXT("Exception %08x at %hs:%d"), hr, pszFile, line));
  235. RaiseException( hr, 0, 0, NULL );
  236. }
  237. inline void dbgRaiseWin32Error( long lError, const char * pszFile, int line )
  238. {
  239. dbgRaiseException( HRESULT_FROM_WIN32( lError ), pszFile, line );
  240. }
  241. inline void dbgRaiseLastError( const char * pszFile, int line )
  242. {
  243. dbgRaiseWin32Error( GetLastError(), pszFile, line );
  244. }
  245. inline void dbgRaiseNtStatus( NTSTATUS ntstatus, const char * pszFile, int line )
  246. {
  247. dbgRaiseException( ntstatus, pszFile, line );
  248. }
  249. #else
  250. inline void TrkRaiseException( HRESULT hr )
  251. {
  252. RaiseException( hr, 0, 0, NULL );
  253. }
  254. inline void TrkRaiseWin32Error( long lError )
  255. {
  256. TrkRaiseException( HRESULT_FROM_WIN32( lError ) );
  257. }
  258. inline void TrkRaiseLastError( )
  259. {
  260. TrkRaiseWin32Error( GetLastError() );
  261. }
  262. inline void TrkRaiseNtStatus( NTSTATUS ntstatus )
  263. {
  264. TrkRaiseException( ntstatus );
  265. }
  266. #endif
  267. //+-------------------------------------------------------------------------
  268. //
  269. // Services.exe simulation
  270. //
  271. //--------------------------------------------------------------------------
  272. //HANDLE
  273. //TrkSvcAddWorkItem (
  274. // IN HANDLE hWaitableObject,
  275. // IN PSVCS_WORKER_CALLBACK pCallbackFunction,
  276. // IN PVOID pContext,
  277. // IN DWORD dwFlags,
  278. // IN DWORD dwTimeout,
  279. // IN HANDLE hDllReference
  280. // );
  281. //+-------------------------------------------------------------------------
  282. //
  283. // Time
  284. //
  285. //--------------------------------------------------------------------------
  286. //-------------------------------------------------------------------//
  287. // //
  288. // CGuid //
  289. // //
  290. //-------------------------------------------------------------------//
  291. #define MAX_STRINGIZED_GUID 35 // not including NULL
  292. void
  293. HexStringizeGuid(const GUID &g, TCHAR * & rptsz );
  294. void
  295. HexStringizeGuidA(const GUID &g, char * & rpsz);
  296. BOOL
  297. HexUnstringizeGuid(const TCHAR * &ptsz, GUID * pg);
  298. //+-------------------------------------------------------------------------
  299. //
  300. // CVolumeSecret inlines
  301. //
  302. //--------------------------------------------------------------------------
  303. inline
  304. CVolumeSecret::CVolumeSecret()
  305. {
  306. memset(this, 0, sizeof(*this));
  307. }
  308. inline
  309. CVolumeSecret::operator == (const CVolumeSecret & other) const
  310. {
  311. return memcmp( _abSecret, other._abSecret, sizeof(_abSecret) ) == 0;
  312. }
  313. inline
  314. CVolumeSecret::operator != (const CVolumeSecret & other) const
  315. {
  316. return memcmp( _abSecret, other._abSecret, sizeof(_abSecret) ) != 0;
  317. }
  318. inline void
  319. CVolumeSecret::Stringize(TCHAR * & rptsz) const
  320. {
  321. wsprintf( rptsz, TEXT("%02X%02X%02X%02X%02X%02X%02X%02X"),
  322. _abSecret[0],
  323. _abSecret[1],
  324. _abSecret[2],
  325. _abSecret[3],
  326. _abSecret[4],
  327. _abSecret[5],
  328. _abSecret[6],
  329. _abSecret[7] );
  330. rptsz += 16;
  331. }
  332. //-------------------------------------------------------------------//
  333. // //
  334. // CObjId inlines
  335. // //
  336. //-------------------------------------------------------------------//
  337. inline void
  338. CObjId::DebugPrint(const TCHAR *ptszName)
  339. {
  340. TCHAR tsz[256];
  341. TCHAR *ptsz = tsz;
  342. Stringize(ptsz);
  343. printf("%s=%s", ptszName, tsz);
  344. }
  345. inline void
  346. CObjId::Stringize(TCHAR * & rptsz) const
  347. {
  348. HexStringizeGuid(_object, rptsz);
  349. }
  350. inline BOOL
  351. CObjId::Unstringize(const TCHAR *&rptsz)
  352. {
  353. return( HexUnstringizeGuid( rptsz, (GUID*)&_object ));
  354. }
  355. inline RPC_STATUS
  356. CObjId::UuidCreate()
  357. {
  358. return(::UuidCreate(&_object));
  359. }
  360. //-------------------------------------------------------------------//
  361. // //
  362. // CVolumeId inlines
  363. // //
  364. //-------------------------------------------------------------------//
  365. // Convert a zero-relative drive letter index into a TCHAR
  366. inline TCHAR
  367. VolChar( LONG iVol )
  368. {
  369. if( 0 > iVol || 26 <= iVol )
  370. return( TEXT('?') );
  371. else
  372. return static_cast<TCHAR>( TEXT('A') + (TCHAR)iVol );
  373. }
  374. // Initialize a volid from a stringized representation of a GUID
  375. inline
  376. CVolumeId::CVolumeId(const TCHAR * ptszStringizedGuid, HRESULT hr)
  377. {
  378. if ( _tcslen(ptszStringizedGuid) < 32)
  379. {
  380. TrkRaiseException(hr);
  381. }
  382. HexUnstringizeGuid( ptszStringizedGuid, &_volume );
  383. }
  384. // Initialize a volid from the result of an
  385. // NtQueryVolumeInformationFile(FileFsObjectIdInformation)
  386. inline
  387. CVolumeId::operator FILE_FS_OBJECTID_INFORMATION () const
  388. {
  389. FILE_FS_OBJECTID_INFORMATION ffoi;
  390. memset( ffoi.ExtendedInfo, 0, sizeof(ffoi.ExtendedInfo) );
  391. memcpy( ffoi.ObjectId, &_volume, sizeof(ffoi.ObjectId) );
  392. return(ffoi);
  393. }
  394. // Write out the volid as a hex string.
  395. inline void
  396. CVolumeId::Stringize(TCHAR * & rptsz) const
  397. {
  398. HexStringizeGuid(_volume, rptsz);
  399. }
  400. // Read in the volid from a hex string.
  401. inline BOOL
  402. CVolumeId::Unstringize(const TCHAR * & rptsz)
  403. {
  404. return( HexUnstringizeGuid( rptsz, (GUID*)&_volume ));
  405. }
  406. //
  407. // We use bit 0 of the volume id as a flag that indicates
  408. // the file has been moved across volumes.
  409. //
  410. inline BOOL
  411. CVolumeId::GetUserBitState() const
  412. {
  413. return(_volume.Data1 & 1);
  414. }
  415. // Create a volume ID, ensuring that the cross-volume
  416. // bit is clear.
  417. inline RPC_STATUS
  418. CVolumeId::UuidCreate()
  419. {
  420. RPC_STATUS Status;
  421. int l=0;
  422. do
  423. {
  424. Status = ::UuidCreate(&_volume);
  425. l++;
  426. // UuidCreate uses the new randomized algorithm,
  427. // so we shouldn't get a net-based value any longer.
  428. TrkAssert( RPC_S_UUID_LOCAL_ONLY != Status );
  429. } while (l<100 && Status == RPC_S_OK && (_volume.Data1 & 1));
  430. if (l==100)
  431. {
  432. return(CO_E_FAILEDTOGENUUID);
  433. }
  434. return(Status);
  435. }
  436. inline
  437. CVolumeId:: operator == (const CVolumeId & Other) const
  438. {
  439. return( 0 == memcmp( &_volume, &Other._volume, sizeof(_volume) ) );
  440. }
  441. inline
  442. CVolumeId:: operator != (const CVolumeId & Other) const
  443. {
  444. return ! (Other == *this);
  445. }
  446. //-------------------------------------------------------------------//
  447. // //
  448. // CMachineId inlines
  449. // //
  450. //-------------------------------------------------------------------//
  451. #define MCID_BYTE_FORMAT_STRING TEXT("(%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X)")
  452. // Initialize from a char buffer.
  453. inline CMachineId::CMachineId(const char * pb, ULONG cb, HRESULT hr)
  454. {
  455. if (cb < sizeof(_szMachine))
  456. {
  457. TrkRaiseException(hr);
  458. }
  459. memcpy(_szMachine, pb, sizeof(_szMachine));
  460. }
  461. // Return the mcid's computer name in Unicode.
  462. inline void
  463. CMachineId::GetName(TCHAR *ptsz, DWORD cch) const
  464. {
  465. RaiseIfInvalid();
  466. TrkAssert(cch >= sizeof(_szMachine));
  467. mbstotcs(ptsz, _szMachine);
  468. }
  469. // Dump the mcid as a string
  470. inline void
  471. CMachineId::Stringize(TCHAR * & rptsz) const
  472. {
  473. RaiseIfInvalid();
  474. mbstotcs( rptsz, _szMachine );
  475. rptsz += _tcslen(rptsz);
  476. }
  477. // Dump the mcid as a GUID
  478. inline void
  479. CMachineId::StringizeAsGuid(TCHAR * & rptsz) const
  480. {
  481. _stprintf(rptsz, TEXT("\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x")
  482. TEXT("\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x"),
  483. (BYTE)_szMachine[0], (BYTE)_szMachine[1], (BYTE)_szMachine[2], (BYTE)_szMachine[3],
  484. (BYTE)_szMachine[4], (BYTE)_szMachine[5], (BYTE)_szMachine[6], (BYTE)_szMachine[7],
  485. (BYTE)_szMachine[8], (BYTE)_szMachine[9], (BYTE)_szMachine[10], (BYTE)_szMachine[11],
  486. (BYTE)_szMachine[12], (BYTE)_szMachine[13], (BYTE)_szMachine[14], (BYTE)_szMachine[15]);
  487. rptsz += 3 * 16;
  488. }
  489. inline void
  490. CMachineId::RaiseIfInvalid() const
  491. {
  492. if( !IsTerminated() )
  493. {
  494. TrkLog(( TRKDBG_WARNING,
  495. TEXT("Invalid CMachineId: ")
  496. MCID_BYTE_FORMAT_STRING,
  497. _szMachine,
  498. (BYTE)_szMachine[0], (BYTE)_szMachine[1], (BYTE)_szMachine[2], (BYTE)_szMachine[3],
  499. (BYTE)_szMachine[4], (BYTE)_szMachine[5], (BYTE)_szMachine[6], (BYTE)_szMachine[7],
  500. (BYTE)_szMachine[8], (BYTE)_szMachine[9], (BYTE)_szMachine[10], (BYTE)_szMachine[11],
  501. (BYTE)_szMachine[12], (BYTE)_szMachine[13], (BYTE)_szMachine[14], (BYTE)_szMachine[15] ));
  502. TrkRaiseWin32Error( ERROR_INVALID_COMPUTERNAME );
  503. }
  504. }
  505. inline BOOL
  506. CMachineId::IsTerminated() const
  507. {
  508. // We're valid if we're terminated.
  509. return('\0' == _szMachine[sizeof(_szMachine)-1] );
  510. }
  511. //-------------------------------------------------------------------//
  512. // //
  513. // CDomainRelativeObjId inlines
  514. // //
  515. //-------------------------------------------------------------------//
  516. #if DBG
  517. inline
  518. CDomainRelativeObjId::CDomainRelativeObjId(const TCHAR * ptszTest)
  519. {
  520. // test constructor only
  521. char * pszWrite = (char*)&_object;
  522. do
  523. {
  524. *pszWrite = (char) *ptszTest;
  525. } while (*pszWrite != '\0' && ptszTest[1] != TEXT(' ') && pszWrite++ && ptszTest++);
  526. }
  527. #endif
  528. inline void
  529. CDomainRelativeObjId::Init()
  530. {
  531. _volume.Init();
  532. _object.Init();
  533. }
  534. inline
  535. CDomainRelativeObjId::operator == (const CDomainRelativeObjId &Other) const
  536. {
  537. return(_volume == Other._volume && _object == Other._object);
  538. }
  539. inline
  540. CDomainRelativeObjId::operator != (const CDomainRelativeObjId &Other) const
  541. {
  542. return !(*this == Other);
  543. }
  544. inline void
  545. CDomainRelativeObjId::DebugPrint(const TCHAR *ptszName)
  546. {
  547. TCHAR tsz[256];
  548. TCHAR *ptsz = tsz;
  549. _volume.Stringize(ptsz);
  550. *ptsz++ = TEXT('-');
  551. _object.Stringize(ptsz);
  552. _tprintf(TEXT(" %s=%s\n"), ptszName, tsz);
  553. }
  554. //+----------------------------------------------------------------------------
  555. //
  556. // Class CTrkRpcConfig
  557. //
  558. // Base class for RPC configuration. This is inherited by CRpcClientBinding
  559. // and CRpcServer. This class inherits from CTrkConfiguration, which
  560. // represents the base key in the registry of the service's configuration.
  561. // This class represents the custom DC name values, the presence of which
  562. // controls whether secure RPC is used.
  563. //
  564. //+----------------------------------------------------------------------------
  565. class CTrkRpcConfig : protected CTrkConfiguration
  566. {
  567. protected:
  568. CTrkRpcConfig();
  569. public:
  570. friend void
  571. ServiceStopCallback( PVOID pContext, BOOLEAN fTimeout );
  572. friend VOID
  573. SVCS_ENTRY_POINT(
  574. DWORD NumArgs,
  575. LPTSTR *ArgsArray,
  576. PSVCHOST_GLOBAL_DATA pSvcsGlobalData,
  577. IN HANDLE SvcRefHandle
  578. );
  579. static BOOL RpcSecurityEnabled()
  580. {
  581. return( 0 == _mtszCustomDcName.NumStrings() );
  582. }
  583. static BOOL UseCustomDc()
  584. {
  585. return( 0 != _mtszCustomDcName.NumStrings() );
  586. }
  587. static BOOL UseCustomSecureDc()
  588. {
  589. return( 0 != _mtszCustomSecureDcName.NumStrings() );
  590. }
  591. static const TCHAR *GetCustomDcName()
  592. {
  593. return( _mtszCustomDcName );
  594. }
  595. static const TCHAR *GetCustomSecureDcName()
  596. {
  597. return( _mtszCustomDcName );
  598. }
  599. protected:
  600. // Since this class is used in multiple places as a base
  601. // class, the data members are static so that we only
  602. // read the registry once.
  603. static BOOL _fInitialized;
  604. // List of DC names to use. If this exists, then we're
  605. // not using secure RPC.
  606. static CMultiTsz _mtszCustomDcName;
  607. // List of DC names to use. If this exists, then we
  608. // are using security RPC (this has priority over the
  609. // previous value).
  610. static CMultiTsz _mtszCustomSecureDcName;
  611. }; // class CTrkRpcConfig
  612. //-------------------------------------------------------------------
  613. //
  614. // CObjIdEnumerator
  615. //
  616. // Enumerate the object IDs on a given volume. This uses the
  617. // FindFirst/FindNext model, and automatically ignores the volume
  618. // ID (which is stored in the NTFS object ID index).
  619. //
  620. //-------------------------------------------------------------------
  621. // The following defines shows how to determine if a filereference
  622. // in the enumeration is actually the volume ID.
  623. #define FILEREF_VOL 3
  624. #define FILEREF_MASK 0x0000ffffffffffff
  625. inline BOOL
  626. IsVolumeFileReference( LONGLONG FileReference )
  627. {
  628. return (FileReference & FILEREF_MASK) == FILEREF_VOL;
  629. }
  630. class CObjIdEnumerator
  631. {
  632. private:
  633. BOOL _fInitializeCalled:1;
  634. // Handle to the object ID index directory
  635. HANDLE _hDir;
  636. // Count of bytes returned by NtQueryDirectoryFile
  637. ULONG _cbObjIdInfo;
  638. // Buffer of data returned from an enumeration of the object ID index,
  639. // and a pointer into that buffer that represents the current location
  640. // (i.e. the cursor).
  641. FILE_OBJECTID_INFORMATION _ObjIdInfo[32];
  642. FILE_OBJECTID_INFORMATION * _pObjIdInfo;
  643. public:
  644. CObjIdEnumerator() : _fInitializeCalled(FALSE), _hDir(INVALID_HANDLE_VALUE) { }
  645. ~CObjIdEnumerator() { UnInitialize(); }
  646. BOOL Initialize( const TCHAR *ptszVolumeDeviceName );
  647. void UnInitialize();
  648. inline BOOL FindFirst( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth );
  649. inline BOOL FindNext( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth );
  650. private:
  651. static
  652. inline void UnloadFileObjectIdInfo( const FILE_OBJECTID_INFORMATION & ObjIdInfo,
  653. CObjId * pobjid, CDomainRelativeObjId * pdroidBirth );
  654. BOOL Find( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth, BOOL fRestart );
  655. };
  656. //+----------------------------------------------------------------------------
  657. //
  658. // CObjIdEnumerator inlines
  659. //
  660. //+----------------------------------------------------------------------------
  661. inline void
  662. CObjIdEnumerator::UnloadFileObjectIdInfo( const FILE_OBJECTID_INFORMATION & ObjIdInfo,
  663. CObjId * pobjid,
  664. CDomainRelativeObjId * pdroidBirth )
  665. {
  666. pdroidBirth->InitFromFOI( ObjIdInfo );
  667. *pobjid = CObjId( FOI_OBJECTID, ObjIdInfo );
  668. }
  669. // Get the first entry in the object ID index
  670. inline BOOL
  671. CObjIdEnumerator::FindFirst( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth )
  672. {
  673. return( Find( pobjid, pdroidBirth, TRUE ) );
  674. }
  675. // Get the next entry in the object ID index.
  676. inline BOOL
  677. CObjIdEnumerator::FindNext( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth )
  678. {
  679. TrkAssert(_cbObjIdInfo % sizeof(_ObjIdInfo[0]) == 0);
  680. // Start by looking to see
  681. // if there's another entry in the _ObjIdInfo buffer.
  682. while (_pObjIdInfo < &_ObjIdInfo[_cbObjIdInfo / sizeof(_ObjIdInfo[0])])
  683. {
  684. // There's an entry in the buffer. Is it a real entry, or the
  685. // volume ID?
  686. if( !IsVolumeFileReference( _pObjIdInfo->FileReference ))
  687. {
  688. // It's a real file entry. Return it to the user.
  689. UnloadFileObjectIdInfo( *_pObjIdInfo, pobjid, pdroidBirth );
  690. _pObjIdInfo ++;
  691. return(TRUE);
  692. }
  693. else
  694. {
  695. // It's the volume ID. Go on to the next entry in
  696. // the buffer.
  697. TrkLog((TRKDBG_GARBAGE_COLLECT|TRKDBG_VOLUME,
  698. TEXT("CObjIdEnumerator::FindNext() skipping volume id.")));
  699. _pObjIdInfo++;
  700. }
  701. }
  702. // If we get here, there are no more entries in the _ObjIdInfo buffer.
  703. // Query the object ID index directory for a new set of records.
  704. return(Find(pobjid, pdroidBirth, FALSE)); // don't restart scan
  705. }
  706. //-------------------------------------------------------------------
  707. //
  708. // CRpcServer
  709. //
  710. // This class maintains a server interface handle. It registers
  711. // the server, registers the endpoint (if it's dynamic), and
  712. // registers authentication info if necessary.
  713. //
  714. // This class is always used as a base class. The derived class
  715. // is responsible for the RpcUseProtseq calls.
  716. //
  717. //-------------------------------------------------------------------
  718. enum RPC_WAIT_FLAG
  719. {
  720. DONT_WAIT,
  721. WAIT
  722. };
  723. class CRpcServer : public CTrkRpcConfig
  724. {
  725. public:
  726. CRpcServer() : _ifspec(NULL), _fEpRegister(FALSE) {}
  727. ~CRpcServer() { UnInitialize(); }
  728. void Initialize( RPC_IF_HANDLE ifspec, ULONG grfRpcServerRegisterInterfaceEx,
  729. UINT cMaxCalls, BOOL fSetAuthInfo,
  730. const TCHAR *ptszProtSeqForEpRegistration );
  731. void UnInitialize();
  732. private:
  733. RPC_IF_HANDLE _ifspec;
  734. BOOL _fEpRegister;
  735. };
  736. //-------------------------------------------------------------------//
  737. // //
  738. // PWorkItem - Virtual function which is called by the CWorkManager //
  739. // when the corresponding waitable handle is signalled. //
  740. // Handles are registered using RegisterWorkItem //
  741. // //
  742. //-------------------------------------------------------------------//
  743. EXTERN DWORD g_cThreadPoolMaxThreads;
  744. EXTERN DWORD g_cThreadPoolThreads;
  745. #if DBG
  746. EXTERN LONG g_cThreadPoolRegistrations;
  747. #endif
  748. // Callback functions for the Win32 thread pool services.
  749. // Call a PWorkItem
  750. VOID NTAPI ThreadPoolCallbackFunction( PVOID pvWorkItem, BOOLEAN fTimeout );
  751. VOID NTAPI ThreadPoolWorkItemFunction( PVOID pvWorkItem );
  752. #ifdef PRIVATE_THREAD_POOL
  753. #include "workman2.hxx"
  754. #endif
  755. // Wrapper for [Un]RegisterWaitForSingleObjectEx
  756. inline HANDLE
  757. TrkRegisterWaitForSingleObjectEx( HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags )
  758. {
  759. HANDLE hWait;
  760. NTSTATUS Status = STATUS_SUCCESS;
  761. #ifdef PRIVATE_THREAD_POOL
  762. hWait = g_pworkman2->RegisterWait( hObject, Callback, Context, dwMilliseconds, dwFlags );
  763. #else
  764. Status = RtlRegisterWait( &hWait, hObject, Callback, Context, dwMilliseconds, dwFlags );
  765. if( !NT_SUCCESS(Status) )
  766. {
  767. SetLastError( RtlNtStatusToDosError( Status ));
  768. hWait = NULL;
  769. }
  770. #endif
  771. #if DBG
  772. if( NULL != hWait )
  773. InterlockedIncrement( &g_cThreadPoolRegistrations );
  774. #endif
  775. TrkLog(( TRKDBG_WORKMAN, TEXT("hWait=%p registered with thread pool (%08x)"), hWait, Status ));
  776. return( hWait );
  777. }
  778. inline BOOL
  779. TrkUnregisterWait( HANDLE hWait, HANDLE hCompletionEvent = (HANDLE)-1 )
  780. {
  781. BOOL fRet = FALSE;
  782. NTSTATUS Status = STATUS_SUCCESS;
  783. IFDBG( InterlockedDecrement( &g_cThreadPoolRegistrations ));
  784. #ifdef PRIVATE_THREAD_POOL
  785. fRet = g_pworkman2->UnregisterWait( hWait );
  786. #else
  787. Status = RtlDeregisterWaitEx( hWait, hCompletionEvent );
  788. if( NT_SUCCESS(Status) )
  789. fRet = TRUE;
  790. else
  791. SetLastError( RtlNtStatusToDosError( Status ));
  792. #endif
  793. TrkLog(( TRKDBG_WORKMAN, TEXT("hWait=%p %s unregistered from thread pool"),
  794. hWait,
  795. fRet ? TEXT("successfully"):TEXT("unsuccessfully") ));
  796. return( fRet );
  797. }
  798. inline NTSTATUS
  799. TrkQueueWorkItem( PVOID Context, ULONG dwFlags )
  800. {
  801. return RtlQueueWorkItem( ThreadPoolWorkItemFunction,
  802. Context,
  803. dwFlags );
  804. }
  805. class PWorkItem
  806. {
  807. public:
  808. virtual void DoWork() = 0;
  809. #if DBG
  810. TCHAR _tszWorkItemSig[48];
  811. PWorkItem() { _tszWorkItemSig[0] = TEXT('\0'); }
  812. #endif
  813. };
  814. //+----------------------------------------------------------------------------
  815. //
  816. // Class: CCriticalSection
  817. //
  818. // This class wraps a CRITICAL_SECTION, and exists to ensure that
  819. // InitializeCriticalSection is properly handled (that API can
  820. // raise STATUS_NO_MEMORY). That is, the critsec is only deleted
  821. // if it has been properly initialized.
  822. //
  823. //+----------------------------------------------------------------------------
  824. class CCriticalSection
  825. {
  826. private:
  827. BOOL _fInitialized;
  828. CRITICAL_SECTION _cs;
  829. public:
  830. CCriticalSection()
  831. {
  832. _fInitialized = FALSE;
  833. }
  834. ~CCriticalSection()
  835. {
  836. UnInitialize();
  837. }
  838. public:
  839. void Initialize()
  840. {
  841. TrkAssert( !_fInitialized );
  842. #if DBG
  843. __try
  844. {
  845. InitializeCriticalSection( &_cs );
  846. _fInitialized = TRUE;
  847. }
  848. __finally
  849. {
  850. if( AbnormalTermination() )
  851. {
  852. TrkLog(( TRKDBG_WARNING, TEXT("InitializeCriticalSection raised") ));
  853. }
  854. }
  855. #else
  856. InitializeCriticalSection( &_cs );
  857. _fInitialized = TRUE;
  858. #endif
  859. }
  860. BOOL IsInitialized()
  861. {
  862. return _fInitialized;
  863. }
  864. void UnInitialize()
  865. {
  866. if( _fInitialized )
  867. {
  868. _fInitialized = FALSE;
  869. DeleteCriticalSection( &_cs );
  870. }
  871. }
  872. void Enter()
  873. {
  874. if( !_fInitialized )
  875. TrkRaiseException( STATUS_NO_MEMORY );
  876. else
  877. EnterCriticalSection( &_cs );
  878. }
  879. BOOL TryEnter()
  880. {
  881. if( !_fInitialized )
  882. {
  883. TrkRaiseException( STATUS_NO_MEMORY );
  884. return 0; // Make compiler happy
  885. }
  886. else
  887. return TryEnterCriticalSection( &_cs );
  888. }
  889. void Leave()
  890. {
  891. TrkAssert( _fInitialized );
  892. if( _fInitialized )
  893. LeaveCriticalSection( &_cs );
  894. }
  895. }; // CCriticalSection
  896. //+----------------------------------------------------------------------------
  897. //
  898. // Class: CActiveThreadList
  899. //
  900. // This class is used to maintain a list of all active threads, be they from
  901. // the NTDLL thread pool or from the RPC thread pool. When such a thread
  902. // begins executing (within the context of this service), Add is called,
  903. // and on completion Remove is called. The reason this class exists is
  904. // for the CancelAllRpc method; this is used during service stop to call
  905. // RpcCancelThread on all active threads.
  906. //
  907. //+----------------------------------------------------------------------------
  908. // Initial size of the array to hold the active threads
  909. #define NUM_ACTIVE_THREAD_LIST 10
  910. // Incremental size by which that array grows
  911. #define INCREMENT_ACTIVE_THREAD_LIST 2
  912. class CActiveThreadList
  913. {
  914. private:
  915. ULONG _cMaxThreads;
  916. ULONG _cActiveThreads;
  917. DWORD *_prgdwThreadIDs;
  918. CCriticalSection _cs;
  919. public:
  920. inline CActiveThreadList();
  921. inline ~CActiveThreadList();
  922. public:
  923. inline void Initialize();
  924. HRESULT AddCurrent( ); // Add the current thread to the list
  925. HRESULT RemoveCurrent( ); // Remove the current thread
  926. void CancelAllRpc(); // Cancel RPCs on all threads in list
  927. inline ULONG GetCount() const;
  928. private:
  929. HRESULT Grow();
  930. }; // class CActiveThreadList
  931. // ------------------------------------
  932. //
  933. // CActiveThreadList::CActiveThreadList
  934. //
  935. // Initialize the thread list
  936. //
  937. // ------------------------------------
  938. CActiveThreadList::CActiveThreadList()
  939. {
  940. _cActiveThreads = _cMaxThreads = 0;
  941. // Allocate an array for the thread IDs. If this alloc fails,
  942. // we'll try to realloc in the AddCurrent method.
  943. _prgdwThreadIDs = new DWORD[ NUM_ACTIVE_THREAD_LIST ];
  944. if( NULL != _prgdwThreadIDs )
  945. {
  946. _cMaxThreads = NUM_ACTIVE_THREAD_LIST;
  947. memset( _prgdwThreadIDs, 0, sizeof(_prgdwThreadIDs[0]) * _cMaxThreads );
  948. }
  949. else
  950. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't alloc CActiveThreadList in constructor") ));
  951. }
  952. inline void
  953. CActiveThreadList::Initialize()
  954. {
  955. _cs.Initialize();
  956. }
  957. // -------------------------------------
  958. //
  959. // CActiveThreadList::~CActiveThreadList
  960. //
  961. // Frees the thread list
  962. //
  963. // -------------------------------------
  964. CActiveThreadList::~CActiveThreadList()
  965. {
  966. if( NULL != _prgdwThreadIDs )
  967. delete [] _prgdwThreadIDs;
  968. _prgdwThreadIDs = NULL;
  969. _cActiveThreads = _cMaxThreads = 0;
  970. }
  971. // ---------------------------
  972. // CActiveThreadList::GetCount
  973. // ---------------------------
  974. ULONG
  975. CActiveThreadList::GetCount() const
  976. {
  977. return( _cActiveThreads );
  978. }
  979. // Global pointer to the one-and-only CActiveThreadList instantiation
  980. extern "C" CActiveThreadList *g_pActiveThreadList INIT(NULL);
  981. //+----------------------------------------------------------------------------
  982. //
  983. // SThreadFromPoolState
  984. //
  985. // This structure stores useful thread state information, which is
  986. // really just the HardErrorMode. When we get a thread from one of
  987. // the thread pools, we save this value, then modify it so that
  988. // we don't get hard errors. When we're done with the thread we
  989. // restore it.
  990. //
  991. // E.g.:
  992. // SThreadFromPoolState state = InitializeThreadFromPool();
  993. // ...
  994. // UnInitializedThreadFromPool( state );
  995. //
  996. //+----------------------------------------------------------------------------
  997. struct SThreadFromPoolState
  998. {
  999. ULONG HardErrorMode;
  1000. };
  1001. inline SThreadFromPoolState
  1002. InitializeThreadFromPool()
  1003. {
  1004. SThreadFromPoolState state;
  1005. // Disable the hard error popup dialog
  1006. RtlSetThreadErrorMode(RTL_ERRORMODE_FAILCRITICALERRORS,
  1007. &state.HardErrorMode);
  1008. // Set the RPC cancel timeout so that RpcCancelThread takes immediate effect.
  1009. RPC_STATUS rpcstatus = RpcMgmtSetCancelTimeout( 0 );
  1010. if( RPC_S_OK != rpcstatus )
  1011. {
  1012. // There's no reason this call should fail, and it's not important enough
  1013. // to justify an abort.
  1014. TrkLog(( TRKDBG_ERROR, TEXT("Ignoring RpcMgtSetCancelTimeout error, %lu"), rpcstatus ));
  1015. }
  1016. // Add this thread to our list of actively-running threads.
  1017. if( NULL != g_pActiveThreadList )
  1018. g_pActiveThreadList->AddCurrent( );
  1019. return( state );
  1020. }
  1021. inline void
  1022. UnInitializeThreadFromPool( SThreadFromPoolState state )
  1023. {
  1024. if( NULL != g_pActiveThreadList )
  1025. g_pActiveThreadList->RemoveCurrent( );
  1026. RtlSetThreadErrorMode(state.HardErrorMode, NULL);
  1027. }
  1028. //+----------------------------------------------------------------------------
  1029. //
  1030. // Begin/EndSingleInstanceTask
  1031. //
  1032. // Based on a counter that counts active instances of a type of tasks,
  1033. // and based on the atomicity of Interlocked*, determine if this
  1034. // is the first instance of this task. If so, return TRUE, if not,
  1035. // restore the counter, and return FALSE.
  1036. //
  1037. //+----------------------------------------------------------------------------
  1038. inline BOOL
  1039. BeginSingleInstanceTask( LONG *pcInstances )
  1040. {
  1041. LONG cInstances = InterlockedIncrement( pcInstances );
  1042. TrkAssert( 1 <= cInstances );
  1043. if( 1 < cInstances )
  1044. {
  1045. TrkLog(( TRKDBG_LOG, TEXT("Skipping single instance task (%d)"), cInstances-1 ));
  1046. #if DBG
  1047. TrkVerify( 0 <= InterlockedDecrement( pcInstances ));
  1048. #else
  1049. InterlockedDecrement( pcInstances );
  1050. #endif
  1051. return( FALSE );
  1052. }
  1053. else
  1054. return( TRUE );
  1055. }
  1056. // After a successful call to BeginSingleInstanceTask, the following
  1057. // should eventually be called.
  1058. inline void
  1059. EndSingleInstanceTask( LONG *pcInstances )
  1060. {
  1061. #if DBG
  1062. TrkVerify( 0 <= InterlockedDecrement( pcInstances ));
  1063. #else
  1064. InterlockedDecrement( pcInstances );
  1065. #endif
  1066. }
  1067. //+----------------------------------------------------------------------------
  1068. //
  1069. // CommonDllInit/CommonDllUnInit
  1070. //
  1071. // Services.exe never unloads service DLLs, so we can't count on dll init
  1072. // to init global non-const variables.
  1073. //
  1074. //+----------------------------------------------------------------------------
  1075. inline void
  1076. CommonDllInit( LONG *pcServiceInstances )
  1077. {
  1078. // Ensure that we're the only copy of this service that has been started.
  1079. // If we're not, raise.
  1080. if( !BeginSingleInstanceTask( pcServiceInstances ))
  1081. {
  1082. TrkLog(( TRKDBG_ERROR, TEXT("Two copies of service have been started") ));
  1083. TrkRaiseWin32Error( ERROR_SERVICE_ALREADY_RUNNING );
  1084. }
  1085. IFDBG( g_cThreadPoolThreads = g_cThreadPoolMaxThreads = g_cThreadPoolRegistrations = 0; )
  1086. g_fRestorePrivilegeEnabled = FALSE;
  1087. // Create the object that tracks all threads that are running
  1088. // in this service.
  1089. g_pActiveThreadList = new CActiveThreadList();
  1090. if( NULL != g_pActiveThreadList )
  1091. g_pActiveThreadList->Initialize();
  1092. #if DBG
  1093. if( NULL == g_pActiveThreadList )
  1094. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't alloc ActiveThreadList") ));
  1095. #endif
  1096. }
  1097. inline void
  1098. CommonDllUnInit( LONG *pcServiceInstances )
  1099. {
  1100. // Delete the list of active threads (should be empty by now).
  1101. // Make sure all thread pool threads go away. All are implemented
  1102. // so that they never run for a long time.
  1103. if( NULL != g_pActiveThreadList )
  1104. {
  1105. for( int i = 0; i < 5 && 1 < g_pActiveThreadList->GetCount(); i++ )
  1106. {
  1107. TrkLog(( TRKDBG_WARNING,
  1108. TEXT("Waiting for work items to complete (%d)"),
  1109. g_pActiveThreadList->GetCount() ));
  1110. Sleep( 1000 );
  1111. }
  1112. }
  1113. TrkAssert( NULL == g_pActiveThreadList || 0 == g_pActiveThreadList->GetCount() );
  1114. if( NULL != g_pActiveThreadList )
  1115. delete g_pActiveThreadList;
  1116. g_pActiveThreadList = NULL;
  1117. // Show that there is no instace of this service running.
  1118. EndSingleInstanceTask( pcServiceInstances );
  1119. }
  1120. //-------------------------------------------------------------------
  1121. //
  1122. // CSvcCtrlInterface
  1123. //
  1124. // This class manages the SCM for both services. It implements
  1125. // the default ServiceHandler routine for the services, but
  1126. // calls to the service to do the service-specific work.
  1127. //
  1128. // ** Note ** There can only be once instance of this class
  1129. // per DLL, because of the static _fStoppedOrStopping member.
  1130. //
  1131. //-------------------------------------------------------------------
  1132. enum PROCESS_TYPE
  1133. {
  1134. STANDALONE_DEBUGGABLE_PROCESS,
  1135. SERVICE_PROCESS
  1136. };
  1137. // The services implement this callback to receive
  1138. // ServiceHandler calls
  1139. class IServiceHandler
  1140. {
  1141. public:
  1142. virtual DWORD ServiceHandler(DWORD dwControl,
  1143. DWORD dwEventType,
  1144. PVOID EventData,
  1145. PVOID pData) = 0;
  1146. };
  1147. #define DEFAULT_WAIT_HINT 30000
  1148. class CSvcCtrlInterface
  1149. {
  1150. private:
  1151. BOOL _fInitializeCalled:1;
  1152. // This flag is set if the service has received a service_stop
  1153. // or service_shutdown request. This is used by tasks that run for an extended
  1154. // period to determine if they should abort.
  1155. // This is static so that we can handle a PNP timing problem
  1156. // (see the comment in CSvcCtrlInterface::ServiceHandler).
  1157. static BOOL _fStoppedOrStopping;
  1158. // Service-specific callback
  1159. IServiceHandler * _pServiceHandler;
  1160. // Values to pass to the SCM on SetServiceStatus
  1161. DWORD _dwState;
  1162. DWORD _dwCheckPoint;
  1163. DWORD _dwControlsAccepted;
  1164. public:
  1165. inline CSvcCtrlInterface() : _fInitializeCalled(FALSE), _ssh(NULL) {}
  1166. inline ~CSvcCtrlInterface() { UnInitialize(); }
  1167. public:
  1168. void Initialize(const TCHAR *ptszServiceName, IServiceHandler *pServiceHandler);
  1169. inline void UnInitialize();
  1170. void SetServiceStatus(DWORD dwState, DWORD dwControlsAccepted, DWORD dwWin32ExitCode);
  1171. void UpdateWaitHint(DWORD dwMilliseconds);
  1172. friend DWORD WINAPI ServiceHandler(DWORD dwControl,
  1173. DWORD dwEventType,
  1174. PVOID EventData,
  1175. PVOID pData);
  1176. inline DWORD GetState();
  1177. inline const BOOL * GetStopFlagAddress() const;
  1178. inline BOOL IsStopping() const;
  1179. SERVICE_STATUS_HANDLE _ssh; // used for registering for PnP notification for volume mount/dismount, lock/unlock.
  1180. private:
  1181. static
  1182. DWORD ServiceHandler(DWORD dwControl,
  1183. DWORD dwEventType,
  1184. PVOID EventData,
  1185. PVOID pData);
  1186. };
  1187. inline DWORD
  1188. CSvcCtrlInterface::GetState()
  1189. {
  1190. return(_dwState);
  1191. }
  1192. inline const BOOL *
  1193. CSvcCtrlInterface::GetStopFlagAddress() const
  1194. {
  1195. return(&_fStoppedOrStopping);
  1196. }
  1197. inline BOOL
  1198. CSvcCtrlInterface::IsStopping() const
  1199. {
  1200. return _fStoppedOrStopping;
  1201. }
  1202. inline void
  1203. CSvcCtrlInterface::UnInitialize()
  1204. {
  1205. }
  1206. //-------------------------------------------------------------------
  1207. //
  1208. // CNewTimer
  1209. //
  1210. // This class wraps the NT timer object. It adds the ability
  1211. // to make a timer persistent (using the registry), and to perform
  1212. // retries with random or exponential backoff (possibly subject
  1213. // to a max lifetime).
  1214. //
  1215. // When a CNewTimer is initialized, the caller provides a PTimerCallback
  1216. // pointer. The Timer method on this abstract base class is called
  1217. // when the NT timer fires.
  1218. //
  1219. //-------------------------------------------------------------------
  1220. class PTimerCallback
  1221. {
  1222. public:
  1223. // Enumeration of what the timer should do after it has
  1224. // fired and the Timer method has been called.
  1225. enum TimerContinuation
  1226. {
  1227. CONTINUE_TIMER, // Set a recurring timer again
  1228. BREAK_TIMER, // Stop the timer
  1229. RETRY_TIMER // Retry the timer
  1230. };
  1231. public:
  1232. virtual TimerContinuation Timer( ULONG ulTimerContext ) = 0;
  1233. };
  1234. EXTERN_C void __cdecl _tmain( int argc, TCHAR **argv ); // for ttimer test
  1235. class CNewTimer : public PWorkItem
  1236. {
  1237. public:
  1238. // Specifies how Retries should be handled.
  1239. enum TimerRetryType
  1240. {
  1241. NO_RETRY,
  1242. RETRY_RANDOMLY,
  1243. RETRY_WITH_BACKOFF
  1244. };
  1245. private:
  1246. // For persistent timers, the following structure is saved to the
  1247. // registry.
  1248. struct PersistentState
  1249. {
  1250. CFILETIME cftSet; // When the timer was set
  1251. CFILETIME cftDue; // When it's next due
  1252. ULONG ulCurrentRetryTime; // If applicable, the current retry value
  1253. };
  1254. private:
  1255. BOOL _fInitializeCalled:1; // Critical section has be initialized
  1256. BOOL _fRunning:1; // Timer is running
  1257. BOOL _fRecurring:1; // SetRecurring was called (not SetSingleShot)
  1258. BOOL _fTimerSignalInProgress:1; // We're in the call to pTimerCallback->Timer
  1259. #if DBG
  1260. mutable LONG _cLocks;
  1261. #endif
  1262. mutable CCriticalSection _cs; // Protects this class
  1263. HANDLE _hTimer; // The NT timer
  1264. const TCHAR * _ptszName; // If non-null, this is persistent timer
  1265. TimerRetryType _RetryType; // How to handle Retries
  1266. // Cookie from RegisterWaitForSingleObjectEx
  1267. HANDLE _hRegisterWaitForSingleObjectEx;
  1268. PTimerCallback * _pTimerCallback; // Who to call in DoWork
  1269. ULONG _ulTimerContext; // Passed to timer callback
  1270. // All the following are in seconds
  1271. ULONG _ulPeriodInSeconds;
  1272. ULONG _ulLowerRetryTime;
  1273. ULONG _ulUpperRetryTime;
  1274. ULONG _ulMaxLifetime;
  1275. ULONG _ulCurrentRetryTime;
  1276. CFILETIME _cftDue; // When the timer is due
  1277. CFILETIME _cftSet; // When the timer was set
  1278. public:
  1279. inline CNewTimer();
  1280. inline ~CNewTimer() { UnInitialize(); }
  1281. public:
  1282. void Initialize( PTimerCallback *pTimerCallback,
  1283. const TCHAR *ptszName,
  1284. ULONG ulTimerContext,
  1285. ULONG ulPeriodInSeconds,
  1286. TimerRetryType retrytype,
  1287. ULONG ulLowerRetryTime,
  1288. ULONG ulUpperRetryTime,
  1289. ULONG ulMaxLifetime );
  1290. void UnInitialize();
  1291. public:
  1292. // Start the timer, and when it fires it's done; it doesn't get reset.
  1293. void SetSingleShot();
  1294. // Start the timer, and when it fires, start it again.
  1295. void SetRecurring();
  1296. // Change the period on the timer.
  1297. inline void ReInitialize( ULONG ulPeriodInSeconds );
  1298. #if DBG
  1299. // Show the state of the timer (for debug)
  1300. void DebugStringize( ULONG cch, TCHAR *ptsz ) const;
  1301. #endif
  1302. // Stop the timer.
  1303. inline void Cancel( );
  1304. // When was the timer originally due to expire?
  1305. inline CFILETIME QueryOriginalDueTime( ) const;
  1306. // What is the period of this timer?
  1307. inline ULONG QueryPeriodInSeconds() const;
  1308. // PWorkItem overload: called by the thread pool when the timer handle signals
  1309. void DoWork();
  1310. // Is this a recurring timer?
  1311. inline BOOL IsRecurring() const;
  1312. // Does this use exponential, random, or no retries?
  1313. inline TimerRetryType
  1314. GetRetryType() const;
  1315. private:
  1316. inline void Lock() const;
  1317. inline void Unlock() const;
  1318. #if DBG
  1319. inline LONG GetLockCount() const;
  1320. #endif
  1321. inline const TCHAR *GetTimerName() const; // Dbg only
  1322. void SetTimer();
  1323. void SaveToRegistry();
  1324. void LoadFromRegistry();
  1325. void RemoveFromRegistry();
  1326. // Test friends
  1327. friend BOOL IsRegistryEntryExtant();
  1328. friend BOOL IsRegistryEntryCorrect( const CFILETIME &cftExpected );
  1329. friend void __cdecl _tmain( int argc, TCHAR **argv );
  1330. friend class CTimerTest;
  1331. friend class CTimerTest1;
  1332. friend class CTimerTest2;
  1333. friend class CTimerTest3;
  1334. friend class CTimerTest4;
  1335. friend class CTimerTest5;
  1336. friend class CTimerTest6;
  1337. };
  1338. inline
  1339. CNewTimer::CNewTimer() : _cftDue(0), _cftSet(0)
  1340. {
  1341. _fInitializeCalled = _fTimerSignalInProgress = FALSE;
  1342. _cftDue = 0;
  1343. _cftSet = 0;
  1344. _fRunning = _fRecurring = FALSE;
  1345. _hTimer = NULL;
  1346. _ptszName = NULL;
  1347. _ulPeriodInSeconds = 0;
  1348. _ulLowerRetryTime = _ulUpperRetryTime = _ulMaxLifetime = 0;
  1349. _ulCurrentRetryTime = 0;
  1350. _pTimerCallback = NULL;
  1351. _ulTimerContext = 0;
  1352. _hRegisterWaitForSingleObjectEx = NULL;
  1353. IFDBG( _cLocks = 0 );
  1354. }
  1355. #if DBG
  1356. inline LONG
  1357. CNewTimer::GetLockCount() const
  1358. {
  1359. return( _cLocks );
  1360. }
  1361. #endif
  1362. inline const TCHAR *
  1363. CNewTimer::GetTimerName() const
  1364. {
  1365. return (NULL == _ptszName) ? TEXT("") : _ptszName;
  1366. }
  1367. inline CFILETIME
  1368. CNewTimer::QueryOriginalDueTime() const
  1369. {
  1370. // When was this timer originally due? We can't look at _cftDue,
  1371. // because we could be retry mode.
  1372. TrkAssert( _fInitializeCalled );
  1373. CFILETIME cft = _cftSet;
  1374. cft.IncrementSeconds( _ulPeriodInSeconds );
  1375. return(cft);
  1376. }
  1377. inline ULONG
  1378. CNewTimer::QueryPeriodInSeconds() const
  1379. {
  1380. TrkAssert( _fInitializeCalled );
  1381. return _ulPeriodInSeconds;
  1382. }
  1383. inline void
  1384. CNewTimer::Lock() const
  1385. {
  1386. TrkAssert( _fInitializeCalled );
  1387. _cs.Enter();
  1388. IFDBG( _cLocks++ );
  1389. }
  1390. inline void
  1391. CNewTimer::Unlock() const
  1392. {
  1393. TrkAssert( _fInitializeCalled );
  1394. IFDBG( _cLocks-- );
  1395. _cs.Leave();
  1396. }
  1397. inline CNewTimer::TimerRetryType
  1398. CNewTimer::GetRetryType() const
  1399. {
  1400. return( _RetryType );
  1401. }
  1402. inline BOOL
  1403. CNewTimer::IsRecurring() const
  1404. {
  1405. return( _fRecurring );
  1406. }
  1407. inline void
  1408. CNewTimer::SetRecurring()
  1409. {
  1410. // Start the timer, and record that it should
  1411. // be started again after firing.
  1412. TrkAssert( _fInitializeCalled );
  1413. Lock();
  1414. IFDBG( LONG cLocks = GetLockCount(); )
  1415. __try
  1416. {
  1417. _fRecurring = TRUE;
  1418. SetTimer();
  1419. }
  1420. __finally
  1421. {
  1422. TrkAssert( GetLockCount() == cLocks );
  1423. Unlock();
  1424. }
  1425. }
  1426. inline void
  1427. CNewTimer::SetSingleShot()
  1428. {
  1429. // Start the timer, and record that it should not start
  1430. // again after firing.
  1431. TrkAssert( _fInitializeCalled );
  1432. Lock();
  1433. IFDBG( LONG cLocks = GetLockCount(); )
  1434. __try
  1435. {
  1436. _fRecurring = FALSE;
  1437. SetTimer();
  1438. }
  1439. __finally
  1440. {
  1441. TrkAssert( GetLockCount() == cLocks );
  1442. Unlock();
  1443. }
  1444. }
  1445. inline void
  1446. CNewTimer::ReInitialize( ULONG ulPeriodInSeconds )
  1447. {
  1448. TrkAssert( _fInitializeCalled );
  1449. Lock();
  1450. __try
  1451. {
  1452. _ulPeriodInSeconds = ulPeriodInSeconds;
  1453. Cancel();
  1454. }
  1455. __finally
  1456. {
  1457. Unlock();
  1458. }
  1459. }
  1460. //-------------------------------------------------------------------
  1461. //
  1462. // PShareMerit
  1463. //
  1464. // This abstract base class should be used by classes which can
  1465. // calculate the merit of a share. A share's merit is a linear
  1466. // value which accounts for the access on the share (more is better),
  1467. // a share's hidden-ness (visible is better), and the share's coverage
  1468. // of the volume (more is better).
  1469. //
  1470. // These share attributes are mapped onto a Merit value in the form
  1471. // of:
  1472. //
  1473. // 0x00AAHCCC
  1474. //
  1475. // where:
  1476. //
  1477. // "AA" represents the access level
  1478. // "H" represents the hidden-ness
  1479. // "CC" represents the coverage of the disk
  1480. //
  1481. // This is structured so as to give highest priority to the access
  1482. // level, next highest priority to the hidden-ness, and least
  1483. // priority to the share's coverage of the volume. The coverage
  1484. // of the volume is represented as 0xFFF minus the share path's
  1485. // length.
  1486. //
  1487. //-------------------------------------------------------------------
  1488. // This class prototype maps the various aspects of a share
  1489. // into a linear measure of its worthiness.
  1490. class PShareMerit
  1491. {
  1492. public:
  1493. PShareMerit() {};
  1494. ~PShareMerit() {};
  1495. public:
  1496. // The access level is the most significant attribute.
  1497. enum enumAccessLevels
  1498. {
  1499. AL_UNKNOWN = 0x00010000,
  1500. AL_NO_ACCESS = 0x00020000,
  1501. AL_WRITE_ACCESS = 0x00030000,
  1502. AL_READ_ACCESS = 0x00040000,
  1503. AL_READ_WRITE_ACCESS = 0x00050000,
  1504. AL_FULL_ACCESS = 0x00060000
  1505. };
  1506. // The hidden-ness is the second most significant
  1507. // attribute
  1508. enum enumHiddenStates
  1509. {
  1510. HS_UNKNOWN = 0x00001000,
  1511. HS_HIDDEN = 0x00002000,
  1512. HS_VISIBLE = 0x00003000
  1513. };
  1514. // The volume coverage is the least significant
  1515. // attribute
  1516. enum enumSharePathCoverage
  1517. {
  1518. SPC_MAX_COVERAGE = 0x00000fff
  1519. };
  1520. public:
  1521. virtual ULONG GetMerit() = 0;
  1522. // The minimum merit is guaranteed to be >= 1
  1523. inline ULONG GetMinimumMerit()
  1524. {
  1525. return( AL_WRITE_ACCESS | HS_HIDDEN );
  1526. }
  1527. };
  1528. //-------------------------------------------------------------------
  1529. //
  1530. // CShareEnumerator
  1531. //
  1532. // This class represents the enumeration of a network share. It
  1533. // can be queried for attributes of a share (share name, covered
  1534. // path, etc.).
  1535. //
  1536. // Note that each of these methods may raise an exception.
  1537. //
  1538. // Also note that this implementation is LanMan-specific. When/if we
  1539. // add support for Netware shares, we should rename this class to
  1540. // CLMShareEnumerator, and add two new classes - CNWShareEnumerator,
  1541. // and CShareEnumerator (which would wrap the other two).
  1542. //
  1543. //-------------------------------------------------------------------
  1544. class CShareEnumerator : public PShareMerit, public CTrkRpcConfig
  1545. {
  1546. // ------------
  1547. // Constructors
  1548. // ------------
  1549. public:
  1550. CShareEnumerator()
  1551. {
  1552. InitLocals();
  1553. }
  1554. inline ~CShareEnumerator()
  1555. {
  1556. UnInitialize();
  1557. };
  1558. // --------------
  1559. // Public Methods
  1560. // --------------
  1561. public:
  1562. VOID Initialize( RPC_BINDING_HANDLE IDL_handle, const TCHAR *ptszMachineName = NULL );
  1563. VOID UnInitialize();
  1564. VOID InitLocals()
  1565. {
  1566. _fInitialized = FALSE;
  1567. _cchSharePath = 0;
  1568. _cEntries = 0;
  1569. _enumHiddenState = HS_UNKNOWN;
  1570. _iCurrentEntry = 0;
  1571. _IDL_handle = NULL;
  1572. _prgshare_info = NULL;
  1573. _tszMachineName[0] = TEXT('\0');
  1574. }
  1575. BOOL Next();
  1576. inline const TCHAR *GetMachineName() const;
  1577. inline const TCHAR *GetShareName() const;
  1578. inline const TCHAR *GetSharePath();
  1579. inline ULONG QueryCCHSharePath();
  1580. BOOL CoversDrivePath( const TCHAR *ptszDrivePath );
  1581. BOOL GenerateUNCPath( TCHAR *ptszUNCPath, const TCHAR * ptszDrivePath );
  1582. // Override the PShareMerit method.
  1583. ULONG GetMerit();
  1584. // ---------------
  1585. // Private Methods
  1586. // ---------------
  1587. private:
  1588. VOID _ClearCache();
  1589. BOOL _IsValidShare();
  1590. BOOL _IsHiddenShare();
  1591. BOOL _IsAdminShare();
  1592. enumAccessLevels _GetAccessLevel();
  1593. void _AbsoluteSDHelper( const PSECURITY_DESCRIPTOR pSDRelative,
  1594. PSECURITY_DESCRIPTOR *ppSDAbs, ULONG *pcbSDAbs,
  1595. PACL *ppDaclAbs, ULONG *pcbDaclAbs,
  1596. PACL *ppSaclAbs, ULONG *pcbSaclAbs,
  1597. PSID *ppSidOwnerAbs, ULONG *pcbSidOwnerAbs,
  1598. PSID *ppSidGroupAbs, ULONG *pcbSidGroupAbs );
  1599. // ------------
  1600. // Private Data
  1601. // ------------
  1602. private:
  1603. BOOL _fInitialized;
  1604. ULONG _cEntries;
  1605. ULONG _iCurrentEntry;
  1606. SHARE_INFO_502 *_prgshare_info;
  1607. TCHAR _tszMachineName[ MAX_PATH + 1 ];
  1608. ULONG _cchSharePath;
  1609. ULONG _ulMerit;
  1610. enumHiddenStates _enumHiddenState;
  1611. RPC_BINDING_HANDLE _IDL_handle;
  1612. }; // class CShareEnumerator
  1613. // ---------------------------------
  1614. // CShareEnumerator::QueryCCHSharePath
  1615. // ---------------------------------
  1616. // Determine the character-count of the share's path, and
  1617. // cache a copy for subsequent calls.
  1618. inline ULONG
  1619. CShareEnumerator::QueryCCHSharePath()
  1620. {
  1621. if( (ULONG) -1 == _cchSharePath )
  1622. _cchSharePath = _tcslen( GetSharePath() );
  1623. return( _cchSharePath );
  1624. }
  1625. // --------------------------------
  1626. // CShareEnumerator::GetMachineName
  1627. // --------------------------------
  1628. inline const TCHAR *
  1629. CShareEnumerator::GetMachineName() const
  1630. {
  1631. return( _tszMachineName );
  1632. }
  1633. // ------------------------------
  1634. // CShareEnumerator::GetShareName
  1635. // ------------------------------
  1636. // Return the share's name from the current entry
  1637. // in the SHARE_INFO structure.
  1638. inline const TCHAR *
  1639. CShareEnumerator::GetShareName() const
  1640. {
  1641. TrkAssert( _fInitialized );
  1642. TrkAssert( _iCurrentEntry < _cEntries );
  1643. return( _prgshare_info[ _iCurrentEntry ].shi502_netname );
  1644. }
  1645. // ------------------------------
  1646. // CShareEnumerator::GetSharePath
  1647. // ------------------------------
  1648. // Get the path name covered by the share from the
  1649. // SHARE_INFO structure.
  1650. inline const TCHAR *
  1651. CShareEnumerator::GetSharePath()
  1652. {
  1653. TrkAssert( _fInitialized );
  1654. TrkAssert( _iCurrentEntry < _cEntries );
  1655. return( _prgshare_info[ _iCurrentEntry ].shi502_path );
  1656. }
  1657. enum RC_AUTHENTICATE
  1658. {
  1659. NO_AUTHENTICATION,
  1660. PRIVACY_AUTHENTICATION,
  1661. INTEGRITY_AUTHENTICATION
  1662. };
  1663. const extern TCHAR s_tszTrkWksLocalRpcProtocol[] INIT( TEXT("ncalrpc") );
  1664. const extern TCHAR s_tszTrkWksLocalRpcEndPoint[] INIT( TRKWKS_LRPC_ENDPOINT_NAME );
  1665. const extern TCHAR s_tszTrkWksRemoteRpcProtocol[] INIT( TEXT("ncacn_np") );
  1666. const extern TCHAR s_tszTrkWksRemoteRpcEndPoint[] INIT( TEXT("\\pipe\\trkwks") );
  1667. const extern TCHAR s_tszTrkWksRemoteRpcEndPointOld[] INIT( TEXT("\\pipe\\ntsvcs") );
  1668. const extern TCHAR s_tszTrkSvrRpcProtocol[] INIT( TEXT("ncacn_ip_tcp") );
  1669. const extern TCHAR s_tszTrkSvrRpcEndPoint[] INIT( TEXT("") );
  1670. //+----------------------------------------------------------------------------
  1671. //
  1672. // CRpcClientBinding
  1673. //
  1674. // This class represents an RPC client-side binding handle. The
  1675. // RcInitialize method creates the binding handle, and optionally sets
  1676. // the appropriate security.
  1677. //
  1678. //+----------------------------------------------------------------------------
  1679. class CRpcClientBinding : public CTrkRpcConfig
  1680. {
  1681. private:
  1682. BOOL _fBound;
  1683. RPC_BINDING_HANDLE _BindingHandle;
  1684. public:
  1685. inline CRpcClientBinding()
  1686. {
  1687. _fBound = FALSE;
  1688. }
  1689. ~CRpcClientBinding()
  1690. {
  1691. UnInitialize();
  1692. }
  1693. void RcInitialize(const CMachineId &mcid,
  1694. const TCHAR *ptszRpcProtocol = s_tszTrkWksRemoteRpcProtocol,
  1695. const TCHAR *ptszRpcEndPoint = s_tszTrkWksRemoteRpcEndPoint,
  1696. RC_AUTHENTICATE auth = INTEGRITY_AUTHENTICATION );
  1697. void UnInitialize();
  1698. inline BOOL IsConnected();
  1699. inline operator RPC_BINDING_HANDLE () const;
  1700. };
  1701. inline BOOL
  1702. CRpcClientBinding::IsConnected()
  1703. {
  1704. return(_fBound);
  1705. }
  1706. inline
  1707. CRpcClientBinding::operator RPC_BINDING_HANDLE () const
  1708. {
  1709. TrkAssert(_fBound);
  1710. return(_BindingHandle);
  1711. }
  1712. //--------------------------------------------------------------------
  1713. //
  1714. // CTrkRegistryKey
  1715. //
  1716. // This class represents the registry key for this service
  1717. // (either trkwks or trksvr). Use its methods to read/write
  1718. // registry values.
  1719. //
  1720. //--------------------------------------------------------------------
  1721. class CTrkRegistryKey
  1722. {
  1723. private:
  1724. HKEY _hkey;
  1725. CCriticalSection _cs;
  1726. public:
  1727. inline CTrkRegistryKey();
  1728. inline ~CTrkRegistryKey();
  1729. public:
  1730. void Initialize();
  1731. LONG SetDword( const TCHAR *ptszName, DWORD dw );
  1732. LONG GetDword( const TCHAR *ptszName, DWORD *pdwRead, DWORD dwDefault );
  1733. LONG Delete( const TCHAR *ptszName );
  1734. private:
  1735. inline LONG Open();
  1736. inline void Close();
  1737. };
  1738. inline
  1739. CTrkRegistryKey::CTrkRegistryKey()
  1740. {
  1741. _hkey = NULL;
  1742. }
  1743. inline void
  1744. CTrkRegistryKey::Initialize()
  1745. {
  1746. _cs.Initialize();
  1747. }
  1748. inline
  1749. CTrkRegistryKey::~CTrkRegistryKey()
  1750. {
  1751. Close();
  1752. _cs.UnInitialize();
  1753. }
  1754. inline void
  1755. CTrkRegistryKey::Close()
  1756. {
  1757. if( NULL != _hkey )
  1758. {
  1759. RegCloseKey( _hkey );
  1760. _hkey = NULL;
  1761. }
  1762. }
  1763. inline LONG
  1764. CTrkRegistryKey::Open()
  1765. {
  1766. if( NULL != _hkey )
  1767. return( ERROR_SUCCESS );
  1768. else
  1769. return( RegOpenKey( HKEY_LOCAL_MACHINE, s_tszKeyNameLinkTrack, &_hkey ));
  1770. }
  1771. //-------------------------------------------------------------------
  1772. //
  1773. // CRegBoolParameter
  1774. //
  1775. // This class represents a bool parameter stored in the registry.
  1776. //
  1777. //-------------------------------------------------------------------
  1778. class CRegBoolParameter : private CTrkRegistryKey
  1779. {
  1780. private:
  1781. BOOL _fSet:1;
  1782. // We're fully initialized when Initialize() has been called,
  1783. // and Set, Clear, or IsSet has been called.
  1784. BOOL _fFullyInitialized:1;
  1785. const TCHAR *_ptszName;
  1786. public:
  1787. inline CRegBoolParameter( const TCHAR *ptszName );
  1788. inline void Initialize();
  1789. public:
  1790. inline HRESULT Set();
  1791. inline HRESULT Clear();
  1792. inline BOOL IsSet();
  1793. };
  1794. inline
  1795. CRegBoolParameter::CRegBoolParameter( const TCHAR *ptszName )
  1796. {
  1797. _ptszName = ptszName;
  1798. _fSet = _fFullyInitialized = FALSE;
  1799. }
  1800. inline HRESULT
  1801. CRegBoolParameter::Set()
  1802. {
  1803. HRESULT hr = SetDword( _ptszName, TRUE );
  1804. if( ERROR_SUCCESS != hr )
  1805. hr = HRESULT_FROM_WIN32(hr);
  1806. _fFullyInitialized = TRUE;
  1807. _fSet = TRUE;
  1808. return( hr );
  1809. }
  1810. inline HRESULT
  1811. CRegBoolParameter::Clear()
  1812. {
  1813. HRESULT hr = Delete( _ptszName );
  1814. if( ERROR_SUCCESS != hr )
  1815. hr = HRESULT_FROM_WIN32(hr);
  1816. _fFullyInitialized = TRUE;
  1817. _fSet = FALSE;
  1818. return( hr );
  1819. }
  1820. inline BOOL
  1821. CRegBoolParameter::IsSet()
  1822. {
  1823. if( !_fFullyInitialized )
  1824. {
  1825. DWORD dw;
  1826. LONG lRet = GetDword( _ptszName, &dw, FALSE );
  1827. TrkAssert( ERROR_SUCCESS == lRet );
  1828. _fSet = dw;
  1829. }
  1830. return( _fSet );
  1831. }
  1832. inline void
  1833. CRegBoolParameter::Initialize()
  1834. {
  1835. CTrkRegistryKey::Initialize();
  1836. }
  1837. //-------------------------------------------------------------------
  1838. //
  1839. // CRegDwordParameter
  1840. //
  1841. // This class represents a DWORD parameter stored in the registry.
  1842. //
  1843. //-------------------------------------------------------------------
  1844. class CRegDwordParameter : private CTrkRegistryKey
  1845. {
  1846. private:
  1847. DWORD _dwValue;
  1848. // We're fully initialized when Initialize() has been called,
  1849. // and Set, Clear, GetValue has been called.
  1850. BOOL _fFullyInitialized:1;
  1851. const TCHAR *_ptszName;
  1852. public:
  1853. inline CRegDwordParameter( const TCHAR *ptszName );
  1854. inline void Initialize();
  1855. public:
  1856. inline HRESULT Set( DWORD dw );
  1857. inline HRESULT Clear();
  1858. inline DWORD GetValue();
  1859. };
  1860. inline
  1861. CRegDwordParameter::CRegDwordParameter( const TCHAR *ptszName )
  1862. {
  1863. _dwValue = 0;
  1864. _ptszName = ptszName;
  1865. _fFullyInitialized = FALSE;
  1866. }
  1867. inline HRESULT
  1868. CRegDwordParameter::Set( DWORD dw)
  1869. {
  1870. HRESULT hr = SetDword( _ptszName, dw );
  1871. if( ERROR_SUCCESS != hr )
  1872. hr = HRESULT_FROM_WIN32(hr);
  1873. _fFullyInitialized = TRUE;
  1874. _dwValue = dw;
  1875. return( hr );
  1876. }
  1877. inline HRESULT
  1878. CRegDwordParameter::Clear()
  1879. {
  1880. HRESULT hr = Delete( _ptszName );
  1881. if( ERROR_SUCCESS != hr )
  1882. hr = HRESULT_FROM_WIN32(hr);
  1883. _fFullyInitialized = TRUE;
  1884. _dwValue = 0;
  1885. return( hr );
  1886. }
  1887. inline DWORD
  1888. CRegDwordParameter::GetValue()
  1889. {
  1890. if( !_fFullyInitialized )
  1891. {
  1892. DWORD dw = 0;
  1893. LONG lRet = GetDword( _ptszName, &dw, FALSE );
  1894. TrkAssert( ERROR_SUCCESS == lRet );
  1895. _fFullyInitialized = TRUE;
  1896. _dwValue = dw;
  1897. }
  1898. return( _dwValue );
  1899. }
  1900. inline void
  1901. CRegDwordParameter::Initialize()
  1902. {
  1903. CTrkRegistryKey::Initialize();
  1904. }
  1905. //-------------------------------------------------------------------//
  1906. // //
  1907. // CSID //
  1908. // //
  1909. //-------------------------------------------------------------------//
  1910. // Wrapper class for NT Security IDs
  1911. class CSID
  1912. {
  1913. public:
  1914. CSID()
  1915. {
  1916. memset( this, 0, sizeof(*this) );
  1917. }
  1918. ~CSID()
  1919. {
  1920. UnInitialize();
  1921. }
  1922. public:
  1923. // Standard Authorities
  1924. enum enumCSIDAuthority
  1925. {
  1926. CSID_NT_AUTHORITY = 0
  1927. };
  1928. public:
  1929. // The primary Initialize method (takes a SID count as the first parameter).
  1930. VOID Initialize( enumCSIDAuthority enumcsidAuthority,
  1931. BYTE cSubAuthorities ,
  1932. DWORD dwSubAuthority0,
  1933. DWORD dwSubAuthority1,
  1934. DWORD dwSubAuthority2,
  1935. DWORD dwSubAuthority3,
  1936. DWORD dwSubAuthority4,
  1937. DWORD dwSubAuthority5,
  1938. DWORD dwSubAuthority6,
  1939. DWORD dwSubAuthority7 );
  1940. // Helper Initialize methods (these do not take a SID count).
  1941. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1942. DWORD dwSubAuthority0,
  1943. DWORD dwSubAuthority1,
  1944. DWORD dwSubAuthority2,
  1945. DWORD dwSubAuthority3,
  1946. DWORD dwSubAuthority4,
  1947. DWORD dwSubAuthority5,
  1948. DWORD dwSubAuthority6,
  1949. DWORD dwSubAuthority7 );
  1950. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1951. DWORD dwSubAuthority0,
  1952. DWORD dwSubAuthority1,
  1953. DWORD dwSubAuthority2,
  1954. DWORD dwSubAuthority3,
  1955. DWORD dwSubAuthority4,
  1956. DWORD dwSubAuthority5,
  1957. DWORD dwSubAuthority6 );
  1958. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1959. DWORD dwSubAuthority0,
  1960. DWORD dwSubAuthority1,
  1961. DWORD dwSubAuthority2,
  1962. DWORD dwSubAuthority3,
  1963. DWORD dwSubAuthority4,
  1964. DWORD dwSubAuthority5 );
  1965. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1966. DWORD dwSubAuthority0,
  1967. DWORD dwSubAuthority1,
  1968. DWORD dwSubAuthority2,
  1969. DWORD dwSubAuthority3,
  1970. DWORD dwSubAuthority4 );
  1971. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1972. DWORD dwSubAuthority0,
  1973. DWORD dwSubAuthority1,
  1974. DWORD dwSubAuthority2,
  1975. DWORD dwSubAuthority3 );
  1976. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1977. DWORD dwSubAuthority0,
  1978. DWORD dwSubAuthority1,
  1979. DWORD dwSubAuthority2 );
  1980. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1981. DWORD dwSubAuthority0,
  1982. DWORD dwSubAuthority1 );
  1983. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1984. DWORD dwSubAuthority0 );
  1985. VOID UnInitialize();
  1986. inline operator const PSID();
  1987. private:
  1988. BOOL _fInitialized;
  1989. PSID _psid;
  1990. };
  1991. // ------------------------
  1992. // CSID::Initialize methods
  1993. // ------------------------
  1994. // Each of these methods simply calls the primary Initialize
  1995. // method, with the appropriate cSID value.
  1996. inline VOID
  1997. CSID::Initialize( enumCSIDAuthority csidAuthority,
  1998. DWORD dwSubAuthority0,
  1999. DWORD dwSubAuthority1,
  2000. DWORD dwSubAuthority2,
  2001. DWORD dwSubAuthority3,
  2002. DWORD dwSubAuthority4,
  2003. DWORD dwSubAuthority5,
  2004. DWORD dwSubAuthority6,
  2005. DWORD dwSubAuthority7 )
  2006. {
  2007. Initialize( csidAuthority, 8,
  2008. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  2009. dwSubAuthority4, dwSubAuthority5, dwSubAuthority6, dwSubAuthority7 );
  2010. }
  2011. inline VOID
  2012. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2013. DWORD dwSubAuthority0,
  2014. DWORD dwSubAuthority1,
  2015. DWORD dwSubAuthority2,
  2016. DWORD dwSubAuthority3,
  2017. DWORD dwSubAuthority4,
  2018. DWORD dwSubAuthority5,
  2019. DWORD dwSubAuthority6 )
  2020. {
  2021. Initialize( csidAuthority, 7,
  2022. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  2023. dwSubAuthority4, dwSubAuthority5, dwSubAuthority6, 0 );
  2024. }
  2025. inline VOID
  2026. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2027. DWORD dwSubAuthority0,
  2028. DWORD dwSubAuthority1,
  2029. DWORD dwSubAuthority2,
  2030. DWORD dwSubAuthority3,
  2031. DWORD dwSubAuthority4,
  2032. DWORD dwSubAuthority5 )
  2033. {
  2034. Initialize( csidAuthority, 6,
  2035. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  2036. dwSubAuthority4, dwSubAuthority5, 0, 0 );
  2037. }
  2038. inline VOID
  2039. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2040. DWORD dwSubAuthority0,
  2041. DWORD dwSubAuthority1,
  2042. DWORD dwSubAuthority2,
  2043. DWORD dwSubAuthority3,
  2044. DWORD dwSubAuthority4 )
  2045. {
  2046. Initialize( csidAuthority, 5,
  2047. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  2048. dwSubAuthority4, 0, 0, 0 );
  2049. }
  2050. inline VOID
  2051. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2052. DWORD dwSubAuthority0,
  2053. DWORD dwSubAuthority1,
  2054. DWORD dwSubAuthority2,
  2055. DWORD dwSubAuthority3 )
  2056. {
  2057. Initialize( csidAuthority, 4,
  2058. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  2059. 0, 0, 0, 0);
  2060. }
  2061. inline VOID
  2062. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2063. DWORD dwSubAuthority0,
  2064. DWORD dwSubAuthority1,
  2065. DWORD dwSubAuthority2 )
  2066. {
  2067. Initialize( csidAuthority, 3,
  2068. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, 0, 0, 0, 0, 0 );
  2069. }
  2070. inline VOID
  2071. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2072. DWORD dwSubAuthority0,
  2073. DWORD dwSubAuthority1 )
  2074. {
  2075. Initialize( csidAuthority, 2,
  2076. dwSubAuthority0, dwSubAuthority1, 0, 0, 0, 0, 0, 0 );
  2077. }
  2078. inline VOID
  2079. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2080. DWORD dwSubAuthority0 )
  2081. {
  2082. Initialize( csidAuthority, 1,
  2083. dwSubAuthority0, 0, 0, 0, 0, 0, 0, 0 );
  2084. }
  2085. // -------------------
  2086. // CSID::OPERATOR PSID
  2087. // -------------------
  2088. inline
  2089. CSID::operator const PSID()
  2090. {
  2091. return( _psid );
  2092. }
  2093. //-------------------------------------------------------------------//
  2094. //
  2095. // CACL
  2096. //
  2097. // This class wraps a DACL, providing methods to add ACEs,
  2098. // and a conversion operator to get the PACL. The current
  2099. // implementation only supports a 128 byte buffer size.
  2100. //
  2101. //-------------------------------------------------------------------//
  2102. // Wrapper for an Access Control List
  2103. #define MIN_ACL_SIZE 128
  2104. class CACL
  2105. {
  2106. public:
  2107. CACL()
  2108. {
  2109. memset( this, 0, sizeof(*this) );
  2110. }
  2111. ~CACL()
  2112. {
  2113. UnInitialize();
  2114. }
  2115. public:
  2116. VOID Initialize();
  2117. VOID UnInitialize();
  2118. //VOID SetSize( const PSID psid );
  2119. operator const PACL() const;
  2120. inline VOID SetDirty();
  2121. inline VOID ClearDirty();
  2122. inline BOOL IsDirty();
  2123. inline BOOL IsInitialized();
  2124. inline BOOL AddAccessAllowed( ACCESS_MASK access_mask, const PSID psid );
  2125. inline BOOL AddAccessDenied( ACCESS_MASK access_mask, const PSID psid );
  2126. private:
  2127. PACL _pacl;
  2128. ULONG _cbacl;
  2129. BOOL _fInitialized:1;
  2130. BOOL _fDirty:1;
  2131. };
  2132. // ----------------------
  2133. // CACL Dirty Bit methods
  2134. // ----------------------
  2135. inline VOID
  2136. CACL::SetDirty()
  2137. {
  2138. _fDirty = TRUE;
  2139. }
  2140. inline VOID
  2141. CACL::ClearDirty()
  2142. {
  2143. _fDirty = FALSE;
  2144. }
  2145. inline BOOL
  2146. CACL::IsDirty()
  2147. {
  2148. return( _fDirty );
  2149. }
  2150. // -------------------
  2151. // CACL::IsInitialized
  2152. // -------------------
  2153. inline BOOL
  2154. CACL::IsInitialized()
  2155. {
  2156. return( _fInitialized );
  2157. }
  2158. // -------------------------
  2159. // CACL::operator const PACL
  2160. // -------------------------
  2161. inline
  2162. CACL::operator const PACL() const
  2163. {
  2164. return( _pacl );
  2165. }
  2166. // --------------------
  2167. // CACL Add ACE methods
  2168. // --------------------
  2169. inline BOOL
  2170. CACL::AddAccessAllowed( ACCESS_MASK access_mask, const PSID psid )
  2171. {
  2172. TrkAssert( _fInitialized );
  2173. return( AddAccessAllowedAce( _pacl, ACL_REVISION, access_mask, const_cast<PSID>(psid) ));
  2174. }
  2175. inline BOOL
  2176. CACL::AddAccessDenied( ACCESS_MASK access_mask, const PSID psid )
  2177. {
  2178. TrkAssert( _fInitialized );
  2179. return( AddAccessDeniedAce( _pacl, ACL_REVISION, access_mask, const_cast<PSID>(psid) ));
  2180. }
  2181. //-------------------------------------------------------------------//
  2182. // //
  2183. // CSecDescriptor
  2184. //
  2185. // Wrapper class for a security descriptor.
  2186. // //
  2187. //-------------------------------------------------------------------//
  2188. class CSecDescriptor
  2189. {
  2190. // ------------
  2191. // Construction
  2192. // ------------
  2193. public:
  2194. CSecDescriptor()
  2195. {
  2196. memset( this, 0, sizeof(*this) );
  2197. }
  2198. ~CSecDescriptor()
  2199. {
  2200. UnInitialize();
  2201. }
  2202. public:
  2203. // Types of ACEs
  2204. enum enumAccessType
  2205. {
  2206. AT_ACCESS_ALLOWED,
  2207. AT_ACCESS_DENIED
  2208. };
  2209. // Types of ACLs
  2210. enum enumAclType
  2211. {
  2212. ACL_IS_SACL, // System (Audit) ACL
  2213. ACL_IS_DACL // Discretionary ACL
  2214. };
  2215. public:
  2216. VOID Initialize();
  2217. VOID UnInitialize();
  2218. void AddAce( const enumAclType AclType, const enumAccessType AccessType, const ACCESS_MASK access_mask, const PSID psid );
  2219. inline operator const PSECURITY_DESCRIPTOR();
  2220. private:
  2221. VOID _Allocate( ULONG cb );
  2222. VOID _ReloadAcl( enumAclType AclType );
  2223. private:
  2224. BOOL _fInitialized;
  2225. PSECURITY_DESCRIPTOR _psd;
  2226. CACL _cDacl;
  2227. CACL _cSacl;
  2228. };
  2229. // ----------------------------------------------------------
  2230. // CSecDescriptor::operator const PSECURITY_DESCRIPTOR()
  2231. // ----------------------------------------------------------
  2232. inline
  2233. CSecDescriptor::operator const PSECURITY_DESCRIPTOR()
  2234. {
  2235. if( _cDacl.IsDirty() )
  2236. _ReloadAcl( ACL_IS_DACL );
  2237. if( _cSacl.IsDirty() )
  2238. _ReloadAcl( ACL_IS_SACL );
  2239. return( _psd );
  2240. }
  2241. //-------------------------------------------------------------------//
  2242. // //
  2243. // CSystemSD
  2244. //
  2245. // Wrapper specifically for a security descriptor that allows
  2246. // access only to Administrators and System.
  2247. //
  2248. //-------------------------------------------------------------------//
  2249. #define MAX_SYSTEM_ACL_LENGTH 32
  2250. class CSystemSD
  2251. {
  2252. public:
  2253. enum ESystemSD
  2254. {
  2255. SYSTEM_AND_ADMINISTRATOR = 0,
  2256. SYSTEM_ONLY = 1
  2257. };
  2258. public:
  2259. void Initialize( ESystemSD = SYSTEM_AND_ADMINISTRATOR );
  2260. void UnInitialize();
  2261. inline operator const PSECURITY_DESCRIPTOR();
  2262. private:
  2263. CSecDescriptor _csd;
  2264. CSID _csidAdministrators;
  2265. CSID _csidSystem;
  2266. };
  2267. inline
  2268. CSystemSD::operator const PSECURITY_DESCRIPTOR ()
  2269. {
  2270. return(_csd.operator const PSECURITY_DESCRIPTOR());
  2271. }
  2272. //-------------------------------------------------------------------//
  2273. // //
  2274. // CSystemSA //
  2275. // sets up System-and-admin security attributes //
  2276. //-------------------------------------------------------------------//
  2277. class CSystemSA
  2278. {
  2279. public:
  2280. inline void Initialize();
  2281. inline void UnInitialize();
  2282. inline operator LPSECURITY_ATTRIBUTES();
  2283. private:
  2284. CSystemSD _ssd;
  2285. SECURITY_ATTRIBUTES _sa;
  2286. };
  2287. inline void
  2288. CSystemSA::Initialize()
  2289. {
  2290. _ssd.Initialize();
  2291. _sa.nLength = sizeof(_sa);
  2292. _sa.lpSecurityDescriptor = _ssd.operator const PSECURITY_DESCRIPTOR();
  2293. _sa.bInheritHandle = FALSE;
  2294. }
  2295. inline void
  2296. CSystemSA::UnInitialize()
  2297. {
  2298. _ssd.UnInitialize();
  2299. }
  2300. inline
  2301. CSystemSA::operator LPSECURITY_ATTRIBUTES()
  2302. {
  2303. return(&_sa);
  2304. }
  2305. /*
  2306. //+------------------------------------------------------------------
  2307. //
  2308. // CRpcPipeControl
  2309. //
  2310. //+------------------------------------------------------------------
  2311. template <class T_PIPE_ELEMENT> class TPRpcPipeCallback
  2312. {
  2313. public:
  2314. virtual void Pull( T_PIPE_ELEMENT *pElement, unsigned long cbBuffer, unsigned long * pcElems ) = 0;
  2315. virtual void Push( T_PIPE_ELEMENT *pElement, unsigned long cElems ) = 0;
  2316. virtual void Alloc( unsigned long cbRequested, T_PIPE_ELEMENT **ppElement, unsigned long * pcbActual ) = 0;
  2317. }; // template <...> class TPRpcPipeCallback
  2318. template <class T_PIPE, class T_PIPE_ELEMENT, class T_C_CALLBACK> class TRpcPipeControl
  2319. {
  2320. public:
  2321. TRpcPipeControl( T_C_CALLBACK *pCallback )
  2322. {
  2323. _pipe.state = reinterpret_cast<char*>(pCallback);
  2324. _pipe.pull = &Pull;
  2325. _pipe.push = &Push;
  2326. _pipe.alloc = &Alloc;
  2327. }
  2328. operator T_PIPE()
  2329. {
  2330. return( _pipe );
  2331. }
  2332. private:
  2333. static void Pull( char * state, T_PIPE_ELEMENT * buf, unsigned long esize, unsigned long * ecount )
  2334. {
  2335. reinterpret_cast<T_C_CALLBACK*>(state)->Pull( buf, esize, ecount );
  2336. }
  2337. static void Push( char * state, T_PIPE_ELEMENT * buf, unsigned long ecount )
  2338. {
  2339. reinterpret_cast<T_C_CALLBACK*>(state)->Push( buf, ecount );
  2340. }
  2341. static void Alloc( char * state, unsigned long bsize, T_PIPE_ELEMENT ** buf, unsigned long * bcount )
  2342. {
  2343. reinterpret_cast<T_C_CALLBACK*>(state)->Alloc( bsize, buf, bcount );
  2344. }
  2345. private:
  2346. T_PIPE _pipe;
  2347. }; // class CRpcPipeControl
  2348. */
  2349. //-------------------------------------------------------------------//
  2350. // //
  2351. // CDebugString
  2352. //
  2353. // This class provides conversion routines for use in dbg output.
  2354. // //
  2355. //-------------------------------------------------------------------//
  2356. // This struct stringizes a service state value. It's a struct so that it
  2357. // can be used as an overload to CDebugString, and it's all inline so that
  2358. // it doesn't compile into the free non-test code.
  2359. struct SServiceState
  2360. {
  2361. DWORD _dwState;
  2362. SServiceState( DWORD dwState )
  2363. {
  2364. _dwState = dwState;
  2365. }
  2366. void Stringize( ULONG cch, TCHAR *ptsz ) const
  2367. {
  2368. UNREFERENCED_PARAMETER(cch);
  2369. switch( _dwState )
  2370. {
  2371. case SERVICE_STOPPED:
  2372. _tcscpy( ptsz, TEXT("Service Stopped") );
  2373. break;
  2374. case SERVICE_START_PENDING:
  2375. _tcscpy( ptsz, TEXT("Service Start Pending") );
  2376. break;
  2377. case SERVICE_STOP_PENDING:
  2378. _tcscpy( ptsz, TEXT("Service Stop Pending") );
  2379. break;
  2380. case SERVICE_RUNNING:
  2381. _tcscpy( ptsz, TEXT("Service Running") );
  2382. break;
  2383. case SERVICE_CONTINUE_PENDING:
  2384. _tcscpy( ptsz, TEXT("Service Continue Pending") );
  2385. break;
  2386. case SERVICE_PAUSE_PENDING:
  2387. _tcscpy( ptsz, TEXT("Service Pause Pending") );
  2388. break;
  2389. case SERVICE_PAUSED:
  2390. _tcscpy( ptsz, TEXT("Service Paused") );
  2391. break;
  2392. default:
  2393. _tcscpy( ptsz, TEXT( "Service State UNKNOWN") );
  2394. break;
  2395. }
  2396. }
  2397. };
  2398. //+----------------------------------------------------------------------------
  2399. //
  2400. // CStringize
  2401. //
  2402. // Create a string representation of various input types. The resulting
  2403. // string is contained within this object, so this is a convenient
  2404. // stack-based means of creating a string. For example:
  2405. //
  2406. // _tprintf( TEXT("VolId = %s\n"), (TCHAR*)CStringize(volid) );
  2407. //
  2408. // This class also handles un-stringization. For example:
  2409. //
  2410. // _stscanf( TEXT("VolId = %s\n"), tszVolId );
  2411. // CStringize strVolId;
  2412. // strVolId.Use( tszVolId );
  2413. // CVolumeId volid = strVolId;
  2414. //
  2415. // BUGBUG: Merge this with CDebugString.
  2416. //
  2417. //+----------------------------------------------------------------------------
  2418. class CStringize
  2419. {
  2420. // ----
  2421. // Data
  2422. // ----
  2423. protected:
  2424. // Buffer for the string
  2425. TCHAR _tsz[ 2*MAX_PATH ];
  2426. // The current string. May or may not point to _tsz.
  2427. const TCHAR *_ptsz;
  2428. // ------------
  2429. // Constructors
  2430. // ------------
  2431. public:
  2432. // Default
  2433. CStringize()
  2434. {
  2435. _ptsz = _tsz;
  2436. _tsz[0] = TEXT('\0');
  2437. }
  2438. // TCHAR
  2439. CStringize( TCHAR tc )
  2440. {
  2441. new(this) CStringize;
  2442. _stprintf(_tsz, TEXT("%c"), tc);
  2443. }
  2444. // int
  2445. CStringize( int i )
  2446. {
  2447. new(this) CStringize;
  2448. _stprintf( _tsz, TEXT("%d"), i );
  2449. }
  2450. // ULONG
  2451. CStringize( unsigned long ul )
  2452. {
  2453. new(this) CStringize;
  2454. _stprintf( _tsz, TEXT("%lu"), ul );
  2455. }
  2456. // CVolumeId
  2457. CStringize( const CVolumeId &volid )
  2458. {
  2459. new(this) CStringize;
  2460. StringizeGUID( static_cast<GUID>(volid), &_tsz[0], sizeof(_tsz)/sizeof(TCHAR) );
  2461. }
  2462. // CVolumeSecret
  2463. CStringize( const CVolumeSecret &volsecret )
  2464. {
  2465. new(this) CStringize;
  2466. TCHAR *ptsz = _tsz;
  2467. volsecret.Stringize(ptsz);
  2468. }
  2469. // CObjId
  2470. CStringize( const CObjId &objid )
  2471. {
  2472. new(this) CStringize;
  2473. StringizeGUID( static_cast<GUID>(objid), &_tsz[0], sizeof(_tsz)/sizeof(TCHAR) );
  2474. }
  2475. // CFILETIME
  2476. CStringize(const CFILETIME &cft)
  2477. {
  2478. cft.Stringize( sizeof(_tsz), _tsz );
  2479. }
  2480. // GUID
  2481. CStringize( const GUID &guid )
  2482. {
  2483. new(this) CStringize;
  2484. StringizeGUID( guid, &_tsz[0], sizeof(_tsz)/sizeof(TCHAR) );
  2485. }
  2486. // CMachineId
  2487. CStringize( const CMachineId &mcid )
  2488. {
  2489. new(this) CStringize;
  2490. mcid.GetName(_tsz, ELEMENTS(_tsz));
  2491. }
  2492. // CDomainRelativeObjId
  2493. CStringize( const CDomainRelativeObjId &droid )
  2494. {
  2495. new(this) CStringize;
  2496. ULONG cch = StringizeGUID( droid.GetVolumeId(), _tsz, sizeof(_tsz) );
  2497. StringizeGUID( droid.GetObjId(), &_tsz[cch], sizeof(_tsz)-cch*sizeof(WCHAR) );
  2498. }
  2499. // -----------
  2500. // Conversions
  2501. // -----------
  2502. public:
  2503. operator const TCHAR*() const
  2504. {
  2505. return( _tsz );
  2506. }
  2507. operator CVolumeId() const
  2508. {
  2509. CVolumeId volid;
  2510. if( !UnStringizeGUID( _ptsz, reinterpret_cast<GUID*>(&volid) )) {
  2511. // TrkRaiseException
  2512. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CVolumeId") ));
  2513. }
  2514. return( volid );
  2515. }
  2516. operator CObjId() const
  2517. {
  2518. CObjId objid;
  2519. if( !UnStringizeGUID( _ptsz, reinterpret_cast<GUID*>(&objid) )) {
  2520. // TrkRaiseException
  2521. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CObjId") ));
  2522. }
  2523. return( objid );
  2524. }
  2525. operator CDomainRelativeObjId() const
  2526. {
  2527. CDomainRelativeObjId droid;
  2528. CVolumeId volid;
  2529. CObjId objid;
  2530. if( !UnStringizeGUID( _ptsz, reinterpret_cast<GUID*>(&volid) ))
  2531. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CDomainRelativeObjId") ));
  2532. else
  2533. {
  2534. const TCHAR *ptszObjId = _tcschr( &_ptsz[1], TEXT('{') );
  2535. if( NULL == ptszObjId )
  2536. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CDomainRelativeObjId") ));
  2537. else
  2538. {
  2539. if( !UnStringizeGUID( ptszObjId, reinterpret_cast<GUID*>(&objid) ))
  2540. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CDomainRelativeObjId") ));
  2541. else
  2542. droid = CDomainRelativeObjId( volid, objid );
  2543. }
  2544. }
  2545. return( droid );
  2546. }
  2547. public:
  2548. // Use a special caller-provided string, rather than _tsz
  2549. inline void Use( const TCHAR *ptsz )
  2550. {
  2551. _tsz[0] = TEXT('\0');
  2552. _ptsz = ptsz;
  2553. }
  2554. private:
  2555. inline ULONG StringizeGUID( const GUID &guid, TCHAR *ptsz, ULONG cchMax ) const
  2556. {
  2557. TCHAR *ptszT = NULL;
  2558. RPC_STATUS rpc_status;
  2559. rpc_status = UuidToString( const_cast<GUID*>(&guid), &ptszT );
  2560. if( NULL != ptszT )
  2561. {
  2562. _tcscpy( ptsz, TEXT("{") );
  2563. _tcscat( ptsz, ptszT );
  2564. _tcscat( ptsz, TEXT("}") );
  2565. RpcStringFree( &ptszT );
  2566. return( _tcslen(ptsz) );
  2567. }
  2568. else
  2569. {
  2570. TrkLog(( TRKDBG_ERROR, TEXT("Failed StringizeGUID (%lu)"), rpc_status ));
  2571. _tcscpy( ptsz, TEXT("") );
  2572. return( 0 );
  2573. }
  2574. }
  2575. inline BOOL UnStringizeGUID( const TCHAR *ptsz, GUID *pguid ) const
  2576. {
  2577. RPC_STATUS rpc_status;
  2578. TCHAR tszTemp[ MAX_PATH ];
  2579. TCHAR *ptszTemp = NULL;
  2580. if( TEXT('{') != ptsz[0] )
  2581. return( FALSE );
  2582. _tcscpy( tszTemp, &ptsz[1] );
  2583. ptszTemp = _tcschr( tszTemp, TEXT('}') );
  2584. if( NULL == ptsz )
  2585. return( FALSE );
  2586. *ptszTemp = TEXT('\0');
  2587. if( RPC_S_OK == UuidFromString( tszTemp, pguid ) )
  2588. {
  2589. return( TRUE );
  2590. }
  2591. else
  2592. return( FALSE );
  2593. }
  2594. };
  2595. //+----------------------------------------------------------------------------
  2596. //
  2597. // CDebugString
  2598. //
  2599. // This class has constructors for various common types. For each type,
  2600. // it stringizes the input, and puts it in the _tsz member. That member
  2601. // is public for easy access.
  2602. //
  2603. // The intent of this class is to provide an easy, stack-based mechanism
  2604. // to stringize a value for a debug output. E.g.:
  2605. //
  2606. // CObjId objid;
  2607. // objid = ...
  2608. // TrkLog(( TRKDBG_ERROR, TEXT("objid = %s"), CDebugString(objid)._tsz ));
  2609. //
  2610. //+----------------------------------------------------------------------------
  2611. #if DBG
  2612. class CDebugString : public CStringize
  2613. {
  2614. public:
  2615. CDebugString(const CObjId &objid ) : CStringize( objid ) {};
  2616. CDebugString(const CMachineId & mcid) : CStringize( mcid ) {};
  2617. CDebugString(const CFILETIME & cft) : CStringize( cft ) {};
  2618. CDebugString(const CVolumeSecret & secret) : CStringize( secret ) {};
  2619. CDebugString(const CVolumeId & volume) : CStringize( volume ) {};
  2620. CDebugString(const CDomainRelativeObjId &droid) : CStringize( droid ) {};
  2621. CDebugString(const GUID &guid ) : CStringize( guid ) {};
  2622. CDebugString(const enum WMNG_STATE state );
  2623. CDebugString(const SServiceState sServiceState );
  2624. CDebugString(LONG iVolume, const PFILE_NOTIFY_INFORMATION );
  2625. CDebugString(const TRKSVR_MESSAGE_TYPE MsgType);
  2626. CDebugString(const CNewTimer &ctimer );
  2627. };
  2628. inline
  2629. CDebugString::CDebugString(const CNewTimer & ctimer)
  2630. {
  2631. ctimer.DebugStringize( ELEMENTS(_tsz), _tsz );
  2632. }
  2633. inline
  2634. CDebugString::CDebugString( const SServiceState sServiceState )
  2635. {
  2636. sServiceState.Stringize( ELEMENTS(_tsz), _tsz );
  2637. }
  2638. #endif // #if DBG
  2639. //-------------------------------------------------------------------//
  2640. // //
  2641. // CVolumeMap
  2642. //
  2643. // Note - not currently used.
  2644. // //
  2645. //-------------------------------------------------------------------//
  2646. #ifdef VOL_REPL
  2647. class CVolumeMap
  2648. {
  2649. public:
  2650. CVolumeMap() : _pVolumeMapEntries(NULL), _cVolumeMapEntries(0), _iNextEntry(0) { }
  2651. ~CVolumeMap() { TrkAssert(_pVolumeMapEntries == NULL); }
  2652. void CopyTo( CVolumeMap * p ) const;
  2653. void MoveTo( CVolumeMap * p );
  2654. void MoveTo( ULONG * pcVolumeMapEntries, VolumeMapEntry ** ppVolumeMapEntries );
  2655. void Initialize( ULONG cVolumeMapEntries, VolumeMapEntry ** ppVolumeMapEntries );
  2656. void UnInitialize( );
  2657. void SetSize( ULONG cVolumeMapEntries ); // can throw
  2658. void Add( const CVolumeId & volume, const CMachineId & machine );
  2659. void Compact();
  2660. inline int Reset();
  2661. inline const VolumeMapEntry &
  2662. Current();
  2663. inline void Next();
  2664. BOOL Merge( CVolumeMap * pOther ); // destroys the contents of pOther, TRUE if changed
  2665. #if DBG
  2666. inline ULONG Count() const;
  2667. #endif
  2668. protected:
  2669. ULONG _cVolumeMapEntries;
  2670. VolumeMapEntry * _pVolumeMapEntries;
  2671. ULONG _iNextEntry;
  2672. };
  2673. inline int
  2674. CVolumeMap::Reset()
  2675. {
  2676. _iNextEntry = 0;
  2677. return(_cVolumeMapEntries);
  2678. }
  2679. inline void
  2680. CVolumeMap::Next()
  2681. {
  2682. _iNextEntry++;
  2683. }
  2684. inline const VolumeMapEntry &
  2685. CVolumeMap::Current()
  2686. {
  2687. return(_pVolumeMapEntries[_iNextEntry]);
  2688. }
  2689. #if DBG
  2690. inline ULONG
  2691. CVolumeMap::Count() const
  2692. {
  2693. return(_cVolumeMapEntries);
  2694. }
  2695. #endif
  2696. #endif
  2697. //
  2698. // QueryVolumeId
  2699. //
  2700. // Get the CVolumeId from a file handle.
  2701. //
  2702. inline NTSTATUS
  2703. QueryVolumeId( const HANDLE hFile, CVolumeId *pvolid )
  2704. {
  2705. NTSTATUS status = STATUS_SUCCESS;
  2706. IO_STATUS_BLOCK Iosb;
  2707. FILE_FS_OBJECTID_INFORMATION fsobOID;
  2708. status = NtQueryVolumeInformationFile( hFile, &Iosb, &fsobOID, sizeof(fsobOID),
  2709. FileFsObjectIdInformation );
  2710. if( !NT_SUCCESS(status) ) goto Exit;
  2711. *pvolid = CVolumeId( fsobOID );
  2712. Exit:
  2713. #if DBG
  2714. if( !NT_SUCCESS(status) && STATUS_OBJECT_NAME_NOT_FOUND != status )
  2715. TrkLog(( TRKDBG_ERROR, TEXT("QueryVolumeId failed (status=%08x)"), status ));
  2716. #endif
  2717. return( status );
  2718. }
  2719. //
  2720. // QueryVolumeId
  2721. //
  2722. // Get the CVolumeId from a file name.
  2723. //
  2724. inline NTSTATUS
  2725. QueryVolumeId( const WCHAR *pwszPath, CVolumeId *pvolid )
  2726. {
  2727. NTSTATUS status = STATUS_SUCCESS;
  2728. HANDLE hFile = NULL;
  2729. status = TrkCreateFile( pwszPath, FILE_READ_ATTRIBUTES,
  2730. FILE_ATTRIBUTE_NORMAL,
  2731. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN,
  2732. FILE_OPEN_NO_RECALL | FILE_SYNCHRONOUS_IO_NONALERT,
  2733. NULL, &hFile );
  2734. if( !NT_SUCCESS(status) )
  2735. {
  2736. hFile = NULL;
  2737. goto Exit;
  2738. }
  2739. status = QueryVolumeId( hFile, pvolid );
  2740. if( !NT_SUCCESS(status) ) goto Exit;
  2741. Exit:
  2742. if( NULL != hFile )
  2743. NtClose( hFile );
  2744. return( status );
  2745. }
  2746. //
  2747. // QueryVolumeId
  2748. //
  2749. // Get the CVolumeId from a drive letter index.
  2750. //
  2751. inline NTSTATUS
  2752. QueryVolumeId( ULONG iVol, CVolumeId *pvolid )
  2753. {
  2754. TCHAR tszPath[] = TEXT("A:\\");
  2755. tszPath[0] += static_cast<TCHAR>(iVol);
  2756. return QueryVolumeId(tszPath, pvolid);
  2757. }
  2758. //
  2759. // QueryVolRelativePath
  2760. //
  2761. // Get the volume-relative path of a file from its handle.
  2762. //
  2763. //
  2764. inline NTSTATUS
  2765. QueryVolRelativePath( HANDLE hFile, TCHAR *ptszVolRelativePath )
  2766. {
  2767. NTSTATUS status;
  2768. IO_STATUS_BLOCK Iosb;
  2769. // FILE_NAME_INFORMATION buffer. This size allows for a MAX_PATH path,
  2770. // plus a string terminator (because sizeof FILE_NAME_INFORMATION already
  2771. // has a character for the name).
  2772. BYTE rgbFileNameInformation[ 2 * MAX_PATH + sizeof(FILE_NAME_INFORMATION) ];
  2773. FILE_NAME_INFORMATION *pfile_name_information
  2774. = (FILE_NAME_INFORMATION*) rgbFileNameInformation;
  2775. // Get the volume-relative path.
  2776. status = NtQueryInformationFile(
  2777. hFile,
  2778. &Iosb,
  2779. pfile_name_information,
  2780. sizeof(rgbFileNameInformation),
  2781. FileNameInformation );
  2782. #ifndef UNICODE
  2783. #error Only Unicode supported
  2784. #endif
  2785. if( !NT_SUCCESS(status) ) goto Exit;
  2786. pfile_name_information->FileName[ pfile_name_information->FileNameLength / sizeof(WCHAR) ]
  2787. = L'\0';
  2788. _tcscpy( ptszVolRelativePath, pfile_name_information->FileName );
  2789. Exit:
  2790. #if DBG
  2791. if( !NT_SUCCESS(status) )
  2792. TrkLog(( TRKDBG_ERROR, TEXT("Failed QueryVolRelativePath, status=%08x"), status ));
  2793. #endif
  2794. return( status );
  2795. }
  2796. //
  2797. // FileIsDirectory
  2798. //
  2799. // Determine if a file is a directory file.
  2800. //
  2801. inline BOOL
  2802. FileIsDirectory( HANDLE hFile )
  2803. {
  2804. NTSTATUS status;
  2805. IO_STATUS_BLOCK Iosb;
  2806. FILE_BASIC_INFORMATION file_basic_information;
  2807. // Get the volume-relative path.
  2808. status = NtQueryInformationFile(
  2809. hFile,
  2810. &Iosb,
  2811. &file_basic_information,
  2812. sizeof(file_basic_information),
  2813. FileBasicInformation );
  2814. return( 0 != (file_basic_information.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) );
  2815. }
  2816. //
  2817. // Generate a "random" dword, based primarily on the
  2818. // performance counter.
  2819. //
  2820. inline DWORD
  2821. QuasiRandomDword()
  2822. {
  2823. DWORD dwRet;
  2824. CFILETIME cftNow;
  2825. LARGE_INTEGER li;
  2826. QueryPerformanceCounter( &li );
  2827. dwRet = li.HighPart ^ li.LowPart;
  2828. dwRet ^= cftNow.LowDateTime();
  2829. dwRet ^= cftNow.HighDateTime();
  2830. return( dwRet );
  2831. }
  2832. //
  2833. // TrkCharUpper
  2834. //
  2835. // Convert to upper case.
  2836. //
  2837. inline WCHAR
  2838. TrkCharUpper( WCHAR wc )
  2839. {
  2840. if( !LCMapStringW( LOCALE_USER_DEFAULT,
  2841. LCMAP_UPPERCASE,
  2842. (LPWSTR)&wc,
  2843. 1,
  2844. (LPWSTR)&wc,
  2845. 1 ))
  2846. {
  2847. TrkLog(( TRKDBG_ERROR, TEXT("Failed LcMapStringW ('%c', %lu)"),
  2848. wc, GetLastError() ));
  2849. }
  2850. return( wc );
  2851. }
  2852. // These are the errors that we see when we attempt to use a volume
  2853. // that has been dismounted and locked from under us.
  2854. inline BOOL
  2855. IsErrorDueToLockedVolume( NTSTATUS status )
  2856. {
  2857. return( STATUS_VOLUME_DISMOUNTED == status // Handle has been broken
  2858. ||
  2859. STATUS_ACCESS_DENIED == status // Volume locked, couldn't open a handle
  2860. ||
  2861. ERROR_ACCESS_DENIED == status
  2862. ||
  2863. HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == status
  2864. ||
  2865. HRESULT_FROM_WIN32(ERROR_OPEN_FAILED) == status );
  2866. }
  2867. // These are the errors that we get from a disk operation that
  2868. // are in some way recoverable.
  2869. inline BOOL
  2870. IsRecoverableDiskError( NTSTATUS status )
  2871. {
  2872. return( TRK_E_CORRUPT_LOG == status
  2873. ||
  2874. ERROR_NOT_READY == status
  2875. ||
  2876. HRESULT_FROM_WIN32(ERROR_NOT_READY) == status
  2877. ||
  2878. STATUS_DEVICE_NOT_READY == status
  2879. ||
  2880. IsErrorDueToLockedVolume( status ));
  2881. }
  2882. // Check to see if the current thread token is a member
  2883. // of the Authenticated Users group. This class is never
  2884. // instantiated, it's just a static helper class.
  2885. class CVerifyAuthentication
  2886. {
  2887. private:
  2888. // The SID for the built-in Authenticated Users group.
  2889. static PSID _psidAuthenticatedUsersGroup;
  2890. private:
  2891. // Constructor is private; this is just a static helper class.
  2892. CVerifyAuthentication()
  2893. {
  2894. }
  2895. public:
  2896. // Initialization
  2897. static void Initialize()
  2898. {
  2899. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  2900. // We shouldn't already be initialized
  2901. if( NULL != _psidAuthenticatedUsersGroup )
  2902. {
  2903. TrkLog(( TRKDBG_WARNING, TEXT("InitForIsAuthenticatedUser called multiple times") ));
  2904. TrkRaiseWin32Error( ERROR_INTERNAL_DB_CORRUPTION );
  2905. }
  2906. // Allocate the Authenticated Users SID
  2907. if( !AllocateAndInitializeSid( &NtAuthority,
  2908. 1,
  2909. SECURITY_AUTHENTICATED_USER_RID,
  2910. 0, 0, 0, 0, 0, 0, 0,
  2911. &_psidAuthenticatedUsersGroup ))
  2912. {
  2913. TrkLog(( TRKDBG_WARNING, TEXT("InitForIsAuthenticatedUser failed (%lu)"), GetLastError() ));
  2914. TrkRaiseLastError();
  2915. }
  2916. }
  2917. // Uninitialization
  2918. static void Uninitialize()
  2919. {
  2920. if( NULL != _psidAuthenticatedUsersGroup )
  2921. {
  2922. FreeSid( _psidAuthenticatedUsersGroup );
  2923. _psidAuthenticatedUsersGroup = NULL;
  2924. }
  2925. }
  2926. // Verify that the caller on this RPC handle is authenticated,
  2927. // by verifying that they're a member of the Authenticated Users
  2928. // group. Raise if not.
  2929. static void VerifyAuthentication( handle_t IDL_handle )
  2930. {
  2931. BOOL fAuthenticatedUser = FALSE;
  2932. // Impersonate the user so we can get their user token.
  2933. RPC_STATUS rpc_status = RpcImpersonateClient( IDL_handle );
  2934. if( S_OK == rpc_status )
  2935. {
  2936. #if DBG
  2937. TCHAR tszCurrentUser[ 200 ] = { TEXT("") };
  2938. ULONG cchCurrentUser = sizeof(tszCurrentUser);
  2939. GetUserName( tszCurrentUser, &cchCurrentUser );
  2940. TrkLog(( TRKDBG_MEND, TEXT("\nCall from %s"), tszCurrentUser ));
  2941. #endif
  2942. // See if this user is authenticated
  2943. if( IsAuthenticatedUser() )
  2944. fAuthenticatedUser = TRUE;
  2945. // Stop impersonating
  2946. RpcRevertToSelf();
  2947. }
  2948. else
  2949. {
  2950. TrkLog(( TRKDBG_WARNING, TEXT("VerifyAuthentication couldn't impersonate") ));
  2951. }
  2952. if( !fAuthenticatedUser )
  2953. {
  2954. TrkLog(( TRKDBG_WARNING, TEXT("Attempt at unauthenticated access") ));
  2955. TrkRaiseWin32Error( ERROR_NOT_AUTHENTICATED );
  2956. }
  2957. }
  2958. private:
  2959. // Check if the current user on this thread is a member
  2960. // of the Authenticated Users group.
  2961. static BOOL IsAuthenticatedUser()
  2962. {
  2963. BOOL fAuthenticatedUser = FALSE;
  2964. TrkAssert( NULL != _psidAuthenticatedUsersGroup );
  2965. if( NULL == _psidAuthenticatedUsersGroup )
  2966. return FALSE;
  2967. if( !CheckTokenMembership( NULL, _psidAuthenticatedUsersGroup, &fAuthenticatedUser ) )
  2968. {
  2969. TrkLog(( TRKDBG_WARNING, TEXT("Failed CheckTokenMembership (%lu)"), GetLastError() ));
  2970. }
  2971. return fAuthenticatedUser;
  2972. }
  2973. }; // CVerifyAuthentication
  2974. //+----------------------------------------------------------------------------
  2975. //
  2976. // CHexStringize
  2977. //
  2978. // Create a string with a hex representation of the input. E.g.:
  2979. //
  2980. // _tprintf( TEXT("1234 in hex is 0x%s\n"), CHexStringize(1234)._tsz );
  2981. //
  2982. //+----------------------------------------------------------------------------
  2983. class CHexStringize
  2984. {
  2985. public:
  2986. TCHAR _tsz[ MAX_PATH ];
  2987. public:
  2988. // Stringize a long
  2989. CHexStringize( long l)
  2990. {
  2991. _stprintf(_tsz, TEXT("%08x"), l);
  2992. }
  2993. // Stringize a long, and take a caller-specified prefix
  2994. CHexStringize( TCHAR *ptsz, long l )
  2995. {
  2996. _stprintf( _tsz, TEXT("%s%08x"), ptsz, l );
  2997. }
  2998. operator const TCHAR*() const
  2999. {
  3000. return( _tsz );
  3001. }
  3002. };
  3003. // Event logging prototypes
  3004. HRESULT TrkReportRawEvent(DWORD EventId,
  3005. WORD wType,
  3006. DWORD cbRawData,
  3007. const void *pvRawData,
  3008. va_list pargs );
  3009. inline HRESULT
  3010. TrkReportRawEventWrapper( DWORD EventId,
  3011. WORD wType,
  3012. DWORD cbRawData,
  3013. const void *pvRawData,
  3014. ... )
  3015. {
  3016. va_list va;
  3017. va_start( va, pvRawData );
  3018. return TrkReportRawEvent( EventId, wType, cbRawData, pvRawData, va );
  3019. }
  3020. inline HRESULT
  3021. TrkReportEvent( DWORD EventId, WORD wType, ... )
  3022. {
  3023. va_list va;
  3024. va_start( va, wType );
  3025. return TrkReportRawEvent( EventId, wType, 0, NULL, va );
  3026. }
  3027. HRESULT TrkReportInternalError(DWORD dwFileNo,
  3028. DWORD dwLineNo,
  3029. HRESULT hr,
  3030. const TCHAR* ptszData = NULL );
  3031. #define TRKREPORT_LAST_PARAM NULL
  3032. //+----------------------------------------------------------------------------
  3033. //
  3034. // COperationLog
  3035. //
  3036. // This class represents a simple, optional, circular log of events that have
  3037. // occurred in the service. By default this log is off, but it can be turned
  3038. // on with a registry setting.
  3039. //
  3040. //+----------------------------------------------------------------------------
  3041. #define OPERATION_LOG_VERSION 1
  3042. class COperationLog
  3043. {
  3044. public:
  3045. // The shutdown bit is set in the log header on a clean
  3046. // service stop.
  3047. enum EHeaderFlags
  3048. {
  3049. PROPER_SHUTDOWN = 0x1
  3050. };
  3051. // The following operations are defined. These are the "opcode"
  3052. // for an entry in the log.
  3053. enum EOperation
  3054. {
  3055. TRKSVR_START = 1,
  3056. TRKSVR_SEARCH,
  3057. TRKSVR_MOVE_NOTIFICATION,
  3058. TRKSVR_REFRESH,
  3059. TRKSVR_SYNC_VOLUMES,
  3060. TRKSVR_DELETE_NOTIFY,
  3061. TRKSVR_STATISTICS,
  3062. TRKSVR_QUOTA,
  3063. TRKSVR_GC
  3064. };
  3065. private:
  3066. // The small log header.
  3067. struct SHeader
  3068. {
  3069. DWORD dwVersion;
  3070. DWORD iRecord;
  3071. DWORD grfFlags;
  3072. DWORD dwReserved;
  3073. };
  3074. // The structure of a record in the log.
  3075. struct SRecord
  3076. {
  3077. DWORD dwOperation;
  3078. FILETIME ftOperation;
  3079. CMachineId mcidSource;
  3080. HRESULT hr;
  3081. DWORD rgdwExtra[8];
  3082. };
  3083. private:
  3084. #ifndef NO_OPLOG
  3085. // Has the class been initialized?
  3086. BOOL _fInitialized:1;
  3087. // Has the log file itself been intiailize (it is
  3088. // initialized lazily)?
  3089. BOOL _fLogFileInitialized:1;
  3090. CCriticalSection _critsec;
  3091. // Handles to the file
  3092. HANDLE _hFile;
  3093. HANDLE _hFileMapping;
  3094. // Record-granular index into the file.
  3095. DWORD _iRecord;
  3096. ULONG _cRecords;
  3097. // Mapped views of the file
  3098. SHeader *_pHeader;
  3099. SRecord *_prgRecords;
  3100. // File name
  3101. const TCHAR *_ptszOperationLog;
  3102. #endif
  3103. public:
  3104. COperationLog( )
  3105. {
  3106. #ifndef NO_OPLOG
  3107. _fInitialized = _fLogFileInitialized = FALSE;
  3108. _iRecord = 0;
  3109. _hFile = INVALID_HANDLE_VALUE;
  3110. _hFileMapping = NULL;
  3111. _ptszOperationLog = NULL;
  3112. _pHeader = NULL;
  3113. _prgRecords = NULL;
  3114. _ptszOperationLog = NULL;
  3115. #endif
  3116. }
  3117. ~COperationLog()
  3118. {
  3119. #ifndef NO_OPLOG
  3120. if( NULL != _pHeader )
  3121. {
  3122. TrkLog(( TRKDBG_VOLUME, TEXT("Flushing operation log with index at %d"), _iRecord ));
  3123. Flush();
  3124. _pHeader->grfFlags |= PROPER_SHUTDOWN;
  3125. Flush();
  3126. UnmapViewOfFile( _pHeader );
  3127. }
  3128. if( NULL != _hFileMapping )
  3129. CloseHandle( _hFileMapping );
  3130. if( INVALID_HANDLE_VALUE != _hFile )
  3131. CloseHandle( _hFile );
  3132. _critsec.UnInitialize();
  3133. #endif
  3134. }
  3135. // Return TRUE if logging is turned on
  3136. inline BOOL Logging()
  3137. {
  3138. #ifndef NO_OPLOG
  3139. return( NULL != _ptszOperationLog );
  3140. #else
  3141. return( FALSE );
  3142. #endif
  3143. }
  3144. // Enter the critsec
  3145. void Lock()
  3146. {
  3147. #ifndef NO_OPLOG
  3148. _critsec.Enter();
  3149. #endif
  3150. }
  3151. // Leave the critsec
  3152. void Unlock()
  3153. {
  3154. #ifndef NO_OPLOG
  3155. _critsec.Leave();
  3156. #endif
  3157. }
  3158. private:
  3159. // Initialize the log file when it's actually needed
  3160. HRESULT InitializeLogFile();
  3161. public:
  3162. // Initialize the class
  3163. inline HRESULT Initialize( const TCHAR *ptszOperationLog );
  3164. // Flush the log/mappings to disk.
  3165. void Flush();
  3166. // Add an entry
  3167. inline void Add( DWORD dwOperation,
  3168. HRESULT hr = S_OK,
  3169. const CMachineId &mcidSource = CMachineId(MCID_INVALID),
  3170. DWORD dwExtra0 = 0,
  3171. DWORD dwExtra1 = 0,
  3172. DWORD dwExtra2 = 0,
  3173. DWORD dwExtra3 = 0,
  3174. DWORD dwExtra4 = 0,
  3175. DWORD dwExtra5 = 0,
  3176. DWORD dwExtra6 = 0,
  3177. DWORD dwExtra7 = 0
  3178. );
  3179. // Wrapper to add an mcid/droid
  3180. inline void Add( DWORD dwOperation,
  3181. HRESULT hr,
  3182. const CMachineId &mcidSource,
  3183. const CDomainRelativeObjId &droid );
  3184. // Wrapper to add an mcid/volid
  3185. inline void Add( DWORD dwOperation,
  3186. HRESULT hr,
  3187. const CMachineId &mcidSource,
  3188. const CVolumeId &volid,
  3189. DWORD dwExtra );
  3190. private:
  3191. #ifndef NO_OPLOG
  3192. void InternalAdd( DWORD dwOperation, HRESULT hr, const CMachineId &mcidSource,
  3193. DWORD dwExtra0, DWORD dwExtra1, DWORD dwExtra2, DWORD dwExtra3,
  3194. DWORD dwExtra4, DWORD dwExtra5, DWORD dwExtra6, DWORD dwExtra7 );
  3195. #endif
  3196. };
  3197. inline void
  3198. COperationLog::Add( DWORD dwOperation,
  3199. HRESULT hr,
  3200. const CMachineId &mcidSource,
  3201. DWORD dwExtra0,
  3202. DWORD dwExtra1,
  3203. DWORD dwExtra2,
  3204. DWORD dwExtra3,
  3205. DWORD dwExtra4,
  3206. DWORD dwExtra5,
  3207. DWORD dwExtra6,
  3208. DWORD dwExtra7
  3209. )
  3210. {
  3211. #ifndef NO_OPLOG
  3212. if( !Logging() )
  3213. return;
  3214. InternalAdd( dwOperation, hr, mcidSource,
  3215. dwExtra0, dwExtra1, dwExtra2, dwExtra3, dwExtra4, dwExtra5, dwExtra6, dwExtra7 );
  3216. #endif
  3217. }
  3218. #define DROID_DWORD(droid,i) ( ((const DWORD*)(&(droid)))[i] )
  3219. inline void
  3220. COperationLog::Add( DWORD dwOperation,
  3221. HRESULT hr,
  3222. const CMachineId &mcidSource,
  3223. const CDomainRelativeObjId &droid )
  3224. {
  3225. #ifndef NO_OPLOG
  3226. // Parameter validation (protect against attack)
  3227. // mcidSource is generated by us, not the client, so it's safe.
  3228. if (!((const void*)(&(droid))))
  3229. {
  3230. return;
  3231. }
  3232. Add( dwOperation, hr, mcidSource,
  3233. DROID_DWORD( droid, 0 ),
  3234. DROID_DWORD( droid, 1 ),
  3235. DROID_DWORD( droid, 2 ),
  3236. DROID_DWORD( droid, 3 ),
  3237. DROID_DWORD( droid, 4 ),
  3238. DROID_DWORD( droid, 5 ),
  3239. DROID_DWORD( droid, 6 ),
  3240. DROID_DWORD( droid, 7 ) );
  3241. #endif
  3242. }
  3243. #define GUID_DWORD(guid,i) ( ((const DWORD*)(&(guid)))[i] )
  3244. inline void
  3245. COperationLog::Add( DWORD dwOperation,
  3246. HRESULT hr,
  3247. const CMachineId &mcidSource,
  3248. const CVolumeId &volid,
  3249. DWORD dwExtra )
  3250. {
  3251. #ifndef NO_OPLOG
  3252. // Parameter validation (protect against attack)
  3253. // mcidSource is generated by us, not the client, so it's safe.
  3254. if (!((const void*)(&(volid))))
  3255. {
  3256. return;
  3257. }
  3258. Add( dwOperation, hr, mcidSource,
  3259. GUID_DWORD( volid, 0 ),
  3260. GUID_DWORD( volid, 1 ),
  3261. GUID_DWORD( volid, 2 ),
  3262. GUID_DWORD( volid, 3 ),
  3263. dwExtra );
  3264. #endif
  3265. }
  3266. inline HRESULT
  3267. COperationLog::Initialize( const TCHAR *ptszOperationLog )
  3268. {
  3269. #ifndef NO_OPLOG
  3270. HRESULT hr = E_FAIL;
  3271. if( NULL == ptszOperationLog || TEXT('\0') == *ptszOperationLog )
  3272. return( S_OK );
  3273. _critsec.Initialize();
  3274. _fInitialized = TRUE;
  3275. _ptszOperationLog = ptszOperationLog;
  3276. TrkLog(( TRKDBG_ERROR, TEXT("Operation log = %s"), _ptszOperationLog ));
  3277. hr = S_OK;
  3278. return( hr );
  3279. #else
  3280. return( S_OK );
  3281. #endif
  3282. }