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 /* -- user.c -- */
34 
35 #include "x11vnc.h"
36 #include "solid.h"
37 #include "cleanup.h"
38 #include "scan.h"
39 #include "screen.h"
40 #include "unixpw.h"
41 #include "sslhelper.h"
42 #include "xwrappers.h"
43 #include "connections.h"
44 #include "inet.h"
45 #include "keyboard.h"
46 #include "cursor.h"
47 #include "remote.h"
48 #include "sslhelper.h"
49 #include "avahi.h"
50 
51 void check_switched_user(void);
52 void lurk_loop(char *str);
53 int switch_user(char *user, int fb_mode);
54 int read_passwds(char *passfile);
55 void install_passwds(void);
56 void check_new_passwds(int force);
57 void progress_client(void);
58 int wait_for_client(int *argc, char** argv, int http);
59 rfbBool custom_passwd_check(rfbClientPtr cl, const char *response, int len);
60 char *xdmcp_insert = NULL;
61 
62 static void switch_user_task_dummy(void);
63 static void switch_user_task_solid_bg(void);
64 static char *get_login_list(int with_display);
65 static char **user_list(char *user_str);
66 static void user2uid(char *user, uid_t *uid, gid_t *gid, char **name, char **home);
67 static int lurk(char **users);
68 static int guess_user_and_switch(char *str, int fb_mode);
69 static int try_user_and_display(uid_t uid, gid_t gid, char *dpystr);
70 static int switch_user_env(uid_t uid, gid_t gid, char *name, char *home, int fb_mode);
71 static void try_to_switch_users(void);
72 
73 
74 /* tasks for after we switch */
switch_user_task_dummy(void)75 static void switch_user_task_dummy(void) {
76 	;	/* dummy does nothing */
77 }
switch_user_task_solid_bg(void)78 static void switch_user_task_solid_bg(void) {
79 	/* we have switched users, some things to do. */
80 	if (use_solid_bg && client_count) {
81 		solid_bg(0);
82 	}
83 }
84 
check_switched_user(void)85 void check_switched_user(void) {
86 	static time_t sched_switched_user = 0;
87 	static int did_solid = 0;
88 	static int did_dummy = 0;
89 	int delay = 15;
90 	time_t now = time(NULL);
91 
92 	if (unixpw_in_progress) return;
93 
94 	if (started_as_root == 1 && users_list) {
95 		try_to_switch_users();
96 		if (started_as_root == 2) {
97 			/*
98 			 * schedule the switch_user_tasks() call
99 			 * 15 secs is for piggy desktops to start up.
100 			 * might not be enough for slow machines...
101 			 */
102 			sched_switched_user = now;
103 			did_dummy = 0;
104 			did_solid = 0;
105 			/* add other activities */
106 		}
107 	}
108 	if (! sched_switched_user) {
109 		return;
110 	}
111 
112 	if (! did_dummy) {
113 		switch_user_task_dummy();
114 		did_dummy = 1;
115 	}
116 	if (! did_solid) {
117 		int doit = 0;
118 		char *ss = solid_str;
119 		if (now >= sched_switched_user + delay) {
120 			doit = 1;
121 		} else if (ss && strstr(ss, "root:") == ss) {
122 		    	if (now >= sched_switched_user + 3) {
123 				doit = 1;
124 			}
125 		} else if (strcmp("root", guess_desktop())) {
126 			usleep(1000 * 1000);
127 			doit = 1;
128 		}
129 		if (doit) {
130 			switch_user_task_solid_bg();
131 			did_solid = 1;
132 		}
133 	}
134 
135 	if (did_dummy && did_solid) {
136 		sched_switched_user = 0;
137 	}
138 }
139 
140 /* utilities for switching users */
get_login_list(int with_display)141 static char *get_login_list(int with_display) {
142 	char *out;
143 #if HAVE_UTMPX_H
144 	int i, cnt, max = 200, ut_namesize = 32;
145 #define DPYMAX 1000
146 	int sawdpy[DPYMAX];
147 	struct utmpx *utx;
148 
149 	/* size based on "username:999," * max */
150 	out = (char *) malloc(max * (ut_namesize+1+3+1) + 1);
151 	out[0] = '\0';
152 
153 	for (i=0; i < DPYMAX; i++) {
154 		sawdpy[i] = 0;
155 	}
156 
157 	setutxent();
158 	cnt = 0;
159 	while (1) {
160 		char *user, *line, *host, *id;
161 		char tmp[10];
162 		int d = -1;
163 		utx = getutxent();
164 		if (! utx) {
165 			break;
166 		}
167 		if (utx->ut_type != USER_PROCESS) {
168 			continue;
169 		}
170 		user = lblanks(utx->ut_user);
171 		if (*user == '\0') {
172 			continue;
173 		}
174 		if (strchr(user, ',')) {
175 			continue;	/* unlikely, but comma is our sep. */
176 		}
177 
178 		line = lblanks(utx->ut_line);
179 		host = lblanks(utx->ut_host);
180 		id   = lblanks(utx->ut_id);
181 
182 		if (with_display) {
183 			if (0 && line[0] != ':' && strcmp(line, "dtlocal")) {
184 				/* XXX useful? */
185 				continue;
186 			}
187 
188 			if (line[0] == ':') {
189 				if (sscanf(line, ":%d", &d) != 1)  {
190 					d = -1;
191 				}
192 			}
193 			if (d < 0 && host[0] == ':') {
194 				if (sscanf(host, ":%d", &d) != 1)  {
195 					d = -1;
196 				}
197 			}
198 			if (d < 0 && id[0] == ':') {
199 				if (sscanf(id, ":%d", &d) != 1)  {
200 					d = -1;
201 				}
202 			}
203 
204 			if (d < 0 || d >= DPYMAX || sawdpy[d]) {
205 				continue;
206 			}
207 			sawdpy[d] = 1;
208 			sprintf(tmp, ":%d", d);
209 		} else {
210 			/* try to eliminate repeats */
211 			int repeat = 0;
212 			char *q;
213 
214 			q = out;
215 			while ((q = strstr(q, user)) != NULL) {
216 				char *p = q + strlen(user) + strlen(":DPY");
217 				if (q == out || *(q-1) == ',') {
218 					/* bounded on left. */
219 					if (*p == ',' || *p == '\0') {
220 						/* bounded on right. */
221 						repeat = 1;
222 						break;
223 					}
224 				}
225 				q = p;
226 			}
227 			if (repeat) {
228 				continue;
229 			}
230 			sprintf(tmp, ":DPY");
231 		}
232 
233 		if (*out) {
234 			strcat(out, ",");
235 		}
236 		strcat(out, user);
237 		strcat(out, tmp);
238 
239 		cnt++;
240 		if (cnt >= max) {
241 			break;
242 		}
243 	}
244 	endutxent();
245 #else
246 	out = strdup("");
247 #endif
248 	return out;
249 }
250 
user_list(char * user_str)251 static char **user_list(char *user_str) {
252 	int n, i;
253 	char *p, **list;
254 
255 	p = user_str;
256 	n = 1;
257 	while (*p++) {
258 		if (*p == ',') {
259 			n++;
260 		}
261 	}
262 	list = (char **) calloc((n+1)*sizeof(char *), 1);
263 
264 	p = strtok(user_str, ",");
265 	i = 0;
266 	while (p) {
267 		list[i++] = strdup(p);
268 		p = strtok(NULL, ",");
269 	}
270 	list[i] = NULL;
271 	return list;
272 }
273 
user2uid(char * user,uid_t * uid,gid_t * gid,char ** name,char ** home)274 static void user2uid(char *user, uid_t *uid, gid_t *gid, char **name, char **home) {
275 	int numerical = 1, gotgroup = 0;
276 	char *q;
277 
278 	*uid = (uid_t) -1;
279 	*name = NULL;
280 	*home = NULL;
281 
282 	q = user;
283 	while (*q) {
284 		if (! isdigit((unsigned char) (*q++))) {
285 			numerical = 0;
286 			break;
287 		}
288 	}
289 
290 	if (user2group != NULL) {
291 		static int *did = NULL;
292 		int i;
293 
294 		if (did == NULL) {
295 			int n = 0;
296 			i = 0;
297 			while (user2group[i] != NULL) {
298 				n++;
299 				i++;
300 			}
301 			did = (int *) malloc((n+1) * sizeof(int));
302 			i = 0;
303 			for (i=0; i<n; i++) {
304 				did[i] = 0;
305 			}
306 		}
307 		i = 0;
308 		while (user2group[i] != NULL) {
309 			if (strstr(user2group[i], user) == user2group[i]) {
310 				char *w = user2group[i] + strlen(user);
311 				if (*w == '.') {
312 #if (SMALL_FOOTPRINT > 2)
313 					gotgroup = 0;
314 #else
315 					struct group* gr = getgrnam(++w);
316 					if (! gr) {
317 						rfbLog("Invalid group: %s\n", w);
318 						clean_up_exit(1);
319 					}
320 					*gid = gr->gr_gid;
321 					if (! did[i]) {
322 						rfbLog("user2uid: using group %s (%d) for %s\n",
323 						    w, (int) *gid, user);
324 						did[i] = 1;
325 					}
326 					gotgroup = 1;
327 #endif
328 				}
329 			}
330 			i++;
331 		}
332 	}
333 
334 	if (numerical) {
335 		int u = atoi(user);
336 
337 		if (u < 0) {
338 			return;
339 		}
340 		*uid = (uid_t) u;
341 	}
342 
343 #if HAVE_PWD_H
344 	if (1) {
345 		struct passwd *pw;
346 		if (numerical) {
347 			pw = getpwuid(*uid);
348 		} else {
349 			pw = getpwnam(user);
350 		}
351 		if (pw) {
352 			*uid  = pw->pw_uid;
353 			if (! gotgroup) {
354 				*gid  = pw->pw_gid;
355 			}
356 			*name = pw->pw_name;	/* n.b. use immediately */
357 			*home = pw->pw_dir;
358 		}
359 	}
360 #endif
361 }
362 
363 
lurk(char ** users)364 static int lurk(char **users) {
365 	uid_t uid;
366 	gid_t gid;
367 	int success = 0, dmin = -1, dmax = -1;
368 	char *p, *logins, **u;
369 	char **list;
370 	int lind;
371 
372 	if ((u = users) != NULL && *u != NULL && *(*u) == ':') {
373 		int len;
374 		char *tmp;
375 
376 		/* extract min and max display numbers */
377 		tmp = *u;
378 		if (strchr(tmp, '-')) {
379 			if (sscanf(tmp, ":%d-%d", &dmin, &dmax) != 2) {
380 				dmin = -1;
381 				dmax = -1;
382 			}
383 		}
384 		if (dmin < 0) {
385 			if (sscanf(tmp, ":%d", &dmin) != 1) {
386 				dmin = -1;
387 				dmax = -1;
388 			} else {
389 				dmax = dmin;
390 			}
391 		}
392 		if ((dmin < 0 || dmax < 0) || dmin > dmax || dmax > 10000) {
393 			dmin = -1;
394 			dmax = -1;
395 		}
396 
397 		/* get user logins regardless of having a display: */
398 		logins = get_login_list(0);
399 
400 		/*
401 		 * now we append the list in users (might as well try
402 		 * them) this will probably allow weird ways of starting
403 		 * xservers to work.
404 		 */
405 		len = strlen(logins);
406 		u++;
407 		while (*u != NULL) {
408 			len += strlen(*u) + strlen(":DPY,");
409 			u++;
410 		}
411 		tmp = (char *) malloc(len+1);
412 		strcpy(tmp, logins);
413 
414 		/* now concatenate them: */
415 		u = users+1;
416 		while (*u != NULL) {
417 			char *q, chk[100];
418 			snprintf(chk, sizeof chk, "%s:DPY", *u);
419 			q = strstr(tmp, chk);
420 			if (q) {
421 				char *p = q + strlen(chk);
422 
423 				if (q == tmp || *(q-1) == ',') {
424 					/* bounded on left. */
425 					if (*p == ',' || *p == '\0') {
426 						/* bounded on right. */
427 						u++;
428 						continue;
429 					}
430 				}
431 			}
432 
433 			if (*tmp) {
434 				strcat(tmp, ",");
435 			}
436 			strcat(tmp, *u);
437 			strcat(tmp, ":DPY");
438 			u++;
439 		}
440 		free(logins);
441 		logins = tmp;
442 
443 	} else {
444 		logins = get_login_list(1);
445 	}
446 
447 	list = (char **) calloc((strlen(logins)+2)*sizeof(char *), 1);
448 	lind = 0;
449 	p = strtok(logins, ",");
450 	while (p) {
451 		list[lind++] = strdup(p);
452 		p = strtok(NULL, ",");
453 	}
454 	free(logins);
455 
456 	lind = 0;
457 	while (list[lind] != NULL) {
458 		char *user, *name, *home, dpystr[10];
459 		char *q, *t;
460 		int ok = 1, dn;
461 
462 		p = list[lind++];
463 
464 		t = strdup(p);	/* bob:0 */
465 		q = strchr(t, ':');
466 		if (! q) {
467 			free(t);
468 			break;
469 		}
470 		*q = '\0';
471 		user = t;
472 		snprintf(dpystr, sizeof dpystr, ":%s", q+1);
473 
474 		if (users) {
475 			u = users;
476 			ok = 0;
477 			while (*u != NULL) {
478 				if (*(*u) == ':') {
479 					u++;
480 					continue;
481 				}
482 				if (!strcmp(user, *u++)) {
483 					ok = 1;
484 					break;
485 				}
486 			}
487 		}
488 
489 		user2uid(user, &uid, &gid, &name, &home);
490 		free(t);
491 
492 		if (! uid || ! gid) {
493 			ok = 0;
494 		}
495 
496 		if (! ok) {
497 			continue;
498 		}
499 
500 		for (dn = dmin; dn <= dmax; dn++) {
501 			if (dn >= 0) {
502 				sprintf(dpystr, ":%d", dn);
503 			}
504 			if (try_user_and_display(uid, gid, dpystr)) {
505 				if (switch_user_env(uid, gid, name, home, 0)) {
506 					rfbLog("lurk: now user: %s @ %s\n",
507 					    name, dpystr);
508 					started_as_root = 2;
509 					success = 1;
510 				}
511 				set_env("DISPLAY", dpystr);
512 				break;
513 			}
514 		}
515 		if (success) {
516 			 break;
517 		}
518 	}
519 
520 	lind = 0;
521 	while (list[lind] != NULL) {
522 		free(list[lind]);
523 		lind++;
524 	}
525 
526 	return success;
527 }
528 
lurk_loop(char * str)529 void lurk_loop(char *str) {
530 	char *tstr = NULL, **users = NULL;
531 
532 	if (strstr(str, "lurk=") != str) {
533 		exit(1);
534 	}
535 	rfbLog("lurking for logins using: '%s'\n", str);
536 	if (strlen(str) > strlen("lurk=")) {
537 		char *q = strchr(str, '=');
538 		tstr = strdup(q+1);
539 		users = user_list(tstr);
540 	}
541 
542 	while (1) {
543 		if (lurk(users)) {
544 			break;
545 		}
546 		sleep(3);
547 	}
548 	if (tstr) {
549 		free(tstr);
550 	}
551 	if (users) {
552 		free(users);
553 	}
554 }
555 
guess_user_and_switch(char * str,int fb_mode)556 static int guess_user_and_switch(char *str, int fb_mode) {
557 	char *dstr, *d;
558 	char *p, *tstr = NULL, *allowed = NULL, *logins, **users = NULL;
559 	int dpy1, ret = 0;
560 	char **list;
561 	int lind;
562 
563 	RAWFB_RET(0)
564 
565 	d = DisplayString(dpy);
566 	/* pick out ":N" */
567 	dstr = strchr(d, ':');
568 	if (! dstr) {
569 		return 0;
570 	}
571 	if (sscanf(dstr, ":%d", &dpy1) != 1) {
572 		return 0;
573 	}
574 	if (dpy1 < 0) {
575 		return 0;
576 	}
577 
578 	if (strstr(str, "guess=") == str && strlen(str) > strlen("guess=")) {
579 		allowed = strchr(str, '=');
580 		allowed++;
581 
582 		tstr = strdup(allowed);
583 		users = user_list(tstr);
584 	}
585 
586 	/* loop over the utmpx entries looking for this display */
587 	logins = get_login_list(1);
588 
589 	list = (char **) calloc((strlen(logins)+2)*sizeof(char *), 1);
590 	lind = 0;
591 	p = strtok(logins, ",");
592 	while (p) {
593 		list[lind++] = strdup(p);
594 		p = strtok(NULL, ",");
595 	}
596 
597 	lind = 0;
598 	while (list[lind] != NULL) {
599 		char *user, *q, *t;
600 		int dpy2, ok = 1;
601 
602 		p = list[lind++];
603 
604 		t = strdup(p);
605 		q = strchr(t, ':');
606 		if (! q) {
607 			free(t);
608 			break;
609 		}
610 		*q = '\0';
611 		user = t;
612 		dpy2 = atoi(q+1);
613 
614 		if (users) {
615 			char **u = users;
616 			ok = 0;
617 			while (*u != NULL) {
618 				if (!strcmp(user, *u++)) {
619 					ok = 1;
620 					break;
621 				}
622 			}
623 		}
624 		if (dpy1 != dpy2) {
625 			ok = 0;
626 		}
627 
628 		if (! ok) {
629 			free(t);
630 			continue;
631 		}
632 
633 		if (switch_user(user, fb_mode)) {
634 			rfbLog("switched to guessed user: %s\n", user);
635 			free(t);
636 			ret = 1;
637 			break;
638 		}
639 	}
640 	if (tstr) {
641 		free(tstr);
642 	}
643 	if (users) {
644 		free(users);
645 	}
646 	if (logins) {
647 		free(logins);
648 	}
649 	return ret;
650 }
651 
try_user_and_display(uid_t uid,gid_t gid,char * dpystr)652 static int try_user_and_display(uid_t uid, gid_t gid, char *dpystr) {
653 	/* NO strtoks */
654 #if LIBVNCSERVER_HAVE_FORK && LIBVNCSERVER_HAVE_SYS_WAIT_H && HAVE_PWD_H
655 	pid_t pid, pidw;
656 	char *home, *name;
657 	int st;
658 	struct passwd *pw;
659 
660 	pw = getpwuid(uid);
661 	if (pw) {
662 		name = pw->pw_name;
663 		home = pw->pw_dir;
664 	} else {
665 		return 0;
666 	}
667 
668 	/*
669 	 * We fork here and try to open the display again as the
670 	 * new user.  Unreadable XAUTHORITY could be a problem...
671 	 * This is not really needed since we have DISPLAY open but:
672 	 * 1) is a good indicator this user owns the session and  2)
673 	 * some activities do spawn new X apps, e.g.  xmessage(1), etc.
674 	 */
675 	if ((pid = fork()) > 0) {
676 		;
677 	} else if (pid == -1) {
678 		fprintf(stderr, "could not fork\n");
679 		rfbLogPerror("fork");
680 		return 0;
681 	} else {
682 		/* child */
683 		Display *dpy2 = NULL;
684 		int rc;
685 
686 		signal(SIGHUP,  SIG_DFL);
687 		signal(SIGINT,  SIG_DFL);
688 		signal(SIGQUIT, SIG_DFL);
689 		signal(SIGTERM, SIG_DFL);
690 
691 		rc = switch_user_env(uid, gid, name, home, 0);
692 		if (! rc) {
693 			exit(1);
694 		}
695 
696 		fclose(stderr);
697 		dpy2 = XOpenDisplay_wr(dpystr);
698 		if (dpy2) {
699 			XCloseDisplay_wr(dpy2);
700 			exit(0);	/* success */
701 		} else {
702 			exit(2);	/* fail */
703 		}
704 	}
705 
706 	/* see what the child says: */
707 	pidw = waitpid(pid, &st, 0);
708 	if (pidw == pid && WIFEXITED(st) && WEXITSTATUS(st) == 0) {
709 		return 1;
710 	}
711 #endif	/* LIBVNCSERVER_HAVE_FORK ... */
712 	return 0;
713 }
714 
switch_user(char * user,int fb_mode)715 int switch_user(char *user, int fb_mode) {
716 	/* NO strtoks */
717 	int doit = 0;
718 	uid_t uid = 0;
719 	gid_t gid = 0;
720 	char *name, *home;
721 
722 	if (*user == '+') {
723 		doit = 1;
724 		user++;
725 	}
726 
727 	ssl_helper_pid(0, -2);	/* waitall */
728 
729 	if (strstr(user, "guess=") == user) {
730 		return guess_user_and_switch(user, fb_mode);
731 	}
732 
733 	user2uid(user, &uid, &gid, &name, &home);
734 
735 	if (uid == (uid_t) -1 || uid == 0) {
736 		return 0;
737 	}
738 	if (gid == 0) {
739 		return 0;
740 	}
741 
742 	if (! doit && dpy) {
743 		/* see if this display works: */
744 		char *dstr = DisplayString(dpy);
745 		doit = try_user_and_display(uid, gid, dstr);
746 	}
747 
748 	if (doit) {
749 		int rc = switch_user_env(uid, gid, name, home, fb_mode);
750 		if (rc) {
751 			started_as_root = 2;
752 		}
753 		return rc;
754 	} else {
755 		return 0;
756 	}
757 }
758 
switch_user_env(uid_t uid,gid_t gid,char * name,char * home,int fb_mode)759 static int switch_user_env(uid_t uid, gid_t gid, char *name, char *home, int fb_mode) {
760 	/* NO strtoks */
761 	char *xauth;
762 	int reset_fb = 0;
763 	int grp_ok = 0;
764 
765 #if !HAVE_SETUID
766 	return 0;
767 #else
768 	/*
769 	 * OK, tricky here, we need to free the shm... otherwise
770 	 * we won't be able to delete it as the other user...
771 	 */
772 	if (fb_mode == 1 && (using_shm && ! xform24to32)) {
773 		reset_fb = 1;
774 		clean_shm(0);
775 		free_tiles();
776 	}
777 #if HAVE_INITGROUPS
778 #if HAVE_PWD_H
779 	if (getpwuid(uid) != NULL && getenv("X11VNC_SINGLE_GROUP") == NULL) {
780 		struct passwd *p = getpwuid(uid);
781 		/* another possibility is p->pw_gid instead of gid */
782 		if (setgid(gid) == 0 && initgroups(p->pw_name, gid) == 0)  {
783 			grp_ok = 1;
784 		} else {
785 			rfbLogPerror("initgroups");
786 		}
787 		endgrent();
788 	}
789 #endif
790 #endif
791 	if (! grp_ok) {
792 		if (setgid(gid) == 0) {
793 			grp_ok = 1;
794 		}
795 	}
796 	if (! grp_ok) {
797 		if (reset_fb) {
798 			/* 2 means we did clean_shm and free_tiles */
799 			do_new_fb(2);
800 		}
801 		return 0;
802 	}
803 
804 	if (setuid(uid) != 0) {
805 		if (reset_fb) {
806 			/* 2 means we did clean_shm and free_tiles */
807 			do_new_fb(2);
808 		}
809 		return 0;
810 	}
811 #endif
812 	if (reset_fb) {
813 		do_new_fb(2);
814 	}
815 
816 	xauth = getenv("XAUTHORITY");
817 	if (xauth && access(xauth, R_OK) != 0) {
818 		*(xauth-2) = '_';	/* yow */
819 	}
820 
821 	set_env("USER", name);
822 	set_env("LOGNAME", name);
823 	set_env("HOME", home);
824 	return 1;
825 }
826 
try_to_switch_users(void)827 static void try_to_switch_users(void) {
828 	static time_t last_try = 0;
829 	time_t now = time(NULL);
830 	char *users, *p;
831 
832 	if (getuid() && geteuid()) {
833 		rfbLog("try_to_switch_users: not root\n");
834 		started_as_root = 2;
835 		return;
836 	}
837 	if (!last_try) {
838 		last_try = now;
839 	} else if (now <= last_try + 2) {
840 		/* try every 3 secs or so */
841 		return;
842 	}
843 	last_try = now;
844 
845 	users = strdup(users_list);
846 
847 	if (strstr(users, "guess=") == users) {
848 		if (switch_user(users, 1)) {
849 			started_as_root = 2;
850 		}
851 		free(users);
852 		return;
853 	}
854 
855 	p = strtok(users, ",");
856 	while (p) {
857 		if (switch_user(p, 1)) {
858 			started_as_root = 2;
859 			rfbLog("try_to_switch_users: now %s\n", p);
860 			break;
861 		}
862 		p = strtok(NULL, ",");
863 	}
864 	free(users);
865 }
866 
read_passwds(char * passfile)867 int read_passwds(char *passfile) {
868 	char line[1024];
869 	char *filename;
870 	char **old_passwd_list = passwd_list;
871 	int linecount = 0, i, remove = 0, read_mode = 0, begin_vo = -1;
872 	struct stat sbuf;
873 	static int max = -1;
874 	FILE *in = NULL;
875 	static time_t last_read = 0;
876 	static int read_cnt = 0;
877 	int db_passwd = 0;
878 
879 	if (max < 0) {
880 		max = 1000;
881 		if (getenv("X11VNC_MAX_PASSWDS")) {
882 			max = atoi(getenv("X11VNC_MAX_PASSWDS"));
883 		}
884 	}
885 
886 	filename = passfile;
887 	if (strstr(filename, "rm:") == filename) {
888 		filename += strlen("rm:");
889 		remove = 1;
890 	} else if (strstr(filename, "read:") == filename) {
891 		filename += strlen("read:");
892 		read_mode = 1;
893 		if (stat(filename, &sbuf) == 0) {
894 			if (sbuf.st_mtime <= last_read) {
895 				return 1;
896 			}
897 			last_read = sbuf.st_mtime;
898 		}
899 	} else if (strstr(filename, "cmd:") == filename) {
900 		int rc;
901 
902 		filename += strlen("cmd:");
903 		read_mode = 1;
904 		in = tmpfile();
905 		if (in == NULL) {
906 			rfbLog("run_user_command tmpfile() failed: %s\n",
907 			    filename);
908 			clean_up_exit(1);
909 		}
910 		rc = run_user_command(filename, latest_client, "read_passwds",
911 		    NULL, 0, in);
912 		if (rc != 0) {
913 			rfbLog("run_user_command command failed: %s\n",
914 			    filename);
915 			clean_up_exit(1);
916 		}
917 		rewind(in);
918 	} else if (strstr(filename, "custom:") == filename) {
919 		return 1;
920 	}
921 
922 	if (in == NULL && stat(filename, &sbuf) == 0) {
923 		/* (poor...) upper bound to number of lines */
924 		max = (int) sbuf.st_size;
925 		last_read = sbuf.st_mtime;
926 	}
927 
928 	/* create 1 more than max to have it be the ending NULL */
929 	passwd_list = (char **) malloc( (max+1) * (sizeof(char *)) );
930 	for (i=0; i<max+1; i++) {
931 		passwd_list[i] = NULL;
932 	}
933 
934 	if (in == NULL) {
935 		in = fopen(filename, "r");
936 	}
937 	if (in == NULL) {
938 		rfbLog("cannot open passwdfile: %s\n", passfile);
939 		rfbLogPerror("fopen");
940 		if (remove) {
941 			unlink(filename);
942 		}
943 		clean_up_exit(1);
944 	}
945 
946 	if (getenv("DEBUG_PASSWDFILE") != NULL) {
947 		db_passwd = 1;
948 	}
949 
950 	while (fgets(line, sizeof line, in) != NULL) {
951 		char *p;
952 		int blank = 1;
953 		int len = strlen(line);
954 
955 		if (db_passwd) {
956 			fprintf(stderr, "read_passwds: raw line: %s\n", line);
957 		}
958 
959 		if (len == 0) {
960 			continue;
961 		} else if (line[len-1] == '\n') {
962 			line[len-1] = '\0';
963 		}
964 		if (line[0] == '\0') {
965 			continue;
966 		}
967 		if (strstr(line, "__SKIP__") != NULL) {
968 			continue;
969 		}
970 		if (strstr(line, "__COMM__") == line) {
971 			continue;
972 		}
973 		if (!strcmp(line, "__BEGIN_VIEWONLY__")) {
974 			if (begin_vo < 0) {
975 				begin_vo = linecount;
976 			}
977 			continue;
978 		}
979 		if (line[0] == '#') {
980 			/* commented out, cannot have password beginning with # */
981 			continue;
982 		}
983 		p = line;
984 		while (*p != '\0') {
985 			if (! isspace((unsigned char) (*p))) {
986 				blank = 0;
987 				break;
988 			}
989 			p++;
990 		}
991 		if (blank) {
992 			continue;
993 		}
994 
995 		passwd_list[linecount++] = strdup(line);
996 		if (db_passwd) {
997 			fprintf(stderr, "read_passwds: keepline: %s\n", line);
998 			fprintf(stderr, "read_passwds: begin_vo: %d\n", begin_vo);
999 		}
1000 
1001 		if (linecount >= max) {
1002 			rfbLog("read_passwds: hit max passwd: %d\n", max);
1003 			break;
1004 		}
1005 	}
1006 	fclose(in);
1007 
1008 	for (i=0; i<1024; i++) {
1009 		line[i] = '\0';
1010 	}
1011 
1012 	if (remove) {
1013 		unlink(filename);
1014 	}
1015 
1016 	if (! linecount) {
1017 		rfbLog("cannot read a valid line from passwdfile: %s\n",
1018 		    passfile);
1019 		if (read_cnt == 0) {
1020 			clean_up_exit(1);
1021 		} else {
1022 			return 0;
1023 		}
1024 	}
1025 	read_cnt++;
1026 
1027 	for (i=0; i<linecount; i++) {
1028 		char *q, *p = passwd_list[i];
1029 		if (!strcmp(p, "__EMPTY__")) {
1030 			*p = '\0';
1031 		} else if ((q = strstr(p, "__COMM__")) != NULL) {
1032 			*q = '\0';
1033 		}
1034 		passwd_list[i] = strdup(p);
1035 		if (db_passwd) {
1036 			fprintf(stderr, "read_passwds: trimline: %s\n", p);
1037 		}
1038 		strzero(p);
1039 	}
1040 
1041 	begin_viewonly = begin_vo;
1042 	if (read_mode && read_cnt > 1) {
1043 		if (viewonly_passwd) {
1044 			free(viewonly_passwd);
1045 			viewonly_passwd = NULL;
1046 		}
1047 	}
1048 
1049 	if (begin_viewonly < 0 && linecount == 2) {
1050 		/* for compatibility with previous 2-line usage: */
1051 		viewonly_passwd = strdup(passwd_list[1]);
1052 		if (db_passwd) {
1053 			fprintf(stderr, "read_passwds: linecount is 2.\n");
1054 		}
1055 		if (screen) {
1056 			char **apd = (char **) screen->authPasswdData;
1057 			if (apd) {
1058 				if (apd[0] != NULL) {
1059 					strzero(apd[0]);
1060 				}
1061 				apd[0] = strdup(passwd_list[0]);
1062 			}
1063 		}
1064 		begin_viewonly = 1;
1065 	}
1066 
1067 	if (old_passwd_list != NULL) {
1068 		char *p;
1069 		i = 0;
1070 		while (old_passwd_list[i] != NULL) {
1071 			p = old_passwd_list[i];
1072 			strzero(p);
1073 			free(old_passwd_list[i]);
1074 			i++;
1075 		}
1076 		free(old_passwd_list);
1077 	}
1078 	return 1;
1079 }
1080 
install_passwds(void)1081 void install_passwds(void) {
1082 	if (viewonly_passwd) {
1083 		/* append the view only passwd after the normal passwd */
1084 		char **passwds_new = (char **) malloc(3*sizeof(char *));
1085 		char **passwds_old = (char **) screen->authPasswdData;
1086 		passwds_new[0] = passwds_old[0];
1087 		passwds_new[1] = viewonly_passwd;
1088 		passwds_new[2] = NULL;
1089 		/* mutex */
1090 		screen->authPasswdData = (void*) passwds_new;
1091 	} else if (passwd_list) {
1092 		int i = 0;
1093 		while(passwd_list[i] != NULL) {
1094 			i++;
1095 		}
1096 		if (begin_viewonly < 0) {
1097 			begin_viewonly = i+1;
1098 		}
1099 		/* mutex */
1100 		screen->authPasswdData = (void*) passwd_list;
1101 		screen->authPasswdFirstViewOnly = begin_viewonly;
1102 	}
1103 }
1104 
check_new_passwds(int force)1105 void check_new_passwds(int force) {
1106 	static time_t last_check = 0;
1107 	time_t now;
1108 
1109 	if (! passwdfile) {
1110 		return;
1111 	}
1112 	if (strstr(passwdfile, "read:") != passwdfile) {
1113 		return;
1114 	}
1115 	if (unixpw_in_progress) return;
1116 
1117 	if (force) {
1118 		last_check = 0;
1119 	}
1120 
1121 	now = time(NULL);
1122 	if (now > last_check + 1) {
1123 		if (read_passwds(passwdfile)) {
1124 			install_passwds();
1125 		}
1126 		last_check = now;
1127 	}
1128 }
1129 
custom_passwd_check(rfbClientPtr cl,const char * response,int len)1130 rfbBool custom_passwd_check(rfbClientPtr cl, const char *response, int len) {
1131 	char *input, *cmd;
1132 	char num[16];
1133 	int j, i, n, rc;
1134 
1135 	rfbLog("custom_passwd_check: len=%d\n", len);
1136 
1137 	if (!passwdfile || strstr(passwdfile, "custom:") != passwdfile) {
1138 		return FALSE;
1139 	}
1140 	cmd = passwdfile + strlen("custom:");
1141 
1142 	sprintf(num, "%d\n", len);
1143 
1144 	input = (char *) malloc(2 * len + 16 + 1);
1145 
1146 	input[0] = '\0';
1147 	strcat(input, num);
1148 	n = strlen(num);
1149 
1150 	j = n;
1151 	for (i=0; i < len; i++) {
1152 		input[j] = cl->authChallenge[i];
1153 		j++;
1154 	}
1155 	for (i=0; i < len; i++) {
1156 		input[j] = response[i];
1157 		j++;
1158 	}
1159 	rc = run_user_command(cmd, cl, "custom_passwd", input, n+2*len, NULL);
1160 	free(input);
1161 	if (rc == 0) {
1162 		return TRUE;
1163 	} else {
1164 		return FALSE;
1165 	}
1166 }
1167 
handle_one_http_request(void)1168 static void handle_one_http_request(void) {
1169 	rfbLog("handle_one_http_request: begin.\n");
1170 	if (inetd || screen->httpPort == 0) {
1171 		int port = find_free_port(5800, 5860);
1172 		if (port) {
1173 			/* mutex */
1174 			screen->httpPort = port;
1175 		} else {
1176 			rfbLog("handle_one_http_request: no http port.\n");
1177 			clean_up_exit(1);
1178 		}
1179 	}
1180 	screen->autoPort = FALSE;
1181 	screen->port = 0;
1182 
1183 	http_connections(1);
1184 
1185 	rfbInitServer(screen);
1186 
1187 	if (!inetd) {
1188 		/* XXX ipv6 */
1189 		int conn = 0;
1190 		while (1) {
1191 			if (0) fprintf(stderr, "%d %d %d  %d\n", conn, screen->listenSock, screen->httpSock, screen->httpListenSock);
1192 			usleep(10 * 1000);
1193 			rfbHttpCheckFds(screen);
1194 			if (conn) {
1195 				if (screen->httpSock < 0) {
1196 					break;
1197 				}
1198 			} else {
1199 				if (screen->httpSock >= 0) {
1200 					conn = 1;
1201 				}
1202 			}
1203 			if (!screen->httpDir) {
1204 				break;
1205 			}
1206 			if (screen->httpListenSock < 0) {
1207 				break;
1208 			}
1209 		}
1210 		rfbLog("handle_one_http_request: finished.\n");
1211 		return;
1212 	} else {
1213 		/* inetd case: */
1214 #if LIBVNCSERVER_HAVE_FORK
1215 		pid_t pid;
1216 		int s_in = screen->inetdSock;
1217 		if (s_in < 0) {
1218 			rfbLog("handle_one_http_request: inetdSock not set up.\n");
1219 			clean_up_exit(1);
1220 		}
1221 		pid = fork();
1222 		if (pid < 0) {
1223 			rfbLog("handle_one_http_request: could not fork.\n");
1224 			clean_up_exit(1);
1225 		} else if (pid > 0) {
1226 			int status;
1227 			pid_t pidw;
1228 			while (1) {
1229 				rfbHttpCheckFds(screen);
1230 				pidw = waitpid(pid, &status, WNOHANG);
1231 				if (pidw == pid && WIFEXITED(status)) {
1232 					break;
1233 				} else if (pidw < 0) {
1234 					break;
1235 				}
1236 			}
1237 			rfbLog("handle_one_http_request: finished.\n");
1238 			return;
1239 		} else {
1240 			int sock = connect_tcp("127.0.0.1", screen->httpPort);
1241 			if (sock < 0) {
1242 				exit(1);
1243 			}
1244 			raw_xfer(sock, s_in, s_in);
1245 			exit(0);
1246 		}
1247 #else
1248 		rfbLog("handle_one_http_request: fork not supported.\n");
1249 		clean_up_exit(1);
1250 #endif
1251 	}
1252 }
1253 
user_supplied_opts(char * opts)1254 void user_supplied_opts(char *opts) {
1255 	char *p, *str;
1256 	char *allow[] = {
1257 		"skip-display", "skip-auth", "skip-shared",
1258 		"scale", "scale_cursor", "sc", "solid", "so", "id",
1259 		"clear_mods", "cm", "clear_keys", "ck", "repeat",
1260 		"clear_all", "ca",
1261 		"speeds", "sp", "readtimeout", "rd",
1262 		"rotate", "ro",
1263 		"geometry", "geom", "ge",
1264 		"noncache", "nc",
1265 		"nodisplay", "nd",
1266 		"viewonly", "vo",
1267 		"tag",
1268 		NULL
1269 	};
1270 
1271 	if (getenv("X11VNC_NO_UNIXPW_OPTS")) {
1272 		return;
1273 	}
1274 
1275 	str = strdup(opts);
1276 
1277 	p = strtok(str, ",");
1278 	while (p) {
1279 		char *q;
1280 		int i, n, m, ok = 0;
1281 
1282 		i = 0;
1283 		while (allow[i] != NULL) {
1284 			if (strstr(allow[i], "skip-")) {
1285 				i++;
1286 				continue;
1287 			}
1288 			if (strstr(p, allow[i]) == p) 	{
1289 				ok = 1;
1290 				break;
1291 			}
1292 			i++;
1293 		}
1294 
1295 		if (! ok && strpbrk(p, "0123456789") == p &&
1296 		    sscanf(p, "%d/%d", &n, &m) == 2) {
1297 			if (scale_str) free(scale_str);
1298 			scale_str = strdup(p);
1299 		} else if (ok) {
1300 			if (0 && strstr(p, "display=") == p) {
1301 				if (use_dpy) free(use_dpy);
1302 				use_dpy = strdup(p + strlen("display="));
1303 			} else if (0 && strstr(p, "auth=") == p) {
1304 				if (auth_file) free(auth_file);
1305 				auth_file = strdup(p + strlen("auth="));
1306 			} else if (0 && !strcmp(p, "shared")) {
1307 				shared = 1;
1308 			} else if (strstr(p, "scale=") == p) {
1309 				if (scale_str) free(scale_str);
1310 				scale_str = strdup(p + strlen("scale="));
1311 			} else if (strstr(p, "scale_cursor=") == p ||
1312 			    strstr(p, "sc=") == p) {
1313 				if (scale_cursor_str) free(scale_cursor_str);
1314 				q = strchr(p, '=') + 1;
1315 				scale_cursor_str = strdup(q);
1316 			} else if (strstr(p, "rotate=") == p ||
1317 			    strstr(p, "ro=") == p) {
1318 				if (rotating_str) free(rotating_str);
1319 				q = strchr(p, '=') + 1;
1320 				rotating_str = strdup(q);
1321 			} else if (!strcmp(p, "solid") || !strcmp(p, "so")) {
1322 				use_solid_bg = 1;
1323 				if (!solid_str) {
1324 					solid_str = strdup(solid_default);
1325 				}
1326 			} else if (!strcmp(p, "viewonly") || !strcmp(p, "vo")) {
1327 				view_only = 1;
1328 			} else if (strstr(p, "solid=") == p ||
1329 			    strstr(p, "so=") == p) {
1330 				use_solid_bg = 1;
1331 				if (solid_str) free(solid_str);
1332 				q = strchr(p, '=') + 1;
1333 				if (!strcmp(q, "R")) {
1334 					solid_str = strdup("root:");
1335 				} else {
1336 					solid_str = strdup(q);
1337 				}
1338 			} else if (strstr(p, "id=") == p) {
1339 				unsigned long win;
1340 				q = p + strlen("id=");
1341 				if (strcmp(q, "pick")) {
1342 					if (scan_hexdec(q, &win)) {
1343 						subwin = win;
1344 					}
1345 				}
1346 			} else if (!strcmp(p, "clear_mods") ||
1347 			    !strcmp(p, "cm")) {
1348 				clear_mods = 1;
1349 			} else if (!strcmp(p, "clear_keys") ||
1350 			    !strcmp(p, "ck")) {
1351 				clear_mods = 2;
1352 			} else if (!strcmp(p, "clear_all") ||
1353 			    !strcmp(p, "ca")) {
1354 				clear_mods = 3;
1355 			} else if (!strcmp(p, "noncache") ||
1356 			    !strcmp(p, "nc")) {
1357 				ncache  = 0;
1358 				ncache0 = 0;
1359 			} else if (strstr(p, "nc=") == p) {
1360 				int n2 = atoi(p + strlen("nc="));
1361 				if (nabs(n2) < nabs(ncache)) {
1362 					if (ncache < 0) {
1363 						ncache = -nabs(n2);
1364 					} else {
1365 						ncache = nabs(n2);
1366 					}
1367 				}
1368 			} else if (!strcmp(p, "repeat")) {
1369 				no_autorepeat = 0;
1370 			} else if (strstr(p, "speeds=") == p ||
1371 			    strstr(p, "sp=") == p) {
1372 				if (speeds_str) free(speeds_str);
1373 				q = strchr(p, '=') + 1;
1374 				speeds_str = strdup(q);
1375 				q = speeds_str;
1376 				while (*q != '\0') {
1377 					if (*q == '-') {
1378 						*q = ',';
1379 					}
1380 					q++;
1381 				}
1382 			} else if (strstr(p, "readtimeout=") == p ||
1383 			    strstr(p, "rd=") == p) {
1384 				q = strchr(p, '=') + 1;
1385 				rfbMaxClientWait = atoi(q) * 1000;
1386 			}
1387 		} else {
1388 			rfbLog("skipping option: %s\n", p);
1389 		}
1390 		p = strtok(NULL, ",");
1391 	}
1392 	free(str);
1393 }
1394 
vnc_redirect_timeout(int sig)1395 static void vnc_redirect_timeout (int sig) {
1396 	write(2, "timeout: no clients connected.\n", 31);
1397 	if (sig) {};
1398 	exit(0);
1399 }
1400 
do_chvt(int vt)1401 static void do_chvt(int vt) {
1402 	char chvt[100];
1403 	sprintf(chvt, "chvt %d >/dev/null 2>/dev/null &", vt);
1404 	rfbLog("running: %s\n", chvt);
1405 	system(chvt);
1406 	sleep(2);
1407 }
1408 
setup_fake_fb(XImage * fb_image,int w,int h,int b)1409 static void setup_fake_fb(XImage* fb_image, int w, int h, int b) {
1410 	if (fake_fb) {
1411 		free(fake_fb);
1412 	}
1413 	fake_fb = (char *) calloc(w*h*b/8, 1);
1414 
1415 	fb_image->data = fake_fb;
1416 	fb_image->format = ZPixmap;
1417 	fb_image->width  = w;
1418 	fb_image->height = h;
1419 	fb_image->bits_per_pixel = b;
1420 	fb_image->bytes_per_line = w*b/8;
1421 	fb_image->bitmap_unit = -1;
1422 	if (b >= 24) {
1423 		fb_image->depth = 24;
1424 		fb_image->red_mask   = 0xff0000;
1425 		fb_image->green_mask = 0x00ff00;
1426 		fb_image->blue_mask  = 0x0000ff;
1427 	} else if (b >= 16) {
1428 		fb_image->depth = 16;
1429 		fb_image->red_mask   = 0x003f;
1430 		fb_image->green_mask = 0x07c0;
1431 		fb_image->blue_mask  = 0xf800;
1432 	} else if (b >= 2) {
1433 		fb_image->depth = 8;
1434 		fb_image->red_mask   = 0x07;
1435 		fb_image->green_mask = 0x38;
1436 		fb_image->blue_mask  = 0xc0;
1437 	} else {
1438 		fb_image->depth = 1;
1439 		fb_image->red_mask   = 0x1;
1440 		fb_image->green_mask = 0x1;
1441 		fb_image->blue_mask  = 0x1;
1442 	}
1443 
1444 	depth = fb_image->depth;
1445 
1446 	dpy_x = wdpy_x = w;
1447 	dpy_y = wdpy_y = h;
1448 	off_x = 0;
1449 	off_y = 0;
1450 }
1451 
1452 void do_announce_http(void);
1453 void do_mention_java_urls(void);
1454 
setup_service(void)1455 static void setup_service(void) {
1456 	if (remote_direct) {
1457 		return;
1458 	}
1459 	if (!inetd) {
1460 		do_mention_java_urls();
1461 		do_announce_http();
1462 		if (!use_openssl) {
1463 			announce(screen->port, use_openssl, NULL);
1464 			fprintf(stdout, "PORT=%d\n", screen->port);
1465 		} else {
1466 			fprintf(stdout, "PORT=%d\n", screen->port);
1467 			if (stunnel_port) {
1468 				fprintf(stdout, "SSLPORT=%d\n", stunnel_port);
1469 			} else if (use_openssl) {
1470 				fprintf(stdout, "SSLPORT=%d\n", screen->port);
1471 			}
1472 		}
1473 		fflush(stdout);
1474 	} else if (!use_openssl && avahi) {
1475 		char *name = rfb_desktop_name;
1476 		char *host = this_host();
1477 		if (!name) {
1478 			name = use_dpy;
1479 		}
1480 		avahi_initialise();
1481 		avahi_advertise(name, host, screen->port);
1482 		free(host);
1483 	}
1484 }
1485 
check_waitbg(void)1486 static void check_waitbg(void) {
1487 	if (getenv("WAITBG")) {
1488 #if LIBVNCSERVER_HAVE_FORK && HAVE_SETSID
1489 		int p, n;
1490 		if ((p = fork()) > 0)  {
1491 			exit(0);
1492 		} else if (p == -1) {
1493 			rfbLogEnable(1);
1494 			fprintf(stderr, "could not fork\n");
1495 			perror("fork");
1496 			clean_up_exit(1);
1497 		}
1498 		if (setsid() == -1) {
1499 			rfbLogEnable(1);
1500 			fprintf(stderr, "setsid failed\n");
1501 			perror("setsid");
1502 			clean_up_exit(1);
1503 		}
1504 		/* adjust our stdio */
1505 		n = open("/dev/null", O_RDONLY);
1506 		dup2(n, 0);
1507 		dup2(n, 1);
1508 		if (! logfile) {
1509 			dup2(n, 2);
1510 		}
1511 		if (n > 2) {
1512 			close(n);
1513 		}
1514 #else
1515 		clean_up_exit(1);
1516 #endif
1517 	}
1518 }
1519 
setup_client_connect(int * did_client_connect)1520 static void setup_client_connect(int *did_client_connect) {
1521 	if (client_connect != NULL) {
1522 		char *remainder = NULL;
1523 		if (inetd) {
1524 			rfbLog("wait_for_client: -connect disallowed in inetd mode: %s\n",
1525 			    client_connect);
1526 		} else if (screen && screen->clientHead) {
1527 			rfbLog("wait_for_client: -connect disallowed: client exists: %s\n",
1528 			    client_connect);
1529 		} else if (strchr(client_connect, '=')) {
1530 			rfbLog("wait_for_client: invalid -connect string: %s\n",
1531 			    client_connect);
1532 		} else {
1533 			char *q = strchr(client_connect, ',');
1534 			if (q) {
1535 				rfbLog("wait_for_client: only using first"
1536 				    " connect host in: %s\n", client_connect);
1537 				remainder = strdup(q+1);
1538 				*q = '\0';
1539 			}
1540 			rfbLog("wait_for_client: reverse_connect(%s)\n",
1541 			    client_connect);
1542 			reverse_connect(client_connect);
1543 			*did_client_connect = 1;
1544 		}
1545 		free(client_connect);
1546 		if (remainder != NULL) {
1547 			/* reset to host2,host3,... */
1548 			client_connect = remainder;
1549 		} else {
1550 			client_connect = NULL;
1551 		}
1552 	}
1553 }
1554 
loop_for_connect(int did_client_connect)1555 static void loop_for_connect(int did_client_connect) {
1556 	int loop = 0;
1557 	time_t start = time(NULL);
1558 
1559 	if (first_conn_timeout < 0) {
1560 		first_conn_timeout = -first_conn_timeout;
1561 	}
1562 
1563 	while (1) {
1564 		loop++;
1565 		if (first_conn_timeout && time(NULL) > start + first_conn_timeout) {
1566 			rfbLog("no client connect after %d seconds.\n", first_conn_timeout);
1567 			shut_down = 1;
1568 		}
1569 		if (shut_down) {
1570 			clean_up_exit(0);
1571 		}
1572 		if (loop < 2) {
1573 			if (did_client_connect) {
1574 				goto screen_check;
1575 			}
1576 			if (inetd) {
1577 				goto screen_check;
1578 			}
1579 			if (screen && screen->clientHead) {
1580 				goto screen_check;
1581 			}
1582 		}
1583 		if ((use_openssl || use_stunnel) && !inetd) {
1584 			int enc_none = (enc_str && !strcmp(enc_str, "none"));
1585 			if (!use_stunnel || enc_none) {
1586 				check_openssl();
1587 				check_https();
1588 			}
1589 			/*
1590 			 * This is to handle an initial verify cert from viewer,
1591 			 * they disconnect right after fetching the cert.
1592 			 */
1593 			if (use_threads) {
1594 				usleep(10 * 1000);
1595 			} else {
1596 				rfbPE(-1);
1597 			}
1598 			if (screen && screen->clientHead) {
1599 				int i;
1600 				if (unixpw) {
1601 					if (! unixpw_in_progress && !vencrypt_enable_plain_login) {
1602 						rfbLog("unixpw but no unixpw_in_progress\n");
1603 						clean_up_exit(1);
1604 					}
1605 					if (unixpw_client && unixpw_client->onHold) {
1606 						rfbLog("taking unixpw_client off hold\n");
1607 						unixpw_client->onHold = FALSE;
1608 					}
1609 				}
1610 				for (i=0; i<10; i++) {
1611 					if (shut_down) {
1612 						clean_up_exit(0);
1613 					}
1614 					usleep(20 * 1000);
1615 					if (0) rfbLog("wait_for_client: %d\n", i);
1616 
1617 					if (! use_threads) {
1618 						if (unixpw) {
1619 							unixpw_in_rfbPE = 1;
1620 						}
1621 						rfbPE(-1);
1622 						if (unixpw) {
1623 							unixpw_in_rfbPE = 0;
1624 						}
1625 					}
1626 
1627 					if (unixpw && !unixpw_in_progress) {
1628 						/* XXX too soon. */
1629 						goto screen_check;
1630 					}
1631 					if (!screen->clientHead) {
1632 						break;
1633 					}
1634 				}
1635 			}
1636 		} else if (use_openssl) {
1637 			check_openssl();
1638 		}
1639 
1640 		if (use_threads) {
1641 			usleep(10 * 1000);
1642 		} else {
1643 			rfbPE(-1);
1644 		}
1645 
1646 		screen_check:
1647 		if (! screen || ! screen->clientHead) {
1648 			usleep(100 * 1000);
1649 			continue;
1650 		}
1651 
1652 		rfbLog("wait_for_client: got client\n");
1653 		break;
1654 	}
1655 }
1656 
do_unixpw_loop(void)1657 static void do_unixpw_loop(void) {
1658 	if (unixpw) {
1659 		if (! unixpw_in_progress && !vencrypt_enable_plain_login) {
1660 			rfbLog("unixpw but no unixpw_in_progress\n");
1661 			clean_up_exit(1);
1662 		}
1663 		if (unixpw_client && unixpw_client->onHold) {
1664 			rfbLog("taking unixpw_client off hold.\n");
1665 			unixpw_client->onHold = FALSE;
1666 		}
1667 		while (1) {
1668 			if (shut_down) {
1669 				clean_up_exit(0);
1670 			}
1671 			if (! use_threads) {
1672 				unixpw_in_rfbPE = 1;
1673 				rfbPE(-1);
1674 				unixpw_in_rfbPE = 0;
1675 			}
1676 			if (unixpw_in_progress) {
1677 				static double lping = 0.0;
1678 				if (lping < dnow() + 5) {
1679 					mark_rect_as_modified(0, 0, 1, 1, 1);
1680 					lping = dnow();
1681 				}
1682 				if (time(NULL) > unixpw_last_try_time + 45) {
1683 					rfbLog("unixpw_deny: timed out waiting for reply.\n");
1684 					unixpw_deny();
1685 				}
1686 				usleep(20 * 1000);
1687 				continue;
1688 			}
1689 			rfbLog("wait_for_client: unixpw finished.\n");
1690 			break;
1691 		}
1692 	}
1693 }
1694 
vnc_redirect_loop(char * vnc_redirect_test,int * vnc_redirect_cnt)1695 static void vnc_redirect_loop(char *vnc_redirect_test, int *vnc_redirect_cnt) {
1696 	if (unixpw) {
1697 		rfbLog("wait_for_client: -unixpw and Xvnc.redirect not allowed\n");
1698 		clean_up_exit(1);
1699 	}
1700 	if (client_connect) {
1701 		rfbLog("wait_for_client: -connect and Xvnc.redirect not allowed\n");
1702 		clean_up_exit(1);
1703 	}
1704 	if (inetd) {
1705 		if (use_openssl) {
1706 			accept_openssl(OPENSSL_INETD, -1);
1707 		}
1708 	} else {
1709 		pid_t pid = 0;
1710 		/* XXX ipv6 */
1711 		if (screen->httpListenSock >= 0) {
1712 #if LIBVNCSERVER_HAVE_FORK
1713 			if ((pid = fork()) > 0) {
1714 				close(screen->httpListenSock);
1715 				/* mutex */
1716 				screen->httpListenSock = -2;
1717 				usleep(500 * 1000);
1718 			} else {
1719 				close(screen->listenSock);
1720 				screen->listenSock = -1;
1721 				while (1) {
1722 					usleep(10 * 1000);
1723 					rfbHttpCheckFds(screen);
1724 				}
1725 				exit(1);
1726 			}
1727 #else
1728 			clean_up_exit(1);
1729 #endif
1730 		}
1731 		if (first_conn_timeout) {
1732 			if (first_conn_timeout < 0) {
1733 				first_conn_timeout = -first_conn_timeout;
1734 			}
1735 			signal(SIGALRM, vnc_redirect_timeout);
1736 			alarm(first_conn_timeout);
1737 		}
1738 		if (use_openssl) {
1739 			int i;
1740 			if (pid == 0) {
1741 				accept_openssl(OPENSSL_VNC, -1);
1742 			} else {
1743 				for (i=0; i < 16; i++) {
1744 					accept_openssl(OPENSSL_VNC, -1);
1745 					rfbLog("iter %d: vnc_redirect_sock: %d\n", i, vnc_redirect_sock);
1746 					if (vnc_redirect_sock >= 0) {
1747 						break;
1748 					}
1749 				}
1750 			}
1751 		} else {
1752 			struct sockaddr_in addr;
1753 #ifdef __hpux
1754 			int addrlen = sizeof(addr);
1755 #else
1756 			socklen_t addrlen = sizeof(addr);
1757 #endif
1758 			if (screen->listenSock < 0) {
1759 				rfbLog("wait_for_client: Xvnc.redirect not listening... sock=%d port=%d\n", screen->listenSock, screen->port);
1760 				clean_up_exit(1);
1761 			}
1762 			vnc_redirect_sock = accept(screen->listenSock, (struct sockaddr *)&addr, &addrlen);
1763 		}
1764 		if (first_conn_timeout) {
1765 			alarm(0);
1766 		}
1767 		if (pid > 0) {
1768 #if LIBVNCSERVER_HAVE_FORK
1769 			int rc;
1770 			pid_t pidw;
1771 			rfbLog("wait_for_client: kill TERM: %d\n", (int) pid);
1772 			kill(pid, SIGTERM);
1773 			usleep(1000 * 1000);	/* 1.0 sec */
1774 			pidw = waitpid(pid, &rc, WNOHANG);
1775 			if (pidw <= 0) {
1776 				usleep(1000 * 1000);	/* 1.0 sec */
1777 				pidw = waitpid(pid, &rc, WNOHANG);
1778 			}
1779 #else
1780 			clean_up_exit(1);
1781 #endif
1782 		}
1783 	}
1784 	if (vnc_redirect_sock < 0) {
1785 		rfbLog("wait_for_client: vnc_redirect failed.\n");
1786 		clean_up_exit(1);
1787 	}
1788 	if (!inetd && use_openssl) {
1789 		/* check for Fetch Cert closing */
1790 		fd_set rfds;
1791 		struct timeval tv;
1792 		int nfds;
1793 
1794 		usleep(300*1000);
1795 
1796 		FD_ZERO(&rfds);
1797 		FD_SET(vnc_redirect_sock, &rfds);
1798 
1799 		tv.tv_sec = 0;
1800 		tv.tv_usec = 200000;
1801 		nfds = select(vnc_redirect_sock+1, &rfds, NULL, NULL, &tv);
1802 
1803 		rfbLog("wait_for_client: vnc_redirect nfds: %d\n", nfds);
1804 		if (nfds > 0) {
1805 			int n;
1806 			n = read(vnc_redirect_sock, vnc_redirect_test, 1);
1807 			if (n <= 0) {
1808 				close(vnc_redirect_sock);
1809 				vnc_redirect_sock = -1;
1810 				rfbLog("wait_for_client: waiting for 2nd connection (Fetch Cert?)\n");
1811 				accept_openssl(OPENSSL_VNC, -1);
1812 				if (vnc_redirect_sock < 0) {
1813 					rfbLog("wait_for_client: vnc_redirect failed.\n");
1814 					clean_up_exit(1);
1815 				}
1816 			} else {
1817 				*vnc_redirect_cnt = n;
1818 			}
1819 		}
1820 	}
1821 }
1822 
do_vnc_redirect(int created_disp,char * vnc_redirect_host,int vnc_redirect_port,int vnc_redirect_cnt,char * vnc_redirect_test)1823 static void do_vnc_redirect(int created_disp, char *vnc_redirect_host, int vnc_redirect_port,
1824     int vnc_redirect_cnt, char *vnc_redirect_test) {
1825 	char *q = strrchr(use_dpy, ':');
1826 	int vdpy = -1, sock = -1;
1827 	int s_in, s_out, i;
1828 	if (vnc_redirect == 2) {
1829 		char num[32];
1830 		sprintf(num, ":%d", vnc_redirect_port);
1831 		q = num;
1832 	}
1833 	if (!q) {
1834 		rfbLog("wait_for_client: can't find number in X display: %s\n", use_dpy);
1835 		clean_up_exit(1);
1836 	}
1837 	if (sscanf(q+1, "%d", &vdpy) != 1) {
1838 		rfbLog("wait_for_client: can't find number in X display: %s\n", q);
1839 		clean_up_exit(1);
1840 	}
1841 	if (vdpy == -1 && vnc_redirect != 2) {
1842 		rfbLog("wait_for_client: can't find number in X display: %s\n", q);
1843 		clean_up_exit(1);
1844 	}
1845 	if (vnc_redirect == 2) {
1846 		if (vdpy < 0) {
1847 			vdpy = -vdpy;
1848 		} else if (vdpy < 200) {
1849 			vdpy += 5900;
1850 		}
1851 	} else {
1852 		vdpy += 5900;
1853 	}
1854 	if (created_disp) {
1855 		usleep(1000*1000);
1856 	}
1857 	for (i=0; i < 20; i++) {
1858 		sock = connect_tcp(vnc_redirect_host, vdpy);
1859 		if (sock >= 0) {
1860 			break;
1861 		}
1862 		rfbLog("wait_for_client: ...\n");
1863 		usleep(500*1000);
1864 	}
1865 	if (sock < 0) {
1866 		rfbLog("wait_for_client: could not connect to a VNC Server at %s:%d\n", vnc_redirect_host, vdpy);
1867 		clean_up_exit(1);
1868 	}
1869 	if (inetd) {
1870 		s_in  = fileno(stdin);
1871 		s_out = fileno(stdout);
1872 	} else {
1873 		s_in = s_out = vnc_redirect_sock;
1874 	}
1875 	if (vnc_redirect_cnt > 0) {
1876 		write(vnc_redirect_sock, vnc_redirect_test, vnc_redirect_cnt);
1877 	}
1878 	rfbLog("wait_for_client: switching control to VNC Server at %s:%d\n", vnc_redirect_host, vdpy);
1879 	raw_xfer(sock, s_in, s_out);
1880 }
1881 
1882 extern char find_display[];
1883 extern char create_display[];
1884 
setup_cmd(char * str,int * vnc_redirect,char ** vnc_redirect_host,int * vnc_redirect_port,int db)1885 char *setup_cmd(char *str, int *vnc_redirect, char **vnc_redirect_host, int *vnc_redirect_port, int db) {
1886 	char *cmd = NULL;
1887 
1888 	if (no_external_cmds || !cmd_ok("WAIT")) {
1889 		rfbLog("wait_for_client external cmds not allowed:"
1890 		    " %s\n", use_dpy);
1891 		clean_up_exit(1);
1892 	}
1893 
1894 	cmd = str + strlen("cmd=");
1895 	if (!strcmp(cmd, "FINDDISPLAY-print")) {
1896 		fprintf(stdout, "%s", find_display);
1897 		clean_up_exit(0);
1898 	}
1899 	if (!strcmp(cmd, "FINDDISPLAY-run")) {
1900 		char tmp[] = "/tmp/fd.XXXXXX";
1901 		char com[100];
1902 		int fd = mkstemp(tmp);
1903 		if (fd >= 0) {
1904 			int ret;
1905 			write(fd, find_display, strlen(find_display));
1906 			close(fd);
1907 			set_env("FINDDISPLAY_run", "1");
1908 			sprintf(com, "/bin/sh %s -n", tmp);
1909 			ret = system(com);
1910 			if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) {
1911 				if (got_findauth && !getenv("FD_XDM")) {
1912 					if (getuid() == 0 || geteuid() == 0) {
1913 						set_env("FD_XDM", "1");
1914 						system(com);
1915 					}
1916 				}
1917 			}
1918 		}
1919 		unlink(tmp);
1920 		exit(0);
1921 	}
1922 	if (!strcmp(str, "FINDCREATEDISPLAY-print")) {
1923 		fprintf(stdout, "%s", create_display);
1924 		clean_up_exit(0);
1925 	}
1926 	if (db) fprintf(stderr, "cmd: %s\n", cmd);
1927 	if (strstr(str, "FINDCREATEDISPLAY") || strstr(str, "FINDDISPLAY")) {
1928 		if (strstr(str, "Xvnc.redirect") || strstr(str, "X.redirect")) {
1929 			*vnc_redirect = 1;
1930 		}
1931 	}
1932 	if (strstr(cmd, "FINDDISPLAY-vnc_redirect") == cmd) {
1933 		int p;
1934 		char h[256];
1935 		if (strlen(cmd) >= 256) {
1936 			rfbLog("wait_for_client string too long: %s\n", str);
1937 			clean_up_exit(1);
1938 		}
1939 		h[0] = '\0';
1940 		if (sscanf(cmd, "FINDDISPLAY-vnc_redirect=%d", &p) == 1) {
1941 			;
1942 		} else if (sscanf(cmd, "FINDDISPLAY-vnc_redirect=%s %d", h, &p) == 2) {
1943 			;
1944 		} else {
1945 			rfbLog("wait_for_client bad string: %s\n", cmd);
1946 			clean_up_exit(1);
1947 		}
1948 		*vnc_redirect_port = p;
1949 		if (strcmp(h, "")) {
1950 			*vnc_redirect_host = strdup(h);
1951 		}
1952 		*vnc_redirect = 2;
1953 		rfbLog("wait_for_client: vnc_redirect: %s:%d\n", *vnc_redirect_host, *vnc_redirect_port);
1954 	}
1955 	return cmd;
1956 }
1957 
build_create_cmd(char * cmd,int * saw_xdmcp,char * usslpeer,char * tmp)1958 static char *build_create_cmd(char *cmd, int *saw_xdmcp, char *usslpeer, char *tmp) {
1959 	char *create_cmd = NULL;
1960 	char *opts = strchr(cmd, '-');
1961 	char st[] = "";
1962 	char fdgeom[128], fdsess[128], fdopts[128], fdextra[256], fdprog[128];
1963 	char fdxsrv[128], fdxdum[128], fdcups[128], fdesd[128];
1964 	char fdnas[128], fdsmb[128], fdtag[128], fdxdmcpif[128];
1965 	char cdout[128];
1966 
1967 	if (opts) {
1968 		opts++;
1969 		if (strstr(opts, "xdmcp")) {
1970 			*saw_xdmcp = 1;
1971 		}
1972 	} else {
1973 		opts = st;
1974 	}
1975 	sprintf(fdgeom, "NONE");
1976 	fdsess[0] = '\0';
1977 	fdgeom[0] = '\0';
1978 	fdopts[0] = '\0';
1979 	fdextra[0] = '\0';
1980 	fdprog[0] = '\0';
1981 	fdxsrv[0] = '\0';
1982 	fdxdum[0] = '\0';
1983 	fdcups[0] = '\0';
1984 	fdesd[0]  = '\0';
1985 	fdnas[0]  = '\0';
1986 	fdsmb[0]  = '\0';
1987 	fdtag[0]  = '\0';
1988 	fdxdmcpif[0]  = '\0';
1989 	cdout[0]  = '\0';
1990 
1991 	if (unixpw && keep_unixpw_opts && !getenv("X11VNC_NO_UNIXPW_OPTS")) {
1992 		char *q, *p, *t = strdup(keep_unixpw_opts);
1993 
1994 		if (strstr(t, "gnome")) {
1995 			sprintf(fdsess, "gnome");
1996 		} else if (strstr(t, "kde")) {
1997 			sprintf(fdsess, "kde");
1998 		} else if (strstr(t, "lxde")) {
1999 			sprintf(fdsess, "lxde");
2000 		} else if (strstr(t, "twm")) {
2001 			sprintf(fdsess, "twm");
2002 		} else if (strstr(t, "fvwm")) {
2003 			sprintf(fdsess, "fvwm");
2004 		} else if (strstr(t, "mwm")) {
2005 			sprintf(fdsess, "mwm");
2006 		} else if (strstr(t, "cde")) {
2007 			sprintf(fdsess, "cde");
2008 		} else if (strstr(t, "dtwm")) {
2009 			sprintf(fdsess, "dtwm");
2010 		} else if (strstr(t, "xterm")) {
2011 			sprintf(fdsess, "xterm");
2012 		} else if (strstr(t, "wmaker")) {
2013 			sprintf(fdsess, "wmaker");
2014 		} else if (strstr(t, "xfce")) {
2015 			sprintf(fdsess, "xfce");
2016 		} else if (strstr(t, "enlightenment")) {
2017 			sprintf(fdsess, "enlightenment");
2018 		} else if (strstr(t, "Xsession")) {
2019 			sprintf(fdsess, "Xsession");
2020 		} else if (strstr(t, "failsafe")) {
2021 			sprintf(fdsess, "failsafe");
2022 		}
2023 
2024 		q = strstr(t, "ge=");
2025 		if (! q) q = strstr(t, "geom=");
2026 		if (! q) q = strstr(t, "geometry=");
2027 		if (q) {
2028 			int ok = 1;
2029 			q = strstr(q, "=");
2030 			q++;
2031 			p = strstr(q, ",");
2032 			if (p) *p = '\0';
2033 			p = q;
2034 			while (*p) {
2035 				if (*p == 'x') {
2036 					;
2037 				} else if (isdigit((int) *p)) {
2038 					;
2039 				} else {
2040 					ok = 0;
2041 					break;
2042 				}
2043 				p++;
2044 			}
2045 			if (ok && strlen(q) < 32) {
2046 				sprintf(fdgeom, "%s", q);
2047 				if (!quiet) {
2048 					rfbLog("set create display geom: %s\n", fdgeom);
2049 				}
2050 			}
2051 		}
2052 		q = strstr(t, "cups=");
2053 		if (q) {
2054 			int p;
2055 			if (sscanf(q, "cups=%d", &p) == 1) {
2056 				sprintf(fdcups, "%d", p);
2057 			}
2058 		}
2059 		q = strstr(t, "esd=");
2060 		if (q) {
2061 			int p;
2062 			if (sscanf(q, "esd=%d", &p) == 1) {
2063 				sprintf(fdesd, "%d", p);
2064 			}
2065 		}
2066 		if (!getenv("FD_TAG")) {
2067 			char *s = NULL;
2068 
2069 			q = strstr(t, "tag=");
2070 			if (q) s = strchr(q, ',');
2071 			if (s) *s = '\0';
2072 
2073 			if (q && strlen(q) < 120) {
2074 				char *p;
2075 				int ok = 1;
2076 				q = strchr(q, '=') + 1;
2077 				p = q;
2078 				while (*p != '\0') {
2079 					char c = *p;
2080 					if (*p == '_' || *p == '-') {
2081 						;
2082 					} else if (!isalnum((int) c)) {
2083 						ok = 0;
2084 						rfbLog("bad tag char: '%c' in '%s'\n", c, q);
2085 						break;
2086 					}
2087 					p++;
2088 				}
2089 				if (ok) {
2090 					sprintf(fdtag, "%s", q);
2091 				}
2092 			}
2093 			if (s) *s = ',';
2094 		}
2095 		free(t);
2096 	}
2097 	if (fdgeom[0] == '\0' && getenv("FD_GEOM")) {
2098 		snprintf(fdgeom,  sizeof fdgeom, "%s", getenv("FD_GEOM"));
2099 	}
2100 	if (fdsess[0] == '\0' && getenv("FD_SESS")) {
2101 		snprintf(fdsess, sizeof fdsess, "%s", getenv("FD_SESS"));
2102 	}
2103 	if (fdopts[0] == '\0' && getenv("FD_OPTS")) {
2104 		snprintf(fdopts, sizeof fdopts, "%s", getenv("FD_OPTS"));
2105 	}
2106 	if (fdextra[0] == '\0' && getenv("FD_EXTRA")) {
2107 		if (!strchr(getenv("FD_EXTRA"), '\'')) {
2108 			snprintf(fdextra, sizeof fdextra, "%s", getenv("FD_EXTRA"));
2109 		}
2110 	}
2111 	if (fdprog[0] == '\0' && getenv("FD_PROG")) {
2112 		snprintf(fdprog, sizeof fdprog, "%s", getenv("FD_PROG"));
2113 	}
2114 	if (fdxsrv[0] == '\0' && getenv("FD_XSRV")) {
2115 		snprintf(fdxsrv, sizeof fdxsrv, "%s", getenv("FD_XSRV"));
2116 	}
2117 	if (fdcups[0] == '\0' && getenv("FD_CUPS")) {
2118 		snprintf(fdcups, sizeof fdcups, "%s", getenv("FD_CUPS"));
2119 	}
2120 	if (fdesd[0] == '\0' && getenv("FD_ESD")) {
2121 		snprintf(fdesd, sizeof fdesd, "%s", getenv("FD_ESD"));
2122 	}
2123 	if (fdnas[0] == '\0' && getenv("FD_NAS")) {
2124 		snprintf(fdnas, sizeof fdnas, "%s", getenv("FD_NAS"));
2125 	}
2126 	if (fdsmb[0] == '\0' && getenv("FD_SMB")) {
2127 		snprintf(fdsmb, sizeof fdsmb, "%s", getenv("FD_SMB"));
2128 	}
2129 	if (fdtag[0] == '\0' && getenv("FD_TAG")) {
2130 		snprintf(fdtag, sizeof fdtag, "%s", getenv("FD_TAG"));
2131 	}
2132 	if (fdxdmcpif[0] == '\0' && getenv("FD_XDMCP_IF")) {
2133 		snprintf(fdxdmcpif,  sizeof fdxdmcpif, "%s", getenv("FD_XDMCP_IF"));
2134 	}
2135 	if (fdxdum[0] == '\0' && getenv("FD_XDUMMY_RUN_AS_ROOT")) {
2136 		snprintf(fdxdum, sizeof fdxdum, "%s", getenv("FD_XDUMMY_RUN_AS_ROOT"));
2137 	}
2138 	if (getenv("CREATE_DISPLAY_OUTPUT")) {
2139 		snprintf(cdout, sizeof cdout, "CREATE_DISPLAY_OUTPUT='%s'", getenv("CREATE_DISPLAY_OUTPUT"));
2140 	}
2141 
2142 	if (strchr(fdgeom, '\''))	fdgeom[0] = '\0';
2143 	if (strchr(fdopts, '\''))	fdopts[0] = '\0';
2144 	if (strchr(fdextra, '\''))	fdextra[0] = '\0';
2145 	if (strchr(fdprog, '\''))	fdprog[0] = '\0';
2146 	if (strchr(fdxsrv, '\''))	fdxsrv[0] = '\0';
2147 	if (strchr(fdcups, '\''))	fdcups[0] = '\0';
2148 	if (strchr(fdesd, '\''))	fdesd[0] = '\0';
2149 	if (strchr(fdnas, '\''))	fdnas[0] = '\0';
2150 	if (strchr(fdsmb, '\''))	fdsmb[0] = '\0';
2151 	if (strchr(fdtag, '\''))	fdtag[0] = '\0';
2152 	if (strchr(fdxdmcpif, '\''))	fdxdmcpif[0] = '\0';
2153 	if (strchr(fdxdum, '\''))	fdxdum[0] = '\0';
2154 	if (strchr(fdsess, '\''))	fdsess[0] = '\0';
2155 	if (strchr(cdout, '\''))	cdout[0] = '\0';
2156 
2157 	set_env("FD_GEOM", fdgeom);
2158 	set_env("FD_OPTS", fdopts);
2159 	set_env("FD_EXTRA", fdextra);
2160 	set_env("FD_PROG", fdprog);
2161 	set_env("FD_XSRV", fdxsrv);
2162 	set_env("FD_CUPS", fdcups);
2163 	set_env("FD_ESD",  fdesd);
2164 	set_env("FD_NAS",  fdnas);
2165 	set_env("FD_SMB",  fdsmb);
2166 	set_env("FD_TAG",  fdtag);
2167 	set_env("FD_XDMCP_IF",  fdxdmcpif);
2168 	set_env("FD_XDUMMY_RUN_AS_ROOT", fdxdum);
2169 	set_env("FD_SESS", fdsess);
2170 
2171 	if (usslpeer || (unixpw && keep_unixpw_user)) {
2172 		char *uu = usslpeer;
2173 		if (!uu) {
2174 			uu = keep_unixpw_user;
2175 		}
2176 		if (strchr(uu, '\''))  {
2177 			uu = "";
2178 		}
2179 		create_cmd = (char *) malloc(strlen(tmp)+1
2180 		    + strlen("env USER='' ")
2181 		    + strlen("FD_GEOM='' ")
2182 		    + strlen("FD_OPTS='' ")
2183 		    + strlen("FD_EXTRA='' ")
2184 		    + strlen("FD_PROG='' ")
2185 		    + strlen("FD_XSRV='' ")
2186 		    + strlen("FD_CUPS='' ")
2187 		    + strlen("FD_ESD='' ")
2188 		    + strlen("FD_NAS='' ")
2189 		    + strlen("FD_SMB='' ")
2190 		    + strlen("FD_TAG='' ")
2191 		    + strlen("FD_XDMCP_IF='' ")
2192 		    + strlen("FD_XDUMMY_RUN_AS_ROOT='' ")
2193 		    + strlen("FD_SESS='' /bin/sh ")
2194 		    + strlen(uu) + 1
2195 		    + strlen(fdgeom) + 1
2196 		    + strlen(fdopts) + 1
2197 		    + strlen(fdextra) + 1
2198 		    + strlen(fdprog) + 1
2199 		    + strlen(fdxsrv) + 1
2200 		    + strlen(fdcups) + 1
2201 		    + strlen(fdesd) + 1
2202 		    + strlen(fdnas) + 1
2203 		    + strlen(fdsmb) + 1
2204 		    + strlen(fdtag) + 1
2205 		    + strlen(fdxdmcpif) + 1
2206 		    + strlen(fdxdum) + 1
2207 		    + strlen(fdsess) + 1
2208 		    + strlen(cdout) + 1
2209 		    + strlen(opts) + 1);
2210 		sprintf(create_cmd, "env USER='%s' FD_GEOM='%s' FD_SESS='%s' "
2211 		    "FD_OPTS='%s' FD_EXTRA='%s' FD_PROG='%s' FD_XSRV='%s' FD_CUPS='%s' "
2212 		    "FD_ESD='%s' FD_NAS='%s' FD_SMB='%s' FD_TAG='%s' FD_XDMCP_IF='%s' "
2213 		    "FD_XDUMMY_RUN_AS_ROOT='%s' %s /bin/sh %s %s",
2214 		    uu, fdgeom, fdsess, fdopts, fdextra, fdprog, fdxsrv,
2215 		    fdcups, fdesd, fdnas, fdsmb, fdtag, fdxdmcpif, fdxdum, cdout, tmp, opts);
2216 	} else {
2217 		create_cmd = (char *) malloc(strlen(tmp)
2218 		    + strlen("/bin/sh ") + 1 + strlen(opts) + 1);
2219 		sprintf(create_cmd, "/bin/sh %s %s", tmp, opts);
2220 	}
2221 	return create_cmd;
2222 }
2223 
certret_extract()2224 static char *certret_extract() {
2225 	char *q, *p, *str = strdup(certret_str);
2226 	char *upeer = NULL;
2227 	int ok = 0;
2228 
2229 	q = strstr(str, "Subject: ");
2230 	if (! q) return NULL;
2231 
2232 	p = strstr(q, "\n");
2233 	if (p) *p = '\0';
2234 
2235 	q = strstr(q, "CN=");
2236 	if (! q) return NULL;
2237 
2238 	if (! getenv("X11VNC_SSLPEER_CN")) {
2239 		p = q;
2240 		q = strstr(q, "/emailAddress=");
2241 		if (! q) q = strstr(p, "/Email=");
2242 		if (! q) return NULL;
2243 	}
2244 
2245 	q = strstr(q, "=");
2246 	if (! q) return NULL;
2247 
2248 	q++;
2249 	p = strstr(q, " ");
2250 	if (p) *p = '\0';
2251 	p = strstr(q, "@");
2252 	if (p) *p = '\0';
2253 	p = strstr(q, "/");
2254 	if (p) *p = '\0';
2255 
2256 	upeer = strdup(q);
2257 
2258 	if (strcmp(upeer, "")) {
2259 		p = upeer;
2260 		while (*p != '\0') {
2261 			char c = *p;
2262 			if (!isalnum((int) c)) {
2263 				*p = '\0';
2264 				break;
2265 			}
2266 			p++;
2267 		}
2268 		if (strcmp(upeer, "")) {
2269 			ok = 1;
2270 		}
2271 	}
2272 	if (! ok) {
2273 		upeer = NULL;
2274 	}
2275 	return upeer;
2276 }
2277 
check_nodisplay(char ** nd,char ** tag)2278 static void check_nodisplay(char **nd, char **tag) {
2279 	if (unixpw && !getenv("X11VNC_NO_UNIXPW_OPTS") && keep_unixpw_opts && keep_unixpw_opts[0] != '\0') {
2280 		char *q, *t2, *t = keep_unixpw_opts;
2281 		q = strstr(t, "nd=");
2282 		if (! q) q = strstr(t, "nodisplay=");
2283 		if (q) {
2284 			q = strchr(q, '=') + 1;
2285 			t = strdup(q);
2286 			q = t;
2287 			t2 = strchr(t, ',');
2288 			if (t2) *t2 = '\0';
2289 
2290 			while (*t != '\0') {
2291 				if (*t == '+') {
2292 					*t = ',';
2293 				}
2294 				t++;
2295 			}
2296 			if (!strchr(q, '\'') && !strpbrk(q, "[](){}`'\"$&*|<>")) {
2297 				if (! quiet) rfbLog("set X11VNC_SKIP_DISPLAY: %s\n", q);
2298 				*nd = q;
2299 			}
2300 		}
2301 
2302 		q = strstr(keep_unixpw_opts, "tag=");
2303 		if (getenv("FD_TAG")) {
2304 			*tag = strdup(getenv("FD_TAG"));
2305 		} else if (q) {
2306 			q = strchr(q, '=') + 1;
2307 			t = strdup(q);
2308 			q = t;
2309 			t2 = strchr(t, ',');
2310 			if (t2) *t2 = '\0';
2311 
2312 			if (strlen(q) < 120) {
2313 				int ok = 1;
2314 				while (*t != '\0') {
2315 					char c = *t;
2316 					if (*t == '_' || *t == '-') {
2317 						;
2318 					} else if (!isalnum((int) c)) {
2319 						ok = 0;
2320 						rfbLog("bad tag char: '%c' in '%s'\n", c, q);
2321 						break;
2322 					}
2323 					t++;
2324 				}
2325 				if (ok) {
2326 					if (! quiet) rfbLog("set FD_TAG: %s\n", q);
2327 					*tag = q;
2328 				}
2329 			}
2330 		}
2331 	}
2332 	if (unixpw_system_greeter_active == 2) {
2333 		if (!keep_unixpw_user) {
2334 			clean_up_exit(1);
2335 		}
2336 		*nd = strdup("all");
2337 	}
2338 }
2339 
get_usslpeer()2340 static char *get_usslpeer() {
2341 	char *u = NULL, *upeer = NULL;
2342 
2343 	if (certret_str) {
2344 		upeer = certret_extract();
2345 	}
2346 	if (!upeer) {
2347 		return NULL;
2348 	}
2349 	rfbLog("sslpeer unix username extracted from x509 cert: %s\n", upeer);
2350 
2351 	u = (char *) malloc(strlen(upeer+2));
2352 	u[0] = '\0';
2353 	if (!strcmp(users_list, "sslpeer=")) {
2354 		sprintf(u, "+%s", upeer);
2355 	} else {
2356 		char *p, *str = strdup(users_list);
2357 		p = strtok(str + strlen("sslpeer="), ",");
2358 		while (p) {
2359 			if (!strcmp(p, upeer)) {
2360 				sprintf(u, "+%s", upeer);
2361 				break;
2362 			}
2363 			p = strtok(NULL, ",");
2364 		}
2365 		free(str);
2366 	}
2367 	if (u[0] == '\0') {
2368 		rfbLog("sslpeer cannot determine user: %s\n", upeer);
2369 		free(u);
2370 		return NULL;
2371 	}
2372 	free(u);
2373 	return upeer;
2374 }
2375 
do_try_switch(char * usslpeer,char * users_list_save)2376 static void do_try_switch(char *usslpeer, char *users_list_save) {
2377 	if (unixpw_system_greeter_active == 2) {
2378 		rfbLog("unixpw_system_greeter: not trying switch to user '%s'\n", usslpeer ? usslpeer : "");
2379 		return;
2380 	}
2381 	if (usslpeer) {
2382 		char *u = (char *) malloc(strlen(usslpeer+2));
2383 		sprintf(u, "+%s", usslpeer);
2384 		if (switch_user(u, 0)) {
2385 			rfbLog("sslpeer switched to user: %s\n", usslpeer);
2386 		} else {
2387 			rfbLog("sslpeer failed to switch to user: %s\n", usslpeer);
2388 		}
2389 		free(u);
2390 
2391 	} else if (users_list_save && keep_unixpw_user) {
2392 		char *user = keep_unixpw_user;
2393 		char *u = (char *)malloc(strlen(user)+1);
2394 
2395 		users_list = users_list_save;
2396 
2397 		u[0] = '\0';
2398 		if (!strcmp(users_list, "unixpw=")) {
2399 			sprintf(u, "+%s", user);
2400 		} else {
2401 			char *p, *str = strdup(users_list);
2402 			p = strtok(str + strlen("unixpw="), ",");
2403 			while (p) {
2404 				if (!strcmp(p, user)) {
2405 					sprintf(u, "+%s", user);
2406 					break;
2407 				}
2408 				p = strtok(NULL, ",");
2409 			}
2410 			free(str);
2411 		}
2412 
2413 		if (u[0] == '\0') {
2414 			rfbLog("unixpw_accept skipping switch to user: %s (drc)\n", user);
2415 		} else if (switch_user(u, 0)) {
2416 			rfbLog("unixpw_accept switched to user: %s (drc)\n", user);
2417 		} else {
2418 			rfbLog("unixpw_accept failed to switch to user: %s (drc)\n", user);
2419 		}
2420 		free(u);
2421 	}
2422 }
2423 
path_lookup(char * prog)2424 static void path_lookup(char *prog) {
2425 	/* see create_display script */
2426 	char *create_display_extra = "/usr/X11R6/bin:/usr/bin/X11:/usr/openwin/bin:/usr/dt/bin:/opt/kde4/bin:/opt/kde3/bin:/opt/gnome/bin:/usr/bin:/bin:/usr/sfw/bin:/usr/local/bin";
2427 	char *path, *try, *p;
2428 	int found = 0, len = strlen(create_display_extra);
2429 
2430 	if (getenv("PATH")) {
2431 		len += strlen(getenv("PATH")) + 1;
2432 		path = (char *) malloc((len+1) * sizeof(char));
2433 		sprintf(path, "%s:%s", getenv("PATH"), create_display_extra);
2434 	} else {
2435 		path = (char *) malloc((len+1) * sizeof(char));
2436 		sprintf(path, "%s", create_display_extra);
2437 	}
2438 	try = (char *) malloc((len+2+strlen(prog)) * sizeof(char));
2439 
2440 	p = strtok(path, ":");
2441 	while (p) {
2442 		struct stat sbuf;
2443 
2444 		sprintf(try, "%s/%s", p, prog);
2445 		if (stat(try, &sbuf) == 0) {
2446 			found = 1;
2447 			break;
2448 		}
2449 		p = strtok(NULL, ":");
2450 	}
2451 
2452 	free(path);
2453 	free(try);
2454 
2455 	if (!found) {
2456 		fprintf(stderr, "\n");
2457 		fprintf(stderr, "The program \"%s\" could not be found in PATH and standard locations.\n", prog);
2458 		fprintf(stderr, "You probably need to install a package that provides the \"%s\" program.\n", prog);
2459 		fprintf(stderr, "Without it FINDCREATEDISPLAY mode may not be able to create an X display.\n");
2460 		fprintf(stderr, "\n");
2461 	}
2462 }
2463 
do_run_cmd(char * cmd,char * create_cmd,char * users_list_save,int created_disp,int db)2464 static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int created_disp, int db) {
2465 	char tmp[] = "/tmp/x11vnc-find_display.XXXXXX";
2466 	char line1[1024], line2[16384];
2467 	char *q, *usslpeer = NULL;
2468 	int n, nodisp = 0, saw_xdmcp = 0;
2469 	int tmp_fd = -1;
2470 	int internal_cmd = 0;
2471 	int tried_switch = 0;
2472 
2473 	memset(line1, 0, sizeof(line1));
2474 	memset(line2, 0, sizeof(line2));
2475 
2476 	if (users_list && strstr(users_list, "sslpeer=") == users_list) {
2477 		usslpeer = get_usslpeer();
2478 		if (! usslpeer) {
2479 			return 0;
2480 		}
2481 	}
2482 	if (getenv("DEBUG_RUN_CMD")) db = 1;
2483 
2484 	/* only sets environment variables: */
2485 	run_user_command("", latest_client, "env", NULL, 0, NULL);
2486 
2487 	if (program_name) {
2488 		set_env("X11VNC_PROG", program_name);
2489 	} else {
2490 		set_env("X11VNC_PROG", "x11vnc");
2491 	}
2492 
2493 	if (!strcmp(cmd, "FINDDISPLAY") ||
2494 	    strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
2495 		char *nd = "";
2496 		char *tag = "";
2497 		char fdout[128];
2498 
2499 		internal_cmd = 1;
2500 
2501 		tmp_fd = mkstemp(tmp);
2502 
2503 		if (tmp_fd < 0) {
2504 			rfbLog("wait_for_client: open failed: %s\n", tmp);
2505 			rfbLogPerror("mkstemp");
2506 			clean_up_exit(1);
2507 		}
2508 		chmod(tmp, 0644);
2509 		if (getenv("X11VNC_FINDDISPLAY_ALWAYS_FAILS")) {
2510 			char *s = "#!/bin/sh\necho _FAIL_\nexit 1\n";
2511 			write(tmp_fd, s, strlen(s));
2512 		} else {
2513 			write(tmp_fd, find_display, strlen(find_display));
2514 		}
2515 		close(tmp_fd);
2516 		nodisp = 1;
2517 
2518 		if (strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
2519 			create_cmd = build_create_cmd(cmd, &saw_xdmcp, usslpeer, tmp);
2520 			if (db) fprintf(stderr, "create_cmd: %s\n", create_cmd);
2521 		}
2522 		if (getenv("X11VNC_SKIP_DISPLAY")) {
2523 			nd = strdup(getenv("X11VNC_SKIP_DISPLAY"));
2524 		}
2525 		check_nodisplay(&nd, &tag);
2526 
2527 		fdout[0] = '\0';
2528 		if (getenv("FIND_DISPLAY_OUTPUT")) {
2529 			snprintf(fdout, sizeof fdout, " FIND_DISPLAY_OUTPUT='%s' ", getenv("FIND_DISPLAY_OUTPUT"));
2530 		}
2531 
2532 		cmd = (char *) malloc(strlen("env X11VNC_SKIP_DISPLAY='' ")
2533 		    + strlen(nd) + strlen(" FD_TAG='' ") + strlen(tag) + strlen(tmp) + strlen("/bin/sh ") + strlen(fdout) + 1);
2534 
2535 		if (strcmp(tag, "")) {
2536 			sprintf(cmd, "env X11VNC_SKIP_DISPLAY='%s' FD_TAG='%s' %s /bin/sh %s", nd, tag, fdout, tmp);
2537 		} else {
2538 			sprintf(cmd, "env X11VNC_SKIP_DISPLAY='%s' %s /bin/sh %s", nd, fdout, tmp);
2539 		}
2540 	}
2541 
2542 	rfbLog("wait_for_client: running: %s\n", cmd);
2543 
2544 	if (create_cmd != NULL) {
2545 		if (strstr(create_cmd, "Xvfb")) {
2546 			path_lookup("Xvfb");
2547 		}
2548 		if (strstr(create_cmd, "Xvnc")) {
2549 			path_lookup("Xvnc");
2550 		}
2551 		if (strstr(create_cmd, "Xdummy")) {
2552 			path_lookup("Xdummy");
2553 		}
2554 	}
2555 
2556 	if (unixpw && !unixpw_nis) {
2557 		int res = 0, k, j, i;
2558 		char line[18000];
2559 
2560 		memset(line, 0, sizeof(line));
2561 
2562 		if (unixpw_system_greeter_active == 2) {
2563 			rfbLog("unixpw_system_greeter: forcing find display failure.\n");
2564 			res = 0;
2565 		} else if (keep_unixpw_user && keep_unixpw_pass) {
2566 			n = sizeof(line);
2567 			if (unixpw_cmd != NULL) {
2568 				res = unixpw_cmd_run(keep_unixpw_user,
2569 				    keep_unixpw_pass, cmd, line, &n);
2570 			} else {
2571 				res = su_verify(keep_unixpw_user,
2572 				    keep_unixpw_pass, cmd, line, &n, nodisp);
2573 			}
2574 		}
2575 
2576 if (db) {fprintf(stderr, "line: "); write(2, line, n); write(2, "\n", 1); fprintf(stderr, "res=%d n=%d\n", res, n);}
2577 		if (! res) {
2578 			rfbLog("wait_for_client: find display cmd failed.\n");
2579 		}
2580 
2581 		if (! res && create_cmd) {
2582 			FILE *mt = fopen(tmp, "w");
2583 			if (! mt) {
2584 				rfbLog("wait_for_client: open failed: %s\n", tmp);
2585 				rfbLogPerror("fopen");
2586 				clean_up_exit(1);
2587 			}
2588 			fprintf(mt, "%s", create_display);
2589 			fclose(mt);
2590 
2591 			findcreatedisplay = 1;
2592 
2593 			if (unixpw_cmd != NULL) {
2594 				/* let the external unixpw command do it: */
2595 				n = sizeof(line);
2596 				close_exec_fds();
2597 				res = unixpw_cmd_run(keep_unixpw_user,
2598 				    keep_unixpw_pass, create_cmd, line, &n);
2599 			} else if (getuid() != 0 && unixpw_system_greeter_active != 2) {
2600 				/* if not root, run as the other user... */
2601 				n = sizeof(line);
2602 				close_exec_fds();
2603 				res = su_verify(keep_unixpw_user,
2604 				    keep_unixpw_pass, create_cmd, line, &n, nodisp);
2605 if (db) fprintf(stderr, "c-res=%d n=%d line: '%s'\n", res, n, line);
2606 
2607 			} else {
2608 				FILE *p;
2609 				close_exec_fds();
2610 				if (unixpw_system_greeter_active == 2) {
2611 					rfbLog("unixpw_system_greeter: not trying su_verify() to run\n");
2612 					rfbLog("unixpw_system_greeter: create display command.\n");
2613 				}
2614 				rfbLog("wait_for_client: running: %s\n", create_cmd);
2615 				p = popen(create_cmd, "r");
2616 				if (! p) {
2617 					rfbLog("wait_for_client: popen failed: %s\n", create_cmd);
2618 					res = 0;
2619 				} else if (fgets(line1, sizeof line1, p) == NULL) {
2620 					rfbLog("wait_for_client: read failed: %s\n", create_cmd);
2621 					res = 0;
2622 				} else {
2623 					n = fread(line2, 1, sizeof line2, p);
2624 					if (pclose(p) != 0) {
2625 						res = 0;
2626 					} else {
2627 						strncpy(line, line1, 100);
2628 						memcpy(line + strlen(line1), line2, n);
2629 if (db) fprintf(stderr, "line1: '%s'\n", line1);
2630 						n += strlen(line1);
2631 						created_disp = 1;
2632 						res = 1;
2633 					}
2634 				}
2635 			}
2636 			if (res && saw_xdmcp && unixpw_system_greeter_active != 2) {
2637 				xdmcp_insert = strdup(keep_unixpw_user);
2638 			}
2639 		}
2640 
2641 		if (tmp_fd >= 0) {
2642 			unlink(tmp);
2643 		}
2644 
2645 		if (! res) {
2646 			rfbLog("wait_for_client: cmd failed: %s\n", cmd);
2647 			unixpw_msg("No DISPLAY found.", 3);
2648 			clean_up_exit(1);
2649 		}
2650 
2651 		/*
2652 		 * we need to hunt for DISPLAY= since there may be
2653 		 * a login banner or something at the beginning.
2654 		 */
2655 		q = strstr(line, "DISPLAY=");
2656 		if (! q) {
2657 			q = line;
2658 		}
2659 		n -= (q - line);
2660 
2661 		for (k = 0; k < 1024; k++) {
2662 			line1[k] = q[k];
2663 			if (q[k] == '\n') {
2664 				k++;
2665 				break;
2666 			}
2667 		}
2668 		n -= k;
2669 		i = 0;
2670 		for (j = 0; j < 16384; j++) {
2671 			if (j < 16384 - 1) {
2672 				/* xauth data, assume pty added CR */
2673 				if (q[k+j] == '\r' && q[k+j+1] == '\n') {
2674 					continue;
2675 				}
2676 			}
2677 
2678 			line2[i] = q[k+j];
2679 			i++;
2680 		}
2681 if (db) write(2, line, 100);
2682 if (db) fprintf(stderr, "\n");
2683 
2684 	} else {
2685 		FILE *p;
2686 		int rc;
2687 		close_exec_fds();
2688 
2689 		if (usslpeer) {
2690 			char *c;
2691 			if (getuid() == 0) {
2692 				c = (char *) malloc(strlen("su - '' -c \"")
2693 				    + strlen(usslpeer) + strlen(cmd) + 1 + 1);
2694 				sprintf(c, "su - '%s' -c \"%s\"", usslpeer, cmd);
2695 			} else {
2696 				c = strdup(cmd);
2697 			}
2698 			p = popen(c, "r");
2699 			free(c);
2700 
2701 		} else if (unixpw_nis && keep_unixpw_user) {
2702 			char *c;
2703 			if (getuid() == 0) {
2704 				c = (char *) malloc(strlen("su - '' -c \"")
2705 				    + strlen(keep_unixpw_user) + strlen(cmd) + 1 + 1);
2706 				sprintf(c, "su - '%s' -c \"%s\"", keep_unixpw_user, cmd);
2707 			} else {
2708 				c = strdup(cmd);
2709 			}
2710 			p = popen(c, "r");
2711 			free(c);
2712 
2713 		} else {
2714 			p = popen(cmd, "r");
2715 		}
2716 
2717 		if (! p) {
2718 			rfbLog("wait_for_client: cmd failed: %s\n", cmd);
2719 			rfbLogPerror("popen");
2720 			if (tmp_fd >= 0) {
2721 				unlink(tmp);
2722 			}
2723 			clean_up_exit(1);
2724 		}
2725 		if (fgets(line1, sizeof line1, p) == NULL) {
2726 			rfbLog("wait_for_client: read failed: %s\n", cmd);
2727 			rfbLogPerror("fgets");
2728 			if (tmp_fd >= 0) {
2729 				unlink(tmp);
2730 			}
2731 			clean_up_exit(1);
2732 		}
2733 		n = fread(line2, 1, sizeof line2, p);
2734 		rc = pclose(p);
2735 
2736 		if (rc != 0) {
2737 			rfbLog("wait_for_client: find display cmd failed.\n");
2738 		}
2739 
2740 		if (create_cmd && rc != 0) {
2741 			FILE *mt = fopen(tmp, "w");
2742 			if (! mt) {
2743 				rfbLog("wait_for_client: open failed: %s\n", tmp);
2744 				rfbLogPerror("fopen");
2745 				if (tmp_fd >= 0) {
2746 					unlink(tmp);
2747 				}
2748 				clean_up_exit(1);
2749 			}
2750 			fprintf(mt, "%s", create_display);
2751 			fclose(mt);
2752 
2753 			findcreatedisplay = 1;
2754 
2755 			rfbLog("wait_for_client: FINDCREATEDISPLAY cmd: %s\n", create_cmd);
2756 
2757 			p = popen(create_cmd, "r");
2758 			if (! p) {
2759 				rfbLog("wait_for_client: cmd failed: %s\n", create_cmd);
2760 				rfbLogPerror("popen");
2761 				if (tmp_fd >= 0) {
2762 					unlink(tmp);
2763 				}
2764 				clean_up_exit(1);
2765 			}
2766 			if (fgets(line1, sizeof line1, p) == NULL) {
2767 				rfbLog("wait_for_client: read failed: %s\n", create_cmd);
2768 				rfbLogPerror("fgets");
2769 				if (tmp_fd >= 0) {
2770 					unlink(tmp);
2771 				}
2772 				clean_up_exit(1);
2773 			}
2774 			n = fread(line2, 1, sizeof line2, p);
2775 			pclose(p);
2776 		}
2777 		if (tmp_fd >= 0) {
2778 			unlink(tmp);
2779 		}
2780 	}
2781 
2782 if (db) fprintf(stderr, "line1=%s\n", line1);
2783 
2784 	if (strstr(line1, "DISPLAY=") != line1) {
2785 		rfbLog("wait_for_client: bad reply '%s'\n", line1);
2786 		if (unixpw) {
2787 			unixpw_msg("No DISPLAY found.", 3);
2788 		}
2789 		clean_up_exit(1);
2790 	}
2791 
2792 
2793 	if (strstr(line1, ",VT=")) {
2794 		int vt;
2795 		char *t = strstr(line1, ",VT=");
2796 		vt = atoi(t + strlen(",VT="));
2797 		*t = '\0';
2798 		if (7 <= vt && vt <= 15) {
2799 			do_chvt(vt);
2800 		}
2801 	} else if (strstr(line1, ",XPID=")) {
2802 		int i, pvt, vt = -1;
2803 		char *t = strstr(line1, ",XPID=");
2804 		pvt = atoi(t + strlen(",XPID="));
2805 		*t = '\0';
2806 		if (pvt > 0) {
2807 			for (i=3; i <= 10; i++) {
2808 				int k;
2809 				char proc[100];
2810 				char buf[100];
2811 				sprintf(proc, "/proc/%d/fd/%d", pvt, i);
2812 if (db) fprintf(stderr, "%d -- %s\n", i, proc);
2813 				for (k=0; k < 100; k++) {
2814 					buf[k] = '\0';
2815 				}
2816 
2817 				if (readlink(proc, buf, sizeof buf) != -1) {
2818 					buf[100-1] = '\0';
2819 if (db) fprintf(stderr, "%d -- %s -- %s\n", i, proc, buf);
2820 					if (strstr(buf, "/dev/tty") == buf) {
2821 						vt = atoi(buf + strlen("/dev/tty"));
2822 						if (vt > 0) {
2823 							break;
2824 						}
2825 					}
2826 				}
2827 			}
2828 		}
2829 		if (7 <= vt && vt <= 12) {
2830 			do_chvt(vt);
2831 		}
2832 	}
2833 
2834 	use_dpy = strdup(line1 + strlen("DISPLAY="));
2835 	q = use_dpy;
2836 	while (*q != '\0') {
2837 		if (*q == '\n' || *q == '\r') *q = '\0';
2838 		q++;
2839 	}
2840 	if (line2[0] != '\0') {
2841 		if (strstr(line2, "XAUTHORITY=") == line2) {
2842 			q = line2;
2843 			while (*q != '\0') {
2844 				if (*q == '\n' || *q == '\r') *q = '\0';
2845 				q++;
2846 			}
2847 			if (auth_file) {
2848 				free(auth_file);
2849 			}
2850 			auth_file = strdup(line2 + strlen("XAUTHORITY="));
2851 
2852 		} else {
2853 			xauth_raw_data = (char *)malloc(n);
2854 			xauth_raw_len = n;
2855 			memcpy(xauth_raw_data, line2, n);
2856 if (db) {fprintf(stderr, "xauth_raw_len: %d\n", n);
2857 write(2, xauth_raw_data, n);
2858 fprintf(stderr, "\n");}
2859 		}
2860 	}
2861 
2862 	if (!tried_switch) {
2863 		do_try_switch(usslpeer, users_list_save);
2864 		tried_switch = 1;
2865 	}
2866 
2867 	if (unixpw) {
2868 		/* Some cleanup and messaging for -unixpw case: */
2869 		char str[32];
2870 
2871 		if (keep_unixpw_user && keep_unixpw_pass) {
2872 			strzero(keep_unixpw_user);
2873 			strzero(keep_unixpw_pass);
2874 			keep_unixpw = 0;
2875 		}
2876 
2877 		if (created_disp) {
2878 			snprintf(str, sizeof str, "Created DISPLAY %s", use_dpy);
2879 		} else {
2880 			snprintf(str, sizeof str, "Using DISPLAY %s", use_dpy);
2881 		}
2882 		unixpw_msg(str, 2);
2883 	}
2884 	return 1;
2885 }
2886 
2887 void ssh_remote_tunnel(char *, int);
2888 
2889 static XImage ximage_struct;
2890 
progress_client(void)2891 void progress_client(void) {
2892 	int i, j = 0, progressed = 0, db = 0;
2893 	double start = dnow();
2894 	if (getenv("PROGRESS_CLIENT_DBG")) {
2895 		rfbLog("progress_client: begin\n");
2896 		db = 1;
2897 	}
2898 	for (i = 0; i < 15; i++) {
2899 		if (latest_client) {
2900 			for (j = 0; j < 10; j++) {
2901 				if (latest_client->state != RFB_PROTOCOL_VERSION) {
2902 					progressed = 1;
2903 					break;
2904 				}
2905 				if (db) rfbLog("progress_client: calling-1 rfbCFD(1) %.6f\n", dnow()-start);
2906 				rfbCFD(1);
2907 			}
2908 		}
2909 		if (progressed) {
2910 			break;
2911 		}
2912 		if (db) rfbLog("progress_client: calling-2 rfbCFD(1) %.6f\n", dnow()-start);
2913 		rfbCFD(1);
2914 	}
2915 	if (!quiet) {
2916 		rfbLog("client progressed=%d in %d/%d %.6f s\n",
2917 		    progressed, i, j, dnow() - start);
2918 	}
2919 }
2920 
wait_for_client(int * argc,char ** argv,int http)2921 int wait_for_client(int *argc, char** argv, int http) {
2922 	/* ugh, here we go... */
2923 	XImage* fb_image;
2924 	int w = 640, h = 480, b = 32;
2925 	int w0 = -1, h0 = -1, i, chg_raw_fb = 0;
2926 	char *str, *q, *cmd = NULL;
2927 	int db = 0, dt = 0;
2928 	char *create_cmd = NULL;
2929 	char *users_list_save = NULL;
2930 	int created_disp = 0, ncache_save;
2931 	int did_client_connect = 0;
2932 	char *vnc_redirect_host = "localhost";
2933 	int vnc_redirect_port = -1, vnc_redirect_cnt = 0;
2934 	char vnc_redirect_test[10];
2935 
2936 	if (getenv("WAIT_FOR_CLIENT_DB")) {
2937 		db = 1;
2938 	}
2939 
2940 	vnc_redirect = 0;
2941 
2942 	if (! use_dpy || strstr(use_dpy, "WAIT:") != use_dpy) {
2943 		return 0;
2944 	}
2945 
2946 	for (i=0; i < *argc; i++) {
2947 		if (!strcmp(argv[i], "-desktop")) {
2948 			dt = 1;
2949 		}
2950 		if (db) fprintf(stderr, "args %d %s\n", i, argv[i]);
2951 	}
2952 	if (!quiet && !strstr(use_dpy, "FINDDISPLAY-run")) {
2953 		rfbLog("\n");
2954 		rfbLog("wait_for_client: %s\n", use_dpy);
2955 		rfbLog("\n");
2956 	}
2957 
2958 	str = strdup(use_dpy);
2959 	str += strlen("WAIT");
2960 
2961 	xdmcp_insert = NULL;
2962 
2963 	/* get any leading geometry: */
2964 	q = strchr(str+1, ':');
2965 	if (q) {
2966 		*q = '\0';
2967 		if (sscanf(str+1, "%dx%d", &w0, &h0) == 2)  {
2968 			w = w0;
2969 			h = h0;
2970 			rfbLog("wait_for_client set: w=%d h=%d\n", w, h);
2971 		} else {
2972 			w0 = -1;
2973 			h0 = -1;
2974 		}
2975 		*q = ':';
2976 		str = q;
2977 	}
2978 	if ((w0 == -1 || h0 == -1) && pad_geometry != NULL) {
2979 		int b0, del = 0;
2980 		char *s = pad_geometry;
2981 		if (strstr(s, "once:") == s) {
2982 			del = 1;
2983 			s += strlen("once:");
2984 		}
2985 		if (sscanf(s, "%dx%dx%d", &w0, &h0, &b0) == 3)  {
2986 			w = nabs(w0);
2987 			h = nabs(h0);
2988 			b = nabs(b0);
2989 		} else if (sscanf(s, "%dx%d", &w0, &h0) == 2)  {
2990 			w = nabs(w0);
2991 			h = nabs(h0);
2992 		}
2993 		if (del) {
2994 			pad_geometry = NULL;
2995 		}
2996 	}
2997 
2998 	/* str currently begins with a ':' */
2999 	if (strstr(str, ":cmd=") == str) {
3000 		/* cmd=/path/to/mycommand */
3001 		str++;
3002 	} else if (strpbrk(str, "0123456789") == str+1) {
3003 		/* :0.0 */
3004 		;
3005 	} else {
3006 		/* hostname:0.0 */
3007 		str++;
3008 	}
3009 
3010 	if (db) fprintf(stderr, "str: %s\n", str);
3011 
3012 	if (strstr(str, "cmd=") == str) {
3013 		cmd = setup_cmd(str, &vnc_redirect, &vnc_redirect_host, &vnc_redirect_port, db);
3014 	}
3015 
3016 	fb_image = &ximage_struct;
3017 	setup_fake_fb(fb_image, w, h, b);
3018 
3019 	if (! dt) {
3020 		char *s;
3021 		argv[*argc] = strdup("-desktop");
3022 		*argc = (*argc) + 1;
3023 
3024 		if (cmd) {
3025 			char *q;
3026 			s = choose_title(":0");
3027 			q = strstr(s, ":0");
3028 			if (q) {
3029 				*q = '\0';
3030 			}
3031 		} else {
3032 			s = choose_title(str);
3033 		}
3034 		rfb_desktop_name = strdup(s);
3035 		argv[*argc] = s;
3036 		*argc = (*argc) + 1;
3037 	}
3038 
3039 	ncache_save = ncache;
3040 	ncache = 0;
3041 
3042 	initialize_allowed_input();
3043 
3044 	if (! multiple_cursors_mode) {
3045 		multiple_cursors_mode = strdup("default");
3046 	}
3047 	initialize_cursors_mode();
3048 
3049 	initialize_screen(argc, argv, fb_image);
3050 
3051 	if (! inetd && ! use_openssl) {
3052 		if (! screen->port || screen->listenSock < 0) {
3053 			if (got_rfbport && got_rfbport_val == 0) {
3054 				;
3055 			} else if (ipv6_listen && ipv6_listen_fd >= 0) {
3056 				rfbLog("Info: listening on IPv6 interface only.  (wait for client)\n");
3057 			} else {
3058 				rfbLogEnable(1);
3059 				rfbLog("Error: could not obtain listening port.  (wait for client)\n");
3060 				if (!got_rfbport && !got_ipv6_listen) {
3061 					rfbLog("If this system is IPv6-only, use the -6 option.\n");
3062 				}
3063 				clean_up_exit(1);
3064 			}
3065 		}
3066 	}
3067 
3068 	initialize_signals();
3069 
3070 	if (ssh_str != NULL) {
3071 		ssh_remote_tunnel(ssh_str, screen->port);
3072 	}
3073 
3074 	if (! raw_fb) {
3075 		chg_raw_fb = 1;
3076 		/* kludge to get RAWFB_RET with dpy == NULL guards */
3077 		raw_fb = (char *) 0x1;
3078 	}
3079 
3080 	if (cmd && !strcmp(cmd, "HTTPONCE")) {
3081 		handle_one_http_request();
3082 		clean_up_exit(0);
3083 	}
3084 
3085 	if (http && check_httpdir()) {
3086 		http_connections(1);
3087 	}
3088 
3089 	if (cmd && unixpw) {
3090 		keep_unixpw = 1;
3091 	}
3092 
3093 	setup_service();
3094 
3095 	check_waitbg();
3096 
3097 	if (vnc_redirect) {
3098 		vnc_redirect_loop(vnc_redirect_test, &vnc_redirect_cnt);
3099 	} else {
3100 
3101 		if (use_threads && !started_rfbRunEventLoop) {
3102 			started_rfbRunEventLoop = 1;
3103 			rfbRunEventLoop(screen, -1, TRUE);
3104 		}
3105 
3106 		if (inetd && use_openssl) {
3107 			accept_openssl(OPENSSL_INETD, -1);
3108 		}
3109 
3110 		setup_client_connect(&did_client_connect);
3111 
3112 		loop_for_connect(did_client_connect);
3113 
3114 		if (unixpw) {
3115 			if (cmd && strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
3116 				if (users_list && strstr(users_list, "unixpw=") == users_list) {
3117 					users_list_save = users_list;
3118 					users_list = NULL;
3119 				}
3120 			}
3121 			do_unixpw_loop();
3122 		} else if (cmd && !use_threads) {
3123 			/* try to get RFB proto done now. */
3124 			progress_client();
3125 		}
3126 	}
3127 
3128 	if (vnc_redirect == 2) {
3129 		;
3130 	} else if (cmd) {
3131 		if (!do_run_cmd(cmd, create_cmd, users_list_save, created_disp, db)) {
3132 			return 0;
3133 		}
3134 	} else {
3135 		use_dpy = strdup(str);
3136 	}
3137 	if (chg_raw_fb) {
3138 		raw_fb = NULL;
3139 	}
3140 
3141 	ncache = ncache_save;
3142 
3143 	if (unixpw && keep_unixpw_opts && keep_unixpw_opts[0] != '\0') {
3144 		user_supplied_opts(keep_unixpw_opts);
3145 	}
3146 	if (create_cmd) {
3147 		free(create_cmd);
3148 	}
3149 
3150 	if (vnc_redirect) {
3151 		do_vnc_redirect(created_disp, vnc_redirect_host, vnc_redirect_port,
3152 		    vnc_redirect_cnt, vnc_redirect_test);
3153 		clean_up_exit(0);
3154 	}
3155 
3156 	return 1;
3157 }
3158 
3159