aboutsummaryrefslogtreecommitdiff
path: root/rpcapd/daemon.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2019-01-07 21:21:20 -0800
committerGuy Harris <guy@alum.mit.edu>2019-01-07 21:21:20 -0800
commit941280a5cd6aefafa79ff4dd032c4467a42c1fd1 (patch)
tree8111ebfb42748bc11661700b92c39504e5d424cb /rpcapd/daemon.c
parenta5f191481140b173ababa9f7dc425ef65bdab739 (diff)
Move the SSL setup and host/port list checking to daemon_serviceloop().
That: 1) arranges that it's done only in one code path; 2) arranges that it not be done in the main connection-accepting thread/process if this isn't an inetd-style daemon; 3) means that we're doing the host/port list checking in inetd-style daemons - we weren't doing it before; 4) means that we're doing both of them after we've turned off non-blocking mode on Windows, not before - doing it before may cause the SSL setup and sending a host/port list check error not to work (as we won't block waiting for input or waiting for buffer space to be available for output). Fix the file descriptor handling for inetd-style daemons while we're at it; we should redirect the standard error to /dev/null - it's not guaranteed to, for example, go to a daemon that reads your error messages and logs them, and it could be going over the connection, which would be a problem. Close the control socket with sock_close() after daemon_serviceloop() returns, in case shutting down the write side is necessary to have the connection shut down cleanly.
Diffstat (limited to 'rpcapd/daemon.c')
-rw-r--r--rpcapd/daemon.c100
1 files changed, 91 insertions, 9 deletions
diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c
index dc92c0ac..88c72b96 100644
--- a/rpcapd/daemon.c
+++ b/rpcapd/daemon.c
@@ -144,11 +144,14 @@ static int rpcapd_discard(SOCKET sock, SSL *, uint32 len);
static void session_close(struct session *);
int
-daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, SSL *ssl, int isactive, int nullAuthAllowed, int uses_ssl)
+daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out,
+ int isactive, char *passiveClients, int nullAuthAllowed, int uses_ssl)
{
struct daemon_slpars pars; // service loop parameters
char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
char errmsgbuf[PCAP_ERRBUF_SIZE + 1]; // buffer for errors to send to the client
+ int host_port_ok;
+ SSL *ssl = NULL;
int nrecv;
struct rpcap_header header; // RPCAP message general header
uint32 plen; // payload length from header
@@ -172,14 +175,6 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, SSL *ssl, int isacti
struct timeval tv; // maximum time the select() can block waiting for data
int retval; // select() return value
- // Set parameters structure
- pars.sockctrl_in = sockctrl_in;
- pars.sockctrl_out = sockctrl_out;
- pars.ssl = ssl;
- pars.protocol_version = 0; // not yet known
- pars.isactive = isactive; // active mode
- pars.nullAuthAllowed = nullAuthAllowed;
-
// We don't have a thread yet.
threaddata.have_thread = 0;
//
@@ -199,6 +194,86 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, SSL *ssl, int isacti
*errbuf = 0; // Initialize errbuf
+#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.
+ //
+ // Even in active mode, the other end has to initiate the TLS
+ // handshake as we still are the server as far as TLS is concerned,
+ // so we don't check isactive.
+ //
+ if (uses_ssl)
+ {
+ ssl = ssl_promotion_rw(1, pars.sockctrl_in, pars.sockctrl_out, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s",
+ errbuf);
+ goto end;
+ }
+ }
+#endif
+
+ // Set parameters structure
+ pars.sockctrl_in = sockctrl_in;
+ pars.sockctrl_out = sockctrl_out;
+ pars.ssl = ssl;
+ pars.protocol_version = 0; // not yet known
+ pars.isactive = isactive; // active mode
+ pars.nullAuthAllowed = nullAuthAllowed;
+
+ //
+ // We have a connection.
+ //
+ // If it's a passive mode connection, check whether the connecting
+ // host is among the ones allowed.
+ //
+ // In either case, we were handed a copy of the host list; free it
+ // as soon as we're done with it.
+ //
+ if (pars.isactive)
+ {
+ // Nothing to do.
+ free(passiveClients);
+ passiveClients = NULL;
+ }
+ else
+ {
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+
+ //
+ // Get the address of the other end of the connection.
+ //
+ fromlen = sizeof(struct sockaddr_storage);
+ if (getpeername(pars.sockctrl_in, (struct sockaddr *)&from,
+ &fromlen) == -1)
+ {
+ sock_geterror("getpeername(): ", errmsgbuf, PCAP_ERRBUF_SIZE);
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
+ rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
+ goto end;
+ }
+
+ //
+ // Are they in the list of host/port combinations we allow?
+ //
+ host_port_ok = (sock_check_hostlist(passiveClients, RPCAP_HOSTLIST_SEP, &from, errmsgbuf, PCAP_ERRBUF_SIZE) == 0);
+ free(passiveClients);
+ passiveClients = NULL;
+ if (!host_port_ok)
+ {
+ //
+ // Sorry, you're not on the guest list.
+ //
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl, 0, PCAP_ERR_HOSTNOAUTH, errmsgbuf, errbuf) == -1)
+ rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
+ goto end;
+ }
+ }
+
//
// The client must first authenticate; loop until they send us a
// message with a version we support and credentials we accept,
@@ -880,6 +955,13 @@ end:
session = NULL;
}
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ SSL_free(ssl);
+ }
+#endif
+
// Print message and return
rpcapd_log(LOGPRIO_DEBUG, "I'm exiting from the child loop");
rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);