Merge remote-tracking branch 'fjoncourt/hmac_support' into hmac_support
authorMichael Rash <mbr@cipherdyne.org>
Mon, 18 Mar 2013 01:34:23 +0000 (21:34 -0400)
committerMichael Rash <mbr@cipherdyne.org>
Mon, 18 Mar 2013 01:34:23 +0000 (21:34 -0400)
Significant merge from Franck Joncourt to add the ability to save command line
args to ~/.fwknoprc stanzas.  This merge is in support of #4.

Conflicts:
lib/fko_util.c
lib/fko_util.h

1  2 
Makefile.am
client/cmd_opts.h
client/config_init.c
client/fwknop.c
client/fwknop_common.h
lib/fko_util.c
lib/fko_util.h
server/utils.c

diff --cc Makefile.am
@@@ -148,43 -148,10 +148,45 @@@ EXTRA_DIST = 
      test/conf/hmac_dual_key_usage_access.conf \
      test/conf/hmac_invalid_type_access.conf \
      test/conf/hmac_md5_access.conf \
 +    test/conf/hmac_md5_short_key_access.conf \
 +    test/conf/hmac_md5_long_key_access.conf \
      test/conf/hmac_sha1_access.conf \
 +    test/conf/hmac_sha1_short_key_access.conf \
 +    test/conf/hmac_sha1_long_key_access.conf \
 +    test/conf/hmac_sha256_access.conf \
 +    test/conf/hmac_sha256_short_key_access.conf \
 +    test/conf/hmac_sha256_long_key_access.conf \
      test/conf/hmac_sha384_access.conf \
 +    test/conf/hmac_sha384_short_key_access.conf \
 +    test/conf/hmac_sha384_long_key_access.conf \
      test/conf/hmac_sha512_access.conf \
 +    test/conf/hmac_sha512_short_key_access.conf \
++    test/conf/hmac_sha512_long_key_access.conf \
      test/conf/hmac_simple_keys_access.conf \
 +    test/conf/hmac_sha256_open_ports_access.conf \
 +    test/conf/fwknoprc_default_hmac_base64_key \
 +    test/conf/fwknoprc_hmac_invalid_type \
 +    test/conf/fwknoprc_hmac_md5_key \
 +    test/conf/fwknoprc_hmac_md5_long_key \
 +    test/conf/fwknoprc_hmac_md5_short_key \
 +    test/conf/fwknoprc_hmac_sha1_key \
 +    test/conf/fwknoprc_hmac_sha1_long_key \
 +    test/conf/fwknoprc_hmac_sha1_short_key \
 +    test/conf/fwknoprc_hmac_sha256_key \
 +    test/conf/fwknoprc_hmac_sha256_long_key \
 +    test/conf/fwknoprc_hmac_sha256_short_key \
 +    test/conf/fwknoprc_hmac_sha384_key \
 +    test/conf/fwknoprc_hmac_sha384_long_key \
 +    test/conf/fwknoprc_hmac_sha384_short_key \
 +    test/conf/fwknoprc_hmac_sha512_key \
 +    test/conf/fwknoprc_hmac_sha512_short_key \
++    test/conf/fwknoprc_hmac_sha512_long_key \
 +    test/conf/fwknoprc_hmac_simple_keys \
 +    test/conf/fwknoprc_invalid_base64_key \
 +    test/conf/fwknoprc_named_key \
 +    test/conf/fwknoprc_with_default_base64_key \
 +    test/conf/fwknoprc_with_default_key \
 +    test/conf/fwknoprc_with_named_key \
      test/conf/icmp_pcap_filter_fwknopd.conf \
      test/conf/invalid_expire_access.conf \
      test/conf/invalid_source_access.conf \
@@@ -41,6 -41,6 +41,7 @@@ enum 
      NAT_RAND_PORT,
      TIME_OFFSET_MINUS,
      TIME_OFFSET_PLUS,
++    SAVE_RC_STANZA,
      NO_SAVE_ARGS,
      SHOW_LAST_ARGS,
      RC_FILE_PATH,
@@@ -51,6 -51,9 +52,9 @@@
      KEY_LEN,
      HMAC_DIGEST_TYPE,
      HMAC_KEY_LEN,
