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.

3204 lines
77 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. Share.c
  5. Abstract:
  6. This module contains support for the Share catagory of APIs for the
  7. NT server service.
  8. Author:
  9. David Treadwell (davidtr) 10-Jan-1991
  10. Revision History:
  11. --*/
  12. #include "srvsvcp.h"
  13. #include "ssreg.h"
  14. #include <lmaccess.h>
  15. #include <lmerr.h>
  16. #include <ntddnfs.h>
  17. #include <tstr.h>
  18. #include <netevent.h>
  19. #include <icanon.h>
  20. #include <seopaque.h>
  21. #include <sertlp.h>
  22. #include <sddl.h>
  23. #define SET_ERROR_PARAMETER(a) \
  24. if ( ARGUMENT_PRESENT( ErrorParameter ) ) { *ErrorParameter = a; }
  25. //
  26. // Use the same directory separator as the object system uses.
  27. //
  28. #define IS_SLASH_SLASH_NAME( _x ) \
  29. ( IS_PATH_SEPARATOR( _x[0] ) && \
  30. IS_PATH_SEPARATOR( _x[1] ) && \
  31. _x[2] == L'.' && \
  32. IS_PATH_SEPARATOR( _x[3] ) )
  33. #define IS_NTPATH_NAME( _x ) \
  34. ( _x && \
  35. IS_PATH_SEPARATOR( _x[0] ) && \
  36. IS_PATH_SEPARATOR( _x[1] ) && \
  37. _x[2] == L'?' && \
  38. IS_PATH_SEPARATOR( _x[3] ) )
  39. //
  40. // Local types.
  41. //
  42. PSHARE_DEL_CONTEXT SrvShareDelContextHead = NULL;
  43. CRITICAL_SECTION ShareDelContextMutex;
  44. GENERIC_MAPPING SrvShareFileGenericMapping = GENERIC_SHARE_FILE_ACCESS_MAPPING;
  45. //
  46. // Forward declarations.
  47. //
  48. PVOID
  49. CaptureShareInfo (
  50. IN DWORD Level,
  51. IN PSHARE_INFO_2 Shi2,
  52. IN DWORD ShareType,
  53. IN LPWSTR Path,
  54. IN LPWSTR Remark,
  55. IN PSECURITY_DESCRIPTOR ConnectSecurityDescriptor,
  56. IN PSECURITY_DESCRIPTOR FileSecurityDescriptor OPTIONAL,
  57. OUT PULONG CapturedBufferLength
  58. );
  59. NET_API_STATUS
  60. DisallowSharedLanmanNetDrives(
  61. IN PUNICODE_STRING NtSharePath
  62. );
  63. NET_API_STATUS
  64. ShareAssignSecurityDescriptor(
  65. IN PSECURITY_DESCRIPTOR PassedSecurityDescriptor,
  66. OUT PSECURITY_DESCRIPTOR *NewSecurityDescriptor
  67. );
  68. NET_API_STATUS
  69. ShareEnumCommon (
  70. IN DWORD Level,
  71. OUT LPBYTE *Buffer,
  72. IN DWORD PreferredMaximumLength,
  73. OUT LPDWORD EntriesRead,
  74. OUT LPDWORD TotalEntries,
  75. IN OUT LPDWORD ResumeHandle OPTIONAL,
  76. IN LPWSTR NetName OPTIONAL
  77. );
  78. NET_API_STATUS
  79. ShareEnumSticky (
  80. IN DWORD Level,
  81. OUT LPBYTE *Buffer,
  82. IN DWORD PreferredMaximumLength,
  83. OUT LPDWORD EntriesRead,
  84. OUT LPDWORD TotalEntries,
  85. IN OUT LPDWORD ResumeHandle OPTIONAL
  86. );
  87. ULONG
  88. SizeShares (
  89. IN ULONG Level,
  90. IN PSHARE_INFO_502 Shi502
  91. );
  92. BOOLEAN
  93. ValidSharePath(
  94. IN LPWSTR SharePath,
  95. IN BOOL IsNtPath
  96. );
  97. NET_API_STATUS NET_API_FUNCTION
  98. NetrShareAdd (
  99. IN LPWSTR ServerName,
  100. IN DWORD Level,
  101. IN LPSHARE_INFO Buffer,
  102. OUT LPDWORD ErrorParameter
  103. )
  104. {
  105. return I_NetrShareAdd( ServerName, Level, Buffer, ErrorParameter, FALSE );
  106. }
  107. NET_API_STATUS NET_API_FUNCTION
  108. I_NetrShareAdd (
  109. IN LPWSTR ServerName,
  110. IN DWORD Level,
  111. IN LPSHARE_INFO Buffer,
  112. OUT LPDWORD ErrorParameter,
  113. IN BOOLEAN BypassSecurity
  114. )
  115. /*++
  116. Routine Description:
  117. This routine communicates with the server FSD to implement the
  118. NetShareAdd function. Only levels 2 and 502 are valid.
  119. Arguments:
  120. ServerName - name of the server.
  121. Level - Request level.
  122. Buffer - Contains the information about the share. If this is a level
  123. 502 request, will also contain a valid security descriptor in
  124. self-relative form.
  125. ErrorParameter - status of the FsControl call.
  126. BypassSecurity - skip security checks
  127. Return Value:
  128. NET_API_STATUS - NO_ERROR or reason for failure.
  129. --*/
  130. {
  131. NET_API_STATUS error;
  132. NTSTATUS status;
  133. PSERVER_REQUEST_PACKET srp;
  134. PVOID capturedBuffer;
  135. LPWSTR path;
  136. LPWSTR netName;
  137. LPWSTR remark;
  138. ULONG bufferLength;
  139. UNICODE_STRING dosSharePath;
  140. UNICODE_STRING ntSharePath;
  141. PSRVSVC_SECURITY_OBJECT securityObject;
  142. PSECURITY_DESCRIPTOR connectSecurityDescriptor;
  143. PSECURITY_DESCRIPTOR fileSecurityDescriptor = NULL;
  144. PSECURITY_DESCRIPTOR newFileSecurityDescriptor = NULL;
  145. UINT driveType = DRIVE_FIXED;
  146. DWORD shareType;
  147. BOOL isIpc;
  148. BOOL isAdmin;
  149. BOOL isDiskAdmin;
  150. BOOL isPrintShare;
  151. BOOL isSpecial;
  152. BOOL isNtPath;
  153. BOOL isTemporary;
  154. BOOL FreeFileSecurityDescriptor;
  155. PSHARE_INFO_2 shi2;
  156. PSHARE_INFO_502 shi502;
  157. ServerName;
  158. //
  159. // Check that user input buffer is not NULL
  160. //
  161. if ( !ARGUMENT_PRESENT( Buffer ) || Buffer->ShareInfo2 == NULL) {
  162. SET_ERROR_PARAMETER(PARM_ERROR_UNKNOWN);
  163. return ERROR_INVALID_PARAMETER;
  164. }
  165. //
  166. // Set up for error cleanup.
  167. //
  168. srp = NULL;
  169. dosSharePath.Buffer = NULL;
  170. ntSharePath.Buffer = NULL;
  171. capturedBuffer = NULL;
  172. FreeFileSecurityDescriptor = FALSE;
  173. //
  174. // Extract Internal buffer information.
  175. //
  176. shi2 = Buffer->ShareInfo2;
  177. //
  178. // 502 may contain a security descriptor.
  179. //
  180. if ( Level == 502 ) {
  181. shi502 = (LPSHARE_INFO_502) Buffer->ShareInfo502;
  182. fileSecurityDescriptor = shi502->shi502_security_descriptor;
  183. //
  184. // check the reserved field. If it is zero, this was called from
  185. // inside the srvsvc. If not, it was through rpc.
  186. //
  187. if ( fileSecurityDescriptor != NULL ) {
  188. if ( !RtlValidSecurityDescriptor( fileSecurityDescriptor ) ) {
  189. SET_ERROR_PARAMETER( SHARE_FILE_SD_PARMNUM );
  190. error = ERROR_INVALID_PARAMETER;
  191. goto exit;
  192. }
  193. if ( shi502->shi502_reserved != 0 ) {
  194. error = ShareAssignSecurityDescriptor(
  195. fileSecurityDescriptor,
  196. &newFileSecurityDescriptor
  197. );
  198. if ( error != NO_ERROR ) {
  199. SS_PRINT(( "NetrShareAdd: ShareAssignSecurityDescriptor "
  200. "error: %d\n", error ));
  201. SET_ERROR_PARAMETER( SHARE_FILE_SD_PARMNUM );
  202. error = ERROR_INVALID_PARAMETER;
  203. goto exit;
  204. }
  205. FreeFileSecurityDescriptor = TRUE;
  206. } else {
  207. newFileSecurityDescriptor = fileSecurityDescriptor;
  208. }
  209. } else {
  210. fileSecurityDescriptor = SsDefaultShareSecurityObject.SecurityDescriptor;
  211. newFileSecurityDescriptor = fileSecurityDescriptor;
  212. }
  213. } else if ( Level != 2 ) {
  214. //
  215. // The only valid levels are 2 and 502. 2 is a subset of 502.
  216. //
  217. error = ERROR_INVALID_LEVEL;
  218. goto exit;
  219. }
  220. else
  221. {
  222. // For level 2, default to the default security descriptor
  223. fileSecurityDescriptor = SsDefaultShareSecurityObject.SecurityDescriptor;
  224. newFileSecurityDescriptor = fileSecurityDescriptor;
  225. }
  226. //
  227. // A share name must be specified.
  228. //
  229. netName = shi2->shi2_netname;
  230. if ( (netName == NULL) || (*netName == '\0') ) {
  231. SET_ERROR_PARAMETER( SHARE_NETNAME_PARMNUM );
  232. error = ERROR_INVALID_PARAMETER;
  233. goto exit;
  234. }
  235. //
  236. // Limit it to NNLEN
  237. //
  238. if ( wcslen(netName) > NNLEN ) {
  239. SET_ERROR_PARAMETER( SHARE_NETNAME_PARMNUM );
  240. error = ERROR_INVALID_PARAMETER;
  241. goto exit;
  242. }
  243. //
  244. // If this is the IPC$ share, or the ADMIN$ share, no path
  245. // may be specified. No path is needed for the IPC$ share, while a path
  246. // is supplied internally for the ADMIN$ share.
  247. //
  248. path = shi2->shi2_path;
  249. remark = shi2->shi2_remark;
  250. shareType = (shi2->shi2_type & ~(STYPE_TEMPORARY));
  251. //
  252. // Figure out which kind of share this is.
  253. //
  254. isIpc = (BOOL)(STRICMP( netName, IPC_SHARE_NAME ) == 0);
  255. isAdmin = (BOOL)(STRICMP( netName, ADMIN_SHARE_NAME ) == 0);
  256. isTemporary = (BOOL)(shi2->shi2_type & STYPE_TEMPORARY);
  257. isNtPath = IS_NTPATH_NAME( path );
  258. // For NTPaths, we only allow disk-style shares
  259. if( isNtPath && (shareType != STYPE_DISKTREE) )
  260. {
  261. SET_ERROR_PARAMETER( SHARE_TYPE_PARMNUM );
  262. error = ERROR_INVALID_PARAMETER;
  263. goto exit;
  264. }
  265. //
  266. // We have an administrative disk share if the share name is a drive letter
  267. // followed by $, and if the path name is the root of that same drive.
  268. //
  269. if( wcslen( netName ) == 2 && netName[1] == L'$' &&
  270. TOUPPER( netName[0] ) >= L'A' && TOUPPER( netName[0]) <= L'Z' &&
  271. path != NULL && wcslen( path ) == 3 &&
  272. TOUPPER( path[0] ) == TOUPPER( netName[0] ) &&
  273. path[1] == L':' && path[2] == L'\\' ) {
  274. //
  275. // The share name and path look to be an administrative disk share.
  276. // If the path refers to a fixed drive, then it really is one.
  277. //
  278. isDiskAdmin = ((SsGetDriveType( path ) == DRIVE_FIXED) ||
  279. (SsGetDriveType( path ) == DRIVE_CDROM) ||
  280. (SsGetDriveType( path ) == DRIVE_REMOVABLE));
  281. } else {
  282. isDiskAdmin = FALSE;
  283. }
  284. isPrintShare = (BOOL)(shareType == STYPE_PRINTQ);
  285. isSpecial = isIpc || isAdmin || isDiskAdmin;
  286. if ( isIpc ) {
  287. if ( path != NULL ) {
  288. SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
  289. error = ERROR_INVALID_PARAMETER;
  290. goto exit;
  291. }
  292. path = NULL;
  293. //
  294. // Let the caller specify a remark if they want. If they don't,
  295. // supply a default remark.
  296. //
  297. if ( remark == NULL ) {
  298. remark = SsIPCShareRemark;
  299. }
  300. shareType = STYPE_IPC;
  301. } else if ( isAdmin ) {
  302. if ( path != NULL ) {
  303. SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
  304. error = ERROR_INVALID_PARAMETER;
  305. goto exit;
  306. }
  307. //
  308. // Let the caller specify a remark if they want. If they don't,
  309. // supply a default remark.
  310. //
  311. if ( remark == NULL ) {
  312. remark = SsAdminShareRemark;
  313. }
  314. shareType = STYPE_DISKTREE;
  315. //
  316. // For the ADMIN$ share, we set the path to the system root
  317. // directory. We get this from from the kernel via the
  318. // read-only shared page (USER_SHARED_DATA)
  319. //
  320. path = USER_SHARED_DATA->NtSystemRoot;
  321. } else {
  322. //
  323. // For all shares other than IPC$ and ADMIN$, a path must be
  324. // specified and must not have .. and . as directory names.
  325. //
  326. if ( (path == NULL) || (*path == '\0') || !ValidSharePath( path, isNtPath ) ) {
  327. SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
  328. error = ERROR_INVALID_NAME;
  329. goto exit;
  330. }
  331. //
  332. // If we've got a disk admin share and they didn't supply a
  333. // comment, use the built in one
  334. //
  335. if( isDiskAdmin && remark == NULL ) {
  336. remark = SsDiskAdminShareRemark;
  337. }
  338. }
  339. //
  340. // The remark must be no longer than MAXCOMMENTSZ.
  341. //
  342. if ( (remark != NULL) && (STRLEN(remark) > MAXCOMMENTSZ) ) {
  343. SET_ERROR_PARAMETER( SHARE_REMARK_PARMNUM );
  344. error = ERROR_INVALID_PARAMETER;
  345. goto exit;
  346. }
  347. //
  348. // If the server service is fully started, make sure that the caller
  349. // is allowed to set share information in the server. We only do
  350. // this if the service is started--the default share and configured
  351. // share creations done during initialization do not need any
  352. // special access.
  353. //
  354. if ( SsData.SsInitialized && BypassSecurity == FALSE ) {
  355. if ( isSpecial ) {
  356. securityObject = &SsShareAdminSecurityObject;
  357. } else if ( isPrintShare ) {
  358. securityObject = &SsSharePrintSecurityObject;
  359. } else {
  360. securityObject = &SsShareFileSecurityObject;
  361. }
  362. error = SsCheckAccess( securityObject, SRVSVC_SHARE_INFO_SET );
  363. if ( error != NO_ERROR ) {
  364. SET_ERROR_PARAMETER( 0 );
  365. goto exit;
  366. }
  367. }
  368. //
  369. // If this is a disk share, make sure that the drive is a type that
  370. // can be shared.
  371. //
  372. if ( (shareType == STYPE_DISKTREE) && !isAdmin ) {
  373. DWORD pathType;
  374. //
  375. // Check the path type. It should be an absolute directory path.
  376. // We do not check the path type for Nt Paths
  377. //
  378. if( !isNtPath )
  379. {
  380. error = NetpPathType(
  381. NULL,
  382. path,
  383. &pathType,
  384. 0
  385. );
  386. if ( (error != NO_ERROR) || (pathType != ITYPE_PATH_ABSD) ) {
  387. error = ERROR_INVALID_NAME;
  388. SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
  389. goto exit;
  390. }
  391. }
  392. driveType = SsGetDriveType( path );
  393. if ( driveType == DRIVE_REMOVABLE ) {
  394. shareType = STYPE_REMOVABLE;
  395. } else if ( driveType == DRIVE_CDROM ) {
  396. shareType = STYPE_CDROM;
  397. } else if ( !(driveType == DRIVE_REMOTE &&
  398. SsData.ServerInfo599.sv599_enablesharednetdrives) &&
  399. driveType != DRIVE_FIXED &&
  400. driveType != DRIVE_RAMDISK ) {
  401. if ( driveType == DRIVE_REMOTE ) {
  402. error = NERR_RedirectedPath;
  403. } else {
  404. error = NERR_UnknownDevDir;
  405. }
  406. SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
  407. goto exit;
  408. }
  409. }
  410. //
  411. // Set up the request packet.
  412. //
  413. srp = SsAllocateSrp( );
  414. if ( srp == NULL ) {
  415. error = ERROR_NOT_ENOUGH_MEMORY;
  416. goto exit;
  417. }
  418. srp->Level = Level;
  419. //
  420. // Get the path name in NT format and put it in the SRP.
  421. //
  422. if ( path != NULL ) {
  423. RtlInitUnicodeString( &dosSharePath, path );
  424. if ( !RtlDosPathNameToNtPathName_U(
  425. dosSharePath.Buffer,
  426. &ntSharePath,
  427. NULL,
  428. NULL ) ) {
  429. SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
  430. error = ERROR_INVALID_PARAMETER;
  431. goto exit;
  432. }
  433. //
  434. // If this is a redirected drive, make sure the redir is not
  435. // LanMan.
  436. //
  437. if ( driveType == DRIVE_REMOTE ) {
  438. error = DisallowSharedLanmanNetDrives( &ntSharePath );
  439. if ( error != NERR_Success ) {
  440. SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
  441. goto exit;
  442. }
  443. } // if remote drive
  444. srp->Name1 = ntSharePath;
  445. }
  446. //
  447. // Determine whether this is an admin share and use the appropriate
  448. // security descriptor.
  449. //
  450. if ( isAdmin || isDiskAdmin ) {
  451. connectSecurityDescriptor = SsShareAdmConnectSecurityObject.SecurityDescriptor;
  452. } else {
  453. connectSecurityDescriptor = SsShareConnectSecurityObject.SecurityDescriptor;
  454. }
  455. //
  456. // If this is a disk share, verify that the directory to be shared
  457. // exists and that the caller has access. (Don't do the access
  458. // check during server startup.) Don't check the admin$ share -- we
  459. // know it exists. Skip removable type disks.
  460. //
  461. if ( !isAdmin &&
  462. (shareType == STYPE_DISKTREE) &&
  463. (shi2->shi2_path != NULL) ) {
  464. OBJECT_ATTRIBUTES objectAttributes;
  465. IO_STATUS_BLOCK iosb;
  466. HANDLE handle = INVALID_HANDLE_VALUE;
  467. NTSTATUS status;
  468. if ( SsData.SsInitialized && BypassSecurity == FALSE &&
  469. (error = RpcImpersonateClient(NULL)) != NO_ERROR ) {
  470. goto exit;
  471. }
  472. InitializeObjectAttributes(
  473. &objectAttributes,
  474. &ntSharePath,
  475. OBJ_CASE_INSENSITIVE,
  476. 0,
  477. NULL
  478. );
  479. status = NtOpenFile(
  480. &handle,
  481. FILE_LIST_DIRECTORY,
  482. &objectAttributes,
  483. &iosb,
  484. FILE_SHARE_READ | FILE_SHARE_WRITE,
  485. FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT
  486. );
  487. if( status == STATUS_INVALID_PARAMETER ) {
  488. status = NtOpenFile(
  489. &handle,
  490. FILE_LIST_DIRECTORY,
  491. &objectAttributes,
  492. &iosb,
  493. FILE_SHARE_READ | FILE_SHARE_WRITE,
  494. FILE_DIRECTORY_FILE
  495. );
  496. }
  497. if ( SsData.SsInitialized && BypassSecurity == FALSE ) {
  498. (VOID)RpcRevertToSelf( );
  499. }
  500. if ( !NT_SUCCESS(status) ) {
  501. if ( SsData.SsInitialized || (status != STATUS_ACCESS_DENIED) ) {
  502. //
  503. // During startup, if the directory does not
  504. // exist (renamed/deleted), log an event.
  505. //
  506. if ( !SsData.SsInitialized &&
  507. ((status == STATUS_OBJECT_NAME_NOT_FOUND) ||
  508. (status == STATUS_OBJECT_PATH_NOT_FOUND)) ) {
  509. LPWSTR subStrings[2];
  510. subStrings[0] = netName;
  511. subStrings[1] = shi2->shi2_path;
  512. SsLogEvent(
  513. EVENT_SRV_CANT_RECREATE_SHARE,
  514. 2,
  515. subStrings,
  516. NO_ERROR
  517. );
  518. }
  519. SET_ERROR_PARAMETER( 0 );
  520. error = RtlNtStatusToDosError( status );
  521. goto exit;
  522. }
  523. } else if( !IS_SLASH_SLASH_NAME( path ) ) {
  524. if ( SsData.SsInitialized ) {
  525. FILE_FS_ATTRIBUTE_INFORMATION fileFsAttributeInformation;
  526. RtlZeroMemory( &fileFsAttributeInformation, sizeof( fileFsAttributeInformation ));
  527. status = NtQueryVolumeInformationFile( handle,
  528. &iosb,
  529. &fileFsAttributeInformation,
  530. sizeof( fileFsAttributeInformation ),
  531. FileFsAttributeInformation
  532. );
  533. if( (status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW) &&
  534. !(fileFsAttributeInformation.FileSystemAttributes &
  535. FILE_SUPPORTS_REPARSE_POINTS) ) {
  536. //
  537. // Query the name from the file system. This is because some
  538. // fs like fat uses only upper case oem names. This can cause
  539. // a problem because some oem characters do not have upper case
  540. // equivalents and thus get mapped to something funny.
  541. //
  542. // We do not do this if the filesystem supports reparse points, since
  543. // we will come up with the wrong name!
  544. //
  545. PFILE_NAME_INFORMATION fileNameInformation;
  546. ULONG fileInfoSize;
  547. ULONG fileNameLength;
  548. fileInfoSize = sizeof(FILE_NAME_INFORMATION) + SIZE_WSTR( path );
  549. fileNameInformation = MIDL_user_allocate( fileInfoSize );
  550. if ( fileNameInformation == NULL ) {
  551. error = ERROR_NOT_ENOUGH_MEMORY;
  552. NtClose( handle );
  553. goto exit;
  554. }
  555. status = NtQueryInformationFile(
  556. handle,
  557. &iosb,
  558. fileNameInformation,
  559. fileInfoSize,
  560. FileNameInformation
  561. );
  562. if ( status == STATUS_SUCCESS ) {
  563. //
  564. // The file name returned is expected to be
  565. // 3 characters shorter than the share path length.
  566. // These 3 characters are "X", ":", "\0".
  567. //
  568. // If the lengths do not match, than this could be a mounted
  569. // FAT volume on an NTFS drive, so we only copy the necessary data
  570. //
  571. fileNameLength = fileNameInformation->FileNameLength;
  572. if ((fileNameLength+3*sizeof(WCHAR)) <= SIZE_WSTR(path)) {
  573. //
  574. // Copy the path name
  575. //
  576. RtlCopyMemory(
  577. (LPBYTE) path + 2*sizeof(WCHAR) + (SIZE_WSTR(path) - (fileNameLength+3*sizeof(WCHAR))),
  578. fileNameInformation->FileName,
  579. fileNameLength
  580. );
  581. path[fileNameLength/sizeof(WCHAR)+2+(SIZE_WSTR(path) - (fileNameLength+3*sizeof(WCHAR)))/sizeof(WCHAR)] = L'\0';
  582. }
  583. }
  584. MIDL_user_free( fileNameInformation );
  585. }
  586. }
  587. NtClose( handle );
  588. } else {
  589. NtClose( handle );
  590. }
  591. }
  592. //
  593. // Capture the share data structure passed in.
  594. //
  595. if ( isSpecial ) {
  596. shareType |= STYPE_SPECIAL;
  597. }
  598. if ( isTemporary ) {
  599. shareType |= STYPE_TEMPORARY;
  600. }
  601. capturedBuffer = CaptureShareInfo(
  602. Level,
  603. shi2,
  604. shareType,
  605. path,
  606. remark,
  607. connectSecurityDescriptor,
  608. newFileSecurityDescriptor,
  609. &bufferLength
  610. );
  611. if ( capturedBuffer == NULL ) {
  612. SET_ERROR_PARAMETER( 0 );
  613. error = ERROR_NOT_ENOUGH_MEMORY;
  614. goto exit;
  615. }
  616. //
  617. // Send the request on to the server.
  618. //
  619. error = SsServerFsControl(
  620. FSCTL_SRV_NET_SHARE_ADD,
  621. srp,
  622. capturedBuffer,
  623. bufferLength
  624. );
  625. SET_ERROR_PARAMETER( srp->Parameters.Set.ErrorParameter );
  626. //
  627. // If the request succeeded, add a value to the Shares key, thus
  628. // effecting a sticky share. We only do this if the server is fully
  629. // started -- the default share and configured share creations done
  630. // during initialization should not be added to the registry.
  631. //
  632. // Don't do this if this is an admin share being [re]created.
  633. //
  634. if ( SsData.SsInitialized &&
  635. (error == NO_ERROR) &&
  636. !isSpecial &&
  637. !isTemporary ) {
  638. SsAddShareToRegistry( shi2, newFileSecurityDescriptor, 0 );
  639. }
  640. //
  641. // If a print share was successfully added, increment the number
  642. // of print shares and update the exported (announced) server type.
  643. //
  644. if ( isPrintShare ) {
  645. InterlockedIncrement( &SsData.NumberOfPrintShares );
  646. SsSetExportedServerType( NULL, FALSE, TRUE );
  647. }
  648. exit:
  649. //
  650. // Clean up. Free the share data structure that was allocated by
  651. // CaptureShareInfo2. Free the server request packet. If there was
  652. // an NT path name allocated by RtlDosPathNameToNtPathName, free it.
  653. // If we created ADMIN$, free the system path string and the system
  654. // path information buffer.
  655. //
  656. if (FreeFileSecurityDescriptor) {
  657. (VOID) RtlDeleteSecurityObject ( &newFileSecurityDescriptor );
  658. }
  659. if ( capturedBuffer != NULL ) {
  660. MIDL_user_free( capturedBuffer );
  661. }
  662. if ( srp != NULL ) {
  663. SsFreeSrp( srp );
  664. }
  665. if ( ntSharePath.Buffer != NULL ) {
  666. RtlFreeUnicodeString( &ntSharePath );
  667. }
  668. return error;
  669. } // NetrShareAdd
  670. NET_API_STATUS
  671. NetrShareCheck (
  672. IN LPWSTR ServerName,
  673. IN LPWSTR Device,
  674. OUT LPDWORD Type
  675. )
  676. /*++
  677. Routine Description:
  678. This routine implements NetShareCheck by calling NetrShareEnum.
  679. Arguments:
  680. None.
  681. Return Value:
  682. NET_API_STATUS - NO_ERROR or reason for failure.
  683. --*/
  684. {
  685. DWORD totalEntries;
  686. DWORD entriesRead;
  687. ULONG i;
  688. PSHARE_INFO_2 shi2;
  689. NET_API_STATUS error;
  690. LPBYTE buffer = NULL;
  691. ServerName;
  692. //
  693. // Call ShareEnumCommon to actually get the information about what
  694. // the shares are on the server. We use this routine rather than
  695. // calling NetrShareEnum because NetShareCheck requires no privilege
  696. // to execute, and we don't want the security checks in
  697. // NetrShareEnum.
  698. //
  699. error = ShareEnumCommon(
  700. 2,
  701. &buffer,
  702. (DWORD)-1,
  703. &entriesRead,
  704. &totalEntries,
  705. NULL,
  706. NULL
  707. );
  708. if ( error != NO_ERROR ) {
  709. if( buffer ) {
  710. MIDL_user_free( buffer );
  711. }
  712. return error;
  713. }
  714. SS_ASSERT( totalEntries == entriesRead );
  715. //
  716. // Attempt to find the drive letter in a share's path name.
  717. //
  718. for ( shi2 = (PSHARE_INFO_2)buffer, i = 0; i < totalEntries; shi2++, i++ ) {
  719. if ( shi2->shi2_path != NULL && Device && *Device == *shi2->shi2_path ) {
  720. //
  721. // Something on the specified disk is shared--free the buffer
  722. // and return the type of share.
  723. //
  724. *Type = shi2->shi2_type & ~STYPE_SPECIAL;
  725. MIDL_user_free( buffer );
  726. return NO_ERROR;
  727. }
  728. }
  729. //
  730. // Nothing on the specified disk is shared. Return an error.
  731. //
  732. MIDL_user_free( buffer );
  733. return NERR_DeviceNotShared;
  734. } // NetrShareCheck
  735. NET_API_STATUS NET_API_FUNCTION
  736. NetrShareDel (
  737. IN LPWSTR ServerName,
  738. IN LPWSTR NetName,
  739. IN DWORD Reserved
  740. )
  741. /*++
  742. Routine Description:
  743. This routine communicates with the server FSD to implement the
  744. NetShareDel function.
  745. Arguments:
  746. None.
  747. Return Value:
  748. NET_API_STATUS - NO_ERROR or reason for failure.
  749. --*/
  750. {
  751. NET_API_STATUS error;
  752. SHARE_DEL_HANDLE handle;
  753. error = I_NetrShareDelStart( ServerName, NetName, Reserved, &handle, TRUE );
  754. if ( error == NO_ERROR ) {
  755. error = NetrShareDelCommit( &handle );
  756. }
  757. return error;
  758. } // NetrShareDel
  759. NET_API_STATUS NET_API_FUNCTION
  760. NetrShareDelStart (
  761. IN LPWSTR ServerName,
  762. IN LPWSTR NetName,
  763. IN DWORD Reserved,
  764. IN PSHARE_DEL_HANDLE ContextHandle
  765. )
  766. {
  767. return I_NetrShareDelStart( ServerName, NetName, Reserved, ContextHandle, TRUE );
  768. }
  769. NET_API_STATUS NET_API_FUNCTION
  770. I_NetrShareDelStart (
  771. IN LPWSTR ServerName,
  772. IN LPWSTR NetName,
  773. IN DWORD Reserved,
  774. IN PSHARE_DEL_HANDLE ContextHandle,
  775. IN BOOLEAN CheckAccess
  776. )
  777. /*++
  778. Routine Description:
  779. This routine implements the first phase of the share deletion
  780. function, which simply remembers that the specified share is to be
  781. deleted. The NetrShareDelCommit function actually deletes the
  782. share. This two-phase deletion is used to delete IPC$, which is
  783. the share used for named pipes, so that RPC can be used to delete
  784. the IPC$ share without receiving RPC errors.
  785. Arguments:
  786. None.
  787. Return Value:
  788. NET_API_STATUS - NO_ERROR or reason for failure.
  789. --*/
  790. {
  791. NET_API_STATUS error;
  792. PSHARE_INFO_2 shareInfo = NULL;
  793. DWORD entriesRead;
  794. DWORD totalEntries;
  795. DWORD shareType;
  796. BOOL isPrintShare;
  797. BOOL isSpecial;
  798. PSRVSVC_SECURITY_OBJECT securityObject;
  799. PSHARE_DEL_CONTEXT context;
  800. ServerName, Reserved;
  801. //
  802. // A share name must be specified.
  803. //
  804. if ( (NetName == NULL) || (*NetName == '\0') ) {
  805. return ERROR_INVALID_PARAMETER;
  806. }
  807. //
  808. // First determine what kind of share is being deleted.
  809. //
  810. error = ShareEnumCommon(
  811. 2,
  812. (LPBYTE *)&shareInfo,
  813. (DWORD)-1,
  814. &entriesRead,
  815. &totalEntries,
  816. NULL,
  817. NetName
  818. );
  819. if ( error != NO_ERROR ) {
  820. if( shareInfo ) {
  821. MIDL_user_free( shareInfo );
  822. }
  823. return error;
  824. }
  825. if ( entriesRead == 0 ) {
  826. if( shareInfo ) {
  827. MIDL_user_free( shareInfo );
  828. }
  829. return NERR_NetNameNotFound;
  830. }
  831. shareType = shareInfo->shi2_type & ~STYPE_SPECIAL;
  832. isSpecial = (BOOL)((shareInfo->shi2_type & STYPE_SPECIAL) != 0);
  833. isPrintShare = (BOOL)(shareType == STYPE_PRINTQ);
  834. MIDL_user_free( shareInfo );
  835. //
  836. // Make sure that the caller is allowed to delete this share.
  837. //
  838. if( CheckAccess ) {
  839. if ( isSpecial ) {
  840. securityObject = &SsShareAdminSecurityObject;
  841. } else if ( isPrintShare ) {
  842. securityObject = &SsSharePrintSecurityObject;
  843. } else {
  844. securityObject = &SsShareFileSecurityObject;
  845. }
  846. error = SsCheckAccess( securityObject, SRVSVC_SHARE_INFO_SET );
  847. if ( error != NO_ERROR ) {
  848. return error;
  849. }
  850. }
  851. //
  852. // Set up context for the commit phase.
  853. //
  854. context = MIDL_user_allocate(
  855. sizeof(SHARE_DEL_CONTEXT) +
  856. wcslen(NetName)*sizeof(WCHAR) + sizeof(WCHAR)
  857. );
  858. if ( context == NULL ) {
  859. return ERROR_NOT_ENOUGH_MEMORY;
  860. }
  861. RtlZeroMemory(
  862. context,
  863. sizeof(SHARE_DEL_CONTEXT) +
  864. wcslen(NetName)*sizeof(WCHAR) + sizeof(WCHAR)
  865. );
  866. context->IsPrintShare = isPrintShare;
  867. context->IsSpecial = isSpecial;
  868. wcscpy( (LPWSTR)(context + 1), NetName );
  869. RtlInitUnicodeString( &context->Srp.Name1, (LPWSTR)(context + 1) );
  870. // Insert it into the context list
  871. EnterCriticalSection( &ShareDelContextMutex );
  872. context->Next = SrvShareDelContextHead;
  873. SrvShareDelContextHead = context;
  874. LeaveCriticalSection( &ShareDelContextMutex );
  875. //
  876. // Return the context pointer as an RPC context handle.
  877. //
  878. *ContextHandle = context;
  879. return NO_ERROR;
  880. } // I_NetrShareDelStart
  881. NET_API_STATUS NET_API_FUNCTION
  882. NetrShareDelCommit (
  883. IN PSHARE_DEL_HANDLE ContextHandle
  884. )
  885. /*++
  886. Routine Description:
  887. This routine implements the second phase of the share deletion
  888. function, which actually deletes the share. The first phase,
  889. NetrShareDelStart simply remembers that the share is to be deleted.
  890. This two-phase deletion is used to delete IPC$, which is the share
  891. used for named pipes, so that RPC can be used to delete the IPC$
  892. share without receiving RPC errors.
  893. Arguments:
  894. None.
  895. Return Value:
  896. NET_API_STATUS - NO_ERROR or reason for failure.
  897. --*/
  898. {
  899. NET_API_STATUS error;
  900. PSHARE_DEL_CONTEXT context;
  901. PSHARE_DEL_CONTEXT pSearch;
  902. //
  903. // The context handle is a pointer to allocated storage containing
  904. // the name of the share being deleted and other useful information.
  905. // Copy the pointer, then clear the context handle.
  906. //
  907. if( (ContextHandle == NULL) || (*ContextHandle == NULL) )
  908. {
  909. return ERROR_INVALID_PARAMETER;
  910. }
  911. context = *ContextHandle;
  912. *ContextHandle = NULL;
  913. //
  914. // Look for this context to validate that its on the list
  915. //
  916. EnterCriticalSection( &ShareDelContextMutex );
  917. pSearch = SrvShareDelContextHead;
  918. if( pSearch == context )
  919. {
  920. SrvShareDelContextHead = pSearch->Next;
  921. context->Next = NULL;
  922. }
  923. else
  924. {
  925. while( (pSearch != NULL) && (pSearch->Next != context) )
  926. {
  927. pSearch = pSearch->Next;
  928. }
  929. if( (pSearch != NULL) && (pSearch->Next == context) )
  930. {
  931. pSearch->Next = pSearch->Next->Next;
  932. context->Next = NULL;
  933. }
  934. else
  935. {
  936. pSearch = NULL;
  937. }
  938. }
  939. LeaveCriticalSection( &ShareDelContextMutex );
  940. if( pSearch == NULL )
  941. {
  942. return ERROR_INVALID_PARAMETER;
  943. }
  944. //
  945. // Send the request on to the server.
  946. //
  947. error = SsServerFsControl(
  948. FSCTL_SRV_NET_SHARE_DEL,
  949. &context->Srp,
  950. NULL,
  951. 0
  952. );
  953. //
  954. // If the request succeeded, remove the value corresponding to the
  955. // share from the Shares key, thus effecting a sticky share
  956. // deletion.
  957. //
  958. // We don't do this if this is an admin share being deleted. No
  959. // registry information is kept for these shares.
  960. //
  961. if ( (error == NO_ERROR) && !context->IsSpecial ) {
  962. SsRemoveShareFromRegistry( (LPWSTR)(context + 1) );
  963. }
  964. //
  965. // If a print share was successfully deleted, decrement the number
  966. // of print shares and update the exported (announced) server type.
  967. //
  968. if ( context->IsPrintShare ) {
  969. InterlockedDecrement( &SsData.NumberOfPrintShares );
  970. SsSetExportedServerType( NULL, FALSE, TRUE );
  971. }
  972. //
  973. // Free the context.
  974. //
  975. MIDL_user_free( context );
  976. return error;
  977. } // NetrShareDelCommit
  978. NET_API_STATUS NET_API_FUNCTION
  979. NetrShareDelSticky (
  980. IN LPWSTR ServerName,
  981. IN LPWSTR NetName,
  982. IN DWORD Reserved
  983. )
  984. /*++
  985. Routine Description:
  986. This routine implements the NetShareDelSticky function. It removes
  987. the named share from the sticky share list in the registry. The
  988. primary use of this function is to delete a sticky share whose
  989. root directory has been deleted, thus preventing actual recreation
  990. of the share, but whose entry still exists in the registry. It can
  991. also be used to remove the persistence of a share without deleting
  992. the current incarnation of the share.
  993. Arguments:
  994. None.
  995. Return Value:
  996. NET_API_STATUS - NO_ERROR or reason for failure.
  997. --*/
  998. {
  999. NET_API_STATUS error;
  1000. PSHARE_INFO_2 shareInfo, shi2;
  1001. DWORD entriesRead;
  1002. DWORD totalEntries;
  1003. DWORD shareType;
  1004. ULONG i;
  1005. BOOL isPrintShare;
  1006. PSRVSVC_SECURITY_OBJECT securityObject;
  1007. ServerName, Reserved;
  1008. //
  1009. // A share name must be specified.
  1010. //
  1011. if ( (NetName == NULL) || (*NetName == '\0') ) {
  1012. return ERROR_INVALID_PARAMETER;
  1013. }
  1014. //
  1015. // First determine what kind of share is being deleted.
  1016. //
  1017. error = ShareEnumSticky(
  1018. 2,
  1019. (LPBYTE *)&shareInfo,
  1020. (DWORD)-1,
  1021. &entriesRead,
  1022. &totalEntries,
  1023. NULL
  1024. );
  1025. if ( error != NO_ERROR ) {
  1026. return error;
  1027. } else if ( entriesRead == 0 ) {
  1028. return NERR_NetNameNotFound;
  1029. }
  1030. for ( shi2 = shareInfo, i = 0 ; i < entriesRead; i++, shi2++ ) {
  1031. if ( _wcsicmp( shi2->shi2_netname, NetName ) == 0 ) {
  1032. break;
  1033. }
  1034. }
  1035. //
  1036. // Does it exist?
  1037. //
  1038. if ( i == entriesRead ) {
  1039. MIDL_user_free( shareInfo );
  1040. return NERR_NetNameNotFound;
  1041. }
  1042. //
  1043. // Use appropriate security object based on whether it is a print
  1044. // share or not. Admin shares are not sticky.
  1045. //
  1046. shareType = shi2->shi2_type & ~STYPE_SPECIAL;
  1047. isPrintShare = (BOOL)(shareType == STYPE_PRINTQ);
  1048. MIDL_user_free( shareInfo );
  1049. //
  1050. // Make sure that the caller is allowed to delete this share.
  1051. //
  1052. if ( isPrintShare ) {
  1053. securityObject = &SsSharePrintSecurityObject;
  1054. } else {
  1055. securityObject = &SsShareFileSecurityObject;
  1056. }
  1057. error = SsCheckAccess(
  1058. securityObject,
  1059. SRVSVC_SHARE_INFO_SET
  1060. );
  1061. if ( error != NO_ERROR ) {
  1062. return error;
  1063. }
  1064. //
  1065. // Remove the value corresponding to the share from the Shares key,
  1066. // thus effecting a sticky share deletion.
  1067. //
  1068. error = SsRemoveShareFromRegistry( NetName );
  1069. if ( error == ERROR_FILE_NOT_FOUND ) {
  1070. error = NERR_NetNameNotFound;
  1071. }
  1072. return error;
  1073. } // NetrShareDelSticky
  1074. NET_API_STATUS NET_API_FUNCTION
  1075. NetrShareEnum (
  1076. SRVSVC_HANDLE ServerName,
  1077. LPSHARE_ENUM_STRUCT InfoStruct,
  1078. DWORD PreferredMaximumLength,
  1079. LPDWORD TotalEntries,
  1080. LPDWORD ResumeHandle
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. This routine communicates with the server FSD to implement the
  1085. NetShareEnum function.
  1086. Arguments:
  1087. None.
  1088. Return Value:
  1089. NET_API_STATUS - NO_ERROR or reason for failure.
  1090. --*/
  1091. {
  1092. NET_API_STATUS error;
  1093. ACCESS_MASK desiredAccess;
  1094. ServerName;
  1095. if( !ARGUMENT_PRESENT( InfoStruct ) ) {
  1096. return ERROR_INVALID_PARAMETER;
  1097. }
  1098. //
  1099. // Determine the desired access.
  1100. //
  1101. switch ( InfoStruct->Level ) {
  1102. case 0:
  1103. case 1:
  1104. case 501:
  1105. desiredAccess = SRVSVC_SHARE_USER_INFO_GET;
  1106. break;
  1107. case 2:
  1108. case 502:
  1109. desiredAccess = SRVSVC_SHARE_ADMIN_INFO_GET;
  1110. break;
  1111. default:
  1112. return ERROR_INVALID_LEVEL;
  1113. }
  1114. //
  1115. // Make sure that the caller has the access necessary for this
  1116. // operation.
  1117. //
  1118. error = SsCheckAccess(
  1119. &SsSharePrintSecurityObject,
  1120. desiredAccess
  1121. );
  1122. if ( error != NO_ERROR ) {
  1123. return error;
  1124. }
  1125. //
  1126. // Use the common routine to get the information.
  1127. //
  1128. if( InfoStruct->ShareInfo.Level2 == NULL ||
  1129. InfoStruct->ShareInfo.Level2->Buffer != NULL ) {
  1130. return ERROR_INVALID_PARAMETER;
  1131. }
  1132. return ShareEnumCommon(
  1133. InfoStruct->Level,
  1134. (LPBYTE *)&InfoStruct->ShareInfo.Level2->Buffer,
  1135. PreferredMaximumLength,
  1136. &InfoStruct->ShareInfo.Level2->EntriesRead,
  1137. TotalEntries,
  1138. ResumeHandle,
  1139. NULL
  1140. );
  1141. } // NetrShareEnum
  1142. NET_API_STATUS NET_API_FUNCTION
  1143. NetrShareEnumSticky (
  1144. SRVSVC_HANDLE ServerName,
  1145. LPSHARE_ENUM_STRUCT InfoStruct,
  1146. DWORD PreferredMaximumLength,
  1147. LPDWORD TotalEntries,
  1148. LPDWORD ResumeHandle OPTIONAL
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. This routine communicates with the server FSD to implement the
  1153. NetShareEnumSticky function.
  1154. Arguments:
  1155. ServerName - the name of the server whose shares we want to enumerate.
  1156. InfoStruct - pointer to a PSHARE_ENUM_STRUCT that will contain the
  1157. output buffer upon completion.
  1158. PreferredMaximumLength - an advisory value that specifies the maximum
  1159. number of bytes the client is expecting to be returned. If -1, the
  1160. client expects the whole list to be returned.
  1161. TotalEntries - Upon return, will contain the number of entries that
  1162. were available.
  1163. ResumeHandle - is not NULL, will contain the resume handle that can be
  1164. used to continue a search.
  1165. Return Value:
  1166. NET_API_STATUS - NO_ERROR or reason for failure.
  1167. --*/
  1168. {
  1169. NET_API_STATUS error;
  1170. ACCESS_MASK desiredAccess;
  1171. ServerName;
  1172. if( !ARGUMENT_PRESENT( InfoStruct ) ) {
  1173. return ERROR_INVALID_PARAMETER;
  1174. }
  1175. if( InfoStruct->ShareInfo.Level2 == NULL ||
  1176. InfoStruct->ShareInfo.Level2->Buffer != NULL ) {
  1177. return ERROR_INVALID_PARAMETER;
  1178. }
  1179. //
  1180. // Determine the desired access.
  1181. //
  1182. switch ( InfoStruct->Level ) {
  1183. case 0:
  1184. case 1:
  1185. desiredAccess = SRVSVC_SHARE_USER_INFO_GET;
  1186. break;
  1187. case 2:
  1188. case 502:
  1189. desiredAccess = SRVSVC_SHARE_ADMIN_INFO_GET;
  1190. break;
  1191. default:
  1192. return ERROR_INVALID_LEVEL;
  1193. }
  1194. //
  1195. // Make sure that the caller has the access necessary for this
  1196. // operation.
  1197. //
  1198. error = SsCheckAccess(
  1199. &SsSharePrintSecurityObject,
  1200. desiredAccess
  1201. );
  1202. if ( error != NO_ERROR ) {
  1203. return error;
  1204. }
  1205. //
  1206. // Use the common routine to get the information.
  1207. //
  1208. return ShareEnumSticky(
  1209. InfoStruct->Level,
  1210. (LPBYTE *)&InfoStruct->ShareInfo.Level2->Buffer,
  1211. PreferredMaximumLength,
  1212. &InfoStruct->ShareInfo.Level2->EntriesRead,
  1213. TotalEntries,
  1214. ResumeHandle
  1215. );
  1216. } // NetrShareEnumSticky
  1217. NET_API_STATUS NET_API_FUNCTION
  1218. NetrShareGetInfo (
  1219. IN LPWSTR ServerName,
  1220. IN LPWSTR NetName,
  1221. IN DWORD Level,
  1222. OUT LPSHARE_INFO Buffer
  1223. )
  1224. /*++
  1225. Routine Description:
  1226. This routine communicates with the server FSD to implement the
  1227. NetShareGetInfo function.
  1228. Arguments:
  1229. None.
  1230. Return Value:
  1231. NET_API_STATUS - NO_ERROR or reason for failure.
  1232. --*/
  1233. {
  1234. NET_API_STATUS error;
  1235. PSHARE_INFO_2 shareInfo = NULL;
  1236. ULONG entriesRead;
  1237. ULONG totalEntries;
  1238. ACCESS_MASK desiredAccess;
  1239. ServerName;
  1240. //
  1241. // A share name must be specified.
  1242. //
  1243. if ( (NetName == NULL) || (*NetName == '\0') ) {
  1244. return ERROR_INVALID_PARAMETER;
  1245. }
  1246. //
  1247. // Determine the desired access.
  1248. //
  1249. switch ( Level ) {
  1250. case 0:
  1251. case 1:
  1252. case 501:
  1253. case 1005:
  1254. desiredAccess = SRVSVC_SHARE_USER_INFO_GET;
  1255. break;
  1256. case 2:
  1257. case 502:
  1258. desiredAccess = SRVSVC_SHARE_ADMIN_INFO_GET;
  1259. break;
  1260. default:
  1261. return ERROR_INVALID_LEVEL;
  1262. }
  1263. //
  1264. // Make sure that the caller has the access necessary for this
  1265. // operation.
  1266. //
  1267. error = SsCheckAccess(
  1268. &SsSharePrintSecurityObject,
  1269. desiredAccess
  1270. );
  1271. if ( error != NO_ERROR ) {
  1272. return error;
  1273. }
  1274. //
  1275. // Use the common routine to get the information.
  1276. //
  1277. error = ShareEnumCommon(
  1278. Level,
  1279. (LPBYTE *)&shareInfo,
  1280. (DWORD)-1,
  1281. &entriesRead,
  1282. &totalEntries,
  1283. NULL,
  1284. NetName
  1285. );
  1286. if ( error != NO_ERROR ) {
  1287. if( shareInfo ) {
  1288. MIDL_user_free( shareInfo );
  1289. }
  1290. return error;
  1291. }
  1292. if ( entriesRead == 0 ) {
  1293. if( shareInfo ) {
  1294. MIDL_user_free( shareInfo );
  1295. }
  1296. return NERR_NetNameNotFound;
  1297. }
  1298. SS_ASSERT( entriesRead == 1 );
  1299. //
  1300. // Make sure that the caller is allowed to get share information on
  1301. // this share.
  1302. //
  1303. if ( Level == 502 ) {
  1304. Buffer->ShareInfo502 = (LPSHARE_INFO_502_I)shareInfo;
  1305. } else {
  1306. Buffer->ShareInfo2 = (LPSHARE_INFO_2)shareInfo;
  1307. }
  1308. return NO_ERROR;
  1309. } // NetrShareGetInfo
  1310. NET_API_STATUS NET_API_FUNCTION
  1311. NetrShareSetInfo (
  1312. IN LPWSTR ServerName,
  1313. IN LPWSTR NetName,
  1314. IN DWORD Level,
  1315. IN LPSHARE_INFO Buffer,
  1316. OUT LPDWORD ErrorParameter OPTIONAL
  1317. )
  1318. /*++
  1319. Routine Description:
  1320. This routine communicates with the server FSD to implement the
  1321. NetShareSetInfo function.
  1322. Arguments:
  1323. None.
  1324. Return Value:
  1325. NET_API_STATUS - NO_ERROR or reason for failure.
  1326. --*/
  1327. {
  1328. NET_API_STATUS error;
  1329. PSERVER_REQUEST_PACKET srp;
  1330. DWORD entriesRead;
  1331. DWORD totalEntries;
  1332. DWORD shareType;
  1333. BOOL isPrintShare;
  1334. BOOL isSpecial;
  1335. PSRVSVC_SECURITY_OBJECT securityObject;
  1336. PVOID capturedBuffer = NULL;
  1337. ULONG bufferLength;
  1338. LPWSTR remark = NULL;
  1339. ULONG maxUses = 0;
  1340. PSECURITY_DESCRIPTOR fileSd = NULL;
  1341. PSECURITY_DESCRIPTOR newFileSd = NULL;
  1342. BOOL setRemark;
  1343. BOOL setFileSd;
  1344. PSHARE_INFO_2 shi2 = NULL;
  1345. SHARE_INFO_2 localShi2;
  1346. ServerName;
  1347. //
  1348. // Check that user input buffer is not NULL
  1349. //
  1350. if (Buffer->ShareInfo2 == NULL) {
  1351. SET_ERROR_PARAMETER(PARM_ERROR_UNKNOWN);
  1352. return ERROR_INVALID_PARAMETER;
  1353. }
  1354. //
  1355. // Determine what the caller is trying to set.
  1356. //
  1357. switch ( Level ) {
  1358. case 502:
  1359. fileSd = Buffer->ShareInfo502->shi502_security_descriptor;
  1360. // *** lack of break is intentional!
  1361. case 2:
  1362. maxUses = Buffer->ShareInfo2->shi2_max_uses;
  1363. // *** lack of break is intentional!
  1364. case 1:
  1365. remark = Buffer->ShareInfo2->shi2_remark;
  1366. break;
  1367. case SHARE_REMARK_INFOLEVEL:
  1368. remark = Buffer->ShareInfo1004->shi1004_remark;
  1369. break;
  1370. case SHARE_MAX_USES_INFOLEVEL:
  1371. maxUses = Buffer->ShareInfo1006->shi1006_max_uses;
  1372. break;
  1373. case SHARE_FILE_SD_INFOLEVEL:
  1374. fileSd = Buffer->ShareInfo1501->shi1501_security_descriptor;
  1375. break;
  1376. case 1005:
  1377. Buffer->ShareInfo1005->shi1005_flags &= SHI1005_VALID_FLAGS_SET;
  1378. break;
  1379. default:
  1380. SS_PRINT(( "NetrShareSetInfo: invalid level: %ld\n", Level ));
  1381. SET_ERROR_PARAMETER( 0 );
  1382. return ERROR_INVALID_LEVEL;
  1383. }
  1384. setRemark = (BOOLEAN)( remark != NULL );
  1385. setFileSd = (BOOLEAN)( fileSd != NULL );
  1386. //
  1387. // A share name must be specified.
  1388. //
  1389. if ( (NetName == NULL) || (*NetName == '\0') ) {
  1390. return ERROR_INVALID_PARAMETER;
  1391. }
  1392. //
  1393. // Determine what kind of share is being modified.
  1394. //
  1395. error = ShareEnumCommon(
  1396. 2,
  1397. (LPBYTE *)&shi2,
  1398. (DWORD)-1,
  1399. &entriesRead,
  1400. &totalEntries,
  1401. NULL,
  1402. NetName
  1403. );
  1404. if ( error != NO_ERROR ) {
  1405. if( shi2 ) {
  1406. MIDL_user_free( shi2 );
  1407. }
  1408. return error;
  1409. }
  1410. if ( entriesRead == 0 ) {
  1411. if( shi2 ) {
  1412. MIDL_user_free( shi2 );
  1413. }
  1414. return NERR_NetNameNotFound;
  1415. }
  1416. shareType = shi2->shi2_type & ~STYPE_SPECIAL;
  1417. isSpecial = (BOOL)((shi2->shi2_type & STYPE_SPECIAL) != 0);
  1418. MIDL_user_free( shi2 );
  1419. //
  1420. // The share ACL cannot be changed on admin shares.
  1421. //
  1422. if ( isSpecial && setFileSd ) {
  1423. SET_ERROR_PARAMETER( SHARE_FILE_SD_PARMNUM );
  1424. error = ERROR_INVALID_PARAMETER;
  1425. goto exit;
  1426. }
  1427. //
  1428. // Figure out which kind of share this is.
  1429. //
  1430. isPrintShare = (BOOL)(shareType == STYPE_PRINTQ);
  1431. //
  1432. // Only disk shares can be affected by 1005
  1433. //
  1434. if( Level == 1005 && shareType != STYPE_DISKTREE ) {
  1435. error = ERROR_BAD_DEV_TYPE;
  1436. goto exit;
  1437. }
  1438. if( SsData.SsInitialized ) {
  1439. //
  1440. // Make sure that the caller is allowed to set share information on
  1441. // this share.
  1442. //
  1443. if ( isSpecial ) {
  1444. securityObject = &SsShareAdminSecurityObject;
  1445. } else if ( isPrintShare ) {
  1446. securityObject = &SsSharePrintSecurityObject;
  1447. } else {
  1448. securityObject = &SsShareFileSecurityObject;
  1449. }
  1450. error = SsCheckAccess( securityObject, SRVSVC_SHARE_INFO_SET );
  1451. if ( error != NO_ERROR ) {
  1452. return error;
  1453. }
  1454. }
  1455. //
  1456. // Just return success if not trying to set anything.
  1457. //
  1458. if ( !setRemark && (maxUses == 0) && !setFileSd && Level != 1005 ) {
  1459. return NO_ERROR;
  1460. }
  1461. //
  1462. // The remark must be no longer than MAXCOMMENTSZ.
  1463. //
  1464. if ( setRemark ) {
  1465. if ( STRLEN(remark) > MAXCOMMENTSZ ) {
  1466. SET_ERROR_PARAMETER( SHARE_REMARK_PARMNUM );
  1467. return ERROR_INVALID_PARAMETER;
  1468. }
  1469. }
  1470. //
  1471. // Mapped the security descriptor to remove the generic permissions
  1472. //
  1473. if ( setFileSd ) {
  1474. if ( !RtlValidSecurityDescriptor( fileSd ) ) {
  1475. SET_ERROR_PARAMETER( SHARE_FILE_SD_PARMNUM );
  1476. return ERROR_INVALID_PARAMETER;
  1477. }
  1478. error = ShareAssignSecurityDescriptor(
  1479. fileSd,
  1480. &newFileSd
  1481. );
  1482. if ( error != NO_ERROR ) {
  1483. SS_PRINT(( "NetrShareSetInfo: ShareAssignSecurityDescriptor "
  1484. "error: %d\n", error ));
  1485. SET_ERROR_PARAMETER( SHARE_FILE_SD_PARMNUM );
  1486. return ERROR_INVALID_PARAMETER;
  1487. }
  1488. }
  1489. //
  1490. // Allocate a request packet.
  1491. //
  1492. srp = SsAllocateSrp( );
  1493. if ( srp == NULL ) {
  1494. error = ERROR_NOT_ENOUGH_MEMORY;
  1495. goto exit;
  1496. }
  1497. srp->Level = Level;
  1498. //
  1499. // Set up the share name.
  1500. //
  1501. RtlInitUnicodeString( &srp->Name1, NetName );
  1502. //
  1503. // Set up the MaxUses field. If equal to 0, then it won't be changed
  1504. // by the server.
  1505. //
  1506. srp->Parameters.Set.Api.ShareInfo.MaxUses = maxUses;
  1507. //
  1508. // Capture the share data structure passed in.
  1509. //
  1510. localShi2.shi2_netname = NetName;
  1511. switch( Level ) {
  1512. case 1005:
  1513. bufferLength = sizeof(SHARE_INFO_1005);
  1514. capturedBuffer = MIDL_user_allocate( bufferLength );
  1515. if( capturedBuffer == NULL ) {
  1516. SET_ERROR_PARAMETER( 0 );
  1517. error = ERROR_NOT_ENOUGH_MEMORY;
  1518. goto exit;
  1519. }
  1520. RtlZeroMemory( capturedBuffer, bufferLength );
  1521. *((PSHARE_INFO_1005) capturedBuffer) = *Buffer->ShareInfo1005;
  1522. break;
  1523. default:
  1524. capturedBuffer = CaptureShareInfo(
  1525. Level,
  1526. &localShi2,
  1527. 0, // ShareType, unused for SHARE_SET_INFO
  1528. NULL,
  1529. remark,
  1530. NULL,
  1531. newFileSd,
  1532. &bufferLength
  1533. );
  1534. if ( capturedBuffer == NULL ) {
  1535. SET_ERROR_PARAMETER( 0 );
  1536. error = ERROR_NOT_ENOUGH_MEMORY;
  1537. goto exit;
  1538. }
  1539. break;
  1540. }
  1541. //
  1542. // Send the request to the server.
  1543. //
  1544. error = SsServerFsControl(
  1545. FSCTL_SRV_NET_SHARE_SET_INFO,
  1546. srp,
  1547. capturedBuffer,
  1548. bufferLength
  1549. );
  1550. //
  1551. // If the request succeeded, modify the share's value in the Shares
  1552. // key, thus effecting a sticky change.
  1553. //
  1554. // We don't do this if this is an admin share being modified. No
  1555. // registry information is kept for these shares.
  1556. //
  1557. if ( (error == NO_ERROR) && !isSpecial ) {
  1558. DWORD entriesRead;
  1559. DWORD totalEntries;
  1560. NET_API_STATUS error2;
  1561. shi2 = NULL;
  1562. error2 = ShareEnumCommon(
  1563. 2,
  1564. (LPBYTE *)&shi2,
  1565. (DWORD)-1,
  1566. &entriesRead,
  1567. &totalEntries,
  1568. NULL,
  1569. NetName
  1570. );
  1571. if ( error2 == NO_ERROR ) {
  1572. DWORD CSCFlags = 0;
  1573. if( Level != 1005 ) {
  1574. PSHARE_INFO_501 shi501 = NULL;
  1575. if( ShareEnumCommon(
  1576. 501,
  1577. (LPBYTE *)&shi501,
  1578. (DWORD)-1,
  1579. &entriesRead,
  1580. &totalEntries,
  1581. NULL,
  1582. NetName
  1583. ) == NO_ERROR && shi501 != NULL ) {
  1584. CSCFlags = shi501->shi501_flags & CSC_MASK;
  1585. }
  1586. if( shi501 ) {
  1587. MIDL_user_free( shi501 );
  1588. }
  1589. } else {
  1590. CSCFlags = Buffer->ShareInfo1005->shi1005_flags & CSC_MASK;
  1591. }
  1592. SsAddShareToRegistry( shi2,
  1593. newFileSd,
  1594. CSCFlags
  1595. );
  1596. }
  1597. if( shi2 ) {
  1598. MIDL_user_free( shi2 );
  1599. }
  1600. }
  1601. //
  1602. // Set up the error parameter if requested and return.
  1603. //
  1604. SET_ERROR_PARAMETER( srp->Parameters.Set.ErrorParameter );
  1605. exit:
  1606. if (srp != NULL) {
  1607. SsFreeSrp( srp );
  1608. }
  1609. if ( newFileSd != NULL ) {
  1610. (VOID)RtlDeleteSecurityObject( &newFileSd );
  1611. }
  1612. if( capturedBuffer != NULL ) {
  1613. MIDL_user_free( capturedBuffer );
  1614. }
  1615. return error;
  1616. } // NetrShareSetInfo
  1617. PVOID
  1618. CaptureShareInfo (
  1619. IN DWORD Level,
  1620. IN PSHARE_INFO_2 Shi2,
  1621. IN DWORD ShareType OPTIONAL,
  1622. IN LPWSTR Path OPTIONAL,
  1623. IN LPWSTR Remark OPTIONAL,
  1624. IN PSECURITY_DESCRIPTOR ConnectSecurityDescriptor OPTIONAL,
  1625. IN PSECURITY_DESCRIPTOR FileSecurityDescriptor OPTIONAL,
  1626. OUT PULONG CapturedBufferLength
  1627. )
  1628. {
  1629. PSHARE_INFO_502 capturedShi502;
  1630. ULONG capturedBufferLength;
  1631. PCHAR variableData;
  1632. ULONG pathNameLength;
  1633. ULONG shareNameLength;
  1634. ULONG remarkLength;
  1635. ULONG connectSDLength = 0;
  1636. ULONG fileSdLength = 0;
  1637. //
  1638. // Determine the lengths of the strings in the buffer and the total
  1639. // length of the buffer.
  1640. //
  1641. if ( Shi2->shi2_netname == NULL ) {
  1642. shareNameLength = 0;
  1643. } else {
  1644. shareNameLength = SIZE_WSTR( Shi2->shi2_netname );
  1645. }
  1646. if ( Path == NULL ) {
  1647. pathNameLength = 0;
  1648. } else {
  1649. pathNameLength = SIZE_WSTR( Path );
  1650. }
  1651. if ( Remark == NULL ) {
  1652. remarkLength = 0;
  1653. } else {
  1654. remarkLength = SIZE_WSTR( Remark );
  1655. }
  1656. if ( ARGUMENT_PRESENT( ConnectSecurityDescriptor ) ) {
  1657. //
  1658. // Allocate extra space for the security descriptor since it needs
  1659. // to be longword-aligned and there may be padding in front of it.
  1660. //
  1661. connectSDLength =
  1662. RtlLengthSecurityDescriptor( ConnectSecurityDescriptor ) +
  1663. sizeof(ULONG);
  1664. }
  1665. if ( ARGUMENT_PRESENT( FileSecurityDescriptor ) ) {
  1666. //
  1667. // ULONG added for alignment.
  1668. //
  1669. fileSdLength = RtlLengthSecurityDescriptor( FileSecurityDescriptor ) +
  1670. sizeof(ULONG);
  1671. }
  1672. //
  1673. // Allocate a buffer in which to capture the share information.
  1674. //
  1675. capturedBufferLength = sizeof(SHARE_INFO_502) +
  1676. shareNameLength +
  1677. remarkLength +
  1678. pathNameLength +
  1679. connectSDLength +
  1680. fileSdLength;
  1681. //
  1682. // Allocate a buffer to hold the input information.
  1683. //
  1684. capturedShi502 = MIDL_user_allocate( capturedBufferLength );
  1685. if ( capturedShi502 == NULL ) {
  1686. *CapturedBufferLength = 0;
  1687. return NULL;
  1688. }
  1689. //
  1690. // Copy over the share info structure.
  1691. //
  1692. *((PSHARE_INFO_2) capturedShi502) = *Shi2;
  1693. //
  1694. // Optionally override the share type.
  1695. //
  1696. if ( ShareType != 0 ) {
  1697. capturedShi502->shi502_type = ShareType;
  1698. }
  1699. //
  1700. // Capture the share name.
  1701. //
  1702. variableData = (PCHAR)( capturedShi502 + 1 );
  1703. if ( shareNameLength != 0 ) {
  1704. capturedShi502->shi502_netname = (LPWSTR)variableData;
  1705. RtlCopyMemory( variableData, Shi2->shi2_netname, shareNameLength );
  1706. variableData += shareNameLength;
  1707. } else {
  1708. capturedShi502->shi502_netname = NULL;
  1709. }
  1710. //
  1711. // Capture the remark.
  1712. //
  1713. if ( remarkLength != 0 ) {
  1714. capturedShi502->shi502_remark = (LPWSTR)variableData;
  1715. RtlCopyMemory( variableData, Remark, remarkLength );
  1716. variableData += remarkLength;
  1717. } else {
  1718. capturedShi502->shi502_remark = NULL;
  1719. }
  1720. //
  1721. // Capture the path.
  1722. //
  1723. if ( pathNameLength > 0 ) {
  1724. capturedShi502->shi502_path = (LPWSTR)variableData;
  1725. RtlCopyMemory( variableData, Path, pathNameLength );
  1726. variableData += pathNameLength;
  1727. } else {
  1728. capturedShi502->shi502_path = NULL;
  1729. }
  1730. //
  1731. // Capture the security descriptor. Use the shi502_permissions field
  1732. // to contain the offset to the security descriptor in the buffer.
  1733. //
  1734. if ( ARGUMENT_PRESENT( ConnectSecurityDescriptor ) ) {
  1735. variableData = (PCHAR)( ((ULONG_PTR)variableData + 3) & ~3 );
  1736. //
  1737. // Store the offset directly into shi502_permissions now. The
  1738. // reason is that shi502_permissions is a 32-bit field, insufficient
  1739. // to contain a pointer under Sundown.
  1740. //
  1741. capturedShi502->shi502_permissions = (ULONG)((ULONG_PTR)variableData -
  1742. (ULONG_PTR)capturedShi502);
  1743. RtlCopyMemory(
  1744. variableData,
  1745. ConnectSecurityDescriptor,
  1746. connectSDLength - sizeof(ULONG)
  1747. );
  1748. variableData += (connectSDLength - sizeof(ULONG));
  1749. } else {
  1750. capturedShi502->shi502_permissions = 0;
  1751. }
  1752. //
  1753. // Capture the self relative form of the file security descriptor.
  1754. //
  1755. if ( ARGUMENT_PRESENT( FileSecurityDescriptor ) ) {
  1756. variableData = (PCHAR)( ((ULONG_PTR)variableData + 3) & ~3 );
  1757. capturedShi502->shi502_security_descriptor = (LPBYTE) variableData;
  1758. variableData += ( fileSdLength - sizeof(ULONG)) ;
  1759. RtlCopyMemory(
  1760. (PVOID)capturedShi502->shi502_security_descriptor,
  1761. FileSecurityDescriptor,
  1762. fileSdLength - sizeof(ULONG)
  1763. );
  1764. } else {
  1765. capturedShi502->shi502_security_descriptor = (LPBYTE) NULL;
  1766. }
  1767. //
  1768. // Convert all the pointers in the structure to offsets from the
  1769. // beginning of the structure.
  1770. //
  1771. POINTER_TO_OFFSET( capturedShi502->shi502_netname, capturedShi502 );
  1772. POINTER_TO_OFFSET( capturedShi502->shi502_remark, capturedShi502 );
  1773. POINTER_TO_OFFSET( capturedShi502->shi502_path, capturedShi502 );
  1774. POINTER_TO_OFFSET( (PCHAR)capturedShi502->shi502_security_descriptor, capturedShi502 );
  1775. //
  1776. // Set up the length of the captured buffer to return to the caller
  1777. // and return the captures structure.
  1778. //
  1779. *CapturedBufferLength = capturedBufferLength;
  1780. return capturedShi502;
  1781. } // CaptureShareInfo
  1782. NET_API_STATUS
  1783. DisallowSharedLanmanNetDrives(
  1784. IN PUNICODE_STRING NtSharePath
  1785. )
  1786. {
  1787. NET_API_STATUS error = NERR_Success;
  1788. NTSTATUS status;
  1789. HANDLE linkHandle;
  1790. OBJECT_ATTRIBUTES objAttr;
  1791. UNICODE_STRING linkTarget;
  1792. ULONG returnedLength = 0;
  1793. UNICODE_STRING tempNtPath;
  1794. linkTarget.Buffer = NULL;
  1795. linkTarget.MaximumLength = 0;
  1796. linkTarget.Length = 0;
  1797. tempNtPath = *NtSharePath;
  1798. //
  1799. // Remove the trailing '\\'
  1800. //
  1801. tempNtPath.Length -= 2;
  1802. InitializeObjectAttributes(
  1803. &objAttr,
  1804. &tempNtPath,
  1805. OBJ_CASE_INSENSITIVE,
  1806. 0,
  1807. NULL
  1808. );
  1809. status = NtOpenSymbolicLinkObject(
  1810. &linkHandle,
  1811. SYMBOLIC_LINK_QUERY,
  1812. &objAttr
  1813. );
  1814. if ( !NT_SUCCESS(status) ) {
  1815. return NERR_Success;
  1816. }
  1817. //
  1818. // Get the size of the buffer needed.
  1819. //
  1820. status = NtQuerySymbolicLinkObject(
  1821. linkHandle,
  1822. &linkTarget,
  1823. &returnedLength
  1824. );
  1825. if ( !NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL ) {
  1826. NtClose( linkHandle );
  1827. return NERR_Success;
  1828. }
  1829. //
  1830. // Allocate our buffer
  1831. //
  1832. linkTarget.Length = (USHORT)returnedLength;
  1833. linkTarget.MaximumLength = (USHORT)(returnedLength + sizeof(WCHAR));
  1834. linkTarget.Buffer = MIDL_user_allocate( linkTarget.MaximumLength );
  1835. if ( linkTarget.Buffer == NULL ) {
  1836. NtClose( linkHandle );
  1837. return NERR_Success;
  1838. }
  1839. status = NtQuerySymbolicLinkObject(
  1840. linkHandle,
  1841. &linkTarget,
  1842. &returnedLength
  1843. );
  1844. NtClose( linkHandle );
  1845. if ( NT_SUCCESS(status) ) {
  1846. //
  1847. // See if this is a lanman drive
  1848. //
  1849. if (_wcsnicmp(
  1850. linkTarget.Buffer,
  1851. DD_NFS_DEVICE_NAME_U,
  1852. wcslen(DD_NFS_DEVICE_NAME_U)) == 0) {
  1853. error = NERR_RedirectedPath;
  1854. }
  1855. }
  1856. MIDL_user_free( linkTarget.Buffer );
  1857. return(error);
  1858. } // DisallowSharedLanmanNetDrives
  1859. NET_API_STATUS
  1860. FillStickyShareInfo(
  1861. IN PSRVSVC_SHARE_ENUM_INFO ShareEnumInfo,
  1862. IN PSHARE_INFO_502 Shi502
  1863. )
  1864. /*++
  1865. Routine Description:
  1866. This routine fills in the output buffer with data from the shi502
  1867. structure.
  1868. Arguments:
  1869. ShareEnumInfo - contains the parameters passed in through the
  1870. NetShareEnumSticky api.
  1871. Shi502 - pointer to a shi502 structure
  1872. Return Value:
  1873. status of operation.
  1874. --*/
  1875. {
  1876. PSHARE_INFO_502 newShi502;
  1877. PCHAR endOfVariableData;
  1878. ShareEnumInfo->TotalBytesNeeded += SizeShares(
  1879. ShareEnumInfo->Level,
  1880. Shi502
  1881. );
  1882. //
  1883. // If we have more data but ran out of space, return ERROR_MORE_DATA
  1884. //
  1885. if ( ShareEnumInfo->TotalBytesNeeded >
  1886. ShareEnumInfo->OutputBufferLength ) {
  1887. return(ERROR_MORE_DATA);
  1888. }
  1889. //
  1890. // Transfer data from the share info 502 structure to the output
  1891. // buffer.
  1892. //
  1893. newShi502 = (PSHARE_INFO_502)ShareEnumInfo->StartOfFixedData;
  1894. ShareEnumInfo->StartOfFixedData += FIXED_SIZE_OF_SHARE(ShareEnumInfo->Level);
  1895. endOfVariableData = ShareEnumInfo->EndOfVariableData;
  1896. //
  1897. // Case on the level to fill in the fixed structure appropriately.
  1898. // We fill in actual pointers in the output structure. This is
  1899. // possible because we are in the server FSD, hence the server
  1900. // service's process and address space.
  1901. //
  1902. // *** This routine assumes that the fixed structure will fit in the
  1903. // buffer!
  1904. //
  1905. // *** Using the switch statement in this fashion relies on the fact
  1906. // that the first fields on the different share structures are
  1907. // identical.
  1908. //
  1909. switch( ShareEnumInfo->Level ) {
  1910. case 502:
  1911. if ( Shi502->shi502_security_descriptor != NULL ) {
  1912. ULONG fileSDLength;
  1913. fileSDLength = RtlLengthSecurityDescriptor(
  1914. Shi502->shi502_security_descriptor
  1915. );
  1916. //
  1917. // DWord Align
  1918. //
  1919. endOfVariableData = (PCHAR) ( (ULONG_PTR) ( endOfVariableData -
  1920. fileSDLength ) & ~3 );
  1921. newShi502->shi502_security_descriptor = endOfVariableData;
  1922. newShi502->shi502_reserved = fileSDLength;
  1923. RtlMoveMemory(
  1924. newShi502->shi502_security_descriptor,
  1925. Shi502->shi502_security_descriptor,
  1926. fileSDLength
  1927. );
  1928. } else {
  1929. newShi502->shi502_security_descriptor = NULL;
  1930. newShi502->shi502_reserved = 0;
  1931. }
  1932. case 2:
  1933. //
  1934. // Set level 2 specific fields in the buffer. Since this server
  1935. // can only have user-level security, share permissions are
  1936. // meaningless.
  1937. //
  1938. newShi502->shi502_permissions = 0;
  1939. newShi502->shi502_max_uses = Shi502->shi502_max_uses;
  1940. //
  1941. // To get the current uses, we need to query the server for this
  1942. //
  1943. {
  1944. PSHARE_INFO_2 shareInfo = NULL;
  1945. NET_API_STATUS error;
  1946. DWORD entriesRead;
  1947. DWORD totalEntries;
  1948. error = ShareEnumCommon(
  1949. 2,
  1950. (LPBYTE *)&shareInfo,
  1951. (DWORD)-1,
  1952. &entriesRead,
  1953. &totalEntries,
  1954. NULL,
  1955. Shi502->shi502_netname
  1956. );
  1957. if ( error != NO_ERROR || entriesRead == 0 ) {
  1958. newShi502->shi502_current_uses = 0;
  1959. } else {
  1960. newShi502->shi502_current_uses = shareInfo->shi2_current_uses;
  1961. }
  1962. if( shareInfo ) {
  1963. MIDL_user_free( shareInfo );
  1964. }
  1965. }
  1966. //
  1967. // Copy the DOS path name to the buffer.
  1968. //
  1969. if ( Shi502->shi502_path != NULL ) {
  1970. endOfVariableData -= SIZE_WSTR( Shi502->shi502_path );
  1971. newShi502->shi502_path = (LPTSTR) endOfVariableData;
  1972. wcscpy( newShi502->shi502_path, Shi502->shi502_path );
  1973. } else {
  1974. newShi502->shi502_path = NULL;
  1975. }
  1976. //
  1977. // We don't have per-share passwords (share-level security)
  1978. // so set the password pointer to NULL.
  1979. //
  1980. newShi502->shi502_passwd = NULL;
  1981. // *** Lack of break is intentional!
  1982. case 1:
  1983. newShi502->shi502_type = Shi502->shi502_type;
  1984. //
  1985. // Copy the remark to the buffer. The routine will handle the
  1986. // case where there is no remark on the share and put a pointer
  1987. // to a zero terminator in the buffer.
  1988. //
  1989. if ( Shi502->shi502_remark != NULL ) {
  1990. endOfVariableData -= SIZE_WSTR( Shi502->shi502_remark );
  1991. newShi502->shi502_remark = (LPTSTR) endOfVariableData;
  1992. wcscpy( newShi502->shi502_remark, Shi502->shi502_remark );
  1993. } else {
  1994. newShi502->shi502_remark = NULL;
  1995. }
  1996. // *** Lack of break is intentional!
  1997. case 0:
  1998. //
  1999. // Copy the share name to the buffer.
  2000. //
  2001. if ( Shi502->shi502_netname != NULL ) {
  2002. endOfVariableData -= SIZE_WSTR( Shi502->shi502_netname );
  2003. newShi502->shi502_netname = (LPTSTR) endOfVariableData;
  2004. wcscpy( newShi502->shi502_netname, Shi502->shi502_netname );
  2005. } else {
  2006. newShi502->shi502_remark = NULL;
  2007. }
  2008. break;
  2009. }
  2010. ShareEnumInfo->EndOfVariableData = endOfVariableData;
  2011. return NO_ERROR;
  2012. } // FillStickyShareInfo
  2013. NET_API_STATUS
  2014. ShareAssignSecurityDescriptor(
  2015. IN PSECURITY_DESCRIPTOR PassedSecurityDescriptor,
  2016. OUT PSECURITY_DESCRIPTOR *NewSecurityDescriptor
  2017. )
  2018. /*++
  2019. Routine Description:
  2020. This routine converts a the generic mappings in an sd to
  2021. standards and specifics.
  2022. Arguments:
  2023. PassedSecurityDescriptor - Security descriptor passed from the client.
  2024. NewSecurityDescriptor - Pointer to a buffer to receive the new sd.
  2025. Return Value:
  2026. NET_API_STATUS - NO_ERROR or reason for failure.
  2027. --*/
  2028. {
  2029. NTSTATUS status;
  2030. HANDLE token;
  2031. PISECURITY_DESCRIPTOR_RELATIVE trustedSecurityDescriptor = NULL;
  2032. NET_API_STATUS error;
  2033. ULONG secLen;
  2034. //
  2035. // We don't necessarily trust the security descriptor passed in from the client.
  2036. // And, since we are going to write to it, we better make sure it is in some
  2037. // memory that we understand.
  2038. //
  2039. try {
  2040. // We only work with Self-Relative SD's, reject any others
  2041. if( !RtlpAreControlBitsSet((PISECURITY_DESCRIPTOR)PassedSecurityDescriptor, SE_SELF_RELATIVE) )
  2042. {
  2043. return ERROR_INVALID_PARAMETER;
  2044. }
  2045. secLen = RtlLengthSecurityDescriptor( PassedSecurityDescriptor );
  2046. if( secLen < sizeof( *trustedSecurityDescriptor ) ) {
  2047. RaiseException( STATUS_INVALID_PARAMETER, 0, 0, NULL );
  2048. }
  2049. trustedSecurityDescriptor = (PISECURITY_DESCRIPTOR_RELATIVE)MIDL_user_allocate( secLen );
  2050. if( trustedSecurityDescriptor == NULL ) {
  2051. RaiseException( STATUS_INSUFFICIENT_RESOURCES, 0, 0, NULL );
  2052. }
  2053. RtlCopyMemory( trustedSecurityDescriptor, PassedSecurityDescriptor, secLen );
  2054. trustedSecurityDescriptor->Owner = 0;
  2055. trustedSecurityDescriptor->Group = 0;
  2056. trustedSecurityDescriptor->Sacl = 0;
  2057. trustedSecurityDescriptor->Control &=
  2058. (SE_DACL_DEFAULTED | SE_DACL_PRESENT | SE_SELF_RELATIVE | SE_DACL_PROTECTED);
  2059. //
  2060. // Impersonate client
  2061. //
  2062. status = RpcImpersonateClient( NULL );
  2063. if( !NT_SUCCESS( status ) ) {
  2064. RaiseException( status, 0, 0, NULL );
  2065. }
  2066. status = NtOpenThreadToken(
  2067. NtCurrentThread(),
  2068. TOKEN_QUERY,
  2069. TRUE,
  2070. &token
  2071. );
  2072. (VOID)RpcRevertToSelf( );
  2073. if( !NT_SUCCESS( status ) ) {
  2074. RaiseException( status, 0, 0, NULL );
  2075. }
  2076. //
  2077. // Get a new sd which has the generics mapped to specifics.
  2078. // the returned sd is in self-relative form.
  2079. //
  2080. status = RtlNewSecurityObject(
  2081. NULL,
  2082. trustedSecurityDescriptor,
  2083. NewSecurityDescriptor,
  2084. FALSE,
  2085. token,
  2086. &SrvShareFileGenericMapping
  2087. );
  2088. ASSERT( RtlValidSecurityDescriptor( *NewSecurityDescriptor ) );
  2089. NtClose( token );
  2090. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  2091. status = GetExceptionCode();
  2092. }
  2093. if( trustedSecurityDescriptor != NULL ) {
  2094. MIDL_user_free( trustedSecurityDescriptor );
  2095. }
  2096. return RtlNtStatusToDosError( status );
  2097. } // ShareAssignSecurityDescriptor
  2098. void
  2099. SHARE_DEL_HANDLE_rundown (
  2100. SHARE_DEL_HANDLE ContextHandle
  2101. )
  2102. {
  2103. (VOID)NetrShareDelCommit( &ContextHandle );
  2104. return;
  2105. } // SHARE_DEL_HANDLE_rundown
  2106. NET_API_STATUS
  2107. ShareEnumCommon (
  2108. IN DWORD Level,
  2109. OUT LPBYTE *Buffer,
  2110. IN DWORD PreferredMaximumLength,
  2111. OUT LPDWORD EntriesRead,
  2112. OUT LPDWORD TotalEntries,
  2113. IN OUT LPDWORD ResumeHandle OPTIONAL,
  2114. IN LPWSTR NetName OPTIONAL
  2115. )
  2116. {
  2117. NET_API_STATUS error;
  2118. PSERVER_REQUEST_PACKET srp;
  2119. if( !ARGUMENT_PRESENT( EntriesRead ) || !ARGUMENT_PRESENT( TotalEntries ) ) {
  2120. return ERROR_INVALID_PARAMETER;
  2121. }
  2122. //
  2123. // Make sure that the level is valid. Since it is an unsigned
  2124. // value, it can never be less than 0.
  2125. //
  2126. if ( (Level > 2) && (Level != 501 ) && (Level != 502) && (Level != 1005) ) {
  2127. return ERROR_INVALID_LEVEL;
  2128. }
  2129. //
  2130. // Set up the input parameters in the request buffer.
  2131. //
  2132. srp = SsAllocateSrp( );
  2133. if ( srp == NULL ) {
  2134. return ERROR_NOT_ENOUGH_MEMORY;
  2135. }
  2136. srp->Level = Level;
  2137. if ( ARGUMENT_PRESENT( NetName ) ) {
  2138. srp->Flags = SRP_RETURN_SINGLE_ENTRY;
  2139. }
  2140. if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
  2141. srp->Parameters.Get.ResumeHandle = *ResumeHandle;
  2142. } else {
  2143. srp->Parameters.Get.ResumeHandle = 0;
  2144. }
  2145. RtlInitUnicodeString( &srp->Name1, NetName );
  2146. //
  2147. // Get the data from the server. This routine will allocate the
  2148. // return buffer and handle the case where PreferredMaximumLength ==
  2149. // -1.
  2150. //
  2151. error = SsServerFsControlGetInfo(
  2152. FSCTL_SRV_NET_SHARE_ENUM,
  2153. srp,
  2154. (PVOID *)Buffer,
  2155. PreferredMaximumLength
  2156. );
  2157. //
  2158. // Set up return information.
  2159. //
  2160. *EntriesRead = srp->Parameters.Get.EntriesRead;
  2161. *TotalEntries = srp->Parameters.Get.TotalEntries;
  2162. if ( *EntriesRead > 0 && ARGUMENT_PRESENT( ResumeHandle ) ) {
  2163. *ResumeHandle = srp->Parameters.Get.ResumeHandle;
  2164. }
  2165. SsFreeSrp( srp );
  2166. //
  2167. // We need to null out the owner, group, and sacl.
  2168. //
  2169. if ( Level == 502 && *Buffer != NULL ) {
  2170. PSHARE_INFO_502 shi502 = (PSHARE_INFO_502) *Buffer;
  2171. PSECURITY_DESCRIPTOR fileSD;
  2172. ULONG i;
  2173. for ( i = 0 ; i < *EntriesRead; i++, shi502++ ) {
  2174. fileSD = shi502->shi502_security_descriptor;
  2175. if ( fileSD != NULL ) {
  2176. PISECURITY_DESCRIPTOR SD = fileSD;
  2177. if (SD->Control & SE_SELF_RELATIVE) {
  2178. PISECURITY_DESCRIPTOR_RELATIVE SDR = fileSD;
  2179. SDR->Owner = 0;
  2180. SDR->Group = 0;
  2181. SDR->Sacl = 0;
  2182. } else {
  2183. SD->Owner = NULL;
  2184. SD->Group = NULL;
  2185. SD->Sacl = NULL;
  2186. }
  2187. SD->Control &=
  2188. (SE_DACL_DEFAULTED | SE_DACL_PROTECTED | SE_DACL_PRESENT | SE_SELF_RELATIVE);
  2189. ASSERT( RtlValidSecurityDescriptor( fileSD ) );
  2190. }
  2191. } // for
  2192. }
  2193. return error;
  2194. } // ShareEnumCommon
  2195. NET_API_STATUS
  2196. ShareEnumSticky (
  2197. IN DWORD Level,
  2198. OUT LPBYTE *Buffer,
  2199. IN DWORD PreferredMaximumLength,
  2200. OUT LPDWORD EntriesRead,
  2201. OUT LPDWORD TotalEntries,
  2202. IN OUT LPDWORD ResumeHandle OPTIONAL
  2203. )
  2204. /*++
  2205. Routine Description:
  2206. This routine enumerates all the shares kept in the registry.
  2207. Arguments:
  2208. Same as NetShareEnumSticky api.
  2209. Return Value:
  2210. status of request.
  2211. --*/
  2212. {
  2213. NET_API_STATUS error;
  2214. BOOLEAN getEverything;
  2215. ULONG oldResumeHandle;
  2216. SRVSVC_SHARE_ENUM_INFO enumInfo;
  2217. //
  2218. // Set up the input parameters in the request buffer.
  2219. //
  2220. enumInfo.Level = Level;
  2221. if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
  2222. enumInfo.ResumeHandle = *ResumeHandle;
  2223. } else {
  2224. enumInfo.ResumeHandle = 0;
  2225. }
  2226. oldResumeHandle = enumInfo.ResumeHandle;
  2227. //
  2228. // If the length of the second buffer is specified as -1, then we
  2229. // are supposed to get all the information, regardless of size.
  2230. // Allocate space for the output buffer and try to use it. If this
  2231. // fails, the SsEnumerateStickyShares will tell us just how much we
  2232. // really need to allocate.
  2233. //
  2234. if ( PreferredMaximumLength == 0xFFFFFFFF ) {
  2235. enumInfo.OutputBufferLength = INITIAL_BUFFER_SIZE;
  2236. getEverything = TRUE;
  2237. } else {
  2238. enumInfo.OutputBufferLength = PreferredMaximumLength;
  2239. getEverything = FALSE;
  2240. }
  2241. enumInfo.OutputBuffer = MIDL_user_allocate( enumInfo.OutputBufferLength );
  2242. if ( enumInfo.OutputBuffer == NULL ) {
  2243. return ERROR_NOT_ENOUGH_MEMORY;
  2244. }
  2245. //
  2246. // Make the request
  2247. //
  2248. error = SsEnumerateStickyShares( &enumInfo );
  2249. //
  2250. // If the call was successful, or there was an error other than
  2251. // ERROR_MORE_DATA (which indicates that the buffer wasn't large
  2252. // enough), or the passed in buffer size was all we're allowed to
  2253. // allocate, return to the caller.
  2254. //
  2255. if ( (error != ERROR_MORE_DATA && error != NERR_BufTooSmall) ||
  2256. !getEverything ) {
  2257. //
  2258. // If no entries were found, free the buffer and set the pointer
  2259. // to NULL.
  2260. //
  2261. if ( enumInfo.EntriesRead == 0 ) {
  2262. MIDL_user_free( enumInfo.OutputBuffer );
  2263. enumInfo.OutputBuffer = NULL;
  2264. }
  2265. goto exit;
  2266. }
  2267. //
  2268. // The initial buffer wasn't large enough, and we're allowed to
  2269. // allocate more. Free the first buffer.
  2270. //
  2271. MIDL_user_free( enumInfo.OutputBuffer );
  2272. //
  2273. // Allocate a buffer large enough to hold all the information, plus
  2274. // a fudge factor in case the amount of information has increased.
  2275. // If the amount of information increased more than the fudge factor,
  2276. // then we give up. This should almost never happen.
  2277. //
  2278. enumInfo.OutputBufferLength = enumInfo.TotalBytesNeeded + EXTRA_ALLOCATION;
  2279. enumInfo.OutputBuffer = MIDL_user_allocate( enumInfo.OutputBufferLength );
  2280. if ( enumInfo.OutputBuffer == NULL ) {
  2281. return ERROR_NOT_ENOUGH_MEMORY;
  2282. }
  2283. //
  2284. // Reset the resume handle in the SRP. It was altered by the first
  2285. // Enum attempt.
  2286. //
  2287. enumInfo.ResumeHandle = oldResumeHandle;
  2288. //
  2289. // Try again to get the information from the server, this time with the
  2290. // larger buffer.
  2291. //
  2292. error = SsEnumerateStickyShares( &enumInfo );
  2293. exit:
  2294. //
  2295. // Set up return information.
  2296. //
  2297. *Buffer = enumInfo.OutputBuffer;
  2298. *EntriesRead = enumInfo.EntriesRead;
  2299. *TotalEntries = enumInfo.TotalEntries;
  2300. if ( *EntriesRead > 0 && ARGUMENT_PRESENT( ResumeHandle ) ) {
  2301. *ResumeHandle = enumInfo.ResumeHandle;
  2302. }
  2303. return error;
  2304. } // ShareEnumSticky
  2305. ULONG
  2306. SizeShares (
  2307. IN ULONG Level,
  2308. IN PSHARE_INFO_502 Shi502
  2309. )
  2310. /*++
  2311. Routine Description:
  2312. This routine returns the size the passed-in share would take up in
  2313. an API output buffer.
  2314. Arguments:
  2315. Level - level of request
  2316. Shi502 - pointer to a shi502 structure
  2317. Return Value:
  2318. ULONG - The number of bytes the share would take up in the
  2319. output buffer.
  2320. --*/
  2321. {
  2322. ULONG shareSize = 0;
  2323. switch ( Level ) {
  2324. case 502:
  2325. if ( Shi502->shi502_security_descriptor != NULL ) {
  2326. //
  2327. // add 4 bytes for possible padding
  2328. //
  2329. shareSize = sizeof( ULONG ) +
  2330. RtlLengthSecurityDescriptor( Shi502->shi502_security_descriptor );
  2331. }
  2332. case 2:
  2333. shareSize += SIZE_WSTR( Shi502->shi502_path );
  2334. case 501:
  2335. case 1:
  2336. shareSize += SIZE_WSTR( Shi502->shi502_remark );
  2337. case 0:
  2338. shareSize += SIZE_WSTR( Shi502->shi502_netname );
  2339. }
  2340. return ( shareSize + FIXED_SIZE_OF_SHARE( Level ) );
  2341. } // SizeShares
  2342. BOOLEAN
  2343. ValidSharePath(
  2344. IN LPWSTR SharePath,
  2345. IN BOOL IsNtPath
  2346. )
  2347. /*++
  2348. Routine Description:
  2349. This routine checks to see if .. and . exists on the path. If they do,
  2350. then we reject this path name.
  2351. Arguments:
  2352. SharePath - The share path to be checked.
  2353. Return Value:
  2354. TRUE, if path is ok.
  2355. --*/
  2356. {
  2357. LPWCH source = SharePath;
  2358. if( IsNtPath )
  2359. {
  2360. // The NT Path is validated by the OPEN call
  2361. return TRUE;
  2362. }
  2363. //
  2364. // Walk through the pathname until we reach the zero terminator. At
  2365. // the start of this loop, source points to the first charaecter
  2366. // after a directory separator or the first character of the
  2367. // pathname.
  2368. //
  2369. //
  2370. // Allow the NT naming convention of slash slash . slash through here
  2371. //
  2372. if( IS_SLASH_SLASH_NAME( source ) ) {
  2373. //
  2374. // We have a path which starts with slash slash
  2375. // Set the buffer ptr so we start checking the pathname after
  2376. // the slash slash dot
  2377. source += 3;
  2378. }
  2379. while ( *source != L'\0' ) {
  2380. if ( *source == L'.') {
  2381. source++;
  2382. if ( ( IS_PATH_SEPARATOR(*source) ) ||
  2383. ( (*source++ == L'.') &&
  2384. IS_PATH_SEPARATOR(*source) ) ) {
  2385. //
  2386. // '.' and '..' appear as a directory names. Reject.
  2387. //
  2388. return(FALSE);
  2389. }
  2390. }
  2391. //
  2392. // source does not point to a dot, so continue until we see
  2393. // another directory separator
  2394. //
  2395. while ( *source != L'\0' ) {
  2396. if ( *source++ == L'\\' ) {
  2397. break;
  2398. }
  2399. }
  2400. }
  2401. return TRUE;
  2402. } // ValidSharePath