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.

1512 lines
38 KiB

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