+     KEY_RIJNDAEL,
+     KEY_RIJNDAEL_BASE64,
 -    KEY_HMAC_BASE64,    
++    KEY_HMAC_BASE64,
      /* Put GPG-related items below the following line */
      GPG_ENCRYPTION      = 0x200,
      GPG_RECIP_KEY,
@@@ -73,6 -76,6 +77,7 @@@ static struct option cmd_opts[] 
      {"access",              1, NULL, 'A'},
      {"save-packet-append",  0, NULL, 'b'},
      {"save-packet",         1, NULL, 'B'},
++    {"save-rc-stanza",      0, NULL, SAVE_RC_STANZA},
      {"no-save-args",        0, NULL, NO_SAVE_ARGS},
      {"server-cmd",          1, NULL, 'C'},
      {"digest-type",         1, NULL, FKO_DIGEST_NAME},
index af72237,769b25c..4bae754
mode 100644,100755..100755
  #include <sys/stat.h>
  #include <fcntl.h>
  
- /* Convert a protocol string to its integer value.
+ #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 */
+ #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 */
+ typedef struct
+ {
+     char name[MAX_LINE_LEN];
+     char val[MAX_LINE_LEN];
+ } TParam;
+ enum
+ {
+     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_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,
+     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",
+     "KEY_BASE64",
+     "HMAC_DIGEST_TYPE",
+     "HMAC_KEY_BASE64",
+     "KEY_FILE",
+     "NAT_ACCESS",
+     "HTTP_USER_AGENT",
+     "RESOLVE_URL",
+     "NAT_LOCAL",
+     "NAT_RAND_PORT",
+     "NAT_PORT"
+ };
+ /**
+  * \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 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.
+  *
+  * \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 1 if a section was found, 0 otherwise
+  */
+ static int
+ 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_found = 0;
+     if (line_size < sizeof(buf))
+     {
+         memset (buf, 0, sizeof(buf));
+         strlcpy(buf, line, line_size);
+         ndx = buf;
+         while(isspace(*ndx))
+             ndx++;
+         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_found = 1;
+             }
+             else
+             {
+             }
+         }
+     }
+     else
+     {
+     }
+     return section_found;
+ }
+ /**
+  * 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)
+ {
+     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.
  */
  static int
  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;
+ }
++/* Assign path to fwknop rc file
++*/
++static void
++set_rc_file(char *rcfile, fko_cli_options_t *options)
++{
++    int     rcf_offset;
++    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");
++            exit(EXIT_FAILURE);
++        }
++
++        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");
++            exit(EXIT_FAILURE);
++        }
++
++        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);
++
++    return;
++}
++
  /* Parse any time offset from the command line
  */
  static int
