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.

460 lines
13 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. adtsrv.c
  5. Abstract:
  6. AdminTools Server functions.
  7. This file contains the remote interface for NetpGetFileSecurity and
  8. NetpSetFileSecurity API.
  9. Author:
  10. Dan Lafferty (danl) 25-Mar-1993
  11. Environment:
  12. User Mode - Win32
  13. Revision History:
  14. 27-Oct-1994 IsaacHe
  15. Make sure the share permissions allow these operations.
  16. 05-Sep-1994 Danl
  17. Free memory and NULL the pointer to the SecurityDescriptor if
  18. a failure occurs. Also free the buffer returned from
  19. NetShareGetInfo.
  20. 25-Mar-1993 danl
  21. Created
  22. --*/
  23. //
  24. // Includes
  25. //
  26. #include "srvsvcp.h"
  27. #include <lmerr.h>
  28. #include <adtcomn.h>
  29. #include <tstr.h>
  30. DWORD AdtsvcDebugLevel = DEBUG_ERROR;
  31. //
  32. // LOCAL FUNCTIONS
  33. //
  34. NET_API_STATUS
  35. AdtCheckShareAccessAndGetFullPath(
  36. LPWSTR pShare,
  37. LPWSTR pFileName,
  38. LPWSTR *pPath,
  39. ACCESS_MASK DesiredAccess
  40. );
  41. NET_API_STATUS NET_API_FUNCTION
  42. NetrpGetFileSecurity (
  43. IN LPWSTR ServerName,
  44. IN LPWSTR ShareName,
  45. IN LPWSTR FileName,
  46. IN SECURITY_INFORMATION RequestedInfo,
  47. OUT PADT_SECURITY_DESCRIPTOR *pSecurityDescriptor
  48. )
  49. /*++
  50. Routine Description:
  51. This function returns to the caller a copy of the security descriptor
  52. protecting a file or directory. It calls GetFileSecurity. The
  53. Security Descriptor is always returned in the self-relative format.
  54. This function is called only when accessing remote files. In this case,
  55. the filename is broken into ServerName, ShareName, and FileName components.
  56. The ServerName gets the request to this routine. The ShareName must be
  57. expanded to find the local path associated with it. This is combined
  58. with the FileName to create a fully qualified pathname that is local
  59. to this machine.
  60. Arguments:
  61. ServerName - A pointer to a string containing the name of the remote
  62. server on which the function is to execute. A NULL pointer or
  63. string specifies the local machine.
  64. ShareName - A pointer to a string that identifies the share name
  65. on which the file is found.
  66. FileName - A pointer to the name fo the file or directory whose
  67. security is being retrieved.
  68. RequestedInfo - The type of security information being requested.
  69. pSecurityDescriptor - A pointer to a pointer to a structure which
  70. contains the buffer pointer for the security descriptor and
  71. a length field for the security descriptor.
  72. Return Value:
  73. NERR_Success - The operation was successful.
  74. ERROR_NOT_ENOUGH_MEMORY - Unable to allocate memory for the security
  75. descriptor.
  76. Other - This function can also return any error that
  77. GetFileSecurity,
  78. RpcImpersonateClient, or
  79. ShareEnumCommon
  80. can return.
  81. --*/
  82. {
  83. NET_API_STATUS status;
  84. PSECURITY_DESCRIPTOR pNewSecurityDescriptor;
  85. DWORD bufSize;
  86. LPWSTR FullPath=NULL;
  87. ACCESS_MASK DesiredAccess = 0;
  88. *pSecurityDescriptor = MIDL_user_allocate(sizeof(ADT_SECURITY_DESCRIPTOR));
  89. if (*pSecurityDescriptor == NULL) {
  90. ADT_LOG0( ERROR, "NetrpGetFileSecurity:MIDL_user_alloc failed\n" );
  91. return ERROR_NOT_ENOUGH_MEMORY;
  92. }
  93. //
  94. // Figure out accesses needed to perform the indicated operation(s).
  95. // This code is taken from ntos\se\semethod.c
  96. //
  97. if ((RequestedInfo & OWNER_SECURITY_INFORMATION) ||
  98. (RequestedInfo & GROUP_SECURITY_INFORMATION) ||
  99. (RequestedInfo & DACL_SECURITY_INFORMATION)) {
  100. DesiredAccess |= READ_CONTROL;
  101. }
  102. if ((RequestedInfo & SACL_SECURITY_INFORMATION)) {
  103. DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  104. }
  105. //
  106. // Check share perms and create a full path string by getting
  107. // the path for the share name, and adding the FileName string to it.
  108. //
  109. status = AdtCheckShareAccessAndGetFullPath(
  110. ShareName,
  111. FileName,
  112. &FullPath,
  113. DesiredAccess
  114. );
  115. if( status == NO_ERROR ) {
  116. if( (status = RpcImpersonateClient(NULL)) == NO_ERROR ) {
  117. //
  118. // Get the File Security information
  119. //
  120. status = PrivateGetFileSecurity(
  121. FullPath,
  122. RequestedInfo,
  123. &pNewSecurityDescriptor,
  124. &bufSize);
  125. if ( status == NO_ERROR ) {
  126. (*pSecurityDescriptor)->Length = bufSize;
  127. (*pSecurityDescriptor)->Buffer = pNewSecurityDescriptor;
  128. }
  129. (VOID)RpcRevertToSelf();
  130. }
  131. MIDL_user_free( FullPath );
  132. }
  133. if ( status != NO_ERROR ) {
  134. MIDL_user_free(*pSecurityDescriptor);
  135. *pSecurityDescriptor = NULL;
  136. }
  137. return status;
  138. }
  139. NET_API_STATUS NET_API_FUNCTION
  140. NetrpSetFileSecurity (
  141. IN LPWSTR ServerName OPTIONAL,
  142. IN LPWSTR ShareName,
  143. IN LPWSTR FileName,
  144. IN SECURITY_INFORMATION SecurityInfo,
  145. IN PADT_SECURITY_DESCRIPTOR pSecurityDescriptor
  146. )
  147. /*++
  148. Routine Description:
  149. This function can be used to set the security of a file or directory.
  150. It calls SetFileSecurity().
  151. Arguments:
  152. ServerName - A pointer to a string containing the name of the remote
  153. server on which the function is to execute. A NULL pointer or
  154. string specifies the local machine.
  155. ShareName - A pointer to a string that identifies the share name
  156. on which the file or directory is found.
  157. FileName - A pointer to the name of the file or directory whose
  158. security is being changed.
  159. SecurityInfo - Information describing the contents
  160. of the Security Descriptor.
  161. pSecurityDescriptor - A pointer to a structure that contains a
  162. self-relative security descriptor and a length.
  163. Return Value:
  164. NERR_Success - The operation was successful.
  165. Other - This function can also return any error that
  166. SetFileSecurity,
  167. RpcImpersonateClient, or
  168. ShareEnumCommon
  169. can return.
  170. --*/
  171. {
  172. NET_API_STATUS status;
  173. LPWSTR FullPath=NULL;
  174. ACCESS_MASK DesiredAccess = 0;
  175. UNREFERENCED_PARAMETER(ServerName);
  176. // Validate the parameters
  177. if( (pSecurityDescriptor->Buffer == NULL) &&
  178. (pSecurityDescriptor->Length > 0) )
  179. {
  180. return ERROR_INVALID_PARAMETER;
  181. }
  182. //
  183. // Figure out accesses needed to perform the indicated operation(s).
  184. // This code is taken from ntos\se\semethod.c
  185. //
  186. if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
  187. (SecurityInfo & GROUP_SECURITY_INFORMATION) ) {
  188. DesiredAccess |= WRITE_OWNER;
  189. }
  190. if (SecurityInfo & DACL_SECURITY_INFORMATION) {
  191. DesiredAccess |= WRITE_DAC;
  192. }
  193. if (SecurityInfo & SACL_SECURITY_INFORMATION) {
  194. DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  195. }
  196. //
  197. // Check perms and create a full path string by getting the path
  198. // for the share name, and adding the FileName string to it.
  199. //
  200. status = AdtCheckShareAccessAndGetFullPath(
  201. ShareName,
  202. FileName,
  203. &FullPath,
  204. DesiredAccess
  205. );
  206. if ( status == NO_ERROR ) {
  207. if( (status = RpcImpersonateClient(NULL)) == NO_ERROR ) {
  208. if (RtlValidRelativeSecurityDescriptor(
  209. pSecurityDescriptor->Buffer,
  210. pSecurityDescriptor->Length,
  211. SecurityInfo)) {
  212. //
  213. // Call SetFileSecurity
  214. //
  215. status = PrivateSetFileSecurity(
  216. FullPath,
  217. SecurityInfo,
  218. pSecurityDescriptor->Buffer);
  219. } else {
  220. status = ERROR_INVALID_SECURITY_DESCR;
  221. }
  222. (VOID)RpcRevertToSelf();
  223. }
  224. MIDL_user_free(FullPath);
  225. }
  226. return(status);
  227. }
  228. NET_API_STATUS
  229. AdtCheckShareAccessAndGetFullPath(
  230. LPWSTR pShare,
  231. LPWSTR pFileName,
  232. LPWSTR *pPath,
  233. ACCESS_MASK DesiredAccess
  234. )
  235. /*++
  236. Routine Description:
  237. This function ensures the DesiredAccess is allowed and finds the
  238. path associated with the share name, combines this with the
  239. file name, and creates a fully qualified path name.
  240. NOTE: This function allocates storage for the pPath string.
  241. Arguments:
  242. pShare - This is a pointer to the share name string.
  243. pFileName - This is a pointer to the file name (or path) string.
  244. pPath - This is a pointer to a location where the pointer to the
  245. complete file path string can be stored. This pointer needs to
  246. be free'd with MIDL_user_free when the caller is finished with it.
  247. DesiredAccess - what we'd like to do through the share
  248. Return Value:
  249. NO_ERROR - if The operation was completely successful.
  250. Other - Errors returned from ShareEnumCommon, and MIDL_user_allocate may be
  251. returned from this routine.
  252. Comments:
  253. The share access checking is complicated by the fact that the share ACL has
  254. had the owner and group SIDs stripped out. We need to put them back
  255. in, or the SsCheckAccess() call will fail.
  256. --*/
  257. {
  258. NET_API_STATUS status;
  259. PSHARE_INFO_502 pshi502 = NULL;
  260. DWORD bufSize;
  261. DWORD fileNameSize;
  262. LPWSTR pLastChar;
  263. DWORD entriesRead;
  264. DWORD totalEntries;
  265. PSECURITY_DESCRIPTOR NewDescriptor = NULL;
  266. SECURITY_DESCRIPTOR ModificationDescriptor;
  267. GENERIC_MAPPING Mapping;
  268. SRVSVC_SECURITY_OBJECT SecurityObject;
  269. HANDLE token;
  270. status = ShareEnumCommon(
  271. 502,
  272. (LPBYTE *)&pshi502,
  273. (DWORD)-1,
  274. &entriesRead,
  275. &totalEntries,
  276. NULL,
  277. pShare
  278. );
  279. if( status != NO_ERROR ) {
  280. goto getout;
  281. } else if( entriesRead == 0 || pshi502 == NULL ) {
  282. status = NERR_NetNameNotFound;
  283. } else if( pshi502->shi502_path == NULL ) {
  284. status = ERROR_BAD_DEV_TYPE;
  285. } else if( pshi502->shi502_security_descriptor != NULL ) {
  286. status = RtlCopySecurityDescriptor( pshi502->shi502_security_descriptor, &NewDescriptor );
  287. if( status != STATUS_SUCCESS )
  288. goto getout;
  289. RtlCreateSecurityDescriptor( &ModificationDescriptor, SECURITY_DESCRIPTOR_REVISION );
  290. RtlSetOwnerSecurityDescriptor( &ModificationDescriptor, SsData.SsLmsvcsGlobalData->LocalSystemSid, FALSE );
  291. RtlSetGroupSecurityDescriptor( &ModificationDescriptor, SsData.SsLmsvcsGlobalData->LocalSystemSid, FALSE );
  292. Mapping.GenericRead = FILE_GENERIC_READ;
  293. Mapping.GenericWrite = FILE_GENERIC_WRITE;
  294. Mapping.GenericExecute = FILE_GENERIC_EXECUTE;
  295. Mapping.GenericAll = FILE_ALL_ACCESS;
  296. if( ImpersonateSelf( SecurityImpersonation ) == FALSE ) {
  297. status = GetLastError();
  298. goto getout;
  299. }
  300. status = NtOpenThreadToken( NtCurrentThread(), TOKEN_QUERY, TRUE, &token );
  301. RevertToSelf();
  302. if( status != STATUS_SUCCESS )
  303. goto getout;
  304. status = RtlSetSecurityObject (
  305. GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
  306. &ModificationDescriptor,
  307. &NewDescriptor,
  308. &Mapping,
  309. token
  310. );
  311. NtClose( token );
  312. if( status == STATUS_SUCCESS ) {
  313. SecurityObject.ObjectName = pShare;
  314. SecurityObject.Mapping = &Mapping;
  315. SecurityObject.SecurityDescriptor = NewDescriptor;
  316. //
  317. // SsCheckAccess does an RpcImpersonateClient()...
  318. //
  319. status = SsCheckAccess( &SecurityObject, DesiredAccess );
  320. }
  321. }
  322. if( status == STATUS_SUCCESS ) {
  323. //
  324. // If the last character is a '\', then we must remove it.
  325. //
  326. pLastChar = pshi502->shi502_path + wcslen(pshi502->shi502_path);
  327. pLastChar--;
  328. if (*pLastChar == L'\\') {
  329. *pLastChar = L'\0';
  330. }
  331. bufSize = STRSIZE(pshi502->shi502_path);
  332. fileNameSize = STRSIZE(pFileName);
  333. *pPath = MIDL_user_allocate( bufSize + fileNameSize );
  334. if (*pPath != NULL) {
  335. wcscpy (*pPath, pshi502->shi502_path);
  336. wcscat (*pPath, pFileName);
  337. } else {
  338. status = ERROR_NOT_ENOUGH_MEMORY;
  339. }
  340. }
  341. getout:
  342. if( NewDescriptor != NULL )
  343. RtlDeleteSecurityObject( &NewDescriptor );
  344. if( pshi502 != NULL )
  345. MIDL_user_free( pshi502 );
  346. return status;
  347. }