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.

629 lines
15 KiB

  1. /*++
  2. Copyright (c) 1990-1994 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. Reply.c
  6. Abstract:
  7. Handles all communication setup for RPC from the Server back
  8. to the Client.
  9. This implementation allows multiple reply handles for one print
  10. handle, but relies on serialized access to context handles on this
  11. machine.
  12. Author:
  13. Albert Ting (AlbertT) 04-June-94
  14. Environment:
  15. User Mode -Win32
  16. Revision History:
  17. --*/
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. #include "ntfytab.h"
  21. PPRINTHANDLE pPrintHandleReplyList = NULL;
  22. DWORD dwRouterUniqueSessionID = 1;
  23. DWORD
  24. OpenReplyRemote(
  25. LPWSTR pszMachine,
  26. PHANDLE phNotifyRemote,
  27. DWORD dwPrinterRemote,
  28. DWORD dwType,
  29. DWORD cbBuffer,
  30. LPBYTE pBuffer)
  31. /*++
  32. Routine Description:
  33. Establishes a context handle from the server back to the client.
  34. RpcReplyOpenPrinter call will fail with access denied when the
  35. client machine is in a different, un-trusted domain than the server.
  36. For that case, we'll continue impersonate and will try to make the call
  37. in the user context.However, if the client machine was previously joined
  38. the server's domain, but is now in another domain, the server can still successfully
  39. make the RPC call back to client.This scenario works because the client's mac address
  40. is still in the server's domain(even if the client's machine name changes).
  41. We know that a call of RpcReplyOpenPrinter in the user context would succeed
  42. in the case when the machines are in the same domain anyway.
  43. but for safety reasons we preffer to first try to make the call in the local system
  44. context and only if it fails we try to make the call in user context.
  45. Arguments:
  46. pszLocalMachine - Machine to talk to.
  47. phNotifyRemote - Remote context handle to set up
  48. dwPrinterRemote - remote printer handle we are talking to.
  49. Return Value:
  50. --*/
  51. {
  52. DWORD dwReturn;
  53. HANDLE hToken;
  54. BOOL bImpersonating = FALSE;
  55. //
  56. // Stop impersonating: This prevents separate session ids from
  57. // being used.
  58. //
  59. hToken = RevertToPrinterSelf();
  60. dwReturn = hToken ? ERROR_SUCCESS : GetLastError();
  61. if (dwReturn == ERROR_SUCCESS)
  62. {
  63. //
  64. // If create a context handle to reply.
  65. //
  66. RpcTryExcept {
  67. dwReturn = RpcReplyOpenPrinter(
  68. pszMachine,
  69. phNotifyRemote,
  70. dwPrinterRemote,
  71. dwType,
  72. cbBuffer,
  73. pBuffer);
  74. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  75. dwReturn = RpcExceptionCode();
  76. } RpcEndExcept
  77. }
  78. //
  79. // Resume impersonating.
  80. //
  81. if (hToken) {
  82. bImpersonating = ImpersonatePrinterClient(hToken);
  83. if (!bImpersonating && dwReturn == ERROR_SUCCESS) {
  84. dwReturn = GetLastError();
  85. }
  86. }
  87. //
  88. // Try the rpc call in user context, if we failed ReplyOpenPrinter call and not in impersonation.
  89. //
  90. if (dwReturn && bImpersonating) {
  91. RpcTryExcept {
  92. dwReturn = RpcReplyOpenPrinter(
  93. pszMachine,
  94. phNotifyRemote,
  95. dwPrinterRemote,
  96. dwType,
  97. cbBuffer,
  98. pBuffer);
  99. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  100. dwReturn = RpcExceptionCode();
  101. } RpcEndExcept
  102. }
  103. return dwReturn;
  104. }
  105. VOID
  106. CloseReplyRemote(
  107. HANDLE hNotifyRemote)
  108. {
  109. HANDLE hToken;
  110. DWORD dwError;
  111. DBGMSG(DBG_NOTIFY, ("CloseReplyRemote requested: 0x%x\n",
  112. hNotifyRemote));
  113. if (!hNotifyRemote)
  114. return;
  115. //
  116. // Stop impersonating: This prevents separate session ids from
  117. // being used.
  118. //
  119. hToken = RevertToPrinterSelf();
  120. dwError = hToken ? ERROR_SUCCESS : GetLastError();
  121. if (dwError == ERROR_SUCCESS)
  122. {
  123. RpcTryExcept {
  124. dwError = RpcReplyClosePrinter(&hNotifyRemote);
  125. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  126. dwError = RpcExceptionCode();
  127. } RpcEndExcept
  128. }
  129. if (dwError) {
  130. DBGMSG(DBG_WARNING, ("FCPCN:ReplyClose error %d, DestroyClientContext: 0x%x\n",
  131. dwError,
  132. hNotifyRemote));
  133. //
  134. // Error trying to close down the notification,
  135. // clear up our context.
  136. //
  137. RpcSmDestroyClientContext(&hNotifyRemote);
  138. }
  139. //
  140. // Resume impersonating.
  141. //
  142. if (hToken && !ImpersonatePrinterClient(hToken)) {
  143. dwError = GetLastError();
  144. }
  145. }
  146. BOOL
  147. RouterReplyPrinter(
  148. HANDLE hNotify,
  149. DWORD dwColor,
  150. DWORD fdwChangeFlags,
  151. PDWORD pdwResult,
  152. DWORD dwReplyType,
  153. PVOID pBuffer)
  154. /*++
  155. Routine Description:
  156. Handle the notification coming in from a remote router (as
  157. opposed to a print providor).
  158. Arguments:
  159. hNotify -- printer that changed, notification context handle
  160. dwColor -- indicates color of data
  161. fdwChangeFlags -- flags that changed
  162. pdwResult -- out DWORD result
  163. dwReplyType -- type of reply that is coming back
  164. pBuffer -- data based on dwReplyType
  165. Return Value:
  166. BOOL TRUE = success
  167. FALSE = fail
  168. --*/
  169. {
  170. PNOTIFY pNotify = (PNOTIFY)hNotify;
  171. BOOL bReturn = FALSE;
  172. EnterRouterSem();
  173. if (!pNotify ||
  174. pNotify->signature != NOTIFYHANDLE_SIGNATURE ||
  175. !pNotify->pPrintHandle) {
  176. SetLastError(ERROR_INVALID_HANDLE);
  177. goto Done;
  178. }
  179. DBGMSG(DBG_NOTIFY, ("RRP: Remote notification received: pNotify 0x%x, pPrintHandle 0x%x\n",
  180. pNotify, pNotify->pPrintHandle));
  181. switch (pNotify->dwType) {
  182. case REPLY_TYPE_NOTIFICATION:
  183. SPLASSERT(dwReplyType == REPLY_PRINTER_CHANGE);
  184. bReturn = ReplyPrinterChangeNotificationWorker(
  185. pNotify->pPrintHandle,
  186. dwColor,
  187. fdwChangeFlags,
  188. pdwResult,
  189. (PPRINTER_NOTIFY_INFO)pBuffer);
  190. break;
  191. default:
  192. DBGMSG(DBG_ERROR, ("RRPCN: Bogus notify 0x%x type: %d\n",
  193. pNotify, pNotify->dwType));
  194. bReturn = FALSE;
  195. SetLastError(ERROR_INVALID_PARAMETER);
  196. break;
  197. }
  198. Done:
  199. LeaveRouterSem();
  200. return bReturn;
  201. }
  202. /*------------------------------------------------------------------------
  203. Routines from here down occur on the client machine.
  204. ------------------------------------------------------------------------*/
  205. VOID
  206. FreePrinterHandleNotifys(
  207. PPRINTHANDLE pPrintHandle)
  208. {
  209. PNOTIFY pNotify;
  210. RouterInSem();
  211. if(pPrintHandle)
  212. {
  213. for(pNotify = pPrintHandle->pNotify;
  214. pNotify;
  215. pNotify = pNotify->pNext) {
  216. pNotify->pPrintHandle = NULL;
  217. }
  218. //
  219. // For safety, remove all replys.
  220. //
  221. RemoveReplyClient(pPrintHandle,
  222. (DWORD)~0);
  223. }
  224. }
  225. VOID
  226. BeginReplyClient(
  227. PPRINTHANDLE pPrintHandle,
  228. DWORD fdwType)
  229. {
  230. RouterInSem();
  231. DBGMSG(DBG_NOTIFY, ("BeginReplyClient called 0x%x type %x (sig=0x%x).\n",
  232. pPrintHandle, fdwType, pPrintHandle->signature));
  233. if(pPrintHandle)
  234. {
  235. if (!pPrintHandle->fdwReplyTypes) {
  236. // Give a unique DWORD session ID for pPrintHandle
  237. while (pPrintHandle->dwUniqueSessionID == 0 ||
  238. pPrintHandle->dwUniqueSessionID == 0xffffffff) {
  239. pPrintHandle->dwUniqueSessionID = dwRouterUniqueSessionID++;
  240. }
  241. pPrintHandle->pNext = pPrintHandleReplyList;
  242. pPrintHandleReplyList = pPrintHandle;
  243. }
  244. pPrintHandle->fdwReplyTypes |= fdwType;
  245. }
  246. }
  247. VOID
  248. EndReplyClient(
  249. PPRINTHANDLE pPrintHandle,
  250. DWORD fdwType)
  251. {
  252. RouterInSem();
  253. DBGMSG(DBG_NOTIFY, ("EndReplyClient called 0x%x type %x.\n",
  254. pPrintHandle, fdwType));
  255. }
  256. VOID
  257. RemoveReplyClient(
  258. PPRINTHANDLE pPrintHandle,
  259. DWORD fdwType)
  260. {
  261. PPRINTHANDLE p;
  262. RouterInSem();
  263. DBGMSG(DBG_NOTIFY, ("RemoveReplyClient called 0x%x typed %x (sig=0x%x).\n",
  264. pPrintHandle, fdwType, pPrintHandle->signature));
  265. if(pPrintHandle)
  266. {
  267. //
  268. // Remove this reply type from the print handle.
  269. //
  270. pPrintHandle->fdwReplyTypes &= ~fdwType;
  271. //
  272. // If no replys remain, remove from linked list.
  273. //
  274. if (!pPrintHandle->fdwReplyTypes) {
  275. // Recover the unique session ID
  276. pPrintHandle->dwUniqueSessionID = 0;
  277. //
  278. // Remove from linked list.
  279. //
  280. if (pPrintHandleReplyList == pPrintHandle) {
  281. pPrintHandleReplyList = pPrintHandle->pNext;
  282. } else {
  283. for (p = pPrintHandleReplyList; p; p=p->pNext) {
  284. if (p->pNext == pPrintHandle) {
  285. p->pNext = pPrintHandle->pNext;
  286. return;
  287. }
  288. }
  289. }
  290. }
  291. }
  292. }
  293. BOOL
  294. ReplyOpenPrinter(
  295. DWORD dwPrinterHandle,
  296. PHANDLE phNotify,
  297. DWORD dwType,
  298. DWORD cbBuffer,
  299. LPBYTE pBuffer)
  300. /*++
  301. Routine Description:
  302. When sending a notification back from the print server to the
  303. client, we open up a notification context handle back on the client.
  304. This way, every time we send back a notification, we just use this
  305. context handle.
  306. Arguments:
  307. dwPrinterHandle - printer handle valid here (on the client). The spoolss.exe
  308. switches this around for us.
  309. phNotify - context handle to return to the remote print server.
  310. dwType - Type of notification
  311. cbBuffer - reserved for extra information passed
  312. pBuffer - reserved for extra information passed
  313. Return Value:
  314. BOOL TRUE = success
  315. FALSE
  316. --*/
  317. {
  318. PPRINTHANDLE pPrintHandle;
  319. PNOTIFY pNotify;
  320. BOOL bReturnValue = FALSE;
  321. EnterRouterSem();
  322. //
  323. // Validate that we are waiting on this print handle.
  324. // We traverse the linked list to ensure that random bogus
  325. // hPrinters (which may point to garbage that looks valid)
  326. // are rejected.
  327. //
  328. for (pPrintHandle = pPrintHandleReplyList;
  329. pPrintHandle;
  330. pPrintHandle = pPrintHandle->pNext) {
  331. if (pPrintHandle->dwUniqueSessionID == dwPrinterHandle)
  332. break;
  333. }
  334. if (!pPrintHandle || !(pPrintHandle->fdwReplyTypes & dwType)) {
  335. DBGMSG(DBG_WARNING, ("ROPCN: Invalid printer handle 0x%x\n",
  336. dwPrinterHandle));
  337. SetLastError(ERROR_INVALID_HANDLE);
  338. goto Done;
  339. }
  340. pNotify = AllocSplMem(sizeof(NOTIFY));
  341. if (!pNotify) {
  342. goto Done;
  343. }
  344. pNotify->signature = NOTIFYHANDLE_SIGNATURE;
  345. pNotify->pPrintHandle = pPrintHandle;
  346. pNotify->dwType = dwType;
  347. //
  348. // Add us to the list of Notifys.
  349. //
  350. pNotify->pNext = pPrintHandle->pNotify;
  351. pPrintHandle->pNotify = pNotify;
  352. DBGMSG(DBG_NOTIFY, ("ROPCN: Notification 0x%x (pPrintHandle 0x%x) set up\n",
  353. pNotify,
  354. pPrintHandle));
  355. *phNotify = (HANDLE)pNotify;
  356. bReturnValue = TRUE;
  357. Done:
  358. LeaveRouterSem();
  359. return bReturnValue;
  360. }
  361. BOOL
  362. ReplyClosePrinter(
  363. HANDLE hNotify)
  364. {
  365. PNOTIFY pNotify = (PNOTIFY)hNotify;
  366. PNOTIFY pNotifyTemp;
  367. BOOL bReturnValue = FALSE;
  368. EnterRouterSem();
  369. if (!pNotify || pNotify->signature != NOTIFYHANDLE_SIGNATURE) {
  370. SetLastError(ERROR_INVALID_HANDLE);
  371. goto Done;
  372. }
  373. if (pNotify->pPrintHandle) {
  374. //
  375. // Trigger a notification if the user is still watching the
  376. // handle.
  377. //
  378. ReplyPrinterChangeNotification(pNotify->pPrintHandle,
  379. PRINTER_CHANGE_FAILED_CONNECTION_PRINTER,
  380. NULL,
  381. NULL);
  382. //
  383. // Remove from notification list
  384. //
  385. if (pNotify->pPrintHandle->pNotify == pNotify) {
  386. pNotify->pPrintHandle->pNotify = pNotify->pNext;
  387. } else {
  388. for (pNotifyTemp = pNotify->pPrintHandle->pNotify;
  389. pNotifyTemp;
  390. pNotifyTemp = pNotifyTemp->pNext) {
  391. if (pNotifyTemp->pNext == pNotify) {
  392. pNotifyTemp->pNext = pNotify->pNext;
  393. break;
  394. }
  395. }
  396. }
  397. }
  398. DBGMSG(DBG_NOTIFY, ("RCPCN: Freeing notify: 0x%x (pPrintHandle 0x%x)\n",
  399. pNotify,
  400. pNotify->pPrintHandle));
  401. FreeSplMem(pNotify);
  402. bReturnValue = TRUE;
  403. Done:
  404. LeaveRouterSem();
  405. return bReturnValue;
  406. }
  407. VOID
  408. RundownPrinterNotify(
  409. HANDLE hNotify)
  410. /*++
  411. Routine Description:
  412. This is the rundown routine for notifications (the context handle
  413. for the print server -> client communication). When the print server
  414. goes down, the context handle gets rundown on the client (now acting
  415. as an RPC server). We should signal the user that something has
  416. changed.
  417. Arguments:
  418. hNotify - Handle that has gone invalid
  419. Return Value:
  420. --*/
  421. {
  422. PNOTIFY pNotify = (PNOTIFY)hNotify;
  423. DBGMSG(DBG_NOTIFY, ("Rundown called: 0x%x type %d\n",
  424. pNotify,
  425. pNotify->dwType));
  426. //
  427. // Notify the client that the printer has changed--it went away.
  428. // This should _always_ be a local event.
  429. //
  430. switch (pNotify->dwType) {
  431. case REPLY_TYPE_NOTIFICATION:
  432. ReplyPrinterChangeNotification((HANDLE)pNotify->pPrintHandle,
  433. PRINTER_CHANGE_FAILED_CONNECTION_PRINTER,
  434. NULL,
  435. NULL);
  436. ReplyClosePrinter(hNotify);
  437. break;
  438. default:
  439. //
  440. // This can legally occur on a pNotify that was reopened
  441. // (due to network error) and hasn't been used yet.
  442. // dwType should be reinitialized every time the pNotify
  443. // is used.
  444. //
  445. DBGMSG(DBG_ERROR, ("Rundown: unknown notify type %d\n",
  446. pNotify->dwType));
  447. }
  448. }