157e22627SCy Schubert /*
257e22627SCy Schubert * Copyright (c) 2002 - 2003
357e22627SCy Schubert * NetGroup, Politecnico di Torino (Italy)
457e22627SCy Schubert * All rights reserved.
557e22627SCy Schubert *
657e22627SCy Schubert * Redistribution and use in source and binary forms, with or without
757e22627SCy Schubert * modification, are permitted provided that the following conditions
857e22627SCy Schubert * are met:
957e22627SCy Schubert *
1057e22627SCy Schubert * 1. Redistributions of source code must retain the above copyright
1157e22627SCy Schubert * notice, this list of conditions and the following disclaimer.
1257e22627SCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
1357e22627SCy Schubert * notice, this list of conditions and the following disclaimer in the
1457e22627SCy Schubert * documentation and/or other materials provided with the distribution.
1557e22627SCy Schubert * 3. Neither the name of the Politecnico di Torino nor the names of its
1657e22627SCy Schubert * contributors may be used to endorse or promote products derived from
1757e22627SCy Schubert * this software without specific prior written permission.
1857e22627SCy Schubert *
1957e22627SCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2057e22627SCy Schubert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2157e22627SCy Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2257e22627SCy Schubert * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2357e22627SCy Schubert * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2457e22627SCy Schubert * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2557e22627SCy Schubert * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2657e22627SCy Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2757e22627SCy Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2857e22627SCy Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2957e22627SCy Schubert * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3057e22627SCy Schubert */
3157e22627SCy Schubert
3257e22627SCy Schubert #ifdef HAVE_CONFIG_H
3357e22627SCy Schubert #include <config.h>
3457e22627SCy Schubert #endif
3557e22627SCy Schubert
3657e22627SCy Schubert #include "ftmacros.h"
3757e22627SCy Schubert #include "varattrs.h"
3857e22627SCy Schubert
3957e22627SCy Schubert #include <errno.h> // for the errno variable
4057e22627SCy Schubert #include <stdlib.h> // for malloc(), free(), ...
4157e22627SCy Schubert #include <string.h> // for strlen(), ...
42*6f9cba8fSJoseph Mingrone #include <limits.h> // for INT_MAX
4357e22627SCy Schubert
4457e22627SCy Schubert #ifdef _WIN32
4557e22627SCy Schubert #include <process.h> // for threads
4657e22627SCy Schubert #else
4757e22627SCy Schubert #include <unistd.h>
4857e22627SCy Schubert #include <pthread.h>
4957e22627SCy Schubert #include <signal.h>
5057e22627SCy Schubert #include <sys/time.h>
5157e22627SCy Schubert #include <sys/types.h> // for select() and such
5257e22627SCy Schubert #include <pwd.h> // for password management
5357e22627SCy Schubert #endif
5457e22627SCy Schubert
5557e22627SCy Schubert #ifdef HAVE_GETSPNAM
5657e22627SCy Schubert #include <shadow.h> // for password management
5757e22627SCy Schubert #endif
5857e22627SCy Schubert
5957e22627SCy Schubert #include <pcap.h> // for libpcap/WinPcap calls
6057e22627SCy Schubert
6157e22627SCy Schubert #include "fmtutils.h"
6257e22627SCy Schubert #include "sockutils.h" // for socket calls
6357e22627SCy Schubert #include "portability.h"
6457e22627SCy Schubert #include "rpcap-protocol.h"
6557e22627SCy Schubert #include "daemon.h"
6657e22627SCy Schubert #include "log.h"
6757e22627SCy Schubert
68*6f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
69*6f9cba8fSJoseph Mingrone #include <openssl/ssl.h>
70*6f9cba8fSJoseph Mingrone #include "sslutils.h"
71*6f9cba8fSJoseph Mingrone #endif
72*6f9cba8fSJoseph Mingrone
7357e22627SCy Schubert //
7457e22627SCy Schubert // Timeout, in seconds, when we're waiting for a client to send us an
7557e22627SCy Schubert // authentication request; if they don't send us a request within that
7657e22627SCy Schubert // interval, we drop the connection, so we don't stay stuck forever.
7757e22627SCy Schubert //
7857e22627SCy Schubert #define RPCAP_TIMEOUT_INIT 90
7957e22627SCy Schubert
8057e22627SCy Schubert //
8157e22627SCy Schubert // Timeout, in seconds, when we're waiting for an authenticated client
8257e22627SCy Schubert // to send us a request, if a capture isn't in progress; if they don't
8357e22627SCy Schubert // send us a request within that interval, we drop the connection, so
8457e22627SCy Schubert // we don't stay stuck forever.
8557e22627SCy Schubert //
8657e22627SCy Schubert #define RPCAP_TIMEOUT_RUNTIME 180
8757e22627SCy Schubert
8857e22627SCy Schubert //
8957e22627SCy Schubert // Time, in seconds, that we wait after a failed authentication attempt
9057e22627SCy Schubert // before processing the next request; this prevents a client from
9157e22627SCy Schubert // rapidly trying different accounts or passwords.
9257e22627SCy Schubert //
9357e22627SCy Schubert #define RPCAP_SUSPEND_WRONGAUTH 1
9457e22627SCy Schubert
9557e22627SCy Schubert // Parameters for the service loop.
9657e22627SCy Schubert struct daemon_slpars
9757e22627SCy Schubert {
9857e22627SCy Schubert SOCKET sockctrl; //!< SOCKET ID of the control connection
99*6f9cba8fSJoseph Mingrone SSL *ssl; //!< Optional SSL handler for the controlling sockets
10057e22627SCy Schubert int isactive; //!< Not null if the daemon has to run in active mode
10157e22627SCy Schubert int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise
10257e22627SCy Schubert };
10357e22627SCy Schubert
10457e22627SCy Schubert //
10557e22627SCy Schubert // Data for a session managed by a thread.
10657e22627SCy Schubert // It includes both a Boolean indicating whether we *have* a thread,
10757e22627SCy Schubert // and a platform-dependent (UN*X vs. Windows) identifier for the
10857e22627SCy Schubert // thread; on Windows, we could use an invalid handle to indicate
10957e22627SCy Schubert // that we don't have a thread, but there *is* no portable "no thread"
11057e22627SCy Schubert // value for a pthread_t on UN*X.
11157e22627SCy Schubert //
11257e22627SCy Schubert struct session {
11357e22627SCy Schubert SOCKET sockctrl;
11457e22627SCy Schubert SOCKET sockdata;
115*6f9cba8fSJoseph Mingrone SSL *ctrl_ssl, *data_ssl; // optional SSL handlers for sockctrl and sockdata.
11657e22627SCy Schubert uint8 protocol_version;
11757e22627SCy Schubert pcap_t *fp;
11857e22627SCy Schubert unsigned int TotCapt;
11957e22627SCy Schubert int have_thread;
12057e22627SCy Schubert #ifdef _WIN32
12157e22627SCy Schubert HANDLE thread;
12257e22627SCy Schubert #else
12357e22627SCy Schubert pthread_t thread;
12457e22627SCy Schubert #endif
12557e22627SCy Schubert };
12657e22627SCy Schubert
12757e22627SCy Schubert // Locally defined functions
128*6f9cba8fSJoseph Mingrone static int daemon_msg_err(SOCKET sockctrl, SSL *, uint32 plen);
12957e22627SCy Schubert static int daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen);
13057e22627SCy Schubert static int daemon_AuthUserPwd(char *username, char *password, char *errbuf);
13157e22627SCy Schubert
13257e22627SCy Schubert static int daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars,
13357e22627SCy Schubert uint32 plen);
13457e22627SCy Schubert
13557e22627SCy Schubert static int daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars,
13657e22627SCy Schubert uint32 plen, char *source, size_t sourcelen);
13757e22627SCy Schubert static int daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars,
13857e22627SCy Schubert uint32 plen, char *source, struct session **sessionp,
139*6f9cba8fSJoseph Mingrone struct rpcap_sampling *samp_param, int uses_ssl);
14057e22627SCy Schubert static int daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars,
14157e22627SCy Schubert struct session *session);
14257e22627SCy Schubert
14357e22627SCy Schubert static int daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
14457e22627SCy Schubert struct session *session, uint32 plen);
145*6f9cba8fSJoseph Mingrone static int daemon_unpackapplyfilter(SOCKET sockctrl, SSL *, struct session *session, uint32 *plenp, char *errbuf);
14657e22627SCy Schubert
14757e22627SCy Schubert static int daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
14857e22627SCy Schubert struct session *session, uint32 plen, struct pcap_stat *stats,
14957e22627SCy Schubert unsigned int svrcapt);
15057e22627SCy Schubert
15157e22627SCy Schubert static int daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars,
15257e22627SCy Schubert uint32 plen, struct rpcap_sampling *samp_param);
15357e22627SCy Schubert
15457e22627SCy Schubert static void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout);
15557e22627SCy Schubert #ifdef _WIN32
15657e22627SCy Schubert static unsigned __stdcall daemon_thrdatamain(void *ptr);
15757e22627SCy Schubert #else
15857e22627SCy Schubert static void *daemon_thrdatamain(void *ptr);
15957e22627SCy Schubert static void noop_handler(int sign);
16057e22627SCy Schubert #endif
16157e22627SCy Schubert
162*6f9cba8fSJoseph Mingrone static int rpcapd_recv_msg_header(SOCKET sock, SSL *, struct rpcap_header *headerp);
163*6f9cba8fSJoseph Mingrone static int rpcapd_recv(SOCKET sock, SSL *, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf);
164*6f9cba8fSJoseph Mingrone static int rpcapd_discard(SOCKET sock, SSL *, uint32 len);
16557e22627SCy Schubert static void session_close(struct session *);
16657e22627SCy Schubert
167*6f9cba8fSJoseph Mingrone //
168*6f9cba8fSJoseph Mingrone // TLS record layer header; used when processing the first message from
169*6f9cba8fSJoseph Mingrone // the client, in case we aren't doing TLS but they are.
170*6f9cba8fSJoseph Mingrone //
171*6f9cba8fSJoseph Mingrone struct tls_record_header {
172*6f9cba8fSJoseph Mingrone uint8 type; // ContentType - will be 22, for Handshake
173*6f9cba8fSJoseph Mingrone uint8 version_major; // TLS protocol major version
174*6f9cba8fSJoseph Mingrone uint8 version_injor; // TLS protocol minor version
175*6f9cba8fSJoseph Mingrone // This is *not* aligned on a 2-byte boundary; we just
176*6f9cba8fSJoseph Mingrone // declare it as two bytes. Don't assume any particular
177*6f9cba8fSJoseph Mingrone // compiler's mechanism for saying "packed"!
178*6f9cba8fSJoseph Mingrone uint8 length_hi; // Upper 8 bits of payload length
179*6f9cba8fSJoseph Mingrone uint8 length_lo; // Low 8 bits of payload length
180*6f9cba8fSJoseph Mingrone };
181*6f9cba8fSJoseph Mingrone
182*6f9cba8fSJoseph Mingrone #define TLS_RECORD_HEADER_LEN 5 // Don't use sizeof in case it's padded
183*6f9cba8fSJoseph Mingrone
184*6f9cba8fSJoseph Mingrone #define TLS_RECORD_TYPE_ALERT 21
185*6f9cba8fSJoseph Mingrone #define TLS_RECORD_TYPE_HANDSHAKE 22
186*6f9cba8fSJoseph Mingrone
187*6f9cba8fSJoseph Mingrone //
188*6f9cba8fSJoseph Mingrone // TLS alert message.
189*6f9cba8fSJoseph Mingrone //
190*6f9cba8fSJoseph Mingrone struct tls_alert {
191*6f9cba8fSJoseph Mingrone uint8 alert_level;
192*6f9cba8fSJoseph Mingrone uint8 alert_description;
193*6f9cba8fSJoseph Mingrone };
194*6f9cba8fSJoseph Mingrone
195*6f9cba8fSJoseph Mingrone #define TLS_ALERT_LEN 2
196*6f9cba8fSJoseph Mingrone
197*6f9cba8fSJoseph Mingrone #define TLS_ALERT_LEVEL_FATAL 2
198*6f9cba8fSJoseph Mingrone #define TLS_ALERT_HANDSHAKE_FAILURE 40
199*6f9cba8fSJoseph Mingrone
20057e22627SCy Schubert static int is_url(const char *source);
20157e22627SCy Schubert
202*6f9cba8fSJoseph Mingrone /*
203*6f9cba8fSJoseph Mingrone * Maximum sizes for fixed-bit-width values.
204*6f9cba8fSJoseph Mingrone */
205*6f9cba8fSJoseph Mingrone #ifndef UINT16_MAX
206*6f9cba8fSJoseph Mingrone #define UINT16_MAX 65535U
207*6f9cba8fSJoseph Mingrone #endif
208*6f9cba8fSJoseph Mingrone
209*6f9cba8fSJoseph Mingrone #ifndef UINT32_MAX
210*6f9cba8fSJoseph Mingrone #define UINT32_MAX 4294967295U
211*6f9cba8fSJoseph Mingrone #endif
212*6f9cba8fSJoseph Mingrone
21357e22627SCy Schubert int
daemon_serviceloop(SOCKET sockctrl,int isactive,char * passiveClients,int nullAuthAllowed,int uses_ssl)21457e22627SCy Schubert daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
215*6f9cba8fSJoseph Mingrone int nullAuthAllowed, int uses_ssl)
21657e22627SCy Schubert {
217*6f9cba8fSJoseph Mingrone uint8 first_octet;
218*6f9cba8fSJoseph Mingrone struct tls_record_header tls_header;
219*6f9cba8fSJoseph Mingrone struct tls_alert tls_alert;
22057e22627SCy Schubert struct daemon_slpars pars; // service loop parameters
22157e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
22257e22627SCy Schubert char errmsgbuf[PCAP_ERRBUF_SIZE + 1]; // buffer for errors to send to the client
22357e22627SCy Schubert int host_port_check_status;
224*6f9cba8fSJoseph Mingrone SSL *ssl = NULL;
22557e22627SCy Schubert int nrecv;
22657e22627SCy Schubert struct rpcap_header header; // RPCAP message general header
22757e22627SCy Schubert uint32 plen; // payload length from header
22857e22627SCy Schubert int authenticated = 0; // 1 if the client has successfully authenticated
22957e22627SCy Schubert char source[PCAP_BUF_SIZE+1]; // keeps the string that contains the interface to open
23057e22627SCy Schubert int got_source = 0; // 1 if we've gotten the source from an open request
23157e22627SCy Schubert #ifndef _WIN32
23257e22627SCy Schubert struct sigaction action;
23357e22627SCy Schubert #endif
23457e22627SCy Schubert struct session *session = NULL; // struct session main variable
23557e22627SCy Schubert const char *msg_type_string; // string for message type
23657e22627SCy Schubert int client_told_us_to_close = 0; // 1 if the client told us to close the capture
23757e22627SCy Schubert
23857e22627SCy Schubert // needed to save the values of the statistics
23957e22627SCy Schubert struct pcap_stat stats;
24057e22627SCy Schubert unsigned int svrcapt;
24157e22627SCy Schubert
24257e22627SCy Schubert struct rpcap_sampling samp_param; // in case sampling has been requested
24357e22627SCy Schubert
24457e22627SCy Schubert // Structures needed for the select() call
24557e22627SCy Schubert fd_set rfds; // set of socket descriptors we have to check
24657e22627SCy Schubert struct timeval tv; // maximum time the select() can block waiting for data
24757e22627SCy Schubert int retval; // select() return value
24857e22627SCy Schubert
24957e22627SCy Schubert *errbuf = 0; // Initialize errbuf
25057e22627SCy Schubert
251*6f9cba8fSJoseph Mingrone //
252*6f9cba8fSJoseph Mingrone // Peek into the socket to determine whether the client sent us
253*6f9cba8fSJoseph Mingrone // a TLS handshake message or a non-TLS rpcapd message.
254*6f9cba8fSJoseph Mingrone //
255*6f9cba8fSJoseph Mingrone // The first byte of an rpcapd request is the version number;
256*6f9cba8fSJoseph Mingrone // the first byte of a TLS handshake message is 22. The
257*6f9cba8fSJoseph Mingrone // first request to an rpcapd server must be an authentication
258*6f9cba8fSJoseph Mingrone // request or a close request, and must have a version number
259*6f9cba8fSJoseph Mingrone // of 0, so it will be possible to distinguish between an
260*6f9cba8fSJoseph Mingrone // initial plaintext request to a server and an initial TLS
261*6f9cba8fSJoseph Mingrone // handshake message.
262*6f9cba8fSJoseph Mingrone //
263*6f9cba8fSJoseph Mingrone nrecv = sock_recv(sockctrl, NULL, (char *)&first_octet, 1,
264*6f9cba8fSJoseph Mingrone SOCK_EOF_ISNT_ERROR|SOCK_MSG_PEEK, errbuf, PCAP_ERRBUF_SIZE);
265*6f9cba8fSJoseph Mingrone if (nrecv == -1)
266*6f9cba8fSJoseph Mingrone {
267*6f9cba8fSJoseph Mingrone // Fatal error.
268*6f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR, "Peek from client failed: %s", errbuf);
269*6f9cba8fSJoseph Mingrone goto end;
270*6f9cba8fSJoseph Mingrone }
271*6f9cba8fSJoseph Mingrone if (nrecv == 0)
272*6f9cba8fSJoseph Mingrone {
273*6f9cba8fSJoseph Mingrone // Client closed the connection.
274*6f9cba8fSJoseph Mingrone goto end;
275*6f9cba8fSJoseph Mingrone }
276*6f9cba8fSJoseph Mingrone
277*6f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
278*6f9cba8fSJoseph Mingrone //
279*6f9cba8fSJoseph Mingrone // We have to upgrade to TLS as soon as possible, so that the
280*6f9cba8fSJoseph Mingrone // whole protocol goes through the encrypted tunnel, including
281*6f9cba8fSJoseph Mingrone // early error messages.
282*6f9cba8fSJoseph Mingrone //
283*6f9cba8fSJoseph Mingrone // Even in active mode, the other end has to initiate the TLS
284*6f9cba8fSJoseph Mingrone // handshake as we still are the server as far as TLS is concerned,
285*6f9cba8fSJoseph Mingrone // so we don't check isactive.
286*6f9cba8fSJoseph Mingrone //
287*6f9cba8fSJoseph Mingrone if (uses_ssl)
288*6f9cba8fSJoseph Mingrone {
289*6f9cba8fSJoseph Mingrone //
290*6f9cba8fSJoseph Mingrone // We're expecting a TLS handshake message. If this
291*6f9cba8fSJoseph Mingrone // isn't one, assume it's a non-TLS rpcapd message.
292*6f9cba8fSJoseph Mingrone //
293*6f9cba8fSJoseph Mingrone // The first octet of a TLS handshake is
294*6f9cba8fSJoseph Mingrone // TLS_RECORD_TYPE_HANDSHAKE.
295*6f9cba8fSJoseph Mingrone //
296*6f9cba8fSJoseph Mingrone if (first_octet != TLS_RECORD_TYPE_HANDSHAKE)
297*6f9cba8fSJoseph Mingrone {
298*6f9cba8fSJoseph Mingrone //
299*6f9cba8fSJoseph Mingrone // We assume this is a non-TLS rpcapd message.
300*6f9cba8fSJoseph Mingrone //
301*6f9cba8fSJoseph Mingrone // Read the message header from the client.
302*6f9cba8fSJoseph Mingrone //
303*6f9cba8fSJoseph Mingrone nrecv = rpcapd_recv_msg_header(sockctrl, NULL, &header);
304*6f9cba8fSJoseph Mingrone if (nrecv == -1)
305*6f9cba8fSJoseph Mingrone {
306*6f9cba8fSJoseph Mingrone // Fatal error.
307*6f9cba8fSJoseph Mingrone goto end;
308*6f9cba8fSJoseph Mingrone }
309*6f9cba8fSJoseph Mingrone if (nrecv == -2)
310*6f9cba8fSJoseph Mingrone {
311*6f9cba8fSJoseph Mingrone // Client closed the connection.
312*6f9cba8fSJoseph Mingrone goto end;
313*6f9cba8fSJoseph Mingrone }
314*6f9cba8fSJoseph Mingrone plen = header.plen;
315*6f9cba8fSJoseph Mingrone
316*6f9cba8fSJoseph Mingrone // Discard the rest of the message.
317*6f9cba8fSJoseph Mingrone if (rpcapd_discard(sockctrl, NULL, plen) == -1)
318*6f9cba8fSJoseph Mingrone {
319*6f9cba8fSJoseph Mingrone // Network error.
320*6f9cba8fSJoseph Mingrone goto end;
321*6f9cba8fSJoseph Mingrone }
322*6f9cba8fSJoseph Mingrone
323*6f9cba8fSJoseph Mingrone //
324*6f9cba8fSJoseph Mingrone // Send an authentication error, indicating
325*6f9cba8fSJoseph Mingrone // that we require TLS.
326*6f9cba8fSJoseph Mingrone //
327*6f9cba8fSJoseph Mingrone if (rpcap_senderror(sockctrl, NULL, header.ver,
328*6f9cba8fSJoseph Mingrone PCAP_ERR_TLS_REQUIRED,
329*6f9cba8fSJoseph Mingrone "TLS is required by this server", errbuf) == -1)
330*6f9cba8fSJoseph Mingrone {
331*6f9cba8fSJoseph Mingrone // That failed; log a message and give up.
332*6f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
333*6f9cba8fSJoseph Mingrone goto end;
334*6f9cba8fSJoseph Mingrone }
335*6f9cba8fSJoseph Mingrone
336*6f9cba8fSJoseph Mingrone // Shut the session down.
337*6f9cba8fSJoseph Mingrone goto end;
338*6f9cba8fSJoseph Mingrone }
339*6f9cba8fSJoseph Mingrone ssl = ssl_promotion(1, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
340*6f9cba8fSJoseph Mingrone if (! ssl)
341*6f9cba8fSJoseph Mingrone {
342*6f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s",
343*6f9cba8fSJoseph Mingrone errbuf);
344*6f9cba8fSJoseph Mingrone goto end;
345*6f9cba8fSJoseph Mingrone }
346*6f9cba8fSJoseph Mingrone }
347*6f9cba8fSJoseph Mingrone else
348*6f9cba8fSJoseph Mingrone #endif
349*6f9cba8fSJoseph Mingrone {
350*6f9cba8fSJoseph Mingrone //
351*6f9cba8fSJoseph Mingrone // We're expecting a non-TLS rpcapd message. If this
352*6f9cba8fSJoseph Mingrone // looks, instead, like a TLS handshake message, send
353*6f9cba8fSJoseph Mingrone // a TLS handshake_failed alert.
354*6f9cba8fSJoseph Mingrone //
355*6f9cba8fSJoseph Mingrone // The first octet of a TLS handshake is
356*6f9cba8fSJoseph Mingrone // TLS_RECORD_TYPE_HANDSHAKE.
357*6f9cba8fSJoseph Mingrone //
358*6f9cba8fSJoseph Mingrone if (first_octet == TLS_RECORD_TYPE_HANDSHAKE)
359*6f9cba8fSJoseph Mingrone {
360*6f9cba8fSJoseph Mingrone //
361*6f9cba8fSJoseph Mingrone // TLS handshake.
362*6f9cba8fSJoseph Mingrone // Read the record header.
363*6f9cba8fSJoseph Mingrone //
364*6f9cba8fSJoseph Mingrone nrecv = sock_recv(sockctrl, ssl, (char *) &tls_header,
365*6f9cba8fSJoseph Mingrone sizeof tls_header, SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR,
366*6f9cba8fSJoseph Mingrone errbuf, PCAP_ERRBUF_SIZE);
367*6f9cba8fSJoseph Mingrone if (nrecv == -1)
368*6f9cba8fSJoseph Mingrone {
369*6f9cba8fSJoseph Mingrone // Network error.
370*6f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
371*6f9cba8fSJoseph Mingrone goto end;
372*6f9cba8fSJoseph Mingrone }
373*6f9cba8fSJoseph Mingrone if (nrecv == 0)
374*6f9cba8fSJoseph Mingrone {
375*6f9cba8fSJoseph Mingrone // Immediate EOF
376*6f9cba8fSJoseph Mingrone goto end;
377*6f9cba8fSJoseph Mingrone }
378*6f9cba8fSJoseph Mingrone plen = (tls_header.length_hi << 8U) | tls_header.length_lo;
379*6f9cba8fSJoseph Mingrone
380*6f9cba8fSJoseph Mingrone // Discard the rest of the message.
381*6f9cba8fSJoseph Mingrone if (rpcapd_discard(sockctrl, NULL, plen) == -1)
382*6f9cba8fSJoseph Mingrone {
383*6f9cba8fSJoseph Mingrone // Network error.
384*6f9cba8fSJoseph Mingrone goto end;
385*6f9cba8fSJoseph Mingrone }
386*6f9cba8fSJoseph Mingrone
387*6f9cba8fSJoseph Mingrone //
388*6f9cba8fSJoseph Mingrone // Send a TLS handshake failure alert.
389*6f9cba8fSJoseph Mingrone // Use the same version the client sent us.
390*6f9cba8fSJoseph Mingrone //
391*6f9cba8fSJoseph Mingrone tls_header.type = TLS_RECORD_TYPE_ALERT;
392*6f9cba8fSJoseph Mingrone tls_header.length_hi = 0;
393*6f9cba8fSJoseph Mingrone tls_header.length_lo = TLS_ALERT_LEN;
394*6f9cba8fSJoseph Mingrone
395*6f9cba8fSJoseph Mingrone if (sock_send(sockctrl, NULL, (char *) &tls_header,
396*6f9cba8fSJoseph Mingrone TLS_RECORD_HEADER_LEN, errbuf, PCAP_ERRBUF_SIZE) == -1)
397*6f9cba8fSJoseph Mingrone {
398*6f9cba8fSJoseph Mingrone // That failed; log a message and give up.
399*6f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
400*6f9cba8fSJoseph Mingrone goto end;
401*6f9cba8fSJoseph Mingrone }
402*6f9cba8fSJoseph Mingrone
403*6f9cba8fSJoseph Mingrone tls_alert.alert_level = TLS_ALERT_LEVEL_FATAL;
404*6f9cba8fSJoseph Mingrone tls_alert.alert_description = TLS_ALERT_HANDSHAKE_FAILURE;
405*6f9cba8fSJoseph Mingrone if (sock_send(sockctrl, NULL, (char *) &tls_alert,
406*6f9cba8fSJoseph Mingrone TLS_ALERT_LEN, errbuf, PCAP_ERRBUF_SIZE) == -1)
407*6f9cba8fSJoseph Mingrone {
408*6f9cba8fSJoseph Mingrone // That failed; log a message and give up.
409*6f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
410*6f9cba8fSJoseph Mingrone goto end;
411*6f9cba8fSJoseph Mingrone }
412*6f9cba8fSJoseph Mingrone //
413*6f9cba8fSJoseph Mingrone // Give up anyway.
414*6f9cba8fSJoseph Mingrone //
415*6f9cba8fSJoseph Mingrone goto end;
416*6f9cba8fSJoseph Mingrone }
417*6f9cba8fSJoseph Mingrone }
418*6f9cba8fSJoseph Mingrone
41957e22627SCy Schubert // Set parameters structure
42057e22627SCy Schubert pars.sockctrl = sockctrl;
421*6f9cba8fSJoseph Mingrone pars.ssl = ssl;
42257e22627SCy Schubert pars.isactive = isactive; // active mode
42357e22627SCy Schubert pars.nullAuthAllowed = nullAuthAllowed;
42457e22627SCy Schubert
42557e22627SCy Schubert //
42657e22627SCy Schubert // We have a connection.
42757e22627SCy Schubert //
42857e22627SCy Schubert // If it's a passive mode connection, check whether the connecting
42957e22627SCy Schubert // host is among the ones allowed.
43057e22627SCy Schubert //
43157e22627SCy Schubert // In either case, we were handed a copy of the host list; free it
43257e22627SCy Schubert // as soon as we're done with it.
43357e22627SCy Schubert //
43457e22627SCy Schubert if (pars.isactive)
43557e22627SCy Schubert {
43657e22627SCy Schubert // Nothing to do.
43757e22627SCy Schubert free(passiveClients);
43857e22627SCy Schubert passiveClients = NULL;
43957e22627SCy Schubert }
44057e22627SCy Schubert else
44157e22627SCy Schubert {
44257e22627SCy Schubert struct sockaddr_storage from;
44357e22627SCy Schubert socklen_t fromlen;
44457e22627SCy Schubert
44557e22627SCy Schubert //
44657e22627SCy Schubert // Get the address of the other end of the connection.
44757e22627SCy Schubert //
44857e22627SCy Schubert fromlen = sizeof(struct sockaddr_storage);
44957e22627SCy Schubert if (getpeername(pars.sockctrl, (struct sockaddr *)&from,
45057e22627SCy Schubert &fromlen) == -1)
45157e22627SCy Schubert {
452*6f9cba8fSJoseph Mingrone sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE,
453*6f9cba8fSJoseph Mingrone "getpeername() failed");
454*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
45557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
45657e22627SCy Schubert goto end;
45757e22627SCy Schubert }
45857e22627SCy Schubert
45957e22627SCy Schubert //
46057e22627SCy Schubert // Are they in the list of host/port combinations we allow?
46157e22627SCy Schubert //
46257e22627SCy Schubert host_port_check_status = sock_check_hostlist(passiveClients, RPCAP_HOSTLIST_SEP, &from, errmsgbuf, PCAP_ERRBUF_SIZE);
46357e22627SCy Schubert free(passiveClients);
46457e22627SCy Schubert passiveClients = NULL;
46557e22627SCy Schubert if (host_port_check_status < 0)
46657e22627SCy Schubert {
46757e22627SCy Schubert if (host_port_check_status == -2) {
46857e22627SCy Schubert //
46957e22627SCy Schubert // We got an error; log it.
47057e22627SCy Schubert //
47157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf);
47257e22627SCy Schubert }
47357e22627SCy Schubert
47457e22627SCy Schubert //
47557e22627SCy Schubert // Sorry, we can't let you in.
47657e22627SCy Schubert //
477*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_HOSTNOAUTH, errmsgbuf, errbuf) == -1)
47857e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
47957e22627SCy Schubert goto end;
48057e22627SCy Schubert }
48157e22627SCy Schubert }
48257e22627SCy Schubert
48357e22627SCy Schubert #ifndef _WIN32
48457e22627SCy Schubert //
48557e22627SCy Schubert // Catch SIGUSR1, but do nothing. We use it to interrupt the
48657e22627SCy Schubert // capture thread to break it out of a loop in which it's
48757e22627SCy Schubert // blocked waiting for packets to arrive.
48857e22627SCy Schubert //
48957e22627SCy Schubert // We don't want interrupted system calls to restart, so that
49057e22627SCy Schubert // the read routine for the pcap_t gets EINTR rather than
49157e22627SCy Schubert // restarting if it's blocked in a system call.
49257e22627SCy Schubert //
49357e22627SCy Schubert memset(&action, 0, sizeof (action));
49457e22627SCy Schubert action.sa_handler = noop_handler;
49557e22627SCy Schubert action.sa_flags = 0;
49657e22627SCy Schubert sigemptyset(&action.sa_mask);
49757e22627SCy Schubert sigaction(SIGUSR1, &action, NULL);
49857e22627SCy Schubert #endif
49957e22627SCy Schubert
50057e22627SCy Schubert //
50157e22627SCy Schubert // The client must first authenticate; loop until they send us a
50257e22627SCy Schubert // message with a version we support and credentials we accept,
50357e22627SCy Schubert // they send us a close message indicating that they're giving up,
50457e22627SCy Schubert // or we get a network error or other fatal error.
50557e22627SCy Schubert //
50657e22627SCy Schubert while (!authenticated)
50757e22627SCy Schubert {
50857e22627SCy Schubert //
50957e22627SCy Schubert // If we're not in active mode, we use select(), with a
51057e22627SCy Schubert // timeout, to wait for an authentication request; if
51157e22627SCy Schubert // the timeout expires, we drop the connection, so that
51257e22627SCy Schubert // a client can't just connect to us and leave us
51357e22627SCy Schubert // waiting forever.
51457e22627SCy Schubert //
51557e22627SCy Schubert if (!pars.isactive)
51657e22627SCy Schubert {
51757e22627SCy Schubert FD_ZERO(&rfds);
51857e22627SCy Schubert // We do not have to block here
51957e22627SCy Schubert tv.tv_sec = RPCAP_TIMEOUT_INIT;
52057e22627SCy Schubert tv.tv_usec = 0;
52157e22627SCy Schubert
52257e22627SCy Schubert FD_SET(pars.sockctrl, &rfds);
52357e22627SCy Schubert
524*6f9cba8fSJoseph Mingrone retval = select((int)pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
52557e22627SCy Schubert if (retval == -1)
52657e22627SCy Schubert {
527*6f9cba8fSJoseph Mingrone sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE,
528*6f9cba8fSJoseph Mingrone "select() failed");
529*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
53057e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
53157e22627SCy Schubert goto end;
53257e22627SCy Schubert }
53357e22627SCy Schubert
53457e22627SCy Schubert // The timeout has expired
53557e22627SCy Schubert // So, this was a fake connection. Drop it down
53657e22627SCy Schubert if (retval == 0)
53757e22627SCy Schubert {
538*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1)
53957e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
54057e22627SCy Schubert goto end;
54157e22627SCy Schubert }
54257e22627SCy Schubert }
54357e22627SCy Schubert
54457e22627SCy Schubert //
54557e22627SCy Schubert // Read the message header from the client.
54657e22627SCy Schubert //
547*6f9cba8fSJoseph Mingrone nrecv = rpcapd_recv_msg_header(pars.sockctrl, pars.ssl, &header);
54857e22627SCy Schubert if (nrecv == -1)
54957e22627SCy Schubert {
55057e22627SCy Schubert // Fatal error.
55157e22627SCy Schubert goto end;
55257e22627SCy Schubert }
55357e22627SCy Schubert if (nrecv == -2)
55457e22627SCy Schubert {
55557e22627SCy Schubert // Client closed the connection.
55657e22627SCy Schubert goto end;
55757e22627SCy Schubert }
55857e22627SCy Schubert
55957e22627SCy Schubert plen = header.plen;
56057e22627SCy Schubert
56157e22627SCy Schubert //
56257e22627SCy Schubert // While we're in the authentication pharse, all requests
56357e22627SCy Schubert // must use version 0.
56457e22627SCy Schubert //
56557e22627SCy Schubert if (header.ver != 0)
56657e22627SCy Schubert {
56757e22627SCy Schubert //
56857e22627SCy Schubert // Send it back to them with their version.
56957e22627SCy Schubert //
570*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl, header.ver,
57157e22627SCy Schubert PCAP_ERR_WRONGVER,
57257e22627SCy Schubert "RPCAP version in requests in the authentication phase must be 0",
57357e22627SCy Schubert errbuf) == -1)
57457e22627SCy Schubert {
57557e22627SCy Schubert // That failed; log a message and give up.
57657e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
57757e22627SCy Schubert goto end;
57857e22627SCy Schubert }
57957e22627SCy Schubert
58057e22627SCy Schubert // Discard the rest of the message and drop the
58157e22627SCy Schubert // connection.
582*6f9cba8fSJoseph Mingrone (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
58357e22627SCy Schubert goto end;
58457e22627SCy Schubert }
58557e22627SCy Schubert
58657e22627SCy Schubert switch (header.type)
58757e22627SCy Schubert {
58857e22627SCy Schubert case RPCAP_MSG_AUTH_REQ:
58957e22627SCy Schubert retval = daemon_msg_auth_req(&pars, plen);
59057e22627SCy Schubert if (retval == -1)
59157e22627SCy Schubert {
59257e22627SCy Schubert // Fatal error; a message has
59357e22627SCy Schubert // been logged, so just give up.
59457e22627SCy Schubert goto end;
59557e22627SCy Schubert }
59657e22627SCy Schubert if (retval == -2)
59757e22627SCy Schubert {
59857e22627SCy Schubert // Non-fatal error; we sent back
59957e22627SCy Schubert // an error message, so let them
60057e22627SCy Schubert // try again.
60157e22627SCy Schubert continue;
60257e22627SCy Schubert }
60357e22627SCy Schubert
60457e22627SCy Schubert // OK, we're authenticated; we sent back
60557e22627SCy Schubert // a reply, so start serving requests.
60657e22627SCy Schubert authenticated = 1;
60757e22627SCy Schubert break;
60857e22627SCy Schubert
60957e22627SCy Schubert case RPCAP_MSG_CLOSE:
61057e22627SCy Schubert //
61157e22627SCy Schubert // The client is giving up.
61257e22627SCy Schubert // Discard the rest of the message, if
61357e22627SCy Schubert // there is anything more.
61457e22627SCy Schubert //
615*6f9cba8fSJoseph Mingrone (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
61657e22627SCy Schubert // We're done with this client.
61757e22627SCy Schubert goto end;
61857e22627SCy Schubert
61957e22627SCy Schubert case RPCAP_MSG_ERROR:
62057e22627SCy Schubert // Log this and close the connection?
62157e22627SCy Schubert // XXX - is this what happens in active
62257e22627SCy Schubert // mode, where *we* initiate the
62357e22627SCy Schubert // connection, and the client gives us
62457e22627SCy Schubert // an error message rather than a "let
62557e22627SCy Schubert // me log in" message, indicating that
62657e22627SCy Schubert // we're not allowed to connect to them?
627*6f9cba8fSJoseph Mingrone (void)daemon_msg_err(pars.sockctrl, pars.ssl, plen);
62857e22627SCy Schubert goto end;
62957e22627SCy Schubert
63057e22627SCy Schubert case RPCAP_MSG_FINDALLIF_REQ:
63157e22627SCy Schubert case RPCAP_MSG_OPEN_REQ:
63257e22627SCy Schubert case RPCAP_MSG_STARTCAP_REQ:
63357e22627SCy Schubert case RPCAP_MSG_UPDATEFILTER_REQ:
63457e22627SCy Schubert case RPCAP_MSG_STATS_REQ:
63557e22627SCy Schubert case RPCAP_MSG_ENDCAP_REQ:
63657e22627SCy Schubert case RPCAP_MSG_SETSAMPLING_REQ:
63757e22627SCy Schubert //
63857e22627SCy Schubert // These requests can't be sent until
63957e22627SCy Schubert // the client is authenticated.
64057e22627SCy Schubert //
64157e22627SCy Schubert msg_type_string = rpcap_msg_type_string(header.type);
64257e22627SCy Schubert if (msg_type_string != NULL)
64357e22627SCy Schubert {
644*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s request sent before authentication was completed", msg_type_string);
64557e22627SCy Schubert }
64657e22627SCy Schubert else
64757e22627SCy Schubert {
648*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type);
64957e22627SCy Schubert }
650*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
651*6f9cba8fSJoseph Mingrone header.ver, PCAP_ERR_WRONGMSG,
652*6f9cba8fSJoseph Mingrone errmsgbuf, errbuf) == -1)
65357e22627SCy Schubert {
65457e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
65557e22627SCy Schubert goto end;
65657e22627SCy Schubert }
65757e22627SCy Schubert // Discard the rest of the message.
658*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
65957e22627SCy Schubert {
66057e22627SCy Schubert // Network error.
66157e22627SCy Schubert goto end;
66257e22627SCy Schubert }
66357e22627SCy Schubert break;
66457e22627SCy Schubert
66557e22627SCy Schubert case RPCAP_MSG_PACKET:
66657e22627SCy Schubert case RPCAP_MSG_FINDALLIF_REPLY:
66757e22627SCy Schubert case RPCAP_MSG_OPEN_REPLY:
66857e22627SCy Schubert case RPCAP_MSG_STARTCAP_REPLY:
66957e22627SCy Schubert case RPCAP_MSG_UPDATEFILTER_REPLY:
67057e22627SCy Schubert case RPCAP_MSG_AUTH_REPLY:
67157e22627SCy Schubert case RPCAP_MSG_STATS_REPLY:
67257e22627SCy Schubert case RPCAP_MSG_ENDCAP_REPLY:
67357e22627SCy Schubert case RPCAP_MSG_SETSAMPLING_REPLY:
67457e22627SCy Schubert //
67557e22627SCy Schubert // These are server-to-client messages.
67657e22627SCy Schubert //
67757e22627SCy Schubert msg_type_string = rpcap_msg_type_string(header.type);
67857e22627SCy Schubert if (msg_type_string != NULL)
67957e22627SCy Schubert {
680*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
68157e22627SCy Schubert }
68257e22627SCy Schubert else
68357e22627SCy Schubert {
684*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
68557e22627SCy Schubert }
686*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
687*6f9cba8fSJoseph Mingrone header.ver, PCAP_ERR_WRONGMSG,
688*6f9cba8fSJoseph Mingrone errmsgbuf, errbuf) == -1)
68957e22627SCy Schubert {
69057e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
69157e22627SCy Schubert goto end;
69257e22627SCy Schubert }
69357e22627SCy Schubert // Discard the rest of the message.
694*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
69557e22627SCy Schubert {
69657e22627SCy Schubert // Fatal error.
69757e22627SCy Schubert goto end;
69857e22627SCy Schubert }
69957e22627SCy Schubert break;
70057e22627SCy Schubert
70157e22627SCy Schubert default:
70257e22627SCy Schubert //
70357e22627SCy Schubert // Unknown message type.
70457e22627SCy Schubert //
705*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
706*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
707*6f9cba8fSJoseph Mingrone header.ver, PCAP_ERR_WRONGMSG,
708*6f9cba8fSJoseph Mingrone errmsgbuf, errbuf) == -1)
70957e22627SCy Schubert {
71057e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
71157e22627SCy Schubert goto end;
71257e22627SCy Schubert }
71357e22627SCy Schubert // Discard the rest of the message.
714*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
71557e22627SCy Schubert {
71657e22627SCy Schubert // Fatal error.
71757e22627SCy Schubert goto end;
71857e22627SCy Schubert }
71957e22627SCy Schubert break;
72057e22627SCy Schubert }
72157e22627SCy Schubert }
72257e22627SCy Schubert
72357e22627SCy Schubert //
72457e22627SCy Schubert // OK, the client has authenticated itself, and we can start
72557e22627SCy Schubert // processing regular requests from it.
72657e22627SCy Schubert //
72757e22627SCy Schubert
72857e22627SCy Schubert //
72957e22627SCy Schubert // We don't have any statistics yet.
73057e22627SCy Schubert //
73157e22627SCy Schubert stats.ps_ifdrop = 0;
73257e22627SCy Schubert stats.ps_recv = 0;
73357e22627SCy Schubert stats.ps_drop = 0;
73457e22627SCy Schubert svrcapt = 0;
73557e22627SCy Schubert
73657e22627SCy Schubert //
73757e22627SCy Schubert // Service requests.
73857e22627SCy Schubert //
73957e22627SCy Schubert for (;;)
74057e22627SCy Schubert {
74157e22627SCy Schubert errbuf[0] = 0; // clear errbuf
74257e22627SCy Schubert
74357e22627SCy Schubert // Avoid zombies connections; check if the connection is opens but no commands are performed
74457e22627SCy Schubert // from more than RPCAP_TIMEOUT_RUNTIME
74557e22627SCy Schubert // Conditions:
74657e22627SCy Schubert // - I have to be in normal mode (no active mode)
74757e22627SCy Schubert // - if the device is open, I don't have to be in the middle of a capture (session->sockdata)
74857e22627SCy Schubert // - if the device is closed, I have always to check if a new command arrives
74957e22627SCy Schubert //
75057e22627SCy Schubert // Be carefully: the capture can have been started, but an error occurred (so session != NULL, but
75157e22627SCy Schubert // sockdata is 0
752*6f9cba8fSJoseph Mingrone if ((!pars.isactive) && (session == NULL || session->sockdata == 0))
75357e22627SCy Schubert {
75457e22627SCy Schubert // Check for the initial timeout
75557e22627SCy Schubert FD_ZERO(&rfds);
75657e22627SCy Schubert // We do not have to block here
75757e22627SCy Schubert tv.tv_sec = RPCAP_TIMEOUT_RUNTIME;
75857e22627SCy Schubert tv.tv_usec = 0;
75957e22627SCy Schubert
76057e22627SCy Schubert FD_SET(pars.sockctrl, &rfds);
761*6f9cba8fSJoseph Mingrone #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
762*6f9cba8fSJoseph Mingrone retval = 1;
763*6f9cba8fSJoseph Mingrone #else
764*6f9cba8fSJoseph Mingrone retval = select((int)pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
765*6f9cba8fSJoseph Mingrone #endif
76657e22627SCy Schubert if (retval == -1)
76757e22627SCy Schubert {
768*6f9cba8fSJoseph Mingrone sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE,
769*6f9cba8fSJoseph Mingrone "select() failed");
770*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
771*6f9cba8fSJoseph Mingrone 0, PCAP_ERR_NETW,
772*6f9cba8fSJoseph Mingrone errmsgbuf, errbuf) == -1)
77357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
77457e22627SCy Schubert goto end;
77557e22627SCy Schubert }
77657e22627SCy Schubert
77757e22627SCy Schubert // The timeout has expired
77857e22627SCy Schubert // So, this was a fake connection. Drop it down
77957e22627SCy Schubert if (retval == 0)
78057e22627SCy Schubert {
781*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
782*6f9cba8fSJoseph Mingrone 0, PCAP_ERR_INITTIMEOUT,
78357e22627SCy Schubert "The RPCAP initial timeout has expired",
78457e22627SCy Schubert errbuf) == -1)
78557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
78657e22627SCy Schubert goto end;
78757e22627SCy Schubert }
78857e22627SCy Schubert }
78957e22627SCy Schubert
79057e22627SCy Schubert //
79157e22627SCy Schubert // Read the message header from the client.
79257e22627SCy Schubert //
793*6f9cba8fSJoseph Mingrone nrecv = rpcapd_recv_msg_header(pars.sockctrl, pars.ssl, &header);
79457e22627SCy Schubert if (nrecv == -1)
79557e22627SCy Schubert {
79657e22627SCy Schubert // Fatal error.
79757e22627SCy Schubert goto end;
79857e22627SCy Schubert }
79957e22627SCy Schubert if (nrecv == -2)
80057e22627SCy Schubert {
80157e22627SCy Schubert // Client closed the connection.
80257e22627SCy Schubert goto end;
80357e22627SCy Schubert }
80457e22627SCy Schubert
80557e22627SCy Schubert plen = header.plen;
80657e22627SCy Schubert
80757e22627SCy Schubert //
80857e22627SCy Schubert // Did the client specify a protocol version that we
80957e22627SCy Schubert // support?
81057e22627SCy Schubert //
81157e22627SCy Schubert if (!RPCAP_VERSION_IS_SUPPORTED(header.ver))
81257e22627SCy Schubert {
81357e22627SCy Schubert //
81457e22627SCy Schubert // Tell them it's not a supported version.
81557e22627SCy Schubert // Send the error message with their version,
81657e22627SCy Schubert // so they don't reject it as having the wrong
81757e22627SCy Schubert // version.
81857e22627SCy Schubert //
819*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
82057e22627SCy Schubert header.ver, PCAP_ERR_WRONGVER,
82157e22627SCy Schubert "RPCAP version in message isn't supported by the server",
82257e22627SCy Schubert errbuf) == -1)
82357e22627SCy Schubert {
82457e22627SCy Schubert // That failed; log a message and give up.
82557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
82657e22627SCy Schubert goto end;
82757e22627SCy Schubert }
82857e22627SCy Schubert
82957e22627SCy Schubert // Discard the rest of the message.
830*6f9cba8fSJoseph Mingrone (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
83157e22627SCy Schubert // Give up on them.
83257e22627SCy Schubert goto end;
83357e22627SCy Schubert }
83457e22627SCy Schubert
83557e22627SCy Schubert switch (header.type)
83657e22627SCy Schubert {
83757e22627SCy Schubert case RPCAP_MSG_ERROR: // The other endpoint reported an error
83857e22627SCy Schubert {
839*6f9cba8fSJoseph Mingrone (void)daemon_msg_err(pars.sockctrl, pars.ssl, plen);
84057e22627SCy Schubert // Do nothing; just exit; the error code is already into the errbuf
84157e22627SCy Schubert // XXX - actually exit....
84257e22627SCy Schubert break;
84357e22627SCy Schubert }
84457e22627SCy Schubert
84557e22627SCy Schubert case RPCAP_MSG_FINDALLIF_REQ:
84657e22627SCy Schubert {
84757e22627SCy Schubert if (daemon_msg_findallif_req(header.ver, &pars, plen) == -1)
84857e22627SCy Schubert {
84957e22627SCy Schubert // Fatal error; a message has
85057e22627SCy Schubert // been logged, so just give up.
85157e22627SCy Schubert goto end;
85257e22627SCy Schubert }
85357e22627SCy Schubert break;
85457e22627SCy Schubert }
85557e22627SCy Schubert
85657e22627SCy Schubert case RPCAP_MSG_OPEN_REQ:
85757e22627SCy Schubert {
85857e22627SCy Schubert //
85957e22627SCy Schubert // Process the open request, and keep
86057e22627SCy Schubert // the source from it, for use later
86157e22627SCy Schubert // when the capture is started.
86257e22627SCy Schubert //
86357e22627SCy Schubert // XXX - we don't care if the client sends
86457e22627SCy Schubert // us multiple open requests, the last
86557e22627SCy Schubert // one wins.
86657e22627SCy Schubert //
86757e22627SCy Schubert retval = daemon_msg_open_req(header.ver, &pars,
86857e22627SCy Schubert plen, source, sizeof(source));
86957e22627SCy Schubert if (retval == -1)
87057e22627SCy Schubert {
87157e22627SCy Schubert // Fatal error; a message has
87257e22627SCy Schubert // been logged, so just give up.
87357e22627SCy Schubert goto end;
87457e22627SCy Schubert }
87557e22627SCy Schubert got_source = 1;
87657e22627SCy Schubert break;
87757e22627SCy Schubert }
87857e22627SCy Schubert
87957e22627SCy Schubert case RPCAP_MSG_STARTCAP_REQ:
88057e22627SCy Schubert {
88157e22627SCy Schubert if (!got_source)
88257e22627SCy Schubert {
88357e22627SCy Schubert // They never told us what device
88457e22627SCy Schubert // to capture on!
885*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
88657e22627SCy Schubert header.ver,
88757e22627SCy Schubert PCAP_ERR_STARTCAPTURE,
88857e22627SCy Schubert "No capture device was specified",
88957e22627SCy Schubert errbuf) == -1)
89057e22627SCy Schubert {
89157e22627SCy Schubert // Fatal error; log an
89257e22627SCy Schubert // error and give up.
89357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
89457e22627SCy Schubert goto end;
89557e22627SCy Schubert }
896*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
89757e22627SCy Schubert {
89857e22627SCy Schubert goto end;
89957e22627SCy Schubert }
90057e22627SCy Schubert break;
90157e22627SCy Schubert }
90257e22627SCy Schubert
90357e22627SCy Schubert if (daemon_msg_startcap_req(header.ver, &pars,
904*6f9cba8fSJoseph Mingrone plen, source, &session, &samp_param,
905*6f9cba8fSJoseph Mingrone uses_ssl) == -1)
90657e22627SCy Schubert {
90757e22627SCy Schubert // Fatal error; a message has
90857e22627SCy Schubert // been logged, so just give up.
90957e22627SCy Schubert goto end;
91057e22627SCy Schubert }
91157e22627SCy Schubert break;
91257e22627SCy Schubert }
91357e22627SCy Schubert
91457e22627SCy Schubert case RPCAP_MSG_UPDATEFILTER_REQ:
91557e22627SCy Schubert {
91657e22627SCy Schubert if (session)
91757e22627SCy Schubert {
91857e22627SCy Schubert if (daemon_msg_updatefilter_req(header.ver,
91957e22627SCy Schubert &pars, session, plen) == -1)
92057e22627SCy Schubert {
92157e22627SCy Schubert // Fatal error; a message has
92257e22627SCy Schubert // been logged, so just give up.
92357e22627SCy Schubert goto end;
92457e22627SCy Schubert }
92557e22627SCy Schubert }
92657e22627SCy Schubert else
92757e22627SCy Schubert {
928*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
929*6f9cba8fSJoseph Mingrone header.ver,
930*6f9cba8fSJoseph Mingrone PCAP_ERR_UPDATEFILTER,
93157e22627SCy Schubert "Device not opened. Cannot update filter",
93257e22627SCy Schubert errbuf) == -1)
93357e22627SCy Schubert {
93457e22627SCy Schubert // That failed; log a message and give up.
93557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
93657e22627SCy Schubert goto end;
93757e22627SCy Schubert }
93857e22627SCy Schubert }
93957e22627SCy Schubert break;
94057e22627SCy Schubert }
94157e22627SCy Schubert
94257e22627SCy Schubert case RPCAP_MSG_CLOSE: // The other endpoint close the pcap session
94357e22627SCy Schubert {
94457e22627SCy Schubert //
94557e22627SCy Schubert // Indicate to our caller that the client
94657e22627SCy Schubert // closed the control connection.
94757e22627SCy Schubert // This is used only in case of active mode.
94857e22627SCy Schubert //
94957e22627SCy Schubert client_told_us_to_close = 1;
95057e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "The other end system asked to close the connection.");
95157e22627SCy Schubert goto end;
95257e22627SCy Schubert }
95357e22627SCy Schubert
95457e22627SCy Schubert case RPCAP_MSG_STATS_REQ:
95557e22627SCy Schubert {
95657e22627SCy Schubert if (daemon_msg_stats_req(header.ver, &pars,
95757e22627SCy Schubert session, plen, &stats, svrcapt) == -1)
95857e22627SCy Schubert {
95957e22627SCy Schubert // Fatal error; a message has
96057e22627SCy Schubert // been logged, so just give up.
96157e22627SCy Schubert goto end;
96257e22627SCy Schubert }
96357e22627SCy Schubert break;
96457e22627SCy Schubert }
96557e22627SCy Schubert
96657e22627SCy Schubert case RPCAP_MSG_ENDCAP_REQ: // The other endpoint close the current capture session
96757e22627SCy Schubert {
96857e22627SCy Schubert if (session)
96957e22627SCy Schubert {
97057e22627SCy Schubert // Save statistics (we can need them in the future)
97157e22627SCy Schubert if (pcap_stats(session->fp, &stats))
97257e22627SCy Schubert {
97357e22627SCy Schubert svrcapt = session->TotCapt;
97457e22627SCy Schubert }
97557e22627SCy Schubert else
97657e22627SCy Schubert {
97757e22627SCy Schubert stats.ps_ifdrop = 0;
97857e22627SCy Schubert stats.ps_recv = 0;
97957e22627SCy Schubert stats.ps_drop = 0;
98057e22627SCy Schubert svrcapt = 0;
98157e22627SCy Schubert }
98257e22627SCy Schubert
98357e22627SCy Schubert if (daemon_msg_endcap_req(header.ver,
98457e22627SCy Schubert &pars, session) == -1)
98557e22627SCy Schubert {
98657e22627SCy Schubert free(session);
98757e22627SCy Schubert session = NULL;
98857e22627SCy Schubert // Fatal error; a message has
98957e22627SCy Schubert // been logged, so just give up.
99057e22627SCy Schubert goto end;
99157e22627SCy Schubert }
99257e22627SCy Schubert free(session);
99357e22627SCy Schubert session = NULL;
99457e22627SCy Schubert }
99557e22627SCy Schubert else
99657e22627SCy Schubert {
997*6f9cba8fSJoseph Mingrone rpcap_senderror(pars.sockctrl, pars.ssl,
998*6f9cba8fSJoseph Mingrone header.ver,
999*6f9cba8fSJoseph Mingrone PCAP_ERR_ENDCAPTURE,
100057e22627SCy Schubert "Device not opened. Cannot close the capture",
100157e22627SCy Schubert errbuf);
100257e22627SCy Schubert }
100357e22627SCy Schubert break;
100457e22627SCy Schubert }
100557e22627SCy Schubert
100657e22627SCy Schubert case RPCAP_MSG_SETSAMPLING_REQ:
100757e22627SCy Schubert {
100857e22627SCy Schubert if (daemon_msg_setsampling_req(header.ver,
100957e22627SCy Schubert &pars, plen, &samp_param) == -1)
101057e22627SCy Schubert {
101157e22627SCy Schubert // Fatal error; a message has
101257e22627SCy Schubert // been logged, so just give up.
101357e22627SCy Schubert goto end;
101457e22627SCy Schubert }
101557e22627SCy Schubert break;
101657e22627SCy Schubert }
101757e22627SCy Schubert
101857e22627SCy Schubert case RPCAP_MSG_AUTH_REQ:
101957e22627SCy Schubert {
102057e22627SCy Schubert //
102157e22627SCy Schubert // We're already authenticated; you don't
102257e22627SCy Schubert // get to reauthenticate.
102357e22627SCy Schubert //
102457e22627SCy Schubert rpcapd_log(LOGPRIO_INFO, "The client sent an RPCAP_MSG_AUTH_REQ message after authentication was completed");
1025*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
1026*6f9cba8fSJoseph Mingrone header.ver,
102757e22627SCy Schubert PCAP_ERR_WRONGMSG,
102857e22627SCy Schubert "RPCAP_MSG_AUTH_REQ request sent after authentication was completed",
102957e22627SCy Schubert errbuf) == -1)
103057e22627SCy Schubert {
103157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
103257e22627SCy Schubert goto end;
103357e22627SCy Schubert }
103457e22627SCy Schubert // Discard the rest of the message.
1035*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
103657e22627SCy Schubert {
103757e22627SCy Schubert // Fatal error.
103857e22627SCy Schubert goto end;
103957e22627SCy Schubert }
104057e22627SCy Schubert goto end;
104157e22627SCy Schubert
104257e22627SCy Schubert case RPCAP_MSG_PACKET:
104357e22627SCy Schubert case RPCAP_MSG_FINDALLIF_REPLY:
104457e22627SCy Schubert case RPCAP_MSG_OPEN_REPLY:
104557e22627SCy Schubert case RPCAP_MSG_STARTCAP_REPLY:
104657e22627SCy Schubert case RPCAP_MSG_UPDATEFILTER_REPLY:
104757e22627SCy Schubert case RPCAP_MSG_AUTH_REPLY:
104857e22627SCy Schubert case RPCAP_MSG_STATS_REPLY:
104957e22627SCy Schubert case RPCAP_MSG_ENDCAP_REPLY:
105057e22627SCy Schubert case RPCAP_MSG_SETSAMPLING_REPLY:
105157e22627SCy Schubert //
105257e22627SCy Schubert // These are server-to-client messages.
105357e22627SCy Schubert //
105457e22627SCy Schubert msg_type_string = rpcap_msg_type_string(header.type);
105557e22627SCy Schubert if (msg_type_string != NULL)
105657e22627SCy Schubert {
105757e22627SCy Schubert rpcapd_log(LOGPRIO_INFO, "The client sent a %s server-to-client message", msg_type_string);
1058*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
105957e22627SCy Schubert }
106057e22627SCy Schubert else
106157e22627SCy Schubert {
106257e22627SCy Schubert rpcapd_log(LOGPRIO_INFO, "The client sent a server-to-client message of type %u", header.type);
1063*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
106457e22627SCy Schubert }
1065*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
1066*6f9cba8fSJoseph Mingrone header.ver, PCAP_ERR_WRONGMSG,
1067*6f9cba8fSJoseph Mingrone errmsgbuf, errbuf) == -1)
106857e22627SCy Schubert {
106957e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
107057e22627SCy Schubert goto end;
107157e22627SCy Schubert }
107257e22627SCy Schubert // Discard the rest of the message.
1073*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
107457e22627SCy Schubert {
107557e22627SCy Schubert // Fatal error.
107657e22627SCy Schubert goto end;
107757e22627SCy Schubert }
107857e22627SCy Schubert goto end;
107957e22627SCy Schubert
108057e22627SCy Schubert default:
108157e22627SCy Schubert //
108257e22627SCy Schubert // Unknown message type.
108357e22627SCy Schubert //
108457e22627SCy Schubert rpcapd_log(LOGPRIO_INFO, "The client sent a message of type %u", header.type);
1085*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
1086*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars.sockctrl, pars.ssl,
1087*6f9cba8fSJoseph Mingrone header.ver, PCAP_ERR_WRONGMSG,
1088*6f9cba8fSJoseph Mingrone errbuf, errmsgbuf) == -1)
108957e22627SCy Schubert {
109057e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
109157e22627SCy Schubert goto end;
109257e22627SCy Schubert }
109357e22627SCy Schubert // Discard the rest of the message.
1094*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
109557e22627SCy Schubert {
109657e22627SCy Schubert // Fatal error.
109757e22627SCy Schubert goto end;
109857e22627SCy Schubert }
109957e22627SCy Schubert goto end;
110057e22627SCy Schubert }
110157e22627SCy Schubert }
110257e22627SCy Schubert }
110357e22627SCy Schubert
110457e22627SCy Schubert end:
110557e22627SCy Schubert // The service loop is finishing up.
110657e22627SCy Schubert // If we have a capture session running, close it.
110757e22627SCy Schubert if (session)
110857e22627SCy Schubert {
110957e22627SCy Schubert session_close(session);
111057e22627SCy Schubert free(session);
111157e22627SCy Schubert session = NULL;
111257e22627SCy Schubert }
111357e22627SCy Schubert
1114*6f9cba8fSJoseph Mingrone if (passiveClients) {
1115*6f9cba8fSJoseph Mingrone free(passiveClients);
1116*6f9cba8fSJoseph Mingrone }
1117*6f9cba8fSJoseph Mingrone //
1118*6f9cba8fSJoseph Mingrone // Finish using the SSL handle for the control socket, if we
1119*6f9cba8fSJoseph Mingrone // have an SSL connection, and close the control socket.
1120*6f9cba8fSJoseph Mingrone //
1121*6f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
1122*6f9cba8fSJoseph Mingrone if (ssl)
1123*6f9cba8fSJoseph Mingrone {
1124*6f9cba8fSJoseph Mingrone // Finish using the SSL handle for the socket.
1125*6f9cba8fSJoseph Mingrone // This must be done *before* the socket is closed.
1126*6f9cba8fSJoseph Mingrone ssl_finish(ssl);
1127*6f9cba8fSJoseph Mingrone }
1128*6f9cba8fSJoseph Mingrone #endif
112957e22627SCy Schubert sock_close(sockctrl, NULL, 0);
113057e22627SCy Schubert
113157e22627SCy Schubert // Print message and return
113257e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "I'm exiting from the child loop");
113357e22627SCy Schubert
113457e22627SCy Schubert return client_told_us_to_close;
113557e22627SCy Schubert }
113657e22627SCy Schubert
113757e22627SCy Schubert /*
113857e22627SCy Schubert * This handles the RPCAP_MSG_ERR message.
113957e22627SCy Schubert */
114057e22627SCy Schubert static int
daemon_msg_err(SOCKET sockctrl,SSL * ssl,uint32 plen)1141*6f9cba8fSJoseph Mingrone daemon_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen)
114257e22627SCy Schubert {
114357e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE];
114457e22627SCy Schubert char remote_errbuf[PCAP_ERRBUF_SIZE];
114557e22627SCy Schubert
114657e22627SCy Schubert if (plen >= PCAP_ERRBUF_SIZE)
114757e22627SCy Schubert {
114857e22627SCy Schubert /*
114957e22627SCy Schubert * Message is too long; just read as much of it as we
115057e22627SCy Schubert * can into the buffer provided, and discard the rest.
115157e22627SCy Schubert */
1152*6f9cba8fSJoseph Mingrone if (sock_recv(sockctrl, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
115357e22627SCy Schubert SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
115457e22627SCy Schubert PCAP_ERRBUF_SIZE) == -1)
115557e22627SCy Schubert {
115657e22627SCy Schubert // Network error.
115757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
115857e22627SCy Schubert return -1;
115957e22627SCy Schubert }
1160*6f9cba8fSJoseph Mingrone if (rpcapd_discard(sockctrl, ssl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1)
116157e22627SCy Schubert {
116257e22627SCy Schubert // Network error.
116357e22627SCy Schubert return -1;
116457e22627SCy Schubert }
116557e22627SCy Schubert
116657e22627SCy Schubert /*
116757e22627SCy Schubert * Null-terminate it.
116857e22627SCy Schubert */
116957e22627SCy Schubert remote_errbuf[PCAP_ERRBUF_SIZE - 1] = '\0';
117057e22627SCy Schubert }
117157e22627SCy Schubert else if (plen == 0)
117257e22627SCy Schubert {
117357e22627SCy Schubert /* Empty error string. */
117457e22627SCy Schubert remote_errbuf[0] = '\0';
117557e22627SCy Schubert }
117657e22627SCy Schubert else
117757e22627SCy Schubert {
1178*6f9cba8fSJoseph Mingrone if (sock_recv(sockctrl, ssl, remote_errbuf, plen,
117957e22627SCy Schubert SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
118057e22627SCy Schubert PCAP_ERRBUF_SIZE) == -1)
118157e22627SCy Schubert {
118257e22627SCy Schubert // Network error.
118357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
118457e22627SCy Schubert return -1;
118557e22627SCy Schubert }
118657e22627SCy Schubert
118757e22627SCy Schubert /*
118857e22627SCy Schubert * Null-terminate it.
118957e22627SCy Schubert */
119057e22627SCy Schubert remote_errbuf[plen] = '\0';
119157e22627SCy Schubert }
119257e22627SCy Schubert // Log the message
119357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Error from client: %s", remote_errbuf);
119457e22627SCy Schubert return 0;
119557e22627SCy Schubert }
119657e22627SCy Schubert
119757e22627SCy Schubert /*
119857e22627SCy Schubert * This handles the RPCAP_MSG_AUTH_REQ message.
119957e22627SCy Schubert * It checks if the authentication credentials supplied by the user are valid.
120057e22627SCy Schubert *
120157e22627SCy Schubert * This function is called if the daemon receives a RPCAP_MSG_AUTH_REQ
120257e22627SCy Schubert * message in its authentication loop. It reads the body of the
120357e22627SCy Schubert * authentication message from the network and checks whether the
120457e22627SCy Schubert * credentials are valid.
120557e22627SCy Schubert *
120657e22627SCy Schubert * \param sockctrl: the socket for the control connection.
120757e22627SCy Schubert *
120857e22627SCy Schubert * \param nullAuthAllowed: '1' if the NULL authentication is allowed.
120957e22627SCy Schubert *
121057e22627SCy Schubert * \param errbuf: a user-allocated buffer in which the error message
121157e22627SCy Schubert * (if one) has to be written. It must be at least PCAP_ERRBUF_SIZE
121257e22627SCy Schubert * bytes long.
121357e22627SCy Schubert *
121457e22627SCy Schubert * \return '0' if everything is fine, '-1' if an unrecoverable error occurred,
121557e22627SCy Schubert * or '-2' if the authentication failed. For errors, an error message is
121657e22627SCy Schubert * returned in the 'errbuf' variable; this gives a message for the
121757e22627SCy Schubert * unrecoverable error or for the authentication failure.
121857e22627SCy Schubert */
121957e22627SCy Schubert static int
daemon_msg_auth_req(struct daemon_slpars * pars,uint32 plen)122057e22627SCy Schubert daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
122157e22627SCy Schubert {
122257e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
122357e22627SCy Schubert char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
122457e22627SCy Schubert int status;
122557e22627SCy Schubert struct rpcap_auth auth; // RPCAP authentication header
122657e22627SCy Schubert char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
122757e22627SCy Schubert int sendbufidx = 0; // index which keeps the number of bytes currently buffered
122857e22627SCy Schubert struct rpcap_authreply *authreply; // authentication reply message
122957e22627SCy Schubert
1230*6f9cba8fSJoseph Mingrone status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
123157e22627SCy Schubert if (status == -1)
123257e22627SCy Schubert {
123357e22627SCy Schubert return -1;
123457e22627SCy Schubert }
123557e22627SCy Schubert if (status == -2)
123657e22627SCy Schubert {
123757e22627SCy Schubert goto error;
123857e22627SCy Schubert }
123957e22627SCy Schubert
124057e22627SCy Schubert switch (ntohs(auth.type))
124157e22627SCy Schubert {
124257e22627SCy Schubert case RPCAP_RMTAUTH_NULL:
124357e22627SCy Schubert {
124457e22627SCy Schubert if (!pars->nullAuthAllowed)
124557e22627SCy Schubert {
124657e22627SCy Schubert // Send the client an error reply.
1247*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
124857e22627SCy Schubert "Authentication failed; NULL authentication not permitted.");
1249*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars->sockctrl, pars->ssl,
1250*6f9cba8fSJoseph Mingrone 0, PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
125157e22627SCy Schubert {
125257e22627SCy Schubert // That failed; log a message and give up.
125357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
125457e22627SCy Schubert return -1;
125557e22627SCy Schubert }
125657e22627SCy Schubert goto error_noreply;
125757e22627SCy Schubert }
125857e22627SCy Schubert break;
125957e22627SCy Schubert }
126057e22627SCy Schubert
126157e22627SCy Schubert case RPCAP_RMTAUTH_PWD:
126257e22627SCy Schubert {
126357e22627SCy Schubert char *username, *passwd;
126457e22627SCy Schubert uint32 usernamelen, passwdlen;
126557e22627SCy Schubert
126657e22627SCy Schubert usernamelen = ntohs(auth.slen1);
126757e22627SCy Schubert username = (char *) malloc (usernamelen + 1);
126857e22627SCy Schubert if (username == NULL)
126957e22627SCy Schubert {
127057e22627SCy Schubert pcap_fmt_errmsg_for_errno(errmsgbuf,
127157e22627SCy Schubert PCAP_ERRBUF_SIZE, errno, "malloc() failed");
127257e22627SCy Schubert goto error;
127357e22627SCy Schubert }
1274*6f9cba8fSJoseph Mingrone status = rpcapd_recv(pars->sockctrl, pars->ssl, username, usernamelen, &plen, errmsgbuf);
127557e22627SCy Schubert if (status == -1)
127657e22627SCy Schubert {
127757e22627SCy Schubert free(username);
127857e22627SCy Schubert return -1;
127957e22627SCy Schubert }
128057e22627SCy Schubert if (status == -2)
128157e22627SCy Schubert {
128257e22627SCy Schubert free(username);
128357e22627SCy Schubert goto error;
128457e22627SCy Schubert }
128557e22627SCy Schubert username[usernamelen] = '\0';
128657e22627SCy Schubert
128757e22627SCy Schubert passwdlen = ntohs(auth.slen2);
128857e22627SCy Schubert passwd = (char *) malloc (passwdlen + 1);
128957e22627SCy Schubert if (passwd == NULL)
129057e22627SCy Schubert {
129157e22627SCy Schubert pcap_fmt_errmsg_for_errno(errmsgbuf,
129257e22627SCy Schubert PCAP_ERRBUF_SIZE, errno, "malloc() failed");
129357e22627SCy Schubert free(username);
129457e22627SCy Schubert goto error;
129557e22627SCy Schubert }
1296*6f9cba8fSJoseph Mingrone status = rpcapd_recv(pars->sockctrl, pars->ssl, passwd, passwdlen, &plen, errmsgbuf);
129757e22627SCy Schubert if (status == -1)
129857e22627SCy Schubert {
129957e22627SCy Schubert free(username);
130057e22627SCy Schubert free(passwd);
130157e22627SCy Schubert return -1;
130257e22627SCy Schubert }
130357e22627SCy Schubert if (status == -2)
130457e22627SCy Schubert {
130557e22627SCy Schubert free(username);
130657e22627SCy Schubert free(passwd);
130757e22627SCy Schubert goto error;
130857e22627SCy Schubert }
130957e22627SCy Schubert passwd[passwdlen] = '\0';
131057e22627SCy Schubert
131157e22627SCy Schubert if (daemon_AuthUserPwd(username, passwd, errmsgbuf))
131257e22627SCy Schubert {
131357e22627SCy Schubert //
131457e22627SCy Schubert // Authentication failed. Let the client
131557e22627SCy Schubert // know.
131657e22627SCy Schubert //
131757e22627SCy Schubert free(username);
131857e22627SCy Schubert free(passwd);
1319*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars->sockctrl, pars->ssl,
1320*6f9cba8fSJoseph Mingrone 0, PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
132157e22627SCy Schubert {
132257e22627SCy Schubert // That failed; log a message and give up.
132357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
132457e22627SCy Schubert return -1;
132557e22627SCy Schubert }
132657e22627SCy Schubert
132757e22627SCy Schubert //
132857e22627SCy Schubert // Suspend for 1 second, so that they can't
132957e22627SCy Schubert // hammer us with repeated tries with an
133057e22627SCy Schubert // attack such as a dictionary attack.
133157e22627SCy Schubert //
133257e22627SCy Schubert // WARNING: this delay is inserted only
133357e22627SCy Schubert // at this point; if the client closes the
133457e22627SCy Schubert // connection and reconnects, the suspension
133557e22627SCy Schubert // time does not have any effect.
133657e22627SCy Schubert //
133757e22627SCy Schubert sleep_secs(RPCAP_SUSPEND_WRONGAUTH);
133857e22627SCy Schubert goto error_noreply;
133957e22627SCy Schubert }
134057e22627SCy Schubert
134157e22627SCy Schubert free(username);
134257e22627SCy Schubert free(passwd);
134357e22627SCy Schubert break;
134457e22627SCy Schubert }
134557e22627SCy Schubert
134657e22627SCy Schubert default:
1347*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
134857e22627SCy Schubert "Authentication type not recognized.");
1349*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars->sockctrl, pars->ssl,
1350*6f9cba8fSJoseph Mingrone 0, PCAP_ERR_AUTH_TYPE_NOTSUP, errmsgbuf, errbuf) == -1)
135157e22627SCy Schubert {
135257e22627SCy Schubert // That failed; log a message and give up.
135357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
135457e22627SCy Schubert return -1;
135557e22627SCy Schubert }
135657e22627SCy Schubert goto error_noreply;
135757e22627SCy Schubert }
135857e22627SCy Schubert
135957e22627SCy Schubert // The authentication succeeded; let the client know.
136057e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
136157e22627SCy Schubert RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
136257e22627SCy Schubert goto error;
136357e22627SCy Schubert
136457e22627SCy Schubert rpcap_createhdr((struct rpcap_header *) sendbuf, 0,
136557e22627SCy Schubert RPCAP_MSG_AUTH_REPLY, 0, sizeof(struct rpcap_authreply));
136657e22627SCy Schubert
136757e22627SCy Schubert authreply = (struct rpcap_authreply *) &sendbuf[sendbufidx];
136857e22627SCy Schubert
136957e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_authreply), NULL, &sendbufidx,
137057e22627SCy Schubert RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
137157e22627SCy Schubert goto error;
137257e22627SCy Schubert
137357e22627SCy Schubert //
1374*6f9cba8fSJoseph Mingrone // Indicate to our peer what versions we support and what our
1375*6f9cba8fSJoseph Mingrone // version of the byte-order magic is (which will tell the
1376*6f9cba8fSJoseph Mingrone // client whether our byte order differs from theirs, in which
1377*6f9cba8fSJoseph Mingrone // case they will need to byte-swap some fields in some
1378*6f9cba8fSJoseph Mingrone // link-layer types' headers).
137957e22627SCy Schubert //
138057e22627SCy Schubert memset(authreply, 0, sizeof(struct rpcap_authreply));
138157e22627SCy Schubert authreply->minvers = RPCAP_MIN_VERSION;
138257e22627SCy Schubert authreply->maxvers = RPCAP_MAX_VERSION;
1383*6f9cba8fSJoseph Mingrone authreply->byte_order_magic = RPCAP_BYTE_ORDER_MAGIC;
138457e22627SCy Schubert
138557e22627SCy Schubert // Send the reply.
1386*6f9cba8fSJoseph Mingrone if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
138757e22627SCy Schubert {
1388*6f9cba8fSJoseph Mingrone // That failed; log a message and give up.
138957e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
139057e22627SCy Schubert return -1;
139157e22627SCy Schubert }
139257e22627SCy Schubert
139357e22627SCy Schubert // Check if all the data has been read; if not, discard the data in excess
1394*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
139557e22627SCy Schubert {
139657e22627SCy Schubert return -1;
139757e22627SCy Schubert }
139857e22627SCy Schubert
139957e22627SCy Schubert return 0;
140057e22627SCy Schubert
140157e22627SCy Schubert error:
1402*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars->sockctrl, pars->ssl, 0, PCAP_ERR_AUTH,
1403*6f9cba8fSJoseph Mingrone errmsgbuf, errbuf) == -1)
140457e22627SCy Schubert {
140557e22627SCy Schubert // That failed; log a message and give up.
140657e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
140757e22627SCy Schubert return -1;
140857e22627SCy Schubert }
140957e22627SCy Schubert
141057e22627SCy Schubert error_noreply:
141157e22627SCy Schubert // Check if all the data has been read; if not, discard the data in excess
1412*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
141357e22627SCy Schubert {
141457e22627SCy Schubert return -1;
141557e22627SCy Schubert }
141657e22627SCy Schubert
141757e22627SCy Schubert return -2;
141857e22627SCy Schubert }
141957e22627SCy Schubert
142057e22627SCy Schubert static int
daemon_AuthUserPwd(char * username,char * password,char * errbuf)142157e22627SCy Schubert daemon_AuthUserPwd(char *username, char *password, char *errbuf)
142257e22627SCy Schubert {
142357e22627SCy Schubert #ifdef _WIN32
142457e22627SCy Schubert /*
142557e22627SCy Schubert * Warning: the user which launches the process must have the
142657e22627SCy Schubert * SE_TCB_NAME right.
142757e22627SCy Schubert * This corresponds to have the "Act as part of the Operating System"
142857e22627SCy Schubert * turned on (administrative tools, local security settings, local
142957e22627SCy Schubert * policies, user right assignment)
143057e22627SCy Schubert * However, it seems to me that if you run it as a service, this
143157e22627SCy Schubert * right should be provided by default.
143257e22627SCy Schubert *
143357e22627SCy Schubert * XXX - hopefully, this returns errors such as ERROR_LOGON_FAILURE,
143457e22627SCy Schubert * which merely indicates that the user name or password is
143557e22627SCy Schubert * incorrect, not whether it's the user name or the password
143657e22627SCy Schubert * that's incorrect, so a client that's trying to brute-force
143757e22627SCy Schubert * accounts doesn't know whether it's the user name or the
143857e22627SCy Schubert * password that's incorrect, so it doesn't know whether to
143957e22627SCy Schubert * stop trying to log in with a given user name and move on
144057e22627SCy Schubert * to another user name.
144157e22627SCy Schubert */
144257e22627SCy Schubert DWORD error;
144357e22627SCy Schubert HANDLE Token;
144457e22627SCy Schubert char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to log
144557e22627SCy Schubert
144657e22627SCy Schubert if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0)
144757e22627SCy Schubert {
1448*6f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
144957e22627SCy Schubert error = GetLastError();
145057e22627SCy Schubert if (error != ERROR_LOGON_FAILURE)
145157e22627SCy Schubert {
145257e22627SCy Schubert // Some error other than an authentication error;
145357e22627SCy Schubert // log it.
145457e22627SCy Schubert pcap_fmt_errmsg_for_win32_err(errmsgbuf,
145557e22627SCy Schubert PCAP_ERRBUF_SIZE, error, "LogonUser() failed");
145657e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf);
145757e22627SCy Schubert }
145857e22627SCy Schubert return -1;
145957e22627SCy Schubert }
146057e22627SCy Schubert
146157e22627SCy Schubert // This call should change the current thread to the selected user.
146257e22627SCy Schubert // I didn't test it.
146357e22627SCy Schubert if (ImpersonateLoggedOnUser(Token) == 0)
146457e22627SCy Schubert {
1465*6f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
146657e22627SCy Schubert pcap_fmt_errmsg_for_win32_err(errmsgbuf, PCAP_ERRBUF_SIZE,
146757e22627SCy Schubert GetLastError(), "ImpersonateLoggedOnUser() failed");
146857e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf);
146957e22627SCy Schubert CloseHandle(Token);
147057e22627SCy Schubert return -1;
147157e22627SCy Schubert }
147257e22627SCy Schubert
147357e22627SCy Schubert CloseHandle(Token);
147457e22627SCy Schubert return 0;
147557e22627SCy Schubert
147657e22627SCy Schubert #else
147757e22627SCy Schubert /*
147857e22627SCy Schubert * See
147957e22627SCy Schubert *
1480*6f9cba8fSJoseph Mingrone * https://www.unixpapa.com/incnote/passwd.html
148157e22627SCy Schubert *
148257e22627SCy Schubert * We use the Solaris/Linux shadow password authentication if
148357e22627SCy Schubert * we have getspnam(), otherwise we just do traditional
148457e22627SCy Schubert * authentication, which, on some platforms, might work, even
148557e22627SCy Schubert * with shadow passwords, if we're running as root. Traditional
148657e22627SCy Schubert * authenticaion won't work if we're not running as root, as
148757e22627SCy Schubert * I think these days all UN*Xes either won't return the password
148857e22627SCy Schubert * at all with getpwnam() or will only do so if you're root.
148957e22627SCy Schubert *
149057e22627SCy Schubert * XXX - perhaps what we *should* be using is PAM, if we have
149157e22627SCy Schubert * it. That might hide all the details of username/password
149257e22627SCy Schubert * authentication, whether it's done with a visible-to-root-
149357e22627SCy Schubert * only password database or some other authentication mechanism,
149457e22627SCy Schubert * behind its API.
149557e22627SCy Schubert */
149657e22627SCy Schubert int error;
149757e22627SCy Schubert struct passwd *user;
149857e22627SCy Schubert char *user_password;
149957e22627SCy Schubert #ifdef HAVE_GETSPNAM
150057e22627SCy Schubert struct spwd *usersp;
150157e22627SCy Schubert #endif
150257e22627SCy Schubert char *crypt_password;
150357e22627SCy Schubert
150457e22627SCy Schubert // This call is needed to get the uid
150557e22627SCy Schubert if ((user = getpwnam(username)) == NULL)
150657e22627SCy Schubert {
1507*6f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
150857e22627SCy Schubert return -1;
150957e22627SCy Schubert }
151057e22627SCy Schubert
151157e22627SCy Schubert #ifdef HAVE_GETSPNAM
151257e22627SCy Schubert // This call is needed to get the password; otherwise 'x' is returned
151357e22627SCy Schubert if ((usersp = getspnam(username)) == NULL)
151457e22627SCy Schubert {
1515*6f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
151657e22627SCy Schubert return -1;
151757e22627SCy Schubert }
151857e22627SCy Schubert user_password = usersp->sp_pwdp;
151957e22627SCy Schubert #else
152057e22627SCy Schubert /*
152157e22627SCy Schubert * XXX - what about other platforms?
152257e22627SCy Schubert * The unixpapa.com page claims this Just Works on *BSD if you're
152357e22627SCy Schubert * running as root - it's from 2000, so it doesn't indicate whether
152457e22627SCy Schubert * macOS (which didn't come out until 2001, under the name Mac OS
152557e22627SCy Schubert * X) behaves like the *BSDs or not, and might also work on AIX.
152657e22627SCy Schubert * HP-UX does something else.
152757e22627SCy Schubert *
152857e22627SCy Schubert * Again, hopefully PAM hides all that.
152957e22627SCy Schubert */
153057e22627SCy Schubert user_password = user->pw_passwd;
153157e22627SCy Schubert #endif
153257e22627SCy Schubert
153357e22627SCy Schubert //
153457e22627SCy Schubert // The Single UNIX Specification says that if crypt() fails it
153557e22627SCy Schubert // sets errno, but some implementatons that haven't been run
153657e22627SCy Schubert // through the SUS test suite might not do so.
153757e22627SCy Schubert //
153857e22627SCy Schubert errno = 0;
153957e22627SCy Schubert crypt_password = crypt(password, user_password);
154057e22627SCy Schubert if (crypt_password == NULL)
154157e22627SCy Schubert {
154257e22627SCy Schubert error = errno;
1543*6f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
154457e22627SCy Schubert if (error == 0)
154557e22627SCy Schubert {
154657e22627SCy Schubert // It didn't set errno.
154757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "crypt() failed");
154857e22627SCy Schubert }
154957e22627SCy Schubert else
155057e22627SCy Schubert {
155157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "crypt() failed: %s",
155257e22627SCy Schubert strerror(error));
155357e22627SCy Schubert }
155457e22627SCy Schubert return -1;
155557e22627SCy Schubert }
155657e22627SCy Schubert if (strcmp(user_password, crypt_password) != 0)
155757e22627SCy Schubert {
1558*6f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
155957e22627SCy Schubert return -1;
156057e22627SCy Schubert }
156157e22627SCy Schubert
156257e22627SCy Schubert if (setuid(user->pw_uid))
156357e22627SCy Schubert {
156457e22627SCy Schubert error = errno;
156557e22627SCy Schubert pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
156657e22627SCy Schubert error, "setuid");
156757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "setuid() failed: %s",
156857e22627SCy Schubert strerror(error));
156957e22627SCy Schubert return -1;
157057e22627SCy Schubert }
157157e22627SCy Schubert
157257e22627SCy Schubert /* if (setgid(user->pw_gid))
157357e22627SCy Schubert {
157457e22627SCy Schubert error = errno;
157557e22627SCy Schubert pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
157657e22627SCy Schubert errno, "setgid");
157757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "setgid() failed: %s",
157857e22627SCy Schubert strerror(error));
157957e22627SCy Schubert return -1;
158057e22627SCy Schubert }
158157e22627SCy Schubert */
158257e22627SCy Schubert return 0;
158357e22627SCy Schubert
158457e22627SCy Schubert #endif
158557e22627SCy Schubert
158657e22627SCy Schubert }
158757e22627SCy Schubert
1588*6f9cba8fSJoseph Mingrone /*
1589*6f9cba8fSJoseph Mingrone * Make sure that the reply length won't overflow 32 bits if we add the
1590*6f9cba8fSJoseph Mingrone * specified amount to it. If it won't, add that amount to it.
1591*6f9cba8fSJoseph Mingrone *
1592*6f9cba8fSJoseph Mingrone * We check whether replylen + itemlen > UINT32_MAX, but subtract itemlen
1593*6f9cba8fSJoseph Mingrone * from both sides, to prevent overflow.
1594*6f9cba8fSJoseph Mingrone */
1595*6f9cba8fSJoseph Mingrone #define CHECK_AND_INCREASE_REPLY_LEN(itemlen) \
1596*6f9cba8fSJoseph Mingrone if (replylen > UINT32_MAX - (itemlen)) { \
1597*6f9cba8fSJoseph Mingrone pcap_strlcpy(errmsgbuf, "Reply length doesn't fit in 32 bits", \
1598*6f9cba8fSJoseph Mingrone sizeof (errmsgbuf)); \
1599*6f9cba8fSJoseph Mingrone goto error; \
1600*6f9cba8fSJoseph Mingrone } \
1601*6f9cba8fSJoseph Mingrone replylen += (uint32)(itemlen)
1602*6f9cba8fSJoseph Mingrone
160357e22627SCy Schubert static int
daemon_msg_findallif_req(uint8 ver,struct daemon_slpars * pars,uint32 plen)160457e22627SCy Schubert daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
160557e22627SCy Schubert {
160657e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
160757e22627SCy Schubert char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
160857e22627SCy Schubert char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
160957e22627SCy Schubert int sendbufidx = 0; // index which keeps the number of bytes currently buffered
161057e22627SCy Schubert pcap_if_t *alldevs = NULL; // pointer to the header of the interface chain
161157e22627SCy Schubert pcap_if_t *d; // temp pointer needed to scan the interface chain
161257e22627SCy Schubert struct pcap_addr *address; // pcap structure that keeps a network address of an interface
161357e22627SCy Schubert uint32 replylen; // length of reply payload
161457e22627SCy Schubert uint16 nif = 0; // counts the number of interface listed
161557e22627SCy Schubert
161657e22627SCy Schubert // Discard the rest of the message; there shouldn't be any payload.
1617*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
161857e22627SCy Schubert {
161957e22627SCy Schubert // Network error.
162057e22627SCy Schubert return -1;
162157e22627SCy Schubert }
162257e22627SCy Schubert
162357e22627SCy Schubert // Retrieve the device list
162457e22627SCy Schubert if (pcap_findalldevs(&alldevs, errmsgbuf) == -1)
162557e22627SCy Schubert goto error;
162657e22627SCy Schubert
162757e22627SCy Schubert if (alldevs == NULL)
162857e22627SCy Schubert {
1629*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
1630*6f9cba8fSJoseph Mingrone PCAP_ERR_NOREMOTEIF,
163157e22627SCy Schubert "No interfaces found! Make sure libpcap/WinPcap is properly installed"
163257e22627SCy Schubert " and you have the right to access to the remote device.",
163357e22627SCy Schubert errbuf) == -1)
163457e22627SCy Schubert {
163557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
163657e22627SCy Schubert return -1;
163757e22627SCy Schubert }
163857e22627SCy Schubert return 0;
163957e22627SCy Schubert }
164057e22627SCy Schubert
164157e22627SCy Schubert // This checks the number of interfaces and computes the total
164257e22627SCy Schubert // length of the payload.
164357e22627SCy Schubert replylen = 0;
164457e22627SCy Schubert for (d = alldevs; d != NULL; d = d->next)
164557e22627SCy Schubert {
164657e22627SCy Schubert nif++;
164757e22627SCy Schubert
1648*6f9cba8fSJoseph Mingrone if (d->description) {
1649*6f9cba8fSJoseph Mingrone size_t stringlen = strlen(d->description);
1650*6f9cba8fSJoseph Mingrone if (stringlen > UINT16_MAX) {
1651*6f9cba8fSJoseph Mingrone pcap_strlcpy(errmsgbuf,
1652*6f9cba8fSJoseph Mingrone "Description length doesn't fit in 16 bits",
1653*6f9cba8fSJoseph Mingrone sizeof (errmsgbuf));
1654*6f9cba8fSJoseph Mingrone goto error;
1655*6f9cba8fSJoseph Mingrone }
1656*6f9cba8fSJoseph Mingrone CHECK_AND_INCREASE_REPLY_LEN(stringlen);
1657*6f9cba8fSJoseph Mingrone }
1658*6f9cba8fSJoseph Mingrone if (d->name) {
1659*6f9cba8fSJoseph Mingrone size_t stringlen = strlen(d->name);
1660*6f9cba8fSJoseph Mingrone if (stringlen > UINT16_MAX) {
1661*6f9cba8fSJoseph Mingrone pcap_strlcpy(errmsgbuf,
1662*6f9cba8fSJoseph Mingrone "Name length doesn't fit in 16 bits",
1663*6f9cba8fSJoseph Mingrone sizeof (errmsgbuf));
1664*6f9cba8fSJoseph Mingrone goto error;
1665*6f9cba8fSJoseph Mingrone }
1666*6f9cba8fSJoseph Mingrone CHECK_AND_INCREASE_REPLY_LEN(stringlen);
1667*6f9cba8fSJoseph Mingrone }
166857e22627SCy Schubert
1669*6f9cba8fSJoseph Mingrone CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_findalldevs_if));
167057e22627SCy Schubert
1671*6f9cba8fSJoseph Mingrone uint16_t naddrs = 0;
167257e22627SCy Schubert for (address = d->addresses; address != NULL; address = address->next)
167357e22627SCy Schubert {
167457e22627SCy Schubert /*
167557e22627SCy Schubert * Send only IPv4 and IPv6 addresses over the wire.
167657e22627SCy Schubert */
167757e22627SCy Schubert switch (address->addr->sa_family)
167857e22627SCy Schubert {
167957e22627SCy Schubert case AF_INET:
168057e22627SCy Schubert #ifdef AF_INET6
168157e22627SCy Schubert case AF_INET6:
168257e22627SCy Schubert #endif
1683*6f9cba8fSJoseph Mingrone CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_sockaddr) * 4);
1684*6f9cba8fSJoseph Mingrone if (naddrs == UINT16_MAX) {
1685*6f9cba8fSJoseph Mingrone pcap_strlcpy(errmsgbuf,
1686*6f9cba8fSJoseph Mingrone "Number of interfaces doesn't fit in 16 bits",
1687*6f9cba8fSJoseph Mingrone sizeof (errmsgbuf));
1688*6f9cba8fSJoseph Mingrone goto error;
1689*6f9cba8fSJoseph Mingrone }
1690*6f9cba8fSJoseph Mingrone naddrs++;
169157e22627SCy Schubert break;
169257e22627SCy Schubert
169357e22627SCy Schubert default:
169457e22627SCy Schubert break;
169557e22627SCy Schubert }
169657e22627SCy Schubert }
169757e22627SCy Schubert }
169857e22627SCy Schubert
1699*6f9cba8fSJoseph Mingrone // RPCAP findalldevs reply
170057e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
170157e22627SCy Schubert &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf,
170257e22627SCy Schubert PCAP_ERRBUF_SIZE) == -1)
170357e22627SCy Schubert goto error;
170457e22627SCy Schubert
170557e22627SCy Schubert rpcap_createhdr((struct rpcap_header *) sendbuf, ver,
170657e22627SCy Schubert RPCAP_MSG_FINDALLIF_REPLY, nif, replylen);
170757e22627SCy Schubert
170857e22627SCy Schubert // send the interface list
170957e22627SCy Schubert for (d = alldevs; d != NULL; d = d->next)
171057e22627SCy Schubert {
171157e22627SCy Schubert uint16 lname, ldescr;
171257e22627SCy Schubert
1713*6f9cba8fSJoseph Mingrone // Note: the findalldevs_if entries are *not* neatly
1714*6f9cba8fSJoseph Mingrone // aligned on 4-byte boundaries, because they're
1715*6f9cba8fSJoseph Mingrone // preceded by strings that aren't padded to 4-byte
1716*6f9cba8fSJoseph Mingrone // boundaries, so we cannot just cast output buffer
1717*6f9cba8fSJoseph Mingrone // boundaries to struct rpcap_findalldevs_if pointers
1718*6f9cba8fSJoseph Mingrone // and store into them - we must fill in a structure and
1719*6f9cba8fSJoseph Mingrone // then copy the structure to the buffer, as not all
1720*6f9cba8fSJoseph Mingrone // systems support unaligned access (some, such as
1721*6f9cba8fSJoseph Mingrone // SPARC, crash; others, such as Arm, may just ignore
1722*6f9cba8fSJoseph Mingrone // the lower-order bits).
1723*6f9cba8fSJoseph Mingrone struct rpcap_findalldevs_if findalldevs_if;
172457e22627SCy Schubert
1725*6f9cba8fSJoseph Mingrone /*
1726*6f9cba8fSJoseph Mingrone * We've already established that the string lengths
1727*6f9cba8fSJoseph Mingrone * fit in 16 bits.
1728*6f9cba8fSJoseph Mingrone */
1729*6f9cba8fSJoseph Mingrone if (d->description)
1730*6f9cba8fSJoseph Mingrone ldescr = (uint16) strlen(d->description);
1731*6f9cba8fSJoseph Mingrone else
1732*6f9cba8fSJoseph Mingrone ldescr = 0;
1733*6f9cba8fSJoseph Mingrone if (d->name)
1734*6f9cba8fSJoseph Mingrone lname = (uint16) strlen(d->name);
1735*6f9cba8fSJoseph Mingrone else
1736*6f9cba8fSJoseph Mingrone lname = 0;
173757e22627SCy Schubert
1738*6f9cba8fSJoseph Mingrone findalldevs_if.desclen = htons(ldescr);
1739*6f9cba8fSJoseph Mingrone findalldevs_if.namelen = htons(lname);
1740*6f9cba8fSJoseph Mingrone findalldevs_if.flags = htonl(d->flags);
174157e22627SCy Schubert
1742*6f9cba8fSJoseph Mingrone uint16_t naddrs = 0;
174357e22627SCy Schubert for (address = d->addresses; address != NULL; address = address->next)
174457e22627SCy Schubert {
174557e22627SCy Schubert /*
174657e22627SCy Schubert * Send only IPv4 and IPv6 addresses over the wire.
174757e22627SCy Schubert */
174857e22627SCy Schubert switch (address->addr->sa_family)
174957e22627SCy Schubert {
175057e22627SCy Schubert case AF_INET:
175157e22627SCy Schubert #ifdef AF_INET6
175257e22627SCy Schubert case AF_INET6:
175357e22627SCy Schubert #endif
1754*6f9cba8fSJoseph Mingrone naddrs++;
175557e22627SCy Schubert break;
175657e22627SCy Schubert
175757e22627SCy Schubert default:
175857e22627SCy Schubert break;
175957e22627SCy Schubert }
176057e22627SCy Schubert }
1761*6f9cba8fSJoseph Mingrone findalldevs_if.naddr = htons(naddrs);
1762*6f9cba8fSJoseph Mingrone findalldevs_if.dummy = 0;
1763*6f9cba8fSJoseph Mingrone
1764*6f9cba8fSJoseph Mingrone if (sock_bufferize(&findalldevs_if, sizeof(struct rpcap_findalldevs_if), sendbuf,
1765*6f9cba8fSJoseph Mingrone &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errmsgbuf,
1766*6f9cba8fSJoseph Mingrone PCAP_ERRBUF_SIZE) == -1)
1767*6f9cba8fSJoseph Mingrone goto error;
176857e22627SCy Schubert
176957e22627SCy Schubert if (sock_bufferize(d->name, lname, sendbuf, &sendbufidx,
177057e22627SCy Schubert RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errmsgbuf,
177157e22627SCy Schubert PCAP_ERRBUF_SIZE) == -1)
177257e22627SCy Schubert goto error;
177357e22627SCy Schubert
177457e22627SCy Schubert if (sock_bufferize(d->description, ldescr, sendbuf, &sendbufidx,
177557e22627SCy Schubert RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errmsgbuf,
177657e22627SCy Schubert PCAP_ERRBUF_SIZE) == -1)
177757e22627SCy Schubert goto error;
177857e22627SCy Schubert
177957e22627SCy Schubert // send all addresses
178057e22627SCy Schubert for (address = d->addresses; address != NULL; address = address->next)
178157e22627SCy Schubert {
178257e22627SCy Schubert struct rpcap_sockaddr *sockaddr;
178357e22627SCy Schubert
178457e22627SCy Schubert /*
178557e22627SCy Schubert * Send only IPv4 and IPv6 addresses over the wire.
178657e22627SCy Schubert */
178757e22627SCy Schubert switch (address->addr->sa_family)
178857e22627SCy Schubert {
178957e22627SCy Schubert case AF_INET:
179057e22627SCy Schubert #ifdef AF_INET6
179157e22627SCy Schubert case AF_INET6:
179257e22627SCy Schubert #endif
179357e22627SCy Schubert sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx];
179457e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL,
179557e22627SCy Schubert &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
179657e22627SCy Schubert goto error;
179757e22627SCy Schubert daemon_seraddr((struct sockaddr_storage *) address->addr, sockaddr);
179857e22627SCy Schubert
179957e22627SCy Schubert sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx];
180057e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL,
180157e22627SCy Schubert &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
180257e22627SCy Schubert goto error;
180357e22627SCy Schubert daemon_seraddr((struct sockaddr_storage *) address->netmask, sockaddr);
180457e22627SCy Schubert
180557e22627SCy Schubert sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx];
180657e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL,
180757e22627SCy Schubert &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
180857e22627SCy Schubert goto error;
180957e22627SCy Schubert daemon_seraddr((struct sockaddr_storage *) address->broadaddr, sockaddr);
181057e22627SCy Schubert
181157e22627SCy Schubert sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx];
181257e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL,
181357e22627SCy Schubert &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
181457e22627SCy Schubert goto error;
181557e22627SCy Schubert daemon_seraddr((struct sockaddr_storage *) address->dstaddr, sockaddr);
181657e22627SCy Schubert break;
181757e22627SCy Schubert
181857e22627SCy Schubert default:
181957e22627SCy Schubert break;
182057e22627SCy Schubert }
182157e22627SCy Schubert }
182257e22627SCy Schubert }
182357e22627SCy Schubert
182457e22627SCy Schubert // We no longer need the device list. Free it.
182557e22627SCy Schubert pcap_freealldevs(alldevs);
182657e22627SCy Schubert
182757e22627SCy Schubert // Send a final command that says "now send it!"
1828*6f9cba8fSJoseph Mingrone if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
182957e22627SCy Schubert {
183057e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
183157e22627SCy Schubert return -1;
183257e22627SCy Schubert }
183357e22627SCy Schubert
183457e22627SCy Schubert return 0;
183557e22627SCy Schubert
183657e22627SCy Schubert error:
183757e22627SCy Schubert if (alldevs)
183857e22627SCy Schubert pcap_freealldevs(alldevs);
183957e22627SCy Schubert
1840*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
1841*6f9cba8fSJoseph Mingrone PCAP_ERR_FINDALLIF, errmsgbuf, errbuf) == -1)
184257e22627SCy Schubert {
184357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
184457e22627SCy Schubert return -1;
184557e22627SCy Schubert }
184657e22627SCy Schubert return 0;
184757e22627SCy Schubert }
184857e22627SCy Schubert
184957e22627SCy Schubert /*
185057e22627SCy Schubert \param plen: the length of the current message (needed in order to be able
185157e22627SCy Schubert to discard excess data in the message, if present)
185257e22627SCy Schubert */
185357e22627SCy Schubert static int
daemon_msg_open_req(uint8 ver,struct daemon_slpars * pars,uint32 plen,char * source,size_t sourcelen)185457e22627SCy Schubert daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
185557e22627SCy Schubert char *source, size_t sourcelen)
185657e22627SCy Schubert {
185757e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
185857e22627SCy Schubert char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
185957e22627SCy Schubert pcap_t *fp; // pcap_t main variable
186057e22627SCy Schubert int nread;
186157e22627SCy Schubert char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
186257e22627SCy Schubert int sendbufidx = 0; // index which keeps the number of bytes currently buffered
186357e22627SCy Schubert struct rpcap_openreply *openreply; // open reply message
186457e22627SCy Schubert
186557e22627SCy Schubert if (plen > sourcelen - 1)
186657e22627SCy Schubert {
1867*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string too long");
186857e22627SCy Schubert goto error;
186957e22627SCy Schubert }
187057e22627SCy Schubert
1871*6f9cba8fSJoseph Mingrone nread = sock_recv(pars->sockctrl, pars->ssl, source, plen,
187257e22627SCy Schubert SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
187357e22627SCy Schubert if (nread == -1)
187457e22627SCy Schubert {
187557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
187657e22627SCy Schubert return -1;
187757e22627SCy Schubert }
187857e22627SCy Schubert source[nread] = '\0';
187957e22627SCy Schubert plen -= nread;
188057e22627SCy Schubert
188157e22627SCy Schubert // Is this a URL rather than a device?
188257e22627SCy Schubert // If so, reject it.
188357e22627SCy Schubert if (is_url(source))
188457e22627SCy Schubert {
1885*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string refers to a remote device");
188657e22627SCy Schubert goto error;
188757e22627SCy Schubert }
188857e22627SCy Schubert
188957e22627SCy Schubert // Open the selected device
189057e22627SCy Schubert // This is a fake open, since we do that only to get the needed parameters, then we close the device again
189157e22627SCy Schubert if ((fp = pcap_open_live(source,
189257e22627SCy Schubert 1500 /* fake snaplen */,
1893*6f9cba8fSJoseph Mingrone 0 /* no promisc */,
189457e22627SCy Schubert 1000 /* fake timeout */,
189557e22627SCy Schubert errmsgbuf)) == NULL)
189657e22627SCy Schubert goto error;
189757e22627SCy Schubert
189857e22627SCy Schubert // Now, I can send a RPCAP open reply message
189957e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
190057e22627SCy Schubert RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
190157e22627SCy Schubert goto error;
190257e22627SCy Schubert
190357e22627SCy Schubert rpcap_createhdr((struct rpcap_header *) sendbuf, ver,
190457e22627SCy Schubert RPCAP_MSG_OPEN_REPLY, 0, sizeof(struct rpcap_openreply));
190557e22627SCy Schubert
190657e22627SCy Schubert openreply = (struct rpcap_openreply *) &sendbuf[sendbufidx];
190757e22627SCy Schubert
190857e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_openreply), NULL, &sendbufidx,
190957e22627SCy Schubert RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
191057e22627SCy Schubert goto error;
191157e22627SCy Schubert
191257e22627SCy Schubert memset(openreply, 0, sizeof(struct rpcap_openreply));
191357e22627SCy Schubert openreply->linktype = htonl(pcap_datalink(fp));
1914*6f9cba8fSJoseph Mingrone /*
1915*6f9cba8fSJoseph Mingrone * This is always 0 for live captures; we no longer support it
1916*6f9cba8fSJoseph Mingrone * as something we read from capture files and supply to
1917*6f9cba8fSJoseph Mingrone * clients, but we have to send it over the wire, as open
1918*6f9cba8fSJoseph Mingrone * replies are expected to have 8 bytes of payload by
1919*6f9cba8fSJoseph Mingrone * existing clients.
1920*6f9cba8fSJoseph Mingrone */
1921*6f9cba8fSJoseph Mingrone openreply->tzoff = 0;
192257e22627SCy Schubert
192357e22627SCy Schubert // We're done with the pcap_t.
192457e22627SCy Schubert pcap_close(fp);
192557e22627SCy Schubert
192657e22627SCy Schubert // Send the reply.
1927*6f9cba8fSJoseph Mingrone if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
192857e22627SCy Schubert {
192957e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
193057e22627SCy Schubert return -1;
193157e22627SCy Schubert }
193257e22627SCy Schubert return 0;
193357e22627SCy Schubert
193457e22627SCy Schubert error:
1935*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_OPEN,
193657e22627SCy Schubert errmsgbuf, errbuf) == -1)
193757e22627SCy Schubert {
193857e22627SCy Schubert // That failed; log a message and give up.
193957e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
194057e22627SCy Schubert return -1;
194157e22627SCy Schubert }
194257e22627SCy Schubert
194357e22627SCy Schubert // Check if all the data has been read; if not, discard the data in excess
1944*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
194557e22627SCy Schubert {
194657e22627SCy Schubert return -1;
194757e22627SCy Schubert }
194857e22627SCy Schubert return 0;
194957e22627SCy Schubert }
195057e22627SCy Schubert
195157e22627SCy Schubert /*
195257e22627SCy Schubert \param plen: the length of the current message (needed in order to be able
195357e22627SCy Schubert to discard excess data in the message, if present)
195457e22627SCy Schubert */
195557e22627SCy Schubert static int
daemon_msg_startcap_req(uint8 ver,struct daemon_slpars * pars,uint32 plen,char * source,struct session ** sessionp,struct rpcap_sampling * samp_param _U_,int uses_ssl)195657e22627SCy Schubert daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
195757e22627SCy Schubert char *source, struct session **sessionp,
1958*6f9cba8fSJoseph Mingrone struct rpcap_sampling *samp_param _U_, int uses_ssl)
195957e22627SCy Schubert {
196057e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
196157e22627SCy Schubert char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
196257e22627SCy Schubert char portdata[PCAP_BUF_SIZE]; // temp variable needed to derive the data port
196357e22627SCy Schubert char peerhost[PCAP_BUF_SIZE]; // temp variable needed to derive the host name of our peer
196457e22627SCy Schubert struct session *session = NULL; // saves state of session
196557e22627SCy Schubert int status;
196657e22627SCy Schubert char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
196757e22627SCy Schubert int sendbufidx = 0; // index which keeps the number of bytes currently buffered
196857e22627SCy Schubert
196957e22627SCy Schubert // socket-related variables
197057e22627SCy Schubert struct addrinfo hints; // temp, needed to open a socket connection
197157e22627SCy Schubert struct addrinfo *addrinfo; // temp, needed to open a socket connection
197257e22627SCy Schubert struct sockaddr_storage saddr; // temp, needed to retrieve the network data port chosen on the local machine
197357e22627SCy Schubert socklen_t saddrlen; // temp, needed to retrieve the network data port chosen on the local machine
197457e22627SCy Schubert int ret; // return value from functions
197557e22627SCy Schubert
197657e22627SCy Schubert // RPCAP-related variables
197757e22627SCy Schubert struct rpcap_startcapreq startcapreq; // start capture request message
197857e22627SCy Schubert struct rpcap_startcapreply *startcapreply; // start capture reply message
197957e22627SCy Schubert int serveropen_dp; // keeps who is going to open the data connection
198057e22627SCy Schubert
198157e22627SCy Schubert addrinfo = NULL;
198257e22627SCy Schubert
1983*6f9cba8fSJoseph Mingrone status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &startcapreq,
198457e22627SCy Schubert sizeof(struct rpcap_startcapreq), &plen, errmsgbuf);
198557e22627SCy Schubert if (status == -1)
198657e22627SCy Schubert {
198757e22627SCy Schubert goto fatal_error;
198857e22627SCy Schubert }
198957e22627SCy Schubert if (status == -2)
199057e22627SCy Schubert {
199157e22627SCy Schubert goto error;
199257e22627SCy Schubert }
199357e22627SCy Schubert
199457e22627SCy Schubert startcapreq.flags = ntohs(startcapreq.flags);
199557e22627SCy Schubert
1996*6f9cba8fSJoseph Mingrone // Check that the client does not ask for UDP is the server has been asked
1997*6f9cba8fSJoseph Mingrone // to enforce encryption, as SSL is not supported yet with UDP:
1998*6f9cba8fSJoseph Mingrone if (uses_ssl && (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM))
1999*6f9cba8fSJoseph Mingrone {
2000*6f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE,
2001*6f9cba8fSJoseph Mingrone "SSL not supported with UDP forward of remote packets");
2002*6f9cba8fSJoseph Mingrone goto error;
2003*6f9cba8fSJoseph Mingrone }
2004*6f9cba8fSJoseph Mingrone
200557e22627SCy Schubert // Create a session structure
200657e22627SCy Schubert session = malloc(sizeof(struct session));
200757e22627SCy Schubert if (session == NULL)
200857e22627SCy Schubert {
2009*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Can't allocate session structure");
201057e22627SCy Schubert goto error;
201157e22627SCy Schubert }
201257e22627SCy Schubert
201357e22627SCy Schubert session->sockdata = INVALID_SOCKET;
2014*6f9cba8fSJoseph Mingrone session->ctrl_ssl = session->data_ssl = NULL;
201557e22627SCy Schubert // We don't have a thread yet.
201657e22627SCy Schubert session->have_thread = 0;
201757e22627SCy Schubert //
201857e22627SCy Schubert // We *shouldn't* have to initialize the thread indicator
201957e22627SCy Schubert // itself, because the compiler *should* realize that we
202057e22627SCy Schubert // only use this if have_thread isn't 0, but we *do* have
202157e22627SCy Schubert // to do it, because not all compilers *do* realize that.
202257e22627SCy Schubert //
202357e22627SCy Schubert // There is no "invalid thread handle" value for a UN*X
202457e22627SCy Schubert // pthread_t, so we just zero it out.
202557e22627SCy Schubert //
202657e22627SCy Schubert #ifdef _WIN32
202757e22627SCy Schubert session->thread = INVALID_HANDLE_VALUE;
202857e22627SCy Schubert #else
202957e22627SCy Schubert memset(&session->thread, 0, sizeof(session->thread));
203057e22627SCy Schubert #endif
203157e22627SCy Schubert
203257e22627SCy Schubert // Open the selected device
203357e22627SCy Schubert if ((session->fp = pcap_open_live(source,
203457e22627SCy Schubert ntohl(startcapreq.snaplen),
203557e22627SCy Schubert (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_PROMISC) ? 1 : 0 /* local device, other flags not needed */,
203657e22627SCy Schubert ntohl(startcapreq.read_timeout),
203757e22627SCy Schubert errmsgbuf)) == NULL)
203857e22627SCy Schubert goto error;
203957e22627SCy Schubert
204057e22627SCy Schubert #if 0
204157e22627SCy Schubert // Apply sampling parameters
204257e22627SCy Schubert fp->rmt_samp.method = samp_param->method;
204357e22627SCy Schubert fp->rmt_samp.value = samp_param->value;
204457e22627SCy Schubert #endif
204557e22627SCy Schubert
204657e22627SCy Schubert /*
204757e22627SCy Schubert We're in active mode if:
204857e22627SCy Schubert - we're using TCP, and the user wants us to be in active mode
204957e22627SCy Schubert - we're using UDP
205057e22627SCy Schubert */
205157e22627SCy Schubert serveropen_dp = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_SERVEROPEN) || (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) || pars->isactive;
205257e22627SCy Schubert
205357e22627SCy Schubert /*
205457e22627SCy Schubert Gets the sockaddr structure referred to the other peer in the ctrl connection
205557e22627SCy Schubert
205657e22627SCy Schubert We need that because:
205757e22627SCy Schubert - if we're in passive mode, we need to know the address family we want to use
205857e22627SCy Schubert (the same used for the ctrl socket)
205957e22627SCy Schubert - if we're in active mode, we need to know the network address of the other host
206057e22627SCy Schubert we want to connect to
206157e22627SCy Schubert */
206257e22627SCy Schubert saddrlen = sizeof(struct sockaddr_storage);
206357e22627SCy Schubert if (getpeername(pars->sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1)
206457e22627SCy Schubert {
2065*6f9cba8fSJoseph Mingrone sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE,
2066*6f9cba8fSJoseph Mingrone "getpeername() failed");
206757e22627SCy Schubert goto error;
206857e22627SCy Schubert }
206957e22627SCy Schubert
207057e22627SCy Schubert memset(&hints, 0, sizeof(struct addrinfo));
207157e22627SCy Schubert hints.ai_socktype = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
207257e22627SCy Schubert hints.ai_family = saddr.ss_family;
207357e22627SCy Schubert
207457e22627SCy Schubert // Now we have to create a new socket to send packets
207557e22627SCy Schubert if (serveropen_dp) // Data connection is opened by the server toward the client
207657e22627SCy Schubert {
2077*6f9cba8fSJoseph Mingrone snprintf(portdata, sizeof portdata, "%d", ntohs(startcapreq.portdata));
207857e22627SCy Schubert
207957e22627SCy Schubert // Get the name of the other peer (needed to connect to that specific network address)
208057e22627SCy Schubert if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peerhost,
208157e22627SCy Schubert sizeof(peerhost), NULL, 0, NI_NUMERICHOST))
208257e22627SCy Schubert {
2083*6f9cba8fSJoseph Mingrone sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE,
2084*6f9cba8fSJoseph Mingrone "getnameinfo() failed");
208557e22627SCy Schubert goto error;
208657e22627SCy Schubert }
208757e22627SCy Schubert
208857e22627SCy Schubert if (sock_initaddress(peerhost, portdata, &hints, &addrinfo, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
208957e22627SCy Schubert goto error;
209057e22627SCy Schubert
2091*6f9cba8fSJoseph Mingrone if ((session->sockdata = sock_open(peerhost, addrinfo, SOCKOPEN_CLIENT, 0, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
209257e22627SCy Schubert goto error;
209357e22627SCy Schubert }
209457e22627SCy Schubert else // Data connection is opened by the client toward the server
209557e22627SCy Schubert {
209657e22627SCy Schubert hints.ai_flags = AI_PASSIVE;
209757e22627SCy Schubert
2098*6f9cba8fSJoseph Mingrone // Make the server socket pick up a free network port for us
2099*6f9cba8fSJoseph Mingrone if (sock_initaddress(NULL, NULL, &hints, &addrinfo, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
210057e22627SCy Schubert goto error;
210157e22627SCy Schubert
2102*6f9cba8fSJoseph Mingrone if ((session->sockdata = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
210357e22627SCy Schubert goto error;
210457e22627SCy Schubert
210557e22627SCy Schubert // get the complete sockaddr structure used in the data connection
210657e22627SCy Schubert saddrlen = sizeof(struct sockaddr_storage);
210757e22627SCy Schubert if (getsockname(session->sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1)
210857e22627SCy Schubert {
2109*6f9cba8fSJoseph Mingrone sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE,
2110*6f9cba8fSJoseph Mingrone "getsockname() failed");
211157e22627SCy Schubert goto error;
211257e22627SCy Schubert }
211357e22627SCy Schubert
211457e22627SCy Schubert // Get the local port the system picked up
211557e22627SCy Schubert if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL,
211657e22627SCy Schubert 0, portdata, sizeof(portdata), NI_NUMERICSERV))
211757e22627SCy Schubert {
2118*6f9cba8fSJoseph Mingrone sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE,
2119*6f9cba8fSJoseph Mingrone "getnameinfo() failed");
212057e22627SCy Schubert goto error;
212157e22627SCy Schubert }
212257e22627SCy Schubert }
212357e22627SCy Schubert
212457e22627SCy Schubert // addrinfo is no longer used
212557e22627SCy Schubert freeaddrinfo(addrinfo);
212657e22627SCy Schubert addrinfo = NULL;
212757e22627SCy Schubert
212857e22627SCy Schubert // Needed to send an error on the ctrl connection
212957e22627SCy Schubert session->sockctrl = pars->sockctrl;
2130*6f9cba8fSJoseph Mingrone session->ctrl_ssl = pars->ssl;
213157e22627SCy Schubert session->protocol_version = ver;
213257e22627SCy Schubert
213357e22627SCy Schubert // Now I can set the filter
2134*6f9cba8fSJoseph Mingrone ret = daemon_unpackapplyfilter(pars->sockctrl, pars->ssl, session, &plen, errmsgbuf);
213557e22627SCy Schubert if (ret == -1)
213657e22627SCy Schubert {
213757e22627SCy Schubert // Fatal error. A message has been logged; just give up.
213857e22627SCy Schubert goto fatal_error;
213957e22627SCy Schubert }
214057e22627SCy Schubert if (ret == -2)
214157e22627SCy Schubert {
214257e22627SCy Schubert // Non-fatal error. Send an error message to the client.
214357e22627SCy Schubert goto error;
214457e22627SCy Schubert }
214557e22627SCy Schubert
214657e22627SCy Schubert // Now, I can send a RPCAP start capture reply message
214757e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
214857e22627SCy Schubert RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
214957e22627SCy Schubert goto error;
215057e22627SCy Schubert
215157e22627SCy Schubert rpcap_createhdr((struct rpcap_header *) sendbuf, ver,
215257e22627SCy Schubert RPCAP_MSG_STARTCAP_REPLY, 0, sizeof(struct rpcap_startcapreply));
215357e22627SCy Schubert
215457e22627SCy Schubert startcapreply = (struct rpcap_startcapreply *) &sendbuf[sendbufidx];
215557e22627SCy Schubert
215657e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_startcapreply), NULL,
215757e22627SCy Schubert &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
215857e22627SCy Schubert goto error;
215957e22627SCy Schubert
216057e22627SCy Schubert memset(startcapreply, 0, sizeof(struct rpcap_startcapreply));
216157e22627SCy Schubert startcapreply->bufsize = htonl(pcap_bufsize(session->fp));
216257e22627SCy Schubert
216357e22627SCy Schubert if (!serveropen_dp)
216457e22627SCy Schubert {
216557e22627SCy Schubert unsigned short port = (unsigned short)strtoul(portdata,NULL,10);
216657e22627SCy Schubert startcapreply->portdata = htons(port);
216757e22627SCy Schubert }
216857e22627SCy Schubert
2169*6f9cba8fSJoseph Mingrone if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
217057e22627SCy Schubert {
217157e22627SCy Schubert // That failed; log a message and give up.
217257e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
217357e22627SCy Schubert goto fatal_error;
217457e22627SCy Schubert }
217557e22627SCy Schubert
217657e22627SCy Schubert if (!serveropen_dp)
217757e22627SCy Schubert {
217857e22627SCy Schubert SOCKET socktemp; // We need another socket, since we're going to accept() a connection
217957e22627SCy Schubert
218057e22627SCy Schubert // Connection creation
218157e22627SCy Schubert saddrlen = sizeof(struct sockaddr_storage);
218257e22627SCy Schubert
218357e22627SCy Schubert socktemp = accept(session->sockdata, (struct sockaddr *) &saddr, &saddrlen);
218457e22627SCy Schubert
218557e22627SCy Schubert if (socktemp == INVALID_SOCKET)
218657e22627SCy Schubert {
2187*6f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
2188*6f9cba8fSJoseph Mingrone "accept() failed");
218957e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Accept of data connection failed: %s",
219057e22627SCy Schubert errbuf);
219157e22627SCy Schubert goto error;
219257e22627SCy Schubert }
219357e22627SCy Schubert
219457e22627SCy Schubert // Now that I accepted the connection, the server socket is no longer needed
219557e22627SCy Schubert sock_close(session->sockdata, NULL, 0);
219657e22627SCy Schubert session->sockdata = socktemp;
219757e22627SCy Schubert }
219857e22627SCy Schubert
2199*6f9cba8fSJoseph Mingrone SSL *ssl = NULL;
2200*6f9cba8fSJoseph Mingrone if (uses_ssl)
2201*6f9cba8fSJoseph Mingrone {
2202*6f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
2203*6f9cba8fSJoseph Mingrone /* In both active or passive cases, wait for the client to initiate the
2204*6f9cba8fSJoseph Mingrone * TLS handshake. Yes during that time the control socket will not be
2205*6f9cba8fSJoseph Mingrone * served, but the same was true from the above call to accept(). */
2206*6f9cba8fSJoseph Mingrone ssl = ssl_promotion(1, session->sockdata, errbuf, PCAP_ERRBUF_SIZE);
2207*6f9cba8fSJoseph Mingrone if (! ssl)
2208*6f9cba8fSJoseph Mingrone {
2209*6f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR, "TLS handshake failed: %s", errbuf);
2210*6f9cba8fSJoseph Mingrone goto error;
2211*6f9cba8fSJoseph Mingrone }
2212*6f9cba8fSJoseph Mingrone #endif
2213*6f9cba8fSJoseph Mingrone }
2214*6f9cba8fSJoseph Mingrone session->data_ssl = ssl;
2215*6f9cba8fSJoseph Mingrone
221657e22627SCy Schubert // Now we have to create a new thread to receive packets
221757e22627SCy Schubert #ifdef _WIN32
221857e22627SCy Schubert session->thread = (HANDLE)_beginthreadex(NULL, 0, daemon_thrdatamain,
221957e22627SCy Schubert (void *) session, 0, NULL);
222057e22627SCy Schubert if (session->thread == 0)
222157e22627SCy Schubert {
2222*6f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread");
222357e22627SCy Schubert goto error;
222457e22627SCy Schubert }
222557e22627SCy Schubert #else
222657e22627SCy Schubert ret = pthread_create(&session->thread, NULL, daemon_thrdatamain,
222757e22627SCy Schubert (void *) session);
222857e22627SCy Schubert if (ret != 0)
222957e22627SCy Schubert {
223057e22627SCy Schubert pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
223157e22627SCy Schubert ret, "Error creating the data thread");
223257e22627SCy Schubert goto error;
223357e22627SCy Schubert }
223457e22627SCy Schubert #endif
223557e22627SCy Schubert session->have_thread = 1;
223657e22627SCy Schubert
223757e22627SCy Schubert // Check if all the data has been read; if not, discard the data in excess
2238*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
223957e22627SCy Schubert goto fatal_error;
224057e22627SCy Schubert
224157e22627SCy Schubert *sessionp = session;
224257e22627SCy Schubert return 0;
224357e22627SCy Schubert
224457e22627SCy Schubert error:
224557e22627SCy Schubert //
224657e22627SCy Schubert // Not a fatal error, so send the client an error message and
224757e22627SCy Schubert // keep serving client requests.
224857e22627SCy Schubert //
224957e22627SCy Schubert *sessionp = NULL;
225057e22627SCy Schubert
225157e22627SCy Schubert if (addrinfo)
225257e22627SCy Schubert freeaddrinfo(addrinfo);
225357e22627SCy Schubert
225457e22627SCy Schubert if (session)
225557e22627SCy Schubert {
225657e22627SCy Schubert session_close(session);
225757e22627SCy Schubert free(session);
225857e22627SCy Schubert }
225957e22627SCy Schubert
2260*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
2261*6f9cba8fSJoseph Mingrone PCAP_ERR_STARTCAPTURE, errmsgbuf, errbuf) == -1)
226257e22627SCy Schubert {
226357e22627SCy Schubert // That failed; log a message and give up.
226457e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
226557e22627SCy Schubert return -1;
226657e22627SCy Schubert }
226757e22627SCy Schubert
226857e22627SCy Schubert // Check if all the data has been read; if not, discard the data in excess
2269*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
227057e22627SCy Schubert {
227157e22627SCy Schubert // Network error.
227257e22627SCy Schubert return -1;
227357e22627SCy Schubert }
227457e22627SCy Schubert
227557e22627SCy Schubert return 0;
227657e22627SCy Schubert
227757e22627SCy Schubert fatal_error:
227857e22627SCy Schubert //
227957e22627SCy Schubert // Fatal network error, so don't try to communicate with
228057e22627SCy Schubert // the client, just give up.
228157e22627SCy Schubert //
228257e22627SCy Schubert *sessionp = NULL;
228357e22627SCy Schubert
228457e22627SCy Schubert if (session)
228557e22627SCy Schubert {
228657e22627SCy Schubert session_close(session);
228757e22627SCy Schubert free(session);
228857e22627SCy Schubert }
228957e22627SCy Schubert
229057e22627SCy Schubert return -1;
229157e22627SCy Schubert }
229257e22627SCy Schubert
229357e22627SCy Schubert static int
daemon_msg_endcap_req(uint8 ver,struct daemon_slpars * pars,struct session * session)229457e22627SCy Schubert daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars,
229557e22627SCy Schubert struct session *session)
229657e22627SCy Schubert {
229757e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
229857e22627SCy Schubert struct rpcap_header header;
229957e22627SCy Schubert
230057e22627SCy Schubert session_close(session);
230157e22627SCy Schubert
230257e22627SCy Schubert rpcap_createhdr(&header, ver, RPCAP_MSG_ENDCAP_REPLY, 0, 0);
230357e22627SCy Schubert
2304*6f9cba8fSJoseph Mingrone if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
230557e22627SCy Schubert {
230657e22627SCy Schubert // That failed; log a message and give up.
230757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
230857e22627SCy Schubert return -1;
230957e22627SCy Schubert }
231057e22627SCy Schubert
231157e22627SCy Schubert return 0;
231257e22627SCy Schubert }
231357e22627SCy Schubert
231457e22627SCy Schubert //
231557e22627SCy Schubert // We impose a limit on the filter program size, so that, on Windows,
231657e22627SCy Schubert // where there's only one server process with multiple threads, it's
231757e22627SCy Schubert // harder to eat all the server address space by sending larger filter
231857e22627SCy Schubert // programs. (This isn't an issue on UN*X, where there are multiple
231957e22627SCy Schubert // server processes, one per client connection.)
232057e22627SCy Schubert //
232157e22627SCy Schubert // We pick a value that limits each filter to 64K; that value is twice
232257e22627SCy Schubert // the in-kernel limit for Linux and 16 times the in-kernel limit for
232357e22627SCy Schubert // *BSD and macOS.
232457e22627SCy Schubert //
232557e22627SCy Schubert // It also prevents an overflow on 32-bit platforms when calculating
232657e22627SCy Schubert // the total size of the filter program. (It's not an issue on 64-bit
232757e22627SCy Schubert // platforms with a 64-bit size_t, as the filter size is 32 bits.)
232857e22627SCy Schubert //
232957e22627SCy Schubert #define RPCAP_BPF_MAXINSNS 8192
233057e22627SCy Schubert
233157e22627SCy Schubert static int
daemon_unpackapplyfilter(SOCKET sockctrl,SSL * ctrl_ssl,struct session * session,uint32 * plenp,char * errmsgbuf)2332*6f9cba8fSJoseph Mingrone daemon_unpackapplyfilter(SOCKET sockctrl, SSL *ctrl_ssl, struct session *session, uint32 *plenp, char *errmsgbuf)
233357e22627SCy Schubert {
233457e22627SCy Schubert int status;
233557e22627SCy Schubert struct rpcap_filter filter;
233657e22627SCy Schubert struct rpcap_filterbpf_insn insn;
233757e22627SCy Schubert struct bpf_insn *bf_insn;
233857e22627SCy Schubert struct bpf_program bf_prog;
233957e22627SCy Schubert unsigned int i;
234057e22627SCy Schubert
2341*6f9cba8fSJoseph Mingrone status = rpcapd_recv(sockctrl, ctrl_ssl, (char *) &filter,
234257e22627SCy Schubert sizeof(struct rpcap_filter), plenp, errmsgbuf);
234357e22627SCy Schubert if (status == -1)
234457e22627SCy Schubert {
234557e22627SCy Schubert return -1;
234657e22627SCy Schubert }
234757e22627SCy Schubert if (status == -2)
234857e22627SCy Schubert {
234957e22627SCy Schubert return -2;
235057e22627SCy Schubert }
235157e22627SCy Schubert
235257e22627SCy Schubert bf_prog.bf_len = ntohl(filter.nitems);
235357e22627SCy Schubert
235457e22627SCy Schubert if (ntohs(filter.filtertype) != RPCAP_UPDATEFILTER_BPF)
235557e22627SCy Schubert {
2356*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported");
235757e22627SCy Schubert return -2;
235857e22627SCy Schubert }
235957e22627SCy Schubert
236057e22627SCy Schubert if (bf_prog.bf_len > RPCAP_BPF_MAXINSNS)
236157e22627SCy Schubert {
2362*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
2363*6f9cba8fSJoseph Mingrone "Filter program is larger than the maximum size of %d instructions",
236457e22627SCy Schubert RPCAP_BPF_MAXINSNS);
236557e22627SCy Schubert return -2;
236657e22627SCy Schubert }
236757e22627SCy Schubert bf_insn = (struct bpf_insn *) malloc (sizeof(struct bpf_insn) * bf_prog.bf_len);
236857e22627SCy Schubert if (bf_insn == NULL)
236957e22627SCy Schubert {
237057e22627SCy Schubert pcap_fmt_errmsg_for_errno(errmsgbuf, PCAP_ERRBUF_SIZE,
237157e22627SCy Schubert errno, "malloc() failed");
237257e22627SCy Schubert return -2;
237357e22627SCy Schubert }
237457e22627SCy Schubert
237557e22627SCy Schubert bf_prog.bf_insns = bf_insn;
237657e22627SCy Schubert
237757e22627SCy Schubert for (i = 0; i < bf_prog.bf_len; i++)
237857e22627SCy Schubert {
2379*6f9cba8fSJoseph Mingrone status = rpcapd_recv(sockctrl, ctrl_ssl, (char *) &insn,
238057e22627SCy Schubert sizeof(struct rpcap_filterbpf_insn), plenp, errmsgbuf);
238157e22627SCy Schubert if (status == -1)
238257e22627SCy Schubert {
238357e22627SCy Schubert return -1;
238457e22627SCy Schubert }
238557e22627SCy Schubert if (status == -2)
238657e22627SCy Schubert {
238757e22627SCy Schubert return -2;
238857e22627SCy Schubert }
238957e22627SCy Schubert
239057e22627SCy Schubert bf_insn->code = ntohs(insn.code);
239157e22627SCy Schubert bf_insn->jf = insn.jf;
239257e22627SCy Schubert bf_insn->jt = insn.jt;
239357e22627SCy Schubert bf_insn->k = ntohl(insn.k);
239457e22627SCy Schubert
239557e22627SCy Schubert bf_insn++;
239657e22627SCy Schubert }
239757e22627SCy Schubert
2398*6f9cba8fSJoseph Mingrone //
2399*6f9cba8fSJoseph Mingrone // XXX - pcap_setfilter() should do the validation for us.
2400*6f9cba8fSJoseph Mingrone //
240157e22627SCy Schubert if (bpf_validate(bf_prog.bf_insns, bf_prog.bf_len) == 0)
240257e22627SCy Schubert {
2403*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions");
240457e22627SCy Schubert return -2;
240557e22627SCy Schubert }
240657e22627SCy Schubert
240757e22627SCy Schubert if (pcap_setfilter(session->fp, &bf_prog))
240857e22627SCy Schubert {
2409*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", pcap_geterr(session->fp));
241057e22627SCy Schubert return -2;
241157e22627SCy Schubert }
241257e22627SCy Schubert
241357e22627SCy Schubert return 0;
241457e22627SCy Schubert }
241557e22627SCy Schubert
241657e22627SCy Schubert static int
daemon_msg_updatefilter_req(uint8 ver,struct daemon_slpars * pars,struct session * session,uint32 plen)241757e22627SCy Schubert daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
241857e22627SCy Schubert struct session *session, uint32 plen)
241957e22627SCy Schubert {
242057e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE];
242157e22627SCy Schubert char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
242257e22627SCy Schubert int ret; // status of daemon_unpackapplyfilter()
242357e22627SCy Schubert struct rpcap_header header; // keeps the answer to the updatefilter command
242457e22627SCy Schubert
2425*6f9cba8fSJoseph Mingrone ret = daemon_unpackapplyfilter(pars->sockctrl, pars->ssl, session, &plen, errmsgbuf);
242657e22627SCy Schubert if (ret == -1)
242757e22627SCy Schubert {
242857e22627SCy Schubert // Fatal error. A message has been logged; just give up.
242957e22627SCy Schubert return -1;
243057e22627SCy Schubert }
243157e22627SCy Schubert if (ret == -2)
243257e22627SCy Schubert {
243357e22627SCy Schubert // Non-fatal error. Send an error reply to the client.
243457e22627SCy Schubert goto error;
243557e22627SCy Schubert }
243657e22627SCy Schubert
243757e22627SCy Schubert // Check if all the data has been read; if not, discard the data in excess
2438*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
243957e22627SCy Schubert {
244057e22627SCy Schubert // Network error.
244157e22627SCy Schubert return -1;
244257e22627SCy Schubert }
244357e22627SCy Schubert
244457e22627SCy Schubert // A response is needed, otherwise the other host does not know that everything went well
244557e22627SCy Schubert rpcap_createhdr(&header, ver, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
244657e22627SCy Schubert
2447*6f9cba8fSJoseph Mingrone if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE))
244857e22627SCy Schubert {
2449*6f9cba8fSJoseph Mingrone // That failed; log a message and give up.
245057e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
245157e22627SCy Schubert return -1;
245257e22627SCy Schubert }
245357e22627SCy Schubert
245457e22627SCy Schubert return 0;
245557e22627SCy Schubert
245657e22627SCy Schubert error:
2457*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
245857e22627SCy Schubert {
245957e22627SCy Schubert return -1;
246057e22627SCy Schubert }
2461*6f9cba8fSJoseph Mingrone rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_UPDATEFILTER,
246257e22627SCy Schubert errmsgbuf, NULL);
246357e22627SCy Schubert
246457e22627SCy Schubert return 0;
246557e22627SCy Schubert }
246657e22627SCy Schubert
246757e22627SCy Schubert /*!
246857e22627SCy Schubert \brief Received the sampling parameters from remote host and it stores in the pcap_t structure.
246957e22627SCy Schubert */
247057e22627SCy Schubert static int
daemon_msg_setsampling_req(uint8 ver,struct daemon_slpars * pars,uint32 plen,struct rpcap_sampling * samp_param)247157e22627SCy Schubert daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
247257e22627SCy Schubert struct rpcap_sampling *samp_param)
247357e22627SCy Schubert {
247457e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
247557e22627SCy Schubert char errmsgbuf[PCAP_ERRBUF_SIZE];
247657e22627SCy Schubert struct rpcap_header header;
247757e22627SCy Schubert struct rpcap_sampling rpcap_samp;
247857e22627SCy Schubert int status;
247957e22627SCy Schubert
2480*6f9cba8fSJoseph Mingrone status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf);
248157e22627SCy Schubert if (status == -1)
248257e22627SCy Schubert {
248357e22627SCy Schubert return -1;
248457e22627SCy Schubert }
248557e22627SCy Schubert if (status == -2)
248657e22627SCy Schubert {
248757e22627SCy Schubert goto error;
248857e22627SCy Schubert }
248957e22627SCy Schubert
249057e22627SCy Schubert // Save these settings in the pcap_t
249157e22627SCy Schubert samp_param->method = rpcap_samp.method;
249257e22627SCy Schubert samp_param->value = ntohl(rpcap_samp.value);
249357e22627SCy Schubert
249457e22627SCy Schubert // A response is needed, otherwise the other host does not know that everything went well
249557e22627SCy Schubert rpcap_createhdr(&header, ver, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0);
249657e22627SCy Schubert
2497*6f9cba8fSJoseph Mingrone if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
249857e22627SCy Schubert {
2499*6f9cba8fSJoseph Mingrone // That failed; log a message and give up.
250057e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
250157e22627SCy Schubert return -1;
250257e22627SCy Schubert }
250357e22627SCy Schubert
2504*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
250557e22627SCy Schubert {
250657e22627SCy Schubert return -1;
250757e22627SCy Schubert }
250857e22627SCy Schubert
250957e22627SCy Schubert return 0;
251057e22627SCy Schubert
251157e22627SCy Schubert error:
2512*6f9cba8fSJoseph Mingrone if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_SETSAMPLING,
251357e22627SCy Schubert errmsgbuf, errbuf) == -1)
251457e22627SCy Schubert {
251557e22627SCy Schubert // That failed; log a message and give up.
251657e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
251757e22627SCy Schubert return -1;
251857e22627SCy Schubert }
251957e22627SCy Schubert
252057e22627SCy Schubert // Check if all the data has been read; if not, discard the data in excess
2521*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
252257e22627SCy Schubert {
252357e22627SCy Schubert return -1;
252457e22627SCy Schubert }
252557e22627SCy Schubert
252657e22627SCy Schubert return 0;
252757e22627SCy Schubert }
252857e22627SCy Schubert
252957e22627SCy Schubert static int
daemon_msg_stats_req(uint8 ver,struct daemon_slpars * pars,struct session * session,uint32 plen,struct pcap_stat * stats,unsigned int svrcapt)253057e22627SCy Schubert daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
253157e22627SCy Schubert struct session *session, uint32 plen, struct pcap_stat *stats,
253257e22627SCy Schubert unsigned int svrcapt)
253357e22627SCy Schubert {
253457e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
253557e22627SCy Schubert char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
253657e22627SCy Schubert char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
253757e22627SCy Schubert int sendbufidx = 0; // index which keeps the number of bytes currently buffered
253857e22627SCy Schubert struct rpcap_stats *netstats; // statistics sent on the network
253957e22627SCy Schubert
254057e22627SCy Schubert // Checks that the header does not contain other data; if so, discard it
2541*6f9cba8fSJoseph Mingrone if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
254257e22627SCy Schubert {
254357e22627SCy Schubert // Network error.
254457e22627SCy Schubert return -1;
254557e22627SCy Schubert }
254657e22627SCy Schubert
254757e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
254857e22627SCy Schubert &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
254957e22627SCy Schubert goto error;
255057e22627SCy Schubert
255157e22627SCy Schubert rpcap_createhdr((struct rpcap_header *) sendbuf, ver,
255257e22627SCy Schubert RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats));
255357e22627SCy Schubert
255457e22627SCy Schubert netstats = (struct rpcap_stats *) &sendbuf[sendbufidx];
255557e22627SCy Schubert
255657e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL,
255757e22627SCy Schubert &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
255857e22627SCy Schubert goto error;
255957e22627SCy Schubert
256057e22627SCy Schubert if (session && session->fp)
256157e22627SCy Schubert {
256257e22627SCy Schubert if (pcap_stats(session->fp, stats) == -1)
256357e22627SCy Schubert {
2564*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s", pcap_geterr(session->fp));
256557e22627SCy Schubert goto error;
256657e22627SCy Schubert }
256757e22627SCy Schubert
256857e22627SCy Schubert netstats->ifdrop = htonl(stats->ps_ifdrop);
256957e22627SCy Schubert netstats->ifrecv = htonl(stats->ps_recv);
257057e22627SCy Schubert netstats->krnldrop = htonl(stats->ps_drop);
257157e22627SCy Schubert netstats->svrcapt = htonl(session->TotCapt);
257257e22627SCy Schubert }
257357e22627SCy Schubert else
257457e22627SCy Schubert {
257557e22627SCy Schubert // We have to keep compatibility with old applications,
257657e22627SCy Schubert // which ask for statistics also when the capture has
257757e22627SCy Schubert // already stopped.
257857e22627SCy Schubert netstats->ifdrop = htonl(stats->ps_ifdrop);
257957e22627SCy Schubert netstats->ifrecv = htonl(stats->ps_recv);
258057e22627SCy Schubert netstats->krnldrop = htonl(stats->ps_drop);
258157e22627SCy Schubert netstats->svrcapt = htonl(svrcapt);
258257e22627SCy Schubert }
258357e22627SCy Schubert
258457e22627SCy Schubert // Send the packet
2585*6f9cba8fSJoseph Mingrone if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
258657e22627SCy Schubert {
258757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
258857e22627SCy Schubert return -1;
258957e22627SCy Schubert }
259057e22627SCy Schubert
259157e22627SCy Schubert return 0;
259257e22627SCy Schubert
259357e22627SCy Schubert error:
2594*6f9cba8fSJoseph Mingrone rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_GETSTATS,
259557e22627SCy Schubert errmsgbuf, NULL);
259657e22627SCy Schubert return 0;
259757e22627SCy Schubert }
259857e22627SCy Schubert
259957e22627SCy Schubert #ifdef _WIN32
260057e22627SCy Schubert static unsigned __stdcall
260157e22627SCy Schubert #else
260257e22627SCy Schubert static void *
260357e22627SCy Schubert #endif
daemon_thrdatamain(void * ptr)260457e22627SCy Schubert daemon_thrdatamain(void *ptr)
260557e22627SCy Schubert {
260657e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE + 1]; // error buffer
260757e22627SCy Schubert struct session *session; // pointer to the struct session for this session
260857e22627SCy Schubert int retval; // general variable used to keep the return value of other functions
260957e22627SCy Schubert struct rpcap_pkthdr *net_pkt_header;// header of the packet
261057e22627SCy Schubert struct pcap_pkthdr *pkt_header; // pointer to the buffer that contains the header of the current packet
261157e22627SCy Schubert u_char *pkt_data; // pointer to the buffer that contains the current packet
261257e22627SCy Schubert size_t sendbufsize; // size for the send buffer
261357e22627SCy Schubert char *sendbuf; // temporary buffer in which data to be sent is buffered
261457e22627SCy Schubert int sendbufidx; // index which keeps the number of bytes currently buffered
261557e22627SCy Schubert int status;
261657e22627SCy Schubert #ifndef _WIN32
261757e22627SCy Schubert sigset_t sigusr1; // signal set with just SIGUSR1
261857e22627SCy Schubert #endif
261957e22627SCy Schubert
262057e22627SCy Schubert session = (struct session *) ptr;
262157e22627SCy Schubert
262257e22627SCy Schubert session->TotCapt = 0; // counter which is incremented each time a packet is received
262357e22627SCy Schubert
262457e22627SCy Schubert // Initialize errbuf
262557e22627SCy Schubert memset(errbuf, 0, sizeof(errbuf));
262657e22627SCy Schubert
262757e22627SCy Schubert //
262857e22627SCy Schubert // We need a buffer large enough to hold a buffer large enough
262957e22627SCy Schubert // for a maximum-size packet for this pcap_t.
263057e22627SCy Schubert //
263157e22627SCy Schubert if (pcap_snapshot(session->fp) < 0)
263257e22627SCy Schubert {
263357e22627SCy Schubert //
263457e22627SCy Schubert // The snapshot length is negative.
263557e22627SCy Schubert // This "should not happen".
263657e22627SCy Schubert //
263757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR,
263857e22627SCy Schubert "Unable to allocate the buffer for this child thread: snapshot length of %d is negative",
263957e22627SCy Schubert pcap_snapshot(session->fp));
264057e22627SCy Schubert sendbuf = NULL; // we can't allocate a buffer, so nothing to free
264157e22627SCy Schubert goto error;
264257e22627SCy Schubert }
264357e22627SCy Schubert //
264457e22627SCy Schubert // size_t is unsigned, and the result of pcap_snapshot() is signed;
264557e22627SCy Schubert // on no platform that we support is int larger than size_t.
264657e22627SCy Schubert // This means that, unless the extra information we prepend to
264757e22627SCy Schubert // a maximum-sized packet is impossibly large, the sum of the
264857e22627SCy Schubert // snapshot length and the size of that extra information will
264957e22627SCy Schubert // fit in a size_t.
265057e22627SCy Schubert //
265157e22627SCy Schubert // So we don't need to make sure that sendbufsize will overflow.
265257e22627SCy Schubert //
2653*6f9cba8fSJoseph Mingrone // However, we *do* need to make sure its value fits in an int,
2654*6f9cba8fSJoseph Mingrone // because sock_send() can't send more than INT_MAX bytes (it could
2655*6f9cba8fSJoseph Mingrone // do so on 64-bit UN*Xes, but can't do so on Windows, not even
2656*6f9cba8fSJoseph Mingrone // 64-bit Windows, as the send() buffer size argument is an int
2657*6f9cba8fSJoseph Mingrone // in Winsock).
2658*6f9cba8fSJoseph Mingrone //
265957e22627SCy Schubert sendbufsize = sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr) + pcap_snapshot(session->fp);
2660*6f9cba8fSJoseph Mingrone if (sendbufsize > INT_MAX)
2661*6f9cba8fSJoseph Mingrone {
2662*6f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR,
2663*6f9cba8fSJoseph Mingrone "Buffer size for this child thread would be larger than %d",
2664*6f9cba8fSJoseph Mingrone INT_MAX);
2665*6f9cba8fSJoseph Mingrone sendbuf = NULL; // we haven't allocated a buffer, so nothing to free
2666*6f9cba8fSJoseph Mingrone goto error;
2667*6f9cba8fSJoseph Mingrone }
266857e22627SCy Schubert sendbuf = (char *) malloc (sendbufsize);
266957e22627SCy Schubert if (sendbuf == NULL)
267057e22627SCy Schubert {
267157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR,
267257e22627SCy Schubert "Unable to allocate the buffer for this child thread");
267357e22627SCy Schubert goto error;
267457e22627SCy Schubert }
267557e22627SCy Schubert
267657e22627SCy Schubert #ifndef _WIN32
267757e22627SCy Schubert //
267857e22627SCy Schubert // Set the signal set to include just SIGUSR1, and block that
267957e22627SCy Schubert // signal; we only want it unblocked when we're reading
268057e22627SCy Schubert // packets - we dn't want any other system calls, such as
268157e22627SCy Schubert // ones being used to send to the client or to log messages,
268257e22627SCy Schubert // to be interrupted.
268357e22627SCy Schubert //
268457e22627SCy Schubert sigemptyset(&sigusr1);
268557e22627SCy Schubert sigaddset(&sigusr1, SIGUSR1);
268657e22627SCy Schubert pthread_sigmask(SIG_BLOCK, &sigusr1, NULL);
268757e22627SCy Schubert #endif
268857e22627SCy Schubert
268957e22627SCy Schubert // Retrieve the packets
269057e22627SCy Schubert for (;;)
269157e22627SCy Schubert {
269257e22627SCy Schubert #ifndef _WIN32
269357e22627SCy Schubert //
269457e22627SCy Schubert // Unblock SIGUSR1 while we might be waiting for packets.
269557e22627SCy Schubert //
269657e22627SCy Schubert pthread_sigmask(SIG_UNBLOCK, &sigusr1, NULL);
269757e22627SCy Schubert #endif
269857e22627SCy Schubert retval = pcap_next_ex(session->fp, &pkt_header, (const u_char **) &pkt_data); // cast to avoid a compiler warning
269957e22627SCy Schubert #ifndef _WIN32
270057e22627SCy Schubert //
270157e22627SCy Schubert // Now block it again.
270257e22627SCy Schubert //
270357e22627SCy Schubert pthread_sigmask(SIG_BLOCK, &sigusr1, NULL);
270457e22627SCy Schubert #endif
270557e22627SCy Schubert if (retval < 0)
270657e22627SCy Schubert break; // error
270757e22627SCy Schubert if (retval == 0) // Read timeout elapsed
270857e22627SCy Schubert continue;
270957e22627SCy Schubert
271057e22627SCy Schubert sendbufidx = 0;
271157e22627SCy Schubert
271257e22627SCy Schubert // Bufferize the general header
271357e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
2714*6f9cba8fSJoseph Mingrone &sendbufidx, (int)sendbufsize, SOCKBUF_CHECKONLY, errbuf,
271557e22627SCy Schubert PCAP_ERRBUF_SIZE) == -1)
271657e22627SCy Schubert {
271757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR,
271857e22627SCy Schubert "sock_bufferize() error sending packet message: %s",
271957e22627SCy Schubert errbuf);
272057e22627SCy Schubert goto error;
272157e22627SCy Schubert }
272257e22627SCy Schubert
272357e22627SCy Schubert rpcap_createhdr((struct rpcap_header *) sendbuf,
272457e22627SCy Schubert session->protocol_version, RPCAP_MSG_PACKET, 0,
272557e22627SCy Schubert (uint16) (sizeof(struct rpcap_pkthdr) + pkt_header->caplen));
272657e22627SCy Schubert
272757e22627SCy Schubert net_pkt_header = (struct rpcap_pkthdr *) &sendbuf[sendbufidx];
272857e22627SCy Schubert
272957e22627SCy Schubert // Bufferize the pkt header
273057e22627SCy Schubert if (sock_bufferize(NULL, sizeof(struct rpcap_pkthdr), NULL,
2731*6f9cba8fSJoseph Mingrone &sendbufidx, (int)sendbufsize, SOCKBUF_CHECKONLY, errbuf,
273257e22627SCy Schubert PCAP_ERRBUF_SIZE) == -1)
273357e22627SCy Schubert {
273457e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR,
273557e22627SCy Schubert "sock_bufferize() error sending packet message: %s",
273657e22627SCy Schubert errbuf);
273757e22627SCy Schubert goto error;
273857e22627SCy Schubert }
273957e22627SCy Schubert
274057e22627SCy Schubert net_pkt_header->caplen = htonl(pkt_header->caplen);
274157e22627SCy Schubert net_pkt_header->len = htonl(pkt_header->len);
274257e22627SCy Schubert net_pkt_header->npkt = htonl(++(session->TotCapt));
2743*6f9cba8fSJoseph Mingrone //
2744*6f9cba8fSJoseph Mingrone // This protocol needs to be updated with a new version
2745*6f9cba8fSJoseph Mingrone // before 2038-01-19 03:14:07 UTC.
2746*6f9cba8fSJoseph Mingrone //
2747*6f9cba8fSJoseph Mingrone net_pkt_header->timestamp_sec = htonl((uint32)pkt_header->ts.tv_sec);
2748*6f9cba8fSJoseph Mingrone net_pkt_header->timestamp_usec = htonl((uint32)pkt_header->ts.tv_usec);
274957e22627SCy Schubert
275057e22627SCy Schubert // Bufferize the pkt data
275157e22627SCy Schubert if (sock_bufferize((char *) pkt_data, pkt_header->caplen,
2752*6f9cba8fSJoseph Mingrone sendbuf, &sendbufidx, (int)sendbufsize, SOCKBUF_BUFFERIZE,
275357e22627SCy Schubert errbuf, PCAP_ERRBUF_SIZE) == -1)
275457e22627SCy Schubert {
275557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR,
275657e22627SCy Schubert "sock_bufferize() error sending packet message: %s",
275757e22627SCy Schubert errbuf);
275857e22627SCy Schubert goto error;
275957e22627SCy Schubert }
276057e22627SCy Schubert
276157e22627SCy Schubert // Send the packet
276257e22627SCy Schubert // If the client dropped the connection, don't report an
276357e22627SCy Schubert // error, just quit.
2764*6f9cba8fSJoseph Mingrone status = sock_send(session->sockdata, session->data_ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE);
276557e22627SCy Schubert if (status < 0)
276657e22627SCy Schubert {
276757e22627SCy Schubert if (status == -1)
276857e22627SCy Schubert {
276957e22627SCy Schubert //
277057e22627SCy Schubert // Error other than "client closed the
277157e22627SCy Schubert // connection out from under us"; report
277257e22627SCy Schubert // it.
277357e22627SCy Schubert //
277457e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR,
277557e22627SCy Schubert "Send of packet to client failed: %s",
277657e22627SCy Schubert errbuf);
277757e22627SCy Schubert }
277857e22627SCy Schubert
277957e22627SCy Schubert //
278057e22627SCy Schubert // Give up in either case.
278157e22627SCy Schubert //
278257e22627SCy Schubert goto error;
278357e22627SCy Schubert }
278457e22627SCy Schubert }
278557e22627SCy Schubert
278657e22627SCy Schubert if (retval < 0 && retval != PCAP_ERROR_BREAK)
278757e22627SCy Schubert {
278857e22627SCy Schubert //
278957e22627SCy Schubert // Failed with an error other than "we were told to break
279057e22627SCy Schubert // out of the loop".
279157e22627SCy Schubert //
279257e22627SCy Schubert // The latter just means that the client told us to stop
279357e22627SCy Schubert // capturing, so there's no error to report.
279457e22627SCy Schubert //
2795*6f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp));
2796*6f9cba8fSJoseph Mingrone rpcap_senderror(session->sockctrl, session->ctrl_ssl, session->protocol_version,
279757e22627SCy Schubert PCAP_ERR_READEX, errbuf, NULL);
279857e22627SCy Schubert }
279957e22627SCy Schubert
280057e22627SCy Schubert error:
280157e22627SCy Schubert //
280257e22627SCy Schubert // The main thread will clean up the session structure.
280357e22627SCy Schubert //
280457e22627SCy Schubert free(sendbuf);
280557e22627SCy Schubert
280657e22627SCy Schubert return 0;
280757e22627SCy Schubert }
280857e22627SCy Schubert
280957e22627SCy Schubert #ifndef _WIN32
281057e22627SCy Schubert //
281157e22627SCy Schubert // Do-nothing handler for SIGUSR1; the sole purpose of SIGUSR1 is to
281257e22627SCy Schubert // interrupt the data thread if it's blocked in a system call waiting
281357e22627SCy Schubert // for packets to arrive.
281457e22627SCy Schubert //
noop_handler(int sign _U_)281557e22627SCy Schubert static void noop_handler(int sign _U_)
281657e22627SCy Schubert {
281757e22627SCy Schubert }
281857e22627SCy Schubert #endif
281957e22627SCy Schubert
282057e22627SCy Schubert /*!
282157e22627SCy Schubert \brief It serializes a network address.
282257e22627SCy Schubert
282357e22627SCy Schubert It accepts a 'sockaddr_storage' structure as input, and it converts it appropriately into a format
282457e22627SCy Schubert that can be used to be sent on the network. Basically, it applies all the hton()
282557e22627SCy Schubert conversion required to the input variable.
282657e22627SCy Schubert
282757e22627SCy Schubert \param sockaddrin a 'sockaddr_storage' pointer to the variable that has to be
282857e22627SCy Schubert serialized. This variable can be both a 'sockaddr_in' and 'sockaddr_in6'.
282957e22627SCy Schubert
283057e22627SCy Schubert \param sockaddrout an 'rpcap_sockaddr' pointer to the variable that will contain
283157e22627SCy Schubert the serialized data. This variable has to be allocated by the user.
283257e22627SCy Schubert
283357e22627SCy Schubert \warning This function supports only AF_INET and AF_INET6 address families.
283457e22627SCy Schubert */
283557e22627SCy Schubert static void
daemon_seraddr(struct sockaddr_storage * sockaddrin,struct rpcap_sockaddr * sockaddrout)283657e22627SCy Schubert daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout)
283757e22627SCy Schubert {
283857e22627SCy Schubert memset(sockaddrout, 0, sizeof(struct sockaddr_storage));
283957e22627SCy Schubert
284057e22627SCy Schubert // There can be the case in which the sockaddrin is not available
284157e22627SCy Schubert if (sockaddrin == NULL) return;
284257e22627SCy Schubert
284357e22627SCy Schubert // Warning: we support only AF_INET and AF_INET6
2844*6f9cba8fSJoseph Mingrone //
2845*6f9cba8fSJoseph Mingrone // Note: as noted above, the output structures are not
2846*6f9cba8fSJoseph Mingrone // neatly aligned on 4-byte boundaries, so we must fill
2847*6f9cba8fSJoseph Mingrone // in an aligned structure and then copy it to the output
2848*6f9cba8fSJoseph Mingrone // buffer with memcpy().
284957e22627SCy Schubert switch (sockaddrin->ss_family)
285057e22627SCy Schubert {
285157e22627SCy Schubert case AF_INET:
285257e22627SCy Schubert {
285357e22627SCy Schubert struct sockaddr_in *sockaddrin_ipv4;
2854*6f9cba8fSJoseph Mingrone struct rpcap_sockaddr_in sockaddrout_ipv4;
285557e22627SCy Schubert
285657e22627SCy Schubert sockaddrin_ipv4 = (struct sockaddr_in *) sockaddrin;
2857*6f9cba8fSJoseph Mingrone
2858*6f9cba8fSJoseph Mingrone sockaddrout_ipv4.family = htons(RPCAP_AF_INET);
2859*6f9cba8fSJoseph Mingrone sockaddrout_ipv4.port = htons(sockaddrin_ipv4->sin_port);
2860*6f9cba8fSJoseph Mingrone memcpy(&sockaddrout_ipv4.addr, &sockaddrin_ipv4->sin_addr, sizeof(sockaddrout_ipv4.addr));
2861*6f9cba8fSJoseph Mingrone memset(sockaddrout_ipv4.zero, 0, sizeof(sockaddrout_ipv4.zero));
2862*6f9cba8fSJoseph Mingrone memcpy(sockaddrout, &sockaddrout_ipv4, sizeof(struct rpcap_sockaddr_in));
286357e22627SCy Schubert break;
286457e22627SCy Schubert }
286557e22627SCy Schubert
286657e22627SCy Schubert #ifdef AF_INET6
286757e22627SCy Schubert case AF_INET6:
286857e22627SCy Schubert {
286957e22627SCy Schubert struct sockaddr_in6 *sockaddrin_ipv6;
2870*6f9cba8fSJoseph Mingrone struct rpcap_sockaddr_in6 sockaddrout_ipv6;
287157e22627SCy Schubert
287257e22627SCy Schubert sockaddrin_ipv6 = (struct sockaddr_in6 *) sockaddrin;
2873*6f9cba8fSJoseph Mingrone
2874*6f9cba8fSJoseph Mingrone sockaddrout_ipv6.family = htons(RPCAP_AF_INET6);
2875*6f9cba8fSJoseph Mingrone sockaddrout_ipv6.port = htons(sockaddrin_ipv6->sin6_port);
2876*6f9cba8fSJoseph Mingrone sockaddrout_ipv6.flowinfo = htonl(sockaddrin_ipv6->sin6_flowinfo);
2877*6f9cba8fSJoseph Mingrone memcpy(&sockaddrout_ipv6.addr, &sockaddrin_ipv6->sin6_addr, sizeof(sockaddrout_ipv6.addr));
2878*6f9cba8fSJoseph Mingrone sockaddrout_ipv6.scope_id = htonl(sockaddrin_ipv6->sin6_scope_id);
2879*6f9cba8fSJoseph Mingrone memcpy(sockaddrout, &sockaddrout_ipv6, sizeof(struct rpcap_sockaddr_in6));
288057e22627SCy Schubert break;
288157e22627SCy Schubert }
288257e22627SCy Schubert #endif
288357e22627SCy Schubert }
288457e22627SCy Schubert }
288557e22627SCy Schubert
288657e22627SCy Schubert
288757e22627SCy Schubert /*!
288857e22627SCy Schubert \brief Suspends a thread for secs seconds.
288957e22627SCy Schubert */
sleep_secs(int secs)289057e22627SCy Schubert void sleep_secs(int secs)
289157e22627SCy Schubert {
2892*6f9cba8fSJoseph Mingrone #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
289357e22627SCy Schubert #ifdef _WIN32
289457e22627SCy Schubert Sleep(secs*1000);
289557e22627SCy Schubert #else
289657e22627SCy Schubert unsigned secs_remaining;
289757e22627SCy Schubert
289857e22627SCy Schubert if (secs <= 0)
289957e22627SCy Schubert return;
290057e22627SCy Schubert secs_remaining = secs;
290157e22627SCy Schubert while (secs_remaining != 0)
290257e22627SCy Schubert secs_remaining = sleep(secs_remaining);
290357e22627SCy Schubert #endif
2904*6f9cba8fSJoseph Mingrone #endif
290557e22627SCy Schubert }
290657e22627SCy Schubert
290757e22627SCy Schubert /*
290857e22627SCy Schubert * Read the header of a message.
290957e22627SCy Schubert */
291057e22627SCy Schubert static int
rpcapd_recv_msg_header(SOCKET sock,SSL * ssl,struct rpcap_header * headerp)2911*6f9cba8fSJoseph Mingrone rpcapd_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *headerp)
291257e22627SCy Schubert {
291357e22627SCy Schubert int nread;
291457e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
291557e22627SCy Schubert
2916*6f9cba8fSJoseph Mingrone nread = sock_recv(sock, ssl, (char *) headerp, sizeof(struct rpcap_header),
291757e22627SCy Schubert SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR, errbuf, PCAP_ERRBUF_SIZE);
291857e22627SCy Schubert if (nread == -1)
291957e22627SCy Schubert {
292057e22627SCy Schubert // Network error.
292157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
292257e22627SCy Schubert return -1;
292357e22627SCy Schubert }
292457e22627SCy Schubert if (nread == 0)
292557e22627SCy Schubert {
292657e22627SCy Schubert // Immediate EOF; that's treated like a close message.
292757e22627SCy Schubert return -2;
292857e22627SCy Schubert }
292957e22627SCy Schubert headerp->plen = ntohl(headerp->plen);
293057e22627SCy Schubert return 0;
293157e22627SCy Schubert }
293257e22627SCy Schubert
293357e22627SCy Schubert /*
293457e22627SCy Schubert * Read data from a message.
293557e22627SCy Schubert * If we're trying to read more data that remains, puts an error
293657e22627SCy Schubert * message into errmsgbuf and returns -2. Otherwise, tries to read
293757e22627SCy Schubert * the data and, if that succeeds, subtracts the amount read from
293857e22627SCy Schubert * the number of bytes of data that remains.
293957e22627SCy Schubert * Returns 0 on success, logs a message and returns -1 on a network
294057e22627SCy Schubert * error.
294157e22627SCy Schubert */
294257e22627SCy Schubert static int
rpcapd_recv(SOCKET sock,SSL * ssl,char * buffer,size_t toread,uint32 * plen,char * errmsgbuf)2943*6f9cba8fSJoseph Mingrone rpcapd_recv(SOCKET sock, SSL *ssl, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf)
294457e22627SCy Schubert {
294557e22627SCy Schubert int nread;
294657e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
294757e22627SCy Schubert
294857e22627SCy Schubert if (toread > *plen)
294957e22627SCy Schubert {
295057e22627SCy Schubert // Tell the client and continue.
2951*6f9cba8fSJoseph Mingrone snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
295257e22627SCy Schubert return -2;
295357e22627SCy Schubert }
2954*6f9cba8fSJoseph Mingrone nread = sock_recv(sock, ssl, buffer, toread,
295557e22627SCy Schubert SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
295657e22627SCy Schubert if (nread == -1)
295757e22627SCy Schubert {
295857e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
295957e22627SCy Schubert return -1;
296057e22627SCy Schubert }
296157e22627SCy Schubert *plen -= nread;
296257e22627SCy Schubert return 0;
296357e22627SCy Schubert }
296457e22627SCy Schubert
296557e22627SCy Schubert /*
296657e22627SCy Schubert * Discard data from a connection.
296757e22627SCy Schubert * Mostly used to discard wrong-sized messages.
296857e22627SCy Schubert * Returns 0 on success, logs a message and returns -1 on a network
296957e22627SCy Schubert * error.
297057e22627SCy Schubert */
297157e22627SCy Schubert static int
rpcapd_discard(SOCKET sock,SSL * ssl,uint32 len)2972*6f9cba8fSJoseph Mingrone rpcapd_discard(SOCKET sock, SSL *ssl, uint32 len)
297357e22627SCy Schubert {
297457e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
297557e22627SCy Schubert
297657e22627SCy Schubert if (len != 0)
297757e22627SCy Schubert {
2978*6f9cba8fSJoseph Mingrone if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
297957e22627SCy Schubert {
298057e22627SCy Schubert // Network error.
298157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
298257e22627SCy Schubert return -1;
298357e22627SCy Schubert }
298457e22627SCy Schubert }
298557e22627SCy Schubert return 0;
298657e22627SCy Schubert }
298757e22627SCy Schubert
298857e22627SCy Schubert //
298957e22627SCy Schubert // Shut down any packet-capture thread associated with the session,
299057e22627SCy Schubert // close the SSL handle for the data socket if we have one, close
299157e22627SCy Schubert // the data socket if we have one, and close the underlying packet
299257e22627SCy Schubert // capture handle if we have one.
299357e22627SCy Schubert //
299457e22627SCy Schubert // We do not, of course, touch the controlling socket that's also
299557e22627SCy Schubert // copied into the session, as the service loop might still use it.
299657e22627SCy Schubert //
session_close(struct session * session)299757e22627SCy Schubert static void session_close(struct session *session)
299857e22627SCy Schubert {
299957e22627SCy Schubert if (session->have_thread)
300057e22627SCy Schubert {
300157e22627SCy Schubert //
300257e22627SCy Schubert // Tell the data connection thread main capture loop to
300357e22627SCy Schubert // break out of that loop.
300457e22627SCy Schubert //
300557e22627SCy Schubert // This may be sufficient to wake up a blocked thread,
300657e22627SCy Schubert // but it's not guaranteed to be sufficient.
300757e22627SCy Schubert //
300857e22627SCy Schubert pcap_breakloop(session->fp);
300957e22627SCy Schubert
301057e22627SCy Schubert #ifdef _WIN32
301157e22627SCy Schubert //
301257e22627SCy Schubert // Set the event on which a read would block, so that,
301357e22627SCy Schubert // if it's currently blocked waiting for packets to
301457e22627SCy Schubert // arrive, it'll wake up, so it can see the "break
301557e22627SCy Schubert // out of the loop" indication. (pcap_breakloop()
301657e22627SCy Schubert // might do this, but older versions don't. Setting
301757e22627SCy Schubert // it twice should, at worst, cause an extra wakeup,
301857e22627SCy Schubert // which shouldn't be a problem.)
301957e22627SCy Schubert //
302057e22627SCy Schubert // XXX - what about modules other than NPF?
302157e22627SCy Schubert //
302257e22627SCy Schubert SetEvent(pcap_getevent(session->fp));
302357e22627SCy Schubert
302457e22627SCy Schubert //
302557e22627SCy Schubert // Wait for the thread to exit, so we don't close
302657e22627SCy Schubert // sockets out from under it.
302757e22627SCy Schubert //
302857e22627SCy Schubert // XXX - have a timeout, so we don't wait forever?
302957e22627SCy Schubert //
303057e22627SCy Schubert WaitForSingleObject(session->thread, INFINITE);
303157e22627SCy Schubert
303257e22627SCy Schubert //
303357e22627SCy Schubert // Release the thread handle, as we're done with
303457e22627SCy Schubert // it.
303557e22627SCy Schubert //
303657e22627SCy Schubert CloseHandle(session->thread);
303757e22627SCy Schubert session->have_thread = 0;
303857e22627SCy Schubert session->thread = INVALID_HANDLE_VALUE;
303957e22627SCy Schubert #else
304057e22627SCy Schubert //
304157e22627SCy Schubert // Send a SIGUSR1 signal to the thread, so that, if
304257e22627SCy Schubert // it's currently blocked waiting for packets to arrive,
304357e22627SCy Schubert // it'll wake up (we've turned off SA_RESTART for
304457e22627SCy Schubert // SIGUSR1, so that the system call in which it's blocked
304557e22627SCy Schubert // should return EINTR rather than restarting).
304657e22627SCy Schubert //
304757e22627SCy Schubert pthread_kill(session->thread, SIGUSR1);
304857e22627SCy Schubert
304957e22627SCy Schubert //
305057e22627SCy Schubert // Wait for the thread to exit, so we don't close
305157e22627SCy Schubert // sockets out from under it.
305257e22627SCy Schubert //
305357e22627SCy Schubert // XXX - have a timeout, so we don't wait forever?
305457e22627SCy Schubert //
305557e22627SCy Schubert pthread_join(session->thread, NULL);
305657e22627SCy Schubert session->have_thread = 0;
305757e22627SCy Schubert memset(&session->thread, 0, sizeof(session->thread));
305857e22627SCy Schubert #endif
305957e22627SCy Schubert }
306057e22627SCy Schubert
3061*6f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
3062*6f9cba8fSJoseph Mingrone if (session->data_ssl)
3063*6f9cba8fSJoseph Mingrone {
3064*6f9cba8fSJoseph Mingrone // Finish using the SSL handle for the socket.
3065*6f9cba8fSJoseph Mingrone // This must be done *before* the socket is closed.
3066*6f9cba8fSJoseph Mingrone ssl_finish(session->data_ssl);
3067*6f9cba8fSJoseph Mingrone session->data_ssl = NULL;
3068*6f9cba8fSJoseph Mingrone }
3069*6f9cba8fSJoseph Mingrone #endif
3070*6f9cba8fSJoseph Mingrone
307157e22627SCy Schubert if (session->sockdata != INVALID_SOCKET)
307257e22627SCy Schubert {
307357e22627SCy Schubert sock_close(session->sockdata, NULL, 0);
307457e22627SCy Schubert session->sockdata = INVALID_SOCKET;
307557e22627SCy Schubert }
307657e22627SCy Schubert
307757e22627SCy Schubert if (session->fp)
307857e22627SCy Schubert {
307957e22627SCy Schubert pcap_close(session->fp);
308057e22627SCy Schubert session->fp = NULL;
308157e22627SCy Schubert }
308257e22627SCy Schubert }
308357e22627SCy Schubert
308457e22627SCy Schubert //
308557e22627SCy Schubert // Check whether a capture source string is a URL or not.
308657e22627SCy Schubert // This includes URLs that refer to a local device; a scheme, followed
308757e22627SCy Schubert // by ://, followed by *another* scheme and ://, is just silly, and
308857e22627SCy Schubert // anybody who supplies that will get an error.
308957e22627SCy Schubert //
309057e22627SCy Schubert static int
is_url(const char * source)309157e22627SCy Schubert is_url(const char *source)
309257e22627SCy Schubert {
309357e22627SCy Schubert char *colonp;
309457e22627SCy Schubert
309557e22627SCy Schubert /*
309657e22627SCy Schubert * RFC 3986 says:
309757e22627SCy Schubert *
309857e22627SCy Schubert * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
309957e22627SCy Schubert *
310057e22627SCy Schubert * hier-part = "//" authority path-abempty
310157e22627SCy Schubert * / path-absolute
310257e22627SCy Schubert * / path-rootless
310357e22627SCy Schubert * / path-empty
310457e22627SCy Schubert *
310557e22627SCy Schubert * authority = [ userinfo "@" ] host [ ":" port ]
310657e22627SCy Schubert *
310757e22627SCy Schubert * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
310857e22627SCy Schubert *
310957e22627SCy Schubert * Step 1: look for the ":" at the end of the scheme.
311057e22627SCy Schubert * A colon in the source is *NOT* sufficient to indicate that
311157e22627SCy Schubert * this is a URL, as interface names on some platforms might
311257e22627SCy Schubert * include colons (e.g., I think some Solaris interfaces
311357e22627SCy Schubert * might).
311457e22627SCy Schubert */
311557e22627SCy Schubert colonp = strchr(source, ':');
311657e22627SCy Schubert if (colonp == NULL)
311757e22627SCy Schubert {
311857e22627SCy Schubert /*
311957e22627SCy Schubert * The source is the device to open. It's not a URL.
312057e22627SCy Schubert */
312157e22627SCy Schubert return (0);
312257e22627SCy Schubert }
312357e22627SCy Schubert
312457e22627SCy Schubert /*
312557e22627SCy Schubert * All schemes must have "//" after them, i.e. we only support
312657e22627SCy Schubert * hier-part = "//" authority path-abempty, not
312757e22627SCy Schubert * hier-part = path-absolute
312857e22627SCy Schubert * hier-part = path-rootless
312957e22627SCy Schubert * hier-part = path-empty
313057e22627SCy Schubert *
313157e22627SCy Schubert * We need that in order to distinguish between a local device
313257e22627SCy Schubert * name that happens to contain a colon and a URI.
313357e22627SCy Schubert */
313457e22627SCy Schubert if (strncmp(colonp + 1, "//", 2) != 0)
313557e22627SCy Schubert {
313657e22627SCy Schubert /*
313757e22627SCy Schubert * The source is the device to open. It's not a URL.
313857e22627SCy Schubert */
313957e22627SCy Schubert return (0);
314057e22627SCy Schubert }
314157e22627SCy Schubert
314257e22627SCy Schubert /*
314357e22627SCy Schubert * It's a URL.
314457e22627SCy Schubert */
314557e22627SCy Schubert return (1);
314657e22627SCy Schubert }
3147