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