You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libtdevnc/x11vnc/sslcmds.c

294 lines
5.5 KiB

/* -- sslcmds.c -- */
#include "x11vnc.h"
#include "inet.h"
#include "cleanup.h"
#if LIBVNCSERVER_HAVE_FORK
#if LIBVNCSERVER_HAVE_SYS_WAIT_H
#if LIBVNCSERVER_HAVE_WAITPID
#define SSLCMDS
#endif
#endif
#endif
void check_stunnel(void);
int start_stunnel(int stunnel_port, int x11vnc_port);
void stop_stunnel(void);
void setup_stunnel(int rport, int *argc, char **argv);
static pid_t stunnel_pid = 0;
void check_stunnel(void) {
static time_t last_check = 0;
time_t now = time(0);
if (last_check + 3 >= now) {
return;
}
last_check = now;
if (stunnel_pid > 0) {
int status;
waitpid(stunnel_pid, &status, WNOHANG);
if (kill(stunnel_pid, 0) != 0) {
waitpid(stunnel_pid, &status, WNOHANG);
rfbLog("stunnel subprocess %d died.\n", stunnel_pid);
stunnel_pid = 0;
clean_up_exit(1);
}
}
}
int start_stunnel(int stunnel_port, int x11vnc_port) {
#ifdef SSLCMDS
char extra[] = ":/usr/sbin:/usr/local/sbin";
char *path, *p, *exe;
char *stunnel_path = NULL;
struct stat verify_buf;
int status;
if (stunnel_pid) {
stop_stunnel();
}
stunnel_pid = 0;
path = getenv("PATH");
if (! path) {
path = strdup(extra);
} else {
path = (char *) malloc(strlen(path)+strlen(extra)+1);
if (! path) {
return 0;
}
strcpy(path, getenv("PATH"));
strcat(path, extra);
}
exe = (char *) malloc(strlen(path) + strlen("stunnel") + 1);
p = strtok(path, ":");
exe[0] = '\0';
while (p) {
struct stat sbuf;
sprintf(exe, "%s/%s", p, "stunnel");
if (! stunnel_path && stat(exe, &sbuf) == 0) {
if (! S_ISDIR(sbuf.st_mode)) {
stunnel_path = exe;
break;
}
}
p = strtok(NULL, ":");
}
if (path) {
free(path);
}
if (! stunnel_path) {
return 0;
}
if (stunnel_path[0] == '\0') {
free(stunnel_path);
return 0;
}
if (no_external_cmds) {
rfbLogEnable(1);
rfbLog("start_stunnel: cannot run external commands in -nocmds mode:\n");
rfbLog(" \"%s\"\n", stunnel_path);
rfbLog(" exiting.\n");
clean_up_exit(1);
}
if (! quiet) {
rfbLog("\n");
rfbLog("starting ssl tunnel: %s %d -> %d\n", stunnel_path,
stunnel_port, x11vnc_port);
}
if (ssl_verify) {
if (stat(ssl_verify, &verify_buf) != 0) {
rfbLog("stunnel: %s does not exist.\n", ssl_verify);
return 0;
}
}
stunnel_pid = fork();
if (stunnel_pid < 0) {
stunnel_pid = 0;
free(stunnel_path);
return 0;
}
if (stunnel_pid == 0) {
FILE *in;
char fd[20];
int i;
for (i=3; i<256; i++) {
close(i);
}
if (use_stunnel == 3) {
char sp[20], xp[20], *a = NULL;
char *st = stunnel_path;
char *pm = stunnel_pem;
char *sv = ssl_verify;
sprintf(sp, "%d", stunnel_port);
sprintf(xp, "%d", x11vnc_port);
if (ssl_verify) {
if(S_ISDIR(verify_buf.st_mode)) {
a = "-a";
} else {
a = "-A";
}
}
if (stunnel_pem && ssl_verify) {
execlp(st, st, "-f", "-d", sp, "-r", xp, "-P",
"none", "-p", pm, a, sv, "-v", "2",
(char *) NULL);
} else if (stunnel_pem && !ssl_verify) {
execlp(st, st, "-f", "-d", sp, "-r", xp, "-P",
"none", "-p", pm,
(char *) NULL);
} else if (!stunnel_pem && ssl_verify) {
execlp(st, st, "-f", "-d", sp, "-r", xp, "-P",
"none", a, sv, "-v", "2",
(char *) NULL);
} else {
execlp(st, st, "-f", "-d", sp, "-r", xp, "-P",
"none", (char *) NULL);
}
exit(1);
}
in = tmpfile();
if (! in) {
exit(1);
}
fprintf(in, "foreground = yes\n");
fprintf(in, "pid =\n");
if (stunnel_pem) {
fprintf(in, "cert = %s\n", stunnel_pem);
}
if (ssl_verify) {
if(S_ISDIR(verify_buf.st_mode)) {
fprintf(in, "CApath = %s\n", ssl_verify);
} else {
fprintf(in, "CAfile = %s\n", ssl_verify);
}
fprintf(in, "verify = 2\n");
}
fprintf(in, ";debug = 7\n\n");
fprintf(in, "[x11vnc_stunnel]\n");
fprintf(in, "accept = %d\n", stunnel_port);
fprintf(in, "connect = %d\n", x11vnc_port);
fflush(in);
rewind(in);
sprintf(fd, "%d", fileno(in));
execlp(stunnel_path, stunnel_path, "-fd", fd, (char *) NULL);
exit(1);
}
free(stunnel_path);
usleep(500 * 1000);
waitpid(stunnel_pid, &status, WNOHANG);
if (kill(stunnel_pid, 0) != 0) {
waitpid(stunnel_pid, &status, WNOHANG);
stunnel_pid = 0;
return 0;
}
if (! quiet) {
rfbLog("stunnel pid is: %d\n", (int) stunnel_pid);
}
return 1;
#else
return 0;
#endif
}
void stop_stunnel(void) {
int status;
if (! stunnel_pid) {
return;
}
#ifdef SSLCMDS
kill(stunnel_pid, SIGTERM);
usleep (150 * 1000);
kill(stunnel_pid, SIGKILL);
usleep (50 * 1000);
waitpid(stunnel_pid, &status, WNOHANG);
#endif
stunnel_pid = 0;
}
void setup_stunnel(int rport, int *argc, char **argv) {
int i, xport = 0;
if (! rport) {
for (i=0; i< *argc; i++) {
if (!strcmp(argv[i], "-rfbport")) {
if (i < *argc - 1) {
rport = atoi(argv[i+1]);
break;
}
}
}
}
if (! rport) {
/* we do our own autoprobing then... */
rport = find_free_port(5900, 5999);
if (! rport) {
goto stunnel_fail;
}
}
xport = find_free_port(5950, 5999);
if (! xport) {
goto stunnel_fail;
}
if (start_stunnel(rport, xport)) {
int tweaked = 0;
char tmp[10];
sprintf(tmp, "%d", xport);
if (argv) {
for (i=0; i< *argc; i++) {
if (!strcmp(argv[i], "-rfbport")) {
if (i < *argc - 1) {
argv[i+i] = strdup(tmp);
tweaked = 1;
break;
}
}
}
if (! tweaked) {
i = *argc;
argv[i] = strdup("-rfbport");
argv[i+1] = strdup(tmp);
*argc += 2;
got_rfbport = 1;
}
}
stunnel_port = rport;
ssl_initialized = 1;
return;
}
stunnel_fail:
rfbLog("failed to start stunnel.\n");
clean_up_exit(1);
}