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.

vncExtInit.cc 31KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2011 Pierre Ossman for Cendio AB
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. #ifdef HAVE_DIX_CONFIG_H
  20. #include <dix-config.h>
  21. #endif
  22. #include <stdio.h>
  23. #include <errno.h>
  24. extern "C" {
  25. #define class c_class
  26. #define public c_public
  27. #define NEED_EVENTS
  28. #include <X11/X.h>
  29. #include <X11/Xproto.h>
  30. #include <X11/Xpoll.h>
  31. #include "misc.h"
  32. #include "os.h"
  33. #include "dixstruct.h"
  34. #include "extnsionst.h"
  35. #include "scrnintstr.h"
  36. #include "selection.h"
  37. #define _VNCEXT_SERVER_
  38. #define _VNCEXT_PROTO_
  39. #include "vncExt.h"
  40. #undef class
  41. #undef xalloc
  42. #undef public
  43. }
  44. #include <rfb/Configuration.h>
  45. #include <rfb/Logger_stdio.h>
  46. #include <rfb/LogWriter.h>
  47. #include <rfb/util.h>
  48. #include <rfb/ServerCore.h>
  49. #include <rdr/HexOutStream.h>
  50. #include <rfb/LogWriter.h>
  51. #undef max
  52. #undef min
  53. #include <network/TcpSocket.h>
  54. #include "XserverDesktop.h"
  55. #include "vncHooks.h"
  56. #include "vncExtInit.h"
  57. #include "xorg-version.h"
  58. extern "C" {
  59. extern void vncExtensionInit();
  60. static void vncResetProc(ExtensionEntry* extEntry);
  61. static void vncBlockHandler(pointer data, OSTimePtr t, pointer readmask);
  62. static void vncWakeupHandler(pointer data, int nfds, pointer readmask);
  63. void vncWriteBlockHandler(fd_set *fds);
  64. void vncWriteWakeupHandler(int nfds, fd_set *fds);
  65. static void vncClientStateChange(CallbackListPtr*, pointer, pointer);
  66. static void SendSelectionChangeEvent(Atom selection);
  67. static int ProcVncExtDispatch(ClientPtr client);
  68. static int SProcVncExtDispatch(ClientPtr client);
  69. static void vncSelectionCallback(CallbackListPtr *callbacks, pointer data,
  70. pointer args);
  71. extern char *display;
  72. extern char *listenaddr;
  73. }
  74. using namespace rfb;
  75. static rfb::LogWriter vlog("vncext");
  76. static unsigned long vncExtGeneration = 0;
  77. static bool initialised = false;
  78. static XserverDesktop* desktop[MAXSCREENS] = { 0, };
  79. void* vncFbptr[MAXSCREENS] = { 0, };
  80. int vncFbstride[MAXSCREENS];
  81. static char* clientCutText = 0;
  82. static int clientCutTextLen = 0;
  83. bool noclipboard = false;
  84. static XserverDesktop* queryConnectDesktop = 0;
  85. static void* queryConnectId = 0;
  86. static int queryConnectTimeout = 0;
  87. static OsTimerPtr queryConnectTimer = 0;
  88. static struct VncInputSelect* vncInputSelectHead = 0;
  89. struct VncInputSelect {
  90. VncInputSelect(ClientPtr c, Window w, int m) : client(c), window(w), mask(m)
  91. {
  92. next = vncInputSelectHead;
  93. vncInputSelectHead = this;
  94. }
  95. ClientPtr client;
  96. Window window;
  97. int mask;
  98. VncInputSelect* next;
  99. };
  100. static int vncErrorBase = 0;
  101. static int vncEventBase = 0;
  102. int vncInetdSock = -1;
  103. rfb::StringParameter httpDir("httpd",
  104. "Directory containing files to serve via HTTP",
  105. "");
  106. rfb::IntParameter httpPort("httpPort", "TCP port to listen for HTTP",0);
  107. rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis",
  108. &rfb::Server::clientWaitTimeMillis);
  109. rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0);
  110. rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11");
  111. rfb::BoolParameter localhostOnly("localhost",
  112. "Only allow connections from localhost",
  113. false);
  114. static PixelFormat vncGetPixelFormat(ScreenPtr pScreen)
  115. {
  116. int depth, bpp;
  117. int trueColour, bigEndian;
  118. int redShift, greenShift, blueShift;
  119. int redMax, greenMax, blueMax;
  120. int i;
  121. VisualPtr vis = NULL;
  122. depth = pScreen->rootDepth;
  123. for (i = 0; i < screenInfo.numPixmapFormats; i++) {
  124. if (screenInfo.formats[i].depth == depth) {
  125. bpp = screenInfo.formats[i].bitsPerPixel;
  126. break;
  127. }
  128. }
  129. if (i == screenInfo.numPixmapFormats) {
  130. fprintf(stderr,"no pixmap format for root depth???\n");
  131. abort();
  132. }
  133. bigEndian = (screenInfo.imageByteOrder == MSBFirst);
  134. for (i = 0; i < pScreen->numVisuals; i++) {
  135. if (pScreen->visuals[i].vid == pScreen->rootVisual) {
  136. vis = &pScreen->visuals[i];
  137. break;
  138. }
  139. }
  140. if (i == pScreen->numVisuals) {
  141. fprintf(stderr,"no visual rec for root visual???\n");
  142. abort();
  143. }
  144. trueColour = (vis->c_class == TrueColor);
  145. if (!trueColour && bpp != 8)
  146. throw rfb::Exception("X server uses unsupported visual");
  147. redShift = ffs(vis->redMask) - 1;
  148. greenShift = ffs(vis->greenMask) - 1;
  149. blueShift = ffs(vis->blueMask) - 1;
  150. redMax = vis->redMask >> redShift;
  151. greenMax = vis->greenMask >> greenShift;
  152. blueMax = vis->blueMask >> blueShift;
  153. return PixelFormat(bpp, depth, bigEndian, trueColour,
  154. redMax, greenMax, blueMax,
  155. redShift, greenShift, blueShift);
  156. }
  157. void vncExtensionInit()
  158. {
  159. if (vncExtGeneration == serverGeneration) {
  160. vlog.error("vncExtensionInit: called twice in same generation?");
  161. return;
  162. }
  163. vncExtGeneration = serverGeneration;
  164. ExtensionEntry* extEntry
  165. = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors,
  166. ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc,
  167. StandardMinorOpcode);
  168. if (!extEntry) {
  169. ErrorF("vncExtInit: AddExtension failed\n");
  170. return;
  171. }
  172. vncErrorBase = extEntry->errorBase;
  173. vncEventBase = extEntry->eventBase;
  174. vlog.info("VNC extension running!");
  175. if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) {
  176. FatalError("Add ClientStateCallback failed\n");
  177. }
  178. if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) {
  179. FatalError("Add SelectionCallback failed\n");
  180. }
  181. try {
  182. if (!initialised) {
  183. rfb::initStdIOLoggers();
  184. initialised = true;
  185. }
  186. for (int scr = 0; scr < screenInfo.numScreens; scr++) {
  187. if (!desktop[scr]) {
  188. network::TcpListener* listener = 0;
  189. network::TcpListener* httpListener = 0;
  190. if (scr == 0 && vncInetdSock != -1) {
  191. if (network::TcpSocket::isSocket(vncInetdSock) &&
  192. !network::TcpSocket::isConnected(vncInetdSock))
  193. {
  194. listener = new network::TcpListener(NULL, 0, 0, vncInetdSock, true);
  195. vlog.info("inetd wait");
  196. }
  197. } else {
  198. int port = rfbport;
  199. if (port == 0) port = 5900 + atoi(display);
  200. port += 1000 * scr;
  201. listener = new network::TcpListener(listenaddr, port, localhostOnly);
  202. vlog.info("Listening for VNC connections on %s interface(s), port %d",
  203. listenaddr == NULL ? "all" : listenaddr, port);
  204. CharArray httpDirStr(httpDir.getData());
  205. if (httpDirStr.buf[0]) {
  206. port = httpPort;
  207. if (port == 0) port = 5800 + atoi(display);
  208. port += 1000 * scr;
  209. httpListener = new network::TcpListener(listenaddr, port, localhostOnly);
  210. vlog.info("Listening for HTTP connections on %s interface(s), port %d",
  211. listenaddr == NULL ? "all" : listenaddr, port);
  212. }
  213. }
  214. CharArray desktopNameStr(desktopName.getData());
  215. PixelFormat pf = vncGetPixelFormat(screenInfo.screens[scr]);
  216. desktop[scr] = new XserverDesktop(screenInfo.screens[scr],
  217. listener,
  218. httpListener,
  219. desktopNameStr.buf,
  220. pf,
  221. vncFbptr[scr],
  222. vncFbstride[scr]);
  223. vlog.info("created VNC server for screen %d", scr);
  224. if (scr == 0 && vncInetdSock != -1 && !listener) {
  225. network::Socket* sock = new network::TcpSocket(vncInetdSock);
  226. desktop[scr]->addClient(sock, false);
  227. vlog.info("added inetd sock");
  228. }
  229. } else {
  230. desktop[scr]->serverReset(screenInfo.screens[scr]);
  231. }
  232. vncHooksInit(screenInfo.screens[scr], desktop[scr]);
  233. }
  234. RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0);
  235. } catch (rdr::Exception& e) {
  236. vlog.error("vncExtInit: %s",e.str());
  237. }
  238. }
  239. static void vncResetProc(ExtensionEntry* extEntry)
  240. {
  241. }
  242. static void vncSelectionCallback(CallbackListPtr *callbacks, pointer data, pointer args)
  243. {
  244. SelectionInfoRec *info = (SelectionInfoRec *) args;
  245. Selection *selection = info->selection;
  246. SendSelectionChangeEvent(selection->selection);
  247. }
  248. static void vncWriteBlockHandlerFallback(OSTimePtr timeout);
  249. static void vncWriteWakeupHandlerFallback();
  250. //
  251. // vncBlockHandler - called just before the X server goes into select(). Call
  252. // on to the block handler for each desktop. Then check whether any of the
  253. // selections have changed, and if so, notify any interested X clients.
  254. //
  255. static void vncBlockHandler(pointer data, OSTimePtr timeout, pointer readmask)
  256. {
  257. fd_set* fds = (fd_set*)readmask;
  258. vncWriteBlockHandlerFallback(timeout);
  259. for (int scr = 0; scr < screenInfo.numScreens; scr++)
  260. if (desktop[scr])
  261. desktop[scr]->blockHandler(fds, timeout);
  262. }
  263. static void vncWakeupHandler(pointer data, int nfds, pointer readmask)
  264. {
  265. fd_set* fds = (fd_set*)readmask;
  266. for (int scr = 0; scr < screenInfo.numScreens; scr++) {
  267. if (desktop[scr]) {
  268. desktop[scr]->wakeupHandler(fds, nfds);
  269. }
  270. }
  271. vncWriteWakeupHandlerFallback();
  272. }
  273. //
  274. // vncWriteBlockHandler - extra hack to be able to get the main select loop
  275. // to monitor writeable fds and not just readable. This requirers a modified
  276. // Xorg and might therefore not be called. When it is called though, it will
  277. // do so before vncBlockHandler (and vncWriteWakeupHandler called after
  278. // vncWakeupHandler).
  279. //
  280. static bool needFallback = true;
  281. static fd_set fallbackFds;
  282. static struct timeval tw;
  283. void vncWriteBlockHandler(fd_set *fds)
  284. {
  285. needFallback = false;
  286. for (int scr = 0; scr < screenInfo.numScreens; scr++)
  287. if (desktop[scr])
  288. desktop[scr]->writeBlockHandler(fds);
  289. }
  290. void vncWriteWakeupHandler(int nfds, fd_set *fds)
  291. {
  292. for (int scr = 0; scr < screenInfo.numScreens; scr++) {
  293. if (desktop[scr]) {
  294. desktop[scr]->writeWakeupHandler(fds, nfds);
  295. }
  296. }
  297. }
  298. static void vncWriteBlockHandlerFallback(OSTimePtr timeout)
  299. {
  300. if (!needFallback)
  301. return;
  302. FD_ZERO(&fallbackFds);
  303. vncWriteBlockHandler(&fallbackFds);
  304. needFallback = true;
  305. if (!XFD_ANYSET(&fallbackFds))
  306. return;
  307. if ((*timeout == NULL) ||
  308. ((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) {
  309. tw.tv_sec = 0;
  310. tw.tv_usec = 10000;
  311. *timeout = &tw;
  312. }
  313. }
  314. static void vncWriteWakeupHandlerFallback()
  315. {
  316. int ret;
  317. struct timeval timeout;
  318. if (!needFallback)
  319. return;
  320. if (!XFD_ANYSET(&fallbackFds))
  321. return;
  322. timeout.tv_sec = 0;
  323. timeout.tv_usec = 0;
  324. ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout);
  325. if (ret < 0) {
  326. ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n",
  327. strerror(errno));
  328. return;
  329. }
  330. if (ret == 0)
  331. return;
  332. vncWriteWakeupHandler(ret, &fallbackFds);
  333. }
  334. static void vncClientStateChange(CallbackListPtr*, pointer, pointer p)
  335. {
  336. ClientPtr client = ((NewClientInfoRec*)p)->client;
  337. if (client->clientState == ClientStateGone) {
  338. VncInputSelect** nextPtr = &vncInputSelectHead;
  339. for (VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) {
  340. if (cur->client == client) {
  341. *nextPtr = cur->next;
  342. delete cur;
  343. continue;
  344. }
  345. nextPtr = &cur->next;
  346. }
  347. }
  348. }
  349. void vncBell()
  350. {
  351. for (int scr = 0; scr < screenInfo.numScreens; scr++) {
  352. if (desktop[scr]) {
  353. desktop[scr]->bell();
  354. }
  355. }
  356. }
  357. void vncClientGone(int fd)
  358. {
  359. if (fd == vncInetdSock) {
  360. fprintf(stderr,"inetdSock client gone\n");
  361. GiveUp(0);
  362. }
  363. }
  364. void vncClientCutText(const char* str, int len)
  365. {
  366. delete [] clientCutText;
  367. clientCutText = new char[len];
  368. memcpy(clientCutText, str, len);
  369. clientCutTextLen = len;
  370. xVncExtClientCutTextNotifyEvent ev;
  371. ev.type = vncEventBase + VncExtClientCutTextNotify;
  372. for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
  373. if (cur->mask & VncExtClientCutTextMask) {
  374. ev.sequenceNumber = cur->client->sequence;
  375. ev.window = cur->window;
  376. ev.time = GetTimeInMillis();
  377. if (cur->client->swapped) {
  378. #if XORG < 112
  379. int n;
  380. swaps(&ev.sequenceNumber, n);
  381. swapl(&ev.window, n);
  382. swapl(&ev.time, n);
  383. #else
  384. swaps(&ev.sequenceNumber);
  385. swapl(&ev.window);
  386. swapl(&ev.time);
  387. #endif
  388. }
  389. WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent),
  390. (char *)&ev);
  391. }
  392. }
  393. }
  394. static CARD32 queryConnectTimerCallback(OsTimerPtr timer,
  395. CARD32 now, pointer arg)
  396. {
  397. if (queryConnectTimeout)
  398. queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed");
  399. // Re-notify clients, causing them to discover that we're done
  400. vncQueryConnect(queryConnectDesktop, queryConnectId);
  401. return 0;
  402. }
  403. void vncQueryConnect(XserverDesktop* desktop, void* opaqueId)
  404. {
  405. // Only one query can be processed at any one time
  406. if (queryConnectTimeout && ((desktop != queryConnectDesktop) ||
  407. (opaqueId != queryConnectId))) {
  408. desktop->approveConnection(opaqueId, false,
  409. "Another connection is currently being queried.");
  410. return;
  411. }
  412. // Get the query timeout. If it's zero, there is no query.
  413. queryConnectTimeout = desktop->getQueryTimeout(opaqueId);
  414. queryConnectId = queryConnectTimeout ? opaqueId : 0;
  415. queryConnectDesktop = queryConnectTimeout ? desktop : 0;
  416. // Notify clients
  417. bool notified = false;
  418. xVncExtQueryConnectNotifyEvent ev;
  419. ev.type = vncEventBase + VncExtQueryConnectNotify;
  420. for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
  421. if (cur->mask & VncExtQueryConnectMask) {
  422. ev.sequenceNumber = cur->client->sequence;
  423. ev.window = cur->window;
  424. if (cur->client->swapped) {
  425. #if XORG < 112
  426. int n;
  427. swaps(&ev.sequenceNumber, n);
  428. swapl(&ev.window, n);
  429. #else
  430. swaps(&ev.sequenceNumber);
  431. swapl(&ev.window);
  432. #endif
  433. }
  434. WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent),
  435. (char *)&ev);
  436. notified = true;
  437. }
  438. }
  439. // If we're being asked to query a connection (rather than to cancel
  440. // a query), and haven't been able to notify clients then reject it.
  441. if (queryConnectTimeout && !notified) {
  442. queryConnectTimeout = 0;
  443. queryConnectId = 0;
  444. queryConnectDesktop = 0;
  445. desktop->approveConnection(opaqueId, false,
  446. "Unable to query the local user to accept the connection.");
  447. return;
  448. }
  449. // Set a timer so that if no-one ever responds, we will eventually
  450. // reject the connection
  451. // NB: We don't set a timer if sock is null, since that indicates
  452. // that pending queries should be cancelled.
  453. if (queryConnectDesktop)
  454. queryConnectTimer = TimerSet(queryConnectTimer, 0,
  455. queryConnectTimeout*2000,
  456. queryConnectTimerCallback, 0);
  457. else
  458. TimerCancel(queryConnectTimer);
  459. }
  460. static void SendSelectionChangeEvent(Atom selection)
  461. {
  462. xVncExtSelectionChangeNotifyEvent ev;
  463. ev.type = vncEventBase + VncExtSelectionChangeNotify;
  464. for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
  465. if (cur->mask & VncExtSelectionChangeMask) {
  466. ev.sequenceNumber = cur->client->sequence;
  467. ev.window = cur->window;
  468. ev.selection = selection;
  469. if (cur->client->swapped) {
  470. #if XORG < 112
  471. int n;
  472. swaps(&ev.sequenceNumber, n);
  473. swapl(&ev.window, n);
  474. swapl(&ev.selection, n);
  475. #else
  476. swaps(&ev.sequenceNumber);
  477. swapl(&ev.window);
  478. swapl(&ev.selection);
  479. #endif
  480. }
  481. WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent),
  482. (char *)&ev);
  483. }
  484. }
  485. }
  486. static int ProcVncExtSetParam(ClientPtr client)
  487. {
  488. char* value1 = 0;
  489. char* value2 = 0;
  490. rfb::VoidParameter *desktop1, *desktop2;
  491. REQUEST(xVncExtSetParamReq);
  492. REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen);
  493. CharArray param(stuff->paramLen+1);
  494. strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
  495. param.buf[stuff->paramLen] = 0;
  496. xVncExtSetParamReply rep;
  497. rep.type = X_Reply;
  498. rep.length = 0;
  499. rep.success = 0;
  500. rep.sequenceNumber = client->sequence;
  501. // Retrieve desktop name before setting
  502. desktop1 = rfb::Configuration::getParam("desktop");
  503. if (desktop1)
  504. value1 = desktop1->getValueStr();
  505. /*
  506. * Allow to change only certain parameters.
  507. * Changing other parameters (for example PAM service name)
  508. * could have negative security impact.
  509. */
  510. if (strncasecmp(param.buf, "desktop", 7) != 0 &&
  511. strncasecmp(param.buf, "AcceptPointerEvents", 19) != 0 &&
  512. (noclipboard || strncasecmp(param.buf, "SendCutText", 11) != 0) &&
  513. (noclipboard || strncasecmp(param.buf, "AcceptCutText", 13) != 0))
  514. goto deny;
  515. rep.success = rfb::Configuration::setParam(param.buf);
  516. // Send DesktopName update if desktop name has been changed
  517. desktop2 = rfb::Configuration::getParam("desktop");
  518. if (desktop2)
  519. value2 = desktop2->getValueStr();
  520. if (value1 && value2 && strcmp(value1, value2)) {
  521. for (int scr = 0; scr < screenInfo.numScreens; scr++) {
  522. if (desktop[scr]) {
  523. desktop[scr]->setDesktopName(value2);
  524. }
  525. }
  526. }
  527. if (value1)
  528. delete [] value1;
  529. if (value2)
  530. delete [] value2;
  531. deny:
  532. if (client->swapped) {
  533. #if XORG < 112
  534. int n;
  535. swaps(&rep.sequenceNumber, n);
  536. swapl(&rep.length, n);
  537. #else
  538. swaps(&rep.sequenceNumber);
  539. swapl(&rep.length);
  540. #endif
  541. }
  542. WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep);
  543. return (client->noClientException);
  544. }
  545. static int SProcVncExtSetParam(ClientPtr client)
  546. {
  547. REQUEST(xVncExtSetParamReq);
  548. #if XORG < 112
  549. register char n;
  550. swaps(&stuff->length, n);
  551. #else
  552. swaps(&stuff->length);
  553. #endif
  554. REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq);
  555. return ProcVncExtSetParam(client);
  556. }
  557. static int ProcVncExtGetParam(ClientPtr client)
  558. {
  559. REQUEST(xVncExtGetParamReq);
  560. REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen);
  561. CharArray param(stuff->paramLen+1);
  562. strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
  563. param.buf[stuff->paramLen] = 0;
  564. xVncExtGetParamReply rep;
  565. rep.type = X_Reply;
  566. rep.sequenceNumber = client->sequence;
  567. rep.success = 0;
  568. int len = 0;
  569. char* value = 0;
  570. rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf);
  571. // Hack to avoid exposing password!
  572. if (strcasecmp(param.buf, "Password") == 0)
  573. p = 0;
  574. if (p) {
  575. value = p->getValueStr();
  576. rep.success = 1;
  577. len = value ? strlen(value) : 0;
  578. }
  579. rep.length = (len + 3) >> 2;
  580. rep.valueLen = len;
  581. if (client->swapped) {
  582. #if XORG < 112
  583. int n;
  584. swaps(&rep.sequenceNumber, n);
  585. swapl(&rep.length, n);
  586. swaps(&rep.valueLen, n);
  587. #else
  588. swaps(&rep.sequenceNumber);
  589. swapl(&rep.length);
  590. swaps(&rep.valueLen);
  591. #endif
  592. }
  593. WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep);
  594. if (value)
  595. WriteToClient(client, len, value);
  596. delete [] value;
  597. return (client->noClientException);
  598. }
  599. static int SProcVncExtGetParam(ClientPtr client)
  600. {
  601. REQUEST(xVncExtGetParamReq);
  602. #if XORG < 112
  603. register char n;
  604. swaps(&stuff->length, n);
  605. #else
  606. swaps(&stuff->length);
  607. #endif
  608. REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq);
  609. return ProcVncExtGetParam(client);
  610. }
  611. static int ProcVncExtGetParamDesc(ClientPtr client)
  612. {
  613. REQUEST(xVncExtGetParamDescReq);
  614. REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen);
  615. CharArray param(stuff->paramLen+1);
  616. strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
  617. param.buf[stuff->paramLen] = 0;
  618. xVncExtGetParamDescReply rep;
  619. rep.type = X_Reply;
  620. rep.sequenceNumber = client->sequence;
  621. rep.success = 0;
  622. int len = 0;
  623. const char* desc = 0;
  624. rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf);
  625. if (p) {
  626. desc = p->getDescription();
  627. rep.success = 1;
  628. len = desc ? strlen(desc) : 0;
  629. }
  630. rep.length = (len + 3) >> 2;
  631. rep.descLen = len;
  632. if (client->swapped) {
  633. #if XORG < 112
  634. int n;
  635. swaps(&rep.sequenceNumber, n);
  636. swapl(&rep.length, n);
  637. swaps(&rep.descLen, n);
  638. #else
  639. swaps(&rep.sequenceNumber);
  640. swapl(&rep.length);
  641. swaps(&rep.descLen);
  642. #endif
  643. }
  644. WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep);
  645. if (desc)
  646. WriteToClient(client, len, (char*)desc);
  647. return (client->noClientException);
  648. }
  649. static int SProcVncExtGetParamDesc(ClientPtr client)
  650. {
  651. REQUEST(xVncExtGetParamDescReq);
  652. #if XORG < 112
  653. register char n;
  654. swaps(&stuff->length, n);
  655. #else
  656. swaps(&stuff->length);
  657. #endif
  658. REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq);
  659. return ProcVncExtGetParamDesc(client);
  660. }
  661. static int ProcVncExtListParams(ClientPtr client)
  662. {
  663. REQUEST(xVncExtListParamsReq);
  664. REQUEST_SIZE_MATCH(xVncExtListParamsReq);
  665. xVncExtListParamsReply rep;
  666. rep.type = X_Reply;
  667. rep.sequenceNumber = client->sequence;
  668. int nParams = 0;
  669. int len = 0;
  670. for (ParameterIterator i; i.param; i.next()) {
  671. int l = strlen(i.param->getName());
  672. if (l <= 255) {
  673. nParams++;
  674. len += l + 1;
  675. }
  676. }
  677. rep.length = (len + 3) >> 2;
  678. rep.nParams = nParams;
  679. if (client->swapped) {
  680. #if XORG < 112
  681. int n;
  682. swaps(&rep.sequenceNumber, n);
  683. swapl(&rep.length, n);
  684. swaps(&rep.nParams, n);
  685. #else
  686. swaps(&rep.sequenceNumber);
  687. swapl(&rep.length);
  688. swaps(&rep.nParams);
  689. #endif
  690. }
  691. WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
  692. rdr::U8* data = new rdr::U8[len];
  693. rdr::U8* ptr = data;
  694. for (ParameterIterator i; i.param; i.next()) {
  695. int l = strlen(i.param->getName());
  696. if (l <= 255) {
  697. *ptr++ = l;
  698. memcpy(ptr, i.param->getName(), l);
  699. ptr += l;
  700. }
  701. }
  702. WriteToClient(client, len, (char*)data);
  703. delete [] data;
  704. return (client->noClientException);
  705. }
  706. static int SProcVncExtListParams(ClientPtr client)
  707. {
  708. REQUEST(xVncExtListParamsReq);
  709. #if XORG < 112
  710. register char n;
  711. swaps(&stuff->length, n);
  712. #else
  713. swaps(&stuff->length);
  714. #endif
  715. REQUEST_SIZE_MATCH(xVncExtListParamsReq);
  716. return ProcVncExtListParams(client);
  717. }
  718. static int ProcVncExtSetServerCutText(ClientPtr client)
  719. {
  720. REQUEST(xVncExtSetServerCutTextReq);
  721. REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen);
  722. char* str = new char[stuff->textLen+1];
  723. strncpy(str, (char*)&stuff[1], stuff->textLen);
  724. str[stuff->textLen] = 0;
  725. for (int scr = 0; scr < screenInfo.numScreens; scr++) {
  726. if (desktop[scr]) {
  727. desktop[scr]->serverCutText(str, stuff->textLen);
  728. }
  729. }
  730. delete [] str;
  731. return (client->noClientException);
  732. }
  733. static int SProcVncExtSetServerCutText(ClientPtr client)
  734. {
  735. REQUEST(xVncExtSetServerCutTextReq);
  736. #if XORG < 112
  737. register char n;
  738. swaps(&stuff->length, n);
  739. #else
  740. swaps(&stuff->length);
  741. #endif
  742. REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq);
  743. #if XORG < 112
  744. swapl(&stuff->textLen, n);
  745. #else
  746. swapl(&stuff->textLen);
  747. #endif
  748. return ProcVncExtSetServerCutText(client);
  749. }
  750. static int ProcVncExtGetClientCutText(ClientPtr client)
  751. {
  752. REQUEST(xVncExtGetClientCutTextReq);
  753. REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
  754. xVncExtGetClientCutTextReply rep;
  755. rep.type = X_Reply;
  756. rep.length = (clientCutTextLen + 3) >> 2;
  757. rep.sequenceNumber = client->sequence;
  758. rep.textLen = clientCutTextLen;
  759. if (client->swapped) {
  760. #if XORG < 112
  761. int n;
  762. swaps(&rep.sequenceNumber, n);
  763. swapl(&rep.length, n);
  764. swapl(&rep.textLen, n);
  765. #else
  766. swaps(&rep.sequenceNumber);
  767. swapl(&rep.length);
  768. swapl(&rep.textLen);
  769. #endif
  770. }
  771. WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep);
  772. if (clientCutText)
  773. WriteToClient(client, clientCutTextLen, clientCutText);
  774. return (client->noClientException);
  775. }
  776. static int SProcVncExtGetClientCutText(ClientPtr client)
  777. {
  778. REQUEST(xVncExtGetClientCutTextReq);
  779. #if XORG < 112
  780. register char n;
  781. swaps(&stuff->length, n);
  782. #else
  783. swaps(&stuff->length);
  784. #endif
  785. REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
  786. return ProcVncExtGetClientCutText(client);
  787. }
  788. static int ProcVncExtSelectInput(ClientPtr client)
  789. {
  790. REQUEST(xVncExtSelectInputReq);
  791. REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
  792. VncInputSelect** nextPtr = &vncInputSelectHead;
  793. VncInputSelect* cur;
  794. for (cur = vncInputSelectHead; cur; cur = *nextPtr) {
  795. if (cur->client == client && cur->window == stuff->window) {
  796. cur->mask = stuff->mask;
  797. if (!cur->mask) {
  798. *nextPtr = cur->next;
  799. delete cur;
  800. }
  801. break;
  802. }
  803. nextPtr = &cur->next;
  804. }
  805. if (!cur) {
  806. cur = new VncInputSelect(client, stuff->window, stuff->mask);
  807. }
  808. return (client->noClientException);
  809. }
  810. static int SProcVncExtSelectInput(ClientPtr client)
  811. {
  812. REQUEST(xVncExtSelectInputReq);
  813. #if XORG < 112
  814. register char n;
  815. swaps(&stuff->length, n);
  816. #else
  817. swaps(&stuff->length);
  818. #endif
  819. REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
  820. #if XORG < 112
  821. swapl(&stuff->window, n);
  822. swapl(&stuff->mask, n);
  823. #else
  824. swapl(&stuff->window);
  825. swapl(&stuff->mask);
  826. #endif
  827. return ProcVncExtSelectInput(client);
  828. }
  829. static int ProcVncExtConnect(ClientPtr client)
  830. {
  831. REQUEST(xVncExtConnectReq);
  832. REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen);
  833. CharArray str(stuff->strLen+1);
  834. strncpy(str.buf, (char*)&stuff[1], stuff->strLen);
  835. str.buf[stuff->strLen] = 0;
  836. xVncExtConnectReply rep;
  837. rep.success = 0;
  838. if (desktop[0]) {
  839. if (stuff->strLen == 0) {
  840. try {
  841. desktop[0]->disconnectClients();
  842. rep.success = 1;
  843. } catch (rdr::Exception& e) {
  844. vlog.error("Disconnecting all clients: %s",e.str());
  845. }
  846. } else {
  847. int port = 5500;
  848. for (int i = 0; i < stuff->strLen; i++) {
  849. if (str.buf[i] == ':') {
  850. port = atoi(&str.buf[i+1]);
  851. str.buf[i] = 0;
  852. break;
  853. }
  854. }
  855. try {
  856. network::Socket* sock = new network::TcpSocket(str.buf, port);
  857. desktop[0]->addClient(sock, true);
  858. rep.success = 1;
  859. } catch (rdr::Exception& e) {
  860. vlog.error("Reverse connection: %s",e.str());
  861. }
  862. }
  863. }
  864. rep.type = X_Reply;
  865. rep.length = 0;
  866. rep.sequenceNumber = client->sequence;
  867. if (client->swapped) {
  868. #if XORG < 112
  869. int n;
  870. swaps(&rep.sequenceNumber, n);
  871. swapl(&rep.length, n);
  872. #else
  873. swaps(&rep.sequenceNumber);
  874. swapl(&rep.length);
  875. #endif
  876. }
  877. WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep);
  878. return (client->noClientException);
  879. }
  880. static int SProcVncExtConnect(ClientPtr client)
  881. {
  882. REQUEST(xVncExtConnectReq);
  883. #if XORG < 112
  884. register char n;
  885. swaps(&stuff->length, n);
  886. #else
  887. swaps(&stuff->length);
  888. #endif
  889. REQUEST_AT_LEAST_SIZE(xVncExtConnectReq);
  890. return ProcVncExtConnect(client);
  891. }
  892. static int ProcVncExtGetQueryConnect(ClientPtr client)
  893. {
  894. REQUEST(xVncExtGetQueryConnectReq);
  895. REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
  896. const char *qcAddress=0, *qcUsername=0;
  897. int qcTimeout;
  898. if (queryConnectDesktop)
  899. qcTimeout = queryConnectDesktop->getQueryTimeout(queryConnectId,
  900. &qcAddress, &qcUsername);
  901. else
  902. qcTimeout = 0;
  903. xVncExtGetQueryConnectReply rep;
  904. rep.type = X_Reply;
  905. rep.sequenceNumber = client->sequence;
  906. rep.timeout = qcTimeout;
  907. rep.addrLen = qcTimeout ? strlen(qcAddress) : 0;
  908. rep.userLen = qcTimeout ? strlen(qcUsername) : 0;
  909. rep.opaqueId = (CARD32)(long)queryConnectId;
  910. rep.length = (rep.userLen + rep.addrLen + 3) >> 2;
  911. if (client->swapped) {
  912. #if XORG < 112
  913. int n;
  914. swaps(&rep.sequenceNumber, n);
  915. swapl(&rep.userLen, n);
  916. swapl(&rep.addrLen, n);
  917. swapl(&rep.timeout, n);
  918. swapl(&rep.opaqueId, n);
  919. #else
  920. swaps(&rep.sequenceNumber);
  921. swapl(&rep.userLen);
  922. swapl(&rep.addrLen);
  923. swapl(&rep.timeout);
  924. swapl(&rep.opaqueId);
  925. #endif
  926. }
  927. WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep);
  928. if (qcTimeout)
  929. WriteToClient(client, strlen(qcAddress), (char*)qcAddress);
  930. if (qcTimeout)
  931. WriteToClient(client, strlen(qcUsername), (char*)qcUsername);
  932. return (client->noClientException);
  933. }
  934. static int SProcVncExtGetQueryConnect(ClientPtr client)
  935. {
  936. REQUEST(xVncExtGetQueryConnectReq);
  937. #if XORG < 112
  938. register char n;
  939. swaps(&stuff->length, n);
  940. #else
  941. swaps(&stuff->length);
  942. #endif
  943. REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
  944. return ProcVncExtGetQueryConnect(client);
  945. }
  946. static int ProcVncExtApproveConnect(ClientPtr client)
  947. {
  948. REQUEST(xVncExtApproveConnectReq);
  949. REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
  950. if (queryConnectId == (void*)stuff->opaqueId) {
  951. for (int scr = 0; scr < screenInfo.numScreens; scr++) {
  952. if (desktop[scr]) {
  953. desktop[scr]->approveConnection(queryConnectId, stuff->approve,
  954. "Connection rejected by local user");
  955. }
  956. }
  957. // Inform other clients of the event and tidy up
  958. vncQueryConnect(queryConnectDesktop, queryConnectId);
  959. }
  960. return (client->noClientException);
  961. }
  962. static int SProcVncExtApproveConnect(ClientPtr client)
  963. {
  964. REQUEST(xVncExtApproveConnectReq);
  965. #if XORG < 112
  966. register char n;
  967. swaps(&stuff->length, n);
  968. swapl(&stuff->opaqueId, n);
  969. #else
  970. swaps(&stuff->length);
  971. swapl(&stuff->opaqueId);
  972. #endif
  973. REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
  974. return ProcVncExtApproveConnect(client);
  975. }
  976. static int ProcVncExtDispatch(ClientPtr client)
  977. {
  978. REQUEST(xReq);
  979. switch (stuff->data) {
  980. case X_VncExtSetParam:
  981. return ProcVncExtSetParam(client);
  982. case X_VncExtGetParam:
  983. return ProcVncExtGetParam(client);
  984. case X_VncExtGetParamDesc:
  985. return ProcVncExtGetParamDesc(client);
  986. case X_VncExtListParams:
  987. return ProcVncExtListParams(client);
  988. case X_VncExtSetServerCutText:
  989. return ProcVncExtSetServerCutText(client);
  990. case X_VncExtGetClientCutText:
  991. return ProcVncExtGetClientCutText(client);
  992. case X_VncExtSelectInput:
  993. return ProcVncExtSelectInput(client);
  994. case X_VncExtConnect:
  995. return ProcVncExtConnect(client);
  996. case X_VncExtGetQueryConnect:
  997. return ProcVncExtGetQueryConnect(client);
  998. case X_VncExtApproveConnect:
  999. return ProcVncExtApproveConnect(client);
  1000. default:
  1001. return BadRequest;
  1002. }
  1003. }
  1004. static int SProcVncExtDispatch(ClientPtr client)
  1005. {
  1006. REQUEST(xReq);
  1007. switch (stuff->data) {
  1008. case X_VncExtSetParam:
  1009. return SProcVncExtSetParam(client);
  1010. case X_VncExtGetParam:
  1011. return SProcVncExtGetParam(client);
  1012. case X_VncExtGetParamDesc:
  1013. return SProcVncExtGetParamDesc(client);
  1014. case X_VncExtListParams:
  1015. return SProcVncExtListParams(client);
  1016. case X_VncExtSetServerCutText:
  1017. return SProcVncExtSetServerCutText(client);
  1018. case X_VncExtGetClientCutText:
  1019. return SProcVncExtGetClientCutText(client);
  1020. case X_VncExtSelectInput:
  1021. return SProcVncExtSelectInput(client);
  1022. case X_VncExtConnect:
  1023. return SProcVncExtConnect(client);
  1024. case X_VncExtGetQueryConnect:
  1025. return SProcVncExtGetQueryConnect(client);
  1026. case X_VncExtApproveConnect:
  1027. return SProcVncExtApproveConnect(client);
  1028. default:
  1029. return BadRequest;
  1030. }
  1031. }