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.

533 lines
13 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. #include "precomp.h"
  22. #include "server.h"
  23. #include "srvrmem.h"
  24. #include "splsvr.h"
  25. WCHAR szCallExitProcessOnShutdown []= L"CallExitProcessOnShutdown";
  26. WCHAR szMaxRpcSize []= L"MaxRpcSize";
  27. WCHAR szPrintKey[] = L"System\\CurrentControlSet\\Control\\Print";
  28. CRITICAL_SECTION RpcNamedPipeCriticalSection;
  29. //
  30. // Default RPC buffer max size 50 MB
  31. //
  32. #define DEFAULT_MAX_RPC_SIZE 50 * 1024 * 1024
  33. DWORD dwCallExitProcessOnShutdown = TRUE;
  34. struct
  35. {
  36. BOOL bRpcEndPointEnabled;
  37. ERemoteRPCEndPointPolicy ePolicyValue;
  38. RPC_STATUS RpcStatus;
  39. } gNamedPipeState = {FALSE, RpcEndPointPolicyUnconfigured, RPC_S_OK};
  40. PSECURITY_DESCRIPTOR gpSecurityDescriptor = NULL;
  41. /*++
  42. Routine Description:
  43. Determines the OS suite of the current system.
  44. Arguments:
  45. pSuiteMask - pointer to word that is going to hold
  46. the OS suite.
  47. Return Value:
  48. S_OK if succeeded
  49. --*/
  50. HRESULT
  51. GetOSSuite(
  52. WORD* pSuiteMask
  53. )
  54. {
  55. HRESULT hr = S_OK;
  56. if (!pSuiteMask)
  57. {
  58. hr = HResultFromWin32(ERROR_INVALID_PARAMETER);
  59. }
  60. if (SUCCEEDED(hr))
  61. {
  62. OSVERSIONINFOEX OSVersionInfoEx = {0};
  63. OSVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  64. *pSuiteMask = 0;
  65. if (GetVersionEx((OSVERSIONINFO*)&OSVersionInfoEx))
  66. {
  67. *pSuiteMask |= OSVersionInfoEx.wSuiteMask;
  68. }
  69. else
  70. {
  71. hr = HResultFromWin32(GetLastError());
  72. }
  73. }
  74. return hr;
  75. }
  76. RPC_STATUS
  77. SpoolerStartRpcServer(
  78. VOID)
  79. /*++
  80. Routine Description:
  81. Arguments:
  82. Return Value:
  83. NERR_Success, or any RPC error codes that can be returned from
  84. RpcServerUnregisterIf.
  85. --*/
  86. {
  87. RPC_STATUS status;
  88. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  89. BOOL Bool;
  90. HKEY hKey;
  91. DWORD cbData;
  92. DWORD dwType;
  93. DWORD dwMaxRpcSize = DEFAULT_MAX_RPC_SIZE;
  94. WORD OSSuite;
  95. //
  96. // Craft up a security descriptor that will grant everyone
  97. // all access to the object (basically, no security)
  98. //
  99. // We do this by putting in a NULL Dacl.
  100. //
  101. // NOTE: rpc should copy the security descriptor,
  102. // Since it currently doesn't, simply allocate it for now and
  103. // leave it around forever.
  104. //
  105. gpSecurityDescriptor = CreateNamedPipeSecurityDescriptor();
  106. if (gpSecurityDescriptor == 0) {
  107. DBGMSG(DBG_ERROR, ("Spoolss: out of memory\n"));
  108. return FALSE;
  109. }
  110. if (FAILED(GetOSSuite(&OSSuite)))
  111. {
  112. DBGMSG(DBG_ERROR, ("Failed to get the OS suite.\n"));
  113. return FALSE;
  114. }
  115. if (OSSuite & (VER_SUITE_BLADE | VER_SUITE_EMBEDDED_RESTRICTED))
  116. {
  117. gNamedPipeState.ePolicyValue = RpcEndPointPolicyDisabled;
  118. }
  119. else
  120. {
  121. gNamedPipeState.ePolicyValue = GetSpoolerNumericPolicyValidate(szRegisterSpoolerRemoteRpcEndPoint,
  122. RpcEndPointPolicyUnconfigured,
  123. RpcEndPointPolicyDisabled);
  124. }
  125. if (gNamedPipeState.ePolicyValue == RpcEndPointPolicyEnabled)
  126. {
  127. if (FAILED(RegisterNamedPipe()))
  128. {
  129. return FALSE;
  130. }
  131. }
  132. else if (gNamedPipeState.ePolicyValue == RpcEndPointPolicyUnconfigured)
  133. {
  134. if (!InitializeCriticalSectionAndSpinCount(&RpcNamedPipeCriticalSection, 0x80000000))
  135. {
  136. return FALSE;
  137. }
  138. }
  139. //
  140. // For now, ignore the second argument.
  141. //
  142. status = RpcServerUseProtseqEpA("ncalrpc", 10, "spoolss", gpSecurityDescriptor);
  143. if (status) {
  144. DBGMSG(DBG_WARN, ("RpcServerUseProtseqEpA 2 = %u\n",status));
  145. return FALSE;
  146. }
  147. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  148. szPrintKey,
  149. 0,
  150. KEY_READ,
  151. &hKey)) {
  152. //
  153. // This value can be used to control if spooler controls ExitProcess
  154. // on shutdown
  155. //
  156. cbData = sizeof(dwCallExitProcessOnShutdown);
  157. RegQueryValueEx(hKey,
  158. szCallExitProcessOnShutdown,
  159. NULL,
  160. &dwType,
  161. (LPBYTE)&dwCallExitProcessOnShutdown,
  162. &cbData);
  163. //
  164. // dwMaxRpcSize specifies the maximum size in bytes of incoming RPC data blocks.
  165. //
  166. cbData = sizeof(dwMaxRpcSize);
  167. if (RegQueryValueEx(hKey,
  168. szMaxRpcSize,
  169. NULL,
  170. &dwType,
  171. (LPBYTE)&dwMaxRpcSize,
  172. &cbData) != ERROR_SUCCESS) {
  173. dwMaxRpcSize = DEFAULT_MAX_RPC_SIZE;
  174. }
  175. RegCloseKey(hKey);
  176. }
  177. //
  178. // Now we need to add the interface. We can just use the winspool_ServerIfHandle
  179. // specified by the MIDL compiler in the stubs (winspl_s.c).
  180. //
  181. status = RpcServerRegisterIf2( winspool_ServerIfHandle,
  182. 0,
  183. 0,
  184. 0,
  185. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  186. dwMaxRpcSize,
  187. NULL
  188. );
  189. if (status) {
  190. DBGMSG(DBG_WARN, ("RpcServerRegisterIf = %u\n",status));
  191. return FALSE;
  192. }
  193. status = RpcMgmtSetServerStackSize(INITIAL_STACK_COMMIT);
  194. if (status != RPC_S_OK) {
  195. DBGMSG(DBG_ERROR, ("Spoolss : RpcMgmtSetServerStackSize = %d\n", status));
  196. }
  197. if( (status = RpcServerRegisterAuthInfo(0,
  198. RPC_C_AUTHN_WINNT,
  199. 0,
  200. 0 )) == RPC_S_OK )
  201. {
  202. // The first argument specifies the minimum number of threads to
  203. // create to handle calls; the second argument specifies the maximum
  204. // concurrent calls to handle. The third argument indicates that
  205. // the routine should not wait.
  206. status = RpcServerListen(1,SPL_MAX_RPC_CALLS,1);
  207. if ( status != RPC_S_OK ) {
  208. DBGMSG(DBG_ERROR, ("Spoolss : RpcServerListen = %d\n", status));
  209. }
  210. }
  211. return (status);
  212. }
  213. /*++
  214. Routine Description:
  215. This routine adds prepares the required masks and flags required for the
  216. DACL on the named pipes used by RPC
  217. Arguments:
  218. None
  219. Return Value:
  220. An allocated Security Descriptor
  221. --*/
  222. /*++
  223. Name:
  224. CreateNamedPipeSecurityDescriptor
  225. Description:
  226. Creates the security descriptor for the named pipe used by RPC
  227. Arguments:
  228. None.
  229. Return Value:
  230. valid pointer to SECURITY_DESCRIPTOR structure if successful
  231. NULL, on error, use GetLastError
  232. --*/
  233. PSECURITY_DESCRIPTOR
  234. CreateNamedPipeSecurityDescriptor(
  235. VOID
  236. )
  237. {
  238. PSECURITY_DESCRIPTOR pServerSD = NULL;
  239. PCWSTR pszStringSecDesc = L"D:(A;;0x100003;;;BU)"
  240. L"(A;;0x100003;;;PU)"
  241. L"(A;;0x1201fb;;;WD)"
  242. L"(A;;0x1201fb;;;AN)"
  243. L"(A;;FA;;;CO)"
  244. L"(A;;FA;;;SY)"
  245. L"(A;;FA;;;BA)";
  246. //
  247. // Builtin Users - FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE
  248. // Power Users - FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE
  249. // Everyone - FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_EA
  250. // Anonymous - FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_EA
  251. // Creator Owner - file all access
  252. // System - file all access
  253. // Administrators - file all access
  254. //
  255. // Anonymous has more permission than BU and PU. The extra permission is needed by the back channel (pipe) used by the
  256. // print server to communicate to the client
  257. //
  258. if (!ConvertStringSecurityDescriptorToSecurityDescriptor(pszStringSecDesc,
  259. SDDL_REVISION_1,
  260. &pServerSD,
  261. NULL))
  262. {
  263. pServerSD = NULL;
  264. }
  265. return pServerSD;
  266. }
  267. /*++
  268. Routine Name
  269. ServerAllowRemoteCalls
  270. Routine Description:
  271. Enables the RPC pipe if policy permits.
  272. If the policy is disabled, then it will fail the call.
  273. If the policy is enbled, then it will succeeded the call without doing anything.
  274. If the policy is unconfigured, it will attempt to enable the pipe
  275. if disabled. It keep a retry count and fails directly after 5 times (hardcoded).
  276. Arguments:
  277. None
  278. Return Value:
  279. HRESULT
  280. --*/
  281. HRESULT
  282. ServerAllowRemoteCalls(
  283. VOID
  284. )
  285. {
  286. HRESULT hr = S_OK;
  287. if (gNamedPipeState.ePolicyValue == RpcEndPointPolicyUnconfigured)
  288. {
  289. EnterCriticalSection(&RpcNamedPipeCriticalSection);
  290. //
  291. // Allow retries. Keep RpcStatus for debugging purposes.
  292. //
  293. if (!gNamedPipeState.bRpcEndPointEnabled)
  294. {
  295. hr = RegisterNamedPipe();
  296. gNamedPipeState.bRpcEndPointEnabled = SUCCEEDED(hr);
  297. gNamedPipeState.RpcStatus = StatusFromHResult(hr);
  298. }
  299. LeaveCriticalSection(&RpcNamedPipeCriticalSection);
  300. }
  301. else if (gNamedPipeState.ePolicyValue == RpcEndPointPolicyDisabled)
  302. {
  303. hr = HResultFromWin32(ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED);
  304. DBGMSG(DBG_WARN, ("Remote connections are not allowed.\n"));
  305. }
  306. return hr;
  307. }
  308. /*++
  309. Routine Name
  310. RegisterNamedPipe
  311. Routine Description:
  312. Registers the named pipe protocol.
  313. Arguments:
  314. None
  315. Return Value:
  316. An HRESULT
  317. --*/
  318. HRESULT
  319. RegisterNamedPipe(
  320. VOID
  321. )
  322. {
  323. RPC_STATUS RpcStatus;
  324. HRESULT hr = S_OK;
  325. HANDLE hToken;
  326. if (hToken = RevertToPrinterSelf())
  327. {
  328. RpcStatus = RpcServerUseProtseqEpA("ncacn_np", 10, "\\pipe\\spoolss", gpSecurityDescriptor);
  329. hr = (RpcStatus == RPC_S_OK) ?
  330. S_OK :
  331. MAKE_HRESULT(SEVERITY_ERROR, FACILITY_RPC, RpcStatus);
  332. if (FAILED(hr))
  333. {
  334. DBGMSG(DBG_WARN, ("RpcServerUseProtseqEpA (ncalrpc) = %u\n",RpcStatus));
  335. }
  336. if (!ImpersonatePrinterClient(hToken) && SUCCEEDED(hr))
  337. {
  338. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WINDOWS, GetLastError());
  339. }
  340. }
  341. return hr;
  342. }
  343. /*++
  344. Routine Name
  345. ServerGetPolicy
  346. Routine Description:
  347. Gets a numeric policy value that was read from the server.
  348. This can be called by providers(localspl).
  349. The policy must be by the server read before initializing providers.
  350. Arguments:
  351. pszPolicyName - policy name
  352. pulValue - pointer to numeric value
  353. Return Value:
  354. HRESULT
  355. --*/
  356. HRESULT
  357. ServerGetPolicy(
  358. IN PCWSTR pszPolicyName,
  359. IN ULONG* pulValue
  360. )
  361. {
  362. HRESULT hr;
  363. ULONG PolicyValue;
  364. ULONG Index;
  365. struct
  366. {
  367. PCWSTR pszName;
  368. ULONG ulValue;
  369. } PolicyTable[] =
  370. {
  371. {szRegisterSpoolerRemoteRpcEndPoint, gNamedPipeState.ePolicyValue},
  372. {NULL , 0}
  373. };
  374. hr = (pulValue && pszPolicyName) ? S_OK : E_POINTER;
  375. if (SUCCEEDED(hr))
  376. {
  377. hr = E_INVALIDARG;
  378. for (Index = 0; PolicyTable[Index].pszName ; Index++)
  379. {
  380. if (_wcsicmp(pszPolicyName, szRegisterSpoolerRemoteRpcEndPoint) == 0)
  381. {
  382. PolicyValue = PolicyTable[Index].ulValue;
  383. hr = S_OK;
  384. break;
  385. }
  386. }
  387. if (SUCCEEDED(hr))
  388. {
  389. *pulValue = PolicyValue;
  390. }
  391. }
  392. return hr;
  393. }