1 /*
2 * x11vnc: a VNC server for X displays.
3 *
4 * Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
5 * All rights reserved.
6 *
7 * This file is part of x11vnc.
8 *
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this software; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22 * USA or see <http://www.gnu.org/licenses/>.
23 *
24 * In addition, as a special exception, Karl J. Runge
25 * gives permission to link the code of its release of x11vnc with the
26 * OpenSSL project's "OpenSSL" library (or with modified versions of it
27 * that use the same license as the "OpenSSL" library), and distribute
28 * the linked executables. You must obey the GNU General Public License
29 * in all respects for all of the code used other than "OpenSSL". If you
30 * modify this file, you may extend this exception to your version of the
31 * file, but you are not obligated to do so. If you do not wish to do
32 * so, delete this exception statement from your version.
33 */
34
35 /*
36 * This program is based on some ideas from the following programs:
37 *
38 * the initial x11vnc.c in libvncserver (Johannes E. Schindelin)
39 * x0rfbserver, the original native X vnc server (Jens Wagner)
40 * krfb, the KDE desktopsharing project (Tim Jansen)
41 *
42 * Please see http://www.karlrunge.com/x11vnc for the most up-to-date
43 * information about x11vnc. Some of the following text may be out
44 * of date.
45 *
46 * The primary goal of this program is to create a portable and simple
47 * command-line server utility that allows a VNC viewer to connect
48 * to an actual X display (as the above do). The only non-standard
49 * dependency of this program is the static library libvncserver.a.
50 * Although in some environments libjpeg.so or libz.so may not be
51 * readily available and needs to be installed, they may be found
52 * at ftp://ftp.uu.net/graphics/jpeg/ and http://www.gzip.org/zlib/,
53 * respectively. To increase portability it is written in plain C.
54 *
55 * Another goal is to improve performance and interactive response.
56 * The algorithm of x0rfbserver was used as a base. Many additional
57 * heuristics are also applied.
58 *
59 * Another goal is to add many features that enable and incourage creative
60 * usage and application of the tool. Apologies for the large number
61 * of options!
62 *
63 * To build:
64 *
65 * Obtain the libvncserver package (http://libvncserver.sourceforge.net).
66 * As of 12/2002 this version of x11vnc.c is contained in the libvncserver
67 * CVS tree and released in version 0.5.
68 *
69 * gcc should be used on all platforms. To build a threaded version put
70 * "-D_REENTRANT -DX11VNC_THREADED" in the environment variable CFLAGS
71 * or CPPFLAGS (e.g. before running the libvncserver configure). The
72 * threaded mode is a bit more responsive, but can be unstable (e.g.
73 * if more than one client the same tight or zrle encoding).
74 *
75 * Known shortcomings:
76 *
77 * The screen updates are good, but of course not perfect since the X
78 * display must be continuously polled and read for changes and this is
79 * slow for most hardware. This can be contrasted with receiving a change
80 * callback from the X server, if that were generally possible... (UPDATE:
81 * this is handled now with the X DAMAGE extension, but unfortunately
82 * that doesn't seem to address the slow read from the video h/w). So,
83 * e.g., opaque moves and similar window activity can be very painful;
84 * one has to modify one's behavior a bit.
85 *
86 * General audio at the remote display is lost unless one separately
87 * sets up some audio side-channel such as esd.
88 *
89 * It does not appear possible to query the X server for the current
90 * cursor shape. We can use XTest to compare cursor to current window's
91 * cursor, but we cannot extract what the cursor is... (UPDATE: we now
92 * use XFIXES extension for this. Also on Solaris and IRIX Overlay
93 * extensions exists that allow drawing the mouse into the framebuffer)
94 *
95 * The current *position* of the remote X mouse pointer is shown with
96 * the -cursor option. Further, if -cursor X is used, a trick
97 * is done to at least show the root window cursor vs non-root cursor.
98 * (perhaps some heuristic can be done to further distinguish cases...,
99 * currently "-cursor some" is a first hack at this)
100 *
101 * Under XFIXES mode for showing the cursor shape, the cursor may be
102 * poorly approximated if it has transparency (alpha channel).
103 *
104 * Windows using visuals other than the default X visual may have
105 * their colors messed up. When using 8bpp indexed color, the colormap
106 * is attempted to be followed, but may become out of date. Use the
107 * -flashcmap option to have colormap flashing as the pointer moves
108 * windows with private colormaps (slow). Displays with mixed depth 8 and
109 * 24 visuals will incorrectly display windows using the non-default one.
110 * On Sun and Sgi hardware we can to work around this with -overlay.
111 *
112 * Feature -id <windowid> can be picky: it can crash for things like
113 * the window not sufficiently mapped into server memory, etc (UPDATE:
114 * we now use the -xrandr mechanisms to trap errors more robustly for
115 * this mode). SaveUnders menus, popups, etc will not be seen.
116 *
117 * Under some situations the keysym unmapping is not correct, especially
118 * if the two keyboards correspond to different languages. The -modtweak
119 * option is the default and corrects most problems. One can use the
120 * -xkb option to try to use the XKEYBOARD extension to clear up any
121 * remaining problems.
122 *
123 * Occasionally, a few tile updates can be missed leaving a patch of
124 * color that needs to be refreshed. This may only be when threaded,
125 * which is no longer the default.
126 *
127 * There seems to be a serious bug with simultaneous clients when
128 * threaded, currently the only workaround in this case is -nothreads
129 * (which is now the default).
130 */
131
132
133 /* -- x11vnc.c -- */
134
135 #include "x11vnc.h"
136 #include "xwrappers.h"
137 #include "xdamage.h"
138 #include "xrecord.h"
139 #include "xevents.h"
140 #include "xinerama.h"
141 #include "xrandr.h"
142 #include "xkb_bell.h"
143 #include "win_utils.h"
144 #include "remote.h"
145 #include "scan.h"
146 #include "gui.h"
147 #include "help.h"
148 #include "user.h"
149 #include "cleanup.h"
150 #include "keyboard.h"
151 #include "pointer.h"
152 #include "cursor.h"
153 #include "userinput.h"
154 #include "screen.h"
155 #include "connections.h"
156 #include "rates.h"
157 #include "unixpw.h"
158 #include "inet.h"
159 #include "sslcmds.h"
160 #include "sslhelper.h"
161 #include "selection.h"
162 #include "pm.h"
163 #include "solid.h"
164
165 /*
166 * main routine for the x11vnc program
167 */
168 void watch_loop(void);
169
170 static int limit_shm(void);
171 static void check_rcfile(int argc, char **argv);
172 static void immediate_switch_user(int argc, char* argv[]);
173 static void print_settings(int try_http, int bg, char *gui_str);
174 static void check_loop_mode(int argc, char* argv[], int force);
175 static void check_appshare_mode(int argc, char* argv[]);
176
177 static int tsdo_timeout_flag;
178
tsdo_timeout(int sig)179 static void tsdo_timeout (int sig) {
180 tsdo_timeout_flag = 1;
181 if (sig) {};
182 }
183
184 #define TASKMAX 32
185 static pid_t ts_tasks[TASKMAX];
186 static int ts_taskn = -1;
187
tsdo(int port,int lsock,int * conn)188 int tsdo(int port, int lsock, int *conn) {
189 int csock, rsock, i, db = 1;
190 pid_t pid;
191 struct sockaddr_in addr;
192 #ifdef __hpux
193 int addrlen = sizeof(addr);
194 #else
195 socklen_t addrlen = sizeof(addr);
196 #endif
197
198 if (*conn < 0) {
199 signal(SIGALRM, tsdo_timeout);
200 tsdo_timeout_flag = 0;
201
202 alarm(10);
203 csock = accept(lsock, (struct sockaddr *)&addr, &addrlen);
204 alarm(0);
205
206 if (db) rfbLog("tsdo: accept: lsock: %d, csock: %d, port: %d\n", lsock, csock, port);
207
208 if (tsdo_timeout_flag > 0 || csock < 0) {
209 close(csock);
210 *conn = -1;
211 return 1;
212 }
213 *conn = csock;
214 } else {
215 csock = *conn;
216 if (db) rfbLog("tsdo: using existing csock: %d, port: %d\n", csock, port);
217 }
218
219 rsock = connect_tcp("127.0.0.1", port);
220 if (rsock < 0) {
221 if (db) rfbLog("tsdo: connect_tcp(port=%d) failed.\n", port);
222 close(csock);
223 return 2;
224 }
225
226 pid = fork();
227 if (pid < 0) {
228 close(csock);
229 close(rsock);
230 return 3;
231 }
232 if (pid > 0) {
233 ts_taskn = (ts_taskn+1) % TASKMAX;
234 ts_tasks[ts_taskn] = pid;
235 close(csock);
236 close(rsock);
237 *conn = -1;
238 return 0;
239 }
240 if (pid == 0) {
241 for (i=0; i<255; i++) {
242 if (i != csock && i != rsock && i != 2) {
243 close(i);
244 }
245 }
246 #if LIBVNCSERVER_HAVE_SETSID
247 if (setsid() == -1) {
248 perror("setsid");
249 close(csock);
250 close(rsock);
251 exit(1);
252 }
253 #else
254 if (setpgrp() == -1) {
255 perror("setpgrp");
256 close(csock);
257 close(rsock);
258 exit(1);
259 }
260 #endif /* SETSID */
261 raw_xfer(rsock, csock, csock);
262 close(csock);
263 close(rsock);
264 exit(0);
265 }
266 return 0;
267 }
268
269 void set_redir_properties(void);
270
271 #define TSMAX 32
272 #define TSSTK 16
273
terminal_services(char * list)274 void terminal_services(char *list) {
275 int i, j, n, db = 1;
276 char *p, *q, *r, *str;
277 #if !NO_X11
278 char *tag[TSMAX];
279 int listen[TSMAX], redir[TSMAX][TSSTK], socks[TSMAX], tstk[TSSTK];
280 double rate_start;
281 int rate_count;
282 Atom at, atom[TSMAX];
283 fd_set rd;
284 Window rwin;
285 XErrorHandler old_handler1;
286 XIOErrorHandler old_handler2;
287 char num[32];
288 time_t last_clean = time(NULL);
289
290 if (getenv("TS_REDIR_DEBUG")) {
291 db = 2;
292 }
293
294 if (! dpy) {
295 return;
296 }
297
298 rwin = RootWindow(dpy, DefaultScreen(dpy));
299
300 at = XInternAtom(dpy, "TS_REDIR_LIST", False);
301 if (at != None) {
302 XChangeProperty(dpy, rwin, at, XA_STRING, 8,
303 PropModeReplace, (unsigned char *)list, strlen(list));
304 XSync(dpy, False);
305 }
306 if (db) fprintf(stderr, "TS_REDIR_LIST Atom: %d.\n", (int) at);
307
308 oh_restart_it_all:
309
310 for (i=0; i<TASKMAX; i++) {
311 ts_tasks[i] = 0;
312 }
313 for (i=0; i<TSMAX; i++) {
314 socks[i] = -1;
315 listen[i] = -1;
316 for (j=0; j<TSSTK; j++) {
317 redir[i][j] = 0;
318 }
319 }
320
321 rate_start = 0.0;
322 rate_count = 0;
323
324 n = 0;
325 str = strdup(list);
326 p = strtok(str, ",");
327 while (p) {
328 int m1, m2;
329 if (db) fprintf(stderr, "item: %s\n", p);
330 q = strrchr(p, ':');
331 if (!q) {
332 p = strtok(NULL, ",");
333 continue;
334 }
335 r = strchr(p, ':');
336 if (!r || r == q) {
337 p = strtok(NULL, ",");
338 continue;
339 }
340
341 m1 = atoi(q+1);
342 *q = '\0';
343 m2 = atoi(r+1);
344 *r = '\0';
345
346 if (m1 <= 0 || m2 <= 0 || m1 >= 0xffff || m2 >= 0xffff) {
347 p = strtok(NULL, ",");
348 continue;
349 }
350
351 redir[n][0] = m1;
352 listen[n] = m2;
353 tag[n] = strdup(p);
354
355 if (db) fprintf(stderr, " %d %d %s\n", redir[n][0], listen[n], tag[n]);
356
357 *r = ':';
358 *q = ':';
359
360 n++;
361 if (n >= TSMAX) {
362 break;
363 }
364 p = strtok(NULL, ",");
365 }
366 free(str);
367
368 if (n==0) {
369 return;
370 }
371
372 at = XInternAtom(dpy, "TS_REDIR_PID", False);
373 if (at != None) {
374 sprintf(num, "%d", getpid());
375 XChangeProperty(dpy, rwin, at, XA_STRING, 8,
376 PropModeReplace, (unsigned char *)num, strlen(num));
377 XSync(dpy, False);
378 }
379
380 for (i=0; i<n; i++) {
381 int k;
382 atom[i] = XInternAtom(dpy, tag[i], False);
383 if (db) fprintf(stderr, "tag: %s atom: %d\n", tag[i], (int) atom[i]);
384 if (atom[i] == None) {
385 continue;
386 }
387 sprintf(num, "%d", redir[i][0]);
388 if (db) fprintf(stderr, " listen: %d redir: %s\n", listen[i], num);
389 XChangeProperty(dpy, rwin, atom[i], XA_STRING, 8,
390 PropModeReplace, (unsigned char *)num, strlen(num));
391 XSync(dpy, False);
392
393 for (k=1; k <= 5; k++) {
394 /* XXX ::1 fallback? */
395 socks[i] = listen_tcp(listen[i], htonl(INADDR_LOOPBACK), 1);
396 if (socks[i] >= 0) {
397 if (db) fprintf(stderr, " listen succeeded: %d\n", listen[i]);
398 break;
399 }
400 if (db) fprintf(stderr, " listen failed***: %d\n", listen[i]);
401 usleep(k * 2000*1000);
402 }
403 }
404
405 if (getenv("TSD_RESTART")) {
406 if (!strcmp(getenv("TSD_RESTART"), "1")) {
407 set_redir_properties();
408 }
409 }
410
411 while (1) {
412 struct timeval tv;
413 int nfd;
414 int fmax = -1;
415
416 tv.tv_sec = 3;
417 tv.tv_usec = 0;
418
419 FD_ZERO(&rd);
420 for (i=0; i<n; i++) {
421 if (socks[i] >= 0) {
422 FD_SET(socks[i], &rd);
423 if (socks[i] > fmax) {
424 fmax = socks[i];
425 }
426 }
427 }
428
429 nfd = select(fmax+1, &rd, NULL, NULL, &tv);
430
431 if (db && 0) fprintf(stderr, "nfd=%d\n", nfd);
432 if (nfd < 0 && errno == EINTR) {
433 XSync(dpy, True);
434 continue;
435 }
436 if (nfd > 0) {
437 int did_ts = 0;
438 for(i=0; i<n; i++) {
439 int k = 0;
440 for (j = 0; j < TSSTK; j++) {
441 tstk[j] = 0;
442 }
443 for (j = 0; j < TSSTK; j++) {
444 if (redir[i][j] != 0) {
445 tstk[k++] = redir[i][j];
446 }
447 }
448 for (j = 0; j < TSSTK; j++) {
449 redir[i][j] = tstk[j];
450 if (tstk[j] != 0) fprintf(stderr, "B redir[%d][%d] = %d %s\n", i, j, tstk[j], tag[i]);
451 }
452 }
453 for(i=0; i<n; i++) {
454 int s = socks[i];
455 if (s < 0) {
456 continue;
457 }
458 if (FD_ISSET(s, &rd)) {
459 int p0, p, found = -1, jzero = -1;
460 int conn = -1;
461
462 get_prop(num, 32, atom[i], None);
463 p0 = atoi(num);
464
465 for (j = TSSTK-1; j >= 0; j--) {
466 if (redir[i][j] == 0) {
467 jzero = j;
468 continue;
469 }
470 if (p0 > 0 && p0 < 0xffff) {
471 if (redir[i][j] == p0) {
472 found = j;
473 break;
474 }
475 }
476 }
477 if (jzero < 0) {
478 jzero = TSSTK-1;
479 }
480 if (found < 0) {
481 if (p0 > 0 && p0 < 0xffff) {
482 redir[i][jzero] = p0;
483 }
484 }
485 for (j = TSSTK-1; j >= 0; j--) {
486 int rc;
487 p = redir[i][j];
488 if (p <= 0 || p >= 0xffff) {
489 redir[i][j] = 0;
490 continue;
491 }
492
493 if (dnow() > rate_start + 10.0) {
494 rate_start = dnow();
495 rate_count = 0;
496 }
497 rate_count++;
498
499 rc = tsdo(p, s, &conn);
500 did_ts++;
501
502 if (rc == 0) {
503 /* AOK */
504 if (db) fprintf(stderr, "tsdo[%d] OK: %d\n", i, p);
505 if (p != p0) {
506 sprintf(num, "%d", p);
507 XChangeProperty(dpy, rwin, atom[i], XA_STRING, 8,
508 PropModeReplace, (unsigned char *)num, strlen(num));
509 XSync(dpy, False);
510 }
511 break;
512 } else if (rc == 1) {
513 /* accept failed */
514 if (db) fprintf(stderr, "tsdo[%d] accept failed: %d, sleep 50ms\n", i, p);
515 usleep(50*1000);
516 break;
517 } else if (rc == 2) {
518 /* connect failed */
519 if (db) fprintf(stderr, "tsdo[%d] connect failed: %d, sleep 50ms rate: %d/10s\n", i, p, rate_count);
520 redir[i][j] = 0;
521 usleep(50*1000);
522 continue;
523 } else if (rc == 3) {
524 /* fork failed */
525 usleep(500*1000);
526 break;
527 }
528 }
529 for (j = 0; j < TSSTK; j++) {
530 if (redir[i][j] != 0) fprintf(stderr, "A redir[%d][%d] = %d %s\n", i, j, redir[i][j], tag[i]);
531 }
532 }
533 }
534 if (did_ts && rate_count > 100) {
535 int db_netstat = 1;
536 char dcmd[100];
537
538 if (no_external_cmds) {
539 db_netstat = 0;
540 }
541
542 rfbLog("terminal_services: throttling high connect rate %d/10s\n", rate_count);
543 usleep(2*1000*1000);
544 rfbLog("terminal_services: stopping ts services.\n");
545 for(i=0; i<n; i++) {
546 int s = socks[i];
547 if (s < 0) {
548 continue;
549 }
550 rfbLog("terminal_services: closing listen=%d sock=%d.\n", listen[i], socks[i]);
551 if (listen[i] >= 0 && db_netstat) {
552 sprintf(dcmd, "netstat -an | grep -w '%d'", listen[i]);
553 fprintf(stderr, "#1 %s\n", dcmd);
554 system(dcmd);
555 }
556 close(s);
557 socks[i] = -1;
558 usleep(2*1000*1000);
559 if (listen[i] >= 0 && db_netstat) {
560 fprintf(stderr, "#2 %s\n", dcmd);
561 system(dcmd);
562 }
563 }
564 usleep(10*1000*1000);
565
566 rfbLog("terminal_services: restarting ts services\n");
567 goto oh_restart_it_all;
568 }
569 }
570 for (i=0; i<TASKMAX; i++) {
571 pid_t p = ts_tasks[i];
572 if (p > 0) {
573 int status;
574 pid_t p2 = waitpid(p, &status, WNOHANG);
575 if (p2 == p) {
576 ts_tasks[i] = 0;
577 }
578 }
579 }
580 /* this is to drop events and exit when X server is gone. */
581 old_handler1 = XSetErrorHandler(trap_xerror);
582 old_handler2 = XSetIOErrorHandler(trap_xioerror);
583 trapped_xerror = 0;
584 trapped_xioerror = 0;
585
586 XSync(dpy, True);
587
588 sprintf(num, "%d", (int) time(NULL));
589 at = XInternAtom(dpy, "TS_REDIR", False);
590 if (at != None) {
591 XChangeProperty(dpy, rwin, at, XA_STRING, 8,
592 PropModeReplace, (unsigned char *)num, strlen(num));
593 XSync(dpy, False);
594 }
595 if (time(NULL) > last_clean + 20 * 60) {
596 int i, j;
597 for(i=0; i<n; i++) {
598 int first = 1;
599 for (j = TSSTK-1; j >= 0; j--) {
600 int s, p = redir[i][j];
601 if (p <= 0 || p >= 0xffff) {
602 redir[i][j] = 0;
603 continue;
604 }
605 s = connect_tcp("127.0.0.1", p);
606 if (s < 0) {
607 redir[i][j] = 0;
608 if (db) fprintf(stderr, "tsdo[%d][%d] clean: connect failed: %d\n", i, j, p);
609 } else {
610 close(s);
611 if (first) {
612 sprintf(num, "%d", p);
613 XChangeProperty(dpy, rwin, atom[i], XA_STRING, 8,
614 PropModeReplace, (unsigned char *)num, strlen(num));
615 XSync(dpy, False);
616 }
617 first = 0;
618 }
619 usleep(500*1000);
620 }
621 }
622 last_clean = time(NULL);
623 }
624 if (trapped_xerror || trapped_xioerror) {
625 if (db) fprintf(stderr, "Xerror: %d/%d\n", trapped_xerror, trapped_xioerror);
626 exit(0);
627 }
628 XSetErrorHandler(old_handler1);
629 XSetIOErrorHandler(old_handler2);
630 }
631 #endif
632 }
633
634 char *ts_services[][2] = {
635 {"FD_CUPS", "TS_CUPS_REDIR"},
636 {"FD_SMB", "TS_SMB_REDIR"},
637 {"FD_ESD", "TS_ESD_REDIR"},
638 {"FD_NAS", "TS_NAS_REDIR"},
639 {NULL, NULL}
640 };
641
do_tsd(void)642 void do_tsd(void) {
643 #if !NO_X11
644 Atom a;
645 char prop[513];
646 pid_t pid;
647 char *cmd;
648 int n, sz = 0;
649 char *disp = DisplayString(dpy);
650 char *logfile = getenv("TS_REDIR_LOGFILE");
651 int db = 0;
652
653 if (getenv("TS_REDIR_DEBUG")) {
654 db = 1;
655 }
656 if (db) fprintf(stderr, "do_tsd() in.\n");
657
658 prop[0] = '\0';
659 a = XInternAtom(dpy, "TS_REDIR_LIST", False);
660 if (a != None) {
661 get_prop(prop, 512, a, None);
662 }
663 if (db) fprintf(stderr, "TS_REDIR_LIST Atom: %d = '%s'\n", (int) a, prop);
664
665 if (prop[0] == '\0') {
666 return;
667 }
668
669 if (! program_name) {
670 program_name = "x11vnc";
671 }
672 sz += strlen(program_name) + 1;
673 sz += strlen("-display") + 1;
674 sz += strlen(disp) + 1;
675 sz += strlen("-tsd") + 1;
676 sz += 1 + strlen(prop) + 1 + 1;
677 sz += strlen("-env TSD_RESTART=1") + 1;
678 sz += strlen("</dev/null 1>/dev/null 2>&1") + 1;
679 sz += strlen(" &") + 1;
680 if (logfile) {
681 sz += strlen(logfile);
682 }
683 if (ipv6_listen) {
684 sz += strlen("-6") + 1;
685 }
686
687 cmd = (char *) malloc(sz);
688
689 if (getenv("XAUTHORITY")) {
690 char *xauth = getenv("XAUTHORITY");
691 if (!strcmp(xauth, "") || access(xauth, R_OK) != 0) {
692 *(xauth-2) = '_'; /* yow */
693 }
694 }
695 sprintf(cmd, "%s -display %s -tsd '%s' -env TSD_RESTART=1 %s </dev/null 1>%s 2>&1 &",
696 program_name, disp, prop, ipv6_listen ? "-6" : "",
697 logfile ? logfile : "/dev/null" );
698 rfbLog("running: %s\n", cmd);
699
700 #if LIBVNCSERVER_HAVE_FORK && LIBVNCSERVER_HAVE_SETSID
701 /* fork into the background now */
702 if ((pid = fork()) > 0) {
703 pid_t pidw;
704 int status;
705 double s = dnow();
706
707 while (dnow() < s + 1.5) {
708 pidw = waitpid(pid, &status, WNOHANG);
709 if (pidw == pid) {
710 break;
711 }
712 usleep(100*1000);
713 }
714 return;
715
716 } else if (pid == -1) {
717 system(cmd);
718 } else {
719 setsid();
720 /* adjust our stdio */
721 n = open("/dev/null", O_RDONLY);
722 dup2(n, 0);
723 dup2(n, 1);
724 dup2(n, 2);
725 if (n > 2) {
726 close(n);
727 }
728 system(cmd);
729 exit(0);
730 }
731 #else
732 system(cmd);
733 #endif
734
735 #endif
736 }
737
set_redir_properties(void)738 void set_redir_properties(void) {
739 #if !NO_X11
740 char *e, *f, *t;
741 Atom a;
742 char num[32];
743 int i, p;
744
745 if (! dpy) {
746 return;
747 }
748
749 i = 0;
750 while (ts_services[i][0] != NULL) {
751 f = ts_services[i][0];
752 t = ts_services[i][1];
753 e = getenv(f);
754 if (!e || strstr(e, "DAEMON-") != e) {
755 i++;
756 continue;
757 }
758 p = atoi(e + strlen("DAEMON-"));
759 if (p <= 0) {
760 i++;
761 continue;
762 }
763 sprintf(num, "%d", p);
764 a = XInternAtom(dpy, t, False);
765 if (a != None) {
766 Window rwin = RootWindow(dpy, DefaultScreen(dpy));
767 fprintf(stderr, "Set: %s %s %s -> %s\n", f, t, e, num);
768 XChangeProperty(dpy, rwin, a, XA_STRING, 8,
769 PropModeReplace, (unsigned char *) num, strlen(num));
770 XSync(dpy, False);
771 }
772 i++;
773 }
774 #endif
775 }
776
check_redir_services(void)777 static void check_redir_services(void) {
778 #if !NO_X11
779 Atom a;
780 char prop[513];
781 time_t tsd_last;
782 int restart = 0;
783 pid_t pid = 0;
784 int db = 0;
785 db = 0;
786
787 if (getenv("TS_REDIR_DEBUG")) {
788 db = 1;
789 }
790 if (db) fprintf(stderr, "check_redir_services in.\n");
791
792 if (! dpy) {
793 return;
794 }
795
796 a = XInternAtom(dpy, "TS_REDIR_PID", False);
797 if (a != None) {
798 prop[0] = '\0';
799 get_prop(prop, 512, a, None);
800 if (prop[0] != '\0') {
801 pid = (pid_t) atoi(prop);
802 }
803 }
804 if (db) fprintf(stderr, "TS_REDIR_PID Atom: %d = '%s'\n", (int) a, prop);
805
806 if (getenv("FD_TAG") && strcmp(getenv("FD_TAG"), "")) {
807 a = XInternAtom(dpy, "FD_TAG", False);
808 if (a != None) {
809 Window rwin = RootWindow(dpy, DefaultScreen(dpy));
810 char *tag = getenv("FD_TAG");
811 XChangeProperty(dpy, rwin, a, XA_STRING, 8,
812 PropModeReplace, (unsigned char *)tag, strlen(tag));
813 XSync(dpy, False);
814 }
815 if (db) fprintf(stderr, "FD_TAG Atom: %d = '%s'\n", (int) a, prop);
816 }
817
818 prop[0] = '\0';
819 a = XInternAtom(dpy, "TS_REDIR", False);
820 if (a != None) {
821 get_prop(prop, 512, a, None);
822 }
823 if (db) fprintf(stderr, "TS_REDIR Atom: %d = '%s'\n", (int) a, prop);
824 if (prop[0] == '\0') {
825 rfbLog("TS_REDIR is empty, restarting...\n");
826 restart = 1;
827 } else {
828 tsd_last = (time_t) atoi(prop);
829 if (time(NULL) > tsd_last + 30) {
830 rfbLog("TS_REDIR seems dead for: %d sec, restarting...\n",
831 time(NULL) - tsd_last);
832 restart = 1;
833 } else if (pid > 0 && time(NULL) > tsd_last + 6) {
834 if (kill(pid, 0) != 0) {
835 rfbLog("TS_REDIR seems dead via kill(%d, 0), restarting...\n",
836 pid);
837 restart = 1;
838 }
839 }
840 }
841 if (restart) {
842
843 if (pid > 1) {
844 rfbLog("killing TS_REDIR_PID: %d\n", pid);
845 kill(pid, SIGTERM);
846 usleep(500*1000);
847 kill(pid, SIGKILL);
848 }
849 do_tsd();
850 if (db) fprintf(stderr, "check_redir_services restarted.\n");
851 return;
852 }
853
854 if (db) fprintf(stderr, "check_redir_services, no restart, calling set_redir_properties.\n");
855 set_redir_properties();
856 #endif
857 }
858
ssh_remote_tunnel(char * instr,int lport)859 void ssh_remote_tunnel(char *instr, int lport) {
860 char *q, *cmd, *ssh;
861 char *s = strdup(instr);
862 int sleep = 300, disp = 0, sport = 0;
863 int rc, len, rport;
864
865 /* user@host:port:disp+secs */
866
867 /* +sleep */
868 q = strrchr(s, '+');
869 if (q) {
870 sleep = atoi(q+1);
871 if (sleep <= 0) {
872 sleep = 1;
873 }
874 *q = '\0';
875 }
876 /* :disp */
877 q = strrchr(s, ':');
878 if (q) {
879 disp = atoi(q+1);
880 *q = '\0';
881 }
882
883 /* :sshport */
884 q = strrchr(s, ':');
885 if (q) {
886 sport = atoi(q+1);
887 *q = '\0';
888 }
889
890 if (getenv("SSH")) {
891 ssh = getenv("SSH");
892 } else {
893 ssh = "ssh";
894 }
895
896 len = 0;
897 len += strlen(ssh) + strlen(s) + 500;
898 cmd = (char *) malloc(len);
899
900 if (disp >= 0 && disp <= 200) {
901 rport = disp + 5900;
902 } else if (disp < 0) {
903 rport = -disp;
904 } else {
905 rport = disp;
906 }
907
908 if (sport > 0) {
909 sprintf(cmd, "%s -f -p %d -R '%d:localhost:%d' '%s' 'sleep %d'", ssh, sport, rport, lport, s, sleep);
910 } else {
911 sprintf(cmd, "%s -f -R '%d:localhost:%d' '%s' 'sleep %d'", ssh, rport, lport, s, sleep);
912 }
913
914 if (no_external_cmds || !cmd_ok("ssh")) {
915 rfbLogEnable(1);
916 rfbLog("cannot run external commands in -nocmds mode:\n");
917 rfbLog(" \"%s\"\n", cmd);
918 rfbLog(" exiting.\n");
919 clean_up_exit(1);
920 }
921
922 close_exec_fds();
923 fprintf(stderr, "\n");
924 rfbLog("running: %s\n", cmd);
925 rc = system(cmd);
926
927 if (rc != 0) {
928 free(cmd);
929 free(s);
930 rfbLog("ssh remote listen failed.\n");
931 clean_up_exit(1);
932 }
933
934 if (1) {
935 FILE *pipe;
936 int mypid = (int) getpid();
937 int bestpid = -1;
938 int best = -1;
939 char line[1024];
940 char *psef = "ps -ef";
941 char *psww = "ps wwwwwwaux";
942 char *ps = psef;
943 /* not portable... but it is really good to terminate the ssh when done. */
944 /* ps -ef | egrep 'ssh2.*-R.*5907:localhost:5900.*runge@celias.lbl.gov.*sleep 300' | grep -v grep | awk '{print $2}' */
945 if (strstr(UT.sysname, "Linux")) {
946 ps = psww;
947 } else if (strstr(UT.sysname, "BSD")) {
948 ps = psww;
949 } else if (strstr(UT.sysname, "Darwin")) {
950 ps = psww;
951 }
952 sprintf(cmd, "env COLUMNS=256 %s | egrep '%s.*-R *%d:localhost:%d.*%s.*sleep *%d' | grep -v grep | awk '{print $2}'", ps, ssh, rport, lport, s, sleep);
953 pipe = popen(cmd, "r");
954 if (pipe) {
955 while (fgets(line, 1024, pipe) != NULL) {
956 int p = atoi(line);
957 if (p > 0) {
958 int score;
959 if (p > mypid) {
960 score = p - mypid;
961 } else {
962 score = p - mypid + 32768;
963 if (score < 0) {
964 score = 32768;
965 }
966 }
967 if (best < 0 || score < best) {
968 best = score;
969 bestpid = p;
970 }
971 }
972 }
973 pclose(pipe);
974 }
975
976 if (bestpid != -1) {
977 ssh_pid = (pid_t) bestpid;
978 rfbLog("guessed ssh pid=%d, will terminate it on exit.\n", bestpid);
979 }
980 }
981
982 free(cmd);
983 free(s);
984 }
985
986 /*
987 * check blacklist for OSs with tight shm limits.
988 */
limit_shm(void)989 static int limit_shm(void) {
990 int limit = 0;
991
992 if (UT.sysname == NULL) {
993 return 0;
994 }
995 if (getenv("X11VNC_NO_LIMIT_SHM")) {
996 return 0;
997 }
998 if (!strcmp(UT.sysname, "SunOS")) {
999 char *r = UT.release;
1000 if (*r == '5' && *(r+1) == '.') {
1001 if (strchr("2345678", *(r+2)) != NULL) {
1002 limit = 1;
1003 }
1004 }
1005 } else if (!strcmp(UT.sysname, "Darwin")) {
1006 limit = 1;
1007 }
1008 if (limit && ! quiet) {
1009 fprintf(stderr, "reducing shm usage on %s %s (adding "
1010 "-onetile)\n", UT.sysname, UT.release);
1011 }
1012 return limit;
1013 }
1014
1015
1016 /*
1017 * quick-n-dirty ~/.x11vncrc: each line (except # comments) is a cmdline option.
1018 */
1019 static int argc2 = 0;
1020 static char **argv2;
1021
check_rcfile(int argc,char ** argv)1022 static void check_rcfile(int argc, char **argv) {
1023 int i, j, pwlast, enclast, norc = 0, argmax = 1024;
1024 char *infile = NULL;
1025 char rcfile[1024];
1026 FILE *rc = NULL;
1027
1028 for (i=1; i < argc; i++) {
1029 if (!strcmp(argv[i], "-printgui")) {
1030 fprintf(stdout, "%s", get_gui_code());
1031 fflush(stdout);
1032 exit(0);
1033 }
1034 if (!strcmp(argv[i], "-norc")) {
1035 norc = 1;
1036 got_norc = 1;
1037 }
1038 if (!strcmp(argv[i], "-QD")) {
1039 norc = 1;
1040 }
1041 if (!strcmp(argv[i], "-rc")) {
1042 if (i+1 >= argc) {
1043 fprintf(stderr, "-rc option requires a "
1044 "filename\n");
1045 exit(1);
1046 } else {
1047 infile = argv[i+1];
1048 }
1049 }
1050 }
1051 rc_norc = norc;
1052 rc_rcfile = strdup("");
1053 if (norc) {
1054 ;
1055 } else if (infile != NULL) {
1056 rc = fopen(infile, "r");
1057 rc_rcfile = strdup(infile);
1058 if (rc == NULL) {
1059 fprintf(stderr, "could not open rcfile: %s\n", infile);
1060 perror("fopen");
1061 exit(1);
1062 }
1063 } else {
1064 char *home = get_home_dir();
1065 if (! home) {
1066 norc = 1;
1067 } else {
1068 memset(rcfile, 0, sizeof(rcfile));
1069 strncpy(rcfile, home, 500);
1070 free(home);
1071
1072 strcat(rcfile, "/.x11vncrc");
1073 infile = rcfile;
1074 rc = fopen(rcfile, "r");
1075 if (rc == NULL) {
1076 norc = 1;
1077 } else {
1078 rc_rcfile = strdup(rcfile);
1079 rc_rcfile_default = 1;
1080 }
1081 }
1082 }
1083
1084 argv2 = (char **) malloc(argmax * sizeof(char *));
1085 argv2[argc2++] = strdup(argv[0]);
1086
1087 if (! norc) {
1088 char line[4096], parm[400], tmp[401];
1089 char *buf, *tbuf;
1090 struct stat sbuf;
1091 int sz;
1092
1093 if (fstat(fileno(rc), &sbuf) != 0) {
1094 fprintf(stderr, "problem with %s\n", infile);
1095 perror("fstat");
1096 exit(1);
1097 }
1098 sz = sbuf.st_size+1; /* allocate whole file size */
1099 if (sz < 1024) {
1100 sz = 1024;
1101 }
1102
1103 buf = (char *) malloc(sz);
1104 buf[0] = '\0';
1105
1106 while (fgets(line, 4096, rc) != NULL) {
1107 char *q, *p = line;
1108 char c;
1109 int cont = 0;
1110
1111 q = p;
1112 c = '\0';
1113 while (*q) {
1114 if (*q == '#') {
1115 if (c != '\\') {
1116 *q = '\0';
1117 break;
1118 }
1119 }
1120 c = *q;
1121 q++;
1122 }
1123
1124 q = p;
1125 c = '\0';
1126 while (*q) {
1127 if (*q == '\n') {
1128 if (c == '\\') {
1129 cont = 1;
1130 *q = '\0';
1131 *(q-1) = ' ';
1132 break;
1133 }
1134 while (isspace((unsigned char) (*q))) {
1135 *q = '\0';
1136 if (q == p) {
1137 break;
1138 }
1139 q--;
1140 }
1141 break;
1142 }
1143 c = *q;
1144 q++;
1145 }
1146 if (q != p && !cont) {
1147 if (*q == '\0') {
1148 q--;
1149 }
1150 while (isspace((unsigned char) (*q))) {
1151 *q = '\0';
1152 if (q == p) {
1153 break;
1154 }
1155 q--;
1156 }
1157 }
1158
1159 p = lblanks(p);
1160
1161 strncat(buf, p, sz - strlen(buf) - 1);
1162 if (cont) {
1163 continue;
1164 }
1165 if (buf[0] == '\0') {
1166 continue;
1167 }
1168
1169 i = 0;
1170 q = buf;
1171 while (*q) {
1172 i++;
1173 if (*q == '\n' || isspace((unsigned char) (*q))) {
1174 break;
1175 }
1176 q++;
1177 }
1178
1179 if (i >= 400) {
1180 fprintf(stderr, "invalid rcfile line: %s/%s\n",
1181 p, buf);
1182 exit(1);
1183 }
1184
1185 if (sscanf(buf, "%s", parm) != 1) {
1186 fprintf(stderr, "invalid rcfile line: %s\n", p);
1187 exit(1);
1188 }
1189 if (parm[0] == '-') {
1190 strncpy(tmp, parm, 400);
1191 } else {
1192 tmp[0] = '-';
1193 strncpy(tmp+1, parm, 400);
1194 }
1195
1196 if (strstr(tmp, "-loop") == tmp) {
1197 if (! getenv("X11VNC_LOOP_MODE")) {
1198 check_loop_mode(argc, argv, 1);
1199 exit(0);
1200 }
1201 }
1202
1203 argv2[argc2++] = strdup(tmp);
1204 if (argc2 >= argmax) {
1205 fprintf(stderr, "too many rcfile options\n");
1206 exit(1);
1207 }
1208
1209 p = buf;
1210 p += strlen(parm);
1211 p = lblanks(p);
1212
1213 if (*p == '\0') {
1214 buf[0] = '\0';
1215 continue;
1216 }
1217
1218 tbuf = (char *) calloc(strlen(p) + 1, 1);
1219
1220 j = 0;
1221 while (*p) {
1222 if (*p == '\\' && *(p+1) == '#') {
1223 ;
1224 } else {
1225 tbuf[j++] = *p;
1226 }
1227 p++;
1228 }
1229
1230 argv2[argc2++] = strdup(tbuf);
1231 free(tbuf);
1232 if (argc2 >= argmax) {
1233 fprintf(stderr, "too many rcfile options\n");
1234 exit(1);
1235 }
1236 buf[0] = '\0';
1237 }
1238 fclose(rc);
1239 free(buf);
1240 }
1241 pwlast = 0;
1242 enclast = 0;
1243 for (i=1; i < argc; i++) {
1244 argv2[argc2++] = strdup(argv[i]);
1245
1246 if (pwlast || !strcmp("-passwd", argv[i])
1247 || !strcmp("-viewpasswd", argv[i])) {
1248 char *p = argv[i];
1249 if (pwlast) {
1250 pwlast = 0;
1251 } else {
1252 pwlast = 1;
1253 }
1254 strzero(p);
1255 }
1256 if (enclast || !strcmp("-enc", argv[i])) {
1257 char *q, *p = argv[i];
1258 if (enclast) {
1259 enclast = 0;
1260 } else {
1261 enclast = 1;
1262 }
1263 q = strstr(p, "pw=");
1264 if (q) {
1265 strzero(q);
1266 }
1267 }
1268 if (argc2 >= argmax) {
1269 fprintf(stderr, "too many rcfile options\n");
1270 exit(1);
1271 }
1272 }
1273 }
1274
immediate_switch_user(int argc,char * argv[])1275 static void immediate_switch_user(int argc, char* argv[]) {
1276 int i, bequiet = 0;
1277 for (i=1; i < argc; i++) {
1278 if (strcmp(argv[i], "-inetd")) {
1279 bequiet = 1;
1280 }
1281 if (strcmp(argv[i], "-quiet")) {
1282 bequiet = 1;
1283 }
1284 if (strcmp(argv[i], "-q")) {
1285 bequiet = 1;
1286 }
1287 }
1288 for (i=1; i < argc; i++) {
1289 char *u, *q;
1290
1291 if (strcmp(argv[i], "-users")) {
1292 continue;
1293 }
1294 if (i == argc - 1) {
1295 fprintf(stderr, "not enough arguments for: -users\n");
1296 exit(1);
1297 }
1298 if (*(argv[i+1]) != '=') {
1299 break;
1300 }
1301
1302 /* wants an immediate switch: =bob */
1303 u = strdup(argv[i+1]);
1304 *u = '+';
1305 q = strchr(u, '.');
1306 if (q) {
1307 user2group = (char **) malloc(2*sizeof(char *));
1308 user2group[0] = strdup(u+1);
1309 user2group[1] = NULL;
1310 *q = '\0';
1311 }
1312 if (strstr(u, "+guess") == u) {
1313 fprintf(stderr, "invalid user: %s\n", u+1);
1314 exit(1);
1315 }
1316 if (!switch_user(u, 0)) {
1317 fprintf(stderr, "Could not switch to user: %s\n", u+1);
1318 exit(1);
1319 } else {
1320 if (!bequiet) {
1321 fprintf(stderr, "Switched to user: %s\n", u+1);
1322 }
1323 started_as_root = 2;
1324 }
1325 free(u);
1326 break;
1327 }
1328 }
1329
quick_pw(char * str)1330 static void quick_pw(char *str) {
1331 char *p, *q;
1332 char tmp[1024];
1333 int db = 0;
1334
1335 if (db) fprintf(stderr, "quick_pw: %s\n", str);
1336
1337 if (! str || str[0] == '\0') {
1338 exit(2);
1339 }
1340 if (str[0] != '%') {
1341 exit(2);
1342 }
1343 /*
1344 * "%-" or "%stdin" means read one line from stdin.
1345 *
1346 * "%env" means it is in $UNIXPW env var.
1347 *
1348 * starting "%/" or "%." means read the first line from that file.
1349 *
1350 * "%%" or "%" means prompt user.
1351 *
1352 * otherwise: %user:pass
1353 */
1354 if (!strcmp(str, "%-") || !strcmp(str, "%stdin")) {
1355 if(fgets(tmp, 1024, stdin) == NULL) {
1356 exit(2);
1357 }
1358 q = strdup(tmp);
1359 } else if (!strcmp(str, "%env")) {
1360 if (getenv("UNIXPW") == NULL) {
1361 exit(2);
1362 }
1363 q = strdup(getenv("UNIXPW"));
1364 } else if (!strcmp(str, "%%") || !strcmp(str, "%")) {
1365 char *t, inp[1024];
1366 fprintf(stdout, "username: ");
1367 if(fgets(tmp, 128, stdin) == NULL) {
1368 exit(2);
1369 }
1370 strcpy(inp, tmp);
1371 t = strchr(inp, '\n');
1372 if (t) {
1373 *t = ':';
1374 } else {
1375 strcat(inp, ":");
1376
1377 }
1378 fprintf(stdout, "password: ");
1379 /* test mode: no_external_cmds does not apply */
1380 system("stty -echo");
1381 if(fgets(tmp, 128, stdin) == NULL) {
1382 fprintf(stdout, "\n");
1383 system("stty echo");
1384 exit(2);
1385 }
1386 system("stty echo");
1387 fprintf(stdout, "\n");
1388 strcat(inp, tmp);
1389 q = strdup(inp);
1390 } else if (str[1] == '/' || str[1] == '.') {
1391 FILE *in = fopen(str+1, "r");
1392 if (in == NULL) {
1393 exit(2);
1394 }
1395 if(fgets(tmp, 1024, in) == NULL) {
1396 exit(2);
1397 }
1398 fclose(in);
1399 q = strdup(tmp);
1400 } else {
1401 q = strdup(str+1);
1402 }
1403 p = (char *) malloc(strlen(q) + 10);
1404 strcpy(p, q);
1405 if (strchr(p, '\n') == NULL) {
1406 strcat(p, "\n");
1407 }
1408
1409 if ((q = strchr(p, ':')) == NULL) {
1410 exit(2);
1411 }
1412 *q = '\0';
1413 if (db) fprintf(stderr, "'%s' '%s'\n", p, q+1);
1414 if (unixpw_cmd) {
1415 if (cmd_verify(p, q+1)) {
1416 fprintf(stdout, "Y %s\n", p);
1417 exit(0);
1418 } else {
1419 fprintf(stdout, "N %s\n", p);
1420 exit(1);
1421 }
1422 } else if (unixpw_nis) {
1423 if (crypt_verify(p, q+1)) {
1424 fprintf(stdout, "Y %s\n", p);
1425 exit(0);
1426 } else {
1427 fprintf(stdout, "N %s\n", p);
1428 exit(1);
1429 }
1430 } else {
1431 char *ucmd = getenv("UNIXPW_CMD");
1432 if (su_verify(p, q+1, ucmd, NULL, NULL, 1)) {
1433 fprintf(stdout, "Y %s\n", p);
1434 exit(0);
1435 } else {
1436 fprintf(stdout, "N %s\n", p);
1437 exit(1);
1438 }
1439 }
1440 /* NOTREACHED */
1441 exit(2);
1442 }
1443
print_settings(int try_http,int bg,char * gui_str)1444 static void print_settings(int try_http, int bg, char *gui_str) {
1445
1446 fprintf(stderr, "\n");
1447 fprintf(stderr, "Settings:\n");
1448 fprintf(stderr, " display: %s\n", use_dpy ? use_dpy
1449 : "null");
1450 #if SMALL_FOOTPRINT < 2
1451 fprintf(stderr, " authfile: %s\n", auth_file ? auth_file
1452 : "null");
1453 fprintf(stderr, " subwin: 0x%lx\n", subwin);
1454 fprintf(stderr, " -sid mode: %d\n", rootshift);
1455 fprintf(stderr, " clip: %s\n", clip_str ? clip_str
1456 : "null");
1457 fprintf(stderr, " flashcmap: %d\n", flash_cmap);
1458 fprintf(stderr, " shiftcmap: %d\n", shift_cmap);
1459 fprintf(stderr, " force_idx: %d\n", force_indexed_color);
1460 fprintf(stderr, " cmap8to24: %d\n", cmap8to24);
1461 fprintf(stderr, " 8to24_opts: %s\n", cmap8to24_str ? cmap8to24_str
1462 : "null");
1463 fprintf(stderr, " 24to32: %d\n", xform24to32);
1464 fprintf(stderr, " visual: %s\n", visual_str ? visual_str
1465 : "null");
1466 fprintf(stderr, " overlay: %d\n", overlay);
1467 fprintf(stderr, " ovl_cursor: %d\n", overlay_cursor);
1468 fprintf(stderr, " scaling: %d %.4f %.4f\n", scaling, scale_fac_x, scale_fac_y);
1469 fprintf(stderr, " viewonly: %d\n", view_only);
1470 fprintf(stderr, " shared: %d\n", shared);
1471 fprintf(stderr, " conn_once: %d\n", connect_once);
1472 fprintf(stderr, " timeout: %d\n", first_conn_timeout);
1473 fprintf(stderr, " ping: %d\n", ping_interval);
1474 fprintf(stderr, " inetd: %d\n", inetd);
1475 fprintf(stderr, " tightfilexfer: %d\n", tightfilexfer);
1476 fprintf(stderr, " http: %d\n", try_http);
1477 fprintf(stderr, " connect: %s\n", client_connect
1478 ? client_connect : "null");
1479 fprintf(stderr, " connectfile %s\n", client_connect_file
1480 ? client_connect_file : "null");
1481 fprintf(stderr, " vnc_conn: %d\n", vnc_connect);
1482 fprintf(stderr, " allow: %s\n", allow_list ? allow_list
1483 : "null");
1484 fprintf(stderr, " input: %s\n", allowed_input_str
1485 ? allowed_input_str : "null");
1486 fprintf(stderr, " passfile: %s\n", passwdfile ? passwdfile
1487 : "null");
1488 fprintf(stderr, " unixpw: %d\n", unixpw);
1489 fprintf(stderr, " unixpw_lst: %s\n", unixpw_list ? unixpw_list:"null");
1490 fprintf(stderr, " ssl: %s\n", openssl_pem ? openssl_pem:"null");
1491 fprintf(stderr, " ssldir: %s\n", ssl_certs_dir ? ssl_certs_dir:"null");
1492 fprintf(stderr, " ssltimeout %d\n", ssl_timeout_secs);
1493 fprintf(stderr, " sslverify: %s\n", ssl_verify ? ssl_verify:"null");
1494 fprintf(stderr, " stunnel: %d\n", use_stunnel);
1495 fprintf(stderr, " accept: %s\n", accept_cmd ? accept_cmd
1496 : "null");
1497 fprintf(stderr, " accept: %s\n", afteraccept_cmd ? afteraccept_cmd
1498 : "null");
1499 fprintf(stderr, " gone: %s\n", gone_cmd ? gone_cmd
1500 : "null");
1501 fprintf(stderr, " users: %s\n", users_list ? users_list
1502 : "null");
1503 fprintf(stderr, " using_shm: %d\n", using_shm);
1504 fprintf(stderr, " flipbytes: %d\n", flip_byte_order);
1505 fprintf(stderr, " onetile: %d\n", single_copytile);
1506 fprintf(stderr, " solid: %s\n", solid_str
1507 ? solid_str : "null");
1508 fprintf(stderr, " blackout: %s\n", blackout_str
1509 ? blackout_str : "null");
1510 fprintf(stderr, " xinerama: %d\n", xinerama);
1511 fprintf(stderr, " xtrap: %d\n", xtrap_input);
1512 fprintf(stderr, " xrandr: %d\n", xrandr);
1513 fprintf(stderr, " xrandrmode: %s\n", xrandr_mode ? xrandr_mode
1514 : "null");
1515 fprintf(stderr, " padgeom: %s\n", pad_geometry
1516 ? pad_geometry : "null");
1517 fprintf(stderr, " logfile: %s\n", logfile ? logfile
1518 : "null");
1519 fprintf(stderr, " logappend: %d\n", logfile_append);
1520 fprintf(stderr, " flag: %s\n", flagfile ? flagfile
1521 : "null");
1522 fprintf(stderr, " rm_flag: %s\n", rm_flagfile ? rm_flagfile
1523 : "null");
1524 fprintf(stderr, " rc_file: \"%s\"\n", rc_rcfile ? rc_rcfile
1525 : "null");
1526 fprintf(stderr, " norc: %d\n", rc_norc);
1527 fprintf(stderr, " dbg: %d\n", crash_debug);
1528 fprintf(stderr, " bg: %d\n", bg);
1529 fprintf(stderr, " mod_tweak: %d\n", use_modifier_tweak);
1530 fprintf(stderr, " isolevel3: %d\n", use_iso_level3);
1531 fprintf(stderr, " xkb: %d\n", use_xkb_modtweak);
1532 fprintf(stderr, " skipkeys: %s\n",
1533 skip_keycodes ? skip_keycodes : "null");
1534 fprintf(stderr, " sloppykeys: %d\n", sloppy_keys);
1535 fprintf(stderr, " skip_dups: %d\n", skip_duplicate_key_events);
1536 fprintf(stderr, " addkeysyms: %d\n", add_keysyms);
1537 fprintf(stderr, " xkbcompat: %d\n", xkbcompat);
1538 fprintf(stderr, " clearmods: %d\n", clear_mods);
1539 fprintf(stderr, " remap: %s\n", remap_file ? remap_file
1540 : "null");
1541 fprintf(stderr, " norepeat: %d\n", no_autorepeat);
1542 fprintf(stderr, " norepeatcnt:%d\n", no_repeat_countdown);
1543 fprintf(stderr, " nofb: %d\n", nofb);
1544 fprintf(stderr, " watchbell: %d\n", watch_bell);
1545 fprintf(stderr, " watchsel: %d\n", watch_selection);
1546 fprintf(stderr, " watchprim: %d\n", watch_primary);
1547 fprintf(stderr, " seldir: %s\n", sel_direction ?
1548 sel_direction : "null");
1549 fprintf(stderr, " cursor: %d\n", show_cursor);
1550 fprintf(stderr, " multicurs: %d\n", show_multiple_cursors);
1551 fprintf(stderr, " curs_mode: %s\n", multiple_cursors_mode
1552 ? multiple_cursors_mode : "null");
1553 fprintf(stderr, " arrow: %d\n", alt_arrow);
1554 fprintf(stderr, " xfixes: %d\n", use_xfixes);
1555 fprintf(stderr, " alphacut: %d\n", alpha_threshold);
1556 fprintf(stderr, " alphafrac: %.2f\n", alpha_frac);
1557 fprintf(stderr, " alpharemove:%d\n", alpha_remove);
1558 fprintf(stderr, " alphablend: %d\n", alpha_blend);
1559 fprintf(stderr, " cursorshape:%d\n", cursor_shape_updates);
1560 fprintf(stderr, " cursorpos: %d\n", cursor_pos_updates);
1561 fprintf(stderr, " xwarpptr: %d\n", use_xwarppointer);
1562 fprintf(stderr, " alwaysinj: %d\n", always_inject);
1563 fprintf(stderr, " buttonmap: %s\n", pointer_remap
1564 ? pointer_remap : "null");
1565 fprintf(stderr, " dragging: %d\n", show_dragging);
1566 fprintf(stderr, " ncache: %d\n", ncache);
1567 fprintf(stderr, " wireframe: %s\n", wireframe_str ?
1568 wireframe_str : WIREFRAME_PARMS);
1569 fprintf(stderr, " wirecopy: %s\n", wireframe_copyrect ?
1570 wireframe_copyrect : wireframe_copyrect_default);
1571 fprintf(stderr, " scrollcopy: %s\n", scroll_copyrect ?
1572 scroll_copyrect : scroll_copyrect_default);
1573 fprintf(stderr, " scr_area: %d\n", scrollcopyrect_min_area);
1574 fprintf(stderr, " scr_skip: %s\n", scroll_skip_str ?
1575 scroll_skip_str : scroll_skip_str0);
1576 fprintf(stderr, " scr_inc: %s\n", scroll_good_str ?
1577 scroll_good_str : scroll_good_str0);
1578 fprintf(stderr, " scr_keys: %s\n", scroll_key_list_str ?
1579 scroll_key_list_str : "null");
1580 fprintf(stderr, " scr_term: %s\n", scroll_term_str ?
1581 scroll_term_str : "null");
1582 fprintf(stderr, " scr_keyrep: %s\n", max_keyrepeat_str ?
1583 max_keyrepeat_str : "null");
1584 fprintf(stderr, " scr_parms: %s\n", scroll_copyrect_str ?
1585 scroll_copyrect_str : SCROLL_COPYRECT_PARMS);
1586 fprintf(stderr, " fixscreen: %s\n", screen_fixup_str ?
1587 screen_fixup_str : "null");
1588 fprintf(stderr, " noxrecord: %d\n", noxrecord);
1589 fprintf(stderr, " grabbuster: %d\n", grab_buster);
1590 fprintf(stderr, " ptr_mode: %d\n", pointer_mode);
1591 fprintf(stderr, " inputskip: %d\n", ui_skip);
1592 fprintf(stderr, " speeds: %s\n", speeds_str
1593 ? speeds_str : "null");
1594 fprintf(stderr, " wmdt: %s\n", wmdt_str
1595 ? wmdt_str : "null");
1596 fprintf(stderr, " debug_ptr: %d\n", debug_pointer);
1597 fprintf(stderr, " debug_key: %d\n", debug_keyboard);
1598 fprintf(stderr, " defer: %d\n", defer_update);
1599 fprintf(stderr, " waitms: %d\n", waitms);
1600 fprintf(stderr, " wait_ui: %.2f\n", wait_ui);
1601 fprintf(stderr, " nowait_bog: %d\n", !wait_bog);
1602 fprintf(stderr, " slow_fb: %.2f\n", slow_fb);
1603 fprintf(stderr, " xrefresh: %.2f\n", xrefresh);
1604 fprintf(stderr, " readtimeout: %d\n", rfbMaxClientWait/1000);
1605 fprintf(stderr, " take_naps: %d\n", take_naps);
1606 fprintf(stderr, " sb: %d\n", screen_blank);
1607 fprintf(stderr, " fbpm: %d\n", !watch_fbpm);
1608 fprintf(stderr, " dpms: %d\n", !watch_dpms);
1609 fprintf(stderr, " xdamage: %d\n", use_xdamage);
1610 fprintf(stderr, " xd_area: %d\n", xdamage_max_area);
1611 fprintf(stderr, " xd_mem: %.3f\n", xdamage_memory);
1612 fprintf(stderr, " sigpipe: %s\n", sigpipe
1613 ? sigpipe : "null");
1614 fprintf(stderr, " threads: %d\n", use_threads);
1615 fprintf(stderr, " fs_frac: %.2f\n", fs_frac);
1616 fprintf(stderr, " gaps_fill: %d\n", gaps_fill);
1617 fprintf(stderr, " grow_fill: %d\n", grow_fill);
1618 fprintf(stderr, " tile_fuzz: %d\n", tile_fuzz);
1619 fprintf(stderr, " snapfb: %d\n", use_snapfb);
1620 fprintf(stderr, " rawfb: %s\n", raw_fb_str
1621 ? raw_fb_str : "null");
1622 fprintf(stderr, " pipeinput: %s\n", pipeinput_str
1623 ? pipeinput_str : "null");
1624 fprintf(stderr, " gui: %d\n", launch_gui);
1625 fprintf(stderr, " gui_mode: %s\n", gui_str
1626 ? gui_str : "null");
1627 fprintf(stderr, " noremote: %d\n", !accept_remote_cmds);
1628 fprintf(stderr, " unsafe: %d\n", !safe_remote_only);
1629 fprintf(stderr, " privremote: %d\n", priv_remote);
1630 fprintf(stderr, " safer: %d\n", more_safe);
1631 fprintf(stderr, " nocmds: %d\n", no_external_cmds);
1632 fprintf(stderr, " deny_all: %d\n", deny_all);
1633 fprintf(stderr, " pid: %d\n", getpid());
1634 fprintf(stderr, "\n");
1635 #endif
1636 }
1637
1638
check_loop_mode(int argc,char * argv[],int force)1639 static void check_loop_mode(int argc, char* argv[], int force) {
1640 int i;
1641 int loop_mode = 0, loop_sleep = 2000, loop_max = 0;
1642
1643 if (force) {
1644 loop_mode = 1;
1645 }
1646 for (i=1; i < argc; i++) {
1647 char *p = argv[i];
1648 if (strstr(p, "--") == p) {
1649 p++;
1650 }
1651 if (strstr(p, "-loop") == p) {
1652 char *q;
1653 loop_mode = 1;
1654 if ((q = strchr(p, ',')) != NULL) {
1655 loop_max = atoi(q+1);
1656 *q = '\0';
1657 }
1658 if (strstr(p, "-loopbg") == p) {
1659 set_env("X11VNC_LOOP_MODE_BG", "1");
1660 loop_sleep = 500;
1661 }
1662
1663 q = strpbrk(p, "0123456789");
1664 if (q) {
1665 loop_sleep = atoi(q);
1666 if (loop_sleep <= 0) {
1667 loop_sleep = 20;
1668 }
1669 }
1670 }
1671 }
1672 if (loop_mode && getenv("X11VNC_LOOP_MODE") == NULL) {
1673 #if LIBVNCSERVER_HAVE_FORK
1674 char **argv2;
1675 int k, i = 1;
1676
1677 set_env("X11VNC_LOOP_MODE", "1");
1678 argv2 = (char **) malloc((argc+1)*sizeof(char *));
1679
1680 for (k=0; k < argc+1; k++) {
1681 argv2[k] = NULL;
1682 if (k < argc) {
1683 argv2[k] = argv[k];
1684 }
1685 }
1686 while (1) {
1687 int status;
1688 pid_t p;
1689 fprintf(stderr, "\n --- x11vnc loop: %d ---\n\n", i++);
1690 fflush(stderr);
1691 usleep(500 * 1000);
1692 if ((p = fork()) > 0) {
1693 fprintf(stderr, " --- x11vnc loop: waiting "
1694 "for: %d\n\n", p);
1695 wait(&status);
1696 } else if (p == -1) {
1697 fprintf(stderr, "could not fork\n");
1698 perror("fork");
1699 exit(1);
1700 } else {
1701 /* loop mode: no_external_cmds does not apply */
1702 execvp(argv[0], argv2);
1703 exit(1);
1704 }
1705
1706 if (loop_max > 0 && i > loop_max) {
1707 fprintf(stderr, "\n --- x11vnc loop: did %d"
1708 " done. ---\n\n", loop_max);
1709 break;
1710 }
1711
1712 fprintf(stderr, "\n --- x11vnc loop: sleeping %d ms "
1713 "---\n\n", loop_sleep);
1714 usleep(loop_sleep * 1000);
1715 }
1716 exit(0);
1717 #else
1718 fprintf(stderr, "fork unavailable, cannot do -loop mode\n");
1719 exit(1);
1720 #endif
1721 }
1722 }
1723
1724 extern int appshare_main(int argc, char* argv[]);
1725
check_appshare_mode(int argc,char * argv[])1726 static void check_appshare_mode(int argc, char* argv[]) {
1727 int i;
1728
1729 for (i=1; i < argc; i++) {
1730 char *p = argv[i];
1731 if (strstr(p, "--") == p) {
1732 p++;
1733 }
1734 if (strstr(p, "-appshare") == p) {
1735 appshare_main(argc, argv);
1736 exit(0);
1737 }
1738 }
1739 }
1740
store_homedir_passwd(char * file)1741 static void store_homedir_passwd(char *file) {
1742 char str1[32], str2[32], *p, *h, *f;
1743 struct stat sbuf;
1744
1745 str1[0] = '\0';
1746 str2[0] = '\0';
1747
1748 /* storepasswd */
1749 if (no_external_cmds || !cmd_ok("storepasswd")) {
1750 fprintf(stderr, "-nocmds cannot be used with -storepasswd\n");
1751 exit(1);
1752 }
1753
1754 fprintf(stderr, "Enter VNC password: ");
1755 system("stty -echo");
1756 if (fgets(str1, 32, stdin) == NULL) {
1757 perror("fgets");
1758 system("stty echo");
1759 exit(1);
1760 }
1761 fprintf(stderr, "\n");
1762
1763 fprintf(stderr, "Verify password: ");
1764 if (fgets(str2, 32, stdin) == NULL) {
1765 perror("fgets");
1766 system("stty echo");
1767 exit(1);
1768 }
1769 fprintf(stderr, "\n");
1770 system("stty echo");
1771
1772 if ((p = strchr(str1, '\n')) != NULL) {
1773 *p = '\0';
1774 }
1775 if ((p = strchr(str2, '\n')) != NULL) {
1776 *p = '\0';
1777 }
1778 if (strcmp(str1, str2)) {
1779 fprintf(stderr, "** passwords differ.\n");
1780 exit(1);
1781 }
1782 if (str1[0] == '\0') {
1783 fprintf(stderr, "** no password supplied.\n");
1784 exit(1);
1785 }
1786
1787 if (file != NULL) {
1788 f = file;
1789 } else {
1790
1791 h = getenv("HOME");
1792 if (! h) {
1793 fprintf(stderr, "** $HOME not set.\n");
1794 exit(1);
1795 }
1796
1797 f = (char *) malloc(strlen(h) + strlen("/.vnc/passwd") + 1);
1798 sprintf(f, "%s/.vnc", h);
1799
1800 if (stat(f, &sbuf) != 0) {
1801 if (mkdir(f, 0755) != 0) {
1802 fprintf(stderr, "** could not create directory %s\n", f);
1803 perror("mkdir");
1804 exit(1);
1805 }
1806 } else if (! S_ISDIR(sbuf.st_mode)) {
1807 fprintf(stderr, "** not a directory %s\n", f);
1808 exit(1);
1809 }
1810
1811 sprintf(f, "%s/.vnc/passwd", h);
1812 }
1813 fprintf(stderr, "Write password to %s? [y]/n ", f);
1814
1815 if (fgets(str2, 32, stdin) == NULL) {
1816 perror("fgets");
1817 exit(1);
1818 }
1819 if (str2[0] == 'n' || str2[0] == 'N') {
1820 fprintf(stderr, "not creating password.\n");
1821 exit(1);
1822 }
1823
1824 if (rfbEncryptAndStorePasswd(str1, f) != 0) {
1825 fprintf(stderr, "** error creating password: %s\n", f);
1826 perror("storepasswd");
1827 exit(1);
1828 }
1829 if (stat(f, &sbuf) != 0) {
1830 fprintf(stderr, "** error creating password: %s\n", f);
1831 perror("stat");
1832 exit(1);
1833 }
1834 fprintf(stdout, "Password written to: %s\n", f);
1835 exit(0);
1836 }
1837
ncache_beta_tester_message(void)1838 void ncache_beta_tester_message(void) {
1839
1840 char msg[] =
1841 "\n"
1842 "******************************************************************************\n"
1843 "\n"
1844 "Hello! Exciting News!!\n"
1845 "\n"
1846 "You have been selected at random to beta-test the x11vnc '-ncache' VNC\n"
1847 "client-side pixel caching feature!\n"
1848 "\n"
1849 "This scheme stores pixel data offscreen on the VNC viewer side for faster\n"
1850 "retrieval. It should work with any VNC viewer.\n"
1851 "\n"
1852 "This method requires much testing and so we hope you will try it out and\n"
1853 "perhaps even report back your observations. However, if you do not want\n"
1854 "to test or use the feature, run x11vnc like this:\n"
1855 "\n"
1856 " x11vnc -noncache ...\n"
1857 "\n"
1858 "Your current setting is: -ncache %d\n"
1859 "\n"
1860 "The feature needs additional testing because we want to have x11vnc\n"
1861 "performance enhancements on by default. Otherwise, only a relative few\n"
1862 "would notice and use the -ncache option (e.g. the wireframe and scroll\n"
1863 "detection features are on by default). A couple things to note:\n"
1864 "\n"
1865 " 1) It uses a large amount of RAM (on both viewer and server sides)\n"
1866 "\n"
1867 " 2) You can actually see the cached pixel data if you scroll down\n"
1868 " to it in your viewer; adjust your viewer's size to hide it.\n"
1869 "\n"
1870 "More info: http://www.karlrunge.com/x11vnc/faq.html#faq-client-caching\n"
1871 "\n"
1872 "waiting for connections:\n"
1873 ;
1874
1875 char msg2[] =
1876 "\n"
1877 "******************************************************************************\n"
1878 "Have you tried the x11vnc '-ncache' VNC client-side pixel caching feature yet?\n"
1879 "\n"
1880 "The scheme stores pixel data offscreen on the VNC viewer side for faster\n"
1881 "retrieval. It should work with any VNC viewer. Try it by running:\n"
1882 "\n"
1883 " x11vnc -ncache 10 ...\n"
1884 "\n"
1885 "One can also add -ncache_cr for smooth 'copyrect' window motion.\n"
1886 "More info: http://www.karlrunge.com/x11vnc/faq.html#faq-client-caching\n"
1887 "\n"
1888 ;
1889
1890 if (raw_fb_str && !macosx_console) {
1891 return;
1892 }
1893 if (quiet) {
1894 return;
1895 }
1896 if (remote_direct) {
1897 return;
1898 }
1899 if (nofb) {
1900 return;
1901 }
1902 #ifdef NO_NCACHE
1903 return;
1904 #endif
1905
1906 if (ncache == 0) {
1907 fprintf(stderr, "%s", msg2);
1908 ncache0 = ncache = 0;
1909 } else {
1910 fprintf(stderr, msg, ncache);
1911 }
1912 }
1913
1914 #define SHOW_NO_PASSWORD_WARNING \
1915 (!got_passwd && !got_rfbauth && (!got_passwdfile || !passwd_list) \
1916 && !query_cmd && !remote_cmd && !unixpw && !got_gui_pw \
1917 && ! ssl_verify && !inetd && !terminal_services_daemon)
1918
do_sleepin(char * sleep)1919 static void do_sleepin(char *sleep) {
1920 int n1, n2, nt;
1921 double f1, f2, ft;
1922
1923 if (strchr(sleep, '-')) {
1924 double s = atof(strchr(sleep, '-')+1);
1925 if (sscanf(sleep, "%d-%d", &n1, &n2) == 2) {
1926 if (n1 > n2) {
1927 nt = n1;
1928 n1 = n2;
1929 n2 = nt;
1930 }
1931 s = n1 + rfac() * (n2 - n1);
1932 } else if (sscanf(sleep, "%lf-%lf", &f1, &f2) == 2) {
1933 if (f1 > f2) {
1934 ft = f1;
1935 f1 = f2;
1936 f2 = ft;
1937 }
1938 s = f1 + rfac() * (f2 - f1);
1939 }
1940 if (getenv("DEBUG_SLEEPIN")) fprintf(stderr, "sleepin: %f secs\n", s);
1941 usleep( (int) (1000*1000*s) );
1942 } else {
1943 n1 = atoi(sleep);
1944 if (getenv("DEBUG_SLEEPIN")) fprintf(stderr, "sleepin: %d secs\n", n1);
1945 if (n1 > 0) {
1946 usleep(1000*1000*n1);
1947 }
1948 }
1949 }
1950
check_guess_auth_file(void)1951 static void check_guess_auth_file(void) {
1952 if (!strcasecmp(auth_file, "guess")) {
1953 char line[4096], *cmd, *q, *disp = use_dpy ? use_dpy: "";
1954 FILE *p;
1955 int n;
1956 if (!program_name) {
1957 rfbLog("-auth guess: no program_name found.\n");
1958 clean_up_exit(1);
1959 }
1960 if (strpbrk(program_name, " \t\r\n")) {
1961 rfbLog("-auth guess: whitespace in program_name '%s'\n", program_name);
1962 clean_up_exit(1);
1963 }
1964 if (no_external_cmds || !cmd_ok("findauth")) {
1965 rfbLog("-auth guess: cannot run external commands in -nocmds mode:\n");
1966 clean_up_exit(1);
1967 }
1968
1969 cmd = (char *)malloc(100 + strlen(program_name) + strlen(disp));
1970 sprintf(cmd, "%s -findauth %s -env _D_XDM=1", program_name, disp);
1971 p = popen(cmd, "r");
1972 if (!p) {
1973 rfbLog("-auth guess: could not run cmd '%s'\n", cmd);
1974 clean_up_exit(1);
1975 }
1976 memset(line, 0, sizeof(line));
1977 n = fread(line, 1, sizeof(line), p);
1978 pclose(p);
1979 q = strrchr(line, '\n');
1980 if (q) *q = '\0';
1981 if (!strcmp(disp, "")) {
1982 disp = getenv("DISPLAY");
1983 if (!disp) {
1984 disp = "unset";
1985 }
1986 }
1987 if (strstr(line, "XAUTHORITY=") != line && !getenv("FD_XDM")) {
1988 if (use_dpy == NULL || strstr(use_dpy, "cmd=FIND") == NULL) {
1989 if (getuid() == 0 || geteuid() == 0) {
1990 char *q = strstr(cmd, "_D_XDM=1");
1991 if (q) {
1992 *q = 'F';
1993 rfbLog("-auth guess: failed for display='%s'\n", disp);
1994 rfbLog("-auth guess: since we are root, retrying with FD_XDM=1\n");
1995 p = popen(cmd, "r");
1996 if (!p) {
1997 rfbLog("-auth guess: could not run cmd '%s'\n", cmd);
1998 clean_up_exit(1);
1999 }
2000 memset(line, 0, sizeof(line));
2001 n = fread(line, 1, sizeof(line), p);
2002 pclose(p);
2003 q = strrchr(line, '\n');
2004 if (q) *q = '\0';
2005 }
2006 }
2007 }
2008 }
2009 if (!strcmp(line, "")) {
2010 rfbLog("-auth guess: failed for display='%s'\n", disp);
2011 clean_up_exit(1);
2012 } else if (strstr(line, "XAUTHORITY=") != line) {
2013 rfbLog("-auth guess: failed. '%s' for display='%s'\n", line, disp);
2014 clean_up_exit(1);
2015 } else if (!strcmp(line, "XAUTHORITY=")) {
2016 rfbLog("-auth guess: using default XAUTHORITY for display='%s'\n", disp);
2017 q = getenv("XAUTHORITY");
2018 if (q) {
2019 *(q-2) = '_'; /* yow */
2020 }
2021 auth_file = NULL;
2022 } else {
2023 rfbLog("-auth guess: using '%s' for disp='%s'\n", line, disp);
2024 auth_file = strdup(line + strlen("XAUTHORITY="));
2025 }
2026 }
2027 }
2028
2029 extern int is_decimal(char *);
2030
main(int argc,char * argv[])2031 int main(int argc, char* argv[]) {
2032
2033 int i, len, tmpi;
2034 int ev, er, maj, min;
2035 char *arg;
2036 int remote_sync = 0;
2037 char *remote_cmd = NULL;
2038 char *query_cmd = NULL;
2039 int query_retries = 0;
2040 double query_delay = 0.5;
2041 char *query_match = NULL;
2042 char *gui_str = NULL;
2043 int got_gui_pw = 0;
2044 int pw_loc = -1, got_passwd = 0, got_rfbauth = 0, nopw = NOPW;
2045 int got_viewpasswd = 0, got_localhost = 0, got_passwdfile = 0;
2046 int vpw_loc = -1;
2047 int dt = 0, bg = 0;
2048 int got_rfbwait = 0;
2049 int got_httpdir = 0, try_http = 0;
2050 int orig_use_xdamage = use_xdamage;
2051 int http_oneport_msg = 0;
2052 XImage *fb0 = NULL;
2053 int ncache_msg = 0;
2054 char *got_rfbport_str = NULL;
2055 int got_rfbport_pos = -1;
2056 int got_tls = 0;
2057 int got_inetd = 0;
2058 int got_noxrandr = 0;
2059
2060 /* used to pass args we do not know about to rfbGetScreen(): */
2061 int argc_vnc_max = 1024;
2062 int argc_vnc = 1; char *argv_vnc[2048];
2063
2064 /* check for -loop mode: */
2065 check_loop_mode(argc, argv, 0);
2066
2067 /* check for -appshare mode: */
2068 check_appshare_mode(argc, argv);
2069
2070 dtime0(&x11vnc_start);
2071
2072 for (i=1; i < argc; i++) {
2073 if (!strcmp(argv[i], "-inetd")) {
2074 got_inetd = 1;
2075 }
2076 }
2077
2078 if (!getuid() || !geteuid()) {
2079 started_as_root = 1;
2080 if (0 && !got_inetd) {
2081 rfbLog("getuid: %d geteuid: %d\n", getuid(), geteuid());
2082 }
2083
2084 /* check for '-users =bob' */
2085 immediate_switch_user(argc, argv);
2086 }
2087
2088 for (i=0; i < 2048; i++) {
2089 argv_vnc[i] = NULL;
2090 }
2091
2092 argv_vnc[0] = strdup(argv[0]);
2093 program_name = strdup(argv[0]);
2094 program_pid = (int) getpid();
2095
2096 solid_default = strdup(solid_default); /* for freeing with -R */
2097
2098 len = 0;
2099 for (i=1; i < argc; i++) {
2100 len += strlen(argv[i]) + 4 + 1;
2101 }
2102 program_cmdline = (char *) malloc(len+1);
2103 program_cmdline[0] = '\0';
2104 for (i=1; i < argc; i++) {
2105 char *s = argv[i];
2106 if (program_cmdline[0]) {
2107 strcat(program_cmdline, " ");
2108 }
2109 if (*s == '-') {
2110 strcat(program_cmdline, s);
2111 } else {
2112 strcat(program_cmdline, "{{");
2113 strcat(program_cmdline, s);
2114 strcat(program_cmdline, "}}");
2115 }
2116 }
2117
2118 for (i=0; i<ICON_MODE_SOCKS; i++) {
2119 icon_mode_socks[i] = -1;
2120 }
2121
2122 check_rcfile(argc, argv);
2123 /* kludge for the new array argv2 set in check_rcfile() */
2124 # define argc argc2
2125 # define argv argv2
2126
2127 # define CHECK_ARGC if (i >= argc-1) { \
2128 fprintf(stderr, "not enough arguments for: %s\n", arg); \
2129 exit(1); \
2130 }
2131
2132 /*
2133 * do a quick check for parameters that apply to "utility"
2134 * commands, i.e. ones that do not run the server.
2135 */
2136 for (i=1; i < argc; i++) {
2137 arg = argv[i];
2138 if (strstr(arg, "--") == arg) {
2139 arg++;
2140 }
2141 if (!strcmp(arg, "-ssldir")) {
2142 CHECK_ARGC
2143 ssl_certs_dir = strdup(argv[++i]);
2144 }
2145 }
2146
2147 /*
2148 * do a quick check for -env parameters
2149 */
2150 for (i=1; i < argc; i++) {
2151 char *p, *q;
2152 arg = argv[i];
2153 if (strstr(arg, "--") == arg) {
2154 arg++;
2155 }
2156 if (!strcmp(arg, "-env")) {
2157 CHECK_ARGC
2158 p = strdup(argv[++i]);
2159 q = strchr(p, '=');
2160 if (! q) {
2161 fprintf(stderr, "no -env '=' found: %s\n", p);
2162 exit(1);
2163 } else {
2164 *q = '\0';
2165 }
2166 set_env(p, q+1);
2167 free(p);
2168 }
2169 }
2170
2171 for (i=1; i < argc; i++) {
2172 /* quick-n-dirty --option handling. */
2173 arg = argv[i];
2174 if (strstr(arg, "--") == arg) {
2175 arg++;
2176 }
2177
2178 if (!strcmp(arg, "-display")) {
2179 CHECK_ARGC
2180 use_dpy = strdup(argv[++i]);
2181 if (strstr(use_dpy, "WAIT")) {
2182 extern char find_display[];
2183 extern char create_display[];
2184 if (strstr(use_dpy, "cmd=FINDDISPLAY-print")) {
2185 fprintf(stdout, "%s", find_display);
2186 exit(0);
2187 }
2188 if (strstr(use_dpy, "cmd=FINDCREATEDISPLAY-print")) {
2189 fprintf(stdout, "%s", create_display);
2190 exit(0);
2191 }
2192 }
2193 continue;
2194 }
2195 if (!strcmp(arg, "-reopen")) {
2196 char *str = getenv("X11VNC_REOPEN_DISPLAY");
2197 if (str) {
2198 int rmax = atoi(str);
2199 if (rmax > 0) {
2200 set_env("X11VNC_REOPEN_DISPLAY", str);
2201 }
2202 } else {
2203 set_env("X11VNC_REOPEN_DISPLAY", "1");
2204 }
2205 continue;
2206 }
2207 if (!strcmp(arg, "-find")) {
2208 use_dpy = strdup("WAIT:cmd=FINDDISPLAY");
2209 continue;
2210 }
2211 if (!strcmp(arg, "-finddpy") || strstr(arg, "-listdpy") == arg) {
2212 int ic = 0;
2213 use_dpy = strdup("WAIT:cmd=FINDDISPLAY-run");
2214 if (argc > i+1) {
2215 set_env("X11VNC_USER", argv[i+1]);
2216 fprintf(stdout, "X11VNC_USER=%s\n", getenv("X11VNC_USER"));
2217 }
2218 if (strstr(arg, "-listdpy") == arg) {
2219 set_env("FIND_DISPLAY_ALL", "1");
2220 }
2221 wait_for_client(&ic, NULL, 0);
2222 exit(0);
2223 continue;
2224 }
2225 if (!strcmp(arg, "-findauth")) {
2226 got_findauth = 1;
2227 if (argc > i+1) {
2228 char *s = argv[i+1];
2229 if (s[0] != '-') {
2230 set_env("FINDAUTH_DISPLAY", argv[i+1]);
2231 i++;
2232 }
2233 }
2234 continue;
2235 }
2236 if (!strcmp(arg, "-create")) {
2237 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvfb");
2238 continue;
2239 }
2240 if (!strcmp(arg, "-create_xsrv")) {
2241 CHECK_ARGC
2242 use_dpy = (char *) malloc(strlen(argv[i+1])+100);
2243 sprintf(use_dpy, "WAIT:cmd=FINDCREATEDISPLAY-%s", argv[++i]);
2244 continue;
2245 }
2246 if (!strcmp(arg, "-xdummy")) {
2247 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xdummy");
2248 continue;
2249 }
2250 if (!strcmp(arg, "-xdummy_xvfb")) {
2251 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xdummy,Xvfb");
2252 continue;
2253 }
2254 if (!strcmp(arg, "-xvnc")) {
2255 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvnc");
2256 continue;
2257 }
2258 if (!strcmp(arg, "-xvnc_redirect")) {
2259 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvnc.redirect");
2260 continue;
2261 }
2262 if (!strcmp(arg, "-redirect")) {
2263 char *q, *t, *t0 = "WAIT:cmd=FINDDISPLAY-vnc_redirect";
2264 CHECK_ARGC
2265 t = (char *) malloc(strlen(t0) + strlen(argv[++i]) + 2);
2266 q = strrchr(argv[i], ':');
2267 if (q) *q = ' ';
2268 sprintf(t, "%s=%s", t0, argv[i]);
2269 use_dpy = t;
2270 continue;
2271 }
2272 if (!strcmp(arg, "-auth") || !strcmp(arg, "-xauth")) {
2273 CHECK_ARGC
2274 auth_file = strdup(argv[++i]);
2275 continue;
2276 }
2277 if (!strcmp(arg, "-N")) {
2278 display_N = 1;
2279 continue;
2280 }
2281 if (!strcmp(arg, "-autoport")) {
2282 CHECK_ARGC
2283 auto_port = atoi(argv[++i]);
2284 continue;
2285 }
2286 if (!strcmp(arg, "-reflect")) {
2287 CHECK_ARGC
2288 raw_fb_str = (char *) malloc(4 + strlen(argv[i+1]) + 1);
2289 sprintf(raw_fb_str, "vnc:%s", argv[++i]);
2290 shared = 1;
2291 continue;
2292 }
2293 if (!strcmp(arg, "-tsd")) {
2294 CHECK_ARGC
2295 terminal_services_daemon = strdup(argv[++i]);
2296 continue;
2297 }
2298 if (!strcmp(arg, "-id") || !strcmp(arg, "-sid")) {
2299 CHECK_ARGC
2300 if (!strcmp(arg, "-sid")) {
2301 rootshift = 1;
2302 } else {
2303 rootshift = 0;
2304 }
2305 i++;
2306 if (!strcmp("pick", argv[i])) {
2307 if (started_as_root) {
2308 fprintf(stderr, "unsafe: %s pick\n",
2309 arg);
2310 exit(1);
2311 } else if (! pick_windowid(&subwin)) {
2312 fprintf(stderr, "invalid %s pick\n",
2313 arg);
2314 exit(1);
2315 }
2316 } else if (! scan_hexdec(argv[i], &subwin)) {
2317 fprintf(stderr, "invalid %s arg: %s\n", arg,
2318 argv[i]);
2319 exit(1);
2320 }
2321 continue;
2322 }
2323 if (!strcmp(arg, "-waitmapped")) {
2324 subwin_wait_mapped = 1;
2325 continue;
2326 }
2327 if (!strcmp(arg, "-clip")) {
2328 CHECK_ARGC
2329 clip_str = strdup(argv[++i]);
2330 continue;
2331 }
2332 if (!strcmp(arg, "-flashcmap")) {
2333 flash_cmap = 1;
2334 continue;
2335 }
2336 if (!strcmp(arg, "-shiftcmap")) {
2337 CHECK_ARGC
2338 shift_cmap = atoi(argv[++i]);
2339 continue;
2340 }
2341 if (!strcmp(arg, "-notruecolor")) {
2342 force_indexed_color = 1;
2343 continue;
2344 }
2345 if (!strcmp(arg, "-advertise_truecolor")) {
2346 advertise_truecolor = 1;
2347 if (i < argc-1) {
2348 char *s = argv[i+1];
2349 if (s[0] != '-') {
2350 if (strstr(s, "reset")) {
2351 advertise_truecolor_reset = 1;
2352 }
2353 i++;
2354 }
2355 }
2356 continue;
2357 }
2358 if (!strcmp(arg, "-overlay")) {
2359 overlay = 1;
2360 continue;
2361 }
2362 if (!strcmp(arg, "-overlay_nocursor")) {
2363 overlay = 1;
2364 overlay_cursor = 0;
2365 continue;
2366 }
2367 if (!strcmp(arg, "-overlay_yescursor")) {
2368 overlay = 1;
2369 overlay_cursor = 2;
2370 continue;
2371 }
2372 if (!strcmp(arg, "-8to24")) {
2373 #if !SKIP_8TO24
2374 cmap8to24 = 1;
2375 if (i < argc-1) {
2376 char *s = argv[i+1];
2377 if (s[0] != '-') {
2378 cmap8to24_str = strdup(s);
2379 i++;
2380 }
2381 }
2382 #endif
2383 continue;
2384 }
2385 if (!strcmp(arg, "-24to32")) {
2386 xform24to32 = 1;
2387 continue;
2388 }
2389 if (!strcmp(arg, "-visual")) {
2390 CHECK_ARGC
2391 visual_str = strdup(argv[++i]);
2392 continue;
2393 }
2394 if (!strcmp(arg, "-scale")) {
2395 CHECK_ARGC
2396 scale_str = strdup(argv[++i]);
2397 continue;
2398 }
2399 if (!strcmp(arg, "-geometry")) {
2400 CHECK_ARGC
2401 scale_str = strdup(argv[++i]);
2402 continue;
2403 }
2404 if (!strcmp(arg, "-scale_cursor")) {
2405 CHECK_ARGC
2406 scale_cursor_str = strdup(argv[++i]);
2407 continue;
2408 }
2409 if (!strcmp(arg, "-viewonly")) {
2410 view_only = 1;
2411 continue;
2412 }
2413 if (!strcmp(arg, "-noviewonly")) {
2414 view_only = 0;
2415 got_noviewonly = 1;
2416 continue;
2417 }
2418 if (!strcmp(arg, "-shared")) {
2419 shared = 1;
2420 continue;
2421 }
2422 if (!strcmp(arg, "-noshared")) {
2423 shared = 0;
2424 continue;
2425 }
2426 if (!strcmp(arg, "-once")) {
2427 connect_once = 1;
2428 got_connect_once = 1;
2429 continue;
2430 }
2431 if (!strcmp(arg, "-many") || !strcmp(arg, "-forever")) {
2432 connect_once = 0;
2433 continue;
2434 }
2435 if (strstr(arg, "-loop") == arg) {
2436 ; /* handled above */
2437 continue;
2438 }
2439 if (strstr(arg, "-appshare") == arg) {
2440 ; /* handled above */
2441 continue;
2442 }
2443 if (strstr(arg, "-freeze_when_obscured") == arg) {
2444 freeze_when_obscured = 1;
2445 continue;
2446 }
2447 if (!strcmp(arg, "-timeout")) {
2448 CHECK_ARGC
2449 first_conn_timeout = atoi(argv[++i]);
2450 continue;
2451 }
2452 if (!strcmp(arg, "-sleepin")) {
2453 CHECK_ARGC
2454 do_sleepin(argv[++i]);
2455 continue;
2456 }
2457 if (!strcmp(arg, "-users")) {
2458 CHECK_ARGC
2459 users_list = strdup(argv[++i]);
2460 continue;
2461 }
2462 if (!strcmp(arg, "-inetd")) {
2463 inetd = 1;
2464 continue;
2465 }
2466 if (!strcmp(arg, "-notightfilexfer")) {
2467 tightfilexfer = 0;
2468 continue;
2469 }
2470 if (!strcmp(arg, "-tightfilexfer")) {
2471 tightfilexfer = 1;
2472 continue;
2473 }
2474 if (!strcmp(arg, "-http")) {
2475 try_http = 1;
2476 continue;
2477 }
2478 if (!strcmp(arg, "-http_ssl")) {
2479 try_http = 1;
2480 http_ssl = 1;
2481 got_tls++;
2482 continue;
2483 }
2484 if (!strcmp(arg, "-avahi") || !strcmp(arg, "-mdns") || !strcmp(arg, "-zeroconf")) {
2485 avahi = 1;
2486 continue;
2487 }
2488 if (!strcmp(arg, "-connect") ||
2489 !strcmp(arg, "-connect_or_exit") ||
2490 !strcmp(arg, "-coe")) {
2491 CHECK_ARGC
2492 if (!strcmp(arg, "-connect_or_exit")) {
2493 connect_or_exit = 1;
2494 } else if (!strcmp(arg, "-coe")) {
2495 connect_or_exit = 1;
2496 }
2497 if (strchr(argv[++i], '/') && !strstr(argv[i], "repeater://")) {
2498 struct stat sb;
2499 client_connect_file = strdup(argv[i]);
2500 if (stat(client_connect_file, &sb) != 0) {
2501 FILE* f = fopen(client_connect_file, "w");
2502 if (f != NULL) fclose(f);
2503 }
2504 } else {
2505 client_connect = strdup(argv[i]);
2506 }
2507 continue;
2508 }
2509 if (!strcmp(arg, "-proxy")) {
2510 CHECK_ARGC
2511 connect_proxy = strdup(argv[++i]);
2512 continue;
2513 }
2514 if (!strcmp(arg, "-vncconnect")) {
2515 vnc_connect = 1;
2516 continue;
2517 }
2518 if (!strcmp(arg, "-novncconnect")) {
2519 vnc_connect = 0;
2520 continue;
2521 }
2522 if (!strcmp(arg, "-allow")) {
2523 CHECK_ARGC
2524 allow_list = strdup(argv[++i]);
2525 continue;
2526 }
2527 if (!strcmp(arg, "-localhost")) {
2528 allow_list = strdup("127.0.0.1");
2529 got_localhost = 1;
2530 continue;
2531 }
2532 if (!strcmp(arg, "-unixsock")) {
2533 CHECK_ARGC
2534 unix_sock = strdup(argv[++i]);
2535 continue;
2536 }
2537 if (!strcmp(arg, "-listen6")) {
2538 CHECK_ARGC
2539 #if X11VNC_IPV6
2540 listen_str6 = strdup(argv[++i]);
2541 #else
2542 ++i;
2543 #endif
2544 continue;
2545 }
2546 if (!strcmp(arg, "-nolookup")) {
2547 host_lookup = 0;
2548 continue;
2549 }
2550 if (!strcmp(arg, "-6")) {
2551 #if X11VNC_IPV6
2552 ipv6_listen = 1;
2553 got_ipv6_listen = 1;
2554 #endif
2555 continue;
2556 }
2557 if (!strcmp(arg, "-no6")) {
2558 #if X11VNC_IPV6
2559 ipv6_listen = 0;
2560 got_ipv6_listen = 0;
2561 #endif
2562 continue;
2563 }
2564 if (!strcmp(arg, "-noipv6")) {
2565 noipv6 = 1;
2566 continue;
2567 }
2568 if (!strcmp(arg, "-noipv4")) {
2569 noipv4 = 1;
2570 continue;
2571 }
2572
2573 if (!strcmp(arg, "-input")) {
2574 CHECK_ARGC
2575 allowed_input_str = strdup(argv[++i]);
2576 continue;
2577 }
2578 if (!strcmp(arg, "-grabkbd")) {
2579 grab_kbd = 1;
2580 continue;
2581 }
2582 if (!strcmp(arg, "-grabptr")) {
2583 grab_ptr = 1;
2584 continue;
2585 }
2586 if (!strcmp(arg, "-ungrabboth")) {
2587 ungrab_both = 1;
2588 continue;
2589 }
2590 if (!strcmp(arg, "-grabalways")) {
2591 grab_kbd = 1;
2592 grab_ptr = 1;
2593 grab_always = 1;
2594 continue;
2595 }
2596 #ifdef ENABLE_GRABLOCAL
2597 if (!strcmp(arg, "-grablocal")) {
2598 CHECK_ARGC
2599 grab_local = atoi(argv[++i]);
2600 continue;
2601 }
2602 #endif
2603 if (!strcmp(arg, "-viewpasswd")) {
2604 vpw_loc = i;
2605 CHECK_ARGC
2606 viewonly_passwd = strdup(argv[++i]);
2607 got_viewpasswd = 1;
2608 continue;
2609 }
2610 if (!strcmp(arg, "-passwdfile")) {
2611 CHECK_ARGC
2612 passwdfile = strdup(argv[++i]);
2613 got_passwdfile = 1;
2614 continue;
2615 }
2616 if (!strcmp(arg, "-svc") || !strcmp(arg, "-service")) {
2617 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvfb");
2618 unixpw = 1;
2619 users_list = strdup("unixpw=");
2620 use_openssl = 1;
2621 openssl_pem = strdup("SAVE");
2622 continue;
2623 }
2624 if (!strcmp(arg, "-svc_xdummy")) {
2625 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xdummy");
2626 unixpw = 1;
2627 users_list = strdup("unixpw=");
2628 use_openssl = 1;
2629 openssl_pem = strdup("SAVE");
2630 continue;
2631 }
2632 if (!strcmp(arg, "-svc_xdummy_xvfb")) {
2633 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xdummy,Xvfb");
2634 unixpw = 1;
2635 users_list = strdup("unixpw=");
2636 use_openssl = 1;
2637 openssl_pem = strdup("SAVE");
2638 continue;
2639 }
2640 if (!strcmp(arg, "-svc_xvnc")) {
2641 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvnc");
2642 unixpw = 1;
2643 users_list = strdup("unixpw=");
2644 use_openssl = 1;
2645 openssl_pem = strdup("SAVE");
2646 continue;
2647 }
2648 if (!strcmp(arg, "-xdmsvc") || !strcmp(arg, "-xdm_service")) {
2649 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvfb.xdmcp");
2650 unixpw = 1;
2651 users_list = strdup("unixpw=");
2652 use_openssl = 1;
2653 openssl_pem = strdup("SAVE");
2654 continue;
2655 }
2656 if (!strcmp(arg, "-sshxdmsvc")) {
2657 use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvfb.xdmcp");
2658 allow_list = strdup("127.0.0.1");
2659 got_localhost = 1;
2660 continue;
2661 }
2662 if (!strcmp(arg, "-unixpw_system_greeter")) {
2663 unixpw_system_greeter = 1;
2664 continue;
2665 }
2666 if (!strcmp(arg, "-unixpw_cmd")
2667 || !strcmp(arg, "-unixpw_cmd_unsafe")) {
2668 CHECK_ARGC
2669 unixpw_cmd = strdup(argv[++i]);
2670 unixpw = 1;
2671 if (strstr(arg, "_unsafe")) {
2672 /* hidden option for testing. */
2673 set_env("UNIXPW_DISABLE_SSL", "1");
2674 set_env("UNIXPW_DISABLE_LOCALHOST", "1");
2675 }
2676 continue;
2677 }
2678 if (strstr(arg, "-unixpw") == arg) {
2679 unixpw = 1;
2680 if (strstr(arg, "-unixpw_nis")) {
2681 unixpw_nis = 1;
2682 }
2683 if (i < argc-1) {
2684 char *s = argv[i+1];
2685 if (s[0] != '-') {
2686 unixpw_list = strdup(s);
2687 i++;
2688 }
2689 if (s[0] == '%') {
2690 unixpw_list = NULL;
2691 quick_pw(s);
2692 exit(2);
2693 }
2694 }
2695 if (strstr(arg, "_unsafe")) {
2696 /* hidden option for testing. */
2697 set_env("UNIXPW_DISABLE_SSL", "1");
2698 set_env("UNIXPW_DISABLE_LOCALHOST", "1");
2699 }
2700 continue;
2701 }
2702 if (strstr(arg, "-nounixpw") == arg) {
2703 unixpw = 0;
2704 unixpw_nis = 0;
2705 if (unixpw_list) {
2706 unixpw_list = NULL;
2707 }
2708 if (unixpw_cmd) {
2709 unixpw_cmd = NULL;
2710 }
2711 continue;
2712 }
2713 if (!strcmp(arg, "-vencrypt")) {
2714 char *s;
2715 CHECK_ARGC
2716 s = strdup(argv[++i]);
2717 got_tls++;
2718 if (strstr(s, "never")) {
2719 vencrypt_mode = VENCRYPT_NONE;
2720 } else if (strstr(s, "support")) {
2721 vencrypt_mode = VENCRYPT_SUPPORT;
2722 } else if (strstr(s, "only")) {
2723 vencrypt_mode = VENCRYPT_SOLE;
2724 } else if (strstr(s, "force")) {
2725 vencrypt_mode = VENCRYPT_FORCE;
2726 } else {
2727 fprintf(stderr, "invalid %s arg: %s\n", arg, s);
2728 exit(1);
2729 }
2730 if (strstr(s, "nodh")) {
2731 vencrypt_kx = VENCRYPT_NODH;
2732 } else if (strstr(s, "nox509")) {
2733 vencrypt_kx = VENCRYPT_NOX509;
2734 }
2735 if (strstr(s, "newdh")) {
2736 create_fresh_dhparams = 1;
2737 }
2738 if (strstr(s, "noplain")) {
2739 vencrypt_enable_plain_login = 0;
2740 } else if (strstr(s, "plain")) {
2741 vencrypt_enable_plain_login = 1;
2742 }
2743 free(s);
2744 continue;
2745 }
2746 if (!strcmp(arg, "-anontls")) {
2747 char *s;
2748 CHECK_ARGC
2749 s = strdup(argv[++i]);
2750 got_tls++;
2751 if (strstr(s, "never")) {
2752 anontls_mode = ANONTLS_NONE;
2753 } else if (strstr(s, "support")) {
2754 anontls_mode = ANONTLS_SUPPORT;
2755 } else if (strstr(s, "only")) {
2756 anontls_mode = ANONTLS_SOLE;
2757 } else if (strstr(s, "force")) {
2758 anontls_mode = ANONTLS_FORCE;
2759 } else {
2760 fprintf(stderr, "invalid %s arg: %s\n", arg, s);
2761 exit(1);
2762 }
2763 if (strstr(s, "newdh")) {
2764 create_fresh_dhparams = 1;
2765 }
2766 free(s);
2767 continue;
2768 }
2769 if (!strcmp(arg, "-sslonly")) {
2770 vencrypt_mode = VENCRYPT_NONE;
2771 anontls_mode = ANONTLS_NONE;
2772 got_tls++;
2773 continue;
2774 }
2775 if (!strcmp(arg, "-dhparams")) {
2776 CHECK_ARGC
2777 dhparams_file = strdup(argv[++i]);
2778 got_tls++;
2779 continue;
2780 }
2781 if (!strcmp(arg, "-nossl")) {
2782 use_openssl = 0;
2783 openssl_pem = NULL;
2784 got_tls = -1000;
2785 continue;
2786 }
2787 if (!strcmp(arg, "-ssl")) {
2788 use_openssl = 1;
2789 if (i < argc-1) {
2790 char *s = argv[i+1];
2791 if (s[0] != '-') {
2792 if (!strcmp(s, "ADH")) {
2793 openssl_pem = strdup("ANON");
2794 } else if (!strcmp(s, "ANONDH")) {
2795 openssl_pem = strdup("ANON");
2796 } else if (!strcmp(s, "TMP")) {
2797 openssl_pem = NULL;
2798 } else {
2799 openssl_pem = strdup(s);
2800 }
2801 i++;
2802 } else {
2803 openssl_pem = strdup("SAVE");
2804 }
2805 } else {
2806 openssl_pem = strdup("SAVE");
2807 }
2808 continue;
2809 }
2810 if (!strcmp(arg, "-enc")) {
2811 use_openssl = 1;
2812 CHECK_ARGC
2813 enc_str = strdup(argv[++i]);
2814 continue;
2815 }
2816 if (!strcmp(arg, "-http_oneport")) {
2817 http_oneport_msg = 1;
2818 use_openssl = 1;
2819 enc_str = strdup("none");
2820 continue;
2821 }
2822 if (!strcmp(arg, "-ssltimeout")) {
2823 CHECK_ARGC
2824 ssl_timeout_secs = atoi(argv[++i]);
2825 continue;
2826 }
2827 if (!strcmp(arg, "-sslnofail")) {
2828 ssl_no_fail = 1;
2829 continue;
2830 }
2831 if (!strcmp(arg, "-ssldir")) {
2832 CHECK_ARGC
2833 ssl_certs_dir = strdup(argv[++i]);
2834 continue;
2835 }
2836 if (!strcmp(arg, "-sslverify")) {
2837 CHECK_ARGC
2838 ssl_verify = strdup(argv[++i]);
2839 got_tls++;
2840 continue;
2841 }
2842 if (!strcmp(arg, "-sslCRL")) {
2843 CHECK_ARGC
2844 ssl_crl = strdup(argv[++i]);
2845 got_tls++;
2846 continue;
2847 }
2848 if (!strcmp(arg, "-sslGenCA")) {
2849 char *cdir = NULL;
2850 if (i < argc-1) {
2851 char *s = argv[i+1];
2852 if (s[0] != '-') {
2853 cdir = strdup(s);
2854 i++;
2855 }
2856 }
2857 sslGenCA(cdir);
2858 exit(0);
2859 continue;
2860 }
2861 if (!strcmp(arg, "-sslGenCert")) {
2862 char *ty, *nm = NULL;
2863 if (i >= argc-1) {
2864 fprintf(stderr, "Must be:\n");
2865 fprintf(stderr, " x11vnc -sslGenCert server ...\n");
2866 fprintf(stderr, "or x11vnc -sslGenCert client ...\n");
2867 exit(1);
2868 }
2869 ty = argv[i+1];
2870 if (strcmp(ty, "server") && strcmp(ty, "client")) {
2871 fprintf(stderr, "Must be:\n");
2872 fprintf(stderr, " x11vnc -sslGenCert server ...\n");
2873 fprintf(stderr, "or x11vnc -sslGenCert client ...\n");
2874 exit(1);
2875 }
2876 if (i < argc-2) {
2877 nm = argv[i+2];
2878 }
2879 sslGenCert(ty, nm);
2880 exit(0);
2881 continue;
2882 }
2883 if (!strcmp(arg, "-sslEncKey")) {
2884 if (i < argc-1) {
2885 char *s = argv[i+1];
2886 sslEncKey(s, 0);
2887 }
2888 exit(0);
2889 continue;
2890 }
2891 if (!strcmp(arg, "-sslCertInfo")) {
2892 if (i < argc-1) {
2893 char *s = argv[i+1];
2894 sslEncKey(s, 1);
2895 }
2896 exit(0);
2897 continue;
2898 }
2899 if (!strcmp(arg, "-sslDelCert")) {
2900 if (i < argc-1) {
2901 char *s = argv[i+1];
2902 sslEncKey(s, 2);
2903 }
2904 exit(0);
2905 continue;
2906 }
2907 if (!strcmp(arg, "-sslScripts")) {
2908 sslScripts();
2909 exit(0);
2910 continue;
2911 }
2912 if (!strcmp(arg, "-stunnel")) {
2913 use_stunnel = 1;
2914 got_tls = -1000;
2915 if (i < argc-1) {
2916 char *s = argv[i+1];
2917 if (s[0] != '-') {
2918 if (!strcmp(s, "TMP")) {
2919 stunnel_pem = NULL;
2920 } else {
2921 stunnel_pem = strdup(s);
2922 }
2923 i++;
2924 } else {
2925 stunnel_pem = strdup("SAVE");
2926 }
2927 } else {
2928 stunnel_pem = strdup("SAVE");
2929 }
2930 continue;
2931 }
2932 if (!strcmp(arg, "-stunnel3")) {
2933 use_stunnel = 3;
2934 got_tls = -1000;
2935 if (i < argc-1) {
2936 char *s = argv[i+1];
2937 if (s[0] != '-') {
2938 if (!strcmp(s, "TMP")) {
2939 stunnel_pem = NULL;
2940 } else {
2941 stunnel_pem = strdup(s);
2942 }
2943 i++;
2944 } else {
2945 stunnel_pem = strdup("SAVE");
2946 }
2947 } else {
2948 stunnel_pem = strdup("SAVE");
2949 }
2950 continue;
2951 }
2952 if (!strcmp(arg, "-https")) {
2953 https_port_num = 0;
2954 try_http = 1;
2955 got_tls++;
2956 if (i < argc-1) {
2957 char *s = argv[i+1];
2958 if (s[0] != '-') {
2959 https_port_num = atoi(s);
2960 i++;
2961 }
2962 }
2963 continue;
2964 }
2965 if (!strcmp(arg, "-httpsredir")) {
2966 https_port_redir = -1;
2967 got_tls++;
2968 if (i < argc-1) {
2969 char *s = argv[i+1];
2970 if (s[0] != '-') {
2971 https_port_redir = atoi(s);
2972 i++;
2973 }
2974 }
2975 continue;
2976 }
2977 if (!strcmp(arg, "-nopw")) {
2978 nopw = 1;
2979 continue;
2980 }
2981 if (!strcmp(arg, "-ssh")) {
2982 CHECK_ARGC
2983 ssh_str = strdup(argv[++i]);
2984 continue;
2985 }
2986 if (!strcmp(arg, "-usepw")) {
2987 usepw = 1;
2988 continue;
2989 }
2990 if (!strcmp(arg, "-storepasswd")) {
2991 if (argc == i+1) {
2992 store_homedir_passwd(NULL);
2993 exit(0);
2994 }
2995 if (argc == i+2) {
2996 store_homedir_passwd(argv[i+1]);
2997 exit(0);
2998 }
2999 if (argc >= i+4 || rfbEncryptAndStorePasswd(argv[i+1],
3000 argv[i+2]) != 0) {
3001 perror("storepasswd");
3002 fprintf(stderr, "-storepasswd failed for file: %s\n",
3003 argv[i+2]);
3004 exit(1);
3005 } else {
3006 fprintf(stderr, "stored passwd in file: %s\n",
3007 argv[i+2]);
3008 exit(0);
3009 }
3010 continue;
3011 }
3012 if (!strcmp(arg, "-showrfbauth")) {
3013 if (argc >= i+2) {
3014 char *f = argv[i+1];
3015 char *s = rfbDecryptPasswdFromFile(f);
3016 if (!s) {
3017 perror("showrfbauth");
3018 fprintf(stderr, "rfbDecryptPasswdFromFile failed: %s\n", f);
3019 exit(1);
3020 }
3021 fprintf(stdout, "rfbDecryptPasswdFromFile file: %s\n", f);
3022 fprintf(stdout, "rfbDecryptPasswdFromFile pass: %s\n", s);
3023 }
3024 exit(0);
3025 }
3026 if (!strcmp(arg, "-accept")) {
3027 CHECK_ARGC
3028 accept_cmd = strdup(argv[++i]);
3029 continue;
3030 }
3031 if (!strcmp(arg, "-afteraccept")) {
3032 CHECK_ARGC
3033 afteraccept_cmd = strdup(argv[++i]);
3034 continue;
3035 }
3036 if (!strcmp(arg, "-gone")) {
3037 CHECK_ARGC
3038 gone_cmd = strdup(argv[++i]);
3039 continue;
3040 }
3041 if (!strcmp(arg, "-noshm")) {
3042 using_shm = 0;
3043 continue;
3044 }
3045 if (!strcmp(arg, "-flipbyteorder")) {
3046 flip_byte_order = 1;
3047 continue;
3048 }
3049 if (!strcmp(arg, "-onetile")) {
3050 single_copytile = 1;
3051 continue;
3052 }
3053 if (!strcmp(arg, "-solid")) {
3054 use_solid_bg = 1;
3055 if (i < argc-1) {
3056 char *s = argv[i+1];
3057 if (s[0] != '-') {
3058 solid_str = strdup(s);
3059 i++;
3060 }
3061 }
3062 if (! solid_str) {
3063 solid_str = strdup(solid_default);
3064 }
3065 continue;
3066 }
3067 if (!strcmp(arg, "-blackout")) {
3068 CHECK_ARGC
3069 blackout_str = strdup(argv[++i]);
3070 continue;
3071 }
3072 if (!strcmp(arg, "-xinerama")) {
3073 xinerama = 1;
3074 continue;
3075 }
3076 if (!strcmp(arg, "-noxinerama")) {
3077 xinerama = 0;
3078 continue;
3079 }
3080 if (!strcmp(arg, "-xtrap")) {
3081 xtrap_input = 1;
3082 continue;
3083 }
3084 if (!strcmp(arg, "-xrandr")) {
3085 xrandr = 1;
3086 if (i < argc-1) {
3087 char *s = argv[i+1];
3088 if (known_xrandr_mode(s)) {
3089 xrandr_mode = strdup(s);
3090 i++;
3091 }
3092 }
3093 continue;
3094 }
3095 if (!strcmp(arg, "-noxrandr")) {
3096 xrandr = 0;
3097 xrandr_maybe = 0;
3098 got_noxrandr = 1;
3099 continue;
3100 }
3101 if (!strcmp(arg, "-rotate")) {
3102 CHECK_ARGC
3103 rotating_str = strdup(argv[++i]);
3104 continue;
3105 }
3106 if (!strcmp(arg, "-padgeom")
3107 || !strcmp(arg, "-padgeometry")) {
3108 CHECK_ARGC
3109 pad_geometry = strdup(argv[++i]);
3110 continue;
3111 }
3112 if (!strcmp(arg, "-o") || !strcmp(arg, "-logfile")) {
3113 CHECK_ARGC
3114 logfile_append = 0;
3115 logfile = strdup(argv[++i]);
3116 continue;
3117 }
3118 if (!strcmp(arg, "-oa") || !strcmp(arg, "-logappend")) {
3119 CHECK_ARGC
3120 logfile_append = 1;
3121 logfile = strdup(argv[++i]);
3122 continue;
3123 }
3124 if (!strcmp(arg, "-flag")) {
3125 CHECK_ARGC
3126 flagfile = strdup(argv[++i]);
3127 continue;
3128 }
3129 if (!strcmp(arg, "-rmflag")) {
3130 CHECK_ARGC
3131 rm_flagfile = strdup(argv[++i]);
3132 continue;
3133 }
3134 if (!strcmp(arg, "-rc")) {
3135 i++; /* done above */
3136 continue;
3137 }
3138 if (!strcmp(arg, "-norc")) {
3139 ; /* done above */
3140 continue;
3141 }
3142 if (!strcmp(arg, "-env")) {
3143 i++; /* done above */
3144 continue;
3145 }
3146 if (!strcmp(arg, "-prog")) {
3147 CHECK_ARGC
3148 if (program_name) {
3149 free(program_name);
3150 }
3151 program_name = strdup(argv[++i]);
3152 continue;
3153 }
3154 if (!strcmp(arg, "-h") || !strcmp(arg, "-help")) {
3155 print_help(0);
3156 continue;
3157 }
3158 if (!strcmp(arg, "-?") || !strcmp(arg, "-opts")) {
3159 print_help(1);
3160 continue;
3161 }
3162 if (!strcmp(arg, "-V") || !strcmp(arg, "-version")) {
3163 fprintf(stdout, "x11vnc: %s\n", lastmod);
3164 exit(0);
3165 continue;
3166 }
3167 if (!strcmp(arg, "-license") ||
3168 !strcmp(arg, "-copying") || !strcmp(arg, "-warranty")) {
3169 print_license();
3170 continue;
3171 }
3172 if (!strcmp(arg, "-dbg")) {
3173 crash_debug = 1;
3174 continue;
3175 }
3176 if (!strcmp(arg, "-nodbg")) {
3177 crash_debug = 0;
3178 continue;
3179 }
3180 if (!strcmp(arg, "-q") || !strcmp(arg, "-quiet")) {
3181 quiet = 1;
3182 continue;
3183 }
3184 if (!strcmp(arg, "-noquiet")) {
3185 quiet = 0;
3186 continue;
3187 }
3188 if (!strcmp(arg, "-v") || !strcmp(arg, "-verbose")) {
3189 verbose = 1;
3190 continue;
3191 }
3192 if (!strcmp(arg, "-bg") || !strcmp(arg, "-background")) {
3193 #if LIBVNCSERVER_HAVE_SETSID
3194 bg = 1;
3195 opts_bg = bg;
3196 #else
3197 if (!got_inetd) {
3198 fprintf(stderr, "warning: -bg mode not supported.\n");
3199 }
3200 #endif
3201 continue;
3202 }
3203 if (!strcmp(arg, "-modtweak")) {
3204 use_modifier_tweak = 1;
3205 continue;
3206 }
3207 if (!strcmp(arg, "-nomodtweak")) {
3208 use_modifier_tweak = 0;
3209 got_nomodtweak = 1;
3210 continue;
3211 }
3212 if (!strcmp(arg, "-isolevel3")) {
3213 use_iso_level3 = 1;
3214 continue;
3215 }
3216 if (!strcmp(arg, "-xkb")) {
3217 use_modifier_tweak = 1;
3218 use_xkb_modtweak = 1;
3219 continue;
3220 }
3221 if (!strcmp(arg, "-noxkb")) {
3222 use_xkb_modtweak = 0;
3223 got_noxkb = 1;
3224 continue;
3225 }
3226 if (!strcmp(arg, "-capslock")) {
3227 watch_capslock = 1;
3228 continue;
3229 }
3230 if (!strcmp(arg, "-skip_lockkeys")) {
3231 skip_lockkeys = 1;
3232 continue;
3233 }
3234 if (!strcmp(arg, "-noskip_lockkeys")) {
3235 skip_lockkeys = 0;
3236 continue;
3237 }
3238 if (!strcmp(arg, "-xkbcompat")) {
3239 xkbcompat = 1;
3240 continue;
3241 }
3242 if (!strcmp(arg, "-skip_keycodes")) {
3243 CHECK_ARGC
3244 skip_keycodes = strdup(argv[++i]);
3245 continue;
3246 }
3247 if (!strcmp(arg, "-sloppy_keys")) {
3248 sloppy_keys++;
3249 continue;
3250 }
3251 if (!strcmp(arg, "-skip_dups")) {
3252 skip_duplicate_key_events = 1;
3253 continue;
3254 }
3255 if (!strcmp(arg, "-noskip_dups")) {
3256 skip_duplicate_key_events = 0;
3257 continue;
3258 }
3259 if (!strcmp(arg, "-add_keysyms")) {
3260 add_keysyms++;
3261 continue;
3262 }
3263 if (!strcmp(arg, "-noadd_keysyms")) {
3264 add_keysyms = 0;
3265 continue;
3266 }
3267 if (!strcmp(arg, "-clear_mods")) {
3268 clear_mods = 1;
3269 continue;
3270 }
3271 if (!strcmp(arg, "-clear_keys")) {
3272 clear_mods = 2;
3273 continue;
3274 }
3275 if (!strcmp(arg, "-clear_all")) {
3276 clear_mods = 3;
3277 continue;
3278 }
3279 if (!strcmp(arg, "-remap")) {
3280 CHECK_ARGC
3281 remap_file = strdup(argv[++i]);
3282 continue;
3283 }
3284 if (!strcmp(arg, "-norepeat")) {
3285 no_autorepeat = 1;
3286 if (i < argc-1) {
3287 char *s = argv[i+1];
3288 if (*s == '-') {
3289 s++;
3290 }
3291 if (isdigit((unsigned char) (*s))) {
3292 no_repeat_countdown = atoi(argv[++i]);
3293 }
3294 }
3295 continue;
3296 }
3297 if (!strcmp(arg, "-repeat")) {
3298 no_autorepeat = 0;
3299 continue;
3300 }
3301 if (!strcmp(arg, "-nofb")) {
3302 nofb = 1;
3303 continue;
3304 }
3305 if (!strcmp(arg, "-nobell")) {
3306 watch_bell = 0;
3307 sound_bell = 0;
3308 continue;
3309 }
3310 if (!strcmp(arg, "-nosel")) {
3311 watch_selection = 0;
3312 watch_primary = 0;
3313 watch_clipboard = 0;
3314 continue;
3315 }
3316 if (!strcmp(arg, "-noprimary")) {
3317 watch_primary = 0;
3318 continue;
3319 }
3320 if (!strcmp(arg, "-nosetprimary")) {
3321 set_primary = 0;
3322 continue;
3323 }
3324 if (!strcmp(arg, "-noclipboard")) {
3325 watch_clipboard = 0;
3326 continue;
3327 }
3328 if (!strcmp(arg, "-nosetclipboard")) {
3329 set_clipboard = 0;
3330 continue;
3331 }
3332 if (!strcmp(arg, "-seldir")) {
3333 CHECK_ARGC
3334 sel_direction = strdup(argv[++i]);
3335 continue;
3336 }
3337 if (!strcmp(arg, "-cursor")) {
3338 show_cursor = 1;
3339 if (i < argc-1) {
3340 char *s = argv[i+1];
3341 if (known_cursors_mode(s)) {
3342 multiple_cursors_mode = strdup(s);
3343 i++;
3344 if (!strcmp(s, "none")) {
3345 show_cursor = 0;
3346 }
3347 }
3348 }
3349 continue;
3350 }
3351 if (!strcmp(arg, "-nocursor")) {
3352 multiple_cursors_mode = strdup("none");
3353 show_cursor = 0;
3354 continue;
3355 }
3356 if (!strcmp(arg, "-cursor_drag")) {
3357 cursor_drag_changes = 1;
3358 continue;
3359 }
3360 if (!strcmp(arg, "-nocursor_drag")) {
3361 cursor_drag_changes = 0;
3362 continue;
3363 }
3364 if (!strcmp(arg, "-arrow")) {
3365 CHECK_ARGC
3366 alt_arrow = atoi(argv[++i]);
3367 continue;
3368 }
3369 if (!strcmp(arg, "-xfixes")) {
3370 use_xfixes = 1;
3371 continue;
3372 }
3373 if (!strcmp(arg, "-noxfixes")) {
3374 use_xfixes = 0;
3375 continue;
3376 }
3377 if (!strcmp(arg, "-alphacut")) {
3378 CHECK_ARGC
3379 alpha_threshold = atoi(argv[++i]);
3380 continue;
3381 }
3382 if (!strcmp(arg, "-alphafrac")) {
3383 CHECK_ARGC
3384 alpha_frac = atof(argv[++i]);
3385 continue;
3386 }
3387 if (!strcmp(arg, "-alpharemove")) {
3388 alpha_remove = 1;
3389 continue;
3390 }
3391 if (!strcmp(arg, "-noalphablend")) {
3392 alpha_blend = 0;
3393 continue;
3394 }
3395 if (!strcmp(arg, "-nocursorshape")) {
3396 cursor_shape_updates = 0;
3397 continue;
3398 }
3399 if (!strcmp(arg, "-cursorpos")) {
3400 cursor_pos_updates = 1;
3401 got_cursorpos = 1;
3402 continue;
3403 }
3404 if (!strcmp(arg, "-nocursorpos")) {
3405 cursor_pos_updates = 0;
3406 continue;
3407 }
3408 if (!strcmp(arg, "-xwarppointer")) {
3409 use_xwarppointer = 1;
3410 continue;
3411 }
3412 if (!strcmp(arg, "-noxwarppointer")) {
3413 use_xwarppointer = 0;
3414 got_noxwarppointer = 1;
3415 continue;
3416 }
3417 if (!strcmp(arg, "-always_inject")) {
3418 always_inject = 1;
3419 continue;
3420 }
3421 if (!strcmp(arg, "-buttonmap")) {
3422 CHECK_ARGC
3423 pointer_remap = strdup(argv[++i]);
3424 continue;
3425 }
3426 if (!strcmp(arg, "-nodragging")) {
3427 show_dragging = 0;
3428 continue;
3429 }
3430 #ifndef NO_NCACHE
3431 if (!strcmp(arg, "-ncache") || !strcmp(arg, "-nc")) {
3432 if (i < argc-1) {
3433 char *s = argv[i+1];
3434 if (s[0] != '-') {
3435 ncache = atoi(s);
3436 i++;
3437 } else {
3438 ncache = ncache_default;
3439 }
3440 } else {
3441 ncache = ncache_default;
3442 }
3443 if (ncache % 2 != 0) {
3444 ncache++;
3445 }
3446 continue;
3447 }
3448 if (!strcmp(arg, "-noncache") || !strcmp(arg, "-nonc")) {
3449 ncache = 0;
3450 continue;
3451 }
3452 if (!strcmp(arg, "-ncache_cr") || !strcmp(arg, "-nc_cr")) {
3453 ncache_copyrect = 1;
3454 continue;
3455 }
3456 if (!strcmp(arg, "-ncache_no_moveraise") || !strcmp(arg, "-nc_no_moveraise")) {
3457 ncache_wf_raises = 1;
3458 continue;
3459 }
3460 if (!strcmp(arg, "-ncache_no_dtchange") || !strcmp(arg, "-nc_no_dtchange")) {
3461 ncache_dt_change = 0;
3462 continue;
3463 }
3464 if (!strcmp(arg, "-ncache_no_rootpixmap") || !strcmp(arg, "-nc_no_rootpixmap")) {
3465 ncache_xrootpmap = 0;
3466 continue;
3467 }
3468 if (!strcmp(arg, "-ncache_keep_anims") || !strcmp(arg, "-nc_keep_anims")) {
3469 ncache_keep_anims = 1;
3470 continue;
3471 }
3472 if (!strcmp(arg, "-ncache_old_wm") || !strcmp(arg, "-nc_old_wm")) {
3473 ncache_old_wm = 1;
3474 continue;
3475 }
3476 if (!strcmp(arg, "-ncache_pad") || !strcmp(arg, "-nc_pad")) {
3477 CHECK_ARGC
3478 ncache_pad = atoi(argv[++i]);
3479 continue;
3480 }
3481 if (!strcmp(arg, "-debug_ncache")) {
3482 ncdb++;
3483 continue;
3484 }
3485 #endif
3486 if (!strcmp(arg, "-wireframe")
3487 || !strcmp(arg, "-wf")) {
3488 wireframe = 1;
3489 if (i < argc-1) {
3490 char *s = argv[i+1];
3491 if (*s != '-') {
3492 wireframe_str = strdup(argv[++i]);
3493 }
3494 }
3495 continue;
3496 }
3497 if (!strcmp(arg, "-nowireframe")
3498 || !strcmp(arg, "-nowf")) {
3499 wireframe = 0;
3500 continue;
3501 }
3502 if (!strcmp(arg, "-nowireframelocal")
3503 || !strcmp(arg, "-nowfl")) {
3504 wireframe_local = 0;
3505 continue;
3506 }
3507 if (!strcmp(arg, "-wirecopyrect")
3508 || !strcmp(arg, "-wcr")) {
3509 CHECK_ARGC
3510 set_wirecopyrect_mode(argv[++i]);
3511 got_wirecopyrect = 1;
3512 continue;
3513 }
3514 if (!strcmp(arg, "-nowirecopyrect")
3515 || !strcmp(arg, "-nowcr")) {
3516 set_wirecopyrect_mode("never");
3517 continue;
3518 }
3519 if (!strcmp(arg, "-debug_wireframe")
3520 || !strcmp(arg, "-dwf")) {
3521 debug_wireframe++;
3522 continue;
3523 }
3524 if (!strcmp(arg, "-scrollcopyrect")
3525 || !strcmp(arg, "-scr")) {
3526 CHECK_ARGC
3527 set_scrollcopyrect_mode(argv[++i]);
3528 got_scrollcopyrect = 1;
3529 continue;
3530 }
3531 if (!strcmp(arg, "-noscrollcopyrect")
3532 || !strcmp(arg, "-noscr")) {
3533 set_scrollcopyrect_mode("never");
3534 continue;
3535 }
3536 if (!strcmp(arg, "-scr_area")) {
3537 int tn;
3538 CHECK_ARGC
3539 tn = atoi(argv[++i]);
3540 if (tn >= 0) {
3541 scrollcopyrect_min_area = tn;
3542 }
3543 continue;
3544 }
3545 if (!strcmp(arg, "-scr_skip")) {
3546 CHECK_ARGC
3547 scroll_skip_str = strdup(argv[++i]);
3548 continue;
3549 }
3550 if (!strcmp(arg, "-scr_inc")) {
3551 CHECK_ARGC
3552 scroll_good_str = strdup(argv[++i]);
3553 continue;
3554 }
3555 if (!strcmp(arg, "-scr_keys")) {
3556 CHECK_ARGC
3557 scroll_key_list_str = strdup(argv[++i]);
3558 continue;
3559 }
3560 if (!strcmp(arg, "-scr_term")) {
3561 CHECK_ARGC
3562 scroll_term_str = strdup(argv[++i]);
3563 continue;
3564 }
3565 if (!strcmp(arg, "-scr_keyrepeat")) {
3566 CHECK_ARGC
3567 max_keyrepeat_str = strdup(argv[++i]);
3568 continue;
3569 }
3570 if (!strcmp(arg, "-scr_parms")) {
3571 CHECK_ARGC
3572 scroll_copyrect_str = strdup(argv[++i]);
3573 continue;
3574 }
3575 if (!strcmp(arg, "-fixscreen")) {
3576 CHECK_ARGC
3577 screen_fixup_str = strdup(argv[++i]);
3578 continue;
3579 }
3580 if (!strcmp(arg, "-debug_scroll")
3581 || !strcmp(arg, "-ds")) {
3582 debug_scroll++;
3583 continue;
3584 }
3585 if (!strcmp(arg, "-noxrecord")) {
3586 noxrecord = 1;
3587 continue;
3588 }
3589 if (!strcmp(arg, "-pointer_mode")
3590 || !strcmp(arg, "-pm")) {
3591 char *p, *s;
3592 CHECK_ARGC
3593 s = argv[++i];
3594 if ((p = strchr(s, ':')) != NULL) {
3595 ui_skip = atoi(p+1);
3596 if (! ui_skip) ui_skip = 1;
3597 *p = '\0';
3598 }
3599 if (atoi(s) < 1 || atoi(s) > pointer_mode_max) {
3600 if (!got_inetd) {
3601 rfbLog("pointer_mode out of range 1-%d: %d\n",
3602 pointer_mode_max, atoi(s));
3603 }
3604 } else {
3605 pointer_mode = atoi(s);
3606 got_pointer_mode = pointer_mode;
3607 }
3608 continue;
3609 }
3610 if (!strcmp(arg, "-input_skip")) {
3611 CHECK_ARGC
3612 ui_skip = atoi(argv[++i]);
3613 if (! ui_skip) ui_skip = 1;
3614 continue;
3615 }
3616 if (!strcmp(arg, "-allinput")) {
3617 all_input = 1;
3618 continue;
3619 }
3620 if (!strcmp(arg, "-noallinput")) {
3621 all_input = 0;
3622 continue;
3623 }
3624 if (!strcmp(arg, "-input_eagerly")) {
3625 handle_events_eagerly = 1;
3626 continue;
3627 }
3628 if (!strcmp(arg, "-noinput_eagerly")) {
3629 handle_events_eagerly = 0;
3630 continue;
3631 }
3632 if (!strcmp(arg, "-speeds")) {
3633 CHECK_ARGC
3634 speeds_str = strdup(argv[++i]);
3635 continue;
3636 }
3637 if (!strcmp(arg, "-wmdt")) {
3638 CHECK_ARGC
3639 wmdt_str = strdup(argv[++i]);
3640 continue;
3641 }
3642 if (!strcmp(arg, "-debug_pointer")
3643 || !strcmp(arg, "-dp")) {
3644 debug_pointer++;
3645 continue;
3646 }
3647 if (!strcmp(arg, "-debug_keyboard")
3648 || !strcmp(arg, "-dk")) {
3649 debug_keyboard++;
3650 continue;
3651 }
3652 if (!strcmp(arg, "-debug_xdamage")) {
3653 debug_xdamage++;
3654 continue;
3655 }
3656 if (!strcmp(arg, "-defer")) {
3657 CHECK_ARGC
3658 defer_update = atoi(argv[++i]);
3659 got_defer = 1;
3660 continue;
3661 }
3662 if (!strcmp(arg, "-setdefer")) {
3663 CHECK_ARGC
3664 set_defer = atoi(argv[++i]);
3665 continue;
3666 }
3667 if (!strcmp(arg, "-wait")) {
3668 CHECK_ARGC
3669 waitms = atoi(argv[++i]);
3670 got_waitms = 1;
3671 continue;
3672 }
3673 if (!strcmp(arg, "-extra_fbur")) {
3674 CHECK_ARGC
3675 extra_fbur = atoi(argv[++i]);
3676 continue;
3677 }
3678 if (!strcmp(arg, "-wait_ui")) {
3679 CHECK_ARGC
3680 wait_ui = atof(argv[++i]);
3681 continue;
3682 }
3683 if (!strcmp(arg, "-nowait_bog")) {
3684 wait_bog = 0;
3685 continue;
3686 }
3687 if (!strcmp(arg, "-slow_fb")) {
3688 CHECK_ARGC
3689 slow_fb = atof(argv[++i]);
3690 continue;
3691 }
3692 if (!strcmp(arg, "-xrefresh")) {
3693 CHECK_ARGC
3694 xrefresh = atof(argv[++i]);
3695 continue;
3696 }
3697 if (!strcmp(arg, "-readtimeout")) {
3698 CHECK_ARGC
3699 rfbMaxClientWait = atoi(argv[++i]) * 1000;
3700 continue;
3701 }
3702 if (!strcmp(arg, "-ping")) {
3703 CHECK_ARGC
3704 ping_interval = atoi(argv[++i]);
3705 continue;
3706 }
3707 if (!strcmp(arg, "-nap")) {
3708 take_naps = 1;
3709 continue;
3710 }
3711 if (!strcmp(arg, "-nonap")) {
3712 take_naps = 0;
3713 continue;
3714 }
3715 if (!strcmp(arg, "-sb")) {
3716 CHECK_ARGC
3717 screen_blank = atoi(argv[++i]);
3718 continue;
3719 }
3720 if (!strcmp(arg, "-nofbpm")) {
3721 watch_fbpm = 1;
3722 continue;
3723 }
3724 if (!strcmp(arg, "-fbpm")) {
3725 watch_fbpm = 0;
3726 continue;
3727 }
3728 if (!strcmp(arg, "-nodpms")) {
3729 watch_dpms = 1;
3730 continue;
3731 }
3732 if (!strcmp(arg, "-dpms")) {
3733 watch_dpms = 0;
3734 continue;
3735 }
3736 if (!strcmp(arg, "-forcedpms")) {
3737 force_dpms = 1;
3738 continue;
3739 }
3740 if (!strcmp(arg, "-clientdpms")) {
3741 client_dpms = 1;
3742 continue;
3743 }
3744 if (!strcmp(arg, "-noserverdpms")) {
3745 no_ultra_dpms = 1;
3746 continue;
3747 }
3748 if (!strcmp(arg, "-noultraext")) {
3749 no_ultra_ext = 1;
3750 continue;
3751 }
3752 if (!strcmp(arg, "-chatwindow")) {
3753 chat_window = 1;
3754 if (argc_vnc + 1 < argc_vnc_max) {
3755 if (!got_inetd) {
3756 rfbLog("setting '-rfbversion 3.6' for -chatwindow.\n");
3757 }
3758 argv_vnc[argc_vnc++] = strdup("-rfbversion");
3759 argv_vnc[argc_vnc++] = strdup("3.6");
3760 }
3761 continue;
3762 }
3763 if (!strcmp(arg, "-xdamage")) {
3764 use_xdamage++;
3765 continue;
3766 }
3767 if (!strcmp(arg, "-noxdamage")) {
3768 use_xdamage = 0;
3769 continue;
3770 }
3771 if (!strcmp(arg, "-xd_area")) {
3772 int tn;
3773 CHECK_ARGC
3774 tn = atoi(argv[++i]);
3775 if (tn >= 0) {
3776 xdamage_max_area = tn;
3777 }
3778 continue;
3779 }
3780 if (!strcmp(arg, "-xd_mem")) {
3781 double f;
3782 CHECK_ARGC
3783 f = atof(argv[++i]);
3784 if (f >= 0.0) {
3785 xdamage_memory = f;
3786 }
3787 continue;
3788 }
3789 if (!strcmp(arg, "-sigpipe") || !strcmp(arg, "-sig")) {
3790 CHECK_ARGC
3791 if (known_sigpipe_mode(argv[++i])) {
3792 sigpipe = strdup(argv[i]);
3793 } else {
3794 fprintf(stderr, "invalid -sigpipe arg: %s, must"
3795 " be \"ignore\" or \"exit\"\n", argv[i]);
3796 exit(1);
3797 }
3798 continue;
3799 }
3800 #if LIBVNCSERVER_HAVE_LIBPTHREAD
3801 if (!strcmp(arg, "-threads")) {
3802 #if defined(X11VNC_THREADED)
3803 use_threads = 1;
3804 #else
3805 if (getenv("X11VNC_THREADED")) {
3806 use_threads = 1;
3807 } else if (1) {
3808 /* we re-enable it due to threaded mode bugfixes. */
3809 use_threads = 1;
3810 } else {
3811 if (!got_inetd) {
3812 rfbLog("\n");
3813 rfbLog("The -threads mode is unstable and not tested or maintained.\n");
3814 rfbLog("It is disabled in the source code. If you really need\n");
3815 rfbLog("the feature you can reenable it at build time by setting\n");
3816 rfbLog("-DX11VNC_THREADED in CPPFLAGS. Or set X11VNC_THREADED=1\n");
3817 rfbLog("in your runtime environment.\n");
3818 rfbLog("\n");
3819 usleep(500*1000);
3820 }
3821 }
3822 #endif
3823 continue;
3824 }
3825 if (!strcmp(arg, "-nothreads")) {
3826 use_threads = 0;
3827 continue;
3828 }
3829 #endif
3830 if (!strcmp(arg, "-fs")) {
3831 CHECK_ARGC
3832 fs_frac = atof(argv[++i]);
3833 continue;
3834 }
3835 if (!strcmp(arg, "-gaps")) {
3836 CHECK_ARGC
3837 gaps_fill = atoi(argv[++i]);
3838 continue;
3839 }
3840 if (!strcmp(arg, "-grow")) {
3841 CHECK_ARGC
3842 grow_fill = atoi(argv[++i]);
3843 continue;
3844 }
3845 if (!strcmp(arg, "-fuzz")) {
3846 CHECK_ARGC
3847 tile_fuzz = atoi(argv[++i]);
3848 continue;
3849 }
3850 if (!strcmp(arg, "-debug_tiles")
3851 || !strcmp(arg, "-dbt")) {
3852 debug_tiles++;
3853 continue;
3854 }
3855 if (!strcmp(arg, "-debug_grabs")) {
3856 debug_grabs++;
3857 continue;
3858 }
3859 if (!strcmp(arg, "-debug_sel")) {
3860 debug_sel++;
3861 continue;
3862 }
3863 if (!strcmp(arg, "-grab_buster")) {
3864 grab_buster++;
3865 continue;
3866 }
3867 if (!strcmp(arg, "-nograb_buster")) {
3868 grab_buster = 0;
3869 continue;
3870 }
3871 if (!strcmp(arg, "-snapfb")) {
3872 use_snapfb = 1;
3873 continue;
3874 }
3875 if (!strcmp(arg, "-rand")) {
3876 /* equiv. to -nopw -rawfb rand for quick tests */
3877 raw_fb_str = strdup("rand");
3878 nopw = 1;
3879 continue;
3880 }
3881 if (!strcmp(arg, "-rawfb")) {
3882 CHECK_ARGC
3883 raw_fb_str = strdup(argv[++i]);
3884 if (strstr(raw_fb_str, "vnc:") == raw_fb_str) {
3885 shared = 1;
3886 }
3887 continue;
3888 }
3889 if (!strcmp(arg, "-freqtab")) {
3890 CHECK_ARGC
3891 freqtab = strdup(argv[++i]);
3892 continue;
3893 }
3894 if (!strcmp(arg, "-pipeinput")) {
3895 CHECK_ARGC
3896 pipeinput_str = strdup(argv[++i]);
3897 continue;
3898 }
3899 if (!strcmp(arg, "-macnodim")) {
3900 macosx_nodimming = 1;
3901 continue;
3902 }
3903 if (!strcmp(arg, "-macnosleep")) {
3904 macosx_nosleep = 1;
3905 continue;
3906 }
3907 if (!strcmp(arg, "-macnosaver")) {
3908 macosx_noscreensaver = 1;
3909 continue;
3910 }
3911 if (!strcmp(arg, "-macnowait")) {
3912 macosx_wait_for_switch = 0;
3913 continue;
3914 }
3915 if (!strcmp(arg, "-macwheel")) {
3916 CHECK_ARGC
3917 macosx_mouse_wheel_speed = atoi(argv[++i]);
3918 continue;
3919 }
3920 if (!strcmp(arg, "-macnoswap")) {
3921 macosx_swap23 = 0;
3922 continue;
3923 }
3924 if (!strcmp(arg, "-macnoresize")) {
3925 macosx_resize = 0;
3926 continue;
3927 }
3928 if (!strcmp(arg, "-maciconanim")) {
3929 CHECK_ARGC
3930 macosx_icon_anim_time = atoi(argv[++i]);
3931 continue;
3932 }
3933 if (!strcmp(arg, "-macmenu")) {
3934 macosx_ncache_macmenu = 1;
3935 continue;
3936 }
3937 if (!strcmp(arg, "-macuskbd")) {
3938 macosx_us_kbd = 1;
3939 continue;
3940 }
3941 if (!strcmp(arg, "-macnoopengl")) {
3942 macosx_no_opengl = 1;
3943 continue;
3944 }
3945 if (!strcmp(arg, "-macnorawfb")) {
3946 macosx_no_rawfb = 1;
3947 continue;
3948 }
3949 if (!strcmp(arg, "-gui")) {
3950 launch_gui = 1;
3951 if (i < argc-1) {
3952 char *s = argv[i+1];
3953 if (*s != '-') {
3954 gui_str = strdup(s);
3955 if (strstr(gui_str, "setp")) {
3956 got_gui_pw = 1;
3957 }
3958 i++;
3959 }
3960 }
3961 continue;
3962 }
3963 if (!strcmp(arg, "-remote") || !strcmp(arg, "-R")
3964 || !strcmp(arg, "-r") || !strcmp(arg, "-remote-control")) {
3965 char *str;
3966 CHECK_ARGC
3967 i++;
3968 str = argv[i];
3969 if (*str == '-') {
3970 /* accidental leading '-' */
3971 str++;
3972 }
3973 if (!strcmp(str, "ping")) {
3974 query_cmd = strdup(str);
3975 } else {
3976 remote_cmd = strdup(str);
3977 }
3978 if (remote_cmd && strchr(remote_cmd, ':') == NULL) {
3979 /* interpret -R -scale 3/4 at least */
3980 if (i < argc-1 && *(argv[i+1]) != '-') {
3981 int n;
3982
3983 /* it must be the parameter value */
3984 i++;
3985 n = strlen(remote_cmd) + strlen(argv[i]) + 2;
3986
3987 str = (char *) malloc(n);
3988 sprintf(str, "%s:%s", remote_cmd, argv[i]);
3989 free(remote_cmd);
3990 remote_cmd = str;
3991 }
3992 }
3993 if (!getenv("QUERY_VERBOSE")) {
3994 quiet = 1;
3995 }
3996 xkbcompat = 0;
3997 continue;
3998 }
3999 if (!strcmp(arg, "-query") || !strcmp(arg, "-Q")) {
4000 CHECK_ARGC
4001 query_cmd = strdup(argv[++i]);
4002 if (!getenv("QUERY_VERBOSE")) {
4003 quiet = 1;
4004 }
4005 xkbcompat = 0;
4006 continue;
4007 }
4008 if (!strcmp(arg, "-query_retries")) {
4009 char *s;
4010 CHECK_ARGC
4011 s = strdup(argv[++i]);
4012 /* n[:t][/match] */
4013 if (strchr(s, '/')) {
4014 char *q = strchr(s, '/');
4015 query_match = strdup(q+1);
4016 *q = '\0';
4017 }
4018 if (strchr(s, ':')) {
4019 char *q = strchr(s, ':');
4020 query_delay = atof(q+1);
4021 }
4022 query_retries = atoi(s);
4023 free(s);
4024 continue;
4025 }
4026 if (!strcmp(arg, "-QD")) {
4027 CHECK_ARGC
4028 query_cmd = strdup(argv[++i]);
4029 query_default = 1;
4030 continue;
4031 }
4032 if (!strcmp(arg, "-sync")) {
4033 remote_sync = 1;
4034 continue;
4035 }
4036 if (!strcmp(arg, "-nosync")) {
4037 remote_sync = 0;
4038 continue;
4039 }
4040 if (!strcmp(arg, "-remote_prefix")) {
4041 CHECK_ARGC
4042 remote_prefix = strdup(argv[++i]);
4043 continue;
4044 }
4045 if (!strcmp(arg, "-noremote")) {
4046 accept_remote_cmds = 0;
4047 continue;
4048 }
4049 if (!strcmp(arg, "-yesremote")) {
4050 accept_remote_cmds = 1;
4051 continue;
4052 }
4053 if (!strcmp(arg, "-unsafe")) {
4054 safe_remote_only = 0;
4055 continue;
4056 }
4057 if (!strcmp(arg, "-privremote")) {
4058 priv_remote = 1;
4059 continue;
4060 }
4061 if (!strcmp(arg, "-safer")) {
4062 more_safe = 1;
4063 continue;
4064 }
4065 if (!strcmp(arg, "-nocmds")) {
4066 no_external_cmds = 1;
4067 continue;
4068 }
4069 if (!strcmp(arg, "-allowedcmds")) {
4070 CHECK_ARGC
4071 allowed_external_cmds = strdup(argv[++i]);
4072 continue;
4073 }
4074 if (!strcmp(arg, "-deny_all")) {
4075 deny_all = 1;
4076 continue;
4077 }
4078 if (!strcmp(arg, "-httpdir")) {
4079 CHECK_ARGC
4080 http_dir = strdup(argv[++i]);
4081 got_httpdir = 1;
4082 continue;
4083 }
4084 if (1) {
4085 if (!strcmp(arg, "-desktop") && i < argc-1) {
4086 dt = 1;
4087 rfb_desktop_name = strdup(argv[i+1]);
4088 }
4089 if (!strcmp(arg, "-passwd")) {
4090 pw_loc = i;
4091 got_passwd = 1;
4092 }
4093 if (!strcmp(arg, "-rfbauth")) {
4094 got_rfbauth = 1;
4095 }
4096 if (!strcmp(arg, "-rfbwait")) {
4097 got_rfbwait = 1;
4098 }
4099 if (!strcmp(arg, "-deferupdate")) {
4100 got_deferupdate = 1;
4101 }
4102 if (!strcmp(arg, "-rfbport") && i < argc-1) {
4103 got_rfbport = 1;
4104 if (!strcasecmp(argv[i+1], "prompt")) {
4105 ;
4106 } else if (!is_decimal(argv[i+1])) {
4107 if (!got_inetd) {
4108 rfbLog("Invalid -rfbport value: '%s'\n", argv[i+1]);
4109 rfbLog("setting it to '-1' to induce failure.\n");
4110 argv[i+1] = strdup("-1");
4111 }
4112 }
4113 got_rfbport_str = strdup(argv[i+1]);
4114 got_rfbport_pos = argc_vnc+1;
4115 got_rfbport_val = atoi(argv[i+1]);
4116 }
4117 if (!strcmp(arg, "-httpport") && i < argc-1) {
4118 if (!is_decimal(argv[i+1])) {
4119 rfbLog("Invalid -httpport value: '%s'\n", argv[i+1]);
4120 clean_up_exit(1);
4121 }
4122 }
4123 if (!strcmp(arg, "-alwaysshared ")) {
4124 got_alwaysshared = 1;
4125 }
4126 if (!strcmp(arg, "-nevershared")) {
4127 got_nevershared = 1;
4128 }
4129 if (!strcmp(arg, "-listen") && i < argc-1) {
4130 listen_str = strdup(argv[i+1]);
4131 }
4132 /* otherwise copy it for libvncserver use below. */
4133 if (!strcmp(arg, "-ultrafilexfer")) {
4134 got_ultrafilexfer = 1;
4135 } else if (argc_vnc < argc_vnc_max) {
4136 argv_vnc[argc_vnc++] = strdup(arg);
4137 } else {
4138 rfbLog("too many arguments.\n");
4139 exit(1);
4140 }
4141 continue;
4142 }
4143 }
4144
4145 if (! getenv("NO_LIBXCB_ALLOW_SLOPPY_LOCK")) {
4146 /* libxcb is a bit too strict for us sometimes... */
4147 set_env("LIBXCB_ALLOW_SLOPPY_LOCK", "1");
4148 }
4149
4150 if (getenv("PATH") == NULL || !strcmp(getenv("PATH"), "")) {
4151 /* set a minimal PATH, usually only null in inetd. */
4152 set_env("PATH", "/bin:/usr/bin");
4153 }
4154
4155 /* handle -findauth case now that cmdline has been read */
4156 if (got_findauth) {
4157 char *s;
4158 int ic = 0;
4159 if (use_dpy != NULL) {
4160 set_env("DISPLAY", use_dpy);
4161 }
4162 use_dpy = strdup("WAIT:cmd=FINDDISPLAY-run");
4163
4164 s = getenv("FINDAUTH_DISPLAY");
4165 if (s && strcmp("", s)) {
4166 set_env("DISPLAY", s);
4167 }
4168 s = getenv("DISPLAY");
4169 if (s && strcmp("", s)) {
4170 set_env("X11VNC_SKIP_DISPLAY", s);
4171 } else {
4172 set_env("X11VNC_SKIP_DISPLAY", ":0");
4173 }
4174 set_env("X11VNC_SKIP_DISPLAY_NEGATE", "1");
4175 set_env("FIND_DISPLAY_XAUTHORITY_PATH", "1");
4176 set_env("FIND_DISPLAY_NO_SHOW_XAUTH", "1");
4177 set_env("FIND_DISPLAY_NO_SHOW_DISPLAY", "1");
4178 wait_for_client(&ic, NULL, 0);
4179 exit(0);
4180 }
4181
4182 /* set OS struct UT */
4183 uname(&UT);
4184
4185 orig_use_xdamage = use_xdamage;
4186
4187 if (!auto_port && getenv("AUTO_PORT")) {
4188 auto_port = atoi(getenv("AUTO_PORT"));
4189 }
4190
4191 if (getenv("X11VNC_LOOP_MODE")) {
4192 if (bg && !getenv("X11VNC_LOOP_MODE_BG")) {
4193 if (! quiet) {
4194 fprintf(stderr, "disabling -bg in -loop "
4195 "mode\n");
4196 }
4197 bg = 0;
4198 } else if (!bg && getenv("X11VNC_LOOP_MODE_BG")) {
4199 if (! quiet) {
4200 fprintf(stderr, "enabling -bg in -loopbg "
4201 "mode\n");
4202 }
4203 bg = 1;
4204 }
4205 if (inetd) {
4206 if (! quiet) {
4207 fprintf(stderr, "disabling -inetd in -loop "
4208 "mode\n");
4209 }
4210 inetd = 0;
4211 }
4212 }
4213
4214 if (launch_gui && (query_cmd || remote_cmd)) {
4215 launch_gui = 0;
4216 gui_str = NULL;
4217 }
4218 if (more_safe) {
4219 launch_gui = 0;
4220 }
4221
4222 #ifdef MACOSX
4223 if (! use_dpy) {
4224 /* we need this for gui since no X properties */
4225 if (!client_connect_file && !client_connect) {
4226 char *user = get_user_name();
4227 char *str = (char *) malloc(strlen(user) + strlen("/tmp/x11vnc-macosx-remote.") + 1);
4228 struct stat sb;
4229 sprintf(str, "/tmp/x11vnc-macosx-remote.%s", user);
4230 if (!remote_cmd && !query_cmd) {
4231 unlink(str);
4232 if (stat(str, &sb) != 0) {
4233 int fd = open(str, O_WRONLY|O_EXCL|O_CREAT, 0600);
4234 if (fd >= 0) {
4235 close(fd);
4236 client_connect_file = str;
4237 }
4238 }
4239 } else {
4240 client_connect_file = str;
4241 }
4242 if (client_connect_file) {
4243 if (!got_inetd) {
4244 rfbLog("MacOS X: set -connect file to %s\n", client_connect_file);
4245 }
4246 }
4247 }
4248 }
4249 #endif
4250 if (got_rfbport_str != NULL && !strcasecmp(got_rfbport_str, "prompt")) {
4251 char *opts, tport[32];
4252
4253 if (gui_str) {
4254 opts = (char *) malloc(strlen(gui_str) + 32);
4255 sprintf(opts, "%s,portprompt", gui_str);
4256 } else {
4257 opts = strdup("portprompt");
4258 }
4259 got_rfbport_val = -1;
4260
4261 do_gui(opts, 0);
4262 if (got_rfbport_val == -1) {
4263 rfbLog("Port prompt indicated cancel.\n");
4264 clean_up_exit(1);
4265 }
4266 if (!got_inetd) {
4267 rfbLog("Port prompt selected: %d\n", got_rfbport_val);
4268 }
4269 sprintf(tport, "%d", got_rfbport_val);
4270 argv_vnc[got_rfbport_pos] = strdup(tport);
4271 free(opts);
4272 }
4273
4274 {
4275 char num[32];
4276 sprintf(num, "%d", got_rfbport_val);
4277 set_env("X11VNC_GOT_RFBPORT_VAL", num);
4278 }
4279
4280 if (got_ultrafilexfer && argc_vnc + 2 < argc_vnc_max) {
4281 argv_vnc[argc_vnc++] = strdup("-rfbversion");
4282 argv_vnc[argc_vnc++] = strdup("3.6");
4283 argv_vnc[argc_vnc++] = strdup("-permitfiletransfer");
4284 }
4285
4286 if (launch_gui) {
4287 int sleep = 0;
4288 if (SHOW_NO_PASSWORD_WARNING && !nopw) {
4289 sleep = 1;
4290 }
4291 do_gui(gui_str, sleep);
4292 }
4293 if (logfile) {
4294 int n;
4295 char *pstr = "%VNCDISPLAY";
4296 if (strstr(logfile, pstr)) {
4297 char *h = this_host();
4298 char *s, *q, *newlog;
4299 int n, p = got_rfbport_val;
4300 /* we don't really know the port yet... so guess */
4301 if (p < 0) {
4302 p = auto_port;
4303 }
4304 if (p <= 0) {
4305 p = 5900;
4306 }
4307 s = (char *) malloc(strlen(h) + 32);
4308 sprintf(s, "%s:%d", h, p);
4309 n = 1;
4310 q = logfile;
4311 while (1) {
4312 char *t = strstr(q, pstr);
4313 if (!t) break;
4314 n++;
4315 q = t+1;
4316 }
4317 newlog = (char *) malloc(strlen(logfile) + n * strlen(pstr));
4318 newlog[0] = '\0';
4319
4320 q = logfile;
4321 while (1) {
4322 char *t = strstr(q, pstr);
4323 if (!t) {
4324 strcat(newlog, q);
4325 break;
4326 }
4327 strncat(newlog, q, t - q);
4328 strcat(newlog, s);
4329 q = t + strlen(pstr);
4330 }
4331 logfile = newlog;
4332 if (!quiet && !got_inetd) {
4333 rfbLog("Expanded logfile to '%s'\n", newlog);
4334
4335 }
4336 free(s);
4337 }
4338 pstr = "%HOME";
4339 if (strstr(logfile, pstr)) {
4340 char *h = get_home_dir();
4341 char *s, *q, *newlog;
4342
4343 s = (char *) malloc(strlen(h) + 32);
4344 sprintf(s, "%s", h);
4345 n = 1;
4346 q = logfile;
4347 while (1) {
4348 char *t = strstr(q, pstr);
4349 if (!t) break;
4350 n++;
4351 q = t+1;
4352 }
4353 newlog = (char *) malloc(strlen(logfile) + n * strlen(pstr));
4354 newlog[0] = '\0';
4355
4356 q = logfile;
4357 while (1) {
4358 char *t = strstr(q, pstr);
4359 if (!t) {
4360 strcat(newlog, q);
4361 break;
4362 }
4363 strncat(newlog, q, t - q);
4364 strcat(newlog, s);
4365 q = t + strlen(pstr);
4366 }
4367 logfile = newlog;
4368 if (!quiet && !got_inetd) {
4369 rfbLog("Expanded logfile to '%s'\n", newlog);
4370 }
4371 free(s);
4372 }
4373
4374 if (logfile_append) {
4375 n = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0666);
4376 } else {
4377 n = open(logfile, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4378 }
4379 if (n < 0) {
4380 fprintf(stderr, "error opening logfile: %s\n", logfile);
4381 perror("open");
4382 exit(1);
4383 }
4384 if (dup2(n, 2) < 0) {
4385 fprintf(stderr, "dup2 failed\n");
4386 perror("dup2");
4387 exit(1);
4388 }
4389 if (n > 2) {
4390 close(n);
4391 }
4392 }
4393 if (ipv6_listen) {
4394 if (inetd) {
4395 ipv6_listen = 0;
4396 }
4397 }
4398 if (inetd && quiet && !logfile) {
4399 int n;
4400 /*
4401 * Redir stderr to /dev/null under -inetd and -quiet
4402 * but no -o logfile. Typical problem:
4403 * Xlib: extension "RECORD" missing on display ":1.0".
4404 * If they want this info, they should use -o logfile,
4405 * or no -q and 2>logfile.
4406 */
4407 n = open("/dev/null", O_WRONLY);
4408 if (n >= 0) {
4409 if (dup2(n, 2) >= 0) {
4410 if (n > 2) {
4411 close(n);
4412 }
4413 }
4414 }
4415 }
4416 if (! quiet && ! inetd) {
4417 int i;
4418 if (http_oneport_msg) {
4419 rfbLog("setting '-enc none' for -http_oneport mode.\n");
4420 }
4421 for (i=1; i < argc_vnc; i++) {
4422 rfbLog("passing arg to libvncserver: %s\n", argv_vnc[i]);
4423 if (!strcmp(argv_vnc[i], "-passwd")) {
4424 i++;
4425 }
4426 }
4427 }
4428
4429 if (remote_cmd || query_cmd) {
4430 /*
4431 * no need to open DISPLAY, just write it to the file now
4432 * similar for query_default.
4433 */
4434 if (client_connect_file || query_default) {
4435 int i, rc = 1;
4436 for (i=0; i <= query_retries; i++) {
4437 rc = do_remote_query(remote_cmd, query_cmd,
4438 remote_sync, query_default);
4439 if (rc == 0) {
4440 if (query_match) {
4441 if (query_result && strstr(query_result, query_match)) {
4442 break;
4443 }
4444 rc = 1;
4445 } else {
4446 break;
4447 }
4448 }
4449 if (i < query_retries) {
4450 fprintf(stderr, "sleep: %.3f\n", query_delay);
4451 usleep( (int) (query_delay * 1000 * 1000) );
4452 }
4453 }
4454 fflush(stderr);
4455 fflush(stdout);
4456 exit(rc);
4457 }
4458 }
4459
4460 if (usepw && ! got_rfbauth && ! got_passwd && ! got_passwdfile && !unixpw) {
4461 char *f, *h = getenv("HOME");
4462 struct stat sbuf;
4463 int found = 0, set_rfbauth = 0;
4464
4465 if (!h) {
4466 rfbLog("HOME unset in -usepw mode.\n");
4467 exit(1);
4468 }
4469 f = (char *) malloc(strlen(h)+strlen("/.vnc/passwdfile") + 1);
4470
4471 sprintf(f, "%s/.vnc/passwd", h);
4472 if (stat(f, &sbuf) == 0) {
4473 found = 1;
4474 if (! quiet) {
4475 rfbLog("-usepw: found %s\n", f);
4476 }
4477 got_rfbauth = 1;
4478 set_rfbauth = 1;
4479 }
4480
4481 sprintf(f, "%s/.vnc/passwdfile", h);
4482 if (! found && stat(f, &sbuf) == 0) {
4483 found = 1;
4484 if (! quiet) {
4485 rfbLog("-usepw: found %s\n", f);
4486 }
4487 got_passwdfile = 1;
4488 passwdfile = strdup(f);
4489 }
4490
4491 #if LIBVNCSERVER_HAVE_FORK
4492 #if LIBVNCSERVER_HAVE_SYS_WAIT_H
4493 #if LIBVNCSERVER_HAVE_WAITPID
4494 if (! found) {
4495 pid_t pid = fork();
4496 if (pid < 0) {
4497 ;
4498 } else if (pid == 0) {
4499 execlp(argv[0], argv[0], "-storepasswd",
4500 (char *) NULL);
4501 exit(1);
4502 } else {
4503 int s;
4504 waitpid(pid, &s, 0);
4505 if (WIFEXITED(s) && WEXITSTATUS(s) == 0) {
4506 got_rfbauth = 1;
4507 set_rfbauth = 1;
4508 found = 1;
4509 }
4510 }
4511 }
4512 #endif
4513 #endif
4514 #endif
4515
4516 if (set_rfbauth) {
4517 sprintf(f, "%s/.vnc/passwd", h);
4518 if (argc_vnc < 100) {
4519 argv_vnc[argc_vnc++] = strdup("-rfbauth");
4520 } else {
4521 exit(1);
4522 }
4523 if (argc_vnc < 100) {
4524 argv_vnc[argc_vnc++] = strdup(f);
4525 } else {
4526 exit(1);
4527 }
4528 }
4529 if (! found) {
4530 fprintf(stderr, "x11vnc -usepw: could not find"
4531 " a password to use.\n");
4532 exit(1);
4533 }
4534 free(f);
4535 }
4536
4537 if (got_rfbauth && (got_passwd || got_viewpasswd || got_passwdfile)) {
4538 fprintf(stderr, "option -rfbauth is incompatible with:\n");
4539 fprintf(stderr, " -passwd, -viewpasswd, and -passwdfile\n");
4540 exit(1);
4541 }
4542 if (got_passwdfile && (got_passwd || got_viewpasswd)) {
4543 fprintf(stderr, "option -passwdfile is incompatible with:\n");
4544 fprintf(stderr, " -passwd and -viewpasswd\n");
4545 exit(1);
4546 }
4547
4548 /*
4549 * If -passwd was used, clear it out of argv. This does not
4550 * work on all UNIX, have to use execvp() in general...
4551 */
4552 if (pw_loc > 0) {
4553 int i;
4554 for (i=pw_loc; i <= pw_loc+1; i++) {
4555 if (i < argc) {
4556 char *p = argv[i];
4557 strzero(p);
4558 }
4559 }
4560 } else if (passwdfile) {
4561 /* read passwd(s) from file */
4562 if (strstr(passwdfile, "cmd:") == passwdfile ||
4563 strstr(passwdfile, "custom:") == passwdfile) {
4564 char tstr[100], *q;
4565 sprintf(tstr, "%f", dnow());
4566 if ((q = strrchr(tstr, '.')) == NULL) {
4567 q = tstr;
4568 } else {
4569 q++;
4570 }
4571 /* never used under cmd:, used to force auth */
4572 argv_vnc[argc_vnc++] = strdup("-passwd");
4573 argv_vnc[argc_vnc++] = strdup(q);
4574 } else if (read_passwds(passwdfile)) {
4575 argv_vnc[argc_vnc++] = strdup("-passwd");
4576 argv_vnc[argc_vnc++] = strdup(passwd_list[0]);
4577 }
4578 got_passwd = 1;
4579 pw_loc = 100; /* just for pw_loc check below */
4580 }
4581 if (vpw_loc > 0) {
4582 int i;
4583 for (i=vpw_loc; i <= vpw_loc+1; i++) {
4584 if (i < argc) {
4585 char *p = argv[i];
4586 strzero(p);
4587 }
4588 }
4589 }
4590 #ifdef HARDWIRE_PASSWD
4591 if (!got_rfbauth && !got_passwd) {
4592 argv_vnc[argc_vnc++] = strdup("-passwd");
4593 argv_vnc[argc_vnc++] = strdup(HARDWIRE_PASSWD);
4594 got_passwd = 1;
4595 pw_loc = 100;
4596 }
4597 #endif
4598 #ifdef HARDWIRE_VIEWPASSWD
4599 if (!got_rfbauth && got_passwd && !viewonly_passwd && !passwd_list) {
4600 viewonly_passwd = strdup(HARDWIRE_VIEWPASSWD);
4601 }
4602 #endif
4603 if (viewonly_passwd && pw_loc < 0) {
4604 rfbLog("-passwd must be supplied when using -viewpasswd\n");
4605 exit(1);
4606 }
4607 if (1) {
4608 /* mix things up a little bit */
4609 unsigned char buf[CHALLENGESIZE];
4610 int k, kmax = (int) (50 * rfac()) + 10;
4611 for (k=0; k < kmax; k++) {
4612 rfbRandomBytes(buf);
4613 }
4614 }
4615
4616 if (SHOW_NO_PASSWORD_WARNING) {
4617 char message[] = "-rfbauth, -passwdfile, -passwd password, "
4618 "or -unixpw required.";
4619 if (! nopw) {
4620 nopassword_warning_msg(got_localhost);
4621 }
4622 #if PASSWD_REQUIRED
4623 rfbLog("%s\n", message);
4624 exit(1);
4625 #endif
4626 #if PASSWD_UNLESS_NOPW
4627 if (! nopw) {
4628 rfbLog("%s\n", message);
4629 exit(1);
4630 }
4631 #endif
4632 message[0] = '\0'; /* avoid compiler warning */
4633 }
4634
4635 if (more_safe) {
4636 if (! quiet) {
4637 rfbLog("-safer mode:\n");
4638 rfbLog(" vnc_connect=0\n");
4639 rfbLog(" accept_remote_cmds=0\n");
4640 rfbLog(" safe_remote_only=1\n");
4641 rfbLog(" launch_gui=0\n");
4642 }
4643 vnc_connect = 0;
4644 accept_remote_cmds = 0;
4645 safe_remote_only = 1;
4646 launch_gui = 0;
4647 }
4648
4649 if (users_list && strchr(users_list, '.')) {
4650 char *p, *q, *tmp = (char *) malloc(strlen(users_list)+1);
4651 char *str = strdup(users_list);
4652 int i, n, db = 1;
4653
4654 tmp[0] = '\0';
4655
4656 n = strlen(users_list) + 1;
4657 user2group = (char **) malloc(n * sizeof(char *));
4658 for (i=0; i<n; i++) {
4659 user2group[i] = NULL;
4660 }
4661
4662 i = 0;
4663 p = strtok(str, ",");
4664 if (db) fprintf(stderr, "users_list: %s\n", users_list);
4665 while (p) {
4666 if (tmp[0] != '\0') {
4667 strcat(tmp, ",");
4668 }
4669 q = strchr(p, '.');
4670 if (q) {
4671 char *s = strchr(p, '=');
4672 if (! s) {
4673 s = p;
4674 } else {
4675 s++;
4676 }
4677 if (s[0] == '+') s++;
4678 user2group[i++] = strdup(s);
4679 if (db) fprintf(stderr, "u2g: %s\n", s);
4680 *q = '\0';
4681 }
4682 strcat(tmp, p);
4683 p = strtok(NULL, ",");
4684 }
4685 free(str);
4686 users_list = tmp;
4687 if (db) fprintf(stderr, "users_list: %s\n", users_list);
4688 }
4689
4690 if (got_tls > 0 && !use_openssl) {
4691 rfbLog("SSL: Error: you did not supply the '-ssl ...' option even\n");
4692 rfbLog("SSL: though you supplied one of these related options:\n");
4693 rfbLog("SSL: -sslonly, -sslverify, -sslCRL, -vencrypt, -anontls,\n");
4694 rfbLog("SSL: -dhparams, -https, -http_ssl, or -httpsredir.\n");
4695 rfbLog("SSL: Restart with, for example, '-ssl SAVE' on the cmd line.\n");
4696 rfbLog("SSL: See the '-ssl' x11vnc -help description for more info.\n");
4697 if (!getenv("X11VNC_FORCE_NO_OPENSSL")) {
4698 exit(1);
4699 }
4700 }
4701
4702 if (unixpw) {
4703 if (inetd) {
4704 use_stunnel = 0;
4705 }
4706 if (! use_stunnel && ! use_openssl) {
4707 if (getenv("UNIXPW_DISABLE_SSL")) {
4708 rfbLog("Skipping -ssl/-stunnel requirement"
4709 " due to\n");
4710 rfbLog("UNIXPW_DISABLE_SSL setting.\n");
4711
4712 if (!getenv("UNIXPW_DISABLE_LOCALHOST")) {
4713 if (!got_localhost) {
4714 rfbLog("Forcing -localhost mode.\n");
4715 }
4716 allow_list = strdup("127.0.0.1");
4717 got_localhost = 1;
4718 }
4719 } else if (have_ssh_env()) {
4720 char *s = getenv("SSH_CONNECTION");
4721 if (! s) s = getenv("SSH_CLIENT");
4722 if (! s) s = "SSH_CONNECTION";
4723 fprintf(stderr, "\n");
4724 rfbLog("Skipping -ssl/-stunnel constraint in"
4725 " -unixpw mode,\n");
4726 rfbLog("assuming your SSH encryption"
4727 " is:\n");
4728 rfbLog(" %s\n", s);
4729
4730 if (!getenv("UNIXPW_DISABLE_LOCALHOST")) {
4731 if (!got_localhost) {
4732 rfbLog("Setting -localhost in SSH + -unixpw mode.\n");
4733 }
4734 allow_list = strdup("127.0.0.1");
4735 got_localhost = 1;
4736 }
4737
4738 rfbLog("If you *actually* want SSL, restart"
4739 " with -ssl on the cmdline\n");
4740 if (! nopw) {
4741 usleep(2000*1000);
4742 }
4743 } else {
4744 if (openssl_present()) {
4745 rfbLog("set -ssl in -unixpw mode.\n");
4746 use_openssl = 1;
4747 } else if (inetd) {
4748 rfbLog("could not set -ssl in -inetd"
4749 " + -unixpw mode.\n");
4750 exit(1);
4751 } else {
4752 rfbLog("set -stunnel in -unixpw mode.\n");
4753 use_stunnel = 1;
4754 }
4755 }
4756 rfbLog("\n");
4757 }
4758 if (use_threads && !getenv("UNIXPW_THREADS")) {
4759 if (! quiet) {
4760 rfbLog("disabling -threads under -unixpw\n");
4761 rfbLog("\n");
4762 }
4763 use_threads = 0;
4764 }
4765 }
4766 if (use_stunnel && ! got_localhost) {
4767 if (! getenv("STUNNEL_DISABLE_LOCALHOST") &&
4768 ! getenv("UNIXPW_DISABLE_LOCALHOST")) {
4769 if (! quiet) {
4770 rfbLog("Setting -localhost in -stunnel mode.\n");
4771 }
4772 allow_list = strdup("127.0.0.1");
4773 got_localhost = 1;
4774 }
4775 }
4776 if (ssl_verify && ! use_stunnel && ! use_openssl) {
4777 rfbLog("-sslverify must be used with -ssl or -stunnel\n");
4778 exit(1);
4779 }
4780 if (https_port_num >= 0 && ! use_openssl) {
4781 rfbLog("-https must be used with -ssl\n");
4782 exit(1);
4783 }
4784
4785 if (use_threads && !got_noxrandr) {
4786 xrandr = 1;
4787 if (! quiet) {
4788 rfbLog("enabling -xrandr in -threads mode.\n");
4789 }
4790 }
4791
4792 /* fixup settings that do not make sense */
4793
4794 if (use_threads && nofb && cursor_pos_updates) {
4795 if (! quiet) {
4796 rfbLog("disabling -threads under -nofb -cursorpos\n");
4797 }
4798 use_threads = 0;
4799 }
4800 if (tile_fuzz < 1) {
4801 tile_fuzz = 1;
4802 }
4803 if (waitms < 0) {
4804 waitms = 0;
4805 }
4806
4807 if (alpha_threshold < 0) {
4808 alpha_threshold = 0;
4809 }
4810 if (alpha_threshold > 256) {
4811 alpha_threshold = 256;
4812 }
4813 if (alpha_frac < 0.0) {
4814 alpha_frac = 0.0;
4815 }
4816 if (alpha_frac > 1.0) {
4817 alpha_frac = 1.0;
4818 }
4819 if (alpha_blend) {
4820 alpha_remove = 0;
4821 }
4822
4823 if (cmap8to24 && overlay) {
4824 if (! quiet) {
4825 rfbLog("disabling -overlay in -8to24 mode.\n");
4826 }
4827 overlay = 0;
4828 }
4829
4830 if (tightfilexfer && view_only) {
4831 if (! quiet) {
4832 rfbLog("setting -notightfilexfer in -viewonly mode.\n");
4833 }
4834 /* how to undo via -R? */
4835 tightfilexfer = 0;
4836 }
4837
4838 if (inetd) {
4839 shared = 0;
4840 connect_once = 1;
4841 bg = 0;
4842 if (use_stunnel) {
4843 exit(1);
4844 }
4845 }
4846
4847 http_try_it = try_http;
4848
4849 if (flip_byte_order && using_shm && ! quiet) {
4850 rfbLog("warning: -flipbyte order only works with -noshm\n");
4851 }
4852
4853 if (! wireframe_copyrect) {
4854 set_wirecopyrect_mode(NULL);
4855 }
4856 if (! scroll_copyrect) {
4857 set_scrollcopyrect_mode(NULL);
4858 }
4859 if (screen_fixup_str) {
4860 parse_fixscreen();
4861 }
4862 initialize_scroll_matches();
4863 initialize_scroll_term();
4864 initialize_max_keyrepeat();
4865
4866 /* increase rfbwait if threaded */
4867 if (use_threads && ! got_rfbwait) {
4868 /* ??? lower this ??? */
4869 rfbMaxClientWait = 604800000;
4870 }
4871
4872 /* no framebuffer (Win2VNC) mode */
4873
4874 if (nofb) {
4875 /* disable things that do not make sense with no fb */
4876 set_nofb_params(0);
4877
4878 if (! got_deferupdate && ! got_defer) {
4879 /* reduce defer time under -nofb */
4880 defer_update = defer_update_nofb;
4881 }
4882 if (got_pointer_mode < 0) {
4883 pointer_mode = POINTER_MODE_NOFB;
4884 }
4885 }
4886
4887 if (ncache < 0) {
4888 ncache_beta_tester = 1;
4889 ncache_msg = 1;
4890 if (ncache == -1) {
4891 ncache = 0;
4892 }
4893 ncache = -ncache;
4894 if (try_http || got_httpdir) {
4895 /* JVM usually not set to handle all the memory */
4896 ncache = 0;
4897 ncache_msg = 0;
4898 }
4899 if (subwin) {
4900 ncache = 0;
4901 ncache_msg = 0;
4902 }
4903 }
4904
4905 if (raw_fb_str) {
4906 set_raw_fb_params(0);
4907 }
4908 if (! got_deferupdate) {
4909 char tmp[40];
4910 sprintf(tmp, "%d", defer_update);
4911 argv_vnc[argc_vnc++] = strdup("-deferupdate");
4912 argv_vnc[argc_vnc++] = strdup(tmp);
4913 }
4914
4915 if (debug_pointer || debug_keyboard) {
4916 if (!logfile) {
4917 if (bg || quiet) {
4918 rfbLog("disabling -bg/-q under -debug_pointer"
4919 "/-debug_keyboard\n");
4920 bg = 0;
4921 quiet = 0;
4922 }
4923 }
4924 }
4925
4926 /* initialize added_keysyms[] array to zeros */
4927 add_keysym(NoSymbol);
4928
4929 /* tie together cases of -localhost vs. -listen localhost */
4930 if (! listen_str) {
4931 if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
4932 listen_str = strdup("localhost");
4933 argv_vnc[argc_vnc++] = strdup("-listen");
4934 argv_vnc[argc_vnc++] = strdup(listen_str);
4935 }
4936 } else if (!strcmp(listen_str, "localhost") ||
4937 !strcmp(listen_str, "127.0.0.1")) {
4938 allow_list = strdup("127.0.0.1");
4939 }
4940
4941 initialize_crash_handler();
4942
4943 if (! quiet) {
4944 if (verbose) {
4945 print_settings(try_http, bg, gui_str);
4946 }
4947 rfbLog("x11vnc version: %s pid: %d\n", lastmod, getpid());
4948 } else {
4949 rfbLogEnable(0);
4950 }
4951
4952 X_INIT;
4953 SCR_INIT;
4954 CLIENT_INIT;
4955 INPUT_INIT;
4956 POINTER_INIT;
4957
4958 /* open the X display: */
4959
4960 #if LIBVNCSERVER_HAVE_XKEYBOARD
4961 /*
4962 * Disable XKEYBOARD before calling XOpenDisplay()
4963 * this should be used if there is ambiguity in the keymapping.
4964 */
4965 if (xkbcompat) {
4966 Bool rc = XkbIgnoreExtension(True);
4967 if (! quiet) {
4968 rfbLog("Disabling xkb XKEYBOARD extension. rc=%d\n",
4969 rc);
4970 }
4971 if (watch_bell) {
4972 watch_bell = 0;
4973 if (! quiet) rfbLog("Disabling bell.\n");
4974 }
4975 }
4976 #else
4977 watch_bell = 0;
4978 use_xkb_modtweak = 0;
4979 #endif
4980
4981 #ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER
4982 if (tightfilexfer) {
4983 rfbLog("rfbRegisterTightVNCFileTransferExtension: 6\n");
4984 rfbRegisterTightVNCFileTransferExtension();
4985 } else {
4986 if (0) rfbLog("rfbUnregisterTightVNCFileTransferExtension: 3\n");
4987 rfbUnregisterTightVNCFileTransferExtension();
4988 }
4989 #endif
4990
4991 initialize_allowed_input();
4992
4993 if (display_N && !got_rfbport) {
4994 char *ud = use_dpy;
4995 if (ud == NULL) {
4996 ud = getenv("DISPLAY");
4997 }
4998 if (ud && strstr(ud, "cmd=") == NULL) {
4999 char *p;
5000 ud = strdup(ud);
5001 p = strrchr(ud, ':');
5002 if (p) {
5003 int N;
5004 char *q = strchr(p, '.');
5005 if (q) {
5006 *q = '\0';
5007 }
5008 N = atoi(p+1);
5009 if (argc_vnc+1 < argc_vnc_max) {
5010 char Nstr[16];
5011 sprintf(Nstr, "%d", (5900 + N) % 65536);
5012 argv_vnc[argc_vnc++] = strdup("-rfbport");
5013 argv_vnc[argc_vnc++] = strdup(Nstr);
5014 got_rfbport = 1;
5015 }
5016 }
5017 free(ud);
5018 }
5019 }
5020
5021 if (users_list && strstr(users_list, "lurk=")) {
5022 if (use_dpy) {
5023 rfbLog("warning: -display does not make sense in "
5024 "\"lurk=\" mode...\n");
5025 }
5026 if (auth_file != NULL && strcmp(auth_file, "guess")) {
5027 set_env("XAUTHORITY", auth_file);
5028 }
5029 lurk_loop(users_list);
5030
5031 } else if (use_dpy && strstr(use_dpy, "WAIT:") == use_dpy) {
5032 char *mcm = multiple_cursors_mode;
5033
5034 if (strstr(use_dpy, "Xdummy")) {
5035 if (!xrandr && !got_noxrandr) {
5036 if (! quiet) {
5037 rfbLog("Enabling -xrandr for possible use of Xdummy server.\n");
5038 }
5039 xrandr = 1;
5040 }
5041 }
5042
5043 waited_for_client = wait_for_client(&argc_vnc, argv_vnc,
5044 try_http && ! got_httpdir);
5045
5046 if (!mcm && multiple_cursors_mode) {
5047 free(multiple_cursors_mode);
5048 multiple_cursors_mode = NULL;
5049 }
5050 }
5051
5052
5053 if (auth_file) {
5054 check_guess_auth_file();
5055 if (auth_file != NULL) {
5056 set_env("XAUTHORITY", auth_file);
5057 }
5058 }
5059
5060 #ifdef MACOSX
5061 if (use_dpy && !strcmp(use_dpy, "console")) {
5062 ;
5063 } else
5064 #endif
5065 if (use_dpy && strcmp(use_dpy, "")) {
5066 dpy = XOpenDisplay_wr(use_dpy);
5067 #ifdef MACOSX
5068 } else if (!subwin && getenv("DISPLAY")
5069 && strstr(getenv("DISPLAY"), "/tmp/") ) {
5070 /* e.g. /tmp/launch-XlspvM/:0 on leopard */
5071 rfbLog("MacOSX: Ignoring $DISPLAY '%s'\n", getenv("DISPLAY"));
5072 rfbLog("MacOSX: Use -display $DISPLAY to force it.\n");
5073 #endif
5074 } else if (raw_fb_str != NULL && raw_fb_str[0] != '+' && !got_noviewonly) {
5075 rfbLog("Not opening DISPLAY in -rawfb mode (force via -rawfb +str)\n");
5076 dpy = NULL; /* don't open it. */
5077 } else if ( (use_dpy = getenv("DISPLAY")) ) {
5078 if (strstr(use_dpy, "localhost") == use_dpy) {
5079 rfbLog("\n");
5080 rfbLog("WARNING: DISPLAY starts with localhost: '%s'\n", use_dpy);
5081 rfbLog("WARNING: Is this an SSH X11 port forwarding? You most\n");
5082 rfbLog("WARNING: likely don't want x11vnc to use that DISPLAY.\n");
5083 rfbLog("WARNING: You probably should supply something\n");
5084 rfbLog("WARNING: like: -display :0 to access the physical\n");
5085 rfbLog("WARNING: X display on the machine where x11vnc is running.\n");
5086 rfbLog("\n");
5087 usleep(500 * 1000);
5088 } else if (using_shm && use_dpy[0] != ':') {
5089 rfbLog("\n");
5090 rfbLog("WARNING: DISPLAY might not be local: '%s'\n", use_dpy);
5091 rfbLog("WARNING: Is this the DISPLAY of another machine? Usually,\n");
5092 rfbLog("WARNING: x11vnc is run on the same machine with the\n");
5093 rfbLog("WARNING: physical X display to be exported by VNC. If\n");
5094 rfbLog("WARNING: that is what you really meant, supply something\n");
5095 rfbLog("WARNING: like: -display :0 on the x11vnc command line.\n");
5096 rfbLog("\n");
5097 usleep(250 * 1000);
5098 }
5099 dpy = XOpenDisplay_wr(use_dpy);
5100 } else {
5101 dpy = XOpenDisplay_wr("");
5102 }
5103 last_open_xdisplay = time(NULL);
5104
5105 if (terminal_services_daemon != NULL) {
5106 terminal_services(terminal_services_daemon);
5107 exit(0);
5108 }
5109
5110 if (dpy && !xrandr && !got_noxrandr) {
5111 #if !NO_X11
5112 Atom trap_xrandr = XInternAtom(dpy, "X11VNC_TRAP_XRANDR", True);
5113 if (trap_xrandr != None) {
5114 if (! quiet) {
5115 rfbLog("Enabling -xrandr due to X11VNC_TRAP_XRANDR atom.\n");
5116 }
5117 xrandr = 1;
5118 }
5119 #endif
5120 }
5121
5122 #ifdef MACOSX
5123 if (! dpy && ! raw_fb_str) {
5124 raw_fb_str = strdup("console");
5125 }
5126 #endif
5127
5128 if (! dpy && raw_fb_str) {
5129 rfbLog("Continuing without X display in -rawfb mode.\n");
5130 goto raw_fb_pass_go_and_collect_200_dollars;
5131 }
5132
5133 if (! dpy && ! use_dpy && ! getenv("DISPLAY")) {
5134 int i, s = 4;
5135 rfbLogEnable(1);
5136 rfbLog("\a\n");
5137 rfbLog("*** XOpenDisplay failed. No -display or DISPLAY.\n");
5138 rfbLog("*** Trying \":0\" in %d seconds. Press Ctrl-C to"
5139 " abort.\n", s);
5140 rfbLog("*** ");
5141 for (i=1; i<=s; i++) {
5142 fprintf(stderr, "%d ", i);
5143 sleep(1);
5144 }
5145 fprintf(stderr, "\n");
5146 use_dpy = ":0";
5147 dpy = XOpenDisplay_wr(use_dpy);
5148 last_open_xdisplay = time(NULL);
5149 if (dpy) {
5150 rfbLog("*** XOpenDisplay of \":0\" successful.\n");
5151 }
5152 rfbLog("\n");
5153 if (quiet) rfbLogEnable(0);
5154 }
5155
5156 if (! dpy) {
5157 char *d = use_dpy;
5158 if (!d) d = getenv("DISPLAY");
5159 if (!d) d = "null";
5160 rfbLogEnable(1);
5161 fprintf(stderr, "\n");
5162 rfbLog("***************************************\n", d);
5163 rfbLog("*** XOpenDisplay failed (%s)\n", d);
5164 xopen_display_fail_message(d);
5165 exit(1);
5166 } else if (use_dpy) {
5167 if (! quiet) rfbLog("Using X display %s\n", use_dpy);
5168 } else {
5169 if (! quiet) rfbLog("Using default X display.\n");
5170 }
5171
5172 if (clip_str != NULL && dpy != NULL) {
5173 check_xinerama_clip();
5174 }
5175
5176 scr = DefaultScreen(dpy);
5177 rootwin = RootWindow(dpy, scr);
5178
5179 #if !NO_X11
5180 if (dpy) {
5181 Window w = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0);
5182 if (! quiet) rfbLog("rootwin: 0x%lx reswin: 0x%lx dpy: 0x%x\n", rootwin, w, dpy);
5183 if (w != None) {
5184 XDestroyWindow(dpy, w);
5185 }
5186 XSync(dpy, False);
5187 }
5188 #endif
5189
5190 if (ncache_beta_tester) {
5191 int h = DisplayHeight(dpy, scr);
5192 int w = DisplayWidth(dpy, scr);
5193 int mem = (w * h * 4) / (1000 * 1000), MEM = 96;
5194 if (mem < 1) mem = 1;
5195
5196 /* limit poor, unsuspecting beta tester's viewer to 96 MB */
5197 if ( (ncache+2) * mem > MEM ) {
5198 int n = (MEM/mem) - 2;
5199 if (n < 0) n = 0;
5200 n = 2 * (n / 2);
5201 if (n < ncache) {
5202 ncache = n;
5203 }
5204 }
5205 }
5206
5207 if (grab_always) {
5208 Window save = window;
5209 window = rootwin;
5210 adjust_grabs(1, 0);
5211 window = save;
5212 }
5213
5214 if ( (remote_cmd && strstr(remote_cmd, "DIRECT:") == remote_cmd)
5215 || (query_cmd && strstr(query_cmd, "DIRECT:") == query_cmd )) {
5216 /* handled below after most everything is setup. */
5217 if (getenv("QUERY_VERBOSE")) {
5218 quiet = 0;
5219 } else {
5220 quiet = 1;
5221 remote_direct = 1;
5222 }
5223 if (!auto_port) {
5224 auto_port = 5970;
5225 }
5226 } else if (remote_cmd || query_cmd) {
5227 int i, rc = 1;
5228 for (i=0; i <= query_retries; i++) {
5229 rc = do_remote_query(remote_cmd, query_cmd, remote_sync,
5230 query_default);
5231 if (rc == 0) {
5232 if (query_match) {
5233 if (query_result && strstr(query_result, query_match)) {
5234 break;
5235 }
5236 rc = 1;
5237 } else {
5238 break;
5239 }
5240 }
5241 if (i < query_retries) {
5242 fprintf(stderr, "sleep: %.3f\n", query_delay);
5243 usleep( (int) (query_delay * 1000 * 1000) );
5244 }
5245 }
5246 XFlush_wr(dpy);
5247 fflush(stderr);
5248 fflush(stdout);
5249 usleep(30 * 1000); /* still needed? */
5250 XCloseDisplay_wr(dpy);
5251 exit(rc);
5252 }
5253
5254 if (! quiet && ! raw_fb_str) {
5255 rfbLog("\n");
5256 rfbLog("------------------ USEFUL INFORMATION ------------------\n");
5257 }
5258
5259 if (priv_remote) {
5260 if (! remote_control_access_ok()) {
5261 rfbLog("** Disabling remote commands in -privremote mode.\n");
5262 accept_remote_cmds = 0;
5263 }
5264 }
5265
5266 sync_tod_with_servertime();
5267 if (grab_buster) {
5268 spawn_grab_buster();
5269 }
5270
5271 #if LIBVNCSERVER_HAVE_LIBXFIXES
5272 if (! XFixesQueryExtension(dpy, &xfixes_base_event_type, &er)) {
5273 if (! quiet && ! raw_fb_str) {
5274 rfbLog("Disabling XFIXES mode: display does not support it.\n");
5275 }
5276 xfixes_base_event_type = 0;
5277 xfixes_present = 0;
5278 } else {
5279 xfixes_present = 1;
5280 }
5281 #endif
5282 if (! xfixes_present) {
5283 use_xfixes = 0;
5284 }
5285
5286 #if LIBVNCSERVER_HAVE_LIBXDAMAGE
5287 if (! XDamageQueryExtension(dpy, &xdamage_base_event_type, &er)) {
5288 if (! quiet && ! raw_fb_str) {
5289 rfbLog("Disabling X DAMAGE mode: display does not support it.\n");
5290 }
5291 xdamage_base_event_type = 0;
5292 xdamage_present = 0;
5293 } else {
5294 xdamage_present = 1;
5295 }
5296 #endif
5297 if (! xdamage_present) {
5298 use_xdamage = 0;
5299 }
5300 if (! quiet && xdamage_present && use_xdamage && ! raw_fb_str) {
5301 rfbLog("X DAMAGE available on display, using it for polling hints.\n");
5302 rfbLog(" To disable this behavior use: '-noxdamage'\n");
5303 rfbLog("\n");
5304 rfbLog(" Most compositing window managers like 'compiz' or 'beryl'\n");
5305 rfbLog(" cause X DAMAGE to fail, and so you may not see any screen\n");
5306 rfbLog(" updates via VNC. Either disable 'compiz' (recommended) or\n");
5307 rfbLog(" supply the x11vnc '-noxdamage' command line option.\n");
5308 }
5309
5310 if (! quiet && wireframe && ! raw_fb_str) {
5311 rfbLog("\n");
5312 rfbLog("Wireframing: -wireframe mode is in effect for window moves.\n");
5313 rfbLog(" If this yields undesired behavior (poor response, painting\n");
5314 rfbLog(" errors, etc) it may be disabled:\n");
5315 rfbLog(" - use '-nowf' to disable wireframing completely.\n");
5316 rfbLog(" - use '-nowcr' to disable the Copy Rectangle after the\n");
5317 rfbLog(" moved window is released in the new position.\n");
5318 rfbLog(" Also see the -help entry for tuning parameters.\n");
5319 rfbLog(" You can press 3 Alt_L's (Left \"Alt\" key) in a row to \n");
5320 rfbLog(" repaint the screen, also see the -fixscreen option for\n");
5321 rfbLog(" periodic repaints.\n");
5322 if (scale_str && !strstr(scale_str, "nocr")) {
5323 rfbLog(" Note: '-scale' is on and this can cause more problems.\n");
5324 }
5325 }
5326
5327 overlay_present = 0;
5328 #if defined(SOLARIS_OVERLAY) && !NO_X11
5329 if (! XQueryExtension(dpy, "SUN_OVL", &maj, &ev, &er)) {
5330 if (! quiet && overlay && ! raw_fb_str) {
5331 rfbLog("Disabling -overlay: SUN_OVL extension not available.\n");
5332 }
5333 } else {
5334 overlay_present = 1;
5335 }
5336 #endif
5337 #if defined(IRIX_OVERLAY) && !NO_X11
5338 if (! XReadDisplayQueryExtension(dpy, &ev, &er)) {
5339 if (! quiet && overlay && ! raw_fb_str) {
5340 rfbLog("Disabling -overlay: IRIX ReadDisplay extension not available.\n");
5341 }
5342 } else {
5343 overlay_present = 1;
5344 }
5345 #endif
5346 if (overlay && !overlay_present) {
5347 overlay = 0;
5348 overlay_cursor = 0;
5349 }
5350
5351 /* cursor shapes setup */
5352 if (! multiple_cursors_mode) {
5353 multiple_cursors_mode = strdup("default");
5354 }
5355 if (show_cursor) {
5356 if(!strcmp(multiple_cursors_mode, "default")
5357 && xfixes_present && use_xfixes) {
5358 free(multiple_cursors_mode);
5359 multiple_cursors_mode = strdup("most");
5360
5361 if (! quiet && ! raw_fb_str) {
5362 rfbLog("\n");
5363 rfbLog("XFIXES available on display, resetting cursor mode\n");
5364 rfbLog(" to: '-cursor most'.\n");
5365 rfbLog(" to disable this behavior use: '-cursor arrow'\n");
5366 rfbLog(" or '-noxfixes'.\n");
5367 }
5368 }
5369 if(!strcmp(multiple_cursors_mode, "most")) {
5370 if (xfixes_present && use_xfixes &&
5371 overlay_cursor == 1) {
5372 if (! quiet && ! raw_fb_str) {
5373 rfbLog("using XFIXES for cursor drawing.\n");
5374 }
5375 overlay_cursor = 0;
5376 }
5377 }
5378 }
5379
5380 if (overlay) {
5381 using_shm = 0;
5382 if (flash_cmap && ! quiet && ! raw_fb_str) {
5383 rfbLog("warning: -flashcmap may be incompatible with -overlay\n");
5384 }
5385 if (show_cursor && overlay_cursor) {
5386 char *s = multiple_cursors_mode;
5387 if (*s == 'X' || !strcmp(s, "some") ||
5388 !strcmp(s, "arrow")) {
5389 /*
5390 * user wants these modes, so disable fb cursor
5391 */
5392 overlay_cursor = 0;
5393 } else {
5394 /*
5395 * "default" and "most", we turn off
5396 * show_cursor since it will automatically
5397 * be in the framebuffer.
5398 */
5399 show_cursor = 0;
5400 }
5401 }
5402 }
5403
5404 initialize_cursors_mode();
5405
5406 /* check for XTEST */
5407 if (! XTestQueryExtension_wr(dpy, &ev, &er, &maj, &min)) {
5408 if (! quiet && ! raw_fb_str) {
5409 rfbLog("\n");
5410 rfbLog("WARNING: XTEST extension not available (either missing from\n");
5411 rfbLog(" display or client library libXtst missing at build time).\n");
5412 rfbLog(" MOST user input (pointer and keyboard) will be DISCARDED.\n");
5413 rfbLog(" If display does have XTEST, be sure to build x11vnc with\n");
5414 rfbLog(" a working libXtst build environment (e.g. libxtst-dev,\n");
5415 rfbLog(" or other packages).\n");
5416 rfbLog("No XTEST extension, switching to -xwarppointer mode for\n");
5417 rfbLog(" pointer motion input.\n");
5418 }
5419 xtest_present = 0;
5420 use_xwarppointer = 1;
5421 } else {
5422 xtest_present = 1;
5423 xtest_base_event_type = ev;
5424 if (maj <= 1 || (maj == 2 && min <= 2)) {
5425 /* no events defined as of 2.2 */
5426 xtest_base_event_type = 0;
5427 }
5428 }
5429
5430 if (! XETrapQueryExtension_wr(dpy, &ev, &er, &maj)) {
5431 xtrap_present = 0;
5432 } else {
5433 xtrap_present = 1;
5434 xtrap_base_event_type = ev;
5435 }
5436
5437 /*
5438 * Window managers will often grab the display during resize,
5439 * etc, using XGrabServer(). To avoid deadlock (our user resize
5440 * input is not processed) we tell the server to process our
5441 * requests during all grabs:
5442 */
5443 disable_grabserver(dpy, 0);
5444
5445 /* check for RECORD */
5446 if (! XRecordQueryVersion_wr(dpy, &maj, &min)) {
5447 xrecord_present = 0;
5448 if (! quiet) {
5449 rfbLog("\n");
5450 rfbLog("The RECORD X extension was not found on the display.\n");
5451 rfbLog("If your system has disabled it by default, you can\n");
5452 rfbLog("enable it to get a nice x11vnc performance speedup\n");
5453 rfbLog("for scrolling by putting this into the \"Module\" section\n");
5454 rfbLog("of /etc/X11/xorg.conf or /etc/X11/XF86Config:\n");
5455 rfbLog("\n");
5456 rfbLog(" Section \"Module\"\n");
5457 rfbLog(" ...\n");
5458 rfbLog(" Load \"record\"\n");
5459 rfbLog(" ...\n");
5460 rfbLog(" EndSection\n");
5461 rfbLog("\n");
5462 }
5463 } else {
5464 xrecord_present = 1;
5465 }
5466
5467 initialize_xrecord();
5468
5469 tmpi = 1;
5470 if (scroll_copyrect) {
5471 if (strstr(scroll_copyrect, "never")) {
5472 tmpi = 0;
5473 }
5474 } else if (scroll_copyrect_default) {
5475 if (strstr(scroll_copyrect_default, "never")) {
5476 tmpi = 0;
5477 }
5478 }
5479 if (! xrecord_present) {
5480 tmpi = 0;
5481 }
5482 #if !LIBVNCSERVER_HAVE_RECORD
5483 tmpi = 0;
5484 #endif
5485 if (! quiet && tmpi && ! raw_fb_str) {
5486 rfbLog("\n");
5487 rfbLog("Scroll Detection: -scrollcopyrect mode is in effect to\n");
5488 rfbLog(" use RECORD extension to try to detect scrolling windows\n");
5489 rfbLog(" (induced by either user keystroke or mouse input).\n");
5490 rfbLog(" If this yields undesired behavior (poor response, painting\n");
5491 rfbLog(" errors, etc) it may be disabled via: '-noscr'\n");
5492 rfbLog(" Also see the -help entry for tuning parameters.\n");
5493 rfbLog(" You can press 3 Alt_L's (Left \"Alt\" key) in a row to \n");
5494 rfbLog(" repaint the screen, also see the -fixscreen option for\n");
5495 rfbLog(" periodic repaints.\n");
5496 if (scale_str && !strstr(scale_str, "nocr")) {
5497 rfbLog(" Note: '-scale' is on and this can cause more problems.\n");
5498 }
5499 }
5500
5501 if (! quiet && ncache && ! raw_fb_str) {
5502 rfbLog("\n");
5503 rfbLog("Client Side Caching: -ncache mode is in effect to provide\n");
5504 rfbLog(" client-side pixel data caching. This speeds up\n");
5505 rfbLog(" iconifying/deiconifying windows, moving and raising\n");
5506 rfbLog(" windows, and reposting menus. In the simple CopyRect\n");
5507 rfbLog(" encoding scheme used (no compression) a huge amount\n");
5508 rfbLog(" of extra memory (20-100MB) is used on both the server and\n");
5509 rfbLog(" client sides. This mode works with any VNC viewer.\n");
5510 rfbLog(" However, in most you can actually see the cached pixel\n");
5511 rfbLog(" data by scrolling down, so you need to re-adjust its size.\n");
5512 rfbLog(" See http://www.karlrunge.com/x11vnc/faq.html#faq-client-caching.\n");
5513 rfbLog(" If this mode yields undesired behavior (poor response,\n");
5514 rfbLog(" painting errors, etc) it may be disabled via: '-ncache 0'\n");
5515 rfbLog(" You can press 3 Alt_L's (Left \"Alt\" key) in a row to \n");
5516 rfbLog(" repaint the screen, also see the -fixscreen option for\n");
5517 rfbLog(" periodic repaints.\n");
5518 if (scale_str) {
5519 rfbLog(" Note: '-scale' is on and this can cause more problems.\n");
5520 }
5521 }
5522 if (ncache && getenv("NCACHE_DEBUG")) {
5523 ncdb = 1;
5524 }
5525
5526 /* check for OS with small shm limits */
5527 if (using_shm && ! single_copytile) {
5528 if (limit_shm()) {
5529 single_copytile = 1;
5530 }
5531 }
5532
5533 single_copytile_orig = single_copytile;
5534
5535 /* check for MIT-SHM */
5536 if (! XShmQueryExtension_wr(dpy)) {
5537 xshm_present = 0;
5538 if (! using_shm) {
5539 if (! quiet && ! raw_fb_str) {
5540 rfbLog("info: display does not support XShm.\n");
5541 }
5542 } else {
5543 if (! quiet && ! raw_fb_str) {
5544 rfbLog("\n");
5545 rfbLog("warning: XShm extension is not available.\n");
5546 rfbLog("For best performance the X Display should be local. (i.e.\n");
5547 rfbLog("the x11vnc and X server processes should be running on\n");
5548 rfbLog("the same machine.)\n");
5549 #if LIBVNCSERVER_HAVE_XSHM
5550 rfbLog("Restart with -noshm to override this.\n");
5551 }
5552 exit(1);
5553 #else
5554 rfbLog("Switching to -noshm mode.\n");
5555 }
5556 using_shm = 0;
5557 #endif
5558 }
5559 } else {
5560 #if !NO_X11
5561 int op, ev, er;
5562 if (XQueryExtension(dpy, "MIT-SHM", &op, &ev, &er)) {
5563 xshm_opcode = op;
5564 if (0) fprintf(stderr, "xshm_opcode: %d %d %d\n", op, ev, er);
5565 }
5566 #endif
5567 }
5568
5569 #if LIBVNCSERVER_HAVE_XKEYBOARD
5570 /* check for XKEYBOARD */
5571 initialize_xkb();
5572 initialize_watch_bell();
5573 if (!xkb_present && use_xkb_modtweak) {
5574 if (! quiet && ! raw_fb_str) {
5575 rfbLog("warning: disabling xkb modtweak. XKEYBOARD ext. not present.\n");
5576 }
5577 use_xkb_modtweak = 0;
5578 }
5579 #endif
5580
5581 if (xkb_present && !use_xkb_modtweak && !got_noxkb) {
5582 if (use_modifier_tweak) {
5583 switch_to_xkb_if_better();
5584 }
5585 }
5586
5587 #if LIBVNCSERVER_HAVE_LIBXRANDR
5588 if (! XRRQueryExtension(dpy, &xrandr_base_event_type, &er)) {
5589 if (xrandr && ! quiet && ! raw_fb_str) {
5590 rfbLog("Disabling -xrandr mode: display does not support X RANDR.\n");
5591 }
5592 xrandr_base_event_type = 0;
5593 xrandr = 0;
5594 xrandr_maybe = 0;
5595 xrandr_present = 0;
5596 } else {
5597 xrandr_present = 1;
5598 }
5599 #endif
5600
5601 check_pm();
5602
5603 if (! quiet && ! raw_fb_str) {
5604 rfbLog("--------------------------------------------------------\n");
5605 rfbLog("\n");
5606 }
5607
5608 raw_fb_pass_go_and_collect_200_dollars:
5609
5610 if (! dpy || raw_fb_str) {
5611 int doit = 0;
5612 /* XXX this needs improvement (esp. for remote control) */
5613 if (! raw_fb_str || strstr(raw_fb_str, "console") == raw_fb_str) {
5614 #ifdef MACOSX
5615 doit = 1;
5616 #endif
5617 }
5618 if (raw_fb_str && strstr(raw_fb_str, "vnc") == raw_fb_str) {
5619 doit = 1;
5620 }
5621 if (doit) {
5622 if (! multiple_cursors_mode) {
5623 multiple_cursors_mode = strdup("most");
5624 }
5625 initialize_cursors_mode();
5626 use_xdamage = orig_use_xdamage;
5627 if (use_xdamage) {
5628 xdamage_present = 1;
5629 initialize_xdamage();
5630 }
5631 }
5632 }
5633
5634 if (! dt) {
5635 static char str[] = "-desktop";
5636 argv_vnc[argc_vnc++] = str;
5637 argv_vnc[argc_vnc++] = choose_title(use_dpy);
5638 rfb_desktop_name = strdup(argv_vnc[argc_vnc-1]);
5639 }
5640
5641 /*
5642 * Create the XImage corresponding to the display framebuffer.
5643 */
5644
5645 fb0 = initialize_xdisplay_fb();
5646
5647 /*
5648 * In some cases (UINPUT touchscreens) we need the dpy_x dpy_y
5649 * to initialize pipeinput. So we do it after fb is created.
5650 */
5651 initialize_pipeinput();
5652
5653 /*
5654 * n.b. we do not have to X_LOCK any X11 calls until watch_loop()
5655 * is called since we are single-threaded until then.
5656 */
5657
5658 initialize_screen(&argc_vnc, argv_vnc, fb0);
5659
5660 if (waited_for_client) {
5661 if (fake_fb) {
5662 free(fake_fb);
5663 fake_fb = NULL;
5664 }
5665 if (use_solid_bg && client_count) {
5666 solid_bg(0);
5667 }
5668 if (accept_cmd && strstr(accept_cmd, "popup") == accept_cmd) {
5669 rfbClientIteratorPtr iter;
5670 rfbClientPtr cl, cl0 = NULL;
5671 int i = 0;
5672 iter = rfbGetClientIterator(screen);
5673 while( (cl = rfbClientIteratorNext(iter)) ) {
5674 i++;
5675 if (i != 1) {
5676 rfbLog("WAIT popup: too many clients\n");
5677 clean_up_exit(1);
5678 }
5679 cl0 = cl;
5680 }
5681 rfbReleaseClientIterator(iter);
5682 if (i != 1 || cl0 == NULL) {
5683 rfbLog("WAIT popup: no clients.\n");
5684 clean_up_exit(1);
5685 }
5686 if (! accept_client(cl0)) {
5687 rfbLog("WAIT popup: denied.\n");
5688 clean_up_exit(1);
5689 }
5690 rfbLog("waited_for_client: popup accepted.\n");
5691 cl0->onHold = FALSE;
5692 }
5693 if (macosx_console) {
5694 refresh_screen(1);
5695 }
5696 if (dpy && xdmcp_insert != NULL) {
5697 #if !NO_X11
5698 char c;
5699 int n = strlen(xdmcp_insert);
5700 KeyCode k, k2;
5701 KeySym sym;
5702 int i, ok = 1;
5703 for (i = 0; i < n; i++) {
5704 c = xdmcp_insert[i];
5705 sym = (KeySym) c;
5706 if (sym < ' ' || sym > 0x7f) {
5707 ok = 0;
5708 break;
5709 }
5710 k = XKeysymToKeycode(dpy, sym);
5711 if (k == NoSymbol) {
5712 ok = 0;
5713 break;
5714 }
5715 }
5716 if (ok) {
5717 XFlush_wr(dpy);
5718 usleep(2*1000*1000);
5719 if (!quiet) {
5720 rfbLog("sending XDM '%s'\n", xdmcp_insert);
5721 }
5722 for (i = 0; i < n; i++) {
5723 c = xdmcp_insert[i];
5724 sym = (KeySym) c;
5725 k = XKeysymToKeycode(dpy, sym);
5726 if (isupper(c)) {
5727 k2 = XKeysymToKeycode(dpy, XK_Shift_L);
5728 XTestFakeKeyEvent_wr(dpy, k2, True, CurrentTime);
5729 XFlush_wr(dpy);
5730 usleep(100*1000);
5731 }
5732 if (0) fprintf(stderr, "C/k %c/%x\n", c, k);
5733 XTestFakeKeyEvent_wr(dpy, k, True, CurrentTime);
5734 XFlush_wr(dpy);
5735 usleep(100*1000);
5736 XTestFakeKeyEvent_wr(dpy, k, False, CurrentTime);
5737 XFlush_wr(dpy);
5738 usleep(100*1000);
5739 if (isupper(c)) {
5740 k2 = XKeysymToKeycode(dpy, XK_Shift_L);
5741 XTestFakeKeyEvent_wr(dpy, k2, False, CurrentTime);
5742 XFlush_wr(dpy);
5743 usleep(100*1000);
5744 }
5745 }
5746 k2 = XKeysymToKeycode(dpy, XK_Tab);
5747 XTestFakeKeyEvent_wr(dpy, k2, True, CurrentTime);
5748 XFlush_wr(dpy);
5749 usleep(100*1000);
5750 XTestFakeKeyEvent_wr(dpy, k2, False, CurrentTime);
5751 XFlush_wr(dpy);
5752 usleep(100*1000);
5753 }
5754 free(xdmcp_insert);
5755 #endif
5756 }
5757 check_redir_services();
5758 }
5759
5760 if (! waited_for_client) {
5761 if (try_http && ! got_httpdir && check_httpdir()) {
5762 http_connections(1);
5763 }
5764 if (ssh_str != NULL) {
5765 ssh_remote_tunnel(ssh_str, screen->port);
5766 }
5767 }
5768
5769 initialize_tiles();
5770
5771 /* rectangular blackout regions */
5772 initialize_blackouts_and_xinerama();
5773
5774 /* created shm or XImages when using_shm = 0 */
5775 initialize_polling_images();
5776
5777 initialize_signals();
5778
5779 initialize_speeds();
5780
5781 if (speeds_read_rate_measured > 80) {
5782 /* framebuffer read is fast at > 80 MB/sec */
5783 int same = 0;
5784 if (waitms == defer_update) {
5785 same = 1;
5786 }
5787 if (! got_waitms) {
5788 waitms /= 2;
5789 if (waitms < 5) {
5790 waitms = 5;
5791 }
5792 if (!quiet) {
5793 rfbLog("fast read: reset -wait ms to: %d\n", waitms);
5794 }
5795 }
5796 if (! got_deferupdate && ! got_defer) {
5797 if (defer_update > 10) {
5798 if (same) {
5799 defer_update = waitms;
5800 } else {
5801 defer_update = 10;
5802 }
5803 if (screen) {
5804 screen->deferUpdateTime = defer_update;
5805 }
5806 rfbLog("fast read: reset -defer ms to: %d\n", defer_update);
5807 }
5808 }
5809 }
5810
5811 initialize_keyboard_and_pointer();
5812
5813 if (inetd && use_openssl) {
5814 if (! waited_for_client) {
5815 accept_openssl(OPENSSL_INETD, -1);
5816 }
5817 }
5818 if (! inetd && ! use_openssl) {
5819 if (! screen->port || screen->listenSock < 0) {
5820 if (got_rfbport && got_rfbport_val == 0) {
5821 ;
5822 } else if (ipv6_listen && ipv6_listen_fd >= 0) {
5823 rfbLog("Info: listening only on IPv6 interface.\n");
5824 } else {
5825 rfbLogEnable(1);
5826 rfbLog("Error: could not obtain listening port.\n");
5827 if (!got_rfbport && !got_ipv6_listen) {
5828 rfbLog("If this system is IPv6-only, use the -6 option.\n");
5829 }
5830 clean_up_exit(1);
5831 }
5832 }
5833 }
5834
5835 #ifdef MACOSX
5836 if (remote_cmd || query_cmd) {
5837 ;
5838 } else if (macosx_console) {
5839 double dt = dnow();
5840 copy_screen();
5841 dt = dnow() - dt;
5842 rfbLog("macosx_console: copied screen in %.3f sec %.1f MB/sec\n",
5843 dt, dpy_x * dpy_y * bpp / (1e+6 * 8 * dt));
5844
5845 }
5846 #endif
5847
5848 if (! quiet) {
5849 rfbLog("screen setup finished.\n");
5850 if (SHOW_NO_PASSWORD_WARNING && !nopw) {
5851 rfbLog("\n");
5852 rfbLog("WARNING: You are running x11vnc WITHOUT"
5853 " a password. See\n");
5854 rfbLog("WARNING: the warning message printed above"
5855 " for more info.\n");
5856 }
5857 }
5858 set_vnc_desktop_name();
5859
5860 if (ncache_beta_tester && (ncache != 0 || ncache_msg)) {
5861 ncache_beta_tester_message();
5862 }
5863
5864 if (remote_cmd || query_cmd) {
5865 /* This is DIRECT: case */
5866 do_remote_query(remote_cmd, query_cmd, remote_sync, query_default);
5867 if (getenv("SLEEP")) sleep(atoi(getenv("SLEEP")));
5868 clean_up_exit(0);
5869 }
5870
5871 #if LIBVNCSERVER_HAVE_FORK && LIBVNCSERVER_HAVE_SETSID
5872 if (bg) {
5873 int p, n;
5874 if (getenv("X11VNC_LOOP_MODE_BG")) {
5875 if (screen && screen->listenSock >= 0) {
5876 close(screen->listenSock);
5877 FD_CLR(screen->listenSock,&screen->allFds);
5878 screen->listenSock = -1;
5879 }
5880 if (screen && screen->httpListenSock >= 0) {
5881 close(screen->httpListenSock);
5882 screen->httpListenSock = -1;
5883 }
5884 if (openssl_sock >= 0) {
5885 close(openssl_sock);
5886 openssl_sock = -1;
5887 }
5888 if (https_sock >= 0) {
5889 close(https_sock);
5890 https_sock = -1;
5891 }
5892 if (openssl_sock6 >= 0) {
5893 close(openssl_sock6);
5894 openssl_sock6 = -1;
5895 }
5896 if (https_sock6 >= 0) {
5897 close(https_sock6);
5898 https_sock6 = -1;
5899 }
5900 if (ipv6_listen_fd >= 0) {
5901 close(ipv6_listen_fd);
5902 ipv6_listen_fd = -1;
5903 }
5904 if (ipv6_http_fd >= 0) {
5905 close(ipv6_http_fd);
5906 ipv6_http_fd = -1;
5907 }
5908 }
5909 /* fork into the background now */
5910 if ((p = fork()) > 0) {
5911 exit(0);
5912 } else if (p == -1) {
5913 rfbLogEnable(1);
5914 fprintf(stderr, "could not fork\n");
5915 perror("fork");
5916 clean_up_exit(1);
5917 }
5918 if (setsid() == -1) {
5919 rfbLogEnable(1);
5920 fprintf(stderr, "setsid failed\n");
5921 perror("setsid");
5922 clean_up_exit(1);
5923 }
5924 /* adjust our stdio */
5925 n = open("/dev/null", O_RDONLY);
5926 dup2(n, 0);
5927 dup2(n, 1);
5928 if (! logfile) {
5929 dup2(n, 2);
5930 }
5931 if (n > 2) {
5932 close(n);
5933 }
5934 }
5935 #endif
5936
5937 watch_loop();
5938
5939 return(0);
5940
5941 #undef argc
5942 #undef argv
5943
5944 }
5945
5946