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