diff options
| author | runge <runge> | 2008-11-22 18:36:33 +0000 | 
|---|---|---|
| committer | runge <runge> | 2008-11-22 18:36:33 +0000 | 
| commit | 6fbba525a924961083bf2e43bb841bd15671f526 (patch) | |
| tree | 3ec0cf4b285fb0140294a151b801c91bc78a612e /x11vnc/sslhelper.c | |
| parent | 63b98dba790fa9835e970b8502d93258862a9373 (diff) | |
| download | libtdevnc-6fbba525a924961083bf2e43bb841bd15671f526.tar.gz libtdevnc-6fbba525a924961083bf2e43bb841bd15671f526.zip  | |
x11vnc: x11vnc.desktop file. -reopen, -dhparams, -sslCRL,
  -setdefer options. -rfbport PROMPT VeNCrypt and TLSVNC SSL/TLS
  encryption support.  Tweaks to choose_delay() algorithm.
  -ssl ANON anonymouse Diffie-Hellman mode.  Fix bugs in certs
  management.  Additions to tray=setpass naive user mode.
Diffstat (limited to 'x11vnc/sslhelper.c')
| -rw-r--r-- | x11vnc/sslhelper.c | 1104 | 
1 files changed, 1064 insertions, 40 deletions
diff --git a/x11vnc/sslhelper.c b/x11vnc/sslhelper.c index 7aad2c4..13e60a3 100644 --- a/x11vnc/sslhelper.c +++ b/x11vnc/sslhelper.c @@ -7,6 +7,7 @@  #include "scan.h"  #include "connections.h"  #include "sslcmds.h" +#include "unixpw.h"  #define OPENSSL_INETD 1  #define OPENSSL_VNC   2 @@ -21,13 +22,6 @@  #endif  #endif -#ifdef NO_SSL_OR_UNIXPW -#undef FORK_OK -#undef LIBVNCSERVER_HAVE_LIBSSL -#define LIBVNCSERVER_HAVE_LIBSSL 0 -#endif - -  int openssl_sock = -1;  int openssl_port_num = 0;  int https_sock = -1; @@ -39,6 +33,11 @@ static int certret_fd = -1;  static mode_t omode;  char *certret_str = NULL; +static char *dhret = NULL; +static int dhret_fd = -1; +char *dhret_str = NULL; +char *new_dh_params = NULL; +  void raw_xfer(int csock, int s_in, int s_out);  #if !LIBVNCSERVER_HAVE_LIBSSL @@ -85,6 +84,7 @@ static SSL_CTX *ctx = NULL;  static RSA *rsa_512 = NULL;  static RSA *rsa_1024 = NULL;  static SSL *ssl = NULL; +static X509_STORE *revocation_store = NULL;  static void init_prng(void); @@ -128,6 +128,9 @@ char *get_saved_pem(char *save, int create) {  	if (strstr(save, "SAVE_PROMPT") == save) {  		prompt = 1;  		s = save + strlen("SAVE_PROMPT"); +	} else if (strstr(save, "SAVE_NOPROMPT") == save) { +		set_env("GENCERT_NOPROMPT", "1"); +		s = save + strlen("SAVE_NOPROMPT");  	} else if (strstr(save, "SAVE") == save) {  		s = save + strlen("SAVE");  	} else { @@ -318,7 +321,7 @@ static char *create_tmp_pem(char *pathin, int prompt) {  	}  	rfbLog("\n");	 -	rfbLog("This will NOT prevent man-in-the-middle attacks UNLESS you\n");	 +	rfbLog("This will NOT prevent Man-In-The-Middle attacks UNLESS you\n");	  	rfbLog("get the certificate information to the VNC viewers SSL\n");	  	rfbLog("tunnel configuration or you take the extra steps to sign it\n");  	rfbLog("with a CA key. However, it will prevent passive network\n"); @@ -486,6 +489,9 @@ static char *create_tmp_pem(char *pathin, int prompt) {  			fprintf(out, "%s", line);  			if (on) {  				fprintf(crt, "%s", line); +				if (!quiet) { +					fprintf(stderr, "%s", line); +				}  			}  			if (strstr(line, "END CERTIFICATE")) {  				on = 0; @@ -585,7 +591,7 @@ static char *get_ssl_verify_file(char *str_in) {  	char *tfile, *tfile2;  	FILE *file;  	struct stat sbuf; -	int count = 0; +	int count = 0, fd;  	if (! str_in) {  		rfbLog("get_ssl_verify_file: no filename\n"); @@ -606,7 +612,15 @@ static char *get_ssl_verify_file(char *str_in) {  	tfile  = (char *) malloc(strlen(tmp) + 1024);  	tfile2 = (char *) malloc(strlen(tmp) + 1024); -	sprintf(tfile, "%s/sslverify-load-%d.crts", tmp, getpid()); +	sprintf(tfile, "%s/sslverify-load-%d.crts.XXXXXX", tmp, getpid()); + +	fd = mkstemp(tfile); +	if (fd < 0) { +		rfbLog("get_ssl_verify_file: %s\n", tfile); +		rfbLogPerror("mkstemp"); +		exit(1); +	} +	close(fd);  	file = fopen(tfile, "w");  	chmod(tfile, 0600); @@ -626,7 +640,7 @@ static char *get_ssl_verify_file(char *str_in) {  				unlink(tfile);  				exit(1);  			} -			fprintf(stderr, "sslverify: loaded %s\n", tfile2); +			rfbLog("sslverify: loaded %s\n", tfile2);  			count++;  		} else if (!strcmp(p, "clients")) { @@ -657,7 +671,7 @@ static char *get_ssl_verify_file(char *str_in) {  					unlink(tfile);  					exit(1);  				} -				fprintf(stderr, "sslverify: loaded %s\n", +				rfbLog("sslverify: loaded %s\n",  				    tfile2);  				count++;  			} @@ -676,7 +690,7 @@ static char *get_ssl_verify_file(char *str_in) {  				unlink(tfile);  				exit(1);  			} -			fprintf(stderr, "sslverify: loaded %s\n", tfile2); +			rfbLog("sslverify: loaded %s\n", tfile2);  			count++;  		}  		p = strtok(NULL, ","); @@ -685,14 +699,167 @@ static char *get_ssl_verify_file(char *str_in) {  	free(tfile2);  	free(str); -	fprintf(stderr, "sslverify: using %d client certs in %s\n", count, -	    tfile); +	rfbLog("sslverify: using %d client certs in\n", count); +	rfbLog("sslverify: %s\n", tfile);  	return tfile;  } +/* based on mod_ssl */ +static int crl_callback(X509_STORE_CTX *callback_ctx) { +	X509_STORE_CTX store_ctx; +	X509_OBJECT obj; +	X509_NAME *subject; +	X509_NAME *issuer; +	X509 *xs; +	X509_CRL *crl; +	X509_REVOKED *revoked; +	EVP_PKEY *pubkey; +	long serial; +	BIO *bio; +	int i, n, rc; +	char *cp, *cp2; +	ASN1_TIME *t; +	 +	/* Determine certificate ingredients in advance */ +	xs      = X509_STORE_CTX_get_current_cert(callback_ctx); +	subject = X509_get_subject_name(xs); +	issuer  = X509_get_issuer_name(xs); +	 +	/* Try to retrieve a CRL corresponding to the _subject_ of +	* the current certificate in order to verify it's integrity. */ +	memset((char *)&obj, 0, sizeof(obj)); +	X509_STORE_CTX_init(&store_ctx, revocation_store, NULL, NULL); +	rc=X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj); +	X509_STORE_CTX_cleanup(&store_ctx); +	crl=obj.data.crl; + +	if(rc>0 && crl) { +		/* Log information about CRL +		 * (A little bit complicated because of ASN.1 and BIOs...) */ +		bio=BIO_new(BIO_s_mem()); +		BIO_printf(bio, "lastUpdate: "); +		ASN1_UTCTIME_print(bio, X509_CRL_get_lastUpdate(crl)); +		BIO_printf(bio, ", nextUpdate: "); +		ASN1_UTCTIME_print(bio, X509_CRL_get_nextUpdate(crl)); +		n=BIO_pending(bio); +		cp=malloc(n+1); +		n=BIO_read(bio, cp, n); +		cp[n]='\0'; +		BIO_free(bio); +		cp2=X509_NAME_oneline(subject, NULL, 0); +		rfbLog("CA CRL: Issuer: %s, %s\n", cp2, cp); +		OPENSSL_free(cp2); +		free(cp); + +		/* Verify the signature on this CRL */ +		pubkey=X509_get_pubkey(xs); +		if(X509_CRL_verify(crl, pubkey)<=0) { +			rfbLog("Invalid signature on CRL\n"); +			X509_STORE_CTX_set_error(callback_ctx, +				X509_V_ERR_CRL_SIGNATURE_FAILURE); +			X509_OBJECT_free_contents(&obj); +			if(pubkey) +				EVP_PKEY_free(pubkey); +			return 0; /* Reject connection */ +		} +		if(pubkey) +			EVP_PKEY_free(pubkey); + +		/* Check date of CRL to make sure it's not expired */ +		t=X509_CRL_get_nextUpdate(crl); +		if(!t) { +			rfbLog("Found CRL has invalid nextUpdate field\n"); +			X509_STORE_CTX_set_error(callback_ctx, +				X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); +			X509_OBJECT_free_contents(&obj); +			return 0; /* Reject connection */ +		} +		if(X509_cmp_current_time(t)<0) { +			rfbLog("Found CRL is expired - " +				"revoking all certificates until you get updated CRL\n"); +			X509_STORE_CTX_set_error(callback_ctx, X509_V_ERR_CRL_HAS_EXPIRED); +			X509_OBJECT_free_contents(&obj); +			return 0; /* Reject connection */ +		} +		X509_OBJECT_free_contents(&obj); +	} + +	/* Try to retrieve a CRL corresponding to the _issuer_ of +	 * the current certificate in order to check for revocation. */ +	memset((char *)&obj, 0, sizeof(obj)); +	X509_STORE_CTX_init(&store_ctx, revocation_store, NULL, NULL); +	rc=X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj); +	X509_STORE_CTX_cleanup(&store_ctx); +	crl=obj.data.crl; + +	if(rc>0 && crl) { +		/* Check if the current certificate is revoked by this CRL */ +		n=sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); +		for(i=0; i<n; i++) { +			revoked=sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); +			if(ASN1_INTEGER_cmp(revoked->serialNumber, +					X509_get_serialNumber(xs)) == 0) { +				serial=ASN1_INTEGER_get(revoked->serialNumber); +				cp=X509_NAME_oneline(issuer, NULL, 0); +				rfbLog("Certificate with serial %ld (0x%lX) " +					"revoked per CRL from issuer %s\n", serial, serial, cp); +				OPENSSL_free(cp); +				X509_STORE_CTX_set_error(callback_ctx, X509_V_ERR_CERT_REVOKED); +				X509_OBJECT_free_contents(&obj); +				return 0; /* Reject connection */ +			} +		} +		X509_OBJECT_free_contents(&obj); +	} + +	return 1; /* Accept connection */ +} + +static int verify_callback(int ok, X509_STORE_CTX *callback_ctx) { +	if (!ssl_verify) { +		rfbLog("CRL_check: skipped.\n"); +		return ok; +	} +	if (!ssl_crl) { +		rfbLog("CRL_check: skipped.\n"); +		return ok; +	} +	if (!ok) { +		rfbLog("CRL_check: client cert is already rejected.\n"); +		return ok; +	} +	if (revocation_store) { +		if (crl_callback(callback_ctx)) { +			rfbLog("CRL_check: succeeded.\n"); +			return 1; +		} else { +			rfbLog("CRL_check: did not pass.\n"); +			return 0; +		} +	} +	/* NOTREACHED */ +	return 1; +} + +#define rfbSecTypeTlsVnc   18 +#define rfbSecTypeVencrypt 19 + +#define rfbVencryptPlain	256 +#define rfbVencryptTlsNone	257 +#define rfbVencryptTlsVnc	258 +#define rfbVencryptTlsPlain	259 +#define rfbVencryptX509None	260 +#define rfbVencryptX509Vnc	261 +#define rfbVencryptX509Plain	262 + +static int vencrypt_selected = 0; +static int tlsvnc_selected = 0; +  static int ssl_client_mode = 0; +static int switch_to_anon_dh(void); +  void openssl_init(int isclient) {  	int db = 0, tmp_pem = 0, do_dh;  	FILE *in; @@ -792,11 +959,27 @@ void openssl_init(int isclient) {  		}  		tmp_pem = 1; +	} else if (!strcmp(openssl_pem, "ANON")) { +		if (ssl_verify) { +			rfbLog("openssl_init: Anonymous Diffie-Hellman cannot" +			    " be used in -sslverify mode.\n");	 +			clean_up_exit(1); +		} +		if (ssl_crl) { +			rfbLog("openssl_init: Anonymous Diffie-Hellman cannot" +			    " be used in -sslCRL mode.\n");	 +			clean_up_exit(1); +		} +		if (!switch_to_anon_dh()) { +			rfbLog("openssl_init: Anonymous Diffie-Hellman setup" +			    " failed.\n");	 +			clean_up_exit(1); +		}  	} else if (strstr(openssl_pem, "SAVE") == openssl_pem) {  		openssl_pem = get_saved_pem(openssl_pem, 1);  		if (! openssl_pem) {  			rfbLog("openssl_init: could not create or open" -			    " saved PEM:\n", openssl_pem);	 +			    " saved PEM: %s\n", openssl_pem);	  			clean_up_exit(1);  		}  		tmp_pem = 0; @@ -834,18 +1017,20 @@ void openssl_init(int isclient) {  		DH_free(dh);  	} -	if (! SSL_CTX_use_certificate_chain_file(ctx, openssl_pem)) { -		rfbLog("openssl_init: SSL_CTX_use_certificate_chain_file() failed.\n");	 -		sslerrexit(); -	} -	if (! SSL_CTX_use_RSAPrivateKey_file(ctx, openssl_pem, -	    SSL_FILETYPE_PEM)) { -		rfbLog("openssl_init: SSL_CTX_set_tmp_rsa(1024) failed.\n");	 -		sslerrexit(); -	} -	if (! SSL_CTX_check_private_key(ctx)) { -		rfbLog("openssl_init: SSL_CTX_set_tmp_rsa(1024) failed.\n");	 -		sslerrexit(); +	if (strcmp(openssl_pem, "ANON")) { +		if (! SSL_CTX_use_certificate_chain_file(ctx, openssl_pem)) { +			rfbLog("openssl_init: SSL_CTX_use_certificate_chain_file() failed.\n");	 +			sslerrexit(); +		} +		if (! SSL_CTX_use_RSAPrivateKey_file(ctx, openssl_pem, +		    SSL_FILETYPE_PEM)) { +			rfbLog("openssl_init: SSL_CTX_set_tmp_rsa(1024) failed.\n");	 +			sslerrexit(); +		} +		if (! SSL_CTX_check_private_key(ctx)) { +			rfbLog("openssl_init: SSL_CTX_set_tmp_rsa(1024) failed.\n");	 +			sslerrexit(); +		}  	}  	if (tmp_pem && ! getenv("X11VNC_KEEP_TMP_PEM")) { @@ -866,6 +1051,46 @@ void openssl_init(int isclient) {  		openssl_pem = NULL;  	} +	if (ssl_crl) { +		struct stat sbuf; +		X509_LOOKUP *lookup; + +		if (stat(ssl_crl, &sbuf) != 0) { +			rfbLog("openssl_init: -sslCRL does not exist %s.\n", +			    ssl_crl ? ssl_crl : "null");	 +			rfbLogPerror("stat"); +			clean_up_exit(1); +		} + +		revocation_store = X509_STORE_new(); +		if (!revocation_store) { +			rfbLog("openssl_init: X509_STORE_new failed.\n"); +			sslerrexit(); +		} +		if (! S_ISDIR(sbuf.st_mode)) { +			lookup = X509_STORE_add_lookup(revocation_store, X509_LOOKUP_file()); +			if (!lookup) { +				rfbLog("openssl_init: X509_STORE_add_lookup failed.\n"); +				sslerrexit(); +			} +			if (!X509_LOOKUP_load_file(lookup, ssl_crl, X509_FILETYPE_PEM))  { +				rfbLog("openssl_init: X509_LOOKUP_load_file failed.\n"); +				sslerrexit(); +			} +		} else { +			lookup = X509_STORE_add_lookup(revocation_store, X509_LOOKUP_hash_dir()); +			if (!lookup) { +				rfbLog("openssl_init: X509_STORE_add_lookup failed.\n"); +				sslerrexit(); +			} +			if (!X509_LOOKUP_add_dir(lookup, ssl_crl, X509_FILETYPE_PEM))  { +				rfbLog("openssl_init: X509_LOOKUP_add_dir failed.\n"); +				sslerrexit(); +			} +		} +		rfbLog("loaded CRL file: %s\n", ssl_crl); +	} +  	if (ssl_verify) {  		struct stat sbuf;  		char *file; @@ -874,7 +1099,7 @@ void openssl_init(int isclient) {  		file = get_ssl_verify_file(ssl_verify);  		if (!file || stat(file, &sbuf) != 0) { -			rfbLog("openssl_init: -sslverify does not exists %s.\n", +			rfbLog("openssl_init: -sslverify does not exist %s.\n",  			    file ? file : "null");	  			rfbLogPerror("stat");  			clean_up_exit(1); @@ -894,7 +1119,11 @@ void openssl_init(int isclient) {  		}  		lvl = SSL_VERIFY_FAIL_IF_NO_PEER_CERT|SSL_VERIFY_PEER; -		SSL_CTX_set_verify(ctx, lvl, NULL); +		if (ssl_crl == NULL) { +			SSL_CTX_set_verify(ctx, lvl, NULL); +		} else { +			SSL_CTX_set_verify(ctx, lvl, verify_callback); +		}  		if (strstr(file, "tmp/sslverify-load-")) {  			/* temporary file */  			unlink(file); @@ -1371,6 +1600,106 @@ static int check_ssl_access(char *addr) {  	return check_access(addr);  } +static int write_exact(int sock, char *buf, int len); +static int read_exact(int sock, char *buf, int len); + +static int finish_auth(rfbClientPtr client, char *type) { +	int security_result, ret; + +	ret = 0; + +if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "finish_auth type=%s\n", type); + +	if (!strcmp(type, "None")) { +		security_result = 0;	/* success */ +		if (write_exact(client->sock, (char *) &security_result, 4)) { +			ret = 1; +		} +		rfbLog("finish_auth: using auth 'None'\n"); +		client->state = RFB_INITIALISATION; + +	} else if (!strcmp(type, "Vnc")) { +		RAND_bytes(client->authChallenge, CHALLENGESIZE); +		if (write_exact(client->sock, (char *) &client->authChallenge, CHALLENGESIZE)) { +			ret = 1; +		} +		rfbLog("finish_auth: using auth 'Vnc', sent challenge.\n"); +		client->state = RFB_AUTHENTICATION; + +	} else if (!strcmp(type, "Plain")) { +		if (!unixpw) { +			rfbLog("finish_auth: *Plain not allowed outside unixpw mode.\n"); +			ret = 0; +		} else { +			char *un, *pw; +			int unlen, pwlen; + +if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "*Plain begin: onHold=%d client=%p unixpw_client=%p\n", client->onHold, (void *) client, (void *) unixpw_client); + +			if (!read_exact(client->sock, (char *)&unlen, 4)) goto fail; +			unlen = Swap32IfLE(unlen); + +if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "unlen: %d\n", unlen); + +			if (!read_exact(client->sock, (char *)&pwlen, 4)) goto fail; +			pwlen = Swap32IfLE(pwlen); + +if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "pwlen: %d\n", pwlen); + +			un = (char *) malloc(unlen+1); +			memset(un, 0, unlen+1); + +			pw = (char *) malloc(pwlen+2); +			memset(pw, 0, pwlen+2); + +			if (!read_exact(client->sock, un, unlen)) goto fail; +			if (!read_exact(client->sock, pw, pwlen)) goto fail; + +if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "*Plain: %d %d '%s' ... \n", unlen, pwlen, un); +			strcat(pw, "\n"); + +			if (unixpw_verify(un, pw)) { +				security_result = 0;	/* success */ +				if (write_exact(client->sock, (char *) &security_result, 4)) { +					ret = 1; +					unixpw_verify_screen(un, pw); +				} +				client->onHold = FALSE; +				client->state = RFB_INITIALISATION; +			} +			if (ret == 0) { +				rfbClientSendString(client, "unixpw failed"); +			} + +			memset(un, 0, unlen+1); +			memset(pw, 0, pwlen+2); +			free(un); +			free(pw); +		} +	} else { +		rfbLog("finish_auth: unknown sub-type: %s\n", type); +		ret = 0; +	} + +	fail: +	return ret; +} + +static int finish_vencrypt_auth(rfbClientPtr client, int subtype) { + +	if (subtype == rfbVencryptTlsNone || subtype == rfbVencryptX509None) { +		return finish_auth(client, "None"); +	} else if (subtype == rfbVencryptTlsVnc || subtype == rfbVencryptX509Vnc) { +		return finish_auth(client, "Vnc"); +	} else if (subtype == rfbVencryptTlsPlain || subtype == rfbVencryptX509Plain) { +		return finish_auth(client, "Plain"); +	} else { +		rfbLog("finish_vencrypt_auth: unknown sub-type: %d\n", subtype); +		return 0; +	} +} + +  void accept_openssl(int mode, int presock) {  	int sock = -1, listen = -1, cport, csock, vsock;	  	int peerport = 0; @@ -1384,15 +1713,18 @@ void accept_openssl(int mode, int presock) {  	rfbClientPtr client;  	pid_t pid;  	char uniq[] = "_evilrats_"; -	char cookie[128], rcookie[128], *name = NULL; +	char cookie[256], rcookie[256], *name = NULL; +	int vencrypt_sel = 0; +	int tlsvnc_sel = 0;  	static time_t last_https = 0; -	static char last_get[128]; +	static char last_get[256];  	static int first = 1; +	unsigned char *rb;  	openssl_last_helper_pid = 0;  	/* zero buffers for use below. */ -	for (i=0; i<128; i++) { +	for (i=0; i<256; i++) {  		if (first) {  			last_get[i] = '\0';  		} @@ -1500,7 +1832,11 @@ void accept_openssl(int mode, int presock) {  	 * but hard to guess exactly (just worrying about local lusers  	 * here, since we use INADDR_LOOPBACK).  	 */ -	sprintf(cookie, "%f/%f", dnow(), x11vnc_start); +	rb = (unsigned char *) malloc(6); +	RAND_bytes((char *)rb, 6); +	sprintf(cookie, "RB=%d%d%d%d%d%d/%f%f/0x%x", +	    rb[0], rb[1], rb[2], rb[3], rb[4], rb[5], +            dnow() - x11vnc_start, x11vnc_start, rb);  	if (mode != OPENSSL_INETD) {  		name = get_remote_host(sock); @@ -1543,6 +1879,23 @@ void accept_openssl(int mode, int presock) {  		certret_fd = -1;  	} +	if (dhret) { +		free(dhret); +	} +	if (dhret_str) { +		free(dhret_str); +		dhret_str = NULL; +	} +	dhret = strdup("/tmp/x11vnc-dhret.XXXXXX"); +	omode = umask(077); +	dhret_fd = mkstemp(dhret); +	umask(omode); +	if (dhret_fd < 0) { +		free(dhret); +		dhret = NULL; +		dhret_fd = -1; +	} +  	/* now fork the child to handle the SSL: */  	pid = fork(); @@ -1614,6 +1967,20 @@ void accept_openssl(int mode, int presock) {  			exit(1);  		} +		if (vencrypt_selected != 0) { +			char *tbuf; +			tbuf = (char *) malloc(strlen(cookie) + 100); +			sprintf(tbuf, "%s,VENCRYPT=%d,%s", uniq, vencrypt_selected, cookie); +			write(vncsock, tbuf, strlen(cookie)); +			goto wrote_cookie; +		} else if (tlsvnc_selected != 0) { +			char *tbuf; +			tbuf = (char *) malloc(strlen(cookie) + 100); +			sprintf(tbuf, "%s,TLSVNC=%d,%s", uniq, tlsvnc_selected, cookie); +			write(vncsock, tbuf, strlen(cookie)); +			goto wrote_cookie; +		} +  		/*  		 * things get messy below since we are trying to do  		 * *both* VNC and Java applet httpd through the same @@ -1907,6 +2274,13 @@ void accept_openssl(int mode, int presock) {  		if (certret) {  			unlink(certret);  		} +		if (dhret_fd >= 0) { +			close(dhret_fd); +			dhret_fd = -1; +		} +		if (dhret) { +			unlink(dhret); +		}  		return;  	}  	if (db) fprintf(stderr, "accept_openssl: vsock: %d\n", vsock); @@ -1920,7 +2294,7 @@ void accept_openssl(int mode, int presock) {  		struct stat sbuf;  		sbuf.st_size = 0;  		if (certret_fd >= 0 && stat(certret, &sbuf) == 0 && sbuf.st_size > 0) { -			certret_str = (char *) malloc(sbuf.st_size+1); +			certret_str = (char *) calloc(sbuf.st_size+1, 1);  			read(certret_fd, certret_str, sbuf.st_size);  			close(certret_fd);  			certret_fd = -1; @@ -1939,6 +2313,59 @@ void accept_openssl(int mode, int presock) {  		}  	} +	if (dhret) { +		struct stat sbuf; +		sbuf.st_size = 0; +		if (dhret_fd >= 0 && stat(dhret, &sbuf) == 0 && sbuf.st_size > 0) { +			dhret_str = (char *) calloc(sbuf.st_size+1, 1); +			read(dhret_fd, dhret_str, sbuf.st_size); +			close(dhret_fd); +			dhret_fd = -1; +		} +		if (dhret_fd >= 0) { +			close(dhret_fd); +			dhret_fd = -1; +		} +		unlink(dhret); +		if (dhret_str && strstr(dhret_str, "NOCERT") == dhret_str) { +			free(dhret_str); +			dhret_str = NULL; +		} +		if (dhret_str) { +			if (new_dh_params == NULL) { +				fprintf(stderr, "dhret_str[%d]:\n%s\n", (int) sbuf.st_size, dhret_str); +				new_dh_params = strdup(dhret_str); +			} +		} +	} + +	if (0) { +		fprintf(stderr, "rcookie: %s\n", rcookie); +		fprintf(stderr, "cookie:  %s\n", cookie); +	} + +	if (strstr(rcookie, uniq) == rcookie) { +		char *q = strstr(rcookie, "RB="); +		if (q && strstr(cookie, q) == cookie) { +			vencrypt_sel = 0; +			tlsvnc_sel = 0; +			q = strstr(rcookie, "VENCRYPT="); +			if (q && sscanf(q, "VENCRYPT=%d,", &vencrypt_sel) == 1) { +				if (vencrypt_sel != 0) { +					rfbLog("SSL: VENCRYPT mode=%d accepted.\n", vencrypt_sel); +					goto accept_client; +				} +			} +			q = strstr(rcookie, "TLSVNC="); +			if (q && sscanf(q, "TLSVNC=%d,", &tlsvnc_sel) == 1) { +				if (tlsvnc_sel != 0) { +					rfbLog("SSL: TLSVNC mode=%d accepted.\n", tlsvnc_sel); +					goto accept_client; +				} +			} +		} +	} +  	if (n != (int) strlen(cookie) || strncmp(cookie, rcookie, n)) {  		rfbLog("SSL: accept_openssl: cookie from ssl_helper FAILED. %d\n", n);  		if (db) fprintf(stderr, "'%s'\n'%s'\n", cookie, rcookie); @@ -1949,7 +2376,7 @@ void accept_openssl(int mode, int presock) {  			rfbLog("SSL: BUT WAIT! HTTPS for helper process succeeded. Good.\n");  			if (mode != OPENSSL_HTTPS) {  				last_https = time(NULL); -				for (i=0; i<128; i++) { +				for (i=0; i<256; i++) {  					last_get[i] = '\0';  				}  				strncpy(last_get, rcookie, 100); @@ -2044,6 +2471,9 @@ void accept_openssl(int mode, int presock) {  		}  		return;  	} + +	accept_client: +  	if (db) fprintf(stderr, "accept_openssl: cookie good: %s\n", cookie);  	rfbLog("SSL: handshake with helper process succeeded.\n"); @@ -2072,6 +2502,17 @@ void accept_openssl(int mode, int presock) {  		    strpbrk(openssl_last_ip, "0123456789") == openssl_last_ip) {  			client->host = strdup(openssl_last_ip);  		} +		if (vencrypt_sel != 0) { +			client->protocolMajorVersion = 3; +			client->protocolMinorVersion = 8; +			if (!finish_vencrypt_auth(client, vencrypt_sel)) { +				rfbCloseClient(client); +			} +		} else if (tlsvnc_sel != 0) { +			client->protocolMajorVersion = 3; +			client->protocolMinorVersion = 8; +			rfbAuthNewClient(client); +		}  	} else {  		rfbLog("SSL: accept_openssl: rfbNewClient failed.\n");  		close(vsock); @@ -2085,6 +2526,567 @@ void accept_openssl(int mode, int presock) {  	}  } +static int read_exact(int sock, char *buf, int len) { +	int n, fail = 0; +	if (sock < 0) { +		return 0; +	} +	while (len > 0) { +		n = read(sock, buf, len); +		if (n > 0) { +			buf += n; +			len -= n; +		} else if (n == 0) { +			fail = 1; +			break; +		} else if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { +			usleep(10*1000); +		} else if (n < 0 && errno != EINTR) { +			fail = 1; +			break; +		} +	} +	if (fail) { +		return 0; +	} else { +		return 1; +	} +} + +static int write_exact(int sock, char *buf, int len) { +	int n, fail = 0; +	if (sock < 0) { +		return 0; +	} +	while (len > 0) { +		n = write(sock, buf, len); +		if (n > 0) { +			buf += n; +			len -= n; +		} else if (n == 0) { +			fail = 1; +			break; +		} else if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { +			usleep(10*1000); +		} else if (n < 0 && errno != EINTR) { +			fail = 1; +			break; +		} +	} +	if (fail) { +		return 0; +	} else { +		return 1; +	} +} + +static int add_anon_dh(void) { +	pid_t pid, pidw; +	char cnf[] = "/tmp/x11vnc-dh.XXXXXX"; +	char *infile = NULL; +	int status, cnf_fd; +	DH *dh; +	BIO *bio; +	FILE *in; +	double ds; +	/* +	 * These are dh parameters (prime, generator), not dh keys. +	 * Evidently it is ok for them to be publicly known. +	 * openssl dhparam -out dh.out 1024 +	 */ +	char *fixed_dh_params =  +"-----BEGIN DH PARAMETERS-----\n" +"MIGHAoGBAL28w69ZnLYBvp8R2OeqtAIms+oatY19iBL4WhGI/7H1OMmkJjIe+OHs\n" +"PXoJfe5ucrnvno7Xm+HJZYa1jnPGQuWoa/VJKXdVjYdJVNzazJKM2daKKcQA4GDc\n" +"msFS5DxLbzUR5jy1n12K3EcbvpyFqDYVTJJXm7NuNuiWRfz3wTozAgEC\n" +"-----END DH PARAMETERS-----\n"; + +	if (dhparams_file != NULL) { +		infile = dhparams_file; +		rfbLog("add_anon_dh: using %s\n", dhparams_file); +		goto readin; +	} + +	cnf_fd = mkstemp(cnf); +	if (cnf_fd < 0) { +		return 0; +	} +	infile = cnf; + +	if (create_fresh_dhparams) { + +		if (new_dh_params != NULL) { +			write(cnf_fd, new_dh_params, strlen(new_dh_params)); +			close(cnf_fd); +		} else { +			char *exe = find_openssl_bin(); +			struct stat sbuf; + +			if (no_external_cmds || !cmd_ok("ssl")) { +				rfbLog("add_anon_dh: cannot run external commands.\n");	 +				return 0; +			} + +			close(cnf_fd); +			if (exe == NULL) { +				return 0; +			} +			ds = dnow(); +			pid = fork(); +			if (pid < 0) { +				return 0; +			} else if (pid == 0) { +				int i; +				for (i=0; i<256; i++) { +					if (i == 2) continue; +					close(i); +				} +				/* rather slow at 1024 */ +				execlp(exe, exe, "dhparam", "-out", cnf, "1024", (char *)0); +				exit(1); +			} +			pidw = waitpid(pid, &status, 0);  +			if (pidw != pid) { +				return 0; +			} +			if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { +				; +			} else { +				return 0; +			} +			rfbLog("add_anon_dh: created new DH params in %.3f secs\n", dnow() - ds); + +			if (stat(cnf, &sbuf) == 0 && sbuf.st_size > 0) { +				/* save it to reuse during our process's lifetime: */ +				int d = open(cnf, O_RDONLY); +				if (d >= 0) { +					int n, len = sbuf.st_size; +					new_dh_params = (char *) calloc(len+1, 1); +					n = read(d, new_dh_params, len); +					close(d); +					if (n != len) { +						free(new_dh_params); +						new_dh_params = NULL; +					} else if (dhret != NULL) { +						d = open(dhret, O_WRONLY); +						if (d >= 0) { +							write(d, new_dh_params, strlen(new_dh_params)); +							close(d); +						} +					} +				} +			} +		} +	} else { +		write(cnf_fd, fixed_dh_params, strlen(fixed_dh_params)); +		close(cnf_fd); +	} + +	readin: + +	ds = dnow(); +	in = fopen(infile, "r"); + +	if (in == NULL) { +		rfbLogPerror("fopen"); +		unlink(cnf); +		return 0; +	} +	bio = BIO_new_fp(in, BIO_CLOSE|BIO_FP_TEXT); +	if (! bio) { +		rfbLog("openssl_init: BIO_new_fp() failed.\n");	 +		unlink(cnf); +		return 0; +	} +	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); +	if (dh == NULL) { +		rfbLog("openssl_init: PEM_read_bio_DHparams() failed.\n");	 +		unlink(cnf); +		BIO_free(bio); +		return 0; +	} +	BIO_free(bio); +	SSL_CTX_set_tmp_dh(ctx, dh); +	rfbLog("loaded Diffie Hellman %d bits, %.3fs\n", 8*DH_size(dh), dnow()-ds); +	DH_free(dh); + +	unlink(cnf); +	return 1; +} + +static int switch_to_anon_dh(void) { +	long mode; +	 +	rfbLog("Using Anonymous Diffie-Hellman mode.\n"); +	rfbLog("WARNING: Anonymous Diffie-Hellman uses encryption but is\n"); +	rfbLog("WARNING: susceptible to a Man-In-The-Middle attack.\n"); +	ctx = SSL_CTX_new( SSLv23_server_method() ); +	if (ctx == NULL) { +		return 0; +	} +	if (!SSL_CTX_set_cipher_list(ctx, "ADH:@STRENGTH")) { +		return 0; +	} +	if (!add_anon_dh()) { +		return 0; +	} + +	mode = 0; +	mode |= SSL_MODE_ENABLE_PARTIAL_WRITE; +	mode |= SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; +	SSL_CTX_set_mode(ctx, mode); + +	SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH); +	SSL_CTX_set_timeout(ctx, 300); +	SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_callback); +	SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + +	return 1; +} + +static int tlsvnc_dialog(int s_in, int s_out) { + +	tlsvnc_selected = 1; + +	if (!switch_to_anon_dh()) { +		rfbLog("tlsvnc: Anonymous Diffie-Hellman failed.\n");	 +		return 0; +	} + +	/* continue with SSL/TLS */ +	return 1; +} + +/* + * Using spec: + * http://www.mail-archive.com/qemu-devel@nongnu.org/msg08681.html + */ +static int vencrypt_dialog(int s_in, int s_out) { +	char buf[256], buf2[256]; +	int subtypes[16]; +	int n, i, ival, ok, db = 1, nsubtypes = 0; + +	vencrypt_selected = 0; + +	/* send version 0.2 */ +	buf[0] = 0; +	buf[1] = 2; + +	if (!write_exact(s_out, buf, 2)) { +		close(s_in); close(s_out); +		return 0; +	} + +	/* read client version 0.2 */ +	memset(buf, 0, sizeof(buf)); +	if (!read_exact(s_in, buf, 2)) { +		close(s_in); close(s_out); +		return 0; +	} +	rfbLog("vencrypt: received %d.%d client version.\n", (int) buf[0], (int) buf[1]); + +	/* close 0.0 */ +	if (buf[0] == 0 && buf[1] == 0) { +		rfbLog("vencrypt: received 0.0 version, closing connection.\n"); +		close(s_in); close(s_out); +		return 0; +	} + +	/* accept only 0.2 */ +	if (buf[0] != 0 || buf[1] != 2) { +		rfbLog("vencrypt: unsupported VeNCrypt version, closing connection.\n"); +		buf[0] = 255; +		write_exact(s_out, buf, 1); +		close(s_in); close(s_out); +		return 0; +	} + +	/* tell them OK */ +	buf[0] = 0; +	if (!write_exact(s_out, buf, 1)) { +		close(s_in); close(s_out); +		return 0; +	} + +	if (getenv("X11VNC_ENABLE_VENCRYPT_PLAIN_LOGIN")) { +		vencrypt_enable_plain_login = atoi(getenv("X11VNC_ENABLE_VENCRYPT_PLAIN_LOGIN")); +	} + +	/* load our list of sub-types: */ +	n = 0; +	if (!ssl_verify && vencrypt_kx != VENCRYPT_NODH) { +		if (screen->authPasswdData != NULL) { +			subtypes[n++] = rfbVencryptTlsVnc; +		} else { +			if (vencrypt_enable_plain_login && unixpw) { +				subtypes[n++] = rfbVencryptTlsPlain; +			} else { +				subtypes[n++] = rfbVencryptTlsNone; +			} +		} +	} +	if (vencrypt_kx != VENCRYPT_NOX509) { +		if (screen->authPasswdData != NULL) { +			subtypes[n++] = rfbVencryptX509Vnc; +		} else { +			if (vencrypt_enable_plain_login && unixpw) { +				subtypes[n++] = rfbVencryptX509Plain; +			} else { +				subtypes[n++] = rfbVencryptX509None; +			} +		} +	} + +	nsubtypes = n; +	for (i = 0; i < nsubtypes; i++) { +		((uint32_t *)buf)[i] = Swap32IfLE(subtypes[i]); +	} + +	/* send number first: */ +	buf2[0] = (char) nsubtypes; +	if (!write_exact(s_out, buf2, 1)) { +		close(s_in); close(s_out); +		return 0; +	} +	/* and now the list: */ +	if (!write_exact(s_out, buf, 4*n)) { +		close(s_in); close(s_out); +		return 0; +	} + +	/* read client's selection: */ +	if (!read_exact(s_in, (char *)&ival, 4)) { +		close(s_in); close(s_out); +		return 0; +	} +	ival = Swap32IfLE(ival); + +	/* zero means no dice: */ +	if (ival == 0) { +		rfbLog("vencrypt: client selected no sub-type, closing connection.\n"); +		close(s_in); close(s_out); +		return 0; +	} + +	/* check if he selected a valid one: */ +	ok = 0; +	for (i = 0; i < nsubtypes; i++) { +		if (ival == subtypes[i]) { +			ok = 1; +		} +	} + +	if (!ok) { +		rfbLog("vencrypt: client selected invalid sub-type: %d\n", ival); +		close(s_in); close(s_out); +		return 0; +	} else { +		char *st = "unknown!!"; +		if (ival == rfbVencryptTlsNone)	  st = "rfbVencryptTlsNone"; +		if (ival == rfbVencryptTlsVnc)    st = "rfbVencryptTlsVnc"; +		if (ival == rfbVencryptTlsPlain)  st = "rfbVencryptTlsPlain"; +		if (ival == rfbVencryptX509None)  st = "rfbVencryptX509None"; +		if (ival == rfbVencryptX509Vnc)   st = "rfbVencryptX509Vnc"; +		if (ival == rfbVencryptX509Plain) st = "rfbVencryptX509Plain"; +		rfbLog("vencrypt: client selected sub-type: %d (%s)\n", ival, st); +	} + +	vencrypt_selected = ival; + +	/* not documented in spec, send OK: */ +	buf[0] = 1; +	if (!write_exact(s_out, buf, 1)) { +		close(s_in); close(s_out); +		return 0; +	} + +	if (vencrypt_selected == rfbVencryptTlsNone || +	    vencrypt_selected == rfbVencryptTlsVnc  || +	    vencrypt_selected == rfbVencryptTlsPlain) { +		/* these modes are Anonymous Diffie-Hellman */ +		if (!switch_to_anon_dh()) { +			rfbLog("vencrypt: Anonymous Diffie-Hellman failed.\n");	 +			return 0; +		} +	} + +	/* continue with SSL/TLS */ +	return 1; +} + +static int check_vnc_tls_mode(int s_in, int s_out) { +	double waited = 0.0, dt = 0.01, start = dnow(); +	struct timeval tv; +	int input = 0, i, n, ok; +	int major, minor, sectype = -1; +	char *proto = "RFB 003.008\n"; +	char *stype = "unknown"; +	char buf[256]; +	 +	vencrypt_selected = 0; +	tlsvnc_selected = 0; + +	if (vencrypt_mode == VENCRYPT_NONE && tlsvnc_mode == TLSVNC_NONE) { +		/* only normal SSL */ +		return 1; +	} +	if (ssl_client_mode) { +		/* XXX check if this can be done in SSL client mode. */ +		if (vencrypt_mode == VENCRYPT_FORCE || tlsvnc_mode == TLSVNC_FORCE) { +			rfbLog("check_vnc_tls_mode: VENCRYPT_FORCE/TLSVNC_FORCE prevents normal SSL\n"); +			return 0; +		} +		return 1; +	} +	if (ssl_verify && vencrypt_mode != VENCRYPT_FORCE && tlsvnc_mode == TLSVNC_FORCE) { +		rfbLog("check_vnc_tls_mode: Cannot use TLSVNC_FORCE with -sslverify (Anon DH only)\n"); +		/* fallback to normal SSL */ +		return 1; +	} + +	while (waited < 0.7) { +		fd_set rfds; +		FD_ZERO(&rfds); +		FD_SET(s_in, &rfds); +		tv.tv_sec = 0;  +		tv.tv_usec = 0;  +		select(s_in+1, &rfds, NULL, NULL, &tv); +		if (FD_ISSET(s_in, &rfds)) { +			input = 1; +			break; +		} +		usleep((int) (1000 * 1000 * dt)); +		waited += dt; +	} +	rfbLog("check_vnc_tls_mode: waited: %f input: %s\n", dnow() - start, input ? "SSL Handshake" : "(future) RFB Handshake"); + +	if (input) { +		/* got SSL client hello, can only assume normal SSL */ +		if (vencrypt_mode == VENCRYPT_FORCE || tlsvnc_mode == TLSVNC_FORCE) { +			rfbLog("check_vnc_tls_mode: VENCRYPT_FORCE/TLSVNC_FORCE prevents normal SSL\n"); +			return 0; +		} +		return 1; +	} + +	/* send RFB 003.008 -- there is no turning back from this point... */ +	if (!write_exact(s_out, proto, strlen(proto))) { +		close(s_in); close(s_out); +		return 0; +	} + +	memset(buf, 0, sizeof(buf)); +	if (!read_exact(s_in, buf, 12)) { +		close(s_in); close(s_out); +		return 0; +	} + +	if (sscanf(buf, "RFB %03d.%03d\n", &major, &minor) != 2) { +		rfbLog("check_vnc_tls_mode: abnormal handshake: '%s'\n", buf); +		close(s_in); close(s_out); +		return 0; +	} +	rfbLog("check_vnc_tls_mode: version: %d.%d\n", major, minor); +	if (major != 3 || minor < 8) { +		rfbLog("check_vnc_tls_mode: invalid version: '%s'\n", buf); +		close(s_in); close(s_out); +		return 0; +	} + +	n = 1; +	if (vencrypt_mode == VENCRYPT_FORCE) { +		buf[n++] = rfbSecTypeVencrypt; +	} else if (tlsvnc_mode == TLSVNC_FORCE && !ssl_verify) { +		buf[n++] = rfbSecTypeTlsVnc; +	} else if (vencrypt_mode == VENCRYPT_SOLE) { +		buf[n++] = rfbSecTypeVencrypt; +	} else if (tlsvnc_mode == TLSVNC_SOLE && !ssl_verify) { +		buf[n++] = rfbSecTypeTlsVnc; +	} else { +		if (vencrypt_mode == VENCRYPT_SUPPORT) { +			buf[n++] = rfbSecTypeVencrypt; +		} +		if (tlsvnc_mode == TLSVNC_SUPPORT && !ssl_verify) { +			buf[n++] = rfbSecTypeTlsVnc; +		} +	} + +	n--; +	buf[0] = (char) n; +	if (!write_exact(s_out, buf, n+1)) { +		close(s_in); close(s_out); +		return 0; +	} +	if (0) fprintf(stderr, "wrote[%d] %d %d %d\n", n, buf[0], buf[1], buf[2]); + +	buf[0] = 0; +	if (!read_exact(s_in, buf, 1)) { +		close(s_in); close(s_out); +		return 0; +	} + +	if (buf[0] == rfbSecTypeVencrypt) stype = "VeNCrypt"; +	if (buf[0] == rfbSecTypeTlsVnc)   stype = "TLSVNC"; + +	rfbLog("check_vnc_tls_mode: reply: %d (%s)\n", (int) buf[0], stype); + +	ok = 0; +	for (i=1; i < n+1; i++) { +		if (buf[0] == buf[i]) { +			ok = 1; +		} +	} +	if (!ok) { +		char *msg = "check_vnc_tls_mode: invalid security-type"; +		int len = strlen(msg); +		rfbLog("%s: %d\n", msg, (int) buf[0]); +		((uint32_t *)buf)[0] = Swap32IfLE(len); +		write_exact(s_out, buf, 4); +		write_exact(s_out, msg, strlen(msg)); +		close(s_in); close(s_out); +		return 0; +	} + +	sectype = (int) buf[0]; + +	if (sectype == rfbSecTypeVencrypt) { +		return vencrypt_dialog(s_in, s_out); +	} else if (sectype == rfbSecTypeTlsVnc) { +		return tlsvnc_dialog(s_in, s_out); +	} else { +		return 0; +	} +} + +static void pr_ssl_info(int verb) { +	SSL_CIPHER *c; +	SSL_SESSION *s; +	char *proto = "unknown"; + +	if (ssl == NULL) { +		return; +	} +	c = SSL_get_current_cipher(ssl); +	s = SSL_get_session(ssl); + +	if (s == NULL) { +		proto = "nosession"; +	} else if (s->ssl_version == SSL2_VERSION) { +		proto = "SSLv2"; +	} else if (s->ssl_version == SSL3_VERSION) { +		proto = "SSLv3"; +	} else if (s->ssl_version == TLS1_VERSION) { +		proto = "TLSv1"; +	} +	if (c != NULL) { +		rfbLog("SSL: ssl_helper[%d]: Cipher: %s %s Proto: %s\n", getpid(), +		    SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c), proto); +	} else { +		rfbLog("SSL: ssl_helper[%d]: Proto: %s\n", getpid(), +		    proto); +	} +} +  static void ssl_timeout (int sig) {  	rfbLog("sig: %d, ssl_init timed out.\n", sig);  	exit(1); @@ -2110,12 +3112,16 @@ static int ssl_init(int s_in, int s_out) {  	}  	if (db) fprintf(stderr, "ssl_init: %d/%d\n", s_in, s_out); +	if (!check_vnc_tls_mode(s_in, s_out)) { +		return 0; +	} +  	ssl = SSL_new(ctx);  	if (ssl == NULL) {  		fprintf(stderr, "SSL_new failed\n");  		return 0;  	} -if (db > 1) fprintf(stderr, "ssl_init: 1\n"); +	if (db > 1) fprintf(stderr, "ssl_init: 1\n");  	SSL_set_session_id_context(ssl, sid, strlen((char *)sid)); @@ -2134,7 +3140,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 1\n");  			return 0;  		}  	} -if (db > 1) fprintf(stderr, "ssl_init: 2\n"); +	if (db > 1) fprintf(stderr, "ssl_init: 2\n");  	if (ssl_client_mode) {  		SSL_set_connect_state(ssl); @@ -2142,12 +3148,12 @@ if (db > 1) fprintf(stderr, "ssl_init: 2\n");  		SSL_set_accept_state(ssl);  	} -if (db > 1) fprintf(stderr, "ssl_init: 3\n"); +	if (db > 1) fprintf(stderr, "ssl_init: 3\n");  	name = get_remote_host(ssock);  	peerport = get_remote_port(ssock); -if (db > 1) fprintf(stderr, "ssl_init: 4\n"); +	if (db > 1) fprintf(stderr, "ssl_init: 4\n");  	while (1) {  		if (db) fprintf(stderr, "calling SSL_accept...\n"); @@ -2173,6 +3179,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");  			if (db) fprintf(stderr, "got SSL_ERROR_WANT_READ\n");  			rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n",  			    getpid(), name, peerport); +			pr_ssl_info(1);  			return 0;  		} else if (err == SSL_ERROR_WANT_WRITE) { @@ -2180,6 +3187,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");  			if (db) fprintf(stderr, "got SSL_ERROR_WANT_WRITE\n");  			rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n",  			    getpid(), name, peerport); +			pr_ssl_info(1);  			return 0;  		} else if (err == SSL_ERROR_SYSCALL) { @@ -2187,6 +3195,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");  			if (db) fprintf(stderr, "got SSL_ERROR_SYSCALL\n");  			rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n",  			    getpid(), name, peerport); +			pr_ssl_info(1);  			return 0;  		} else if (err == SSL_ERROR_ZERO_RETURN) { @@ -2194,6 +3203,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");  			if (db) fprintf(stderr, "got SSL_ERROR_ZERO_RETURN\n");  			rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n",  			    getpid(), name, peerport); +			pr_ssl_info(1);  			return 0;  		} else if (rc < 0) { @@ -2207,12 +3217,14 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");  					break;  				}  			} +			pr_ssl_info(1);  			return 0;  		} else if (dnow() > start + 3.0) {  			rfbLog("SSL: ssl_helper[%d]: timeout looping SSL_accept() "  			    "fatal.\n", getpid()); +			pr_ssl_info(1);  			return 0;  		} else { @@ -2220,11 +3232,13 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");  			if (bio == NULL) {  				rfbLog("SSL: ssl_helper[%d]: ssl BIO is null. "  				    "fatal.\n", getpid()); +				pr_ssl_info(1);  				return 0;  			}  			if (BIO_eof(bio)) {  				rfbLog("SSL: ssl_helper[%d]: ssl BIO is EOF. "  				    "fatal.\n", getpid()); +				pr_ssl_info(1);  				return 0;  			}  		} @@ -2233,6 +3247,8 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");  	rfbLog("SSL: ssl_helper[%d]: SSL_accept() succeeded for: %s:%d\n", getpid(), name, peerport); +	pr_ssl_info(0); +  	if (SSL_get_verify_result(ssl) == X509_V_OK) {  		X509 *x;  		FILE *cr = NULL; @@ -2358,6 +3374,14 @@ static void ssl_xfer(int csock, int s_in, int s_out, int is_https) {  	cptr = 0;	/* offsets into ABSIZE buffers */  	sptr = 0; +	if (vencrypt_selected > 0 || tlsvnc_selected > 0) { +		char tmp[16]; +		/* read and discard the extra RFB version */ +		memset(tmp, 0, sizeof(tmp)); +		read(csock, tmp, 12); +		if (0) fprintf(stderr, "extra: %s\n", tmp); +	} +  	while (1) {  		int c_to_s, s_to_c, closing;  | 
