sslcmds.c 19.7 KB
Newer Older
1
/*
2
   Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> 
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   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.
*/

33 34 35 36 37
/* -- sslcmds.c -- */

#include "x11vnc.h"
#include "inet.h"
#include "cleanup.h"
38 39
#include "sslhelper.h"
#include "ssltools.h"
runge's avatar
runge committed
40
#include "connections.h"
41 42 43 44 45 46 47 48 49 50

#if LIBVNCSERVER_HAVE_FORK
#if LIBVNCSERVER_HAVE_SYS_WAIT_H
#if LIBVNCSERVER_HAVE_WAITPID
#define SSLCMDS
#endif
#endif
#endif


51
void check_stunnel(void);
52
int start_stunnel(int stunnel_port, int x11vnc_port, int hport, int x11vnc_hport);
53 54
void stop_stunnel(void);
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 58 59
void sslGenCA(char *cdir);
void sslGenCert(char *ty, char *nm);
void sslEncKey(char *path, int info_only);
60 61 62

static pid_t stunnel_pid = 0;

63 64
void check_stunnel(void) {
	static time_t last_check = 0;
65
	time_t now = time(NULL);
66 67 68 69 70 71

	if (last_check + 3 >= now) {
		return;
	}
	last_check = now;

72 73
	/* double check that stunnel is still running: */

74 75
	if (stunnel_pid > 0) {
		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 84 85 86 87 88 89
			rfbLog("stunnel subprocess %d died.\n", stunnel_pid); 
			stunnel_pid = 0;
			clean_up_exit(1);
		}
	}
}

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 94
	char *path, *p, *exe;
	char *stunnel_path = NULL;
95
	struct stat verify_buf;
96
	struct stat crl_buf;
97
	int status, tmp_pem = 0;
98 99 100 101 102 103 104 105

	if (stunnel_pid) {
		stop_stunnel();
	}
	stunnel_pid = 0;

	path = getenv("PATH");
	if (! path) {
106
		path = strdup(extra+1);
107
	} else {
108
		char *pt = path;
109 110 111 112
		path = (char *) malloc(strlen(path)+strlen(extra)+1);
		if (! path) {
			return 0;
		}
113
		strcpy(path, pt);
114 115 116
		strcat(path, extra);
	}

117
	exe = (char *) malloc(strlen(path) + 1 + strlen("stunnel4") + 1);
118 119 120 121 122 123 124 125

	p = strtok(path, ":");

	exe[0] = '\0';

	while (p) {
		struct stat sbuf;

126 127 128 129 130 131 132 133
		sprintf(exe, "%s/%s", p, "stunnel4");
		if (! stunnel_path && stat(exe, &sbuf) == 0) {
			if (! S_ISDIR(sbuf.st_mode)) {
				stunnel_path = exe;
				break;
			}
		}

134 135 136 137 138 139 140 141 142 143 144 145 146 147
		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);
	}

148 149 150 151 152 153
	if (getenv("STUNNEL_PROG")) {
		free(exe);
		exe = strdup(getenv("STUNNEL_PROG"));
		stunnel_path = exe;
	}

154
	if (! stunnel_path) {
155
		free(exe);
156 157 158
		return 0;
	}
	if (stunnel_path[0] == '\0') {
159
		free(exe);
160 161 162
		return 0;
	}

163
	/* stunnel */
164
	if (no_external_cmds || !cmd_ok("stunnel")) {
165 166 167 168 169 170 171
		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);
	}

172 173 174 175 176 177
	if (! quiet) {
		rfbLog("\n");
		rfbLog("starting ssl tunnel: %s  %d -> %d\n", stunnel_path,
		    stunnel_port, x11vnc_port);
	}

178 179 180 181
	if (stunnel_pem && strstr(stunnel_pem, "SAVE") == stunnel_pem) {
		stunnel_pem = get_saved_pem(stunnel_pem, 1);
		if (! stunnel_pem) {
			rfbLog("start_stunnel: could not create or open"
182
			    " saved PEM.\n");	
183 184
			clean_up_exit(1);
		}
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
	} else if (!stunnel_pem) {
		stunnel_pem = create_tmp_pem(NULL, 0);
		if (! stunnel_pem) {
			rfbLog("start_stunnel: could not create temporary,"
			    " self-signed PEM.\n");	
			clean_up_exit(1);
		}
		tmp_pem = 1;
		if (getenv("X11VNC_SHOW_TMP_PEM")) {
			FILE *in = fopen(stunnel_pem, "r");
			if (in != NULL) {
				char line[128];
				fprintf(stderr, "\n");
				while (fgets(line, 128, in) != NULL) {
					fprintf(stderr, "%s", line);
				}
				fprintf(stderr, "\n");
				fclose(in);
			}
		}
205 206
	}

