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