From e38fb835d0622125f514561c9c34f52f1ff54cd7 Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Thu, 28 Feb 2013 22:53:08 +0100 Subject: [PATCH 01/10] Added save capability for a specific stanza in fwknoprc. --- client/config_init.c | 655 +++++++++++++++++++++++++++++++++++++++-- client/fwknop_common.h | 1 + 2 files changed, 633 insertions(+), 23 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index 38ea0f21..2d86babc 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -27,7 +27,10 @@ * USA * ****************************************************************************** -*/ + */ + +/* FIXME: Finish save capability. */ + #include "fwknop_common.h" #include "netinet_common.h" #include "config_init.h" @@ -36,23 +39,119 @@ #include #include -/* Convert a digest_type string to its integer value. -*/ -static short -digest_strtoint(const char *dt_str) +#define RC_PARAM_TEMPLATE "%-24s %s\n" /*!< Template to define param = val in a rc file */ +#define FWKNOP_CLI_ARG_BM(x) ((uint32_t)(1 << (x))) /*!< Bitmask command line arg */ +#define FWKNOPRC_OFLAGS (O_WRONLY|O_CREAT|O_EXCL) /*!< O_flags used to create an fwknoprc file with the open function */ +#define FWKNOPRC_MODE (S_IRUSR|S_IWUSR) /*!< mode used to create an fwknoprc file with the open function */ + +enum { - if(strcasecmp(dt_str, "md5") == 0) - return(FKO_DIGEST_MD5); - else if(strcasecmp(dt_str, "sha1") == 0) - return(FKO_DIGEST_SHA1); - else if(strcasecmp(dt_str, "sha256") == 0) - return(FKO_DIGEST_SHA256); - else if(strcasecmp(dt_str, "sha384") == 0) - return(FKO_DIGEST_SHA384); - else if(strcasecmp(dt_str, "sha512") == 0) - return(FKO_DIGEST_SHA512); + FWKNOP_CLI_ARG_DIGEST_TYPE = 0, + FWKNOP_CLI_ARG_SPA_SERVER_PROTO, + FWKNOP_CLI_ARG_SPA_SERVER_PORT, + FWKNOP_CLI_ARG_SPA_SOURCE_PORT, + FWKNOP_CLI_ARG_FW_TIMEOUT, + FWKNOP_CLI_ARG_ALLOW_IP, + FWKNOP_CLI_ARG_TIME_OFFSET, + FWKNOP_CLI_ARG_ENCRYPTION_MODE, + FWKNOP_CLI_ARG_USE_GPG, + FWKNOP_CLI_ARG_USE_GPG_AGENT, + FWKNOP_CLI_ARG_GPG_RECIPIENT, + FWKNOP_CLI_ARG_GPG_SIGNER, + FWKNOP_CLI_ARG_GPG_HOMEDIR, + FWKNOP_CLI_ARG_SPOOF_USER, + FWKNOP_CLI_ARG_SPOOF_SOURCE_IP, + FWKNOP_CLI_ARG_ACCESS, + FWKNOP_CLI_ARG_SPA_SERVER, + FWKNOP_CLI_ARG_RAND_PORT, + FWKNOP_CLI_ARG_KEY_FILE, + FWKNOP_CLI_ARG_NAT_ACCESS, + FWKNOP_CLI_ARG_HTTP_USER_AGENT, + FWKNOP_CLI_ARG_RESOLVE_URL, + FWKNOP_CLI_ARG_NAT_LOCAL, + FWKNOP_CLI_ARG_NAT_RAND_PORT, + FWKNOP_CLI_ARG_NAT_PORT, + FWKNOP_CLI_ARG_NB +} fwknop_cli_arg_t; + +const char* fwknop_cli_key_tab[FWKNOP_CLI_ARG_NB] = +{ + "DIGEST_TYPE", + "SPA_SERVER_PROTO", + "SPA_SERVER_PORT", + "SPA_SOURCE_PORT", + "FW_TIMEOUT", + "ALLOW_IP", + "TIME_OFFSET", + "ENCRYPTION_MODE", + "USE_GPG", + "USE_GPG_AGENT", + "GPG_RECIPIENT", + "GPG_SIGNER", + "GPG_HOMEDIR", + "SPOOF_USER", + "SPOOF_SOURCE_IP", + "ACCESS", + "SPA_SERVER", + "RAND_PORT", + "KEY_FILE", + "NAT_ACCESS", + "HTTP_USER_AGENT", + "RESOLVE_URL", + "NAT_LOCAL", + "NAT_RAND_PORT", + "NAT_PORT" +}; + +/** + * \brief Lookup a section in a line and fetch it. + * + * This function parses a NULL terminated string in order to find a section, + * something like [mysection]. If it succeeds, the stanza is retrieved. + * + * \param line String containing a line from the rc file to check for a section + * \param line_size size of the line buffer + * \param rc_section String to store the section found + * \param rc_section_size Size of the rc_section buffer + * + * \return 0 if a section was found, 1 otherwise + */ +static int +lookup_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16_t rc_section_size) +{ + char *ndx, *emark; + char buf[MAX_LINE_LEN]; + int section_not_found = 1; + + /* FIXME : we may want to remove unwanted whitespaces before processing */ + if (line_size < sizeof(buf)) + { + memset (buf, 0, sizeof(buf)); + strlcpy(buf, line, line_size); + + ndx = buf; + + if(*ndx == '[') + { + ndx++; + emark = strchr(ndx, ']'); + if(emark != NULL) + { + *emark = '\0'; + memset(rc_section, 0, rc_section_size); + strlcpy(rc_section, ndx, rc_section_size); + section_not_found = 0; + } + else + { + } + } + } else - return(-1); + { + } + + return section_not_found; } /* Convert an encryption_mode string to its integer value. @@ -76,7 +175,114 @@ enc_mode_strtoint(const char *enc_mode_str) return(-1); } -/* Convert a protocol string to its integer value. +/** + * \brief Return an encryption mode string according to an enc_mode integer value + * + * This function checks if the encryption mode integer is valid, and write the + * encryption mode string associated. + * + * \param enc_mode Encryption mode inetger value (FKO_ENC_MODE_CBC, FKO_ENC_MODE_ECB ...) + * \param enc_mode_str Buffer to write the encryption mode string + * \param enc_mode_size size of the encryption mode string buffer + * + * \return 1 if the encryption mode integer value is not supported, 0 otherwise + */ +static unsigned short +enc_mode_inttostr(unsigned int enc_mode, char* enc_mode_str, size_t enc_mode_size) +{ + unsigned short enc_mode_not_valid = 0; + + memset(enc_mode_str, 0, enc_mode_size); + + switch (enc_mode) + { + case FKO_ENC_MODE_CBC : + strlcpy(enc_mode_str, "CBC", enc_mode_size); + break; + case FKO_ENC_MODE_ECB : + strlcpy(enc_mode_str, "ECB", enc_mode_size); + break; + case FKO_ENC_MODE_CFB : + strlcpy(enc_mode_str, "CFB", enc_mode_size); + break; + case FKO_ENC_MODE_OFB : + strlcpy(enc_mode_str, "OFB", enc_mode_size); + break; + case FKO_ENC_MODE_CTR : + strlcpy(enc_mode_str, "CTR", enc_mode_size); + break; + default: + enc_mode_not_valid = 1; + break; + } + + return enc_mode_not_valid; +} + +/* Convert a digest_type string to its integer value. +*/ +static short +digest_strtoint(const char *dt_str) +{ + if(strcasecmp(dt_str, "md5") == 0) + return(FKO_DIGEST_MD5); + else if(strcasecmp(dt_str, "sha1") == 0) + return(FKO_DIGEST_SHA1); + else if(strcasecmp(dt_str, "sha256") == 0) + return(FKO_DIGEST_SHA256); + else if(strcasecmp(dt_str, "sha384") == 0) + return(FKO_DIGEST_SHA384); + else if(strcasecmp(dt_str, "sha512") == 0) + return(FKO_DIGEST_SHA512); + else + return(-1); +} + +/** + * \brief Return a digest string according to a digest integer value + * + * This function checks the digest integer is valid, and write the digest + * string associated. + * + * \param digest Digest inetger value (FKO_DIGEST_MD5, FKO_DIGEST_SHA1 ...) + * \param digest_str Buffer to write the digest string + * \param digest_size size of the digest string buffer + * + * \return 1 if the digest integer value is not supported, 0 otherwise + */ +static unsigned short +digest_inttostr(unsigned int digest, char* digest_str, size_t digest_size) +{ + unsigned short digest_not_valid = 0; + + memset(digest_str, 0, digest_size); + + switch (digest) + { + case FKO_DIGEST_MD5: + strlcpy(digest_str, "MD5", digest_size); + break; + case FKO_DIGEST_SHA1: + strlcpy(digest_str, "SHA1", digest_size); + break; + case FKO_DIGEST_SHA256: + strlcpy(digest_str, "SHA256", digest_size); + break; + case FKO_DIGEST_SHA384: + strlcpy(digest_str, "SHA384", digest_size); + break; + case FKO_DIGEST_SHA512: + strlcpy(digest_str, "SHA512", digest_size); + break; + default: + digest_not_valid = 1; + break; + } + + return digest_not_valid; +} + +/* Convert a protocol string to its intger value. */ static int proto_strtoint(const char *pr_str) @@ -97,6 +303,50 @@ proto_strtoint(const char *pr_str) return(-1); } +/** + * \brief Return a prototype string according to a prototype integer value + * + * This function checks the prototype integer is valid, and write the prototype + * string associated. + * + * \param proto Prototype inetger value (UDP_RAW, UDP, TCPRAW...) + * \param proto_str Buffer to write the prototype string + * \param proto_size size of the prototype string buffer + * + * \return 1 if the digest integer value is not supported, 0 otherwise + */ +static int +proto_inttostr(unsigned int proto, char* pr_str, size_t pr_size) +{ + uint8_t proto_not_valid = 0; + + memset(pr_str, 0, pr_size); + + switch (proto) + { + case FKO_PROTO_UDP_RAW: + strlcpy(pr_str, "UDPRAW", pr_size); + break; + case FKO_PROTO_UDP: + strlcpy(pr_str, "UDP", pr_size); + break; + case FKO_PROTO_TCP_RAW: + strlcpy(pr_str, "TCPRAW", pr_size); + break; + case FKO_PROTO_TCP: + strlcpy(pr_str, "TCP", pr_size); + break; + case FKO_PROTO_ICMP: + strlcpy(pr_str, "ICMP", pr_size); + break; + default: + proto_not_valid = 1; + break; + } + + return proto_not_valid; +} + /* Parse any time offset from the command line */ static int @@ -159,7 +409,7 @@ create_fwknoprc(const char *rcfile) /* Try to create the initial rcfile with user read/write rights only. * If the rcfile already exists, an error is returned */ - rcfile_fd = open(rcfile, O_WRONLY|O_CREAT|O_EXCL , S_IRUSR|S_IWUSR); + rcfile_fd = open(rcfile, FWKNOPRC_OFLAGS ,FWKNOPRC_MODE); // If an error occured ... if (rcfile_fd == -1) { @@ -483,6 +733,135 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val) return(0); } +/** + * \brief Write a cli parameter to a file handle + * + * This function writes into a file handle a command line parameter + * + * \param fhandle File handle to write the new parameter to + * \param arg_ndx Argument index + * \param options FKO command line option structure + */ +static void +add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) +{ + char val[MAX_LINE_LEN] = {0}; + + if (arg_ndx >= FWKNOP_CLI_ARG_NB) + return; + + if (fhandle == NULL) + return; + + /* Zero the val buffer */ + memset(val, 0, sizeof(val)); + + /* Selecty the argument to add and store its string value into val */ + switch (arg_ndx) + { + case FWKNOP_CLI_ARG_DIGEST_TYPE : + digest_inttostr(options->digest_type, val, sizeof(val)); + break; + case FWKNOP_CLI_ARG_SPA_SERVER_PROTO : + proto_inttostr(options->spa_proto, val, sizeof(val)); + break; + case FWKNOP_CLI_ARG_SPA_SERVER_PORT : + strlcpy(val, options->spa_server_str, sizeof(val)); + break; + case FWKNOP_CLI_ARG_SPA_SOURCE_PORT : + snprintf(val, sizeof(val)-1, "%d", options->spa_src_port); + break; + case FWKNOP_CLI_ARG_FW_TIMEOUT : + snprintf(val, sizeof(val)-1, "%d", options->fw_timeout); + break; + case FWKNOP_CLI_ARG_ALLOW_IP : + strlcpy(val, options->allow_ip_str, sizeof(val)); + break; + case FWKNOP_CLI_ARG_TIME_OFFSET : + if (options->time_offset_minus != 0) + snprintf(val, sizeof(val)-1, "%d", options->time_offset_minus); + else if (options->time_offset_plus != 0) + snprintf(val, sizeof(val)-1, "%d", options->time_offset_minus); + else + { + } + break; + case FWKNOP_CLI_ARG_ENCRYPTION_MODE : + enc_mode_inttostr(options->encryption_mode, val, sizeof(val)); + break; + case FWKNOP_CLI_ARG_USE_GPG : + if (options->use_gpg == 0) + strlcpy(val, "N", sizeof(val)); + else + strlcpy(val, "Y", sizeof(val)); + break; + case FWKNOP_CLI_ARG_USE_GPG_AGENT : + if (options->use_gpg_agent == 0) + strlcpy(val, "N", sizeof(val)); + else + strlcpy(val, "Y", sizeof(val)); + break; + case FWKNOP_CLI_ARG_GPG_RECIPIENT : + strlcpy(val, options->gpg_recipient_key, sizeof(val)); + break; + case FWKNOP_CLI_ARG_GPG_SIGNER : + strlcpy(val, options->gpg_signer_key, sizeof(val)); + break; + case FWKNOP_CLI_ARG_GPG_HOMEDIR : + strlcpy(val, options->gpg_home_dir, sizeof(val)); + break; + case FWKNOP_CLI_ARG_SPOOF_USER : + strlcpy(val, options->spoof_user, sizeof(val)); + break; + case FWKNOP_CLI_ARG_SPOOF_SOURCE_IP : + strlcpy(val, options->spoof_ip_src_str, sizeof(val)); + break; + case FWKNOP_CLI_ARG_ACCESS : + strlcpy(val, options->access_str, sizeof(val)); + break; + case FWKNOP_CLI_ARG_SPA_SERVER : + strlcpy(val, options->spa_server_str, sizeof(val)); + break; + case FWKNOP_CLI_ARG_RAND_PORT : + snprintf(val, sizeof(val)-1, "%d", options->rand_port); + break; + case FWKNOP_CLI_ARG_KEY_FILE : + strlcpy(val, options->get_key_file, sizeof(val)); + break; + case FWKNOP_CLI_ARG_NAT_ACCESS : + strlcpy(val, options->nat_access_str, sizeof(val)); + break; + case FWKNOP_CLI_ARG_HTTP_USER_AGENT : + strlcpy(val, options->http_user_agent, sizeof(val)); + break; + case FWKNOP_CLI_ARG_RESOLVE_URL : + if (options->resolve_url != NULL) + strlcpy(val, options->resolve_url, sizeof(val)); + else + { + } + break; + case FWKNOP_CLI_ARG_NAT_LOCAL : + snprintf(val, sizeof(val)-1, "%d", options->nat_local); + break; + case FWKNOP_CLI_ARG_NAT_RAND_PORT : + snprintf(val, sizeof(val)-1, "%d", options->nat_rand_port); + break; + case FWKNOP_CLI_ARG_NAT_PORT : + snprintf(val, sizeof(val)-1, "%d", options->nat_port); + break; + default: + fprintf(stderr, "Warning from add_rc_param() : Bad command line argument %u", arg_ndx); + return; + } + + if(options->verbose > 3) + fprintf(stderr, "Updating param (%u) %s to %s\n", + arg_ndx, fwknop_cli_key_tab[arg_ndx], val); + + fprintf(fhandle, RC_PARAM_TEMPLATE, fwknop_cli_key_tab[arg_ndx], val); +} + /* Process (create if necessary) the users ~/.fwknoprc file. */ static void @@ -673,6 +1052,175 @@ process_rc(fko_cli_options_t *options) exit(EXIT_FAILURE); } +/** + * \brief Update the user rc file with the new parameters for a selected stanza. + * + * This function writes the new configuration in a temporary file and renames it + * as the new rc file afterwards. All of the previous parameters for the + * selected stanza are removed and replaced by the arguments from the command + * line. + * + * \param options structure containing all of the fko settings + * \param args_bitmask command line argument bitmask + */ +static void +update_rc(fko_cli_options_t *options, uint32_t args_bitmask) +{ + FILE *rc; + FILE *rc_update; + int rcf_offset; + int stanza_found = 0; + int stanza_updated = 0; + char line[MAX_LINE_LEN]; + char rcfile[MAX_PATH_LEN]; + char rcfile_update[MAX_PATH_LEN]; + char curr_stanza[MAX_LINE_LEN] = {0}; + char *homedir; + uint16_t arg_ndx = 0; + int rcfile_fd = -1; + +#ifdef WIN32 + homedir = getenv("USERPROFILE"); +#else + homedir = getenv("HOME"); +#endif + + if(homedir == NULL) + { + fprintf(stderr, "update_rc() : Unable to determine HOME directory.\n" + " No .fwknoprc file processed.\n"); + return; + } + + memset(rcfile, 0, MAX_PATH_LEN); + memset(rcfile_update, 0, MAX_PATH_LEN); + + strlcpy(rcfile, homedir, MAX_PATH_LEN); + + rcf_offset = strlen(rcfile); + + /* Sanity check the path to .fwknoprc. + * The preceeding path plus the path separator and '.fwknoprc' = 11 + * cannot exceed MAX_PATH_LEN. + */ + if(rcf_offset > (MAX_PATH_LEN - 11)) + { + fprintf(stderr, "update_rc() : Path to .fwknoprc file is too long.\n" + " No .fwknoprc file processed.\n"); + return; + } + + rcfile[rcf_offset] = PATH_SEP; + strlcat(rcfile, ".fwknoprc", MAX_PATH_LEN); + + strlcpy(rcfile_update, rcfile, MAX_PATH_LEN); + strlcat(rcfile_update, ".updated", MAX_PATH_LEN); + + /* Create a new temporary rc file */ + rcfile_fd = open(rcfile_update, FWKNOPRC_OFLAGS, FWKNOPRC_MODE); + if (rcfile_fd == -1) + { + fprintf(stderr, "update_rc() : Unable to create initial rc file: %s: %s\n", + rcfile_update, strerror(errno)); + return; + } + close(rcfile_fd); + + /* Open the current rcfile and a temporary one respectively in read and + * write mode */ + if ((rc = fopen(rcfile, "r")) == NULL) + { + fprintf(stderr, "update_rc() : Unable to open rc file: %s: %s\n", + rcfile, strerror(errno)); + } + + if ((rc_update = fopen(rcfile_update, "w")) == NULL) + { + fprintf(stderr, "update_rc() : Unable to open rc file: %s: %s\n", + rcfile_update, strerror(errno)); + } + + /* Go though the file line by line */ + stanza_found = 0; + while ((fgets(line, MAX_LINE_LEN, rc)) != NULL) + { + line[MAX_LINE_LEN-1] = '\0'; + + /* If we find a section... */ + if(lookup_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)) == 0) + { + /* and this is the one we are looking for, we add the new settings */ + if (strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN)==0) + { + stanza_found = 1; + fprintf(rc_update, "%s", line); + + if(options->verbose > 3) + fprintf(stderr, "Updating %s stanza\n", curr_stanza); + + for (arg_ndx=0 ; arg_ndxuse_rc_stanza); + + if(options->verbose > 3) + fprintf(stderr, "Updating %s stanza\n", curr_stanza); + + for (arg_ndx=0 ; arg_ndxno_save_args = 1; + options->save_rc_stanza= 1; strlcpy(options->use_rc_stanza, optarg, MAX_LINE_LEN); break; case 'E': @@ -811,9 +1362,11 @@ config_init(fko_cli_options_t *options, int argc, char **argv) switch(cmd_arg) { case 'a': strlcpy(options->allow_ip_str, optarg, MAX_IPV4_STR_LEN); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_ALLOW_IP); break; case 'A': strlcpy(options->access_str, optarg, MAX_LINE_LEN); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_ACCESS); break; case 'b': options->save_packet_file_append = 1; @@ -826,6 +1379,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) break; case 'D': strlcpy(options->spa_server_str, optarg, MAX_SERVER_STR_LEN); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_SPA_SERVER); break; case 'E': strlcpy(options->args_save_file, optarg, MAX_PATH_LEN); @@ -839,13 +1393,16 @@ config_init(fko_cli_options_t *options, int argc, char **argv) 0, (2 << 16)); exit(EXIT_FAILURE); } + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_FW_TIMEOUT); break; case 'g': case GPG_ENCRYPTION: options->use_gpg = 1; + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_USE_GPG); break; case 'G': strlcpy(options->get_key_file, optarg, MAX_PATH_LEN); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_KEY_FILE); break; case 'h': usage(); @@ -893,6 +1450,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) optarg); exit(EXIT_FAILURE); } + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_DIGEST_TYPE); break; case 'M': case ENCRYPTION_MODE: @@ -903,6 +1461,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) optarg); exit(EXIT_FAILURE); } + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_ENCRYPTION_MODE); break; case NO_SAVE_ARGS: options->no_save_args = 1; @@ -913,10 +1472,12 @@ config_init(fko_cli_options_t *options, int argc, char **argv) break; case 'N': strlcpy(options->nat_access_str, optarg, MAX_LINE_LEN); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_NAT_ACCESS); break; case 'p': options->spa_dst_port = strtol_wrapper(optarg, 0, MAX_PORT, EXIT_UPON_ERR, &is_err); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_SPA_SERVER_PORT); break; case 'P': if((options->spa_proto = proto_strtoint(optarg)) < 0) @@ -924,15 +1485,18 @@ config_init(fko_cli_options_t *options, int argc, char **argv) fprintf(stderr, "Unrecognized protocol: %s\n", optarg); exit(EXIT_FAILURE); } + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_SPA_SERVER_PROTO); break; case 'Q': strlcpy(options->spoof_ip_src_str, optarg, MAX_IPV4_STR_LEN); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_SPOOF_SOURCE_IP); break; case RC_FILE_PATH: strlcpy(options->rc_file, optarg, MAX_PATH_LEN); break; case 'r': options->rand_port = 1; + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_RAND_PORT); break; case 'R': options->resolve_ip_http = 1; @@ -947,6 +1511,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) exit(EXIT_FAILURE); } strlcpy(options->resolve_url, optarg, strlen(optarg)+1); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_RESOLVE_URL); break; case SHOW_LAST_ARGS: options->show_last_command = 1; @@ -957,15 +1522,18 @@ config_init(fko_cli_options_t *options, int argc, char **argv) case 'S': options->spa_src_port = strtol_wrapper(optarg, 0, MAX_PORT, EXIT_UPON_ERR, &is_err); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_SPA_SOURCE_PORT); break; case 'T': options->test = 1; break; case 'u': strlcpy(options->http_user_agent, optarg, HTTP_MAX_USER_AGENT_LEN); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_HTTP_USER_AGENT); break; case 'U': strlcpy(options->spoof_user, optarg, MAX_USERNAME_LEN); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_SPOOF_USER); break; case 'v': /* Handled earlier. @@ -977,34 +1545,47 @@ config_init(fko_cli_options_t *options, int argc, char **argv) case GPG_RECIP_KEY: options->use_gpg = 1; strlcpy(options->gpg_recipient_key, optarg, MAX_GPG_KEY_ID); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_USE_GPG); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_GPG_RECIPIENT); break; case GPG_SIGNER_KEY: options->use_gpg = 1; strlcpy(options->gpg_signer_key, optarg, MAX_GPG_KEY_ID); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_USE_GPG); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_GPG_SIGNER); break; case GPG_HOME_DIR: options->use_gpg = 1; strlcpy(options->gpg_home_dir, optarg, MAX_PATH_LEN); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_USE_GPG); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_GPG_HOMEDIR); break; case GPG_AGENT: options->use_gpg = 1; options->use_gpg_agent = 1; + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_USE_GPG); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_USE_GPG_AGENT); break; case NAT_LOCAL: options->nat_local = 1; + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_NAT_LOCAL); break; case NAT_RAND_PORT: options->nat_rand_port = 1; + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_NAT_RAND_PORT); break; case NAT_PORT: options->nat_port = strtol_wrapper(optarg, 0, MAX_PORT, EXIT_UPON_ERR, &is_err); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_NAT_PORT); break; case TIME_OFFSET_PLUS: options->time_offset_plus = parse_time_offset(optarg); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_TIME_OFFSET); break; case TIME_OFFSET_MINUS: options->time_offset_minus = parse_time_offset(optarg); + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_TIME_OFFSET); break; case USE_HMAC: options->use_hmac = 1; @@ -1015,10 +1596,37 @@ config_init(fko_cli_options_t *options, int argc, char **argv) } } - /* Now that we have all of our options set, we can validate them. - */ + /* Ask the user whether we overwrite the stanza from the rcfile with the + * command line arguments */ + if ( (options->save_rc_stanza == 1) + && (cli_arg_bitmask != 0) + && (options->got_named_stanza == 1) ) + { + fprintf(stdout, "Overwritting stanza [%s] [Y/n] ? ", options->use_rc_stanza); + + if (scanf("%c", &user_input ) != 1) + user_input = 'Y'; + + if (user_input != 'Y') + { + options->save_rc_stanza = 0; + process_rc(options); + } + } + + /* Force a stanza found since we are going to update it. We cannot update + * the rcfile without prio validation */ + if ( (options->save_rc_stanza == 1) && (cli_arg_bitmask != 0) ) + options->got_named_stanza = 1; + + /* Now that we have all of our options set, we can validate them */ validate_options(options); + /* We can upgrade our settings with the parameters set on the command + * line by the user */ + if ( (options->save_rc_stanza == 1) && (cli_arg_bitmask != 0) ) + update_rc(options, cli_arg_bitmask); + return; } @@ -1043,8 +1651,9 @@ usage(void) " -n, --named-config Specify an named configuration stanza in the\n" " '$HOME/.fwknoprc' file to provide some of all\n" " of the configuration parameters.\n" - " -N, --nat-access Gain NAT access to an internal service\n" - " protected by the fwknop server.\n" + " If more arguments are set through the command\n" + " line, the configuration is updated accordingly\n" + " -N, --nat-access Gain NAT access to an internal service.\n" " -p, --server-port Set the destination port for outgoing SPA\n" " packet.\n" " -P, --server-proto Set the protocol (udp, tcp, http, tcpraw,\n" diff --git a/client/fwknop_common.h b/client/fwknop_common.h index 01915f1b..c7923be7 100644 --- a/client/fwknop_common.h +++ b/client/fwknop_common.h @@ -152,6 +152,7 @@ typedef struct fko_cli_options char use_rc_stanza[MAX_LINE_LEN]; unsigned char got_named_stanza; + unsigned char save_rc_stanza; //char config_file[MAX_PATH_LEN]; From 38a803fb71d463a3e20227f03d7cff64f85e578b Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Sun, 3 Mar 2013 18:41:31 +0100 Subject: [PATCH 02/10] * Added KEY, KEY_BASE64 and HMAC_KEY_BASE64 definitions to the save capability. * Allowed section to be found during an update of fwknoprc even if there are somes spaces before the stanza. * Allowed the user to strike the ENTER key to overwrite the section as it will be done with the 'Y' char. --- client/config_init.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index 2d86babc..47771cd1 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -40,6 +40,7 @@ #include #define RC_PARAM_TEMPLATE "%-24s %s\n" /*!< Template to define param = val in a rc file */ +#define RC_SECTION_TEMPLATE "[%s]\n" /*!< Template to define a section in a rc file */ #define FWKNOP_CLI_ARG_BM(x) ((uint32_t)(1 << (x))) /*!< Bitmask command line arg */ #define FWKNOPRC_OFLAGS (O_WRONLY|O_CREAT|O_EXCL) /*!< O_flags used to create an fwknoprc file with the open function */ #define FWKNOPRC_MODE (S_IRUSR|S_IWUSR) /*!< mode used to create an fwknoprc file with the open function */ @@ -64,6 +65,9 @@ enum FWKNOP_CLI_ARG_ACCESS, FWKNOP_CLI_ARG_SPA_SERVER, FWKNOP_CLI_ARG_RAND_PORT, + FWKNOP_CLI_ARG_KEY, + FWKNOP_CLI_ARG_KEY_BASE64, + FWKNOP_CLI_ARG_KEY_HMAC_BASE64, FWKNOP_CLI_ARG_KEY_FILE, FWKNOP_CLI_ARG_NAT_ACCESS, FWKNOP_CLI_ARG_HTTP_USER_AGENT, @@ -94,6 +98,9 @@ const char* fwknop_cli_key_tab[FWKNOP_CLI_ARG_NB] = "ACCESS", "SPA_SERVER", "RAND_PORT", + "KEY", + "KEY_BASE64", + "HMAC_KEY_BASE64", "KEY_FILE", "NAT_ACCESS", "HTTP_USER_AGENT", @@ -123,7 +130,6 @@ lookup_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16 char buf[MAX_LINE_LEN]; int section_not_found = 1; - /* FIXME : we may want to remove unwanted whitespaces before processing */ if (line_size < sizeof(buf)) { memset (buf, 0, sizeof(buf)); @@ -131,6 +137,9 @@ lookup_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16 ndx = buf; + while(isspace(*ndx)) + ndx++; + if(*ndx == '[') { ndx++; @@ -1120,7 +1129,7 @@ update_rc(fko_cli_options_t *options, uint32_t args_bitmask) rcfile_fd = open(rcfile_update, FWKNOPRC_OFLAGS, FWKNOPRC_MODE); if (rcfile_fd == -1) { - fprintf(stderr, "update_rc() : Unable to create initial rc file: %s: %s\n", + fprintf(stderr, "update_rc() : Unable to create temporary rc file: %s: %s\n", rcfile_update, strerror(errno)); return; } @@ -1132,6 +1141,7 @@ update_rc(fko_cli_options_t *options, uint32_t args_bitmask) { fprintf(stderr, "update_rc() : Unable to open rc file: %s: %s\n", rcfile, strerror(errno)); + return; } if ((rc_update = fopen(rcfile_update, "w")) == NULL) @@ -1153,7 +1163,7 @@ update_rc(fko_cli_options_t *options, uint32_t args_bitmask) if (strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN)==0) { stanza_found = 1; - fprintf(rc_update, "%s", line); + fprintf(rc_update, RC_SECTION_TEMPLATE, curr_stanza); if(options->verbose > 3) fprintf(stderr, "Updating %s stanza\n", curr_stanza); @@ -1607,7 +1617,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) if (scanf("%c", &user_input ) != 1) user_input = 'Y'; - if (user_input != 'Y') + if ((user_input != 'Y') && (user_input != 0x0A)) { options->save_rc_stanza = 0; process_rc(options); From 053db37c0dd711ff7c189fb84f498af859cb7a4c Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Tue, 5 Mar 2013 21:01:38 +0100 Subject: [PATCH 03/10] Added more command line switches in order for the user to be able to specify the Rijndael, Rijndael base64 and HMAC key. --- client/cmd_opts.h | 6 +++++ client/config_init.c | 58 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/client/cmd_opts.h b/client/cmd_opts.h index 0a4854c4..7b74b3f5 100644 --- a/client/cmd_opts.h +++ b/client/cmd_opts.h @@ -54,6 +54,9 @@ enum { GPG_AGENT, SPA_ICMP_TYPE, SPA_ICMP_CODE, + KEY_RIJNDAEL, + KEY_RIJNDAEL_BASE64, + KEY_HMAC_BASE64, NOOP /* Just to be a marker for the end */ }; @@ -87,6 +90,9 @@ static struct option cmd_opts[] = {"http-proxy", 1, NULL, 'H'}, {"key-gen", 0, NULL, 'k'}, {"key-gen-file", 1, NULL, 'K'}, + {"key-rijndael", 1, NULL, KEY_RIJNDAEL }, + {"key-rijndael-base64", 1, NULL, KEY_RIJNDAEL_BASE64 }, + {"key-hmac-base64", 1, NULL, KEY_HMAC_BASE64 }, {"icmp-type", 1, NULL, SPA_ICMP_TYPE }, {"icmp-code", 1, NULL, SPA_ICMP_CODE }, {"last-cmd", 0, NULL, 'l'}, diff --git a/client/config_init.c b/client/config_init.c index 47771cd1..39a55299 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -29,7 +29,9 @@ ****************************************************************************** */ -/* FIXME: Finish save capability. */ +/* FIXME: Finish save capability. + * SPAC_ICMP_TYPE and ICMP_SPA_CODE are not stored in the stanza + */ #include "fwknop_common.h" #include "netinet_common.h" @@ -65,8 +67,8 @@ enum FWKNOP_CLI_ARG_ACCESS, FWKNOP_CLI_ARG_SPA_SERVER, FWKNOP_CLI_ARG_RAND_PORT, - FWKNOP_CLI_ARG_KEY, - FWKNOP_CLI_ARG_KEY_BASE64, + FWKNOP_CLI_ARG_KEY_RIJNDAEL, + FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64, FWKNOP_CLI_ARG_KEY_HMAC_BASE64, FWKNOP_CLI_ARG_KEY_FILE, FWKNOP_CLI_ARG_NAT_ACCESS, @@ -837,6 +839,15 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) case FWKNOP_CLI_ARG_KEY_FILE : strlcpy(val, options->get_key_file, sizeof(val)); break; + case FWKNOP_CLI_ARG_KEY_RIJNDAEL: + strlcpy(val, options->key, sizeof(val)); + break; + case FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64: + strlcpy(val, options->key_base64, sizeof(val)); + break; + case FWKNOP_CLI_ARG_KEY_HMAC_BASE64: + strlcpy(val, options->hmac_key_base64, sizeof(val)); + break; case FWKNOP_CLI_ARG_NAT_ACCESS : strlcpy(val, options->nat_access_str, sizeof(val)); break; @@ -1428,6 +1439,35 @@ config_init(fko_cli_options_t *options, int argc, char **argv) options->key_gen = 1; strlcpy(options->key_gen_file, optarg, MAX_PATH_LEN); break; + case KEY_RIJNDAEL: + strlcpy(options->key, optarg, MAX_KEY_LEN); + options->have_key = 1; + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_KEY_RIJNDAEL); + break; + case KEY_RIJNDAEL_BASE64: + if (! is_base64((unsigned char *) optarg, strlen(optarg))) + { + fprintf(stderr, + "Base64 encoded Rijndael argument '%s' doesn't look like base64-encoded data.\n", + optarg); + exit(EXIT_FAILURE); + } + strlcpy(options->key_base64, optarg, MAX_KEY_LEN); + options->have_base64_key = 1; + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64); + break; + case KEY_HMAC_BASE64: + if (! is_base64((unsigned char *) optarg, strlen(optarg))) + { + fprintf(stderr, + "Base64 encoded HMAC argument '%s' doesn't look like base64-encoded data.\n", + optarg); + exit(EXIT_FAILURE); + } + strlcpy(options->hmac_key_base64, optarg, MAX_KEY_LEN); + options->have_hmac_base64_key = 1; + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_KEY_HMAC_BASE64); + break; case SPA_ICMP_TYPE: options->spa_icmp_type = strtol_wrapper(optarg, 0, MAX_ICMP_TYPE, NO_EXIT_UPON_ERR, &is_err); @@ -1698,6 +1738,18 @@ usage(void) " -k, --key-gen Generate SPA Rijndael + HMAC keys.\n" " -K, --key-gen-file Write generated Rijndael + HMAC keys to a\n" " file\n" + " --key-rijndael Specify the Rijndael key. Since the password is\n" + " visible to utilities (like 'ps' under Unix) this\n" + " form should only be used where security is not\n" + " important.\n" + " --key-base64-rijndael Specify the base64 encoded Rijndael key. Since\n" + " the password is visible to utilities (like 'ps'\n" + " under Unix) this form should only be used where\n" + " security is not important.\n" + " --key-base64-hmac Specify the base64 encoded HMAC key. Since the\n" + " password is visible to utilities (like 'ps'\n" + " under Unix) this form should only be used where\n" + " security is not important.\n" " -r, --rand-port Send the SPA packet over a randomly assigned\n" " port (requires a broader pcap filter on the\n" " server side than the default of udp 62201).\n" From c2ef7f224ad067251b5c6b4790a2465be943139f Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Sat, 9 Mar 2013 12:17:17 +0100 Subject: [PATCH 04/10] Moved static functions from the client to the fko_util.c file. --- client/config_init.c | 128 ------------------------------------------- lib/fko_util.c | 94 +++++++++++++++++++++++++++++++ lib/fko_util.h | 22 ++++---- 3 files changed, 106 insertions(+), 138 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index 52b0db0f..ec4bdb28 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -165,134 +165,6 @@ lookup_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16 return section_not_found; } -/* Convert an encryption_mode string to its integer value. -*/ -static int -enc_mode_strtoint(const char *enc_mode_str) -{ - if(strcasecmp(enc_mode_str, "cbc") == 0) - return(FKO_ENC_MODE_CBC); - else if(strcasecmp(enc_mode_str, "ecb") == 0) - return(FKO_ENC_MODE_ECB); - else if(strcasecmp(enc_mode_str, "cfb") == 0) - return(FKO_ENC_MODE_CFB); - else if(strcasecmp(enc_mode_str, "pcbc") == 0) - return(-1); /* not supported yet */ - else if(strcasecmp(enc_mode_str, "ofb") == 0) - return(FKO_ENC_MODE_OFB); - else if(strcasecmp(enc_mode_str, "ctr") == 0) - return(FKO_ENC_MODE_CTR); - else - return(-1); -} - -/** - * \brief Return an encryption mode string according to an enc_mode integer value - * - * This function checks if the encryption mode integer is valid, and write the - * encryption mode string associated. - * - * \param enc_mode Encryption mode inetger value (FKO_ENC_MODE_CBC, FKO_ENC_MODE_ECB ...) - * \param enc_mode_str Buffer to write the encryption mode string - * \param enc_mode_size size of the encryption mode string buffer - * - * \return 1 if the encryption mode integer value is not supported, 0 otherwise - */ -static unsigned short -enc_mode_inttostr(unsigned int enc_mode, char* enc_mode_str, size_t enc_mode_size) -{ - unsigned short enc_mode_not_valid = 0; - - memset(enc_mode_str, 0, enc_mode_size); - - switch (enc_mode) - { - case FKO_ENC_MODE_CBC : - strlcpy(enc_mode_str, "CBC", enc_mode_size); - break; - case FKO_ENC_MODE_ECB : - strlcpy(enc_mode_str, "ECB", enc_mode_size); - break; - case FKO_ENC_MODE_CFB : - strlcpy(enc_mode_str, "CFB", enc_mode_size); - break; - case FKO_ENC_MODE_OFB : - strlcpy(enc_mode_str, "OFB", enc_mode_size); - break; - case FKO_ENC_MODE_CTR : - strlcpy(enc_mode_str, "CTR", enc_mode_size); - break; - default: - enc_mode_not_valid = 1; - break; - } - - return enc_mode_not_valid; -} - -/* Convert a digest_type string to its integer value. -*/ -static short -digest_strtoint(const char *dt_str) -{ - if(strcasecmp(dt_str, "md5") == 0) - return(FKO_DIGEST_MD5); - else if(strcasecmp(dt_str, "sha1") == 0) - return(FKO_DIGEST_SHA1); - else if(strcasecmp(dt_str, "sha256") == 0) - return(FKO_DIGEST_SHA256); - else if(strcasecmp(dt_str, "sha384") == 0) - return(FKO_DIGEST_SHA384); - else if(strcasecmp(dt_str, "sha512") == 0) - return(FKO_DIGEST_SHA512); - else - return(-1); -} - -/** - * \brief Return a digest string according to a digest integer value - * - * This function checks the digest integer is valid, and write the digest - * string associated. - * - * \param digest Digest inetger value (FKO_DIGEST_MD5, FKO_DIGEST_SHA1 ...) - * \param digest_str Buffer to write the digest string - * \param digest_size size of the digest string buffer - * - * \return 1 if the digest integer value is not supported, 0 otherwise - */ -static unsigned short -digest_inttostr(unsigned int digest, char* digest_str, size_t digest_size) -{ - unsigned short digest_not_valid = 0; - - memset(digest_str, 0, digest_size); - - switch (digest) - { - case FKO_DIGEST_MD5: - strlcpy(digest_str, "MD5", digest_size); - break; - case FKO_DIGEST_SHA1: - strlcpy(digest_str, "SHA1", digest_size); - break; - case FKO_DIGEST_SHA256: - strlcpy(digest_str, "SHA256", digest_size); - break; - case FKO_DIGEST_SHA384: - strlcpy(digest_str, "SHA384", digest_size); - break; - case FKO_DIGEST_SHA512: - strlcpy(digest_str, "SHA512", digest_size); - break; - default: - digest_not_valid = 1; - break; - } - - return digest_not_valid; -} - /* Convert a protocol string to its intger value. */ static int diff --git a/lib/fko_util.c b/lib/fko_util.c index 099c30a8..1ae3f563 100644 --- a/lib/fko_util.c +++ b/lib/fko_util.c @@ -63,6 +63,49 @@ digest_strtoint(const char *dt_str) return(-1); } +/** + * \brief Return a digest string according to a digest integer value + * + * This function checks the digest integer is valid, and write the digest + * string associated. + * + * \param digest Digest inetger value (FKO_DIGEST_MD5, FKO_DIGEST_SHA1 ...) + * \param digest_str Buffer to write the digest string + * \param digest_size size of the digest string buffer + * + * \return -1 if the digest integer value is not supported, 0 otherwise + */ +short +digest_inttostr(int digest, char* digest_str, size_t digest_size) +{ + short digest_not_valid = 0; + + memset(digest_str, 0, digest_size); + + switch (digest) + { + case FKO_DIGEST_MD5: + strlcpy(digest_str, "MD5", digest_size); + break; + case FKO_DIGEST_SHA1: + strlcpy(digest_str, "SHA1", digest_size); + break; + case FKO_DIGEST_SHA256: + strlcpy(digest_str, "SHA256", digest_size); + break; + case FKO_DIGEST_SHA384: + strlcpy(digest_str, "SHA384", digest_size); + break; + case FKO_DIGEST_SHA512: + strlcpy(digest_str, "SHA512", digest_size); + break; + default: + digest_not_valid = -1; + break; + } + + return digest_not_valid; +} short hmac_digest_strtoint(const char *dt_str) { @@ -114,6 +157,57 @@ enc_mode_strtoint(const char *enc_mode_str) return(-1); } +/** + * \brief Return an encryption mode string according to an enc_mode integer value + * + * This function checks if the encryption mode integer is valid, and write the + * encryption mode string associated. + * + * \param enc_mode Encryption mode inetger value (FKO_ENC_MODE_CBC, FKO_ENC_MODE_ECB ...) + * \param enc_mode_str Buffer to write the encryption mode string + * \param enc_mode_size size of the encryption mode string buffer + * + * \return -1 if the encryption mode integer value is not supported, 0 otherwise + */ +short +enc_mode_inttostr(int enc_mode, char* enc_mode_str, size_t enc_mode_size) +{ + short enc_mode_not_valid = 0; + + memset(enc_mode_str, 0, enc_mode_size); + + switch (enc_mode) + { + case FKO_ENC_MODE_CBC : + strlcpy(enc_mode_str, "CBC", enc_mode_size); + break; + case FKO_ENC_MODE_ECB : + strlcpy(enc_mode_str, "ECB", enc_mode_size); + break; + case FKO_ENC_MODE_CFB : + strlcpy(enc_mode_str, "CFB", enc_mode_size); + break; + case FKO_ENC_MODE_PCBC : + //strlcpy(enc_mode_str, "PCBC", enc_mode_size); + enc_mode_not_valid = -1; + break; + case FKO_ENC_MODE_OFB : + strlcpy(enc_mode_str, "OFB", enc_mode_size); + break; + case FKO_ENC_MODE_CTR : + strlcpy(enc_mode_str, "CTR", enc_mode_size); + break; + case FKO_ENC_MODE_CBC_LEGACY_IV: + strlcpy(enc_mode_str, "LEGACY", enc_mode_size); + break; + default: + enc_mode_not_valid = -1; + break; + } + + return enc_mode_not_valid; +} + int strtol_wrapper(const char * const str, const int min, const int max, const int exit_upon_err, int *err) diff --git a/lib/fko_util.h b/lib/fko_util.h index a1e88504..2a234350 100644 --- a/lib/fko_util.h +++ b/lib/fko_util.h @@ -33,17 +33,19 @@ /* Function prototypes */ -int is_valid_encoded_msg_len(const int len); -int is_valid_pt_msg_len(const int len); -int is_valid_digest_len(const int len); -int enc_mode_strtoint(const char *enc_mode_str); -int strtol_wrapper(const char * const str, const int min, - const int max, const int exit_upon_err, int *is_err); -short digest_strtoint(const char *dt_str); -short hmac_digest_strtoint(const char *dt_str); +int is_valid_encoded_msg_len(const int len); +int is_valid_pt_msg_len(const int len); +int is_valid_digest_len(const int len); +int enc_mode_strtoint(const char *enc_mode_str); +short enc_mode_inttostr(int enc_mode, char* enc_mode_str, size_t enc_mode_size); +int strtol_wrapper(const char * const str, const int min, + const int max, const int exit_upon_err, int *is_err); +short digest_strtoint(const char *dt_str); +short digest_inttostr(int digest, char* digest_str, size_t digest_size); +short hmac_digest_strtoint(const char *dt_str); -size_t strlcat(char *dst, const char *src, size_t siz); -size_t strlcpy(char *dst, const char *src, size_t siz); +size_t strlcat(char *dst, const char *src, size_t siz); +size_t strlcpy(char *dst, const char *src, size_t siz); #endif /* FKO_UTIL_H */ From c5163fcc24a1ef22c4540044aaacc9c9063741ff Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Sat, 9 Mar 2013 12:39:05 +0100 Subject: [PATCH 05/10] Added new parameters HMAC_DIGEST_TYPE to the save capability. --- client/config_init.c | 7 ++++++- lib/fko_util.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ lib/fko_util.h | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/client/config_init.c b/client/config_init.c index ec4bdb28..6bd9616e 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -30,7 +30,6 @@ */ /* FIXME: Finish save capability. - * SPAC_ICMP_TYPE and ICMP_SPA_CODE are not stored in the stanza */ #include "fwknop_common.h" @@ -69,6 +68,7 @@ enum FWKNOP_CLI_ARG_RAND_PORT, FWKNOP_CLI_ARG_KEY_RIJNDAEL, FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64, + FWKNOP_CLI_ARG_HMAC_DIGEST_TYPE, FWKNOP_CLI_ARG_KEY_HMAC_BASE64, FWKNOP_CLI_ARG_KEY_FILE, FWKNOP_CLI_ARG_NAT_ACCESS, @@ -102,6 +102,7 @@ const char* fwknop_cli_key_tab[FWKNOP_CLI_ARG_NB] = "RAND_PORT", "KEY", "KEY_BASE64", + "HMAC_DIGEST_TYPE", "HMAC_KEY_BASE64", "KEY_FILE", "NAT_ACCESS", @@ -736,6 +737,9 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) case FWKNOP_CLI_ARG_KEY_HMAC_BASE64: strlcpy(val, options->hmac_key_base64, sizeof(val)); break; + case FWKNOP_CLI_ARG_HMAC_DIGEST_TYPE : + hmac_digest_inttostr(options->hmac_type, val, sizeof(val)); + break; case FWKNOP_CLI_ARG_NAT_ACCESS : strlcpy(val, options->nat_access_str, sizeof(val)); break; @@ -1378,6 +1382,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) optarg); exit(EXIT_FAILURE); } + cli_arg_bitmask |= FWKNOP_CLI_ARG_BM(FWKNOP_CLI_ARG_HMAC_DIGEST_TYPE); break; case HMAC_KEY_LEN: options->hmac_key_len = strtol_wrapper(optarg, 1, diff --git a/lib/fko_util.c b/lib/fko_util.c index 1ae3f563..1052609c 100644 --- a/lib/fko_util.c +++ b/lib/fko_util.c @@ -106,6 +106,7 @@ digest_inttostr(int digest, char* digest_str, size_t digest_size) return digest_not_valid; } + short hmac_digest_strtoint(const char *dt_str) { @@ -123,6 +124,50 @@ hmac_digest_strtoint(const char *dt_str) return(-1); } +/** + * \brief Return a hmac digest string according to a hmac digest integer value + * + * This function checks if the digest integer is valid, and write the digest + * string associated. + * + * \param digest Digest inetger value (FKO_HMAC_MD5, FKO_HMAC_SHA1 ...) + * \param digest_str Buffer to write the digest string + * \param digest_size size of the digest string buffer + * + * \return -1 if the digest integer value is not supported, 0 otherwise + */ +short +hmac_digest_inttostr(int digest, char* digest_str, size_t digest_size) +{ + short digest_not_valid = 0; + + memset(digest_str, 0, digest_size); + + switch (digest) + { + case FKO_HMAC_MD5: + strlcpy(digest_str, "MD5", digest_size); + break; + case FKO_HMAC_SHA1: + strlcpy(digest_str, "SHA1", digest_size); + break; + case FKO_HMAC_SHA256: + strlcpy(digest_str, "SHA256", digest_size); + break; + case FKO_HMAC_SHA384: + strlcpy(digest_str, "SHA384", digest_size); + break; + case FKO_HMAC_SHA512: + strlcpy(digest_str, "SHA512", digest_size); + break; + default: + digest_not_valid = -1; + break; + } + + return digest_not_valid; +} + /* Validate plaintext input size */ int diff --git a/lib/fko_util.h b/lib/fko_util.h index 2a234350..dc629429 100644 --- a/lib/fko_util.h +++ b/lib/fko_util.h @@ -43,6 +43,7 @@ int strtol_wrapper(const char * const str, const int min, short digest_strtoint(const char *dt_str); short digest_inttostr(int digest, char* digest_str, size_t digest_size); short hmac_digest_strtoint(const char *dt_str); +short hmac_digest_inttostr(int digest, char* digest_str, size_t digest_size); size_t strlcat(char *dst, const char *src, size_t siz); size_t strlcpy(char *dst, const char *src, size_t siz); From 8a2bc732b76b5a265cc38890e0c0eee1a1170ce6 Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Sun, 10 Mar 2013 18:17:08 +0100 Subject: [PATCH 06/10] Fixed data format for some arguments in fwknoprc when they are saved. --- client/config_init.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index 6bd9616e..56725029 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -114,6 +114,7 @@ const char* fwknop_cli_key_tab[FWKNOP_CLI_ARG_NB] = }; /** + * \brief Lookup a section in a line and fetch it. * \brief Lookup a section in a line and fetch it. * * This function parses a NULL terminated string in order to find a section, @@ -666,7 +667,7 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) proto_inttostr(options->spa_proto, val, sizeof(val)); break; case FWKNOP_CLI_ARG_SPA_SERVER_PORT : - strlcpy(val, options->spa_server_str, sizeof(val)); + snprintf(val, sizeof(val)-1, "%d", options->spa_dst_port); break; case FWKNOP_CLI_ARG_SPA_SOURCE_PORT : snprintf(val, sizeof(val)-1, "%d", options->spa_src_port); @@ -679,9 +680,9 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) break; case FWKNOP_CLI_ARG_TIME_OFFSET : if (options->time_offset_minus != 0) - snprintf(val, sizeof(val)-1, "%d", options->time_offset_minus); + snprintf(val, sizeof(val)-1, "-%d", options->time_offset_minus); else if (options->time_offset_plus != 0) - snprintf(val, sizeof(val)-1, "%d", options->time_offset_minus); + snprintf(val, sizeof(val)-1, "%d", options->time_offset_plus); else { } @@ -723,7 +724,7 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) strlcpy(val, options->spa_server_str, sizeof(val)); break; case FWKNOP_CLI_ARG_RAND_PORT : - snprintf(val, sizeof(val)-1, "%d", options->rand_port); + val[0] = (options->rand_port) ? 'Y' : 'N'; break; case FWKNOP_CLI_ARG_KEY_FILE : strlcpy(val, options->get_key_file, sizeof(val)); @@ -754,10 +755,10 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) } break; case FWKNOP_CLI_ARG_NAT_LOCAL : - snprintf(val, sizeof(val)-1, "%d", options->nat_local); + val[0] = (options->nat_local) ? 'Y' : 'N'; break; case FWKNOP_CLI_ARG_NAT_RAND_PORT : - snprintf(val, sizeof(val)-1, "%d", options->nat_rand_port); + val[0] = (options->nat_rand_port) ? 'Y' : 'N'; break; case FWKNOP_CLI_ARG_NAT_PORT : snprintf(val, sizeof(val)-1, "%d", options->nat_port); @@ -1104,7 +1105,7 @@ update_rc(fko_cli_options_t *options, uint32_t args_bitmask) * othewise we already updated it earlier. */ if (stanza_updated == 0) { - fprintf(rc_update, "[%s]\n", options->use_rc_stanza); + fprintf(rc_update, "\n[%s]\n", options->use_rc_stanza); if(options->verbose > 3) fprintf(stderr, "Updating %s stanza\n", curr_stanza); @@ -1591,7 +1592,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) } /* Force a stanza found since we are going to update it. We cannot update - * the rcfile without prio validation */ + * the rcfile without prior validation */ if ( (options->save_rc_stanza == 1) && (cli_arg_bitmask != 0) ) options->got_named_stanza = 1; @@ -1716,4 +1717,3 @@ usage(void) return; } -/***EOF***/ From 977ee18c3f75966de0be52cce54eace40c0185ef Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Sun, 10 Mar 2013 20:55:19 +0100 Subject: [PATCH 07/10] New function bool_to_yesno. --- client/config_init.c | 45 +++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) mode change 100644 => 100755 client/config_init.c diff --git a/client/config_init.c b/client/config_init.c old mode 100644 new mode 100755 index 56725029..a86058fb --- a/client/config_init.c +++ b/client/config_init.c @@ -1,11 +1,11 @@ /* ****************************************************************************** * - * File: config_init.c + * \file config_init.c * - * Author: Damien Stuart + * \author Damien Stuart * - * Purpose: Command-line and config file processing for fwknop client. + * \brief Command-line and config file processing for fwknop client. * * Copyright 2009-2010 Damien Stuart (dstuart@dstuart.org) * @@ -45,6 +45,8 @@ #define FWKNOP_CLI_ARG_BM(x) ((uint32_t)(1 << (x))) /*!< Bitmask command line arg */ #define FWKNOPRC_OFLAGS (O_WRONLY|O_CREAT|O_EXCL) /*!< O_flags used to create an fwknoprc file with the open function */ #define FWKNOPRC_MODE (S_IRUSR|S_IWUSR) /*!< mode used to create an fwknoprc file with the open function */ +#define PARAM_YES_VALUE "Y" /*!< String which represents a YES value for a parameter in fwknoprc */ +#define PARAM_NO_VALUE "N" /*!< String which represents a NO value for a parameter in fwknoprc */ enum { @@ -114,7 +116,26 @@ const char* fwknop_cli_key_tab[FWKNOP_CLI_ARG_NB] = }; /** - * \brief Lookup a section in a line and fetch it. + * \brief Set a string as a Yes or No value according to a boolean (0 or 1). + * + * This function checks whether a value is set to zero or not, and updates a + * string to a YES_NO parameter value. + * The string must be zeroed before being passed to the function. + * + * \param val Variable to check + * \param s String where to store the YES_NO value. + * \param len Number of bytes avaialble for the s buffer. + */ +static void +bool_to_yesno(int val, char* s, size_t len) +{ + if (val == 0) + strlcpy(s, PARAM_NO_VALUE, len); + else + strlcpy(s, PARAM_YES_VALUE, len); +} + +/** * \brief Lookup a section in a line and fetch it. * * This function parses a NULL terminated string in order to find a section, @@ -691,16 +712,10 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) enc_mode_inttostr(options->encryption_mode, val, sizeof(val)); break; case FWKNOP_CLI_ARG_USE_GPG : - if (options->use_gpg == 0) - strlcpy(val, "N", sizeof(val)); - else - strlcpy(val, "Y", sizeof(val)); + bool_to_yesno(options->use_gpg, val, sizeof(val)); break; case FWKNOP_CLI_ARG_USE_GPG_AGENT : - if (options->use_gpg_agent == 0) - strlcpy(val, "N", sizeof(val)); - else - strlcpy(val, "Y", sizeof(val)); + bool_to_yesno(options->use_gpg_agent, val, sizeof(val)); break; case FWKNOP_CLI_ARG_GPG_RECIPIENT : strlcpy(val, options->gpg_recipient_key, sizeof(val)); @@ -724,7 +739,7 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) strlcpy(val, options->spa_server_str, sizeof(val)); break; case FWKNOP_CLI_ARG_RAND_PORT : - val[0] = (options->rand_port) ? 'Y' : 'N'; + bool_to_yesno(options->rand_port, val, sizeof(val)); break; case FWKNOP_CLI_ARG_KEY_FILE : strlcpy(val, options->get_key_file, sizeof(val)); @@ -755,10 +770,10 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) } break; case FWKNOP_CLI_ARG_NAT_LOCAL : - val[0] = (options->nat_local) ? 'Y' : 'N'; + bool_to_yesno(options->nat_local, val, sizeof(val)); break; case FWKNOP_CLI_ARG_NAT_RAND_PORT : - val[0] = (options->nat_rand_port) ? 'Y' : 'N'; + bool_to_yesno(options->nat_rand_port, val, sizeof(val)); break; case FWKNOP_CLI_ARG_NAT_PORT : snprintf(val, sizeof(val)-1, "%d", options->nat_port); From 366536055fd18600c879f4147b4612ce2f056d97 Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Wed, 13 Mar 2013 07:13:50 +0100 Subject: [PATCH 08/10] Added the possibility to parse only sedction in a fwknoprc file and not only the whole file --- client/config_init.c | 193 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 185 insertions(+), 8 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index a86058fb..5b6b826e 100755 --- a/client/config_init.c +++ b/client/config_init.c @@ -41,6 +41,7 @@ #include #define RC_PARAM_TEMPLATE "%-24s %s\n" /*!< Template to define param = val in a rc file */ +#define RC_SECTION_DEFAULT "default" /*!< Name of the default section in fwknoprc */ #define RC_SECTION_TEMPLATE "[%s]\n" /*!< Template to define a section in a rc file */ #define FWKNOP_CLI_ARG_BM(x) ((uint32_t)(1 << (x))) /*!< Bitmask command line arg */ #define FWKNOPRC_OFLAGS (O_WRONLY|O_CREAT|O_EXCL) /*!< O_flags used to create an fwknoprc file with the open function */ @@ -48,6 +49,12 @@ #define PARAM_YES_VALUE "Y" /*!< String which represents a YES value for a parameter in fwknoprc */ #define PARAM_NO_VALUE "N" /*!< String which represents a NO value for a parameter in fwknoprc */ +typedef struct +{ + char name[MAX_LINE_LEN]; + char val[MAX_LINE_LEN]; +} TParam; + enum { FWKNOP_CLI_ARG_DIGEST_TYPE = 0, @@ -136,7 +143,7 @@ bool_to_yesno(int val, char* s, size_t len) } /** - * \brief Lookup a section in a line and fetch it. + * \brief Check if a section is in a line and fetch it. * * This function parses a NULL terminated string in order to find a section, * something like [mysection]. If it succeeds, the stanza is retrieved. @@ -146,14 +153,14 @@ bool_to_yesno(int val, char* s, size_t len) * \param rc_section String to store the section found * \param rc_section_size Size of the rc_section buffer * - * \return 0 if a section was found, 1 otherwise + * \return 1 if a section was found, 0 otherwise */ static int -lookup_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16_t rc_section_size) +is_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16_t rc_section_size) { char *ndx, *emark; char buf[MAX_LINE_LEN]; - int section_not_found = 1; + int section_found = 0; if (line_size < sizeof(buf)) { @@ -174,7 +181,7 @@ lookup_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16 *emark = '\0'; memset(rc_section, 0, rc_section_size); strlcpy(rc_section, ndx, rc_section_size); - section_not_found = 0; + section_found = 1; } else { @@ -185,7 +192,44 @@ lookup_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16 { } - return section_not_found; + return section_found; +} + +/** + * + */ +static int +is_rc_param(const char *line, TParam *param) +{ + char var[MAX_LINE_LEN] = {0}; + char val[MAX_LINE_LEN] = {0}; + char *ndx; + + /* Fetch the variable and its value */ + if(sscanf(line, "%s %[^ ;\t\n\r#]", var, val) != 2) + { + fprintf(stderr, + "*Invalid entry in '%s'", line); + return 0; + } + + /* Remove any colon that may be on the end of the var */ + if((ndx = strrchr(var, ':')) != NULL) + *ndx = '\0'; + + /* Even though sscanf should automatically add a terminating + * NULL byte, an assumption is made that the input arrays are + * big enough, so we'll force a terminating NULL byte regardless + */ + var[MAX_LINE_LEN-1] = 0x0; + val[MAX_LINE_LEN-1] = 0x0; + + + /* Copy back the val and var in the structure */ + strlcpy(param->name, var, sizeof(param->name)); + strlcpy(param->val, val, sizeof(param->val)); + + return 1; } /* Convert a protocol string to its intger value. @@ -417,6 +461,8 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val) { int tmpint, is_err; + fprintf(stdout, "Parsing variable %s...\n", var); + /* Digest Type */ if(CONF_VAR_IS(var, "DIGEST_TYPE")) { @@ -790,6 +836,137 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) fprintf(fhandle, RC_PARAM_TEMPLATE, fwknop_cli_key_tab[arg_ndx], val); } +static int +process_rc_section(char *section_name, fko_cli_options_t *options) +{ + FILE *rc; + int line_num = 0, do_exit = 0; + int rcf_offset; + char line[MAX_LINE_LEN]; + char rcfile[MAX_PATH_LEN]; + char curr_stanza[MAX_LINE_LEN] = {0}; + TParam param; + int rc_section_found = 0; + + char *homedir; + + memset(rcfile, 0x0, MAX_PATH_LEN); + + if(options->rc_file[0] == 0x0) + { +#ifdef WIN32 + homedir = getenv("USERPROFILE"); +#else + homedir = getenv("HOME"); +#endif + + if(homedir == NULL) + { + fprintf(stderr, "Warning: Unable to determine HOME directory.\n" + " No .fwknoprc file processed.\n"); + return -1; + } + + strlcpy(rcfile, homedir, MAX_PATH_LEN); + + rcf_offset = strlen(rcfile); + + /* Sanity check the path to .fwknoprc. + * The preceeding path plus the path separator and '.fwknoprc' = 11 + * cannot exceed MAX_PATH_LEN. + */ + if(rcf_offset > (MAX_PATH_LEN - 11)) + { + fprintf(stderr, "Warning: Path to .fwknoprc file is too long.\n" + " No .fwknoprc file processed.\n"); + return -1; + } + + rcfile[rcf_offset] = PATH_SEP; + strlcat(rcfile, ".fwknoprc", MAX_PATH_LEN); + } + else + { + strlcpy(rcfile, options->rc_file, MAX_PATH_LEN); + } + + /* Check rc file permissions - if anything other than user read/write, + * then throw a warning. This change was made to help ensure that the + * client consumes a proper rc file with strict permissions set (thanks + * to Fernando Arnaboldi from IOActive for pointing this out). + */ + verify_file_perms_ownership(rcfile); + + /* Open the rc file for reading, if it does not exist, then create + * an initial .fwknoprc file with defaults and go on. + */ + if ((rc = fopen(rcfile, "r")) == NULL) + { + if(errno == ENOENT) + { + if(create_fwknoprc(rcfile) != 0) + return -1; + } + else + fprintf(stderr, "Unable to open rc file: %s: %s\n", + rcfile, strerror(errno)); + + return - 1; + } + + if (options->verbose > 3) + fprintf(stderr, "process_rc_section() : Parsing section '%s' ...\n", section_name); + + while ((fgets(line, MAX_LINE_LEN, rc)) != NULL) + { + line_num++; + line[MAX_LINE_LEN-1] = '\0'; + + /* Get past comments and empty lines (note: we only look at the + * first character. + */ + if(IS_EMPTY_LINE(line[0])) + continue; + + /* Check which section we are working on */ + if (is_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza))) + { + rc_section_found = (strcasecmp(curr_stanza, section_name) == 0) ? 1 : 0; + + if (strcasecmp(curr_stanza, options->use_rc_stanza) == 0) + options->got_named_stanza = 1; + + continue; + } + + /* We are not in the good section */ + else if (rc_section_found == 0) + continue; + + /* We have not found a valid parameter */ + else if (is_rc_param(line, ¶m) == 0) + continue; + + /* We have a valid parameter */ + else + { + if(parse_rc_param(options, param.name, param.val) < 0) + { + fprintf(stderr, "Parameter error in %s, line %i: var=%s, val=%s\n", + rcfile, line_num, param.name, param.val); + do_exit = 1; + } + } + } + + fclose(rc); + + if (do_exit) + exit(EXIT_FAILURE); + + return 0; +} + /* Process (create if necessary) the users ~/.fwknoprc file. */ static void @@ -1076,7 +1253,7 @@ update_rc(fko_cli_options_t *options, uint32_t args_bitmask) line[MAX_LINE_LEN-1] = '\0'; /* If we find a section... */ - if(lookup_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)) == 0) + if(is_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)) == 0) { /* and this is the one we are looking for, we add the new settings */ if (strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN)==0) @@ -1284,7 +1461,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) /* First process the .fwknoprc file. */ - process_rc(options); + process_rc_section(RC_SECTION_DEFAULT, options); /* Reset the options index so we can run through them again. */ From 212075094cf2b5380e85af34145917921639423d Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Thu, 14 Mar 2013 22:16:37 +0100 Subject: [PATCH 09/10] Added the possibility to parse only sedction in a fwknoprc file and not only the whole file - more. --- client/config_init.c | 272 +++++++++---------------------------------- 1 file changed, 58 insertions(+), 214 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index 5b6b826e..d9070e09 100755 --- a/client/config_init.c +++ b/client/config_init.c @@ -196,7 +196,12 @@ is_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16_t r } /** + * Grab a variable and its value from a rc line. * + * \param line Line to parse for a variable + * \param param Parameter structure where to store the variable name and its value + * + * \return 0 if no variable has been found, 1 otherwise. */ static int is_rc_param(const char *line, TParam *param) @@ -448,7 +453,6 @@ create_fwknoprc(const char *rcfile) "#CLIENT_TIMEOUT 60\n" "#\n" "\n" - "###EOF###\n" ); fclose(rc); @@ -461,7 +465,8 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val) { int tmpint, is_err; - fprintf(stdout, "Parsing variable %s...\n", var); + if(options->verbose > 3) + fprintf(stderr, "add_rc_param() : Parsing variable %s...\n", var); /* Digest Type */ if(CONF_VAR_IS(var, "DIGEST_TYPE")) @@ -830,12 +835,25 @@ add_rc_param(FILE* fhandle, uint16_t arg_ndx, fko_cli_options_t *options) } if(options->verbose > 3) - fprintf(stderr, "Updating param (%u) %s to %s\n", + fprintf(stderr, "add_rc_param() : Updating param (%u) %s to %s\n", arg_ndx, fwknop_cli_key_tab[arg_ndx], val); fprintf(fhandle, RC_PARAM_TEMPLATE, fwknop_cli_key_tab[arg_ndx], val); } +/** + * Process the fwknoprc file and lookup a section to extract its settings. + * + * This function aims at loading the settings for a specific section in + * a fwknoprc file. + * + * \param section_name Name of the section to lookup. + * \param options Fwknop option structure where settings have to + * be stored. + * + * \return 0 if the section has been found and processed successfully + * a negative value if one or more errors occured + */ static int process_rc_section(char *section_name, fko_cli_options_t *options) { @@ -967,196 +985,6 @@ process_rc_section(char *section_name, fko_cli_options_t *options) return 0; } -/* Process (create if necessary) the users ~/.fwknoprc file. -*/ -static void -process_rc(fko_cli_options_t *options) -{ - FILE *rc; - int line_num = 0, do_exit = 0; - int rcf_offset; - char line[MAX_LINE_LEN]; - char rcfile[MAX_PATH_LEN]; - char curr_stanza[MAX_LINE_LEN] = {0}; - char var[MAX_LINE_LEN] = {0}; - char val[MAX_LINE_LEN] = {0}; - - char *ndx, *emark, *homedir; - - memset(rcfile, 0x0, MAX_PATH_LEN); - - if(options->rc_file[0] == 0x0) - { -#ifdef WIN32 - homedir = getenv("USERPROFILE"); -#else - homedir = getenv("HOME"); -#endif - - if(homedir == NULL) - { - fprintf(stderr, "Warning: Unable to determine HOME directory.\n" - " No .fwknoprc file processed.\n"); - return; - } - - strlcpy(rcfile, homedir, MAX_PATH_LEN); - - rcf_offset = strlen(rcfile); - - /* Sanity check the path to .fwknoprc. - * The preceeding path plus the path separator and '.fwknoprc' = 11 - * cannot exceed MAX_PATH_LEN. - */ - if(rcf_offset > (MAX_PATH_LEN - 11)) - { - fprintf(stderr, "Warning: Path to .fwknoprc file is too long.\n" - " No .fwknoprc file processed.\n"); - return; - } - - rcfile[rcf_offset] = PATH_SEP; - strlcat(rcfile, ".fwknoprc", MAX_PATH_LEN); - } - else - { - strlcpy(rcfile, options->rc_file, MAX_PATH_LEN); - } - - /* Check rc file permissions - if anything other than user read/write, - * then throw a warning. This change was made to help ensure that the - * client consumes a proper rc file with strict permissions set (thanks - * to Fernando Arnaboldi from IOActive for pointing this out). - */ - verify_file_perms_ownership(rcfile); - - /* Open the rc file for reading, if it does not exist, then create - * an initial .fwknoprc file with defaults and go on. - */ - if ((rc = fopen(rcfile, "r")) == NULL) - { - if(errno == ENOENT) - { - if(create_fwknoprc(rcfile) != 0) - return; - } - else - fprintf(stderr, "Unable to open rc file: %s: %s\n", - rcfile, strerror(errno)); - - return; - } - - /* Read in and parse the rc file parameters. - */ - while ((fgets(line, MAX_LINE_LEN, rc)) != NULL) - { - line_num++; - line[MAX_LINE_LEN-1] = '\0'; - - ndx = line; - - /* Skip any leading whitespace. - */ - while(isspace(*ndx)) - ndx++; - - /* Get past comments and empty lines (note: we only look at the - * first character. - */ - if(IS_EMPTY_LINE(line[0])) - continue; - - if(*ndx == '[') - { - ndx++; - emark = strchr(ndx, ']'); - if(emark == NULL) - { - fprintf(stderr, "Unterminated stanza line: '%s'. Skipping.\n", - line); - continue; - } - - *emark = '\0'; - - strlcpy(curr_stanza, ndx, MAX_LINE_LEN); - - if(options->verbose > 3) - fprintf(stderr, - "RC FILE: %s, LINE: %s\tSTANZA: %s:\n", - rcfile, line, curr_stanza - ); - - continue; - } - - if(sscanf(line, "%s %[^ ;\t\n\r#]", var, val) != 2) - { - fprintf(stderr, - "*Invalid entry in %s at line %i.\n - '%s'", - rcfile, line_num, line - ); - continue; - } - - /* Remove any colon that may be on the end of the var - */ - if((ndx = strrchr(var, ':')) != NULL) - *ndx = '\0'; - - /* Even though sscanf should automatically add a terminating - * NULL byte, an assumption is made that the input arrays are - * big enough, so we'll force a terminating NULL byte regardless - */ - var[MAX_LINE_LEN-1] = 0x0; - val[MAX_LINE_LEN-1] = 0x0; - - if(options->verbose > 3) - fprintf(stderr, - "RC FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n", - rcfile, line, var, val - ); - - /* We do not proceed with parsing until we know we are in - * a stanza. - */ - if(strlen(curr_stanza) < 1) - continue; - - /* Process the values. We assume we will see the default stanza - * first, then if a named-stanza is specified, we process its - * entries as well. - */ - if(strcasecmp(curr_stanza, "default") == 0) - { - if(parse_rc_param(options, var, val) < 0) - { - fprintf(stderr, "Parameter error in %s, line %i: var=%s, val=%s\n", - rcfile, line_num, var, val); - do_exit = 1; - } - } - else if(options->use_rc_stanza[0] != '\0' - && strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN)==0) - { - options->got_named_stanza = 1; - if(parse_rc_param(options, var, val) < 0) - { - fprintf(stderr, - "Parameter error in %s, stanza: %s, line %i: var=%s, val=%s\n", - rcfile, curr_stanza, line_num, var, val); - do_exit = 1; - } - } - - } /* end while fgets rc */ - fclose(rc); - - if(do_exit) - exit(EXIT_FAILURE); -} - /** * \brief Update the user rc file with the new parameters for a selected stanza. * @@ -1253,7 +1081,7 @@ update_rc(fko_cli_options_t *options, uint32_t args_bitmask) line[MAX_LINE_LEN-1] = '\0'; /* If we find a section... */ - if(is_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)) == 0) + if(is_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)) == 1) { /* and this is the one we are looking for, we add the new settings */ if (strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN)==0) @@ -1262,7 +1090,7 @@ update_rc(fko_cli_options_t *options, uint32_t args_bitmask) fprintf(rc_update, RC_SECTION_TEMPLATE, curr_stanza); if(options->verbose > 3) - fprintf(stderr, "Updating %s stanza\n", curr_stanza); + fprintf(stderr, "update_rc() : Updating %s stanza\n", curr_stanza); for (arg_ndx=0 ; arg_ndxuse_rc_stanza); if(options->verbose > 3) - fprintf(stderr, "Updating %s stanza\n", curr_stanza); + fprintf(stderr, "update_rc() : Updating %s stanza\n", curr_stanza); for (arg_ndx=0 ; arg_ndxsave_rc_stanza == 1) - && (cli_arg_bitmask != 0) - && (options->got_named_stanza == 1) ) + /* We are asked to save a new stanza wit the args supplied on the command line */ + if ( (options->save_rc_stanza == 1) && (cli_arg_bitmask != 0) ) { - fprintf(stdout, "Overwritting stanza [%s] [Y/n] ? ", options->use_rc_stanza); - - if (scanf("%c", &user_input ) != 1) - user_input = 'Y'; - - if ((user_input != 'Y') && (user_input != 0x0A)) + /* Ask the user whether we overwrite the stanza from the rcfile with the + * command line arguments */ + if (options->got_named_stanza == 1) { - options->save_rc_stanza = 0; - process_rc(options); + fprintf(stdout, "Overwritting stanza [%s] [Y/n] ? ", options->use_rc_stanza); + + if (scanf("%c", &user_input ) != 1) + user_input = 'Y'; + + /* Cancel the current operation since the user discard the overwrite. + * It would be nice to be able to reset the args set by the user on the + * command line or to reset the settings. */ + if ((user_input != 'Y') && (user_input != 0x0A)) + { + fprintf(stderr, "Canceling...\n"); + exit(EXIT_FAILURE); + } } + + /* Force a stanza found since we are going to update it. We cannot update + * the rcfile without prior validation */ + else + options->got_named_stanza = 1; } - /* Force a stanza found since we are going to update it. We cannot update - * the rcfile without prior validation */ - if ( (options->save_rc_stanza == 1) && (cli_arg_bitmask != 0) ) - options->got_named_stanza = 1; + /* Load the specified stanza */ + else if (options->got_named_stanza == 1) + { + options->save_rc_stanza = 0; + process_rc_section(options->use_rc_stanza, options); + } + + /* Discard the save stanza since there is no args specified on the command line */ + else + options->save_rc_stanza = 0; /* Now that we have all of our options set, we can validate them */ validate_options(options); /* We can upgrade our settings with the parameters set on the command * line by the user */ - if ( (options->save_rc_stanza == 1) && (cli_arg_bitmask != 0) ) + if (options->save_rc_stanza == 1) update_rc(options, cli_arg_bitmask); return; From b9046df64de2472fa59a318a99f86b6ef2eaa78e Mon Sep 17 00:00:00 2001 From: Franck Joncourt Date: Thu, 14 Mar 2013 22:39:36 +0100 Subject: [PATCH 10/10] Remove useless comment. --- client/config_init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index d9070e09..769b25c0 100755 --- a/client/config_init.c +++ b/client/config_init.c @@ -29,9 +29,6 @@ ****************************************************************************** */ -/* FIXME: Finish save capability. - */ - #include "fwknop_common.h" #include "netinet_common.h" #include "config_init.h"