@@@ -170,7 -412,7 +470,7 @@@ create_fwknoprc(const char *rcfile
          "##############################################################################\n"
          "#\n"
          "# We start with the 'default' stanza.  Uncomment and edit for your\n"
--        "# preferences.  The client will use its build-in default for those items\n"
++        "# preferences.  The client will use its built-in default for those items\n"
          "# that are commented out.\n"
          "#\n"
          "[default]\n"
@@@ -459,68 -703,214 +761,166 @@@ parse_rc_param(fko_cli_options_t *optio
      return(0);
  }
  
- /* Process (create if necessary) the users ~/.fwknoprc file.
- */
+ /**
+  * \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
- process_rc(fko_cli_options_t *options)
+ add_rc_param(FILE* fhandle, uint16_t arg_ndx, 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;
+     if (arg_ndx >= FWKNOP_CLI_ARG_NB)
+         return;
  
-     memset(rcfile, 0x0, MAX_PATH_LEN);
+     if (fhandle == NULL)
+         return;
  
-     if(options->rc_file[0] == 0x0)
-     {
- #ifdef WIN32
-         homedir = getenv("USERPROFILE");
- #else
-         homedir = getenv("HOME");
- #endif
+     /* Zero the val buffer */
+     memset(val, 0, sizeof(val));
  
-         if(homedir == NULL)
-         {
-             fprintf(stderr, "Warning: Unable to determine HOME directory.\n"
-                 " No .fwknoprc file processed.\n");
+     /* 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 :
+             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);
+             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_plus);
+             else
+             {
+             }
+             break;
+         case FWKNOP_CLI_ARG_ENCRYPTION_MODE :
+             enc_mode_inttostr(options->encryption_mode, val, sizeof(val));
+             break;
+         case FWKNOP_CLI_ARG_USE_GPG :
+             bool_to_yesno(options->use_gpg, val, sizeof(val));
+             break;
+         case FWKNOP_CLI_ARG_USE_GPG_AGENT :
+             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));
+             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 :
+             bool_to_yesno(options->rand_port, val, sizeof(val));
+             break;
+         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_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;
+         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 :
+             bool_to_yesno(options->nat_local, val, sizeof(val));
+             break;
+         case FWKNOP_CLI_ARG_NAT_RAND_PORT :
+             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);
+             break;
+         default:
+             fprintf(stderr, "Warning from add_rc_param() : Bad command line argument %u", arg_ndx);
              return;
-         }
-         strlcpy(rcfile, homedir, MAX_PATH_LEN);
+     }
  
-         rcf_offset = strlen(rcfile);
+     if(options->verbose > 3)
+         fprintf(stderr, "add_rc_param() : Updating param (%u) %s to %s\n",
+                 arg_ndx, fwknop_cli_key_tab[arg_ndx], val);
  
-         /* 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;
-         }
+     fprintf(fhandle, RC_PARAM_TEMPLATE, fwknop_cli_key_tab[arg_ndx], val);
+ }
  
-         rcfile[rcf_offset] = PATH_SEP;
-         strlcat(rcfile, ".fwknoprc", MAX_PATH_LEN);
-     }
-     else
-     {
-         strlcpy(rcfile, options->rc_file, MAX_PATH_LEN);
-     }
+ /**
+  * 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)
+ {
+     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;
  
-     /* 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);
 -    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);
++    set_rc_file(rcfile, options);
  
      /* Open the rc file for reading, if it does not exist, then create
       * an initial .fwknoprc file with defaults and go on.
              fprintf(stderr, "Unable to open rc file: %s: %s\n",
                  rcfile, strerror(errno));
  
-         return;
 -        return - 1;
++        return -1;
      }
  
-     /* Read in and parse the rc file parameters.
-     */
+     if (options->verbose > 3)
 -        fprintf(stderr, "process_rc_section() : Parsing section '%s' ...\n", section_name);
 -    
++        fprintf(stderr, "process_rc_section() : Parsing section '%s' ...\n",
++                section_name);
++
      while ((fgets(line, MAX_LINE_LEN, rc)) != NULL)
      {
          line_num++;
          */
          if(IS_EMPTY_LINE(line[0]))
              continue;
 -        
 +
-         if(*ndx == '[')
+         /* Check which section we are working on */
+         if (is_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)))
          {
-             ndx++;
-             emark = strchr(ndx, ']');
-             if(emark == NULL)
-             {
-                 fprintf(stderr, "Unterminated stanza line: '%s'.  Skipping.\n",
-                     line);
-                 continue;
-             }
-             *emark = '\0';
+             rc_section_found = (strcasecmp(curr_stanza, section_name) == 0) ? 1 : 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
-                 );
+             if (strcasecmp(curr_stanza, options->use_rc_stanza) == 0)
+                 options->got_named_stanza = 1;
  
              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
-             );
+         /* We are not in the good section */
+         else if (rc_section_found == 0)
              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)
+         /* We have not found a valid parameter */
+         else if (is_rc_param(line, &param) == 0)
              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)
+         /* We have a valid parameter */
+         else
          {
-             if(parse_rc_param(options, var, val) < 0)
+            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, var, val);
+                     rcfile, line_num, param.name, param.val);
                  do_exit = 1;
 -            }            
 +            }
          }
