1 /*
2    Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3    All rights reserved.
4 
5 This file is part of x11vnc.
6 
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11 
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21 
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables.  You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL".  If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so.  If you do not wish to do
30 so, delete this exception statement from your version.
31 */
32 
33 /* -- connections.c -- */
34 
35 #include "x11vnc.h"
36 #include "inet.h"
37 #include "remote.h"
38 #include "keyboard.h"
39 #include "cleanup.h"
40 #include "gui.h"
41 #include "solid.h"
42 #include "rates.h"
43 #include "screen.h"
44 #include "unixpw.h"
45 #include "user.h"
46 #include "scan.h"
47 #include "sslcmds.h"
48 #include "sslhelper.h"
49 #include "xwrappers.h"
50 #include "xevents.h"
51 #include "win_utils.h"
52 #include "macosx.h"
53 #include "macosxCG.h"
54 #include "userinput.h"
55 #include "pointer.h"
56 #include "xrandr.h"
57 #include "xi2_devices.h"
58 
59 
60 /*
61  * routines for handling incoming, outgoing, etc connections
62  */
63 
64 /* string for the VNC_CONNECT property */
65 char vnc_connect_str[VNC_CONNECT_MAX+1];
66 Atom vnc_connect_prop = None;
67 char x11vnc_remote_str[X11VNC_REMOTE_MAX+1];
68 Atom x11vnc_remote_prop = None;
69 rfbClientPtr inetd_client = NULL;
70 
71 int all_clients_initialized(void);
72 char *list_clients(void);
73 int new_fb_size_clients(rfbScreenInfoPtr s);
74 void close_all_clients(void);
75 void close_clients(char *str);
76 void set_client_input(char *str);
77 void set_child_info(void);
78 int cmd_ok(char *cmd);
79 void client_gone(rfbClientPtr client);
80 void client_gone_chat_helper(rfbClientPtr client);
81 void reverse_connect(char *str);
82 void set_vnc_connect_prop(char *str);
83 void read_vnc_connect_prop(int);
84 void set_x11vnc_remote_prop(char *str);
85 void read_x11vnc_remote_prop(int);
86 void check_connect_inputs(void);
87 void check_gui_inputs(void);
88 rfbClientPtr create_new_client(int sock, int start_thread);
89 enum rfbNewClientAction new_client(rfbClientPtr client);
90 enum rfbNewClientAction new_client_chat_helper(rfbClientPtr client);
91 rfbBool password_check_chat_helper(rfbClientPtr cl, const char* response, int len);
92 void start_client_info_sock(char *host_port_cookie);
93 void send_client_info(char *str);
94 void adjust_grabs(int grab, int quiet);
95 void check_new_clients(void);
96 int accept_client(rfbClientPtr client);
97 void check_ipv6_listen(long usec);
98 void check_unix_sock(long usec);
99 int run_user_command(char *cmd, rfbClientPtr client, char *mode, char *input,
100     int len, FILE *output);
101 int check_access(char *addr);
102 void client_set_net(rfbClientPtr client);
103 char *get_xprop(char *prop, Window win);
104 int set_xprop(char *prop, Window win, char *value);
105 char *bcx_xattach(char *str, int *pg_init, int *kg_init);
106 void grab_state(int *ptr_grabbed, int *kbd_grabbed);
107 char *wininfo(Window win, int show_children);
108 
109 static rfbClientPtr *client_match(char *str);
110 static void free_client_data(rfbClientPtr client);
111 static void ugly_geom(char *p, int *x, int *y);
112 static int ugly_window(char *addr, char *userhost, int X, int Y,
113     int timeout, char *mode, int accept);
114 static int action_match(char *action, int rc);
115 static void check_connect_file(char *file);
116 static void send_client_connect(void);
117 
118 
119 /*
120  * check that all clients are in RFB_NORMAL state
121  */
all_clients_initialized(void)122 int all_clients_initialized(void) {
123 	rfbClientIteratorPtr iter;
124 	rfbClientPtr cl;
125 	int ok = 1;
126 
127 	if (! screen) {
128 		return ok;
129 	}
130 
131 	iter = rfbGetClientIterator(screen);
132 	while( (cl = rfbClientIteratorNext(iter)) ) {
133 		if (cl->state != RFB_NORMAL) {
134 			ok = 0;
135 		} else {
136 			client_normal_count++;
137 		}
138 	}
139 	rfbReleaseClientIterator(iter);
140 
141 	return ok;
142 }
143 
list_clients(void)144 char *list_clients(void) {
145 	rfbClientIteratorPtr iter;
146 	rfbClientPtr cl;
147 	char *list, tmp[256];
148 	int count = 0;
149 
150 	if (!screen) {
151 		return strdup("");
152 	}
153 
154 	iter = rfbGetClientIterator(screen);
155 	while( (cl = rfbClientIteratorNext(iter)) ) {
156 		client_set_net(cl);
157 		count++;
158 	}
159 	rfbReleaseClientIterator(iter);
160 
161 	/*
162 	 * each client:
163          * <id>:<ip>:<port>:<user>:<unix>:<hostname>:<input>:<loginview>:<time>,
164 	 * 8+1+64+1+5+1+24+1+24+1+256+1+5+1+1+1+10+1
165 	 * 123.123.123.123:60000/0x11111111-rw,
166 	 * so count+1 * 1000 must cover it.
167 	 */
168 	list = (char *) malloc((count+1)*1000);
169 
170 	list[0] = '\0';
171 
172 	iter = rfbGetClientIterator(screen);
173 	while( (cl = rfbClientIteratorNext(iter)) ) {
174 		ClientData *cd = (ClientData *) cl->clientData;
175 		char *tmp_host, *p;
176 
177 		if (! cd) {
178 			continue;
179 		}
180 		if (*list != '\0') {
181 			strcat(list, ",");
182 		}
183 		sprintf(tmp, "0x%x:", cd->uid);
184 		strcat(list, tmp);
185 		p = tmp_host = strdup(cl->host);
186 		while (*p) {
187 			if (*p == ':') *p = '#';
188 			p++;
189 		}
190 		strcat(list, tmp_host);
191 		free(tmp_host);
192 		strcat(list, ":");
193 		sprintf(tmp, "%d:", cd->client_port);
194 		strcat(list, tmp);
195 		if (cd->username[0] == '\0') {
196 			char *s = ident_username(cl);
197 			if (s) free(s);
198 		}
199 		if (strstr(cd->username, "UNIX:") == cd->username) {
200 			strcat(list, cd->username + strlen("UNIX:"));
201 		} else {
202 			strcat(list, cd->username);
203 		}
204 		strcat(list, ":");
205 		if (cd->unixname[0] == '\0') {
206 			strcat(list, "none");
207 		} else {
208 			strcat(list, cd->unixname);
209 		}
210 		strcat(list, ":");
211 		p = tmp_host = strdup(cd->hostname);
212 		while (*p) {
213 			if (*p == ':') *p = '#';
214 			p++;
215 		}
216 		strcat(list, tmp_host);
217 		free(tmp_host);
218 		strcat(list, ":");
219 		strcat(list, cd->input);
220 		strcat(list, ":");
221 		sprintf(tmp, "%d", cd->login_viewonly);
222 		strcat(list, tmp);
223 		strcat(list, ":");
224 		sprintf(tmp, "%d", (int) cd->login_time);
225 		strcat(list, tmp);
226 	}
227 	rfbReleaseClientIterator(iter);
228 	return list;
229 }
230 
231 /* count number of clients supporting NewFBSize */
new_fb_size_clients(rfbScreenInfoPtr s)232 int new_fb_size_clients(rfbScreenInfoPtr s) {
233 	rfbClientIteratorPtr iter;
234 	rfbClientPtr cl;
235 	int count = 0;
236 
237 	if (! s) {
238 		return 0;
239 	}
240 
241 	iter = rfbGetClientIterator(s);
242 	while( (cl = rfbClientIteratorNext(iter)) ) {
243 		if (cl->useNewFBSize) {
244 			count++;
245 		}
246 	}
247 	rfbReleaseClientIterator(iter);
248 	return count;
249 }
250 
close_all_clients(void)251 void close_all_clients(void) {
252 	rfbClientIteratorPtr iter;
253 	rfbClientPtr cl;
254 
255 	if (! screen) {
256 		return;
257 	}
258 
259 	iter = rfbGetClientIterator(screen);
260 	while( (cl = rfbClientIteratorNext(iter)) ) {
261 		rfbCloseClient(cl);
262 		rfbClientConnectionGone(cl);
263 	}
264 	rfbReleaseClientIterator(iter);
265 }
266 
client_match(char * str)267 static rfbClientPtr *client_match(char *str) {
268 	rfbClientIteratorPtr iter;
269 	rfbClientPtr cl, *cl_list;
270 	int i, n, host_warn = 0, hex_warn = 0;
271 
272 	n = client_count + 10;
273 	cl_list = (rfbClientPtr *) malloc(n * sizeof(rfbClientPtr));
274 
275 	i = 0;
276 	iter = rfbGetClientIterator(screen);
277 	while( (cl = rfbClientIteratorNext(iter)) ) {
278 		ClientData *cd = (ClientData *) cl->clientData;
279 		if (strstr(str, "0x") == str) {
280 			unsigned int in;
281 			int id;
282 			if (! cd) {
283 				continue;
284 			}
285 			if (sscanf(str, "0x%x", &in) != 1) {
286 				if (hex_warn++) {
287 					continue;
288 				}
289 				rfbLog("skipping invalid client hex id: %s\n",
290 				    str);
291 				continue;
292 			}
293 			id = (unsigned int) in;
294 			if (cd->uid == id) {
295 				cl_list[i++] = cl;
296 			}
297 		} else {
298 			int port = -1;
299 			char *rstr = strdup(str);
300 			char *q = strrchr(rstr, ':');
301 			if (q) {
302 				port = atoi(q+1);
303 				*q = '\0';
304 				if (port == 0 && q[1] != '0') {
305 					port = -1;
306 				} else if (port < 0) {
307 					port = -port;
308 				} else if (port < 200) {
309 					port = 5500 + port;
310 				}
311 			}
312 			if (ipv6_ip(str)) {
313 				;
314 			} else if (! dotted_ip(str, 0)) {
315 				char *orig = rstr;
316 				rstr = host2ip(rstr);
317 				free(orig);
318 				if (rstr == NULL || *rstr == '\0') {
319 					if (host_warn++) {
320 						continue;
321 					}
322 					rfbLog("skipping bad lookup: \"%s\"\n", str);
323 					continue;
324 				}
325 				rfbLog("lookup: %s -> %s port=%d\n", str, rstr, port);
326 			}
327 			if (!strcmp(rstr, cl->host)) {
328 				int ok = 1;
329 				if (port > 0) {
330 					if (cd != NULL && cd->client_port > 0) {
331 						if (cd->client_port != port) {
332 							ok = 0;
333 						}
334 					} else {
335 						int cport = get_remote_port(cl->sock);
336 						if (cport != port) {
337 							ok = 0;
338 						}
339 					}
340 				}
341 				if (ok) {
342 					cl_list[i++] = cl;
343 				}
344 			}
345 			free(rstr);
346 		}
347 		if (i >= n - 1) {
348 			break;
349 		}
350 	}
351 	rfbReleaseClientIterator(iter);
352 
353 	cl_list[i] = NULL;
354 
355 	return cl_list;
356 }
357 
close_clients(char * str)358 void close_clients(char *str) {
359 	rfbClientPtr *cl_list, *cp;
360 
361 	if (!strcmp(str, "all") || !strcmp(str, "*")) {
362 		close_all_clients();
363 		return;
364 	}
365 
366 	if (! screen) {
367 		return;
368 	}
369 
370 	cl_list = client_match(str);
371 
372 	cp = cl_list;
373 	while (*cp) {
374 		rfbCloseClient(*cp);
375 		rfbClientConnectionGone(*cp);
376 		cp++;
377 	}
378 	free(cl_list);
379 }
380 
set_client_input(char * str)381 void set_client_input(char *str) {
382 	rfbClientPtr *cl_list, *cp;
383 	char *p, *val;
384 
385 	/* str is "match:value" */
386 
387 	if (! screen) {
388 		return;
389 	}
390 
391 	p = strrchr(str, ':');
392 	if (! p) {
393 		return;
394 	}
395 	*p = '\0';
396 	p++;
397 	val = short_kmbcf(p);
398 
399 	cl_list = client_match(str);
400 
401 	cp = cl_list;
402 	while (*cp) {
403 		ClientData *cd = (ClientData *) (*cp)->clientData;
404 		if (! cd) {
405 			continue;
406 		}
407 		cd->input[0] = '\0';
408 		strcat(cd->input, "_");
409 		strcat(cd->input, val);
410 		cp++;
411 	}
412 
413 	free(val);
414 	free(cl_list);
415 }
416 
set_child_info(void)417 void set_child_info(void) {
418 	char pid[16];
419 	/* set up useful environment for child process */
420 	sprintf(pid, "%d", (int) getpid());
421 	set_env("X11VNC_PID", pid);
422 	if (program_name) {
423 		/* e.g. for remote control -R */
424 		set_env("X11VNC_PROG", program_name);
425 	}
426 	if (program_cmdline) {
427 		set_env("X11VNC_CMDLINE", program_cmdline);
428 	}
429 	if (raw_fb_str) {
430 		set_env("X11VNC_RAWFB_STR", raw_fb_str);
431 	} else {
432 		set_env("X11VNC_RAWFB_STR", "");
433 	}
434 }
435 
cmd_ok(char * cmd)436 int cmd_ok(char *cmd) {
437 	char *p, *str;
438 	if (no_external_cmds) {
439 		return 0;
440 	}
441 	if (! cmd || cmd[0] == '\0') {
442 		return 0;
443 	}
444 	if (! allowed_external_cmds) {
445 		/* default, allow any (overridden by -nocmds) */
446 		return 1;
447 	}
448 
449 	str = strdup(allowed_external_cmds);
450 	p = strtok(str, ",");
451 	while (p) {
452 		if (!strcmp(p, cmd)) {
453 			free(str);
454 			return 1;
455 		}
456 		p = strtok(NULL, ",");
457 	}
458 	free(str);
459 	return 0;
460 }
461 
462 /*
463  * utility to run a user supplied command setting some RFB_ env vars.
464  * used by, e.g., accept_client() and client_gone()
465  */
run_user_command(char * cmd,rfbClientPtr client,char * mode,char * input,int len,FILE * output)466 int run_user_command(char *cmd, rfbClientPtr client, char *mode, char *input,
467    int len, FILE *output) {
468 	char *old_display = NULL;
469 	char *addr = NULL;
470 	char str[100];
471 	int rc, ok;
472 	ClientData *cd = NULL;
473 	client_set_net(client);
474 	if (client != NULL) {
475 		cd = (ClientData *) client->clientData;
476 		addr = client->host;
477 	}
478 
479 	if (addr == NULL || addr[0] == '\0') {
480 		addr = "unknown-host";
481 	}
482 
483 	/* set RFB_CLIENT_ID to semi unique id for command to use */
484 	if (cd && cd->uid) {
485 		sprintf(str, "0x%x", cd->uid);
486 	} else {
487 		/* not accepted yet: */
488 		sprintf(str, "0x%x", clients_served);
489 	}
490 	set_env("RFB_CLIENT_ID", str);
491 
492 	/* set RFB_CLIENT_IP to IP addr for command to use */
493 	set_env("RFB_CLIENT_IP", addr);
494 
495 	/* set RFB_X11VNC_PID to our pid for command to use */
496 	sprintf(str, "%d", (int) getpid());
497 	set_env("RFB_X11VNC_PID", str);
498 
499 	if (client == NULL) {
500 		;
501 	} else if (client->state == RFB_PROTOCOL_VERSION) {
502 		set_env("RFB_STATE", "PROTOCOL_VERSION");
503 	} else if (client->state == RFB_SECURITY_TYPE) {
504 		set_env("RFB_STATE", "SECURITY_TYPE");
505 	} else if (client->state == RFB_AUTHENTICATION) {
506 		set_env("RFB_STATE", "AUTHENTICATION");
507 	} else if (client->state == RFB_INITIALISATION) {
508 		set_env("RFB_STATE", "INITIALISATION");
509 	} else if (client->state == RFB_NORMAL) {
510 		set_env("RFB_STATE", "NORMAL");
511 	} else {
512 		set_env("RFB_STATE", "UNKNOWN");
513 	}
514 	if (certret_str) {
515 		set_env("RFB_SSL_CLIENT_CERT", certret_str);
516 	} else {
517 		set_env("RFB_SSL_CLIENT_CERT", "");
518 	}
519 
520 	/* set RFB_CLIENT_PORT to peer port for command to use */
521 	if (cd && cd->client_port > 0) {
522 		sprintf(str, "%d", cd->client_port);
523 	} else if (client) {
524 		sprintf(str, "%d", get_remote_port(client->sock));
525 	}
526 	set_env("RFB_CLIENT_PORT", str);
527 
528 	set_env("RFB_MODE", mode);
529 
530 	/*
531 	 * now do RFB_SERVER_IP and RFB_SERVER_PORT (i.e. us!)
532 	 * This will establish a 5-tuple (including tcp) the external
533 	 * program can potentially use to work out the virtual circuit
534 	 * for this connection.
535 	 */
536 	if (cd && cd->server_ip) {
537 		set_env("RFB_SERVER_IP", cd->server_ip);
538 	} else if (client) {
539 		char *sip = get_local_host(client->sock);
540 		set_env("RFB_SERVER_IP", sip);
541 		if (sip) free(sip);
542 	}
543 
544 	if (cd && cd->server_port > 0) {
545 		sprintf(str, "%d", cd->server_port);
546 	} else if (client) {
547 		sprintf(str, "%d", get_local_port(client->sock));
548 	}
549 	set_env("RFB_SERVER_PORT", str);
550 
551 	if (cd) {
552 		sprintf(str, "%d", cd->login_viewonly);
553 	} else {
554 		sprintf(str, "%d", -1);
555 	}
556 	set_env("RFB_LOGIN_VIEWONLY", str);
557 
558 	if (cd) {
559 		sprintf(str, "%d", (int) cd->login_time);
560 	} else {
561 		sprintf(str, ">%d", (int) time(NULL));
562 	}
563 	set_env("RFB_LOGIN_TIME", str);
564 
565 	sprintf(str, "%d", (int) time(NULL));
566 	set_env("RFB_CURRENT_TIME", str);
567 
568 	if (!cd || !cd->username || cd->username[0] == '\0') {
569 		set_env("RFB_USERNAME", "unknown-user");
570 	} else {
571 		set_env("RFB_USERNAME", cd->username);
572 	}
573 	/*
574 	 * Better set DISPLAY to the one we are polling, if they
575 	 * want something trickier, they can handle on their own
576 	 * via environment, etc.
577 	 */
578 	if (getenv("DISPLAY")) {
579 		old_display = strdup(getenv("DISPLAY"));
580 	}
581 
582 	if (raw_fb && ! dpy) {	/* raw_fb hack */
583 		set_env("DISPLAY", "rawfb");
584 	} else {
585 		set_env("DISPLAY", DisplayString(dpy));
586 	}
587 
588 	/*
589 	 * work out the number of clients (have to use client_count
590 	 * since there is deadlock in rfbGetClientIterator)
591 	 */
592 	sprintf(str, "%d", client_count);
593 	set_env("RFB_CLIENT_COUNT", str);
594 
595 	/* gone, accept, afteraccept */
596 	ok = 0;
597 	if (!strcmp(mode, "env")) {
598 		return 1;
599 	}
600 	if (!strcmp(mode, "accept") && cmd_ok("accept")) {
601 		ok = 1;
602 	}
603 	if (!strcmp(mode, "afteraccept") && cmd_ok("afteraccept")) {
604 		ok = 1;
605 	}
606 	if (!strcmp(mode, "gone") && cmd_ok("gone")) {
607 		ok = 1;
608 	}
609 	if (!strcmp(mode, "cmd_verify") && cmd_ok("unixpw")) {
610 		ok = 1;
611 	}
612 	if (!strcmp(mode, "read_passwds") && cmd_ok("passwdfile")) {
613 		ok = 1;
614 	}
615 	if (!strcmp(mode, "custom_passwd") && cmd_ok("custom_passwd")) {
616 		ok = 1;
617 	}
618 	if (no_external_cmds || !ok) {
619 		rfbLogEnable(1);
620 		rfbLog("cannot run external commands in -nocmds mode:\n");
621 		rfbLog("   \"%s\"\n", cmd);
622 		rfbLog("   exiting.\n");
623 		clean_up_exit(1);
624 	}
625 	rfbLog("running command:\n");
626 	if (!quiet) {
627 		fprintf(stderr, "\n  %s\n\n", cmd);
628 	}
629 	close_exec_fds();
630 
631 	if (output != NULL) {
632 		FILE *ph;
633 		char line[1024];
634 		char *cmd2 = NULL;
635 		char tmp[] = "/tmp/x11vnc-tmp.XXXXXX";
636 		int deltmp = 0;
637 
638 		if (input != NULL) {
639 			int tmp_fd = mkstemp(tmp);
640 			if (tmp_fd < 0) {
641 				rfbLog("mkstemp failed on: %s\n", tmp);
642 				clean_up_exit(1);
643 			}
644 			write(tmp_fd, input, len);
645 			close(tmp_fd);
646 			deltmp = 1;
647 			cmd2 = (char *) malloc(100 + strlen(tmp) + strlen(cmd));
648 			sprintf(cmd2, "/bin/cat %s | %s", tmp, cmd);
649 
650 			ph = popen(cmd2, "r");
651 		} else {
652 			ph = popen(cmd, "r");
653 		}
654 		if (ph == NULL) {
655 			rfbLog("popen(%s) failed", cmd);
656 			rfbLogPerror("popen");
657 			clean_up_exit(1);
658 		}
659 		memset(line, 0, sizeof(line));
660 		while (fgets(line, sizeof(line), ph) != NULL) {
661 			int j, k = -1;
662 			if (0) fprintf(stderr, "line: %s", line);
663 			/* take care to handle embedded nulls */
664 			for (j=0; j < (int) sizeof(line); j++) {
665 				if (line[j] != '\0') {
666 					k = j;
667 				}
668 			}
669 			if (k >= 0) {
670 				write(fileno(output), line, k+1);
671 			}
672 			memset(line, 0, sizeof(line));
673 		}
674 
675 		rc = pclose(ph);
676 
677 		if (cmd2 != NULL) {
678 			free(cmd2);
679 		}
680 		if (deltmp) {
681 			unlink(tmp);
682 		}
683 		goto got_rc;
684 	} else if (input != NULL) {
685 		FILE *ph = popen(cmd, "w");
686 		if (ph == NULL) {
687 			rfbLog("popen(%s) failed", cmd);
688 			rfbLogPerror("popen");
689 			clean_up_exit(1);
690 		}
691 		write(fileno(ph), input, len);
692 		rc = pclose(ph);
693 		goto got_rc;
694 	}
695 
696 #if LIBVNCSERVER_HAVE_FORK
697 	{
698 		pid_t pid;
699 		struct sigaction sa, intr, quit;
700 		sigset_t omask;
701 
702 		sa.sa_handler = SIG_IGN;
703 		sa.sa_flags = 0;
704 		sigemptyset(&sa.sa_mask);
705 		sigaction(SIGINT,  &sa, &intr);
706 		sigaction(SIGQUIT, &sa, &quit);
707 
708 		sigaddset(&sa.sa_mask, SIGCHLD);
709 		sigprocmask(SIG_BLOCK, &sa.sa_mask, &omask);
710 
711 		if ((pid = fork()) > 0 || pid == -1) {
712 
713 			if (pid != -1) {
714 				waitpid(pid, &rc, 0);
715 			}
716 
717 			sigaction(SIGINT,  &intr, (struct sigaction *) NULL);
718 			sigaction(SIGQUIT, &quit, (struct sigaction *) NULL);
719 			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) NULL);
720 
721 			if (pid == -1) {
722 				fprintf(stderr, "could not fork\n");
723 				rfbLogPerror("fork");
724 				rc = system(cmd);
725 			}
726 		} else {
727 			/* this should close port 5900, etc.. */
728 			int fd;
729 			sigaction(SIGINT,  &intr, (struct sigaction *) NULL);
730 			sigaction(SIGQUIT, &quit, (struct sigaction *) NULL);
731 			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) NULL);
732 			for (fd=3; fd<256; fd++) {
733 				close(fd);
734 			}
735 /* XXX test more */
736 			if (!strcmp(mode, "gone")) {
737 #if HAVE_SETSID
738 				setsid();
739 #else
740 				setpgrp();
741 #endif
742 			}
743 			execlp("/bin/sh", "/bin/sh", "-c", cmd, (char *) NULL);
744 			exit(1);
745 		}
746 	}
747 #else
748 	rc = system(cmd);
749 #endif
750 	got_rc:
751 
752 	if (rc >= 256) {
753 		rc = rc/256;
754 	}
755 	rfbLog("command returned: %d\n", rc);
756 
757 	if (old_display) {
758 		set_env("DISPLAY", old_display);
759 		free(old_display);
760 	}
761 
762 	return rc;
763 }
764 
free_client_data(rfbClientPtr client)765 static void free_client_data(rfbClientPtr client) {
766 	if (! client) {
767 		return;
768 	}
769 	if (client->clientData) {
770 		ClientData *cd = (ClientData *) client->clientData;
771 		if (cd) {
772 			if (cd->server_ip) {
773 				free(cd->server_ip);
774 				cd->server_ip = NULL;
775 			}
776 			if (cd->hostname) {
777 				free(cd->hostname);
778 				cd->hostname = NULL;
779 			}
780 			if (cd->username) {
781 				free(cd->username);
782 				cd->username = NULL;
783 			}
784 			if (cd->unixname) {
785 				free(cd->unixname);
786 				cd->unixname = NULL;
787 			}
788 			if (cd->cursor) {
789 			        rfbFreeCursor(cd->cursor);
790 			        cd->cursor = NULL;
791 			}
792 			if (cd->under_cursor_buffer) {
793 			        free(cd->under_cursor_buffer);
794 			        cd->under_cursor_buffer = NULL;
795 			}
796 			if (cd->cursor_region) {
797 				sraRgnDestroy(cd->cursor_region);
798 				cd->cursor_region = NULL;
799 			}
800 		}
801 		free(client->clientData);
802 		client->clientData = NULL;
803 	}
804 }
805 
806 static int accepted_client = 0;
807 
808 /*
809  * callback for when a client disconnects
810  */
client_gone(rfbClientPtr client)811 void client_gone(rfbClientPtr client) {
812 	ClientData *cd = NULL;
813 
814 	CLIENT_LOCK;
815 
816 	client_count--;
817 	if (client_count < 0) client_count = 0;
818 
819 	speeds_net_rate_measured = 0;
820 	speeds_net_latency_measured = 0;
821 
822 	rfbLog("client_count: %d\n", client_count);
823 	last_client_gone = dnow();
824 
825 	if (unixpw_in_progress && unixpw_client) {
826 		if (client == unixpw_client) {
827 			unixpw_in_progress = 0;
828 			/* mutex */
829 			screen->permitFileTransfer = unixpw_file_xfer_save;
830 			if ((tightfilexfer = unixpw_tightvnc_xfer_save)) {
831 #ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER
832 				rfbLog("rfbRegisterTightVNCFileTransferExtension: 3\n");
833 				rfbRegisterTightVNCFileTransferExtension();
834 #endif
835 			}
836 			unixpw_client = NULL;
837 			copy_screen();
838 		}
839 	}
840 
841 
842 	if (no_autorepeat && client_count == 0) {
843 		autorepeat(1, 0);
844 	}
845 	if (use_solid_bg && client_count == 0) {
846 		solid_bg(1);
847 	}
848 	if ((ncache || ncache0) && client_count == 0) {
849 		kde_no_animate(1);
850 	}
851 	if (client->clientData) {
852 		cd = (ClientData *) client->clientData;
853 		if (cd->ssl_helper_pid > 0) {
854 			int status;
855 			rfbLog("sending SIGTERM to ssl_helper_pid: %d\n",
856 			    cd->ssl_helper_pid);
857 			kill(cd->ssl_helper_pid, SIGTERM);
858 			usleep(200*1000);
859 #if LIBVNCSERVER_HAVE_SYS_WAIT_H && HAVE_WAITPID
860 			waitpid(cd->ssl_helper_pid, &status, WNOHANG);
861 #endif
862 			ssl_helper_pid(cd->ssl_helper_pid, -1);	/* delete */
863 		}
864 	}
865 	if (gone_cmd && *gone_cmd != '\0') {
866 		if (strstr(gone_cmd, "popup") == gone_cmd) {
867 			int x = -64000, y = -64000, timeout = 120;
868 			char *userhost = ident_username(client);
869 			char *addr, *p, *mode;
870 
871 			/* extract timeout */
872 			if ((p = strchr(gone_cmd, ':')) != NULL) {
873 				int in;
874 				if (sscanf(p+1, "%d", &in) == 1) {
875 					timeout = in;
876 				}
877 			}
878 			/* extract geometry */
879 			if ((p = strpbrk(gone_cmd, "+-")) != NULL) {
880 				ugly_geom(p, &x, &y);
881 			}
882 
883 			/* find mode: mouse, key, or both */
884 			if (strstr(gone_cmd, "popupmouse") == gone_cmd) {
885 				mode = "mouse_only";
886 			} else if (strstr(gone_cmd, "popupkey") == gone_cmd) {
887 				mode = "key_only";
888 			} else {
889 				mode = "both";
890 			}
891 
892 			addr = client->host;
893 
894 			ugly_window(addr, userhost, x, y, timeout, mode, 0);
895 
896 			free(userhost);
897 		} else {
898 			rfbLog("client_gone: using cmd: %s\n", client->host);
899 			run_user_command(gone_cmd, client, "gone", NULL, 0, NULL);
900 		}
901 	}
902 
903 	/* remove clients XInput2 master device */
904         if(use_multipointer)
905 	  if(removeMD(dpy, cd->ptr_id))
906 	    rfbLog("removed XInput2 MD for client %s.\n", client->host);
907 
908 	free_client_data(client);
909 
910 	if (inetd && client == inetd_client) {
911 		rfbLog("inetd viewer exited.\n");
912 		if (gui_pid > 0) {
913 			rfbLog("killing gui_pid %d\n", gui_pid);
914 			kill(gui_pid, SIGTERM);
915 		}
916 		clean_up_exit(0);
917 	}
918 
919 	if (connect_once) {
920 		/*
921 		 * This non-exit is done for a bad passwd to be consistent
922 		 * with our RFB_CLIENT_REFUSE behavior in new_client()  (i.e.
923 		 * we disconnect after 1 successful connection).
924 		 */
925 		if ((client->state == RFB_PROTOCOL_VERSION ||
926 		     client->state == RFB_SECURITY_TYPE ||
927 		     client->state == RFB_AUTHENTICATION ||
928 		     client->state == RFB_INITIALISATION) && accepted_client) {
929 			rfbLog("connect_once: invalid password or early "
930 			   "disconnect.  %d\n", client->state);
931 			rfbLog("connect_once: waiting for next connection.\n");
932 			accepted_client--;
933 			if (accepted_client < 0) {
934 				accepted_client = 0;
935 			}
936 			CLIENT_UNLOCK;
937 			if (connect_or_exit) {
938 				clean_up_exit(1);
939 			}
940 			return;
941 		}
942 		if (shared && client_count > 0)  {
943 			rfbLog("connect_once: other shared clients still "
944 			    "connected, not exiting.\n");
945 			CLIENT_UNLOCK;
946 			return;
947 		}
948 
949 		rfbLog("viewer exited.\n");
950 		if ((client_connect || connect_or_exit) && gui_pid > 0) {
951 			rfbLog("killing gui_pid %d\n", gui_pid);
952 			kill(gui_pid, SIGTERM);
953 		}
954 		CLIENT_UNLOCK;
955 		clean_up_exit(0);
956 	}
957 #ifdef MACOSX
958 	if (macosx_console && client_count == 0) {
959 		macosxCG_refresh_callback_off();
960 	}
961 #endif
962 	CLIENT_UNLOCK;
963 }
964 
965 /*
966  * Simple routine to limit access via string compare.  A power user will
967  * want to compile libvncserver with libwrap support and use /etc/hosts.allow.
968  */
check_access(char * addr)969 int check_access(char *addr) {
970 	int allowed = 0;
971 	int ssl = 0;
972 	char *p, *list;
973 
974 	if (use_openssl || use_stunnel) {
975 		ssl = 1;
976 	}
977 	if (deny_all) {
978 		rfbLog("check_access: new connections are currently "
979 		    "blocked.\n");
980 		return 0;
981 	}
982 	if (addr == NULL || *addr == '\0') {
983 		rfbLog("check_access: denying empty host IP address string.\n");
984 		return 0;
985 	}
986 
987 	if (allow_list == NULL) {
988 		/* set to "" to possibly append allow_once */
989 		allow_list = strdup("");
990 	}
991 	if (*allow_list == '\0' && allow_once == NULL) {
992 		/* no constraints, accept it */
993 		return 1;
994 	}
995 
996 	if (strchr(allow_list, '/')) {
997 		/* a file of IP addresess or prefixes */
998 		int len, len2 = 0;
999 		struct stat sbuf;
1000 		FILE *in;
1001 		char line[1024], *q;
1002 
1003 		if (stat(allow_list, &sbuf) != 0) {
1004 			rfbLogEnable(1);
1005 			rfbLog("check_access: failure stating file: %s\n",
1006 			    allow_list);
1007 			rfbLogPerror("stat");
1008 			clean_up_exit(1);
1009 		}
1010 		len = sbuf.st_size + 1;	/* 1 more for '\0' at end */
1011 		if (allow_once) {
1012 			len2 = strlen(allow_once) + 2;
1013 			len += len2;
1014 		}
1015 		if (ssl) {
1016 			len2 = strlen("127.0.0.1") + 2;
1017 			len += len2;
1018 		}
1019 		list = (char *) malloc(len);
1020 		list[0] = '\0';
1021 
1022 		in = fopen(allow_list, "r");
1023 		if (in == NULL) {
1024 			rfbLogEnable(1);
1025 			rfbLog("check_access: cannot open: %s\n", allow_list);
1026 			rfbLogPerror("fopen");
1027 			clean_up_exit(1);
1028 		}
1029 		while (fgets(line, 1024, in) != NULL) {
1030 			if ( (q = strchr(line, '#')) != NULL) {
1031 				*q = '\0';
1032 			}
1033 			if (strlen(list) + strlen(line) >=
1034 			    (size_t) (len - len2)) {
1035 				/* file grew since our stat() */
1036 				break;
1037 			}
1038 			strcat(list, line);
1039 		}
1040 		fclose(in);
1041 		if (allow_once) {
1042 			strcat(list, "\n");
1043 			strcat(list, allow_once);
1044 			strcat(list, "\n");
1045 		}
1046 		if (ssl) {
1047 			strcat(list, "\n");
1048 			strcat(list, "127.0.0.1");
1049 			strcat(list, "\n");
1050 		}
1051 	} else {
1052 		int len = strlen(allow_list) + 1;
1053 		if (allow_once) {
1054 			len += strlen(allow_once) + 1;
1055 		}
1056 		if (ssl) {
1057 			len += strlen("127.0.0.1") + 1;
1058 		}
1059 		list = (char *) malloc(len);
1060 		list[0] = '\0';
1061 		strcat(list, allow_list);
1062 		if (allow_once) {
1063 			strcat(list, ",");
1064 			strcat(list, allow_once);
1065 		}
1066 		if (ssl) {
1067 			strcat(list, ",");
1068 			strcat(list, "127.0.0.1");
1069 		}
1070 	}
1071 
1072 	if (allow_once) {
1073 		free(allow_once);
1074 		allow_once = NULL;
1075 	}
1076 
1077 	p = strtok(list, ", \t\n\r");
1078 	while (p) {
1079 		char *chk, *q, *r = NULL;
1080 		if (*p == '\0') {
1081 			p = strtok(NULL, ", \t\n\r");
1082 			continue;
1083 		}
1084 		if (ipv6_ip(p)) {
1085 			chk = p;
1086 		} else if (! dotted_ip(p, 1)) {
1087 			r = host2ip(p);
1088 			if (r == NULL || *r == '\0') {
1089 				rfbLog("check_access: bad lookup \"%s\"\n", p);
1090 				p = strtok(NULL, ", \t\n\r");
1091 				continue;
1092 			}
1093 			rfbLog("check_access: lookup %s -> %s\n", p, r);
1094 			chk = r;
1095 		} else {
1096 			chk = p;
1097 		}
1098 		if (getenv("X11VNC_DEBUG_ACCESS")) fprintf(stderr, "chk: %s  part: %s  addr: %s\n", chk, p, addr);
1099 
1100 		q = strstr(addr, chk);
1101 		if (ipv6_ip(addr)) {
1102 			if (!strcmp(chk, "localhost") && !strcmp(addr, "::1")) {
1103 				rfbLog("check_access: client addr %s is local.\n", addr);
1104 				allowed = 1;
1105 			} else if (!strcmp(chk, "::1") && !strcmp(addr, "::1")) {
1106 				rfbLog("check_access: client addr %s is local.\n", addr);
1107 				allowed = 1;
1108 			} else if (!strcmp(chk, "127.0.0.1") && !strcmp(addr, "::1")) {
1109 				/* this if for host2ip("localhost") */
1110 				rfbLog("check_access: client addr %s is local.\n", addr);
1111 				allowed = 1;
1112 			} else if (q == addr) {
1113 				rfbLog("check_access: client %s matches pattern %s\n", addr, chk);
1114 				allowed = 1;
1115 			}
1116 		} else if (chk[strlen(chk)-1] != '.') {
1117 			if (!strcmp(addr, chk)) {
1118 				if (chk != p) {
1119 					rfbLog("check_access: client %s " "matches host %s=%s\n", addr, chk, p);
1120 				} else {
1121 					rfbLog("check_access: client %s " "matches host %s\n", addr, chk);
1122 				}
1123 				allowed = 1;
1124 			} else if(!strcmp(chk, "localhost") && !strcmp(addr, "127.0.0.1")) {
1125 				allowed = 1;
1126 			}
1127 		} else if (q == addr) {
1128 			rfbLog("check_access: client %s matches pattern %s\n", addr, chk);
1129 			allowed = 1;
1130 		}
1131 		p = strtok(NULL, ", \t\n\r");
1132 		if (r) {
1133 			free(r);
1134 		}
1135 		if (allowed) {
1136 			break;
1137 		}
1138 	}
1139 	free(list);
1140 	return allowed;
1141 }
1142 
1143 /*
1144  * x11vnc's first (and only) visible widget: accept/reject dialog window.
1145  * We go through this pain to avoid dependency on libXt...
1146  */
ugly_window(char * addr,char * userhost,int X,int Y,int timeout,char * mode,int accept)1147 static int ugly_window(char *addr, char *userhost, int X, int Y,
1148     int timeout, char *mode, int accept) {
1149 #if NO_X11
1150 	if (!addr || !userhost || !X || !Y || !timeout || !mode || !accept) {}
1151 	RAWFB_RET(0)
1152 	nox11_exit(1);
1153 	return 0;
1154 #else
1155 
1156 #define t2x2_width 16
1157 #define t2x2_height 16
1158 static unsigned char t2x2_bits[] = {
1159    0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff,
1160    0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33,
1161    0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33};
1162 
1163 	Window awin;
1164 	GC gc;
1165 	XSizeHints hints;
1166 	XGCValues values;
1167 	static XFontStruct *font_info = NULL;
1168 	static Pixmap ico = 0;
1169 	unsigned long valuemask = 0;
1170 	static char dash_list[] = {20, 40};
1171 	int list_length = sizeof(dash_list);
1172 
1173 	Atom wm_protocols;
1174 	Atom wm_delete_window;
1175 
1176 	XEvent ev;
1177 	long evmask = ExposureMask | KeyPressMask | ButtonPressMask
1178 	    | StructureNotifyMask;
1179 	double waited = 0.0;
1180 
1181 	/* strings and geometries y/n */
1182 	KeyCode key_y, key_n, key_v;
1183 	char strh[100];
1184 	char stri[100];
1185 	char str1_b[] = "To accept: press \"y\" or click the \"Yes\" button";
1186 	char str2_b[] = "To reject: press \"n\" or click the \"No\" button";
1187 	char str3_b[] = "View only: press \"v\" or click the \"View\" button";
1188 	char str1_m[] = "To accept: click the \"Yes\" button";
1189 	char str2_m[] = "To reject: click the \"No\" button";
1190 	char str3_m[] = "View only: click the \"View\" button";
1191 	char str1_k[] = "To accept: press \"y\"";
1192 	char str2_k[] = "To reject: press \"n\"";
1193 	char str3_k[] = "View only: press \"v\"";
1194 	char *str1, *str2, *str3;
1195 	char str_y[] = "Yes";
1196 	char str_n[] = "No";
1197 	char str_v[] = "View";
1198 	int x, y, w = 345, h = 175, ret = 0;
1199 	int X_sh = 20, Y_sh = 30, dY = 20;
1200 	int Ye_x = 20,  Ye_y = 0, Ye_w = 45, Ye_h = 20;
1201 	int No_x = 75,  No_y = 0, No_w = 45, No_h = 20;
1202 	int Vi_x = 130, Vi_y = 0, Vi_w = 45, Vi_h = 20;
1203 	char *sprop = "new x11vnc client";
1204 
1205 	KeyCode key_o;
1206 
1207 	RAWFB_RET(0)
1208 
1209 	if (! accept) {
1210 		sprintf(str_y, "OK");
1211 		sprop = "x11vnc client disconnected";
1212 		h = 110;
1213 		str1 = "";
1214 		str2 = "";
1215 		str3 = "";
1216 	} else if (!strcmp(mode, "mouse_only")) {
1217 		str1 = str1_m;
1218 		str2 = str2_m;
1219 		str3 = str3_m;
1220 	} else if (!strcmp(mode, "key_only")) {
1221 		str1 = str1_k;
1222 		str2 = str2_k;
1223 		str3 = str3_k;
1224 		h -= dY;
1225 	} else {
1226 		str1 = str1_b;
1227 		str2 = str2_b;
1228 		str3 = str3_b;
1229 	}
1230 	if (view_only) {
1231 		h -= dY;
1232 	}
1233 
1234 	/* XXX handle coff_x/coff_y? */
1235 	if (X < -dpy_x) {
1236 		x = (dpy_x - w)/2;	/* large negative: center */
1237 		if (x < 0) x = 0;
1238 	} else if (X < 0) {
1239 		x = dpy_x + X - w;	/* from lower right */
1240 	} else {
1241 		x = X;			/* from upper left */
1242 	}
1243 
1244 	if (Y < -dpy_y) {
1245 		y = (dpy_y - h)/2;
1246 		if (y < 0) y = 0;
1247 	} else if (Y < 0) {
1248 		y = dpy_y + Y - h;
1249 	} else {
1250 		y = Y;
1251 	}
1252 
1253 	X_LOCK;
1254 
1255 	awin = XCreateSimpleWindow(dpy, window, x, y, w, h, 4,
1256 	    BlackPixel(dpy, scr), WhitePixel(dpy, scr));
1257 
1258 	wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
1259 	wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
1260 	XSetWMProtocols(dpy, awin, &wm_delete_window, 1);
1261 
1262 	if (! ico) {
1263 		ico = XCreateBitmapFromData(dpy, awin, (char *) t2x2_bits,
1264 		    t2x2_width, t2x2_height);
1265 	}
1266 
1267 	hints.flags = PPosition | PSize | PMinSize;
1268 	hints.x = x;
1269 	hints.y = y;
1270 	hints.width = w;
1271 	hints.height = h;
1272 	hints.min_width = w;
1273 	hints.min_height = h;
1274 
1275 	XSetStandardProperties(dpy, awin, sprop, "x11vnc query", ico, NULL,
1276 	    0, &hints);
1277 
1278 	XSelectInput_wr(dpy, awin, evmask);
1279 
1280 	if (! font_info && (font_info = XLoadQueryFont(dpy, "fixed")) == NULL) {
1281 		rfbLogEnable(1);
1282 		rfbLog("ugly_window: cannot locate font fixed.\n");
1283 		X_UNLOCK;
1284 		clean_up_exit(1);
1285 	}
1286 
1287 	gc = XCreateGC(dpy, awin, valuemask, &values);
1288 	XSetFont(dpy, gc, font_info->fid);
1289 	XSetForeground(dpy, gc, BlackPixel(dpy, scr));
1290 	XSetLineAttributes(dpy, gc, 1, LineSolid, CapButt, JoinMiter);
1291 	XSetDashes(dpy, gc, 0, dash_list, list_length);
1292 
1293 	XMapWindow(dpy, awin);
1294 	XFlush_wr(dpy);
1295 
1296 	if (accept) {
1297 		char *ip = addr;
1298 		char *type = "accept";
1299 		if (unixpw && strstr(userhost, "UNIX:") != userhost) {
1300 			type = "UNIXPW";
1301 			if (openssl_last_ip) {
1302 				ip = openssl_last_ip;
1303 			}
1304 		}
1305 		snprintf(strh, sizeof strh, "x11vnc: %s connection from %s?", type, ip);
1306 	} else {
1307 		snprintf(strh, sizeof strh, "x11vnc: client disconnected from %s", addr);
1308 	}
1309 	snprintf(stri, sizeof stri, "        (%s)", userhost);
1310 
1311 	key_o = XKeysymToKeycode(dpy, XStringToKeysym("o"));
1312 	key_y = XKeysymToKeycode(dpy, XStringToKeysym("y"));
1313 	key_n = XKeysymToKeycode(dpy, XStringToKeysym("n"));
1314 	key_v = XKeysymToKeycode(dpy, XStringToKeysym("v"));
1315 
1316 	while (1) {
1317 		int out = -1, x, y, tw, k;
1318 
1319 		if (XCheckWindowEvent(dpy, awin, evmask, &ev)) {
1320 			;	/* proceed to handling */
1321 		} else if (XCheckTypedEvent(dpy, ClientMessage, &ev)) {
1322 			;	/* proceed to handling */
1323 		} else {
1324 			int ms = 100;	/* sleep a bit */
1325 			usleep(ms * 1000);
1326 			waited += ((double) ms)/1000.;
1327 			if (timeout && (int) waited >= timeout) {
1328 				rfbLog("ugly_window: popup timed out after "
1329 				    "%d seconds.\n", timeout);
1330 				out = 0;
1331 				ev.type = 0;
1332 			} else {
1333 				continue;
1334 			}
1335 		}
1336 
1337 		switch(ev.type) {
1338 		case Expose:
1339 			while (XCheckTypedEvent(dpy, Expose, &ev)) {
1340 				;
1341 			}
1342 			k=0;
1343 
1344 			/* instructions */
1345 			XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
1346 			    strh, strlen(strh));
1347 			XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
1348 			    stri, strlen(stri));
1349 			if (accept) {
1350 			  XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
1351 			    str1, strlen(str1));
1352 			  XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
1353 			    str2, strlen(str2));
1354 			  if (! view_only) {
1355 				XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
1356 				    str3, strlen(str3));
1357 			  }
1358 			}
1359 
1360 			if (!strcmp(mode, "key_only")) {
1361 				break;
1362 			}
1363 
1364 			/* buttons */
1365 			Ye_y = Y_sh+k*dY;
1366 			No_y = Y_sh+k*dY;
1367 			Vi_y = Y_sh+k*dY;
1368 			XDrawRectangle(dpy, awin, gc, Ye_x, Ye_y, Ye_w, Ye_h);
1369 
1370 			if (accept) {
1371 			  XDrawRectangle(dpy, awin, gc, No_x, No_y, No_w, No_h);
1372 			  if (! view_only) {
1373 				XDrawRectangle(dpy, awin, gc, Vi_x, Vi_y,
1374 				    Vi_w, Vi_h);
1375 			  }
1376 			}
1377 
1378 			tw = XTextWidth(font_info, str_y, strlen(str_y));
1379 			tw = (Ye_w - tw)/2;
1380 			if (tw < 0) tw = 1;
1381 			XDrawString(dpy, awin, gc, Ye_x+tw, Ye_y+Ye_h-5,
1382 			    str_y, strlen(str_y));
1383 
1384 			if (!accept) {
1385 				break;
1386 			}
1387 			tw = XTextWidth(font_info, str_n, strlen(str_n));
1388 			tw = (No_w - tw)/2;
1389 			if (tw < 0) tw = 1;
1390 			XDrawString(dpy, awin, gc, No_x+tw, No_y+No_h-5,
1391 			    str_n, strlen(str_n));
1392 
1393 			if (! view_only) {
1394 				tw = XTextWidth(font_info, str_v,
1395 				    strlen(str_v));
1396 				tw = (Vi_w - tw)/2;
1397 				if (tw < 0) tw = 1;
1398 				XDrawString(dpy, awin, gc, Vi_x+tw,
1399 				    Vi_y+Vi_h-5, str_v, strlen(str_v));
1400 			}
1401 
1402 			break;
1403 
1404 		case ClientMessage:
1405 			if (ev.xclient.message_type == wm_protocols &&
1406 			    (Atom) ev.xclient.data.l[0] == wm_delete_window) {
1407 				out = 0;
1408 			}
1409 			break;
1410 
1411 		case ButtonPress:
1412 			x = ev.xbutton.x;
1413 			y = ev.xbutton.y;
1414 			if (!strcmp(mode, "key_only")) {
1415 				;
1416 			} else if (x > Ye_x && x < Ye_x+Ye_w && y > Ye_y
1417 			    && y < Ye_y+Ye_h) {
1418 				out = 1;
1419 			} else if (! accept) {
1420 				;
1421 			} else if (x > No_x && x < No_x+No_w && y > No_y
1422 			    && y < No_y+No_h) {
1423 				out = 0;
1424 			} else if (! view_only && x > Vi_x && x < Vi_x+Vi_w
1425 			    && y > Vi_y && y < Vi_y+Ye_h) {
1426 				out = 2;
1427 			}
1428 			break;
1429 
1430 		case KeyPress:
1431 			if (!strcmp(mode, "mouse_only")) {
1432 				;
1433 			} else if (! accept) {
1434 				if (ev.xkey.keycode == key_o) {
1435 					out = 1;
1436 				}
1437 				if (ev.xkey.keycode == key_y) {
1438 					out = 1;
1439 				}
1440 			} else if (ev.xkey.keycode == key_y) {
1441 				out = 1;
1442 				;
1443 			} else if (ev.xkey.keycode == key_n) {
1444 				out = 0;
1445 			} else if (! view_only && ev.xkey.keycode == key_v) {
1446 				out = 2;
1447 			}
1448 			break;
1449 		default:
1450 			break;
1451 		}
1452 		if (out != -1) {
1453 			ret = out;
1454 			XSelectInput_wr(dpy, awin, 0);
1455 			XUnmapWindow(dpy, awin);
1456 			XFree_wr(gc);
1457 			XDestroyWindow(dpy, awin);
1458 			XFlush_wr(dpy);
1459 			break;
1460 		}
1461 	}
1462 	X_UNLOCK;
1463 
1464 	return ret;
1465 #endif	/* NO_X11 */
1466 }
1467 
1468 /*
1469  * process a "yes:0,no:*,view:3" type action list comparing to command
1470  * return code rc.  * means the default action with no other match.
1471  */
action_match(char * action,int rc)1472 static int action_match(char *action, int rc) {
1473 	char *p, *q, *s = strdup(action);
1474 	int cases[4], i, result;
1475 	char *labels[4];
1476 
1477 	labels[1] = "yes";
1478 	labels[2] = "no";
1479 	labels[3] = "view";
1480 
1481 	rfbLog("accept_client: process action line: %s\n",
1482 	    action);
1483 
1484 	for (i=1; i <= 3; i++) {
1485 		cases[i] = -2;
1486 	}
1487 
1488 	p = strtok(s, ",");
1489 	while (p) {
1490 		if ((q = strchr(p, ':')) != NULL) {
1491 			int in, k = 1;
1492 			*q = '\0';
1493 			q++;
1494 			if (strstr(p, "yes") == p) {
1495 				k = 1;
1496 			} else if (strstr(p, "no") == p) {
1497 				k = 2;
1498 			} else if (strstr(p, "view") == p) {
1499 				k = 3;
1500 			} else {
1501 				rfbLogEnable(1);
1502 				rfbLog("invalid action line: %s\n", action);
1503 				clean_up_exit(1);
1504 			}
1505 			if (*q == '*') {
1506 				cases[k] = -1;
1507 			} else if (sscanf(q, "%d", &in) == 1) {
1508 				if (in < 0) {
1509 					rfbLogEnable(1);
1510 					rfbLog("invalid action line: %s\n",
1511 					    action);
1512 					clean_up_exit(1);
1513 				}
1514 				cases[k] = in;
1515 			} else {
1516 				rfbLogEnable(1);
1517 				rfbLog("invalid action line: %s\n", action);
1518 				clean_up_exit(1);
1519 			}
1520 		} else {
1521 			rfbLogEnable(1);
1522 			rfbLog("invalid action line: %s\n", action);
1523 			clean_up_exit(1);
1524 		}
1525 		p = strtok(NULL, ",");
1526 	}
1527 	free(s);
1528 
1529 	result = -1;
1530 	for (i=1; i <= 3; i++) {
1531 		if (cases[i] == -1) {
1532 			rfbLog("accept_client: default action is case=%d %s\n",
1533 			    i, labels[i]);
1534 			result = i;
1535 			break;
1536 		}
1537 	}
1538 	if (result == -1) {
1539 		rfbLog("accept_client: no default action\n");
1540 	}
1541 	for (i=1; i <= 3; i++) {
1542 		if (cases[i] >= 0 && cases[i] == rc) {
1543 			rfbLog("accept_client: matched action is case=%d %s\n",
1544 			    i, labels[i]);
1545 			result = i;
1546 			break;
1547 		}
1548 	}
1549 	if (result < 0) {
1550 		rfbLog("no action match: %s rc=%d set to no\n", action, rc);
1551 		result = 2;
1552 	}
1553 	return result;
1554 }
1555 
ugly_geom(char * p,int * x,int * y)1556 static void ugly_geom(char *p, int *x, int *y) {
1557 	int x1, y1;
1558 
1559 	if (sscanf(p, "+%d+%d", &x1, &y1) == 2) {
1560 		*x = x1;
1561 		*y = y1;
1562 	} else if (sscanf(p, "+%d-%d", &x1, &y1) == 2) {
1563 		*x = x1;
1564 		*y = -y1;
1565 	} else if (sscanf(p, "-%d+%d", &x1, &y1) == 2) {
1566 		*x = -x1;
1567 		*y = y1;
1568 	} else if (sscanf(p, "-%d-%d", &x1, &y1) == 2) {
1569 		*x = -x1;
1570 		*y = -y1;
1571 	}
1572 }
1573 
1574 /*
1575  * Simple routine to prompt the user on the X display whether an incoming
1576  * client should be allowed to connect or not.  If a gui is involved it
1577  * will be running in the environment/context of the X11 DISPLAY.
1578  *
1579  * The command supplied via -accept is run as is (i.e. no string
1580  * substitution) with the RFB_CLIENT_IP environment variable set to the
1581  * incoming client's numerical IP address.
1582  *
1583  * If the external command exits with 0 the client is accepted, otherwise
1584  * the client is rejected.
1585  *
1586  * Some builtins are provided:
1587  *
1588  *	xmessage:  use homebrew xmessage(1) for the external command.
1589  *	popup:     use internal X widgets for prompting.
1590  *
1591  */
accept_client(rfbClientPtr client)1592 int accept_client(rfbClientPtr client) {
1593 
1594 	char xmessage[200], *cmd = NULL;
1595 	char *addr = client->host;
1596 	char *action = NULL;
1597 
1598 	if (accept_cmd == NULL || *accept_cmd == '\0') {
1599 		return 1;	/* no command specified, so we accept */
1600 	}
1601 
1602 	if (addr == NULL || addr[0] == '\0') {
1603 		addr = "unknown-host";
1604 	}
1605 
1606 	if (strstr(accept_cmd, "popup") == accept_cmd) {
1607 		/* use our builtin popup button */
1608 
1609 		/* (popup|popupkey|popupmouse)[+-X+-Y][:timeout] */
1610 
1611 		int ret, timeout = 120;
1612 		int x = -64000, y = -64000;
1613 		char *p, *mode;
1614 		char *userhost = ident_username(client);
1615 
1616 		/* extract timeout */
1617 		if ((p = strchr(accept_cmd, ':')) != NULL) {
1618 			int in;
1619 			if (sscanf(p+1, "%d", &in) == 1) {
1620 				timeout = in;
1621 			}
1622 		}
1623 		/* extract geometry */
1624 		if ((p = strpbrk(accept_cmd, "+-")) != NULL) {
1625 			ugly_geom(p, &x, &y);
1626 		}
1627 
1628 		/* find mode: mouse, key, or both */
1629 		if (strstr(accept_cmd, "popupmouse") == accept_cmd) {
1630 			mode = "mouse_only";
1631 		} else if (strstr(accept_cmd, "popupkey") == accept_cmd) {
1632 			mode = "key_only";
1633 		} else {
1634 			mode = "both";
1635 		}
1636 
1637 		if (dpy == NULL && use_dpy && strstr(use_dpy, "WAIT:") ==
1638 		    use_dpy) {
1639 			rfbLog("accept_client: warning allowing client under conditions:\n");
1640 			rfbLog("  -display WAIT:, dpy == NULL, -accept popup.\n");
1641 			rfbLog("   There will be another popup.\n");
1642 			return 1;
1643 		}
1644 
1645 		rfbLog("accept_client: using builtin popup for: %s\n", addr);
1646 		if ((ret = ugly_window(addr, userhost, x, y, timeout,
1647 		    mode, 1))) {
1648 			free(userhost);
1649 			if (ret == 2) {
1650 				rfbLog("accept_client: viewonly: %s\n", addr);
1651 				client->viewOnly = TRUE;
1652 			}
1653 			rfbLog("accept_client: popup accepted: %s\n", addr);
1654 			return 1;
1655 		} else {
1656 			free(userhost);
1657 			rfbLog("accept_client: popup rejected: %s\n", addr);
1658 			return 0;
1659 		}
1660 
1661 	} else if (!strcmp(accept_cmd, "xmessage")) {
1662 		/* make our own command using xmessage(1) */
1663 
1664 		if (view_only) {
1665 			sprintf(xmessage, "xmessage -buttons yes:0,no:2 -center"
1666 			    " 'x11vnc: accept connection from %s?'", addr);
1667 		} else {
1668 			sprintf(xmessage, "xmessage -buttons yes:0,no:2,"
1669 			    "view-only:3 -center" " 'x11vnc: accept connection"
1670 			    " from %s?'", addr);
1671 			action = "yes:0,no:*,view:3";
1672 		}
1673 		cmd = xmessage;
1674 
1675 	} else {
1676 		/* use the user supplied command: */
1677 
1678 		cmd = accept_cmd;
1679 
1680 		/* extract any action prefix:  yes:N,no:M,view:K */
1681 		if (strstr(accept_cmd, "yes:") == accept_cmd) {
1682 			char *p;
1683 			if ((p = strpbrk(accept_cmd, " \t")) != NULL) {
1684 				int i;
1685 				cmd = p;
1686 				p = accept_cmd;
1687 				for (i=0; i<200; i++) {
1688 					if (*p == ' ' || *p == '\t') {
1689 						xmessage[i] = '\0';
1690 						break;
1691 					}
1692 					xmessage[i] = *p;
1693 					p++;
1694 				}
1695 				xmessage[200-1] = '\0';
1696 				action = xmessage;
1697 			}
1698 		}
1699 	}
1700 
1701 	if (cmd) {
1702 		int rc;
1703 
1704 		rfbLog("accept_client: using cmd for: %s\n", addr);
1705 		rc = run_user_command(cmd, client, "accept", NULL, 0, NULL);
1706 
1707 		if (action) {
1708 			int result;
1709 
1710 			if (rc < 0) {
1711 				rfbLog("accept_client: cannot use negative "
1712 				    "rc: %d, action %s\n", rc, action);
1713 				result = 2;
1714 			} else {
1715 				result = action_match(action, rc);
1716 			}
1717 
1718 			if (result == 1) {
1719 				rc = 0;
1720 			} else if (result == 2) {
1721 				rc = 1;
1722 			} else if (result == 3) {
1723 				rc = 0;
1724 				rfbLog("accept_client: viewonly: %s\n", addr);
1725 				client->viewOnly = TRUE;
1726 			} else {
1727 				rc = 1;	/* NOTREACHED */
1728 			}
1729 		}
1730 
1731 		if (rc == 0) {
1732 			rfbLog("accept_client: accepted: %s\n", addr);
1733 			return 1;
1734 		} else {
1735 			rfbLog("accept_client: rejected: %s\n", addr);
1736 			return 0;
1737 		}
1738 	} else {
1739 		rfbLog("accept_client: no command, rejecting %s\n", addr);
1740 		return 0;
1741 	}
1742 
1743 	/* return 0; NOTREACHED */
1744 }
1745 
check_ipv6_listen(long usec)1746 void check_ipv6_listen(long usec) {
1747 #if X11VNC_IPV6
1748 	fd_set fds;
1749 	struct timeval tv;
1750 	int nfds, csock = -1, one = 1;
1751 	struct sockaddr_in6 addr;
1752 	socklen_t addrlen = sizeof(addr);
1753 	rfbClientPtr cl;
1754 	int nmax = 0;
1755 	char *name;
1756 
1757 	if (!ipv6_listen || noipv6) {
1758 		return;
1759 	}
1760 	if (ipv6_listen_fd < 0 && ipv6_http_fd < 0) {
1761 		return;
1762 	}
1763 
1764 	FD_ZERO(&fds);
1765 	if (ipv6_listen_fd >= 0) {
1766 		FD_SET(ipv6_listen_fd, &fds);
1767 		nmax = ipv6_listen_fd;
1768 	}
1769 	if (ipv6_http_fd >= 0 && screen->httpSock < 0) {
1770 		FD_SET(ipv6_http_fd, &fds);
1771 		if (ipv6_http_fd > nmax) {
1772 			nmax = ipv6_http_fd;
1773 		}
1774 	}
1775 
1776 	tv.tv_sec = 0;
1777 	tv.tv_usec = 0;
1778 
1779 	nfds = select(nmax+1, &fds, NULL, NULL, &tv);
1780 
1781 	if (nfds <= 0) {
1782 		return;
1783 	}
1784 
1785 	if (ipv6_listen_fd >= 0 && FD_ISSET(ipv6_listen_fd, &fds)) {
1786 
1787 		csock = accept(ipv6_listen_fd, (struct sockaddr *)&addr, &addrlen);
1788 		if (csock < 0) {
1789 			rfbLogPerror("check_ipv6_listen: accept");
1790 			goto err1;
1791 		}
1792 		if (fcntl(csock, F_SETFL, O_NONBLOCK) < 0) {
1793 			rfbLogPerror("check_ipv6_listen: fcntl");
1794 			close(csock);
1795 			goto err1;
1796 		}
1797 		if (setsockopt(csock, IPPROTO_TCP, TCP_NODELAY,
1798 		    (char *)&one, sizeof(one)) < 0) {
1799 			rfbLogPerror("check_ipv6_listen: setsockopt");
1800 			close(csock);
1801 			goto err1;
1802 		}
1803 
1804 		name = ipv6_getipaddr((struct sockaddr *) &addr, addrlen);
1805 
1806 		ipv6_client_ip_str = name;
1807 		cl = rfbNewClient(screen, csock);
1808 		ipv6_client_ip_str = NULL;
1809 		if (cl == NULL) {
1810 			close(csock);
1811 			goto err1;
1812 		}
1813 
1814 		if (name) {
1815 			if (cl->host) {
1816 				free(cl->host);
1817 			}
1818 			cl->host = name;
1819 			rfbLog("ipv6 client: %s\n", name);
1820 		}
1821 	}
1822 
1823 	err1:
1824 
1825 	if (ipv6_http_fd >= 0 && FD_ISSET(ipv6_http_fd, &fds)) {
1826 
1827 		csock = accept(ipv6_http_fd, (struct sockaddr *)&addr, &addrlen);
1828 		if (csock < 0) {
1829 			rfbLogPerror("check_ipv6_listen: accept");
1830 			return;
1831 		}
1832 		if (fcntl(csock, F_SETFL, O_NONBLOCK) < 0) {
1833 			rfbLogPerror("check_ipv6_listen: fcntl");
1834 			close(csock);
1835 			return;
1836 		}
1837 		if (setsockopt(csock, IPPROTO_TCP, TCP_NODELAY,
1838 		    (char *)&one, sizeof(one)) < 0) {
1839 			rfbLogPerror("check_ipv6_listen: setsockopt");
1840 			close(csock);
1841 			return;
1842 		}
1843 
1844 		rfbLog("check_ipv6_listen: setting httpSock to %d\n", csock);
1845 		screen->httpSock = csock;
1846 
1847 		if (screen->httpListenSock < 0) {
1848 			/* this may not always work... */
1849 			int save = screen->httpListenSock;
1850 			screen->httpListenSock = ipv6_http_fd;
1851 			rfbLog("check_ipv6_listen: no httpListenSock, calling rfbHttpCheckFds()\n");
1852 			rfbHttpCheckFds(screen);
1853 			screen->httpListenSock = save;
1854 		}
1855 	}
1856 #endif
1857 	if (usec) {}
1858 }
1859 
check_unix_sock(long usec)1860 void check_unix_sock(long usec) {
1861 	fd_set fds;
1862 	struct timeval tv;
1863 	int nfds, csock = -1;
1864 	rfbClientPtr cl;
1865 	int nmax = 0;
1866 	char *name;
1867 
1868 	if (!unix_sock || unix_sock_fd < 0) {
1869 		return;
1870 	}
1871 
1872 	FD_ZERO(&fds);
1873 	if (unix_sock_fd >= 0) {
1874 		FD_SET(unix_sock_fd, &fds);
1875 		nmax = unix_sock_fd;
1876 	}
1877 
1878 	tv.tv_sec = 0;
1879 	tv.tv_usec = 0;
1880 
1881 	nfds = select(nmax+1, &fds, NULL, NULL, &tv);
1882 
1883 	if (nfds <= 0) {
1884 		return;
1885 	}
1886 
1887 	if (unix_sock_fd >= 0 && FD_ISSET(unix_sock_fd, &fds)) {
1888 		csock = accept_unix(unix_sock_fd);
1889 		if (csock < 0) {
1890 			return;
1891 		}
1892 		if (fcntl(csock, F_SETFL, O_NONBLOCK) < 0) {
1893 			rfbLogPerror("check_unix_sock: fcntl");
1894 			close(csock);
1895 			return;
1896 		}
1897 
1898 		/* rfbNewClient() will screw us with setsockopt TCP_NODELAY...
1899 		   you need to comment out in libvncserver/rfbserver.c:
1900 			rfbLogPerror("setsockopt failed");
1901 			close(sock);
1902 			return NULL;
1903 		 */
1904 		cl = rfbNewClient(screen, csock);
1905 
1906 		if (cl == NULL) {
1907 			close(csock);
1908 			return;
1909 		}
1910 
1911 		name = strdup(unix_sock);
1912 
1913 		if (name) {
1914 			if (cl->host) {
1915 				free(cl->host);
1916 			}
1917 			cl->host = name;
1918 			rfbLog("unix sock client: %s\n", name);
1919 		}
1920 	}
1921 }
1922 
1923 /*
1924  * For the -connect <file> option: periodically read the file looking for
1925  * a connect string.  If one is found set client_connect to it.
1926  */
check_connect_file(char * file)1927 static void check_connect_file(char *file) {
1928 	FILE *in;
1929 	char line[VNC_CONNECT_MAX], host[VNC_CONNECT_MAX];
1930 	static int first_warn = 1, truncate_ok = 1;
1931 	static double last_time = 0.0, delay = 0.5;
1932 	double now = dnow();
1933 	struct stat sbuf;
1934 
1935 	if (last_time == 0.0) {
1936 		if (!getenv("X11VNC_APPSHARE_ACTIVE")) {
1937 			/* skip first */
1938 			last_time = now;
1939 		} else {
1940 			delay = 0.25;
1941 		}
1942 	}
1943 	if (now - last_time < delay) {
1944 		/* check only about once a second */
1945 		return;
1946 	}
1947 	last_time = now;
1948 
1949 	if (! truncate_ok) {
1950 		/* check if permissions changed */
1951 		if (access(file, W_OK) == 0) {
1952 			truncate_ok = 1;
1953 		} else {
1954 			return;
1955 		}
1956 	}
1957 
1958 	if (stat(file, &sbuf) == 0) {
1959 		/* skip empty file directly */
1960 		if (sbuf.st_size == 0) {
1961 			return;
1962 		}
1963 	}
1964 
1965 	in = fopen(file, "r");
1966 	if (in == NULL) {
1967 		if (first_warn) {
1968 			rfbLog("check_connect_file: fopen failure: %s\n", file);
1969 			rfbLogPerror("fopen");
1970 			first_warn = 0;
1971 		}
1972 		return;
1973 	}
1974 
1975 	if (fgets(line, VNC_CONNECT_MAX, in) != NULL) {
1976 		if (sscanf(line, "%s", host) == 1) {
1977 			if (strlen(host) > 0) {
1978 				char *str = strdup(host);
1979 				if (strlen(str) > 38) {
1980 					char trim[100];
1981 					trim[0] = '\0';
1982 					strncat(trim, str, 38);
1983 					rfbLog("read connect file: %s ...\n",
1984 					    trim);
1985 				} else {
1986 					rfbLog("read connect file: %s\n", str);
1987 				}
1988 				if (!strcmp(str, "cmd=stop") &&
1989 				    dnowx() < 3.0) {
1990 					rfbLog("ignoring stale cmd=stop\n");
1991 				} else {
1992 					client_connect = str;
1993 				}
1994 			}
1995 		}
1996 	}
1997 	fclose(in);
1998 
1999 	/* truncate file */
2000 	in = fopen(file, "w");
2001 	if (in != NULL) {
2002 		fclose(in);
2003 	} else {
2004 		/* disable if we cannot truncate */
2005 		rfbLog("check_connect_file: could not truncate %s, "
2006 		   "disabling checking.\n", file);
2007 		truncate_ok = 0;
2008 	}
2009 }
2010 
socks5_proxy(char * host,int port,int sock)2011 static int socks5_proxy(char *host, int port, int sock) {
2012 	unsigned char buf[512], tmp[2];
2013 	char reply[512];
2014 	int len, n, i, j = 0;
2015 
2016 	memset(buf, 0, 512);
2017 	memset(reply, 0, 512);
2018 
2019 	buf[0] = 0x5;
2020 	buf[1] = 0x1;
2021 	buf[2] = 0x0;
2022 
2023 	write(sock, buf, 3);
2024 
2025 	n = read(sock, buf, 2);
2026 
2027 	if (n != 2) {
2028 		rfbLog("socks5_proxy: read error: %d\n", n);
2029 		close(sock);
2030 		return 0;
2031 	}
2032 	if (buf[0] != 0x5 || buf[1] != 0x0) {
2033 		rfbLog("socks5_proxy: handshake error: %d %d\n", (int) buf[0], (int) buf[1]);
2034 		close(sock);
2035 		return 0;
2036 	}
2037 
2038 	buf[0] = 0x5;
2039 	buf[1] = 0x1;
2040 	buf[2] = 0x0;
2041 	buf[3] = 0x3;
2042 
2043 	buf[4] = (unsigned char) strlen(host);
2044 	strcat((char *) buf+5, host);
2045 
2046 	len = 5 + strlen(host);
2047 
2048 	buf[len]   = (unsigned char) (port >> 8);
2049 	buf[len+1] = (unsigned char) (port & 0xff);
2050 
2051 	write(sock, buf, len+2);
2052 
2053 	for (i=0; i<4; i++) {
2054 		int n;
2055 		n = read(sock, tmp, 1);
2056 		j++;
2057 		if (n < 0) {
2058 			if (errno != EINTR) {
2059 				break;
2060 			} else {
2061 				i--;
2062 				if (j > 100) {
2063 					break;
2064 				}
2065 				continue;
2066 			}
2067 		}
2068 		if (n == 0) {
2069 			break;
2070 		}
2071 		reply[i] = tmp[0];
2072 	}
2073 	if (reply[3] == 0x1) {
2074 		read(sock, reply+4, 4 + 2);
2075 	} else if (reply[3] == 0x3) {
2076 		n = read(sock, tmp, 1);
2077 		reply[4] = tmp[0];
2078 		read(sock, reply+5, (int) reply[4] + 2);
2079 	} else if (reply[3] == 0x4) {
2080 		read(sock, reply+4, 16 + 2);
2081 	}
2082 
2083 	if (0) {
2084 		int i;
2085 		for (i=0; i<len+2; i++) {
2086 			fprintf(stderr, "b[%d]: %d\n", i, (int) buf[i]);
2087 		}
2088 		for (i=0; i<len+2; i++) {
2089 			fprintf(stderr, "r[%d]: %d\n", i, (int) reply[i]);
2090 		}
2091 	}
2092 	if (reply[0] == 0x5 && reply[1] == 0x0 && reply[2] == 0x0) {
2093 		rfbLog("SOCKS5 connect OK to %s:%d sock=%d\n", host, port, sock);
2094 		return 1;
2095 	} else {
2096 		rfbLog("SOCKS5 error to %s:%d sock=%d\n", host, port, sock);
2097 		close(sock);
2098 		return 0;
2099 	}
2100 }
2101 
socks_proxy(char * host,int port,int sock)2102 static int socks_proxy(char *host, int port, int sock) {
2103 	unsigned char buf[512], tmp[2];
2104 	char reply[16];
2105 	int socks4a = 0, len, i, j = 0, d1, d2, d3, d4;
2106 
2107 	memset(buf, 0, 512);
2108 
2109 	buf[0] = 0x4;
2110 	buf[1] = 0x1;
2111 	buf[2] = (unsigned char) (port >> 8);
2112 	buf[3] = (unsigned char) (port & 0xff);
2113 
2114 
2115 	if (strlen(host) > 256)  {
2116 		rfbLog("socks_proxy: hostname too long: %s\n", host);
2117 		close(sock);
2118 		return 0;
2119 	}
2120 
2121 	if (!strcmp(host, "localhost") || !strcmp(host, "127.0.0.1")) {
2122 		buf[4] = 127;
2123 		buf[5] = 0;
2124 		buf[6] = 0;
2125 		buf[7] = 1;
2126 	} else if (sscanf(host, "%d.%d.%d.%d", &d1, &d2, &d3, &d4) == 4) {
2127 		buf[4] = (unsigned char) d1;
2128 		buf[5] = (unsigned char) d2;
2129 		buf[6] = (unsigned char) d3;
2130 		buf[7] = (unsigned char) d4;
2131 	} else {
2132 		buf[4] = 0x0;
2133 		buf[5] = 0x0;
2134 		buf[6] = 0x0;
2135 		buf[7] = 0x3;
2136 		socks4a = 1;
2137 	}
2138 	len = 8;
2139 
2140 	strcat((char *)buf+8, "nobody");
2141 	len += strlen("nobody") + 1;
2142 
2143 	if (socks4a) {
2144 		strcat((char *) buf+8+strlen("nobody") + 1, host);
2145 		len += strlen(host) + 1;
2146 	}
2147 
2148 	write(sock, buf, len);
2149 
2150 	for (i=0; i<8; i++) {
2151 		int n;
2152 		n = read(sock, tmp, 1);
2153 		j++;
2154 		if (n < 0) {
2155 			if (errno != EINTR) {
2156 				break;
2157 			} else {
2158 				i--;
2159 				if (j > 100) {
2160 					break;
2161 				}
2162 				continue;
2163 			}
2164 		}
2165 		if (n == 0) {
2166 			break;
2167 		}
2168 		reply[i] = tmp[0];
2169 	}
2170 	if (0) {
2171 		int i;
2172 		for (i=0; i<len; i++) {
2173 			fprintf(stderr, "b[%d]: %d\n", i, (int) buf[i]);
2174 		}
2175 		for (i=0; i<8; i++) {
2176 			fprintf(stderr, "r[%d]: %d\n", i, (int) reply[i]);
2177 		}
2178 	}
2179 	if (reply[0] == 0x0 && reply[1] == 0x5a) {
2180 		if (socks4a) {
2181 			rfbLog("SOCKS4a connect OK to %s:%d sock=%d\n", host, port, sock);
2182 		} else {
2183 			rfbLog("SOCKS4  connect OK to %s:%d sock=%d\n", host, port, sock);
2184 		}
2185 		return 1;
2186 	} else {
2187 		if (socks4a) {
2188 			rfbLog("SOCKS4a error to %s:%d sock=%d\n", host, port, sock);
2189 		} else {
2190 			rfbLog("SOCKS4  error to %s:%d sock=%d\n", host, port, sock);
2191 		}
2192 		close(sock);
2193 		return 0;
2194 	}
2195 }
2196 
2197 #define PXY_HTTP	1
2198 #define PXY_GET		2
2199 #define PXY_SOCKS	3
2200 #define PXY_SOCKS5	4
2201 #define PXY_SSH		5
2202 #define PXY 3
2203 
2204 static int pxy_get_sock;
2205 
pconnect(int psock,char * host,int port,int type,char * http_path,char * gethost,int getport)2206 static int pconnect(int psock, char *host, int port, int type, char *http_path, char *gethost, int getport) {
2207 	char reply[4096];
2208 	int i, ok, len;
2209 	char *req;
2210 
2211 	pxy_get_sock = -1;
2212 
2213 	if (type == PXY_SOCKS) {
2214 		return socks_proxy(host, port, psock);
2215 	}
2216 	if (type == PXY_SOCKS5) {
2217 		return socks5_proxy(host, port, psock);
2218 	}
2219 	if (type == PXY_SSH) {
2220 		return 1;
2221 	}
2222 
2223 	len = strlen("CONNECT ") + strlen(host);
2224 	if (type == PXY_GET) {
2225 		len += strlen(http_path) + strlen(gethost);
2226 		len += strlen("host=") + 1 + strlen("port=") + 1 + 1;
2227 	}
2228 	len += 1 + 20 + strlen("HTTP/1.1\r\n") + 1;
2229 
2230 	req = (char *)malloc(len);
2231 
2232 	if (type == PXY_GET) {
2233 		int noquery = 0;
2234 		char *t = strstr(http_path, "__END__");
2235 		if (t) {
2236 			noquery = 1;
2237 			*t = '\0';
2238 		}
2239 
2240 		if (noquery) {
2241 			sprintf(req, "GET %s HTTP/1.1\r\n", http_path);
2242 		} else {
2243 			sprintf(req, "GET %shost=%s&port=%d HTTP/1.1\r\n", http_path, host, port);
2244 		}
2245 	} else {
2246 		sprintf(req, "CONNECT %s:%d HTTP/1.1\r\n", host, port);
2247 	}
2248 	rfbLog("http proxy: %s", req);
2249 	write(psock, req, strlen(req));
2250 
2251 	if (type == PXY_GET) {
2252 		char *t = "Connection: close\r\n";
2253 		write(psock, t, strlen(t));
2254 	}
2255 
2256 	if (type == PXY_GET) {
2257 		sprintf(req, "Host: %s:%d\r\n", gethost, getport);
2258 		rfbLog("http proxy: %s", req);
2259 		sprintf(req, "Host: %s:%d\r\n\r\n", gethost, getport);
2260 	} else {
2261 		sprintf(req, "Host: %s:%d\r\n", host, port);
2262 		rfbLog("http proxy: %s", req);
2263 		sprintf(req, "Host: %s:%d\r\n\r\n", host, port);
2264 	}
2265 
2266 	write(psock, req, strlen(req));
2267 
2268 	ok = 0;
2269 	reply[0] = '\0';
2270 
2271 	for (i=0; i<4096; i++) {
2272 		int n;
2273 		req[0] = req[1] = '\0';
2274 		n = read(psock, req, 1);
2275 		if (n < 0) {
2276 			if (errno != EINTR) {
2277 				break;
2278 			} else {
2279 				continue;
2280 			}
2281 		}
2282 		if (n == 0) {
2283 			break;
2284 		}
2285 		strcat(reply, req);
2286 		if (strstr(reply, "\r\n\r\n")) {
2287 			if (strstr(reply, "HTTP/") == reply) {
2288 				char *q = strchr(reply, ' ');
2289 				if (q) {
2290 					q++;
2291 					if (q[0] == '2' && q[1] == '0' && q[2] == '0' && q[3] == ' ') {
2292 						ok = 1;
2293 					}
2294 				}
2295 			}
2296 			break;
2297 		}
2298 	}
2299 
2300 	if (type == PXY_GET) {
2301 		char *t1 = strstr(reply, "VNC-IP-Port: ");
2302 		char *t2 = strstr(reply, "VNC-Host-Port: ");
2303 		char *s, *newhost = NULL;
2304 		int newport = 0;
2305 		fprintf(stderr, "%s\n", reply);
2306 		if (t1) {
2307 			t1 += strlen("VNC-IP-Port: ");
2308 			s = strstr(t1, ":");
2309 			if (s) {
2310 				*s = '\0';
2311 				newhost = strdup(t1);
2312 				newport = atoi(s+1);
2313 			}
2314 		} else if (t2) {
2315 			t2 += strlen("VNC-Host-Port: ");
2316 			s = strstr(t2, ":");
2317 			if (s) {
2318 				*s = '\0';
2319 				newhost = strdup(t2);
2320 				newport = atoi(s+1);
2321 			}
2322 		}
2323 		if (newhost && newport > 0) {
2324 			rfbLog("proxy GET reconnect to: %s:%d\n", newhost, newport);
2325 			pxy_get_sock = connect_tcp(newhost, newport);
2326 		}
2327 	}
2328 	free(req);
2329 
2330 	return ok;
2331 }
2332 
proxy_connect(char * host,int port)2333 static int proxy_connect(char *host, int port) {
2334 	char *p, *q, *str;
2335 	int i, n, pxy[PXY],pxy_p[PXY];
2336 	int psock = -1;
2337 	char *pxy_h[PXY], *pxy_g[PXY];
2338 
2339 	if (! connect_proxy) {
2340 		return -1;
2341 	}
2342 	str = strdup(connect_proxy);
2343 
2344 	for (i=0; i<PXY; i++) {
2345 		pxy[i] = 0;
2346 		pxy_p[i] = 0;
2347 		pxy_h[i] = NULL;
2348 		pxy_g[i] = NULL;
2349 	}
2350 
2351 	n = 0;
2352 	p = str;
2353 	while (p) {
2354 		char *hp, *c, *s = NULL;
2355 
2356 		q = strchr(p, ',');
2357 		if (q) {
2358 			*q = '\0';
2359 		}
2360 
2361 		if (n==0) fprintf(stderr, "\n");
2362 		rfbLog("proxy_connect[%d]: %s\n", n+1, p);
2363 
2364 		pxy[n] = 0;
2365 		pxy_p[n] = 0;
2366 		pxy_h[n] = NULL;
2367 		pxy_g[n] = NULL;
2368 
2369 		if (strstr(p, "socks://") == p)	{
2370 			hp = strstr(p, "://") + 3;
2371 			pxy[n] = PXY_SOCKS;
2372 		} else if (strstr(p, "socks4://") == p) {
2373 			hp = strstr(p, "://") + 3;
2374 			pxy[n] = PXY_SOCKS;
2375 		} else if (strstr(p, "socks5://") == p) {
2376 			hp = strstr(p, "://") + 3;
2377 			pxy[n] = PXY_SOCKS5;
2378 		} else if (strstr(p, "ssh://") == p) {
2379 			if (n != 0) {
2380 				rfbLog("ssh:// proxy must be the first one\n");
2381 				clean_up_exit(1);
2382 			}
2383 			hp = strstr(p, "://") + 3;
2384 			pxy[n] = PXY_SSH;
2385 		} else if (strstr(p, "http://") == p) {
2386 			hp = strstr(p, "://") + 3;
2387 			pxy[n] = PXY_HTTP;
2388 		} else if (strstr(p, "https://") == p) {
2389 			hp = strstr(p, "://") + 3;
2390 			pxy[n] = PXY_HTTP;
2391 		} else {
2392 			hp = p;
2393 			pxy[n] = PXY_HTTP;
2394 		}
2395 		c = strstr(hp, ":");
2396 		if (!c && pxy[n] == PXY_SSH) {
2397 			char *hp2 = (char *) malloc(strlen(hp) + 5);
2398 			sprintf(hp2, "%s:1", hp);
2399 			hp = hp2;
2400 			c = strstr(hp, ":");
2401 		}
2402 		if (!c) {
2403 			pxy[n] = 0;
2404 			if (q) {
2405 				*q = ',';
2406 				p = q + 1;
2407 			} else {
2408 				p = NULL;
2409 			}
2410 			continue;
2411 		}
2412 
2413 		if (pxy[n] == PXY_HTTP) {
2414 			s = strstr(c, "/");
2415 			if (s) {
2416 				pxy[n] = PXY_GET;
2417 				pxy_g[n] = strdup(s);
2418 				*s = '\0';
2419 			}
2420 		}
2421 		pxy_p[n] = atoi(c+1);
2422 
2423 		if (pxy_p[n] <= 0) {
2424 			pxy[n] = 0;
2425 			pxy_p[n] = 0;
2426 			if (q) {
2427 				*q = ',';
2428 				p = q + 1;
2429 			} else {
2430 				p = NULL;
2431 			}
2432 			continue;
2433 		}
2434 		*c = '\0';
2435 		pxy_h[n] = strdup(hp);
2436 
2437 		if (++n >= PXY) {
2438 			break;
2439 		}
2440 
2441 		if (q) {
2442 			*q = ',';
2443 			p = q + 1;
2444 		} else {
2445 			p = NULL;
2446 		}
2447 	}
2448 	free(str);
2449 
2450 	if (!n) {
2451 		psock = -1;
2452 		goto pxy_clean;
2453 	}
2454 
2455 	if (pxy[0] == PXY_SSH) {
2456 		int rc, len = 0;
2457 		char *cmd, *ssh;
2458 		int sport = find_free_port(7300, 8000);
2459 		if (getenv("SSH")) {
2460 			ssh = getenv("SSH");
2461 		} else {
2462 			ssh = "ssh";
2463 		}
2464 		len = 200 + strlen(ssh) + strlen(pxy_h[0]) + strlen(host);
2465 		cmd = (char *) malloc(len);
2466 		if (n == 1) {
2467 			if (pxy_p[0] <= 1) {
2468 				sprintf(cmd, "%s -f       -L '%d:%s:%d' '%s' 'sleep 20'", ssh,           sport, host, port, pxy_h[0]);
2469 			} else {
2470 				sprintf(cmd, "%s -f -p %d -L '%d:%s:%d' '%s' 'sleep 20'", ssh, pxy_p[0], sport, host, port, pxy_h[0]);
2471 			}
2472 		} else {
2473 			if (pxy_p[0] <= 1) {
2474 				sprintf(cmd, "%s -f       -L '%d:%s:%d' '%s' 'sleep 20'", ssh,           sport, pxy_h[1], pxy_p[1], pxy_h[0]);
2475 			} else {
2476 				sprintf(cmd, "%s -f -p %d -L '%d:%s:%d' '%s' 'sleep 20'", ssh, pxy_p[0], sport, pxy_h[1], pxy_p[1], pxy_h[0]);
2477 			}
2478 		}
2479 		if (no_external_cmds || !cmd_ok("ssh")) {
2480 			rfbLogEnable(1);
2481 			rfbLog("cannot run external commands in -nocmds mode:\n");
2482 			rfbLog("   \"%s\"\n", cmd);
2483 			rfbLog("   exiting.\n");
2484 			clean_up_exit(1);
2485 		}
2486 		close_exec_fds();
2487 		fprintf(stderr, "\n");
2488 		rfbLog("running: %s\n", cmd);
2489 		rc = system(cmd);
2490 		free(cmd);
2491 		if (rc != 0) {
2492 			psock = -1;
2493 			goto pxy_clean;
2494 		}
2495 		psock = connect_tcp("localhost", sport);
2496 
2497 	} else {
2498 		psock = connect_tcp(pxy_h[0], pxy_p[0]);
2499 	}
2500 
2501 	if (psock < 0) {
2502 		psock = -1;
2503 		goto pxy_clean;
2504 	}
2505 	rfbLog("opened socket to proxy: %s:%d\n", pxy_h[0], pxy_p[0]);
2506 
2507 	if (n >= 2) {
2508 		if (! pconnect(psock, pxy_h[1], pxy_p[1], pxy[0], pxy_g[0], pxy_h[0], pxy_p[0])) {
2509 			close(psock); psock = -1; goto pxy_clean;
2510 		}
2511 		if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
2512 
2513 		if (n >= 3) {
2514 			if (! pconnect(psock, pxy_h[2], pxy_p[2], pxy[1], pxy_g[1], pxy_h[1], pxy_p[1])) {
2515 				close(psock); psock = -1; goto pxy_clean;
2516 			}
2517 			if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
2518 			if (! pconnect(psock, host, port, pxy[2], pxy_g[2], pxy_h[2], pxy_p[2])) {
2519 				close(psock); psock = -1; goto pxy_clean;
2520 			}
2521 			if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
2522 
2523 		} else {
2524 			if (! pconnect(psock, host, port, pxy[1], pxy_g[1], pxy_h[1], pxy_p[1])) {
2525 				close(psock); psock = -1; goto pxy_clean;
2526 			}
2527 			if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
2528 		}
2529 	} else {
2530 		if (! pconnect(psock, host, port, pxy[0], pxy_g[0], pxy_h[0], pxy_p[0])) {
2531 			close(psock); psock = -1; goto pxy_clean;
2532 		}
2533 		if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
2534 	}
2535 
2536 	pxy_clean:
2537 	for (i=0; i < PXY; i++) {
2538 		if (pxy_h[i] != NULL) {
2539 			free(pxy_h[i]);
2540 		}
2541 		if (pxy_g[i] != NULL) {
2542 			free(pxy_g[i]);
2543 		}
2544 	}
2545 
2546 	return psock;
2547 }
2548 
get_repeater_string(char * str,int * len)2549 char *get_repeater_string(char *str, int *len) {
2550 	int pren, which = 0;
2551 	int prestring_len = 0;
2552 	char *prestring = NULL, *ptmp = NULL;
2553 	char *equals = strchr(str, '=');
2554 	char *plus   = strrchr(str, '+');
2555 
2556 	*len = 0;
2557 	if (!plus || !equals) {
2558 		return NULL;
2559 	}
2560 
2561 	*plus = '\0';
2562 	if (strstr(str, "repeater=") == str) {
2563 		/* ultravnc repeater http://www.uvnc.com/addons/repeater.html */
2564 		prestring_len = 250;
2565 		ptmp = (char *) calloc(prestring_len+1, 1);
2566 		snprintf(ptmp, prestring_len, "%s", str + strlen("repeater="));
2567 		which = 1;
2568 	} else if (strstr(str, "pre=") == str) {
2569 		prestring_len = strlen(str + strlen("pre="));
2570 		ptmp = (char *) calloc(prestring_len+1, 1);
2571 		snprintf(ptmp, prestring_len+1, "%s", str + strlen("pre="));
2572 		which = 2;
2573 	} else if (sscanf(str, "pre%d=", &pren) == 1) {
2574 		if (pren > 0 && pren <= 16384) {
2575 			prestring_len = pren;
2576 			ptmp = (char *) calloc(prestring_len+1, 1);
2577 			snprintf(prestring, prestring_len, "%s", equals+1);
2578 			which = 3;
2579 		}
2580 	}
2581 	if (ptmp != NULL) {
2582 		int i, k = 0;
2583 		char *p = ptmp;
2584 		prestring = (char *)calloc(prestring_len+1, 1);
2585 		/* translate \n to newline, etc. */
2586 		for (i=0; i < prestring_len; i++) {
2587 			if (i < prestring_len-1 && *(p+i) == '\\') {
2588 				if (*(p+i+1) == 'r') {
2589 					prestring[k++] = '\r'; i++;
2590 				} else if (*(p+i+1) == 'n') {
2591 					prestring[k++] = '\n'; i++;
2592 				} else if (*(p+i+1) == 't') {
2593 					prestring[k++] = '\t'; i++;
2594 				} else if (*(p+i+1) == 'a') {
2595 					prestring[k++] = '\a'; i++;
2596 				} else if (*(p+i+1) == 'b') {
2597 					prestring[k++] = '\b'; i++;
2598 				} else if (*(p+i+1) == 'v') {
2599 					prestring[k++] = '\v'; i++;
2600 				} else if (*(p+i+1) == 'f') {
2601 					prestring[k++] = '\f'; i++;
2602 				} else if (*(p+i+1) == '\\') {
2603 					prestring[k++] = '\\'; i++;
2604 				} else if (*(p+i+1) == 'c') {
2605 					prestring[k++] = ','; i++;
2606 				} else {
2607 					prestring[k++] = *(p+i);
2608 				}
2609 			} else {
2610 				prestring[k++] = *(p+i);
2611 			}
2612 		}
2613 		if (which == 2) {
2614 			prestring_len = k;
2615 		}
2616 		if (!quiet) {
2617 			rfbLog("-connect prestring: '%s'\n", prestring);
2618 		}
2619 		free(ptmp);
2620 	}
2621 	*plus = '+';
2622 
2623 	*len = prestring_len;
2624 	return prestring;
2625 }
2626 
2627 #ifndef USE_TIMEOUT_INTERRUPT
2628 #define USE_TIMEOUT_INTERRUPT 0
2629 #endif
2630 
reverse_connect_timeout(int sig)2631 static void reverse_connect_timeout (int sig) {
2632 	rfbLog("sig: %d, reverse_connect_timeout.\n", sig);
2633 #if USE_TIMEOUT_INTERRUPT
2634 	rfbLog("reverse_connect_timeout proceeding assuming connect(2) interrupt.\n");
2635 #else
2636 	clean_up_exit(0);
2637 #endif
2638 }
2639 
2640 
2641 /*
2642  * Do a reverse connect for a single "host" or "host:port"
2643  */
2644 
do_reverse_connect(char * str_in)2645 static int do_reverse_connect(char *str_in) {
2646 	rfbClientPtr cl;
2647 	char *host, *p, *str = str_in;
2648 	char *prestring = NULL;
2649 	int prestring_len = 0;
2650 	int rport = 5500, len = strlen(str);
2651 	int set_alarm = 0;
2652 
2653 	if (len < 1) {
2654 		return 0;
2655 	}
2656 	if (len > 1024) {
2657 		rfbLog("reverse_connect: string too long: %d bytes\n", len);
2658 		return 0;
2659 	}
2660 	if (!screen) {
2661 		rfbLog("reverse_connect: screen not setup yet.\n");
2662 		return 0;
2663 	}
2664 	if (unixpw_in_progress) return 0;
2665 
2666 	/* look for repeater pre-string */
2667 	if (strchr(str, '=') && strrchr(str, '+')
2668 	    && (strstr(str, "pre") == str || strstr(str, "repeater=") == str)) {
2669 		prestring = get_repeater_string(str, &prestring_len);
2670 		str = strrchr(str, '+') + 1;
2671 	} else if (strrchr(str, '+') && strstr(str, "repeater://") == str) {
2672 		/* repeater://host:port+string */
2673 		/*   repeater=string+host:port */
2674 		char *plus = strrchr(str, '+');
2675 		str = (char *) malloc(strlen(str_in)+1);
2676 		*plus = '\0';
2677 		sprintf(str, "repeater=%s+%s", plus+1, str_in + strlen("repeater://"));
2678 		prestring = get_repeater_string(str, &prestring_len);
2679 		str = strrchr(str, '+') + 1;
2680 		*plus = '+';
2681 	}
2682 
2683 	/* copy in to host */
2684 	host = (char *) malloc(len+1);
2685 	if (! host) {
2686 		rfbLog("reverse_connect: could not malloc string %d\n", len);
2687 		return 0;
2688 	}
2689 	strncpy(host, str, len);
2690 	host[len] = '\0';
2691 
2692 	/* extract port, if any */
2693 	if ((p = strrchr(host, ':')) != NULL) {
2694 		rport = atoi(p+1);
2695 		if (rport < 0) {
2696 			rport = -rport;
2697 		} else if (rport < 20) {
2698 			rport = 5500 + rport;
2699 		}
2700 		*p = '\0';
2701 	}
2702 
2703 	if (ipv6_client_ip_str) {
2704 		free(ipv6_client_ip_str);
2705 		ipv6_client_ip_str = NULL;
2706 	}
2707 
2708 	if (use_openssl) {
2709 		int vncsock;
2710 		if (connect_proxy) {
2711 			vncsock = proxy_connect(host, rport);
2712 		} else {
2713 			vncsock = connect_tcp(host, rport);
2714 		}
2715 		if (vncsock < 0) {
2716 			rfbLog("reverse_connect: failed to connect to: %s\n", str);
2717 			return 0;
2718 		}
2719 		if (prestring != NULL) {
2720 			write(vncsock, prestring, prestring_len);
2721 			free(prestring);
2722 		}
2723 /* XXX use header */
2724 #define OPENSSL_REVERSE 6
2725 		if (!getenv("X11VNC_DISABLE_SSL_CLIENT_MODE")) {
2726 			openssl_init(1);
2727 		}
2728 
2729 		if (first_conn_timeout > 0) {
2730 			set_alarm = 1;
2731 			signal(SIGALRM, reverse_connect_timeout);
2732 #if USE_TIMEOUT_INTERRUPT
2733 			siginterrupt(SIGALRM, 1);
2734 #endif
2735 			rfbLog("reverse_connect: using alarm() timeout of %d seconds.\n", first_conn_timeout);
2736 			alarm(first_conn_timeout);
2737 		}
2738 		accept_openssl(OPENSSL_REVERSE, vncsock);
2739 		if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);}
2740 
2741 		openssl_init(0);
2742 		free(host);
2743 		return 1;
2744 	}
2745 
2746 	if (use_stunnel) {
2747 		if(strcmp(host, "localhost") && strcmp(host, "127.0.0.1")) {
2748 			if (!getenv("STUNNEL_DISABLE_LOCALHOST")) {
2749 				rfbLog("reverse_connect: error host not localhost in -stunnel mode.\n");
2750 				free(host);
2751 				return 0;
2752 			}
2753 		}
2754 	}
2755 
2756 	if (unixpw) {
2757 		int is_localhost = 0, user_disabled_it = 0;
2758 
2759 		if(!strcmp(host, "localhost") || !strcmp(host, "127.0.0.1")) {
2760 			is_localhost = 1;
2761 		}
2762 		if (getenv("UNIXPW_DISABLE_LOCALHOST")) {
2763 			user_disabled_it = 1;
2764 		}
2765 
2766 		if (! is_localhost) {
2767 			if (user_disabled_it) {
2768 				rfbLog("reverse_connect: warning disabling localhost constraint in -unixpw\n");
2769 			} else {
2770 				rfbLog("reverse_connect: error not localhost in -unixpw\n");
2771 				free(host);
2772 				return 0;
2773 			}
2774 		}
2775 	}
2776 
2777 	if (first_conn_timeout > 0) {
2778 		set_alarm = 1;
2779 		signal(SIGALRM, reverse_connect_timeout);
2780 #if USE_TIMEOUT_INTERRUPT
2781 		siginterrupt(SIGALRM, 1);
2782 #endif
2783 		rfbLog("reverse_connect: using alarm() timeout of %d seconds.\n", first_conn_timeout);
2784 		alarm(first_conn_timeout);
2785 	}
2786 
2787 	if (connect_proxy != NULL) {
2788 		int sock = proxy_connect(host, rport);
2789 		if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);}
2790 		if (sock >= 0) {
2791 			if (prestring != NULL) {
2792 				write(sock, prestring, prestring_len);
2793 				free(prestring);
2794 			}
2795 			cl = create_new_client(sock, 1);
2796 		} else {
2797 			return 0;
2798 		}
2799 	} else if (prestring != NULL) {
2800 		int sock = connect_tcp(host, rport);
2801 		if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);}
2802 		if (sock >= 0) {
2803 			write(sock, prestring, prestring_len);
2804 			free(prestring);
2805 			cl = create_new_client(sock, 1);
2806 		} else {
2807 			return 0;
2808 		}
2809 	} else {
2810 		cl = rfbReverseConnection(screen, host, rport);
2811 		if (cl == NULL) {
2812 			int sock = connect_tcp(host, rport);
2813 			if (sock >= 0) {
2814 				cl = create_new_client(sock, 1);
2815 			}
2816 		}
2817 		if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);}
2818 		if (cl != NULL && use_threads) {
2819 			cl->onHold = FALSE;
2820 			rfbStartOnHoldClient(cl);
2821 		}
2822 	}
2823 
2824 	free(host);
2825 
2826 	if (ipv6_client_ip_str) {
2827 		free(ipv6_client_ip_str);
2828 		ipv6_client_ip_str = NULL;
2829 	}
2830 
2831 
2832 	if (cl == NULL) {
2833 		if (quiet && connect_or_exit) {
2834 			rfbLogEnable(1);
2835 		}
2836 		rfbLog("reverse_connect: %s failed\n", str);
2837 		return 0;
2838 	} else {
2839 		rfbLog("reverse_connect: %s/%s OK\n", str, cl->host);
2840 		/* let's see if anyone complains: */
2841 		if (! getenv("X11VNC_REVERSE_CONNECTION_NO_AUTH")) {
2842 			rfbLog("reverse_connect: turning on auth for %s\n",
2843 			    cl->host);
2844 			cl->reverseConnection = FALSE;
2845 		}
2846 		return 1;
2847 	}
2848 }
2849 
2850 /*
2851  * Break up comma separated list of hosts and call do_reverse_connect()
2852  */
reverse_connect(char * str)2853 void reverse_connect(char *str) {
2854 	char *p, *tmp;
2855 	int sleep_between_host = 300;
2856 	int sleep_min = 1500, sleep_max = 4500, n_max = 5;
2857 	int n, tot, t, dt = 100, cnt = 0;
2858 	int nclients0 = client_count;
2859 	int lcnt, j;
2860 	char **list;
2861 	int do_appshare = 0;
2862 
2863 	if (!getenv("X11VNC_REVERSE_USE_OLD_SLEEP")) {
2864 		sleep_min = 500;
2865 		sleep_max = 2500;
2866 	}
2867 
2868 	if (unixpw_in_progress) return;
2869 
2870 	tmp = strdup(str);
2871 
2872 	list = (char **) calloc( (strlen(tmp)+2) * sizeof (char *), 1);
2873 	lcnt = 0;
2874 
2875 	p = strtok(tmp, ", \t\r\n");
2876 	while (p) {
2877 		list[lcnt++] = strdup(p);
2878 		p = strtok(NULL, ", \t\r\n");
2879 	}
2880 	free(tmp);
2881 
2882 	if (subwin && getenv("X11VNC_APPSHARE_ACTIVE")) {
2883 		do_appshare = 1;
2884 		sleep_between_host = 0;	/* too agressive??? */
2885 	}
2886 	if (getenv("X11VNC_REVERSE_SLEEP_BETWEEN_HOST")) {
2887 		sleep_between_host = atoi(getenv("X11VNC_REVERSE_SLEEP_BETWEEN_HOST"));
2888 	}
2889 
2890 	if (do_appshare) {
2891 		if (screen && dpy) {
2892 			char *s = choose_title(DisplayString(dpy));
2893 
2894 			/* mutex */
2895 			screen->desktopName = s;
2896 			if (rfb_desktop_name) {
2897 				free(rfb_desktop_name);
2898 			}
2899 			rfb_desktop_name = strdup(s);
2900 		}
2901 	}
2902 
2903 	for (j = 0; j < lcnt; j++) {
2904 		p = list[j];
2905 
2906 		if ((n = do_reverse_connect(p)) != 0) {
2907 			int i;
2908 			progress_client();
2909 			for (i=0; i < 3; i++) {
2910 				rfbPE(-1);
2911 			}
2912 		}
2913 		cnt += n;
2914 		if (list[j+1] != NULL) {
2915 			t = 0;
2916 			while (t < sleep_between_host) {
2917 				double t1, t2;
2918 				int i;
2919 				t1 = dnow();
2920 				for (i=0; i < 8; i++) {
2921 					rfbPE(-1);
2922 					if (do_appshare && t == 0) {
2923 						rfbPE(-1);
2924 					}
2925 				}
2926 				t2 = dnow();
2927 				t += (int) (1000 * (t2 - t1));
2928 				if (t >= sleep_between_host) {
2929 					break;
2930 				}
2931 				usleep(dt * 1000);
2932 				t += dt;
2933 			}
2934 		}
2935 	}
2936 
2937 	for (j = 0; j < lcnt; j++) {
2938 		p = list[j];
2939 		if (p) free(p);
2940 	}
2941 	free(list);
2942 
2943 	if (cnt == 0) {
2944 		if (connect_or_exit) {
2945 			rfbLogEnable(1);
2946 			rfbLog("exiting under -connect_or_exit\n");
2947 			if (gui_pid > 0) {
2948 				rfbLog("killing gui_pid %d\n", gui_pid);
2949 				kill(gui_pid, SIGTERM);
2950 			}
2951 			clean_up_exit(1);
2952 		}
2953 		if (xrandr || xrandr_maybe) {
2954 			check_xrandr_event("reverse_connect1");
2955 		}
2956 		return;
2957 	}
2958 
2959 	/*
2960 	 * XXX: we need to process some of the initial handshaking
2961 	 * events, otherwise the client can get messed up (why??)
2962 	 * so we send rfbProcessEvents() all over the place.
2963 	 *
2964 	 * How much is this still needed?
2965 	 */
2966 
2967 	n = cnt;
2968 	if (n >= n_max) {
2969 		n = n_max;
2970 	}
2971 	t = sleep_max - sleep_min;
2972 	tot = sleep_min + ((n-1) * t) / (n_max-1);
2973 
2974 	if (do_appshare) {
2975 		tot /= 3;
2976 		if (tot < dt) {
2977 			tot = dt;
2978 		}
2979 		tot = 0;	/* too agressive??? */
2980 	}
2981 
2982 	if (getenv("X11VNC_REVERSE_SLEEP_MAX")) {
2983 		tot = atoi(getenv("X11VNC_REVERSE_SLEEP_MAX"));
2984 	}
2985 
2986 	t = 0;
2987 	while (t < tot) {
2988 		int i;
2989 		double t1, t2;
2990 		t1 = dnow();
2991 		for (i=0; i < 8; i++) {
2992 			rfbPE(-1);
2993 			if (t == 0) rfbPE(-1);
2994 		}
2995 		t2 = dnow();
2996 		t += (int) (1000 * (t2 - t1));
2997 		if (t >= tot) {
2998 			break;
2999 		}
3000 		usleep(dt * 1000);
3001 		t += dt;
3002 	}
3003 	if (connect_or_exit) {
3004 		if (client_count <= nclients0)  {
3005 			for (t = 0; t < 10; t++) {
3006 				int i;
3007 				for (i=0; i < 3; i++) {
3008 					rfbPE(-1);
3009 				}
3010 				usleep(100 * 1000);
3011 			}
3012 		}
3013 		if (client_count <= nclients0)  {
3014 			rfbLogEnable(1);
3015 			rfbLog("exiting under -connect_or_exit\n");
3016 			if (gui_pid > 0) {
3017 				rfbLog("killing gui_pid %d\n", gui_pid);
3018 				kill(gui_pid, SIGTERM);
3019 			}
3020 			clean_up_exit(1);
3021 		}
3022 	}
3023 	if (xrandr || xrandr_maybe) {
3024 		check_xrandr_event("reverse_connect2");
3025 	}
3026 }
3027 
3028 /*
3029  * Routines for monitoring the VNC_CONNECT and X11VNC_REMOTE properties
3030  * for changes.  The vncconnect(1) will set it on our X display.
3031  */
set_vnc_connect_prop(char * str)3032 void set_vnc_connect_prop(char *str) {
3033 	RAWFB_RET_VOID
3034 #if !NO_X11
3035 	if (vnc_connect_prop == None) return;
3036 	XChangeProperty(dpy, rootwin, vnc_connect_prop, XA_STRING, 8,
3037 	    PropModeReplace, (unsigned char *)str, strlen(str));
3038 #else
3039 	if (!str) {}
3040 #endif	/* NO_X11 */
3041 }
3042 
set_x11vnc_remote_prop(char * str)3043 void set_x11vnc_remote_prop(char *str) {
3044 	RAWFB_RET_VOID
3045 #if !NO_X11
3046 	if (x11vnc_remote_prop == None) return;
3047 	XChangeProperty(dpy, rootwin, x11vnc_remote_prop, XA_STRING, 8,
3048 	    PropModeReplace, (unsigned char *)str, strlen(str));
3049 #else
3050 	if (!str) {}
3051 #endif	/* NO_X11 */
3052 }
3053 
read_vnc_connect_prop(int nomsg)3054 void read_vnc_connect_prop(int nomsg) {
3055 #if NO_X11
3056 	RAWFB_RET_VOID
3057 	if (!nomsg) {}
3058 	return;
3059 #else
3060 	Atom type;
3061 	int format, slen, dlen;
3062 	unsigned long nitems = 0, bytes_after = 0;
3063 	unsigned char* data = NULL;
3064 	int db = 1;
3065 
3066 	vnc_connect_str[0] = '\0';
3067 	slen = 0;
3068 
3069 	if (! vnc_connect || vnc_connect_prop == None) {
3070 		/* not active or problem with VNC_CONNECT atom */
3071 		return;
3072 	}
3073 	RAWFB_RET_VOID
3074 
3075 	/* read the property value into vnc_connect_str: */
3076 	do {
3077 		if (XGetWindowProperty(dpy, DefaultRootWindow(dpy),
3078 		    vnc_connect_prop, nitems/4, VNC_CONNECT_MAX/16, False,
3079 		    AnyPropertyType, &type, &format, &nitems, &bytes_after,
3080 		    &data) == Success) {
3081 
3082 			dlen = nitems * (format/8);
3083 			if (slen + dlen > VNC_CONNECT_MAX) {
3084 				/* too big */
3085 				rfbLog("warning: truncating large VNC_CONNECT"
3086 				   " string > %d bytes.\n", VNC_CONNECT_MAX);
3087 				XFree_wr(data);
3088 				break;
3089 			}
3090 			memcpy(vnc_connect_str+slen, data, dlen);
3091 			slen += dlen;
3092 			vnc_connect_str[slen] = '\0';
3093 			XFree_wr(data);
3094 		}
3095 	} while (bytes_after > 0);
3096 
3097 	vnc_connect_str[VNC_CONNECT_MAX] = '\0';
3098 	if (! db || nomsg) {
3099 		;
3100 	} else {
3101 		rfbLog("read VNC_CONNECT: %s\n", vnc_connect_str);
3102 	}
3103 #endif	/* NO_X11 */
3104 }
3105 
read_x11vnc_remote_prop(int nomsg)3106 void read_x11vnc_remote_prop(int nomsg) {
3107 #if NO_X11
3108 	RAWFB_RET_VOID
3109 	if (!nomsg) {}
3110 	return;
3111 #else
3112 	Atom type;
3113 	int format, slen, dlen;
3114 	unsigned long nitems = 0, bytes_after = 0;
3115 	unsigned char* data = NULL;
3116 	int db = 1;
3117 
3118 	x11vnc_remote_str[0] = '\0';
3119 	slen = 0;
3120 
3121 	if (! vnc_connect || x11vnc_remote_prop == None) {
3122 		/* not active or problem with X11VNC_REMOTE atom */
3123 		return;
3124 	}
3125 	RAWFB_RET_VOID
3126 
3127 	/* read the property value into x11vnc_remote_str: */
3128 	do {
3129 		if (XGetWindowProperty(dpy, DefaultRootWindow(dpy),
3130 		    x11vnc_remote_prop, nitems/4, X11VNC_REMOTE_MAX/16, False,
3131 		    AnyPropertyType, &type, &format, &nitems, &bytes_after,
3132 		    &data) == Success) {
3133 
3134 			dlen = nitems * (format/8);
3135 			if (slen + dlen > X11VNC_REMOTE_MAX) {
3136 				/* too big */
3137 				rfbLog("warning: truncating large X11VNC_REMOTE"
3138 				   " string > %d bytes.\n", X11VNC_REMOTE_MAX);
3139 				XFree_wr(data);
3140 				break;
3141 			}
3142 			memcpy(x11vnc_remote_str+slen, data, dlen);
3143 			slen += dlen;
3144 			x11vnc_remote_str[slen] = '\0';
3145 			XFree_wr(data);
3146 		}
3147 	} while (bytes_after > 0);
3148 
3149 	x11vnc_remote_str[X11VNC_REMOTE_MAX] = '\0';
3150 	if (! db || nomsg) {
3151 		;
3152 	} else if (strstr(x11vnc_remote_str, "ans=stop:N/A,ans=quit:N/A,ans=")) {
3153 		;
3154 	} else if (strstr(x11vnc_remote_str, "qry=stop,quit,exit")) {
3155 		;
3156 	} else if (strstr(x11vnc_remote_str, "ack=") == x11vnc_remote_str) {
3157 		;
3158 	} else if (quiet && strstr(x11vnc_remote_str, "qry=ping") ==
3159 	    x11vnc_remote_str) {
3160 		;
3161 	} else if (strstr(x11vnc_remote_str, "cmd=") &&
3162 	    strstr(x11vnc_remote_str, "passwd")) {
3163 		rfbLog("read X11VNC_REMOTE: *\n");
3164 	} else if (strlen(x11vnc_remote_str) > 36) {
3165 		char trim[100];
3166 		trim[0] = '\0';
3167 		strncat(trim, x11vnc_remote_str, 36);
3168 		rfbLog("read X11VNC_REMOTE: %s ...\n", trim);
3169 
3170 	} else {
3171 		rfbLog("read X11VNC_REMOTE: %s\n", x11vnc_remote_str);
3172 	}
3173 #endif	/* NO_X11 */
3174 }
3175 
3176 extern int rc_npieces;
3177 
grab_state(int * ptr_grabbed,int * kbd_grabbed)3178 void grab_state(int *ptr_grabbed, int *kbd_grabbed) {
3179 	int rcp, rck;
3180 	double t0, t1;
3181 	double ta, tb, tc;
3182 	*ptr_grabbed = -1;
3183 	*kbd_grabbed = -1;
3184 
3185 	if (!dpy) {
3186 		return;
3187 	}
3188 	*ptr_grabbed = 0;
3189 	*kbd_grabbed = 0;
3190 
3191 #if !NO_X11
3192 	X_LOCK;
3193 
3194 	XSync(dpy, False);
3195 
3196 	ta = t0 = dnow();
3197 
3198 	rcp = XGrabPointer(dpy, window, False, 0, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
3199 	XUngrabPointer(dpy, CurrentTime);
3200 
3201 	tb = dnow();
3202 
3203 	rck = XGrabKeyboard(dpy, window, False, GrabModeAsync, GrabModeAsync, CurrentTime);
3204 	XUngrabKeyboard(dpy, CurrentTime);
3205 
3206 	tc = dnow();
3207 
3208 	XSync(dpy, False);
3209 
3210 	t1 = dnow();
3211 
3212 	X_UNLOCK;
3213 	if (rcp == AlreadyGrabbed || rcp == GrabFrozen) {
3214 		*ptr_grabbed = 1;
3215 	}
3216 	if (rck == AlreadyGrabbed || rck == GrabFrozen) {
3217 		*kbd_grabbed = 1;
3218 	}
3219 	if (rc_npieces < 10) {
3220 		rfbLog("grab_state: checked %d,%d in %.6f sec (%.6f %.6f)\n",
3221 		    *ptr_grabbed, *kbd_grabbed, t1-t0, tb-ta, tc-tb);
3222 	}
3223 #endif
3224 }
3225 
pmove(int x,int y)3226 static void pmove(int x, int y) {
3227 	if (x < 0 || y < 0) {
3228 		rfbLog("pmove: skipping negative x or y: %d %d\n", x, y);
3229 		return;
3230 	}
3231 	rfbLog("pmove: x y: %d %d\n", x, y);
3232 	pointer_event(0, x, y, NULL);
3233 	X_LOCK;
3234 	XFlush_wr(dpy);
3235 	X_UNLOCK;
3236 }
3237 
3238 
bcx_xattach(char * str,int * pg_init,int * kg_init)3239 char *bcx_xattach(char *str, int *pg_init, int *kg_init) {
3240 	int grab_check = 1;
3241 	int shift = 20;
3242 	int final_x = 30, final_y = 30;
3243 	int extra_x = -1, extra_y = -1;
3244 	int t1, t2, dt = 40 * 1000;
3245 	int ifneeded = 0;
3246 	char *dir = "none", *flip = "none", *q;
3247 	int pg1, kg1, pg2, kg2;
3248 	char _bcx_res[128];
3249 
3250 	/* str:[up,down,left,right]+nograbcheck+shift=n+final=x+y+extra_move=x+y+[master_to_slave,slave_to_master,M2S,S2M]+dt=n+retry=n+ifneeded */
3251 
3252 	if (strstr(str, "up")) {
3253 		dir = "up";
3254 	} else if (strstr(str, "down")) {
3255 		dir = "down";
3256 	} else if (strstr(str, "left")) {
3257 		dir = "left";
3258 	} else if (strstr(str, "right")) {
3259 		dir = "right";
3260 	} else {
3261 		return strdup("FAIL,NO_DIRECTION_SPECIFIED");
3262 	}
3263 
3264 	if (strstr(str, "master_to_slave") || strstr(str, "M2S")) {
3265 		flip = "M2S";
3266 	} else if (strstr(str, "slave_to_master") || strstr(str, "S2M")) {
3267 		flip = "S2M";
3268 	} else {
3269 		return strdup("FAIL,NO_MODE_CHANGE_SPECIFIED");
3270 	}
3271 
3272 	if (strstr(str, "nograbcheck")) {
3273 		grab_check = 0;
3274 	}
3275 	if (strstr(str, "ifneeded")) {
3276 		ifneeded = 1;
3277 	}
3278 	q = strstr(str, "shift=");
3279 	if (q && sscanf(q, "shift=%d", &t1) == 1) {
3280 		shift = t1;
3281 	}
3282 	q = strstr(str, "final=");
3283 	if (q && sscanf(q, "final=%d+%d", &t1, &t2) == 2) {
3284 		final_x = t1;
3285 		final_y = t2;
3286 	}
3287 	q = strstr(str, "extra_move=");
3288 	if (q && sscanf(q, "extra_move=%d+%d", &t1, &t2) == 2) {
3289 		extra_x = t1;
3290 		extra_y = t2;
3291 	}
3292 	q = strstr(str, "dt=");
3293 	if (q && sscanf(q, "dt=%d", &t1) == 1) {
3294 		dt = t1 * 1000;
3295 	}
3296 
3297 	if (grab_check) {
3298 		int read_init = 0;
3299 
3300 		if (*pg_init >=0 && *kg_init >=0)  {
3301 			pg1 = *pg_init;
3302 			kg1 = *kg_init;
3303 			read_init = 1;
3304 		} else {
3305 			grab_state(&pg1, &kg1);
3306 			read_init = 0;
3307 		}
3308 
3309 		if (!strcmp(flip, "M2S")) {
3310 			if (ifneeded && pg1 == 1 && kg1 == 1) {
3311 				rfbLog("bcx_xattach: M2S grab state is already what we want, skipping moves:  %d,%d\n", pg1, kg1);
3312 				return strdup("DONE,GRAB_OK");
3313 			}
3314 		} else if (!strcmp(flip, "S2M")) {
3315 			if (ifneeded && pg1 == 0 && kg1 == 0) {
3316 				rfbLog("bcx_xattach: S2M grab state is already what we want, skipping moves:  %d,%d\n", pg1, kg1);
3317 				return strdup("DONE,GRAB_OK");
3318 			}
3319 		}
3320 
3321 		if (read_init) {
3322 			;
3323 		} else if (!strcmp(flip, "M2S")) {
3324 			if (pg1 != 0 || kg1 != 0) {
3325 				rfbLog("bcx_xattach: M2S init grab state incorrect:  %d,%d\n", pg1, kg1);
3326 				usleep(2*dt);
3327 				grab_state(&pg1, &kg1);
3328 				rfbLog("bcx_xattach: slept and retried, grab is now: %d,%d\n", pg1, kg1);
3329 			}
3330 		} else if (!strcmp(flip, "S2M")) {
3331 			if (pg1 != 1 || kg1 != 1) {
3332 				rfbLog("bcx_xattach: S2M init grab state incorrect:  %d,%d\n", pg1, kg1);
3333 				usleep(2*dt);
3334 				grab_state(&pg1, &kg1);
3335 				rfbLog("bcx_xattach: slept and retried, grab is now: %d,%d\n", pg1, kg1);
3336 			}
3337 		}
3338 		if (!read_init) {
3339 			*pg_init = pg1;
3340 			*kg_init = kg1;
3341 		}
3342 	}
3343 
3344 	/*
3345 	 * A guide for BARCO xattach:
3346 	 *
3347 	 *   For -cursor_rule 'b(0):%:t(1),t(1):%:b(0)'
3348 	 *	down+M2S  up+S2M
3349 	 *   For -cursor_rule 'r(0):%:l(1),l(1):%:r(0)'
3350 	 *	right+M2S  left+S2M
3351 	 *
3352 	 *   For -cursor_rule 't(0):%:b(1),b(1):%:t(0)'
3353 	 *	up+M2S  down+S2M
3354 	 *   For -cursor_rule 'l(0):%:r(1),r(1):%:l(0)'
3355 	 *	left+M2S  right+S2M
3356 	 *   For -cursor_rule 'l(0):%:r(1),r(1):%:l(0),r(0):%:l(1),l(1):%:r(0)'
3357 	 *	left+M2S  right+S2M  (we used to do both 'right')
3358 	 */
3359 
3360 	if (!strcmp(flip, "M2S")) {
3361 		if (!strcmp(dir, "up")) {
3362 			pmove(shift, 0);		/* go to top edge */
3363 			usleep(dt);
3364 			pmove(shift+1, 0);		/* move 1 for MotionNotify */
3365 		} else if (!strcmp(dir, "down")) {
3366 			pmove(shift,   dpy_y-1);	/* go to bottom edge */
3367 			usleep(dt);
3368 			pmove(shift+1, dpy_y-1);	/* move 1 for MotionNotify */
3369 		} else if (!strcmp(dir, "left")) {
3370 			pmove(0, shift);		/* go to left edge */
3371 			usleep(dt);
3372 			pmove(0, shift+1);		/* move 1 for MotionNotify */
3373 		} else if (!strcmp(dir, "right")) {
3374 			pmove(dpy_x-1, shift);		/* go to right edge */
3375 			usleep(dt);
3376 			pmove(dpy_x-1, shift+1);	/* move 1 for Motion Notify  */
3377 		}
3378 	} else if (!strcmp(flip, "S2M")) {
3379 		int dts = dt/2;
3380 		if (!strcmp(dir, "up")) {
3381 			pmove(shift, 2);		/* Approach top edge in 3 moves.  1st move */
3382 			usleep(dts);
3383 			pmove(shift, 1);		/* 2nd move */
3384 			usleep(dts);
3385 			pmove(shift, 0);		/* 3rd move */
3386 			usleep(dts);
3387 			pmove(shift+1, 0);		/* move 1 for MotionNotify */
3388 			usleep(dts);
3389 			pmove(shift+1, dpy_y-2);	/* go to height-2 for extra pixel (slave y now == 0?) */
3390 			usleep(dts);
3391 			pmove(shift,   dpy_y-2);	/* move 1 for MotionNotify */
3392 			usleep(dts);
3393 			pmove(shift, 1);		/* go to 1 to be sure slave y == 0 */
3394 			usleep(dts);
3395 			pmove(shift+1, 1);		/* move 1 for MotionNotify */
3396 		} else if (!strcmp(dir, "down")) {
3397 			pmove(shift,   dpy_y-3);	/* Approach bottom edge in 3 moves.  1st move */
3398 			usleep(dts);
3399 			pmove(shift,   dpy_y-2);	/* 2nd move */
3400 			usleep(dts);
3401 			pmove(shift,   dpy_y-1);	/* 3rd move */
3402 			usleep(dts);
3403 			pmove(shift+1, dpy_y-1);	/* move 1 for MotionNotify */
3404 			usleep(dts);
3405 			pmove(shift+1, 1);		/* go to 1 for extra pixel (slave y now == dpy_y-1?) */
3406 			usleep(dts);
3407 			pmove(shift, 1);		/* move 1 for MotionNotify */
3408 			usleep(dts);
3409 			pmove(shift,   dpy_y-2);	/* go to dpy_y-2 to be sure slave y == dpy_y-1 */
3410 			usleep(dts);
3411 			pmove(shift+1, dpy_y-2);	/* move 1 for MotionNotify */
3412 		} else if (!strcmp(dir, "left")) {
3413 			pmove(2, shift);		/* Approach left edge in 3 moves.  1st move */
3414 			usleep(dts);
3415 			pmove(1, shift);		/* 2nd move */
3416 			usleep(dts);
3417 			pmove(0, shift);		/* 3rd move */
3418 			usleep(dts);
3419 			pmove(0, shift+1);		/* move 1 for MotionNotify */
3420 			usleep(dts);
3421 			pmove(dpy_x-2, shift+1);	/* go to width-2 for extra pixel (slave x now == 0?) */
3422 			usleep(dts);
3423 			pmove(dpy_x-2, shift);		/* move 1 for MotionNotify */
3424 			usleep(dts);
3425 			pmove(1, shift);		/* go to 1 to be sure slave x == 0 */
3426 			usleep(dts);
3427 			pmove(1, shift+1);		/* move 1 for MotionNotify */
3428 		} else if (!strcmp(dir, "right")) {
3429 			pmove(dpy_x-3, shift);		/* Approach right edge in 3 moves.  1st move */
3430 			usleep(dts);
3431 			pmove(dpy_x-2, shift);		/* 2nd move */
3432 			usleep(dts);
3433 			pmove(dpy_x-1, shift);		/* 3rd move */
3434 			usleep(dts);
3435 			pmove(dpy_x-1, shift+1);	/* move 1 for MotionNotify */
3436 			usleep(dts);
3437 			pmove(1, shift+1);		/* go to 1 to extra pixel (slave x now == dpy_x-1?) */
3438 			usleep(dts);
3439 			pmove(1, shift);		/* move 1 for MotionNotify */
3440 			usleep(dts);
3441 			pmove(dpy_x-2, shift);		/* go to dpy_x-2 to be sure slave x == dpy_x-1 */
3442 			usleep(dts);
3443 			pmove(dpy_x-2, shift+1);	/* move 1 for MotionNotify */
3444 		}
3445 	}
3446 
3447 	usleep(dt);
3448 	pmove(final_x, final_y);
3449 	usleep(dt);
3450 
3451 	if (extra_x >= 0 && extra_y >= 0) {
3452 		pmove(extra_x, extra_y);
3453 		usleep(dt);
3454 	}
3455 
3456 	strcpy(_bcx_res, "DONE");
3457 
3458 	if (grab_check) {
3459 		char st[64];
3460 
3461 		usleep(3*dt);
3462 		grab_state(&pg2, &kg2);
3463 
3464 		if (!strcmp(flip, "M2S")) {
3465 			if (pg2 != 1 || kg2 != 1) {
3466 				rfbLog("bcx_xattach: M2S fini grab state incorrect:  %d,%d\n", pg2, kg2);
3467 				usleep(2*dt);
3468 				grab_state(&pg2, &kg2);
3469 				rfbLog("bcx_xattach: slept and retried, grab is now: %d,%d\n", pg2, kg2);
3470 			}
3471 		} else if (!strcmp(flip, "S2M")) {
3472 			if (pg2 != 0 || kg2 != 0) {
3473 				rfbLog("bcx_xattach: S2M fini grab state incorrect:  %d,%d\n", pg2, kg2);
3474 				usleep(2*dt);
3475 				grab_state(&pg2, &kg2);
3476 				rfbLog("bcx_xattach: slept and retried, grab is now: %d,%d\n", pg2, kg2);
3477 			}
3478 		}
3479 
3480 		sprintf(st, ":%d,%d-%d,%d", pg1, kg1, pg2, kg2);
3481 
3482 		if (getenv("GRAB_CHECK_LOOP")) {
3483 			int i, n = atoi(getenv("GRAB_CHECK_LOOP"));
3484 			rfbLog("grab st: %s\n", st);
3485 			for (i=0; i < n; i++) {
3486 				usleep(dt);
3487 				grab_state(&pg2, &kg2);
3488 				sprintf(st, ":%d,%d-%d,%d", pg1, kg1, pg2, kg2);
3489 				rfbLog("grab st: %s\n", st);
3490 			}
3491 		}
3492 
3493 		if (!strcmp(flip, "M2S")) {
3494 			if (pg1 == 0 && kg1 == 0 && pg2 == 1 && kg2 == 1) {
3495 				strcat(_bcx_res, ",GRAB_OK");
3496 			} else {
3497 				rfbLog("bcx_xattach: M2S grab state incorrect: %d,%d -> %d,%d\n", pg1, kg1, pg2, kg2);
3498 				strcat(_bcx_res, ",GRAB_FAIL");
3499 				if (pg2 == 1 && kg2 == 1) {
3500 					strcat(_bcx_res, "_INIT");
3501 				} else if (pg1 == 0 && kg1 == 0) {
3502 					strcat(_bcx_res, "_FINAL");
3503 				}
3504 				strcat(_bcx_res, st);
3505 			}
3506 		} else if (!strcmp(flip, "S2M")) {
3507 			if (pg1 == 1 && kg1 == 1 && pg2 == 0 && kg2 == 0) {
3508 				strcat(_bcx_res, ",GRAB_OK");
3509 			} else {
3510 				rfbLog("bcx_xattach: S2M grab state incorrect: %d,%d -> %d,%d\n", pg1, kg1, pg2, kg2);
3511 				strcat(_bcx_res, ",GRAB_FAIL");
3512 				if (pg2 == 0 && kg2 == 0) {
3513 					strcat(_bcx_res, "_INIT");
3514 				} else if (pg1 == 1 && kg1 == 1) {
3515 					strcat(_bcx_res, "_FINAL");
3516 				}
3517 				strcat(_bcx_res, st);
3518 			}
3519 		}
3520 	}
3521 	return strdup(_bcx_res);
3522 }
3523 
set_xprop(char * prop,Window win,char * value)3524 int set_xprop(char *prop, Window win, char *value) {
3525 	int rc = -1;
3526 #if !NO_X11
3527 	Atom aprop;
3528 
3529 	RAWFB_RET(rc)
3530 
3531 	if (!prop || !value) {
3532 		return rc;
3533 	}
3534 	if (win == None) {
3535 		win = rootwin;
3536 	}
3537 	aprop = XInternAtom(dpy, prop, False);
3538 	if (aprop == None) {
3539 		return rc;
3540 	}
3541 	rc = XChangeProperty(dpy, win, aprop, XA_STRING, 8,
3542 	    PropModeReplace, (unsigned char *)value, strlen(value));
3543 	return rc;
3544 #else
3545 	RAWFB_RET(rc)
3546 	if (!prop || !win || !value) {}
3547 	return rc;
3548 #endif	/* NO_X11 */
3549 }
3550 
get_xprop(char * prop,Window win)3551 char *get_xprop(char *prop, Window win) {
3552 #if NO_X11
3553 	RAWFB_RET(NULL)
3554 	if (!prop || !win) {}
3555 	return NULL;
3556 #else
3557 	Atom type, aprop;
3558 	int format, slen, dlen;
3559 	unsigned long nitems = 0, bytes_after = 0;
3560 	unsigned char* data = NULL;
3561 	char get_str[VNC_CONNECT_MAX+1];
3562 
3563 	RAWFB_RET(NULL)
3564 
3565 	if (prop == NULL || !strcmp(prop, "")) {
3566 		return NULL;
3567 	}
3568 	if (win == None) {
3569 		win = rootwin;
3570 	}
3571 	aprop = XInternAtom(dpy, prop, True);
3572 	if (aprop == None) {
3573 		return NULL;
3574 	}
3575 
3576 	get_str[0] = '\0';
3577 	slen = 0;
3578 
3579 	/* read the property value into get_str: */
3580 	do {
3581 		if (XGetWindowProperty(dpy, win, aprop, nitems/4,
3582 		    VNC_CONNECT_MAX/16, False, AnyPropertyType, &type,
3583 		    &format, &nitems, &bytes_after, &data) == Success) {
3584 
3585 			dlen = nitems * (format/8);
3586 			if (slen + dlen > VNC_CONNECT_MAX) {
3587 				/* too big */
3588 				rfbLog("get_xprop: warning: truncating large '%s'"
3589 				   " string > %d bytes.\n", prop, VNC_CONNECT_MAX);
3590 				XFree_wr(data);
3591 				break;
3592 			}
3593 			memcpy(get_str+slen, data, dlen);
3594 			slen += dlen;
3595 			get_str[slen] = '\0';
3596 			XFree_wr(data);
3597 		}
3598 	} while (bytes_after > 0);
3599 
3600 	get_str[VNC_CONNECT_MAX] = '\0';
3601 	rfbLog("get_prop: read: '%s' = '%s'\n", prop, get_str);
3602 
3603 	return strdup(get_str);
3604 #endif	/* NO_X11 */
3605 }
3606 
3607 static char _win_fmt[1000];
3608 
win_fmt(Window win,XWindowAttributes a)3609 static char *win_fmt(Window win, XWindowAttributes a) {
3610 	memset(_win_fmt, 0, sizeof(_win_fmt));
3611 	sprintf(_win_fmt, "0x%lx:%dx%dx%d+%d+%d-map:%d-bw:%d-cl:%d-vis:%d-bs:%d/%d",
3612 	    win, a.width, a.height, a.depth, a.x, a.y, a.map_state, a.border_width, a.class,
3613 	    (int) ((a.visual)->visualid), a.backing_store, a.save_under);
3614 	return _win_fmt;
3615 }
3616 
wininfo(Window win,int show_children)3617 char *wininfo(Window win, int show_children) {
3618 #if NO_X11
3619 	RAWFB_RET(NULL)
3620 	if (!win || !show_children) {}
3621 	return NULL;
3622 #else
3623 	XWindowAttributes attr;
3624 	int n, size = X11VNC_REMOTE_MAX;
3625 	char get_str[X11VNC_REMOTE_MAX+1];
3626 	unsigned int nchildren;
3627 	Window rr, pr, *children;
3628 
3629 	RAWFB_RET(NULL)
3630 
3631 	if (win == None) {
3632 		return strdup("None");
3633 	}
3634 
3635 	X_LOCK;
3636 	if (!valid_window(win, &attr, 1)) {
3637 		X_UNLOCK;
3638 		return strdup("Invalid");
3639 	}
3640 	get_str[0] = '\0';
3641 
3642 	if (show_children) {
3643 		XQueryTree_wr(dpy, win, &rr, &pr, &children, &nchildren);
3644 	} else {
3645 		nchildren = 1;
3646 		children = (Window *) calloc(2 * sizeof(Window), 1);
3647 		children[0] = win;
3648 	}
3649 	for (n=0; n < (int) nchildren; n++) {
3650 		char tmp[32];
3651 		char *str = "Invalid";
3652 		Window w = children[n];
3653 		if (valid_window(w, &attr, 1)) {
3654 			if (!show_children) {
3655 				str = win_fmt(w, attr);
3656 			} else {
3657 				sprintf(tmp, "0x%lx", w);
3658 				str = tmp;
3659 			}
3660 		}
3661 		if ((int) (strlen(get_str) + 1 + strlen(str)) >= size) {
3662 			break;
3663 		}
3664 		if (n > 0) {
3665 			strcat(get_str, ",");
3666 		}
3667 		strcat(get_str, str);
3668 	}
3669 	get_str[size] = '\0';
3670 	if (!show_children) {
3671 		free(children);
3672 	} else if (nchildren) {
3673 		XFree_wr(children);
3674 	}
3675 	rfbLog("wininfo computed: %s\n", get_str);
3676 	X_UNLOCK;
3677 
3678 	return strdup(get_str);
3679 #endif	/* NO_X11 */
3680 }
3681 
3682 /*
3683  * check if client_connect has been set, if so make the reverse connections.
3684  */
send_client_connect(void)3685 static void send_client_connect(void) {
3686 	if (client_connect != NULL) {
3687 		char *str = client_connect;
3688 		if (strstr(str, "cmd=") == str || strstr(str, "qry=") == str) {
3689 			process_remote_cmd(client_connect, 0);
3690 		} else if (strstr(str, "ans=") == str
3691 		    || strstr(str, "aro=") == str) {
3692 			;
3693 		} else if (strstr(str, "ack=") == str) {
3694 			;
3695 		} else {
3696 			reverse_connect(client_connect);
3697 		}
3698 		free(client_connect);
3699 		client_connect = NULL;
3700 	}
3701 }
3702 
3703 /*
3704  * monitor the various input methods
3705  */
check_connect_inputs(void)3706 void check_connect_inputs(void) {
3707 
3708 	if (unixpw_in_progress) return;
3709 
3710 	/* flush any already set: */
3711 	send_client_connect();
3712 
3713 	/* connect file: */
3714 	if (client_connect_file != NULL) {
3715 		check_connect_file(client_connect_file);
3716 	}
3717 	send_client_connect();
3718 
3719 	/* VNC_CONNECT property (vncconnect program) */
3720 	if (vnc_connect && *vnc_connect_str != '\0') {
3721 		client_connect = strdup(vnc_connect_str);
3722 		vnc_connect_str[0] = '\0';
3723 	}
3724 	send_client_connect();
3725 
3726 	/* X11VNC_REMOTE property */
3727 	if (vnc_connect && *x11vnc_remote_str != '\0') {
3728 		client_connect = strdup(x11vnc_remote_str);
3729 		x11vnc_remote_str[0] = '\0';
3730 	}
3731 	send_client_connect();
3732 }
3733 
check_gui_inputs(void)3734 void check_gui_inputs(void) {
3735 	int i, gnmax = 0, n = 0, nfds;
3736 	int socks[ICON_MODE_SOCKS];
3737 	fd_set fds;
3738 	struct timeval tv;
3739 	char buf[X11VNC_REMOTE_MAX+1];
3740 	ssize_t nbytes;
3741 
3742 	if (unixpw_in_progress) return;
3743 
3744 	for (i=0; i<ICON_MODE_SOCKS; i++) {
3745 		if (icon_mode_socks[i] >= 0) {
3746 			socks[n++] = i;
3747 			if (icon_mode_socks[i] > gnmax) {
3748 				gnmax = icon_mode_socks[i];
3749 			}
3750 		}
3751 	}
3752 
3753 	if (! n) {
3754 		return;
3755 	}
3756 
3757 	FD_ZERO(&fds);
3758 	for (i=0; i<n; i++) {
3759 		FD_SET(icon_mode_socks[socks[i]], &fds);
3760 	}
3761 	tv.tv_sec = 0;
3762 	tv.tv_usec = 0;
3763 
3764 	nfds = select(gnmax+1, &fds, NULL, NULL, &tv);
3765 	if (nfds <= 0) {
3766 		return;
3767 	}
3768 
3769 	for (i=0; i<n; i++) {
3770 		int k, fd = icon_mode_socks[socks[i]];
3771 		char *p;
3772 		char **list;
3773 		int lind;
3774 
3775 		if (! FD_ISSET(fd, &fds)) {
3776 			continue;
3777 		}
3778 		for (k=0; k<=X11VNC_REMOTE_MAX; k++) {
3779 			buf[k] = '\0';
3780 		}
3781 		nbytes = read(fd, buf, X11VNC_REMOTE_MAX);
3782 		if (nbytes <= 0) {
3783 			close(fd);
3784 			icon_mode_socks[socks[i]] = -1;
3785 			continue;
3786 		}
3787 
3788 		list = (char **) calloc((strlen(buf)+2) * sizeof(char *), 1);
3789 
3790 		lind = 0;
3791 		p = strtok(buf, "\r\n");
3792 		while (p) {
3793 			list[lind++] = strdup(p);
3794 			p = strtok(NULL, "\r\n");
3795 		}
3796 
3797 		lind = 0;
3798 		while (list[lind] != NULL) {
3799 			p = list[lind++];
3800 			if (strstr(p, "cmd=") == p ||
3801 			    strstr(p, "qry=") == p) {
3802 				char *str = process_remote_cmd(p, 1);
3803 				if (! str) {
3804 					str = strdup("");
3805 				}
3806 				nbytes = write(fd, str, strlen(str));
3807 				write(fd, "\n", 1);
3808 				free(str);
3809 				if (nbytes < 0) {
3810 					close(fd);
3811 					icon_mode_socks[socks[i]] = -1;
3812 					break;
3813 				}
3814 			}
3815 		}
3816 
3817 		lind = 0;
3818 		while (list[lind] != NULL) {
3819 			p = list[lind++];
3820 			if (p) free(p);
3821 		}
3822 		free(list);
3823 	}
3824 }
3825 
create_new_client(int sock,int start_thread)3826 rfbClientPtr create_new_client(int sock, int start_thread) {
3827 	rfbClientPtr cl;
3828 
3829 	if (!screen) {
3830 		return NULL;
3831 	}
3832 
3833 	cl = rfbNewClient(screen, sock);
3834 
3835 	if (cl == NULL) {
3836 		return NULL;
3837 	}
3838 	if (use_threads) {
3839 		cl->onHold = FALSE;
3840 		if (start_thread) {
3841 			rfbStartOnHoldClient(cl);
3842 		}
3843 	}
3844 	return cl;
3845 }
3846 
3847 static int turn_off_truecolor = 0;
3848 
turn_off_truecolor_ad(rfbClientPtr client)3849 static void turn_off_truecolor_ad(rfbClientPtr client) {
3850 	if (client) {}
3851 	if (turn_off_truecolor) {
3852 		rfbLog("turning off truecolor advertising.\n");
3853 		/* mutex */
3854 		screen->serverFormat.trueColour = FALSE;
3855 		screen->displayHook = NULL;
3856 		screen->serverFormat.redShift   = 0;
3857 		screen->serverFormat.greenShift = 0;
3858 		screen->serverFormat.blueShift  = 0;
3859 		screen->serverFormat.redMax     = 0;
3860 		screen->serverFormat.greenMax   = 0;
3861 		screen->serverFormat.blueMax    = 0;
3862 		turn_off_truecolor = 0;
3863 	}
3864 }
3865 
3866 /*
3867  * some overrides for the local console text chat.
3868  * could be useful in general for local helpers.
3869  */
3870 
password_check_chat_helper(rfbClientPtr cl,const char * response,int len)3871 rfbBool password_check_chat_helper(rfbClientPtr cl, const char* response, int len) {
3872 	if (response || len) {}
3873 	if (cl != chat_window_client) {
3874 		rfbLog("invalid client during chat_helper login\n");
3875 		return FALSE;
3876 	} else {
3877 		if (!cl->host) {
3878 			rfbLog("empty cl->host during chat_helper login\n");
3879 			return FALSE;
3880 		}
3881 		if (strcmp(cl->host, "127.0.0.1")) {
3882 			rfbLog("invalid cl->host during chat_helper login: %s\n", cl->host);
3883 			return FALSE;
3884 		}
3885 		rfbLog("chat_helper login accepted\n");
3886 		return TRUE;
3887 	}
3888 }
3889 
new_client_chat_helper(rfbClientPtr client)3890 enum rfbNewClientAction new_client_chat_helper(rfbClientPtr client) {
3891 	if (client) {}
3892 	client->clientGoneHook = client_gone_chat_helper;
3893 	rfbLog("new chat helper\n");
3894 	return(RFB_CLIENT_ACCEPT);
3895 }
3896 
client_gone_chat_helper(rfbClientPtr client)3897 void client_gone_chat_helper(rfbClientPtr client) {
3898 	if (client) {}
3899 	rfbLog("finished chat helper\n");
3900 	chat_window_client = NULL;
3901 }
3902 
client_set_net(rfbClientPtr client)3903 void client_set_net(rfbClientPtr client) {
3904 	ClientData *cd;
3905 	if (client == NULL) {
3906 		return;
3907 	}
3908 	cd = (ClientData *) client->clientData;
3909 	if (cd == NULL) {
3910 		return;
3911 	}
3912 	if (cd->client_port < 0) {
3913 		double dt = dnow();
3914 		cd->client_port = get_remote_port(client->sock);
3915 		cd->server_port = get_local_port(client->sock);
3916 		cd->server_ip   = get_local_host(client->sock);
3917 		cd->hostname = ip2host(client->host);
3918 		rfbLog("client_set_net: %s  %.4f\n", client->host, dnow() - dt);
3919 	}
3920 }
3921 /*
3922  * libvncserver callback for when a new client connects
3923  */
new_client(rfbClientPtr client)3924 enum rfbNewClientAction new_client(rfbClientPtr client) {
3925 	ClientData *cd;
3926 
3927 	CLIENT_LOCK;
3928 
3929 	last_event = last_input = time(NULL);
3930 
3931 	latest_client = client;
3932 
3933 	if (inetd) {
3934 		/*
3935 		 * Set this so we exit as soon as connection closes,
3936 		 * otherwise client_gone is only called after RFB_CLIENT_ACCEPT
3937 		 */
3938 		if (inetd_client == NULL) {
3939 			inetd_client = client;
3940 			client->clientGoneHook = client_gone;
3941 		}
3942 	}
3943 
3944 	clients_served++;
3945 
3946 	if (use_openssl || use_stunnel) {
3947 		if (! ssl_initialized) {
3948 			rfbLog("denying additional client: %s ssl not setup"
3949 			    " yet.\n", client->host);
3950 			CLIENT_UNLOCK;
3951 			return(RFB_CLIENT_REFUSE);
3952 		}
3953 	}
3954 	if (unixpw_in_progress) {
3955 		rfbLog("denying additional client: %s during -unixpw login.\n",
3956 		     client->host);
3957 		CLIENT_UNLOCK;
3958 		return(RFB_CLIENT_REFUSE);
3959 	}
3960 	if (connect_once) {
3961 		if (screen->dontDisconnect && screen->neverShared) {
3962 			if (! shared && accepted_client) {
3963 				rfbLog("denying additional client: %s:%d\n",
3964 				     client->host, get_remote_port(client->sock));
3965 				CLIENT_UNLOCK;
3966 				return(RFB_CLIENT_REFUSE);
3967 			}
3968 		}
3969 	}
3970 
3971 	if (ipv6_client_ip_str != NULL) {
3972 		rfbLog("renaming client->host from '%s' to '%s'\n",
3973 		    client->host ? client->host : "", ipv6_client_ip_str);
3974 		if (client->host) {
3975 			free(client->host);
3976 		}
3977 		client->host = strdup(ipv6_client_ip_str);
3978 	}
3979 
3980 	if (! check_access(client->host)) {
3981 		rfbLog("denying client: %s does not match %s\n", client->host,
3982 		    allow_list ? allow_list : "(null)" );
3983 		CLIENT_UNLOCK;
3984 		return(RFB_CLIENT_REFUSE);
3985 	}
3986 
3987         if(use_multipointer && xi2_device_creation_in_progress) {
3988             rfbLog("denying additional client: %s during MD creation.\n", client->host);
3989 	    CLIENT_UNLOCK;
3990             return(RFB_CLIENT_REFUSE);
3991         }
3992 
3993 	client->clientData = (void *) calloc(sizeof(ClientData), 1);
3994 	cd = (ClientData *) client->clientData;
3995 
3996 	/* see client_set_net() we delay the DNS lookups during handshake */
3997 	cd->client_port = -1;
3998 	cd->username = strdup("");
3999 	cd->unixname = strdup("");
4000 	cd->cursor_x_saved = cd->cursor_y_saved = -1;
4001 
4002 	cd->input[0] = '-';
4003 	cd->login_viewonly = -1;
4004 	cd->login_time = time(NULL);
4005 	cd->ssl_helper_pid = 0;
4006 
4007 	if (use_openssl && openssl_last_helper_pid) {
4008 		cd->ssl_helper_pid = openssl_last_helper_pid;
4009 		openssl_last_helper_pid = 0;
4010 	}
4011 
4012 	if (! accept_client(client)) {
4013 		rfbLog("denying client: %s local user rejected connection.\n",
4014 		    client->host);
4015 		rfbLog("denying client: accept_cmd=\"%s\"\n",
4016 		    accept_cmd ? accept_cmd : "(null)" );
4017 
4018 		free_client_data(client);
4019 
4020 		CLIENT_UNLOCK;
4021 		return(RFB_CLIENT_REFUSE);
4022 	}
4023 
4024 	/* We will RFB_CLIENT_ACCEPT or RFB_CLIENT_ON_HOLD from here on. */
4025 
4026 	if (passwdfile) {
4027 		if (strstr(passwdfile, "read:") == passwdfile ||
4028 		    strstr(passwdfile, "cmd:") == passwdfile) {
4029 			if (read_passwds(passwdfile)) {
4030 				install_passwds();
4031 			} else {
4032 				rfbLog("problem reading: %s\n", passwdfile);
4033 				clean_up_exit(1);
4034 			}
4035 		} else if (strstr(passwdfile, "custom:") == passwdfile) {
4036 			if (screen) {
4037 				/* mutex */
4038 				screen->passwordCheck = custom_passwd_check;
4039 			}
4040 		}
4041 	}
4042 
4043 	cd->uid = clients_served;
4044 
4045         /*
4046 	  create new XInput2 master device and add it it to client
4047 	*/
4048         if(use_multipointer)
4049           {
4050 	    char tmp[256];
4051             snprintf(tmp, sizeof tmp, "x11vnc %s", client->host);
4052 
4053             xi2_device_creation_in_progress = 1;
4054 
4055 	    if((cd->ptr_id = createMD(dpy, tmp)) < 0) {
4056 	      rfbLog("ERROR creating XInput2 MD for client %s, denying client.\n", client->host);
4057 	      free_client_data(client);
4058 	      xi2_device_creation_in_progress = 0;
4059 	      CLIENT_UNLOCK;
4060 	      return(RFB_CLIENT_REFUSE);
4061 	    }
4062 
4063             cd->kbd_id = getPairedMD(dpy, cd->ptr_id);
4064 
4065             rfbLog("Created XInput2 MD %i %i for client %s.\n", cd->ptr_id, cd->kbd_id, client->host);
4066 
4067             xi2_device_creation_in_progress = 0;
4068 
4069             snprintf(tmp, sizeof tmp, "%i", cd->uid);
4070 	    cd->cursor = setClientCursor(dpy, cd->ptr_id, 0.4*(cd->ptr_id%3), 0.2*(cd->ptr_id%5), 1*(cd->ptr_id%2), tmp);
4071 	    if(!cd->cursor)
4072               rfbLog("Setting cursor for client %s failed.\n", client->host);
4073 
4074 	    cd->cursor_region = sraRgnCreate();
4075           }
4076 
4077 	client->clientGoneHook = client_gone;
4078 
4079 	if (client_count) {
4080 		speeds_net_rate_measured = 0;
4081 		speeds_net_latency_measured = 0;
4082 	}
4083 	client_count++;
4084 
4085 	last_keyboard_input = last_pointer_input = time(NULL);
4086 
4087 	if (no_autorepeat && client_count == 1 && ! view_only) {
4088 		/*
4089 		 * first client, turn off X server autorepeat
4090 		 * XXX handle dynamic change of view_only and per-client.
4091 		 */
4092 		autorepeat(0, 0);
4093 	}
4094 #ifdef MACOSX
4095 	if (macosx_console && client_count == 1) {
4096 		macosxCG_refresh_callback_on();
4097 	}
4098 #endif
4099 	if (use_solid_bg && client_count == 1) {
4100 		solid_bg(0);
4101 	}
4102 
4103 	if (pad_geometry) {
4104 		install_padded_fb(pad_geometry);
4105 	}
4106 
4107 	cd->timer = last_new_client = dnow();
4108 	cd->send_cmp_rate = 0.0;
4109 	cd->send_raw_rate = 0.0;
4110 	cd->latency = 0.0;
4111 	cd->cmp_bytes_sent = 0;
4112 	cd->raw_bytes_sent = 0;
4113 
4114 	accepted_client++;
4115 	rfbLog("incr accepted_client=%d for %s:%d  sock=%d\n", accepted_client,
4116 	    client->host, get_remote_port(client->sock), client->sock);
4117 	last_client = time(NULL);
4118 
4119 	if (ncache) {
4120 		check_ncache(1, 0);
4121 	}
4122 
4123 	if (advertise_truecolor && indexed_color) {
4124 		int rs = 0, gs = 2, bs = 4;
4125 		int rm = 3, gm = 3, bm = 3;
4126 		if (bpp >= 24) {
4127 			rs = 0, gs = 8, bs = 16;
4128 			rm = 255, gm = 255, bm = 255;
4129 		} else if (bpp >= 16) {
4130 			rs = 0, gs = 5, bs = 10;
4131 			rm = 31, gm = 31, bm = 31;
4132 		}
4133 		rfbLog("advertising truecolor.\n");
4134 		if (getenv("ADVERT_BMSHIFT")) {
4135 			bm--;
4136 		}
4137 
4138 		if (use_threads) LOCK(client->updateMutex);
4139 
4140 		client->format.trueColour = TRUE;
4141 		client->format.redShift   = rs;
4142 		client->format.greenShift = gs;
4143 		client->format.blueShift  = bs;
4144 		client->format.redMax     = rm;
4145 		client->format.greenMax   = gm;
4146 		client->format.blueMax    = bm;
4147 
4148 		if (use_threads) UNLOCK(client->updateMutex);
4149 
4150 		rfbSetTranslateFunction(client);
4151 
4152 		/* mutex */
4153 		screen->serverFormat.trueColour = TRUE;
4154 		screen->serverFormat.redShift   = rs;
4155 		screen->serverFormat.greenShift = gs;
4156 		screen->serverFormat.blueShift  = bs;
4157 		screen->serverFormat.redMax     = rm;
4158 		screen->serverFormat.greenMax   = gm;
4159 		screen->serverFormat.blueMax    = bm;
4160 		screen->displayHook = turn_off_truecolor_ad;
4161 
4162 		turn_off_truecolor = 1;
4163 	}
4164 
4165 	if (unixpw) {
4166 		unixpw_in_progress = 1;
4167 		unixpw_client = client;
4168 		unixpw_login_viewonly = 0;
4169 
4170 		unixpw_file_xfer_save = screen->permitFileTransfer;
4171 		screen->permitFileTransfer = FALSE;
4172 		unixpw_tightvnc_xfer_save = tightfilexfer;
4173 		tightfilexfer = 0;
4174 #ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER
4175 		rfbLog("rfbUnregisterTightVNCFileTransferExtension: 1\n");
4176 		rfbUnregisterTightVNCFileTransferExtension();
4177 #endif
4178 
4179 		if (client->viewOnly) {
4180 			unixpw_login_viewonly = 1;
4181 			client->viewOnly = FALSE;
4182 		}
4183 		unixpw_last_try_time = time(NULL) + 10;
4184 
4185 		unixpw_screen(1);
4186 		unixpw_keystroke(0, 0, 1);
4187 
4188 		if (!unixpw_in_rfbPE) {
4189 			rfbLog("new client: %s in non-unixpw_in_rfbPE.\n",
4190 			     client->host);
4191 		}
4192 		CLIENT_UNLOCK;
4193 		if (!use_threads) {
4194 			/* always put client on hold even if unixpw_in_rfbPE is true */
4195 			return(RFB_CLIENT_ON_HOLD);
4196 		} else {
4197 			/* unixpw threads is still in testing mode, disabled by default. See UNIXPW_THREADS */
4198 			return(RFB_CLIENT_ACCEPT);
4199 		}
4200 	}
4201 
4202 	CLIENT_UNLOCK;
4203 	return(RFB_CLIENT_ACCEPT);
4204 }
4205 
start_client_info_sock(char * host_port_cookie)4206 void start_client_info_sock(char *host_port_cookie) {
4207 	char *host = NULL, *cookie = NULL, *p;
4208 	char *str = strdup(host_port_cookie);
4209 	int i, port, sock, next = -1;
4210 	static time_t start_time[ICON_MODE_SOCKS];
4211 	time_t oldest = 0;
4212 	int db = 0;
4213 
4214 	port = -1;
4215 
4216 	for (i = 0; i < ICON_MODE_SOCKS; i++) {
4217 		if (icon_mode_socks[i] < 0) {
4218 			next = i;
4219 			break;
4220 		}
4221 		if (oldest == 0 || start_time[i] < oldest) {
4222 			next = i;
4223 			oldest = start_time[i];
4224 		}
4225 	}
4226 
4227 	p = strtok(str, ":");
4228 	i = 0;
4229 	while (p) {
4230 		if (i == 0) {
4231 			host = strdup(p);
4232 		} else if (i == 1) {
4233 			port = atoi(p);
4234 		} else if (i == 2) {
4235 			cookie = strdup(p);
4236 		}
4237 		i++;
4238 		p = strtok(NULL, ":");
4239 	}
4240 	free(str);
4241 
4242 	if (db) fprintf(stderr, "%s/%d/%s next=%d\n", host, port, cookie, next);
4243 
4244 	if (host && port && cookie) {
4245 		if (*host == '\0') {
4246 			free(host);
4247 			host = strdup("localhost");
4248 		}
4249 		sock = connect_tcp(host, port);
4250 		if (sock < 0) {
4251 			usleep(200 * 1000);
4252 			sock = connect_tcp(host, port);
4253 		}
4254 		if (sock >= 0) {
4255 			char *lst = list_clients();
4256 			icon_mode_socks[next] = sock;
4257 			start_time[next] = time(NULL);
4258 			write(sock, "COOKIE:", strlen("COOKIE:"));
4259 			write(sock, cookie, strlen(cookie));
4260 			write(sock, "\n", strlen("\n"));
4261 			write(sock, "none\n", strlen("none\n"));
4262 			write(sock, "none\n", strlen("none\n"));
4263 			write(sock, lst, strlen(lst));
4264 			write(sock, "\n", strlen("\n"));
4265 			if (db) {
4266 				fprintf(stderr, "list: %s\n", lst);
4267 			}
4268 			free(lst);
4269 			rfbLog("client_info_sock to: %s:%d\n", host, port);
4270 		} else {
4271 			rfbLog("failed client_info_sock: %s:%d\n", host, port);
4272 		}
4273 	} else {
4274 		rfbLog("malformed client_info_sock: %s\n", host_port_cookie);
4275 	}
4276 
4277 	if (host) free(host);
4278 	if (cookie) free(cookie);
4279 }
4280 
send_client_info(char * str)4281 void send_client_info(char *str) {
4282 	int i;
4283 	static char *pstr = NULL;
4284 	static int len = 128;
4285 
4286 	if (!str || strlen(str) == 0) {
4287 		return;
4288 	}
4289 
4290 	if (!pstr)  {
4291 		pstr = (char *)malloc(len);
4292 	}
4293 	if (strlen(str) + 2 > (size_t) len) {
4294 		free(pstr);
4295 		len *= 2;
4296 		pstr = (char *)malloc(len);
4297 	}
4298 	strcpy(pstr, str);
4299 	strcat(pstr, "\n");
4300 
4301 	if (icon_mode_fh) {
4302 		if (0) fprintf(icon_mode_fh, "\n");
4303 		fprintf(icon_mode_fh, "%s", pstr);
4304 		fflush(icon_mode_fh);
4305 	}
4306 
4307 	for (i=0; i<ICON_MODE_SOCKS; i++) {
4308 		int len, n, sock = icon_mode_socks[i];
4309 		char *buf = pstr;
4310 
4311 		if (sock < 0) {
4312 			continue;
4313 		}
4314 
4315 		len = strlen(pstr);
4316 		while (len > 0) {
4317 			if (0) write(sock, "\n", 1);
4318 			n = write(sock, buf, len);
4319 			if (n > 0) {
4320 				buf += n;
4321 				len -= n;
4322 				continue;
4323 			}
4324 
4325 			if (n < 0 && errno == EINTR) {
4326 				continue;
4327 			}
4328 			close(sock);
4329 			icon_mode_socks[i] = -1;
4330 			break;
4331 		}
4332 	}
4333 }
4334 
adjust_grabs(int grab,int quiet)4335 void adjust_grabs(int grab, int quiet) {
4336 	RAWFB_RET_VOID
4337 #if NO_X11
4338 	if (!grab || !quiet) {}
4339 	return;
4340 #else
4341 	/* n.b. caller decides to X_LOCK or not. */
4342 	if (grab) {
4343 		if (grab_kbd) {
4344 			if (! quiet) {
4345 				rfbLog("grabbing keyboard with XGrabKeyboard\n");
4346 			}
4347 			XGrabKeyboard(dpy, window, False, GrabModeAsync,
4348 			    GrabModeAsync, CurrentTime);
4349 		}
4350 		if (grab_ptr) {
4351 			if (! quiet) {
4352 				rfbLog("grabbing pointer with XGrabPointer\n");
4353 			}
4354 			XGrabPointer(dpy, window, False, 0, GrabModeAsync,
4355 			    GrabModeAsync, None, None, CurrentTime);
4356 		}
4357 	} else {
4358 		if (grab_kbd) {
4359 			if (! quiet) {
4360 				rfbLog("ungrabbing keyboard with XUngrabKeyboard\n");
4361 			}
4362 			XUngrabKeyboard(dpy, CurrentTime);
4363 		}
4364 		if (grab_ptr) {
4365 			if (! quiet) {
4366 				rfbLog("ungrabbing pointer with XUngrabPointer\n");
4367 			}
4368 			XUngrabPointer(dpy, CurrentTime);
4369 		}
4370 	}
4371 #endif	/* NO_X11 */
4372 }
4373 
check_new_clients(void)4374 void check_new_clients(void) {
4375 	static int last_count = -1;
4376 	rfbClientIteratorPtr iter;
4377 	rfbClientPtr cl;
4378 	int i, send_info = 0;
4379 	int run_after_accept = 0;
4380 
4381 	if (unixpw_in_progress) {
4382 		static double lping = 0.0;
4383 		if (lping < dnow() + 5) {
4384 			mark_rect_as_modified(0, 0, 1, 1, 1);
4385 			lping = dnow();
4386 		}
4387 		if (unixpw_client && unixpw_client->viewOnly) {
4388 			unixpw_login_viewonly = 1;
4389 			unixpw_client->viewOnly = FALSE;
4390 		}
4391 		if (time(NULL) > unixpw_last_try_time + 45) {
4392 			rfbLog("unixpw_deny: timed out waiting for reply.\n");
4393 			unixpw_deny();
4394 		}
4395 		return;
4396 	}
4397 
4398 	if (grab_always) {
4399 		;
4400 	} else if (grab_kbd || grab_ptr) {
4401 		static double last_force = 0.0;
4402 		if (client_count != last_count || dnow() > last_force + 0.25) {
4403 			int q = (client_count == last_count);
4404 			last_force = dnow();
4405 			X_LOCK;
4406 			if (client_count) {
4407 				adjust_grabs(1, q);
4408 			} else {
4409 				adjust_grabs(0, q);
4410 			}
4411 			X_UNLOCK;
4412 		}
4413 	}
4414 
4415 	if (last_count == -1) {
4416 		last_count = 0;
4417 	} else if (client_count == last_count) {
4418 		return;
4419 	}
4420 
4421 	if (! all_clients_initialized()) {
4422 		return;
4423 	}
4424 
4425 	if (client_count > last_count) {
4426 		if (afteraccept_cmd != NULL && afteraccept_cmd[0] != '\0') {
4427 			run_after_accept = 1;
4428 		}
4429 	}
4430 
4431 	last_count = client_count;
4432 
4433 	if (! screen) {
4434 		return;
4435 	}
4436 
4437 	if (! client_count) {
4438 		send_client_info("clients:none");
4439 		return;
4440 	}
4441 
4442 	iter = rfbGetClientIterator(screen);
4443 	while( (cl = rfbClientIteratorNext(iter)) ) {
4444 		ClientData *cd = (ClientData *) cl->clientData;
4445 		char *s;
4446 
4447 		client_set_net(cl);
4448 		if (! cd) {
4449 			continue;
4450 		}
4451 
4452 		if (cd->login_viewonly < 0) {
4453 			/* this is a general trigger to initialize things */
4454 			if (cl->viewOnly) {
4455 				cd->login_viewonly = 1;
4456 				s = allowed_input_view_only;
4457 				if (s && cd->input[0] == '-') {
4458 					cl->viewOnly = FALSE;
4459 					cd->input[0] = '\0';
4460 					strncpy(cd->input, s, CILEN);
4461 				}
4462 			} else {
4463 				cd->login_viewonly = 0;
4464 				s = allowed_input_normal;
4465 				if (s && cd->input[0] == '-') {
4466 					cd->input[0] = '\0';
4467 					strncpy(cd->input, s, CILEN);
4468 				}
4469 			}
4470 			if (run_after_accept) {
4471 				run_user_command(afteraccept_cmd, cl,
4472 				    "afteraccept", NULL, 0, NULL);
4473 			}
4474 		}
4475 	}
4476 	rfbReleaseClientIterator(iter);
4477 
4478 	if (icon_mode_fh) {
4479 		send_info++;
4480 	}
4481 	for (i = 0; i < ICON_MODE_SOCKS; i++) {
4482 		if (send_info || icon_mode_socks[i] >= 0) {
4483 			send_info++;
4484 			break;
4485 		}
4486 	}
4487 	if (send_info) {
4488 		char *str, *s = list_clients();
4489 		str = (char *) malloc(strlen("clients:") + strlen(s) + 1);
4490 		sprintf(str, "clients:%s", s);
4491 		send_client_info(str);
4492 		free(str);
4493 		free(s);
4494 	}
4495 }
4496 
4497