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.

1256 lines
36 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. RaiseIfInvalid();
  443. // To get domain name: if you link to netlib.lib, you can call NetpGetDomainName,
  444. // which does all the work for you. Or you could copy the code
  445. // from \nt\private\net\netlib\domname.c
  446. NET_API_STATUS Status;
  447. WCHAR * pwszDomain;
  448. DWORD dwErr;
  449. PDOMAIN_CONTROLLER_INFOA pdci = NULL;
  450. __try
  451. {
  452. // Get the domain name ...
  453. Status = NetpGetDomainName(&pwszDomain);
  454. if (Status != NO_ERROR)
  455. {
  456. pwszDomain = NULL;
  457. TrkRaiseWin32Error(Status);
  458. }
  459. // and validate it.
  460. if (cchBuf < wcslen(pwszDomain) + 1 + strlen(_szMachine) + 1 + 1)
  461. {
  462. TrkRaiseException(TRK_E_DOMAIN_COMPUTER_NAMES_TOO_LONG);
  463. }
  464. // Copy the domain name then the machine name into the return buffer.
  465. wcstotcs((TCHAR*)ptszAuthName, pwszDomain);
  466. _tcscat((TCHAR*)ptszAuthName, TEXT("\\"));
  467. mbstotcs(_tcschr((TCHAR*)ptszAuthName, 0), _szMachine);
  468. _tcscat((TCHAR*)ptszAuthName, TEXT("$"));
  469. }
  470. __finally
  471. {
  472. if (pwszDomain != NULL)
  473. {
  474. NetApiBufferFree(pwszDomain);
  475. }
  476. }
  477. }
  478. //+----------------------------------------------------------------------------
  479. //
  480. // GetFileTimeNow
  481. //
  482. // Get the current FILETIME (UTC).
  483. //
  484. //+----------------------------------------------------------------------------
  485. FILETIME GetFileTimeNow()
  486. {
  487. SYSTEMTIME st;
  488. FILETIME ft;
  489. GetSystemTime(&st);
  490. SystemTimeToFileTime(&st, &ft);
  491. return(ft);
  492. }
  493. //+----------------------------------------------------------------------------
  494. //
  495. // CDomainRelativeObjId::Stringize
  496. //
  497. // Stringize a droid.
  498. //
  499. //+----------------------------------------------------------------------------
  500. TCHAR *
  501. CDomainRelativeObjId::Stringize( TCHAR * ptszOutBuf, DWORD cchBuf ) const
  502. {
  503. TCHAR *ptszBuf = ptszOutBuf;
  504. _volume.Stringize(ptszBuf); /*in, out, c++ reference*/
  505. _object.Stringize(ptszBuf); /*in, out, c++ reference*/
  506. TrkAssert(_tcslen(ptszOutBuf) + 1 < cchBuf);
  507. return(ptszOutBuf);
  508. }
  509. //+----------------------------------------------------------------------------
  510. //
  511. // CTrkRegistryKey::Delete
  512. //
  513. // Common code to delete a registry key, relative to _hkey.
  514. //
  515. //+----------------------------------------------------------------------------
  516. LONG
  517. CTrkRegistryKey::Delete( const TCHAR *ptszName )
  518. {
  519. LONG lRet = 0;
  520. _cs.Enter();
  521. __try
  522. {
  523. // Open _hkey if it's not already.
  524. lRet = Open();
  525. // And delete the value
  526. if( ERROR_SUCCESS == lRet )
  527. {
  528. RegDeleteValue( _hkey, ptszName );
  529. Close();
  530. }
  531. }
  532. __finally
  533. {
  534. _cs.Leave();
  535. }
  536. return( lRet );
  537. }
  538. //+----------------------------------------------------------------------------
  539. //
  540. // CTrkRegistryKey::SetDword
  541. //
  542. // Set a REG_DWORD value under _hkey.
  543. //
  544. //+---------------------------------------------------------------------------0
  545. LONG
  546. CTrkRegistryKey::SetDword( const TCHAR *ptszName, DWORD dw )
  547. {
  548. LONG lRet = 0;
  549. _cs.Enter();
  550. __try
  551. {
  552. // Open _hkey if it's not already
  553. lRet = Open();
  554. // And set the value
  555. if ( ERROR_SUCCESS == lRet )
  556. {
  557. lRet = RegSetValueEx( _hkey,
  558. ptszName,
  559. 0,
  560. REG_DWORD,
  561. reinterpret_cast<CONST BYTE *>(&dw),
  562. sizeof(dw) );
  563. if( ERROR_SUCCESS != lRet )
  564. {
  565. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't set registry value for %s (%lu)"),
  566. ptszName, lRet ));
  567. RegDeleteKey( _hkey, ptszName );
  568. }
  569. Close();
  570. }
  571. }
  572. __finally
  573. {
  574. _cs.Leave();
  575. }
  576. return( lRet );
  577. }
  578. //+----------------------------------------------------------------------------
  579. //
  580. // CTrkRegistryKey::GetDword
  581. //
  582. // Get a REG_DWORD value from _hkey.
  583. //
  584. //+---------------------------------------------------------------------------0
  585. LONG
  586. CTrkRegistryKey::GetDword( const TCHAR *ptszName, DWORD *pdwRead, DWORD dwDefault )
  587. {
  588. LONG lRet;
  589. DWORD dwRead;
  590. DWORD cbData = sizeof(*pdwRead);
  591. DWORD dwType;
  592. *pdwRead = dwDefault;
  593. _cs.Enter();
  594. __try
  595. {
  596. // Open _hkey if it's not already.
  597. lRet = Open();
  598. if( ERROR_SUCCESS != lRet )
  599. __leave;
  600. // Get the DWORD
  601. lRet = RegQueryValueEx( _hkey, ptszName, 0, &dwType,
  602. reinterpret_cast<BYTE*>(&dwRead), &cbData );
  603. if( ERROR_SUCCESS == lRet )
  604. {
  605. // Validate the type
  606. if( REG_DWORD != dwType || sizeof(dwRead) != cbData )
  607. {
  608. TrkLog(( TRKDBG_ERROR, TEXT("Wrong type/size (%d/%d) for registry value %s"),
  609. dwType, cbData, ptszName ));
  610. RegDeleteKey( _hkey, ptszName );
  611. }
  612. else
  613. {
  614. *pdwRead = dwRead;
  615. }
  616. }
  617. else if( ERROR_FILE_NOT_FOUND == lRet
  618. ||
  619. ERROR_PATH_NOT_FOUND == lRet )
  620. {
  621. lRet = ERROR_SUCCESS;
  622. }
  623. else
  624. {
  625. TrkLog(( TRKDBG_ERROR,
  626. TEXT("Couldn't read %s from registry (%lu)"), ptszName, lRet ));
  627. RegDeleteKey( _hkey, ptszName );
  628. __leave;
  629. }
  630. }
  631. __finally
  632. {
  633. Close();
  634. _cs.Leave();
  635. }
  636. return( lRet );
  637. }
  638. //+----------------------------------------------------------------------------
  639. //
  640. // ThreadPoolCallbackFunction
  641. //
  642. // This function is passed as the callback function to
  643. // RegisterWaitForSingleObjectEx. The context is a PWorkItem pointer.
  644. //
  645. // Arguments:
  646. // [pvWorkItem]
  647. // The Context parameter from RegisterWaitForSingleObjectEx.
  648. // Is a PWorkItem*
  649. // [fTimeout]
  650. // We always register INFINITE as the timeout, so this value
  651. // should always be FALSE.
  652. //
  653. //+----------------------------------------------------------------------------
  654. VOID NTAPI
  655. ThreadPoolCallbackFunction( PVOID pvWorkItem, BOOLEAN fTimeout )
  656. {
  657. SThreadFromPoolState state;
  658. PWorkItem *pWorkItem = reinterpret_cast<PWorkItem*>(pvWorkItem);
  659. TrkLog(( TRKDBG_WORKMAN, TEXT("Enter ThreadPoolCallbackFunction for %s (%p/%p)"),
  660. pWorkItem->_tszWorkItemSig, pWorkItem, *reinterpret_cast<UINT_PTR*>(pWorkItem) ));
  661. TrkAssert( FALSE == fTimeout );
  662. // Make sure we never raise back into the thread pool.
  663. __try
  664. {
  665. // Update thread-count stats. Note that this isn't
  666. // thread-safe, but for private statistics it's not worth
  667. // creating a critsec.
  668. InterlockedIncrement( reinterpret_cast<LONG*>(&g_cThreadPoolThreads) );
  669. if( g_cThreadPoolThreads > g_cThreadPoolMaxThreads )
  670. g_cThreadPoolMaxThreads = g_cThreadPoolThreads;
  671. // Set our necessary thread-specific settings
  672. state = InitializeThreadFromPool();
  673. // Process the signal
  674. pWorkItem->DoWork();
  675. }
  676. __except( BREAK_THEN_RETURN( EXCEPTION_EXECUTE_HANDLER ))
  677. {
  678. TrkLog(( TRKDBG_ERROR, TEXT("Unexpected exception on thread pool callback (%08x)"),
  679. GetExceptionCode() ));
  680. }
  681. TrkLog(( TRKDBG_WORKMAN, TEXT("Exit ThreadPoolCallbackFunction for %s (%p)"),
  682. pWorkItem->_tszWorkItemSig, pWorkItem ));
  683. InterlockedDecrement( reinterpret_cast<LONG*>(&g_cThreadPoolThreads) );
  684. //IFDBG( TrkRtlCheckForOrphanedCriticalSections( GetCurrentThread() ));
  685. // Restore the original thread-specific settings
  686. UnInitializeThreadFromPool( state );
  687. }
  688. // The work item callback function (used for RtlQueueWorkItem)
  689. // just calls to the function above.
  690. VOID NTAPI
  691. ThreadPoolWorkItemFunction( PVOID pvWorkItem )
  692. {
  693. ThreadPoolCallbackFunction( pvWorkItem, FALSE );
  694. }
  695. //+----------------------------------------------------------------------------
  696. //
  697. // RunningAsAdministratorHack
  698. //
  699. // This routine is only used by test/debug hooks. It checks to see if
  700. // the thread is running as an administrative user by seeing if we can
  701. // get write access to the service's parameters key in the registry.
  702. //
  703. //+----------------------------------------------------------------------------
  704. BOOL
  705. RunningAsAdministratorHack()
  706. {
  707. LONG lResult = 0;
  708. HKEY hkey = NULL;
  709. BOOL fReturn = FALSE;
  710. lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  711. s_tszKeyNameLinkTrack,
  712. 0, // Options, reserved must be zero
  713. KEY_ALL_ACCESS,
  714. &hkey );
  715. if( ERROR_SUCCESS == lResult )
  716. {
  717. fReturn = TRUE;
  718. RegCloseKey( hkey );
  719. }
  720. return( fReturn );
  721. }
  722. //+----------------------------------------------------------------------------
  723. //
  724. // EnablePrivilege
  725. //
  726. // Enable the specified privielge in the current access token if
  727. // it is available.
  728. //
  729. //+----------------------------------------------------------------------------
  730. BOOL
  731. EnablePrivilege( const TCHAR *ptszPrivilegeName )
  732. {
  733. BOOL fSuccess = FALSE;
  734. HANDLE hToken = INVALID_HANDLE_VALUE;
  735. LUID luid;
  736. TOKEN_PRIVILEGES token_privileges;
  737. // Get the process token.
  738. if( !OpenProcessToken( GetCurrentProcess(),
  739. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  740. &hToken))
  741. {
  742. TrkLog(( TRKDBG_ERROR, TEXT("Failed OpenProcessToken (%lu)"), GetLastError() ));
  743. goto Exit;
  744. }
  745. // Look up the name of this privilege.
  746. if( !LookupPrivilegeValue( (LPTSTR) NULL, ptszPrivilegeName, &luid ))
  747. {
  748. TrkLog(( TRKDBG_ERROR, TEXT("Failed LookupPrivilegeValue (%lu)"), GetLastError() ));
  749. goto Exit;
  750. }
  751. // Enable the privilege.
  752. token_privileges.PrivilegeCount = 1;
  753. token_privileges.Privileges[0].Luid = luid;
  754. token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  755. AdjustTokenPrivileges( hToken, FALSE, &token_privileges, sizeof(TOKEN_PRIVILEGES),
  756. (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL);
  757. // The return value doesn't tell us anything useful. We have to check GetLastError
  758. // for ERROR_SUCCESS or ERROR_NOT_ALL_ASSIGNED.
  759. if( ERROR_SUCCESS != GetLastError() )
  760. {
  761. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't adjust process token privileges (%lu)"), GetLastError() ));
  762. goto Exit;
  763. }
  764. fSuccess = TRUE;
  765. Exit:
  766. if( INVALID_HANDLE_VALUE != hToken )
  767. CloseHandle( hToken );
  768. return( fSuccess );
  769. }
  770. #if DBG
  771. CDebugString::CDebugString(const TRKSVR_MESSAGE_TYPE MsgType)
  772. {
  773. switch(MsgType)
  774. {
  775. case old_SEARCH:
  776. _tcscpy( _tsz, TEXT("old_SEARCH") ); break;
  777. case SEARCH:
  778. _tcscpy( _tsz, TEXT("SEARCH") ); break;
  779. case MOVE_NOTIFICATION:
  780. _tcscpy( _tsz, TEXT("MOVE_NOTIFICATION") ); break;
  781. case REFRESH:
  782. _tcscpy( _tsz, TEXT("REFRESH") ); break;
  783. case SYNC_VOLUMES:
  784. _tcscpy( _tsz, TEXT("SYNC_VOLUMES") ); break;
  785. case DELETE_NOTIFY:
  786. _tcscpy( _tsz, TEXT("DELETE_NOTIFY") ); break;
  787. case STATISTICS:
  788. _tcscpy( _tsz, TEXT("STATISTICS") ); break;
  789. default:
  790. _tcscpy( _tsz, TEXT("UNKNOWN") ); break;
  791. }
  792. }
  793. #endif // #if DBG
  794. #if DBG
  795. CDebugString::CDebugString(LONG VolIndex, const PFILE_NOTIFY_INFORMATION pNotifyInfo )
  796. {
  797. TCHAR *ptsz = _tsz;
  798. _tsz[0] = TEXT('\0');
  799. switch( pNotifyInfo->Action )
  800. {
  801. case FILE_ACTION_ADDED:
  802. _tcscat( _tsz, TEXT("Added ")); break;
  803. case FILE_ACTION_REMOVED:
  804. _tcscat( _tsz, TEXT("Removed ")); break;
  805. case FILE_ACTION_MODIFIED:
  806. _tcscat( _tsz, TEXT("Modified ")); break;
  807. case FILE_ACTION_RENAMED_OLD_NAME:
  808. _tcscat( _tsz, TEXT("Rename old name ")); break;
  809. case FILE_ACTION_RENAMED_NEW_NAME:
  810. _tcscat( _tsz, TEXT("Rename new name ")); break;
  811. case FILE_ACTION_ADDED_STREAM:
  812. _tcscat( _tsz, TEXT("Added stream ")); break;
  813. case FILE_ACTION_REMOVED_STREAM:
  814. _tcscat( _tsz, TEXT("Removed stream ")); break;
  815. case FILE_ACTION_MODIFIED_STREAM:
  816. _tcscat( _tsz, TEXT("Modified stream ")); break;
  817. case FILE_ACTION_REMOVED_BY_DELETE:
  818. _tcscat( _tsz, TEXT("Removed by delete ")); break;
  819. case FILE_ACTION_ID_NOT_TUNNELLED:
  820. _tcscat( _tsz, TEXT("OID not tunnelled ")); break;
  821. case FILE_ACTION_TUNNELLED_ID_COLLISION:
  822. _tcscat( _tsz, TEXT("OID tunnel collision ")); break;
  823. default:
  824. _stprintf( _tsz, TEXT("Unknown action (0x%x)"), pNotifyInfo->Action ); break;
  825. }
  826. ptsz = _tsz + _tcslen(_tsz);
  827. // The name length for an object ID is always 72
  828. if( pNotifyInfo->FileNameLength != 72 )
  829. _stprintf( ptsz, TEXT(" name length=%d"), pNotifyInfo->FileNameLength );
  830. else
  831. {
  832. // Stringize the path of this object ID
  833. CDomainRelativeObjId droidBirth;
  834. CObjId objid( FOI_OBJECTID, *(FILE_OBJECTID_INFORMATION*)pNotifyInfo->FileName );
  835. ptsz[0] = VolChar(VolIndex);
  836. ptsz[1] = TEXT(':');
  837. ptsz[2] = TEXT('\0');
  838. FindLocalPath( VolIndex, objid, &droidBirth, &ptsz[2] );
  839. ptsz += _tcslen(ptsz);
  840. ptsz += _stprintf( ptsz, TEXT(" - %c:"), VolChar(VolIndex) );
  841. _stprintf( ptsz, TEXT("%s"), CDebugString(objid)._tsz );
  842. ptsz += _tcslen(ptsz);
  843. }
  844. }
  845. #endif // #if DBG
  846. //+----------------------------------------------------------------------------
  847. //
  848. // CActiveThreadList::AddCurrent
  849. //
  850. // Add the current thread to the list of threads maintained by this class.
  851. //
  852. //+----------------------------------------------------------------------------
  853. HRESULT
  854. CActiveThreadList::AddCurrent( )
  855. {
  856. HRESULT hr = S_OK;
  857. HANDLE hThread = NULL;
  858. if( !_cs.IsInitialized() )
  859. {
  860. TrkLog(( TRKDBG_WARNING, TEXT("Active thread list critsec not initialized!!!") ));
  861. return S_OK;
  862. }
  863. _cs.Enter();
  864. if( _cActiveThreads < _cMaxThreads )
  865. {
  866. // Add the thread ID at the end of the list.
  867. _prgdwThreadIDs[ _cActiveThreads++ ] = GetCurrentThreadId();
  868. }
  869. else
  870. {
  871. // Alloc a larger buffer for the list, then add the thread ID.
  872. hr = Grow();
  873. if( SUCCEEDED(hr) )
  874. {
  875. _prgdwThreadIDs[ _cActiveThreads++ ] = GetCurrentThreadId();
  876. }
  877. }
  878. #if DBG
  879. if( SUCCEEDED(hr) )
  880. TrkLog(( TRKDBG_WORKMAN, TEXT("Added thread 0x%x to the active thread list (%d)"),
  881. GetCurrentThreadId(), _cActiveThreads ));
  882. #endif
  883. _cs.Leave();
  884. return( hr );
  885. }
  886. //+----------------------------------------------------------------------------
  887. //
  888. // CActiveThreadList::RemoveCurrent
  889. //
  890. // Remove the current thread ID from the list which is maintained by this
  891. // class.
  892. //
  893. //+----------------------------------------------------------------------------
  894. HRESULT
  895. CActiveThreadList::RemoveCurrent( )
  896. {
  897. HRESULT hr = S_OK;
  898. BOOL fFound = FALSE;
  899. DWORD dwThreadID = GetCurrentThreadId();
  900. if( !_cs.IsInitialized() )
  901. return S_OK;
  902. _cs.Enter();
  903. // Search for the current thread's ID in the list.
  904. for( ULONG i = 0; i < _cActiveThreads; i++ )
  905. {
  906. if( _prgdwThreadIDs[ i ] == dwThreadID )
  907. {
  908. // We found this thread. Remove it from the list by copying down
  909. // all the IDs behind it.
  910. memcpy( &_prgdwThreadIDs[i], &_prgdwThreadIDs[i+1],
  911. (--_cActiveThreads - i) * sizeof(_prgdwThreadIDs[0]) );
  912. _prgdwThreadIDs[ _cActiveThreads ] = 0;
  913. TrkLog(( TRKDBG_WORKMAN, TEXT("Removed thread 0x%x from the active thread list (%d)"),
  914. dwThreadID, _cActiveThreads ));
  915. fFound = TRUE;
  916. break;
  917. }
  918. }
  919. if( !fFound )
  920. {
  921. hr = E_FAIL;
  922. TrkLog(( TRKDBG_WORKMAN, TEXT("CActiveThreadList couldn't remove thread 0x%x, not found"),
  923. dwThreadID ));
  924. }
  925. _cs.Leave();
  926. return( hr );
  927. }
  928. //+----------------------------------------------------------------------------
  929. //
  930. // CActiveThreadList::CancelAllRpc
  931. //
  932. // Call RpcCancelThread on each of the threads in the list.
  933. //
  934. //+----------------------------------------------------------------------------
  935. void
  936. CActiveThreadList::CancelAllRpc()
  937. {
  938. if( !_cs.IsInitialized() )
  939. return;
  940. _cs.Enter();
  941. TrkLog(( TRKDBG_WKS|TRKDBG_SVR, TEXT("Canceling all out-going RPCs") ));
  942. // Loop through the list of threads.
  943. for( ULONG i = 0; i < _cActiveThreads; i++ )
  944. {
  945. TrkAssert( 0 != _prgdwThreadIDs[i] );
  946. // Get a thread handle for this thread ID.
  947. HANDLE hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, _prgdwThreadIDs[i] );
  948. if( NULL == hThread )
  949. {
  950. // Nothing we can do about it. Move on to the next thread.
  951. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open thread 0x%x to cancel RPC (%lu)"),
  952. _prgdwThreadIDs[i], GetLastError() ));
  953. continue;
  954. }
  955. // Cancel any out-going RPC on this thread.
  956. RPC_STATUS rpcstatus = RpcCancelThread( hThread );
  957. if( RPC_S_OK != rpcstatus )
  958. {
  959. TrkLog(( TRKDBG_ERROR, TEXT("Failed RpcCancelThread on %p/0x%x (%lu)"),
  960. hThread, _prgdwThreadIDs[i], rpcstatus ));
  961. }
  962. else
  963. {
  964. TrkLog(( TRKDBG_WORKMAN, TEXT("Canceled RPC on %p/0x%x"),
  965. hThread, _prgdwThreadIDs[i] ));
  966. }
  967. // Close the thread handle and move on.
  968. CloseHandle( hThread );
  969. }
  970. _cs.Leave();
  971. }
  972. //+----------------------------------------------------------------------------
  973. //
  974. // CActiveThreadList::Grow
  975. //
  976. // Private member function to grow the buffer used to hold the thread IDs.
  977. //
  978. //+----------------------------------------------------------------------------
  979. HRESULT
  980. CActiveThreadList::Grow()
  981. {
  982. // This is a private method, the critsec has already been entered.
  983. HRESULT hr = S_OK;
  984. DWORD *prgNew = NULL;
  985. ULONG cMaxThreads = _cMaxThreads + INCREMENT_ACTIVE_THREAD_LIST;
  986. prgNew = new DWORD[ cMaxThreads ];
  987. if( NULL == prgNew )
  988. {
  989. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't grow active thread list") ));
  990. return( E_OUTOFMEMORY );
  991. }
  992. TrkLog(( TRKDBG_WORKMAN, TEXT("Growing active thread list from %d to %d"),
  993. _cMaxThreads, cMaxThreads ));
  994. memcpy( prgNew, _prgdwThreadIDs, _cMaxThreads*sizeof(_prgdwThreadIDs[0]) );
  995. _cMaxThreads = cMaxThreads;
  996. delete [] _prgdwThreadIDs;
  997. _prgdwThreadIDs = prgNew;
  998. return( hr );
  999. }