Home | History | Annotate | Download | only in x11vnc
      1 /*
      2    Copyright (C) 2002-2010 Karl J. Runge <runge (at) 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 */
     75 static void switch_user_task_dummy(void) {
     76 	;	/* dummy does nothing */
     77 }
     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 
     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 */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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