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 /* -- util.c -- */
34 
35 #include "x11vnc.h"
36 #include "cleanup.h"
37 #include "win_utils.h"
38 #include "unixpw.h"
39 #include "connections.h"
40 
41 struct timeval _mysleep;
42 
43 /* this is only for debugging mutexes. see util.h */
44 int hxl = 0;
45 
46 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
47 MUTEX(x11Mutex);
48 MUTEX(scrollMutex);
49 #endif
50 
51 int nfix(int i, int n);
52 int nmin(int n, int m);
53 int nmax(int n, int m);
54 int nabs(int n);
55 double dabs(double x);
56 void lowercase(char *str);
57 void uppercase(char *str);
58 char *lblanks(char *str);
59 void strzero(char *str);
60 int scan_hexdec(char *str, unsigned long *num);
61 int parse_geom(char *str, int *wp, int *hp, int *xp, int *yp, int W, int H);
62 void set_env(char *name, char *value);
63 char *bitprint(unsigned int st, int nbits);
64 char *get_user_name(void);
65 char *get_home_dir(void);
66 char *get_shell(void);
67 char *this_host(void);
68 
69 int match_str_list(char *str, char **list);
70 char **create_str_list(char *cslist);
71 
72 double dtime(double *);
73 double dtime0(double *);
74 double dnow(void);
75 double dnowx(void);
76 double rnow(void);
77 double rfac(void);
78 
79 int rfbPE(long usec);
80 void rfbCFD(long usec);
81 
82 double rect_overlap(int x1, int y1, int x2, int y2, int X1, int Y1,
83     int X2, int Y2);
84 
85 char *choose_title(char *display);
86 
87 
88 /*
89  * routine to keep 0 <= i < n
90  */
nfix(int i,int n)91 int nfix(int i, int n) {
92 	if (i < 0) {
93 		i = 0;
94 	} else if (i >= n) {
95 		i = n - 1;
96 	}
97 	return i;
98 }
99 
nmin(int n,int m)100 int nmin(int n, int m) {
101 	if (n < m) {
102 		return n;
103 	} else {
104 		return m;
105 	}
106 }
107 
nmax(int n,int m)108 int nmax(int n, int m) {
109 	if (n > m) {
110 		return n;
111 	} else {
112 		return m;
113 	}
114 }
115 
nabs(int n)116 int nabs(int n) {
117 	if (n < 0) {
118 		return -n;
119 	} else {
120 		return n;
121 	}
122 }
123 
dabs(double x)124 double dabs(double x) {
125 	if (x < 0.0) {
126 		return -x;
127 	} else {
128 		return x;
129 	}
130 }
131 
lowercase(char * str)132 void lowercase(char *str) {
133 	char *p;
134 	if (str == NULL) {
135 		return;
136 	}
137 	p = str;
138 	while (*p != '\0') {
139 		*p = tolower((unsigned char) (*p));
140 		p++;
141 	}
142 }
143 
uppercase(char * str)144 void uppercase(char *str) {
145 	char *p;
146 	if (str == NULL) {
147 		return;
148 	}
149 	p = str;
150 	while (*p != '\0') {
151 		*p = toupper((unsigned char) (*p));
152 		p++;
153 	}
154 }
155 
lblanks(char * str)156 char *lblanks(char *str) {
157 	char *p = str;
158 	while (*p != '\0') {
159 		if (! isspace((unsigned char) (*p))) {
160 			break;
161 		}
162 		p++;
163 	}
164 	return p;
165 }
166 
strzero(char * str)167 void strzero(char *str) {
168 	char *p = str;
169 	if (p != NULL) {
170 		while (*p != '\0') {
171 			*p = '\0';
172 			p++;
173 		}
174 	}
175 }
176 
is_decimal(char * str)177 int is_decimal(char *str) {
178 	char *p = str;
179 	if (p != NULL) {
180 		int first = 1;
181 		while (*p != '\0') {
182 			if (first && *p == '-') {
183 				;
184 			} else if (isdigit((int) *p)) {
185 				;
186 			} else {
187 				return 0;
188 			}
189 			first = 0;
190 			p++;
191 		}
192 		return 1;
193 	}
194 	return 0;
195 }
196 
scan_hexdec(char * str,unsigned long * num)197 int scan_hexdec(char *str, unsigned long *num) {
198 	if (sscanf(str, "0x%lx", num) != 1) {
199 		if (sscanf(str, "%lu", num) != 1) {
200 			return 0;
201 		}
202 	}
203 	return 1;
204 }
205 
parse_geom(char * str,int * wp,int * hp,int * xp,int * yp,int W,int H)206 int parse_geom(char *str, int *wp, int *hp, int *xp, int *yp, int W, int H) {
207 	int w, h, x, y;
208 	if (! str) {
209 		return 0;
210 	}
211 	/* handle +/-x and +/-y */
212 	if (sscanf(str, "%dx%d+%d+%d", &w, &h, &x, &y) == 4) {
213 		;
214 	} else if (sscanf(str, "%dx%d-%d+%d", &w, &h, &x, &y) == 4) {
215 		w = nabs(w);
216 		x = W - x - w;
217 	} else if (sscanf(str, "%dx%d+%d-%d", &w, &h, &x, &y) == 4) {
218 		h = nabs(h);
219 		y = H - y - h;
220 	} else if (sscanf(str, "%dx%d-%d-%d", &w, &h, &x, &y) == 4) {
221 		w = nabs(w);
222 		h = nabs(h);
223 		x = W - x - w;
224 		y = H - y - h;
225 	} else {
226 		return 0;
227 	}
228 	*wp = w;
229 	*hp = h;
230 	*xp = x;
231 	*yp = y;
232 	return 1;
233 }
234 
set_env(char * name,char * value)235 void set_env(char *name, char *value) {
236 	char *str;
237 	if (! name) {
238 		return;
239 	}
240 	if (! value) {
241 		value = "";
242 	}
243 	str = (char *) malloc(strlen(name) + 1 + strlen(value) + 1);
244 	sprintf(str, "%s=%s", name, value);
245 	putenv(str);
246 }
247 
bitprint(unsigned int st,int nbits)248 char *bitprint(unsigned int st, int nbits) {
249 	static char str[33];
250 	int i, mask;
251 	if (nbits > 32) {
252 		nbits = 32;
253 	}
254 	for (i=0; i<nbits; i++) {
255 		str[i] = '0';
256 	}
257 	str[nbits] = '\0';
258 	mask = 1;
259 	for (i=nbits-1; i>=0; i--) {
260 		if (st & mask) {
261 			str[i] = '1';
262 		}
263 		mask = mask << 1;
264 	}
265 	return str;	/* take care to use or copy immediately */
266 }
267 
get_user_name(void)268 char *get_user_name(void) {
269 	char *user = NULL;
270 
271 	user = getenv("USER");
272 	if (user == NULL) {
273 		user = getenv("LOGNAME");
274 	}
275 
276 #if LIBVNCSERVER_HAVE_PWD_H
277 	if (user == NULL) {
278 		struct passwd *pw = getpwuid(getuid());
279 		if (pw) {
280 			user = pw->pw_name;
281 		}
282 	}
283 #endif
284 
285 	if (user) {
286 		return(strdup(user));
287 	} else {
288 		return(strdup("unknown-user"));
289 	}
290 }
291 
get_home_dir(void)292 char *get_home_dir(void) {
293 	char *home = NULL;
294 
295 	home = getenv("HOME");
296 
297 #if LIBVNCSERVER_HAVE_PWD_H
298 	if (home == NULL) {
299 		struct passwd *pw = getpwuid(getuid());
300 		if (pw) {
301 			home = pw->pw_dir;
302 		}
303 	}
304 #endif
305 
306 	if (home) {
307 		return(strdup(home));
308 	} else {
309 		return(strdup("/"));
310 	}
311 }
312 
get_shell(void)313 char *get_shell(void) {
314 	char *shell = NULL;
315 
316 	shell = getenv("SHELL");
317 
318 #if LIBVNCSERVER_HAVE_PWD_H
319 	if (shell == NULL) {
320 		struct passwd *pw = getpwuid(getuid());
321 		if (pw) {
322 			shell = pw->pw_shell;
323 		}
324 	}
325 #endif
326 
327 	if (shell) {
328 		return(strdup(shell));
329 	} else {
330 		return(strdup("/bin/sh"));
331 	}
332 }
333 
334 /*
335  * utility to get the current host name
336  */
this_host(void)337 char *this_host(void) {
338 	char host[MAXN];
339 #if LIBVNCSERVER_HAVE_GETHOSTNAME
340 	if (gethostname(host, MAXN) == 0) {
341 		host[MAXN-1] = '\0';
342 		return strdup(host);
343 	} else if (UT.nodename) {
344 		return strdup(UT.nodename);
345 	}
346 #endif
347 	return NULL;
348 }
349 
match_str_list(char * str,char ** list)350 int match_str_list(char *str, char **list) {
351 	int i = 0, matched = 0;
352 
353 	if (! str || ! list) {
354 		return 0;
355 	}
356 	while (list[i] != NULL) {
357 		if (!strcmp(list[i], "*")) {
358 			matched = 1;
359 			break;
360 		} else if (strstr(str, list[i])) {
361 			matched = 1;
362 			break;
363 		}
364 		i++;
365 	}
366 	return matched;
367 }
368 
create_str_list(char * cslist)369 char **create_str_list(char *cslist) {
370 	int i, n;
371 	char *p, *str;
372 	char **list = NULL;
373 
374 	if (! cslist) {
375 		return NULL;
376 	}
377 
378 	str = strdup(cslist);
379 	n = 1;
380 	p = str;
381 	while (*p != '\0') {
382 		if (*p == ',') {
383 			n++;
384 		}
385 		p++;
386 	}
387 
388 	/* the extra last one holds NULL */
389 	list = (char **) calloc((n+1)*sizeof(char *), 1);
390 
391 	p = strtok(str, ",");
392 	i = 0;
393 	while (p && i < n) {
394 		list[i++] = strdup(p);
395 		p = strtok(NULL, ",");
396 	}
397 	free(str);
398 
399 	return list;
400 }
401 
402 /*
403  * simple function for measuring sub-second time differences, using
404  * a double to hold the value.
405  */
dtime(double * t_old)406 double dtime(double *t_old) {
407 	/*
408 	 * usage: call with 0.0 to initialize, subsequent calls give
409 	 * the time difference since last call.
410 	 */
411 	double t_now, dt;
412 	struct timeval now;
413 
414 	gettimeofday(&now, NULL);
415 	t_now = now.tv_sec + ( (double) now.tv_usec/1000000. );
416 	if (*t_old == 0.0) {
417 		*t_old = t_now;
418 		return t_now;
419 	}
420 	dt = t_now - *t_old;
421 	*t_old = t_now;
422 	return(dt);
423 }
424 
425 /* common dtime() activities: */
dtime0(double * t_old)426 double dtime0(double *t_old) {
427 	*t_old = 0.0;
428 	return dtime(t_old);
429 }
430 
dnow(void)431 double dnow(void) {
432 	double t;
433 	return dtime0(&t);
434 }
435 
dnowx(void)436 double dnowx(void) {
437 	return dnow() - x11vnc_start;
438 }
439 
rnow(void)440 double rnow(void) {
441 	double t = dnow();
442 	t = t - ((int) t);
443 	if (t > 1.0) {
444 		t = 1.0;
445 	} else if (t < 0.0) {
446 		t = 0.0;
447 	}
448 	return t;
449 }
450 
rfac(void)451 double rfac(void) {
452 	double f;
453 	static int first = 1;
454 
455 	if (first) {
456 		unsigned int s;
457 		if (getenv("RAND_SEED")) {
458 			s = (unsigned int) atoi(getenv("RAND_SEED"));
459 		} else {
460 			s = (unsigned int) ((int) getpid() + 100000 * rnow());
461 		}
462 		srand(s);
463 		first = 0;
464 	}
465 
466 	f = (double) rand();
467 	f = f / ((double) RAND_MAX);
468 
469 	return f;
470 }
471 
check_allinput_rate(void)472 void check_allinput_rate(void) {
473 	static double last_all_input_check = 0.0;
474 	static int set = 0, verb = -1;
475 
476 	if (use_threads) {
477 		return;
478 	}
479 	if (verb < 0) {
480 		verb = 0;
481 		if (getenv("RATE_VERB")) verb = 1;
482 	}
483 	if (! set) {
484 		set = 1;
485 		last_all_input_check = dnow();
486 	} else {
487 		int dt = 5;
488 		if (x11vnc_current > last_all_input_check + dt) {
489 			int n, nq = 0;
490 			while ((n = rfbCheckFds(screen, 0))) {
491 				nq += n;
492 			}
493 			if (verb) fprintf(stderr, "nqueued: %d\n", nq);
494 			if (getenv("CHECK_RATE") && nq > 18 * dt) {
495 				double rate = nq / dt;
496 				if (verb) rfbLog("check_allinput_rate:\n");
497 				if (verb) rfbLog("Client is sending %.1f extra requests per second for the\n", rate);
498 				if (verb) rfbLog("past %d seconds! (queued: %d)\n", dt, nq);
499 				if (strstr(getenv("CHECK_RATE"), "allinput") && !all_input && !handle_events_eagerly) {
500 					rfbLog("Switching to -allpinput mode.\n");
501 					all_input = 1;
502 				}
503 			}
504 			set = 0;
505 		}
506 	}
507 }
508 
do_allinput(long usec)509 static void do_allinput(long usec) {
510 	static double last = 0.0;
511 	static int meas = 0, verb = -1;
512 	int n, f = 1, cnt = 0, m = 0;
513 	long usec0;
514 	double now;
515 	if (!screen || !screen->clientHead) {
516 		return;
517 	}
518 	if (use_threads) {
519 		return;
520 	}
521 	if (usec < 0) {
522 		usec = 0;
523 	}
524 	usec0 = usec;
525 	if (last == 0.0) {
526 		last = dnow();
527 	}
528 	if (verb < 0) {
529 		verb = 0;
530 		if (getenv("RATE_VERB")) verb = 1;
531 	}
532 	while ((n = rfbCheckFds(screen, usec)) > 0) {
533 		if (f) {
534 			if (verb) fprintf(stderr, " *");
535 			f = 0;
536 		}
537 		if (cnt++ > 30) {
538 			break;
539 		}
540 		meas += n;
541 		m += n;
542 	}
543 	if (verb) fprintf(stderr, "+%d/%d", cnt, m);
544 	now = dnow();
545 	if (now > last + 2.0) {
546 		double rate = meas / (now - last);
547 		if (verb) fprintf(stderr, "\n allinput rate: %.2f ", rate);
548 		meas = 0;
549 		last = dnow();
550 	}
551 }
552 
553 /*
554  * utility wrapper to call rfbProcessEvents
555  * checks that we are not in threaded mode.
556  */
557 #define USEC_MAX 999999		/* libvncsever assumes < 1 second */
rfbPE(long usec)558 int rfbPE(long usec) {
559 	int uip0 = unixpw_in_progress;
560 	static int check_rate = -1;
561 	int res = 0;
562 	if (! screen) {
563 		return res;
564 	}
565  	if (unixpw && unixpw_in_progress && !unixpw_in_rfbPE) {
566 		rfbLog("unixpw_in_rfbPE: skipping rfbPE\n");
567  		return res;
568  	}
569 
570 	if (debug_tiles > 2) {
571 		double tm = dnow();
572 		fprintf(stderr, "rfbPE(%d)  t: %.4f\n",
573 		    (int) usec, tm - x11vnc_start);
574 	}
575 
576 	if (usec > USEC_MAX) {
577 		usec = USEC_MAX;
578 	}
579 	if (! use_threads) {
580 		rfbBool r;
581 		r = rfbProcessEvents(screen, usec);
582 		if (r) {
583 			res = 1;
584 		}
585 	}
586 
587  	if (unixpw && unixpw_in_progress && !uip0) {
588 		if (!unixpw_in_rfbPE) {
589 			rfbLog("rfbPE: got new client in non-rfbPE\n");
590 			;	/* this is new unixpw client  */
591 		}
592  	}
593 
594 	if (ipv6_listen) {
595 		check_ipv6_listen(usec);
596 	}
597 	if (unix_sock) {
598 		check_unix_sock(usec);
599 	}
600 	if (check_rate != 0) {
601 		if (check_rate < 0) {
602 			if (getenv("CHECK_RATE")) {
603 				check_rate = 1;
604 			} else {
605 				check_rate = 0;
606 			}
607 		}
608 		if (check_rate && !all_input && x11vnc_current < last_client + 45)  {
609 			check_allinput_rate();
610 		}
611 	}
612 	if (all_input) {
613 		do_allinput(usec);
614 	}
615 	return res;
616 }
617 
rfbCFD(long usec)618 void rfbCFD(long usec) {
619 	int uip0 = unixpw_in_progress;
620 	if (! screen) {
621 		return;
622 	}
623  	if (unixpw && unixpw_in_progress && !unixpw_in_rfbPE) {
624 		static int msgs = 0;
625 		static double last_reset = 0.0;
626 		if (dnow() > last_reset + 5.0) {
627 			msgs = 0;
628 			last_reset = dnow();
629 		}
630 		if (msgs++ < 10) {
631 			rfbLog("unixpw_in_rfbPE: skipping rfbCFD\n");
632 			if (msgs == 10) {
633 				rfbLog("unixpw_in_rfbPE: skipping rfbCFD ...\n");
634 			}
635 		}
636  		return;
637  	}
638 	if (usec > USEC_MAX) {
639 		usec = USEC_MAX;
640 	}
641 
642 	if (debug_tiles > 2) {
643 		double tm = dnow();
644 		fprintf(stderr, "rfbCFD(%d) t: %.4f\n",
645 		    (int) usec, tm - x11vnc_start);
646 	}
647 
648 
649 	if (! use_threads) {
650 		if (all_input) {
651 			do_allinput(usec);
652 		} else {
653 			if (handle_events_eagerly) {
654 				screen->handleEventsEagerly = TRUE;
655 			} else {
656 				screen->handleEventsEagerly = FALSE;
657 			}
658 			rfbCheckFds(screen, usec);
659 		}
660 	}
661 
662  	if (unixpw && unixpw_in_progress && !uip0) {
663 		if (!unixpw_in_rfbPE) {
664 			rfbLog("rfbCFD: got new client in non-rfbPE\n");
665 			;	/* this is new unixpw client  */
666 		}
667  	}
668 }
669 
rect_overlap(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2)670 double rect_overlap(int x1, int y1, int x2, int y2, int X1, int Y1,
671     int X2, int Y2) {
672 	double a, A, o;
673 	sraRegionPtr r, R;
674 	sraRectangleIterator *iter;
675 	sraRect rt;
676 
677 	a = nabs((x2 - x1) * (y2 - y1));
678 	A = nabs((X2 - X1) * (Y2 - Y1));
679 
680 	if (a == 0 || A == 0) {
681 		return 0.0;
682 	}
683 
684 	r = sraRgnCreateRect(x1, y1, x2, y2);
685 	R = sraRgnCreateRect(X1, Y1, X2, Y2);
686 
687 	sraRgnAnd(r, R);
688 
689 	o = 0.0;
690 	iter = sraRgnGetIterator(r);
691 	while (sraRgnIteratorNext(iter, &rt)) {
692 		o += nabs( (rt.x2 - rt.x1) * (rt.y2 - rt.y1) );
693 	}
694 	sraRgnReleaseIterator(iter);
695 
696 	sraRgnDestroy(r);
697 	sraRgnDestroy(R);
698 
699 	if (a < A) {
700 		o = o/a;
701 	} else {
702 		o = o/A;
703 	}
704 	return o;
705 }
706 
707 /*
708  * choose a desktop name
709  */
choose_title(char * display)710 char *choose_title(char *display) {
711 	static char title[(MAXN+10)];
712 
713 	memset(title, 0, sizeof(title));
714 	strcpy(title, "x11vnc");
715 
716 	if (display == NULL) {
717 		display = getenv("DISPLAY");
718 	}
719 
720 #ifdef MACOSX
721 	if (display == NULL || strstr(display, "/tmp/") == display) {
722 		char *u = get_user_name();
723 		char *th = this_host();
724 		if (strlen(u) > MAXN/4)  {
725 			u = "someone";
726 		}
727 		strcpy(title, u);
728 		if (th == NULL && UT.nodename) {
729 			th = UT.nodename;
730 		}
731 		if (th) {
732 			strcat(title, "@");
733 			strncat(title, th, MAXN - strlen(title));
734 		}
735 		return title;
736 	}
737 #endif
738 
739 	if (display == NULL) {
740 		return title;
741 	}
742 
743 	/* use display: */
744 	title[0] = '\0';
745 	if (display[0] == ':') {
746 		char *th = this_host();
747 		if (th != NULL) {
748 			strncpy(title, th, MAXN - strlen(title));
749 		}
750 	}
751 	strncat(title, display, MAXN - strlen(title));
752 	X_LOCK;
753 	if (subwin && dpy && valid_window(subwin, NULL, 0)) {
754 #if !NO_X11
755 		char *name = NULL;
756 		int do_appshare = getenv("X11VNC_APPSHARE_ACTIVE") ? 1 : 0;
757 		if (0 && do_appshare) {
758 			title[0] = '\0';
759 		}
760 		if (XFetchName(dpy, subwin, &name)) {
761 			if (name) {
762 				if (title[0] != '\0') {
763 					strncat(title, " ",  MAXN - strlen(title));
764 				}
765 				strncat(title, name, MAXN - strlen(title));
766 				free(name);
767 			}
768 		}
769 		if (do_appshare) {
770 			Window c;
771 			int x, y;
772 			if (xtranslate(subwin, rootwin, 0, 0, &x, &y, &c, 1)) {
773 				char tmp[32];
774 				if (scaling) {
775 					x *= scale_fac_x;
776 					y *= scale_fac_y;
777 				}
778 				sprintf(tmp, " XY=%d,%d", x, y);
779 				strncat(title, tmp, MAXN - strlen(title));
780 			}
781 			rfbLog("appshare title: %s\n", title);
782 		}
783 #endif	/* NO_X11 */
784 	}
785 	X_UNLOCK;
786 	return title;
787 }
788