1 /*
2    Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3    All rights reserved.
4 
5 This file is part of x11vnc.
6 
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11 
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21 
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables.  You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL".  If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so.  If you do not wish to do
30 so, delete this exception statement from your version.
31 */
32 
33 /* -- 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 
check_stunnel(void)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 
start_stunnel(int stunnel_port,int x11vnc_port,int hport,int x11vnc_hport)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 
stop_stunnel(void)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 
setup_stunnel(int rport,int * argc,char ** argv)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 
get_Cert_dir(char * cdir_in,char ** tmp_in)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 
getsslscript(char * cdir,char * name,char * script)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 
sslScripts(void)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 
sslGenCA(char * cdir)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 
sslGenCert(char * ty,char * nm)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 
sslEncKey(char * path,int mode)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