-         else if(options->use_rc_stanza[0] != '\0'
-           && strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN)==0)
+     }
+     fclose(rc);
+     if (do_exit)
+         exit(EXIT_FAILURE);
+     return 0;
+ }
+ /**
+  * \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);
++    set_rc_file(rcfile, options);
+     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 temporary 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));
+         return;
+     }
+     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(is_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)) == 1)
          {
-             options->got_named_stanza = 1;
-             if(parse_rc_param(options, var, val) < 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)
              {
-                 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;
+                 stanza_found = 1;
+                 fprintf(rc_update, RC_SECTION_TEMPLATE, curr_stanza);
+                 if(options->verbose > 3)
+                     fprintf(stderr, "update_rc() : Updating %s stanza\n", curr_stanza);
+                 for (arg_ndx=0 ; arg_ndx<FWKNOP_CLI_ARG_NB ; arg_ndx++)
+                 {
+                     if (FWKNOP_CLI_ARG_BM(arg_ndx) & args_bitmask)
+                         add_rc_param(rc_update, arg_ndx, options);
+                 }
+                 stanza_updated = 1;
+                 continue;
              }
+             /* otherwise we disable the stanza since it is another section */
+             else
+               stanza_found = 0;
          }
  
-     } /* end while fgets rc */
+         /* For the current section we do not add previous settings until we
+          * find an empty line*/
+         if (stanza_found)
+         {
+             if (!IS_EMPTY_LINE(line[0]))
+                 continue;
+             else
+                 stanza_found = 0;
+         }
+         /* Add the line to the new rcfile */
+         fprintf(rc_update, "%s", line);
+     }
+     /* If the stanza has not been found, we append the settings to the file,
+      * othewise we already updated it earlier. */
+     if (stanza_updated == 0)
+     {
+         fprintf(rc_update, "\n[%s]\n", options->use_rc_stanza);
+         if(options->verbose > 3)
+             fprintf(stderr, "update_rc() : Updating %s stanza\n", curr_stanza);
+         for (arg_ndx=0 ; arg_ndx<FWKNOP_CLI_ARG_NB ; arg_ndx++)
+         {
+             if (FWKNOP_CLI_ARG_BM(arg_ndx) & args_bitmask)
+                 add_rc_param(rc_update, arg_ndx, options);
+         }
+     }
+     /* Close file handles */
      fclose(rc);
+     fclose(rc_update);
  
-     if(do_exit)
-         exit(EXIT_FAILURE);
+     /* Renamed the temporary file as the new rc file */
+     if (remove(rcfile) != 0)
+     {
+         fprintf(stderr, "update_rc() : Unable to remove %s to %s : %s\n",
+             rcfile_update, rcfile, strerror(errno));
+     }
+     if (rename(rcfile_update, rcfile) != 0)
+     {
+         fprintf(stderr, "update_rc() : Unable to rename %s to %s\n",
+             rcfile_update, rcfile);
+     }
  }
  
  /* Sanity and bounds checks for the various options.
@@@ -743,7 -1246,9 +1226,8 @@@ set_defaults(fko_cli_options_t *options
  void
  config_init(fko_cli_options_t *options, int argc, char **argv)
  {
-     int       cmd_arg, index, is_err;
+     int         cmd_arg, index, is_err;
+     uint32_t    cli_arg_bitmask = 0;
 -    char        user_input = 0;
  
      /* Zero out options and opts_track.
      */
                  exit(EXIT_SUCCESS);
              case 'n':
                  options->no_save_args = 1;
 -                options->save_rc_stanza= 1;
                  strlcpy(options->use_rc_stanza, optarg, MAX_LINE_LEN);
                  break;
++            case SAVE_RC_STANZA:
++                options->save_rc_stanza = 1;
++                break;
              case 'E':
                  strlcpy(options->args_save_file, optarg, MAX_PATH_LEN);
                  break;
                  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);
++                    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);
              case KEY_LEN:
                  options->key_len = strtol_wrapper(optarg, 1,
                          MAX_KEY_LEN, NO_EXIT_UPON_ERR, &is_err);
              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 SAVE_RC_STANZA:
++                /* We already handled this earlier, so we do nothing here
++                */
 +                break;
              case 'T':
                  options->test = 1;
                  break;
          }
      }
  
