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.

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