Windows NT 4.0 source code leak
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.

1453 lines
36 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ea.c
  5. Abstract:
  6. This module contains various support routines for extended attributes.
  7. Author:
  8. David Treadwell (davidtr) 5-Apr-1990
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #define BugCheckFileId SRV_FILE_EA
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text( PAGE, SrvAreEasNeeded )
  16. #pragma alloc_text( PAGE, SrvGetOs2FeaOffsetOfError )
  17. #pragma alloc_text( PAGE, SrvGetOs2GeaOffsetOfError )
  18. #pragma alloc_text( PAGE, SrvOs2FeaListToNt )
  19. #pragma alloc_text( PAGE, SrvOs2FeaListSizeToNt )
  20. #pragma alloc_text( PAGE, SrvOs2FeaToNt )
  21. #pragma alloc_text( PAGE, SrvOs2GeaListToNt )
  22. #pragma alloc_text( PAGE, SrvOs2GeaListSizeToNt )
  23. #pragma alloc_text( PAGE, SrvOs2GeaToNt )
  24. #pragma alloc_text( PAGE, SrvNtFullEaToOs2 )
  25. #pragma alloc_text( PAGE, SrvGetNumberOfEasInList )
  26. #pragma alloc_text( PAGE, SrvQueryOs2FeaList )
  27. #pragma alloc_text( PAGE, SrvSetOs2FeaList )
  28. #pragma alloc_text( PAGE, SrvConstructNullOs2FeaList )
  29. #endif
  30. BOOLEAN
  31. SrvAreEasNeeded (
  32. IN PFILE_FULL_EA_INFORMATION NtFullEa
  33. )
  34. /*++
  35. Routine Description:
  36. This routine checks whether any of the full EAs in the list have the
  37. FILE_NEED_EA bit set in the flags field.
  38. Arguments:
  39. NtFullEa - a pointer to a pointer to where the NT-style full EA list
  40. is stored.
  41. Return Value:
  42. BOOLEAN - TRUE if any EA has FILE_NEED_EA set, FALSE otherwise.
  43. --*/
  44. {
  45. PFILE_FULL_EA_INFORMATION lastEa;
  46. PAGED_CODE( );
  47. do {
  48. if ( NtFullEa->Flags & FILE_NEED_EA ) {
  49. return TRUE;
  50. }
  51. lastEa = NtFullEa;
  52. NtFullEa = (PFILE_FULL_EA_INFORMATION)(
  53. (PCHAR)NtFullEa + NtFullEa->NextEntryOffset );
  54. } while ( lastEa->NextEntryOffset != 0 );
  55. return FALSE;
  56. } // SrvAreEasNeeded
  57. USHORT
  58. SrvGetOs2FeaOffsetOfError (
  59. IN ULONG NtErrorOffset,
  60. IN PFILE_FULL_EA_INFORMATION NtFullEa,
  61. IN PFEALIST FeaList
  62. )
  63. /*++
  64. Routine Description:
  65. Finds the offset in a FEALIST that corresponds to an offset into
  66. a list of FILE_FULL_EA_INFORMATION structures. This is used when
  67. NtSetEaFile returns an offset to an EA that caused an error, and we
  68. need to return the offset into the list of EAs given to us by the
  69. client.
  70. Arguments:
  71. NtErrorOffset - offset of the EA in the NT full EA list that caused
  72. the error.
  73. NtFullEa - a pointer to a pointer to where the NT-style full EA list
  74. is stored. A buffer is allocated and pointer to by *NtFullEa.
  75. FeaList - pointer to the OS/2 1.2 FEALIST.
  76. Return Value:
  77. USHORT - offset into the FEALIST.
  78. --*/
  79. {
  80. PFEA fea = FeaList->list;
  81. PFEA lastFeaStartLocation;
  82. PFILE_FULL_EA_INFORMATION offsetLocation;
  83. PAGED_CODE( );
  84. //
  85. // If the NT error offset is zero, return 0 for the FEA error offset.
  86. //
  87. // !!! this shouldn't be necessary if the loop below is written
  88. // correctly.
  89. //if ( NtErrorOffset == 0 ) {
  90. // return 0;
  91. //}
  92. //
  93. // Find where in the NT full EA list the error occurred and the
  94. // last possible start location for an FEA in the FEALIST.
  95. //
  96. offsetLocation = (PFILE_FULL_EA_INFORMATION)(
  97. (PCHAR)NtFullEa + NtErrorOffset);
  98. lastFeaStartLocation = (PFEA)( (PCHAR)FeaList +
  99. SmbGetUlong( &FeaList->cbList ) -
  100. sizeof(FEA) - 1 );
  101. //
  102. // Walk through both lists simultaneously until one of three conditions
  103. // is true:
  104. // - we reach or pass the offset in the NT full EA list
  105. // - we reach the end of the NT full EA list
  106. // - we reach the end of the FEALIST.
  107. //
  108. while ( NtFullEa < offsetLocation &&
  109. NtFullEa->NextEntryOffset != 0 &&
  110. fea <= lastFeaStartLocation ) {
  111. NtFullEa = (PFILE_FULL_EA_INFORMATION)(
  112. (PCHAR)NtFullEa + NtFullEa->NextEntryOffset );
  113. fea = (PFEA)( (PCHAR)fea + sizeof(FEA) + fea->cbName + 1 +
  114. SmbGetUshort( &fea->cbValue ) );
  115. }
  116. //
  117. // If NtFullEa is not equal to the offset location we calculated,
  118. // somebody screwed up.
  119. //
  120. //ASSERT( NtFullEa == offsetLocation );
  121. return (USHORT)( (PCHAR)fea - (PCHAR)FeaList );
  122. } // SrvGetOs2FeaOffsetOfError
  123. USHORT
  124. SrvGetOs2GeaOffsetOfError (
  125. IN ULONG NtErrorOffset,
  126. IN PFILE_GET_EA_INFORMATION NtGetEa,
  127. IN PGEALIST GeaList
  128. )
  129. /*++
  130. Routine Description:
  131. Finds the offset in a GEALIST that corresponds to an offset into
  132. a list of FILE_GET_EA_INFORMATION structures. This is used when
  133. NtQueryEaFile returns an offset to an EA that caused an error, and we
  134. need to return the offset into the list of EAs given to us by the
  135. client.
  136. Arguments:
  137. NtErrorOffset - offset of the EA in the NT get EA list that caused
  138. the error.
  139. NtGetEa - a pointer to a pointer to where the NT-style get EA list
  140. is stored. A buffer is allocated and pointer to by *NtGetEa.
  141. GeaList - pointer to the OS/2 1.2 GEALIST.
  142. Return Value:
  143. USHORT - offset into the GEALIST.
  144. --*/
  145. {
  146. PGEA gea = GeaList->list;
  147. PGEA lastGeaStartLocation;
  148. PFILE_GET_EA_INFORMATION offsetLocation;
  149. PAGED_CODE( );
  150. //
  151. // Find where in the NT get EA list the error occurred and the
  152. // last possible start location for an GEA in the GEALIST.
  153. //
  154. offsetLocation = (PFILE_GET_EA_INFORMATION)((PCHAR)NtGetEa + NtErrorOffset);
  155. lastGeaStartLocation = (PGEA)( (PCHAR)GeaList +
  156. SmbGetUlong( &GeaList->cbList ) - sizeof(GEA) );
  157. //
  158. // Walk through both lists simultaneously until one of three conditions
  159. // is true:
  160. // - we reach or pass the offset in the NT full EA list
  161. // - we reach the end of the NT get EA list
  162. // - we reach the end of the GEALIST.
  163. //
  164. while ( NtGetEa < offsetLocation &&
  165. NtGetEa->NextEntryOffset != 0 &&
  166. gea <= lastGeaStartLocation ) {
  167. NtGetEa = (PFILE_GET_EA_INFORMATION)(
  168. (PCHAR)NtGetEa + NtGetEa->NextEntryOffset );
  169. gea = (PGEA)( (PCHAR)gea + sizeof(GEA) + gea->cbName );
  170. }
  171. //
  172. // If NtGetEa is not equal to the offset location we calculated,
  173. // somebody screwed up.
  174. //
  175. // bugbug - Davemont - no assert in Cairo (as it was in SrvGetOs2FeaOffsetOfError)
  176. // because OFS does not correctly return offset of failed EA in iosb.information,
  177. // because of stuff in the object store handler (see RobertFe).
  178. // ASSERT( NtGetEa == offsetLocation );
  179. return (USHORT)( (PCHAR)gea - (PCHAR)GeaList );
  180. } // SrvGetOs2GeaOffsetOfError
  181. NTSTATUS
  182. SrvOs2FeaListToNt (
  183. IN PFEALIST FeaList,
  184. OUT PFILE_FULL_EA_INFORMATION *NtFullEa,
  185. OUT PULONG BufferLength,
  186. OUT PUSHORT EaErrorOffset
  187. )
  188. /*++
  189. Routine Description:
  190. Converts a list of OS/2 1.2 FEAs to NT style. Memory is allocated from
  191. non-paged pool to hold the NT full EA list. The calling routine is
  192. responsible for deallocating this memory when it is done with it.
  193. WARNING! It is the responsibility of the calling routine to ensure
  194. that the value in FeaList->cbList will fit within the buffer allocated
  195. to FeaList. This prevents malicious redirectors from causing an
  196. access violation in the server.
  197. Arguments:
  198. FeaList - pointer to the OS/2 1.2 FEALIST to convert.
  199. NtFullEa - a pointer to a pointer to where the NT-style full EA list
  200. is stored. A buffer is allocated and pointer to by *NtFullEa.
  201. BufferLength - length of the allocated buffer.
  202. Return Value:
  203. NTSTATUS - STATUS_SUCCESS or STATUS_INSUFF_SERVER_RESOURCES.
  204. --*/
  205. {
  206. PFEA lastFeaStartLocation;
  207. PFEA fea = NULL;
  208. PFEA lastFea = NULL;
  209. PFILE_FULL_EA_INFORMATION ntFullEa = NULL;
  210. PFILE_FULL_EA_INFORMATION lastNtFullEa = NULL;
  211. PAGED_CODE( );
  212. //
  213. // Find out how large the OS/2 1.2 FEALIST will be after it is
  214. // converted to NT format. This is necessary in order to
  215. // determine how large a buffer to allocate to receive the NT
  216. // EAs.
  217. //
  218. *BufferLength = SrvOs2FeaListSizeToNt( FeaList );
  219. //
  220. // Allocate a buffer to hold the NT list. This is allocated from
  221. // non-paged pool so that it may be used in IRP-based IO requests.
  222. //
  223. *NtFullEa = ALLOCATE_NONPAGED_POOL( *BufferLength, BlockTypeDataBuffer );
  224. if ( *NtFullEa == NULL ) {
  225. INTERNAL_ERROR(
  226. ERROR_LEVEL_EXPECTED,
  227. "SrvOs2FeaListToNt: Unable to allocate %d bytes from nonpaged "
  228. "pool.",
  229. *BufferLength,
  230. NULL
  231. );
  232. return STATUS_INSUFF_SERVER_RESOURCES;
  233. }
  234. //
  235. // Find the last location at which an FEA can start. The -1 is to
  236. // account for the zero terminator on the name field of the FEA.
  237. //
  238. lastFeaStartLocation = (PFEA)( (PCHAR)FeaList +
  239. SmbGetUlong( &FeaList->cbList ) -
  240. sizeof(FEA) - 1 );
  241. //
  242. // Go through the FEA list, converting from OS/2 1.2 format to NT
  243. // until we pass the last possible location in which an FEA can start.
  244. //
  245. for ( fea = FeaList->list, ntFullEa = *NtFullEa, lastNtFullEa = ntFullEa;
  246. fea <= lastFeaStartLocation;
  247. fea = (PFEA)( (PCHAR)fea + sizeof(FEA) +
  248. fea->cbName + 1 + SmbGetUshort( &fea->cbValue ) ) ) {
  249. //
  250. // Check for an invalid flag bit. If set, return an error.
  251. //
  252. if ( (fea->fEA & ~FEA_NEEDEA) != 0 ) {
  253. *EaErrorOffset = (USHORT)( (PCHAR)fea - (ULONG)FeaList );
  254. return STATUS_INVALID_PARAMETER;
  255. }
  256. lastNtFullEa = ntFullEa;
  257. lastFea = fea;
  258. ntFullEa = SrvOs2FeaToNt( ntFullEa, fea );
  259. }
  260. //
  261. // Make sure that the FEALIST size parameter was correct. If we ended
  262. // on an EA that was not the first location after the end of the
  263. // last FEA, then the size parameter was wrong. Return an offset to
  264. // the EA that caused the error.
  265. //
  266. if ( (PCHAR)fea != (PCHAR)FeaList + SmbGetUlong( &FeaList->cbList ) ) {
  267. *EaErrorOffset = (USHORT)( (PCHAR)lastFea - (PCHAR)FeaList );
  268. DEALLOCATE_NONPAGED_POOL( *NtFullEa );
  269. return STATUS_UNSUCCESSFUL;
  270. }
  271. //
  272. // Set the NextEntryOffset field of the last full EA to 0 to indicate
  273. // the end of the list.
  274. //
  275. lastNtFullEa->NextEntryOffset = 0;
  276. return STATUS_SUCCESS;
  277. } // SrvOs2FeaListToNt
  278. ULONG
  279. SrvOs2FeaListSizeToNt (
  280. IN PFEALIST FeaList
  281. )
  282. /*++
  283. Routine Description:
  284. Get the number of bytes that would be required to represent the
  285. FEALIST in NT format.
  286. WARNING: This routine makes no checks on the size of the FEALIST
  287. buffer. It is assumed that FeaList->cbList is a legitimate value.
  288. WARNING: The value returned by this routine may be as much as three
  289. higher than the actual size needed to hold the FEAs in NT format.
  290. See comments below.
  291. Arguments:
  292. Fea - a pointer to the list of FEAs.
  293. Return Value:
  294. ULONG - number of bytes required to hold the EAs in NT format.
  295. --*/
  296. {
  297. ULONG size = 0;
  298. PFEA lastFeaStartLocation;
  299. PFEA fea;
  300. PAGED_CODE( );
  301. //
  302. // Find the last location at which an FEA can start. The -1 is to
  303. // account for the zero terminator on the name field of the FEA.
  304. //
  305. lastFeaStartLocation = (PFEA)( (PCHAR)FeaList +
  306. SmbGetUlong( &FeaList->cbList ) -
  307. sizeof(FEA) - 1 );
  308. //
  309. // Go through the FEA list until we pass the last possible location
  310. // in which an FEA can start.
  311. //
  312. for ( fea = FeaList->list;
  313. fea <= lastFeaStartLocation;
  314. fea = (PFEA)( (PCHAR)fea + sizeof(FEA) +
  315. fea->cbName + 1 + SmbGetUshort( &fea->cbValue ) ) ) {
  316. //
  317. // SmbGetNtSizeOfFea returns the number of bytes needed to hold
  318. // a single FEA in NT format, including any padding needed for
  319. // longword-alignment. Since the size of the buffer needed to
  320. // hold the NT EA list does not include any padding after the
  321. // last EA, the value returned by this routine may be as much as
  322. // three higher than the size actually needed.
  323. //
  324. size += SmbGetNtSizeOfFea( fea );
  325. }
  326. return size;
  327. } // SrvOs2FeaListSizeToNt
  328. PVOID
  329. SrvOs2FeaToNt (
  330. OUT PFILE_FULL_EA_INFORMATION NtFullEa,
  331. IN PFEA Fea
  332. )
  333. /*++
  334. Routine Description:
  335. Converts a single OS/2 FEA to NT full EA style. The FEA need not have
  336. any particular alignment. This routine makes no checks on buffer
  337. overrunning--this is the responsibility of the calling routine.
  338. Arguments:
  339. NtFullEa - a pointer to where the NT full EA is to be written.
  340. Fea - pointer to the OS/2 1.2 FEA to convert.
  341. Return Value:
  342. A pointer to the location after the last byte written.
  343. --*/
  344. {
  345. PCHAR ptr;
  346. PAGED_CODE( );
  347. NtFullEa->Flags = Fea->fEA;
  348. NtFullEa->EaNameLength = Fea->cbName;
  349. NtFullEa->EaValueLength = SmbGetUshort( &Fea->cbValue );
  350. ptr = NtFullEa->EaName;
  351. RtlMoveMemory( ptr, (PVOID)(Fea+1), Fea->cbName );
  352. ptr += NtFullEa->EaNameLength;
  353. *ptr++ = '\0';
  354. //
  355. // Copy the EA value to the NT full EA.
  356. //
  357. RtlMoveMemory(
  358. ptr,
  359. (PCHAR)(Fea+1) + NtFullEa->EaNameLength + 1,
  360. NtFullEa->EaValueLength
  361. );
  362. ptr += NtFullEa->EaValueLength;
  363. //
  364. // Longword-align ptr to determine the offset to the next location
  365. // for an NT full EA.
  366. //
  367. ptr = (PCHAR)( ((ULONG)ptr + 3) & ~3 );
  368. NtFullEa->NextEntryOffset = (ULONG)( ptr - (PCHAR)NtFullEa );
  369. return ptr;
  370. } // SrvOs2FeaToNt
  371. NTSTATUS
  372. SrvOs2GeaListToNt (
  373. IN PGEALIST GeaList,
  374. OUT PFILE_GET_EA_INFORMATION *NtGetEa,
  375. OUT PULONG BufferLength,
  376. OUT PUSHORT EaErrorOffset
  377. )
  378. /*++
  379. Routine Description:
  380. Converts a list of OS/2 1.2 GEAs to NT style. Memory is allocated from
  381. non-paged pool to hold the NT get EA list. The calling routine is
  382. responsible for deallocating this memory when it is done with it.
  383. WARNING! It is the responsibility of the calling routine to ensure
  384. that the value in GeaList->cbList will fit within the buffer allocated
  385. to GeaList. This prevents malicious redirectors from causing an
  386. access violation in the server.
  387. Arguments:
  388. GeaList - pointer to the OS/2 1.2 GEALIST to convert.
  389. NtGetEa - a pointer to a pointer to where the NT-style get EA list
  390. is stored. A buffer is allocated and pointer to by *NtGetEa.
  391. BufferLength - length of the allocated buffer.
  392. Return Value:
  393. NTSTATUS - STATUS_SUCCESS or STATUS_INSUFF_SERVER_RESOURCES.
  394. --*/
  395. {
  396. PGEA lastGeaStartLocation;
  397. PGEA gea = NULL;
  398. PGEA lastGea = NULL;
  399. PFILE_GET_EA_INFORMATION ntGetEa = NULL;
  400. PFILE_GET_EA_INFORMATION lastNtGetEa = NULL;
  401. PAGED_CODE( );
  402. //
  403. // Find out how large the OS/2 1.2 GEALIST will be after it is
  404. // converted to NT format. This is necessary in order to
  405. // determine how large a buffer to allocate to receive the NT
  406. // EAs.
  407. //
  408. *BufferLength = SrvOs2GeaListSizeToNt( GeaList );
  409. if ( *BufferLength == 0 ) {
  410. *EaErrorOffset = 0;
  411. return STATUS_OS2_EA_LIST_INCONSISTENT;
  412. }
  413. //
  414. // Allocate a buffer to hold the NT list. This is allocated from
  415. // non-paged pool so that it may be used in IRP-based IO requests.
  416. //
  417. *NtGetEa = ALLOCATE_NONPAGED_POOL( *BufferLength, BlockTypeDataBuffer );
  418. if ( *NtGetEa == NULL ) {
  419. INTERNAL_ERROR(
  420. ERROR_LEVEL_EXPECTED,
  421. "SrvOs2GeaListToNt: Unable to allocate %d bytes from nonpaged "
  422. "pool.",
  423. *BufferLength,
  424. NULL
  425. );
  426. return STATUS_INSUFF_SERVER_RESOURCES;
  427. }
  428. //
  429. // Find the last location at which a GEA can start. The zero
  430. // terminator on the name field of the GEA is accounted for by the
  431. // szName[0] field in the GEA structure.
  432. //
  433. lastGeaStartLocation = (PGEA)( (PCHAR)GeaList +
  434. SmbGetUlong( &GeaList->cbList ) - sizeof(GEA) );
  435. //
  436. // Go through the GEA list, converting from OS/2 1.2 format to NT
  437. // until we pass the last possible location in which an GEA can start.
  438. //
  439. for ( gea = GeaList->list, ntGetEa = *NtGetEa, lastNtGetEa = ntGetEa;
  440. gea <= lastGeaStartLocation;
  441. gea = (PGEA)( (PCHAR)gea + sizeof(GEA) + gea->cbName ) ) {
  442. lastNtGetEa = ntGetEa;
  443. lastGea = gea;
  444. ntGetEa = SrvOs2GeaToNt( ntGetEa, gea );
  445. }
  446. //
  447. // Make sure that the GEALIST size parameter was correct. If we ended
  448. // on an EA that was not the first location after the end of the
  449. // last GEA, then the size parameter was wrong. Return an offset to
  450. // the EA that caused the error.
  451. //
  452. if ( (PCHAR)gea != (PCHAR)GeaList + SmbGetUlong( &GeaList->cbList ) ) {
  453. *EaErrorOffset = (USHORT)( (PCHAR)lastGea - (PCHAR)GeaList );
  454. return STATUS_UNSUCCESSFUL;
  455. }
  456. //
  457. // Set the NextEntryOffset field of the last get EA to 0 to indicate
  458. // the end of the list.
  459. //
  460. lastNtGetEa->NextEntryOffset = 0;
  461. return STATUS_SUCCESS;
  462. } // SrvOs2GeaListToNt
  463. ULONG
  464. SrvOs2GeaListSizeToNt (
  465. IN PGEALIST GeaList
  466. )
  467. /*++
  468. Routine Description:
  469. Get the number of bytes that would be required to represent the
  470. GEALIST in NT format.
  471. WARNING: This routine makes no checks on the size of the GEALIST
  472. buffer. It is assumed that GeaList->cbList is a legitimate value.
  473. WARNING: The value returned by this routine may be as much as three
  474. higher than the actual size needed to hold the GEAs in NT format.
  475. See comments below.
  476. Arguments:
  477. Gea - a pointer to the list of GEAs.
  478. Size - number of bytes required to hold the EAs in NT format.
  479. Return Value:
  480. NTSTATUS - STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW if the GEA list was
  481. larger than it's buffer.
  482. --*/
  483. {
  484. ULONG size = 0;
  485. PGEA lastGeaStartLocation;
  486. PGEA gea;
  487. PAGED_CODE( );
  488. //
  489. // Find the last location at which an GEA can start. The zero
  490. // terminator in the name is accounted for by the szName[1] field
  491. // at the end of the GEA structure definition.
  492. //
  493. lastGeaStartLocation = (PGEA)( (PCHAR)GeaList +
  494. SmbGetUlong( &GeaList->cbList ) - sizeof(GEA) );
  495. //
  496. // Go through the GEA list until we pass the last possible location
  497. // in which an GEA can start.
  498. //
  499. for ( gea = GeaList->list;
  500. gea <= lastGeaStartLocation;
  501. gea = (PGEA)( (PCHAR)gea + sizeof(GEA) + gea->cbName ) ) {
  502. //
  503. // SmbGetNtSizeOfGea returns the number of bytes needed to hold
  504. // a single GEA in NT format. This includes any padding needed
  505. // for longword-alignment. Since the size of the buffer needed
  506. // to hold the NT EA list does not include any padding after the
  507. // last EA, the value returned by this routine may be as much as
  508. // three higher than the size actually needed.
  509. //
  510. size += SmbGetNtSizeOfGea( gea );
  511. }
  512. return size;
  513. } // SrvOs2GeaListSizeToNt
  514. PVOID
  515. SrvOs2GeaToNt (
  516. OUT PFILE_GET_EA_INFORMATION NtGetEa,
  517. IN PGEA Gea
  518. )
  519. /*++
  520. Routine Description:
  521. Converts a single OS/2 GEA to NT get EA style. The GEA need not have
  522. any particular alignment. This routine makes no checks on buffer
  523. overrunning--this is the responsibility of the calling routine.
  524. Arguments:
  525. NtGetEa - a pointer to where the NT get EA is to be written.
  526. Gea - pointer to the OS/2 1.2 GEA to convert.
  527. Return Value:
  528. A pointer to the location after the last byte written.
  529. --*/
  530. {
  531. PCHAR ptr;
  532. PAGED_CODE( );
  533. NtGetEa->EaNameLength = Gea->cbName;
  534. ptr = NtGetEa->EaName;
  535. RtlMoveMemory( ptr, Gea->szName, Gea->cbName );
  536. ptr += NtGetEa->EaNameLength;
  537. *ptr++ = '\0';
  538. //
  539. // Longword-align ptr to determine the offset to the next location
  540. // for an NT full EA.
  541. //
  542. ptr = (PCHAR)( ((ULONG)ptr + 3) & ~3 );
  543. NtGetEa->NextEntryOffset = (ULONG)( ptr - (PCHAR)NtGetEa );
  544. return ptr;
  545. } // SrvOs2GeaToNt
  546. PVOID
  547. SrvNtFullEaToOs2 (
  548. OUT PFEA Fea,
  549. IN PFILE_FULL_EA_INFORMATION NtFullEa
  550. )
  551. /*++
  552. Routine Description:
  553. Converts a single NT full EA to OS/2 FEA style. The FEA need not have
  554. any particular alignment. This routine makes no checks on buffer
  555. overrunning--this is the responsibility of the calling routine.
  556. Arguments:
  557. Fea - a pointer to the location where the OS/2 FEA is to be written.
  558. NtFullEa - a pointer to the NT full EA.
  559. Return Value:
  560. A pointer to the location after the last byte written.
  561. --*/
  562. {
  563. PCHAR ptr;
  564. ULONG i;
  565. PAGED_CODE( );
  566. Fea->fEA = (UCHAR)NtFullEa->Flags;
  567. Fea->cbName = NtFullEa->EaNameLength;
  568. SmbPutUshort( &Fea->cbValue, NtFullEa->EaValueLength );
  569. //
  570. // Copy the attribute name.
  571. //
  572. for ( i = 0, ptr = (PCHAR) (Fea + 1);
  573. i < (ULONG) NtFullEa->EaNameLength;
  574. i++, ptr++) {
  575. *ptr = RtlUpperChar( NtFullEa->EaName[i] );
  576. }
  577. *ptr++ = '\0';
  578. RtlMoveMemory(
  579. ptr,
  580. NtFullEa->EaName + NtFullEa->EaNameLength + 1,
  581. NtFullEa->EaValueLength
  582. );
  583. return (ptr + NtFullEa->EaValueLength);
  584. } // SrvNtFullEaToOs2
  585. CLONG
  586. SrvGetNumberOfEasInList (
  587. IN PVOID List
  588. )
  589. /*++
  590. Routine Description:
  591. Finds the number of EAs in an NT get or full EA list. The list
  592. should have already been verified to be legitimate to prevent access
  593. violations.
  594. Arguments:
  595. List - a pointer to the NT get or full EA list.
  596. Return Value:
  597. CLONG - the number of EAs in the list.
  598. --*/
  599. {
  600. CLONG count = 1;
  601. PULONG ea;
  602. PAGED_CODE( );
  603. //
  604. // Walk through the list. The first longword of each EA is the offset
  605. // to the next EA.
  606. //
  607. for ( ea = List; *ea != 0; ea = (PULONG)( (PCHAR)ea + *ea ) ) {
  608. count++;
  609. }
  610. return count;
  611. } // SrvGetNumberOfEasInList
  612. NTSTATUS
  613. SrvQueryOs2FeaList (
  614. IN HANDLE FileHandle,
  615. IN PGEALIST GeaList OPTIONAL,
  616. IN PFILE_GET_EA_INFORMATION NtGetEaList OPTIONAL,
  617. IN ULONG GeaListLength OPTIONAL,
  618. IN PFEALIST FeaList,
  619. IN ULONG BufferLength,
  620. OUT PUSHORT EaErrorOffset
  621. )
  622. /*++
  623. Routine Description:
  624. Converts a single NT full EA list to OS/2 FEALIST style. The FEALIST
  625. need not have any particular alignment.
  626. Arguments:
  627. FileHandle - handle to a file open with FILE_READ_EA access.
  628. GeaList - if non-NULL, an OS/2 1.2 style GEALIST used to get only
  629. a subset of the files EAs rather than all the EAs. Only the
  630. EAs listed in GEALIST are returned.
  631. NtGetEaList - if non-NULL, an NT style get EA list used to get only
  632. a subset of the files EAs rather than all the EAs. Only the
  633. EAs listed in GEALIST are returned.
  634. GeaListLength - the maximum possible length of the GeaList (used to
  635. prevent access violations) or the actual size of the NtGetEaList.
  636. FeaList - where to write the OS/2 1.2 style FEALIST for the file.
  637. BufferLength - length of Buffer.
  638. Return Value:
  639. NTSTATUS - STATUS_SUCCESS, STATUS_BUFFER_OVERFLOW if the EAs wouldn't
  640. fit in Buffer, or a value returned by NtQuery{Information,Ea}File.
  641. --*/
  642. {
  643. NTSTATUS status;
  644. PFEA fea = FeaList->list;
  645. PFILE_FULL_EA_INFORMATION ntFullEa;
  646. PFILE_GET_EA_INFORMATION ntGetEa = NULL;
  647. ULONG ntGetEaBufferLength = 0;
  648. FILE_EA_INFORMATION eaInfo;
  649. IO_STATUS_BLOCK ioStatusBlock;
  650. PSRV_EA_INFORMATION eaInformation = NULL;
  651. ULONG eaBufferSize;
  652. ULONG errorOffset;
  653. BOOLEAN isFirstCall = TRUE;
  654. PAGED_CODE( );
  655. *EaErrorOffset = 0;
  656. //
  657. // Find out how big a buffer we need to get the EAs.
  658. //
  659. status = NtQueryInformationFile(
  660. FileHandle,
  661. &ioStatusBlock,
  662. &eaInfo,
  663. sizeof(FILE_EA_INFORMATION),
  664. FileEaInformation
  665. );
  666. if ( !NT_SUCCESS(status) ) {
  667. INTERNAL_ERROR(
  668. ERROR_LEVEL_UNEXPECTED,
  669. "SrvQueryOs2FeaList: NtQueryInformationFile(ea information) "
  670. "returned %X",
  671. status,
  672. NULL
  673. );
  674. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  675. goto exit;
  676. }
  677. //
  678. // If the file has no EAs, return an FEA size = 4 (that's what OS/2
  679. // does--it accounts for the size of the cbList field of an
  680. // FEALIST). Also, store the NT EA size in case there is a buffer
  681. // overflow and we need to return the total EA size to the client.
  682. //
  683. if ( eaInfo.EaSize == 0 ) {
  684. SmbPutUlong( &FeaList->cbList, 4 );
  685. } else {
  686. SmbPutUlong( &FeaList->cbList, eaInfo.EaSize );
  687. }
  688. if ( eaInfo.EaSize == 0 && GeaList == NULL && NtGetEaList == NULL ) {
  689. status = STATUS_SUCCESS;
  690. goto exit;
  691. }
  692. //
  693. // If a GEALIST was specified, convert it to NT style.
  694. //
  695. if ( ARGUMENT_PRESENT(GeaList) ) {
  696. //
  697. // Make sure that the value in GeaList->cbList is legitimate
  698. // (allows the GEALIST to fit within its buffer).
  699. //
  700. if ( SmbGetUlong( &GeaList->cbList ) > GeaListLength ) {
  701. status = STATUS_OS2_EA_LIST_INCONSISTENT;
  702. goto exit;
  703. }
  704. //
  705. // Convert the GEALIST to NT style. SrvOs2GeaListToNt allocates
  706. // space to hold the NT get EA list, so remember to deallocate
  707. // this before exiting this routine.
  708. //
  709. status = SrvOs2GeaListToNt(
  710. GeaList,
  711. &ntGetEa,
  712. &ntGetEaBufferLength,
  713. EaErrorOffset
  714. );
  715. if ( !NT_SUCCESS(status) ) {
  716. return status;
  717. }
  718. }
  719. //
  720. // If an NT-style get EA list was specified, use it.
  721. //
  722. if ( ARGUMENT_PRESENT(NtGetEaList) ) {
  723. ntGetEa = NtGetEaList;
  724. ntGetEaBufferLength = GeaListLength;
  725. }
  726. //
  727. // HACKHACK: eaInfo.EaSize is the size needed by OS/2. For NT,
  728. // the system has no way of telling us how big a buffer we need.
  729. // According to BrianAn, this should not be bigger than twice
  730. // what OS/2 needs.
  731. //
  732. eaBufferSize = eaInfo.EaSize * EA_SIZE_FUDGE_FACTOR;
  733. //
  734. // If a get EA list was specified, a larger buffer is needed to hold
  735. // all the EAs. This is because some or all of the specified EAs
  736. // may not exist, yet they will still be returned by the file system
  737. // with value length = 0. Add to the EA size the amount of space the
  738. // get EA list would use if it were converted to a full EA list.
  739. //
  740. if ( ntGetEa != NULL ) {
  741. eaBufferSize += ntGetEaBufferLength +
  742. ( SrvGetNumberOfEasInList( ntGetEa ) *
  743. ( sizeof(FILE_FULL_EA_INFORMATION) -
  744. sizeof(FILE_GET_EA_INFORMATION) ));
  745. }
  746. //
  747. // Allocate a buffer to receive the EAs. If the total EA size is
  748. // small enough to get it all in one call to NtQueryEaFile, allocate
  749. // a buffer that large. If The EAs are large, use a buffer size that
  750. // is the smallest size guaranteed to hold at least one EA.
  751. //
  752. // The buffer must be allocated from non-paged pool for the IRP
  753. // request built below.
  754. //
  755. eaBufferSize = MIN( MAX_SIZE_OF_SINGLE_EA, eaBufferSize ) +
  756. sizeof(SRV_EA_INFORMATION);
  757. eaInformation = ALLOCATE_NONPAGED_POOL( eaBufferSize, BlockTypeDataBuffer );
  758. if ( eaInformation == NULL ) {
  759. INTERNAL_ERROR(
  760. ERROR_LEVEL_EXPECTED,
  761. "SrvQueryOs2FeaList: Unable to allocate %d bytes from nonpaged "
  762. "pool.",
  763. eaBufferSize,
  764. NULL
  765. );
  766. status = STATUS_INSUFF_SERVER_RESOURCES;
  767. goto exit;
  768. }
  769. //
  770. // Get the EAs.
  771. //
  772. while(1) {
  773. ULONG feaSize;
  774. status = SrvQueryEaFile(
  775. isFirstCall,
  776. FileHandle,
  777. ntGetEa,
  778. ntGetEaBufferLength,
  779. eaInformation,
  780. eaBufferSize,
  781. &errorOffset
  782. );
  783. if ( status == STATUS_NO_MORE_EAS ) {
  784. break;
  785. }
  786. if ( !NT_SUCCESS(status) ) {
  787. if ( ARGUMENT_PRESENT(GeaList) ) {
  788. *EaErrorOffset = SrvGetOs2GeaOffsetOfError(
  789. errorOffset,
  790. ntGetEa,
  791. GeaList
  792. );
  793. //
  794. // SrvQueryEaFile has already logged the error. Do not
  795. // create another log entry here.
  796. //
  797. IF_DEBUG(SMB_ERRORS) {
  798. PGEA errorGea = (PGEA)( (PCHAR)GeaList + *EaErrorOffset );
  799. SrvPrint1( "EA error offset in GEALIST: 0x%lx\n", *EaErrorOffset );
  800. SrvPrint1( "name: %s\n", errorGea->szName );
  801. }
  802. }
  803. goto exit;
  804. }
  805. isFirstCall = FALSE;
  806. ntFullEa = eaInformation->CurrentEntry;
  807. //
  808. // See if there is enough room to hold the EA in the user buffer.
  809. //
  810. // *** STATUS_BUFFER_OVERFLOW is a special status code for the
  811. // find2 logic. See that code before making changes here.
  812. feaSize = SmbGetOs2SizeOfNtFullEa( ntFullEa );
  813. if ( feaSize > (ULONG)( (PCHAR)FeaList + BufferLength - (PCHAR)fea ) ) {
  814. status = STATUS_BUFFER_OVERFLOW;
  815. goto exit;
  816. }
  817. //
  818. // Copy the NT format EA to OS/2 1.2 format and set the fea
  819. // pointer for the next iteration.
  820. //
  821. fea = SrvNtFullEaToOs2( fea, ntFullEa );
  822. ASSERT( (ULONG)fea <= (ULONG)FeaList + BufferLength );
  823. }
  824. //
  825. // Set the number of bytes in the FEALIST.
  826. //
  827. SmbPutUlong(
  828. &FeaList->cbList,
  829. (PCHAR)fea - (PCHAR)FeaList
  830. );
  831. status = STATUS_SUCCESS;
  832. exit:
  833. //
  834. // Deallocate the buffers used to hold the NT get and full EA lists.
  835. //
  836. if ( ntGetEa != NULL && ARGUMENT_PRESENT(GeaList) ) {
  837. DEALLOCATE_NONPAGED_POOL( ntGetEa );
  838. }
  839. if ( eaInformation != NULL ) {
  840. DEALLOCATE_NONPAGED_POOL( eaInformation );
  841. }
  842. return status;
  843. } // SrvQueryOs2FeaList
  844. NTSTATUS
  845. SrvSetOs2FeaList (
  846. IN HANDLE FileHandle,
  847. IN PFEALIST FeaList,
  848. IN ULONG BufferLength,
  849. OUT PUSHORT EaErrorOffset
  850. )
  851. /*++
  852. Routine Description:
  853. Sets the EAs on a file given an OS/2 1.2 representation of the EAs.
  854. Arguments:
  855. FileHandle - handle to a file open with FILE_WRITE_EA access whose
  856. EAs are to be set.
  857. FeaList - a pointer to the location where the OS/2 FEALIST is stored.
  858. BufferLength - maximum size of the buffer the FEALIST structure can
  859. have. This is used to prevent a malicious redirector from causing
  860. an access violation in the server.
  861. Return Value:
  862. NTSTATUS - what happened
  863. --*/
  864. {
  865. NTSTATUS status;
  866. ULONG os2FeaListSize;
  867. PFILE_FULL_EA_INFORMATION ntFullEa;
  868. ULONG ntFullEaBufferLength;
  869. ULONG errorOffset;
  870. PAGED_CODE( );
  871. *EaErrorOffset = 0;
  872. //
  873. // Special case for too-small FEALIST: don't set anything.
  874. //
  875. if ( SmbGetUlong( &FeaList->cbList ) <= sizeof(FeaList->cbList) ) {
  876. return STATUS_SUCCESS;
  877. }
  878. //
  879. // Make sure that the value in Fealist->cbList is legitimate.
  880. //
  881. os2FeaListSize = SmbGetUlong( &FeaList->cbList );
  882. if ( os2FeaListSize > BufferLength ) {
  883. DEBUG SrvPrint2(
  884. "SrvSetOs2FeaList: EA list size is inconsistent. Actual size"
  885. "is %d, expected maximum size is %d",
  886. os2FeaListSize,
  887. BufferLength
  888. );
  889. return STATUS_OS2_EA_LIST_INCONSISTENT;
  890. }
  891. //
  892. // Convert the FEALIST to NT style.
  893. //
  894. status = SrvOs2FeaListToNt(
  895. FeaList,
  896. &ntFullEa,
  897. &ntFullEaBufferLength,
  898. EaErrorOffset
  899. );
  900. if ( !NT_SUCCESS(status) ) {
  901. //
  902. // SrvOs2FeaListToNt has already logged the error. Do not
  903. // create another log entry here.
  904. //
  905. return status;
  906. }
  907. //
  908. // Set the file's EAs with a directly-built IRP. Doing this rather
  909. // than calling the NtSetEaFile system service prevents a copy of
  910. // the input data from occurring.
  911. //
  912. // *** The operation is performed synchronously.
  913. //
  914. status = SrvIssueSetEaRequest(
  915. FileHandle,
  916. ntFullEa,
  917. ntFullEaBufferLength,
  918. &errorOffset
  919. );
  920. if ( !NT_SUCCESS(status) ) {
  921. //
  922. // An error occurred. Find the offset into the EA list of the
  923. // error.
  924. //
  925. *EaErrorOffset = SrvGetOs2FeaOffsetOfError(
  926. errorOffset,
  927. ntFullEa,
  928. FeaList
  929. );
  930. INTERNAL_ERROR(
  931. ERROR_LEVEL_EXPECTED,
  932. "SrvSetOs2FeaList: SrvIssueSetEaRequest returned %X",
  933. status,
  934. NULL
  935. );
  936. IF_DEBUG(ERRORS) {
  937. PFEA errorFea = (PFEA)( (PCHAR)FeaList + *EaErrorOffset );
  938. SrvPrint1( "EA error offset in FEALIST: 0x%lx\n", *EaErrorOffset );
  939. SrvPrint3( "name: %s, value len: %ld, value: %s", errorFea+1,
  940. SmbGetUshort( &errorFea->cbValue ),
  941. (PCHAR)(errorFea+1) + errorFea->cbName + 1 );
  942. }
  943. }
  944. //
  945. // Deallocate the buffer used to hold the NT full EA list.
  946. //
  947. DEALLOCATE_NONPAGED_POOL( ntFullEa );
  948. return status;
  949. } // SrvSetOs2FeaList
  950. NTSTATUS
  951. SrvConstructNullOs2FeaList (
  952. IN PFILE_GET_EA_INFORMATION NtGeaList,
  953. OUT PFEALIST FeaList,
  954. IN ULONG BufferLength
  955. )
  956. /*++
  957. Routine Description:
  958. Converts a single NT full EA list to OS/2 FEALIST style for files
  959. with no eas. When a file has no eas but a GEAlist was supplied,
  960. we need to return an ealist that has all the attributes specified
  961. in the GEAlist present but with CbValues of 0. This routine was
  962. specifically written for the files . and .. but can be used to get
  963. the FEAlist of a no ea file given the NT Gea list.
  964. Arguments:
  965. NtGetEaList - if non-NULL, an NT style get EA list used to get only
  966. a subset of the files EAs rather than all the EAs. Only the
  967. EAs listed in GEALIST are returned.
  968. FeaList - where to write the OS/2 1.2 style FEALIST for the file.
  969. BufferLength - length of Buffer.
  970. Return Value:
  971. NTSTATUS - STATUS_SUCCESS, STATUS_BUFFER_OVERFLOW if the EAs wouldn't
  972. fit in Buffer, or a value returned by NtQuery{Information,Ea}File.
  973. --*/
  974. {
  975. PCHAR ptr;
  976. PFEA fea = FeaList->list;
  977. PFILE_GET_EA_INFORMATION currentGea = NtGeaList;
  978. LONG remainingBytes = BufferLength;
  979. ULONG i;
  980. PAGED_CODE( );
  981. //
  982. // Get the EAs.
  983. //
  984. for ( ; ; ) {
  985. //
  986. // Is our buffer big enough?
  987. //
  988. remainingBytes -= ( sizeof( FEA ) + currentGea->EaNameLength + 1 );
  989. if ( remainingBytes < 0 ) {
  990. return STATUS_BUFFER_OVERFLOW;
  991. }
  992. //
  993. // We know what these are.
  994. //
  995. fea->fEA = 0;
  996. fea->cbName = currentGea->EaNameLength;
  997. SmbPutUshort( &fea->cbValue, 0);
  998. //
  999. // Copy the attribute name.
  1000. //
  1001. for ( i = 0, ptr = (PCHAR) (fea + 1);
  1002. i < (ULONG) currentGea->EaNameLength;
  1003. i++, ptr++) {
  1004. *ptr = RtlUpperChar( currentGea->EaName[i] );
  1005. }
  1006. *ptr++ = '\0';
  1007. fea = (PFEA) ptr;
  1008. //
  1009. // Is this the last one?
  1010. //
  1011. if ( currentGea->NextEntryOffset == 0 ) {
  1012. break;
  1013. }
  1014. //
  1015. // Move to the next attribute
  1016. //
  1017. currentGea = (PFILE_GET_EA_INFORMATION)
  1018. ((PCHAR) currentGea + currentGea->NextEntryOffset);
  1019. }
  1020. //
  1021. // Set the number of bytes in the FEALIST.
  1022. //
  1023. SmbPutUlong(
  1024. &FeaList->cbList,
  1025. (PCHAR)fea - (PCHAR)FeaList
  1026. );
  1027. return STATUS_SUCCESS;
  1028. } // SrvConstructNullOs2FeaList