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.

1829 lines
52 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. //
  6. // File: trksvr.hxx
  7. //
  8. // Contents: Definitions local to this directory.
  9. // Put includes of files liable to change often in this file.
  10. //
  11. // Classes: CTrkSvrSvc
  12. // CTrkSvrConfiguration
  13. // CDbConnection
  14. // CIntraDomainTable
  15. // CCrossDomainTable
  16. // CVolumeTable
  17. // CDenialChecker
  18. // CGhostTable - DBG only
  19. // CQuotaTable
  20. //
  21. // Functions:
  22. //
  23. //
  24. //
  25. // History: 18-Nov-96 BillMo Created.
  26. // 18-Nov-97 WeiruC Added CQuotaTable class.
  27. //
  28. // Notes: Put includes of files that don't change often into pch.cxx.
  29. //
  30. // Codework: Put in services.exe : _hDllReference
  31. //
  32. //--------------------------------------------------------------------------
  33. #include "trklib.hxx"
  34. #include <trkwks.h>
  35. #include <trksvr.h>
  36. #include "resource.h"
  37. //+-------------------------------------------------------------------------
  38. //
  39. // Strings
  40. //
  41. //--------------------------------------------------------------------------
  42. const extern TCHAR tszValueNameSeq[] INIT( TEXT("seqRefresh") );
  43. #ifndef EVENT_SOURCE_DEFINED
  44. #define EVENT_SOURCE_DEFINED
  45. const extern TCHAR* g_ptszEventSource INIT( TEXT("Distributed Link Tracking Server") );
  46. #endif
  47. //
  48. // LDAP classes and container names
  49. //
  50. const extern TCHAR s_VolumeTableRDN[] INIT( TEXT("CN=VolumeTable,CN=FileLinks,CN=System,") );
  51. const extern TCHAR s_ObjectMoveTableRDN[] INIT( TEXT("CN=ObjectMoveTable,CN=FileLinks,CN=System,") );
  52. const extern TCHAR s_objectClass[] INIT( TEXT("objectClass") );
  53. const extern TCHAR s_linkTrackVolumeTable[] INIT( TEXT("linkTrackVolumeTable") );
  54. const extern TCHAR s_linkTrackObjectMoveTable[] INIT( TEXT("linkTrackObjectMoveTable") );
  55. const extern TCHAR s_linkTrackVolEntry[] INIT( TEXT("linkTrackVolEntry") );
  56. const extern TCHAR s_linkTrackOMTEntry[] INIT( TEXT("linkTrackOMTEntry") );
  57. const extern TCHAR s_Cn[] INIT( TEXT("CN") );
  58. //
  59. // Tables
  60. //
  61. // Volume Table (voltab.cxx)
  62. //
  63. // Design VOLUMEID -> MACHINEID SECRET TIME NotificationSequence
  64. // Logical DN currMachineId volumeSecret timeVolChange seqNotification
  65. //
  66. // DN is stringized volume id
  67. const extern TCHAR s_currMachineId[] INIT( TEXT("volTableIdxGUID") ); // was "currMachineId"
  68. const extern TCHAR s_volumeSecret[] INIT( TEXT("linkTrackSecret") );
  69. const extern TCHAR s_objectCount[] INIT( TEXT("objectCount") );
  70. const extern TCHAR s_seqNotification[] INIT( TEXT("seqNotification") );
  71. const extern TCHAR s_timeRefresh[] INIT( TEXT("timeRefresh") );
  72. const extern TCHAR s_timeVolChange[] INIT( TEXT("timeVolChange") );
  73. const extern TCHAR s_volTableGUID[] INIT( TEXT("volTableGUID") );
  74. //const extern TCHAR s_volTableIdxGUID[] INIT( TEXT("volTableIdxGUID") ); // used for currMachineId
  75. #ifdef VOL_REPL
  76. const extern TCHAR s_timeVolChangeSearch[] INIT( TEXT("(timeVolChange;binary>=") );
  77. #endif
  78. const extern TCHAR s_currMachineIdSearch[] INIT( TEXT("(volTableIdxGUID;binary=") );
  79. // Object Move Table (idt_ldap.cxx)
  80. //
  81. // Design Birth/Current -> New Birth RefreshSequence
  82. // Design VOLUMEID:OBJID -> VOLUMEID:OBJID VOLUMEID:BIRTHID ULONG
  83. // Logical DN currVolumeId:currObjectId birthVolumeId:birthObjectId seqRefresh
  84. // Actual str(VOLUMEID:OBJID) currMachineId:objId birthMachineId:currReplsetid linkTrackSecret
  85. //
  86. // DN is stringized Birth/Current
  87. const extern TCHAR s_birthLocation[] INIT( TEXT("birthLocation") );
  88. const extern TCHAR s_currentLocation[] INIT( TEXT("currentLocation") );
  89. const extern TCHAR s_oMTGuid[] INIT( TEXT("oMTGuid") );
  90. const extern TCHAR s_oMTIndxGuid[] INIT( TEXT("oMTIndxGuid") );
  91. const extern TCHAR s_RestoreTime[] INIT( TEXT("System\\CurrentControlSet\\Services\\NtDs\\Parameters\\RestoreTime") );
  92. const extern TCHAR s_RestoreBegin[] INIT( TEXT("RestoreBegin") );
  93. const extern TCHAR s_rIDManagerReference[] INIT( TEXT("rIDManagerReference") );
  94. const extern TCHAR s_fSMORoleOwner[] INIT( TEXT("fSMORoleOwner") );
  95. //--------------------------------------------------------------------------
  96. //
  97. // General defines
  98. //
  99. //--------------------------------------------------------------------------
  100. #define MAX_SHORTENABLE_SEGMENTS (NUM_VOLUMES)
  101. #define CCH_UINT32 10 // Max chars for a DWORD value
  102. #define CCH_UINT64 20 // Max chars for a QUADWORD value
  103. #define MAX_WAIT_FOR_DS_STARTUP_SECONDS 360
  104. //--------------------------------------------------------------------------
  105. //
  106. // Forward declarations
  107. //
  108. //--------------------------------------------------------------------------
  109. class CTrkSvrConfiguration;
  110. class CTrkSvrSvc;
  111. //-------------------------------------------------------------------//
  112. // //
  113. // Global variables //
  114. // //
  115. //-------------------------------------------------------------------//
  116. EXTERN CTrkSvrSvc * g_ptrksvr; // For RPC stubs to call service
  117. EXTERN LONG g_ctrksvr INIT(0); // Used to protect against multiple service instances
  118. //--------------------------------------------------------------------------
  119. //
  120. // Ldap enumeration
  121. //
  122. //--------------------------------------------------------------------------
  123. typedef enum
  124. {
  125. ENUM_DELETE_ENTRY,
  126. ENUM_KEEP_ENTRY,
  127. ENUM_DELETE_QUOTAFLAGS,
  128. ENUM_ABORT
  129. } ENUM_ACTION;
  130. typedef ENUM_ACTION (*PFN_LDAP_ENUMERATE_CALLBACK)(
  131. LDAP * pLdap,
  132. LDAPMessage * pResult,
  133. void* UserParam1,
  134. void* UserParam2
  135. );
  136. ENUM_ACTION
  137. GcEnumerateCallback(
  138. LDAP * pLdap,
  139. LDAPMessage * pResult,
  140. PVOID pvContext,
  141. void*
  142. );
  143. BOOL // FALSE if aborted (ENUM_ABORT returned by callback)
  144. LdapEnumerate(
  145. LDAP * pLdap,
  146. TCHAR * ptszBaseDn,
  147. ULONG Scope,
  148. TCHAR * Filter,
  149. TCHAR * Attributes[],
  150. PFN_LDAP_ENUMERATE_CALLBACK pCallback,
  151. PVOID pvContext,
  152. void* UserParam2 = NULL
  153. );
  154. //--------------------------------------------------------------------------
  155. //
  156. // Garbage collection
  157. //
  158. //--------------------------------------------------------------------------
  159. class CQuotaTable;
  160. // This structure holds context during enumeration
  161. // in a GC
  162. typedef struct
  163. {
  164. // All entries with lower sequence numbers
  165. // should be deleted.
  166. SequenceNumber seqOldestToKeep;
  167. // The highest sequence number we should see.
  168. SequenceNumber seqCurrent;
  169. // If true, abort (happens on service stop).
  170. const BOOL *pfAbort;
  171. // How long to sleep between non-noop iterations
  172. DWORD dwRepetitiveTaskDelay;
  173. // The quota table
  174. CQuotaTable *pqtable;
  175. // The number of entries that have been deleted (otherwise).
  176. ULONG cEntries;
  177. } GC_ENUM_CONTEXT;
  178. typedef struct
  179. {
  180. LONG cDelta;
  181. DWORD dwRepetitiveTaskDelay;
  182. DWORD dwPass;
  183. BOOL fCountAll;
  184. enum EPass
  185. {
  186. FIRST_PASS, SECOND_PASS
  187. };
  188. } TRUE_COUNT_ENUM_CONTEXT;
  189. //--------------------------------------------------------------------------
  190. //
  191. // Quota table
  192. //
  193. //--------------------------------------------------------------------------
  194. #define QFLAG_UNCOUNTED 0x8
  195. #define QFLAG_DELETED 0x4
  196. //+-------------------------------------------------------------------------
  197. //
  198. // Class: CDbConnection
  199. //
  200. // Purpose: Handles shared connection to database
  201. //
  202. // Notes:
  203. //
  204. //--------------------------------------------------------------------------
  205. class CDbConnection
  206. {
  207. public:
  208. // --------------------> indent 24 characters
  209. inline CDbConnection();
  210. inline ~CDbConnection();
  211. void Initialize(CSvcCtrlInterface * psvc, OPTIONAL const TCHAR *ptszHostName = NULL );
  212. void UnInitialize();
  213. inline const TCHAR *GetBaseDn() { Ldap(); return _pszBaseDn; }
  214. LDAP * Ldap();
  215. private:
  216. BOOL _fInitializeCalled:1;
  217. CCriticalSection _cs;
  218. LDAP * _pldap;
  219. TCHAR * _pszBaseDn;
  220. };
  221. inline // put all types/attributes on same line as inline
  222. CDbConnection::CDbConnection() :
  223. _fInitializeCalled(FALSE)
  224. {
  225. // Normally critsecs are initialized in the Initialize method.
  226. // But for this class the Initialize method doesn't get called right
  227. // away, so we'll try to initialize here and deal with it in Ldap()
  228. // if this fails.
  229. __try
  230. {
  231. _cs.Initialize();
  232. }
  233. __except( EXCEPTION_EXECUTE_HANDLER )
  234. {
  235. }
  236. }
  237. inline
  238. CDbConnection::~CDbConnection()
  239. {
  240. UnInitialize();
  241. _cs.UnInitialize();
  242. }
  243. //+-------------------------------------------------------------------------
  244. //
  245. // Class: CCrossDomainTable
  246. //
  247. // Purpose: Contains cross domain links
  248. //
  249. // Notes: Columns
  250. // -------
  251. //
  252. // prev_location new_location birth_id
  253. //
  254. //--------------------------------------------------------------------------
  255. class CCrossDomainTable
  256. {
  257. public:
  258. inline CCrossDomainTable(CDbConnection & dbc);
  259. inline ~CCrossDomainTable();
  260. void Initialize();
  261. void UnInitialize();
  262. private:
  263. BOOL _fInitializeCalled:1;
  264. const CDbConnection &
  265. _dbc;
  266. };
  267. inline
  268. CCrossDomainTable::CCrossDomainTable(CDbConnection & dbc) :
  269. _fInitializeCalled(FALSE),
  270. _dbc(dbc)
  271. {
  272. }
  273. inline
  274. CCrossDomainTable::~CCrossDomainTable()
  275. {
  276. UnInitialize();
  277. }
  278. //+-------------------------------------------------------------------------
  279. //
  280. // Class: CRefreshSequenceStorage
  281. //
  282. // Purpose: Stores the refresh sequence number in the DS's restorable
  283. // table data.
  284. //
  285. //--------------------------------------------------------------------------
  286. class CVolumeTable;
  287. class CRefreshSequenceStorage
  288. {
  289. public:
  290. inline CRefreshSequenceStorage( CVolumeTable * pVolTab, CQuotaTable *pQuotaTab, CTrkSvrConfiguration *psvrconfig );
  291. inline ~CRefreshSequenceStorage();
  292. inline void Initialize();
  293. public:
  294. SequenceNumber GetSequenceNumber();
  295. void IncrementSequenceNumber();
  296. private:
  297. SequenceNumber _seq;
  298. CCriticalSection _cs;
  299. CVolumeTable * _pVolTab;
  300. CQuotaTable * _pQuotaTab;
  301. CTrkSvrConfiguration * _psvrconfig;
  302. CFILETIME _cftLastRead;
  303. };
  304. inline
  305. CRefreshSequenceStorage::CRefreshSequenceStorage( CVolumeTable * pVolTab,
  306. CQuotaTable *pQuotaTab,
  307. CTrkSvrConfiguration *psvrconfig ) :
  308. _pVolTab(pVolTab),
  309. _pQuotaTab(pQuotaTab),
  310. _cftLastRead(0),
  311. _psvrconfig(psvrconfig)
  312. {
  313. }
  314. inline void
  315. CRefreshSequenceStorage::Initialize()
  316. {
  317. _cs.Initialize();
  318. }
  319. inline
  320. CRefreshSequenceStorage::~CRefreshSequenceStorage()
  321. {
  322. _cs.UnInitialize();
  323. }
  324. //+----------------------------------------------------------------------------
  325. //
  326. // Class CAbbreviatedIDString
  327. //
  328. // Take an ID (e.g. a Droid) and create an abbreviated string for
  329. // dbg outs.
  330. //
  331. //+----------------------------------------------------------------------------
  332. class CAbbreviatedIDString
  333. {
  334. private:
  335. TCHAR _tsz[ 8 ]; // e.g. {01:02}
  336. public:
  337. inline CAbbreviatedIDString( const CDomainRelativeObjId &droid );
  338. inline operator const TCHAR *() const;
  339. };
  340. inline
  341. CAbbreviatedIDString::CAbbreviatedIDString( const CDomainRelativeObjId &droid )
  342. {
  343. GUID guidObjId, guidVolId;
  344. droid.GetVolumeId().SerializeRaw( reinterpret_cast<BYTE*>(&guidVolId) );
  345. droid.GetObjId().SerializeRaw( reinterpret_cast<BYTE*>(&guidObjId) );
  346. _stprintf( _tsz, TEXT("{%02x:%02x}"),
  347. guidVolId.Data1 & 0xFF, guidObjId.Data1 & 0xFF );
  348. }
  349. inline
  350. CAbbreviatedIDString::operator const TCHAR *() const
  351. {
  352. return( _tsz );
  353. }
  354. //+-------------------------------------------------------------------------
  355. //
  356. // Class: CIntraDomainTable (a.k.a. Object Move Table)
  357. //
  358. // Purpose: Handles updates and queries of the location database.
  359. //
  360. // Notes: Columns
  361. // -------
  362. //
  363. // prev_location(indexed) new_location birth_id
  364. //
  365. //--------------------------------------------------------------------------
  366. struct IDT_ENTRY;
  367. class CQuotaTable;
  368. class CIntraDomainTable
  369. {
  370. public:
  371. inline CIntraDomainTable(
  372. CDbConnection & dbc,
  373. CRefreshSequenceStorage * pseqRefresh
  374. );
  375. inline ~CIntraDomainTable();
  376. void Initialize( CTrkSvrConfiguration *pTrkSvrConfiguration, CQuotaTable* pqtable );
  377. void UnInitialize();
  378. public:
  379. BOOL Add(const CDomainRelativeObjId &droidKey,
  380. const CDomainRelativeObjId &droidNew,
  381. const CDomainRelativeObjId &droidBirth,
  382. BOOL *pfQuotaExceeded = NULL OPTIONAL
  383. );
  384. //-> indent 4 chars
  385. BOOL Delete(const CDomainRelativeObjId &droidKey);
  386. ULONG GarbageCollect( SequenceNumber seqCurrent,
  387. SequenceNumber seqOldestToKeep,
  388. const BOOL * pfAbort );
  389. BOOL Modify(const CDomainRelativeObjId &droidKey,
  390. const CDomainRelativeObjId &droidNew,
  391. const CDomainRelativeObjId &droidBirth
  392. );
  393. BOOL Query(const CDomainRelativeObjId &droidKey,
  394. CDomainRelativeObjId *pdroidNew,
  395. CDomainRelativeObjId *pdroidBirth,
  396. BOOL *pfDeleted = NULL OPTIONAL,
  397. BOOL *pfCounted = NULL OPTIONAL );
  398. BOOL Query( LDAP* pLdap,
  399. LDAPMessage *pEntry,
  400. const CDomainRelativeObjId ldKey,
  401. CDomainRelativeObjId *pldNew,
  402. CDomainRelativeObjId *pldBirth,
  403. BOOL *pfDeleted = NULL OPTIONAL,
  404. BOOL *pfCounted = NULL OPTIONAL );
  405. BOOL Touch(const CDomainRelativeObjId &droidKey);
  406. #if DBG
  407. void PurgeAll();
  408. #endif
  409. private:
  410. inline const TCHAR *GetBaseDn() { return _dbc.GetBaseDn(); }
  411. inline LDAP * Ldap() { return _dbc.Ldap(); }
  412. private:
  413. BOOL _fInitializeCalled:1;
  414. CDbConnection & _dbc;
  415. CRegBoolParameter _QuotaReported;
  416. CRefreshSequenceStorage *
  417. _pRefreshSequenceStorage;
  418. CQuotaTable* _pqtable;
  419. CTrkSvrConfiguration
  420. *_pTrkSvrConfiguration;
  421. };
  422. inline
  423. CIntraDomainTable::CIntraDomainTable(CDbConnection & dbc,
  424. CRefreshSequenceStorage * pRefreshSequenceStorage ) :
  425. _fInitializeCalled(FALSE),
  426. _dbc(dbc),
  427. _pRefreshSequenceStorage( pRefreshSequenceStorage ),
  428. _QuotaReported( TEXT("IntraDomainTableQuotaReported") )
  429. {
  430. }
  431. inline
  432. CIntraDomainTable::~CIntraDomainTable()
  433. {
  434. UnInitialize();
  435. }
  436. // Objects to make constructing quota table keys easy.
  437. class CLdapSeqNum
  438. {
  439. public:
  440. CLdapSeqNum()
  441. {
  442. _tcscpy( _tszSeq, TEXT("0") );
  443. }
  444. CLdapSeqNum(SequenceNumber seq)
  445. {
  446. _stprintf( _tszSeq, TEXT("%lu"), seq );
  447. }
  448. operator TCHAR*()
  449. {
  450. return( _tszSeq );
  451. }
  452. TCHAR _tszSeq[ CCH_UINT32 ];
  453. };
  454. class CLdapQuotaKeyDn
  455. {
  456. public:
  457. CLdapQuotaKeyDn(const TCHAR* ptszBaseDn, const CMachineId& mcid)
  458. {
  459. TCHAR* ptsz;
  460. _tcscpy(_tszDn, TEXT("CN="));
  461. _tcscat(_tszDn, TEXT("QTDC_"));
  462. ptsz = _tszDn + _tcslen(_tszDn);
  463. mcid.Stringize(ptsz);
  464. *ptsz++ = TEXT(',');
  465. _tcscpy(ptsz, s_VolumeTableRDN);
  466. _tcscat(_tszDn, ptszBaseDn);
  467. TrkAssert(_tcslen(_tszDn) < ELEMENTS(_tszDn));
  468. }
  469. inline operator TCHAR* () { return _tszDn; }
  470. private:
  471. TCHAR _tszDn[MAX_PATH];
  472. };
  473. class CLdapQuotaCounterKeyDn
  474. {
  475. public:
  476. CLdapQuotaCounterKeyDn(const TCHAR* ptszBaseDn)
  477. {
  478. TCHAR* ptsz;
  479. _tcscpy(_tszDn, TEXT("CN="));
  480. _tcscat(_tszDn, TEXT("QT_Counter"));
  481. ptsz = _tszDn + _tcslen(_tszDn);
  482. *ptsz++ = TEXT(',');
  483. _tcscpy(ptsz, s_VolumeTableRDN);
  484. _tcscat(_tszDn, ptszBaseDn);
  485. TrkAssert(_tcslen(_tszDn) < ELEMENTS(_tszDn));
  486. }
  487. inline operator TCHAR* () { return _tszDn; }
  488. private:
  489. TCHAR _tszDn[MAX_PATH];
  490. };
  491. //+------------------------------------------------------------------------
  492. //
  493. // Class: CQuotaTable
  494. //
  495. // Purpose: Encapsulate functionalities that enforce quota on the
  496. // tables in the DC (move table, volume table).
  497. //
  498. //-------------------------------------------------------------------------
  499. class CQuotaTable : public PTimerCallback
  500. {
  501. public:
  502. // constructor/destructor
  503. CQuotaTable(CDbConnection& dbc);
  504. ~CQuotaTable();
  505. // initialization/uninitialization
  506. void Initialize(CVolumeTable *pvoltab,
  507. CIntraDomainTable *pidt,
  508. CTrkSvrSvc *psvrsvc,
  509. CTrkSvrConfiguration *pcfgsvr );
  510. void UnInitialize();
  511. BOOL IsDesignatedDc( BOOL fRaiseOnError = FALSE );
  512. // timer call back
  513. virtual TimerContinuation Timer(ULONG);
  514. // checking quota
  515. BOOL IsMoveQuotaExceeded();
  516. BOOL IsVolumeQuotaExceeded(const CMachineId& mcid, ULONG cUncountedVolumes);
  517. BOOL UpdateFlags(LDAP* pLdap, TCHAR* dnKey, BYTE bFlags);
  518. void DeleteFlags(LDAP* pLdap, TCHAR* dnKey);
  519. void OnServiceStopRequest();
  520. void IncrementMoveCountCache() { InterlockedIncrement(&_lCachedMoveTableCount); }
  521. void DecrementMoveCountCache() { InterlockedDecrement(&_lCachedMoveTableCount); }
  522. inline void IncrementVolumeCountCache();
  523. inline void DecrementVolumeCountCache();
  524. void InvalidateCache()
  525. {
  526. _cftCacheLastUpdated = 0;
  527. DeleteCounter();
  528. }
  529. void Statistics( TRKSVR_STATISTICS *pTrkSvrStatistics );
  530. void OnMoveTableGcComplete( ULONG cEntriesDeleted );
  531. private:
  532. enum EBackgroundForegroundTask
  533. {
  534. BACKGROUND = 1,
  535. FOREGROUND
  536. };
  537. private:
  538. void Lock();
  539. void Unlock();
  540. DWORD CalculateMoveLimit(); // Doesn't raise
  541. inline LDAP* Ldap() const { return _dbc.Ldap(); }
  542. inline const TCHAR *GetBaseDn() { return _dbc.GetBaseDn(); }
  543. BOOL ReadCounter(DWORD* dwCounter);
  544. HRESULT DeleteCounter();
  545. void GetTrueCount( DWORD* pdwTrueCount,
  546. EBackgroundForegroundTask eBackgroundForegroundTask );
  547. void WriteCounter(DWORD);
  548. void ValidateCache( BOOL fForceHint = FALSE );
  549. HRESULT ReadFlags(LDAP* pLdap, TCHAR* dnKey, BYTE* bFlags);
  550. BOOL DeleteOrphanedEntries( const CDomainRelativeObjId rgdroidList[], ULONG cSegments,
  551. const CDomainRelativeObjId &droidBirth,
  552. const CDomainRelativeObjId &droidCurrent );
  553. void ShortenString( LDAP* pLdap, LDAPMessage* pMessage, BYTE *pbFlags,
  554. const CDomainRelativeObjId &droidCurrent );
  555. TCHAR * GetFirstCN( LDAP *pLdap, LDAPMessage *pMessage );
  556. static ENUM_ACTION
  557. MoveTableEnumCallback( LDAP * pLdap,
  558. LDAPMessage * pResult,
  559. void* cEntries,
  560. void* pvThis );
  561. static ENUM_ACTION
  562. VolumeTableEnumCallback( LDAP * pLdap,
  563. LDAPMessage * pResult,
  564. void* pcEntries,
  565. void* pvThis );
  566. private:
  567. enum
  568. {
  569. QUOTA_TIMER = 0,
  570. QUOTA_CLEANUP_TIMER = 1
  571. } EQuotaTimer;
  572. BOOL _fInitializeCalled:1;
  573. BOOL _fIsDesignatedDc:1;
  574. BOOL _fStopping:1;
  575. CFILETIME _cftDesignatedDc;
  576. CTrkSvrConfiguration *_pcfgsvr;
  577. CDbConnection& _dbc;
  578. DWORD _dwMoveLimit;
  579. CMachineId _mcid;
  580. LONG _lCachedMoveTableCount;
  581. LONG _lCachedVolumeTableCount;
  582. CFILETIME _cftCacheLastUpdated;
  583. CVolumeTable *_pvoltab;
  584. CIntraDomainTable *_pidt;
  585. CTrkSvrSvc *_psvrsvc;
  586. CNewTimer _timer;
  587. CCriticalSection _cs;
  588. #if DBG
  589. LONG _cLocks;
  590. #endif
  591. };
  592. inline void
  593. CQuotaTable::OnServiceStopRequest()
  594. {
  595. _fStopping = TRUE;
  596. }
  597. inline void
  598. CQuotaTable::Lock()
  599. {
  600. _cs.Enter();
  601. #if DBG
  602. _cLocks++;
  603. #endif
  604. }
  605. inline void
  606. CQuotaTable::Unlock()
  607. {
  608. TrkAssert( 0 < _cLocks );
  609. _cs.Leave();
  610. #if DBG
  611. _cLocks--;
  612. #endif
  613. }
  614. inline void
  615. CQuotaTable::IncrementVolumeCountCache()
  616. {
  617. Lock();
  618. _lCachedVolumeTableCount++;
  619. _dwMoveLimit = CalculateMoveLimit(); // Doesn't raise
  620. Unlock();
  621. }
  622. inline void
  623. CQuotaTable::DecrementVolumeCountCache()
  624. {
  625. Lock();
  626. --_lCachedVolumeTableCount;
  627. _dwMoveLimit = CalculateMoveLimit(); // Doesn't raise
  628. Unlock();
  629. }
  630. //+-------------------------------------------------------------------------
  631. //
  632. // Class: CVolumeTable
  633. //
  634. // Purpose: Table of volumes
  635. //
  636. // Notes:
  637. //
  638. //--------------------------------------------------------------------------
  639. class CVolumeTable
  640. #ifdef VOL_REPL
  641. : PTimerCallback
  642. #endif
  643. {
  644. public: // Construction/destruction
  645. inline CVolumeTable(
  646. CDbConnection & dbc,
  647. CRefreshSequenceStorage * pRefreshSequenceStorage
  648. );
  649. inline ~CVolumeTable();
  650. void Initialize(CTrkSvrConfiguration *pconfigSvr,
  651. CQuotaTable *pqtable);
  652. void UnInitialize();
  653. public: // Public RPC level interface - must be parameter checked
  654. HRESULT ClaimVolume( const CMachineId & mcidClient,
  655. const CVolumeId & volume,
  656. const CVolumeSecret & secretOld,
  657. const CVolumeSecret & secretNew,
  658. SequenceNumber * pseq,
  659. FILETIME * pftLastRefresh );
  660. HRESULT PreCreateVolume( const CMachineId & mcidClient,
  661. const CVolumeSecret & secret,
  662. ULONG cUncountedVolumes,
  663. CVolumeId * pvolume );
  664. HRESULT DeleteVolume( const CMachineId & mcidClient,
  665. const CVolumeId & volume );
  666. HRESULT FindVolume( const CVolumeId & volume,
  667. CMachineId * pmcid );
  668. HRESULT QueryVolume( const CMachineId & mcidClient,
  669. const CVolumeId & volume,
  670. SequenceNumber * pseq,
  671. FILETIME * pftLastRefresh );
  672. //-> indent 4 chars
  673. BOOL Touch( const CVolumeId & volume );
  674. public:
  675. HRESULT SetSequenceNumber(const CVolumeId & volume, SequenceNumber seq);
  676. HRESULT SetSecret( const CVolumeId & volume, const CVolumeSecret & secret );
  677. int GetAvailableNotificationQuota( const CVolumeId & volid );
  678. DWORD CountVolumes( const CMachineId & mcidClient );
  679. ULONG GarbageCollect( SequenceNumber seqCurrent, SequenceNumber seqOldestToKeep, const BOOL * pfAbort );
  680. HRESULT GetVolumeInfo( const CVolumeId & volume,
  681. CMachineId * pmcid,
  682. CVolumeSecret * psecret,
  683. SequenceNumber * pseq,
  684. CFILETIME *pcftRefresh );
  685. HRESULT GetMachine( const CVolumeId & volume, CMachineId * pmcid );
  686. HRESULT SetMachine( const CVolumeId & volume, const CMachineId & mcid );
  687. HRESULT SetMachineAndSecret(const CVolumeId & volume, const CMachineId & mcid,
  688. const CVolumeSecret & secret);
  689. inline const TCHAR *GetBaseDn() { return _dbc.GetBaseDn(); }
  690. inline LDAP * Ldap() const { return _dbc.Ldap(); }
  691. #if DBG
  692. void PurgeCache( );
  693. #endif
  694. HRESULT AddVolidToTable( const CVolumeId & volume,
  695. const CMachineId & mcidClient,
  696. const CVolumeSecret & secret );
  697. void PurgeAll();
  698. #ifdef VOL_REPL
  699. void QueryVolumeChanges( const CFILETIME &ftFirstChange, CVolumeMap * pVolMap );
  700. void SimpleTimer( DWORD dwTimerId );
  701. #endif
  702. private:
  703. HRESULT MapResult(int ldap_err) const;
  704. #ifdef VOL_REPL
  705. void _QueryVolumeChanges( const CFILETIME &ftFirstChange, CVolumeMap * pVolMap );
  706. #endif
  707. private:
  708. BOOL _fInitializeCalled:1;
  709. CDbConnection & _dbc;
  710. CRefreshSequenceStorage *
  711. _pRefreshSequenceStorage;
  712. CTrkSvrConfiguration *
  713. _pconfigSvr;
  714. // State for caching the volume table so that
  715. // synchronizing the workstation's volume tables is efficient (normally the workstation
  716. // queries will hit the cached query.)
  717. CQuotaTable* _pqtable;
  718. #ifdef VOL_REPL
  719. CCritcalSection _csQueryCache;
  720. CVolumeMap _VolMap; // keeps cache of query since we have many machines
  721. // getting the updates
  722. CFILETIME _cftCacheLowest;
  723. CSimpleTimer _timerQueryCache;
  724. DWORD _SecondsPreviousToNow;
  725. #endif
  726. };
  727. inline
  728. CVolumeTable::CVolumeTable( CDbConnection & dbc,
  729. CRefreshSequenceStorage * pRefreshSequenceStorage
  730. ) :
  731. _dbc(dbc),
  732. _fInitializeCalled(FALSE),
  733. _pRefreshSequenceStorage( pRefreshSequenceStorage ),
  734. _pconfigSvr(NULL)
  735. {
  736. }
  737. inline
  738. CVolumeTable::~CVolumeTable()
  739. {
  740. UnInitialize();
  741. }
  742. //+----------------------------------------------------------------------------
  743. //
  744. // CActiveCreates
  745. //
  746. // Keep track of Create-Volume requests that are in the callback.
  747. // This is necessary to ensure that we don't have one machine tying up
  748. // more than one thread on the server.
  749. //
  750. //+----------------------------------------------------------------------------
  751. class CActiveCreates
  752. {
  753. private:
  754. // Keep an array of the active machines.
  755. CMachineId *_prg;
  756. ULONG _cEntries;
  757. CCriticalSection _cs;
  758. public:
  759. CActiveCreates()
  760. {
  761. _prg = NULL;
  762. _cEntries = 0;
  763. }
  764. void Initialize( ULONG cEntries )
  765. {
  766. // Allocate an array of machine IDs.
  767. _prg = new CMachineId[ cEntries ];
  768. if( NULL == _prg )
  769. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  770. _cEntries = cEntries;
  771. memset( _prg, 0, cEntries * sizeof(CMachineId) );
  772. // Initialize the critical section. If this raises, ignore the
  773. // exception; we'll catch it later whenever we call _cs.Lock.
  774. __try
  775. {
  776. _cs.Initialize();
  777. }
  778. __except( EXCEPTION_EXECUTE_HANDLER )
  779. {
  780. TrkLog(( TRKDBG_WARNING, TEXT("Exception in CActiveCreates constructor (%08x)"),
  781. GetExceptionCode() ));
  782. }
  783. }
  784. ~CActiveCreates()
  785. {
  786. if( NULL != _prg )
  787. delete[] _prg;
  788. _cs.UnInitialize();
  789. }
  790. public:
  791. // Add a machine to the list of active creates.
  792. // This raises if the machine is already in the list.
  793. void Add( const CMachineId &mcid )
  794. {
  795. _cs.Enter();
  796. __try // __finally
  797. {
  798. int iFree = -1;
  799. // Search the array to see if this machine is already in
  800. // the list. While we're at it, assuming it's not already in
  801. // the list, find a free entry.
  802. for( int i = 0; i < _cEntries; i++ )
  803. {
  804. // Is this the machine?
  805. if( mcid == _prg[i] )
  806. {
  807. // Yes, this machine is already in the list. Raise.
  808. TrkLog(( TRKDBG_ERROR, TEXT("Machine attempting simultaneous creates (%s)"),
  809. (const TCHAR*) CDebugString(mcid) ));
  810. TrkRaiseException(TRK_E_DENIAL_OF_SERVICE_ATTACK);
  811. }
  812. // Otherwise, is this a free entry?
  813. else if( CMachineId() == _prg[i] )
  814. iFree = i;
  815. }
  816. // If we reach this point, the machine isn't already on the list,
  817. // so we'll add it.
  818. if( -1 != iFree )
  819. // Add the machine to a free entry in the list.
  820. _prg[ iFree ] = mcid;
  821. else
  822. {
  823. // There was no free entry in the list (this should never
  824. // happen).
  825. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't find free space in CActiveCreates") ));
  826. TrkRaiseWin32Error( ERROR_INTERNAL_DB_CORRUPTION );
  827. }
  828. }
  829. __finally
  830. {
  831. _cs.Leave();
  832. }
  833. }
  834. // Remove an entry from the list
  835. void Remove( const CMachineId &mcid )
  836. {
  837. _cs.Enter();
  838. __try
  839. {
  840. for( int i = 0; i < _cEntries; i++ )
  841. {
  842. if( mcid == _prg[i] )
  843. {
  844. _prg[i] = CMachineId();
  845. break;
  846. }
  847. }
  848. #if DBG
  849. if( i == _cEntries )
  850. {
  851. TrkLog(( TRKDBG_ERROR, TEXT("*** Not found in CActiveCreates::Remove ***") ));
  852. }
  853. #endif
  854. }
  855. __finally
  856. {
  857. _cs.Leave();
  858. }
  859. }
  860. };
  861. //+-------------------------------------------------------------------------
  862. //
  863. // Class: CDenialChecker
  864. //
  865. // Purpose: Checks for denial of service attacks
  866. //
  867. // Notes:
  868. //
  869. //--------------------------------------------------------------------------
  870. struct ACTIVECLIENT;
  871. class CDenialChecker : public PTimerCallback
  872. {
  873. public:
  874. inline CDenialChecker();
  875. inline ~CDenialChecker();
  876. void Initialize( ULONG ulHistoryPeriod );
  877. void UnInitialize();
  878. void CheckClient(const CMachineId &mcidClient);
  879. virtual TimerContinuation Timer( ULONG ulTimerId ); // timeout for clearing out old ACTIVECLIENTs
  880. private:
  881. BOOL _fInitializeCalled;
  882. CNewTimer _timer;
  883. ACTIVECLIENT * _pListHead;
  884. CCriticalSection _cs;
  885. #if DBG
  886. LONG _lAllocs;
  887. #endif
  888. };
  889. inline
  890. CDenialChecker::CDenialChecker() :
  891. _fInitializeCalled(FALSE)
  892. {
  893. }
  894. inline
  895. CDenialChecker::~CDenialChecker()
  896. {
  897. UnInitialize();
  898. }
  899. class CTrkSvrRpcServer : public CRpcServer
  900. {
  901. public:
  902. void Initialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData, CTrkSvrConfiguration *pTrkSvrConfig );
  903. void UnInitialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData );
  904. };
  905. //+-------------------------------------------------------------------------
  906. //
  907. // Class: CTrkSvrSvc
  908. //
  909. // Purpose: Tracking (Server) Service
  910. //
  911. // Notes:
  912. //
  913. //--------------------------------------------------------------------------
  914. #define MAX_SVR_THREADS 10
  915. class CTrkSvrSvc : public PTimerCallback,
  916. public IServiceHandler
  917. {
  918. public: // Initialization
  919. inline CTrkSvrSvc();
  920. inline ~CTrkSvrSvc();
  921. void Initialize(SVCHOST_GLOBAL_DATA * pSvcsGlobalData );
  922. void UnInitialize(HRESULT hr);
  923. public: // RPC server methods
  924. void DeleteNotify(
  925. const CMachineId & mcidClient,
  926. TRKSVR_CALL_DELETE * pDelete
  927. );
  928. HRESULT MoveNotify(
  929. const CMachineId & mcidClient,
  930. TRKSVR_CALL_MOVE_NOTIFICATION * pMove
  931. );
  932. void Search(
  933. TRK_FILE_TRACKING_INFORMATION * pSearches
  934. );
  935. void old_Search(
  936. old_TRK_FILE_TRACKING_INFORMATION * pSearches
  937. );
  938. HRESULT SyncVolume(
  939. const CMachineId & mcidClient,
  940. TRKSVR_SYNC_VOLUME * pSyncVolume,
  941. ULONG cUncountedCreates
  942. );
  943. void Refresh(
  944. const CMachineId & mcidClient,
  945. TRKSVR_CALL_REFRESH * pRefresh
  946. );
  947. void Statistics(
  948. TRKSVR_STATISTICS *pTrkSvrStatistics
  949. );
  950. public: // General publics
  951. HRESULT SvrMessage( handle_t IDL_handle, TRKSVR_MESSAGE_UNION * pMsg );
  952. inline void CheckClient( const CMachineId & mcid );
  953. BOOL CountPrioritizedThread( const TRKSVR_MESSAGE_UNION * pMsg );
  954. void ReleasePrioritizedThread( );
  955. void DoRefresh( const CRpcClientBinding & rc );
  956. inline DWORD GetState();
  957. virtual TimerContinuation Timer( ULONG ulTimerContext ); // refresh timer
  958. DWORD ServiceHandler(DWORD dwControl, // IServiceHandler implementation
  959. DWORD dwEventType,
  960. PVOID EventData,
  961. PVOID pData);
  962. inline const BOOL * GetStopFlagAddress();
  963. BOOL RequireSecureRPC();
  964. HRESULT CreateVolume(const CMachineId & mcidClient, const TRKSVR_SYNC_VOLUME& pSyncVolume);
  965. inline void SetLastError( HRESULT hr );
  966. void OnRequestStart( TRKSVR_MESSAGE_TYPE MsgType );
  967. void OnRequestEnd( TRKSVR_MESSAGE_UNION * pMsg, const CMachineId &mcid, HRESULT hr );
  968. void RaiseIfStopped();
  969. void Scan(
  970. IN const CDomainRelativeObjId * pdroidNotificationCurrent, OPTIONAL
  971. IN const CDomainRelativeObjId * pdroidNotificationNew, OPTIONAL
  972. IN const CDomainRelativeObjId & droidBirth,
  973. OUT CDomainRelativeObjId * pdroidList,
  974. IN int cdroidList,
  975. OUT int * pcSegments,
  976. IN OUT CDomainRelativeObjId * pdroidScan,
  977. OUT BOOL *pfStringDeleted
  978. );
  979. public: // testing
  980. friend class CTestSvrSvc;
  981. void TestRestore( const TCHAR * ptszMachine );
  982. private:
  983. void MoveNotify(const CDomainRelativeObjId &droidCurrent,
  984. const CDomainRelativeObjId &droidBirth,
  985. const CDomainRelativeObjId &droidNew,
  986. BOOL *pfQuotaExceeded );
  987. SequenceNumber GetSequenceNumber( const CMachineId & mcidClient,
  988. const CVolumeId & volume);
  989. void SetSequenceNumber( const CVolumeId & volume, // must ensure that validation already done for volume
  990. SequenceNumber seq );
  991. inline BOOL IncrementAndCheckWritesPerHour();
  992. inline void IncrementWritesPerHour();
  993. BOOL CheckWritesPerHour();
  994. inline ULONG NumWritesThisHour() const;
  995. BOOL VerifyMachineOwnsVolume( const CMachineId &mcid, const CVolumeId & volid );
  996. private: // data members
  997. BOOL _fInitializeCalled:1;
  998. // Indicates if we're hesitating before doing a GC
  999. // (see DoWork)
  1000. BOOL _fHesitatingBeforeGC:1;
  1001. // Indicates that service_stop/shutdown has been received
  1002. BOOL _fStopping:1;
  1003. // If true, and we're in a GC phase, GC the volume table
  1004. // rather than the move table.
  1005. BOOL _fGCVolumeTable:1;
  1006. SVCHOST_GLOBAL_DATA * _pSvcsGlobalData;
  1007. // Protect against denail-of-service attacks.
  1008. CDenialChecker _denial;
  1009. // This protects against a client doing too many creates.
  1010. CActiveCreates _activeCreates;
  1011. // LDAP manager
  1012. CDbConnection _dbc;
  1013. CRefreshSequenceStorage
  1014. _refreshSequence;
  1015. CCrossDomainTable _cdt;
  1016. CIntraDomainTable _idt;
  1017. CVolumeTable _voltab;
  1018. CRegDwordParameter _MoveCounterReset;
  1019. CNewTimer _timerGC;
  1020. LONG _cGarbageCollectionsRunning;
  1021. CQuotaTable _qtable;
  1022. CTrkSvrRpcServer _rpc;
  1023. CSvcCtrlInterface _svcctrl;
  1024. CTrkSvrConfiguration
  1025. _configSvr;
  1026. LONG _cAvailableThreads, _cLowestAvailableThreads;
  1027. // The following values track the number of writes (to the DS)
  1028. // in an hour. If this gets too high, trksvr disallows writes
  1029. // for the rest of the hour.
  1030. CFILETIME _cftWritesPerHour;
  1031. ULONG _cWritesPerHour;
  1032. CCriticalSection _csWritesPerHour;
  1033. // Statistics
  1034. struct tagStats
  1035. {
  1036. ULONG cSyncVolumeRequests, cSyncVolumeErrors, cSyncVolumeThreads;
  1037. ULONG cCreateVolumeRequests, cCreateVolumeErrors;
  1038. ULONG cClaimVolumeRequests, cClaimVolumeErrors;
  1039. ULONG cQueryVolumeRequests, cQueryVolumeErrors;
  1040. ULONG cFindVolumeRequests, cFindVolumeErrors;
  1041. ULONG cTestVolumeRequests, cTestVolumeErrors;
  1042. ULONG cSearchRequests, cSearchErrors, cSearchThreads;
  1043. ULONG cMoveNotifyRequests, cMoveNotifyErrors, cMoveNotifyThreads;
  1044. ULONG cRefreshRequests, cRefreshErrors, cRefreshThreads;
  1045. ULONG cDeleteNotifyRequests, cDeleteNotifyErrors, cDeleteNotifyThreads;
  1046. //ULONG ulGCIterationPeriod;
  1047. //SHORT cEntriesToGC;
  1048. SHORT cEntriesGCed;
  1049. SHORT cMaxDsWriteEvents;
  1050. SHORT cCurrentFailedWrites;
  1051. CFILETIME cftLastSuccessfulRequest;
  1052. CFILETIME cftServiceStartTime;
  1053. HRESULT hrLastError;
  1054. } _Stats;
  1055. public:
  1056. COperationLog _OperationLog;
  1057. };
  1058. inline
  1059. CTrkSvrSvc::CTrkSvrSvc() :
  1060. _fInitializeCalled(FALSE),
  1061. _fHesitatingBeforeGC(FALSE),
  1062. _fStopping(FALSE),
  1063. _idt(_dbc, &_refreshSequence),
  1064. _cdt(_dbc),
  1065. _voltab(_dbc, &_refreshSequence),
  1066. _qtable(_dbc),
  1067. _cWritesPerHour(0),
  1068. _cGarbageCollectionsRunning(0),
  1069. _fGCVolumeTable(FALSE),
  1070. _MoveCounterReset( TEXT("MoveCounterReset") ),
  1071. _refreshSequence( &_voltab, &_qtable, &_configSvr ) // refreshSequence uses voltab to store its state
  1072. {
  1073. // Statistics
  1074. memset( &_Stats, 0, sizeof(_Stats) );
  1075. _Stats.cftLastSuccessfulRequest = 0;
  1076. _Stats.cftServiceStartTime = CFILETIME();
  1077. }
  1078. inline
  1079. CTrkSvrSvc::~CTrkSvrSvc()
  1080. {
  1081. TrkAssert(!_fInitializeCalled);
  1082. }
  1083. inline const BOOL *
  1084. CTrkSvrSvc::GetStopFlagAddress()
  1085. {
  1086. return(_svcctrl.GetStopFlagAddress());
  1087. }
  1088. inline BOOL
  1089. CTrkSvrSvc::RequireSecureRPC()
  1090. {
  1091. return( _rpc.RpcSecurityEnabled() );
  1092. }
  1093. inline void
  1094. CTrkSvrSvc::SetLastError( HRESULT hr )
  1095. {
  1096. _Stats.hrLastError = hr;
  1097. }
  1098. inline void
  1099. CTrkSvrSvc::CheckClient( const CMachineId & mcid )
  1100. {
  1101. _denial.CheckClient( mcid );
  1102. }
  1103. inline DWORD
  1104. CTrkSvrSvc::GetState()
  1105. {
  1106. return( _svcctrl.GetState() );
  1107. }
  1108. inline void
  1109. CTrkSvrSvc::IncrementWritesPerHour()
  1110. {
  1111. #if DBG
  1112. LONG l = InterlockedIncrement( (LONG*)&_cWritesPerHour );
  1113. TrkLog(( TRKDBG_SVR, TEXT("WritesPerHour: %d"), l ));
  1114. #else
  1115. InterlockedIncrement( (LONG*)&_cWritesPerHour );
  1116. #endif
  1117. }
  1118. inline BOOL
  1119. CTrkSvrSvc::IncrementAndCheckWritesPerHour()
  1120. {
  1121. IncrementWritesPerHour();
  1122. return CheckWritesPerHour();
  1123. }
  1124. inline ULONG
  1125. CTrkSvrSvc::NumWritesThisHour() const
  1126. {
  1127. return _cWritesPerHour;
  1128. }
  1129. //+-------------------------------------------------------------------------
  1130. //
  1131. // Class: CLdapBinaryMod
  1132. //
  1133. // Purpose: Wrapper for all the structures used by LDAP for binary
  1134. // attribute modifications
  1135. //
  1136. // Notes:
  1137. //
  1138. //--------------------------------------------------------------------------
  1139. class CLdapBinaryMod
  1140. {
  1141. public:
  1142. inline CLdapBinaryMod();
  1143. // note: the pszAttrName is not copied!
  1144. inline CLdapBinaryMod(const TCHAR * pszAttrName,
  1145. PCCH bv_val,
  1146. ULONG bv_len,
  1147. int mod_op);
  1148. // note: the pszAttrName is not copied!
  1149. void Init(const TCHAR * pszAttrName,
  1150. PCCH bv_val,
  1151. ULONG bv_len,
  1152. int mod_op);
  1153. public:
  1154. LDAPMod _mod;
  1155. private:
  1156. LDAP_BERVAL _BerVal;
  1157. LDAP_BERVAL * _apBerVals[2];
  1158. };
  1159. inline
  1160. CLdapBinaryMod::CLdapBinaryMod()
  1161. {
  1162. }
  1163. inline
  1164. CLdapBinaryMod::CLdapBinaryMod(const TCHAR * pszAttrName,
  1165. PCCH bv_val,
  1166. ULONG bv_len,
  1167. int mod_op)
  1168. {
  1169. Init(pszAttrName, bv_val, bv_len, mod_op);
  1170. }
  1171. inline void
  1172. CLdapBinaryMod::Init(const TCHAR * pszAttrName, PCCH bv_val, ULONG bv_len, int mod_op)
  1173. {
  1174. _mod.mod_op = LDAP_MOD_BVALUES | mod_op;
  1175. _mod.mod_type = (TCHAR*)pszAttrName;
  1176. // bv_val might be null if this is a delete.
  1177. if( NULL != bv_val )
  1178. {
  1179. _BerVal.bv_len = bv_len;
  1180. _BerVal.bv_val = const_cast<PCHAR>(bv_val);
  1181. _apBerVals[0] = &_BerVal;
  1182. _apBerVals[1] = NULL;
  1183. _mod.mod_bvalues = _apBerVals;
  1184. }
  1185. else
  1186. _mod.mod_bvalues = NULL;
  1187. }
  1188. //+-------------------------------------------------------------------------
  1189. //
  1190. // Class: CLdapStringMod
  1191. //
  1192. // Purpose: Wrapper for all the structures used by LDAP for string
  1193. // attribute modifications
  1194. //
  1195. // Notes:
  1196. //
  1197. //--------------------------------------------------------------------------
  1198. class CLdapStringMod
  1199. {
  1200. public:
  1201. inline CLdapStringMod();
  1202. // note: the pszAttrName is not copied!
  1203. inline CLdapStringMod(const TCHAR * pszAttrName,
  1204. const TCHAR * str_val,
  1205. int mod_op);
  1206. // note: the pszAttrName is not copied!
  1207. void Init(const TCHAR * pszAttrName,
  1208. const TCHAR * str_val,
  1209. int mod_op);
  1210. public:
  1211. LDAPMod _mod;
  1212. private:
  1213. TCHAR * _apsz[2];
  1214. };
  1215. inline
  1216. CLdapStringMod::CLdapStringMod()
  1217. {
  1218. }
  1219. inline
  1220. CLdapStringMod::CLdapStringMod(const TCHAR * pszAttrName,
  1221. const TCHAR * str_val,
  1222. int mod_op)
  1223. {
  1224. // if we're specifying the objectClass we don't
  1225. TrkAssert(_tcscmp(pszAttrName, s_objectClass) != 0 ||
  1226. mod_op == 0);
  1227. Init(pszAttrName, str_val, mod_op);
  1228. }
  1229. inline void
  1230. CLdapStringMod::Init(const TCHAR * pszAttrName,
  1231. const TCHAR * str_val,
  1232. int mod_op)
  1233. {
  1234. _mod.mod_op = mod_op;
  1235. _mod.mod_type = (TCHAR*)pszAttrName;
  1236. _mod.mod_vals.modv_strvals = _apsz;
  1237. _apsz[0] = (TCHAR*)str_val;
  1238. _apsz[1] = NULL;
  1239. }
  1240. //+-------------------------------------------------------------------------
  1241. //
  1242. // Class: CLdapTimeValue
  1243. //
  1244. //--------------------------------------------------------------------------
  1245. class CLdapTimeValue
  1246. {
  1247. public:
  1248. CLdapTimeValue()
  1249. {
  1250. //memset(_abPad,0,sizeof(_abPad));
  1251. _stprintf( _tszTime, TEXT("%I64u"), (LONGLONG)CFILETIME() );
  1252. }
  1253. CLdapTimeValue(const CFILETIME &cft)
  1254. {
  1255. _stprintf( _tszTime, TEXT("%I64u"), (LONGLONG) cft );
  1256. }
  1257. // mikehill: is this still necessary?
  1258. void Swap();
  1259. inline BYTE & Byte(int i)
  1260. {
  1261. return( ((BYTE*)this)[i] );
  1262. }
  1263. operator TCHAR*()
  1264. {
  1265. return( _tszTime );
  1266. }
  1267. TCHAR _tszTime[ CCH_UINT64 ];
  1268. //BYTE _abPad[sizeof(GUID) - sizeof(CFILETIME)];
  1269. };
  1270. inline void
  1271. CLdapTimeValue::Swap()
  1272. {
  1273. BYTE b;
  1274. for (int i=0; i<sizeof(*this)/2; i++)
  1275. {
  1276. b = Byte(i);
  1277. Byte(i) = Byte(sizeof(*this)-i-1);
  1278. Byte(sizeof(*this)-i-1) = b;
  1279. }
  1280. }
  1281. //+-------------------------------------------------------------------------
  1282. //
  1283. // Class: CLdapRefreshSeq
  1284. //
  1285. //--------------------------------------------------------------------------
  1286. class CLdapRefresh
  1287. {
  1288. public:
  1289. CLdapRefresh( SequenceNumber seq )
  1290. {
  1291. _stprintf( _tszSeq, TEXT("%u"), seq );
  1292. }
  1293. operator TCHAR*()
  1294. {
  1295. return( _tszSeq );
  1296. }
  1297. TCHAR _tszSeq[ CCH_UINT64 ];
  1298. };
  1299. //+-------------------------------------------------------------------------
  1300. //
  1301. // Class: CLdapOMTAddModify
  1302. //
  1303. // Purpose: Wrapper for all the structures used to set a linkTrackOMTEntry
  1304. // (an entry in the Object Move Table)
  1305. //
  1306. //
  1307. // Notes:
  1308. //
  1309. //--------------------------------------------------------------------------
  1310. class CLdapOMTAddModify
  1311. {
  1312. public:
  1313. CLdapOMTAddModify(
  1314. const CDomainRelativeObjId & droidKey,
  1315. const CDomainRelativeObjId & droidNew,
  1316. const CDomainRelativeObjId & droidBirth,
  1317. const ULONG & seqRefresh,
  1318. BYTE bFlags, // Only used on LDAP_MOD_ADD
  1319. int mod_op
  1320. );
  1321. CLdapStringMod _lsmClass;
  1322. CLdapBinaryMod _lbmCurrentLocation;
  1323. CLdapBinaryMod _lbmBirthLocation;
  1324. CLdapStringMod _lsmRefresh;
  1325. CLdapBinaryMod _lbmFlags;
  1326. // We need to keep a CLdapTimeValue as a member in order to guarantee that
  1327. // it will remain in memory (_lsmRefresh will point to this data).
  1328. CLdapRefresh _ltvRefresh;
  1329. LDAPMod * _mods[7];
  1330. };
  1331. class CLdapVolumeKeyDn
  1332. {
  1333. public:
  1334. // specific volume
  1335. CLdapVolumeKeyDn( const TCHAR * ptszBaseDn, const CVolumeId & volume )
  1336. {
  1337. // Compose, e.g., the following DN:
  1338. // "CN=e3d954b2-d0a7-11d0-8cb6-00c04fd90f85,CN=VolumeTable,CN=FileLinks,DC=TRKDOM"
  1339. TCHAR *psz = _szDn;
  1340. _tcscpy(_szDn, TEXT("CN="));
  1341. psz += _tcslen(_szDn);
  1342. volume.Stringize(psz);
  1343. *psz++ = TEXT(',');
  1344. _tcscpy(psz, s_VolumeTableRDN); // The vol table, relative to the base
  1345. _tcscat(psz, ptszBaseDn);
  1346. TrkAssert(_tcslen(_szDn) < ELEMENTS(_szDn));
  1347. }
  1348. // all volumes
  1349. CLdapVolumeKeyDn( const TCHAR * ptszBaseDn )
  1350. {
  1351. _tcscpy(_szDn, s_VolumeTableRDN);
  1352. _tcscat(_szDn, ptszBaseDn);
  1353. TrkAssert(_tcslen(_szDn) < ELEMENTS(_szDn));
  1354. }
  1355. inline operator TCHAR * () { return _szDn; }
  1356. private:
  1357. TCHAR _szDn[MAX_PATH];
  1358. };
  1359. //+-------------------------------------------------------------------------
  1360. //
  1361. // Class: CLdapIdtKeyDn
  1362. //
  1363. // Purpose: Generates distinguished name for a CDomainRelativeObjId
  1364. //
  1365. // Notes:
  1366. //
  1367. //--------------------------------------------------------------------------
  1368. class CLdapIdtKeyDn
  1369. {
  1370. public:
  1371. inline CLdapIdtKeyDn(const TCHAR * pszBaseDn, const CDomainRelativeObjId &ld);
  1372. inline CLdapIdtKeyDn(const TCHAR * pszBaseDn );
  1373. inline operator TCHAR * ();
  1374. private:
  1375. TCHAR _szDn[MAX_PATH];
  1376. };
  1377. inline CLdapIdtKeyDn::CLdapIdtKeyDn(const TCHAR * pszBaseDn, const CDomainRelativeObjId
  1378. &ld)
  1379. {
  1380. // puts in something like "CN=v23487...65239238o23487...48652398"
  1381. ld.FillLdapIdtKeyBuffer(_szDn, sizeof(_szDn)/sizeof(_szDn[0]));
  1382. // make sure room for that string and the table name and the base dn
  1383. if (_tcslen(_szDn) +
  1384. 1 +
  1385. _tcslen(s_ObjectMoveTableRDN) +
  1386. _tcslen(pszBaseDn) + 1 >
  1387. sizeof(_szDn)/sizeof(_szDn[0]))
  1388. {
  1389. TrkRaiseException(TRK_E_DN_TOO_LONG);
  1390. }
  1391. _tcscat(_szDn, TEXT(","));
  1392. _tcscat(_szDn, s_ObjectMoveTableRDN);
  1393. _tcscat(_szDn, pszBaseDn);
  1394. TrkAssert(_tcslen(_szDn) < sizeof(_szDn)/sizeof(_szDn[0]));
  1395. }
  1396. inline CLdapIdtKeyDn::CLdapIdtKeyDn(const TCHAR * pszBaseDn)
  1397. {
  1398. // make sure room for that string and the table name and the base dn
  1399. if (1 +
  1400. _tcslen(s_ObjectMoveTableRDN) +
  1401. _tcslen(pszBaseDn) + 1 >
  1402. sizeof(_szDn)/sizeof(_szDn[0]))
  1403. {
  1404. TrkRaiseException(TRK_E_DN_TOO_LONG);
  1405. }
  1406. _tcscpy(_szDn, s_ObjectMoveTableRDN);
  1407. _tcscat(_szDn, pszBaseDn);
  1408. TrkAssert(_tcslen(_szDn) < sizeof(_szDn)/sizeof(_szDn[0]));
  1409. }
  1410. inline CLdapIdtKeyDn::operator TCHAR * ()
  1411. {
  1412. return(_szDn);
  1413. }