diff options
Diffstat (limited to 'x11vnc/connections.c')
-rw-r--r-- | x11vnc/connections.c | 4437 |
1 files changed, 0 insertions, 4437 deletions
diff --git a/x11vnc/connections.c b/x11vnc/connections.c deleted file mode 100644 index d2a9b5c..0000000 --- a/x11vnc/connections.c +++ /dev/null @@ -1,4437 +0,0 @@ -/* - Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> - All rights reserved. - -This file is part of x11vnc. - -x11vnc is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -x11vnc is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with x11vnc; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA -or see <http://www.gnu.org/licenses/>. - -In addition, as a special exception, Karl J. Runge -gives permission to link the code of its release of x11vnc with the -OpenSSL project's "OpenSSL" library (or with modified versions of it -that use the same license as the "OpenSSL" library), and distribute -the linked executables. You must obey the GNU General Public License -in all respects for all of the code used other than "OpenSSL". If you -modify this file, you may extend this exception to your version of the -file, but you are not obligated to do so. If you do not wish to do -so, delete this exception statement from your version. -*/ - -/* -- connections.c -- */ - -#include "x11vnc.h" -#include "inet.h" -#include "remote.h" -#include "keyboard.h" -#include "cleanup.h" -#include "gui.h" -#include "solid.h" -#include "rates.h" -#include "screen.h" -#include "unixpw.h" -#include "user.h" -#include "scan.h" -#include "sslcmds.h" -#include "sslhelper.h" -#include "xwrappers.h" -#include "xevents.h" -#include "win_utils.h" -#include "macosx.h" -#include "macosxCG.h" -#include "userinput.h" -#include "pointer.h" -#include "xrandr.h" - -/* - * routines for handling incoming, outgoing, etc connections - */ - -/* string for the VNC_CONNECT property */ -char vnc_connect_str[VNC_CONNECT_MAX+1]; -Atom vnc_connect_prop = None; -char x11vnc_remote_str[X11VNC_REMOTE_MAX+1]; -Atom x11vnc_remote_prop = None; -rfbClientPtr inetd_client = NULL; - -int all_clients_initialized(void); -char *list_clients(void); -int new_fb_size_clients(rfbScreenInfoPtr s); -void close_all_clients(void); -void close_clients(char *str); -void set_client_input(char *str); -void set_child_info(void); -int cmd_ok(char *cmd); -void client_gone(rfbClientPtr client); -void client_gone_chat_helper(rfbClientPtr client); -void reverse_connect(char *str); -void set_vnc_connect_prop(char *str); -void read_vnc_connect_prop(int); -void set_x11vnc_remote_prop(char *str); -void read_x11vnc_remote_prop(int); -void check_connect_inputs(void); -void check_gui_inputs(void); -rfbClientPtr create_new_client(int sock, int start_thread); -enum rfbNewClientAction new_client(rfbClientPtr client); -enum rfbNewClientAction new_client_chat_helper(rfbClientPtr client); -rfbBool password_check_chat_helper(rfbClientPtr cl, const char* response, int len); -void start_client_info_sock(char *host_port_cookie); -void send_client_info(char *str); -void adjust_grabs(int grab, int quiet); -void check_new_clients(void); -int accept_client(rfbClientPtr client); -void check_ipv6_listen(long usec); -void check_unix_sock(long usec); -int run_user_command(char *cmd, rfbClientPtr client, char *mode, char *input, - int len, FILE *output); -int check_access(char *addr); -void client_set_net(rfbClientPtr client); -char *get_xprop(char *prop, Window win); -int set_xprop(char *prop, Window win, char *value); -char *bcx_xattach(char *str, int *pg_init, int *kg_init); -void grab_state(int *ptr_grabbed, int *kbd_grabbed); -char *wininfo(Window win, int show_children); - -static rfbClientPtr *client_match(char *str); -static void free_client_data(rfbClientPtr client); -static void ugly_geom(char *p, int *x, int *y); -static int ugly_window(char *addr, char *userhost, int X, int Y, - int timeout, char *mode, int accept); -static int action_match(char *action, int rc); -static void check_connect_file(char *file); -static void send_client_connect(void); - - -/* - * check that all clients are in RFB_NORMAL state - */ -int all_clients_initialized(void) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int ok = 1; - - if (! screen) { - return ok; - } - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (cl->state != RFB_NORMAL) { - ok = 0; - } else { - client_normal_count++; - } - } - rfbReleaseClientIterator(iter); - - return ok; -} - -char *list_clients(void) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - char *list, tmp[256]; - int count = 0; - - if (!screen) { - return strdup(""); - } - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - client_set_net(cl); - count++; - } - rfbReleaseClientIterator(iter); - - /* - * each client: - * <id>:<ip>:<port>:<user>:<unix>:<hostname>:<input>:<loginview>:<time>, - * 8+1+64+1+5+1+24+1+24+1+256+1+5+1+1+1+10+1 - * 123.123.123.123:60000/0x11111111-rw, - * so count+1 * 1000 must cover it. - */ - list = (char *) malloc((count+1)*1000); - - list[0] = '\0'; - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - ClientData *cd = (ClientData *) cl->clientData; - char *tmp_host, *p; - - if (! cd) { - continue; - } - if (*list != '\0') { - strcat(list, ","); - } - sprintf(tmp, "0x%x:", cd->uid); - strcat(list, tmp); - p = tmp_host = strdup(cl->host); - while (*p) { - if (*p == ':') *p = '#'; - p++; - } - strcat(list, tmp_host); - free(tmp_host); - strcat(list, ":"); - sprintf(tmp, "%d:", cd->client_port); - strcat(list, tmp); - if (cd->username[0] == '\0') { - char *s = ident_username(cl); - if (s) free(s); - } - if (strstr(cd->username, "UNIX:") == cd->username) { - strcat(list, cd->username + strlen("UNIX:")); - } else { - strcat(list, cd->username); - } - strcat(list, ":"); - if (cd->unixname[0] == '\0') { - strcat(list, "none"); - } else { - strcat(list, cd->unixname); - } - strcat(list, ":"); - p = tmp_host = strdup(cd->hostname); - while (*p) { - if (*p == ':') *p = '#'; - p++; - } - strcat(list, tmp_host); - free(tmp_host); - strcat(list, ":"); - strcat(list, cd->input); - strcat(list, ":"); - sprintf(tmp, "%d", cd->login_viewonly); - strcat(list, tmp); - strcat(list, ":"); - sprintf(tmp, "%d", (int) cd->login_time); - strcat(list, tmp); - } - rfbReleaseClientIterator(iter); - return list; -} - -/* count number of clients supporting NewFBSize */ -int new_fb_size_clients(rfbScreenInfoPtr s) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int count = 0; - - if (! s) { - return 0; - } - - iter = rfbGetClientIterator(s); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (cl->useNewFBSize) { - count++; - } - } - rfbReleaseClientIterator(iter); - return count; -} - -void close_all_clients(void) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - - if (! screen) { - return; - } - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - rfbCloseClient(cl); - rfbClientConnectionGone(cl); - } - rfbReleaseClientIterator(iter); -} - -static rfbClientPtr *client_match(char *str) { - rfbClientIteratorPtr iter; - rfbClientPtr cl, *cl_list; - int i, n, host_warn = 0, hex_warn = 0; - - n = client_count + 10; - cl_list = (rfbClientPtr *) malloc(n * sizeof(rfbClientPtr)); - - i = 0; - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - ClientData *cd = (ClientData *) cl->clientData; - if (strstr(str, "0x") == str) { - unsigned int in; - int id; - if (! cd) { - continue; - } - if (sscanf(str, "0x%x", &in) != 1) { - if (hex_warn++) { - continue; - } - rfbLog("skipping invalid client hex id: %s\n", - str); - continue; - } - id = (unsigned int) in; - if (cd->uid == id) { - cl_list[i++] = cl; - } - } else { - int port = -1; - char *rstr = strdup(str); - char *q = strrchr(rstr, ':'); - if (q) { - port = atoi(q+1); - *q = '\0'; - if (port == 0 && q[1] != '0') { - port = -1; - } else if (port < 0) { - port = -port; - } else if (port < 200) { - port = 5500 + port; - } - } - if (ipv6_ip(str)) { - ; - } else if (! dotted_ip(str, 0)) { - char *orig = rstr; - rstr = host2ip(rstr); - free(orig); - if (rstr == NULL || *rstr == '\0') { - if (host_warn++) { - continue; - } - rfbLog("skipping bad lookup: \"%s\"\n", str); - continue; - } - rfbLog("lookup: %s -> %s port=%d\n", str, rstr, port); - } - if (!strcmp(rstr, cl->host)) { - int ok = 1; - if (port > 0) { - if (cd != NULL && cd->client_port > 0) { - if (cd->client_port != port) { - ok = 0; - } - } else { - int cport = get_remote_port(cl->sock); - if (cport != port) { - ok = 0; - } - } - } - if (ok) { - cl_list[i++] = cl; - } - } - free(rstr); - } - if (i >= n - 1) { - break; - } - } - rfbReleaseClientIterator(iter); - - cl_list[i] = NULL; - - return cl_list; -} - -void close_clients(char *str) { - rfbClientPtr *cl_list, *cp; - - if (!strcmp(str, "all") || !strcmp(str, "*")) { - close_all_clients(); - return; - } - - if (! screen) { - return; - } - - cl_list = client_match(str); - - cp = cl_list; - while (*cp) { - rfbCloseClient(*cp); - rfbClientConnectionGone(*cp); - cp++; - } - free(cl_list); -} - -void set_client_input(char *str) { - rfbClientPtr *cl_list, *cp; - char *p, *val; - - /* str is "match:value" */ - - if (! screen) { - return; - } - - p = strrchr(str, ':'); - if (! p) { - return; - } - *p = '\0'; - p++; - val = short_kmbcf(p); - - cl_list = client_match(str); - - cp = cl_list; - while (*cp) { - ClientData *cd = (ClientData *) (*cp)->clientData; - if (! cd) { - continue; - } - cd->input[0] = '\0'; - strcat(cd->input, "_"); - strcat(cd->input, val); - cp++; - } - - free(val); - free(cl_list); -} - -void set_child_info(void) { - char pid[16]; - /* set up useful environment for child process */ - sprintf(pid, "%d", (int) getpid()); - set_env("X11VNC_PID", pid); - if (program_name) { - /* e.g. for remote control -R */ - set_env("X11VNC_PROG", program_name); - } - if (program_cmdline) { - set_env("X11VNC_CMDLINE", program_cmdline); - } - if (raw_fb_str) { - set_env("X11VNC_RAWFB_STR", raw_fb_str); - } else { - set_env("X11VNC_RAWFB_STR", ""); - } -} - -int cmd_ok(char *cmd) { - char *p, *str; - if (no_external_cmds) { - return 0; - } - if (! cmd || cmd[0] == '\0') { - return 0; - } - if (! allowed_external_cmds) { - /* default, allow any (overridden by -nocmds) */ - return 1; - } - - str = strdup(allowed_external_cmds); - p = strtok(str, ","); - while (p) { - if (!strcmp(p, cmd)) { - free(str); - return 1; - } - p = strtok(NULL, ","); - } - free(str); - return 0; -} - -/* - * utility to run a user supplied command setting some RFB_ env vars. - * used by, e.g., accept_client() and client_gone() - */ -int run_user_command(char *cmd, rfbClientPtr client, char *mode, char *input, - int len, FILE *output) { - char *old_display = NULL; - char *addr = NULL; - char str[100]; - int rc, ok; - ClientData *cd = NULL; - client_set_net(client); - if (client != NULL) { - cd = (ClientData *) client->clientData; - addr = client->host; - } - - if (addr == NULL || addr[0] == '\0') { - addr = "unknown-host"; - } - - /* set RFB_CLIENT_ID to semi unique id for command to use */ - if (cd && cd->uid) { - sprintf(str, "0x%x", cd->uid); - } else { - /* not accepted yet: */ - sprintf(str, "0x%x", clients_served); - } - set_env("RFB_CLIENT_ID", str); - - /* set RFB_CLIENT_IP to IP addr for command to use */ - set_env("RFB_CLIENT_IP", addr); - - /* set RFB_X11VNC_PID to our pid for command to use */ - sprintf(str, "%d", (int) getpid()); - set_env("RFB_X11VNC_PID", str); - - if (client == NULL) { - ; - } else if (client->state == RFB_PROTOCOL_VERSION) { - set_env("RFB_STATE", "PROTOCOL_VERSION"); - } else if (client->state == RFB_SECURITY_TYPE) { - set_env("RFB_STATE", "SECURITY_TYPE"); - } else if (client->state == RFB_AUTHENTICATION) { - set_env("RFB_STATE", "AUTHENTICATION"); - } else if (client->state == RFB_INITIALISATION) { - set_env("RFB_STATE", "INITIALISATION"); - } else if (client->state == RFB_NORMAL) { - set_env("RFB_STATE", "NORMAL"); - } else { - set_env("RFB_STATE", "UNKNOWN"); - } - if (certret_str) { - set_env("RFB_SSL_CLIENT_CERT", certret_str); - } else { - set_env("RFB_SSL_CLIENT_CERT", ""); - } - - /* set RFB_CLIENT_PORT to peer port for command to use */ - if (cd && cd->client_port > 0) { - sprintf(str, "%d", cd->client_port); - } else if (client) { - sprintf(str, "%d", get_remote_port(client->sock)); - } - set_env("RFB_CLIENT_PORT", str); - - set_env("RFB_MODE", mode); - - /* - * now do RFB_SERVER_IP and RFB_SERVER_PORT (i.e. us!) - * This will establish a 5-tuple (including tcp) the external - * program can potentially use to work out the virtual circuit - * for this connection. - */ - if (cd && cd->server_ip) { - set_env("RFB_SERVER_IP", cd->server_ip); - } else if (client) { - char *sip = get_local_host(client->sock); - set_env("RFB_SERVER_IP", sip); - if (sip) free(sip); - } - - if (cd && cd->server_port > 0) { - sprintf(str, "%d", cd->server_port); - } else if (client) { - sprintf(str, "%d", get_local_port(client->sock)); - } - set_env("RFB_SERVER_PORT", str); - - if (cd) { - sprintf(str, "%d", cd->login_viewonly); - } else { - sprintf(str, "%d", -1); - } - set_env("RFB_LOGIN_VIEWONLY", str); - - if (cd) { - sprintf(str, "%d", (int) cd->login_time); - } else { - sprintf(str, ">%d", (int) time(NULL)); - } - set_env("RFB_LOGIN_TIME", str); - - sprintf(str, "%d", (int) time(NULL)); - set_env("RFB_CURRENT_TIME", str); - - if (!cd || !cd->username || cd->username[0] == '\0') { - set_env("RFB_USERNAME", "unknown-user"); - } else { - set_env("RFB_USERNAME", cd->username); - } - /* - * Better set DISPLAY to the one we are polling, if they - * want something trickier, they can handle on their own - * via environment, etc. - */ - if (getenv("DISPLAY")) { - old_display = strdup(getenv("DISPLAY")); - } - - if (raw_fb && ! dpy) { /* raw_fb hack */ - set_env("DISPLAY", "rawfb"); - } else { - set_env("DISPLAY", DisplayString(dpy)); - } - - /* - * work out the number of clients (have to use client_count - * since there is deadlock in rfbGetClientIterator) - */ - sprintf(str, "%d", client_count); - set_env("RFB_CLIENT_COUNT", str); - - /* gone, accept, afteraccept */ - ok = 0; - if (!strcmp(mode, "env")) { - return 1; - } - if (!strcmp(mode, "accept") && cmd_ok("accept")) { - ok = 1; - } - if (!strcmp(mode, "afteraccept") && cmd_ok("afteraccept")) { - ok = 1; - } - if (!strcmp(mode, "gone") && cmd_ok("gone")) { - ok = 1; - } - if (!strcmp(mode, "cmd_verify") && cmd_ok("unixpw")) { - ok = 1; - } - if (!strcmp(mode, "read_passwds") && cmd_ok("passwdfile")) { - ok = 1; - } - if (!strcmp(mode, "custom_passwd") && cmd_ok("custom_passwd")) { - ok = 1; - } - if (no_external_cmds || !ok) { - rfbLogEnable(1); - rfbLog("cannot run external commands in -nocmds mode:\n"); - rfbLog(" \"%s\"\n", cmd); - rfbLog(" exiting.\n"); - clean_up_exit(1); - } - rfbLog("running command:\n"); - if (!quiet) { - fprintf(stderr, "\n %s\n\n", cmd); - } - close_exec_fds(); - - if (output != NULL) { - FILE *ph; - char line[1024]; - char *cmd2 = NULL; - char tmp[] = "/tmp/x11vnc-tmp.XXXXXX"; - int deltmp = 0; - - if (input != NULL) { - int tmp_fd = mkstemp(tmp); - if (tmp_fd < 0) { - rfbLog("mkstemp failed on: %s\n", tmp); - clean_up_exit(1); - } - write(tmp_fd, input, len); - close(tmp_fd); - deltmp = 1; - cmd2 = (char *) malloc(100 + strlen(tmp) + strlen(cmd)); - sprintf(cmd2, "/bin/cat %s | %s", tmp, cmd); - - ph = popen(cmd2, "r"); - } else { - ph = popen(cmd, "r"); - } - if (ph == NULL) { - rfbLog("popen(%s) failed", cmd); - rfbLogPerror("popen"); - clean_up_exit(1); - } - memset(line, 0, sizeof(line)); - while (fgets(line, sizeof(line), ph) != NULL) { - int j, k = -1; - if (0) fprintf(stderr, "line: %s", line); - /* take care to handle embedded nulls */ - for (j=0; j < (int) sizeof(line); j++) { - if (line[j] != '\0') { - k = j; - } - } - if (k >= 0) { - write(fileno(output), line, k+1); - } - memset(line, 0, sizeof(line)); - } - - rc = pclose(ph); - - if (cmd2 != NULL) { - free(cmd2); - } - if (deltmp) { - unlink(tmp); - } - goto got_rc; - } else if (input != NULL) { - FILE *ph = popen(cmd, "w"); - if (ph == NULL) { - rfbLog("popen(%s) failed", cmd); - rfbLogPerror("popen"); - clean_up_exit(1); - } - write(fileno(ph), input, len); - rc = pclose(ph); - goto got_rc; - } - -#if LIBVNCSERVER_HAVE_FORK - { - pid_t pid, pidw; - struct sigaction sa, intr, quit; - sigset_t omask; - - sa.sa_handler = SIG_IGN; - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - sigaction(SIGINT, &sa, &intr); - sigaction(SIGQUIT, &sa, &quit); - - sigaddset(&sa.sa_mask, SIGCHLD); - sigprocmask(SIG_BLOCK, &sa.sa_mask, &omask); - - if ((pid = fork()) > 0 || pid == -1) { - - if (pid != -1) { - pidw = waitpid(pid, &rc, 0); - } - - sigaction(SIGINT, &intr, (struct sigaction *) NULL); - sigaction(SIGQUIT, &quit, (struct sigaction *) NULL); - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) NULL); - - if (pid == -1) { - fprintf(stderr, "could not fork\n"); - rfbLogPerror("fork"); - rc = system(cmd); - } - } else { - /* this should close port 5900, etc.. */ - int fd; - sigaction(SIGINT, &intr, (struct sigaction *) NULL); - sigaction(SIGQUIT, &quit, (struct sigaction *) NULL); - sigprocmask(SIG_SETMASK, &omask, (sigset_t *) NULL); - for (fd=3; fd<256; fd++) { - close(fd); - } -/* XXX test more */ - if (!strcmp(mode, "gone")) { -#if LIBVNCSERVER_HAVE_SETSID - setsid(); -#else - setpgrp(); -#endif - } - execlp("/bin/sh", "/bin/sh", "-c", cmd, (char *) NULL); - exit(1); - } - } -#else - rc = system(cmd); -#endif - got_rc: - - if (rc >= 256) { - rc = rc/256; - } - rfbLog("command returned: %d\n", rc); - - if (old_display) { - set_env("DISPLAY", old_display); - free(old_display); - } - - return rc; -} - -static void free_client_data(rfbClientPtr client) { - if (! client) { - return; - } - if (client->clientData) { - ClientData *cd = (ClientData *) client->clientData; - if (cd) { - if (cd->server_ip) { - free(cd->server_ip); - cd->server_ip = NULL; - } - if (cd->hostname) { - free(cd->hostname); - cd->hostname = NULL; - } - if (cd->username) { - free(cd->username); - cd->username = NULL; - } - if (cd->unixname) { - free(cd->unixname); - cd->unixname = NULL; - } - } - free(client->clientData); - client->clientData = NULL; - } -} - -static int accepted_client = 0; - -/* - * callback for when a client disconnects - */ -void client_gone(rfbClientPtr client) { - ClientData *cd = NULL; - - CLIENT_LOCK; - - client_count--; - if (client_count < 0) client_count = 0; - - speeds_net_rate_measured = 0; - speeds_net_latency_measured = 0; - - rfbLog("client_count: %d\n", client_count); - last_client_gone = dnow(); - - if (unixpw_in_progress && unixpw_client) { - if (client == unixpw_client) { - unixpw_in_progress = 0; - /* mutex */ - screen->permitFileTransfer = unixpw_file_xfer_save; - if ((tightfilexfer = unixpw_tightvnc_xfer_save)) { -#ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER - rfbLog("rfbRegisterTightVNCFileTransferExtension: 3\n"); - rfbRegisterTightVNCFileTransferExtension(); -#endif - } - unixpw_client = NULL; - copy_screen(); - } - } - - - if (no_autorepeat && client_count == 0) { - autorepeat(1, 0); - } - if (use_solid_bg && client_count == 0) { - solid_bg(1); - } - if ((ncache || ncache0) && client_count == 0) { - kde_no_animate(1); - } - if (client->clientData) { - cd = (ClientData *) client->clientData; - if (cd->ssl_helper_pid > 0) { - int status; - rfbLog("sending SIGTERM to ssl_helper_pid: %d\n", - cd->ssl_helper_pid); - kill(cd->ssl_helper_pid, SIGTERM); - usleep(200*1000); -#if LIBVNCSERVER_HAVE_SYS_WAIT_H && LIBVNCSERVER_HAVE_WAITPID - waitpid(cd->ssl_helper_pid, &status, WNOHANG); -#endif - ssl_helper_pid(cd->ssl_helper_pid, -1); /* delete */ - } - } - if (gone_cmd && *gone_cmd != '\0') { - if (strstr(gone_cmd, "popup") == gone_cmd) { - int x = -64000, y = -64000, timeout = 120; - char *userhost = ident_username(client); - char *addr, *p, *mode; - - /* extract timeout */ - if ((p = strchr(gone_cmd, ':')) != NULL) { - int in; - if (sscanf(p+1, "%d", &in) == 1) { - timeout = in; - } - } - /* extract geometry */ - if ((p = strpbrk(gone_cmd, "+-")) != NULL) { - ugly_geom(p, &x, &y); - } - - /* find mode: mouse, key, or both */ - if (strstr(gone_cmd, "popupmouse") == gone_cmd) { - mode = "mouse_only"; - } else if (strstr(gone_cmd, "popupkey") == gone_cmd) { - mode = "key_only"; - } else { - mode = "both"; - } - - addr = client->host; - - ugly_window(addr, userhost, x, y, timeout, mode, 0); - - free(userhost); - } else { - rfbLog("client_gone: using cmd: %s\n", client->host); - run_user_command(gone_cmd, client, "gone", NULL, 0, NULL); - } - } - - free_client_data(client); - - if (inetd && client == inetd_client) { - rfbLog("inetd viewer exited.\n"); - if (gui_pid > 0) { - rfbLog("killing gui_pid %d\n", gui_pid); - kill(gui_pid, SIGTERM); - } - clean_up_exit(0); - } - - if (connect_once) { - /* - * This non-exit is done for a bad passwd to be consistent - * with our RFB_CLIENT_REFUSE behavior in new_client() (i.e. - * we disconnect after 1 successful connection). - */ - if ((client->state == RFB_PROTOCOL_VERSION || - client->state == RFB_SECURITY_TYPE || - client->state == RFB_AUTHENTICATION || - client->state == RFB_INITIALISATION) && accepted_client) { - rfbLog("connect_once: invalid password or early " - "disconnect. %d\n", client->state); - rfbLog("connect_once: waiting for next connection.\n"); - accepted_client--; - if (accepted_client < 0) { - accepted_client = 0; - } - CLIENT_UNLOCK; - if (connect_or_exit) { - clean_up_exit(1); - } - return; - } - if (shared && client_count > 0) { - rfbLog("connect_once: other shared clients still " - "connected, not exiting.\n"); - CLIENT_UNLOCK; - return; - } - - rfbLog("viewer exited.\n"); - if ((client_connect || connect_or_exit) && gui_pid > 0) { - rfbLog("killing gui_pid %d\n", gui_pid); - kill(gui_pid, SIGTERM); - } - CLIENT_UNLOCK; - clean_up_exit(0); - } -#ifdef MACOSX - if (macosx_console && client_count == 0) { - macosxCG_refresh_callback_off(); - } -#endif - CLIENT_UNLOCK; -} - -/* - * Simple routine to limit access via string compare. A power user will - * want to compile libvncserver with libwrap support and use /etc/hosts.allow. - */ -int check_access(char *addr) { - int allowed = 0; - int ssl = 0; - char *p, *list; - - if (use_openssl || use_stunnel) { - ssl = 1; - } - if (deny_all) { - rfbLog("check_access: new connections are currently " - "blocked.\n"); - return 0; - } - if (addr == NULL || *addr == '\0') { - rfbLog("check_access: denying empty host IP address string.\n"); - return 0; - } - - if (allow_list == NULL) { - /* set to "" to possibly append allow_once */ - allow_list = strdup(""); - } - if (*allow_list == '\0' && allow_once == NULL) { - /* no constraints, accept it */ - return 1; - } - - if (strchr(allow_list, '/')) { - /* a file of IP addresess or prefixes */ - int len, len2 = 0; - struct stat sbuf; - FILE *in; - char line[1024], *q; - - if (stat(allow_list, &sbuf) != 0) { - rfbLogEnable(1); - rfbLog("check_access: failure stating file: %s\n", - allow_list); - rfbLogPerror("stat"); - clean_up_exit(1); - } - len = sbuf.st_size + 1; /* 1 more for '\0' at end */ - if (allow_once) { - len2 = strlen(allow_once) + 2; - len += len2; - } - if (ssl) { - len2 = strlen("127.0.0.1") + 2; - len += len2; - } - list = (char *) malloc(len); - list[0] = '\0'; - - in = fopen(allow_list, "r"); - if (in == NULL) { - rfbLogEnable(1); - rfbLog("check_access: cannot open: %s\n", allow_list); - rfbLogPerror("fopen"); - clean_up_exit(1); - } - while (fgets(line, 1024, in) != NULL) { - if ( (q = strchr(line, '#')) != NULL) { - *q = '\0'; - } - if (strlen(list) + strlen(line) >= - (size_t) (len - len2)) { - /* file grew since our stat() */ - break; - } - strcat(list, line); - } - fclose(in); - if (allow_once) { - strcat(list, "\n"); - strcat(list, allow_once); - strcat(list, "\n"); - } - if (ssl) { - strcat(list, "\n"); - strcat(list, "127.0.0.1"); - strcat(list, "\n"); - } - } else { - int len = strlen(allow_list) + 1; - if (allow_once) { - len += strlen(allow_once) + 1; - } - if (ssl) { - len += strlen("127.0.0.1") + 1; - } - list = (char *) malloc(len); - list[0] = '\0'; - strcat(list, allow_list); - if (allow_once) { - strcat(list, ","); - strcat(list, allow_once); - } - if (ssl) { - strcat(list, ","); - strcat(list, "127.0.0.1"); - } - } - - if (allow_once) { - free(allow_once); - allow_once = NULL; - } - - p = strtok(list, ", \t\n\r"); - while (p) { - char *chk, *q, *r = NULL; - if (*p == '\0') { - p = strtok(NULL, ", \t\n\r"); - continue; - } - if (ipv6_ip(p)) { - chk = p; - } else if (! dotted_ip(p, 1)) { - r = host2ip(p); - if (r == NULL || *r == '\0') { - rfbLog("check_access: bad lookup \"%s\"\n", p); - p = strtok(NULL, ", \t\n\r"); - continue; - } - rfbLog("check_access: lookup %s -> %s\n", p, r); - chk = r; - } else { - chk = p; - } - if (getenv("X11VNC_DEBUG_ACCESS")) fprintf(stderr, "chk: %s part: %s addr: %s\n", chk, p, addr); - - q = strstr(addr, chk); - if (ipv6_ip(addr)) { - if (!strcmp(chk, "localhost") && !strcmp(addr, "::1")) { - rfbLog("check_access: client addr %s is local.\n", addr); - allowed = 1; - } else if (!strcmp(chk, "::1") && !strcmp(addr, "::1")) { - rfbLog("check_access: client addr %s is local.\n", addr); - allowed = 1; - } else if (!strcmp(chk, "127.0.0.1") && !strcmp(addr, "::1")) { - /* this if for host2ip("localhost") */ - rfbLog("check_access: client addr %s is local.\n", addr); - allowed = 1; - } else if (q == addr) { - rfbLog("check_access: client %s matches pattern %s\n", addr, chk); - allowed = 1; - } - } else if (chk[strlen(chk)-1] != '.') { - if (!strcmp(addr, chk)) { - if (chk != p) { - rfbLog("check_access: client %s " "matches host %s=%s\n", addr, chk, p); - } else { - rfbLog("check_access: client %s " "matches host %s\n", addr, chk); - } - allowed = 1; - } else if(!strcmp(chk, "localhost") && !strcmp(addr, "127.0.0.1")) { - allowed = 1; - } - } else if (q == addr) { - rfbLog("check_access: client %s matches pattern %s\n", addr, chk); - allowed = 1; - } - p = strtok(NULL, ", \t\n\r"); - if (r) { - free(r); - } - if (allowed) { - break; - } - } - free(list); - return allowed; -} - -/* - * x11vnc's first (and only) visible widget: accept/reject dialog window. - * We go through this pain to avoid dependency on libXt... - */ -static int ugly_window(char *addr, char *userhost, int X, int Y, - int timeout, char *mode, int accept) { -#if NO_X11 - if (!addr || !userhost || !X || !Y || !timeout || !mode || !accept) {} - RAWFB_RET(0) - nox11_exit(1); - return 0; -#else - -#define t2x2_width 16 -#define t2x2_height 16 -static unsigned char t2x2_bits[] = { - 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, - 0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, - 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33}; - - Window awin; - GC gc; - XSizeHints hints; - XGCValues values; - static XFontStruct *font_info = NULL; - static Pixmap ico = 0; - unsigned long valuemask = 0; - static char dash_list[] = {20, 40}; - int list_length = sizeof(dash_list); - - Atom wm_protocols; - Atom wm_delete_window; - - XEvent ev; - long evmask = ExposureMask | KeyPressMask | ButtonPressMask - | StructureNotifyMask; - double waited = 0.0; - - /* strings and geometries y/n */ - KeyCode key_y, key_n, key_v; - char strh[100]; - char stri[100]; - char str1_b[] = "To accept: press \"y\" or click the \"Yes\" button"; - char str2_b[] = "To reject: press \"n\" or click the \"No\" button"; - char str3_b[] = "View only: press \"v\" or click the \"View\" button"; - char str1_m[] = "To accept: click the \"Yes\" button"; - char str2_m[] = "To reject: click the \"No\" button"; - char str3_m[] = "View only: click the \"View\" button"; - char str1_k[] = "To accept: press \"y\""; - char str2_k[] = "To reject: press \"n\""; - char str3_k[] = "View only: press \"v\""; - char *str1, *str2, *str3; - char str_y[] = "Yes"; - char str_n[] = "No"; - char str_v[] = "View"; - int x, y, w = 345, h = 175, ret = 0; - int X_sh = 20, Y_sh = 30, dY = 20; - int Ye_x = 20, Ye_y = 0, Ye_w = 45, Ye_h = 20; - int No_x = 75, No_y = 0, No_w = 45, No_h = 20; - int Vi_x = 130, Vi_y = 0, Vi_w = 45, Vi_h = 20; - char *sprop = "new x11vnc client"; - - KeyCode key_o; - - RAWFB_RET(0) - - if (! accept) { - sprintf(str_y, "OK"); - sprop = "x11vnc client disconnected"; - h = 110; - str1 = ""; - str2 = ""; - str3 = ""; - } else if (!strcmp(mode, "mouse_only")) { - str1 = str1_m; - str2 = str2_m; - str3 = str3_m; - } else if (!strcmp(mode, "key_only")) { - str1 = str1_k; - str2 = str2_k; - str3 = str3_k; - h -= dY; - } else { - str1 = str1_b; - str2 = str2_b; - str3 = str3_b; - } - if (view_only) { - h -= dY; - } - - /* XXX handle coff_x/coff_y? */ - if (X < -dpy_x) { - x = (dpy_x - w)/2; /* large negative: center */ - if (x < 0) x = 0; - } else if (X < 0) { - x = dpy_x + X - w; /* from lower right */ - } else { - x = X; /* from upper left */ - } - - if (Y < -dpy_y) { - y = (dpy_y - h)/2; - if (y < 0) y = 0; - } else if (Y < 0) { - y = dpy_y + Y - h; - } else { - y = Y; - } - - X_LOCK; - - awin = XCreateSimpleWindow(dpy, window, x, y, w, h, 4, - BlackPixel(dpy, scr), WhitePixel(dpy, scr)); - - wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); - wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(dpy, awin, &wm_delete_window, 1); - - if (! ico) { - ico = XCreateBitmapFromData(dpy, awin, (char *) t2x2_bits, - t2x2_width, t2x2_height); - } - - hints.flags = PPosition | PSize | PMinSize; - hints.x = x; - hints.y = y; - hints.width = w; - hints.height = h; - hints.min_width = w; - hints.min_height = h; - - XSetStandardProperties(dpy, awin, sprop, "x11vnc query", ico, NULL, - 0, &hints); - - XSelectInput_wr(dpy, awin, evmask); - - if (! font_info && (font_info = XLoadQueryFont(dpy, "fixed")) == NULL) { - rfbLogEnable(1); - rfbLog("ugly_window: cannot locate font fixed.\n"); - X_UNLOCK; - clean_up_exit(1); - } - - gc = XCreateGC(dpy, awin, valuemask, &values); - XSetFont(dpy, gc, font_info->fid); - XSetForeground(dpy, gc, BlackPixel(dpy, scr)); - XSetLineAttributes(dpy, gc, 1, LineSolid, CapButt, JoinMiter); - XSetDashes(dpy, gc, 0, dash_list, list_length); - - XMapWindow(dpy, awin); - XFlush_wr(dpy); - - if (accept) { - char *ip = addr; - char *type = "accept"; - if (unixpw && strstr(userhost, "UNIX:") != userhost) { - type = "UNIXPW"; - if (openssl_last_ip) { - ip = openssl_last_ip; - } - } - snprintf(strh, 100, "x11vnc: %s connection from %s?", type, ip); - } else { - snprintf(strh, 100, "x11vnc: client disconnected from %s", addr); - } - snprintf(stri, 100, " (%s)", userhost); - - key_o = XKeysymToKeycode(dpy, XStringToKeysym("o")); - key_y = XKeysymToKeycode(dpy, XStringToKeysym("y")); - key_n = XKeysymToKeycode(dpy, XStringToKeysym("n")); - key_v = XKeysymToKeycode(dpy, XStringToKeysym("v")); - - while (1) { - int out = -1, x, y, tw, k; - - if (XCheckWindowEvent(dpy, awin, evmask, &ev)) { - ; /* proceed to handling */ - } else if (XCheckTypedEvent(dpy, ClientMessage, &ev)) { - ; /* proceed to handling */ - } else { - int ms = 100; /* sleep a bit */ - usleep(ms * 1000); - waited += ((double) ms)/1000.; - if (timeout && (int) waited >= timeout) { - rfbLog("ugly_window: popup timed out after " - "%d seconds.\n", timeout); - out = 0; - ev.type = 0; - } else { - continue; - } - } - - switch(ev.type) { - case Expose: - while (XCheckTypedEvent(dpy, Expose, &ev)) { - ; - } - k=0; - - /* instructions */ - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - strh, strlen(strh)); - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - stri, strlen(stri)); - if (accept) { - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - str1, strlen(str1)); - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - str2, strlen(str2)); - if (! view_only) { - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - str3, strlen(str3)); - } - } - - if (!strcmp(mode, "key_only")) { - break; - } - - /* buttons */ - Ye_y = Y_sh+k*dY; - No_y = Y_sh+k*dY; - Vi_y = Y_sh+k*dY; - XDrawRectangle(dpy, awin, gc, Ye_x, Ye_y, Ye_w, Ye_h); - - if (accept) { - XDrawRectangle(dpy, awin, gc, No_x, No_y, No_w, No_h); - if (! view_only) { - XDrawRectangle(dpy, awin, gc, Vi_x, Vi_y, - Vi_w, Vi_h); - } - } - - tw = XTextWidth(font_info, str_y, strlen(str_y)); - tw = (Ye_w - tw)/2; - if (tw < 0) tw = 1; - XDrawString(dpy, awin, gc, Ye_x+tw, Ye_y+Ye_h-5, - str_y, strlen(str_y)); - - if (!accept) { - break; - } - tw = XTextWidth(font_info, str_n, strlen(str_n)); - tw = (No_w - tw)/2; - if (tw < 0) tw = 1; - XDrawString(dpy, awin, gc, No_x+tw, No_y+No_h-5, - str_n, strlen(str_n)); - - if (! view_only) { - tw = XTextWidth(font_info, str_v, - strlen(str_v)); - tw = (Vi_w - tw)/2; - if (tw < 0) tw = 1; - XDrawString(dpy, awin, gc, Vi_x+tw, - Vi_y+Vi_h-5, str_v, strlen(str_v)); - } - - break; - - case ClientMessage: - if (ev.xclient.message_type == wm_protocols && - (Atom) ev.xclient.data.l[0] == wm_delete_window) { - out = 0; - } - break; - - case ButtonPress: - x = ev.xbutton.x; - y = ev.xbutton.y; - if (!strcmp(mode, "key_only")) { - ; - } else if (x > Ye_x && x < Ye_x+Ye_w && y > Ye_y - && y < Ye_y+Ye_h) { - out = 1; - } else if (! accept) { - ; - } else if (x > No_x && x < No_x+No_w && y > No_y - && y < No_y+No_h) { - out = 0; - } else if (! view_only && x > Vi_x && x < Vi_x+Vi_w - && y > Vi_y && y < Vi_y+Ye_h) { - out = 2; - } - break; - - case KeyPress: - if (!strcmp(mode, "mouse_only")) { - ; - } else if (! accept) { - if (ev.xkey.keycode == key_o) { - out = 1; - } - if (ev.xkey.keycode == key_y) { - out = 1; - } - } else if (ev.xkey.keycode == key_y) { - out = 1; - ; - } else if (ev.xkey.keycode == key_n) { - out = 0; - } else if (! view_only && ev.xkey.keycode == key_v) { - out = 2; - } - break; - default: - break; - } - if (out != -1) { - ret = out; - XSelectInput_wr(dpy, awin, 0); - XUnmapWindow(dpy, awin); - XFree_wr(gc); - XDestroyWindow(dpy, awin); - XFlush_wr(dpy); - break; - } - } - X_UNLOCK; - - return ret; -#endif /* NO_X11 */ -} - -/* - * process a "yes:0,no:*,view:3" type action list comparing to command - * return code rc. * means the default action with no other match. - */ -static int action_match(char *action, int rc) { - char *p, *q, *s = strdup(action); - int cases[4], i, result; - char *labels[4]; - - labels[1] = "yes"; - labels[2] = "no"; - labels[3] = "view"; - - rfbLog("accept_client: process action line: %s\n", - action); - - for (i=1; i <= 3; i++) { - cases[i] = -2; - } - - p = strtok(s, ","); - while (p) { - if ((q = strchr(p, ':')) != NULL) { - int in, k = 1; - *q = '\0'; - q++; - if (strstr(p, "yes") == p) { - k = 1; - } else if (strstr(p, "no") == p) { - k = 2; - } else if (strstr(p, "view") == p) { - k = 3; - } else { - rfbLogEnable(1); - rfbLog("invalid action line: %s\n", action); - clean_up_exit(1); - } - if (*q == '*') { - cases[k] = -1; - } else if (sscanf(q, "%d", &in) == 1) { - if (in < 0) { - rfbLogEnable(1); - rfbLog("invalid action line: %s\n", - action); - clean_up_exit(1); - } - cases[k] = in; - } else { - rfbLogEnable(1); - rfbLog("invalid action line: %s\n", action); - clean_up_exit(1); - } - } else { - rfbLogEnable(1); - rfbLog("invalid action line: %s\n", action); - clean_up_exit(1); - } - p = strtok(NULL, ","); - } - free(s); - - result = -1; - for (i=1; i <= 3; i++) { - if (cases[i] == -1) { - rfbLog("accept_client: default action is case=%d %s\n", - i, labels[i]); - result = i; - break; - } - } - if (result == -1) { - rfbLog("accept_client: no default action\n"); - } - for (i=1; i <= 3; i++) { - if (cases[i] >= 0 && cases[i] == rc) { - rfbLog("accept_client: matched action is case=%d %s\n", - i, labels[i]); - result = i; - break; - } - } - if (result < 0) { - rfbLog("no action match: %s rc=%d set to no\n", action, rc); - result = 2; - } - return result; -} - -static void ugly_geom(char *p, int *x, int *y) { - int x1, y1; - - if (sscanf(p, "+%d+%d", &x1, &y1) == 2) { - *x = x1; - *y = y1; - } else if (sscanf(p, "+%d-%d", &x1, &y1) == 2) { - *x = x1; - *y = -y1; - } else if (sscanf(p, "-%d+%d", &x1, &y1) == 2) { - *x = -x1; - *y = y1; - } else if (sscanf(p, "-%d-%d", &x1, &y1) == 2) { - *x = -x1; - *y = -y1; - } -} - -/* - * Simple routine to prompt the user on the X display whether an incoming - * client should be allowed to connect or not. If a gui is involved it - * will be running in the environment/context of the X11 DISPLAY. - * - * The command supplied via -accept is run as is (i.e. no string - * substitution) with the RFB_CLIENT_IP environment variable set to the - * incoming client's numerical IP address. - * - * If the external command exits with 0 the client is accepted, otherwise - * the client is rejected. - * - * Some builtins are provided: - * - * xmessage: use homebrew xmessage(1) for the external command. - * popup: use internal X widgets for prompting. - * - */ -int accept_client(rfbClientPtr client) { - - char xmessage[200], *cmd = NULL; - char *addr = client->host; - char *action = NULL; - - if (accept_cmd == NULL || *accept_cmd == '\0') { - return 1; /* no command specified, so we accept */ - } - - if (addr == NULL || addr[0] == '\0') { - addr = "unknown-host"; - } - - if (strstr(accept_cmd, "popup") == accept_cmd) { - /* use our builtin popup button */ - - /* (popup|popupkey|popupmouse)[+-X+-Y][:timeout] */ - - int ret, timeout = 120; - int x = -64000, y = -64000; - char *p, *mode; - char *userhost = ident_username(client); - - /* extract timeout */ - if ((p = strchr(accept_cmd, ':')) != NULL) { - int in; - if (sscanf(p+1, "%d", &in) == 1) { - timeout = in; - } - } - /* extract geometry */ - if ((p = strpbrk(accept_cmd, "+-")) != NULL) { - ugly_geom(p, &x, &y); - } - - /* find mode: mouse, key, or both */ - if (strstr(accept_cmd, "popupmouse") == accept_cmd) { - mode = "mouse_only"; - } else if (strstr(accept_cmd, "popupkey") == accept_cmd) { - mode = "key_only"; - } else { - mode = "both"; - } - - if (dpy == NULL && use_dpy && strstr(use_dpy, "WAIT:") == - use_dpy) { - rfbLog("accept_client: warning allowing client under conditions:\n"); - rfbLog(" -display WAIT:, dpy == NULL, -accept popup.\n"); - rfbLog(" There will be another popup.\n"); - return 1; - } - - rfbLog("accept_client: using builtin popup for: %s\n", addr); - if ((ret = ugly_window(addr, userhost, x, y, timeout, - mode, 1))) { - free(userhost); - if (ret == 2) { - rfbLog("accept_client: viewonly: %s\n", addr); - client->viewOnly = TRUE; - } - rfbLog("accept_client: popup accepted: %s\n", addr); - return 1; - } else { - free(userhost); - rfbLog("accept_client: popup rejected: %s\n", addr); - return 0; - } - - } else if (!strcmp(accept_cmd, "xmessage")) { - /* make our own command using xmessage(1) */ - - if (view_only) { - sprintf(xmessage, "xmessage -buttons yes:0,no:2 -center" - " 'x11vnc: accept connection from %s?'", addr); - } else { - sprintf(xmessage, "xmessage -buttons yes:0,no:2," - "view-only:3 -center" " 'x11vnc: accept connection" - " from %s?'", addr); - action = "yes:0,no:*,view:3"; - } - cmd = xmessage; - - } else { - /* use the user supplied command: */ - - cmd = accept_cmd; - - /* extract any action prefix: yes:N,no:M,view:K */ - if (strstr(accept_cmd, "yes:") == accept_cmd) { - char *p; - if ((p = strpbrk(accept_cmd, " \t")) != NULL) { - int i; - cmd = p; - p = accept_cmd; - for (i=0; i<200; i++) { - if (*p == ' ' || *p == '\t') { - xmessage[i] = '\0'; - break; - } - xmessage[i] = *p; - p++; - } - xmessage[200-1] = '\0'; - action = xmessage; - } - } - } - - if (cmd) { - int rc; - - rfbLog("accept_client: using cmd for: %s\n", addr); - rc = run_user_command(cmd, client, "accept", NULL, 0, NULL); - - if (action) { - int result; - - if (rc < 0) { - rfbLog("accept_client: cannot use negative " - "rc: %d, action %s\n", rc, action); - result = 2; - } else { - result = action_match(action, rc); - } - - if (result == 1) { - rc = 0; - } else if (result == 2) { - rc = 1; - } else if (result == 3) { - rc = 0; - rfbLog("accept_client: viewonly: %s\n", addr); - client->viewOnly = TRUE; - } else { - rc = 1; /* NOTREACHED */ - } - } - - if (rc == 0) { - rfbLog("accept_client: accepted: %s\n", addr); - return 1; - } else { - rfbLog("accept_client: rejected: %s\n", addr); - return 0; - } - } else { - rfbLog("accept_client: no command, rejecting %s\n", addr); - return 0; - } - - /* return 0; NOTREACHED */ -} - -void check_ipv6_listen(long usec) { -#if X11VNC_IPV6 - fd_set fds; - struct timeval tv; - int nfds, csock = -1, one = 1; - struct sockaddr_in6 addr; - socklen_t addrlen = sizeof(addr); - rfbClientPtr cl; - int nmax = 0; - char *name; - - if (!ipv6_listen || noipv6) { - return; - } - if (ipv6_listen_fd < 0 && ipv6_http_fd < 0) { - return; - } - - FD_ZERO(&fds); - if (ipv6_listen_fd >= 0) { - FD_SET(ipv6_listen_fd, &fds); - nmax = ipv6_listen_fd; - } - if (ipv6_http_fd >= 0 && screen->httpSock < 0) { - FD_SET(ipv6_http_fd, &fds); - if (ipv6_http_fd > nmax) { - nmax = ipv6_http_fd; - } - } - - tv.tv_sec = 0; - tv.tv_usec = 0; - - nfds = select(nmax+1, &fds, NULL, NULL, &tv); - - if (nfds <= 0) { - return; - } - - if (ipv6_listen_fd >= 0 && FD_ISSET(ipv6_listen_fd, &fds)) { - - csock = accept(ipv6_listen_fd, (struct sockaddr *)&addr, &addrlen); - if (csock < 0) { - rfbLogPerror("check_ipv6_listen: accept"); - goto err1; - } - if (fcntl(csock, F_SETFL, O_NONBLOCK) < 0) { - rfbLogPerror("check_ipv6_listen: fcntl"); - close(csock); - goto err1; - } - if (setsockopt(csock, IPPROTO_TCP, TCP_NODELAY, - (char *)&one, sizeof(one)) < 0) { - rfbLogPerror("check_ipv6_listen: setsockopt"); - close(csock); - goto err1; - } - - name = ipv6_getipaddr((struct sockaddr *) &addr, addrlen); - - ipv6_client_ip_str = name; - cl = rfbNewClient(screen, csock); - ipv6_client_ip_str = NULL; - if (cl == NULL) { - close(csock); - goto err1; - } - - if (name) { - if (cl->host) { - free(cl->host); - } - cl->host = name; - rfbLog("ipv6 client: %s\n", name); - } - } - - err1: - - if (ipv6_http_fd >= 0 && FD_ISSET(ipv6_http_fd, &fds)) { - - csock = accept(ipv6_http_fd, (struct sockaddr *)&addr, &addrlen); - if (csock < 0) { - rfbLogPerror("check_ipv6_listen: accept"); - return; - } - if (fcntl(csock, F_SETFL, O_NONBLOCK) < 0) { - rfbLogPerror("check_ipv6_listen: fcntl"); - close(csock); - return; - } - if (setsockopt(csock, IPPROTO_TCP, TCP_NODELAY, - (char *)&one, sizeof(one)) < 0) { - rfbLogPerror("check_ipv6_listen: setsockopt"); - close(csock); - return; - } - - rfbLog("check_ipv6_listen: setting httpSock to %d\n", csock); - screen->httpSock = csock; - - if (screen->httpListenSock < 0) { - /* this may not always work... */ - int save = screen->httpListenSock; - screen->httpListenSock = ipv6_http_fd; - rfbLog("check_ipv6_listen: no httpListenSock, calling rfbHttpCheckFds()\n"); - rfbHttpCheckFds(screen); - screen->httpListenSock = save; - } - } -#endif - if (usec) {} -} - -void check_unix_sock(long usec) { - fd_set fds; - struct timeval tv; - int nfds, csock = -1; - rfbClientPtr cl; - int nmax = 0; - char *name; - - if (!unix_sock || unix_sock_fd < 0) { - return; - } - - FD_ZERO(&fds); - if (unix_sock_fd >= 0) { - FD_SET(unix_sock_fd, &fds); - nmax = unix_sock_fd; - } - - tv.tv_sec = 0; - tv.tv_usec = 0; - - nfds = select(nmax+1, &fds, NULL, NULL, &tv); - - if (nfds <= 0) { - return; - } - - if (unix_sock_fd >= 0 && FD_ISSET(unix_sock_fd, &fds)) { - csock = accept_unix(unix_sock_fd); - if (csock < 0) { - return; - } - if (fcntl(csock, F_SETFL, O_NONBLOCK) < 0) { - rfbLogPerror("check_unix_sock: fcntl"); - close(csock); - return; - } - - /* rfbNewClient() will screw us with setsockopt TCP_NODELAY... - you need to comment out in libvncserver/rfbserver.c: - rfbLogPerror("setsockopt failed"); - close(sock); - return NULL; - */ - cl = rfbNewClient(screen, csock); - - if (cl == NULL) { - close(csock); - return; - } - - name = strdup(unix_sock); - - if (name) { - if (cl->host) { - free(cl->host); - } - cl->host = name; - rfbLog("unix sock client: %s\n", name); - } - } -} - -/* - * For the -connect <file> option: periodically read the file looking for - * a connect string. If one is found set client_connect to it. - */ -static void check_connect_file(char *file) { - FILE *in; - char line[VNC_CONNECT_MAX], host[VNC_CONNECT_MAX]; - static int first_warn = 1, truncate_ok = 1; - static double last_time = 0.0, delay = 0.5; - double now = dnow(); - struct stat sbuf; - - if (last_time == 0.0) { - if (!getenv("X11VNC_APPSHARE_ACTIVE")) { - /* skip first */ - last_time = now; - } else { - delay = 0.25; - } - } - if (now - last_time < delay) { - /* check only about once a second */ - return; - } - last_time = now; - - if (! truncate_ok) { - /* check if permissions changed */ - if (access(file, W_OK) == 0) { - truncate_ok = 1; - } else { - return; - } - } - - if (stat(file, &sbuf) == 0) { - /* skip empty file directly */ - if (sbuf.st_size == 0) { - return; - } - } - - in = fopen(file, "r"); - if (in == NULL) { - if (first_warn) { - rfbLog("check_connect_file: fopen failure: %s\n", file); - rfbLogPerror("fopen"); - first_warn = 0; - } - return; - } - - if (fgets(line, VNC_CONNECT_MAX, in) != NULL) { - if (sscanf(line, "%s", host) == 1) { - if (strlen(host) > 0) { - char *str = strdup(host); - if (strlen(str) > 38) { - char trim[100]; - trim[0] = '\0'; - strncat(trim, str, 38); - rfbLog("read connect file: %s ...\n", - trim); - } else { - rfbLog("read connect file: %s\n", str); - } - if (!strcmp(str, "cmd=stop") && - dnowx() < 3.0) { - rfbLog("ignoring stale cmd=stop\n"); - } else { - client_connect = str; - } - } - } - } - fclose(in); - - /* truncate file */ - in = fopen(file, "w"); - if (in != NULL) { - fclose(in); - } else { - /* disable if we cannot truncate */ - rfbLog("check_connect_file: could not truncate %s, " - "disabling checking.\n", file); - truncate_ok = 0; - } -} - -static int socks5_proxy(char *host, int port, int sock) { - unsigned char buf[512], tmp[2]; - char reply[512]; - int len, n, i, j = 0; - - memset(buf, 0, 512); - memset(reply, 0, 512); - - buf[0] = 0x5; - buf[1] = 0x1; - buf[2] = 0x0; - - write(sock, buf, 3); - - n = read(sock, buf, 2); - - if (n != 2) { - rfbLog("socks5_proxy: read error: %d\n", n); - close(sock); - return 0; - } - if (buf[0] != 0x5 || buf[1] != 0x0) { - rfbLog("socks5_proxy: handshake error: %d %d\n", (int) buf[0], (int) buf[1]); - close(sock); - return 0; - } - - buf[0] = 0x5; - buf[1] = 0x1; - buf[2] = 0x0; - buf[3] = 0x3; - - buf[4] = (unsigned char) strlen(host); - strcat((char *) buf+5, host); - - len = 5 + strlen(host); - - buf[len] = (unsigned char) (port >> 8); - buf[len+1] = (unsigned char) (port & 0xff); - - write(sock, buf, len+2); - - for (i=0; i<4; i++) { - int n; - n = read(sock, tmp, 1); - j++; - if (n < 0) { - if (errno != EINTR) { - break; - } else { - i--; - if (j > 100) { - break; - } - continue; - } - } - if (n == 0) { - break; - } - reply[i] = tmp[0]; - } - if (reply[3] == 0x1) { - read(sock, reply+4, 4 + 2); - } else if (reply[3] == 0x3) { - n = read(sock, tmp, 1); - reply[4] = tmp[0]; - read(sock, reply+5, (int) reply[4] + 2); - } else if (reply[3] == 0x4) { - read(sock, reply+4, 16 + 2); - } - - if (0) { - int i; - for (i=0; i<len+2; i++) { - fprintf(stderr, "b[%d]: %d\n", i, (int) buf[i]); - } - for (i=0; i<len+2; i++) { - fprintf(stderr, "r[%d]: %d\n", i, (int) reply[i]); - } - } - if (reply[0] == 0x5 && reply[1] == 0x0 && reply[2] == 0x0) { - rfbLog("SOCKS5 connect OK to %s:%d sock=%d\n", host, port, sock); - return 1; - } else { - rfbLog("SOCKS5 error to %s:%d sock=%d\n", host, port, sock); - close(sock); - return 0; - } -} - -static int socks_proxy(char *host, int port, int sock) { - unsigned char buf[512], tmp[2]; - char reply[16]; - int socks4a = 0, len, i, j = 0, d1, d2, d3, d4; - - memset(buf, 0, 512); - - buf[0] = 0x4; - buf[1] = 0x1; - buf[2] = (unsigned char) (port >> 8); - buf[3] = (unsigned char) (port & 0xff); - - - if (strlen(host) > 256) { - rfbLog("socks_proxy: hostname too long: %s\n", host); - close(sock); - return 0; - } - - if (!strcmp(host, "localhost") || !strcmp(host, "127.0.0.1")) { - buf[4] = 127; - buf[5] = 0; - buf[6] = 0; - buf[7] = 1; - } else if (sscanf(host, "%d.%d.%d.%d", &d1, &d2, &d3, &d4) == 4) { - buf[4] = (unsigned char) d1; - buf[5] = (unsigned char) d2; - buf[6] = (unsigned char) d3; - buf[7] = (unsigned char) d4; - } else { - buf[4] = 0x0; - buf[5] = 0x0; - buf[6] = 0x0; - buf[7] = 0x3; - socks4a = 1; - } - len = 8; - - strcat((char *)buf+8, "nobody"); - len += strlen("nobody") + 1; - - if (socks4a) { - strcat((char *) buf+8+strlen("nobody") + 1, host); - len += strlen(host) + 1; - } - - write(sock, buf, len); - - for (i=0; i<8; i++) { - int n; - n = read(sock, tmp, 1); - j++; - if (n < 0) { - if (errno != EINTR) { - break; - } else { - i--; - if (j > 100) { - break; - } - continue; - } - } - if (n == 0) { - break; - } - reply[i] = tmp[0]; - } - if (0) { - int i; - for (i=0; i<len; i++) { - fprintf(stderr, "b[%d]: %d\n", i, (int) buf[i]); - } - for (i=0; i<8; i++) { - fprintf(stderr, "r[%d]: %d\n", i, (int) reply[i]); - } - } - if (reply[0] == 0x0 && reply[1] == 0x5a) { - if (socks4a) { - rfbLog("SOCKS4a connect OK to %s:%d sock=%d\n", host, port, sock); - } else { - rfbLog("SOCKS4 connect OK to %s:%d sock=%d\n", host, port, sock); - } - return 1; - } else { - if (socks4a) { - rfbLog("SOCKS4a error to %s:%d sock=%d\n", host, port, sock); - } else { - rfbLog("SOCKS4 error to %s:%d sock=%d\n", host, port, sock); - } - close(sock); - return 0; - } -} - -#define PXY_HTTP 1 -#define PXY_GET 2 -#define PXY_SOCKS 3 -#define PXY_SOCKS5 4 -#define PXY_SSH 5 -#define PXY 3 - -static int pxy_get_sock; - -static int pconnect(int psock, char *host, int port, int type, char *http_path, char *gethost, int getport) { - char reply[4096]; - int i, ok, len; - char *req; - - pxy_get_sock = -1; - - if (type == PXY_SOCKS) { - return socks_proxy(host, port, psock); - } - if (type == PXY_SOCKS5) { - return socks5_proxy(host, port, psock); - } - if (type == PXY_SSH) { - return 1; - } - - len = strlen("CONNECT ") + strlen(host); - if (type == PXY_GET) { - len += strlen(http_path) + strlen(gethost); - len += strlen("host=") + 1 + strlen("port=") + 1 + 1; - } - len += 1 + 20 + strlen("HTTP/1.1\r\n") + 1; - - req = (char *)malloc(len); - - if (type == PXY_GET) { - int noquery = 0; - char *t = strstr(http_path, "__END__"); - if (t) { - noquery = 1; - *t = '\0'; - } - - if (noquery) { - sprintf(req, "GET %s HTTP/1.1\r\n", http_path); - } else { - sprintf(req, "GET %shost=%s&port=%d HTTP/1.1\r\n", http_path, host, port); - } - } else { - sprintf(req, "CONNECT %s:%d HTTP/1.1\r\n", host, port); - } - rfbLog("http proxy: %s", req); - write(psock, req, strlen(req)); - - if (type == PXY_GET) { - char *t = "Connection: close\r\n"; - write(psock, t, strlen(t)); - } - - if (type == PXY_GET) { - sprintf(req, "Host: %s:%d\r\n", gethost, getport); - rfbLog("http proxy: %s", req); - sprintf(req, "Host: %s:%d\r\n\r\n", gethost, getport); - } else { - sprintf(req, "Host: %s:%d\r\n", host, port); - rfbLog("http proxy: %s", req); - sprintf(req, "Host: %s:%d\r\n\r\n", host, port); - } - - write(psock, req, strlen(req)); - - ok = 0; - reply[0] = '\0'; - - for (i=0; i<4096; i++) { - int n; - req[0] = req[1] = '\0'; - n = read(psock, req, 1); - if (n < 0) { - if (errno != EINTR) { - break; - } else { - continue; - } - } - if (n == 0) { - break; - } - strcat(reply, req); - if (strstr(reply, "\r\n\r\n")) { - if (strstr(reply, "HTTP/") == reply) { - char *q = strchr(reply, ' '); - if (q) { - q++; - if (q[0] == '2' && q[1] == '0' && q[2] == '0' && q[3] == ' ') { - ok = 1; - } - } - } - break; - } - } - - if (type == PXY_GET) { - char *t1 = strstr(reply, "VNC-IP-Port: "); - char *t2 = strstr(reply, "VNC-Host-Port: "); - char *s, *newhost = NULL; - int newport = 0; - fprintf(stderr, "%s\n", reply); - if (t1) { - t1 += strlen("VNC-IP-Port: "); - s = strstr(t1, ":"); - if (s) { - *s = '\0'; - newhost = strdup(t1); - newport = atoi(s+1); - } - } else if (t2) { - t2 += strlen("VNC-Host-Port: "); - s = strstr(t2, ":"); - if (s) { - *s = '\0'; - newhost = strdup(t2); - newport = atoi(s+1); - } - } - if (newhost && newport > 0) { - rfbLog("proxy GET reconnect to: %s:%d\n", newhost, newport); - pxy_get_sock = connect_tcp(newhost, newport); - } - } - free(req); - - return ok; -} - -static int proxy_connect(char *host, int port) { - char *p, *q, *str; - int i, n, pxy[PXY],pxy_p[PXY]; - int psock = -1; - char *pxy_h[PXY], *pxy_g[PXY]; - - if (! connect_proxy) { - return -1; - } - str = strdup(connect_proxy); - - for (i=0; i<PXY; i++) { - pxy[i] = 0; - pxy_p[i] = 0; - pxy_h[i] = NULL; - pxy_g[i] = NULL; - } - - n = 0; - p = str; - while (p) { - char *hp, *c, *s = NULL; - - q = strchr(p, ','); - if (q) { - *q = '\0'; - } - - if (n==0) fprintf(stderr, "\n"); - rfbLog("proxy_connect[%d]: %s\n", n+1, p); - - pxy[n] = 0; - pxy_p[n] = 0; - pxy_h[n] = NULL; - pxy_g[n] = NULL; - - if (strstr(p, "socks://") == p) { - hp = strstr(p, "://") + 3; - pxy[n] = PXY_SOCKS; - } else if (strstr(p, "socks4://") == p) { - hp = strstr(p, "://") + 3; - pxy[n] = PXY_SOCKS; - } else if (strstr(p, "socks5://") == p) { - hp = strstr(p, "://") + 3; - pxy[n] = PXY_SOCKS5; - } else if (strstr(p, "ssh://") == p) { - if (n != 0) { - rfbLog("ssh:// proxy must be the first one\n"); - clean_up_exit(1); - } - hp = strstr(p, "://") + 3; - pxy[n] = PXY_SSH; - } else if (strstr(p, "http://") == p) { - hp = strstr(p, "://") + 3; - pxy[n] = PXY_HTTP; - } else if (strstr(p, "https://") == p) { - hp = strstr(p, "://") + 3; - pxy[n] = PXY_HTTP; - } else { - hp = p; - pxy[n] = PXY_HTTP; - } - c = strstr(hp, ":"); - if (!c && pxy[n] == PXY_SSH) { - char *hp2 = (char *) malloc(strlen(hp) + 5); - sprintf(hp2, "%s:1", hp); - hp = hp2; - c = strstr(hp, ":"); - } - if (!c) { - pxy[n] = 0; - if (q) { - *q = ','; - p = q + 1; - } else { - p = NULL; - } - continue; - } - - if (pxy[n] == PXY_HTTP) { - s = strstr(c, "/"); - if (s) { - pxy[n] = PXY_GET; - pxy_g[n] = strdup(s); - *s = '\0'; - } - } - pxy_p[n] = atoi(c+1); - - if (pxy_p[n] <= 0) { - pxy[n] = 0; - pxy_p[n] = 0; - if (q) { - *q = ','; - p = q + 1; - } else { - p = NULL; - } - continue; - } - *c = '\0'; - pxy_h[n] = strdup(hp); - - if (++n >= PXY) { - break; - } - - if (q) { - *q = ','; - p = q + 1; - } else { - p = NULL; - } - } - free(str); - - if (!n) { - psock = -1; - goto pxy_clean; - } - - if (pxy[0] == PXY_SSH) { - int rc, len = 0; - char *cmd, *ssh; - int sport = find_free_port(7300, 8000); - if (getenv("SSH")) { - ssh = getenv("SSH"); - } else { - ssh = "ssh"; - } - len = 200 + strlen(ssh) + strlen(pxy_h[0]) + strlen(host); - cmd = (char *) malloc(len); - if (n == 1) { - if (pxy_p[0] <= 1) { - sprintf(cmd, "%s -f -L '%d:%s:%d' '%s' 'sleep 20'", ssh, sport, host, port, pxy_h[0]); - } else { - sprintf(cmd, "%s -f -p %d -L '%d:%s:%d' '%s' 'sleep 20'", ssh, pxy_p[0], sport, host, port, pxy_h[0]); - } - } else { - if (pxy_p[0] <= 1) { - sprintf(cmd, "%s -f -L '%d:%s:%d' '%s' 'sleep 20'", ssh, sport, pxy_h[1], pxy_p[1], pxy_h[0]); - } else { - sprintf(cmd, "%s -f -p %d -L '%d:%s:%d' '%s' 'sleep 20'", ssh, pxy_p[0], sport, pxy_h[1], pxy_p[1], pxy_h[0]); - } - } - if (no_external_cmds || !cmd_ok("ssh")) { - rfbLogEnable(1); - rfbLog("cannot run external commands in -nocmds mode:\n"); - rfbLog(" \"%s\"\n", cmd); - rfbLog(" exiting.\n"); - clean_up_exit(1); - } - close_exec_fds(); - fprintf(stderr, "\n"); - rfbLog("running: %s\n", cmd); - rc = system(cmd); - free(cmd); - if (rc != 0) { - psock = -1; - goto pxy_clean; - } - psock = connect_tcp("localhost", sport); - - } else { - psock = connect_tcp(pxy_h[0], pxy_p[0]); - } - - if (psock < 0) { - psock = -1; - goto pxy_clean; - } - rfbLog("opened socket to proxy: %s:%d\n", pxy_h[0], pxy_p[0]); - - if (n >= 2) { - if (! pconnect(psock, pxy_h[1], pxy_p[1], pxy[0], pxy_g[0], pxy_h[0], pxy_p[0])) { - close(psock); psock = -1; goto pxy_clean; - } - if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;} - - if (n >= 3) { - if (! pconnect(psock, pxy_h[2], pxy_p[2], pxy[1], pxy_g[1], pxy_h[1], pxy_p[1])) { - close(psock); psock = -1; goto pxy_clean; - } - if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;} - if (! pconnect(psock, host, port, pxy[2], pxy_g[2], pxy_h[2], pxy_p[2])) { - close(psock); psock = -1; goto pxy_clean; - } - if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;} - - } else { - if (! pconnect(psock, host, port, pxy[1], pxy_g[1], pxy_h[1], pxy_p[1])) { - close(psock); psock = -1; goto pxy_clean; - } - if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;} - } - } else { - if (! pconnect(psock, host, port, pxy[0], pxy_g[0], pxy_h[0], pxy_p[0])) { - close(psock); psock = -1; goto pxy_clean; - } - if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;} - } - - pxy_clean: - for (i=0; i < PXY; i++) { - if (pxy_h[i] != NULL) { - free(pxy_h[i]); - } - if (pxy_g[i] != NULL) { - free(pxy_g[i]); - } - } - - return psock; -} - -char *get_repeater_string(char *str, int *len) { - int pren, which = 0; - int prestring_len = 0; - char *prestring = NULL, *ptmp = NULL; - char *equals = strchr(str, '='); - char *plus = strrchr(str, '+'); - - *len = 0; - if (!plus || !equals) { - return NULL; - } - - *plus = '\0'; - if (strstr(str, "repeater=") == str) { - /* ultravnc repeater http://www.uvnc.com/addons/repeater.html */ - prestring_len = 250; - ptmp = (char *) calloc(prestring_len+1, 1); - snprintf(ptmp, 250, "%s", str + strlen("repeater=")); - which = 1; - } else if (strstr(str, "pre=") == str) { - prestring_len = strlen(str + strlen("pre=")); - ptmp = (char *) calloc(prestring_len+1, 1); - snprintf(ptmp, prestring_len+1, "%s", str + strlen("pre=")); - which = 2; - } else if (sscanf(str, "pre%d=", &pren) == 1) { - if (pren > 0 && pren <= 16384) { - prestring_len = pren; - ptmp = (char *) calloc(prestring_len+1, 1); - snprintf(prestring, prestring_len, "%s", equals+1); - which = 3; - } - } - if (ptmp != NULL) { - int i, k = 0; - char *p = ptmp; - prestring = (char *)calloc(prestring_len+1, 1); - /* translate \n to newline, etc. */ - for (i=0; i < prestring_len; i++) { - if (i < prestring_len-1 && *(p+i) == '\\') { - if (*(p+i+1) == 'r') { - prestring[k++] = '\r'; i++; - } else if (*(p+i+1) == 'n') { - prestring[k++] = '\n'; i++; - } else if (*(p+i+1) == 't') { - prestring[k++] = '\t'; i++; - } else if (*(p+i+1) == 'a') { - prestring[k++] = '\a'; i++; - } else if (*(p+i+1) == 'b') { - prestring[k++] = '\b'; i++; - } else if (*(p+i+1) == 'v') { - prestring[k++] = '\v'; i++; - } else if (*(p+i+1) == 'f') { - prestring[k++] = '\f'; i++; - } else if (*(p+i+1) == '\\') { - prestring[k++] = '\\'; i++; - } else if (*(p+i+1) == 'c') { - prestring[k++] = ','; i++; - } else { - prestring[k++] = *(p+i); - } - } else { - prestring[k++] = *(p+i); - } - } - if (which == 2) { - prestring_len = k; - } - if (!quiet) { - rfbLog("-connect prestring: '%s'\n", prestring); - } - free(ptmp); - } - *plus = '+'; - - *len = prestring_len; - return prestring; -} - -#ifndef USE_TIMEOUT_INTERRUPT -#define USE_TIMEOUT_INTERRUPT 0 -#endif - -static void reverse_connect_timeout (int sig) { - rfbLog("sig: %d, reverse_connect_timeout.\n", sig); -#if USE_TIMEOUT_INTERRUPT - rfbLog("reverse_connect_timeout proceeding assuming connect(2) interrupt.\n"); -#else - clean_up_exit(0); -#endif -} - - -/* - * Do a reverse connect for a single "host" or "host:port" - */ - -static int do_reverse_connect(char *str_in) { - rfbClientPtr cl; - char *host, *p, *str = str_in, *s = NULL; - char *prestring = NULL; - int prestring_len = 0; - int rport = 5500, len = strlen(str); - int set_alarm = 0; - - if (len < 1) { - return 0; - } - if (len > 1024) { - rfbLog("reverse_connect: string too long: %d bytes\n", len); - return 0; - } - if (!screen) { - rfbLog("reverse_connect: screen not setup yet.\n"); - return 0; - } - if (unixpw_in_progress) return 0; - - /* look for repeater pre-string */ - if (strchr(str, '=') && strrchr(str, '+') - && (strstr(str, "pre") == str || strstr(str, "repeater=") == str)) { - prestring = get_repeater_string(str, &prestring_len); - str = strrchr(str, '+') + 1; - } else if (strrchr(str, '+') && strstr(str, "repeater://") == str) { - /* repeater://host:port+string */ - /* repeater=string+host:port */ - char *plus = strrchr(str, '+'); - str = (char *) malloc(strlen(str_in)+1); - s = str; - *plus = '\0'; - sprintf(str, "repeater=%s+%s", plus+1, str_in + strlen("repeater://")); - prestring = get_repeater_string(str, &prestring_len); - str = strrchr(str, '+') + 1; - *plus = '+'; - } - - /* copy in to host */ - host = (char *) malloc(len+1); - if (! host) { - rfbLog("reverse_connect: could not malloc string %d\n", len); - return 0; - } - strncpy(host, str, len); - host[len] = '\0'; - - /* extract port, if any */ - if ((p = strrchr(host, ':')) != NULL) { - rport = atoi(p+1); - if (rport < 0) { - rport = -rport; - } else if (rport < 20) { - rport = 5500 + rport; - } - *p = '\0'; - } - - if (ipv6_client_ip_str) { - free(ipv6_client_ip_str); - ipv6_client_ip_str = NULL; - } - - if (use_openssl) { - int vncsock; - if (connect_proxy) { - vncsock = proxy_connect(host, rport); - } else { - vncsock = connect_tcp(host, rport); - } - if (vncsock < 0) { - rfbLog("reverse_connect: failed to connect to: %s\n", str); - return 0; - } - if (prestring != NULL) { - write(vncsock, prestring, prestring_len); - free(prestring); - } -/* XXX use header */ -#define OPENSSL_REVERSE 6 - if (!getenv("X11VNC_DISABLE_SSL_CLIENT_MODE")) { - openssl_init(1); - } - - if (first_conn_timeout > 0) { - set_alarm = 1; - signal(SIGALRM, reverse_connect_timeout); -#if USE_TIMEOUT_INTERRUPT - siginterrupt(SIGALRM, 1); -#endif - rfbLog("reverse_connect: using alarm() timeout of %d seconds.\n", first_conn_timeout); - alarm(first_conn_timeout); - } - accept_openssl(OPENSSL_REVERSE, vncsock); - if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);} - - openssl_init(0); - free(host); - return 1; - } - - if (use_stunnel) { - if(strcmp(host, "localhost") && strcmp(host, "127.0.0.1")) { - if (!getenv("STUNNEL_DISABLE_LOCALHOST")) { - rfbLog("reverse_connect: error host not localhost in -stunnel mode.\n"); - return 0; - } - } - } - - if (unixpw) { - int is_localhost = 0, user_disabled_it = 0; - - if(!strcmp(host, "localhost") || !strcmp(host, "127.0.0.1")) { - is_localhost = 1; - } - if (getenv("UNIXPW_DISABLE_LOCALHOST")) { - user_disabled_it = 1; - } - - if (! is_localhost) { - if (user_disabled_it) { - rfbLog("reverse_connect: warning disabling localhost constraint in -unixpw\n"); - } else { - rfbLog("reverse_connect: error not localhost in -unixpw\n"); - return 0; - } - } - } - - if (first_conn_timeout > 0) { - set_alarm = 1; - signal(SIGALRM, reverse_connect_timeout); -#if USE_TIMEOUT_INTERRUPT - siginterrupt(SIGALRM, 1); -#endif - rfbLog("reverse_connect: using alarm() timeout of %d seconds.\n", first_conn_timeout); - alarm(first_conn_timeout); - } - - if (connect_proxy != NULL) { - int sock = proxy_connect(host, rport); - if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);} - if (sock >= 0) { - if (prestring != NULL) { - write(sock, prestring, prestring_len); - free(prestring); - } - cl = create_new_client(sock, 1); - } else { - return 0; - } - } else if (prestring != NULL) { - int sock = connect_tcp(host, rport); - if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);} - if (sock >= 0) { - write(sock, prestring, prestring_len); - free(prestring); - cl = create_new_client(sock, 1); - } else { - return 0; - } - } else { - cl = rfbReverseConnection(screen, host, rport); - if (cl == NULL) { - int sock = connect_tcp(host, rport); - if (sock >= 0) { - cl = create_new_client(sock, 1); - } - } - if (set_alarm) {alarm(0); signal(SIGALRM, SIG_DFL);} - if (cl != NULL && use_threads) { - cl->onHold = FALSE; - rfbStartOnHoldClient(cl); - } - } - - free(host); - - if (ipv6_client_ip_str) { - free(ipv6_client_ip_str); - ipv6_client_ip_str = NULL; - } - - - if (cl == NULL) { - if (quiet && connect_or_exit) { - rfbLogEnable(1); - } - rfbLog("reverse_connect: %s failed\n", str); - return 0; - } else { - rfbLog("reverse_connect: %s/%s OK\n", str, cl->host); - /* let's see if anyone complains: */ - if (! getenv("X11VNC_REVERSE_CONNECTION_NO_AUTH")) { - rfbLog("reverse_connect: turning on auth for %s\n", - cl->host); - cl->reverseConnection = FALSE; - } - return 1; - } -} - -/* - * Break up comma separated list of hosts and call do_reverse_connect() - */ -void reverse_connect(char *str) { - char *p, *tmp; - int sleep_between_host = 300; - int sleep_min = 1500, sleep_max = 4500, n_max = 5; - int n, tot, t, dt = 100, cnt = 0; - int nclients0 = client_count; - int lcnt, j; - char **list; - int do_appshare = 0; - - if (!getenv("X11VNC_REVERSE_USE_OLD_SLEEP")) { - sleep_min = 500; - sleep_max = 2500; - } - - if (unixpw_in_progress) return; - - tmp = strdup(str); - - list = (char **) calloc( (strlen(tmp)+2) * sizeof (char *), 1); - lcnt = 0; - - p = strtok(tmp, ", \t\r\n"); - while (p) { - list[lcnt++] = strdup(p); - p = strtok(NULL, ", \t\r\n"); - } - free(tmp); - - if (subwin && getenv("X11VNC_APPSHARE_ACTIVE")) { - do_appshare = 1; - sleep_between_host = 0; /* too agressive??? */ - } - if (getenv("X11VNC_REVERSE_SLEEP_BETWEEN_HOST")) { - sleep_between_host = atoi(getenv("X11VNC_REVERSE_SLEEP_BETWEEN_HOST")); - } - - if (do_appshare) { - if (screen && dpy) { - char *s = choose_title(DisplayString(dpy)); - - /* mutex */ - screen->desktopName = s; - if (rfb_desktop_name) { - free(rfb_desktop_name); - } - rfb_desktop_name = strdup(s); - } - } - - for (j = 0; j < lcnt; j++) { - p = list[j]; - - if ((n = do_reverse_connect(p)) != 0) { - int i; - progress_client(); - for (i=0; i < 3; i++) { - rfbPE(-1); - } - } - cnt += n; - if (list[j+1] != NULL) { - t = 0; - while (t < sleep_between_host) { - double t1, t2; - int i; - t1 = dnow(); - for (i=0; i < 8; i++) { - rfbPE(-1); - if (do_appshare && t == 0) { - rfbPE(-1); - } - } - t2 = dnow(); - t += (int) (1000 * (t2 - t1)); - if (t >= sleep_between_host) { - break; - } - usleep(dt * 1000); - t += dt; - } - } - } - - for (j = 0; j < lcnt; j++) { - p = list[j]; - if (p) free(p); - } - free(list); - - if (cnt == 0) { - if (connect_or_exit) { - rfbLogEnable(1); - rfbLog("exiting under -connect_or_exit\n"); - if (gui_pid > 0) { - rfbLog("killing gui_pid %d\n", gui_pid); - kill(gui_pid, SIGTERM); - } - clean_up_exit(1); - } - if (xrandr || xrandr_maybe) { - check_xrandr_event("reverse_connect1"); - } - return; - } - - /* - * XXX: we need to process some of the initial handshaking - * events, otherwise the client can get messed up (why??) - * so we send rfbProcessEvents() all over the place. - * - * How much is this still needed? - */ - - n = cnt; - if (n >= n_max) { - n = n_max; - } - t = sleep_max - sleep_min; - tot = sleep_min + ((n-1) * t) / (n_max-1); - - if (do_appshare) { - tot /= 3; - if (tot < dt) { - tot = dt; - } - tot = 0; /* too agressive??? */ - } - - if (getenv("X11VNC_REVERSE_SLEEP_MAX")) { - tot = atoi(getenv("X11VNC_REVERSE_SLEEP_MAX")); - } - - t = 0; - while (t < tot) { - int i; - double t1, t2; - t1 = dnow(); - for (i=0; i < 8; i++) { - rfbPE(-1); - if (t == 0) rfbPE(-1); - } - t2 = dnow(); - t += (int) (1000 * (t2 - t1)); - if (t >= tot) { - break; - } - usleep(dt * 1000); - t += dt; - } - if (connect_or_exit) { - if (client_count <= nclients0) { - for (t = 0; t < 10; t++) { - int i; - for (i=0; i < 3; i++) { - rfbPE(-1); - } - usleep(100 * 1000); - } - } - if (client_count <= nclients0) { - rfbLogEnable(1); - rfbLog("exiting under -connect_or_exit\n"); - if (gui_pid > 0) { - rfbLog("killing gui_pid %d\n", gui_pid); - kill(gui_pid, SIGTERM); - } - clean_up_exit(1); - } - } - if (xrandr || xrandr_maybe) { - check_xrandr_event("reverse_connect2"); - } -} - -/* - * Routines for monitoring the VNC_CONNECT and X11VNC_REMOTE properties - * for changes. The vncconnect(1) will set it on our X display. - */ -void set_vnc_connect_prop(char *str) { - RAWFB_RET_VOID -#if !NO_X11 - if (vnc_connect_prop == None) return; - XChangeProperty(dpy, rootwin, vnc_connect_prop, XA_STRING, 8, - PropModeReplace, (unsigned char *)str, strlen(str)); -#else - if (!str) {} -#endif /* NO_X11 */ -} - -void set_x11vnc_remote_prop(char *str) { - RAWFB_RET_VOID -#if !NO_X11 - if (x11vnc_remote_prop == None) return; - XChangeProperty(dpy, rootwin, x11vnc_remote_prop, XA_STRING, 8, - PropModeReplace, (unsigned char *)str, strlen(str)); -#else - if (!str) {} -#endif /* NO_X11 */ -} - -void read_vnc_connect_prop(int nomsg) { -#if NO_X11 - RAWFB_RET_VOID - if (!nomsg) {} - return; -#else - Atom type; - int format, slen, dlen; - unsigned long nitems = 0, bytes_after = 0; - unsigned char* data = NULL; - int db = 1; - - vnc_connect_str[0] = '\0'; - slen = 0; - - if (! vnc_connect || vnc_connect_prop == None) { - /* not active or problem with VNC_CONNECT atom */ - return; - } - RAWFB_RET_VOID - - /* read the property value into vnc_connect_str: */ - do { - if (XGetWindowProperty(dpy, DefaultRootWindow(dpy), - vnc_connect_prop, nitems/4, VNC_CONNECT_MAX/16, False, - AnyPropertyType, &type, &format, &nitems, &bytes_after, - &data) == Success) { - - dlen = nitems * (format/8); - if (slen + dlen > VNC_CONNECT_MAX) { - /* too big */ - rfbLog("warning: truncating large VNC_CONNECT" - " string > %d bytes.\n", VNC_CONNECT_MAX); - XFree_wr(data); - break; - } - memcpy(vnc_connect_str+slen, data, dlen); - slen += dlen; - vnc_connect_str[slen] = '\0'; - XFree_wr(data); - } - } while (bytes_after > 0); - - vnc_connect_str[VNC_CONNECT_MAX] = '\0'; - if (! db || nomsg) { - ; - } else { - rfbLog("read VNC_CONNECT: %s\n", vnc_connect_str); - } -#endif /* NO_X11 */ -} - -void read_x11vnc_remote_prop(int nomsg) { -#if NO_X11 - RAWFB_RET_VOID - if (!nomsg) {} - return; -#else - Atom type; - int format, slen, dlen; - unsigned long nitems = 0, bytes_after = 0; - unsigned char* data = NULL; - int db = 1; - - x11vnc_remote_str[0] = '\0'; - slen = 0; - - if (! vnc_connect || x11vnc_remote_prop == None) { - /* not active or problem with X11VNC_REMOTE atom */ - return; - } - RAWFB_RET_VOID - - /* read the property value into x11vnc_remote_str: */ - do { - if (XGetWindowProperty(dpy, DefaultRootWindow(dpy), - x11vnc_remote_prop, nitems/4, X11VNC_REMOTE_MAX/16, False, - AnyPropertyType, &type, &format, &nitems, &bytes_after, - &data) == Success) { - - dlen = nitems * (format/8); - if (slen + dlen > X11VNC_REMOTE_MAX) { - /* too big */ - rfbLog("warning: truncating large X11VNC_REMOTE" - " string > %d bytes.\n", X11VNC_REMOTE_MAX); - XFree_wr(data); - break; - } - memcpy(x11vnc_remote_str+slen, data, dlen); - slen += dlen; - x11vnc_remote_str[slen] = '\0'; - XFree_wr(data); - } - } while (bytes_after > 0); - - x11vnc_remote_str[X11VNC_REMOTE_MAX] = '\0'; - if (! db || nomsg) { - ; - } else if (strstr(x11vnc_remote_str, "ans=stop:N/A,ans=quit:N/A,ans=")) { - ; - } else if (strstr(x11vnc_remote_str, "qry=stop,quit,exit")) { - ; - } else if (strstr(x11vnc_remote_str, "ack=") == x11vnc_remote_str) { - ; - } else if (quiet && strstr(x11vnc_remote_str, "qry=ping") == - x11vnc_remote_str) { - ; - } else if (strstr(x11vnc_remote_str, "cmd=") && - strstr(x11vnc_remote_str, "passwd")) { - rfbLog("read X11VNC_REMOTE: *\n"); - } else if (strlen(x11vnc_remote_str) > 36) { - char trim[100]; - trim[0] = '\0'; - strncat(trim, x11vnc_remote_str, 36); - rfbLog("read X11VNC_REMOTE: %s ...\n", trim); - - } else { - rfbLog("read X11VNC_REMOTE: %s\n", x11vnc_remote_str); - } -#endif /* NO_X11 */ -} - -extern int rc_npieces; - -void grab_state(int *ptr_grabbed, int *kbd_grabbed) { - int rcp, rck; - double t0, t1; - double ta, tb, tc; - *ptr_grabbed = -1; - *kbd_grabbed = -1; - - if (!dpy) { - return; - } - *ptr_grabbed = 0; - *kbd_grabbed = 0; - -#if !NO_X11 - X_LOCK; - - XSync(dpy, False); - - ta = t0 = dnow(); - - rcp = XGrabPointer(dpy, window, False, 0, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - XUngrabPointer(dpy, CurrentTime); - - tb = dnow(); - - rck = XGrabKeyboard(dpy, window, False, GrabModeAsync, GrabModeAsync, CurrentTime); - XUngrabKeyboard(dpy, CurrentTime); - - tc = dnow(); - - XSync(dpy, False); - - t1 = dnow(); - - X_UNLOCK; - if (rcp == AlreadyGrabbed || rcp == GrabFrozen) { - *ptr_grabbed = 1; - } - if (rck == AlreadyGrabbed || rck == GrabFrozen) { - *kbd_grabbed = 1; - } - if (rc_npieces < 10) { - rfbLog("grab_state: checked %d,%d in %.6f sec (%.6f %.6f)\n", - *ptr_grabbed, *kbd_grabbed, t1-t0, tb-ta, tc-tb); - } -#endif -} - -static void pmove(int x, int y) { - if (x < 0 || y < 0) { - rfbLog("pmove: skipping negative x or y: %d %d\n", x, y); - return; - } - rfbLog("pmove: x y: %d %d\n", x, y); - pointer_event(0, x, y, NULL); - X_LOCK; - XFlush_wr(dpy); - X_UNLOCK; -} - - -char *bcx_xattach(char *str, int *pg_init, int *kg_init) { - int grab_check = 1; - int shift = 20; - int final_x = 30, final_y = 30; - int extra_x = -1, extra_y = -1; - int t1, t2, dt = 40 * 1000; - int ifneeded = 0; - char *dir = "none", *flip = "none", *q; - int pg1, kg1, pg2, kg2; - char _bcx_res[128]; - - /* str:[up,down,left,right]+nograbcheck+shift=n+final=x+y+extra_move=x+y+[master_to_slave,slave_to_master,M2S,S2M]+dt=n+retry=n+ifneeded */ - - if (strstr(str, "up")) { - dir = "up"; - } else if (strstr(str, "down")) { - dir = "down"; - } else if (strstr(str, "left")) { - dir = "left"; - } else if (strstr(str, "right")) { - dir = "right"; - } else { - return strdup("FAIL,NO_DIRECTION_SPECIFIED"); - } - - if (strstr(str, "master_to_slave") || strstr(str, "M2S")) { - flip = "M2S"; - } else if (strstr(str, "slave_to_master") || strstr(str, "S2M")) { - flip = "S2M"; - } else { - return strdup("FAIL,NO_MODE_CHANGE_SPECIFIED"); - } - - if (strstr(str, "nograbcheck")) { - grab_check = 0; - } - if (strstr(str, "ifneeded")) { - ifneeded = 1; - } - q = strstr(str, "shift="); - if (q && sscanf(q, "shift=%d", &t1) == 1) { - shift = t1; - } - q = strstr(str, "final="); - if (q && sscanf(q, "final=%d+%d", &t1, &t2) == 2) { - final_x = t1; - final_y = t2; - } - q = strstr(str, "extra_move="); - if (q && sscanf(q, "extra_move=%d+%d", &t1, &t2) == 2) { - extra_x = t1; - extra_y = t2; - } - q = strstr(str, "dt="); - if (q && sscanf(q, "dt=%d", &t1) == 1) { - dt = t1 * 1000; - } - - if (grab_check) { - int read_init = 0; - - if (*pg_init >=0 && *kg_init >=0) { - pg1 = *pg_init; - kg1 = *kg_init; - read_init = 1; - } else { - grab_state(&pg1, &kg1); - read_init = 0; - } - - if (!strcmp(flip, "M2S")) { - if (ifneeded && pg1 == 1 && kg1 == 1) { - rfbLog("bcx_xattach: M2S grab state is already what we want, skipping moves: %d,%d\n", pg1, kg1); - return strdup("DONE,GRAB_OK"); - } - } else if (!strcmp(flip, "S2M")) { - if (ifneeded && pg1 == 0 && kg1 == 0) { - rfbLog("bcx_xattach: S2M grab state is already what we want, skipping moves: %d,%d\n", pg1, kg1); - return strdup("DONE,GRAB_OK"); - } - } - - if (read_init) { - ; - } else if (!strcmp(flip, "M2S")) { - if (pg1 != 0 || kg1 != 0) { - rfbLog("bcx_xattach: M2S init grab state incorrect: %d,%d\n", pg1, kg1); - usleep(2*dt); - grab_state(&pg1, &kg1); - rfbLog("bcx_xattach: slept and retried, grab is now: %d,%d\n", pg1, kg1); - } - } else if (!strcmp(flip, "S2M")) { - if (pg1 != 1 || kg1 != 1) { - rfbLog("bcx_xattach: S2M init grab state incorrect: %d,%d\n", pg1, kg1); - usleep(2*dt); - grab_state(&pg1, &kg1); - rfbLog("bcx_xattach: slept and retried, grab is now: %d,%d\n", pg1, kg1); - } - } - if (!read_init) { - *pg_init = pg1; - *kg_init = kg1; - } - } - - /* - * A guide for BARCO xattach: - * - * For -cursor_rule 'b(0):%:t(1),t(1):%:b(0)' - * down+M2S up+S2M - * For -cursor_rule 'r(0):%:l(1),l(1):%:r(0)' - * right+M2S left+S2M - * - * For -cursor_rule 't(0):%:b(1),b(1):%:t(0)' - * up+M2S down+S2M - * For -cursor_rule 'l(0):%:r(1),r(1):%:l(0)' - * left+M2S right+S2M - * For -cursor_rule 'l(0):%:r(1),r(1):%:l(0),r(0):%:l(1),l(1):%:r(0)' - * left+M2S right+S2M (we used to do both 'right') - */ - - if (!strcmp(flip, "M2S")) { - if (!strcmp(dir, "up")) { - pmove(shift, 0); /* go to top edge */ - usleep(dt); - pmove(shift+1, 0); /* move 1 for MotionNotify */ - } else if (!strcmp(dir, "down")) { - pmove(shift, dpy_y-1); /* go to bottom edge */ - usleep(dt); - pmove(shift+1, dpy_y-1); /* move 1 for MotionNotify */ - } else if (!strcmp(dir, "left")) { - pmove(0, shift); /* go to left edge */ - usleep(dt); - pmove(0, shift+1); /* move 1 for MotionNotify */ - } else if (!strcmp(dir, "right")) { - pmove(dpy_x-1, shift); /* go to right edge */ - usleep(dt); - pmove(dpy_x-1, shift+1); /* move 1 for Motion Notify */ - } - } else if (!strcmp(flip, "S2M")) { - int dts = dt/2; - if (!strcmp(dir, "up")) { - pmove(shift, 2); /* Approach top edge in 3 moves. 1st move */ - usleep(dts); - pmove(shift, 1); /* 2nd move */ - usleep(dts); - pmove(shift, 0); /* 3rd move */ - usleep(dts); - pmove(shift+1, 0); /* move 1 for MotionNotify */ - usleep(dts); - pmove(shift+1, dpy_y-2); /* go to height-2 for extra pixel (slave y now == 0?) */ - usleep(dts); - pmove(shift, dpy_y-2); /* move 1 for MotionNotify */ - usleep(dts); - pmove(shift, 1); /* go to 1 to be sure slave y == 0 */ - usleep(dts); - pmove(shift+1, 1); /* move 1 for MotionNotify */ - } else if (!strcmp(dir, "down")) { - pmove(shift, dpy_y-3); /* Approach bottom edge in 3 moves. 1st move */ - usleep(dts); - pmove(shift, dpy_y-2); /* 2nd move */ - usleep(dts); - pmove(shift, dpy_y-1); /* 3rd move */ - usleep(dts); - pmove(shift+1, dpy_y-1); /* move 1 for MotionNotify */ - usleep(dts); - pmove(shift+1, 1); /* go to 1 for extra pixel (slave y now == dpy_y-1?) */ - usleep(dts); - pmove(shift, 1); /* move 1 for MotionNotify */ - usleep(dts); - pmove(shift, dpy_y-2); /* go to dpy_y-2 to be sure slave y == dpy_y-1 */ - usleep(dts); - pmove(shift+1, dpy_y-2); /* move 1 for MotionNotify */ - } else if (!strcmp(dir, "left")) { - pmove(2, shift); /* Approach left edge in 3 moves. 1st move */ - usleep(dts); - pmove(1, shift); /* 2nd move */ - usleep(dts); - pmove(0, shift); /* 3rd move */ - usleep(dts); - pmove(0, shift+1); /* move 1 for MotionNotify */ - usleep(dts); - pmove(dpy_x-2, shift+1); /* go to width-2 for extra pixel (slave x now == 0?) */ - usleep(dts); - pmove(dpy_x-2, shift); /* move 1 for MotionNotify */ - usleep(dts); - pmove(1, shift); /* go to 1 to be sure slave x == 0 */ - usleep(dts); - pmove(1, shift+1); /* move 1 for MotionNotify */ - } else if (!strcmp(dir, "right")) { - pmove(dpy_x-3, shift); /* Approach right edge in 3 moves. 1st move */ - usleep(dts); - pmove(dpy_x-2, shift); /* 2nd move */ - usleep(dts); - pmove(dpy_x-1, shift); /* 3rd move */ - usleep(dts); - pmove(dpy_x-1, shift+1); /* move 1 for MotionNotify */ - usleep(dts); - pmove(1, shift+1); /* go to 1 to extra pixel (slave x now == dpy_x-1?) */ - usleep(dts); - pmove(1, shift); /* move 1 for MotionNotify */ - usleep(dts); - pmove(dpy_x-2, shift); /* go to dpy_x-2 to be sure slave x == dpy_x-1 */ - usleep(dts); - pmove(dpy_x-2, shift+1); /* move 1 for MotionNotify */ - } - } - - usleep(dt); - pmove(final_x, final_y); - usleep(dt); - - if (extra_x >= 0 && extra_y >= 0) { - pmove(extra_x, extra_y); - usleep(dt); - } - - strcpy(_bcx_res, "DONE"); - - if (grab_check) { - char st[64]; - - usleep(3*dt); - grab_state(&pg2, &kg2); - - if (!strcmp(flip, "M2S")) { - if (pg2 != 1 || kg2 != 1) { - rfbLog("bcx_xattach: M2S fini grab state incorrect: %d,%d\n", pg2, kg2); - usleep(2*dt); - grab_state(&pg2, &kg2); - rfbLog("bcx_xattach: slept and retried, grab is now: %d,%d\n", pg2, kg2); - } - } else if (!strcmp(flip, "S2M")) { - if (pg2 != 0 || kg2 != 0) { - rfbLog("bcx_xattach: S2M fini grab state incorrect: %d,%d\n", pg2, kg2); - usleep(2*dt); - grab_state(&pg2, &kg2); - rfbLog("bcx_xattach: slept and retried, grab is now: %d,%d\n", pg2, kg2); - } - } - - sprintf(st, ":%d,%d-%d,%d", pg1, kg1, pg2, kg2); - - if (getenv("GRAB_CHECK_LOOP")) { - int i, n = atoi(getenv("GRAB_CHECK_LOOP")); - rfbLog("grab st: %s\n", st); - for (i=0; i < n; i++) { - usleep(dt); - grab_state(&pg2, &kg2); - sprintf(st, ":%d,%d-%d,%d", pg1, kg1, pg2, kg2); - rfbLog("grab st: %s\n", st); - } - } - - if (!strcmp(flip, "M2S")) { - if (pg1 == 0 && kg1 == 0 && pg2 == 1 && kg2 == 1) { - strcat(_bcx_res, ",GRAB_OK"); - } else { - rfbLog("bcx_xattach: M2S grab state incorrect: %d,%d -> %d,%d\n", pg1, kg1, pg2, kg2); - strcat(_bcx_res, ",GRAB_FAIL"); - if (pg2 == 1 && kg2 == 1) { - strcat(_bcx_res, "_INIT"); - } else if (pg1 == 0 && kg1 == 0) { - strcat(_bcx_res, "_FINAL"); - } - strcat(_bcx_res, st); - } - } else if (!strcmp(flip, "S2M")) { - if (pg1 == 1 && kg1 == 1 && pg2 == 0 && kg2 == 0) { - strcat(_bcx_res, ",GRAB_OK"); - } else { - rfbLog("bcx_xattach: S2M grab state incorrect: %d,%d -> %d,%d\n", pg1, kg1, pg2, kg2); - strcat(_bcx_res, ",GRAB_FAIL"); - if (pg2 == 0 && kg2 == 0) { - strcat(_bcx_res, "_INIT"); - } else if (pg1 == 1 && kg1 == 1) { - strcat(_bcx_res, "_FINAL"); - } - strcat(_bcx_res, st); - } - } - } - return strdup(_bcx_res); -} - -int set_xprop(char *prop, Window win, char *value) { - int rc = -1; -#if !NO_X11 - Atom aprop; - - RAWFB_RET(rc) - - if (!prop || !value) { - return rc; - } - if (win == None) { - win = rootwin; - } - aprop = XInternAtom(dpy, prop, False); - if (aprop == None) { - return rc; - } - rc = XChangeProperty(dpy, win, aprop, XA_STRING, 8, - PropModeReplace, (unsigned char *)value, strlen(value)); - return rc; -#else - RAWFB_RET(rc) - if (!prop || !win || !value) {} - return rc; -#endif /* NO_X11 */ -} - -char *get_xprop(char *prop, Window win) { -#if NO_X11 - RAWFB_RET(NULL) - if (!prop || !win) {} - return NULL; -#else - Atom type, aprop; - int format, slen, dlen; - unsigned long nitems = 0, bytes_after = 0; - unsigned char* data = NULL; - char get_str[VNC_CONNECT_MAX+1]; - - RAWFB_RET(NULL) - - if (prop == NULL || !strcmp(prop, "")) { - return NULL; - } - if (win == None) { - win = rootwin; - } - aprop = XInternAtom(dpy, prop, True); - if (aprop == None) { - return NULL; - } - - get_str[0] = '\0'; - slen = 0; - - /* read the property value into get_str: */ - do { - if (XGetWindowProperty(dpy, win, aprop, nitems/4, - VNC_CONNECT_MAX/16, False, AnyPropertyType, &type, - &format, &nitems, &bytes_after, &data) == Success) { - - dlen = nitems * (format/8); - if (slen + dlen > VNC_CONNECT_MAX) { - /* too big */ - rfbLog("get_xprop: warning: truncating large '%s'" - " string > %d bytes.\n", prop, VNC_CONNECT_MAX); - XFree_wr(data); - break; - } - memcpy(get_str+slen, data, dlen); - slen += dlen; - get_str[slen] = '\0'; - XFree_wr(data); - } - } while (bytes_after > 0); - - get_str[VNC_CONNECT_MAX] = '\0'; - rfbLog("get_prop: read: '%s' = '%s'\n", prop, get_str); - - return strdup(get_str); -#endif /* NO_X11 */ -} - -static char _win_fmt[1000]; - -static char *win_fmt(Window win, XWindowAttributes a) { - memset(_win_fmt, 0, sizeof(_win_fmt)); - sprintf(_win_fmt, "0x%lx:%dx%dx%d+%d+%d-map:%d-bw:%d-cl:%d-vis:%d-bs:%d/%d", - win, a.width, a.height, a.depth, a.x, a.y, a.map_state, a.border_width, a.class, - (int) ((a.visual)->visualid), a.backing_store, a.save_under); - return _win_fmt; -} - -char *wininfo(Window win, int show_children) { -#if NO_X11 - RAWFB_RET(NULL) - if (!win || !show_children) {} - return NULL; -#else - XWindowAttributes attr; - int n, size = X11VNC_REMOTE_MAX; - char get_str[X11VNC_REMOTE_MAX+1]; - unsigned int nchildren; - Window rr, pr, *children; - - RAWFB_RET(NULL) - - if (win == None) { - return strdup("None"); - } - - X_LOCK; - if (!valid_window(win, &attr, 1)) { - X_UNLOCK; - return strdup("Invalid"); - } - get_str[0] = '\0'; - - if (show_children) { - XQueryTree_wr(dpy, win, &rr, &pr, &children, &nchildren); - } else { - nchildren = 1; - children = (Window *) calloc(2 * sizeof(Window), 1); - children[0] = win; - } - for (n=0; n < (int) nchildren; n++) { - char tmp[32]; - char *str = "Invalid"; - Window w = children[n]; - if (valid_window(w, &attr, 1)) { - if (!show_children) { - str = win_fmt(w, attr); - } else { - sprintf(tmp, "0x%lx", w); - str = tmp; - } - } - if ((int) (strlen(get_str) + 1 + strlen(str)) >= size) { - break; - } - if (n > 0) { - strcat(get_str, ","); - } - strcat(get_str, str); - } - get_str[size] = '\0'; - if (!show_children) { - free(children); - } else if (nchildren) { - XFree_wr(children); - } - rfbLog("wininfo computed: %s\n", get_str); - X_UNLOCK; - - return strdup(get_str); -#endif /* NO_X11 */ -} - -/* - * check if client_connect has been set, if so make the reverse connections. - */ -static void send_client_connect(void) { - if (client_connect != NULL) { - char *str = client_connect; - if (strstr(str, "cmd=") == str || strstr(str, "qry=") == str) { - process_remote_cmd(client_connect, 0); - } else if (strstr(str, "ans=") == str - || strstr(str, "aro=") == str) { - ; - } else if (strstr(str, "ack=") == str) { - ; - } else { - reverse_connect(client_connect); - } - free(client_connect); - client_connect = NULL; - } -} - -/* - * monitor the various input methods - */ -void check_connect_inputs(void) { - - if (unixpw_in_progress) return; - - /* flush any already set: */ - send_client_connect(); - - /* connect file: */ - if (client_connect_file != NULL) { - check_connect_file(client_connect_file); - } - send_client_connect(); - - /* VNC_CONNECT property (vncconnect program) */ - if (vnc_connect && *vnc_connect_str != '\0') { - client_connect = strdup(vnc_connect_str); - vnc_connect_str[0] = '\0'; - } - send_client_connect(); - - /* X11VNC_REMOTE property */ - if (vnc_connect && *x11vnc_remote_str != '\0') { - client_connect = strdup(x11vnc_remote_str); - x11vnc_remote_str[0] = '\0'; - } - send_client_connect(); -} - -void check_gui_inputs(void) { - int i, gnmax = 0, n = 0, nfds; - int socks[ICON_MODE_SOCKS]; - fd_set fds; - struct timeval tv; - char buf[X11VNC_REMOTE_MAX+1]; - ssize_t nbytes; - - if (unixpw_in_progress) return; - - for (i=0; i<ICON_MODE_SOCKS; i++) { - if (icon_mode_socks[i] >= 0) { - socks[n++] = i; - if (icon_mode_socks[i] > gnmax) { - gnmax = icon_mode_socks[i]; - } - } - } - - if (! n) { - return; - } - - FD_ZERO(&fds); - for (i=0; i<n; i++) { - FD_SET(icon_mode_socks[socks[i]], &fds); - } - tv.tv_sec = 0; - tv.tv_usec = 0; - - nfds = select(gnmax+1, &fds, NULL, NULL, &tv); - if (nfds <= 0) { - return; - } - - for (i=0; i<n; i++) { - int k, fd = icon_mode_socks[socks[i]]; - char *p; - char **list; - int lind; - - if (! FD_ISSET(fd, &fds)) { - continue; - } - for (k=0; k<=X11VNC_REMOTE_MAX; k++) { - buf[k] = '\0'; - } - nbytes = read(fd, buf, X11VNC_REMOTE_MAX); - if (nbytes <= 0) { - close(fd); - icon_mode_socks[socks[i]] = -1; - continue; - } - - list = (char **) calloc((strlen(buf)+2) * sizeof(char *), 1); - - lind = 0; - p = strtok(buf, "\r\n"); - while (p) { - list[lind++] = strdup(p); - p = strtok(NULL, "\r\n"); - } - - lind = 0; - while (list[lind] != NULL) { - p = list[lind++]; - if (strstr(p, "cmd=") == p || - strstr(p, "qry=") == p) { - char *str = process_remote_cmd(p, 1); - if (! str) { - str = strdup(""); - } - nbytes = write(fd, str, strlen(str)); - write(fd, "\n", 1); - free(str); - if (nbytes < 0) { - close(fd); - icon_mode_socks[socks[i]] = -1; - break; - } - } - } - - lind = 0; - while (list[lind] != NULL) { - p = list[lind++]; - if (p) free(p); - } - free(list); - } -} - -rfbClientPtr create_new_client(int sock, int start_thread) { - rfbClientPtr cl; - - if (!screen) { - return NULL; - } - - cl = rfbNewClient(screen, sock); - - if (cl == NULL) { - return NULL; - } - if (use_threads) { - cl->onHold = FALSE; - if (start_thread) { - rfbStartOnHoldClient(cl); - } - } - return cl; -} - -static int turn_off_truecolor = 0; - -static void turn_off_truecolor_ad(rfbClientPtr client) { - if (client) {} - if (turn_off_truecolor) { - rfbLog("turning off truecolor advertising.\n"); - /* mutex */ - screen->serverFormat.trueColour = FALSE; - screen->displayHook = NULL; - screen->serverFormat.redShift = 0; - screen->serverFormat.greenShift = 0; - screen->serverFormat.blueShift = 0; - screen->serverFormat.redMax = 0; - screen->serverFormat.greenMax = 0; - screen->serverFormat.blueMax = 0; - turn_off_truecolor = 0; - } -} - -/* - * some overrides for the local console text chat. - * could be useful in general for local helpers. - */ - -rfbBool password_check_chat_helper(rfbClientPtr cl, const char* response, int len) { - if (response || len) {} - if (cl != chat_window_client) { - rfbLog("invalid client during chat_helper login\n"); - return FALSE; - } else { - if (!cl->host) { - rfbLog("empty cl->host during chat_helper login\n"); - return FALSE; - } - if (strcmp(cl->host, "127.0.0.1")) { - rfbLog("invalid cl->host during chat_helper login: %s\n", cl->host); - return FALSE; - } - rfbLog("chat_helper login accepted\n"); - return TRUE; - } -} - -enum rfbNewClientAction new_client_chat_helper(rfbClientPtr client) { - if (client) {} - client->clientGoneHook = client_gone_chat_helper; - rfbLog("new chat helper\n"); - return(RFB_CLIENT_ACCEPT); -} - -void client_gone_chat_helper(rfbClientPtr client) { - if (client) {} - rfbLog("finished chat helper\n"); - chat_window_client = NULL; -} - -void client_set_net(rfbClientPtr client) { - ClientData *cd; - if (client == NULL) { - return; - } - cd = (ClientData *) client->clientData; - if (cd == NULL) { - return; - } - if (cd->client_port < 0) { - double dt = dnow(); - cd->client_port = get_remote_port(client->sock); - cd->server_port = get_local_port(client->sock); - cd->server_ip = get_local_host(client->sock); - cd->hostname = ip2host(client->host); - rfbLog("client_set_net: %s %.4f\n", client->host, dnow() - dt); - } -} -/* - * libvncserver callback for when a new client connects - */ -enum rfbNewClientAction new_client(rfbClientPtr client) { - ClientData *cd; - - CLIENT_LOCK; - - last_event = last_input = time(NULL); - - latest_client = client; - - if (inetd) { - /* - * Set this so we exit as soon as connection closes, - * otherwise client_gone is only called after RFB_CLIENT_ACCEPT - */ - if (inetd_client == NULL) { - inetd_client = client; - client->clientGoneHook = client_gone; - } - } - - clients_served++; - - if (use_openssl || use_stunnel) { - if (! ssl_initialized) { - rfbLog("denying additional client: %s ssl not setup" - " yet.\n", client->host); - CLIENT_UNLOCK; - return(RFB_CLIENT_REFUSE); - } - } - if (unixpw_in_progress) { - rfbLog("denying additional client: %s during -unixpw login.\n", - client->host); - CLIENT_UNLOCK; - return(RFB_CLIENT_REFUSE); - } - if (connect_once) { - if (screen->dontDisconnect && screen->neverShared) { - if (! shared && accepted_client) { - rfbLog("denying additional client: %s:%d\n", - client->host, get_remote_port(client->sock)); - CLIENT_UNLOCK; - return(RFB_CLIENT_REFUSE); - } - } - } - - if (ipv6_client_ip_str != NULL) { - rfbLog("renaming client->host from '%s' to '%s'\n", - client->host ? client->host : "", ipv6_client_ip_str); - if (client->host) { - free(client->host); - } - client->host = strdup(ipv6_client_ip_str); - } - - if (! check_access(client->host)) { - rfbLog("denying client: %s does not match %s\n", client->host, - allow_list ? allow_list : "(null)" ); - CLIENT_UNLOCK; - return(RFB_CLIENT_REFUSE); - } - - client->clientData = (void *) calloc(sizeof(ClientData), 1); - cd = (ClientData *) client->clientData; - - /* see client_set_net() we delay the DNS lookups during handshake */ - cd->client_port = -1; - cd->username = strdup(""); - cd->unixname = strdup(""); - - cd->input[0] = '-'; - cd->login_viewonly = -1; - cd->login_time = time(NULL); - cd->ssl_helper_pid = 0; - - if (use_openssl && openssl_last_helper_pid) { - cd->ssl_helper_pid = openssl_last_helper_pid; - openssl_last_helper_pid = 0; - } - - if (! accept_client(client)) { - rfbLog("denying client: %s local user rejected connection.\n", - client->host); - rfbLog("denying client: accept_cmd=\"%s\"\n", - accept_cmd ? accept_cmd : "(null)" ); - - free_client_data(client); - - CLIENT_UNLOCK; - return(RFB_CLIENT_REFUSE); - } - - /* We will RFB_CLIENT_ACCEPT or RFB_CLIENT_ON_HOLD from here on. */ - - if (passwdfile) { - if (strstr(passwdfile, "read:") == passwdfile || - strstr(passwdfile, "cmd:") == passwdfile) { - if (read_passwds(passwdfile)) { - install_passwds(); - } else { - rfbLog("problem reading: %s\n", passwdfile); - clean_up_exit(1); - } - } else if (strstr(passwdfile, "custom:") == passwdfile) { - if (screen) { - /* mutex */ - screen->passwordCheck = custom_passwd_check; - } - } - } - - cd->uid = clients_served; - - client->clientGoneHook = client_gone; - - if (client_count) { - speeds_net_rate_measured = 0; - speeds_net_latency_measured = 0; - } - client_count++; - - last_keyboard_input = last_pointer_input = time(NULL); - - if (no_autorepeat && client_count == 1 && ! view_only) { - /* - * first client, turn off X server autorepeat - * XXX handle dynamic change of view_only and per-client. - */ - autorepeat(0, 0); - } -#ifdef MACOSX - if (macosx_console && client_count == 1) { - macosxCG_refresh_callback_on(); - } -#endif - if (use_solid_bg && client_count == 1) { - solid_bg(0); - } - - if (pad_geometry) { - install_padded_fb(pad_geometry); - } - - cd->timer = last_new_client = dnow(); - cd->send_cmp_rate = 0.0; - cd->send_raw_rate = 0.0; - cd->latency = 0.0; - cd->cmp_bytes_sent = 0; - cd->raw_bytes_sent = 0; - - accepted_client++; - rfbLog("incr accepted_client=%d for %s:%d sock=%d\n", accepted_client, - client->host, get_remote_port(client->sock), client->sock); - last_client = time(NULL); - - if (ncache) { - check_ncache(1, 0); - } - - if (advertise_truecolor && indexed_color) { - int rs = 0, gs = 2, bs = 4; - int rm = 3, gm = 3, bm = 3; - if (bpp >= 24) { - rs = 0, gs = 8, bs = 16; - rm = 255, gm = 255, bm = 255; - } else if (bpp >= 16) { - rs = 0, gs = 5, bs = 10; - rm = 31, gm = 31, bm = 31; - } - rfbLog("advertising truecolor.\n"); - if (getenv("ADVERT_BMSHIFT")) { - bm--; - } - - if (use_threads) LOCK(client->updateMutex); - - client->format.trueColour = TRUE; - client->format.redShift = rs; - client->format.greenShift = gs; - client->format.blueShift = bs; - client->format.redMax = rm; - client->format.greenMax = gm; - client->format.blueMax = bm; - - if (use_threads) UNLOCK(client->updateMutex); - - rfbSetTranslateFunction(client); - - /* mutex */ - screen->serverFormat.trueColour = TRUE; - screen->serverFormat.redShift = rs; - screen->serverFormat.greenShift = gs; - screen->serverFormat.blueShift = bs; - screen->serverFormat.redMax = rm; - screen->serverFormat.greenMax = gm; - screen->serverFormat.blueMax = bm; - screen->displayHook = turn_off_truecolor_ad; - - turn_off_truecolor = 1; - } - - if (unixpw) { - unixpw_in_progress = 1; - unixpw_client = client; - unixpw_login_viewonly = 0; - - unixpw_file_xfer_save = screen->permitFileTransfer; - screen->permitFileTransfer = FALSE; - unixpw_tightvnc_xfer_save = tightfilexfer; - tightfilexfer = 0; -#ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER - rfbLog("rfbUnregisterTightVNCFileTransferExtension: 1\n"); - rfbUnregisterTightVNCFileTransferExtension(); -#endif - - if (client->viewOnly) { - unixpw_login_viewonly = 1; - client->viewOnly = FALSE; - } - unixpw_last_try_time = time(NULL) + 10; - - unixpw_screen(1); - unixpw_keystroke(0, 0, 1); - - if (!unixpw_in_rfbPE) { - rfbLog("new client: %s in non-unixpw_in_rfbPE.\n", - client->host); - } - CLIENT_UNLOCK; - if (!use_threads) { - /* always put client on hold even if unixpw_in_rfbPE is true */ - return(RFB_CLIENT_ON_HOLD); - } else { - /* unixpw threads is still in testing mode, disabled by default. See UNIXPW_THREADS */ - return(RFB_CLIENT_ACCEPT); - } - } - - CLIENT_UNLOCK; - return(RFB_CLIENT_ACCEPT); -} - -void start_client_info_sock(char *host_port_cookie) { - char *host = NULL, *cookie = NULL, *p; - char *str = strdup(host_port_cookie); - int i, port, sock, next = -1; - static time_t start_time[ICON_MODE_SOCKS]; - time_t oldest = 0; - int db = 0; - - port = -1; - - for (i = 0; i < ICON_MODE_SOCKS; i++) { - if (icon_mode_socks[i] < 0) { - next = i; - break; - } - if (oldest == 0 || start_time[i] < oldest) { - next = i; - oldest = start_time[i]; - } - } - - p = strtok(str, ":"); - i = 0; - while (p) { - if (i == 0) { - host = strdup(p); - } else if (i == 1) { - port = atoi(p); - } else if (i == 2) { - cookie = strdup(p); - } - i++; - p = strtok(NULL, ":"); - } - free(str); - - if (db) fprintf(stderr, "%s/%d/%s next=%d\n", host, port, cookie, next); - - if (host && port && cookie) { - if (*host == '\0') { - free(host); - host = strdup("localhost"); - } - sock = connect_tcp(host, port); - if (sock < 0) { - usleep(200 * 1000); - sock = connect_tcp(host, port); - } - if (sock >= 0) { - char *lst = list_clients(); - icon_mode_socks[next] = sock; - start_time[next] = time(NULL); - write(sock, "COOKIE:", strlen("COOKIE:")); - write(sock, cookie, strlen(cookie)); - write(sock, "\n", strlen("\n")); - write(sock, "none\n", strlen("none\n")); - write(sock, "none\n", strlen("none\n")); - write(sock, lst, strlen(lst)); - write(sock, "\n", strlen("\n")); - if (db) { - fprintf(stderr, "list: %s\n", lst); - } - free(lst); - rfbLog("client_info_sock to: %s:%d\n", host, port); - } else { - rfbLog("failed client_info_sock: %s:%d\n", host, port); - } - } else { - rfbLog("malformed client_info_sock: %s\n", host_port_cookie); - } - - if (host) free(host); - if (cookie) free(cookie); -} - -void send_client_info(char *str) { - int i; - static char *pstr = NULL; - static int len = 128; - - if (!str || strlen(str) == 0) { - return; - } - - if (!pstr) { - pstr = (char *)malloc(len); - } - if (strlen(str) + 2 > (size_t) len) { - free(pstr); - len *= 2; - pstr = (char *)malloc(len); - } - strcpy(pstr, str); - strcat(pstr, "\n"); - - if (icon_mode_fh) { - if (0) fprintf(icon_mode_fh, "\n"); - fprintf(icon_mode_fh, "%s", pstr); - fflush(icon_mode_fh); - } - - for (i=0; i<ICON_MODE_SOCKS; i++) { - int len, n, sock = icon_mode_socks[i]; - char *buf = pstr; - - if (sock < 0) { - continue; - } - - len = strlen(pstr); - while (len > 0) { - if (0) write(sock, "\n", 1); - n = write(sock, buf, len); - if (n > 0) { - buf += n; - len -= n; - continue; - } - - if (n < 0 && errno == EINTR) { - continue; - } - close(sock); - icon_mode_socks[i] = -1; - break; - } - } -} - -void adjust_grabs(int grab, int quiet) { - RAWFB_RET_VOID -#if NO_X11 - if (!grab || !quiet) {} - return; -#else - /* n.b. caller decides to X_LOCK or not. */ - if (grab) { - if (grab_kbd) { - if (! quiet) { - rfbLog("grabbing keyboard with XGrabKeyboard\n"); - } - XGrabKeyboard(dpy, window, False, GrabModeAsync, - GrabModeAsync, CurrentTime); - } - if (grab_ptr) { - if (! quiet) { - rfbLog("grabbing pointer with XGrabPointer\n"); - } - XGrabPointer(dpy, window, False, 0, GrabModeAsync, - GrabModeAsync, None, None, CurrentTime); - } - } else { - if (grab_kbd) { - if (! quiet) { - rfbLog("ungrabbing keyboard with XUngrabKeyboard\n"); - } - XUngrabKeyboard(dpy, CurrentTime); - } - if (grab_ptr) { - if (! quiet) { - rfbLog("ungrabbing pointer with XUngrabPointer\n"); - } - XUngrabPointer(dpy, CurrentTime); - } - } -#endif /* NO_X11 */ -} - -void check_new_clients(void) { - static int last_count = -1; - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int i, send_info = 0; - int run_after_accept = 0; - - if (unixpw_in_progress) { - static double lping = 0.0; - if (lping < dnow() + 5) { - mark_rect_as_modified(0, 0, 1, 1, 1); - lping = dnow(); - } - if (unixpw_client && unixpw_client->viewOnly) { - unixpw_login_viewonly = 1; - unixpw_client->viewOnly = FALSE; - } - if (time(NULL) > unixpw_last_try_time + 45) { - rfbLog("unixpw_deny: timed out waiting for reply.\n"); - unixpw_deny(); - } - return; - } - - if (grab_always) { - ; - } else if (grab_kbd || grab_ptr) { - static double last_force = 0.0; - if (client_count != last_count || dnow() > last_force + 0.25) { - int q = (client_count == last_count); - last_force = dnow(); - X_LOCK; - if (client_count) { - adjust_grabs(1, q); - } else { - adjust_grabs(0, q); - } - X_UNLOCK; - } - } - - if (last_count == -1) { - last_count = 0; - } else if (client_count == last_count) { - return; - } - - if (! all_clients_initialized()) { - return; - } - - if (client_count > last_count) { - if (afteraccept_cmd != NULL && afteraccept_cmd[0] != '\0') { - run_after_accept = 1; - } - } - - last_count = client_count; - - if (! screen) { - return; - } - - if (! client_count) { - send_client_info("clients:none"); - return; - } - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - ClientData *cd = (ClientData *) cl->clientData; - char *s; - - client_set_net(cl); - if (! cd) { - continue; - } - - if (cd->login_viewonly < 0) { - /* this is a general trigger to initialize things */ - if (cl->viewOnly) { - cd->login_viewonly = 1; - s = allowed_input_view_only; - if (s && cd->input[0] == '-') { - cl->viewOnly = FALSE; - cd->input[0] = '\0'; - strncpy(cd->input, s, CILEN); - } - } else { - cd->login_viewonly = 0; - s = allowed_input_normal; - if (s && cd->input[0] == '-') { - cd->input[0] = '\0'; - strncpy(cd->input, s, CILEN); - } - } - if (run_after_accept) { - run_user_command(afteraccept_cmd, cl, - "afteraccept", NULL, 0, NULL); - } - } - } - rfbReleaseClientIterator(iter); - - if (icon_mode_fh) { - send_info++; - } - for (i = 0; i < ICON_MODE_SOCKS; i++) { - if (send_info || icon_mode_socks[i] >= 0) { - send_info++; - break; - } - } - if (send_info) { - char *str, *s = list_clients(); - str = (char *) malloc(strlen("clients:") + strlen(s) + 1); - sprintf(str, "clients:%s", s); - send_client_info(str); - free(str); - free(s); - } -} - |