Leaked source code of windows server 2003
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.

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