207
	if (ssl_verify) {
208 209 210 211
		char *file = get_ssl_verify_file(ssl_verify);
		if (file) {
			ssl_verify = file;
		}
212 213
		if (stat(ssl_verify, &verify_buf) != 0) {
			rfbLog("stunnel: %s does not exist.\n", ssl_verify);
214
			clean_up_exit(1);
215
		}
216
	}
217 218 219 220 221 222
	if (ssl_crl) {
		if (stat(ssl_crl, &crl_buf) != 0) {
			rfbLog("stunnel: %s does not exist.\n", ssl_crl);
			clean_up_exit(1);
		}
	}
223 224 225 226 227

	stunnel_pid = fork();

	if (stunnel_pid < 0) {
		stunnel_pid = 0;
228
		free(exe);
229 230 231 232 233 234 235
		return 0;
	}

	if (stunnel_pid == 0) {
		FILE *in;
		char fd[20];
		int i;
236 237 238 239 240 241 242 243 244
		char *st_if = getenv("STUNNEL_LISTEN");

		if (st_if == NULL) {
			st_if = "";
		} else {
			st_if = (char *) malloc(strlen(st_if) + 2);
			sprintf(st_if, "%s:", getenv("STUNNEL_LISTEN"));
		}

245 246 247 248 249 250

		for (i=3; i<256; i++) {
			close(i);
		}

		if (use_stunnel == 3) {
251
			char sp[30], xp[30], *a = NULL;
252 253 254
			char *st = stunnel_path;
			char *pm = stunnel_pem;
			char *sv = ssl_verify;
255 256 257

			sprintf(sp, "%d", stunnel_port);
			sprintf(xp, "%d", x11vnc_port);
258 259 260 261 262 263 264 265

			if (ssl_verify) {
				if(S_ISDIR(verify_buf.st_mode)) {
					a = "-a";
				} else {
					a = "-A";
				}
			}
266 267 268 269 270

			if (ssl_crl) {
				rfbLog("stunnel: stunnel3 does not support CRL. %s\n", ssl_crl);
				clean_up_exit(1);
			}
271
			
272
			if (stunnel_pem && ssl_verify) {
273
				/* XXX double check -v 2 */
274 275 276 277 278 279 280 281 282 283 284
				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);
285
			} else {
286 287
				execlp(st, st, "-f", "-d", sp, "-r", xp, "-P",
				    "none", (char *) NULL);
288 289 290 291 292 293 294 295
			}
			exit(1);
		}

		in = tmpfile();
		if (! in) {
			exit(1);
		}
296

297 298 299 300 301
		fprintf(in, "foreground = yes\n");
		fprintf(in, "pid =\n");
		if (stunnel_pem) {
			fprintf(in, "cert = %s\n", stunnel_pem);
		}
302 303 304 305 306 307 308
		if (ssl_crl) {
			if(S_ISDIR(crl_buf.st_mode)) {
				fprintf(in, "CRLpath = %s\n", ssl_crl);
			} else {
				fprintf(in, "CRLfile = %s\n", ssl_crl);
			}
		}
309 310 311 312 313 314 315 316 317
		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");
318
		fprintf(in, "[x11vnc_stunnel]\n");
319
		fprintf(in, "accept = %s%d\n", st_if, stunnel_port);
320 321
		fprintf(in, "connect = %d\n", x11vnc_port);

322 323
		if (hport > 0 && x11vnc_hport > 0) {
			fprintf(in, "\n[x11vnc_http]\n");
324
			fprintf(in, "accept = %s%d\n", st_if, hport);
325 326 327
			fprintf(in, "connect = %d\n", x11vnc_hport);
		}

328 329
		fflush(in);
		rewind(in);
330 331 332 333 334 335 336 337 338 339

		if (getenv("STUNNEL_DEBUG")) {
			char line[1000];
			fprintf(stderr, "\nstunnel config contents:\n\n");
			while (fgets(line, sizeof(line), in) != NULL) {
				fprintf(stderr, "%s", line);
			}
			fprintf(stderr, "\n");
			rewind(in);
		}
