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.

1254 lines
35 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. //
  6. // File: common.cxx
  7. //
  8. // Contents: Code common to Tracking (Workstation) Service and
  9. // Tracking (Server) Service.
  10. //
  11. // Classes:
  12. //
  13. // Functions:
  14. //
  15. //
  16. //
  17. // History: 18-Nov-96 BillMo Created.
  18. //
  19. // Notes:
  20. //
  21. // Codework:
  22. //
  23. //--------------------------------------------------------------------------
  24. #include <pch.cxx>
  25. #pragma hdrstop
  26. #include "trklib.hxx"
  27. #include "ntlsa.h" // LsaGetUserName
  28. #if MAX_COMPUTERNAME_LENGTH != 15
  29. #error MAX_COMPUTERNAME_LENGTH assumed to be 15
  30. #endif
  31. //DWORD g_ftIndex;
  32. const TCHAR s_HexGuidString[] = TEXT("%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X");
  33. #define CCH_HEXGUID_STRING (8+4+4+2*8)
  34. EXTERN_C const CLSID CLSID_TrackFile = {0x8790c947, 0xa30b, 0x11d0, {0x8c, 0xab, 0x00, 0xc0, 0x4f, 0xd9, 0x0f, 0x85} };
  35. #if DBG
  36. #define TRK_E_ERROR_MAP(tr,hr) { tr, hr, TEXT(#tr) }
  37. #else
  38. #define TRK_E_ERROR_MAP(tr,hr) { tr, hr }
  39. #endif
  40. // Map of TRK_E_ type error codes to HRESULTs, and in the debug build to strings.
  41. const TrkEMap g_TrkEMap[] =
  42. {
  43. TRK_E_ERROR_MAP(TRK_S_OUT_OF_SYNC, HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR) ),
  44. TRK_E_ERROR_MAP(TRK_E_CORRUPT_LOG, HRESULT_FROM_WIN32(ERROR_INTERNAL_DB_CORRUPTION) ),
  45. TRK_E_ERROR_MAP(TRK_E_TIMER_REGISTRY_CORRUPT, HRESULT_FROM_WIN32(ERROR_REGISTRY_CORRUPT) ),
  46. TRK_E_ERROR_MAP(TRK_E_REGISTRY_REFRESH_CORRUPT, HRESULT_FROM_WIN32(ERROR_REGISTRY_CORRUPT) ),
  47. TRK_E_ERROR_MAP(TRK_E_CORRUPT_IDT, HRESULT_FROM_WIN32(ERROR_INTERNAL_DB_CORRUPTION) ),
  48. TRK_E_ERROR_MAP(TRK_E_DB_CONNECT_ERROR, HRESULT_FROM_WIN32(ERROR_INTERNAL_DB_CORRUPTION) ),
  49. TRK_E_ERROR_MAP(TRK_E_DN_TOO_LONG, CO_E_PATHTOOLONG ),
  50. TRK_E_ERROR_MAP(TRK_E_DOMAIN_COMPUTER_NAMES_TOO_LONG, HRESULT_FROM_WIN32(ERROR_INVALID_COMPUTERNAME) ),
  51. TRK_E_ERROR_MAP(TRK_E_BAD_USERNAME_NO_SLASH, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) ),
  52. TRK_E_ERROR_MAP(TRK_E_UNKNOWN_SID, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) ),
  53. TRK_E_ERROR_MAP(TRK_E_IMPERSONATED_COMPUTERNAME_TOO_LONG, HRESULT_FROM_WIN32(ERROR_INVALID_COMPUTERNAME) ),
  54. TRK_E_ERROR_MAP(TRK_E_UNKNOWN_SVR_MESSAGE_TYPE, HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR) ),
  55. TRK_E_ERROR_MAP(TRK_E_FAIL_TEST, E_FAIL ),
  56. TRK_E_ERROR_MAP(TRK_E_DENIAL_OF_SERVICE_ATTACK, HRESULT_FROM_WIN32(ERROR_RETRY) ),
  57. TRK_E_ERROR_MAP(TRK_E_SERVICE_NOT_RUNNING, HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) ),
  58. TRK_E_ERROR_MAP(TRK_E_TOO_MANY_UNSHORTENED_NOTIFICATIONS, HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) ),
  59. TRK_E_ERROR_MAP(TRK_E_CORRUPT_CLNTSYNC, HRESULT_FROM_WIN32(ERROR_INTERNAL_DB_CORRUPTION) ),
  60. TRK_E_ERROR_MAP(TRK_E_COMPUTER_NAME_TOO_LONG, HRESULT_FROM_WIN32(ERROR_INVALID_COMPUTERNAME) ),
  61. TRK_E_ERROR_MAP(TRK_E_SERVICE_STOPPING, HRESULT_FROM_WIN32(ERROR_NO_TRACKING_SERVICE) ),
  62. TRK_E_ERROR_MAP(TRK_E_BIRTHIDS_DONT_MATCH, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) ),
  63. TRK_E_ERROR_MAP(TRK_E_CORRUPT_VOLTAB, HRESULT_FROM_WIN32(ERROR_INTERNAL_DB_CORRUPTION) ),
  64. TRK_E_ERROR_MAP(TRK_E_INTERNAL_ERROR, HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR) ),
  65. TRK_E_ERROR_MAP(TRK_E_PATH_TOO_LONG, CO_E_PATHTOOLONG ),
  66. TRK_E_ERROR_MAP(TRK_E_GET_MACHINE_NAME_FAIL, HRESULT_FROM_WIN32(ERROR_INVALID_COMPUTERNAME) ),
  67. TRK_E_ERROR_MAP(TRK_E_SET_VOLUME_STATE_FAIL, HRESULT_FROM_WIN32(ERROR_INTERNAL_DB_CORRUPTION) ),
  68. TRK_E_ERROR_MAP(TRK_E_VOLUME_ACCESS_DENIED, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) ),
  69. TRK_E_ERROR_MAP(TRK_S_VOLUME_NOT_FOUND, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) ),
  70. TRK_E_ERROR_MAP(TRK_S_VOLUME_NOT_OWNED, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) ),
  71. TRK_E_ERROR_MAP(TRK_E_REFERRAL, HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR) ),
  72. TRK_E_ERROR_MAP(TRK_E_NOT_FOUND, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ),
  73. TRK_E_ERROR_MAP(TRK_E_UNAVAILABLE, HRESULT_FROM_WIN32(ERROR_CONNECTION_UNAVAIL) ),
  74. TRK_E_ERROR_MAP(TRK_E_TIMEOUT, HRESULT_FROM_WIN32(ERROR_SERVICE_REQUEST_TIMEOUT) ),
  75. TRK_E_ERROR_MAP(TRK_E_VOLUME_QUOTA_EXCEEDED, HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_QUOTA) ),
  76. TRK_E_ERROR_MAP(TRK_S_NOTIFICATION_QUOTA_EXCEEDED, HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_QUOTA) ),
  77. TRK_E_ERROR_MAP(TRK_E_SERVER_TOO_BUSY, HRESULT_FROM_WIN32(RPC_S_SERVER_TOO_BUSY) ),
  78. TRK_E_ERROR_MAP(TRK_E_INVALID_VOLUME_ID, HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR) ),
  79. TRK_E_ERROR_MAP(TRK_E_POTENTIAL_FILE_FOUND, HRESULT_FROM_WIN32(ERROR_POTENTIAL_FILE_FOUND) ),
  80. TRK_E_ERROR_MAP(TRK_E_NULL_COMPUTERNAME, HRESULT_FROM_WIN32(ERROR_INVALID_COMPUTERNAME) ),
  81. TRK_E_ERROR_MAP(TRK_E_NOT_FOUND_AND_LAST_VOLUME_NOT_FOUND, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ),
  82. TRK_E_ERROR_MAP(TRK_E_NOT_FOUND_BUT_LAST_VOLUME_FOUND, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) )
  83. };
  84. //+----------------------------------------------------------------------------
  85. //
  86. // Function: GetErrorString
  87. //
  88. // Synopsis: Map an TRK_E_ error to a descriptive string.
  89. //
  90. //+----------------------------------------------------------------------------
  91. #if DBG
  92. const TCHAR * GetErrorString(HRESULT hr)
  93. {
  94. ULONG iError;
  95. if( S_OK == hr )
  96. return( TEXT("S_OK") );
  97. for( iError = 0; iError < sizeof(g_TrkEMap)/sizeof(*g_TrkEMap); iError++ )
  98. {
  99. if( g_TrkEMap[iError].tr == hr )
  100. return( g_TrkEMap[iError].ptszDescription );
  101. }
  102. return( TEXT("Not a TRK_E_ error") );
  103. }
  104. #endif
  105. //+----------------------------------------------------------------------------
  106. //
  107. // Function: MapTR2HR
  108. //
  109. // Synopsis: Map a TRK_E_ type error code to an HRESULT. If the input is
  110. // already a non-trk HRESULT, the input will be returned unchanged.
  111. //
  112. //+----------------------------------------------------------------------------
  113. HRESULT MapTR2HR( HRESULT tr )
  114. {
  115. ULONG iError;
  116. HRESULT hr = tr;
  117. if( S_OK == hr )
  118. return( hr );
  119. // Convert TRK_E_ error codes into an HRESULT
  120. for( iError = 0; iError < sizeof(g_TrkEMap)/sizeof(*g_TrkEMap); iError++ )
  121. {
  122. if( g_TrkEMap[iError].tr == hr )
  123. {
  124. hr = g_TrkEMap[iError].hr;
  125. break;
  126. }
  127. }
  128. // If this HRESULT is actually an NTSTATUS, then convert it to a Win32
  129. // error, then back to an HRESULT.
  130. if( FACILITY_NT_BIT & hr )
  131. {
  132. if( STATUS_VOLUME_NOT_UPGRADED == hr )
  133. hr = HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  134. else
  135. hr = HRESULT_FROM_WIN32( RtlNtStatusToDosError(hr & ~FACILITY_NT_BIT) );
  136. }
  137. return( hr );
  138. }
  139. //+----------------------------------------------------------------------------
  140. //
  141. // HexStringizeGuid
  142. //
  143. // Optimized conversion from a GUID to a string.
  144. //
  145. //+----------------------------------------------------------------------------
  146. inline void
  147. HexStringizeByte( BYTE b, TCHAR* &rptsz )
  148. {
  149. static const TCHAR _tszLookup[] = { TEXT("0123456789ABCDEF") };
  150. *rptsz++ = _tszLookup[ b >> 4 ];
  151. *rptsz++ = _tszLookup[ b & 0xF ];
  152. }
  153. void
  154. HexStringizeGuid(const GUID &g, TCHAR * & rptsz)
  155. {
  156. HexStringizeByte( HIGH_BYTE(HIGH_WORD(g.Data1)), rptsz );
  157. HexStringizeByte( LO_BYTE(HIGH_WORD(g.Data1)), rptsz );
  158. HexStringizeByte( HIGH_BYTE(LO_WORD(g.Data1)), rptsz );
  159. HexStringizeByte( LO_BYTE(LO_WORD(g.Data1)), rptsz );
  160. HexStringizeByte( HIGH_BYTE(g.Data2), rptsz );
  161. HexStringizeByte( LO_BYTE(g.Data2), rptsz );
  162. HexStringizeByte( HIGH_BYTE(g.Data3), rptsz );
  163. HexStringizeByte( LO_BYTE(g.Data3), rptsz );
  164. for( int i = 0; i < sizeof(g.Data4); i++ )
  165. HexStringizeByte( g.Data4[i], rptsz );
  166. *rptsz = TEXT('\0');
  167. }
  168. //+----------------------------------------------------------------------------
  169. //
  170. // HexUnstringizeGuid
  171. //
  172. // Convert a string to a GUID. This is not used as often as HexStringizeGuid,
  173. // so it uses the CRT.
  174. //
  175. //+----------------------------------------------------------------------------
  176. BOOL
  177. HexUnstringizeGuid(const TCHAR * &ptsz, GUID * pg)
  178. {
  179. DWORD Data1;
  180. DWORD Data2;
  181. DWORD Data3;
  182. DWORD Data40;
  183. DWORD Data41;
  184. DWORD Data42;
  185. DWORD Data43;
  186. DWORD Data44;
  187. DWORD Data45;
  188. DWORD Data46;
  189. DWORD Data47;
  190. if( 11 != _stscanf( ptsz,
  191. s_HexGuidString,
  192. &Data1,
  193. &Data2,
  194. &Data3,
  195. &Data40,
  196. &Data41,
  197. &Data42,
  198. &Data43,
  199. &Data44,
  200. &Data45,
  201. &Data46,
  202. &Data47))
  203. {
  204. return( FALSE );
  205. }
  206. pg->Data1 = Data1;
  207. pg->Data2 = (WORD)Data2;
  208. pg->Data3 = (WORD)Data3;
  209. pg->Data4[0] = (BYTE)Data40;
  210. pg->Data4[1] = (BYTE)Data41;
  211. pg->Data4[2] = (BYTE)Data42;
  212. pg->Data4[3] = (BYTE)Data43;
  213. pg->Data4[4] = (BYTE)Data44;
  214. pg->Data4[5] = (BYTE)Data45;
  215. pg->Data4[6] = (BYTE)Data46;
  216. pg->Data4[7] = (BYTE)Data47;
  217. ptsz += CCH_HEXGUID_STRING;
  218. return( TRUE );
  219. }
  220. TCHAR *
  221. wcstotcs(TCHAR *ptszBuf, const WCHAR *pwsz)
  222. {
  223. #ifdef UNICODE
  224. wcscpy(ptszBuf, pwsz);
  225. #else
  226. wcstombs(ptszBuf, pwsz, (wcslen(pwsz)+1)*sizeof(WCHAR));
  227. #endif
  228. return(ptszBuf);
  229. }
  230. CHAR *
  231. tcstombs(CHAR *pszBuf, const TCHAR *ptsz)
  232. {
  233. #ifdef UNICODE
  234. wcstombs(pszBuf, ptsz, (_tcslen(ptsz)+1)*sizeof(CHAR));
  235. #else
  236. strcpy(pszBuf, ptsz);
  237. #endif
  238. return(pszBuf);
  239. }
  240. WCHAR *
  241. tcstowcs(WCHAR *pwszBuf, const TCHAR *ptsz)
  242. {
  243. #ifdef UNICODE
  244. wcscpy(pwszBuf, ptsz);
  245. #else
  246. mbstowcs(pwszBuf, ptsz, (_tcslen(ptsz)+1)*sizeof(WCHAR));
  247. #endif
  248. return(pwszBuf);
  249. }
  250. TCHAR *
  251. mbstotcs(TCHAR *ptszBuf, const CHAR *psz)
  252. {
  253. #ifdef UNICODE
  254. mbstowcs(ptszBuf, psz, (strlen(psz)+1)*sizeof(WCHAR));
  255. #else
  256. _tcscpy(ptszBuf, psz);
  257. #endif
  258. return(ptszBuf);
  259. }
  260. DWORD
  261. TrkTimeUnits(const SYSTEMTIME &st)
  262. {
  263. CFILETIME cft( st );
  264. // 2**32 * 100e-9 = 429.4967296 seconds
  265. //
  266. // 32bit int can last 1844674407371 seconds = 58494.24173551 years
  267. return( cft.HighDateTime() );
  268. }
  269. DWORD
  270. TrkTimeUnits(const CFILETIME &cft)
  271. {
  272. // 2**32 * 100e-9 = 429.4967296 seconds
  273. //
  274. // 32bit int can last 1844674407371 seconds = 58494.24173551 years
  275. return( cft.HighDateTime() );
  276. }
  277. #if DBG
  278. void
  279. CMachineId::AssertValid()
  280. {
  281. }
  282. #endif // #if DBG
  283. //+----------------------------------------------------------------------------
  284. //
  285. // CMachineId::CMachineId( ptsz )
  286. //
  287. // Instantiate a mcid from a computer name, e.g. "mymachine".
  288. //
  289. //+----------------------------------------------------------------------------
  290. CMachineId::CMachineId(const TCHAR * ptszPath)
  291. {
  292. HRESULT hr = E_FAIL;
  293. int nReturn;
  294. // Zero everything out first
  295. new(this) CMachineId;
  296. // Ensure that this isn't a real path, it should
  297. // have been pre-processed already.
  298. TrkAssert( _tcslen(ptszPath) < 2
  299. ||
  300. ( TEXT('\\') != ptszPath[0]
  301. &&
  302. TEXT(':') != ptszPath[1]
  303. )
  304. );
  305. // Ensure that it's not too long.
  306. if (_tcslen(ptszPath) > MAX_COMPUTERNAME_LENGTH )
  307. TrkRaiseException( TRK_E_COMPUTER_NAME_TOO_LONG );
  308. #ifndef _UNICODE
  309. #error Ansi build not supported.
  310. #endif
  311. // Convert the Unicode machine name into Ansi, using
  312. // the OEM code page (the netbios/computer name is always
  313. // OEM code page, not the Windows Ansi code page).
  314. nReturn = WideCharToMultiByte( CP_OEMCP, 0,
  315. ptszPath, -1,
  316. _szMachine, sizeof(_szMachine),
  317. NULL, NULL );
  318. if( 0 == nReturn )
  319. TrkRaiseLastError();
  320. TrkLog(( TRKDBG_WARNING, TEXT("Machine name is: %hs (from %s)"),
  321. _szMachine, ptszPath ));
  322. Normalize(); // Guarantee a terminator
  323. }
  324. //+----------------------------------------------------------------------------
  325. //
  326. // CMachineId::CMachineId( type )
  327. //
  328. // Initialize an mcid. The type indicates if the mcid should be for the
  329. // local computer, a DC (possibly doing a rediscovery), or invalid.
  330. //
  331. //+----------------------------------------------------------------------------
  332. CMachineId::CMachineId(MCID_CREATE_TYPE type)
  333. {
  334. DWORD dwSize = MAX_COMPUTERNAME_LENGTH+1;
  335. CHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
  336. int nReturn;
  337. TrkAssert(type == MCID_LOCAL ||
  338. type == MCID_INVALID ||
  339. type == MCID_DOMAIN ||
  340. type == MCID_DOMAIN_REDISCOVERY ||
  341. type == MCID_PDC_REQUIRED);
  342. // Basic initialization
  343. new(this) CMachineId;
  344. if (type == MCID_INVALID)
  345. goto Exit;
  346. switch (type)
  347. {
  348. case MCID_LOCAL:
  349. {
  350. WCHAR wszComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  351. // Create an MCID of the local machine
  352. // We can't call GetComputerNameA, because it uses
  353. // RtlUnicodeStringToAnsiString and consequently returns
  354. // a Windows/Ansi string, when it should be returning an
  355. // OEM string.
  356. if (!GetComputerNameW(wszComputerName, &dwSize))
  357. TrkRaiseException(HRESULT_FROM_WIN32(GetLastError()));
  358. nReturn = WideCharToMultiByte( CP_OEMCP, 0,
  359. wszComputerName, -1,
  360. szComputerName, sizeof(szComputerName),
  361. NULL, NULL );
  362. if( 0 == nReturn )
  363. TrkRaiseLastError();
  364. }
  365. break;
  366. case MCID_DOMAIN:
  367. case MCID_DOMAIN_REDISCOVERY:
  368. case MCID_PDC_REQUIRED:
  369. // Create an MCID for a DC
  370. DWORD dwErr;
  371. PDOMAIN_CONTROLLER_INFOW pdci;
  372. // DsGetDcName gets us the appropriate DC computer name
  373. // (of the form \\machine). We call the W version
  374. // because the A version returns an Ansi string,
  375. // rather than an OEM string.
  376. dwErr = DsGetDcNameW(NULL, NULL, NULL, NULL,
  377. DS_RETURN_FLAT_NAME |
  378. DS_BACKGROUND_ONLY |
  379. DS_DIRECTORY_SERVICE_REQUIRED |
  380. DS_WRITABLE_REQUIRED |
  381. (type == MCID_DOMAIN_REDISCOVERY ?
  382. DS_FORCE_REDISCOVERY : 0 ) |
  383. (type == MCID_PDC_REQUIRED ?
  384. DS_PDC_REQUIRED : 0 ),
  385. &pdci);
  386. if (dwErr != NO_ERROR)
  387. {
  388. TrkRaiseWin32Error(dwErr);
  389. }
  390. // Validate the returned name.
  391. TrkAssert(pdci->DomainControllerName &&
  392. pdci->DomainControllerName[0] == L'\\' &&
  393. pdci->DomainControllerName[1] == L'\\');
  394. dwSize = wcslen(pdci->DomainControllerName + 2);
  395. if ( dwSize + 1 > sizeof(_szMachine))
  396. {
  397. NetApiBufferFree(pdci);
  398. TrkRaiseException(HRESULT_FROM_WIN32(ERROR_INVALID_NAME));
  399. }
  400. // Keep the returned name.
  401. nReturn = WideCharToMultiByte( CP_OEMCP, 0,
  402. &pdci->DomainControllerName[2], -1,
  403. _szMachine, sizeof(_szMachine),
  404. NULL, NULL );
  405. if( 0 == nReturn )
  406. TrkRaiseLastError();
  407. NetApiBufferFree(pdci);
  408. goto Exit;
  409. } // switch
  410. if (dwSize + 1 <= sizeof(_szMachine))
  411. {
  412. strcpy(_szMachine, szComputerName);
  413. Normalize();
  414. }
  415. else
  416. {
  417. TrkRaiseException(HRESULT_FROM_WIN32(ERROR_INVALID_NAME));
  418. }
  419. Exit:
  420. Normalize(); // Guarantee a terminator
  421. return;
  422. }
  423. #ifndef UNICODE
  424. extern "C"
  425. NET_API_STATUS
  426. NetpGetDomainName (
  427. IN LPWSTR *ComputerNamePtr);
  428. #endif
  429. //+----------------------------------------------------------------------------
  430. //
  431. // CMachineId::GetLocalAuthName
  432. //
  433. // Returns the authentication name for use in secure RPC (to be used in
  434. // the RpcBindingSetAuthInfo on the server). The name
  435. // is of the form DOMAIN\MACHINE$, where DOMAIN is the local domain
  436. // and MACHINE is the contents of this CMachineId
  437. //
  438. //+----------------------------------------------------------------------------
  439. void
  440. CMachineId::GetLocalAuthName(RPC_TCHAR * ptszAuthName, DWORD cchBuf) const
  441. {
  442. // To get domain name: if you link to netlib.lib, you can call NetpGetDomainName,
  443. // which does all the work for you. Or you could copy the code
  444. // from \nt\private\net\netlib\domname.c
  445. NET_API_STATUS Status;
  446. WCHAR * pwszDomain;
  447. DWORD dwErr;
  448. PDOMAIN_CONTROLLER_INFOA pdci = NULL;
  449. __try
  450. {
  451. // Get the domain name ...
  452. Status = NetpGetDomainName(&pwszDomain);
  453. if (Status != NO_ERROR)
  454. {
  455. pwszDomain = NULL;
  456. TrkRaiseWin32Error(Status);
  457. }
  458. // and validate it.
  459. if (cchBuf < wcslen(pwszDomain) + 1 + strlen(_szMachine) + 1 + 1)
  460. {
  461. TrkRaiseException(TRK_E_DOMAIN_COMPUTER_NAMES_TOO_LONG);
  462. }
  463. // Copy the domain name then the machine name into the return buffer.
  464. wcstotcs((TCHAR*)ptszAuthName, pwszDomain);
  465. _tcscat((TCHAR*)ptszAuthName, TEXT("\\"));
  466. mbstotcs(_tcschr((TCHAR*)ptszAuthName, 0), _szMachine);
  467. _tcscat((TCHAR*)ptszAuthName, TEXT("$"));
  468. }
  469. __finally
  470. {
  471. if (pwszDomain != NULL)
  472. {
  473. NetApiBufferFree(pwszDomain);
  474. }
  475. }
  476. }
  477. //+----------------------------------------------------------------------------
  478. //
  479. // GetFileTimeNow
  480. //
  481. // Get the current FILETIME (UTC).
  482. //
  483. //+----------------------------------------------------------------------------
  484. FILETIME GetFileTimeNow()
  485. {
  486. SYSTEMTIME st;
  487. FILETIME ft;
  488. GetSystemTime(&st);
  489. SystemTimeToFileTime(&st, &ft);
  490. return(ft);
  491. }
  492. //+----------------------------------------------------------------------------
  493. //
  494. // CDomainRelativeObjId::Stringize
  495. //
  496. // Stringize a droid.
  497. //
  498. //+----------------------------------------------------------------------------
  499. TCHAR *
  500. CDomainRelativeObjId::Stringize( TCHAR * ptszOutBuf, DWORD cchBuf ) const
  501. {
  502. TCHAR *ptszBuf = ptszOutBuf;
  503. _volume.Stringize(ptszBuf); /*in, out, c++ reference*/
  504. _object.Stringize(ptszBuf); /*in, out, c++ reference*/
  505. TrkAssert(_tcslen(ptszOutBuf) + 1 < cchBuf);
  506. return(ptszOutBuf);
  507. }
  508. //+----------------------------------------------------------------------------
  509. //
  510. // CTrkRegistryKey::Delete
  511. //
  512. // Common code to delete a registry key, relative to _hkey.
  513. //
  514. //+----------------------------------------------------------------------------
  515. LONG
  516. CTrkRegistryKey::Delete( const TCHAR *ptszName )
  517. {
  518. LONG lRet = 0;
  519. _cs.Enter();
  520. __try
  521. {
  522. // Open _hkey if it's not already.
  523. lRet = Open();
  524. // And delete the value
  525. if( ERROR_SUCCESS == lRet )
  526. {
  527. RegDeleteValue( _hkey, ptszName );
  528. Close();
  529. }
  530. }
  531. __finally
  532. {
  533. _cs.Leave();
  534. }
  535. return( lRet );
  536. }
  537. //+----------------------------------------------------------------------------
  538. //
  539. // CTrkRegistryKey::SetDword
  540. //
  541. // Set a REG_DWORD value under _hkey.
  542. //
  543. //+---------------------------------------------------------------------------0
  544. LONG
  545. CTrkRegistryKey::SetDword( const TCHAR *ptszName, DWORD dw )
  546. {
  547. LONG lRet = 0;
  548. _cs.Enter();
  549. __try
  550. {
  551. // Open _hkey if it's not already
  552. lRet = Open();
  553. // And set the value
  554. if ( ERROR_SUCCESS == lRet )
  555. {
  556. lRet = RegSetValueEx( _hkey,
  557. ptszName,
  558. 0,
  559. REG_DWORD,
  560. reinterpret_cast<CONST BYTE *>(&dw),
  561. sizeof(dw) );
  562. if( ERROR_SUCCESS != lRet )
  563. {
  564. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't set registry value for %s (%lu)"),
  565. ptszName, lRet ));
  566. RegDeleteKey( _hkey, ptszName );
  567. }
  568. Close();
  569. }
  570. }
  571. __finally
  572. {
  573. _cs.Leave();
  574. }
  575. return( lRet );
  576. }
  577. //+----------------------------------------------------------------------------
  578. //
  579. // CTrkRegistryKey::GetDword
  580. //
  581. // Get a REG_DWORD value from _hkey.
  582. //
  583. //+---------------------------------------------------------------------------0
  584. LONG
  585. CTrkRegistryKey::GetDword( const TCHAR *ptszName, DWORD *pdwRead, DWORD dwDefault )
  586. {
  587. LONG lRet;
  588. DWORD dwRead;
  589. DWORD cbData = sizeof(*pdwRead);
  590. DWORD dwType;
  591. *pdwRead = dwDefault;
  592. _cs.Enter();
  593. __try
  594. {
  595. // Open _hkey if it's not already.
  596. lRet = Open();
  597. if( ERROR_SUCCESS != lRet )
  598. __leave;
  599. // Get the DWORD
  600. lRet = RegQueryValueEx( _hkey, ptszName, 0, &dwType,
  601. reinterpret_cast<BYTE*>(&dwRead), &cbData );
  602. if( ERROR_SUCCESS == lRet )
  603. {
  604. // Validate the type
  605. if( REG_DWORD != dwType || sizeof(dwRead) != cbData )
  606. {
  607. TrkLog(( TRKDBG_ERROR, TEXT("Wrong type/size (%d/%d) for registry value %s"),
  608. dwType, cbData, ptszName ));
  609. RegDeleteKey( _hkey, ptszName );
  610. }
  611. else
  612. {
  613. *pdwRead = dwRead;
  614. }
  615. }
  616. else if( ERROR_FILE_NOT_FOUND == lRet
  617. ||
  618. ERROR_PATH_NOT_FOUND == lRet )
  619. {
  620. lRet = ERROR_SUCCESS;
  621. }
  622. else
  623. {
  624. TrkLog(( TRKDBG_ERROR,
  625. TEXT("Couldn't read %s from registry (%lu)"), ptszName, lRet ));
  626. RegDeleteKey( _hkey, ptszName );
  627. __leave;
  628. }
  629. }
  630. __finally
  631. {
  632. Close();
  633. _cs.Leave();
  634. }
  635. return( lRet );
  636. }
  637. //+----------------------------------------------------------------------------
  638. //
  639. // ThreadPoolCallbackFunction
  640. //
  641. // This function is passed as the callback function to
  642. // RegisterWaitForSingleObjectEx. The context is a PWorkItem pointer.
  643. //
  644. // Arguments:
  645. // [pvWorkItem]
  646. // The Context parameter from RegisterWaitForSingleObjectEx.
  647. // Is a PWorkItem*
  648. // [fTimeout]
  649. // We always register INFINITE as the timeout, so this value
  650. // should always be FALSE.
  651. //
  652. //+----------------------------------------------------------------------------
  653. VOID NTAPI
  654. ThreadPoolCallbackFunction( PVOID pvWorkItem, BOOLEAN fTimeout )
  655. {
  656. SThreadFromPoolState state;
  657. PWorkItem *pWorkItem = reinterpret_cast<PWorkItem*>(pvWorkItem);
  658. TrkLog(( TRKDBG_WORKMAN, TEXT("Enter ThreadPoolCallbackFunction for %s (%p/%p)"),
  659. pWorkItem->_tszWorkItemSig, pWorkItem, *reinterpret_cast<UINT_PTR*>(pWorkItem) ));
  660. TrkAssert( FALSE == fTimeout );
  661. // Make sure we never raise back into the thread pool.
  662. __try
  663. {
  664. // Update thread-count stats. Note that this isn't
  665. // thread-safe, but for private statistics it's not worth
  666. // creating a critsec.
  667. InterlockedIncrement( reinterpret_cast<LONG*>(&g_cThreadPoolThreads) );
  668. if( g_cThreadPoolThreads > g_cThreadPoolMaxThreads )
  669. g_cThreadPoolMaxThreads = g_cThreadPoolThreads;
  670. // Set our necessary thread-specific settings
  671. state = InitializeThreadFromPool();
  672. // Process the signal
  673. pWorkItem->DoWork();
  674. }
  675. __except( BREAK_THEN_RETURN( EXCEPTION_EXECUTE_HANDLER ))
  676. {
  677. TrkLog(( TRKDBG_ERROR, TEXT("Unexpected exception on thread pool callback (%08x)"),
  678. GetExceptionCode() ));
  679. }
  680. TrkLog(( TRKDBG_WORKMAN, TEXT("Exit ThreadPoolCallbackFunction for %s (%p)"),
  681. pWorkItem->_tszWorkItemSig, pWorkItem ));
  682. InterlockedDecrement( reinterpret_cast<LONG*>(&g_cThreadPoolThreads) );
  683. //IFDBG( TrkRtlCheckForOrphanedCriticalSections( GetCurrentThread() ));
  684. // Restore the original thread-specific settings
  685. UnInitializeThreadFromPool( state );
  686. }
  687. // The work item callback function (used for RtlQueueWorkItem)
  688. // just calls to the function above.
  689. VOID NTAPI
  690. ThreadPoolWorkItemFunction( PVOID pvWorkItem )
  691. {
  692. ThreadPoolCallbackFunction( pvWorkItem, FALSE );
  693. }
  694. //+----------------------------------------------------------------------------
  695. //
  696. // RunningAsAdministratorHack
  697. //
  698. // This routine is only used by test/debug hooks. It checks to see if
  699. // the thread is running as an administrative user by seeing if we can
  700. // get write access to the service's parameters key in the registry.
  701. //
  702. //+----------------------------------------------------------------------------
  703. BOOL
  704. RunningAsAdministratorHack()
  705. {
  706. LONG lResult = 0;
  707. HKEY hkey = NULL;
  708. BOOL fReturn = FALSE;
  709. lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  710. s_tszKeyNameLinkTrack,
  711. 0, // Options, reserved must be zero
  712. KEY_ALL_ACCESS,
  713. &hkey );
  714. if( ERROR_SUCCESS == lResult )
  715. {
  716. fReturn = TRUE;
  717. RegCloseKey( hkey );
  718. }
  719. return( fReturn );
  720. }
  721. //+----------------------------------------------------------------------------
  722. //
  723. // EnablePrivilege
  724. //
  725. // Enable the specified privielge in the current access token if
  726. // it is available.
  727. //
  728. //+----------------------------------------------------------------------------
  729. BOOL
  730. EnablePrivilege( const TCHAR *ptszPrivilegeName )
  731. {
  732. BOOL fSuccess = FALSE;
  733. HANDLE hToken = INVALID_HANDLE_VALUE;
  734. LUID luid;
  735. TOKEN_PRIVILEGES token_privileges;
  736. // Get the process token.
  737. if( !OpenProcessToken( GetCurrentProcess(),
  738. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  739. &hToken))
  740. {
  741. TrkLog(( TRKDBG_ERROR, TEXT("Failed OpenProcessToken (%lu)"), GetLastError() ));
  742. goto Exit;
  743. }
  744. // Look up the name of this privilege.
  745. if( !LookupPrivilegeValue( (LPTSTR) NULL, ptszPrivilegeName, &luid ))
  746. {
  747. TrkLog(( TRKDBG_ERROR, TEXT("Failed LookupPrivilegeValue (%lu)"), GetLastError() ));
  748. goto Exit;
  749. }
  750. // Enable the privilege.
  751. token_privileges.PrivilegeCount = 1;
  752. token_privileges.Privileges[0].Luid = luid;
  753. token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  754. AdjustTokenPrivileges( hToken, FALSE, &token_privileges, sizeof(TOKEN_PRIVILEGES),
  755. (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL);
  756. // The return value doesn't tell us anything useful. We have to check GetLastError
  757. // for ERROR_SUCCESS or ERROR_NOT_ALL_ASSIGNED.
  758. if( ERROR_SUCCESS != GetLastError() )
  759. {
  760. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't adjust process token privileges (%lu)"), GetLastError() ));
  761. goto Exit;
  762. }
  763. fSuccess = TRUE;
  764. Exit:
  765. if( INVALID_HANDLE_VALUE != hToken )
  766. CloseHandle( hToken );
  767. return( fSuccess );
  768. }
  769. #if DBG
  770. CDebugString::CDebugString(const TRKSVR_MESSAGE_TYPE MsgType)
  771. {
  772. switch(MsgType)
  773. {
  774. case old_SEARCH:
  775. _tcscpy( _tsz, TEXT("old_SEARCH") ); break;
  776. case SEARCH:
  777. _tcscpy( _tsz, TEXT("SEARCH") ); break;
  778. case MOVE_NOTIFICATION:
  779. _tcscpy( _tsz, TEXT("MOVE_NOTIFICATION") ); break;
  780. case REFRESH:
  781. _tcscpy( _tsz, TEXT("REFRESH") ); break;
  782. case SYNC_VOLUMES:
  783. _tcscpy( _tsz, TEXT("SYNC_VOLUMES") ); break;
  784. case DELETE_NOTIFY:
  785. _tcscpy( _tsz, TEXT("DELETE_NOTIFY") ); break;
  786. case STATISTICS:
  787. _tcscpy( _tsz, TEXT("STATISTICS") ); break;
  788. default:
  789. _tcscpy( _tsz, TEXT("UNKNOWN") ); break;
  790. }
  791. }
  792. #endif // #if DBG
  793. #if DBG
  794. CDebugString::CDebugString(LONG VolIndex, const PFILE_NOTIFY_INFORMATION pNotifyInfo )
  795. {
  796. TCHAR *ptsz = _tsz;
  797. _tsz[0] = TEXT('\0');
  798. switch( pNotifyInfo->Action )
  799. {
  800. case FILE_ACTION_ADDED:
  801. _tcscat( _tsz, TEXT("Added ")); break;
  802. case FILE_ACTION_REMOVED:
  803. _tcscat( _tsz, TEXT("Removed ")); break;
  804. case FILE_ACTION_MODIFIED:
  805. _tcscat( _tsz, TEXT("Modified ")); break;
  806. case FILE_ACTION_RENAMED_OLD_NAME:
  807. _tcscat( _tsz, TEXT("Rename old name ")); break;
  808. case FILE_ACTION_RENAMED_NEW_NAME:
  809. _tcscat( _tsz, TEXT("Rename new name ")); break;
  810. case FILE_ACTION_ADDED_STREAM:
  811. _tcscat( _tsz, TEXT("Added stream ")); break;
  812. case FILE_ACTION_REMOVED_STREAM:
  813. _tcscat( _tsz, TEXT("Removed stream ")); break;
  814. case FILE_ACTION_MODIFIED_STREAM:
  815. _tcscat( _tsz, TEXT("Modified stream ")); break;
  816. case FILE_ACTION_REMOVED_BY_DELETE:
  817. _tcscat( _tsz, TEXT("Removed by delete ")); break;
  818. case FILE_ACTION_ID_NOT_TUNNELLED:
  819. _tcscat( _tsz, TEXT("OID not tunnelled ")); break;
  820. case FILE_ACTION_TUNNELLED_ID_COLLISION:
  821. _tcscat( _tsz, TEXT("OID tunnel collision ")); break;
  822. default:
  823. _stprintf( _tsz, TEXT("Unknown action (0x%x)"), pNotifyInfo->Action ); break;
  824. }
  825. ptsz = _tsz + _tcslen(_tsz);
  826. // The name length for an object ID is always 72
  827. if( pNotifyInfo->FileNameLength != 72 )
  828. _stprintf( ptsz, TEXT(" name length=%d"), pNotifyInfo->FileNameLength );
  829. else
  830. {
  831. // Stringize the path of this object ID
  832. CDomainRelativeObjId droidBirth;
  833. CObjId objid( FOI_OBJECTID, *(FILE_OBJECTID_INFORMATION*)pNotifyInfo->FileName );
  834. ptsz[0] = VolChar(VolIndex);
  835. ptsz[1] = TEXT(':');
  836. ptsz[2] = TEXT('\0');
  837. FindLocalPath( VolIndex, objid, &droidBirth, &ptsz[2] );
  838. ptsz += _tcslen(ptsz);
  839. ptsz += _stprintf( ptsz, TEXT(" - %c:"), VolChar(VolIndex) );
  840. _stprintf( ptsz, TEXT("%s"), CDebugString(objid)._tsz );
  841. ptsz += _tcslen(ptsz);
  842. }
  843. }
  844. #endif // #if DBG
  845. //+----------------------------------------------------------------------------
  846. //
  847. // CActiveThreadList::AddCurrent
  848. //
  849. // Add the current thread to the list of threads maintained by this class.
  850. //
  851. //+----------------------------------------------------------------------------
  852. HRESULT
  853. CActiveThreadList::AddCurrent( )
  854. {
  855. HRESULT hr = S_OK;
  856. HANDLE hThread = NULL;
  857. if( !_cs.IsInitialized() )
  858. {
  859. TrkLog(( TRKDBG_WARNING, TEXT("Active thread list critsec not initialized!!!") ));
  860. return S_OK;
  861. }
  862. _cs.Enter();
  863. if( _cActiveThreads < _cMaxThreads )
  864. {
  865. // Add the thread ID at the end of the list.
  866. _prgdwThreadIDs[ _cActiveThreads++ ] = GetCurrentThreadId();
  867. }
  868. else
  869. {
  870. // Alloc a larger buffer for the list, then add the thread ID.
  871. hr = Grow();
  872. if( SUCCEEDED(hr) )
  873. {
  874. _prgdwThreadIDs[ _cActiveThreads++ ] = GetCurrentThreadId();
  875. }
  876. }
  877. #if DBG
  878. if( SUCCEEDED(hr) )
  879. TrkLog(( TRKDBG_WORKMAN, TEXT("Added thread 0x%x to the active thread list (%d)"),
  880. GetCurrentThreadId(), _cActiveThreads ));
  881. #endif
  882. _cs.Leave();
  883. return( hr );
  884. }
  885. //+----------------------------------------------------------------------------
  886. //
  887. // CActiveThreadList::RemoveCurrent
  888. //
  889. // Remove the current thread ID from the list which is maintained by this
  890. // class.
  891. //
  892. //+----------------------------------------------------------------------------
  893. HRESULT
  894. CActiveThreadList::RemoveCurrent( )
  895. {
  896. HRESULT hr = S_OK;
  897. BOOL fFound = FALSE;
  898. DWORD dwThreadID = GetCurrentThreadId();
  899. if( !_cs.IsInitialized() )
  900. return S_OK;
  901. _cs.Enter();
  902. // Search for the current thread's ID in the list.
  903. for( ULONG i = 0; i < _cActiveThreads; i++ )
  904. {
  905. if( _prgdwThreadIDs[ i ] == dwThreadID )
  906. {
  907. // We found this thread. Remove it from the list by copying down
  908. // all the IDs behind it.
  909. memcpy( &_prgdwThreadIDs[i], &_prgdwThreadIDs[i+1],
  910. (--_cActiveThreads - i) * sizeof(_prgdwThreadIDs[0]) );
  911. _prgdwThreadIDs[ _cActiveThreads ] = 0;
  912. TrkLog(( TRKDBG_WORKMAN, TEXT("Removed thread 0x%x from the active thread list (%d)"),
  913. dwThreadID, _cActiveThreads ));
  914. fFound = TRUE;
  915. break;
  916. }
  917. }
  918. if( !fFound )
  919. {
  920. hr = E_FAIL;
  921. TrkLog(( TRKDBG_WORKMAN, TEXT("CActiveThreadList couldn't remove thread 0x%x, not found"),
  922. dwThreadID ));
  923. }
  924. _cs.Leave();
  925. return( hr );
  926. }
  927. //+----------------------------------------------------------------------------
  928. //
  929. // CActiveThreadList::CancelAllRpc
  930. //
  931. // Call RpcCancelThread on each of the threads in the list.
  932. //
  933. //+----------------------------------------------------------------------------
  934. void
  935. CActiveThreadList::CancelAllRpc()
  936. {
  937. if( !_cs.IsInitialized() )
  938. return;
  939. _cs.Enter();
  940. TrkLog(( TRKDBG_WKS|TRKDBG_SVR, TEXT("Canceling all out-going RPCs") ));
  941. // Loop through the list of threads.
  942. for( ULONG i = 0; i < _cActiveThreads; i++ )
  943. {
  944. TrkAssert( 0 != _prgdwThreadIDs[i] );
  945. // Get a thread handle for this thread ID.
  946. HANDLE hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, _prgdwThreadIDs[i] );
  947. if( NULL == hThread )
  948. {
  949. // Nothing we can do about it. Move on to the next thread.
  950. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open thread 0x%x to cancel RPC (%lu)"),
  951. _prgdwThreadIDs[i], GetLastError() ));
  952. continue;
  953. }
  954. // Cancel any out-going RPC on this thread.
  955. RPC_STATUS rpcstatus = RpcCancelThread( hThread );
  956. if( RPC_S_OK != rpcstatus )
  957. {
  958. TrkLog(( TRKDBG_ERROR, TEXT("Failed RpcCancelThread on %p/0x%x (%lu)"),
  959. hThread, _prgdwThreadIDs[i], rpcstatus ));
  960. }
  961. else
  962. {
  963. TrkLog(( TRKDBG_WORKMAN, TEXT("Canceled RPC on %p/0x%x"),
  964. hThread, _prgdwThreadIDs[i] ));
  965. }
  966. // Close the thread handle and move on.
  967. CloseHandle( hThread );
  968. }
  969. _cs.Leave();
  970. }
  971. //+----------------------------------------------------------------------------
  972. //
  973. // CActiveThreadList::Grow
  974. //
  975. // Private member function to grow the buffer used to hold the thread IDs.
  976. //
  977. //+----------------------------------------------------------------------------
  978. HRESULT
  979. CActiveThreadList::Grow()
  980. {
  981. // This is a private method, the critsec has already been entered.
  982. HRESULT hr = S_OK;
  983. DWORD *prgNew = NULL;
  984. ULONG cMaxThreads = _cMaxThreads + INCREMENT_ACTIVE_THREAD_LIST;
  985. prgNew = new DWORD[ cMaxThreads ];
  986. if( NULL == prgNew )
  987. {
  988. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't grow active thread list") ));
  989. return( E_OUTOFMEMORY );
  990. }
  991. TrkLog(( TRKDBG_WORKMAN, TEXT("Growing active thread list from %d to %d"),
  992. _cMaxThreads, cMaxThreads ));
  993. memcpy( prgNew, _prgdwThreadIDs, _cMaxThreads*sizeof(_prgdwThreadIDs[0]) );
  994. _cMaxThreads = cMaxThreads;
  995. delete [] _prgdwThreadIDs;
  996. _prgdwThreadIDs = prgNew;
  997. return( hr );
  998. }