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