Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2447 lines
79 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. //
  6. // File: svrsvc.cxx
  7. //
  8. // Contents: Code for CTrkSvrSvc
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. //
  15. //
  16. // History: 18-Nov-96 BillMo Created.
  17. //
  18. // Notes:
  19. //
  20. // Codework:
  21. //
  22. //--------------------------------------------------------------------------
  23. #include "pch.cxx"
  24. #pragma hdrstop
  25. #include "trksvr.hxx"
  26. #include "ntlsa.h"
  27. #define THIS_FILE_NUMBER SVRSVC_CXX_FILE_NO
  28. #if DBG
  29. DWORD g_Debug = 0;
  30. #endif
  31. const extern TCHAR s_tszKeyNameLinkTrack[] = TEXT("System\\CurrentControlSet\\Services\\TrkSvr\\Parameters");
  32. //+----------------------------------------------------------------------------
  33. //
  34. // CTrkSvrSvc::Initialize
  35. //
  36. // Initialize the TrkSvr service.
  37. //
  38. //+----------------------------------------------------------------------------
  39. void
  40. CTrkSvrSvc::Initialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData )
  41. {
  42. __try
  43. {
  44. _cLowestAvailableThreads = _cAvailableThreads = MAX_SVR_THREADS;
  45. _fInitializeCalled = TRUE;
  46. g_ptrksvr = this;
  47. _pSvcsGlobalData = pSvcsGlobalData;
  48. // Initialize the object that manages the SCM.
  49. _svcctrl.Initialize(TEXT("TrkSvr"), this);
  50. // Initialize registry-configurable parameters.
  51. _configSvr.Initialize();
  52. // If requested, prepare to log all operations (to a file)
  53. if( _configSvr.UseOperationLog() )
  54. _OperationLog.Initialize( _configSvr.GetOperationLog() );
  55. TrkLog(( TRKDBG_SVR, TEXT("Distributed Link Tracking (Server) service starting on thread=%d(0x%x)"),
  56. GetCurrentThreadId(), GetCurrentThreadId() ));
  57. // This is a hacked stub that looks and acts like the Win32 thread pool services
  58. #ifdef PRIVATE_THREAD_POOL
  59. {
  60. HRESULT hr = S_OK;
  61. g_pworkman2 = new CThreadPoolStub;
  62. if( NULL == g_pworkman2 )
  63. {
  64. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't create the thread pool manager") ));
  65. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  66. }
  67. hr = g_pworkman2->Initialize();
  68. if( FAILED(hr) )
  69. {
  70. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't initialize the thread pool manager") ));
  71. TrkRaiseException( hr );
  72. }
  73. }
  74. #endif
  75. // The denial checker provides protection against a denial-of-service
  76. // attack, where a client floods us with calls.
  77. _denial.Initialize(_configSvr.GetHistoryPeriod() );
  78. // This critsec protects _cWritesPerHour & _cftWritesPerHour.
  79. // See CTrkSvrSvc::CheckWritesPerHour
  80. _csWritesPerHour.Initialize();
  81. // This maintains the "time" for purposes of refreshing entries.
  82. _refreshSequence.Initialize();
  83. // The cross-domain table
  84. _cdt.Initialize();
  85. // The intra-domain table
  86. _idt.Initialize( &_configSvr, &_qtable );
  87. // The volume table
  88. _voltab.Initialize( &_configSvr, &_qtable );
  89. // The quota manager
  90. _qtable.Initialize(&_voltab, &_idt, this, &_configSvr );
  91. // Set the quota timer. This was originally every 30 days, but is now
  92. // every day. In order to maintain compatibility with the tests, we
  93. // still use the GCPeriod value (30 days), but divide it by the new
  94. // GCDivisor value (30) to get the correct period.
  95. // This timer doesn't have a standard retry, because of the way
  96. // we hesitate 30 minutes before doing anything. So retries are
  97. // done explicitely.
  98. _timerGC.Initialize(this,
  99. TEXT("NextGarbageCollectTime"), // This is a persistent timer
  100. 0, // Context ID
  101. _configSvr.GetGCPeriod() / _configSvr.GetGCDivisor(),
  102. CNewTimer::NO_RETRY,
  103. 0, 0, 0 ); // No retries or max lifetime
  104. _timerGC.SetRecurring();
  105. TrkLog(( TRKDBG_VOLUME, TEXT("GC timer: %s"),
  106. (const TCHAR*) CDebugString(_timerGC) ));
  107. // Used in the Timer method to determine if we should reset the
  108. // move table counter value.
  109. _MoveCounterReset.Initialize();
  110. // Initialize ourself as an RPC server
  111. _rpc.Initialize( _pSvcsGlobalData, &_configSvr );
  112. // Tell the SCM that we're running.
  113. _svcctrl.SetServiceStatus(SERVICE_RUNNING,
  114. SERVICE_ACCEPT_STOP |
  115. SERVICE_ACCEPT_SHUTDOWN,
  116. NO_ERROR);
  117. _OperationLog.Add( COperationLog::TRKSVR_START );
  118. }
  119. __except( BreakOnDebuggableException() )
  120. {
  121. // Don't log an event for protseq-not-supported; this happens during a normal
  122. // setup.
  123. if( HRESULT_FROM_WIN32(RPC_S_PROTSEQ_NOT_SUPPORTED) != GetExceptionCode() )
  124. {
  125. TrkReportEvent( EVENT_TRK_SERVICE_START_FAILURE, EVENTLOG_ERROR_TYPE,
  126. static_cast<const TCHAR*>( CHexStringize( GetExceptionCode() )),
  127. NULL );
  128. }
  129. TrkRaiseException( GetExceptionCode() );
  130. }
  131. }
  132. //+----------------------------------------------------------------------------
  133. //
  134. // CTrkSvrSvc::UnInitialize
  135. //
  136. // Cancel any out-going RPCs, stop all timers, close everything down,
  137. // and send a service_stopped to the SCM.
  138. //
  139. //+----------------------------------------------------------------------------
  140. void
  141. CTrkSvrSvc::UnInitialize(HRESULT hr)
  142. {
  143. if (_fInitializeCalled)
  144. {
  145. _fInitializeCalled = FALSE;
  146. // Cancel any out-going RPCs on threads in this service
  147. if( NULL != g_pActiveThreadList )
  148. g_pActiveThreadList->CancelAllRpc();
  149. // stop classes that use threads first ...
  150. _rpc.UnInitialize( _pSvcsGlobalData );
  151. _timerGC.UnInitialize();
  152. _csWritesPerHour.UnInitialize();
  153. // ... then release used resources
  154. _qtable.UnInitialize();
  155. _voltab.UnInitialize();
  156. _idt.UnInitialize();
  157. _cdt.UnInitialize();
  158. _dbc.UnInitialize();
  159. _denial.UnInitialize();
  160. if (_configSvr.GetTestFlags() & TRK_TEST_FLAG_WAIT_ON_EXIT)
  161. {
  162. TrkLog((TRKDBG_ERROR, TEXT("Waiting 60 seconds before exitting for heap dump")));
  163. Sleep(60000);
  164. }
  165. #if PRIVATE_THREAD_POOL
  166. {
  167. g_pworkman2->UnInitialize();
  168. delete g_pworkman2;
  169. g_pworkman2 = NULL;
  170. }
  171. #endif
  172. g_ptrksvr = NULL;
  173. // If the error is protseq-not-supported, ignore it. This is normal
  174. // during setup.
  175. if( (hr & 0x0FFF0000) == FACILITY_WIN32 )
  176. hr = hr & ~(0x0FFF0000);
  177. _svcctrl.SetServiceStatus(SERVICE_STOPPED, 0,
  178. HRESULT_FROM_WIN32(RPC_S_PROTSEQ_NOT_SUPPORTED) == hr ? 0 : hr
  179. );
  180. //_svcctrl.UnInitialize();
  181. }
  182. }
  183. //+----------------------------------------------------------------------------
  184. //
  185. // CTrkSvrSvc::ServiceHandler
  186. //
  187. // This method gets called by the SCM for notification of all service
  188. // activity.
  189. //
  190. // NOTE: In services.exe, this method is called on the one and only ServiceHandler
  191. // thread. So while we execute, no other service in this process can
  192. // receive notifications. Thus it is important that we do nothing
  193. // blocking or time-consuming here.
  194. //
  195. //+----------------------------------------------------------------------------
  196. DWORD
  197. CTrkSvrSvc::ServiceHandler(DWORD dwControl,
  198. DWORD dwEventType,
  199. PVOID EventData,
  200. PVOID pData)
  201. {
  202. DWORD dwRet = NO_ERROR;
  203. switch (dwControl)
  204. {
  205. case SERVICE_CONTROL_SHUTDOWN:
  206. case SERVICE_CONTROL_STOP:
  207. _fStopping = TRUE;
  208. _qtable.OnServiceStopRequest();
  209. ServiceStopCallback( this, FALSE );
  210. break;
  211. case SERVICE_CONTROL_PAUSE:
  212. break;
  213. case SERVICE_CONTROL_CONTINUE:
  214. break;
  215. case SERVICE_CONTROL_INTERROGATE:
  216. break;
  217. default:
  218. dwRet = ERROR_CALL_NOT_IMPLEMENTED;
  219. break;
  220. }
  221. return(dwRet);
  222. }
  223. //+----------------------------------------------------------------------------
  224. //
  225. // CTrkSvrSvc::RaiseIfStopped
  226. //
  227. // This method raises an exception if a global flag is set indicating
  228. // that we've received a service stop/shutdown request. This is used
  229. // in places where we have a thread that could run for a while; we periodically
  230. // call this method to prevent service stop from blocking.
  231. //
  232. //+----------------------------------------------------------------------------
  233. void
  234. CTrkSvrSvc::RaiseIfStopped()
  235. {
  236. if ( * _svcctrl.GetStopFlagAddress() )
  237. TrkRaiseException( TRK_E_SERVICE_STOPPING );
  238. }
  239. //+----------------------------------------------------------------------------
  240. //
  241. // CTrkSvrSvc::CheckWritesPerHour
  242. //
  243. // Check _cWritesPerHour to see if we're writing to much to the DS.
  244. // This is a simplistic algorithm in an effort to reduce risk. We
  245. // just let _cWritesPerHour increment until it hits the max, then
  246. // check to see when that count was started. If more than an
  247. // hour ago, then reset the count & the clock.
  248. //
  249. //+----------------------------------------------------------------------------
  250. BOOL
  251. CTrkSvrSvc::CheckWritesPerHour()
  252. {
  253. BOOL fExceeded = FALSE;
  254. if( _cWritesPerHour >= _configSvr.GetMaxDSWritesPerHour() )
  255. {
  256. _csWritesPerHour.Enter();
  257. __try
  258. {
  259. // Check the count again, as it may have changed whil we
  260. // were waiting for the critsec.
  261. if( _cWritesPerHour >= _configSvr.GetMaxDSWritesPerHour() )
  262. {
  263. CFILETIME cft; // Defaults to current time
  264. // Did the "hour" for _cWritesPerHour actually start more
  265. // than an hour ago?
  266. cft.DecrementSeconds( _configSvr.GetMaxDSWritesPeriod() ); // An hour
  267. if( cft > _cftWritesPerHour )
  268. {
  269. TrkLog(( TRKDBG_SVR, TEXT("Resetting writes-per-hour clock (%d)"),
  270. _cWritesPerHour ));
  271. // Yes, this write is OK, and we should reset the write time.
  272. _cftWritesPerHour = CFILETIME();
  273. _cWritesPerHour = 0;
  274. _Stats.cCurrentFailedWrites = 0;
  275. }
  276. else
  277. {
  278. TrkLog(( TRKDBG_WARNING,
  279. TEXT("Exceeded writes-per-hour (started at %s)"),
  280. (const TCHAR*) CDebugString(_cftWritesPerHour) ));
  281. if( 0 == _Stats.cCurrentFailedWrites )
  282. _Stats.cMaxDsWriteEvents++;
  283. _Stats.cCurrentFailedWrites++;
  284. fExceeded = TRUE;
  285. }
  286. }
  287. }
  288. __finally
  289. {
  290. _csWritesPerHour.Leave();
  291. }
  292. }
  293. return fExceeded;
  294. }
  295. void
  296. CTrkSvrSvc::Scan(
  297. IN const CDomainRelativeObjId * pdroidNotificationCurrent, OPTIONAL
  298. IN const CDomainRelativeObjId * pdroidNotificationNew, OPTIONAL
  299. IN const CDomainRelativeObjId & droidBirth,
  300. OUT CDomainRelativeObjId * pdroidList,
  301. IN int cdroidList,
  302. OUT int * pcSegments,
  303. IN OUT CDomainRelativeObjId * pdroidScan,
  304. OUT BOOL * pfStringDeleted
  305. )
  306. {
  307. CDomainRelativeObjId droidNextBirth, droidNextNew;
  308. BOOL fFound = FALSE;
  309. BOOL fBirthSame = FALSE;
  310. BOOL fCycle = FALSE;
  311. *pfStringDeleted = FALSE;
  312. //
  313. // loop through the string until the birth ids don't match, or
  314. // we've run out of buffer space, or we get to the end of the string
  315. //
  316. do
  317. {
  318. if (pdroidNotificationCurrent && *pdroidScan == *pdroidNotificationCurrent)
  319. {
  320. TrkAssert(pdroidNotificationNew);
  321. droidNextNew = *pdroidNotificationNew;
  322. droidNextBirth = droidBirth;
  323. fFound = TRUE;
  324. *pfStringDeleted = FALSE;
  325. }
  326. else
  327. {
  328. fFound = _idt.Query(*pdroidScan, &droidNextNew, &droidNextBirth, pfStringDeleted );
  329. RaiseIfStopped();
  330. }
  331. if (fFound)
  332. {
  333. TrkLog((TRKDBG_MEND, TEXT("CTrkSvrSvc::Scan() - iSegment=%d, %s --> %s [%s] found"),
  334. *pcSegments,
  335. static_cast<const TCHAR*>(CAbbreviatedIDString(*pdroidScan)),
  336. static_cast<const TCHAR*>(CAbbreviatedIDString(droidNextNew)),
  337. static_cast<const TCHAR*>(CAbbreviatedIDString(droidNextBirth)) ));
  338. // Check to see if we've already been here before.
  339. // E.g., don't loop forever on A->Ba, B->Aa.
  340. for( int j = 0; j < *pcSegments; j++ )
  341. {
  342. if( pdroidList[ j ] == droidNextNew )
  343. {
  344. TrkLog(( TRKDBG_MEND, TEXT("Cycle detected during mend (on %s)"),
  345. static_cast<const TCHAR*>(CAbbreviatedIDString(*pdroidScan)) ));
  346. fCycle = TRUE;
  347. break;
  348. }
  349. }
  350. if( !fCycle )
  351. {
  352. fBirthSame = droidNextBirth == droidBirth;
  353. if (fBirthSame)
  354. {
  355. pdroidList[ (*pcSegments)++ ] = *pdroidScan;
  356. *pdroidScan = droidNextNew;
  357. }
  358. else
  359. {
  360. // We can stop searching. We found a segment that starts
  361. // with *pdroidScan, but it's from another string because
  362. // it has a different birth ID.
  363. TrkLog(( TRKDBG_MEND, TEXT("Birth IDs don't match: %s, %s"),
  364. (const TCHAR*) CDebugString(droidBirth),
  365. (const TCHAR*) CDebugString(droidNextBirth) ));
  366. }
  367. }
  368. }
  369. } while ( *pcSegments < cdroidList && fFound && fBirthSame && !fCycle );
  370. if ( *pcSegments == cdroidList || fCycle )
  371. {
  372. TrkRaiseException(TRK_E_TOO_MANY_UNSHORTENED_NOTIFICATIONS);
  373. }
  374. }
  375. //+----------------------------------------------------------------------------
  376. //
  377. // CTrkSvrSvc::MoveNotify
  378. //
  379. // Handle a move notify request from trkwks.
  380. //
  381. // This routine is complicated by DS replication. It is possible that two trksvr
  382. // services may modify the same entry in the IDT within a replication window.
  383. // The only way to prevent this is to design such that only the designated DC
  384. // modifies entries. For this MoveNotify routine, that would mean that an
  385. // entry would be added for each notification, the designated DC would then
  386. // shorten the base entry, and delete this new one. That's not friendly
  387. // to the DS, however, because deleted objects must continue to be stored
  388. // for an extended period of time.
  389. //
  390. // Consequently, if this notify modifies an existing entry, this routine
  391. // performs a modify rather than an add. For example, if a file is
  392. // moved from A to B to C, and this routine is being called for that
  393. // second move, it would just modify the existing entry from A->B to
  394. // A->C.
  395. //
  396. // The risk here is that another DC will attempt to modify this entry
  397. // within the same replication window. We don't have to worry though
  398. // about another DC doing a notify; trkwks only sends to one DC.
  399. // There are two cases to worry about. One is the case where another DC
  400. // marks an entry to be deleted. If that happens after we do the modify
  401. // here, then there is no problem; the entry is no longer needed anyway.
  402. // If that happens before we do our modify here, then the delete flag
  403. // will be lost. This case is rare, and the unnecessary entry won't
  404. // stay in the table forever; it will be garbage collected.
  405. //
  406. // The other case of potential conflict is if an entry has not
  407. // yet been counted; in this case the designated DC might count
  408. // it and clear the uncounted flag. If our modify causes that
  409. // flag to be uncleared, then the move table count would be corrupted.
  410. // So if the uncounted flag is set, we do an add rather than a modify.
  411. //
  412. //+----------------------------------------------------------------------------
  413. void
  414. CTrkSvrSvc::MoveNotify(const CDomainRelativeObjId &droidCurrent,
  415. const CDomainRelativeObjId &droidBirth,
  416. const CDomainRelativeObjId &droidNew,
  417. BOOL *pfQuotaExceeded )
  418. {
  419. BOOL fAdded = FALSE, fModified = FALSE, fExists = FALSE;
  420. BOOL fDeleted = FALSE, fCounted = FALSE;
  421. // ignore cross-domain moves for now
  422. CDomainRelativeObjId droidNextNew;
  423. CDomainRelativeObjId droidNextBirth;
  424. CDomainRelativeObjId droidNewIDT, droidBirthIDT;
  425. TrkLog((TRKDBG_MOVE, TEXT("CTrkSvrSvc::MoveNotify\n curr = %s\n new = %s\n birth = %s"),
  426. (const TCHAR*)CDebugString(droidCurrent),
  427. (const TCHAR*) CDebugString(droidNew),
  428. (const TCHAR*) CDebugString(droidBirth) ));
  429. // Does the entry exist already?
  430. fExists = _idt.Query( droidBirth, &droidNewIDT, &droidBirthIDT, &fDeleted, &fCounted );
  431. #if DBG
  432. if( fExists )
  433. TrkLog(( TRKDBG_MOVE, TEXT("Birth entry already exists (%s, %s)"),
  434. fDeleted ? TEXT("deleted") : TEXT("not deleted"),
  435. fCounted ? TEXT("counted") : TEXT("not counted") ));
  436. #endif
  437. if( fExists
  438. &&
  439. fCounted
  440. &&
  441. droidNewIDT == droidCurrent )
  442. {
  443. TrkLog(( TRKDBG_MOVE, TEXT("Attempting to modify existing entry") ));
  444. // The birth entry for this file already points to the source
  445. // of the notify. We can just modify it.
  446. fModified = _idt.Modify( droidBirth, droidNew, droidBirth );
  447. }
  448. // If the modify didn't work or wasn't attempted, then just add this
  449. // new entry
  450. if( !fModified )
  451. fAdded = _idt.Add( droidCurrent, droidNew, droidBirth, pfQuotaExceeded );
  452. TrkLog((TRKDBG_MEND, TEXT("CTrkSvrSvc::MoveNotify() %s %s --> %s [%s]"),
  453. fModified ? TEXT("modified")
  454. : (fAdded ? TEXT("added") : TEXT("couldn't be added") ),
  455. static_cast<const TCHAR*>(CAbbreviatedIDString(droidCurrent)),
  456. static_cast<const TCHAR*>(CAbbreviatedIDString(droidNew)),
  457. static_cast<const TCHAR*>(CAbbreviatedIDString(droidBirth)) ));
  458. }
  459. //+----------------------------------------------------------------------------
  460. //
  461. // CTrkSvrSvc::Search
  462. //
  463. // Given a droid, look up the new droid for that object, and look up
  464. // the mcid of the machine that owns that droid's volume.
  465. //
  466. //+----------------------------------------------------------------------------
  467. void
  468. CTrkSvrSvc::Search(/*in, out*/ TRK_FILE_TRACKING_INFORMATION *pSearch)
  469. {
  470. HRESULT hr = S_OK;
  471. CDomainRelativeObjId droidNew;
  472. CDomainRelativeObjId droidBirth;
  473. CMachineId mcidNew;
  474. BOOL fFoundObject;
  475. IFDBG( TCHAR * ptszRoute=TEXT(""); )
  476. TrkLog(( TRKDBG_MEND, TEXT("Searching for %s"),
  477. static_cast<const TCHAR*>(CAbbreviatedIDString(pSearch->droidLast)) ));
  478. // If all the move notifies for a file have reached the DC, we can do a
  479. // lookup based on the birth ID. But if one segment is missing, this would fail.
  480. // So we look up based on the last ID first, and if that files try the birth ID.
  481. // Try to map the last ID to the current droid.
  482. fFoundObject = _idt.Query( pSearch->droidLast, &droidNew, &droidBirth);
  483. if ( fFoundObject )
  484. {
  485. IFDBG( ptszRoute = TEXT("'last' found in IDT"); )
  486. }
  487. else
  488. {
  489. // We couldn't find the last known ID. Try mapping
  490. // from the birth ID.
  491. fFoundObject = _idt.Query( pSearch->droidBirth, &droidNew, &droidBirth );
  492. if( fFoundObject )
  493. {
  494. IFDBG( ptszRoute = TEXT("'birth' found in IDT"); )
  495. }
  496. }
  497. // Did we find the new droid for the file?
  498. if ( fFoundObject )
  499. {
  500. // Yes, we found it. Is it really the same file (the birth ID matches)?
  501. if( droidBirth != pSearch->droidBirth )
  502. {
  503. TrkLog(( TRKDBG_MEND, TEXT("Birth ID unexpected:\n %s,\n %s,\n %s"),
  504. (const TCHAR*) CDebugString(droidBirth),
  505. (const TCHAR*) CDebugString(pSearch->droidBirth),
  506. (const TCHAR*) CDebugString(droidNew) ));
  507. pSearch->hr = TRK_E_NOT_FOUND;
  508. goto Exit;
  509. }
  510. // We have a good ID. This file may have multiple segments in the DS.
  511. // Starting with the one we have, scan across any additional segments
  512. // to find the most up-to-date droid.
  513. CDomainRelativeObjId droidList[MAX_SHORTENABLE_SEGMENTS];
  514. int cSegments = 0;
  515. BOOL fStringDeleted = FALSE;
  516. Scan(
  517. NULL,
  518. NULL,
  519. droidBirth,
  520. droidList,
  521. sizeof(droidList)/sizeof(droidList[0]),
  522. &cSegments,
  523. &droidNew,
  524. &fStringDeleted
  525. );
  526. }
  527. else
  528. {
  529. // We couldn't find either the birth or last ID.
  530. pSearch->hr = TRK_E_NOT_FOUND;
  531. TrkLog(( TRKDBG_MEND, TEXT("neither 'birth' nor 'last' found") ));
  532. }
  533. // If we found the object in the move table, look up the machine ID in the
  534. // volume table.
  535. if (fFoundObject)
  536. {
  537. TrkLog((TRKDBG_MEND, TEXT("CTrkSvrSvc::Search( birth=%s last=%s ) successful, 'new=%s', %s"),
  538. static_cast<const TCHAR*>(CAbbreviatedIDString(pSearch->droidBirth)),
  539. static_cast<const TCHAR*>(CAbbreviatedIDString(pSearch->droidLast)),
  540. static_cast<const TCHAR*>(CAbbreviatedIDString(droidNew)),
  541. ptszRoute ));
  542. // Find the volume that holds this droid.
  543. pSearch->hr = _voltab.FindVolume( droidNew.GetVolumeId(),
  544. &mcidNew );
  545. if( S_OK == pSearch->hr )
  546. {
  547. // We found the volume.
  548. TrkLog(( TRKDBG_MEND, TEXT("CTrkSvrSvc::Search, volid found (%s -> %s)"),
  549. (const TCHAR*) CDebugString(droidNew.GetVolumeId()),
  550. (const TCHAR*) CDebugString(mcidNew) ));
  551. pSearch->hr = S_OK;
  552. pSearch->droidLast = droidNew;
  553. pSearch->mcidLast = mcidNew;
  554. }
  555. else
  556. {
  557. // We were able to find the object in the move table, but couldn't
  558. // find the volume in the volume table.
  559. TrkLog(( TRKDBG_MEND, TEXT("CTrkSvrSvc::Search, volid not found (%s, %08x)"),
  560. (const TCHAR*) CDebugString(droidNew.GetVolumeId()),
  561. pSearch->hr ));
  562. pSearch->hr = TRK_E_NOT_FOUND;
  563. }
  564. }
  565. else
  566. {
  567. HRESULT hr = S_OK;
  568. // We couldn't find the object in the move table.
  569. TrkLog((TRKDBG_MEND, TEXT("CTrkSvrSvc::Search( birth=%s last=%s ) not found, %s"),
  570. static_cast<const TCHAR*>(CAbbreviatedIDString(pSearch->droidBirth)),
  571. static_cast<const TCHAR*>(CAbbreviatedIDString(pSearch->droidLast)),
  572. ptszRoute));
  573. // As an optimization, try looking up the last volume anyway. When this
  574. // search request fails, the trkwks service typically looks up the location
  575. // of the volume ID in droidLast, so we do that lookup now instead of forcing
  576. // trkwks to make a separate request.
  577. hr = _voltab.FindVolume( pSearch->droidLast.GetVolumeId(),
  578. &mcidNew );
  579. if( S_OK == hr )
  580. {
  581. TrkLog(( TRKDBG_MEND, TEXT("CTrkSvrSvc::Search, but last volid found (%s -> %s)"),
  582. (const TCHAR*) CDebugString(pSearch->droidLast.GetVolumeId()),
  583. (const TCHAR*) CDebugString(mcidNew) ));
  584. pSearch->hr = TRK_E_NOT_FOUND_BUT_LAST_VOLUME_FOUND;
  585. pSearch->mcidLast = mcidNew;
  586. }
  587. else
  588. {
  589. TrkLog(( TRKDBG_MEND, TEXT("CTrkSvrSvc::Search, volid not found either (%s, %08x)"),
  590. (const TCHAR*) CDebugString(pSearch->droidLast.GetVolumeId()),
  591. pSearch->hr ));
  592. pSearch->hr = TRK_E_NOT_FOUND_AND_LAST_VOLUME_NOT_FOUND;
  593. }
  594. }
  595. Exit:
  596. return;
  597. }
  598. //+----------------------------------------------------------------------------
  599. //
  600. // CTrkSvrSvc::old_Search
  601. //
  602. // This method is provided for compatibility with NT5/Beta2 clients. Those
  603. // clients would do two RPCs, one to get the new droid, then another to map
  604. // the volid in that droid to an mcid. In the modern SEARCH request, the
  605. // client gets both back in a single call.
  606. //
  607. // The distinction between the two kinds of clients is made by the
  608. // TRKSVR_MESSAGE_TYPE in the request. Old clients pass the value
  609. // now defined as old_SEARCH, new clients pass the value SEARCH.
  610. //
  611. //+----------------------------------------------------------------------------
  612. void
  613. CTrkSvrSvc::old_Search(/*in, out*/ old_TRK_FILE_TRACKING_INFORMATION *pSearch)
  614. {
  615. TRK_FILE_TRACKING_INFORMATION FileTrkInfo;
  616. FileTrkInfo.droidBirth = pSearch->droidBirth;
  617. FileTrkInfo.droidLast = pSearch->droidLast;
  618. Search(&FileTrkInfo);
  619. pSearch->hr = FileTrkInfo.hr;
  620. pSearch->droidLast = FileTrkInfo.droidLast;
  621. }
  622. //+----------------------------------------------------------------------------
  623. //
  624. // CTrkSvrSvc::Timer
  625. //
  626. // This callback method is called by the GC timer when it's time to do a
  627. // GC.
  628. //
  629. // This method doesn't raise.
  630. //
  631. //+----------------------------------------------------------------------------
  632. PTimerCallback::TimerContinuation
  633. CTrkSvrSvc::Timer( ULONG ulTimerContext )
  634. {
  635. HRESULT hr = S_OK;
  636. BOOL fInvalidateCache = FALSE;
  637. TimerContinuation continuation = CONTINUE_TIMER;
  638. NTSTATUS Status = STATUS_SUCCESS;
  639. TrkLog(( TRKDBG_SVR, TEXT("\nGC timer has fired") ));
  640. __try
  641. {
  642. // Only the designated DC does garbage collecting.
  643. if( !_qtable.IsDesignatedDc( TRUE ) ) // TRUE => raise on error
  644. {
  645. TrkLog(( TRKDBG_SVR, TEXT("Not GC-ing; not the designated DC") ));
  646. continuation = CONTINUE_TIMER;
  647. __leave;
  648. }
  649. // See if this domain is too young to do anything.
  650. if( _refreshSequence.GetSequenceNumber()
  651. <
  652. static_cast<SequenceNumber>(_configSvr.GetGCMinCycles()) )
  653. {
  654. TrkLog(( TRKDBG_GARBAGE_COLLECT | TRKDBG_SVR,
  655. TEXT("Nothing to GC (%d)"),
  656. _refreshSequence.GetSequenceNumber() ));
  657. continuation = CONTINUE_TIMER;
  658. __leave;
  659. }
  660. // Is this the part one of the timer ?
  661. if( !_fHesitatingBeforeGC )
  662. {
  663. // Yes, this is part one. We'll do some work, then
  664. // reset the timer for a small delay (so that we don't
  665. // do a bunch of work during system initialization).
  666. #if DBG
  667. {
  668. if( _configSvr.GetGCHesitation() > (5*60) )
  669. TrkLog(( TRKDBG_SVR, TEXT("Hesitating for %d minutes before running GC"),
  670. _configSvr.GetGCHesitation() / 60 ));
  671. else
  672. TrkLog(( TRKDBG_SVR, TEXT("Hesitating for %d seconds before running GC"),
  673. _configSvr.GetGCHesitation() ));
  674. }
  675. #endif
  676. _fHesitatingBeforeGC = TRUE;
  677. _timerGC.ReInitialize( _configSvr.GetGCHesitation() ); // Doesn't raise
  678. continuation = CONTINUE_TIMER;
  679. }
  680. else
  681. {
  682. _fHesitatingBeforeGC = FALSE;
  683. _Stats.cEntriesGCed = 0;
  684. // Update the sequence number
  685. _refreshSequence.IncrementSequenceNumber();
  686. TrkLog(( TRKDBG_SVR, TEXT("Updated the GC counter to %d"),
  687. _refreshSequence.GetSequenceNumber() ));
  688. // See if we need to invalidate the move table count cache (once a month).
  689. // This is done for robustness, so that if the count gets out of sync for any
  690. // reason, we self-correct. _MoveCounterReset holds the sequence number
  691. // of the last time we did an invalidate.
  692. if( (SequenceNumber) _MoveCounterReset.GetValue()
  693. >=
  694. _refreshSequence.GetSequenceNumber() )
  695. {
  696. // Invalid value
  697. TrkLog(( TRKDBG_WARNING,
  698. TEXT("_MoveCounterReset is invalid (%d, %d), resetting"),
  699. _MoveCounterReset.GetValue(),
  700. _refreshSequence.GetSequenceNumber() ));
  701. _MoveCounterReset.Set
  702. ( (DWORD) _refreshSequence.GetSequenceNumber() );
  703. }
  704. else if( _MoveCounterReset.GetValue() + _configSvr.GetGCDivisor()
  705. <= _refreshSequence.GetSequenceNumber()
  706. )
  707. {
  708. TrkLog(( TRKDBG_SVR | TRKDBG_GARBAGE_COLLECT,
  709. TEXT("Cache will be invalidated (%d)"), _MoveCounterReset.GetValue() ));
  710. fInvalidateCache = TRUE;
  711. }
  712. // Calculate the seq number of the oldest entry to keep.
  713. ULONG seqOldestToKeep = _refreshSequence.GetSequenceNumber() - _configSvr.GetGCMinCycles() + 1;
  714. TrkLog((TRKDBG_GARBAGE_COLLECT | TRKDBG_SVR,
  715. TEXT("\nGarbage collecting all entries older than %d"),
  716. seqOldestToKeep));
  717. // Delete old entries from the move table
  718. _Stats.cEntriesGCed
  719. += (SHORT)_idt.GarbageCollect( _refreshSequence.GetSequenceNumber(),
  720. seqOldestToKeep,
  721. _svcctrl.GetStopFlagAddress() );
  722. // And delete old entries from the volume table
  723. _Stats.cEntriesGCed
  724. += (SHORT)_voltab.GarbageCollect( _refreshSequence.GetSequenceNumber(),
  725. seqOldestToKeep,
  726. _svcctrl.GetStopFlagAddress() );
  727. _OperationLog.Add( COperationLog::TRKSVR_GC, S_OK, CMachineId(MCID_INVALID),
  728. seqOldestToKeep, _Stats.cEntriesGCed );
  729. // Reset the timer to its normal period.
  730. _timerGC.ReInitialize( _configSvr.GetGCPeriod() / _configSvr.GetGCDivisor() );
  731. continuation = CONTINUE_TIMER;
  732. }
  733. }
  734. __except( BreakOnDebuggableException() )
  735. {
  736. hr = GetExceptionCode();
  737. TrkLog(( TRKDBG_WARNING,
  738. TEXT("Ignoring exception in CTrkSvrSvc::Timer (%08x)"),
  739. hr ));
  740. _OperationLog.Add( COperationLog::TRKSVR_GC, hr, CMachineId(MCID_INVALID) );
  741. }
  742. // The Quota table's cached counts may be bad now that we've deleted
  743. // entries from the tables.
  744. if( fInvalidateCache )
  745. {
  746. _qtable.InvalidateCache();
  747. _MoveCounterReset.Set( (DWORD) _refreshSequence.GetSequenceNumber() );
  748. }
  749. TrkAssert( _timerGC.IsRecurring() );
  750. return( continuation );
  751. }
  752. SequenceNumber
  753. CTrkSvrSvc::GetSequenceNumber( const CMachineId & mcidClient, const CVolumeId & volume )
  754. {
  755. HRESULT hr;
  756. SequenceNumber seq;
  757. FILETIME ftLastRefresh;
  758. hr = _voltab.QueryVolume(mcidClient, volume, &seq, &ftLastRefresh);
  759. if( S_OK != hr )
  760. {
  761. // Raise on error. E.g. if mcidClient doesn't own this volume.
  762. TrkLog(( TRKDBG_ERROR,
  763. TEXT("CTrkSvrSvc::GetSequenceNumber --> %08x"), hr ));
  764. TrkRaiseException(hr);
  765. }
  766. return(seq);
  767. }
  768. void
  769. CTrkSvrSvc::SetSequenceNumber( const CVolumeId & volume, // must ensure that validation already done for volume
  770. SequenceNumber seq )
  771. {
  772. HRESULT hr;
  773. hr = _voltab.SetSequenceNumber( volume, seq );
  774. if (hr != S_OK)
  775. {
  776. TrkRaiseException( hr );
  777. }
  778. }
  779. HRESULT
  780. CTrkSvrSvc::MoveNotify( const CMachineId & mcidClient,
  781. TRKSVR_CALL_MOVE_NOTIFICATION * pMove )
  782. {
  783. HRESULT hr = S_OK;
  784. SequenceNumber seqExpected;
  785. CVolumeId volid;
  786. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cMoveNotifyRequests) );
  787. pMove->cProcessed = 0;
  788. //
  789. // ensure we have at least one notification because we assume that
  790. // the current volume of the first notification is the same for all
  791. // of the notifications in this rpc.
  792. //
  793. if (pMove->cNotifications == 0)
  794. {
  795. return(S_OK);
  796. }
  797. // Get the machine for this volume and the sequence number expected
  798. // ensure that the machine is actually the owner of the volume.
  799. // (This will raise if mcidClient doesn't own this volid.)
  800. volid = *pMove->pvolid;
  801. seqExpected = GetSequenceNumber(mcidClient, volid);
  802. // Is this the sequence number we were expecting for this client volume?
  803. TrkLog((TRKDBG_MOVE, TEXT("sequence no %d %sexpected for %s (%sforcing, expected %d)"),
  804. pMove->seq,
  805. seqExpected != pMove->seq ? TEXT("un") : TEXT(""),
  806. (const TCHAR*) CDebugString(volid),
  807. pMove->fForceSeqNumber ? TEXT("") : TEXT("not "),
  808. seqExpected
  809. ));
  810. if( seqExpected != pMove->seq )
  811. {
  812. // No, it's not the right sequence number.
  813. if( !pMove->fForceSeqNumber )
  814. {
  815. // The caller hasn't requested an override, so this is an error.
  816. pMove->seq = seqExpected;
  817. return TRK_S_OUT_OF_SYNC;
  818. }
  819. }
  820. //
  821. // Before processing the actual move notifications, ensure that we
  822. // have enough quota... assume that each move notify is going to
  823. // to need one unit of quota (the writes will actually update
  824. // the quota accurately.)
  825. //
  826. #ifdef VOL_QUOTA
  827. if (pMove->cNotifications > GetAvailableNotificationQuota( ) )
  828. {
  829. TrkRaiseException( TRK_E_NOTIFICATION_QUOTA_EXCEEDED );
  830. }
  831. #endif
  832. while (pMove->cProcessed < pMove->cNotifications)
  833. {
  834. // the only errors are fatal since we always make a record of
  835. // a notification or merge it with an existing record
  836. BOOL fQuotaExceeded = FALSE;
  837. if( CheckWritesPerHour() )
  838. {
  839. TrkLog(( TRKDBG_SVR, TEXT("Stopping move-notifications due to too many writes (%d)"),
  840. NumWritesThisHour() ));
  841. break;
  842. }
  843. MoveNotify(CDomainRelativeObjId( volid, pMove->rgobjidCurrent[pMove->cProcessed] ),
  844. pMove->rgdroidBirth[pMove->cProcessed],
  845. pMove->rgdroidNew[pMove->cProcessed],
  846. &fQuotaExceeded
  847. );
  848. if( fQuotaExceeded )
  849. {
  850. hr = TRK_S_NOTIFICATION_QUOTA_EXCEEDED;
  851. break;
  852. }
  853. pMove->cProcessed++;
  854. IncrementWritesPerHour();
  855. RaiseIfStopped();
  856. }
  857. if( 0 != pMove->cProcessed )
  858. {
  859. SetSequenceNumber( volid, pMove->seq + pMove->cProcessed );
  860. TrkLog(( TRKDBG_SVR, TEXT("Updated sequence number to %d"), pMove->seq+pMove->cProcessed ));
  861. }
  862. if( 0 != pMove->cNotifications )
  863. {
  864. //TrkLog(( TRKDBG_WARNING, TEXT("pMove = %p"), pMove ));
  865. pMove->cNotifications = 0; // don't need to send the data back
  866. //TrkLog(( TRKDBG_WARNING, TEXT("Free rgdroidNew (%p)"), pMove->rgdroidNew ));
  867. //MIDL_user_free( pMove->rgdroidNew );
  868. pMove->rgdroidNew = NULL;
  869. //TrkLog(( TRKDBG_WARNING, TEXT("Free rgobjidCurrent (%p)"), pMove->rgobjidCurrent ));
  870. //MIDL_user_free( pMove->rgobjidCurrent );
  871. pMove->rgobjidCurrent = NULL;
  872. //TrkLog(( TRKDBG_WARNING, TEXT("Free rgdroidBirth (%p)"), pMove->rgdroidBirth ));
  873. //MIDL_user_free( pMove->rgdroidBirth );
  874. pMove->rgdroidBirth = NULL;
  875. }
  876. return(hr);
  877. }
  878. BOOL
  879. CTrkSvrSvc::VerifyMachineOwnsVolume( const CMachineId &mcid, const CVolumeId & volid )
  880. {
  881. HRESULT hr;
  882. SequenceNumber seq;
  883. FILETIME ft;
  884. hr = _voltab.QueryVolume(
  885. mcid,
  886. volid,
  887. &seq,
  888. &ft);
  889. if (hr != S_OK)
  890. return FALSE;
  891. else
  892. return TRUE;
  893. }
  894. //+----------------------------------------------------------------------------
  895. //
  896. // CTrkSvrSvc::DeleteNotify
  897. //
  898. // Process a delete-notify request from a client. This request provides
  899. // information about a file that has been deleted, so that we can purge
  900. // it from the move table.
  901. //
  902. //+----------------------------------------------------------------------------
  903. void
  904. CTrkSvrSvc::DeleteNotify( const CMachineId & mcidClient, TRKSVR_CALL_DELETE * pDelete )
  905. {
  906. CVolumeId vol;
  907. HRESULT hr = TRK_S_VOLUME_NOT_FOUND;
  908. // Loop through all of the notifications in this batch.
  909. for (ULONG i=0; i < pDelete->cdroidBirth; i++)
  910. {
  911. // Look up the current location of the file, and if it
  912. // is on an owned volume, then allow the delete.
  913. CDomainRelativeObjId droidCurrent;
  914. CDomainRelativeObjId droidBirth;
  915. // Don't embark on a slow operation if the service is stopping.
  916. RaiseIfStopped();
  917. // If we've already written a lot to the DS in the past hour,
  918. // abort so we don't flood the replication queue.
  919. if( CheckWritesPerHour() )
  920. {
  921. TrkLog(( TRKDBG_WARNING, TEXT("Stopping delete-notify due to too many writes") ));
  922. TrkRaiseException( TRK_E_SERVER_TOO_BUSY );
  923. }
  924. // Read the existing entry for this file.
  925. if (_idt.Query(pDelete->adroidBirth[i], &droidCurrent, &droidBirth))
  926. {
  927. // The entry exists.
  928. TrkAssert(droidBirth == pDelete->adroidBirth[i]);
  929. // See if this is the same volume that we checked on the
  930. // previous iteration through the loop. If so, no need to
  931. // look up again.
  932. if (vol == droidCurrent.GetVolumeId())
  933. {
  934. hr = S_OK;
  935. }
  936. else
  937. {
  938. // We need to check that whoever sent this delete-notify
  939. // request really owns the volume.
  940. vol = droidCurrent.GetVolumeId();
  941. if( !VerifyMachineOwnsVolume( mcidClient, vol ))
  942. {
  943. TrkLog((TRKDBG_OBJID_DELETIONS,
  944. TEXT("DeleteNotify _voltab.QueryVolume( %s ) -> %s\n"),
  945. (const TCHAR*) CDebugString( vol ),
  946. GetErrorString(hr) ));
  947. vol = CVolumeId();
  948. }
  949. }
  950. // If the volume is owned, go ahead with the deletion.
  951. if (hr == S_OK)
  952. {
  953. BOOL f = _idt.Delete( pDelete->adroidBirth[i] );
  954. TrkLog((TRKDBG_OBJID_DELETIONS,
  955. TEXT("DeleteNotify _idt.Delete( %s ) -> %s\n"),
  956. (const TCHAR*) CDebugString( pDelete->adroidBirth[i] ),
  957. f ? TEXT("Ok") : TEXT("Not Found") ));
  958. if( f )
  959. IncrementWritesPerHour();
  960. }
  961. } // if (_idt.Query(pDelete->adroidBirth[i], &droidCurrent, &droidBirth))
  962. else
  963. {
  964. // Attempted to delete an entry that doesn't exist.
  965. TrkLog((TRKDBG_OBJID_DELETIONS,
  966. TEXT("DeleteNotify _idt.Query( droidBirth=%s ) not found\n"),
  967. (const TCHAR*) CDebugString( pDelete->adroidBirth[i] ) ));
  968. }
  969. }
  970. if( 0 != pDelete->cdroidBirth )
  971. {
  972. //MIDL_user_free( pDelete->adroidBirth );
  973. //pDelete->adroidBirth = NULL;
  974. pDelete->cdroidBirth = 0;
  975. }
  976. }
  977. void
  978. CTrkSvrSvc::Refresh( const CMachineId &mcidClient, TRKSVR_CALL_REFRESH * pRefresh )
  979. {
  980. // save away the input and zero the output so we don't marshall a
  981. // ton of refresh info back to the client
  982. ULONG cSources = pRefresh->cSources;
  983. ULONG cVolumes = pRefresh->cVolumes;
  984. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cRefreshRequests) );
  985. pRefresh->cSources = 0;
  986. pRefresh->cVolumes = 0;
  987. // Touch the move table entries
  988. for (ULONG i=0; i < cSources ; i++)
  989. {
  990. // Ensure we're not overloading the replication log
  991. if( CheckWritesPerHour() )
  992. {
  993. TrkLog(( TRKDBG_SVR, TEXT("Aborting refresh due to writes-per-hour") ));
  994. TrkRaiseException( TRK_E_SERVER_TOO_BUSY );
  995. }
  996. // Touch the entry in the move table.
  997. if( _idt.Touch( pRefresh->adroidBirth[i] ))
  998. IncrementWritesPerHour();
  999. }
  1000. // Touch the volume table entries
  1001. for (i=0; i < cVolumes ; i++)
  1002. {
  1003. // Ensure we're not overloading the replication log
  1004. if( CheckWritesPerHour() )
  1005. {
  1006. TrkLog(( TRKDBG_SVR, TEXT("Aborting refresh due to writes-per-hour") ));
  1007. TrkRaiseException( TRK_E_SERVER_TOO_BUSY );
  1008. }
  1009. // Ensure this volume is owned by the machine.
  1010. // mikehill_test
  1011. if( !VerifyMachineOwnsVolume( mcidClient, pRefresh->avolid[i] ))
  1012. {
  1013. TrkLog(( TRKDBG_WARNING,
  1014. TEXT("Machine can't touch volume it doesn't own (%s, %s)"),
  1015. (const TCHAR*) CDebugString(mcidClient),
  1016. (const TCHAR*) CDebugString(pRefresh->avolid[i]) ));
  1017. continue;
  1018. }
  1019. // Touch the entry in the volume table
  1020. if( _voltab.Touch( pRefresh->avolid[i] ))
  1021. IncrementWritesPerHour();
  1022. }
  1023. }
  1024. void
  1025. CTrkSvrSvc::Statistics( TRKSVR_STATISTICS *pStatistics )
  1026. {
  1027. pStatistics->cSyncVolumeRequests = _Stats.cSyncVolumeRequests;
  1028. pStatistics->cSyncVolumeErrors = _Stats.cSyncVolumeErrors;
  1029. pStatistics->cSyncVolumeThreads = _Stats.cSyncVolumeThreads;
  1030. pStatistics->cCreateVolumeRequests = _Stats.cCreateVolumeRequests;
  1031. pStatistics->cCreateVolumeErrors = _Stats.cCreateVolumeErrors;
  1032. pStatistics->cClaimVolumeRequests = _Stats.cClaimVolumeRequests;
  1033. pStatistics->cClaimVolumeErrors = _Stats.cClaimVolumeErrors;
  1034. pStatistics->cQueryVolumeRequests = _Stats.cQueryVolumeRequests;
  1035. pStatistics->cQueryVolumeErrors = _Stats.cQueryVolumeErrors;
  1036. pStatistics->cFindVolumeRequests = _Stats.cFindVolumeRequests;
  1037. pStatistics->cFindVolumeErrors = _Stats.cFindVolumeErrors;
  1038. pStatistics->cTestVolumeRequests = _Stats.cTestVolumeRequests;
  1039. pStatistics->cTestVolumeErrors = _Stats.cTestVolumeErrors;
  1040. pStatistics->cSearchRequests = _Stats.cSearchRequests;
  1041. pStatistics->cSearchErrors = _Stats.cSearchErrors;
  1042. pStatistics->cSearchThreads = _Stats.cSearchThreads;
  1043. pStatistics->cMoveNotifyRequests = _Stats.cMoveNotifyRequests;
  1044. pStatistics->cMoveNotifyErrors = _Stats.cMoveNotifyErrors;
  1045. pStatistics->cMoveNotifyThreads = _Stats.cMoveNotifyThreads;
  1046. pStatistics->cRefreshRequests = _Stats.cRefreshRequests;
  1047. pStatistics->cRefreshErrors = _Stats.cRefreshErrors;
  1048. pStatistics->cRefreshThreads = _Stats.cRefreshThreads;
  1049. pStatistics->lRefreshCounter = _refreshSequence.GetSequenceNumber();
  1050. pStatistics->cDeleteNotifyRequests = _Stats.cDeleteNotifyRequests;
  1051. pStatistics->cDeleteNotifyErrors = _Stats.cDeleteNotifyErrors;
  1052. pStatistics->cDeleteNotifyThreads = _Stats.cDeleteNotifyThreads;
  1053. pStatistics->ftLastSuccessfulRequest = _Stats.cftLastSuccessfulRequest;
  1054. pStatistics->ftServiceStart = _Stats.cftServiceStartTime;
  1055. //pStatistics->ulGCIterationPeriod = _Stats.ulGCIterationPeriod;
  1056. //pStatistics->cEntriesToGC = _Stats.cEntriesToGC;
  1057. pStatistics->cEntriesGCed = _Stats.cEntriesGCed;
  1058. pStatistics->hrLastError = _Stats.hrLastError;
  1059. pStatistics->ftNextGC = _timerGC.QueryOriginalDueTime();
  1060. pStatistics->cLowestAvailableRpcThreads=_cLowestAvailableThreads;
  1061. pStatistics->cAvailableRpcThreads = _cAvailableThreads;
  1062. pStatistics->cMaxRpcThreads = MAX_SVR_THREADS;
  1063. pStatistics->cNumThreadPoolThreads = g_cThreadPoolThreads;
  1064. pStatistics->cMostThreadPoolThreads = g_cThreadPoolMaxThreads;
  1065. //pStatistics->SvcCtrlState = _svcctrl.GetState();
  1066. pStatistics->cMaxDsWriteEvents = _Stats.cMaxDsWriteEvents;
  1067. pStatistics->cCurrentFailedWrites = _Stats.cCurrentFailedWrites;
  1068. _qtable.Statistics( pStatistics );
  1069. OSVERSIONINFO verinfo;
  1070. memset( &verinfo, 0, sizeof(verinfo) );
  1071. verinfo.dwOSVersionInfoSize = sizeof(verinfo);
  1072. if( GetVersionEx( &verinfo ))
  1073. {
  1074. pStatistics->Version.dwMajor = verinfo.dwMajorVersion;
  1075. pStatistics->Version.dwMinor = verinfo.dwMinorVersion;
  1076. pStatistics->Version.dwBuildNumber = verinfo.dwBuildNumber;
  1077. }
  1078. else
  1079. {
  1080. TrkLog(( TRKDBG_ERROR, TEXT("Failed GetVersionInfo (%lu)"), GetLastError() ));
  1081. }
  1082. return;
  1083. }
  1084. HRESULT
  1085. CTrkSvrSvc::SyncVolume(const CMachineId & mcidClient, TRKSVR_SYNC_VOLUME * pSyncVolume,
  1086. ULONG cUncountedCreates )
  1087. {
  1088. HRESULT hr = S_OK;
  1089. switch (pSyncVolume->SyncType)
  1090. {
  1091. case CREATE_VOLUME:
  1092. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cCreateVolumeRequests) );
  1093. if( CheckWritesPerHour() )
  1094. {
  1095. hr = TRK_E_SERVER_TOO_BUSY;
  1096. TrkLog(( TRKDBG_VOLTAB | TRKDBG_WARNING,
  1097. TEXT("Rejected CreateVolume, too many writes (%d)"),
  1098. NumWritesThisHour() ));
  1099. }
  1100. else
  1101. {
  1102. hr = _voltab.PreCreateVolume(
  1103. mcidClient,
  1104. pSyncVolume->secret,
  1105. cUncountedCreates,
  1106. &pSyncVolume->volume );
  1107. if( SUCCEEDED(hr) )
  1108. IncrementWritesPerHour();
  1109. }
  1110. if(hr == S_OK)
  1111. {
  1112. TrkLog((TRKDBG_VOLTAB,
  1113. TEXT("CreateVolume(machine=%s secret=%s volid(out)=%s) -> VOLUME_OK"),
  1114. (const TCHAR*) CDebugString(mcidClient),
  1115. (const TCHAR*) CDebugString(pSyncVolume->secret),
  1116. (const TCHAR*) CDebugString(pSyncVolume->volume) ));
  1117. }
  1118. else
  1119. {
  1120. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cCreateVolumeErrors) );
  1121. TrkLog((TRKDBG_VOLTAB,
  1122. TEXT("CreateVolume(machine=%s secret=%s) -> CreateFailed (%08x)"),
  1123. (const TCHAR*) CDebugString(mcidClient),
  1124. (const TCHAR*) CDebugString(pSyncVolume->secret),
  1125. hr ));
  1126. }
  1127. break;
  1128. case QUERY_VOLUME:
  1129. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cQueryVolumeRequests) );
  1130. hr = _voltab.QueryVolume(
  1131. mcidClient,
  1132. pSyncVolume->volume,
  1133. &pSyncVolume->seq,
  1134. &pSyncVolume->ftLastRefresh
  1135. );
  1136. TrkLog((TRKDBG_VOLTAB,
  1137. TEXT("QueryVolume(machine=%s volid=%s seq(out)=%d ftLastRefresh(out)=%d) -> %s"),
  1138. (const TCHAR*) CDebugString(mcidClient),
  1139. (const TCHAR*) CDebugString(pSyncVolume->volume),
  1140. pSyncVolume->seq,
  1141. pSyncVolume->ftLastRefresh.dwLowDateTime,
  1142. GetErrorString(hr)));
  1143. if( FAILED(hr) )
  1144. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cQueryVolumeErrors) );
  1145. break;
  1146. case FIND_VOLUME:
  1147. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cFindVolumeRequests) );
  1148. hr = _voltab.FindVolume(
  1149. pSyncVolume->volume,
  1150. &pSyncVolume->machine
  1151. );
  1152. TrkLog((TRKDBG_VOLTAB,
  1153. TEXT("FindVolume(volid=%s machine(out)=%s) -> %s"),
  1154. (const TCHAR*) CDebugString(pSyncVolume->volume),
  1155. (const TCHAR*) CDebugString(pSyncVolume->machine),
  1156. GetErrorString(hr)));
  1157. if( FAILED(hr) )
  1158. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cFindVolumeErrors) );
  1159. break;
  1160. case CLAIM_VOLUME:
  1161. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cClaimVolumeRequests) );
  1162. if( CheckWritesPerHour() )
  1163. {
  1164. hr = TRK_E_SERVER_TOO_BUSY;
  1165. TrkLog(( TRKDBG_VOLTAB | TRKDBG_WARNING,
  1166. TEXT("Rejected ClaimVolume, too many writes (%d)"),
  1167. NumWritesThisHour() ));
  1168. }
  1169. else
  1170. {
  1171. hr = _voltab.ClaimVolume(
  1172. mcidClient,
  1173. pSyncVolume->volume,
  1174. pSyncVolume->secretOld,
  1175. pSyncVolume->secret,
  1176. &pSyncVolume->seq,
  1177. &pSyncVolume->ftLastRefresh
  1178. );
  1179. if( S_OK == hr ) // Might return TRK_S_VOLUME_NOT_FOUND
  1180. IncrementWritesPerHour();
  1181. }
  1182. TrkLog((TRKDBG_VOLTAB,
  1183. TEXT("ClaimVolume(machine=%s volid=%s secret=%s->%s seq(out)=%d ftLastRefresh(out)=%s) -> %s"),
  1184. (const TCHAR*) CDebugString(mcidClient),
  1185. (const TCHAR*) CDebugString(pSyncVolume->volume),
  1186. (const TCHAR*) CDebugString(pSyncVolume->secretOld),
  1187. (const TCHAR*) CDebugString(pSyncVolume->secret),
  1188. pSyncVolume->seq,
  1189. (const TCHAR*) CDebugString(pSyncVolume->ftLastRefresh),
  1190. GetErrorString(hr)));
  1191. if( FAILED(hr) )
  1192. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cClaimVolumeErrors) );
  1193. break;
  1194. case TEST_VOLUME:
  1195. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cTestVolumeRequests) );
  1196. if( !(_configSvr.GetTestFlags() & TRK_TEST_FLAG_ALLOC_TEST_VOLUME) )
  1197. {
  1198. hr = E_NOTIMPL;
  1199. break;
  1200. }
  1201. if( CVolumeSecret() != pSyncVolume->secret )
  1202. {
  1203. hr = _voltab.SetSecret( pSyncVolume->volume, pSyncVolume->secret );
  1204. if( FAILED(hr) ) break;
  1205. }
  1206. hr = _voltab.SetSequenceNumber( pSyncVolume->volume, pSyncVolume->seq );
  1207. if( FAILED(hr) ) break;
  1208. if( CMachineId() != pSyncVolume->machine )
  1209. {
  1210. hr = _voltab.SetMachine( pSyncVolume->volume, pSyncVolume->machine );
  1211. if ( FAILED(hr) ) break;
  1212. }
  1213. if( SUCCEEDED(hr) )
  1214. IncrementWritesPerHour();
  1215. if( FAILED(hr) )
  1216. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cTestVolumeErrors) );
  1217. break;
  1218. case DELETE_VOLUME:
  1219. //InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cDeleteVolumeRequests) );
  1220. if( CheckWritesPerHour() )
  1221. {
  1222. hr = TRK_E_SERVER_TOO_BUSY;
  1223. TrkLog(( TRKDBG_VOLTAB | TRKDBG_WARNING,
  1224. TEXT("Rejected DeleteVolume, too many writes (%d)"),
  1225. NumWritesThisHour() ));
  1226. }
  1227. else
  1228. {
  1229. hr = _voltab.DeleteVolume(
  1230. mcidClient,
  1231. pSyncVolume->volume
  1232. );
  1233. if( SUCCEEDED(hr) )
  1234. IncrementWritesPerHour();
  1235. }
  1236. TrkLog((TRKDBG_VOLTAB,
  1237. TEXT("DeleteVolume(machine=%s volid=%s -> %s"),
  1238. (const TCHAR*) CDebugString(mcidClient),
  1239. (const TCHAR*) CDebugString(pSyncVolume->volume),
  1240. GetErrorString(hr)));
  1241. /*
  1242. if( FAILED(hr) )
  1243. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cClaimVolumeErrors) );
  1244. */
  1245. break;
  1246. default:
  1247. TrkAssert(0 && "unknown switch type in SyncVolume");
  1248. hr = TRK_S_VOLUME_NOT_FOUND;
  1249. break;
  1250. }
  1251. return(hr);
  1252. }
  1253. //
  1254. // If we have 0 threads, then accept any pri <=9
  1255. // If we have 1 thread, then accept any pri <=9
  1256. // If we have 2 threads, then accept any pri <=7
  1257. // If we have 3 threads, then accept any pri <=6
  1258. // If we have 4 threads, then accept any pri <=5
  1259. // If we have 5 threads, then accept any pri <=4
  1260. // If we have 6 threads, then accept any pri <=3
  1261. // If we have 7 threads, then accept any pri <=0
  1262. // If we have 8 threads, then accept any pri <=0
  1263. // If we have 9 threads, then accept any pri <=0
  1264. // If we have 10 threads, don't accept any
  1265. //
  1266. BOOL
  1267. CTrkSvrSvc::CountPrioritizedThread( const TRKSVR_MESSAGE_UNION * pMsg )
  1268. {
  1269. static LONG Accept[10] = { 0, 0, 0, 3, 4, 5, 6, 7, 9, 9 };
  1270. TrkAssert( ELEMENTS(Accept) == MAX_SVR_THREADS );
  1271. LONG l = InterlockedDecrement( &_cAvailableThreads );
  1272. // It's not worth a lock to protect this statistic, we'll just hope that we
  1273. // don't get pre-empted during the update.
  1274. _cLowestAvailableThreads = min( _cLowestAvailableThreads, l );
  1275. TrkAssert( l >= -1 && l < MAX_SVR_THREADS );
  1276. if (l == -1 || pMsg->Priority > Accept[ l ])
  1277. {
  1278. InterlockedIncrement( &_cAvailableThreads );
  1279. return( FALSE );
  1280. }
  1281. return(TRUE);
  1282. }
  1283. void
  1284. CTrkSvrSvc::ReleasePrioritizedThread()
  1285. {
  1286. LONG l = InterlockedIncrement( &_cAvailableThreads );
  1287. TrkAssert( l >= 0 && l <= MAX_SVR_THREADS );
  1288. }
  1289. HRESULT
  1290. CTrkSvrSvc::CreateVolume(const CMachineId & mcidClient, const TRKSVR_SYNC_VOLUME& pSyncVolume)
  1291. {
  1292. return _voltab.AddVolidToTable(pSyncVolume.volume, mcidClient, pSyncVolume.secret );
  1293. }
  1294. void
  1295. CTrkSvrSvc::OnRequestStart( TRKSVR_MESSAGE_TYPE MsgType )
  1296. {
  1297. switch( MsgType )
  1298. {
  1299. case SEARCH:
  1300. case old_SEARCH:
  1301. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cSearchRequests) );
  1302. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cSearchThreads) );
  1303. break;
  1304. case MOVE_NOTIFICATION:
  1305. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cMoveNotifyRequests) );
  1306. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cMoveNotifyThreads) );
  1307. break;
  1308. case REFRESH:
  1309. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cRefreshRequests) );
  1310. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cRefreshThreads) );
  1311. break;
  1312. case SYNC_VOLUMES:
  1313. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cSyncVolumeRequests) );
  1314. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cSyncVolumeThreads) );
  1315. break;
  1316. case DELETE_NOTIFY:
  1317. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cDeleteNotifyRequests) );
  1318. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cDeleteNotifyThreads) );
  1319. break;
  1320. case STATISTICS:
  1321. break;
  1322. default:
  1323. TrkLog(( TRKDBG_ERROR, TEXT("Invalid MsgType in CTrkSvrSvc::OnRequestStart(%d)"),
  1324. MsgType ));
  1325. TrkAssert( FALSE );
  1326. }
  1327. }
  1328. void
  1329. CTrkSvrSvc::OnRequestEnd( TRKSVR_MESSAGE_UNION * pMsg, const CMachineId &mcid, HRESULT hr )
  1330. {
  1331. int i = 0;
  1332. __try
  1333. {
  1334. switch( pMsg->MessageType )
  1335. {
  1336. case SEARCH:
  1337. case old_SEARCH:
  1338. InterlockedDecrement( reinterpret_cast<LONG*>(&_Stats.cSearchThreads) );
  1339. if( FAILED(hr)
  1340. ||
  1341. ( 1 <= pMsg->Search.cSearch && S_OK != pMsg->Search.pSearches->hr ))
  1342. {
  1343. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cSearchErrors) );
  1344. }
  1345. _OperationLog.Add( COperationLog::TRKSVR_SEARCH, hr, mcid, pMsg->Search.pSearches->droidBirth );
  1346. break;
  1347. case MOVE_NOTIFICATION:
  1348. InterlockedDecrement( reinterpret_cast<LONG*>(&_Stats.cMoveNotifyThreads) );
  1349. if( S_OK != hr )
  1350. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cMoveNotifyErrors) );
  1351. _OperationLog.Add( COperationLog::TRKSVR_MOVE_NOTIFICATION, hr, mcid );
  1352. break;
  1353. case REFRESH:
  1354. InterlockedDecrement( reinterpret_cast<LONG*>(&_Stats.cRefreshThreads) );
  1355. if( FAILED(hr) )
  1356. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cRefreshErrors) );
  1357. _OperationLog.Add( COperationLog::TRKSVR_REFRESH, hr, mcid, pMsg->Refresh.cSources, pMsg->Refresh.cVolumes );
  1358. break;
  1359. case SYNC_VOLUMES:
  1360. InterlockedDecrement( reinterpret_cast<LONG*>(&_Stats.cSyncVolumeThreads) );
  1361. if( FAILED(hr) )
  1362. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cSyncVolumeErrors) );
  1363. _OperationLog.Add( COperationLog::TRKSVR_SYNC_VOLUMES, hr, mcid );
  1364. break;
  1365. case DELETE_NOTIFY:
  1366. InterlockedDecrement( reinterpret_cast<LONG*>(&_Stats.cDeleteNotifyThreads) );
  1367. if( FAILED(hr) )
  1368. InterlockedIncrement( reinterpret_cast<LONG*>(&_Stats.cDeleteNotifyErrors) );
  1369. _OperationLog.Add( COperationLog::TRKSVR_DELETE_NOTIFY, hr, mcid );
  1370. break;
  1371. case STATISTICS:
  1372. break;
  1373. }
  1374. if( FAILED(hr) )
  1375. SetLastError( hr );
  1376. else if( STATISTICS != pMsg->MessageType )
  1377. _Stats.cftLastSuccessfulRequest = CFILETIME();
  1378. }
  1379. __except( BreakOnDebuggableException() )
  1380. {
  1381. TrkLog(( TRKDBG_WARNING, TEXT("Ignoring exception in OnRequestEnd") ));
  1382. }
  1383. return;
  1384. }
  1385. //+----------------------------------------------------------------------------
  1386. //
  1387. // CTrkSvrSvc::SvrMessage
  1388. //
  1389. // This is the primary starting point for processing of the trksvr
  1390. // service's LnkSvrMessage RPC method. For the most part, it looks
  1391. // at the MessageType (the request is in the form of a union, with
  1392. // a message-type and type-appropriate parameters), then switches
  1393. // to specific handler routine.
  1394. //
  1395. //+----------------------------------------------------------------------------
  1396. HRESULT
  1397. CTrkSvrSvc::SvrMessage(
  1398. handle_t IDL_handle,
  1399. TRKSVR_MESSAGE_UNION * pMsg)
  1400. {
  1401. HRESULT hr = S_OK;
  1402. ULONG i;
  1403. ULONG cSources;
  1404. CMachineId mcidClient;
  1405. SThreadFromPoolState OriginalThreadFromPoolState;
  1406. if (GetState() != SERVICE_RUNNING)
  1407. {
  1408. return(TRK_E_SERVICE_NOT_RUNNING);
  1409. }
  1410. // If we're getting busy (wrt active threads), we may have
  1411. // to reject this request, based on how busy we are and the
  1412. // priority of the request.
  1413. if (!CountPrioritizedThread( pMsg ))
  1414. {
  1415. return(TRK_E_SERVER_TOO_BUSY);
  1416. }
  1417. __try
  1418. {
  1419. // Set thread-specific settings, saving the old settings.
  1420. OriginalThreadFromPoolState = InitializeThreadFromPool();
  1421. // Update statistics
  1422. OnRequestStart( pMsg->MessageType );
  1423. // Query the IDL handle for the client's mcid. Don't do it, though, if
  1424. // we're not using secure RPC (which only happens in testing),
  1425. // or if the message type is statistics.
  1426. if( STATISTICS == pMsg->MessageType )
  1427. {
  1428. // All messages that come in to this routine are from a machine account
  1429. // (in which trkwks runs). The exception to this rule is the Statistics
  1430. // request, which comes from a user. We'll allow all Authenticated Users
  1431. // access to the statistics (they can access the DS tables by default
  1432. // anyway).
  1433. if( RequireSecureRPC() )
  1434. {
  1435. RPC_STATUS RpcStatus;
  1436. RpcStatus = RpcImpersonateClient(IDL_handle);
  1437. if (RpcStatus != RPC_S_OK)
  1438. TrkRaiseWin32Error(RpcStatus);
  1439. RpcRevertToSelf();
  1440. }
  1441. mcidClient = CMachineId( MCID_LOCAL );
  1442. }
  1443. else
  1444. {
  1445. mcidClient = NULL != pMsg->ptszMachineID && !g_ptrksvr->RequireSecureRPC()
  1446. ? CMachineId(pMsg->ptszMachineID)
  1447. : CMachineId(IDL_handle);
  1448. }
  1449. // Check for a client doing a denial-of-service attack.
  1450. if( RequireSecureRPC() ) // Always true except in testing
  1451. CheckClient(mcidClient);
  1452. // Switch on the message type.
  1453. switch (pMsg->MessageType)
  1454. {
  1455. case SEARCH:
  1456. TrkLog((TRKDBG_MEND|TRKDBG_SVR, TEXT("SEARCH from \\\\%s"),
  1457. (const TCHAR*) CDebugString( mcidClient )));
  1458. for (i=0; i<pMsg->Search.cSearch; i++)
  1459. {
  1460. TrkAssert( NULL != pMsg->Search.pSearches );
  1461. pMsg->Search.pSearches[i].hr = TRK_E_UNAVAILABLE;
  1462. }
  1463. for (i=0; i<pMsg->Search.cSearch; i++)
  1464. {
  1465. Search(&pMsg->Search.pSearches[i]);
  1466. }
  1467. break;
  1468. case old_SEARCH:
  1469. TrkLog((TRKDBG_MEND|TRKDBG_SVR, TEXT("old_SEARCH from \\\\%s"),
  1470. (const TCHAR*) CDebugString( mcidClient )));
  1471. for (i=0; i<pMsg->old_Search.cSearch; i++)
  1472. {
  1473. pMsg->old_Search.pSearches[i].hr = TRK_E_UNAVAILABLE;
  1474. }
  1475. for (i=0; i<pMsg->old_Search.cSearch; i++)
  1476. {
  1477. old_Search(&pMsg->old_Search.pSearches[i]);
  1478. }
  1479. break;
  1480. case MOVE_NOTIFICATION:
  1481. TrkLog((TRKDBG_MOVE|TRKDBG_SVR, TEXT("MOVE_NOTIFICATION from \\\\%s (%d notifications)"),
  1482. (const TCHAR*) CDebugString( mcidClient ),
  1483. pMsg->MoveNotification.cNotifications ));
  1484. hr = MoveNotify( mcidClient, &pMsg->MoveNotification );
  1485. break;
  1486. case REFRESH:
  1487. TrkLog((TRKDBG_GARBAGE_COLLECT|TRKDBG_SVR, TEXT("REFRESH from \\\\%s"),
  1488. (const TCHAR*) CDebugString( mcidClient )));
  1489. Refresh( mcidClient, &pMsg->Refresh );
  1490. break;
  1491. case SYNC_VOLUMES:
  1492. {
  1493. BOOL fHaveCreateVolume = FALSE;
  1494. TRKSVR_SYNC_VOLUME rgCopyOfSyncVolumes[NUM_VOLUMES];
  1495. ULONG cUncountedCreates = 0;
  1496. // Validate the number of volumes in this request to protect against an unruly
  1497. // client.
  1498. if(pMsg->SyncVolumes.cVolumes > NUM_VOLUMES)
  1499. {
  1500. TrkLog((TRKDBG_ERROR, TEXT("Number of volumes exceeded per machine limit %d"), pMsg->SyncVolumes.cVolumes));
  1501. TrkRaiseException( E_INVALIDARG );
  1502. }
  1503. // Pre-initialize the return buffer.
  1504. for (i=0; i < pMsg->SyncVolumes.cVolumes; i++)
  1505. {
  1506. pMsg->SyncVolumes.pVolumes[i].hr = TRK_S_VOLUME_NOT_FOUND;
  1507. }
  1508. // Perform the sync for each of the volumes.
  1509. for (i=0; i < pMsg->SyncVolumes.cVolumes; i++)
  1510. {
  1511. // Perform the sync.
  1512. pMsg->SyncVolumes.pVolumes[i].hr
  1513. = SyncVolume(mcidClient, pMsg->SyncVolumes.pVolumes + i, cUncountedCreates );
  1514. // Keep track of the number of CREATE_VOLUME sub-requests.
  1515. if(CREATE_VOLUME == pMsg->SyncVolumes.pVolumes[i].SyncType &&
  1516. pMsg->SyncVolumes.pVolumes[i].hr == S_OK)
  1517. {
  1518. fHaveCreateVolume = TRUE;
  1519. cUncountedCreates++;
  1520. }
  1521. // Make a copy of the newly generated volume id so that we can
  1522. // add it to the DS later. We want to make sure we don't
  1523. // add the entry to the DS until we're sure it made it onto
  1524. // the client.
  1525. // (There once was a bug where the newly created
  1526. // volid was written to the DS, then returned to the client,
  1527. // but the client wasn't receiving the response due to an
  1528. // security problem. Consequently, the client kept asking
  1529. // and asking for the volume ID, all of which went into the DS.
  1530. // So now we make sure the client gets it, and we have a
  1531. // per-client volume quota.)
  1532. rgCopyOfSyncVolumes[i] = pMsg->SyncVolumes.pVolumes[i];
  1533. }
  1534. #ifdef VOL_REPL
  1535. if (pMsg->SyncVolumes.ppVolumeChanges != NULL)
  1536. {
  1537. CFILETIME ftChangesUntilThisTime;
  1538. CVolumeMap VolMap;
  1539. if (CFILETIME(-1) != CFILETIME(pMsg->SyncVolumes.ftFirstChange))
  1540. {
  1541. _voltab.QueryVolumeChanges(
  1542. CFILETIME(pMsg->SyncVolumes.ftFirstChange),
  1543. &VolMap );
  1544. VolMap.MoveTo( &pMsg->SyncVolumes.cChanges, pMsg->SyncVolumes.ppVolumeChanges );
  1545. pMsg->SyncVolumes.ftFirstChange = ftChangesUntilThisTime;
  1546. }
  1547. }
  1548. #endif
  1549. // If there were successful CREATE_VOLUME sub-requests in this
  1550. // SYNC_VOLUME request, send the new IDs back to the client now,
  1551. // and write the volids to the DS.
  1552. if(TRUE == fHaveCreateVolume)
  1553. {
  1554. TrkLog((TRKDBG_LOG, TEXT("Calling back to trkwks")));
  1555. __try
  1556. {
  1557. // Note: A trkwks could tie up several threads by blocking
  1558. // in this callback. Worse case this DOS attack blocks
  1559. // trksvr, but it can't cause any great harm to the DC or DS.
  1560. hr = LnkSvrMessageCallback(pMsg);
  1561. TrkLog(( TRKDBG_SVR, TEXT("LnkSvrMessageCallback returned %08x"), hr ));
  1562. }
  1563. __except(BreakOnDebuggableException())
  1564. {
  1565. hr = GetExceptionCode();
  1566. TrkLog((TRKDBG_ERROR, TEXT("Exception in Callback, %08x"), hr));
  1567. }
  1568. // If callback is successful, add the created volumes into the DS. Otherwise don't do
  1569. // anything.
  1570. TrkAssert(pMsg->SyncVolumes.cVolumes <= 26);
  1571. if( SUCCEEDED(hr) )
  1572. {
  1573. for (i=0; i < pMsg->SyncVolumes.cVolumes; i++)
  1574. {
  1575. if(CREATE_VOLUME == pMsg->SyncVolumes.pVolumes[i].SyncType && S_OK == pMsg->SyncVolumes.pVolumes[i].hr)
  1576. {
  1577. pMsg->SyncVolumes.pVolumes[i].hr =
  1578. CreateVolume(mcidClient, rgCopyOfSyncVolumes[i]);
  1579. }
  1580. }
  1581. }
  1582. pMsg->SyncVolumes.cVolumes = 0;
  1583. }
  1584. break;
  1585. }
  1586. case DELETE_NOTIFY:
  1587. TrkLog((TRKDBG_OBJID_DELETIONS|TRKDBG_SVR,
  1588. TEXT("DELETE_NOTIFY from \\\\%s"),
  1589. (const TCHAR*) CDebugString( mcidClient )));
  1590. DeleteNotify( mcidClient, &pMsg->Delete );
  1591. break;
  1592. case STATISTICS:
  1593. TrkLog(( TRKDBG_SVR, TEXT("TRKSVR_STATISTICS"),
  1594. (const TCHAR*) CDebugString(mcidClient) ));
  1595. memset( &pMsg->Statistics, 0, sizeof(TRKSVR_STATISTICS) );
  1596. Statistics( &pMsg->Statistics );
  1597. break;
  1598. default:
  1599. hr = TRK_E_UNKNOWN_SVR_MESSAGE_TYPE;
  1600. break;
  1601. }
  1602. }
  1603. __except(BreakOnDebuggableException())
  1604. {
  1605. hr = GetExceptionCode();
  1606. TrkLog((TRKDBG_ERROR, TEXT("LnkSvrMessage exception %08X caught during %s"),
  1607. hr,
  1608. (const TCHAR*) CDebugString(pMsg->MessageType) ));
  1609. }
  1610. // Update statistics
  1611. OnRequestEnd( pMsg, mcidClient, hr );
  1612. ReleasePrioritizedThread();
  1613. // Restore the thread-specif settings.
  1614. UnInitializeThreadFromPool( OriginalThreadFromPoolState );
  1615. return(hr);
  1616. }
  1617. HRESULT
  1618. StubLnkSvrMessage_Old(
  1619. handle_t IDL_handle,
  1620. TRKSVR_MESSAGE_UNION_OLD * pMsg)
  1621. {
  1622. HRESULT hr;
  1623. TrkLog((TRKDBG_SVR, TEXT("Received downlevel call: ... thunking")));
  1624. TRKSVR_MESSAGE_UNION Msg2;
  1625. Msg2.MessageType = pMsg->MessageType;
  1626. Msg2.Priority = PRI_5;
  1627. switch (Msg2.MessageType)
  1628. {
  1629. case (SEARCH):
  1630. Msg2.Search = pMsg->Search;
  1631. break;
  1632. case (MOVE_NOTIFICATION):
  1633. Msg2.MoveNotification = pMsg->MoveNotification;
  1634. break;
  1635. case (REFRESH):
  1636. Msg2.Refresh = pMsg->Refresh;
  1637. break;
  1638. case (SYNC_VOLUMES):
  1639. Msg2.SyncVolumes = pMsg->SyncVolumes;
  1640. break;
  1641. case (DELETE_NOTIFY):
  1642. Msg2.Delete = pMsg->Delete;
  1643. break;
  1644. }
  1645. Msg2.ptszMachineID = pMsg->ptszMachineID;
  1646. hr = StubLnkSvrMessage( IDL_handle, &Msg2 );
  1647. switch (Msg2.MessageType)
  1648. {
  1649. case (SEARCH):
  1650. pMsg->Search = Msg2.Search;
  1651. break;
  1652. case (MOVE_NOTIFICATION):
  1653. pMsg->MoveNotification = Msg2.MoveNotification;
  1654. break;
  1655. case (REFRESH):
  1656. pMsg->Refresh = Msg2.Refresh;
  1657. break;
  1658. case (SYNC_VOLUMES):
  1659. pMsg->SyncVolumes = Msg2.SyncVolumes ;
  1660. break;
  1661. case (DELETE_NOTIFY):
  1662. pMsg->Delete = Msg2.Delete;
  1663. break;
  1664. }
  1665. pMsg->ptszMachineID = Msg2.ptszMachineID;
  1666. return(hr);
  1667. }
  1668. // must return a positive number (success code) if it doesn't want the caller
  1669. // to find another DC to do it on.
  1670. HRESULT
  1671. StubLnkSvrMessage(
  1672. handle_t IDL_handle,
  1673. TRKSVR_MESSAGE_UNION * pMsg)
  1674. {
  1675. return( g_ptrksvr->SvrMessage( IDL_handle, pMsg ));
  1676. }
  1677. void
  1678. CTrkSvrRpcServer::Initialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData, CTrkSvrConfiguration * pTrkSvrConfig )
  1679. {
  1680. RPC_STATUS rpcstatus;
  1681. NET_API_STATUS netstatus;
  1682. // Ensure there's a tcp/ip binding handle
  1683. rpcstatus = RpcServerUseProtseq( const_cast<TCHAR*>(s_tszTrkSvrRpcProtocol),
  1684. pTrkSvrConfig->GetSvrMaxRpcCalls(), NULL);
  1685. if (rpcstatus != RPC_S_OK &&
  1686. rpcstatus != RPC_S_DUPLICATE_ENDPOINT)
  1687. {
  1688. // Log an event, unless it's a not-supported error, which happens during
  1689. // a normal setup.
  1690. if( RPC_S_PROTSEQ_NOT_SUPPORTED != rpcstatus )
  1691. {
  1692. TrkLog((TRKDBG_ERROR, TEXT("RpcServerUseProtseqEp %08x"), rpcstatus));
  1693. TrkReportInternalError( THIS_FILE_NUMBER, __LINE__, HRESULT_FROM_WIN32(rpcstatus),
  1694. TRKREPORT_LAST_PARAM );
  1695. }
  1696. TrkRaiseWin32Error(rpcstatus);
  1697. }
  1698. // If we don't have a pSvcsGlobalData (we're not running in services.exe),
  1699. // tell RpcServerRegisterIfEx to automatically set up a listen thread.
  1700. CRpcServer::Initialize( Stubtrksvr_v1_0_s_ifspec,
  1701. NULL == pSvcsGlobalData ? RPC_IF_AUTOLISTEN : 0,
  1702. pTrkSvrConfig->GetSvrMaxRpcCalls(),
  1703. RpcSecurityEnabled(), // fSetAuthInfo
  1704. s_tszTrkSvrRpcProtocol );
  1705. TrkLog(( TRKDBG_RPC, TEXT("Registered TrkSvr RPC server %s (%d)"),
  1706. RpcSecurityEnabled() ? TEXT("") : TEXT("(without authorization)"),
  1707. pTrkSvrConfig->GetSvrMaxRpcCalls() ));
  1708. }
  1709. void
  1710. CTrkSvrRpcServer::UnInitialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData )
  1711. {
  1712. TrkLog(( TRKDBG_RPC, TEXT("Unregistering TrkSvr RPC server") ));
  1713. CRpcServer::UnInitialize( );
  1714. TrkLog(( TRKDBG_RPC, TEXT("Unregistered TrkSvr RPC server") ));
  1715. }
  1716. CMachineId::CMachineId(handle_t ClientBinding)
  1717. {
  1718. RPC_STATUS RpcStatus;
  1719. NTSTATUS status;
  1720. BOOL f;
  1721. HANDLE hToken = NULL;
  1722. PTOKEN_USER pToken;
  1723. BYTE * pbToken = NULL;
  1724. PSID LocalSystemSid = NULL;
  1725. PUNICODE_STRING pUserName = NULL;
  1726. PUNICODE_STRING pUserDomainName = NULL;
  1727. NET_API_STATUS NetStatus;
  1728. WCHAR *pwszDomain = NULL;
  1729. BOOLEAN fIsWorkGroup;
  1730. LPBYTE pbAccountInfo = NULL;
  1731. BOOL fImpersonating = FALSE;
  1732. // Begin impersonating the user.
  1733. RpcStatus = RpcImpersonateClient(ClientBinding);
  1734. if (RpcStatus != RPC_S_OK)
  1735. TrkRaiseWin32Error(RpcStatus);
  1736. fImpersonating = TRUE;
  1737. __try
  1738. {
  1739. WCHAR wszCurrentUser[ UNLEN+1 ];
  1740. WCHAR wszDomainName[ CNLEN+1 ];
  1741. // Get the local domain name (so we can verify it against the user's).
  1742. NetStatus = NetpGetDomainNameEx(&pwszDomain, &fIsWorkGroup);
  1743. if (NetStatus != NO_ERROR)
  1744. {
  1745. pwszDomain = NULL;
  1746. TrkReportInternalError( THIS_FILE_NUMBER, __LINE__, HRESULT_FROM_WIN32(NetStatus),
  1747. TRKREPORT_LAST_PARAM );
  1748. TrkRaiseWin32Error(NetStatus);
  1749. }
  1750. TrkAssert( !fIsWorkGroup );
  1751. // Get the user's name & domain (possible because we're
  1752. // impersonating).
  1753. status = LsaGetUserName( &pUserName, &pUserDomainName );
  1754. if( !NT_SUCCESS(status) )
  1755. {
  1756. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get user name (%08x)"), status ));
  1757. TrkRaiseNtStatus( status );
  1758. }
  1759. memcpy( wszCurrentUser, pUserName->Buffer, pUserName->Length );
  1760. wszCurrentUser[ pUserName->Length / sizeof(WCHAR) ] = L'\0';
  1761. // Ensure this is a user in this domain
  1762. {
  1763. UNICODE_STRING LocalDomainName = { 0, 0, NULL };
  1764. RtlInitUnicodeString( &LocalDomainName, pwszDomain );
  1765. if( 0 != RtlCompareUnicodeString( pUserDomainName, &LocalDomainName, TRUE ))
  1766. {
  1767. TrkLog(( TRKDBG_WARNING, TEXT("User %s is from another domain"),
  1768. wszCurrentUser ));
  1769. TrkRaiseException( TRK_E_UNKNOWN_SID );
  1770. }
  1771. }
  1772. // The user name should end in a '$', since it should be a
  1773. // machine account.
  1774. if (wszCurrentUser[ pUserName->Length / sizeof(WCHAR) - 1] != L'$')
  1775. {
  1776. // No dollar suffix, it's probably local system on the DC
  1777. DWORD SizeRequired;
  1778. // Get the user's SID
  1779. if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken))
  1780. {
  1781. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open thread token for %ws (%08x)"), wszCurrentUser, HRESULT_FROM_WIN32(GetLastError()) ));
  1782. TrkRaiseLastError();
  1783. }
  1784. if (!GetTokenInformation( hToken,
  1785. TokenUser,
  1786. NULL,
  1787. 0,
  1788. &SizeRequired ) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  1789. {
  1790. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get thread token information (1) for %ws (%08x)"), wszCurrentUser, HRESULT_FROM_WIN32(GetLastError()) ));
  1791. TrkRaiseLastError();
  1792. }
  1793. pbToken = new BYTE [SizeRequired];
  1794. if (pbToken == NULL)
  1795. TrkRaiseWin32Error(ERROR_NOT_ENOUGH_MEMORY);
  1796. pToken = (PTOKEN_USER) pbToken;
  1797. if (!GetTokenInformation( hToken,
  1798. TokenUser,
  1799. pToken,
  1800. SizeRequired,
  1801. &SizeRequired ))
  1802. {
  1803. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get thread token information (2) for %ws (%08x)"), wszCurrentUser, HRESULT_FROM_WIN32(GetLastError()) ));
  1804. TrkRaiseLastError();
  1805. }
  1806. // Get the local system SID
  1807. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1808. if (! AllocateAndInitializeSid(
  1809. &NtAuthority,
  1810. 1,
  1811. SECURITY_LOCAL_SYSTEM_RID,
  1812. 0, 0, 0, 0, 0, 0, 0,
  1813. &LocalSystemSid ))
  1814. {
  1815. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't Alloc/Init SID for %ws (%08x)"), wszCurrentUser, HRESULT_FROM_WIN32(GetLastError()) ));
  1816. TrkRaiseLastError();
  1817. }
  1818. // Verify that the user is local system.
  1819. BOOL fEqual = EqualSid( pToken->User.Sid, LocalSystemSid );
  1820. if (!fEqual)
  1821. {
  1822. TrkLog(( TRKDBG_ERROR, TEXT("Unknown SID: %ws"), wszCurrentUser ));
  1823. TrkRaiseException(TRK_E_UNKNOWN_SID);
  1824. }
  1825. *this = CMachineId(MCID_LOCAL);
  1826. Normalize();
  1827. AssertValid();
  1828. } // if (wszCurrentUser[ pUserName->Length / sizeof(WCHAR) - 1] != L'$')
  1829. else
  1830. {
  1831. // We don't need to be impersonating any longer, potentially (though
  1832. // not likely) ACLs on the SAM could prevent the impersonated user
  1833. // from making this call. So we might as well revert now.
  1834. TrkAssert( fImpersonating );
  1835. if( fImpersonating )
  1836. {
  1837. RpcRevertToSelf();
  1838. fImpersonating = FALSE;
  1839. }
  1840. // Get account info for this user, so we can
  1841. // verify that it's a machine account.
  1842. NetStatus = NetUserGetInfo( NULL, // Check on this server
  1843. wszCurrentUser,
  1844. 1, // Get USER_INFO_1
  1845. &pbAccountInfo );
  1846. if (NetStatus != 0)
  1847. {
  1848. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get user %s info (%08x)"),
  1849. wszCurrentUser,
  1850. NetStatus));
  1851. TrkRaiseWin32Error(NetStatus);
  1852. }
  1853. TrkLog(( TRKDBG_SVR, TEXT("\nUser is %s"), wszCurrentUser));
  1854. if ((((USER_INFO_1*)pbAccountInfo)->usri1_flags &
  1855. (UF_WORKSTATION_TRUST_ACCOUNT | UF_SERVER_TRUST_ACCOUNT)) == 0)
  1856. {
  1857. // if the account is not a workstation or backup dc account, fail
  1858. TrkRaiseException( TRK_E_CALLER_NOT_MACHINE_ACCOUNT );
  1859. }
  1860. // overwrite the $
  1861. wszCurrentUser[ pUserName->Length / sizeof(WCHAR) - 1] = L'\0';
  1862. if (_tcslen(wszCurrentUser) + 1 > sizeof(_szMachine))
  1863. TrkRaiseException(TRK_E_IMPERSONATED_COMPUTERNAME_TOO_LONG);
  1864. else if( TEXT('\0') == wszCurrentUser[0] )
  1865. TrkRaiseException( TRK_E_NULL_COMPUTERNAME );
  1866. memset(&_szMachine, 0, sizeof(_szMachine));
  1867. // Convert the Unicode computer name into Ansi, using
  1868. // the OEMCP codepage (NetBios/computer names are always
  1869. // in OEMCP, not Window/Ansi).
  1870. if( 0 == WideCharToMultiByte( CP_OEMCP, 0,
  1871. wszCurrentUser,
  1872. -1,
  1873. _szMachine,
  1874. sizeof(_szMachine),
  1875. NULL, NULL ))
  1876. {
  1877. TrkLog(( TRKDBG_ERROR,
  1878. TEXT("Couldn't convert machine name %s to multi-byte (%lu)"),
  1879. wszCurrentUser, GetLastError() ));
  1880. TrkRaiseLastError();
  1881. }
  1882. TrkLog(( TRKDBG_WARNING,
  1883. TEXT("Converted machine name: %hs (from %s, ")
  1884. MCID_BYTE_FORMAT_STRING,
  1885. _szMachine, wszCurrentUser,
  1886. (BYTE)_szMachine[0], (BYTE)_szMachine[1], (BYTE)_szMachine[2], (BYTE)_szMachine[3],
  1887. (BYTE)_szMachine[4], (BYTE)_szMachine[5], (BYTE)_szMachine[6], (BYTE)_szMachine[7],
  1888. (BYTE)_szMachine[8], (BYTE)_szMachine[9], (BYTE)_szMachine[10], (BYTE)_szMachine[11],
  1889. (BYTE)_szMachine[12], (BYTE)_szMachine[13], (BYTE)_szMachine[14], (BYTE)_szMachine[15] ));
  1890. Normalize();
  1891. AssertValid();
  1892. } // if (wszCurrentUser[ pUserName->Length / ... else
  1893. }
  1894. __finally
  1895. {
  1896. if( fImpersonating )
  1897. {
  1898. RpcRevertToSelf();
  1899. fImpersonating = FALSE;
  1900. }
  1901. if (hToken != NULL)
  1902. {
  1903. CloseHandle(hToken);
  1904. }
  1905. if (pbToken != NULL)
  1906. {
  1907. delete [] pbToken;
  1908. }
  1909. if (LocalSystemSid != NULL)
  1910. {
  1911. FreeSid( LocalSystemSid );
  1912. }
  1913. if (pUserName != NULL)
  1914. {
  1915. LsaFreeMemory(pUserName->Buffer);
  1916. LsaFreeMemory(pUserName);
  1917. }
  1918. if (pUserDomainName != NULL)
  1919. {
  1920. LsaFreeMemory(pUserDomainName->Buffer);
  1921. LsaFreeMemory(pUserDomainName);
  1922. }
  1923. if (pbAccountInfo != NULL)
  1924. {
  1925. NetApiBufferFree(pbAccountInfo);
  1926. }
  1927. if( NULL != pwszDomain )
  1928. NetApiBufferFree(pwszDomain);
  1929. }
  1930. }