340 341 342 343 344
		
		sprintf(fd, "%d", fileno(in));
		execlp(stunnel_path, stunnel_path, "-fd", fd, (char *) NULL);
		exit(1);
	}
345 346

	free(exe);
347
	usleep(750 * 1000);
348 349

	waitpid(stunnel_pid, &status, WNOHANG); 
350 351 352 353 354 355 356 357 358 359 360 361

	if (ssl_verify && strstr(ssl_verify, "/sslverify-tmp-load-")) {
		/* temporary file */
		usleep(1000 * 1000);
		unlink(ssl_verify);
	}
	if (tmp_pem) {
		/* temporary cert */
		usleep(1500 * 1000);
		unlink(stunnel_pem);
	}

362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
	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) {
394 395
	int i, xport = 0, hport = 0, xhport = 0;

396
	if (! rport && argc && argv) {
397
		for (i=0; i< *argc; i++) {
398
			if (argv[i] && !strcmp(argv[i], "-rfbport")) {
399 400 401 402 403 404 405 406 407 408 409 410 411 412
				if (i < *argc - 1) {
					rport = atoi(argv[i+1]);
				}
			}
		}
	}

	if (! rport) {
		/* we do our own autoprobing then... */
		rport = find_free_port(5900, 5999);
		if (! rport) {
			goto stunnel_fail;
		}
	}
413

414 415 416 417
	xport = find_free_port(5950, 5999);
	if (! xport) {
		goto stunnel_fail; 
	}
418

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
	if (https_port_num > 0) {
		hport = https_port_num;
	}

	if (! hport && argc && argv) {
		for (i=0; i< *argc; i++) {
			if (argv[i] && !strcmp(argv[i], "-httpport")) {
				if (i < *argc - 1) {
					hport = atoi(argv[i+1]);
				}
			}
		}
	}

	if (! hport && http_try_it) {
		hport = find_free_port(rport-100, rport-1);
		if (! hport) {
			goto stunnel_fail;
		}
	}
	if (hport) {
		xhport = find_free_port(5850, 5899);
		if (! xhport) {
			goto stunnel_fail; 
		}
		stunnel_http_port = hport;
	}
	

	if (start_stunnel(rport, xport, hport, xhport)) {
449
		int tweaked = 0;
450
		char tmp[30];
451
		sprintf(tmp, "%d", xport);
452 453 454
		if (argc && argv) {
			for (i=0; i < *argc; i++) {
				if (argv[i] && !strcmp(argv[i], "-rfbport")) {
455
					if (i < *argc - 1) {
456
						/* replace orig value */
457 458 459 460 461 462 463 464 465 466 467 468
						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;
469
				got_rfbport_val = atoi(tmp);
470 471 472
			}
		}
		stunnel_port = rport;
473
		ssl_initialized = 1;
474 475 476 477 478 479 480 481
		return;
	}

	stunnel_fail:
	rfbLog("failed to start stunnel.\n");
	clean_up_exit(1);
}

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
char *get_Cert_dir(char *cdir_in, char **tmp_in) {
	char *cdir, *home, *tmp;
	struct stat sbuf;
	int i;
	char *cases1[] = {"/.vnc", "/.vnc/certs", "/.vnc/certs/CA"};
	char *cases2[] = {"", "/CA", "/tmp"};

	if (cdir_in != NULL) {
		cdir = cdir_in;
	} else {
		cdir = ssl_certs_dir;
	}

	if (cdir == NULL) {
		home = get_home_dir();
		if (! home) {
			return NULL;
		}
		cdir = (char *) malloc(strlen(home) + strlen("/.vnc/certs/CA") + 1);
		for (i=0; i<3; i++) {
			sprintf(cdir, "%s%s", home, cases1[i]);
			if (stat(cdir, &sbuf) != 0) {
				rfbLog("creating dir: %s\n", cdir);
				if (mkdir(cdir, 0755) != 0) {
					rfbLog("could not create directory %s\n", cdir);
					rfbLogPerror("mkdir");
					return NULL;
				}
			} else if (! S_ISDIR(sbuf.st_mode)) {
				rfbLog("not a directory: %s\n", cdir);
				return NULL;
			}
		}
		sprintf(cdir, "%s%s", home, cases1[1]);
	}

518
	tmp = (char *) malloc(strlen(cdir) + strlen("/tmp") + 1);
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
	for (i=0; i<3; i++) {
		int ret;
		sprintf(tmp, "%s%s", cdir, cases2[i]);
		if (stat(tmp, &sbuf) != 0) {
			rfbLog("creating dir: %s\n", tmp);
			if (! strcmp(cases2[i], "/tmp")) {
				ret = mkdir(tmp, 0700);
			} else {
				ret = mkdir(tmp, 0755);
			}
				
			if (ret != 0) {
				rfbLog("could not create directory %s\n", tmp);
				rfbLogPerror("mkdir");
				return NULL;
			}
		} else if (! S_ISDIR(sbuf.st_mode)) {
			rfbLog("not a directory: %s\n", tmp);
			return NULL;
		}
	}
	sprintf(tmp, "%s/tmp", cdir);
	*tmp_in = tmp;
	return cdir;
}

545
static char *getsslscript(char *cdir, char *name, char *script) {
546
	char *openssl = find_openssl_bin();
547
	char *tmp, *scr, *cdir_use;
548 549
	FILE *out;

550 551 552 553 554
	if (! openssl || openssl[0] == '\0') {
		exit(1);
	}

	if (!name || !script) {
555 556 557 558
		exit(1);
	}

	cdir_use = get_Cert_dir(cdir, &tmp);
559
	if (!cdir_use || !tmp) {
560 561 562
		exit(1);
	}

563
	scr = (char *) malloc(strlen(tmp) + 1 + strlen(name) + 30);
564

565 566
	sprintf(scr, "%s/%s.%d.sh", tmp, name, getpid());
	out = fopen(scr, "w");
567
	if (! out) {
568
		rfbLog("could not open: %s\n", scr);
569 570 571
		rfbLogPerror("fopen");
		exit(1);
	}
572
	fprintf(out, "%s", script);
573 574 575 576 577 578 579 580 581
	fclose(out);

	rfbLog("Using openssl:   %s\n", openssl);
	rfbLog("Using certs dir: %s\n", cdir_use);
	fprintf(stderr, "\n");

	set_env("BASE_DIR", cdir_use);
	set_env("OPENSSL", openssl);

582
	return scr;
583 584
}

585 586 587 588 589 590 591 592 593
void sslScripts(void) {
	fprintf(stdout, "======================================================\n");
	fprintf(stdout, "genCA script for '-sslGenCA':\n\n");
	fprintf(stdout, "%s\n", genCA);
	fprintf(stdout, "======================================================\n");
	fprintf(stdout, "genCert script for '-sslGenCert', etc.:\n\n");
	fprintf(stdout, "%s\n", genCert);
}

594 595
void sslGenCA(char *cdir) {
	char *cmd, *scr = getsslscript(cdir, "genca", genCA);
596

597
	if (! scr) {
598 599 600
		exit(1);
	}

601 602
	cmd = (char *)malloc(strlen("/bin/sh ") + strlen(scr) + 1);
	sprintf(cmd, "/bin/sh %s", scr);
603

604 605
	system(cmd);
	unlink(scr);
606

607 608 609 610 611 612 613 614
	free(cmd);
	free(scr);
}

void sslGenCert(char *ty, char *nm) {
	char *cmd, *scr = getsslscript(NULL, "gencert", genCert);

	if (! scr) {
615 616 617
		exit(1);
	}

618 619
	cmd = (char *)malloc(strlen("/bin/sh ") + strlen(scr) + 1);
	sprintf(cmd, "/bin/sh %s", scr);
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639

	if (! ty) {
		set_env("TYPE", "");
	} else {
		set_env("TYPE", ty);
	}
	if (! nm) {
		set_env("NAME", "");
	} else {
		char *q = strstr(nm, "SAVE-");
		if (!strcmp(nm, "SAVE")) {
			set_env("NAME", "");
		} else if (q == nm) {
			q += strlen("SAVE-");
			set_env("NAME", q);
		} else {
			set_env("NAME", nm);
		}
	}

640 641 642 643 644
	system(cmd);
	unlink(scr);

	free(cmd);
	free(scr);
645 646 647 648
}

void sslEncKey(char *path, int mode) {
	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 653 654 655 656 657 658 659
	struct stat sbuf;
	FILE *file;
	static int depth = 0;

	if (depth > 0) {
		/* get_saved_pem may call us back. */
		return;
	}
660 661 662 663 664

	if (! path) {
		return;
	}

665 666 667 668 669 670 671 672 673 674 675
	depth++;

	if (mode == 1) {
		info_only = 1;
	} else if (mode == 2) {
		delete_only = 1;
	}

	if (! openssl) {
		exit(1);
	}
676

677
	cdir = get_Cert_dir(NULL, &tca);
678
	if (! cdir || ! tca) {
679 680 681 682 683 684 685 686 687 688 689 690
		fprintf(stderr, "could not find Cert dir\n");
		exit(1);
	}

	if (!strcasecmp(path, "LL") || !strcasecmp(path, "LISTL")) {
		listlong = 1;
		path = "LIST";
	}

	if (strstr(path, "SAVE") == path) {
		char *p = get_saved_pem(path, 0);
		if (p == NULL) {
691 692
			fprintf(stderr, "could not find saved pem "
			    "matching: %s\n", path);
693 694 695 696
			exit(1);
		}
		path = p;

697 698
	} else if (!strcmp(path, "CA")) {
		tca = (char *) malloc(strlen(cdir)+strlen("/CA/cacert.pem")+1);
699 700 701
		sprintf(tca, "%s/CA/cacert.pem", cdir);
		path = tca;

702 703 704 705 706 707 708 709 710
	} else if (info_only && (!strcasecmp(path, "LIST") ||
	    !strcasecmp(path, "LS") || !strcasecmp(path, "ALL"))) {

		if (! program_name || strchr(program_name, ' ')) {
			fprintf(stderr, "bad program name.\n");
			exit(1);
		}
		if (strchr(cdir, '\'')) {
			fprintf(stderr, "bad certdir char: %s\n", cdir);
711 712
			exit(1);
		}
713 714 715 716 717 718

		tca = (char *) malloc(2*strlen(cdir)+strlen(program_name)+1000);

		sprintf(tca, "find '%s' | egrep '/(CA|tmp|clients)$|"
		    "\\.(crt|pem|key|req)$' | grep -v CA/newcerts", cdir);

719 720
		if (!strcasecmp(path, "ALL")) {
			/* ugh.. */
721 722
			strcat(tca, " | egrep -v 'private/cakey.pem|"
			    "(CA|tmp|clients)$' | xargs -n1 ");
723 724 725 726 727
			strcat(tca, program_name);
			strcat(tca, " -ssldir '");
			strcat(tca, cdir);
			strcat(tca, "' -sslCertInfo 2>&1 ");
		} else if (listlong) {
728
			strcat(tca, " | xargs ls -ld ");
729 730
		}
		system(tca);
731 732
		free(tca);

733
		depth--;
734 735
		return;

736 737
	} else if (info_only && (!strcasecmp(path, "HASHON")
	    || !strcasecmp(path, "HASHOFF"))) {
738 739 740 741 742 743 744 745 746

		tmp_fd = mkstemp(tmp);
		if (tmp_fd < 0) {
			exit(1);
		}

		write(tmp_fd, genCert, strlen(genCert));
		close(tmp_fd);

747
		scr = (char *) malloc(strlen("/bin/sh ") + strlen(tmp) + 1);
748 749 750 751 752 753 754 755 756 757 758 759
		sprintf(scr, "/bin/sh %s", tmp);

		set_env("BASE_DIR", cdir);
		set_env("OPENSSL", openssl);
		set_env("TYPE", "server");
		if (!strcasecmp(path, "HASHON")) {
			set_env("HASHON", "1");
		} else {
			set_env("HASHOFF", "1");
		}
		system(scr);
		unlink(tmp);
760 761
		free(scr);

762
		depth--;
763 764 765
		return;
	}

766

767
	if (stat(path, &sbuf) != 0) {
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
	    if (strstr(path, "client") || strchr(path, '/') == NULL) {
		int i;
		tca = (char *) malloc(strlen(cdir) + strlen(path) + 100);
		for (i = 1; i <= 15; i++)  {
			tca[0] = '\0';
			if (       i == 1) {
			    sprintf(tca, "%s/%s", cdir, path); 
			} else if (i == 2 && mode > 0) {
			    sprintf(tca, "%s/%s.crt", cdir, path); 
			} else if (i == 3) {
			    sprintf(tca, "%s/%s.pem", cdir, path); 
			} else if (i == 4 && mode > 1) {
			    sprintf(tca, "%s/%s.req", cdir, path); 
			} else if (i == 5 && mode > 1) {
			    sprintf(tca, "%s/%s.key", cdir, path); 
			} else if (i == 6) {
			    sprintf(tca, "%s/clients/%s", cdir, path); 
			} else if (i == 7 && mode > 0) {
			    sprintf(tca, "%s/clients/%s.crt", cdir, path); 
			} else if (i == 8) {
			    sprintf(tca, "%s/clients/%s.pem", cdir, path); 
			} else if (i == 9 && mode > 1) {
			    sprintf(tca, "%s/clients/%s.req", cdir, path); 
			} else if (i == 10 && mode > 1) {
			    sprintf(tca, "%s/clients/%s.key", cdir, path); 
			} else if (i == 11) {
			    sprintf(tca, "%s/server-%s", cdir, path); 
			} else if (i == 12 && mode > 0) {
			    sprintf(tca, "%s/server-%s.crt", cdir, path); 
			} else if (i == 13) {
			    sprintf(tca, "%s/server-%s.pem", cdir, path); 
			} else if (i == 14 && mode > 1) {
			    sprintf(tca, "%s/server-%s.req", cdir, path); 
			} else if (i == 15 && mode > 1) {
			    sprintf(tca, "%s/server-%s.key", cdir, path); 
			}
			if (tca[0] == '\0') {
				continue;
			}
			if (stat(tca, &sbuf) == 0) {
				path = tca;
				break;
810 811
			}
		}
812
	    }
813 814 815 816 817 818 819 820 821
	}

	if (stat(path, &sbuf) != 0) {
		rfbLog("sslEncKey: %s\n", path);
		rfbLogPerror("stat");
		exit(1);
	}

	if (! info_only) {
822
		cert = (char *) malloc(2*(sbuf.st_size + 1024));
823 824 825 826 827 828 829 830 831
		file = fopen(path, "r");
		if (file == NULL) {
			rfbLog("sslEncKey: %s\n", path);
			rfbLogPerror("fopen");
			exit(1);
		}
		incert = 0;
		cert[0] = '\0';
		while (fgets(line, 1024, file) != NULL) {
832 833
			if (strstr(line, "-----BEGIN CERTIFICATE-----")
			    == line) {
834 835 836
				incert = 1;
			}
			if (incert) {
runge's avatar
runge committed
837 838
				if (strlen(cert)+strlen(line) <
				    2 * (size_t) sbuf.st_size) {
839 840
					strcat(cert, line);
				}
841
			}
842 843
			if (strstr(line, "-----END CERTIFICATE-----")
			    == line) {
844 845 846 847 848 849 850 851 852 853 854 855 856 857
				incert = 0;
			}
		}
		fclose(file);
	}

	tmp_fd = mkstemp(tmp);
	if (tmp_fd < 0) {
		exit(1);
	}

	write(tmp_fd, genCert, strlen(genCert));
	close(tmp_fd);

858
        scr = (char *) malloc(strlen("/bin/sh ") + strlen(tmp) + 1);
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
	sprintf(scr, "/bin/sh %s", tmp);

	set_env("BASE_DIR", "/no/such/dir");
	set_env("OPENSSL", openssl);
	set_env("TYPE", "server");
	if (info_only) {
		set_env("INFO_ONLY", path);
	} else if (delete_only) {
		set_env("DELETE_ONLY", path);
	} else {
		set_env("ENCRYPT_ONLY", path);
	}
	system(scr);
	unlink(tmp);

	if (! mode && cert && cert[0] != '\0') {
875 876
		int got_cert = 0;
		file = fopen(path, "r");
877 878 879 880 881
		if (file == NULL) {
			rfbLog("sslEncKey: %s\n", path);
			rfbLogPerror("fopen");
			exit(1);
		}
882 883 884 885 886 887 888 889 890 891
		while (fgets(line, 1024, file) != NULL) {
			if (strstr(line, "-----BEGIN CERTIFICATE-----")
			    == line) {
				got_cert++;
			}
			if (strstr(line, "-----END CERTIFICATE-----")
			    == line) {
				got_cert++;
			}
		}
892
		fclose(file);
893 894 895 896 897 898 899 900 901 902
		if (got_cert < 2) {
			file = fopen(path, "a");
			if (file == NULL) {
				rfbLog("sslEncKey: %s\n", path);
				rfbLogPerror("fopen");
				exit(1);
			}
			fprintf(file, "%s", cert);
			fclose(file);
		}
903 904 905 906 907 908
		free(cert);
	}

	depth--;
}