diff options
Diffstat (limited to 'rpcapd/rpcapd.c')
-rw-r--r-- | rpcapd/rpcapd.c | 155 |
1 files changed, 119 insertions, 36 deletions
diff --git a/rpcapd/rpcapd.c b/rpcapd/rpcapd.c index 12a71ab4..76e676c5 100644 --- a/rpcapd/rpcapd.c +++ b/rpcapd/rpcapd.c @@ -90,6 +90,7 @@ static HANDLE state_change_event; //!< event to signal that a state change shou #endif static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration +static int uses_ssl; //!< '1' to use TLS over the data socket extern char *optarg; // for getopt() @@ -148,6 +149,11 @@ static void printusage(void) #ifndef _WIN32 " -i run in inetd mode (UNIX only)\n\n" #endif +#ifdef HAVE_OPENSSL + " -S encrypt all communication with SSL (implements rpcaps://)\n" + " -K <pem_file> uses the SSL private key in this file (default: key.pem)\n" + " -C <pem_file> uses the certificate from this file (default: cert.pem)\n" +#endif " -s <config_file> save the current configuration to file\n\n" " -f <config_file> load the current configuration from file; all switches\n" " specified from the command line are ignored\n\n" @@ -354,10 +360,11 @@ int main(int argc, char *argv[]) signal(SIGPIPE, SIG_IGN); #endif -#ifndef _WIN32 # ifdef HAVE_OPENSSL if (uses_ssl) init_ssl_or_die(1); # endif + +#ifndef _WIN32 if (isrunbyinetd) { // @@ -407,13 +414,26 @@ int main(int argc, char *argv[]) close(devnull_fd); } + SSL *ssl = NULL; +#ifdef HAVE_OPENSSL + if (uses_ssl) + { + ssl = ssl_promotion_rw(1, sockctrl_in, sockctrl_out, errbuf, PCAP_ERRBUF_SIZE); + if (! ssl) + { + rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s", + errbuf); + exit(2); + } + } +#endif // // Handle this client. // This is passive mode, so we don't care whether we were // told by the client to close. // - (void)daemon_serviceloop(sockctrl_in, sockctrl_out, 0, - nullAuthAllowed); + (void)daemon_serviceloop(sockctrl_in, sockctrl_out, ssl, 0, + nullAuthAllowed, uses_ssl); // // Nothing more to do. @@ -1059,6 +1079,22 @@ accept_connections(void) sock_cleanup(); } +#ifdef _WIN32 +// +// A structure to hold the parameter to the windows thread +// (on unix there is no need for this explicit copy since the +// fork "inherits" the parent stack) +// +struct sock_copy { + SOCKET sockctrl; +# ifdef HAVE_OPENSSL + SSL *ssl; +# else + void *ssl; +# endif +}; +#endif + // // Accept a connection and start a worker thread, on Windows, or a // worker process, on UN*X, to handle the connection. @@ -1071,10 +1107,12 @@ accept_connection(SOCKET listen_sock) struct sockaddr_storage from; // generic sockaddr_storage variable socklen_t fromlen; // keeps the length of the sockaddr_storage variable + SSL *ssl = NULL; + #ifdef _WIN32 HANDLE threadId; // handle for the subthread u_long off = 0; - SOCKET *sockctrl_temp; + struct sock_copy *sock_copy = NULL; #else pid_t pid; #endif @@ -1113,15 +1151,29 @@ accept_connection(SOCKET listen_sock) return; } +#ifdef HAVE_OPENSSL + /* We have to upgrade to TLS as soon as possible so that the whole protocol + * goes through the encrypted tunnel, including early error messages. */ + if (uses_ssl) + { + ssl = ssl_promotion(1, sockctrl, errbuf, PCAP_ERRBUF_SIZE); + if (! ssl) + { + rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s", + errbuf); + goto error; + } + } +#endif + // // We have a connection. // Check whether the connecting host is among the ones allowed. // if (sock_check_hostlist(hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0) { - rpcap_senderror(sockctrl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL); - sock_close(sockctrl, NULL, 0); - return; + rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL); + goto error; } #ifdef _WIN32 @@ -1137,16 +1189,14 @@ accept_connection(SOCKET listen_sock) if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR) { sock_geterror("ioctlsocket(FIONBIO): ", errbuf, PCAP_ERRBUF_SIZE); - rpcap_senderror(sockctrl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL); - sock_close(sockctrl, NULL, 0); - return; + rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL); + goto error; } if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR) { sock_geterror("ioctlsocket(FIONBIO): ", errbuf, PCAP_ERRBUF_SIZE); - rpcap_senderror(sockctrl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL); - sock_close(sockctrl, NULL, 0); - return; + rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL); + goto error; } // @@ -1156,26 +1206,24 @@ accept_connection(SOCKET listen_sock) // I guess we *could* just cast sockctrl to a void *, but that's // a bit ugly. // - sockctrl_temp = (SOCKET *)malloc(sizeof (SOCKET)); - if (sockctrl_temp == NULL) + sock_copy = malloc(sizeof(*sock_copy)); + if (sock_copy == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc() failed"); - rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL); - sock_close(sockctrl, NULL, 0); - return; + rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_OPEN, errbuf, NULL); + goto error; } - *sockctrl_temp = sockctrl; + sock_copy->sockctrl = sockctrl; + sock_copy->ssl = NULL; threadId = (HANDLE)_beginthreadex(NULL, 0, - main_passive_serviceloop_thread, (void *) sockctrl_temp, 0, NULL); + main_passive_serviceloop_thread, (void *) sock_copy, 0, NULL); if (threadId == 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the child thread"); - rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL); - sock_close(sockctrl, NULL, 0); - free(sockctrl_temp); - return; + rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_OPEN, errbuf, NULL); + goto error; } CloseHandle(threadId); #else @@ -1183,9 +1231,8 @@ accept_connection(SOCKET listen_sock) if (pid == -1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the child process"); - rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL); - sock_close(sockctrl, NULL, 0); - return; + rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_OPEN, errbuf, NULL); + goto error; } if (pid == 0) { @@ -1216,8 +1263,8 @@ accept_connection(SOCKET listen_sock) // This is passive mode, so we don't care whether we were // told by the client to close. // - (void)daemon_serviceloop(sockctrl, sockctrl, 0, - nullAuthAllowed); + (void)daemon_serviceloop(sockctrl, sockctrl, ssl, 0, + nullAuthAllowed, uses_ssl); close(sockctrl); @@ -1226,8 +1273,25 @@ accept_connection(SOCKET listen_sock) // I am the parent // Close the socket for this session (must be open only in the child) +#ifdef HAVE_OPENSSL + if (ssl) + { + SSL_free(ssl); + ssl = NULL; + } +#endif closesocket(sockctrl); #endif + return; + +error: +#ifdef _WIN32 + if (sock_copy) free(sock_copy); +#endif +#ifdef HAVE_OPENSSL + if (ssl) SSL_free(ssl); // Have to be done before closing soskctrl +#endif + sock_close(sockctrl, NULL, 0); } /*! @@ -1251,6 +1315,7 @@ main_active(void *ptr) struct addrinfo hints; // temporary struct to keep settings needed to open the new socket struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket struct active_pars *activepars; + SSL *ssl = NULL; activepars = (struct active_pars *) ptr; @@ -1295,9 +1360,28 @@ main_active(void *ptr) continue; } - activeclose = daemon_serviceloop(sockctrl, sockctrl, 1, - nullAuthAllowed); +#ifdef HAVE_OPENSSL + /* Even in active mode the other other end has to initiate the TLS handshake + * as we still are the server as far as TLS is concerned: */ + if (uses_ssl) + { + ssl = ssl_promotion(1, sockctrl, errbuf, PCAP_ERRBUF_SIZE); + if (! ssl) + { + rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s", + errbuf); + sock_close(sockctrl, NULL, 0); + continue; + } + } +#endif + + activeclose = daemon_serviceloop(sockctrl, sockctrl, ssl, 1, + nullAuthAllowed, uses_ssl); +#ifdef HAVE_OPENSSL + if (ssl) SSL_free(ssl); +#endif sock_close(sockctrl, NULL, 0); // If the connection is closed by the user explicitely, don't try to connect to it again @@ -1316,9 +1400,7 @@ main_active(void *ptr) // unsigned __stdcall main_passive_serviceloop_thread(void *ptr) { - SOCKET sockctrl; - - sockctrl = *((SOCKET *)ptr); + struct sock_copy sock = *(struct sock_copy *)ptr; free(ptr); // @@ -1326,9 +1408,10 @@ unsigned __stdcall main_passive_serviceloop_thread(void *ptr) // This is passive mode, so we don't care whether we were // told by the client to close. // - (void)daemon_serviceloop(sockctrl, sockctrl, 0, nullAuthAllowed); + (void)daemon_serviceloop(sock.sockctrl, sock.sockctrl, sock.ssl, 0, + nullAuthAllowed, uses_ssl); - sock_close(sockctrl, NULL, 0); + sock_close(sock.sockctrl, NULL, 0); return 0; } |