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.

647 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. slmcheck.c
  5. Abstract:
  6. This source file defines a single function that will check the
  7. consistency of a SLM Status file.
  8. --*/
  9. #include "precomp.h"
  10. #include "slmcheck.tmh"
  11. #pragma hdrstop
  12. #ifdef SLMDBG
  13. //
  14. // This is terrible
  15. //
  16. NTSTATUS
  17. NtCreateEvent (
  18. OUT PHANDLE EventHandle,
  19. IN ACCESS_MASK DesiredAccess,
  20. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  21. IN EVENT_TYPE EventType,
  22. IN BOOLEAN InitialState
  23. );
  24. //
  25. // So is this
  26. //
  27. NTSTATUS
  28. NtWaitForSingleObject(
  29. IN HANDLE Handle,
  30. IN BOOLEAN Alertable,
  31. IN PLARGE_INTEGER Timeout OPTIONAL
  32. );
  33. BOOLEAN SrvDisallowSlmAccessEnabled = FALSE;
  34. BOOLEAN SrvSlmFailed = FALSE;
  35. #define toupper(c) ( (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c )
  36. NTSTATUS
  37. SrvpValidateStatusFile(
  38. IN PVOID StatusFileData,
  39. IN ULONG StatusFileLength,
  40. OUT PULONG FileOffsetOfInvalidData
  41. );
  42. VOID
  43. SrvReportCorruptSlmStatus (
  44. IN PUNICODE_STRING StatusFile,
  45. IN NTSTATUS Status,
  46. IN ULONG Offset,
  47. IN ULONG Operation,
  48. IN PSESSION Session
  49. )
  50. {
  51. NTSTATUS status;
  52. ANSI_STRING ansiStatusFile;
  53. TIME time;
  54. TIME_FIELDS timeFields;
  55. ULONG i, j;
  56. UNICODE_STRING userName;
  57. if( SrvSlmFailed ) {
  58. return;
  59. }
  60. status = RtlUnicodeStringToAnsiString( &ansiStatusFile, StatusFile, TRUE );
  61. ASSERT( NT_SUCCESS(status) );
  62. KeQuerySystemTime( &time );
  63. RtlTimeToTimeFields( &time, &timeFields );
  64. SrvGetUserAndDomainName ( Session, &userName, NULL );
  65. KdPrint(( "\n*** CORRUPT STATUS FILE DETECTED ***\n"
  66. " File: %Z\n"
  67. " Status: 0x%lx, Offset: 0x%lx, detected on %s\n",
  68. &ansiStatusFile, Status, Offset,
  69. Operation == SLMDBG_CLOSE ? "close" : "rename" ));
  70. KdPrint(( " Workstation: %wZ, User: %wZ, OS: %d\n",
  71. &Session->Connection->PagedConnection->ClientMachineNameString,
  72. &userName,
  73. &SrvClientTypes[Session->Connection->SmbDialect] ));
  74. KdPrint(( " Current time: %d-%d-%d ",
  75. timeFields.Month, timeFields.Day, timeFields.Year ));
  76. KdPrint(( "%d:%d:%d\n",
  77. timeFields.Hour, timeFields.Minute, timeFields.Second ));
  78. SrvReleaseUserAndDomainName( Session, &userName, NULL );
  79. #if 0
  80. //
  81. // Send a broadcast message.
  82. //
  83. SrvSendSecondClassMailslot( ansiStatusFile.Buffer, StatusFile->Length + 1,
  84. "BLUBBER", "BLUBBER" );
  85. #endif
  86. RtlFreeAnsiString( &ansiStatusFile );
  87. } // SrvReportCorruptSlmStatus
  88. VOID
  89. SrvReportSlmStatusOperations (
  90. IN PRFCB Rfcb,
  91. IN BOOLEAN Force
  92. )
  93. {
  94. ULONG first, last, i;
  95. PRFCB_TRACE trace;
  96. TIME_FIELDS timeFields;
  97. PSZ command;
  98. BOOLEAN oplockBreak;
  99. if( !Force && SrvSlmFailed ) {
  100. return;
  101. }
  102. KdPrint(( " Number of operations: %d, number of writes: %d\n",
  103. Rfcb->OperationCount, Rfcb->WriteCount ));
  104. if( Rfcb->Connection && GET_BLOCK_STATE(Rfcb->Connection) != BlockStateActive ) {
  105. KdPrint(( " Connection State = %u\n", GET_BLOCK_STATE( Rfcb->Connection )));
  106. }
  107. if ( Rfcb->TraceWrapped || (Rfcb->NextTrace != 0) ) {
  108. first = Rfcb->TraceWrapped ? Rfcb->NextTrace : 0;
  109. last = Rfcb->NextTrace == 0 ? SLMDBG_TRACE_COUNT - 1 :
  110. Rfcb->NextTrace - 1;
  111. i = first;
  112. while ( TRUE ) {
  113. trace = &Rfcb->Trace[i];
  114. RtlTimeToTimeFields( &trace->Time, &timeFields );
  115. KdPrint(( " %s%d: ", i < 10 ? "0" : "", i ));
  116. KdPrint(( "%d-%d-%d ",
  117. timeFields.Month, timeFields.Day, timeFields.Year ));
  118. KdPrint(( "%s%d:%s%d:",
  119. timeFields.Hour < 10 ? "0" : "", timeFields.Hour,
  120. timeFields.Minute < 10 ? "0" : "", timeFields.Minute ));
  121. KdPrint(( "%s%d: ",
  122. timeFields.Second < 10 ? "0" : "", timeFields.Second ));
  123. oplockBreak = FALSE;
  124. switch ( trace->Command ) {
  125. case SMB_COM_READ:
  126. case SMB_COM_WRITE:
  127. case SMB_COM_READ_ANDX:
  128. case SMB_COM_WRITE_ANDX:
  129. case SMB_COM_LOCK_AND_READ:
  130. case SMB_COM_WRITE_AND_UNLOCK:
  131. case SMB_COM_WRITE_AND_CLOSE:
  132. case SMB_COM_READ_RAW:
  133. case SMB_COM_WRITE_RAW:
  134. case SMB_COM_LOCK_BYTE_RANGE:
  135. case SMB_COM_UNLOCK_BYTE_RANGE:
  136. case SMB_COM_LOCKING_ANDX:
  137. switch ( trace->Command ) {
  138. case SMB_COM_READ:
  139. command = "Read";
  140. break;
  141. case SMB_COM_WRITE:
  142. command = "Write";
  143. break;
  144. case SMB_COM_READ_ANDX:
  145. command = "Read And X";
  146. break;
  147. case SMB_COM_WRITE_ANDX:
  148. command = "Write And X";
  149. break;
  150. case SMB_COM_LOCK_AND_READ:
  151. command = "Lock And Read";
  152. break;
  153. case SMB_COM_WRITE_AND_UNLOCK:
  154. command = "Write And Unlock";
  155. break;
  156. case SMB_COM_WRITE_AND_CLOSE:
  157. command = "Write And Close";
  158. break;
  159. case SMB_COM_READ_RAW:
  160. if ( (trace->Flags & 1) == 0 ) {
  161. command = "Read Raw (copy)";
  162. } else {
  163. command = "Read Raw (MDL)";
  164. }
  165. break;
  166. case SMB_COM_WRITE_RAW:
  167. if ( (trace->Flags & 2) == 0 ) {
  168. if ( (trace->Flags & 1) == 0 ) {
  169. command = "Write Raw (copy, no immed)";
  170. } else {
  171. command = "Write Raw (MDL, no immed)";
  172. }
  173. } else {
  174. if ( (trace->Flags & 1) == 0 ) {
  175. command = "Write Raw (copy, immed)";
  176. } else {
  177. command = "Write Raw (MDL, immed)";
  178. }
  179. }
  180. break;
  181. case SMB_COM_LOCK_BYTE_RANGE:
  182. command = "Lock Byte Range";
  183. break;
  184. case SMB_COM_UNLOCK_BYTE_RANGE:
  185. command = "Unlock Byte Range";
  186. break;
  187. case SMB_COM_LOCKING_ANDX:
  188. if ( trace->Flags == 0 ) {
  189. command = "Locking And X (lock)";
  190. } else if ( trace->Flags == 1 ) {
  191. command = "Locking And X (unlock)";
  192. } else {
  193. command = "Locking And X (release oplock)";
  194. oplockBreak = TRUE;
  195. }
  196. break;
  197. }
  198. if ( !oplockBreak ) {
  199. KdPrint(( "%s, offset = 0x%lx, len = 0x%lx\n",
  200. command, trace->Data.ReadWrite.Offset,
  201. trace->Data.ReadWrite.Length ));
  202. } else {
  203. KdPrint(( "%s\n", command ));
  204. }
  205. break;
  206. default:
  207. KdPrint(( "command = 0x%lx, flags = 0x%lx\n",
  208. trace->Command, trace->Flags ));
  209. }
  210. if ( i == last ) break;
  211. if ( ++i == SLMDBG_TRACE_COUNT ) i = 0;
  212. }
  213. }
  214. SrvSendSecondClassMailslot( "SLM CORRUPTION", 15, "BLUBBER", "BLUBBER" );
  215. return;
  216. } // SrvReportSlmStatusOperations
  217. VOID
  218. SrvCreateMagicSlmName (
  219. IN PUNICODE_STRING StatusFile,
  220. OUT PUNICODE_STRING MagicFile
  221. )
  222. {
  223. LONG fileLength;
  224. ULONG dirLength;
  225. PCHAR magicName = "\\status.nfw";
  226. PCHAR src;
  227. PWCH dest;
  228. fileLength = (strlen( magicName ) + 1) * sizeof(WCHAR);
  229. dirLength = SrvGetSubdirectoryLength( StatusFile );
  230. MagicFile->MaximumLength = (USHORT)(dirLength + fileLength);
  231. MagicFile->Length = (USHORT)(MagicFile->MaximumLength - sizeof(WCHAR));
  232. MagicFile->Buffer = ExAllocatePool( PagedPool, MagicFile->MaximumLength );
  233. ASSERT( MagicFile->Buffer != NULL );
  234. RtlCopyMemory( MagicFile->Buffer, StatusFile->Buffer, dirLength );
  235. src = magicName;
  236. dest = (PWCH)((PCHAR)MagicFile->Buffer + dirLength);
  237. for ( fileLength = strlen(magicName); fileLength >= 0; fileLength-- ) {
  238. *dest++ = *src++;
  239. }
  240. return;
  241. } // SrvCreateMagicSlmName
  242. VOID
  243. SrvDisallowSlmAccess (
  244. IN PUNICODE_STRING StatusFile,
  245. IN HANDLE RootDirectory
  246. )
  247. {
  248. NTSTATUS status;
  249. UNICODE_STRING file;
  250. OBJECT_ATTRIBUTES objectAttributes;
  251. HANDLE fileHandle;
  252. IO_STATUS_BLOCK iosb;
  253. if( SrvSlmFailed ) {
  254. return;
  255. }
  256. SrvSlmFailed = TRUE;
  257. if( SrvDisallowSlmAccessEnabled == FALSE ) {
  258. return;
  259. }
  260. SrvCreateMagicSlmName( StatusFile, &file );
  261. InitializeObjectAttributes(
  262. &objectAttributes,
  263. &file,
  264. OBJ_CASE_INSENSITIVE,
  265. RootDirectory,
  266. NULL
  267. );
  268. KdPrint(( "Disallowing access to SLM directory %wZ\n", &file ));
  269. status = IoCreateFile(
  270. &fileHandle,
  271. GENERIC_READ,
  272. &objectAttributes,
  273. &iosb,
  274. NULL,
  275. 0,
  276. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  277. FILE_OPEN_IF,
  278. FILE_NON_DIRECTORY_FILE,
  279. NULL,
  280. 0,
  281. CreateFileTypeNone,
  282. NULL,
  283. 0
  284. );
  285. ExFreePool( file.Buffer );
  286. if ( NT_SUCCESS(status) ) {
  287. status = iosb.Status;
  288. }
  289. if ( NT_SUCCESS(status) ) {
  290. NtClose( fileHandle );
  291. } else {
  292. KdPrint(( "Attempt to disallow SLM access failed: 0x%lx\n", status ));
  293. }
  294. return;
  295. } // SrvDisallowSlmAccess
  296. BOOLEAN
  297. SrvIsSlmAccessDisallowed (
  298. IN PUNICODE_STRING StatusFile,
  299. IN HANDLE RootDirectory
  300. )
  301. {
  302. NTSTATUS status;
  303. UNICODE_STRING file;
  304. OBJECT_ATTRIBUTES objectAttributes;
  305. HANDLE fileHandle;
  306. IO_STATUS_BLOCK iosb;
  307. if ( !SrvDisallowSlmAccessEnabled ) {
  308. return FALSE;
  309. }
  310. SrvCreateMagicSlmName( StatusFile, &file );
  311. InitializeObjectAttributes(
  312. &objectAttributes,
  313. &file,
  314. OBJ_CASE_INSENSITIVE,
  315. RootDirectory,
  316. NULL
  317. );
  318. status = IoCreateFile(
  319. &fileHandle,
  320. GENERIC_READ,
  321. &objectAttributes,
  322. &iosb,
  323. NULL,
  324. 0,
  325. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  326. FILE_OPEN,
  327. FILE_NON_DIRECTORY_FILE,
  328. NULL,
  329. 0,
  330. CreateFileTypeNone,
  331. NULL,
  332. 0
  333. );
  334. ExFreePool( file.Buffer );
  335. if ( NT_SUCCESS(status) ) {
  336. status = iosb.Status;
  337. }
  338. if ( NT_SUCCESS(status) ) {
  339. NtClose( fileHandle );
  340. return TRUE;
  341. } else {
  342. return FALSE;
  343. }
  344. } // SrvIsSlmAccessDisallowed
  345. BOOLEAN
  346. SrvIsEtcFile (
  347. IN PUNICODE_STRING FileName
  348. )
  349. {
  350. if ( ((RtlUnicodeStringToAnsiSize( FileName ) - 1) >= 4) &&
  351. (toupper(FileName->Buffer[0]) == 'E') &&
  352. (toupper(FileName->Buffer[1]) == 'T') &&
  353. (toupper(FileName->Buffer[2]) == 'C') &&
  354. ( FileName->Buffer[3] == '\\') ) {
  355. return TRUE;
  356. } else {
  357. LONG i;
  358. for ( i = 0;
  359. i < (LONG)RtlUnicodeStringToAnsiSize( FileName ) - 1 - 4;
  360. i++ ) {
  361. if ( ( FileName->Buffer[i] == '\\') &&
  362. (toupper(FileName->Buffer[i+1]) == 'E' ) &&
  363. (toupper(FileName->Buffer[i+2]) == 'T' ) &&
  364. (toupper(FileName->Buffer[i+3]) == 'C' ) &&
  365. ( FileName->Buffer[i+4] == '\\') ) {
  366. return TRUE;
  367. }
  368. }
  369. }
  370. return FALSE;
  371. } // SrvIsEtcFile
  372. BOOLEAN
  373. SrvIsSlmStatus (
  374. IN PUNICODE_STRING StatusFile
  375. )
  376. {
  377. UNICODE_STRING baseName;
  378. if ( !SrvIsEtcFile( StatusFile ) ) {
  379. return FALSE;
  380. }
  381. SrvGetBaseFileName( StatusFile, &baseName );
  382. if ( ((RtlUnicodeStringToAnsiSize( &baseName ) - 1) == 10) &&
  383. (toupper(baseName.Buffer[0]) == 'S') &&
  384. (toupper(baseName.Buffer[1]) == 'T') &&
  385. (toupper(baseName.Buffer[2]) == 'A') &&
  386. (toupper(baseName.Buffer[3]) == 'T') &&
  387. (toupper(baseName.Buffer[4]) == 'U') &&
  388. (toupper(baseName.Buffer[5]) == 'S') &&
  389. ( baseName.Buffer[6] == '.') &&
  390. (toupper(baseName.Buffer[7]) == 'S') &&
  391. (toupper(baseName.Buffer[8]) == 'L') &&
  392. (toupper(baseName.Buffer[9]) == 'M') ) {
  393. return TRUE;
  394. }
  395. return FALSE;
  396. } // SrvIsSlmStatus
  397. BOOLEAN
  398. SrvIsTempSlmStatus (
  399. IN PUNICODE_STRING StatusFile
  400. )
  401. {
  402. UNICODE_STRING baseName;
  403. if ( !SrvIsEtcFile( StatusFile ) ) {
  404. return FALSE;
  405. }
  406. SrvGetBaseFileName( StatusFile, &baseName );
  407. if ( ((RtlUnicodeStringToAnsiSize( &baseName ) - 1) == 5) &&
  408. (toupper(baseName.Buffer[0]) == 'T') &&
  409. ( baseName.Buffer[1] == '0') ) {
  410. return TRUE;
  411. }
  412. return FALSE;
  413. } // SrvIsTempSlmStatus
  414. NTSTATUS
  415. SrvValidateSlmStatus(
  416. IN HANDLE StatusFile,
  417. IN PWORK_CONTEXT WorkContext,
  418. OUT PULONG FileOffsetOfInvalidData
  419. )
  420. {
  421. NTSTATUS Status;
  422. IO_STATUS_BLOCK IoStatus;
  423. PULONG buffer, p, ep, s;
  424. LARGE_INTEGER offset;
  425. ULONG previousRun = 0;
  426. HANDLE eventHandle;
  427. OBJECT_ATTRIBUTES obja;
  428. ULONG key;
  429. #define ZERORUNLEN 2048
  430. #define SLMREADSIZE (10 * 4096)
  431. if( SrvSlmFailed ) {
  432. return STATUS_SUCCESS;
  433. }
  434. buffer = ExAllocatePoolWithTag( NonPagedPool, SLMREADSIZE, BlockTypeDataBuffer );
  435. if( buffer == NULL ) {
  436. return STATUS_SUCCESS;
  437. }
  438. *FileOffsetOfInvalidData = 0;
  439. offset.QuadPart = 0;
  440. InitializeObjectAttributes( &obja, NULL, OBJ_CASE_INSENSITIVE, NULL, NULL );
  441. Status = NtCreateEvent( &eventHandle,
  442. EVENT_ALL_ACCESS,
  443. &obja,
  444. SynchronizationEvent,
  445. FALSE
  446. );
  447. if( !NT_SUCCESS( Status ) ) {
  448. return STATUS_SUCCESS;
  449. }
  450. if( ARGUMENT_PRESENT( WorkContext ) ) {
  451. key = WorkContext->Rfcb->ShiftedFid |
  452. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  453. }
  454. //
  455. // Scan through the file, looking for a run of zeros
  456. //
  457. while( 1 ) {
  458. RtlZeroMemory( &IoStatus, sizeof( IoStatus ) );
  459. Status = NtReadFile( StatusFile,
  460. eventHandle,
  461. NULL,
  462. NULL,
  463. &IoStatus,
  464. buffer,
  465. SLMREADSIZE,
  466. &offset,
  467. ARGUMENT_PRESENT( WorkContext ) ? &key : NULL
  468. );
  469. if( Status == STATUS_PENDING ) {
  470. NtWaitForSingleObject( eventHandle, FALSE, NULL );
  471. }
  472. Status = IoStatus.Status;
  473. if( Status == STATUS_END_OF_FILE ) {
  474. break;
  475. }
  476. if( Status != STATUS_SUCCESS ) {
  477. NtClose( eventHandle );
  478. ExFreePool( buffer );
  479. return Status;
  480. }
  481. if( IoStatus.Information == 0 ) {
  482. break;
  483. }
  484. ep = (PULONG)((ULONG)buffer + IoStatus.Information);
  485. for( p = buffer; p < ep; p++ ) {
  486. if( *p == 0 ) {
  487. for( s = p; s < ep && *s == 0; s++ )
  488. ;
  489. if( (ULONG)s - (ULONG)p >= ZERORUNLEN ) {
  490. *FileOffsetOfInvalidData = offset.LowPart + ((ULONG)p - (ULONG)buffer);
  491. KdPrint(( "SRV: Run of %u zeros in SLM file at offset %u decimal!\n",
  492. (ULONG)s - (ULONG)p, *FileOffsetOfInvalidData ));
  493. ExFreePool( buffer );
  494. NtClose( eventHandle );
  495. return STATUS_UNSUCCESSFUL;
  496. }
  497. p = s;
  498. }
  499. }
  500. offset.QuadPart += IoStatus.Information;
  501. }
  502. NtClose( eventHandle );
  503. ExFreePool( buffer );
  504. return( STATUS_SUCCESS );
  505. }
  506. #endif