diff options
Diffstat (limited to 'extcap/sshdump.c')
-rw-r--r-- | extcap/sshdump.c | 206 |
1 files changed, 159 insertions, 47 deletions
diff --git a/extcap/sshdump.c b/extcap/sshdump.c index e7390ee3e5..15adec4b6a 100644 --- a/extcap/sshdump.c +++ b/extcap/sshdump.c @@ -29,7 +29,7 @@ #include <cli_main.h> -static gchar* sshdump_extcap_interface; +static char* sshdump_extcap_interface; #ifdef _WIN32 #define DEFAULT_SSHDUMP_EXTCAP_INTERFACE "sshdump.exe" #else @@ -37,7 +37,7 @@ static gchar* sshdump_extcap_interface; #endif #define SSHDUMP_VERSION_MAJOR "1" -#define SSHDUMP_VERSION_MINOR "0" +#define SSHDUMP_VERSION_MINOR "2" #define SSHDUMP_VERSION_RELEASE "0" #define SSH_READ_BLOCK_SIZE 256 @@ -51,13 +51,17 @@ enum { OPT_REMOTE_USERNAME, OPT_REMOTE_PASSWORD, OPT_REMOTE_INTERFACE, + OPT_REMOTE_CAPTURE_COMMAND_SELECT, OPT_REMOTE_CAPTURE_COMMAND, OPT_REMOTE_FILTER, OPT_SSHKEY, OPT_SSHKEY_PASSPHRASE, OPT_PROXYCOMMAND, + OPT_SSH_SHA1, OPT_REMOTE_COUNT, - OPT_REMOTE_SUDO, + OPT_REMOTE_SUDO, // Deprecated + OPT_REMOTE_PRIV, + OPT_REMOTE_PRIV_USER, OPT_REMOTE_NOPROM }; @@ -66,8 +70,11 @@ static struct ws_option longopts[] = { { "help", ws_no_argument, NULL, OPT_HELP}, { "version", ws_no_argument, NULL, OPT_VERSION}, SSH_BASE_OPTIONS, + { "remote-capture-command-select", ws_required_argument, NULL, OPT_REMOTE_CAPTURE_COMMAND_SELECT}, { "remote-capture-command", ws_required_argument, NULL, OPT_REMOTE_CAPTURE_COMMAND}, - { "remote-sudo", ws_no_argument, NULL, OPT_REMOTE_SUDO }, + { "remote-sudo", ws_no_argument, NULL, OPT_REMOTE_SUDO }, // Deprecated + { "remote-priv", ws_required_argument, NULL, OPT_REMOTE_PRIV }, + { "remote-priv-user", ws_required_argument, NULL, OPT_REMOTE_PRIV_USER }, { "remote-noprom", ws_no_argument, NULL, OPT_REMOTE_NOPROM }, { 0, 0, 0, 0} }; @@ -90,7 +97,7 @@ static int ssh_loop_read(ssh_channel channel, FILE* fp) if (nbytes == 0) { break; } - if (fwrite(buffer, 1, nbytes, fp) != (guint)nbytes) { + if (fwrite(buffer, 1, nbytes, fp) != (unsigned)nbytes) { ws_warning("Error writing to fifo"); ret = EXIT_FAILURE; goto end; @@ -105,7 +112,7 @@ static int ssh_loop_read(ssh_channel channel, FILE* fp) ws_warning("Error reading from channel"); goto end; } - if (fwrite(buffer, 1, nbytes, stderr) != (guint)nbytes) { + if (fwrite(buffer, 1, nbytes, stderr) != (unsigned)nbytes) { ws_warning("Error writing to stderr"); break; } @@ -119,7 +126,7 @@ end: return ret; } -static char* local_interfaces_to_filter(const guint16 remote_port) +static char* local_interfaces_to_filter(const uint16_t remote_port) { GSList* interfaces = local_interfaces_to_list(); char* filter = interfaces_list_to_filter(interfaces, remote_port); @@ -127,11 +134,16 @@ static char* local_interfaces_to_filter(const guint16 remote_port) return filter; } -static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_command, const gboolean use_sudo, gboolean noprom, - const char* iface, const char* cfilter, const guint32 count) +static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_command_select, + const char* capture_command, const char* privilege, bool noprom, + const char* iface, const char* cfilter, const uint32_t count) { - gchar* cmdline; + char* cmdline = NULL; ssh_channel channel; + char** ifaces_array = NULL; + int ifaces_array_num = 0; + GString *ifaces_string; + char *ifaces = NULL; char* quoted_iface = NULL; char* quoted_filter = NULL; char* count_str = NULL; @@ -151,23 +163,54 @@ static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_command ssh_options_get_port(sshs, &remote_port); + if (capture_command_select == NULL || !g_strcmp0(capture_command_select, "other")) { + if (capture_command && *capture_command) { + cmdline = g_strdup(capture_command); + ws_debug("Remote capture command has disabled other options"); + } else { + capture_command_select = "tcpdump"; + } + } + /* escape parameters to go save with the shell */ - if (capture_command && *capture_command) { - cmdline = g_strdup(capture_command); - ws_debug("Remote capture command has disabled other options"); - } else { + if (!g_strcmp0(capture_command_select, "tcpdump")) { quoted_iface = iface ? g_shell_quote(iface) : NULL; quoted_filter = g_shell_quote(cfilter ? cfilter : ""); if (count > 0) - count_str = g_strdup_printf("-c %u", count); + count_str = ws_strdup_printf("-c %u", count); - cmdline = g_strdup_printf("%s tcpdump -U %s%s %s -w - %s %s", - use_sudo ? "sudo" : "", + cmdline = ws_strdup_printf("%s tcpdump -U %s%s %s -w - %s %s", + privilege, quoted_iface ? "-i " : "", quoted_iface ? quoted_iface : "", noprom ? "-p" : "", count_str ? count_str : "", quoted_filter); + } else if (!g_strcmp0(capture_command_select, "dumpcap")) { + if (iface) { + ifaces_array = g_strsplit(iface, " ", -1); + ifaces_string = g_string_new(NULL); + while (ifaces_array[ifaces_array_num]) + { + quoted_iface = g_shell_quote(ifaces_array[ifaces_array_num]); + g_string_append_printf(ifaces_string, "-i %s ", quoted_iface); + ifaces_array_num++; + } + ifaces = g_string_free(ifaces_string, false); + } + quoted_filter = g_shell_quote(cfilter ? cfilter : ""); + if (count > 0) + count_str = ws_strdup_printf("-c %u", count); + + cmdline = ws_strdup_printf("%s dumpcap %s %s -w - %s -f %s", + privilege, + noprom ? "-p" : "", + ifaces ? ifaces : "", + count_str ? count_str : "", + quoted_filter); + + g_free(ifaces); + g_strfreev(ifaces_array); } ws_debug("Running: %s", cmdline); @@ -187,7 +230,8 @@ static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_command } static int ssh_open_remote_connection(const ssh_params_t* params, const char* iface, const char* cfilter, - const char* capture_command, const gboolean use_sudo, gboolean noprom, const guint32 count, const char* fifo) + const char* capture_command_select, const char* capture_command, const char* privilege, + bool noprom, const uint32_t count, const char* fifo) { ssh_session sshs = NULL; ssh_channel channel = NULL; @@ -211,7 +255,7 @@ static int ssh_open_remote_connection(const ssh_params_t* params, const char* if goto cleanup; } - channel = run_ssh_command(sshs, capture_command, use_sudo, noprom, iface, cfilter, count); + channel = run_ssh_command(sshs, capture_command_select, capture_command, privilege, noprom, iface, cfilter, count); if (!channel) { ws_warning("Can't run ssh command."); @@ -262,7 +306,7 @@ static char* interfaces_list_to_filter(GSList* interfaces, unsigned int remote_p } g_string_append_printf(filter, ") and port %u)", remote_port); } - return g_string_free(filter, FALSE); + return g_string_free(filter, false); } static int list_config(char *interface, unsigned int remote_port) @@ -286,7 +330,7 @@ static int list_config(char *interface, unsigned int remote_port) "{type=string}{tooltip=The remote SSH host. It can be both " "an IP address or a hostname}{required=true}{group=Server}\n", inc++); printf("arg {number=%u}{call=--remote-port}{display=Remote SSH server port}" - "{type=unsigned}{tooltip=The remote SSH host port (1-65535)}" + "{type=unsigned}{default=22}{tooltip=The remote SSH host port (1-65535)}" "{range=1,65535}{group=Server}\n", inc++); printf("arg {number=%u}{call=--remote-username}{display=Remote SSH server username}" "{type=string}{tooltip=The remote SSH username. If not provided, " @@ -295,7 +339,7 @@ static int list_config(char *interface, unsigned int remote_port) "{type=password}{tooltip=The SSH password, used when other methods (SSH agent " "or key files) are unavailable.}{group=Authentication}\n", inc++); printf("arg {number=%u}{call=--sshkey}{display=Path to SSH private key}" - "{type=fileselect}{tooltip=The path on the local filesystem of the private ssh key}" + "{type=fileselect}{tooltip=The path on the local filesystem of the private SSH key (OpenSSH format)}" "{mustexist=true}{group=Authentication}\n", inc++); printf("arg {number=%u}{call=--sshkey-passphrase}{display=SSH key passphrase}" "{type=password}{tooltip=Passphrase to unlock the SSH private key}{group=Authentication}\n", @@ -303,13 +347,31 @@ static int list_config(char *interface, unsigned int remote_port) printf("arg {number=%u}{call=--proxycommand}{display=ProxyCommand}" "{type=string}{tooltip=The command to use as proxy for the SSH connection}" "{group=Authentication}\n", inc++); + printf("arg {number=%u}{call=--ssh-sha1}{display=Support SHA-1 keys (deprecated)}" + "{type=boolflag}{tooltip=Support keys and key exchange algorithms using SHA-1 (deprecated)}{group=Authentication}" + "\n", inc++); printf("arg {number=%u}{call=--remote-interface}{display=Remote interface}" "{type=string}{tooltip=The remote network interface used for capture" "}{group=Capture}\n", inc++); + printf("arg {number=%u}{call=--remote-capture-command-select}{display=Remote capture command selection}" + "{type=radio}{tooltip=The remote capture command to build a command line for}{group=Capture}\n", inc); + printf("value {arg=%u}{value=dumpcap}{display=dumpcap}\n", inc); + printf("value {arg=%u}{value=tcpdump}{display=tcpdump}{default=true}\n", inc); + printf("value {arg=%u}{value=other}{display=Other:}\n", inc++); printf("arg {number=%u}{call=--remote-capture-command}{display=Remote capture command}" "{type=string}{tooltip=The remote command used to capture}{group=Capture}\n", inc++); - printf("arg {number=%u}{call=--remote-sudo}{display=Use sudo on the remote machine}" - "{type=boolean}{tooltip=Prepend the capture command with sudo on the remote machine}" + // Deprecated + //printf("arg {number=%u}{call=--remote-sudo}{display=Use sudo on the remote machine}" + // "{type=boolflag}{tooltip=Prepend the capture command with sudo on the remote machine}" + // "{group=Capture}\n", inc++); + printf("arg {number=%u}{call=--remote-priv}{display=Gain capture privilege on the remote machine}" + "{type=radio}{tooltip=Optionally prepend the capture command with sudo or doas on the remote machine}" + "{group=Capture}\n", inc); + printf("value {arg=%u}{value=none}{display=none}{default=true}\n", inc); + printf("value {arg=%u}{value=sudo}{display=sudo}\n", inc); + printf("value {arg=%u}{value=doas -n}{display=doas}\n", inc++); + printf("arg {number=%u}{call=--remote-priv-user}{display=Privileged user name for sudo or doas}" + "{type=string}{tooltip=User name of privileged user to execute the capture command on the remote machine}" "{group=Capture}\n", inc++); printf("arg {number=%u}{call=--remote-noprom}{display=No promiscuous mode}" "{type=boolflag}{tooltip=Don't use promiscuous mode on the remote machine}{group=Capture}" @@ -341,7 +403,7 @@ static char* concat_filters(const char* extcap_filter, const char* remote_filter if (!remote_filter && !extcap_filter) return NULL; - return g_strdup_printf("(%s) and (%s)", extcap_filter, remote_filter); + return ws_strdup_printf("(%s) and (%s)", extcap_filter, remote_filter); } int main(int argc, char *argv[]) @@ -351,22 +413,21 @@ int main(int argc, char *argv[]) int option_idx = 0; ssh_params_t* ssh_params = ssh_params_new(); char* remote_interface = NULL; + char* remote_capture_command_select = NULL; char* remote_capture_command = NULL; char* remote_filter = NULL; - guint32 count = 0; + uint32_t count = 0; int ret = EXIT_FAILURE; extcap_parameters* extcap_conf = g_new0(extcap_parameters, 1); char* help_url; char* help_header = NULL; - gboolean use_sudo = FALSE; - gboolean noprom = FALSE; - gchar* interface_description = g_strdup("SSH remote capture"); + char* priv = NULL; + char* priv_user = NULL; + bool noprom = false; + char* interface_description = g_strdup("SSH remote capture"); /* Initialize log handler early so we can have proper logging during startup. */ - ws_log_init("sshdump", NULL); - - /* Early logging command-line initialization. */ - ws_log_parse_args(&argc, argv, NULL, LOG_ARGS_NOEXIT); + extcap_log_init("sshdump"); sshdump_extcap_interface = g_path_get_basename(argv[0]); @@ -379,7 +440,7 @@ int main(int argc, char *argv[]) * Attempt to get the pathname of the directory containing the * executable file. */ - err_msg = init_progfile_dir(argv[0]); + err_msg = configuration_init(argv[0], NULL); if (err_msg != NULL) { ws_warning("Can't get pathname of directory containing the extcap program: %s.", err_msg); @@ -392,14 +453,14 @@ int main(int argc, char *argv[]) g_free(help_url); add_libssh_info(extcap_conf); if (g_strcmp0(sshdump_extcap_interface, DEFAULT_SSHDUMP_EXTCAP_INTERFACE)) { - gchar* temp = interface_description; - interface_description = g_strdup_printf("%s, custom version", interface_description); + char* temp = interface_description; + interface_description = ws_strdup_printf("%s, custom version", interface_description); g_free(temp); } extcap_base_register_interface(extcap_conf, sshdump_extcap_interface, interface_description, 147, "Remote capture dependent DLT"); g_free(interface_description); - help_header = g_strdup_printf( + help_header = ws_strdup_printf( " %s --extcap-interfaces\n" " %s --extcap-interface=%s --extcap-dlts\n" " %s --extcap-interface=%s --extcap-config\n" @@ -415,15 +476,18 @@ int main(int argc, char *argv[]) extcap_help_add_option(extcap_conf, "--remote-port <port>", "the remote SSH port"); extcap_help_add_option(extcap_conf, "--remote-username <username>", "the remote SSH username"); extcap_help_add_option(extcap_conf, "--remote-password <password>", "the remote SSH password. If not specified, ssh-agent and ssh-key are used"); - extcap_help_add_option(extcap_conf, "--sshkey <public key path>", "the path of the ssh key"); - extcap_help_add_option(extcap_conf, "--sshkey-passphrase <public key passphrase>", "the passphrase to unlock public ssh"); - extcap_help_add_option(extcap_conf, "--proxycommand <proxy command>", "the command to use as proxy the the ssh connection"); + extcap_help_add_option(extcap_conf, "--sshkey <private key path>", "the path of the SSH key (OpenSSH format)"); + extcap_help_add_option(extcap_conf, "--sshkey-passphrase <private key passphrase>", "the passphrase to unlock private SSH key"); + extcap_help_add_option(extcap_conf, "--proxycommand <proxy command>", "the command to use as proxy for the SSH connection"); + extcap_help_add_option(extcap_conf, "--ssh-sha1", "support keys and key exchange using SHA-1 (deprecated)"); extcap_help_add_option(extcap_conf, "--remote-interface <iface>", "the remote capture interface"); + extcap_help_add_option(extcap_conf, "--remote-capture-command-select <selection>", "dumpcap, tcpdump or other remote capture command"); extcap_help_add_option(extcap_conf, "--remote-capture-command <capture command>", "the remote capture command"); - extcap_help_add_option(extcap_conf, "--remote-sudo", "use sudo on the remote machine to capture"); + //extcap_help_add_option(extcap_conf, "--remote-sudo", "use sudo on the remote machine to capture"); // Deprecated + extcap_help_add_option(extcap_conf, "--remote-priv <selection>", "none, sudo or doas"); + extcap_help_add_option(extcap_conf, "--remote-priv-user <username>", "privileged user name"); extcap_help_add_option(extcap_conf, "--remote-noprom", "don't use promiscuous mode on the remote machine"); - extcap_help_add_option(extcap_conf, "--remote-filter <filter>", "a filter for remote capture (default: don't " - "listen on local interfaces IPs)"); + extcap_help_add_option(extcap_conf, "--remote-filter <filter>", "a filter for remote capture (default: don't listen on local interfaces IPs)"); extcap_help_add_option(extcap_conf, "--remote-count <count>", "the number of packets to capture"); ws_opterr = 0; @@ -487,18 +551,39 @@ int main(int argc, char *argv[]) ssh_params->proxycommand = g_strdup(ws_optarg); break; + case OPT_SSH_SHA1: + ssh_params->ssh_sha1 = true; + break; + case OPT_REMOTE_INTERFACE: g_free(remote_interface); remote_interface = g_strdup(ws_optarg); break; + case OPT_REMOTE_CAPTURE_COMMAND_SELECT: + g_free(remote_capture_command_select); + remote_capture_command_select = g_strdup(ws_optarg); + break; + case OPT_REMOTE_CAPTURE_COMMAND: g_free(remote_capture_command); remote_capture_command = g_strdup(ws_optarg); break; case OPT_REMOTE_SUDO: - use_sudo = TRUE; + // Deprecated + g_free(priv); + priv = g_strdup("sudo"); + break; + + case OPT_REMOTE_PRIV: + g_free(priv); + priv = g_strdup(ws_optarg); + break; + + case OPT_REMOTE_PRIV_USER: + g_free(priv_user); + priv_user = g_strdup(ws_optarg); break; case OPT_REMOTE_FILTER: @@ -514,7 +599,7 @@ int main(int argc, char *argv[]) break; case OPT_REMOTE_NOPROM: - noprom = TRUE; + noprom = true; break; case ':': @@ -552,16 +637,40 @@ int main(int argc, char *argv[]) if (extcap_conf->capture) { char* filter; + char* privilege; if (!ssh_params->host) { ws_warning("Missing parameter: --remote-host"); goto end; } + + if ((priv) && g_strcmp0(priv, "none") && strlen(g_strstrip(priv))) { + if ((priv_user) && strlen(g_strstrip(priv_user))) + /* Both sudo and doas use the same command line option */ + privilege = g_strconcat(priv, " -u ", priv_user, NULL); + else + privilege = g_strdup(priv); + } else { + privilege = g_strdup(""); + } + + // This may result in the use of a different port number than was given in + // the default filter string, as presented in the config dialog. The default + // given is always using the default SSH port since there's no remote SSH port + // given on the command line to get the extcap arguments. + // However the remote SSH port used here is the one given on the command line + // when the capture us started, which is the indended one. + // And this is only happening when no remote filter is specified on the command + // line to start the capture. + if (remote_filter == NULL) + remote_filter = local_interfaces_to_filter(ssh_params->port); filter = concat_filters(extcap_conf->capture_filter, remote_filter); - ssh_params->debug = extcap_conf->debug; + ssh_params_set_log_level(ssh_params, extcap_conf->debug); ret = ssh_open_remote_connection(ssh_params, remote_interface, - filter, remote_capture_command, use_sudo, noprom, count, extcap_conf->fifo); + filter, remote_capture_command_select, remote_capture_command, + privilege, noprom, count, extcap_conf->fifo); g_free(filter); + g_free(privilege); } else { ws_debug("You should not come here... maybe some parameter missing?"); ret = EXIT_FAILURE; @@ -570,9 +679,12 @@ int main(int argc, char *argv[]) end: /* clean up stuff */ ssh_params_free(ssh_params); + g_free(remote_capture_command_select); g_free(remote_capture_command); g_free(remote_interface); g_free(remote_filter); + g_free(priv); + g_free(priv_user); extcap_base_cleanup(&extcap_conf); return ret; } |