Home | History | Annotate | Download | only in x11vnc
      1 /*
      2    Copyright (C) 2002-2010 Karl J. Runge <runge (at) karlrunge.com>
      3    All rights reserved.
      4 
      5 This file is part of x11vnc.
      6 
      7 x11vnc is free software; you can redistribute it and/or modify
      8 it under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 2 of the License, or (at
     10 your option) any later version.
     11 
     12 x11vnc is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with x11vnc; if not, write to the Free Software
     19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
     20 or see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, as a special exception, Karl J. Runge
     23 gives permission to link the code of its release of x11vnc with the
     24 OpenSSL project's "OpenSSL" library (or with modified versions of it
     25 that use the same license as the "OpenSSL" library), and distribute
     26 the linked executables.  You must obey the GNU General Public License
     27 in all respects for all of the code used other than "OpenSSL".  If you
     28 modify this file, you may extend this exception to your version of the
     29 file, but you are not obligated to do so.  If you do not wish to do
     30 so, delete this exception statement from your version.
     31 */
     32 
     33 /* -- sslcmds.c -- */
     34 
     35 #include "x11vnc.h"
     36 #include "inet.h"
     37 #include "cleanup.h"
     38 #include "sslhelper.h"
     39 #include "ssltools.h"
     40 #include "connections.h"
     41 
     42 #if LIBVNCSERVER_HAVE_FORK
     43 #if LIBVNCSERVER_HAVE_SYS_WAIT_H
     44 #if LIBVNCSERVER_HAVE_WAITPID
     45 #define SSLCMDS
     46 #endif
     47 #endif
     48 #endif
     49 
     50 
     51 void check_stunnel(void);
     52 int start_stunnel(int stunnel_port, int x11vnc_port, int hport, int x11vnc_hport);
     53 void stop_stunnel(void);
     54 void setup_stunnel(int rport, int *argc, char **argv);
     55 char *get_Cert_dir(char *cdir_in, char **tmp_in);
     56 void sslScripts(void);
     57 void sslGenCA(char *cdir);
     58 void sslGenCert(char *ty, char *nm);
     59 void sslEncKey(char *path, int info_only);
     60 
     61 static pid_t stunnel_pid = 0;
     62 
     63 void check_stunnel(void) {
     64 	static time_t last_check = 0;
     65 	time_t now = time(NULL);
     66 
     67 	if (last_check + 3 >= now) {
     68 		return;
     69 	}
     70 	last_check = now;
     71 
     72 	/* double check that stunnel is still running: */
     73 
     74 	if (stunnel_pid > 0) {
     75 		int status;
     76 #ifdef SSLCMDS
     77 		waitpid(stunnel_pid, &status, WNOHANG);
     78 #endif
     79 		if (kill(stunnel_pid, 0) != 0) {
     80 #ifdef SSLCMDS
     81 			waitpid(stunnel_pid, &status, WNOHANG);
     82 #endif
     83 			rfbLog("stunnel subprocess %d died.\n", stunnel_pid);
     84 			stunnel_pid = 0;
     85 			clean_up_exit(1);
     86 		}
     87 	}
     88 }
     89 
     90 int start_stunnel(int stunnel_port, int x11vnc_port, int hport, int x11vnc_hport) {
     91 #ifdef SSLCMDS
     92 	char extra[] = ":/usr/sbin:/usr/local/sbin:/dist/sbin";
     93 	char *path, *p, *exe;
     94 	char *stunnel_path = NULL;
     95 	struct stat verify_buf;
     96 	struct stat crl_buf;
     97 	int status, tmp_pem = 0;
     98 
     99 	if (stunnel_pid) {
    100 		stop_stunnel();
    101 	}
    102 	stunnel_pid = 0;
    103 
    104 	path = getenv("PATH");
    105 	if (! path) {
    106 		path = strdup(extra+1);
    107 	} else {
    108 		char *pt = path;
    109 		path = (char *) malloc(strlen(path)+strlen(extra)+1);
    110 		if (! path) {
    111 			return 0;
    112 		}
    113 		strcpy(path, pt);
    114 		strcat(path, extra);
    115 	}
    116 
    117 	exe = (char *) malloc(strlen(path) + 1 + strlen("stunnel4") + 1);
    118 
    119 	p = strtok(path, ":");
    120 
    121 	exe[0] = '\0';
    122 
    123 	while (p) {
    124 		struct stat sbuf;
    125 
    126 		sprintf(exe, "%s/%s", p, "stunnel4");
    127 		if (! stunnel_path && stat(exe, &sbuf) == 0) {
    128 			if (! S_ISDIR(sbuf.st_mode)) {
    129 				stunnel_path = exe;
    130 				break;
    131 			}
    132 		}
    133 
    134 		sprintf(exe, "%s/%s", p, "stunnel");
    135 		if (! stunnel_path && stat(exe, &sbuf) == 0) {
    136 			if (! S_ISDIR(sbuf.st_mode)) {
    137 				stunnel_path = exe;
    138 				break;
    139 			}
    140 		}
    141 
    142 		p = strtok(NULL, ":");
    143 	}
    144 	if (path) {
    145 		free(path);
    146 	}
    147 
    148 	if (getenv("STUNNEL_PROG")) {
    149 		free(exe);
    150 		exe = strdup(getenv("STUNNEL_PROG"));
    151 		stunnel_path = exe;
    152 	}
    153 
    154 	if (! stunnel_path) {
    155 		free(exe);
    156 		return 0;
    157 	}
    158 	if (stunnel_path[0] == '\0') {
    159 		free(exe);
    160 		return 0;
    161 	}
    162 
    163 	/* stunnel */
    164 	if (no_external_cmds || !cmd_ok("stunnel")) {
    165 		rfbLogEnable(1);
    166 		rfbLog("start_stunnel: cannot run external commands in -nocmds mode:\n");
    167 		rfbLog("   \"%s\"\n", stunnel_path);
    168 		rfbLog("   exiting.\n");
    169 		clean_up_exit(1);
    170 	}
    171 
    172 	if (! quiet) {
    173 		rfbLog("\n");
    174 		rfbLog("starting ssl tunnel: %s  %d -> %d\n", stunnel_path,
    175 		    stunnel_port, x11vnc_port);
    176 	}
    177 
    178 	if (stunnel_pem && strstr(stunnel_pem, "SAVE") == stunnel_pem) {
    179 		stunnel_pem = get_saved_pem(stunnel_pem, 1);
    180 		if (! stunnel_pem) {
    181 			rfbLog("start_stunnel: could not create or open"
    182 			    " saved PEM.\n");
    183 			clean_up_exit(1);
    184 		}
    185 	} else if (!stunnel_pem) {
    186 		stunnel_pem = create_tmp_pem(NULL, 0);
    187 		if (! stunnel_pem) {
    188 			rfbLog("start_stunnel: could not create temporary,"
    189 			    " self-signed PEM.\n");
    190 			clean_up_exit(1);
    191 		}
    192 		tmp_pem = 1;
    193 		if (getenv("X11VNC_SHOW_TMP_PEM")) {
    194 			FILE *in = fopen(stunnel_pem, "r");
    195 			if (in != NULL) {
    196 				char line[128];
    197 				fprintf(stderr, "\n");
    198 				while (fgets(line, 128, in) != NULL) {
    199 					fprintf(stderr, "%s", line);
    200 				}
    201 				fprintf(stderr, "\n");
    202 				fclose(in);
    203 			}
    204 		}
    205 	}
    206 
    207 	if (ssl_verify) {
    208 		char *file = get_ssl_verify_file(ssl_verify);
    209 		if (file) {
    210 			ssl_verify = file;
    211 		}
    212 		if (stat(ssl_verify, &verify_buf) != 0) {
    213 			rfbLog("stunnel: %s does not exist.\n", ssl_verify);
    214 			clean_up_exit(1);
    215 		}
    216 	}
    217 	if (ssl_crl) {
    218 		if (stat(ssl_crl, &crl_buf) != 0) {
    219 			rfbLog("stunnel: %s does not exist.\n", ssl_crl);
    220 			clean_up_exit(1);
    221 		}
    222 	}
    223 
    224 	stunnel_pid = fork();
    225 
    226 	if (stunnel_pid < 0) {
    227 		stunnel_pid = 0;
    228 		free(exe);
    229 		return 0;
    230 	}
    231 
    232 	if (stunnel_pid == 0) {
    233 		FILE *in;
    234 		char fd[20];
    235 		int i;
    236 		char *st_if = getenv("STUNNEL_LISTEN");
    237 
    238 		if (st_if == NULL) {
    239 			st_if = "";
    240 		} else {
    241 			st_if = (char *) malloc(strlen(st_if) + 2);
    242 			sprintf(st_if, "%s:", getenv("STUNNEL_LISTEN"));
    243 		}
    244 
    245 
    246 		for (i=3; i<256; i++) {
    247 			close(i);
    248 		}
    249 
    250 		if (use_stunnel == 3) {
    251 			char sp[30], xp[30], *a = NULL;
    252 			char *st = stunnel_path;
    253 			char *pm = stunnel_pem;
    254 			char *sv = ssl_verify;
    255 
    256 			sprintf(sp, "%d", stunnel_port);
    257 			sprintf(xp, "%d", x11vnc_port);
    258 
    259 			if (ssl_verify) {
    260 				if(S_ISDIR(verify_buf.st_mode)) {
    261 					a = "-a";
    262 				} else {
    263 					a = "-A";
    264 				}
    265 			}
    266 
    267 			if (ssl_crl) {
    268 				rfbLog("stunnel: stunnel3 does not support CRL. %s\n", ssl_crl);
    269 				clean_up_exit(1);
    270 			}
    271 
    272 			if (stunnel_pem && ssl_verify) {
    273 				/* XXX double check -v 2 */
    274 				execlp(st, st, "-f", "-d", sp, "-r", xp, "-P",
    275 				    "none", "-p", pm, a, sv, "-v", "2",
    276 				    (char *) NULL);
    277 			} else if (stunnel_pem && !ssl_verify) {
    278 				execlp(st, st, "-f", "-d", sp, "-r", xp, "-P",
    279 				    "none", "-p", pm,
    280 				    (char *) NULL);
    281 			} else if (!stunnel_pem && ssl_verify) {
    282 				execlp(st, st, "-f", "-d", sp, "-r", xp, "-P",
    283 				    "none", a, sv, "-v", "2",
    284 				    (char *) NULL);
    285 			} else {
    286 				execlp(st, st, "-f", "-d", sp, "-r", xp, "-P",
    287 				    "none", (char *) NULL);
    288 			}
    289 			exit(1);
    290 		}
    291 
    292 		in = tmpfile();
    293 		if (! in) {
    294 			exit(1);
    295 		}
    296 
    297 		fprintf(in, "foreground = yes\n");
    298 		fprintf(in, "pid =\n");
    299 		if (stunnel_pem) {
    300 			fprintf(in, "cert = %s\n", stunnel_pem);
    301 		}
    302 		if (ssl_crl) {
    303 			if(S_ISDIR(crl_buf.st_mode)) {
    304 				fprintf(in, "CRLpath = %s\n", ssl_crl);
    305 			} else {
    306 				fprintf(in, "CRLfile = %s\n", ssl_crl);
    307 			}
    308 		}
    309 		if (ssl_verify) {
    310 			if(S_ISDIR(verify_buf.st_mode)) {
    311 				fprintf(in, "CApath = %s\n", ssl_verify);
    312 			} else {
    313 				fprintf(in, "CAfile = %s\n", ssl_verify);
    314 			}
    315 			fprintf(in, "verify = 2\n");
    316 		}
    317 		fprintf(in, ";debug = 7\n\n");
    318 		fprintf(in, "[x11vnc_stunnel]\n");
    319 		fprintf(in, "accept = %s%d\n", st_if, stunnel_port);
    320 		fprintf(in, "connect = %d\n", x11vnc_port);
    321 
    322 		if (hport > 0 && x11vnc_hport > 0) {
    323 			fprintf(in, "\n[x11vnc_http]\n");
    324 			fprintf(in, "accept = %s%d\n", st_if, hport);
    325 			fprintf(in, "connect = %d\n", x11vnc_hport);
    326 		}
    327 
    328 		fflush(in);
    329 		rewind(in);
    330 
    331 		if (getenv("STUNNEL_DEBUG")) {
    332 			char line[1000];
    333 			fprintf(stderr, "\nstunnel config contents:\n\n");
    334 			while (fgets(line, sizeof(line), in) != NULL) {
    335 				fprintf(stderr, "%s", line);
    336 			}
    337 			fprintf(stderr, "\n");
    338 			rewind(in);
    339 		}
    340 
    341 		sprintf(fd, "%d", fileno(in));
    342 		execlp(stunnel_path, stunnel_path, "-fd", fd, (char *) NULL);
    343 		exit(1);
    344 	}
    345 
    346 	free(exe);
    347 	usleep(750 * 1000);
    348 
    349 	waitpid(stunnel_pid, &status, WNOHANG);
    350 
    351 	if (ssl_verify && strstr(ssl_verify, "/sslverify-tmp-load-")) {
    352 		/* temporary file */
    353 		usleep(1000 * 1000);
    354 		unlink(ssl_verify);
    355 	}
    356 	if (tmp_pem) {
    357 		/* temporary cert */
    358 		usleep(1500 * 1000);
    359 		unlink(stunnel_pem);
    360 	}
    361 
    362 	if (kill(stunnel_pid, 0) != 0) {
    363 		waitpid(stunnel_pid, &status, WNOHANG);
    364 		stunnel_pid = 0;
    365 		return 0;
    366 	}
    367 
    368 	if (! quiet) {
    369 		rfbLog("stunnel pid is: %d\n", (int) stunnel_pid);
    370 	}
    371 
    372 	return 1;
    373 #else
    374 	return 0;
    375 #endif
    376 }
    377 
    378 void stop_stunnel(void) {
    379 	int status;
    380 	if (! stunnel_pid) {
    381 		return;
    382 	}
    383 #ifdef SSLCMDS
    384 	kill(stunnel_pid, SIGTERM);
    385 	usleep (150 * 1000);
    386 	kill(stunnel_pid, SIGKILL);
    387 	usleep (50 * 1000);
    388 	waitpid(stunnel_pid, &status, WNOHANG);
    389 #endif
    390 	stunnel_pid = 0;
    391 }
    392 
    393 void setup_stunnel(int rport, int *argc, char **argv) {
    394 	int i, xport = 0, hport = 0, xhport = 0;
    395 
    396 	if (! rport && argc && argv) {
    397 		for (i=0; i< *argc; i++) {
    398 			if (argv[i] && !strcmp(argv[i], "-rfbport")) {
    399 				if (i < *argc - 1) {
    400 					rport = atoi(argv[i+1]);
    401 				}
    402 			}
    403 		}
    404 	}
    405 
    406 	if (! rport) {
    407 		/* we do our own autoprobing then... */
    408 		rport = find_free_port(5900, 5999);
    409 		if (! rport) {
    410 			goto stunnel_fail;
    411 		}
    412 	}
    413 
    414 	xport = find_free_port(5950, 5999);
    415 	if (! xport) {
    416 		goto stunnel_fail;
    417 	}
    418 
    419 	if (https_port_num > 0) {
    420 		hport = https_port_num;
    421 	}
    422 
    423 	if (! hport && argc && argv) {
    424 		for (i=0; i< *argc; i++) {
    425 			if (argv[i] && !strcmp(argv[i], "-httpport")) {
    426 				if (i < *argc - 1) {
    427 					hport = atoi(argv[i+1]);
    428 				}
    429 			}
    430 		}
    431 	}
    432 
    433 	if (! hport && http_try_it) {
    434 		hport = find_free_port(rport-100, rport-1);
    435 		if (! hport) {
    436 			goto stunnel_fail;
    437 		}
    438 	}
    439 	if (hport) {
    440 		xhport = find_free_port(5850, 5899);
    441 		if (! xhport) {
    442 			goto stunnel_fail;
    443 		}
    444 		stunnel_http_port = hport;
    445 	}
    446 
    447 
    448 	if (start_stunnel(rport, xport, hport, xhport)) {
    449 		int tweaked = 0;
    450 		char tmp[30];
    451 		sprintf(tmp, "%d", xport);
    452 		if (argc && argv) {
    453 			for (i=0; i < *argc; i++) {
    454 				if (argv[i] && !strcmp(argv[i], "-rfbport")) {
    455 					if (i < *argc - 1) {
    456 						/* replace orig value */
    457 						argv[i+i] = strdup(tmp);
    458 						tweaked = 1;
    459 						break;
    460 					}
    461 				}
    462 			}
    463 			if (! tweaked) {
    464 				i = *argc;
    465 				argv[i] = strdup("-rfbport");
    466 				argv[i+1] = strdup(tmp);
    467 				*argc += 2;
    468 				got_rfbport = 1;
    469 				got_rfbport_val = atoi(tmp);
    470 			}
    471 		}
    472 		stunnel_port = rport;
    473 		ssl_initialized = 1;
    474 		return;
    475 	}
    476 
    477 	stunnel_fail:
    478 	rfbLog("failed to start stunnel.\n");
    479 	clean_up_exit(1);
    480 }
    481 
    482 char *get_Cert_dir(char *cdir_in, char **tmp_in) {
    483 	char *cdir, *home, *tmp;
    484 	struct stat sbuf;
    485 	int i;
    486 	char *cases1[] = {"/.vnc", "/.vnc/certs", "/.vnc/certs/CA"};
    487 	char *cases2[] = {"", "/CA", "/tmp"};
    488 
    489 	if (cdir_in != NULL) {
    490 		cdir = cdir_in;
    491 	} else {
    492 		cdir = ssl_certs_dir;
    493 	}
    494 
    495 	if (cdir == NULL) {
    496 		home = get_home_dir();
    497 		if (! home) {
    498 			return NULL;
    499 		}
    500 		cdir = (char *) malloc(strlen(home) + strlen("/.vnc/certs/CA") + 1);
    501 		for (i=0; i<3; i++) {
    502 			sprintf(cdir, "%s%s", home, cases1[i]);
    503 			if (stat(cdir, &sbuf) != 0) {
    504 				rfbLog("creating dir: %s\n", cdir);
    505 				if (mkdir(cdir, 0755) != 0) {
    506 					rfbLog("could not create directory %s\n", cdir);
    507 					rfbLogPerror("mkdir");
    508 					return NULL;
    509 				}
    510 			} else if (! S_ISDIR(sbuf.st_mode)) {
    511 				rfbLog("not a directory: %s\n", cdir);
    512 				return NULL;
    513 			}
    514 		}
    515 		sprintf(cdir, "%s%s", home, cases1[1]);
    516 	}
    517 
    518 	tmp = (char *) malloc(strlen(cdir) + strlen("/tmp") + 1);
    519 	for (i=0; i<3; i++) {
    520 		int ret;
    521 		sprintf(tmp, "%s%s", cdir, cases2[i]);
    522 		if (stat(tmp, &sbuf) != 0) {
    523 			rfbLog("creating dir: %s\n", tmp);
    524 			if (! strcmp(cases2[i], "/tmp")) {
    525 				ret = mkdir(tmp, 0700);
    526 			} else {
    527 				ret = mkdir(tmp, 0755);
    528 			}
    529 
    530 			if (ret != 0) {
    531 				rfbLog("could not create directory %s\n", tmp);
    532 				rfbLogPerror("mkdir");
    533 				return NULL;
    534 			}
    535 		} else if (! S_ISDIR(sbuf.st_mode)) {
    536 			rfbLog("not a directory: %s\n", tmp);
    537 			return NULL;
    538 		}
    539 	}
    540 	sprintf(tmp, "%s/tmp", cdir);
    541 	*tmp_in = tmp;
    542 	return cdir;
    543 }
    544 
    545 static char *getsslscript(char *cdir, char *name, char *script) {
    546 	char *openssl = find_openssl_bin();
    547 	char *tmp, *scr, *cdir_use;
    548 	FILE *out;
    549 
    550 	if (! openssl || openssl[0] == '\0') {
    551 		exit(1);
    552 	}
    553 
    554 	if (!name || !script) {
    555 		exit(1);
    556 	}
    557 
    558 	cdir_use = get_Cert_dir(cdir, &tmp);
    559 	if (!cdir_use || !tmp) {
    560 		exit(1);
    561 	}
    562 
    563 	scr = (char *) malloc(strlen(tmp) + 1 + strlen(name) + 30);
    564 
    565 	sprintf(scr, "%s/%s.%d.sh", tmp, name, getpid());
    566 	out = fopen(scr, "w");
    567 	if (! out) {
    568 		rfbLog("could not open: %s\n", scr);
    569 		rfbLogPerror("fopen");
    570 		exit(1);
    571 	}
    572 	fprintf(out, "%s", script);
    573 	fclose(out);
    574 
    575 	rfbLog("Using openssl:   %s\n", openssl);
    576 	rfbLog("Using certs dir: %s\n", cdir_use);
    577 	fprintf(stderr, "\n");
    578 
    579 	set_env("BASE_DIR", cdir_use);
    580 	set_env("OPENSSL", openssl);
    581 
    582 	return scr;
    583 }
    584 
    585 void sslScripts(void) {
    586 	fprintf(stdout, "======================================================\n");
    587 	fprintf(stdout, "genCA script for '-sslGenCA':\n\n");
    588 	fprintf(stdout, "%s\n", genCA);
    589 	fprintf(stdout, "======================================================\n");
    590 	fprintf(stdout, "genCert script for '-sslGenCert', etc.:\n\n");
    591 	fprintf(stdout, "%s\n", genCert);
    592 }
    593 
    594 void sslGenCA(char *cdir) {
    595 	char *cmd, *scr = getsslscript(cdir, "genca", genCA);
    596 
    597 	if (! scr) {
    598 		exit(1);
    599 	}
    600 
    601 	cmd = (char *)malloc(strlen("/bin/sh ") + strlen(scr) + 1);
    602 	sprintf(cmd, "/bin/sh %s", scr);
    603 
    604 	system(cmd);
    605 	unlink(scr);
    606 
    607 	free(cmd);
    608 	free(scr);
    609 }
    610 
    611 void sslGenCert(char *ty, char *nm) {
    612 	char *cmd, *scr = getsslscript(NULL, "gencert", genCert);
    613 
    614 	if (! scr) {
    615 		exit(1);
    616 	}
    617 
    618 	cmd = (char *)malloc(strlen("/bin/sh ") + strlen(scr) + 1);
    619 	sprintf(cmd, "/bin/sh %s", scr);
    620 
    621 	if (! ty) {
    622 		set_env("TYPE", "");
    623 	} else {
    624 		set_env("TYPE", ty);
    625 	}
    626 	if (! nm) {
    627 		set_env("NAME", "");
    628 	} else {
    629 		char *q = strstr(nm, "SAVE-");
    630 		if (!strcmp(nm, "SAVE")) {
    631 			set_env("NAME", "");
    632 		} else if (q == nm) {
    633 			q += strlen("SAVE-");
    634 			set_env("NAME", q);
    635 		} else {
    636 			set_env("NAME", nm);
    637 		}
    638 	}
    639 
    640 	system(cmd);
    641 	unlink(scr);
    642 
    643 	free(cmd);
    644 	free(scr);
    645 }
    646 
    647 void sslEncKey(char *path, int mode) {
    648 	char *openssl = find_openssl_bin();
    649 	char *scr, *cert = NULL, *tca, *cdir = NULL;
    650 	char line[1024], tmp[] = "/tmp/x11vnc-tmp.XXXXXX";
    651 	int tmp_fd, incert, info_only = 0, delete_only = 0, listlong = 0;
    652 	struct stat sbuf;
    653 	FILE *file;
    654 	static int depth = 0;
    655 
    656 	if (depth > 0) {
    657 		/* get_saved_pem may call us back. */
    658 		return;
    659 	}
    660 
    661 	if (! path) {
    662 		return;
    663 	}
    664 
    665 	depth++;
    666 
    667 	if (mode == 1) {
    668 		info_only = 1;
    669 	} else if (mode == 2) {
    670 		delete_only = 1;
    671 	}
    672 
    673 	if (! openssl) {
    674 		exit(1);
    675 	}
    676 
    677 	cdir = get_Cert_dir(NULL, &tca);
    678 	if (! cdir || ! tca) {
    679 		fprintf(stderr, "could not find Cert dir\n");
    680 		exit(1);
    681 	}
    682 
    683 	if (!strcasecmp(path, "LL") || !strcasecmp(path, "LISTL")) {
    684 		listlong = 1;
    685 		path = "LIST";
    686 	}
    687 
    688 	if (strstr(path, "SAVE") == path) {
    689 		char *p = get_saved_pem(path, 0);
    690 		if (p == NULL) {
    691 			fprintf(stderr, "could not find saved pem "
    692 			    "matching: %s\n", path);
    693 			exit(1);
    694 		}
    695 		path = p;
    696 
    697 	} else if (!strcmp(path, "CA")) {
    698 		tca = (char *) malloc(strlen(cdir)+strlen("/CA/cacert.pem")+1);
    699 		sprintf(tca, "%s/CA/cacert.pem", cdir);
    700 		path = tca;
    701 
    702 	} else if (info_only && (!strcasecmp(path, "LIST") ||
    703 	    !strcasecmp(path, "LS") || !strcasecmp(path, "ALL"))) {
    704 
    705 		if (! program_name || strchr(program_name, ' ')) {
    706 			fprintf(stderr, "bad program name.\n");
    707 			exit(1);
    708 		}
    709 		if (strchr(cdir, '\'')) {
    710 			fprintf(stderr, "bad certdir char: %s\n", cdir);
    711 			exit(1);
    712 		}
    713 
    714 		tca = (char *) malloc(2*strlen(cdir)+strlen(program_name)+1000);
    715 
    716 		sprintf(tca, "find '%s' | egrep '/(CA|tmp|clients)$|"
    717 		    "\\.(crt|pem|key|req)$' | grep -v CA/newcerts", cdir);
    718 
    719 		if (!strcasecmp(path, "ALL")) {
    720 			/* ugh.. */
    721 			strcat(tca, " | egrep -v 'private/cakey.pem|"
    722 			    "(CA|tmp|clients)$' | xargs -n1 ");
    723 			strcat(tca, program_name);
    724 			strcat(tca, " -ssldir '");
    725 			strcat(tca, cdir);
    726 			strcat(tca, "' -sslCertInfo 2>&1 ");
    727 		} else if (listlong) {
    728 			strcat(tca, " | xargs ls -ld ");
    729 		}
    730 		system(tca);
    731 		free(tca);
    732 
    733 		depth--;
    734 		return;
    735 
    736 	} else if (info_only && (!strcasecmp(path, "HASHON")
    737 	    || !strcasecmp(path, "HASHOFF"))) {
    738 
    739 		tmp_fd = mkstemp(tmp);
    740 		if (tmp_fd < 0) {
    741 			exit(1);
    742 		}
    743 
    744 		write(tmp_fd, genCert, strlen(genCert));
    745 		close(tmp_fd);
    746 
    747 		scr = (char *) malloc(strlen("/bin/sh ") + strlen(tmp) + 1);
    748 		sprintf(scr, "/bin/sh %s", tmp);
    749 
    750 		set_env("BASE_DIR", cdir);
    751 		set_env("OPENSSL", openssl);
    752 		set_env("TYPE", "server");
    753 		if (!strcasecmp(path, "HASHON")) {
    754 			set_env("HASHON", "1");
    755 		} else {
    756 			set_env("HASHOFF", "1");
    757 		}
    758 		system(scr);
    759 		unlink(tmp);
    760 		free(scr);
    761 
    762 		depth--;
    763 		return;
    764 	}
    765 
    766 
    767 	if (stat(path, &sbuf) != 0) {
    768 	    if (strstr(path, "client") || strchr(path, '/') == NULL) {
    769 		int i;
    770 		tca = (char *) malloc(strlen(cdir) + strlen(path) + 100);
    771 		for (i = 1; i <= 15; i++)  {
    772 			tca[0] = '\0';
    773 			if (       i == 1) {
    774 			    sprintf(tca, "%s/%s", cdir, path);
    775 			} else if (i == 2 && mode > 0) {
    776 			    sprintf(tca, "%s/%s.crt", cdir, path);
    777 			} else if (i == 3) {
    778 			    sprintf(tca, "%s/%s.pem", cdir, path);
    779 			} else if (i == 4 && mode > 1) {
    780 			    sprintf(tca, "%s/%s.req", cdir, path);
    781 			} else if (i == 5 && mode > 1) {
    782 			    sprintf(tca, "%s/%s.key", cdir, path);
    783 			} else if (i == 6) {
    784 			    sprintf(tca, "%s/clients/%s", cdir, path);
    785 			} else if (i == 7 && mode > 0) {
    786 			    sprintf(tca, "%s/clients/%s.crt", cdir, path);
    787 			} else if (i == 8) {
    788 			    sprintf(tca, "%s/clients/%s.pem", cdir, path);
    789 			} else if (i == 9 && mode > 1) {
    790 			    sprintf(tca, "%s/clients/%s.req", cdir, path);
    791 			} else if (i == 10 && mode > 1) {
    792 			    sprintf(tca, "%s/clients/%s.key", cdir, path);
    793 			} else if (i == 11) {
    794 			    sprintf(tca, "%s/server-%s", cdir, path);
    795 			} else if (i == 12 && mode > 0) {
    796 			    sprintf(tca, "%s/server-%s.crt", cdir, path);
    797 			} else if (i == 13) {
    798 			    sprintf(tca, "%s/server-%s.pem", cdir, path);
    799 			} else if (i == 14 && mode > 1) {
    800 			    sprintf(tca, "%s/server-%s.req", cdir, path);
    801 			} else if (i == 15 && mode > 1) {
    802 			    sprintf(tca, "%s/server-%s.key", cdir, path);
    803 			}
    804 			if (tca[0] == '\0') {
    805 				continue;
    806 			}
    807 			if (stat(tca, &sbuf) == 0) {
    808 				path = tca;
    809 				break;
    810 			}
    811 		}
    812 	    }
    813 	}
    814 
    815 	if (stat(path, &sbuf) != 0) {
    816 		rfbLog("sslEncKey: %s\n", path);
    817 		rfbLogPerror("stat");
    818 		exit(1);
    819 	}
    820 
    821 	if (! info_only) {
    822 		cert = (char *) malloc(2*(sbuf.st_size + 1024));
    823 		file = fopen(path, "r");
    824 		if (file == NULL) {
    825 			rfbLog("sslEncKey: %s\n", path);
    826 			rfbLogPerror("fopen");
    827 			exit(1);
    828 		}
    829 		incert = 0;
    830 		cert[0] = '\0';
    831 		while (fgets(line, 1024, file) != NULL) {
    832 			if (strstr(line, "-----BEGIN CERTIFICATE-----")
    833 			    == line) {
    834 				incert = 1;
    835 			}
    836 			if (incert) {
    837 				if (strlen(cert)+strlen(line) <
    838 				    2 * (size_t) sbuf.st_size) {
    839 					strcat(cert, line);
    840 				}
    841 			}
    842 			if (strstr(line, "-----END CERTIFICATE-----")
    843 			    == line) {
    844 				incert = 0;
    845 			}
    846 		}
    847 		fclose(file);
    848 	}
    849 
    850 	tmp_fd = mkstemp(tmp);
    851 	if (tmp_fd < 0) {
    852 		exit(1);
    853 	}
    854 
    855 	write(tmp_fd, genCert, strlen(genCert));
    856 	close(tmp_fd);
    857 
    858         scr = (char *) malloc(strlen("/bin/sh ") + strlen(tmp) + 1);
    859 	sprintf(scr, "/bin/sh %s", tmp);
    860 
    861 	set_env("BASE_DIR", "/no/such/dir");
    862 	set_env("OPENSSL", openssl);
    863 	set_env("TYPE", "server");
    864 	if (info_only) {
    865 		set_env("INFO_ONLY", path);
    866 	} else if (delete_only) {
    867 		set_env("DELETE_ONLY", path);
    868 	} else {
    869 		set_env("ENCRYPT_ONLY", path);
    870 	}
    871 	system(scr);
    872 	unlink(tmp);
    873 
    874 	if (! mode && cert && cert[0] != '\0') {
    875 		int got_cert = 0;
    876 		file = fopen(path, "r");
    877 		if (file == NULL) {
    878 			rfbLog("sslEncKey: %s\n", path);
    879 			rfbLogPerror("fopen");
    880 			exit(1);
    881 		}
    882 		while (fgets(line, 1024, file) != NULL) {
    883 			if (strstr(line, "-----BEGIN CERTIFICATE-----")
    884 			    == line) {
    885 				got_cert++;
    886 			}
    887 			if (strstr(line, "-----END CERTIFICATE-----")
    888 			    == line) {
    889 				got_cert++;
    890 			}
    891 		}
    892 		fclose(file);
    893 		if (got_cert < 2) {
    894 			file = fopen(path, "a");
    895 			if (file == NULL) {
    896 				rfbLog("sslEncKey: %s\n", path);
    897 				rfbLogPerror("fopen");
    898 				exit(1);
    899 			}
    900 			fprintf(file, "%s", cert);
    901 			fclose(file);
    902 		}
    903 		free(cert);
    904 	}
    905 
    906 	depth--;
    907 }
    908 
    909