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.

1353 lines
32 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. svcshare.c
  5. Abstract:
  6. This module contains routines for supporting the share APIs in the
  7. server service, NetShareAdd, NetShareCheck, NetShareDel,
  8. NetShareEnum, NetShareGetInfo, and NetShareSetInfo.
  9. Author:
  10. David Treadwell (davidtr) 15-Jan-1991
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "svcshare.tmh"
  15. #pragma hdrstop
  16. #define BugCheckFileId SRV_FILE_SVCSHARE
  17. #define DISK_ROOT_NAME_TEMPLATE L"\\DosDevices\\X:\\"
  18. //
  19. // Forward declarations.
  20. //
  21. STATIC
  22. VOID
  23. FillShareInfoBuffer (
  24. IN PSERVER_REQUEST_PACKET Srp,
  25. IN PVOID Block,
  26. IN OUT PVOID *FixedStructure,
  27. IN LPWSTR *EndOfVariableData
  28. );
  29. STATIC
  30. BOOLEAN
  31. FilterShares (
  32. IN PSERVER_REQUEST_PACKET Srp,
  33. IN PVOID Block
  34. );
  35. STATIC
  36. ULONG
  37. SizeShares (
  38. IN PSERVER_REQUEST_PACKET Srp,
  39. IN PVOID Block
  40. );
  41. #ifdef ALLOC_PRAGMA
  42. #pragma alloc_text( PAGE, SrvNetShareAdd )
  43. #pragma alloc_text( PAGE, SrvNetShareDel )
  44. #pragma alloc_text( PAGE, SrvNetShareEnum )
  45. #pragma alloc_text( PAGE, SrvNetShareSetInfo )
  46. #pragma alloc_text( PAGE, FillShareInfoBuffer )
  47. #pragma alloc_text( PAGE, FilterShares )
  48. #pragma alloc_text( PAGE, SizeShares )
  49. #endif
  50. #define FIXED_SIZE_OF_SHARE(level) \
  51. ( (level) == 0 ? sizeof(SHARE_INFO_0) : \
  52. (level) == 1 ? sizeof(SHARE_INFO_1) : \
  53. (level) == 2 ? sizeof(SHARE_INFO_2) : \
  54. (level) == 501 ? sizeof(SHARE_INFO_501) : \
  55. (level) == 502 ? sizeof(SHARE_INFO_502) : \
  56. sizeof(SHARE_INFO_1005) )
  57. NTSTATUS
  58. SrvNetShareAdd (
  59. IN PSERVER_REQUEST_PACKET Srp,
  60. IN PVOID Buffer,
  61. IN ULONG BufferLength
  62. )
  63. /*++
  64. Routine Description:
  65. This routine processes the NetShareAdd API in the server.
  66. Arguments:
  67. Srp - a pointer to the server request packet that contains all
  68. the information necessary to satisfy the request. This includes:
  69. INPUT:
  70. Name1 - the NT path name of the share.
  71. OUTPUT:
  72. Parameters.Set.ErrorParameter - if STATUS_INVALID_PARAMETER is
  73. returned, this contains the index of the parameter in error.
  74. Buffer - a pointer to a SHARE_INFO2 structure for the new share.
  75. BufferLength - total length of this buffer.
  76. Return Value:
  77. NTSTATUS - result of operation to return to the server service.
  78. --*/
  79. {
  80. #ifdef INCLUDE_SMB_PERSISTENT
  81. ULONG strippedType;
  82. BOOLEAN allowPersistentHandles;
  83. #endif
  84. NTSTATUS status;
  85. PSHARE share;
  86. SHARE_TYPE shareType;
  87. BOOLEAN isSpecial;
  88. BOOLEAN isRemovable;
  89. BOOLEAN isCdrom;
  90. UNICODE_STRING shareName;
  91. UNICODE_STRING ntPath;
  92. UNICODE_STRING dosPath;
  93. UNICODE_STRING remark;
  94. PSHARE_INFO_502 shi502;
  95. PSECURITY_DESCRIPTOR securityDescriptor = NULL;
  96. PSECURITY_DESCRIPTOR fileSecurityDescriptor = NULL;
  97. PAGED_CODE( );
  98. //
  99. // We usually don't return any information about the parameter in
  100. // error.
  101. //
  102. Srp->Parameters.Set.ErrorParameter = 0;
  103. //
  104. // Convert the offsets in the share data structure to pointers. Also
  105. // make sure that all the pointers are within the specified buffer.
  106. //
  107. shi502 = Buffer;
  108. OFFSET_TO_POINTER( shi502->shi502_netname, shi502 );
  109. OFFSET_TO_POINTER( shi502->shi502_remark, shi502 );
  110. OFFSET_TO_POINTER( shi502->shi502_path, shi502 );
  111. OFFSET_TO_POINTER( shi502->shi502_security_descriptor, shi502 );
  112. //
  113. // Construct the security descriptor pointer by hand, because
  114. // shi502_permissions is only 32 bits in width.
  115. //
  116. if( shi502->shi502_permissions ) {
  117. securityDescriptor =
  118. (PSECURITY_DESCRIPTOR)((PCHAR)shi502 + shi502->shi502_permissions);
  119. }
  120. else
  121. {
  122. // Connect securityDescriptor is REQUIRED!
  123. return STATUS_INVALID_PARAMETER;
  124. }
  125. if ( !POINTER_IS_VALID( shi502->shi502_netname, shi502, BufferLength ) ||
  126. !POINTER_IS_VALID( shi502->shi502_remark, shi502, BufferLength ) ||
  127. !POINTER_IS_VALID( shi502->shi502_path, shi502, BufferLength ) ||
  128. !POINTER_IS_VALID( securityDescriptor, shi502, BufferLength ) ||
  129. !POINTER_IS_VALID( shi502->shi502_security_descriptor, shi502, BufferLength ) ) {
  130. return STATUS_ACCESS_VIOLATION;
  131. }
  132. //
  133. // Check the share type
  134. //
  135. isSpecial = (BOOLEAN)((shi502->shi502_type & STYPE_SPECIAL) != 0);
  136. isRemovable = FALSE;
  137. isCdrom = FALSE;
  138. #ifdef INCLUDE_SMB_PERSISTENT
  139. allowPersistentHandles = (BOOLEAN)((shi502->shi502_type & STYPE_PERSISTENT) != 0);
  140. strippedType = shi502->shi502_type & ~(STYPE_TEMPORARY|STYPE_SPECIAL);
  141. strippedType = strippedType & ~STYPE_PERSISTENT;
  142. if (strippedType == STYPE_DISKTREE) {
  143. // for now, hardcode in that all disk shares are persistent.
  144. // need to fix this for persistent handles.
  145. allowPersistentHandles = TRUE;
  146. }
  147. switch ( strippedType ) {
  148. #else
  149. switch ( shi502->shi502_type & ~(STYPE_TEMPORARY|STYPE_SPECIAL) ) {
  150. #endif
  151. case STYPE_CDROM:
  152. isCdrom = TRUE; // lack of break is intentional
  153. case STYPE_REMOVABLE:
  154. isRemovable = TRUE; // lack of break is intentional
  155. case STYPE_DISKTREE:
  156. shareType = ShareTypeDisk;
  157. break;
  158. case STYPE_PRINTQ:
  159. shareType = ShareTypePrint;
  160. break;
  161. case STYPE_IPC:
  162. shareType = ShareTypePipe;
  163. break;
  164. default:
  165. //
  166. // An illegal share type was passed in.
  167. //
  168. IF_DEBUG(SMB_ERRORS) {
  169. KdPrint(( "SrvNetShareAdd: illegal share type: %ld\n",
  170. shi502->shi502_type ));
  171. }
  172. Srp->Parameters.Set.ErrorParameter = SHARE_TYPE_PARMNUM;
  173. return STATUS_INVALID_PARAMETER;
  174. }
  175. //
  176. // Get pointers to the share name, path, remark, and security
  177. // descriptor.
  178. //
  179. RtlInitUnicodeString( &shareName, (PWCH)shi502->shi502_netname );
  180. ntPath = Srp->Name1;
  181. RtlInitUnicodeString( &dosPath, (PWCH)shi502->shi502_path );
  182. RtlInitUnicodeString( &remark, (PWCH)shi502->shi502_remark );
  183. //
  184. // If this is level 502, get the file security descriptor
  185. //
  186. if ( Srp->Level == 502 ) {
  187. fileSecurityDescriptor = shi502->shi502_security_descriptor;
  188. //
  189. // if the sd is invalid, quit.
  190. //
  191. if ( fileSecurityDescriptor != NULL &&
  192. !RtlValidSecurityDescriptor( fileSecurityDescriptor) ) {
  193. Srp->Parameters.Set.ErrorParameter = SHARE_FILE_SD_PARMNUM;
  194. return STATUS_INVALID_PARAMETER;
  195. }
  196. }
  197. //
  198. // Allocate a share block.
  199. //
  200. SrvAllocateShare(
  201. &share,
  202. &shareName,
  203. &ntPath,
  204. &dosPath,
  205. &remark,
  206. securityDescriptor,
  207. fileSecurityDescriptor,
  208. shareType
  209. );
  210. if ( share == NULL ) {
  211. DEBUG KdPrint(( "SrvNetShareAdd: unable to allocate share block\n" ));
  212. return STATUS_INSUFF_SERVER_RESOURCES;
  213. }
  214. share->SpecialShare = isSpecial;
  215. share->Removable = isRemovable;
  216. #ifdef INCLUDE_SMB_PERSISTENT
  217. share->AllowPersistentHandles = allowPersistentHandles;
  218. #endif
  219. //
  220. // Set the MaxUses field in the share. The CurrentUses field was
  221. // zeroed by SrvAllocateShare.
  222. //
  223. share->MaxUses = shi502->shi502_max_uses;
  224. if ( shareType == ShareTypePrint ) {
  225. status = SrvOpenPrinter((PWCH)shi502->shi502_path,
  226. &share->Type.hPrinter,
  227. &Srp->ErrorCode
  228. );
  229. if ( !NT_SUCCESS(status) ) {
  230. SrvFreeShare( share );
  231. return status;
  232. }
  233. if ( Srp->ErrorCode != NO_ERROR ) {
  234. SrvFreeShare( share );
  235. return STATUS_SUCCESS;
  236. }
  237. }
  238. //
  239. // Mark the share if it is in the DFS
  240. //
  241. SrvIsShareInDfs( share, &share->IsDfs, &share->IsDfsRoot );
  242. //
  243. // Ensure that another share with the same name doesn't already
  244. // exist. Insert the share block in the global share list.
  245. //
  246. ACQUIRE_LOCK( &SrvShareLock );
  247. if ( SrvFindShare( &share->ShareName ) != NULL ) {
  248. //
  249. // A share with the same name exists. Clean up and return an
  250. // error.
  251. //
  252. // *** Note that SrvFindShare ignores existing shares that are
  253. // closing. This allows a new share to be created even if
  254. // and old share with the same name is in the "twilight
  255. // zone" between existence and nonexistence because of a
  256. // stray reference.
  257. //
  258. RELEASE_LOCK( &SrvShareLock );
  259. SrvFreeShare( share );
  260. Srp->ErrorCode = NERR_DuplicateShare;
  261. return STATUS_SUCCESS;
  262. }
  263. //
  264. // Insert the share on the global ordered list.
  265. //
  266. SrvAddShare( share );
  267. RELEASE_LOCK( &SrvShareLock );
  268. //
  269. // Is this is a removable type e.g. Floppy or CDROM, fill up the
  270. // file system name.
  271. //
  272. if ( isRemovable ) {
  273. PWSTR fileSystemName;
  274. ULONG fileSystemNameLength;
  275. if ( isCdrom ) {
  276. //
  277. // uses cdfs
  278. //
  279. fileSystemName = StrFsCdfs;
  280. fileSystemNameLength = sizeof( FS_CDFS ) - sizeof(WCHAR);
  281. } else {
  282. //
  283. // assume it's fat
  284. //
  285. fileSystemName = StrFsFat;
  286. fileSystemNameLength = sizeof( FS_FAT ) - sizeof(WCHAR);
  287. }
  288. SrvFillInFileSystemName(
  289. share,
  290. fileSystemName,
  291. fileSystemNameLength
  292. );
  293. }
  294. //
  295. // If this is an administrative disk share, update SrvDiskConfiguration
  296. // to cause the scavenger thread to check the disk free space. The server
  297. // service has already verified that the format of the pathname is valid
  298. // before it allowed the ShareAdd to get this far.
  299. //
  300. // We want to skip this if its a \\?\ name
  301. //
  302. if( share->SpecialShare && share->ShareType == ShareTypeDisk &&
  303. share->ShareName.Buffer[1] == L'$' &&
  304. share->DosPathName.Buffer[0] != L'\\' ) {
  305. ACQUIRE_LOCK( &SrvConfigurationLock );
  306. SrvDiskConfiguration |= (0x80000000 >> (share->DosPathName.Buffer[0] - L'A'));
  307. RELEASE_LOCK( &SrvConfigurationLock );
  308. }
  309. //
  310. // Dereference the share block, because we're going to forget
  311. // its address. (The initial reference count is 2.)
  312. //
  313. SrvDereferenceShare( share );
  314. return STATUS_SUCCESS;
  315. } // SrvNetShareAdd
  316. NTSTATUS
  317. SrvNetShareDel (
  318. IN PSERVER_REQUEST_PACKET Srp,
  319. IN PVOID Buffer,
  320. IN ULONG BufferLength
  321. )
  322. /*++
  323. Routine Description:
  324. This routine processes the NetShareDel API in the server.
  325. Arguments:
  326. Srp - a pointer to the server request packet that contains all
  327. the information necessary to satisfy the request. This includes:
  328. INPUT:
  329. Name1 - name of the share to delete.
  330. OUTPUT:
  331. None.
  332. Buffer - unused.
  333. BufferLength - unused.
  334. Return Value:
  335. NTSTATUS - result of operation to return to the server service.
  336. --*/
  337. {
  338. PSHARE share;
  339. DWORD AdministrativeDiskBit = 0;
  340. PAGED_CODE( );
  341. Buffer, BufferLength;
  342. //
  343. // Find the share with the specified name. Note that if a share
  344. // with the specified name exists but is closing, it will not be
  345. // found.
  346. //
  347. ACQUIRE_LOCK( &SrvShareLock );
  348. share = SrvFindShare( &Srp->Name1 );
  349. if ( share == NULL ) {
  350. //
  351. // No share with the specified name exists. Return an error.
  352. //
  353. RELEASE_LOCK( &SrvShareLock );
  354. Srp->ErrorCode = NERR_NetNameNotFound;
  355. return STATUS_SUCCESS;
  356. }
  357. //
  358. // Make sure the DFS state for this share is accurate
  359. //
  360. SrvIsShareInDfs( share, &share->IsDfs, &share->IsDfsRoot );
  361. //
  362. // If the share really is in the DFS, then do not allow it to be deleted
  363. //
  364. if( share->IsDfs == TRUE ) {
  365. RELEASE_LOCK( &SrvShareLock );
  366. IF_DEBUG( DFS ) {
  367. KdPrint(("NetShareDel attempted on share in DFS!\n" ));
  368. }
  369. Srp->ErrorCode = NERR_IsDfsShare;
  370. return STATUS_SUCCESS;
  371. }
  372. // Don't allow the deletion of IPC$, as behavior is very bad with it gone
  373. // (Named-pipe traffic doesn't work, so NetAPI's and RPC don't work..)
  374. if( share->SpecialShare )
  375. {
  376. UNICODE_STRING Ipc = { 8, 8, L"IPC$" };
  377. if( RtlCompareUnicodeString( &Ipc, &share->ShareName, TRUE ) == 0 )
  378. {
  379. RELEASE_LOCK( &SrvShareLock );
  380. Srp->ErrorCode = ERROR_ACCESS_DENIED;
  381. return STATUS_SUCCESS;
  382. }
  383. }
  384. switch( share->ShareType ) {
  385. case ShareTypePrint:
  386. //
  387. // This is a print share: close the printer.
  388. //
  389. SrvClosePrinter( share->Type.hPrinter );
  390. break;
  391. case ShareTypeDisk:
  392. //
  393. // See if this was an administrative disk share
  394. //
  395. if( share->SpecialShare && share->DosPathName.Buffer[1] == L'$' ) {
  396. AdministrativeDiskBit = (0x80000000 >> (share->DosPathName.Buffer[0] - L'A'));
  397. }
  398. break;
  399. }
  400. //
  401. // Close the share, then release the lock.
  402. //
  403. // *** Note that this places a requirement on lock levels! See
  404. // lock.h .
  405. //
  406. #ifdef INCLUDE_SMB_PERSISTENT
  407. if (share->AllowPersistentHandles) {
  408. // clean up state file here...
  409. }
  410. #endif
  411. SrvCloseShare( share );
  412. RELEASE_LOCK( &SrvShareLock );
  413. //
  414. // If this was an administrative disk share, update SrvDiskConfiguration
  415. // to cause the scavenger thread to ignore this disk.
  416. //
  417. if( AdministrativeDiskBit ) {
  418. ACQUIRE_LOCK( &SrvConfigurationLock );
  419. SrvDiskConfiguration &= ~AdministrativeDiskBit;
  420. RELEASE_LOCK( &SrvConfigurationLock );
  421. }
  422. return STATUS_SUCCESS;
  423. } // SrvNetShareDel
  424. NTSTATUS
  425. SrvNetShareEnum (
  426. IN PSERVER_REQUEST_PACKET Srp,
  427. IN PVOID Buffer,
  428. IN ULONG BufferLength
  429. )
  430. /*++
  431. Routine Description:
  432. This routine processes the NetShareEnum API in the server.
  433. Arguments:
  434. Srp - a pointer to the server request packet that contains all
  435. the information necessary to satisfy the request. This includes:
  436. INPUT:
  437. Level - level of information to return, 0, 1, or 2.
  438. Parameters.Get.ResumeHandle - share ID to determine where to
  439. start returning info. We start with the first share with an
  440. ID greater than this value.
  441. OUTPUT:
  442. Parameters.Get.EntriesRead - the number of entries that fit in
  443. the output buffer.
  444. Parameters.Get.TotalEntries - the total number of entries that
  445. would be returned with a large enough buffer.
  446. Parameters.Get.TotalBytesNeeded - the buffer size that would be
  447. required to hold all the entries.
  448. Parameters.Get.ResumeHandle - share ID of last share returned.
  449. Buffer - a pointer to the buffer for results.
  450. BufferLength - the length of this buffer.
  451. Return Value:
  452. NTSTATUS - result of operation to return to the server service.
  453. --*/
  454. {
  455. PAGED_CODE( );
  456. return SrvShareEnumApiHandler(
  457. Srp,
  458. Buffer,
  459. BufferLength,
  460. FilterShares,
  461. SizeShares,
  462. FillShareInfoBuffer
  463. );
  464. } // SrvNetShareEnum
  465. NTSTATUS
  466. SrvNetShareSetInfo (
  467. IN PSERVER_REQUEST_PACKET Srp,
  468. IN PVOID Buffer,
  469. IN ULONG BufferLength
  470. )
  471. /*++
  472. Routine Description:
  473. This routine processes the NetShareSetInfo API in the server.
  474. Arguments:
  475. Srp - a pointer to the server request packet that contains all
  476. the information necessary to satisfy the request. This includes:
  477. INPUT:
  478. Name1 - name of the share to set information on.
  479. Parameters.Set.Api.ShareInfo.MaxUses - if not 0, a new maximum
  480. user count. If the current count of users on the share
  481. exceeds the new value, no check is made, but no new
  482. tree connects are allowed.
  483. OUTPUT:
  484. Parameters.Set.ErrorParameter - if ERROR_INVALID_PARAMETER is
  485. returned, this contains the index of the parameter in error.
  486. Buffer - a pointer to a SHARE_INFO_502 structure.
  487. BufferLength - length of this buffer.
  488. Return Value:
  489. NTSTATUS - result of operation to return to the user.
  490. --*/
  491. {
  492. PSHARE share;
  493. UNICODE_STRING remark;
  494. PWCH newRemarkBuffer = NULL;
  495. ULONG maxUses;
  496. ULONG level;
  497. PSHARE_INFO_502 shi502;
  498. PSECURITY_DESCRIPTOR fileSD;
  499. PSECURITY_DESCRIPTOR securityDescriptor = NULL;
  500. PAGED_CODE( );
  501. //
  502. // Convert the offsets in the share data structure to pointers. Also
  503. // make sure that all the pointers are within the specified buffer.
  504. //
  505. level = Srp->Level;
  506. switch( level ) {
  507. default:
  508. shi502 = Buffer;
  509. if( shi502->shi502_permissions ) {
  510. securityDescriptor =
  511. (PSECURITY_DESCRIPTOR)((PCHAR)shi502 + shi502->shi502_permissions);
  512. }
  513. OFFSET_TO_POINTER( shi502->shi502_netname, shi502 );
  514. OFFSET_TO_POINTER( shi502->shi502_remark, shi502 );
  515. OFFSET_TO_POINTER( shi502->shi502_path, shi502 );
  516. OFFSET_TO_POINTER( shi502->shi502_security_descriptor, shi502 );
  517. if ( !POINTER_IS_VALID( shi502->shi502_netname, shi502, BufferLength ) ||
  518. !POINTER_IS_VALID( shi502->shi502_remark, shi502, BufferLength ) ||
  519. !POINTER_IS_VALID( shi502->shi502_path, shi502, BufferLength ) ||
  520. !POINTER_IS_VALID( securityDescriptor, shi502, BufferLength ) ||
  521. !POINTER_IS_VALID( shi502->shi502_security_descriptor, shi502, BufferLength ) ) {
  522. return STATUS_ACCESS_VIOLATION;
  523. }
  524. break;
  525. case 1005:
  526. break;
  527. }
  528. //
  529. // Acquire the lock that protects the share list and attempt to find
  530. // the correct share.
  531. //
  532. ACQUIRE_LOCK( &SrvShareLock );
  533. share = SrvFindShare( &Srp->Name1 );
  534. if ( share == NULL ) {
  535. IF_DEBUG(API_ERRORS) {
  536. KdPrint(( "SrvNetShareSetInfo: share %wZ not found.\n",
  537. &Srp->Name1 ));
  538. }
  539. RELEASE_LOCK( &SrvShareLock );
  540. Srp->ErrorCode = NERR_NetNameNotFound;
  541. return STATUS_SUCCESS;
  542. }
  543. if( level == 1005 ) {
  544. if( share->ShareType != ShareTypeDisk ) {
  545. Srp->Parameters.Set.ErrorParameter = 0;
  546. Srp->ErrorCode = ERROR_BAD_DEV_TYPE;
  547. } else {
  548. PSHARE_INFO_1005 shi1005 = Buffer;
  549. share->CSCState = shi1005->shi1005_flags & CSC_MASK;
  550. Srp->ErrorCode = 0;
  551. }
  552. RELEASE_LOCK( &SrvShareLock );
  553. return STATUS_SUCCESS;
  554. }
  555. //
  556. // Set up local variables.
  557. //
  558. maxUses = Srp->Parameters.Set.Api.ShareInfo.MaxUses;
  559. //
  560. // If a remark was specified, allocate space for a new remark and
  561. // copy over the remark.
  562. //
  563. if ( ARGUMENT_PRESENT( shi502->shi502_remark ) ) {
  564. RtlInitUnicodeString( &remark, shi502->shi502_remark );
  565. newRemarkBuffer = ALLOCATE_HEAP_COLD(
  566. remark.MaximumLength,
  567. BlockTypeDataBuffer
  568. );
  569. if ( newRemarkBuffer == NULL ) {
  570. RELEASE_LOCK( &SrvShareLock );
  571. INTERNAL_ERROR(
  572. ERROR_LEVEL_EXPECTED,
  573. "SrvNetShareSetInfo: unable to allocate %ld bytes of heap.\n",
  574. remark.MaximumLength,
  575. NULL
  576. );
  577. Srp->Parameters.Set.ErrorParameter = SHARE_REMARK_PARMNUM;
  578. return STATUS_INSUFF_SERVER_RESOURCES;
  579. }
  580. }
  581. //
  582. // If a file security descriptor was specified, allocate space for a
  583. // new SD and copy over the new SD. We do this before setting the
  584. // MaxUses in case the allocation fails and we have to back out.
  585. //
  586. // Don't let a file ACL be specified for admin shares.
  587. //
  588. fileSD = shi502->shi502_security_descriptor;
  589. if ( ((level == 502) || (level == SHARE_FILE_SD_INFOLEVEL)) &&
  590. ARGUMENT_PRESENT( fileSD ) ) {
  591. PSECURITY_DESCRIPTOR newFileSD;
  592. ULONG newFileSDLength;
  593. if ( share->SpecialShare || !RtlValidSecurityDescriptor( fileSD ) ) {
  594. RELEASE_LOCK( &SrvShareLock );
  595. if ( newRemarkBuffer != NULL) {
  596. FREE_HEAP( newRemarkBuffer );
  597. }
  598. Srp->Parameters.Set.ErrorParameter = SHARE_FILE_SD_PARMNUM;
  599. return STATUS_INVALID_PARAMETER;
  600. }
  601. newFileSDLength = RtlLengthSecurityDescriptor( fileSD );
  602. newFileSD = ALLOCATE_HEAP_COLD(
  603. newFileSDLength,
  604. BlockTypeDataBuffer
  605. );
  606. if ( newFileSD == NULL ) {
  607. RELEASE_LOCK( &SrvShareLock );
  608. INTERNAL_ERROR(
  609. ERROR_LEVEL_EXPECTED,
  610. "SrvNetShareSetInfo: unable to allocate %ld bytes of heap.\n",
  611. newFileSDLength,
  612. NULL
  613. );
  614. Srp->Parameters.Set.ErrorParameter = SHARE_FILE_SD_PARMNUM;
  615. //
  616. // Free the remarks buffer allocated
  617. //
  618. if ( newRemarkBuffer != NULL) {
  619. FREE_HEAP( newRemarkBuffer );
  620. }
  621. return STATUS_INSUFF_SERVER_RESOURCES;
  622. }
  623. ACQUIRE_LOCK( share->SecurityDescriptorLock );
  624. //
  625. // Free the old security descriptor
  626. //
  627. if ( share->FileSecurityDescriptor != NULL ) {
  628. FREE_HEAP( share->FileSecurityDescriptor );
  629. }
  630. //
  631. // And set up the new one.
  632. //
  633. share->FileSecurityDescriptor = newFileSD;
  634. RtlCopyMemory(
  635. share->FileSecurityDescriptor,
  636. fileSD,
  637. newFileSDLength
  638. );
  639. RELEASE_LOCK( share->SecurityDescriptorLock );
  640. }
  641. //
  642. // Replace the old remark if a new one was specified.
  643. //
  644. if ( newRemarkBuffer != NULL ) {
  645. //
  646. // Free the old remark buffer.
  647. //
  648. if ( share->Remark.Buffer != NULL ) {
  649. FREE_HEAP( share->Remark.Buffer );
  650. }
  651. //
  652. // And set up the new one.
  653. //
  654. share->Remark.Buffer = newRemarkBuffer;
  655. share->Remark.MaximumLength = remark.MaximumLength;
  656. RtlCopyUnicodeString( &share->Remark, &remark );
  657. }
  658. #ifdef INCLUDE_SMB_PERSISTENT
  659. if ((shi502->shi502_type != 0) &&
  660. (share->ShareType == ShareTypeDisk)) {
  661. if ((BOOLEAN)((shi502->shi502_type & STYPE_PERSISTENT) != 0)) {
  662. if (! share->AllowPersistentHandles) {
  663. // init persistent handles here
  664. }
  665. share->AllowPersistentHandles = TRUE;
  666. } else if (share->AllowPersistentHandles ) {
  667. share->AllowPersistentHandles = FALSE;
  668. // clean up persistent handle state here.
  669. }
  670. }
  671. #endif
  672. //
  673. // If MaxUses was specified, set the new value.
  674. //
  675. if ( maxUses != 0 ) {
  676. share->MaxUses = maxUses;
  677. }
  678. //
  679. // Release the share lock.
  680. //
  681. RELEASE_LOCK( &SrvShareLock );
  682. //
  683. // Set up the error parameter to 0 (no error) and return.
  684. //
  685. Srp->Parameters.Set.ErrorParameter = 0;
  686. return STATUS_SUCCESS;
  687. } // SrvNetShareSetInfo
  688. VOID
  689. FillShareInfoBuffer (
  690. IN PSERVER_REQUEST_PACKET Srp,
  691. IN PVOID Block,
  692. IN OUT PVOID *FixedStructure,
  693. IN LPWSTR *EndOfVariableData
  694. )
  695. /*++
  696. Routine Description:
  697. This routine puts a single fixed share structure and, if it fits,
  698. associated variable data, into a buffer. Fixed data goes at the
  699. beginning of the buffer, variable data at the end.
  700. Arguments:
  701. Level - the level of information to copy from the share.
  702. Block - the share from which to get information.
  703. FixedStructure - where the ine buffer to place the fixed structure.
  704. This pointer is updated to point to the next available
  705. position for a fixed structure.
  706. EndOfVariableData - the last position on the buffer that variable
  707. data for this structure can occupy. The actual variable data
  708. is written before this position as long as it won't overwrite
  709. fixed structures. It is would overwrite fixed structures, it
  710. is not written.
  711. Return Value:
  712. None.
  713. --*/
  714. {
  715. PSHARE share = Block;
  716. PSHARE_INFO_501 shi501 = *FixedStructure;
  717. PSHARE_INFO_502 shi502 = *FixedStructure;
  718. PSHARE_INFO_1005 shi1005 = *FixedStructure;
  719. PAGED_CODE( );
  720. //
  721. // Update FixedStructure to point to the next structure
  722. // location.
  723. //
  724. *FixedStructure = (PCHAR)*FixedStructure + FIXED_SIZE_OF_SHARE( Srp->Level );
  725. ASSERT( (ULONG_PTR)*EndOfVariableData >= (ULONG_PTR)*FixedStructure );
  726. //
  727. // Case on the level to fill in the fixed structure appropriately.
  728. // We fill in actual pointers in the output structure. This is
  729. // possible because we are in the server FSD, hence the server
  730. // service's process and address space.
  731. //
  732. // *** This routine assumes that the fixed structure will fit in the
  733. // buffer!
  734. //
  735. // *** Using the switch statement in this fashion relies on the fact
  736. // that the first fields on the different share structures are
  737. // identical.
  738. //
  739. switch( Srp->Level ) {
  740. case 1005:
  741. shi1005->shi1005_flags = 0;
  742. SrvIsShareInDfs( share, &share->IsDfs, &share->IsDfsRoot );
  743. if( share->IsDfs ) {
  744. shi1005->shi1005_flags |= SHI1005_FLAGS_DFS;
  745. }
  746. if( share->IsDfsRoot ) {
  747. shi1005->shi1005_flags |= SHI1005_FLAGS_DFS_ROOT;
  748. }
  749. shi1005->shi1005_flags |= share->CSCState;
  750. break;
  751. case 502:
  752. ACQUIRE_LOCK_SHARED( share->SecurityDescriptorLock );
  753. if ( share->FileSecurityDescriptor != NULL ) {
  754. ULONG fileSDLength;
  755. fileSDLength =
  756. RtlLengthSecurityDescriptor( share->FileSecurityDescriptor );
  757. //
  758. // DWord Align
  759. //
  760. *EndOfVariableData = (LPWSTR) ( (ULONG_PTR) ((PCHAR) *EndOfVariableData -
  761. fileSDLength ) & ~3 );
  762. shi502->shi502_security_descriptor = *EndOfVariableData;
  763. shi502->shi502_reserved = fileSDLength;
  764. RtlCopyMemory(
  765. shi502->shi502_security_descriptor,
  766. share->FileSecurityDescriptor,
  767. fileSDLength
  768. );
  769. } else {
  770. shi502->shi502_security_descriptor = NULL;
  771. shi502->shi502_reserved = 0;
  772. }
  773. RELEASE_LOCK( share->SecurityDescriptorLock );
  774. case 2:
  775. //
  776. // Set level 2 specific fields in the buffer. Since this server
  777. // can only have user-level security, share permissions are
  778. // meaningless.
  779. //
  780. shi502->shi502_permissions = 0;
  781. shi502->shi502_max_uses = share->MaxUses;
  782. shi502->shi502_current_uses = share->CurrentUses;
  783. //
  784. // Copy the DOS path name to the buffer.
  785. //
  786. SrvCopyUnicodeStringToBuffer(
  787. &share->DosPathName,
  788. *FixedStructure,
  789. EndOfVariableData,
  790. &shi502->shi502_path
  791. );
  792. //
  793. // We don't have per-share passwords (share-level security)
  794. // so set the password pointer to NULL.
  795. //
  796. shi502->shi502_passwd = NULL;
  797. // *** Lack of break is intentional!
  798. case 501:
  799. if( Srp->Level == 501 ) {
  800. shi501->shi501_flags = share->CSCState;
  801. }
  802. // *** Lack of break is intentional!
  803. case 1:
  804. //
  805. // Convert the server's internal representation of share types
  806. // to the expected format.
  807. //
  808. switch ( share->ShareType ) {
  809. case ShareTypeDisk:
  810. shi502->shi502_type = STYPE_DISKTREE;
  811. break;
  812. case ShareTypePrint:
  813. shi502->shi502_type = STYPE_PRINTQ;
  814. break;
  815. case ShareTypePipe:
  816. shi502->shi502_type = STYPE_IPC;
  817. break;
  818. default:
  819. //
  820. // This should never happen. It means that somebody
  821. // stomped on the share block.
  822. //
  823. INTERNAL_ERROR(
  824. ERROR_LEVEL_UNEXPECTED,
  825. "FillShareInfoBuffer: invalid share type in share: %ld",
  826. share->ShareType,
  827. NULL
  828. );
  829. shi502->shi502_type = 0;
  830. }
  831. if ( share->SpecialShare ) {
  832. shi502->shi502_type |= STYPE_SPECIAL;
  833. }
  834. #ifdef INCLUDE_SMB_PERSISTENT
  835. if ( share->AllowPersistentHandles ) {
  836. shi502->shi502_type |= STYPE_PERSISTENT;
  837. }
  838. #endif
  839. //
  840. // Copy the remark to the buffer. The routine will handle the
  841. // case where there is no remark on the share and put a pointer
  842. // to a zero terminator in the buffer.
  843. //
  844. // *** We hold the share lock to keep SrvNetShareSetInfo from
  845. // changing the remark during the copy. (Changing the
  846. // remark can result in different storage being allocated.)
  847. //
  848. SrvCopyUnicodeStringToBuffer(
  849. &share->Remark,
  850. *FixedStructure,
  851. EndOfVariableData,
  852. &shi502->shi502_remark
  853. );
  854. // *** Lack of break is intentional!
  855. case 0:
  856. //
  857. // Copy the share name to the buffer.
  858. //
  859. SrvCopyUnicodeStringToBuffer(
  860. &share->ShareName,
  861. *FixedStructure,
  862. EndOfVariableData,
  863. &shi502->shi502_netname
  864. );
  865. break;
  866. default:
  867. //
  868. // This should never happen. The server service should have
  869. // checked for an invalid level.
  870. //
  871. INTERNAL_ERROR(
  872. ERROR_LEVEL_UNEXPECTED,
  873. "FillShareInfoBuffer: invalid level number: %ld",
  874. Srp->Level,
  875. NULL
  876. );
  877. }
  878. return;
  879. } // FillShareInfoBuffer
  880. BOOLEAN
  881. FilterShares (
  882. IN PSERVER_REQUEST_PACKET Srp,
  883. IN PVOID Block
  884. )
  885. /*++
  886. Routine Description:
  887. This routine is intended to be called by SrvEnumApiHandler to check
  888. whether a particular share should be returned.
  889. Arguments:
  890. Srp - a pointer to the SRP for the operation. Name1 ("netname"
  891. on NetShareGetInfo) is used to do the filtering.
  892. Block - a pointer to the share to check.
  893. Return Value:
  894. TRUE if the block should be placed in the output buffer, FALSE
  895. if it should be passed over.
  896. --*/
  897. {
  898. PSHARE share = Block;
  899. PAGED_CODE( );
  900. //
  901. // If this is an Enum, then we definitely want the share. An Enum
  902. // leaves the net name blank; a get info sets the name to the share
  903. // name on which to return info.
  904. //
  905. if ( Srp->Name1.Length == 0 ) {
  906. return TRUE;
  907. }
  908. //
  909. // This is a get info; use the share only if the share name matches
  910. // the Name1 field of the SRP.
  911. //
  912. return RtlEqualUnicodeString(
  913. &Srp->Name1,
  914. &share->ShareName,
  915. TRUE
  916. );
  917. } // FilterShares
  918. ULONG
  919. SizeShares (
  920. IN PSERVER_REQUEST_PACKET Srp,
  921. IN PVOID Block
  922. )
  923. /*++
  924. Routine Description:
  925. This routine returns the size the passed-in share would take up in
  926. an API output buffer.
  927. Arguments:
  928. Srp - a pointer to the SRP for the operation. Only the Level
  929. parameter is used.
  930. Block - a pointer to the share to size.
  931. Return Value:
  932. ULONG - The number of bytes the share would take up in the
  933. output buffer.
  934. --*/
  935. {
  936. PSHARE share = Block;
  937. ULONG shareSize = 0;
  938. PAGED_CODE( );
  939. switch ( Srp->Level ) {
  940. case 502:
  941. ACQUIRE_LOCK_SHARED( share->SecurityDescriptorLock );
  942. if ( share->FileSecurityDescriptor != NULL ) {
  943. //
  944. // add 4 bytes for possible padding
  945. //
  946. shareSize = sizeof( ULONG ) +
  947. RtlLengthSecurityDescriptor( share->FileSecurityDescriptor );
  948. }
  949. RELEASE_LOCK( share->SecurityDescriptorLock );
  950. case 2:
  951. shareSize += SrvLengthOfStringInApiBuffer(&share->DosPathName);
  952. case 501:
  953. case 1:
  954. shareSize += SrvLengthOfStringInApiBuffer(&share->Remark);
  955. case 0:
  956. shareSize += SrvLengthOfStringInApiBuffer(&share->ShareName);
  957. }
  958. return ( shareSize + FIXED_SIZE_OF_SHARE( Srp->Level ) );
  959. } // SizeShares