-     /* Now that we have all of our options set, we can validate them.
-     */
 -    /* 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) )
 -    {
 -        /* Ask the user whether we overwrite the stanza from the rcfile with the
 -         * command line arguments */
 -        if (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';
 -
 -            /* 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;
 -    }
 -
+     /* Load the specified stanza */
 -    else if (options->got_named_stanza == 1)
++    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)
+         update_rc(options, cli_arg_bitmask);
      return;
  }
  
  void
  usage(void)
  {
--    fprintf(stdout, "\n%s client version %s\n%s\n\n", MY_NAME, MY_VERSION, MY_DESC);
++    fprintf(stdout, "\n%s client version %s\n%s - http://%s/fwknop/\n\n",
++            MY_NAME, MY_VERSION, MY_DESC, HTTP_RESOLVE_HOST);
      fprintf(stdout,
        "Usage: fwknop -A <port list> [-s|-R|-a] -D <spa_server> [options]\n\n"
        " -h, --help                  Print this usage message and exit.\n"
        "                             on the server.\n"
        " -B, --save-packet           Save the generated packet data to the\n"
        "                             specified file.\n"
++      " -b, --save-packet-append    Append the generated packet data to the\n"
++      "                             file specified with the -B option.\n"
        " -a, --allow-ip              Specify IP address to allow within the SPA\n"
        "                             packet.\n"
        " -C, --server-cmd            Specify a command that the fwknop server will\n"
        "                             server side than the default of udp 62201).\n"
        " -T, --test                  Build the SPA packet but do not send it over\n"
        "                             the network.\n"
--      " -v, --verbose               Set verbose mode.\n"
++      " -v, --verbose               Set verbose mode (may specify multiple times).\n"
        " -V, --version               Print version number.\n"
        " -m, --digest-type           Specify the message digest algorithm to use.\n"
        "                             (md5, sha1, sha256, sha384, or sha512). The\n"
        "     --gpg-agent             Use GPG agent if available.\n"
        "     --no-save-args          Do not save fwknop command line args to the\n"
        "                             $HOME/fwknop.run file\n"
++      "     --rc-file               Specify path to the fwknop rc file (default\n"
++      "                             is $HOME/.fwknoprc\n"
++      "     --save-rc-stanza        Save command line arguments to the\n"
++      "                             $HOME/.fwknoprc stanza specified with the\n"
++      "                             -n option.\n"
        "     --nat-local             Access a local service via a forwarded port\n"
        "                             on the fwknopd server system.\n"
        "     --nat-port              Specify the port to forward to access a\n"
diff --cc client/fwknop.c
@@@ -1147,6 -1014,6 +1147,9 @@@ display_ctx(fko_ctx_t ctx
      char       *hmac_data       = NULL;
      char       *spa_digest      = NULL;
      char       *spa_data        = NULL;
++    char        digest_str[MAX_LINE_LEN]   = {0};
++    char        hmac_str[MAX_LINE_LEN]     = {0};
++    char        enc_mode_str[MAX_LINE_LEN] = {0};
  
      time_t      timestamp       = 0;
      short       msg_type        = -1;
      fko_get_spa_digest(ctx, &spa_digest);
      fko_get_spa_data(ctx, &spa_data);
  
++    digest_inttostr(digest_type, digest_str, sizeof(digest_str));
++    hmac_digest_inttostr(hmac_type, hmac_str, sizeof(hmac_str));
++    enc_mode_inttostr(encryption_mode, enc_mode_str, sizeof(enc_mode_str));
++
      printf("\nFKO Field Values:\n=================\n\n");
      printf("   Random Value: %s\n", rand_val == NULL ? "<NULL>" : rand_val);
      printf("       Username: %s\n", username == NULL ? "<NULL>" : username);
      printf(" Message String: %s\n", spa_message == NULL ? "<NULL>" : spa_message);
      printf("     Nat Access: %s\n", nat_access == NULL ? "<NULL>" : nat_access);
      printf("    Server Auth: %s\n", server_auth == NULL ? "<NULL>" : server_auth);
 -    printf(" Client Timeout: %u\n", client_timeout);
 -    printf("    Digest Type: %d\n", digest_type);
 -    printf("      HMAC Type: %d\n", hmac_type);
 -    printf("Encryption Mode: %d\n", encryption_mode);
 +    printf(" Client Timeout: %u (seconds)\n", client_timeout);
-     printf("    Digest Type: %d (%s)\n", digest_type, digest_inttostr(digest_type));
-     printf("      HMAC Type: %d (%s)\n", hmac_type, digest_inttostr(hmac_type));
++    printf("    Digest Type: %d (%s)\n", digest_type, digest_str);
++    printf("      HMAC Type: %d (%s)\n", hmac_type, hmac_str);
 +    printf("Encryption Type: %d (%s)\n", encryption_type, enc_type_inttostr(encryption_type));
-     printf("Encryption Mode: %d (%s)\n", encryption_mode, enc_mode_inttostr(encryption_mode));
++    printf("Encryption Mode: %d (%s)\n", encryption_mode, enc_mode_str);
      printf("\n   Encoded Data: %s\n", enc_data == NULL ? "<NULL>" : enc_data);
      printf("SPA Data Digest: %s\n", spa_digest == NULL ? "<NULL>" : spa_digest);
      printf("           HMAC: %s\n", hmac_data == NULL ? "<NULL>" : hmac_data);
Simple merge
diff --cc lib/fko_util.c
@@@ -63,6 -63,50 +63,51 @@@ 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:
++            strlcpy(digest_str, "Unknown", digest_size);
+             digest_not_valid = -1;
+             break;
+     }
+     return digest_not_valid;
+ }
  short
  hmac_digest_strtoint(const char *dt_str)
  {
          return(-1);
  }
  
 +/* Return encryption type string representation
 +*/
 +const char *
 +enc_type_inttostr(const int type)
 +{
 +    if(type == FKO_ENC_MODE_UNKNOWN)
 +        return("Unknown encryption type");
 +    else if(type == FKO_ENCRYPTION_RIJNDAEL)
 +        return("Rijndael");
 +    else if(type == FKO_ENCRYPTION_GPG)
 +        return("GPG");
 +
 +    return("Unknown encryption type");
 +}
 +
- /* Return encryption mode string representation
- */
- const char *
- enc_mode_inttostr(const int mode)
- {
-     if(mode == FKO_ENC_MODE_UNKNOWN)
-         return("Unknown encryption mode");
-     else if(mode == FKO_ENC_MODE_ECB)
-         return("ECB");
-     else if(mode == FKO_ENC_MODE_CBC)
-         return("CBC");
-     else if(mode == FKO_ENC_MODE_CFB)
-         return("CFB");
-     else if(mode == FKO_ENC_MODE_PCBC)
-         return("PCBC");
-     else if(mode == FKO_ENC_MODE_OFB)
-         return("OFB");
-     else if(mode == FKO_ENC_MODE_CTR)
-         return("CTR");
-     else if(mode == FKO_ENC_MODE_ASYMMETRIC)
-         return("Asymmetric");
-     else if(mode == FKO_ENC_MODE_CBC_LEGACY_IV)
-         return("CBC legacy initialization vector");
-     return("Unknown encryption mode");
- }
 +/* Return message type string representation
 +*/
 +const char *
 +msg_type_inttostr(const int type)
 +{
 +    if(type == FKO_COMMAND_MSG)
 +        return("Command msg");
 +    else if(type == FKO_ACCESS_MSG)
 +        return("Access msg");
 +    else if(type == FKO_NAT_ACCESS_MSG)
 +        return("NAT access msg");
 +    else if(type == FKO_CLIENT_TIMEOUT_ACCESS_MSG)
 +        return("Client timeout access msg");
 +    else if(type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
 +        return("Client timeout NAT access msg");
 +    else if(type == FKO_LOCAL_NAT_ACCESS_MSG)
 +        return("Local NAT access msg");
 +    else if(type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
 +        return("Client timeout local NAT access msg");
 +
 +    return("Unknown message type");
 +}
 +
- /* Return digest string representation
- */
- const char *
- digest_inttostr(const int type)
+ /**
+  * \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)
  {
-     if(type == FKO_DIGEST_MD5 || type == FKO_HMAC_MD5)
-         return("MD5");
-     else if(type == FKO_DIGEST_SHA1 || type == FKO_HMAC_SHA1)
-         return("SHA1");
-     else if(type == FKO_DIGEST_SHA256 || type == FKO_HMAC_SHA256)
-         return("SHA256");
-     else if(type == FKO_DIGEST_SHA384 || type == FKO_HMAC_SHA384)
-         return("SHA384");
-     else if(type == FKO_DIGEST_SHA512 || type == FKO_HMAC_SHA512)
-         return("SHA512");
-     return("Unknown digest type");
+     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:
++            strlcpy(digest_str, "Unknown", digest_size);
+             digest_not_valid = -1;
+             break;
+     }
+     return digest_not_valid;
  }
  
  /* Validate plaintext input size
@@@ -198,6 -202,57 +242,60 @@@ enc_mode_strtoint(const char *enc_mode_
          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);
++            strlcpy(enc_mode_str, "CBC legacy IV", enc_mode_size);
++            break;
++        case FKO_ENC_MODE_ASYMMETRIC:
++            strlcpy(enc_mode_str, "Asymmetric", 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 --cc lib/fko_util.h
  
  /* 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);
- const char * msg_type_inttostr(const int type);
- short 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);
+ short   hmac_digest_inttostr(int digest, char* digest_str, size_t digest_size);
 +const char * enc_type_inttostr(const int type);
- const char * enc_mode_inttostr(const int mode);
- const char * digest_inttostr(const int type);
- short hmac_digest_strtoint(const char *dt_str);
++const char * msg_type_inttostr(const int type);
 +
- 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 */
  
diff --cc server/utils.c
@@@ -84,9 -84,8 +84,12 @@@ dump_ctx(fko_ctx_t ctx
      char       *nat_access      = NULL;
      char       *server_auth     = NULL;
      char       *enc_data        = NULL;
 +    char       *hmac_data       = NULL;
      char       *spa_digest      = NULL;
      char       *spa_data        = NULL;
++    char        digest_str[MAX_LINE_LEN]   = {0};
++    char        hmac_str[MAX_LINE_LEN]     = {0};
++    char        enc_mode_str[MAX_LINE_LEN] = {0};
  
      time_t      timestamp       = 0;
      short       msg_type        = -1;
      fko_get_spa_digest(ctx, &spa_digest);
      fko_get_spa_data(ctx, &spa_data);
  
++    digest_inttostr(digest_type, digest_str, sizeof(digest_str));
++    hmac_digest_inttostr(hmac_type, hmac_str, sizeof(hmac_str));
++    enc_mode_inttostr(encryption_mode, enc_mode_str, sizeof(enc_mode_str));
++
      memset(buf, 0x0, CTX_DUMP_BUFSIZE);
  
      ndx = buf;
      ndx += cp;
      cp = sprintf(ndx, " Client Timeout: %u\n", client_timeout);
      ndx += cp;
-     cp = sprintf(ndx, "    Digest Type: %u (%s)\n", digest_type, digest_inttostr(digest_type));
 -    cp = sprintf(ndx, "    Digest Type: %u\n", digest_type);
++    cp = sprintf(ndx, "    Digest Type: %u (%s)\n", digest_type, digest_str);
 +    ndx += cp;
-     cp = sprintf(ndx, "      HMAC Type: %u (%s)\n", hmac_type, digest_inttostr(hmac_type));
++    cp = sprintf(ndx, "      HMAC Type: %u (%s)\n", hmac_type, hmac_str);
 +    ndx += cp;
 +    cp = sprintf(ndx, "Encryption Type: %d (%s)\n", encryption_type, enc_type_inttostr(encryption_type));
 +    ndx += cp;
-     cp = sprintf(ndx, "Encryption Mode: %d (%s)\n", encryption_mode, enc_mode_inttostr(encryption_mode));
++    cp = sprintf(ndx, "Encryption Mode: %d (%s)\n", encryption_mode, enc_mode_str);
      ndx += cp;
      cp = sprintf(ndx, "   Encoded Data: %s\n", enc_data == NULL ? "<NULL>" : enc_data);
      ndx += cp;