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.

599 lines
17 KiB

  1. /*++
  2. Copyright (c) 1990-1993 Microsoft Corporation
  3. Module Name:
  4. splrpc.c
  5. Abstract:
  6. This file contains routines for starting and stopping RPC servers.
  7. SpoolerStartRpcServer
  8. SpoolerStopRpcServer
  9. Author:
  10. Krishna Ganugapati krishnaG
  11. Environment:
  12. User Mode - Win32
  13. Revision History:
  14. 14-Oct-1993 KrishnaG
  15. Created
  16. 25-May-1999 khaleds
  17. Added:
  18. CreateNamedPipeSecurityDescriptor
  19. BuildNamedPipeProtection
  20. --*/
  21. //
  22. // INCLUDES
  23. //
  24. #define NOMINMAX
  25. #include <nt.h>
  26. #include <ntrtl.h>
  27. #include <nturtl.h>
  28. #include <windows.h>
  29. #include <winspool.h>
  30. #include <winsplp.h>
  31. #include <rpc.h>
  32. #include "splsvr.h"
  33. #include "splr.h"
  34. #include "server.h"
  35. #ifndef _SRVRMEM_H_
  36. #include "srvrmem.h"
  37. #endif
  38. WCHAR szSerializeRpc []= L"SerializeRpc";
  39. WCHAR szCallExitProcessOnShutdown []= L"CallExitProcessOnShutdown";
  40. WCHAR szMaxRpcSize []= L"MaxRpcSize";
  41. WCHAR szPrintKey[] = L"System\\CurrentControlSet\\Control\\Print";
  42. #define DEFAULT_MAX_RPC_SIZE 1024*1024 // default maximum rpc data block size in bytes
  43. DWORD dwCallExitProcessOnShutdown = TRUE;
  44. RPC_STATUS
  45. SpoolerStartRpcServer(
  46. VOID)
  47. /*++
  48. Routine Description:
  49. Arguments:
  50. Return Value:
  51. NERR_Success, or any RPC error codes that can be returned from
  52. RpcServerUnregisterIf.
  53. --*/
  54. {
  55. unsigned char * InterfaceAddress;
  56. RPC_STATUS status;
  57. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  58. BOOL Bool;
  59. HKEY hKey;
  60. DWORD cbData;
  61. DWORD dwSerializeRpc = 0;
  62. DWORD dwType;
  63. DWORD dwMaxRpcSize;
  64. InterfaceAddress = "\\pipe\\spoolss";
  65. // Croft up a security descriptor that will grant everyone
  66. // all access to the object (basically, no security)
  67. //
  68. // We do this by putting in a NULL Dacl.
  69. //
  70. // NOTE: rpc should copy the security descriptor,
  71. // Since it currently doesn't, simply allocate it for now and
  72. // leave it around forever.
  73. //
  74. SecurityDescriptor = CreateNamedPipeSecurityDescriptor();
  75. if (SecurityDescriptor == 0) {
  76. DBGMSG(DBG_ERROR, ("Spoolss: out of memory\n"));
  77. return FALSE;
  78. }
  79. //
  80. // For now, ignore the second argument.
  81. //
  82. status = RpcServerUseProtseqEpA("ncacn_np", 10, InterfaceAddress, SecurityDescriptor);
  83. if (status) {
  84. DBGMSG(DBG_WARN, ("RpcServerUseProtseqEpA 1 = %u\n",status));
  85. return FALSE;
  86. }
  87. //
  88. // For now, ignore the second argument.
  89. //
  90. status = RpcServerUseProtseqEpA("ncalrpc", 10, "spoolss", SecurityDescriptor);
  91. if (status) {
  92. DBGMSG(DBG_WARN, ("RpcServerUseProtseqEpA 2 = %u\n",status));
  93. return FALSE;
  94. }
  95. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  96. szPrintKey,
  97. 0,
  98. KEY_READ,
  99. &hKey)) {
  100. //
  101. // Ignore failure case since we can use the default
  102. //
  103. cbData = sizeof(dwSerializeRpc);
  104. RegQueryValueEx(hKey,
  105. szSerializeRpc,
  106. NULL,
  107. &dwType,
  108. (LPBYTE)&dwSerializeRpc,
  109. &cbData);
  110. //
  111. // This value can be used to control if spooler controls ExitProcess
  112. // on shutdown
  113. //
  114. cbData = sizeof(dwCallExitProcessOnShutdown);
  115. RegQueryValueEx(hKey,
  116. szCallExitProcessOnShutdown,
  117. NULL,
  118. &dwType,
  119. (LPBYTE)&dwCallExitProcessOnShutdown,
  120. &cbData);
  121. //
  122. // dwMaxRpcSize specifies the maximum size in bytes of incoming RPC data blocks.
  123. //
  124. cbData = sizeof(dwMaxRpcSize);
  125. if (RegQueryValueEx(hKey,
  126. szMaxRpcSize,
  127. NULL,
  128. &dwType,
  129. (LPBYTE)&dwMaxRpcSize,
  130. &cbData) != ERROR_SUCCESS) {
  131. dwMaxRpcSize = DEFAULT_MAX_RPC_SIZE;
  132. }
  133. RegCloseKey(hKey);
  134. }
  135. //
  136. // Now we need to add the interface. We can just use the winspool_ServerIfHandle
  137. // specified by the MIDL compiler in the stubs (winspl_s.c).
  138. //
  139. status = RpcServerRegisterIf2( winspool_ServerIfHandle,
  140. 0,
  141. 0,
  142. 0,
  143. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  144. dwMaxRpcSize,
  145. NULL
  146. );
  147. if (status) {
  148. DBGMSG(DBG_WARN, ("RpcServerRegisterIf = %u\n",status));
  149. return FALSE;
  150. }
  151. if (dwSerializeRpc) {
  152. // By default, rpc will serialize access to context handles. Since
  153. // the spooler needs to be able to have two threads access a context
  154. // handle at once, and it knows what it is doing, we will tell rpc
  155. // not to serialize access to context handles.
  156. I_RpcSsDontSerializeContext();
  157. }
  158. status = RpcMgmtSetServerStackSize(INITIAL_STACK_COMMIT);
  159. if (status != RPC_S_OK) {
  160. DBGMSG(DBG_ERROR, ("Spoolss : RpcMgmtSetServerStackSize = %d\n", status));
  161. }
  162. // The first argument specifies the minimum number of threads to
  163. // create to handle calls; the second argument specifies the maximum
  164. // concurrent calls to handle. The third argument indicates that
  165. // the routine should not wait.
  166. status = RpcServerListen(1,SPL_MAX_RPC_CALLS,1);
  167. if ( status != RPC_S_OK ) {
  168. DBGMSG(DBG_ERROR, ("Spoolss : RpcServerListen = %d\n", status));
  169. }
  170. return (status);
  171. }
  172. #define MAX_ACE 7
  173. #define DBGCHK( Condition, ErrorInfo ) \
  174. if( Condition ) DBGMSG( DBG_WARNING, ErrorInfo )
  175. /*++
  176. Routine Description:
  177. This routine adds prepares the required masks and flags required for the
  178. DACL on the named pipes used by RPC
  179. Arguments:
  180. None
  181. Return Value:
  182. An allocated Security Descriptor
  183. --*/
  184. PSECURITY_DESCRIPTOR
  185. CreateNamedPipeSecurityDescriptor(
  186. VOID
  187. )
  188. {
  189. UCHAR AceType[MAX_ACE];
  190. PSID AceSid[MAX_ACE];
  191. BYTE InheritFlags[MAX_ACE];
  192. DWORD AceCount;
  193. PSECURITY_DESCRIPTOR ServerSD = NULL;
  194. //
  195. // For Code optimization we replace 5 individaul
  196. // SID_IDENTIFIER_AUTHORITY with an array of
  197. // SID_IDENTIFIER_AUTHORITYs
  198. // where
  199. // SidAuthority[0] = UserSidAuthority
  200. // SidAuthority[1] = PowerSidAuthority
  201. // SidAuthority[2] = EveryOneSidAuthority
  202. // SidAuthority[3] = CreatorSidAuthority
  203. // SidAuthority[4] = SystemSidAuthority
  204. // SidAuthority[5] = AdminSidAuthority
  205. //
  206. SID_IDENTIFIER_AUTHORITY SidAuthority[MAX_ACE] = {
  207. SECURITY_NT_AUTHORITY,
  208. SECURITY_NT_AUTHORITY,
  209. SECURITY_WORLD_SID_AUTHORITY,
  210. SECURITY_NT_AUTHORITY,
  211. SECURITY_CREATOR_SID_AUTHORITY,
  212. SECURITY_NT_AUTHORITY,
  213. SECURITY_NT_AUTHORITY
  214. };
  215. //
  216. // For code optimization we replace 6 individual Sids with
  217. // an array of Sids; On Whistler, Anonymous user will no longer
  218. // be granted access to resources whose ACLs grant access to Everyone.
  219. //
  220. // We need to give access to Anonymous user to access the RPC pipe
  221. // for the reverse RPC connection when RPC calls could come as
  222. // Anonymous from either NT4 machines, Whistler Personal or Whitler
  223. // across domains.
  224. //
  225. // Sid[0] = UserSid
  226. // Sid[1] = PowerSid
  227. // Sid[2] = EveryOne
  228. // Sid[3] = Anonymous
  229. // Sid[4] = CreatorSid
  230. // Sid[5] = SystemSid
  231. // Sid[6] = AdminSid
  232. //
  233. PSID Sids[MAX_ACE] = {NULL,NULL,NULL,NULL,NULL};
  234. ACCESS_MASK AceMask[MAX_ACE] = {
  235. FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE ,
  236. FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE ,
  237. (FILE_GENERIC_READ | FILE_WRITE_DATA | FILE_ALL_ACCESS) &
  238. ~WRITE_DAC &~WRITE_OWNER & ~DELETE & ~FILE_CREATE_PIPE_INSTANCE,
  239. (FILE_GENERIC_READ | FILE_WRITE_DATA | FILE_ALL_ACCESS) &
  240. ~WRITE_DAC &~WRITE_OWNER & ~DELETE & ~FILE_CREATE_PIPE_INSTANCE,
  241. STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS,
  242. STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS,
  243. STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS
  244. };
  245. DWORD SubAuthorities[3*MAX_ACE] = {
  246. 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_USERS ,
  247. 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_POWER_USERS ,
  248. 1 , SECURITY_WORLD_RID , 0 ,
  249. 1 , SECURITY_ANONYMOUS_LOGON_RID , 0 ,
  250. 1 , SECURITY_CREATOR_OWNER_RID , 0 ,
  251. 1 , SECURITY_LOCAL_SYSTEM_RID , 0 ,
  252. 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_ADMINS
  253. };
  254. //
  255. // Name Pipe SD
  256. //
  257. for(AceCount = 0;
  258. ( (AceCount < MAX_ACE) &&
  259. AllocateAndInitializeSid(&SidAuthority[AceCount],
  260. (BYTE)SubAuthorities[AceCount*3],
  261. SubAuthorities[AceCount*3+1],
  262. SubAuthorities[AceCount*3+2],
  263. 0, 0, 0, 0, 0, 0,
  264. &Sids[AceCount]));
  265. AceCount++)
  266. {
  267. AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE;
  268. AceSid[AceCount] = Sids[AceCount];
  269. InheritFlags[AceCount] = 0;
  270. }
  271. if(AceCount == MAX_ACE)
  272. {
  273. if(!BuildNamedPipeProtection( AceType,
  274. AceCount,
  275. AceSid,
  276. AceMask,
  277. InheritFlags,
  278. NULL,
  279. NULL,
  280. NULL,
  281. &ServerSD ) )
  282. {
  283. DBGMSG( DBG_WARNING,( "Couldn't buidl Named Pipe protection" ) );
  284. }
  285. }
  286. else
  287. {
  288. DBGMSG( DBG_WARNING,( "Couldn't Allocate and initialize SIDs" ) );
  289. }
  290. for(AceCount=0;AceCount<MAX_ACE;AceCount++)
  291. {
  292. if(Sids[AceCount])
  293. FreeSid( Sids[AceCount] );
  294. }
  295. return ServerSD;
  296. }
  297. BOOL
  298. BuildNamedPipeProtection(
  299. IN PUCHAR AceType,
  300. IN DWORD AceCount,
  301. IN PSID *AceSid,
  302. IN ACCESS_MASK *AceMask,
  303. IN BYTE *InheritFlags,
  304. IN PSID OwnerSid,
  305. IN PSID GroupSid,
  306. IN PGENERIC_MAPPING GenericMap,
  307. OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor
  308. )
  309. /*++
  310. Routine Description:
  311. This routine builds a self-relative security descriptor ready
  312. to be applied to one of the print manager objects.
  313. If so indicated, a pointer to the last RID of the SID in the last
  314. ACE of the DACL is returned and a flag set indicating that the RID
  315. must be replaced before the security descriptor is applied to an object.
  316. This is to support USER object protection, which must grant some
  317. access to the user represented by the object.
  318. The SACL of each of these objects will be set to:
  319. Audit
  320. Success | Fail
  321. WORLD
  322. (Write | Delete | WriteDacl | AccessSystemSecurity)
  323. Arguments:
  324. AceType - Array of AceTypes.
  325. Must be ACCESS_ALLOWED_ACE_TYPE or ACCESS_DENIED_ACE_TYPE.
  326. AceCount - The number of ACEs to be included in the DACL.
  327. AceSid - Points to an array of SIDs to be granted access by the DACL.
  328. If the target SAM object is a User object, then the last entry
  329. in this array is expected to be the SID of an account within the
  330. domain with the last RID not yet set. The RID will be set during
  331. actual account creation.
  332. AceMask - Points to an array of accesses to be granted by the DACL.
  333. The n'th entry of this array corresponds to the n'th entry of
  334. the AceSid array. These masks should not include any generic
  335. access types.
  336. InheritFlags - Pointer to an array of inherit flags.
  337. The n'th entry of this array corresponds to the n'th entry of
  338. the AceSid array.
  339. OwnerSid - The SID of the owner to be assigned to the descriptor.
  340. GroupSid - The SID of the group to be assigned to the descriptor.
  341. GenericMap - Points to a generic mapping for the target object type.
  342. ppSecurityDescriptor - Receives a pointer to the security descriptor.
  343. This will be allcated from the process' heap, not the spooler's,
  344. and should therefore be freed with LocalFree().
  345. IN DWORD AceCount,
  346. IN PSID *AceSid,
  347. IN ACCESS_MASK *AceMask,
  348. IN BYTE *InheritFlags,
  349. IN PSID OwnerSid,
  350. IN PSID GroupSid,
  351. IN PGENERIC_MAPPING GenericMap,
  352. OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor
  353. Return Value:
  354. TBS.
  355. --*/
  356. {
  357. SECURITY_DESCRIPTOR Absolute;
  358. PSECURITY_DESCRIPTOR Relative = NULL;
  359. PACL TmpAcl= NULL;
  360. PACCESS_ALLOWED_ACE TmpAce;
  361. DWORD SDLength;
  362. DWORD DaclLength;
  363. DWORD i;
  364. BOOL OK;
  365. //
  366. // The approach is to set up an absolute security descriptor that
  367. // looks like what we want and then copy it to make a self-relative
  368. // security descriptor.
  369. //
  370. OK = InitializeSecurityDescriptor( &Absolute,
  371. SECURITY_DESCRIPTOR_REVISION1 );
  372. DBGCHK( !OK, ( "Failed to initialize security descriptor. Error %d", GetLastError() ) );
  373. //
  374. // Owner
  375. //
  376. OK = SetSecurityDescriptorOwner( &Absolute, OwnerSid, FALSE );
  377. DBGCHK( !OK, ( "Failed to set security descriptor owner. Error %d", GetLastError() ) );
  378. //
  379. // Group
  380. //
  381. OK = SetSecurityDescriptorGroup( &Absolute, GroupSid, FALSE );
  382. DBGCHK( !OK, ( "Failed to set security descriptor group. Error %d", GetLastError() ) );
  383. //
  384. // Discretionary ACL
  385. //
  386. // Calculate its length,
  387. // Allocate it,
  388. // Initialize it,
  389. // Add each ACE
  390. // Set ACE as InheritOnly if necessary
  391. // Add it to the security descriptor
  392. //
  393. DaclLength = (DWORD)sizeof(ACL);
  394. for (i=0; i<AceCount; i++) {
  395. DaclLength += GetLengthSid( AceSid[i] ) +
  396. (DWORD)sizeof(ACCESS_ALLOWED_ACE) -
  397. (DWORD)sizeof(DWORD); //Subtract out SidStart field length
  398. }
  399. TmpAcl = SrvrAllocSplMem( DaclLength );
  400. if (!TmpAcl) {
  401. DBGCHK( !TmpAcl, ( "Out of heap space: Can't allocate ACL." ) );
  402. *ppSecurityDescriptor = NULL;
  403. return(FALSE);
  404. }
  405. OK = InitializeAcl( TmpAcl, DaclLength, ACL_REVISION2 );
  406. DBGCHK( !OK, ( "Failed to set initialize ACL. Error %d", GetLastError() ) );
  407. for (i=0; i<AceCount; i++)
  408. {
  409. if( AceType[i] == ACCESS_ALLOWED_ACE_TYPE )
  410. OK = AddAccessAllowedAce ( TmpAcl, ACL_REVISION2, AceMask[i], AceSid[i] );
  411. else
  412. OK = AddAccessDeniedAce ( TmpAcl, ACL_REVISION2, AceMask[i], AceSid[i] );
  413. DBGCHK( !OK, ( "Failed to add access-allowed ACE. Error %d", GetLastError() ) );
  414. if (InheritFlags[i] != 0)
  415. {
  416. OK = GetAce( TmpAcl, i, (LPVOID *)&TmpAce );
  417. DBGCHK( !OK, ( "Failed to get ACE. Error %d", GetLastError() ) );
  418. TmpAce->Header.AceFlags = InheritFlags[i];
  419. }
  420. }
  421. OK = SetSecurityDescriptorDacl (&Absolute, TRUE, TmpAcl, FALSE );
  422. DBGCHK( !OK, ( "Failed to set security descriptor DACL. Error %d", GetLastError() ) );
  423. //
  424. // Convert the Security Descriptor to Self-Relative
  425. //
  426. // Get the length needed
  427. // Allocate that much memory
  428. // Copy it
  429. // Free the generated absolute ACLs
  430. //
  431. SDLength = GetSecurityDescriptorLength( &Absolute );
  432. Relative = LocalAlloc( 0, SDLength );
  433. if (!Relative) {
  434. DBGCHK( !Relative, ( "Out of heap space: Can't allocate security descriptor" ) );
  435. goto Fail;
  436. }
  437. OK = MakeSelfRelativeSD(&Absolute, Relative, &SDLength );
  438. if (!OK) {
  439. DBGCHK( !OK, ( "Failed to create self-relative security descriptor DACL. Error %d", GetLastError() ) );
  440. goto Fail;
  441. }
  442. SrvrFreeSplMem( TmpAcl );
  443. *ppSecurityDescriptor = Relative;
  444. return( OK );
  445. Fail:
  446. if (TmpAcl){
  447. FreeSplMem(TmpAcl);
  448. }
  449. if (Relative) {
  450. LocalFree(Relative);
  451. }
  452. *ppSecurityDescriptor = NULL;
  453. return(FALSE);
  454. }