diff --git a/client/fwknop.c b/client/fwknop.c index f8f29828..0afade3d 100644 --- a/client/fwknop.c +++ b/client/fwknop.c @@ -64,7 +64,6 @@ static int is_hostname_str_with_port(const char *str, static void enable_fault_injections(fko_cli_options_t * const opts); #endif -#define MAX_CMDLINE_ARGS 50 /*!< should be way more than enough */ #define NAT_ACCESS_STR_TEMPLATE "%s,%d" /*!< Template for a nat access string ip,port with sscanf*/ #define HOSTNAME_BUFSIZE 64 /*!< Maximum size of a hostname string */ #define CTX_DUMP_BUFSIZE 4096 /*!< Maximum size allocated to a FKO context dump */ @@ -985,13 +984,15 @@ run_last_args(fko_cli_options_t *options, const char * const args_save_file) FILE *args_file_ptr = NULL; int current_arg_ctr = 0; - int argc_new = 0, args_broken = 0, buf_size=0; + int argc_new = 0; int i = 0; char args_str[MAX_LINE_LEN] = {0}; char arg_tmp[MAX_LINE_LEN] = {0}; char *argv_new[MAX_CMDLINE_ARGS]; /* should be way more than enough */ + memset(argv_new, 0x0, sizeof(argv_new)); + if(verify_file_perms_ownership(args_save_file) != 1) return 0; @@ -1016,49 +1017,26 @@ run_last_args(fko_cli_options_t *options, const char * const args_save_file) else { arg_tmp[current_arg_ctr] = '\0'; - buf_size = strlen(arg_tmp) + 1; - argv_new[argc_new] = calloc(1, buf_size); - if (argv_new[argc_new] == NULL) + if (add_argv(argv_new, &argc_new, arg_tmp, options) != 1) { - log_msg(LOG_VERBOSITY_ERROR, "[*] calloc failure for cmd line arg."); fclose(args_file_ptr); return 0; } - strlcpy(argv_new[argc_new], arg_tmp, buf_size); current_arg_ctr = 0; - argc_new++; - if(argc_new >= MAX_CMDLINE_ARGS) - { - log_msg(LOG_VERBOSITY_ERROR, "[*] max command line args exceeded."); - args_broken = 1; - break; - } } } } fclose(args_file_ptr); - if(! args_broken) - { - /* Reset the options index so we can run through them again. - */ - optind = 0; + /* Reset the options index so we can run through them again. + */ + optind = 0; - config_init(options, argc_new, argv_new); - } + config_init(options, argc_new, argv_new); /* Since we passed in our own copies, free up malloc'd memory */ - for (i=0; i < argc_new; i++) - { - if(argv_new[i] == NULL) - break; - else - free(argv_new[i]); - } - - if(args_broken) - return 0; + free_argv(argv_new, &argc_new); return 1; } diff --git a/client/fwknop_common.h b/client/fwknop_common.h index cc81b1be..fe390d90 100644 --- a/client/fwknop_common.h +++ b/client/fwknop_common.h @@ -47,6 +47,10 @@ */ #define DEF_CONFIG_FILE MY_NAME".conf" +/* Command line argument / argv handling +*/ +#define MAX_CMDLINE_ARGS 50 /*!< should be way more than enough */ + /* For time offset handling */ #define MAX_TIME_STR_LEN 9 @@ -63,7 +67,6 @@ #define HTTP_BACKUP_RESOLVE_HOST "www.cipherdyne.com" #define HTTP_RESOLVE_URL "/cgi-bin/myip" #define WGET_RESOLVE_URL_SSL "https://" HTTP_RESOLVE_HOST HTTP_RESOLVE_URL -#define WGET_RESOLVE_ARGS " --secure-protocol=auto --quiet" #define HTTP_MAX_REQUEST_LEN 2000 #define HTTP_MAX_RESPONSE_LEN 2000 #define HTTP_MAX_USER_AGENT_LEN 100 diff --git a/client/http_resolve_host.c b/client/http_resolve_host.c index 88f2ca53..3f724721 100644 --- a/client/http_resolve_host.c +++ b/client/http_resolve_host.c @@ -31,6 +31,7 @@ */ #include "fwknop_common.h" #include "utils.h" +#include #include @@ -306,20 +307,40 @@ parse_url(char *res_url, struct url* url) int resolve_ip_https(fko_cli_options_t *options) { - int o1, o2, o3, o4, got_resp=0, i; + int o1, o2, o3, o4, got_resp=0, i=0; char *ndx, resp[MAX_IPV4_STR_LEN+1] = {0}; - char wget_ssl_cmd[MAX_URL_PATH_LEN] = {0}; struct url url; /* for validation only */ - FILE *wget; + char wget_ssl_cmd[MAX_URL_PATH_LEN] = {0}; /* for verbose logging only */ - memset(&url, 0, sizeof(url)); + char *wget_argv[MAX_CMDLINE_ARGS]; /* for execvpe() with no environment */ + char *output_args[4] = {"--secure-protocol=auto", "--quiet", "-O", "-"}; + int wget_argc=0; + int pipe_fd[2]; + pid_t pid=0; + FILE *output; + int status; + + memset(&url, 0x0, sizeof(url)); + memset(wget_argv, 0x0, sizeof(wget_argv)); if(options->wget_bin != NULL) + { strlcpy(wget_ssl_cmd, options->wget_bin, sizeof(wget_ssl_cmd)); + if (add_argv(wget_argv, &wget_argc, options->wget_bin, options) != 1) + { + free_argv(wget_argv, &wget_argc); + return -1; + } + } else { #ifdef WGET_EXE strlcpy(wget_ssl_cmd, WGET_EXE, sizeof(wget_ssl_cmd)); + if (add_argv(wget_argv, &wget_argc, WGET_EXE, options) != 1) + { + free_argv(wget_argv, &wget_argc); + return -1; + } #else log_msg(LOG_VERBOSITY_ERROR, "[*] Use --wget-cmd to specify path to the wget command."); @@ -327,22 +348,36 @@ resolve_ip_https(fko_cli_options_t *options) #endif } - /* Tack on the SSL args to wget - */ - strlcat(wget_ssl_cmd, WGET_RESOLVE_ARGS, sizeof(wget_ssl_cmd)); - /* See whether we're supposed to change the default wget user agent */ if(! options->use_wget_user_agent) { - strlcat(wget_ssl_cmd, " -U '", sizeof(wget_ssl_cmd)); + strlcat(wget_ssl_cmd, " -U ", sizeof(wget_ssl_cmd)); strlcat(wget_ssl_cmd, options->http_user_agent, sizeof(wget_ssl_cmd)); - strlcat(wget_ssl_cmd, "'", sizeof(wget_ssl_cmd)); + if (add_argv(wget_argv, &wget_argc, "-U", options) != 1) + { + free_argv(wget_argv, &wget_argc); + return -1; + } + if (add_argv(wget_argv, &wget_argc, options->http_user_agent, options) != 1) + { + free_argv(wget_argv, &wget_argc); + return -1; + } } /* We collect the IP from wget's stdout */ - strlcat(wget_ssl_cmd, " -O - ", sizeof(wget_ssl_cmd)); + strlcat(wget_ssl_cmd, + " --secure-protocol=auto --quiet -O - ", sizeof(wget_ssl_cmd)); + for (i=0; i < 4; i++) + { + if (add_argv(wget_argv, &wget_argc, output_args[i], options) != 1) + { + free_argv(wget_argv, &wget_argc); + return -1; + } + } if(options->resolve_url != NULL) { @@ -361,44 +396,79 @@ resolve_ip_https(fko_cli_options_t *options) /* tack on the original URL to the wget command */ strlcat(wget_ssl_cmd, options->resolve_url, sizeof(wget_ssl_cmd)); + if (add_argv(wget_argv, &wget_argc, options->resolve_url, options) != 1) + { + free_argv(wget_argv, &wget_argc); + return -1; + } } else { /* tack on the default URL to the wget command */ strlcat(wget_ssl_cmd, WGET_RESOLVE_URL_SSL, sizeof(wget_ssl_cmd)); + if (add_argv(wget_argv, &wget_argc, WGET_RESOLVE_URL_SSL, options) != 1) + { + free_argv(wget_argv, &wget_argc); + return -1; + } } /* We drive wget to resolve the external IP via SSL. This may not * work on all platforms, but is a better strategy for now than * requiring that fwknop link against an SSL library. */ - wget = popen(wget_ssl_cmd, "r"); - - if(wget == NULL) + if(pipe(pipe_fd) < 0) { - log_msg(LOG_VERBOSITY_ERROR, "[*] Could not run cmd: %s", - wget_ssl_cmd); + log_msg(LOG_VERBOSITY_ERROR, "[*] pipe() error"); return -1; } - /* Expecting one line of wget output that contains the resolved IP. - */ - if ((fgets(resp, sizeof(resp), wget)) != NULL) + pid = fork(); + if (pid == 0) { - got_resp = 1; + close(pipe_fd[0]); + dup2(pipe_fd[1], STDOUT_FILENO); + dup2(pipe_fd[1], STDERR_FILENO); + execvpe(wget_argv[0], wget_argv, (char * const *)NULL); + } + else if(pid == -1) + { + log_msg(LOG_VERBOSITY_INFO, "[*] Could not fork() for wget."); + return -1; } - pclose(wget); - ndx = resp; - for(i=0; i= 0 && o1 <= 255 && o2 >= 0 && o2 <= 255 @@ -413,7 +483,6 @@ resolve_ip_https(fko_cli_options_t *options) return 1; } } - log_msg(LOG_VERBOSITY_ERROR, "[-] Could not resolve IP via: '%s'", wget_ssl_cmd); return -1; diff --git a/client/utils.c b/client/utils.c index ff16c2ee..7a38fbaa 100644 --- a/client/utils.c +++ b/client/utils.c @@ -275,4 +275,54 @@ proto_strtoint(const char *pr_str) return proto_int; } +int +add_argv(char **argv_new, int *argc_new, + const char *new_arg, fko_cli_options_t *opts) +{ + int buf_size = 0; + + if(opts->verbose > 2) + log_msg(LOG_VERBOSITY_NORMAL, "[+] add_argv() + arg: %s", new_arg); + + buf_size = strlen(new_arg) + 1; + argv_new[*argc_new] = calloc(1, buf_size); + + if(argv_new[*argc_new] == NULL) + { + log_msg(LOG_VERBOSITY_ERROR, "[*] Memory allocation error."); + return 0; + } + strlcpy(argv_new[*argc_new], new_arg, buf_size); + + *argc_new += 1; + + if(*argc_new >= MAX_CMDLINE_ARGS-1) + { + log_msg(LOG_VERBOSITY_ERROR, "[*] max command line args exceeded."); + return 0; + } + + argv_new[*argc_new] = NULL; + + return 1; +} + +void +free_argv(char **argv_new, int *argc_new) +{ + int i; + + if(argv_new == NULL || *argv_new == NULL) + return; + + for (i=0; i < *argc_new; i++) + { + if(argv_new[i] == NULL) + break; + else + free(argv_new[i]); + } + return; +} + /***EOF***/ diff --git a/client/utils.h b/client/utils.h index 0529eef0..e747b0c5 100644 --- a/client/utils.h +++ b/client/utils.h @@ -59,5 +59,7 @@ int verify_file_perms_ownership(const char *file); int resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size_t ip_bufsize); short proto_inttostr(int proto, char *proto_str, size_t proto_size); short proto_strtoint(const char *pr_str); +int add_argv(char **argv_new, int *argc_new, const char *new_arg, fko_cli_options_t *opts); +void free_argv(char **argv_new, int *argc_new); #endif /* UTILS_H */