Branch data Line data Source code
1 : : /**
2 : : * \file client/config_init.c
3 : : *
4 : : * \brief Command-line and config file processing for fwknop client.
5 : : */
6 : :
7 : : /* Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
8 : : * Copyright (C) 2009-2015 fwknop developers and contributors. For a full
9 : : * list of contributors, see the file 'CREDITS'.
10 : : *
11 : : * License (GNU General Public License):
12 : : *
13 : : * This program is free software; you can redistribute it and/or
14 : : * modify it under the terms of the GNU General Public License
15 : : * as published by the Free Software Foundation; either version 2
16 : : * of the License, or (at your option) any later version.
17 : : *
18 : : * This program is distributed in the hope that it will be useful,
19 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : : * GNU General Public License for more details.
22 : : *
23 : : * You should have received a copy of the GNU General Public License
24 : : * along with this program; if not, write to the Free Software
25 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 : : * USA
27 : : *
28 : : ******************************************************************************
29 : : */
30 : :
31 : : #include "fwknop_common.h"
32 : : #include "netinet_common.h"
33 : : #include "config_init.h"
34 : : #include "cmd_opts.h"
35 : : #include "utils.h"
36 : : #include <sys/stat.h>
37 : : #include <fcntl.h>
38 : :
39 : : #ifdef WIN32
40 : : #define STDIN_FILENO 0
41 : : #endif
42 : :
43 : : #define RC_PARAM_TEMPLATE "%-24s %s\n" /*!< Template to define param = val in a rc file */
44 : : #define RC_SECTION_DEFAULT "default" /*!< Name of the default section in fwknoprc */
45 : : #define RC_SECTION_TEMPLATE "[%s]\n" /*!< Template to define a section in a rc file */
46 : : #define FWKNOPRC_OFLAGS (O_WRONLY|O_CREAT|O_EXCL) /*!< O_flags used to create an fwknoprc file with the open function */
47 : : #define FWKNOPRC_MODE (S_IRUSR|S_IWUSR) /*!< mode used to create an fwknoprc file with the open function */
48 : : #define PARAM_YES_VALUE "Y" /*!< String which represents a YES value for a parameter in fwknoprc */
49 : : #define PARAM_NO_VALUE "N" /*!< String which represents a NO value for a parameter in fwknoprc */
50 : : #define POSITION_TO_BITMASK(x) ((uint32_t)(1) << ((x) % 32)) /*!< Macro do get a bitmask from a position */
51 : : #define BITMASK_ARRAY_SIZE 2 /*!< Number of 32bits integer used to handle bitmask in the fko_var_bitmask_t structure */
52 : : #define LF_CHAR 0x0A /*!< Hexadecimal value associated to the LF char */
53 : :
54 : : #ifdef HAVE_C_UNIT_TESTS /* LCOV_EXCL_START */
55 : : #include "cunit_common.h"
56 : : DECLARE_TEST_SUITE(config_init, "Config init test suite");
57 : : #endif /* LCOV_EXCL_STOP */
58 : :
59 : : /**
60 : : * Structure to handle long bitmask.
61 : : *
62 : : * The structure is built as an array of unsigned 32 bits integer to be able to
63 : : * easily increase the size of the bitmask.
64 : : * This bitmask can contains at most (BITMASK_ARRAY_SIZE * 32) values.
65 : : */
66 : : typedef struct fko_var_bitmask
67 : : {
68 : : uint32_t dw[BITMASK_ARRAY_SIZE]; /*!< Array of bitmasks */
69 : : } fko_var_bitmask_t;
70 : :
71 : : /**
72 : : * Structure to handle a variable in an rcfile (name and value)
73 : : */
74 : : typedef struct rc_file_param
75 : : {
76 : : char name[MAX_LINE_LEN]; /*!< Variable name */
77 : : char val[MAX_LINE_LEN]; /*!< Variable value */
78 : : } rc_file_param_t;
79 : :
80 : : /**
81 : : * Structure to identify a configuration variable (name and position)
82 : : */
83 : : typedef struct fko_var
84 : : {
85 : : const char name[32]; /*!< Variable name in fwknoprc */
86 : : unsigned int pos; /*!< Variable position from the fwknop_cli_arg_t enumeration */
87 : : } fko_var_t;
88 : :
89 : : enum
90 : : {
91 : : FWKNOP_CLI_FIRST_ARG = 0,
92 : : FWKNOP_CLI_ARG_DIGEST_TYPE = 0,
93 : : FWKNOP_CLI_ARG_SPA_SERVER_PROTO,
94 : : FWKNOP_CLI_ARG_SPA_SERVER_PORT,
95 : : FWKNOP_CLI_ARG_SPA_SOURCE_PORT,
96 : : FWKNOP_CLI_ARG_FW_TIMEOUT,
97 : : FWKNOP_CLI_ARG_ALLOW_IP,
98 : : FWKNOP_CLI_ARG_TIME_OFFSET,
99 : : FWKNOP_CLI_ARG_ENCRYPTION_MODE,
100 : : FWKNOP_CLI_ARG_USE_GPG,
101 : : FWKNOP_CLI_ARG_USE_GPG_AGENT,
102 : : FWKNOP_CLI_ARG_GPG_NO_SIGNING_PW,
103 : : FWKNOP_CLI_ARG_GPG_RECIPIENT,
104 : : FWKNOP_CLI_ARG_GPG_SIGNER,
105 : : FWKNOP_CLI_ARG_GPG_HOMEDIR,
106 : : FWKNOP_CLI_ARG_GPG_EXE_PATH,
107 : : FWKNOP_CLI_ARG_SPOOF_USER,
108 : : FWKNOP_CLI_ARG_SPOOF_SOURCE_IP,
109 : : FWKNOP_CLI_ARG_ACCESS,
110 : : FWKNOP_CLI_ARG_SPA_SERVER,
111 : : FWKNOP_CLI_ARG_RAND_PORT,
112 : : FWKNOP_CLI_ARG_KEY_RIJNDAEL,
113 : : FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64,
114 : : FWKNOP_CLI_ARG_GPG_SIGNING_PW,
115 : : FWKNOP_CLI_ARG_GPG_SIGNING_PW_BASE64,
116 : : FWKNOP_CLI_ARG_HMAC_DIGEST_TYPE,
117 : : FWKNOP_CLI_ARG_KEY_HMAC_BASE64,
118 : : FWKNOP_CLI_ARG_KEY_HMAC,
119 : : FWKNOP_CLI_ARG_USE_HMAC,
120 : : FWKNOP_CLI_ARG_USE_WGET_USER_AGENT,
121 : : FWKNOP_CLI_ARG_KEY_FILE,
122 : : FWKNOP_CLI_ARG_HMAC_KEY_FILE,
123 : : FWKNOP_CLI_ARG_NAT_ACCESS,
124 : : FWKNOP_CLI_ARG_HTTP_USER_AGENT,
125 : : FWKNOP_CLI_ARG_RESOLVE_URL,
126 : : FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4,
127 : : FWKNOP_CLI_ARG_NAT_LOCAL,
128 : : FWKNOP_CLI_ARG_NAT_RAND_PORT,
129 : : FWKNOP_CLI_ARG_NAT_PORT,
130 : : FWKNOP_CLI_ARG_VERBOSE,
131 : : FWKNOP_CLI_ARG_RESOLVE_IP_HTTP,
132 : : FWKNOP_CLI_ARG_RESOLVE_IP_HTTPS,
133 : : FWKNOP_CLI_ARG_RESOLVE_HTTP_ONLY,
134 : : FWKNOP_CLI_ARG_WGET_CMD,
135 : : FWKNOP_CLI_ARG_NO_SAVE_ARGS,
136 : : FWKNOP_CLI_LAST_ARG
137 : : } fwknop_cli_arg_t;
138 : :
139 : : static fko_var_t fko_var_array[FWKNOP_CLI_LAST_ARG] =
140 : : {
141 : : { "DIGEST_TYPE", FWKNOP_CLI_ARG_DIGEST_TYPE },
142 : : { "SPA_SERVER_PROTO", FWKNOP_CLI_ARG_SPA_SERVER_PROTO },
143 : : { "SPA_SERVER_PORT", FWKNOP_CLI_ARG_SPA_SERVER_PORT },
144 : : { "SPA_SOURCE_PORT", FWKNOP_CLI_ARG_SPA_SOURCE_PORT },
145 : : { "FW_TIMEOUT", FWKNOP_CLI_ARG_FW_TIMEOUT },
146 : : { "ALLOW_IP", FWKNOP_CLI_ARG_ALLOW_IP },
147 : : { "TIME_OFFSET", FWKNOP_CLI_ARG_TIME_OFFSET },
148 : : { "ENCRYPTION_MODE", FWKNOP_CLI_ARG_ENCRYPTION_MODE },
149 : : { "USE_GPG", FWKNOP_CLI_ARG_USE_GPG },
150 : : { "USE_GPG_AGENT", FWKNOP_CLI_ARG_USE_GPG_AGENT },
151 : : { "GPG_RECIPIENT", FWKNOP_CLI_ARG_GPG_RECIPIENT },
152 : : { "GPG_SIGNER", FWKNOP_CLI_ARG_GPG_SIGNER },
153 : : { "GPG_HOMEDIR", FWKNOP_CLI_ARG_GPG_HOMEDIR },
154 : : { "GPG_EXE", FWKNOP_CLI_ARG_GPG_EXE_PATH },
155 : : { "GPG_SIGNING_PW", FWKNOP_CLI_ARG_GPG_SIGNING_PW },
156 : : { "GPG_SIGNING_PW_BASE64", FWKNOP_CLI_ARG_GPG_SIGNING_PW_BASE64 },
157 : : { "GPG_NO_SIGNING_PW", FWKNOP_CLI_ARG_GPG_NO_SIGNING_PW },
158 : : { "SPOOF_USER", FWKNOP_CLI_ARG_SPOOF_USER },
159 : : { "SPOOF_SOURCE_IP", FWKNOP_CLI_ARG_SPOOF_SOURCE_IP },
160 : : { "ACCESS", FWKNOP_CLI_ARG_ACCESS },
161 : : { "SPA_SERVER", FWKNOP_CLI_ARG_SPA_SERVER },
162 : : { "RAND_PORT", FWKNOP_CLI_ARG_RAND_PORT },
163 : : { "KEY", FWKNOP_CLI_ARG_KEY_RIJNDAEL },
164 : : { "KEY_BASE64", FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64 },
165 : : { "HMAC_DIGEST_TYPE", FWKNOP_CLI_ARG_HMAC_DIGEST_TYPE },
166 : : { "HMAC_KEY_BASE64", FWKNOP_CLI_ARG_KEY_HMAC_BASE64 },
167 : : { "HMAC_KEY", FWKNOP_CLI_ARG_KEY_HMAC },
168 : : { "USE_HMAC", FWKNOP_CLI_ARG_USE_HMAC },
169 : : { "USE_WGET_USER_AGENT", FWKNOP_CLI_ARG_USE_WGET_USER_AGENT },
170 : : { "KEY_FILE", FWKNOP_CLI_ARG_KEY_FILE },
171 : : { "HMAC_KEY_FILE", FWKNOP_CLI_ARG_HMAC_KEY_FILE },
172 : : { "NAT_ACCESS", FWKNOP_CLI_ARG_NAT_ACCESS },
173 : : { "HTTP_USER_AGENT", FWKNOP_CLI_ARG_HTTP_USER_AGENT },
174 : : { "RESOLVE_URL", FWKNOP_CLI_ARG_RESOLVE_URL },
175 : : { "SERVER_RESOLVE_IPV4", FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4 },
176 : : { "NAT_LOCAL", FWKNOP_CLI_ARG_NAT_LOCAL },
177 : : { "NAT_RAND_PORT", FWKNOP_CLI_ARG_NAT_RAND_PORT },
178 : : { "NAT_PORT", FWKNOP_CLI_ARG_NAT_PORT },
179 : : { "VERBOSE", FWKNOP_CLI_ARG_VERBOSE },
180 : : { "RESOLVE_IP_HTTP", FWKNOP_CLI_ARG_RESOLVE_IP_HTTP },
181 : : { "RESOLVE_IP_HTTPS", FWKNOP_CLI_ARG_RESOLVE_IP_HTTPS },
182 : : { "RESOLVE_HTTP_ONLY", FWKNOP_CLI_ARG_RESOLVE_HTTP_ONLY },
183 : : { "WGET_CMD", FWKNOP_CLI_ARG_WGET_CMD },
184 : : { "NO_SAVE_ARGS", FWKNOP_CLI_ARG_NO_SAVE_ARGS }
185 : : };
186 : :
187 : : /* Array to define which conf. variables are critical and should not be
188 : : * overwritten when a stanza is updated using the --save-rc-stanza arg
189 : : * without the user validation */
190 : : static int critical_var_array[] =
191 : : {
192 : : FWKNOP_CLI_ARG_KEY_RIJNDAEL,
193 : : FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64,
194 : : FWKNOP_CLI_ARG_KEY_HMAC,
195 : : FWKNOP_CLI_ARG_KEY_HMAC_BASE64,
196 : : FWKNOP_CLI_ARG_GPG_RECIPIENT,
197 : : FWKNOP_CLI_ARG_GPG_SIGNER,
198 : : FWKNOP_CLI_ARG_GPG_SIGNING_PW,
199 : : FWKNOP_CLI_ARG_GPG_SIGNING_PW_BASE64
200 : : };
201 : :
202 : : /**
203 : : * @brief Generate Rijndael + HMAC keys from /dev/urandom (base64 encoded).
204 : : *
205 : : * @param options FKO command line option structure
206 : : */
207 : : static void
208 : 2483 : generate_keys(fko_cli_options_t *options)
209 : : {
210 : : int res;
211 : :
212 : : /* If asked, we have to generate the keys */
213 [ + + ]: 2483 : if(options->key_gen)
214 : : {
215 : : /* Zero out the key buffers */
216 : 114 : memset(&(options->key_base64), 0x00, sizeof(options->key_base64));
217 : 114 : memset(&(options->hmac_key_base64), 0x00, sizeof(options->hmac_key_base64));
218 : :
219 : : /* Generate the key through libfko */
220 : 114 : res = fko_key_gen(options->key_base64, options->key_len,
221 : : options->hmac_key_base64, options->hmac_key_len,
222 : : options->hmac_type);
223 : :
224 : : /* Exit upon key generation failure*/
225 [ - + ]: 114 : if(res != FKO_SUCCESS)
226 : : {
227 : 0 : log_msg(LOG_VERBOSITY_ERROR, "%s: fko_key_gen: Error %i - %s",
228 : : MY_NAME, res, fko_errstr(res));
229 : 0 : exit(EXIT_FAILURE);
230 : : }
231 : :
232 : : /* Everything is ok - nothing to do */
233 : : else;
234 : : }
235 : :
236 : : /* No key generation asked - nothing to do */
237 : : else;
238 : 2483 : }
239 : :
240 : : /**
241 : : * @brief Check if a variable is a critical var.
242 : : *
243 : : * This function check the critical_var_array table to find if the variable
244 : : * position is available.
245 : : *
246 : : * @param var_pos Fwknop configuration variable position
247 : : *
248 : : * @return 1 the variable is critical, 0 otherwise
249 : : */
250 : : static int
251 : 12 : var_is_critical(short var_pos)
252 : : {
253 : : int ndx; /* Index on the critical_var_array array */
254 : 12 : int var_found = 0;
255 : :
256 : : /* Go through the array of critical vars */
257 [ + + ]: 67 : for (ndx=0 ; ndx<ARRAY_SIZE(critical_var_array) ; ndx++)
258 : : {
259 : : /* and check if we find it */
260 [ + + ]: 61 : if (var_pos == critical_var_array[ndx])
261 : : {
262 : : var_found = 1;
263 : : break;
264 : : }
265 : : }
266 : :
267 : 12 : return var_found;
268 : : }
269 : :
270 : : /**
271 : : * @brief Add a variable to a bitmask
272 : : *
273 : : * This function adds the bitmask associated to a variable position, to a
274 : : * bitmask.
275 : : *
276 : : * @param var_pos Fwknop configuration variable position
277 : : * @param bm fko_var_bitmask_t variable to update
278 : : */
279 : : static void
280 : 16597 : add_var_to_bitmask(short var_pos, fko_var_bitmask_t *bm)
281 : : {
282 : : unsigned int bitmask_ndx;
283 : :
284 : : /* Look for the index on the uint32_t array we have to process */
285 : 16597 : bitmask_ndx = var_pos / 32;
286 : :
287 : : /* Set the bitmask according to the index found */
288 [ + + ]: 16597 : if (bitmask_ndx < BITMASK_ARRAY_SIZE)
289 : 16595 : bm->dw[bitmask_ndx] |= POSITION_TO_BITMASK(var_pos);
290 : :
291 : : /* The index on the uint32_t bitmask is invalid */
292 : : else
293 : 2 : log_msg(LOG_VERBOSITY_WARNING,
294 : : "add_var_to_bitmask() : Bad variable position %u", var_pos);
295 : 16597 : }
296 : :
297 : : /**
298 : : * @brief Remove a variable from a bitmask
299 : : *
300 : : * This function removes the bitmask associated to the variable position from a
301 : : * bitmask.
302 : : *
303 : : * @param var_pos Fwknop configuration variable position
304 : : * @param bm fko_var_bitmask_t structure to update
305 : : */
306 : : static void
307 : 4 : remove_var_from_bitmask(short var_pos, fko_var_bitmask_t *bm)
308 : : {
309 : : unsigned int bitmask_ndx;
310 : :
311 : : /* Look for the index on the uint32_t array we have to process */
312 : 4 : bitmask_ndx = var_pos / 32;
313 : :
314 : : /* Set the bitmask according to the index found */
315 [ + - ]: 4 : if (bitmask_ndx < BITMASK_ARRAY_SIZE)
316 : 4 : bm->dw[bitmask_ndx] &= ~POSITION_TO_BITMASK(var_pos);
317 : :
318 : : /* The index on the uint32_t bitmask is invalid */
319 : : else
320 : 0 : log_msg(LOG_VERBOSITY_WARNING,
321 : : "remove_from_bitmask() : Bad variable position %u", var_pos);
322 : 4 : }
323 : :
324 : : /**
325 : : * @brief Return whether a variable is available in a bitmask
326 : : *
327 : : * The variable bitmask is looked for in the bitmask.
328 : : *
329 : : * @param var_pos Fwknop configuration variable position
330 : : * @param bm fko_var_bitmask_t structure to check
331 : : *
332 : : * @return 1 if the bitmsk contains the variable, 0 otherwise.
333 : : */
334 : : static int
335 : 4012 : bitmask_has_var(short var_pos, fko_var_bitmask_t *bm)
336 : : {
337 : : unsigned int bitmask_ndx;
338 : 4012 : int var_found = 0;
339 : :
340 : : /* Look for the index on the uint32_t array we have to process */
341 : 4012 : bitmask_ndx = var_pos / 32;
342 : :
343 : : /* Check the bitmask according to the index found */
344 [ + + ]: 4012 : if (bitmask_ndx < BITMASK_ARRAY_SIZE)
345 : : {
346 [ + + ]: 4010 : if ( bm->dw[bitmask_ndx] & POSITION_TO_BITMASK(var_pos) )
347 : 619 : var_found = 1;
348 : : }
349 : :
350 : : /* The index on the uint32_t bitmask is invalid */
351 : : else
352 : 2 : log_msg(LOG_VERBOSITY_WARNING, "bitmask_has_var_ndx() : Bad variable position %u", var_pos);
353 : :
354 : 4012 : return var_found;
355 : : }
356 : :
357 : : /**
358 : : * @brief Ask the user if a variable must be overwritten or not for a specific stanza
359 : : *
360 : : * If the user sets other chars than a 'y' char, we assume he does not want to
361 : : * overwrite the variable.
362 : : *
363 : : * @param var Variable which should be overwritten
364 : : * @param stanza Stanza where the variable should be overwritten
365 : : *
366 : : * @return 1 if the user wants to overwrite the variable, 0 otherwise
367 : : */
368 : : static int
369 : 5 : ask_overwrite_var(const char *var, const char *stanza)
370 : : {
371 : 5 : char user_input = 'N';
372 : 5 : int overwrite = 0;
373 : : int c;
374 : 5 : int first_char = 1;;
375 : :
376 : 5 : log_msg(LOG_VERBOSITY_NORMAL,
377 : : "Variable '%s' found in stanza '%s'. Overwrite [N/y] ? ",
378 : : var, stanza);
379 : :
380 [ + + ]: 10 : while ((c=getchar()) != LF_CHAR)
381 : : {
382 [ + - ]: 5 : if (first_char)
383 : 5 : user_input = c;
384 : : first_char = 0;
385 : : }
386 : :
387 [ + + ]: 5 : if (user_input == 'y')
388 : 4 : overwrite = 1;
389 : :
390 : 5 : return overwrite;
391 : : }
392 : :
393 : : /**
394 : : * @brief Lookup a variable in the variable array according to its name
395 : : *
396 : : * This function parses the fko_var_array table and try to find a match
397 : : * for the user string, which indicates we have found a configuration variable.
398 : : *
399 : : * @param str String to compare against every fwknop conf variables
400 : : *
401 : : * @return A pointer on the variable structure, or NULL if not found
402 : : */
403 : : static fko_var_t *
404 : 3208 : lookup_var_by_name(const char *var_name)
405 : : {
406 : : short ndx; /* Index on the the fko_var_array table */
407 : 3208 : fko_var_t *var = NULL;
408 : :
409 : : /* Check str against each variable available in fko_var_array */
410 [ + + ]: 76604 : for (ndx=0 ; ndx<ARRAY_SIZE(fko_var_array) ; ndx++)
411 : : {
412 [ + + ]: 76601 : if (CONF_VAR_IS(var_name, fko_var_array[ndx].name))
413 : : {
414 : 3205 : var = &(fko_var_array[ndx]);
415 : 3205 : break;
416 : : }
417 : : }
418 : :
419 : 3208 : return var;
420 : : }
421 : :
422 : : /**
423 : : * @brief Lookup a variable in the variable array according to its position
424 : : *
425 : : * This function parses the fko_var_array table and try to find a match
426 : : * for the position, which indicates we have found a configuration variable.
427 : : *
428 : : * @param var_pos Position to compare against every fwknop conf variables
429 : : *
430 : : * @return A pointer on the variable structure, or NULL if not found
431 : : */
432 : : static fko_var_t *
433 : 616 : lookup_var_by_position(short var_pos)
434 : : {
435 : : short ndx; /* Index on the the fko_var_array table */
436 : 616 : fko_var_t *var = NULL;
437 : :
438 : : /* Check str against each variable available in fko_var_array */
439 [ + - ]: 15192 : for (ndx=0 ; ndx<ARRAY_SIZE(fko_var_array) ; ndx++)
440 : : {
441 [ + + ]: 15192 : if (var_pos == fko_var_array[ndx].pos)
442 : : {
443 : 616 : var = &(fko_var_array[ndx]);
444 : 616 : break;
445 : : }
446 : : }
447 : :
448 : 616 : return var;
449 : : }
450 : :
451 : : /**
452 : : * @brief Set a string as a Yes or No value according to a boolean (0 or 1).
453 : : *
454 : : * This function checks whether a value is set to zero or not, and updates a
455 : : * string to a YES_NO parameter value.
456 : : * The string must be zeroed before being passed to the function.
457 : : *
458 : : * @param val Variable to check
459 : : * @param s String where to store the YES_NO value.
460 : : * @param len Number of bytes avaialble for the s buffer.
461 : : */
462 : : static void
463 : 138 : bool_to_yesno(int val, char* s, size_t len)
464 : : {
465 [ + + ]: 138 : if (val == 0)
466 : 1 : strlcpy(s, PARAM_NO_VALUE, len);
467 : : else
468 : 137 : strlcpy(s, PARAM_YES_VALUE, len);
469 : 138 : }
470 : :
471 : : /**
472 : : * @brief Is a string formatted as YES string.
473 : : *
474 : : * @param s String to check for a YES string
475 : : *
476 : : * @return 1 if the string match the YES pattern, 0 otherwise
477 : : */
478 : : static int
479 : 50 : is_yes_str(const char *s)
480 : : {
481 : : int valid;
482 : :
483 [ + + ]: 50 : if (strcasecmp(PARAM_YES_VALUE, s) == 0)
484 : : valid = 1;
485 : : else
486 : 22 : valid = 0;
487 : :
488 : 50 : return valid;
489 : : }
490 : :
491 : : /**
492 : : * @brief Check if a section is in a line and fetch it.
493 : : *
494 : : * This function parses a NULL terminated string in order to find a section,
495 : : * something like [mysection]. If it succeeds, the stanza is retrieved.
496 : : *
497 : : * @param line String containing a line from the rc file to check for a section
498 : : * @param line_size size of the line buffer
499 : : * @param rc_section String to store the section found
500 : : * @param rc_section_size Size of the rc_section buffer
501 : : *
502 : : * @return 1 if a section was found, 0 otherwise
503 : : */
504 : : static int
505 : 10762 : is_rc_section(const char* line, uint16_t line_size, char* rc_section, uint16_t rc_section_size)
506 : : {
507 : : char *ndx, *emark;
508 : 10762 : char buf[MAX_LINE_LEN] = {0};
509 : 10762 : int section_found = 0;
510 : :
511 [ + - ]: 10762 : if (line_size < sizeof(buf))
512 : : {
513 : 10762 : strlcpy(buf, line, sizeof(buf));
514 : :
515 : 10762 : ndx = buf;
516 : :
517 [ + + ]: 10766 : while(isspace(*ndx))
518 : 4 : ndx++;
519 : :
520 [ + + ]: 10762 : if(*ndx == '[')
521 : : {
522 : 4282 : ndx++;
523 : 4282 : emark = strchr(ndx, ']');
524 [ + - ]: 4282 : if(emark != NULL)
525 : : {
526 : 4282 : *emark = '\0';
527 : 4282 : memset(rc_section, 0, rc_section_size);
528 : 4282 : strlcpy(rc_section, ndx, rc_section_size);
529 : 4282 : section_found = 1;
530 : : }
531 : : else
532 : : {
533 : : }
534 : : }
535 : : }
536 : : else
537 : : {
538 : : }
539 : :
540 : 10762 : return section_found;
541 : : }
542 : :
543 : : /**
544 : : * @brief Grab a variable and its value from a rc line.
545 : : *
546 : : * @param line Line to parse for a variable
547 : : * @param param Parameter structure where to store the variable name and its value
548 : : *
549 : : * @return 0 if no variable has been found, 1 otherwise.
550 : : */
551 : : static int
552 : 3209 : is_rc_param(const char *line, rc_file_param_t *param)
553 : : {
554 : 3209 : char var[MAX_LINE_LEN] = {0};
555 : 3209 : char val[MAX_LINE_LEN] = {0};
556 : : char *ndx;
557 : :
558 : : memset(param, 0, sizeof(*param));
559 : :
560 : : /* Fetch the variable and its value */
561 [ + + ]: 3209 : if(sscanf(line, "%s %[^ ;\t\n\r#]", var, val) != 2)
562 : : {
563 : 1 : log_msg(LOG_VERBOSITY_WARNING,
564 : : "*Invalid entry in '%s'", line);
565 : 1 : return 0;
566 : : }
567 : :
568 : : /* Remove any colon that may be on the end of the var */
569 [ + + ]: 3208 : if((ndx = strrchr(var, ':')) != NULL)
570 : 977 : *ndx = '\0';
571 : :
572 : : /* Even though sscanf should automatically add a terminating
573 : : * NULL byte, an assumption is made that the input arrays are
574 : : * big enough, so we'll force a terminating NULL byte regardless
575 : : */
576 : 3208 : var[MAX_LINE_LEN-1] = 0x0;
577 : 3208 : val[MAX_LINE_LEN-1] = 0x0;
578 : :
579 : : /* Copy back the val and var in the structure */
580 : 3208 : strlcpy(param->name, var, sizeof(param->name));
581 : 3208 : strlcpy(param->val, val, sizeof(param->val));
582 : :
583 : 3208 : return 1;
584 : : }
585 : :
586 : : /**
587 : : * \brief Dump available stanzas from a fwknoprc file
588 : : *
589 : : * This function parses a rcfile and looks for configured stanzas.
590 : : * They are all displayed except the default stanza.
591 : : *
592 : : * \param rcfile full path to the rcfile to parse
593 : : */
594 : : static int
595 : 2 : dump_configured_stanzas_from_rcfile(const char* rcfile)
596 : : {
597 : : FILE *rc;
598 : 2 : char line[MAX_LINE_LEN] = {0};
599 : 2 : char curr_stanza[MAX_LINE_LEN] = {0};
600 : :
601 : : /* Open the rcfile in read mode */
602 [ + + ]: 2 : if ((rc = fopen(rcfile, "r")) == NULL)
603 : : {
604 : 1 : log_msg(LOG_VERBOSITY_WARNING, "Unable to open rc file: %s: %s",
605 : 1 : rcfile, strerror(errno));
606 : :
607 : 1 : return EXIT_FAILURE;
608 : : }
609 : :
610 : 1 : log_msg(LOG_VERBOSITY_NORMAL, "The following stanzas are configured in %s :", rcfile);
611 : :
612 : : /* Parse the rcfile line by line to find stanza */
613 [ + + ]: 10 : while ((fgets(line, MAX_LINE_LEN, rc)) != NULL)
614 : : {
615 : 8 : line[MAX_LINE_LEN-1] = '\0';
616 : :
617 : : /* Get past comments and empty lines (note: we only look at the first
618 : : * character. */
619 [ + + ][ + - ]: 8 : if(IS_EMPTY_LINE(line[0]))
[ + - ][ - + ]
620 : 2 : continue;
621 : :
622 : : /* Check which section we are working on */
623 [ + + ]: 6 : else if (is_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)))
624 : : {
625 : : /* Print the stanza and continue - we exclude the default stanza */
626 [ + + ]: 3 : if (strcasecmp(curr_stanza, RC_SECTION_DEFAULT) != 0)
627 : 2 : log_msg(LOG_VERBOSITY_NORMAL, " - %s", curr_stanza);
628 : 8 : continue;
629 : : }
630 : :
631 : : /* Nothing we care about */
632 : : else;
633 : : }
634 : :
635 : 1 : fclose(rc);
636 : :
637 : 1 : return EXIT_SUCCESS;
638 : : }
639 : :
640 : : /* Assign path to fwknop rc file
641 : : */
642 : : static void
643 : 2928 : set_rc_file(char *rcfile, fko_cli_options_t *options)
644 : : {
645 : : int rcf_offset;
646 : : char *homedir;
647 : :
648 : : memset(rcfile, 0x0, MAX_PATH_LEN);
649 : :
650 [ + + ]: 2928 : if(options->rc_file[0] == 0x0)
651 : : {
652 [ + + ]: 1668 : if(options->no_home_dir)
653 : : {
654 : 1 : log_msg(LOG_VERBOSITY_ERROR,
655 : : "Warning: in --no-home-dir mode, must set --rc-file path.");
656 : 1 : exit(EXIT_FAILURE);
657 : : }
658 : : #ifdef WIN32
659 : : homedir = getenv("USERPROFILE");
660 : : #else
661 : 1667 : homedir = getenv("HOME");
662 : : #endif
663 : :
664 [ - + ]: 1667 : if(homedir == NULL)
665 : : {
666 : 0 : log_msg(LOG_VERBOSITY_ERROR, "Warning: Unable to determine HOME directory.\n"
667 : : " No .fwknoprc file processed.");
668 : 0 : exit(EXIT_FAILURE);
669 : : }
670 : :
671 : 1667 : strlcpy(rcfile, homedir, MAX_PATH_LEN);
672 : :
673 : 1667 : rcf_offset = strlen(rcfile);
674 : :
675 : : /* Sanity check the path to .fwknoprc.
676 : : * The preceding path plus the path separator and '.fwknoprc' = 11
677 : : * cannot exceed MAX_PATH_LEN.
678 : : */
679 [ + + ]: 1667 : if(rcf_offset > (MAX_PATH_LEN - 11))
680 : : {
681 : 1 : log_msg(LOG_VERBOSITY_ERROR, "Warning: Path to .fwknoprc file is too long.\n"
682 : : " No .fwknoprc file processed.");
683 : 1 : exit(EXIT_FAILURE);
684 : : }
685 : :
686 : 1666 : rcfile[rcf_offset] = PATH_SEP;
687 : 1666 : strlcat(rcfile, ".fwknoprc", MAX_PATH_LEN);
688 : : }
689 : : else
690 : : {
691 : 1260 : strlcpy(rcfile, options->rc_file, MAX_PATH_LEN);
692 : : }
693 : :
694 : : /* Check rc file permissions - if anything other than user read/write,
695 : : * then throw a warning. This change was made to help ensure that the
696 : : * client consumes a proper rc file with strict permissions set (thanks
697 : : * to Fernando Arnaboldi from IOActive for pointing this out).
698 : : */
699 [ + + ]: 2926 : if(verify_file_perms_ownership(rcfile) != 1)
700 : 1 : exit(EXIT_FAILURE);
701 : :
702 : 2925 : return;
703 : : }
704 : :
705 : : static void
706 : 2483 : keys_status(fko_cli_options_t *options)
707 : : {
708 : 2483 : FILE *key_gen_file_ptr = NULL;
709 : 2483 : char rcfile[MAX_PATH_LEN] = {0};
710 : :
711 [ + + ]: 2483 : if(options->key_gen == 1)
712 : : {
713 [ + + ]: 114 : if(options->key_gen_file[0] != '\0')
714 : : {
715 [ + + ]: 2 : if ((key_gen_file_ptr = fopen(options->key_gen_file, "w")) == NULL)
716 : : {
717 : 1 : log_msg(LOG_VERBOSITY_ERROR, "Unable to create key gen file: %s: %s",
718 : 1 : options->key_gen_file, strerror(errno));
719 : 1 : exit(EXIT_FAILURE);
720 : : }
721 : : fprintf(key_gen_file_ptr, "KEY_BASE64: %s\nHMAC_KEY_BASE64: %s\n",
722 : 1 : options->key_base64, options->hmac_key_base64);
723 : 1 : fclose(key_gen_file_ptr);
724 : 1 : log_msg(LOG_VERBOSITY_NORMAL,
725 : : "[+] Wrote Rijndael and HMAC keys to: %s",
726 : : options->key_gen_file);
727 : : }
728 : : else
729 : : {
730 [ + + ]: 112 : if(options->save_rc_stanza == 1)
731 : : {
732 : 11 : set_rc_file(rcfile, options);
733 : 11 : log_msg(LOG_VERBOSITY_NORMAL,
734 : : "[+] Wrote Rijndael and HMAC keys to rc file: %s", rcfile);
735 : : }
736 : : else
737 : 101 : log_msg(LOG_VERBOSITY_NORMAL,
738 : : "KEY_BASE64: %s\nHMAC_KEY_BASE64: %s",
739 : 101 : options->key_base64, options->hmac_key_base64);
740 : : }
741 : :
742 : : /* Always exit out in --key-gen mode since the fwknopd server
743 : : * has no way to know what the new keys are
744 : : */
745 : 113 : exit(EXIT_SUCCESS);
746 : : }
747 : 2369 : }
748 : :
749 : :
750 : : /* Parse any time offset from the command line
751 : : */
752 : : static int
753 : 17 : parse_time_offset(const char *offset_str, int *offset)
754 : : {
755 : : int i, j;
756 : 17 : int offset_type = TIME_OFFSET_SECONDS;
757 : 17 : int os_len = strlen(offset_str);
758 : 17 : int is_err = 0;
759 : :
760 : 17 : char offset_digits[MAX_TIME_STR_LEN] = {0};
761 : :
762 : 17 : j=0;
763 [ + + ]: 71 : for (i=0; i < os_len; i++) {
764 [ + + ]: 65 : if (isdigit(offset_str[i])) {
765 : 44 : offset_digits[j] = offset_str[i];
766 : 44 : j++;
767 [ + + ]: 44 : if(j >= MAX_TIME_STR_LEN)
768 : : {
769 : : return 0;
770 : : }
771 [ + + ]: 21 : } else if (offset_str[i] == 'm' || offset_str[i] == 'M') {
772 : : offset_type = TIME_OFFSET_MINUTES;
773 : : break;
774 [ + + ]: 18 : } else if (offset_str[i] == 'h' || offset_str[i] == 'H') {
775 : : offset_type = TIME_OFFSET_HOURS;
776 : : break;
777 [ + + ]: 16 : } else if (offset_str[i] == 'd' || offset_str[i] == 'D') {
778 : : offset_type = TIME_OFFSET_DAYS;
779 : : break;
780 : : }
781 : : }
782 : :
783 : 14 : offset_digits[j] = '\0';
784 : :
785 [ + + ]: 14 : if (j < 1)
786 : : return 0;
787 : :
788 : 13 : *offset = strtol_wrapper(offset_digits, 0, (2 << 15),
789 : : NO_EXIT_UPON_ERR, &is_err);
790 : :
791 : : /* Apply the offset_type multiplier
792 : : */
793 : 13 : *offset *= offset_type;
794 : :
795 : 13 : return is_err == 0 ? 1 : 0;
796 : : }
797 : :
798 : : static int
799 : 1 : create_fwknoprc(const char *rcfile)
800 : : {
801 : 1 : FILE *rc = NULL;
802 : 1 : int rcfile_fd = -1;
803 : :
804 : 1 : log_msg(LOG_VERBOSITY_NORMAL, "[*] Creating initial rc file: %s.", rcfile);
805 : :
806 : : /* Try to create the initial rcfile with user read/write rights only.
807 : : * If the rcfile already exists, an error is returned */
808 : 1 : rcfile_fd = open(rcfile, FWKNOPRC_OFLAGS ,FWKNOPRC_MODE);
809 : :
810 : : // If an error occurred ...
811 [ - + ]: 1 : if (rcfile_fd == -1) {
812 : 0 : log_msg(LOG_VERBOSITY_WARNING, "Unable to create initial rc file: %s: %s",
813 : 0 : rcfile, strerror(errno));
814 : 0 : return(-1);
815 : : }
816 : :
817 : : // Free the rcfile descriptor
818 : 1 : close(rcfile_fd);
819 : :
820 [ - + ]: 1 : if ((rc = fopen(rcfile, "w")) == NULL)
821 : : {
822 : 0 : log_msg(LOG_VERBOSITY_WARNING, "Unable to write default setup to rcfile: %s: %s",
823 : 0 : rcfile, strerror(errno));
824 : 0 : return(-1);
825 : : }
826 : :
827 : : fprintf(rc,
828 : : "# .fwknoprc\n"
829 : : "##############################################################################\n"
830 : : "#\n"
831 : : "# Firewall Knock Operator (fwknop) client rc file.\n"
832 : : "#\n"
833 : : "# This file contains user-specific fwknop client configuration default\n"
834 : : "# and named parameter sets for specific invocations of the fwknop client.\n"
835 : : "#\n"
836 : : "# Each section (or stanza) is identified and started by a line in this\n"
837 : : "# file that contains a single identifier surrounded by square brackets.\n"
838 : : "# It is this identifier (or name) that is used from the fwknop command line\n"
839 : : "# via the '-n <name>' argument to reference the corresponding stanza.\n"
840 : : "#\n"
841 : : "# The parameters within the stanza typically match corresponding client \n"
842 : : "# command-line parameters.\n"
843 : : "#\n"
844 : : "# The first one should always be `[default]' as it defines the global\n"
845 : : "# default settings for the user. These override the program defaults\n"
846 : : "# for these parameters. If a named stanza is used, its entries will\n"
847 : : "# override any of the default values. Command-line options will trump them\n"
848 : : "# all.\n"
849 : : "#\n"
850 : : "# Subsequent stanzas will have only the overriding and destination\n"
851 : : "# specific parameters.\n"
852 : : "#\n"
853 : : "# Lines starting with `#' and empty lines are ignored.\n"
854 : : "#\n"
855 : : "# See the fwknop.8 man page for a complete list of valid parameters\n"
856 : : "# and their values.\n"
857 : : "#\n"
858 : : "##############################################################################\n"
859 : : "#\n"
860 : : "# We start with the 'default' stanza. Uncomment and edit for your\n"
861 : : "# preferences. The client will use its built-in default for those items\n"
862 : : "# that are commented out.\n"
863 : : "#\n"
864 : : "[default]\n"
865 : : "\n"
866 : : "#DIGEST_TYPE sha256\n"
867 : : "#FW_TIMEOUT 30\n"
868 : : "#SPA_SERVER_PORT 62201\n"
869 : : "#SPA_SERVER_PROTO udp\n"
870 : : "#ALLOW_IP <ip addr>\n"
871 : : "#SPOOF_USER <username>\n"
872 : : "#SPOOF_SOURCE_IP <IPaddr>\n"
873 : : "#TIME_OFFSET 0\n"
874 : : "#USE_GPG N\n"
875 : : "#GPG_HOMEDIR /path/to/.gnupg\n"
876 : : "#GPG_EXE /path/to/gpg\n"
877 : : "#GPG_SIGNER <signer ID>\n"
878 : : "#GPG_RECIPIENT <recipient ID>\n"
879 : : "#NO_SAVE_ARGS N\n"
880 : : "\n"
881 : : "# User-provided named stanzas:\n"
882 : : "\n"
883 : : "# Example for a destination server of 192.168.1.20 to open access to\n"
884 : : "# SSH for an IP that is resolved externally, and one with a NAT request\n"
885 : : "# for a specific source IP that maps port 8088 on the server\n"
886 : : "# to port 88 on 192.168.1.55 with timeout.\n"
887 : : "#\n"
888 : : "#[myssh]\n"
889 : : "#SPA_SERVER 192.168.1.20\n"
890 : : "#ACCESS tcp/22\n"
891 : : "#ALLOW_IP resolve\n"
892 : : "#\n"
893 : : "#[mynatreq]\n"
894 : : "#SPA_SERVER 192.168.1.20\n"
895 : : "#ACCESS tcp/8088\n"
896 : : "#ALLOW_IP 10.21.2.6\n"
897 : : "#NAT_ACCESS 192.168.1.55,88\n"
898 : : "#CLIENT_TIMEOUT 60\n"
899 : : "#\n"
900 : : "\n"
901 : : );
902 : :
903 : 1 : fclose(rc);
904 : :
905 : 1 : return(0);
906 : : }
907 : :
908 : : static int
909 : 3198 : parse_rc_param(fko_cli_options_t *options, const char *var_name, char * val)
910 : : {
911 : : int tmpint, is_err;
912 : 3198 : int parse_error = 0; /* 0 if the variable has been successfully processed, < 0 otherwise */
913 : : fko_var_t *var; /* Pointer on an fwknop variable structure */
914 : :
915 : 3198 : log_msg(LOG_VERBOSITY_DEBUG, "parse_rc_param() : Parsing variable %s...", var_name);
916 : :
917 : : /* Lookup the variable according to its name. */
918 : 3198 : var = lookup_var_by_name(var_name);
919 : :
920 : : /* The variable is not handled if its pointer is NULL */
921 [ + + ]: 3198 : if (var == NULL)
922 : : parse_error = -1;
923 : :
924 : : /* Digest Type */
925 [ + + ]: 3195 : else if (var->pos == FWKNOP_CLI_ARG_DIGEST_TYPE)
926 : : {
927 : 55 : tmpint = digest_strtoint(val);
928 [ + + ]: 55 : if(tmpint < 0)
929 : : parse_error = -1;
930 : : else
931 : 54 : options->digest_type = tmpint;
932 : : }
933 : : /* Server protocol */
934 [ + + ]: 3140 : else if (var->pos == FWKNOP_CLI_ARG_SPA_SERVER_PROTO)
935 : : {
936 : 21 : tmpint = proto_strtoint(val);
937 [ + + ]: 21 : if(tmpint < 0)
938 : : parse_error = -1;
939 : : else
940 : 20 : options->spa_proto = tmpint;
941 : : }
942 : : /* Server port */
943 [ + + ]: 3119 : else if (var->pos == FWKNOP_CLI_ARG_SPA_SERVER_PORT)
944 : : {
945 : 10 : tmpint = strtol_wrapper(val, 0, MAX_PORT, NO_EXIT_UPON_ERR, &is_err);
946 [ + - ]: 10 : if(is_err == FKO_SUCCESS)
947 : 10 : options->spa_dst_port = tmpint;
948 : : else
949 : : parse_error = -1;
950 : : }
951 : : /* Source port */
952 [ + + ]: 3109 : else if (var->pos == FWKNOP_CLI_ARG_SPA_SOURCE_PORT)
953 : : {
954 : 3 : tmpint = strtol_wrapper(val, 0, MAX_PORT, NO_EXIT_UPON_ERR, &is_err);
955 [ + - ]: 3 : if(is_err == FKO_SUCCESS)
956 : 3 : options->spa_src_port = tmpint;
957 : : else
958 : : parse_error = -1;
959 : : }
960 : : /* Firewall rule timeout */
961 [ + + ]: 3106 : else if (var->pos == FWKNOP_CLI_ARG_FW_TIMEOUT)
962 : : {
963 : 26 : tmpint = strtol_wrapper(val, 0, (2 << 15), NO_EXIT_UPON_ERR, &is_err);
964 [ + - ]: 26 : if(is_err == FKO_SUCCESS)
965 : 26 : options->fw_timeout = tmpint;
966 : : else
967 : : parse_error = -1;
968 : : }
969 : : /* Allow IP */
970 [ + + ]: 3080 : else if (var->pos == FWKNOP_CLI_ARG_ALLOW_IP)
971 : : {
972 : : /* In case this was set previously
973 : : */
974 : 10 : options->resolve_ip_http_https = 0;
975 : :
976 : : /* use source, resolve, or an actual IP
977 : : */
978 [ + + ]: 10 : if(strcasecmp(val, "source") == 0)
979 : 3 : strlcpy(options->allow_ip_str, "0.0.0.0", sizeof(options->allow_ip_str));
980 [ + + ]: 7 : else if(strcasecmp(val, "resolve") == 0)
981 : 3 : options->resolve_ip_http_https = 1;
982 : : else /* Assume IP address and validate */
983 : : {
984 : 4 : strlcpy(options->allow_ip_str, val, sizeof(options->allow_ip_str));
985 [ - + ]: 4 : if(! is_valid_ipv4_addr(options->allow_ip_str, strlen(options->allow_ip_str)))
986 : 0 : parse_error = -1;
987 : : }
988 : : }
989 : : /* Time Offset */
990 [ + + ]: 3070 : else if (var->pos == FWKNOP_CLI_ARG_TIME_OFFSET)
991 : : {
992 [ + + ]: 9 : if(val[0] == '-')
993 : : {
994 : 6 : val++;
995 [ - + ]: 6 : if(! parse_time_offset(val, &options->time_offset_minus))
996 : 0 : parse_error = -1;
997 : : }
998 : : else
999 [ + + ]: 3 : if (! parse_time_offset(val, &options->time_offset_plus))
1000 : 2 : parse_error = -1;
1001 : :
1002 [ + + ]: 9 : if(parse_error == -1)
1003 : 2 : log_msg(LOG_VERBOSITY_WARNING,
1004 : : "TIME_OFFSET argument '%s' invalid.", val);
1005 : : }
1006 : : /* symmetric encryption mode */
1007 [ + + ]: 3061 : else if (var->pos == FWKNOP_CLI_ARG_ENCRYPTION_MODE)
1008 : : {
1009 : 9 : tmpint = enc_mode_strtoint(val);
1010 [ + + ]: 9 : if(tmpint < 0)
1011 : : parse_error = -1;
1012 : : else
1013 : 8 : options->encryption_mode = tmpint;
1014 : : }
1015 : : /* Use GPG ? */
1016 [ + + ]: 3052 : else if (var->pos == FWKNOP_CLI_ARG_USE_GPG)
1017 : : {
1018 [ + + ]: 9 : if (is_yes_str(val))
1019 : 2 : options->use_gpg = 1;
1020 : : else;
1021 : : }
1022 : : /* Use GPG Agent ? */
1023 [ + + ]: 3043 : else if (var->pos == FWKNOP_CLI_ARG_USE_GPG_AGENT)
1024 : : {
1025 [ + + ]: 9 : if (is_yes_str(val))
1026 : 1 : options->use_gpg_agent = 1;
1027 : : else;
1028 : : }
1029 : : /* No GPG signing passphrase ? */
1030 [ + + ]: 3034 : else if (var->pos == FWKNOP_CLI_ARG_GPG_NO_SIGNING_PW)
1031 : : {
1032 [ + - ]: 1 : if (is_yes_str(val))
1033 : 1 : options->gpg_no_signing_pw = 1;
1034 : : else;
1035 : : }
1036 : : /* GPG Recipient */
1037 [ + + ]: 3033 : else if (var->pos == FWKNOP_CLI_ARG_GPG_RECIPIENT)
1038 : : {
1039 : 2 : strlcpy(options->gpg_recipient_key, val, sizeof(options->gpg_recipient_key));
1040 : : }
1041 : : /* GPG Signer */
1042 [ + + ]: 3031 : else if (var->pos == FWKNOP_CLI_ARG_GPG_SIGNER)
1043 : : {
1044 : 10 : strlcpy(options->gpg_signer_key, val, sizeof(options->gpg_signer_key));
1045 : : }
1046 : : /* GPG Homedir */
1047 [ + + ]: 3021 : else if (var->pos == FWKNOP_CLI_ARG_GPG_HOMEDIR)
1048 : : {
1049 : 11 : strlcpy(options->gpg_home_dir, val, sizeof(options->gpg_home_dir));
1050 : : }
1051 : : /* GPG path */
1052 [ + + ]: 3010 : else if (var->pos == FWKNOP_CLI_ARG_GPG_EXE_PATH)
1053 : : {
1054 : 1 : strlcpy(options->gpg_exe, val, sizeof(options->gpg_exe));
1055 : : }
1056 : : /* Spoof User */
1057 [ + + ]: 3009 : else if (var->pos == FWKNOP_CLI_ARG_SPOOF_USER)
1058 : : {
1059 : 7 : strlcpy(options->spoof_user, val, sizeof(options->spoof_user));
1060 : : }
1061 : : /* Spoof Source IP */
1062 [ + + ]: 3002 : else if (var->pos == FWKNOP_CLI_ARG_SPOOF_SOURCE_IP)
1063 : : {
1064 : 4 : strlcpy(options->spoof_ip_src_str, val, sizeof(options->spoof_ip_src_str));
1065 : : }
1066 : : /* ACCESS request */
1067 [ + + ]: 2998 : else if (var->pos == FWKNOP_CLI_ARG_ACCESS)
1068 : : {
1069 : 7 : strlcpy(options->access_str, val, sizeof(options->access_str));
1070 : : }
1071 : : /* SPA Server (destination) */
1072 [ + + ]: 2991 : else if (var->pos == FWKNOP_CLI_ARG_SPA_SERVER)
1073 : : {
1074 : 7 : strlcpy(options->spa_server_str, val, sizeof(options->spa_server_str));
1075 : : }
1076 : : /* Rand port ? */
1077 [ + + ]: 2984 : else if (var->pos == FWKNOP_CLI_ARG_RAND_PORT)
1078 : : {
1079 [ + - ]: 1 : if (is_yes_str(val))
1080 : 1 : options->rand_port = 1;
1081 : : else;
1082 : : }
1083 : : /* Rijndael key */
1084 [ + + ]: 2983 : else if (var->pos == FWKNOP_CLI_ARG_KEY_RIJNDAEL)
1085 : : {
1086 : 137 : strlcpy(options->key, val, sizeof(options->key));
1087 : 137 : options->have_key = 1;
1088 : : }
1089 : : /* Rijndael key (base-64 encoded) */
1090 [ + + ]: 2846 : else if (var->pos == FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64)
1091 : : {
1092 [ + + ]: 985 : if (! is_base64((unsigned char *) val, strlen(val)))
1093 : : {
1094 : 2 : log_msg(LOG_VERBOSITY_WARNING,
1095 : : "KEY_BASE64 argument '%s' doesn't look like base64-encoded data.",
1096 : : val);
1097 : 2 : parse_error = -1;
1098 : : }
1099 : 985 : strlcpy(options->key_base64, val, sizeof(options->key_base64));
1100 : 985 : options->have_base64_key = 1;
1101 : : }
1102 : : /* GnuPG signing passphrase */
1103 [ + + ]: 1861 : else if (var->pos == FWKNOP_CLI_ARG_GPG_SIGNING_PW)
1104 : : {
1105 : 2 : strlcpy(options->key, val, sizeof(options->key));
1106 : 2 : options->have_key = 1;
1107 : : }
1108 : : /* GnuPG signing passphrase (base-64 encoded) */
1109 [ + + ]: 1859 : else if (var->pos == FWKNOP_CLI_ARG_GPG_SIGNING_PW_BASE64)
1110 : : {
1111 [ + + ]: 2 : if (! is_base64((unsigned char *) val, strlen(val)))
1112 : : {
1113 : 1 : log_msg(LOG_VERBOSITY_WARNING,
1114 : : "GPG_SIGNING_KEY_BASE64 argument '%s' doesn't look like base64-encoded data.",
1115 : : val);
1116 : 1 : parse_error = -1;
1117 : : }
1118 : 2 : strlcpy(options->key_base64, val, sizeof(options->key_base64));
1119 : 2 : options->have_base64_key = 1;
1120 : : }
1121 : : /* HMAC digest type */
1122 [ + + ]: 1857 : else if (var->pos == FWKNOP_CLI_ARG_HMAC_DIGEST_TYPE)
1123 : : {
1124 : 763 : tmpint = hmac_digest_strtoint(val);
1125 [ + + ]: 763 : if(tmpint < 0)
1126 : : {
1127 : 1 : log_msg(LOG_VERBOSITY_WARNING,
1128 : : "HMAC_DIGEST_TYPE argument '%s' must be one of {md5,sha1,sha256,sha384,sha512,sha3_256,sha3_512}",
1129 : : val);
1130 : 1 : parse_error = -1;
1131 : : }
1132 : : else
1133 : : {
1134 : 762 : options->hmac_type = tmpint;
1135 : : }
1136 : : }
1137 : : /* HMAC key (base64 encoded) */
1138 [ + + ]: 1094 : else if (var->pos == FWKNOP_CLI_ARG_KEY_HMAC_BASE64)
1139 : : {
1140 [ + + ]: 997 : if (! is_base64((unsigned char *) val, strlen(val)))
1141 : : {
1142 : 1 : log_msg(LOG_VERBOSITY_WARNING,
1143 : : "HMAC_KEY_BASE64 argument '%s' doesn't look like base64-encoded data.",
1144 : : val);
1145 : 1 : parse_error = -1;
1146 : : }
1147 : 997 : strlcpy(options->hmac_key_base64, val, sizeof(options->hmac_key_base64));
1148 : 997 : options->have_hmac_base64_key = 1;
1149 : 997 : options->use_hmac = 1;
1150 : : }
1151 : :
1152 : : /* HMAC key */
1153 [ + + ]: 97 : else if (var->pos == FWKNOP_CLI_ARG_KEY_HMAC)
1154 : : {
1155 : 50 : strlcpy(options->hmac_key, val, sizeof(options->hmac_key));
1156 : 50 : options->have_hmac_key = 1;
1157 : 50 : options->use_hmac = 1;
1158 : : }
1159 : :
1160 : : /* --use-hmac */
1161 [ + + ]: 47 : else if (var->pos == FWKNOP_CLI_ARG_USE_HMAC)
1162 : : {
1163 [ + - ]: 8 : if (is_yes_str(val))
1164 : 8 : options->use_hmac = 1;
1165 : : }
1166 : : /* --use-wget-user-agent */
1167 [ + + ]: 39 : else if (var->pos == FWKNOP_CLI_ARG_USE_WGET_USER_AGENT)
1168 : : {
1169 [ + - ]: 1 : if (is_yes_str(val))
1170 : 1 : options->use_wget_user_agent = 1;
1171 : : }
1172 : : /* Key file */
1173 [ + + ]: 38 : else if (var->pos == FWKNOP_CLI_ARG_KEY_FILE)
1174 : : {
1175 : 1 : strlcpy(options->get_key_file, val, sizeof(options->get_key_file));
1176 : : }
1177 : : /* HMAC key file */
1178 [ + + ]: 37 : else if (var->pos == FWKNOP_CLI_ARG_HMAC_KEY_FILE)
1179 : : {
1180 : 1 : strlcpy(options->get_key_file, val,
1181 : : sizeof(options->get_hmac_key_file));
1182 : : }
1183 : : /* NAT Access Request */
1184 [ + + ]: 36 : else if (var->pos == FWKNOP_CLI_ARG_NAT_ACCESS)
1185 : : {
1186 : 1 : strlcpy(options->nat_access_str, val, sizeof(options->nat_access_str));
1187 : : }
1188 : : /* HTTP User Agent */
1189 [ + + ]: 35 : else if (var->pos == FWKNOP_CLI_ARG_HTTP_USER_AGENT)
1190 : : {
1191 : 3 : strlcpy(options->http_user_agent, val, sizeof(options->http_user_agent));
1192 : : }
1193 : : /* Resolve URL */
1194 [ + + ]: 32 : else if (var->pos == FWKNOP_CLI_ARG_RESOLVE_URL)
1195 : : {
1196 [ - + ]: 3 : if(options->resolve_url != NULL)
1197 : 0 : free(options->resolve_url);
1198 : 3 : tmpint = strlen(val)+1;
1199 : 3 : options->resolve_url = calloc(1, tmpint);
1200 [ - + ]: 3 : if(options->resolve_url == NULL)
1201 : : {
1202 : 0 : log_msg(LOG_VERBOSITY_ERROR,"Memory allocation error for resolve URL.");
1203 : 0 : exit(EXIT_FAILURE);
1204 : : }
1205 : 3 : strlcpy(options->resolve_url, val, tmpint);
1206 : : }
1207 : : /* Resolve the SPA server (via DNS) - accept IPv4 addresses only ? */
1208 [ + + ]: 29 : else if (var->pos == FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4)
1209 : : {
1210 [ + - ]: 1 : if (is_yes_str(val))
1211 : : {
1212 : 1 : options->spa_server_resolve_ipv4 = 1;
1213 : : }
1214 : : }
1215 : : /* wget command */
1216 [ + + ]: 28 : else if (var->pos == FWKNOP_CLI_ARG_WGET_CMD)
1217 : : {
1218 [ - + ]: 2 : if(options->wget_bin != NULL)
1219 : 0 : free(options->wget_bin);
1220 : 2 : tmpint = strlen(val)+1;
1221 : 2 : options->wget_bin = calloc(1, tmpint);
1222 [ - + ]: 2 : if(options->wget_bin == NULL)
1223 : : {
1224 : 0 : log_msg(LOG_VERBOSITY_ERROR,"Memory allocation error for wget command path.");
1225 : 0 : exit(EXIT_FAILURE);
1226 : : }
1227 : 2 : strlcpy(options->wget_bin, val, tmpint);
1228 : : }
1229 : : /* NAT Local ? */
1230 [ + + ]: 26 : else if (var->pos == FWKNOP_CLI_ARG_NAT_LOCAL)
1231 : : {
1232 [ + - ]: 2 : if (is_yes_str(val))
1233 : 2 : options->nat_local = 1;
1234 : : else;
1235 : : }
1236 : : /* NAT rand port ? */
1237 [ + + ]: 24 : else if (var->pos == FWKNOP_CLI_ARG_NAT_RAND_PORT)
1238 : : {
1239 [ + + ]: 2 : if (is_yes_str(val))
1240 : 1 : options->nat_rand_port = 1;
1241 : : else;
1242 : : }
1243 : : /* NAT port */
1244 [ + + ]: 22 : else if (var->pos == FWKNOP_CLI_ARG_NAT_PORT)
1245 : : {
1246 : 6 : tmpint = strtol_wrapper(val, 0, MAX_PORT, NO_EXIT_UPON_ERR, &is_err);
1247 [ + - ]: 6 : if(is_err == FKO_SUCCESS)
1248 : 6 : options->nat_port = tmpint;
1249 : : else
1250 : : parse_error = -1;
1251 : : }
1252 : : /* VERBOSE level */
1253 [ + + ]: 16 : else if (var->pos == FWKNOP_CLI_ARG_VERBOSE)
1254 : : {
1255 [ + + ]: 8 : if (is_yes_str(val))
1256 : 6 : options->verbose = 1;
1257 : : else
1258 : : {
1259 : 2 : tmpint = strtol_wrapper(val, 0, LOG_LAST_VERBOSITY - 1, NO_EXIT_UPON_ERR, &is_err);
1260 [ + + ]: 2 : if(is_err == FKO_SUCCESS)
1261 : 1 : options->verbose = tmpint;
1262 : : else
1263 : : parse_error = -1;
1264 : : }
1265 : :
1266 [ + + ]: 8 : if (parse_error == 0)
1267 : 7 : log_set_verbosity(LOG_DEFAULT_VERBOSITY + options->verbose);
1268 : : }
1269 : : /* RESOLVE_IP_HTTPS ? */
1270 [ + + ]: 8 : else if (var->pos == FWKNOP_CLI_ARG_RESOLVE_IP_HTTPS)
1271 : : {
1272 [ + - ]: 2 : if (is_yes_str(val))
1273 : 2 : options->resolve_ip_http_https = 1;
1274 : : else;
1275 : : }
1276 : : /* RESOLVE_IP_HTTP ? This actually results in HTTPS resolution by default
1277 : : * unless --resolve-http-only is also given
1278 : : */
1279 [ + + ]: 6 : else if (var->pos == FWKNOP_CLI_ARG_RESOLVE_IP_HTTP)
1280 : : {
1281 [ + + ]: 5 : if (is_yes_str(val))
1282 : 1 : options->resolve_ip_http_https = 1;
1283 : : else;
1284 : : }
1285 : : /* RESOLVE_HTTP_ONLY ? Force HTTP instead of HTTPS IP resolution.
1286 : : */
1287 [ + - ]: 1 : else if (var->pos == FWKNOP_CLI_ARG_RESOLVE_HTTP_ONLY)
1288 : : {
1289 [ + - ]: 1 : if (is_yes_str(val))
1290 : 1 : options->resolve_http_only = 1;
1291 : : else;
1292 : : }
1293 : : /* avoid saving .fwknop.run by default */
1294 [ # # ]: 0 : else if (var->pos == FWKNOP_CLI_ARG_NO_SAVE_ARGS)
1295 : : {
1296 [ # # ]: 0 : if (is_yes_str(val))
1297 : 0 : options->no_save_args = 1;
1298 : : else;
1299 : : }
1300 : : /* The variable is not a configuration variable */
1301 : : else
1302 : : {
1303 : : parse_error = -1;
1304 : : }
1305 : :
1306 : 3198 : return(parse_error);
1307 : : }
1308 : :
1309 : : /**
1310 : : * @brief Write a cli parameter to a file handle
1311 : : *
1312 : : * This function writes into a file handle a command line parameter
1313 : : *
1314 : : * @param fhandle File handle to write the new parameter to
1315 : : * @param var_pos Variable position
1316 : : * @param options FKO command line option structure
1317 : : */
1318 : : static void
1319 : 616 : add_single_var_to_rc(FILE* fhandle, short var_pos, fko_cli_options_t *options)
1320 : : {
1321 : 616 : char val[MAX_LINE_LEN] = {0};
1322 : : fko_var_t *var;
1323 : :
1324 : 616 : var = lookup_var_by_position(var_pos);
1325 : :
1326 [ + - ]: 616 : if (var == NULL)
1327 : 0 : return;
1328 : :
1329 [ + - ]: 616 : if (fhandle == NULL)
1330 : : return;
1331 : :
1332 : : /* Select the argument to add and store its string value into val */
1333 [ + + + + : 616 : switch (var->pos)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + - +
+ + + + -
+ + + - ]
1334 : : {
1335 : : case FWKNOP_CLI_ARG_DIGEST_TYPE :
1336 : 12 : digest_inttostr(options->digest_type, val, sizeof(val));
1337 : 12 : break;
1338 : : case FWKNOP_CLI_ARG_SPA_SERVER_PROTO :
1339 : 6 : proto_inttostr(options->spa_proto, val, sizeof(val));
1340 : 6 : break;
1341 : : case FWKNOP_CLI_ARG_SPA_SERVER_PORT :
1342 : 1 : snprintf(val, sizeof(val)-1, "%d", options->spa_dst_port);
1343 : : break;
1344 : : case FWKNOP_CLI_ARG_SPA_SOURCE_PORT :
1345 : 1 : snprintf(val, sizeof(val)-1, "%d", options->spa_src_port);
1346 : : break;
1347 : : case FWKNOP_CLI_ARG_FW_TIMEOUT :
1348 : 13 : snprintf(val, sizeof(val)-1, "%d", options->fw_timeout);
1349 : : break;
1350 : : case FWKNOP_CLI_ARG_ALLOW_IP :
1351 : 78 : strlcpy(val, options->allow_ip_str, sizeof(val));
1352 : 78 : break;
1353 : : case FWKNOP_CLI_ARG_TIME_OFFSET :
1354 [ + + ]: 4 : if (options->time_offset_minus != 0)
1355 : 1 : snprintf(val, sizeof(val)-1, "-%d", options->time_offset_minus);
1356 [ + - ]: 3 : else if (options->time_offset_plus != 0)
1357 : 3 : snprintf(val, sizeof(val)-1, "%d", options->time_offset_plus);
1358 : : else;
1359 : : break;
1360 : : case FWKNOP_CLI_ARG_ENCRYPTION_MODE :
1361 : 2 : enc_mode_inttostr(options->encryption_mode, val, sizeof(val));
1362 : 2 : break;
1363 : : case FWKNOP_CLI_ARG_USE_GPG :
1364 : 7 : bool_to_yesno(options->use_gpg, val, sizeof(val));
1365 : 7 : break;
1366 : : case FWKNOP_CLI_ARG_USE_GPG_AGENT :
1367 : 1 : bool_to_yesno(options->use_gpg_agent, val, sizeof(val));
1368 : 1 : break;
1369 : : case FWKNOP_CLI_ARG_GPG_RECIPIENT :
1370 : 7 : strlcpy(val, options->gpg_recipient_key, sizeof(val));
1371 : 7 : break;
1372 : : case FWKNOP_CLI_ARG_GPG_SIGNER :
1373 : 7 : strlcpy(val, options->gpg_signer_key, sizeof(val));
1374 : 7 : break;
1375 : : case FWKNOP_CLI_ARG_GPG_HOMEDIR :
1376 : 7 : strlcpy(val, options->gpg_home_dir, sizeof(val));
1377 : 7 : break;
1378 : : case FWKNOP_CLI_ARG_GPG_EXE_PATH :
1379 : 1 : strlcpy(val, options->gpg_exe, sizeof(val));
1380 : 1 : break;
1381 : : case FWKNOP_CLI_ARG_GPG_NO_SIGNING_PW :
1382 : 7 : bool_to_yesno(options->gpg_no_signing_pw, val, sizeof(val));
1383 : 7 : break;
1384 : : case FWKNOP_CLI_ARG_SPOOF_USER :
1385 : 3 : strlcpy(val, options->spoof_user, sizeof(val));
1386 : 3 : break;
1387 : : case FWKNOP_CLI_ARG_SPOOF_SOURCE_IP :
1388 : 1 : strlcpy(val, options->spoof_ip_src_str, sizeof(val));
1389 : 1 : break;
1390 : : case FWKNOP_CLI_ARG_ACCESS :
1391 : 90 : strlcpy(val, options->access_str, sizeof(val));
1392 : 90 : break;
1393 : : case FWKNOP_CLI_ARG_SPA_SERVER :
1394 : 91 : strlcpy(val, options->spa_server_str, sizeof(val));
1395 : 91 : break;
1396 : : case FWKNOP_CLI_ARG_RAND_PORT :
1397 : 1 : bool_to_yesno(options->rand_port, val, sizeof(val));
1398 : 1 : break;
1399 : : case FWKNOP_CLI_ARG_KEY_FILE :
1400 : 9 : strlcpy(val, options->get_key_file, sizeof(val));
1401 : 9 : break;
1402 : : case FWKNOP_CLI_ARG_HMAC_KEY_FILE :
1403 : 2 : strlcpy(val, options->get_hmac_key_file, sizeof(val));
1404 : 2 : break;
1405 : : case FWKNOP_CLI_ARG_KEY_RIJNDAEL:
1406 : 1 : strlcpy(val, options->key, sizeof(val));
1407 : 1 : break;
1408 : : case FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64:
1409 : 10 : strlcpy(val, options->key_base64, sizeof(val));
1410 : 10 : break;
1411 : : case FWKNOP_CLI_ARG_KEY_HMAC_BASE64:
1412 : 11 : strlcpy(val, options->hmac_key_base64, sizeof(val));
1413 : 11 : break;
1414 : : case FWKNOP_CLI_ARG_KEY_HMAC:
1415 : 1 : strlcpy(val, options->hmac_key, sizeof(val));
1416 : 1 : break;
1417 : : case FWKNOP_CLI_ARG_HMAC_DIGEST_TYPE :
1418 : 10 : hmac_digest_inttostr(options->hmac_type, val, sizeof(val));
1419 : 10 : break;
1420 : : case FWKNOP_CLI_ARG_USE_HMAC :
1421 : 18 : bool_to_yesno(options->use_hmac, val, sizeof(val));
1422 : 18 : break;
1423 : : case FWKNOP_CLI_ARG_USE_WGET_USER_AGENT :
1424 : 1 : bool_to_yesno(options->use_wget_user_agent, val, sizeof(val));
1425 : 1 : break;
1426 : : case FWKNOP_CLI_ARG_NAT_ACCESS :
1427 : 11 : strlcpy(val, options->nat_access_str, sizeof(val));
1428 : 11 : break;
1429 : : case FWKNOP_CLI_ARG_HTTP_USER_AGENT :
1430 : 1 : strlcpy(val, options->http_user_agent, sizeof(val));
1431 : 1 : break;
1432 : : case FWKNOP_CLI_ARG_RESOLVE_URL :
1433 [ + - ]: 8 : if (options->resolve_url != NULL)
1434 : 8 : strlcpy(val, options->resolve_url, sizeof(val));
1435 : : else;
1436 : : break;
1437 : : case FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4:
1438 : 0 : bool_to_yesno(options->spa_server_resolve_ipv4, val, sizeof(val));
1439 : 0 : break;
1440 : : case FWKNOP_CLI_ARG_NAT_LOCAL :
1441 : 2 : bool_to_yesno(options->nat_local, val, sizeof(val));
1442 : 2 : break;
1443 : : case FWKNOP_CLI_ARG_NAT_RAND_PORT :
1444 : 1 : bool_to_yesno(options->nat_rand_port, val, sizeof(val));
1445 : 1 : break;
1446 : : case FWKNOP_CLI_ARG_NAT_PORT :
1447 : 6 : snprintf(val, sizeof(val)-1, "%d", options->nat_port);
1448 : : break;
1449 : : case FWKNOP_CLI_ARG_VERBOSE:
1450 [ + + ]: 83 : if((options->verbose == 0) || (options->verbose == 1))
1451 : 1 : bool_to_yesno(options->verbose, val, sizeof(val));
1452 : : else
1453 : 82 : snprintf(val, sizeof(val)-1, "%d", options->verbose);
1454 : : break;
1455 : : case FWKNOP_CLI_ARG_RESOLVE_IP_HTTPS:
1456 : 14 : bool_to_yesno(options->resolve_ip_http_https, val, sizeof(val));
1457 : 14 : break;
1458 : : case FWKNOP_CLI_ARG_RESOLVE_IP_HTTP:
1459 : 0 : bool_to_yesno(options->resolve_ip_http_https, val, sizeof(val));
1460 : 0 : break;
1461 : : case FWKNOP_CLI_ARG_RESOLVE_HTTP_ONLY:
1462 : 1 : bool_to_yesno(options->resolve_http_only, val, sizeof(val));
1463 : 1 : break;
1464 : : case FWKNOP_CLI_ARG_WGET_CMD :
1465 [ + - ]: 2 : if (options->wget_bin != NULL)
1466 : 2 : strlcpy(val, options->wget_bin, sizeof(val));
1467 : : break;
1468 : : case FWKNOP_CLI_ARG_NO_SAVE_ARGS :
1469 : 84 : bool_to_yesno(options->no_save_args, val, sizeof(val));
1470 : 84 : break;
1471 : : default:
1472 : 0 : log_msg(LOG_VERBOSITY_WARNING,
1473 : : "Warning from add_single_var_to_rc() : Bad variable position %u",
1474 : : var->pos);
1475 : 0 : return;
1476 : : }
1477 : :
1478 : 616 : log_msg(LOG_VERBOSITY_DEBUG,
1479 : : "add_single_var_to_rc() : Updating param (%u) %s to %s",
1480 : 616 : var->pos, var->name, val);
1481 : :
1482 : 616 : fprintf(fhandle, RC_PARAM_TEMPLATE, var->name, val);
1483 : : }
1484 : :
1485 : : /**
1486 : : * @brief Add configuration variables in a file
1487 : : *
1488 : : * The parameters are selected by a bitmask and extracted from the
1489 : : * fko_cli_options_t structure.
1490 : : *
1491 : : * @param rc File handle on the file to write to
1492 : : * @param options fko_cli_options_t structure containing the values of the parameters
1493 : : * @param bitmask Bitmask used to select the parameters to add
1494 : : */
1495 : : static void
1496 : 91 : add_multiple_vars_to_rc(FILE* rc, fko_cli_options_t *options, fko_var_bitmask_t *bitmask)
1497 : : {
1498 : 91 : short ndx = 0; /* Index of a configuration variable in fko_var_array table */
1499 : : short position; /* Position of the configuration variable */
1500 : :
1501 [ + + ]: 4095 : for (ndx=0 ; ndx<ARRAY_SIZE(fko_var_array) ; ndx++)
1502 : : {
1503 : 4004 : position = fko_var_array[ndx].pos;
1504 [ + + ]: 4004 : if (bitmask_has_var(position, bitmask))
1505 : 616 : add_single_var_to_rc(rc, position, options);
1506 : : }
1507 : 91 : }
1508 : :
1509 : : /**
1510 : : * @brief Process the fwknoprc file and lookup a section to extract its settings.
1511 : : *
1512 : : * This function aims at loading the settings for a specific section in
1513 : : * a fwknoprc file.
1514 : : *
1515 : : * @param section_name Name of the section to lookup.
1516 : : * @param options Fwknop option structure where settings have to
1517 : : * be stored.
1518 : : *
1519 : : * @return 0 if the section has been found and processed successfully
1520 : : * a negative value if one or more errors occurred
1521 : : */
1522 : : static int
1523 : 2822 : process_rc_section(char *section_name, fko_cli_options_t *options)
1524 : : {
1525 : : FILE *rc;
1526 : 2822 : int line_num = 0, do_exit = 0;
1527 : 2822 : char line[MAX_LINE_LEN] = {0};
1528 : 2822 : char rcfile[MAX_PATH_LEN] = {0};
1529 : 2822 : char curr_stanza[MAX_LINE_LEN] = {0};
1530 : : rc_file_param_t param;
1531 : 2822 : int rc_section_found = 0;
1532 : :
1533 : 2822 : set_rc_file(rcfile, options);
1534 : :
1535 : : /* Open the rc file for reading, if it does not exist, then create
1536 : : * an initial .fwknoprc file with defaults and go on.
1537 : : */
1538 [ + + ]: 2821 : if ((rc = fopen(rcfile, "r")) == NULL)
1539 : : {
1540 [ + + ]: 15 : if(errno == ENOENT)
1541 : : {
1542 : 1 : if(create_fwknoprc(rcfile) != 0)
1543 : : return -1;
1544 : : }
1545 : : else
1546 : 14 : log_msg(LOG_VERBOSITY_WARNING, "Unable to open rc file: %s: %s",
1547 : : rcfile, strerror(errno));
1548 : :
1549 : : return -1;
1550 : : }
1551 : :
1552 : 2806 : log_msg(LOG_VERBOSITY_DEBUG, "process_rc_section() : Parsing section '%s' ...",
1553 : : section_name);
1554 : :
1555 [ + + ]: 136369 : while ((fgets(line, MAX_LINE_LEN, rc)) != NULL)
1556 : : {
1557 : 130758 : line_num++;
1558 : 130758 : line[MAX_LINE_LEN-1] = '\0';
1559 : :
1560 : : /* Get past comments and empty lines (note: we only look at the
1561 : : * first character.
1562 : : */
1563 [ + + ][ + - ]: 130758 : if(IS_EMPTY_LINE(line[0]))
[ + - ][ - + ]
1564 : 120354 : continue;
1565 : :
1566 : : /* Check which section we are working on */
1567 [ + + ]: 10404 : if (is_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)))
1568 : : {
1569 : 4185 : rc_section_found = (strcasecmp(curr_stanza, section_name) == 0) ? 1 : 0;
1570 : :
1571 [ + + ]: 4185 : if (strcasecmp(curr_stanza, options->use_rc_stanza) == 0)
1572 : 667 : options->got_named_stanza = 1;
1573 : :
1574 : 4185 : continue;
1575 : : }
1576 : :
1577 : : /* We are not in the good section */
1578 [ + + ]: 6219 : else if (rc_section_found == 0)
1579 : 3020 : continue;
1580 : :
1581 : : /* We have not found a valid parameter */
1582 [ + + ]: 3199 : else if (is_rc_param(line, ¶m) == 0)
1583 : : {
1584 : : do_exit = 1; /* We don't allow improperly formatted lines */
1585 : : break;
1586 : : }
1587 : :
1588 : : /* We have a valid parameter */
1589 : : else
1590 : : {
1591 [ + + ]: 3198 : if(parse_rc_param(options, param.name, param.val) < 0)
1592 : : {
1593 : 14 : log_msg(LOG_VERBOSITY_WARNING,
1594 : : "Parameter error in %s, line %i: var=%s, val=%s",
1595 : : rcfile, line_num, param.name, param.val);
1596 : 130757 : do_exit = 1;
1597 : : }
1598 : : }
1599 : : }
1600 : :
1601 : 2806 : fclose(rc);
1602 : :
1603 [ + + ]: 2806 : if (do_exit)
1604 : 15 : exit(EXIT_FAILURE);
1605 : :
1606 : : return 0;
1607 : : }
1608 : :
1609 : : /**
1610 : : * @brief Update the user rc file with the new parameters for a selected stanza.
1611 : : *
1612 : : * This function writes the new configuration in a temporary file and renames it
1613 : : * as the new rc file afterwards. All of the previous parameters for the
1614 : : * selected stanza are removed and replaced by the arguments from the command
1615 : : * line.
1616 : : *
1617 : : * @param options structure containing all of the fko settings
1618 : : * @param args_bitmask command line argument bitmask
1619 : : */
1620 : : static void
1621 : 91 : update_rc(fko_cli_options_t *options, fko_var_bitmask_t *bitmask)
1622 : : {
1623 : : FILE *rc;
1624 : : FILE *rc_update;
1625 : 91 : int rcfile_fd = -1;
1626 : 91 : int stanza_found = 0;
1627 : 91 : int stanza_updated = 0;
1628 : 91 : char line[MAX_LINE_LEN] = {0};
1629 : 91 : char rcfile[MAX_PATH_LEN] = {0};
1630 : 91 : char rcfile_update[MAX_PATH_LEN] = {0};
1631 : 91 : char curr_stanza[MAX_LINE_LEN] = {0};
1632 : : rc_file_param_t param; /* Structure to contain a conf. variable name with its value */
1633 : : fko_var_t *var;
1634 : :
1635 : 91 : set_rc_file(rcfile, options);
1636 : :
1637 : 91 : strlcpy(rcfile_update, rcfile, sizeof(rcfile_update));
1638 : 91 : strlcat(rcfile_update, ".updated", sizeof(rcfile_update));
1639 : :
1640 : : /* Create a new temporary rc file */
1641 : 91 : rcfile_fd = open(rcfile_update, FWKNOPRC_OFLAGS, FWKNOPRC_MODE);
1642 [ - + ]: 91 : if (rcfile_fd == -1)
1643 : : {
1644 : 0 : log_msg(LOG_VERBOSITY_WARNING,
1645 : : "update_rc() : Unable to create temporary rc file: %s: %s",
1646 : 0 : rcfile_update, strerror(errno));
1647 : 0 : return;
1648 : : }
1649 : 91 : close(rcfile_fd);
1650 : :
1651 : : /* Open the current rcfile and a temporary one respectively in read and
1652 : : * write mode */
1653 [ - + ]: 91 : if ((rc = fopen(rcfile, "r")) == NULL)
1654 : : {
1655 : 0 : log_msg(LOG_VERBOSITY_WARNING,
1656 : : "update_rc() : Unable to open rc file: %s: %s",
1657 : 0 : rcfile, strerror(errno));
1658 : 0 : return;
1659 : : }
1660 : :
1661 [ + - ]: 91 : if ((rc_update = fopen(rcfile_update, "w")) == NULL)
1662 : : {
1663 : 0 : log_msg(LOG_VERBOSITY_WARNING,
1664 : : "update_rc() : Unable to open rc file: %s: %s",
1665 : 0 : rcfile_update, strerror(errno));
1666 : 0 : fclose(rc);
1667 : 0 : return;
1668 : : }
1669 : :
1670 : : /* Go through the file line by line */
1671 : : stanza_found = 0;
1672 [ + + ]: 443 : while ((fgets(line, MAX_LINE_LEN, rc)) != NULL)
1673 : : {
1674 : 352 : line[MAX_LINE_LEN-1] = '\0';
1675 : :
1676 : : /* Get past comments and empty lines (note: we only look at the
1677 : : * first character.
1678 : : */
1679 [ + - ][ + - ]: 352 : if(IS_EMPTY_LINE(line[0]))
[ + - ][ - + ]
1680 : 0 : continue;
1681 : :
1682 : : /* If we find a section... */
1683 [ + + ]: 352 : if(is_rc_section(line, strlen(line), curr_stanza, sizeof(curr_stanza)) == 1)
1684 : : {
1685 : : /* and we have already parsed the section we wanted to save, we
1686 : : * can update our parameters */
1687 [ + + ]: 94 : if (stanza_found)
1688 : : {
1689 : 1 : log_msg(LOG_VERBOSITY_DEBUG, "update_rc() : Updating %s stanza", options->use_rc_stanza);
1690 : 1 : add_multiple_vars_to_rc(rc_update, options, bitmask);
1691 : : fprintf(rc_update, "\n");
1692 : 1 : stanza_found = 0;
1693 : 1 : stanza_updated = 1;
1694 : : }
1695 : :
1696 : : /* and this is the one we are looking for, we set the stanza
1697 : : * as found */
1698 [ + + ]: 93 : else if (strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN) == 0)
1699 : : stanza_found = 1;
1700 : :
1701 : : /* otherwise we disable the stanza */
1702 : : else
1703 : 10 : stanza_found = 0;
1704 : : }
1705 : :
1706 : : /* If we are processing a parameter for our stanza */
1707 [ + + ]: 258 : else if (stanza_found)
1708 : : {
1709 : : /* and the user has specified a force option, there is no need to
1710 : : * check for critical variables */
1711 [ + + ]: 219 : if (options->force_save_rc_stanza)
1712 : 209 : continue;
1713 : :
1714 : : /* ask the user what to do with the critical var found in the
1715 : : * rcfile */
1716 [ + - ]: 10 : else if (is_rc_param(line, ¶m))
1717 : : {
1718 [ + - ]: 10 : if ( ((var=lookup_var_by_name(param.name)) != NULL)
1719 [ + + ]: 10 : && var_is_critical(var->pos) )
1720 : : {
1721 [ + + ]: 5 : if (ask_overwrite_var(var->name, curr_stanza))
1722 : 4 : continue;
1723 : : else
1724 : 1 : remove_var_from_bitmask(var->pos, bitmask);
1725 : : }
1726 : : else
1727 : 5 : continue;
1728 : : }
1729 : : else
1730 : : {
1731 : : /* is_rc_param() returns false only when there is an
1732 : : * improperly formatted line - bail
1733 : : */
1734 : 0 : fclose(rc);
1735 : 0 : fclose(rc_update);
1736 : 0 : return;
1737 : : }
1738 : : }
1739 : :
1740 : : /* We're not processing any important variables from our stanza and no new
1741 : : * stanza */
1742 : : else;
1743 : :
1744 : : /* Add the line to the new rcfile */
1745 : : fprintf(rc_update, "%s", line);
1746 : : }
1747 : :
1748 : : /* The configuration has not been updated yet */
1749 [ + + ]: 91 : if (stanza_updated == 0)
1750 : : {
1751 : : /* but the stanza has been found, We update it now. */
1752 [ + + ]: 90 : if (stanza_found == 1)
1753 : 82 : log_msg(LOG_VERBOSITY_DEBUG, "update_rc() : Updating %s stanza",
1754 : 82 : options->use_rc_stanza);
1755 : :
1756 : : /* otherwise we append the new settings to the file */
1757 : : else
1758 : : {
1759 : : fprintf(rc_update, "\n");
1760 : 8 : log_msg(LOG_VERBOSITY_DEBUG, "update_rc() : Inserting new %s stanza",
1761 : 8 : options->use_rc_stanza);
1762 : 8 : fprintf(rc_update, RC_SECTION_TEMPLATE, options->use_rc_stanza);
1763 : : }
1764 : :
1765 : 90 : add_multiple_vars_to_rc(rc_update, options, bitmask);
1766 : : }
1767 : :
1768 : : /* otherwise we have already done everything. Nothing to do. */
1769 : : else;
1770 : :
1771 : : /* Close file handles */
1772 : 91 : fclose(rc);
1773 : 91 : fclose(rc_update);
1774 : :
1775 : : /* Renamed the temporary file as the new rc file */
1776 [ - + ]: 91 : if (remove(rcfile) != 0)
1777 : : {
1778 : 0 : log_msg(LOG_VERBOSITY_WARNING,
1779 : : "update_rc() : Unable to remove %s to %s : %s",
1780 : 0 : rcfile_update, rcfile, strerror(errno));
1781 : : }
1782 : :
1783 [ - + ]: 91 : if (rename(rcfile_update, rcfile) != 0)
1784 : : {
1785 : 91 : log_msg(LOG_VERBOSITY_WARNING,
1786 : : "update_rc() : Unable to rename %s to %s",
1787 : : rcfile_update, rcfile);
1788 : : }
1789 : : }
1790 : :
1791 : : /* Sanity and bounds checks for the various options.
1792 : : */
1793 : : static void
1794 : 2496 : validate_options(fko_cli_options_t *options)
1795 : : {
1796 [ + + ]: 2496 : if ( (options->use_rc_stanza[0] != 0x0)
1797 : : && (options->got_named_stanza == 0)
1798 [ + + ]: 372 : && (options->save_rc_stanza == 0) )
1799 : : {
1800 : 1 : log_msg(LOG_VERBOSITY_ERROR,
1801 : : "Named configuration stanza: [%s] was not found.",
1802 : 1 : options->use_rc_stanza);
1803 : 1 : exit(EXIT_FAILURE);
1804 : : }
1805 : :
1806 [ + + ][ + + ]: 2495 : if ( (options->save_rc_stanza == 1) && (options->use_rc_stanza[0] == 0) )
1807 : : {
1808 : : /* Set the stanza name to the -D arg value
1809 : : */
1810 [ + + ]: 9 : if (options->spa_server_str[0] == 0x0)
1811 : : {
1812 : 2 : log_msg(LOG_VERBOSITY_ERROR,
1813 : : "Must use --destination unless --test mode is used");
1814 : 2 : exit(EXIT_FAILURE);
1815 : : }
1816 : :
1817 : 7 : strlcpy(options->use_rc_stanza, options->spa_server_str, sizeof(options->use_rc_stanza));
1818 : : }
1819 : :
1820 : : /* Must have a destination unless we are just testing or getting the
1821 : : * the version, and must use one of [-s|-R|-a].
1822 : : */
1823 [ + + ]: 2493 : if(!options->test
1824 [ + + ]: 2355 : && !options->key_gen
1825 [ + + ]: 2252 : && !options->version
1826 [ + + ]: 2251 : && !options->show_last_command
1827 [ + + ]: 2247 : && !options->run_last_command)
1828 : : {
1829 [ + + ]: 2243 : if (options->spa_server_str[0] == 0x0)
1830 : : {
1831 : 2 : log_msg(LOG_VERBOSITY_ERROR,
1832 : : "Must use --destination unless --test mode is used");
1833 : 2 : exit(EXIT_FAILURE);
1834 : : }
1835 : :
1836 [ + + ]: 2241 : if (options->resolve_url != NULL)
1837 : 22 : options->resolve_ip_http_https = 1;
1838 : :
1839 [ + + ]: 2241 : if (!options->resolve_ip_http_https)
1840 : : {
1841 [ + + ]: 2209 : if(options->allow_ip_str[0] == 0x0)
1842 : : {
1843 : 1 : log_msg(LOG_VERBOSITY_ERROR,
1844 : : "Must use one of [-s|-R|-a] to specify IP for SPA access.");
1845 : 1 : exit(EXIT_FAILURE);
1846 : : }
1847 [ + + ]: 2208 : else if(options->verbose
1848 [ + + ]: 2202 : && strncmp(options->allow_ip_str, "0.0.0.0", strlen("0.0.0.0")) == 0)
1849 : : {
1850 : 4 : log_msg(LOG_VERBOSITY_WARNING,
1851 : : "[-] WARNING: Should use -a or -R to harden SPA against potential MITM attacks");
1852 : : }
1853 : : }
1854 : : }
1855 : :
1856 : : /* Make sure -a overrides IP resolution
1857 : : */
1858 [ + + ]: 2490 : if(options->allow_ip_str[0] != 0x0
1859 [ + - ]: 2347 : && strncasecmp(options->allow_ip_str, "resolve", strlen("resolve")) != 0)
1860 : : {
1861 : 2347 : options->resolve_ip_http_https = 0;
1862 : :
1863 [ + + ]: 2347 : if(! is_valid_ipv4_addr(options->allow_ip_str, strlen(options->allow_ip_str)))
1864 : : {
1865 : 1 : log_msg(LOG_VERBOSITY_ERROR,
1866 : : "Invalid allow IP specified for SPA access");
1867 : 1 : exit(EXIT_FAILURE);
1868 : : }
1869 : : }
1870 : :
1871 [ + + ]: 2489 : if (options->spoof_ip_src_str[0] != 0x00)
1872 : : {
1873 [ + + ]: 10 : if(! is_valid_ipv4_addr(options->spoof_ip_src_str, strlen(options->spoof_ip_src_str)))
1874 : : {
1875 : 1 : log_msg(LOG_VERBOSITY_ERROR, "Invalid spoof IP");
1876 : 1 : exit(EXIT_FAILURE);
1877 : : }
1878 [ + + ]: 9 : if(options->spa_proto != FKO_PROTO_TCP_RAW
1879 : 9 : && options->spa_proto != FKO_PROTO_UDP_RAW
1880 [ + + ]: 3 : && options->spa_proto != FKO_PROTO_ICMP)
1881 : : {
1882 : 1 : log_msg(LOG_VERBOSITY_ERROR,
1883 : : "Must set -P <udpraw|tcpraw|icmp> with a spoofed source IP");
1884 : 1 : exit(EXIT_FAILURE);
1885 : : }
1886 : : }
1887 : :
1888 [ + + ][ + + ]: 2487 : if(options->resolve_ip_http_https || options->spa_proto == FKO_PROTO_HTTP)
1889 [ + + ]: 37 : if (options->http_user_agent[0] == '\0')
1890 : 32 : snprintf(options->http_user_agent, HTTP_MAX_USER_AGENT_LEN,
1891 : : "%s%s", "Fwknop/", MY_VERSION);
1892 : :
1893 [ + + ][ + + ]: 2487 : if(options->http_proxy[0] != 0x0 && options->spa_proto != FKO_PROTO_HTTP)
1894 : : {
1895 : 1 : log_msg(LOG_VERBOSITY_ERROR,
1896 : : "Cannot set --http-proxy with a non-HTTP protocol.");
1897 : 1 : exit(EXIT_FAILURE);
1898 : : }
1899 : :
1900 : : /* If we are using gpg, we must at least have the recipient set.
1901 : : */
1902 [ + + ]: 2486 : if(options->use_gpg)
1903 : : {
1904 [ + + ]: 84 : if(strlen(options->gpg_recipient_key) == 0)
1905 : : {
1906 : 1 : log_msg(LOG_VERBOSITY_ERROR,
1907 : : "Must specify --gpg-recipient-key when GPG is used.");
1908 : 1 : exit(EXIT_FAILURE);
1909 : : }
1910 : : }
1911 : :
1912 [ + + ]: 2485 : if(options->encryption_mode == FKO_ENC_MODE_ASYMMETRIC
1913 [ + - ]: 1 : && ! options->use_gpg)
1914 : : {
1915 : 1 : log_msg(LOG_VERBOSITY_ERROR,
1916 : : "Must specify GPG recipient/signing keys when Asymmetric encryption mode is used.");
1917 : 1 : exit(EXIT_FAILURE);
1918 : : }
1919 : :
1920 [ + + ]: 2484 : if(options->encryption_mode == FKO_ENC_MODE_CBC_LEGACY_IV
1921 [ + + ]: 4 : && options->use_hmac)
1922 : : {
1923 : 1 : log_msg(LOG_VERBOSITY_ERROR,
1924 : : "Legacy encryption mode is incompatible with HMAC usage.");
1925 : 1 : exit(EXIT_FAILURE);
1926 : : }
1927 : :
1928 : : /* Validate HMAC digest type
1929 : : */
1930 [ + + ][ + + ]: 2483 : if(options->use_hmac && options->hmac_type == FKO_HMAC_UNKNOWN)
1931 : 18 : options->hmac_type = FKO_DEFAULT_HMAC_MODE;
1932 : :
1933 [ + + ][ + + ]: 2483 : if(options->key_gen && options->hmac_type == FKO_HMAC_UNKNOWN)
1934 : 103 : options->hmac_type = FKO_DEFAULT_HMAC_MODE;
1935 : :
1936 : 2483 : return;
1937 : : }
1938 : :
1939 : : /* Establish a few defaults such as UDP/62201 for sending the SPA
1940 : : * packet (can be changed with --server-proto/--server-port)
1941 : : */
1942 : : static void
1943 : 2544 : set_defaults(fko_cli_options_t *options)
1944 : : {
1945 : 2544 : options->spa_proto = FKO_DEFAULT_PROTO;
1946 : 2544 : options->spa_dst_port = FKO_DEFAULT_PORT;
1947 : 2544 : options->fw_timeout = -1;
1948 : :
1949 : 2544 : options->key_len = FKO_DEFAULT_KEY_LEN;
1950 : 2544 : options->hmac_key_len = FKO_DEFAULT_HMAC_KEY_LEN;
1951 : 2544 : options->hmac_type = FKO_HMAC_UNKNOWN; /* updated when HMAC key is used */
1952 : :
1953 : 2544 : options->spa_icmp_type = ICMP_ECHOREPLY; /* only used in '-P icmp' mode */
1954 : 2544 : options->spa_icmp_code = 0; /* only used in '-P icmp' mode */
1955 : :
1956 : 2544 : options->input_fd = FD_INVALID;
1957 : :
1958 : 2544 : return;
1959 : : }
1960 : :
1961 : : /* Initialize program configuration via config file and/or command-line
1962 : : * switches.
1963 : : */
1964 : : void
1965 : 2544 : config_init(fko_cli_options_t *options, int argc, char **argv)
1966 : : {
1967 : 2544 : int cmd_arg, index, is_err, rlen=0;
1968 : : fko_var_bitmask_t var_bitmask;
1969 : 2544 : char rcfile[MAX_PATH_LEN] = {0};
1970 : :
1971 : : /* Zero out options, opts_track and bitmask.
1972 : : */
1973 : : memset(options, 0x00, sizeof(fko_cli_options_t));
1974 : : memset(&var_bitmask, 0x00, sizeof(fko_var_bitmask_t));
1975 : :
1976 : : /* Make sure a few reasonable defaults are set
1977 : : */
1978 : 2544 : set_defaults(options);
1979 : :
1980 : : /* First pass over cmd_line args to see if a named-stanza in the
1981 : : * rc file is used.
1982 : : */
1983 [ + + ]: 23336 : while ((cmd_arg = getopt_long(argc, argv,
1984 : : GETOPTS_OPTION_STRING, cmd_opts, &index)) != -1) {
1985 [ + + + + : 18249 : switch(cmd_arg) {
+ + + + +
+ + ]
1986 : : case 'h':
1987 : 1 : usage();
1988 : 1 : exit(EXIT_SUCCESS);
1989 : : case NO_SAVE_ARGS:
1990 : 1905 : options->no_save_args = 1;
1991 : 1905 : break;
1992 : : case 'n':
1993 : 384 : strlcpy(options->use_rc_stanza, optarg, sizeof(options->use_rc_stanza));
1994 : 384 : break;
1995 : : case NO_HOME_DIR:
1996 : 1 : options->no_home_dir = 1;
1997 : 1 : break;
1998 : : case NO_RC_FILE:
1999 : 3 : options->no_rc_file = 1;
2000 : 3 : break;
2001 : : case SAVE_RC_STANZA:
2002 : 109 : options->save_rc_stanza = 1;
2003 : 109 : break;
2004 : : case STANZA_LIST:
2005 : 5 : options->stanza_list = 1;
2006 : 5 : break;
2007 : : case 'E':
2008 : 8 : strlcpy(options->args_save_file, optarg, sizeof(options->args_save_file));
2009 : 8 : break;
2010 : : case RC_FILE_PATH:
2011 : 872 : strlcpy(options->rc_file, optarg, sizeof(options->rc_file));
2012 : 872 : break;
2013 : : case 'v':
2014 : 4794 : options->verbose++;
2015 : 4794 : add_var_to_bitmask(FWKNOP_CLI_ARG_VERBOSE, &var_bitmask);
2016 : 10625 : break;
2017 : : }
2018 : : }
2019 : :
2020 : : /* Update the verbosity level for the log module */
2021 : 2543 : log_set_verbosity(LOG_DEFAULT_VERBOSITY + options->verbose);
2022 : :
2023 [ + + ]: 2543 : if(options->no_rc_file)
2024 : : {
2025 [ + + ]: 3 : if(options->save_rc_stanza)
2026 : : {
2027 : 1 : log_msg(LOG_VERBOSITY_ERROR,
2028 : : "Cannot save an rc stanza in --no-rc-file mode.");
2029 : 1 : exit(EXIT_FAILURE);
2030 : : }
2031 [ + + ]: 2 : if (options->use_rc_stanza[0] != 0x0)
2032 : : {
2033 : 1 : log_msg(LOG_VERBOSITY_ERROR,
2034 : : "Cannot set stanza name in --no-rc-file mode.");
2035 : 1 : exit(EXIT_FAILURE);
2036 : : }
2037 [ + - ]: 1 : if (options->stanza_list)
2038 : : {
2039 : 1 : log_msg(LOG_VERBOSITY_ERROR,
2040 : : "Cannot list stanzas in --no-rc-file mode.");
2041 : 1 : exit(EXIT_FAILURE);
2042 : : }
2043 : : }
2044 : : else
2045 : : {
2046 : : /* Dump the configured stanzas from an rcfile */
2047 [ + + ]: 2540 : if (options->stanza_list == 1)
2048 : : {
2049 : 4 : set_rc_file(rcfile, options);
2050 : 2 : exit(dump_configured_stanzas_from_rcfile(rcfile));
2051 : : }
2052 : :
2053 : : /* First process the .fwknoprc file.
2054 : : */
2055 : 2536 : process_rc_section(RC_SECTION_DEFAULT, options);
2056 : :
2057 : : /* Load the user specified stanza from .fwknoprc file */
2058 [ + + ][ + + ]: 2522 : if ( (options->got_named_stanza) && (options->save_rc_stanza == 0) )
2059 : 286 : process_rc_section(options->use_rc_stanza, options);
2060 : : }
2061 : :
2062 : : /* Reset the options index so we can run through them again.
2063 : : */
2064 : 2520 : optind = 0;
2065 : :
2066 [ + + ]: 23048 : while ((cmd_arg = getopt_long(argc, argv,
2067 : : GETOPTS_OPTION_STRING, cmd_opts, &index)) != -1) {
2068 : :
2069 [ + + + + : 18032 : switch(cmd_arg) {
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ ]
2070 : : case 'a':
2071 : 2363 : strlcpy(options->allow_ip_str, optarg, sizeof(options->allow_ip_str));
2072 : 2363 : add_var_to_bitmask(FWKNOP_CLI_ARG_ALLOW_IP, &var_bitmask);
2073 : 15296 : break;
2074 : : case 'A':
2075 : 2677 : strlcpy(options->access_str, optarg, sizeof(options->access_str));
2076 : 2677 : add_var_to_bitmask(FWKNOP_CLI_ARG_ACCESS, &var_bitmask);
2077 : 2677 : break;
2078 : : case 'b':
2079 : 1 : options->save_packet_file_append = 1;
2080 : 1 : break;
2081 : : case 'B':
2082 : 4 : strlcpy(options->save_packet_file, optarg, sizeof(options->save_packet_file));
2083 : 4 : break;
2084 : : case 'C':
2085 : 21 : strlcpy(options->server_command, optarg, sizeof(options->server_command));
2086 : 21 : break;
2087 : : case 'D':
2088 : 2397 : strlcpy(options->spa_server_str, optarg, sizeof(options->spa_server_str));
2089 : 2397 : add_var_to_bitmask(FWKNOP_CLI_ARG_SPA_SERVER, &var_bitmask);
2090 : 2397 : break;
2091 : : case 'E':
2092 : 8 : strlcpy(options->args_save_file, optarg, sizeof(options->args_save_file));
2093 : 8 : break;
2094 : : case 'f':
2095 : 24 : options->fw_timeout = strtol_wrapper(optarg, 0,
2096 : : (2 << 16), NO_EXIT_UPON_ERR, &is_err);
2097 [ + + ]: 24 : if(is_err != FKO_SUCCESS)
2098 : : {
2099 : 1 : log_msg(LOG_VERBOSITY_ERROR, "--fw-timeout must be within [%d-%d]",
2100 : : 0, (2 << 16));
2101 : 1 : exit(EXIT_FAILURE);
2102 : : }
2103 : 23 : add_var_to_bitmask(FWKNOP_CLI_ARG_FW_TIMEOUT, &var_bitmask);
2104 : 23 : break;
2105 : : case FAULT_INJECTION_TAG:
2106 : : #if HAVE_LIBFIU
2107 : 30 : strlcpy(options->fault_injection_tag, optarg, sizeof(options->fault_injection_tag));
2108 : : #else
2109 : : log_msg(LOG_VERBOSITY_ERROR,
2110 : : "fwknop not compiled with fault injection support.", optarg);
2111 : : exit(EXIT_FAILURE);
2112 : : #endif
2113 : 30 : break;
2114 : : case 'g':
2115 : : case GPG_ENCRYPTION:
2116 : 4 : options->use_gpg = 1;
2117 : 4 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_GPG, &var_bitmask);
2118 : 4 : break;
2119 : : case 'G':
2120 : 1535 : strlcpy(options->get_key_file, optarg, sizeof(options->get_key_file));
2121 : 1535 : add_var_to_bitmask(FWKNOP_CLI_ARG_KEY_FILE, &var_bitmask);
2122 : 1535 : break;
2123 : : case GET_HMAC_KEY:
2124 : 3 : strlcpy(options->get_hmac_key_file, optarg,
2125 : : sizeof(options->get_hmac_key_file));
2126 : 3 : options->use_hmac = 1;
2127 : 3 : add_var_to_bitmask(FWKNOP_CLI_ARG_HMAC_KEY_FILE, &var_bitmask);
2128 : 3 : break;
2129 : : case 'H':
2130 : 4 : options->spa_proto = FKO_PROTO_HTTP;
2131 : 4 : strlcpy(options->http_proxy, optarg, sizeof(options->http_proxy));
2132 : 4 : break;
2133 : : case 'k':
2134 : 119 : options->key_gen = 1;
2135 : 119 : break;
2136 : : case 'K':
2137 : 2 : options->key_gen = 1;
2138 : 2 : strlcpy(options->key_gen_file, optarg, sizeof(options->key_gen_file));
2139 : 2 : break;
2140 : : case KEY_RIJNDAEL:
2141 : 10 : strlcpy(options->key, optarg, sizeof(options->key));
2142 : 10 : options->have_key = 1;
2143 : 10 : add_var_to_bitmask(FWKNOP_CLI_ARG_KEY_RIJNDAEL, &var_bitmask);
2144 : 10 : break;
2145 : : case KEY_RIJNDAEL_BASE64:
2146 [ + + ]: 7 : if (! is_base64((unsigned char *) optarg, strlen(optarg)))
2147 : : {
2148 : 1 : log_msg(LOG_VERBOSITY_ERROR,
2149 : : "Base64 encoded Rijndael argument '%s' doesn't look like base64-encoded data.",
2150 : : optarg);
2151 : 1 : exit(EXIT_FAILURE);
2152 : : }
2153 : 6 : strlcpy(options->key_base64, optarg, sizeof(options->key_base64));
2154 : 6 : options->have_base64_key = 1;
2155 : 6 : add_var_to_bitmask(FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64, &var_bitmask);
2156 : 6 : break;
2157 : : case KEY_HMAC_BASE64:
2158 [ + + ]: 4 : if (! is_base64((unsigned char *) optarg, strlen(optarg)))
2159 : : {
2160 : 1 : log_msg(LOG_VERBOSITY_ERROR,
2161 : : "Base64 encoded HMAC argument '%s' doesn't look like base64-encoded data.",
2162 : : optarg);
2163 : 1 : exit(EXIT_FAILURE);
2164 : : }
2165 : 3 : strlcpy(options->hmac_key_base64, optarg, sizeof(options->hmac_key_base64));
2166 : 3 : options->have_hmac_base64_key = 1;
2167 : 3 : options->use_hmac = 1;
2168 : 3 : add_var_to_bitmask(FWKNOP_CLI_ARG_KEY_HMAC_BASE64, &var_bitmask);
2169 : 3 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_HMAC, &var_bitmask);
2170 : 3 : break;
2171 : : case KEY_HMAC:
2172 : 4 : strlcpy(options->hmac_key, optarg, sizeof(options->hmac_key));
2173 : 4 : options->have_hmac_key = 1;
2174 : 4 : options->use_hmac = 1;
2175 : 4 : add_var_to_bitmask(FWKNOP_CLI_ARG_KEY_HMAC, &var_bitmask);
2176 : 4 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_HMAC, &var_bitmask);
2177 : 4 : break;
2178 : : case KEY_LEN:
2179 : 3 : options->key_len = strtol_wrapper(optarg, 1,
2180 : : MAX_KEY_LEN, NO_EXIT_UPON_ERR, &is_err);
2181 [ + + ]: 3 : if(is_err != FKO_SUCCESS)
2182 : : {
2183 : 2 : log_msg(LOG_VERBOSITY_ERROR,
2184 : : "Invalid key length '%s', must be in [%d-%d]",
2185 : : optarg, 1, MAX_KEY_LEN);
2186 : 2 : exit(EXIT_FAILURE);
2187 : : }
2188 : : break;
2189 : : case HMAC_DIGEST_TYPE:
2190 [ + + ]: 31 : if((options->hmac_type = hmac_digest_strtoint(optarg)) < 0)
2191 : : {
2192 : 4 : log_msg(LOG_VERBOSITY_ERROR,
2193 : : "* Invalid hmac digest type: %s, use {md5,sha1,sha256,sha384,sha512,sha3_256,sha3_512}",
2194 : : optarg);
2195 : 4 : exit(EXIT_FAILURE);
2196 : : }
2197 : 27 : add_var_to_bitmask(FWKNOP_CLI_ARG_HMAC_DIGEST_TYPE, &var_bitmask);
2198 : 27 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_HMAC, &var_bitmask);
2199 : 27 : options->use_hmac = 1;
2200 : 27 : break;
2201 : : case HMAC_KEY_LEN:
2202 : 3 : options->hmac_key_len = strtol_wrapper(optarg, 1,
2203 : : MAX_KEY_LEN, NO_EXIT_UPON_ERR, &is_err);
2204 [ + + ]: 3 : if(is_err != FKO_SUCCESS)
2205 : : {
2206 : 2 : log_msg(LOG_VERBOSITY_ERROR,
2207 : : "Invalid hmac key length '%s', must be in [%d-%d]",
2208 : : optarg, 1, MAX_KEY_LEN);
2209 : 2 : exit(EXIT_FAILURE);
2210 : : }
2211 : 1 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_HMAC, &var_bitmask);
2212 : 1 : options->use_hmac = 1;
2213 : 1 : break;
2214 : : case SPA_ICMP_TYPE:
2215 : 2 : options->spa_icmp_type = strtol_wrapper(optarg, 0,
2216 : : MAX_ICMP_TYPE, NO_EXIT_UPON_ERR, &is_err);
2217 [ + + ]: 2 : if(is_err != FKO_SUCCESS)
2218 : : {
2219 : 1 : log_msg(LOG_VERBOSITY_ERROR,
2220 : : "Invalid icmp type '%s', must be in [%d-%d]",
2221 : : optarg, 0, MAX_ICMP_TYPE);
2222 : 1 : exit(EXIT_FAILURE);
2223 : : }
2224 : : break;
2225 : : case SPA_ICMP_CODE:
2226 : 2 : options->spa_icmp_code = strtol_wrapper(optarg, 0,
2227 : : MAX_ICMP_CODE, NO_EXIT_UPON_ERR, &is_err);
2228 [ + + ]: 2 : if(is_err != FKO_SUCCESS)
2229 : : {
2230 : 1 : log_msg(LOG_VERBOSITY_ERROR,
2231 : : "Invalid icmp code '%s', must be in [%d-%d]",
2232 : : optarg, 0, MAX_ICMP_CODE);
2233 : 1 : exit(EXIT_FAILURE);
2234 : : }
2235 : : break;
2236 : : case 'l':
2237 : 4 : options->run_last_command = 1;
2238 : 4 : break;
2239 : : case 'm':
2240 : : case FKO_DIGEST_NAME:
2241 [ + + ]: 18 : if((options->digest_type = digest_strtoint(optarg)) < 0)
2242 : : {
2243 : 1 : log_msg(LOG_VERBOSITY_ERROR,
2244 : : "* Invalid digest type: %s, use {md5,sha1,sha256,sha384,sha512,sha3_256,sha3_512}",
2245 : : optarg);
2246 : 1 : exit(EXIT_FAILURE);
2247 : : }
2248 : 17 : add_var_to_bitmask(FWKNOP_CLI_ARG_DIGEST_TYPE, &var_bitmask);
2249 : 17 : break;
2250 : : case 'M':
2251 : : case ENCRYPTION_MODE:
2252 [ + + ]: 18 : if((options->encryption_mode = enc_mode_strtoint(optarg)) < 0)
2253 : : {
2254 : 2 : log_msg(LOG_VERBOSITY_ERROR,
2255 : : "* Invalid encryption mode: %s, use {CBC,CTR,legacy,Asymmetric}",
2256 : : optarg);
2257 : 2 : exit(EXIT_FAILURE);
2258 : : }
2259 : 16 : add_var_to_bitmask(FWKNOP_CLI_ARG_ENCRYPTION_MODE, &var_bitmask);
2260 : 16 : break;
2261 : : case NO_SAVE_ARGS:
2262 : 1886 : options->no_save_args = 1;
2263 : 1886 : add_var_to_bitmask(FWKNOP_CLI_ARG_NO_SAVE_ARGS, &var_bitmask);
2264 : 1886 : break;
2265 : : case 'n':
2266 : : /* We already handled this earlier, so we do nothing here
2267 : : */
2268 : : break;
2269 : : case 'N':
2270 : 36 : strlcpy(options->nat_access_str, optarg, sizeof(options->nat_access_str));
2271 : 36 : add_var_to_bitmask(FWKNOP_CLI_ARG_NAT_ACCESS, &var_bitmask);
2272 : 36 : break;
2273 : : case 'p':
2274 : 4 : options->spa_dst_port = strtol_wrapper(optarg, 0,
2275 : : MAX_PORT, EXIT_UPON_ERR, &is_err);
2276 : 2 : add_var_to_bitmask(FWKNOP_CLI_ARG_SPA_SERVER_PORT, &var_bitmask);
2277 : 2 : break;
2278 : : case 'P':
2279 [ + + ]: 30 : if((options->spa_proto = proto_strtoint(optarg)) < 0)
2280 : : {
2281 : 1 : log_msg(LOG_VERBOSITY_ERROR, "Unrecognized protocol: %s", optarg);
2282 : 1 : exit(EXIT_FAILURE);
2283 : : }
2284 : 29 : add_var_to_bitmask(FWKNOP_CLI_ARG_SPA_SERVER_PROTO, &var_bitmask);
2285 : 29 : break;
2286 : : case 'Q':
2287 : 9 : strlcpy(options->spoof_ip_src_str, optarg, sizeof(options->spoof_ip_src_str));
2288 : 9 : add_var_to_bitmask(FWKNOP_CLI_ARG_SPOOF_SOURCE_IP, &var_bitmask);
2289 : 9 : break;
2290 : : case RC_FILE_PATH:
2291 : 854 : strlcpy(options->rc_file, optarg, sizeof(options->rc_file));
2292 : 854 : break;
2293 : : case 'r':
2294 : 5 : options->rand_port = 1;
2295 : 5 : add_var_to_bitmask(FWKNOP_CLI_ARG_RAND_PORT, &var_bitmask);
2296 : 5 : break;
2297 : : case 'R':
2298 : 30 : options->resolve_ip_http_https = 1;
2299 : 30 : add_var_to_bitmask(FWKNOP_CLI_ARG_RESOLVE_IP_HTTPS, &var_bitmask);
2300 : 30 : break;
2301 : : case RESOLVE_HTTP_ONLY:
2302 : 5 : options->resolve_http_only = 1;
2303 : 5 : options->resolve_ip_http_https = 1;
2304 : 5 : add_var_to_bitmask(FWKNOP_CLI_ARG_RESOLVE_HTTP_ONLY, &var_bitmask);
2305 : 5 : add_var_to_bitmask(FWKNOP_CLI_ARG_RESOLVE_IP_HTTPS, &var_bitmask);
2306 : 5 : break;
2307 : : case RESOLVE_URL:
2308 [ - + ]: 19 : if(options->resolve_url != NULL)
2309 : 0 : free(options->resolve_url);
2310 : 19 : rlen = strlen(optarg) + 1;
2311 : 19 : options->resolve_url = calloc(1, rlen);
2312 [ - + ]: 19 : if(options->resolve_url == NULL)
2313 : : {
2314 : 0 : log_msg(LOG_VERBOSITY_ERROR, "Memory allocation error for resolve URL.");
2315 : 0 : exit(EXIT_FAILURE);
2316 : : }
2317 : 19 : strlcpy(options->resolve_url, optarg, rlen);
2318 : 19 : add_var_to_bitmask(FWKNOP_CLI_ARG_RESOLVE_URL, &var_bitmask);
2319 : 19 : break;
2320 : : case SERVER_RESOLVE_IPV4:
2321 : 1 : options->spa_server_resolve_ipv4 = 1;
2322 : 1 : break;
2323 : : case 'w':
2324 [ - + ]: 2 : if(options->wget_bin != NULL)
2325 : 0 : free(options->wget_bin);
2326 : 2 : rlen = strlen(optarg) + 1;
2327 : 2 : options->wget_bin = calloc(1, rlen);
2328 [ - + ]: 2 : if(options->wget_bin == NULL)
2329 : : {
2330 : 0 : log_msg(LOG_VERBOSITY_ERROR, "Memory allocation error for resolve URL.");
2331 : 0 : exit(EXIT_FAILURE);
2332 : : }
2333 : 2 : strlcpy(options->wget_bin, optarg, rlen);
2334 : 2 : add_var_to_bitmask(FWKNOP_CLI_ARG_WGET_CMD, &var_bitmask);
2335 : 2 : break;
2336 : : case SHOW_LAST_ARGS:
2337 : 4 : options->show_last_command = 1;
2338 : 4 : break;
2339 : : case 's':
2340 : 9 : strlcpy(options->allow_ip_str, "0.0.0.0", sizeof(options->allow_ip_str));
2341 : 9 : break;
2342 : : case 'S':
2343 : 1 : options->spa_src_port = strtol_wrapper(optarg, 0,
2344 : : MAX_PORT, EXIT_UPON_ERR, &is_err);
2345 : 1 : add_var_to_bitmask(FWKNOP_CLI_ARG_SPA_SOURCE_PORT, &var_bitmask);
2346 : 1 : break;
2347 : : case SAVE_RC_STANZA:
2348 : : /* We already handled this earlier, so we do nothing here
2349 : : */
2350 : : break;
2351 : : case 'T':
2352 : 149 : options->test = 1;
2353 : 149 : break;
2354 : : case 'u':
2355 : 2 : strlcpy(options->http_user_agent, optarg, sizeof(options->http_user_agent));
2356 : 2 : add_var_to_bitmask(FWKNOP_CLI_ARG_HTTP_USER_AGENT, &var_bitmask);
2357 : 2 : break;
2358 : : case 'U':
2359 : 6 : strlcpy(options->spoof_user, optarg, sizeof(options->spoof_user));
2360 : 6 : add_var_to_bitmask(FWKNOP_CLI_ARG_SPOOF_USER, &var_bitmask);
2361 : 6 : break;
2362 : : case 'v':
2363 : : /* Handled earlier.
2364 : : */
2365 : : break;
2366 : : case 'V':
2367 : 1 : options->version = 1;
2368 : 1 : break;
2369 : : case GPG_RECIP_KEY:
2370 : 81 : options->use_gpg = 1;
2371 : 81 : strlcpy(options->gpg_recipient_key, optarg, sizeof(options->gpg_recipient_key));
2372 : 81 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_GPG, &var_bitmask);
2373 : 81 : add_var_to_bitmask(FWKNOP_CLI_ARG_GPG_RECIPIENT, &var_bitmask);
2374 : 81 : break;
2375 : : case GPG_SIGNER_KEY:
2376 : 81 : options->use_gpg = 1;
2377 : 81 : strlcpy(options->gpg_signer_key, optarg, sizeof(options->gpg_signer_key));
2378 : 81 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_GPG, &var_bitmask);
2379 : 81 : add_var_to_bitmask(FWKNOP_CLI_ARG_GPG_SIGNER, &var_bitmask);
2380 : 81 : break;
2381 : : case GPG_HOME_DIR:
2382 : 83 : options->use_gpg = 1;
2383 : 83 : strlcpy(options->gpg_home_dir, optarg, sizeof(options->gpg_home_dir));
2384 : 83 : chop_char(options->gpg_home_dir, PATH_SEP);
2385 : 83 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_GPG, &var_bitmask);
2386 : 83 : add_var_to_bitmask(FWKNOP_CLI_ARG_GPG_HOMEDIR, &var_bitmask);
2387 : 83 : break;
2388 : : case GPG_EXE_PATH:
2389 : 4 : options->use_gpg = 1;
2390 : 4 : strlcpy(options->gpg_exe, optarg, sizeof(options->gpg_exe));
2391 : 4 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_GPG, &var_bitmask);
2392 : 4 : add_var_to_bitmask(FWKNOP_CLI_ARG_GPG_EXE_PATH, &var_bitmask);
2393 : 4 : break;
2394 : : case GPG_AGENT:
2395 : 1 : options->use_gpg = 1;
2396 : 1 : options->use_gpg_agent = 1;
2397 : 1 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_GPG, &var_bitmask);
2398 : 1 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_GPG_AGENT, &var_bitmask);
2399 : 1 : break;
2400 : : case GPG_ALLOW_NO_SIGNING_PW:
2401 : 32 : options->use_gpg = 1;
2402 : 32 : options->gpg_no_signing_pw = 1;
2403 : 32 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_GPG, &var_bitmask);
2404 : 32 : add_var_to_bitmask(FWKNOP_CLI_ARG_GPG_NO_SIGNING_PW, &var_bitmask);
2405 : 32 : break;
2406 : : case NAT_LOCAL:
2407 : 13 : options->nat_local = 1;
2408 : 13 : add_var_to_bitmask(FWKNOP_CLI_ARG_NAT_LOCAL, &var_bitmask);
2409 : 13 : break;
2410 : : case NAT_RAND_PORT:
2411 : 7 : options->nat_rand_port = 1;
2412 : 7 : add_var_to_bitmask(FWKNOP_CLI_ARG_NAT_RAND_PORT, &var_bitmask);
2413 : 7 : break;
2414 : : case NAT_PORT:
2415 : 11 : options->nat_port = strtol_wrapper(optarg, 0,
2416 : : MAX_PORT, EXIT_UPON_ERR, &is_err);
2417 : 11 : add_var_to_bitmask(FWKNOP_CLI_ARG_NAT_PORT, &var_bitmask);
2418 : 11 : break;
2419 : : case NO_HOME_DIR:
2420 : : /* We already handled this earlier, so we do nothing here
2421 : : */
2422 : : break;
2423 : : case NO_RC_FILE:
2424 : : /* We already handled this earlier, so we do nothing here
2425 : : */
2426 : : break;
2427 : : case TIME_OFFSET_PLUS:
2428 [ + + ]: 5 : if (! parse_time_offset(optarg, &options->time_offset_plus))
2429 : : {
2430 : 1 : log_msg(LOG_VERBOSITY_WARNING,
2431 : : "Invalid time offset: '%s'", optarg);
2432 : 1 : exit(EXIT_FAILURE);
2433 : : }
2434 : 4 : add_var_to_bitmask(FWKNOP_CLI_ARG_TIME_OFFSET, &var_bitmask);
2435 : 4 : break;
2436 : : case TIME_OFFSET_MINUS:
2437 [ + + ]: 3 : if (! parse_time_offset(optarg, &options->time_offset_minus))
2438 : : {
2439 : 1 : log_msg(LOG_VERBOSITY_WARNING,
2440 : : "Invalid time offset: '%s'", optarg);
2441 : 1 : exit(EXIT_FAILURE);
2442 : : }
2443 : 2 : add_var_to_bitmask(FWKNOP_CLI_ARG_TIME_OFFSET, &var_bitmask);
2444 : 2 : break;
2445 : : case USE_HMAC:
2446 : 16 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_HMAC, &var_bitmask);
2447 : 16 : options->use_hmac = 1;
2448 : 16 : break;
2449 : : case USE_WGET_USER_AGENT:
2450 : 2 : add_var_to_bitmask(FWKNOP_CLI_ARG_USE_WGET_USER_AGENT, &var_bitmask);
2451 : 2 : options->use_wget_user_agent = 1;
2452 : 2 : break;
2453 : : case FORCE_SAVE_RC_STANZA:
2454 : 95 : options->force_save_rc_stanza = 1;
2455 : 95 : break;
2456 : : case FD_SET_STDIN:
2457 : 1 : options->input_fd = STDIN_FILENO;
2458 : 1 : break;
2459 : : case FD_SET_ALT:
2460 : : #ifdef WIN32
2461 : : log_msg(LOG_VERBOSITY_ERROR, "Read password from FD not supported on Windows");
2462 : : exit(EXIT_FAILURE);
2463 : : #endif
2464 : 12 : options->input_fd = strtol_wrapper(optarg, 0,
2465 : : -1, EXIT_UPON_ERR, &is_err);
2466 : 11 : break;
2467 : : default:
2468 : 2 : usage();
2469 : 2 : exit(EXIT_FAILURE);
2470 : : }
2471 : : }
2472 : :
2473 : : /* Now that we have all of our options set, we can validate them */
2474 : 2496 : validate_options(options);
2475 : :
2476 : : /* Generate Rijndael + HMAC keys from /dev/random and base64 encode
2477 : : */
2478 : 2483 : generate_keys(options);
2479 : :
2480 : : /* We can upgrade our settings with the parameters set on the command
2481 : : * line by the user */
2482 [ + + ]: 2483 : if (options->save_rc_stanza == 1)
2483 : : {
2484 : : /* If we are asked to generate keys, we add them to the bitmask so
2485 : : * that they can be added to the stanza when updated */
2486 [ + + ]: 91 : if (options->key_gen == 1)
2487 : : {
2488 : 11 : add_var_to_bitmask(FWKNOP_CLI_ARG_KEY_RIJNDAEL_BASE64, &var_bitmask);
2489 : 11 : add_var_to_bitmask(FWKNOP_CLI_ARG_KEY_HMAC_BASE64, &var_bitmask);
2490 : : }
2491 : : else;
2492 : :
2493 : 91 : update_rc(options, &var_bitmask);
2494 : : }
2495 : : else;
2496 : :
2497 : 2483 : keys_status(options);
2498 : :
2499 : 2369 : return;
2500 : : }
2501 : :
2502 : : /* Print usage message...
2503 : : */
2504 : : void
2505 : 3 : usage(void)
2506 : : {
2507 : 3 : log_msg(LOG_VERBOSITY_NORMAL,
2508 : : "\n%s client version %s\n%s - http://%s/fwknop/\n",
2509 : : MY_NAME, MY_VERSION, MY_DESC, HTTP_RESOLVE_HOST);
2510 : 3 : log_msg(LOG_VERBOSITY_NORMAL,
2511 : : "Usage: fwknop -A <port list> [-s|-R|-a] -D <spa_server> [options]\n\n"
2512 : : " -n, --named-config Specify a named configuration stanza in the\n"
2513 : : " '$HOME/.fwknoprc' file to provide some of all\n"
2514 : : " of the configuration parameters.\n"
2515 : : " If more arguments are set through the command\n"
2516 : : " line, the configuration is updated accordingly.\n"
2517 : : " -A, --access Provide a list of ports/protocols to open\n"
2518 : : " on the server (e.g. 'tcp/22').\n"
2519 : : " -a, --allow-ip Specify IP address to allow within the SPA\n"
2520 : : " packet (e.g. '123.2.3.4'). If \n"
2521 : : " -D, --destination Specify the hostname or IP address of the\n"
2522 : : " fwknop server.\n"
2523 : : " --use-hmac Add an HMAC to the outbound SPA packet for\n"
2524 : : " authenticated encryption.\n"
2525 : : " -h, --help Print this usage message and exit.\n"
2526 : : " -B, --save-packet Save the generated packet data to the\n"
2527 : : " specified file.\n"
2528 : : " -b, --save-packet-append Append the generated packet data to the\n"
2529 : : " file specified with the -B option.\n"
2530 : : " -C, --server-cmd Specify a command that the fwknop server will\n"
2531 : : " execute on behalf of the fwknop client..\n"
2532 : : " -N, --nat-access Gain NAT access to an internal service.\n"
2533 : : " -p, --server-port Set the destination port for outgoing SPA\n"
2534 : : " packet.\n"
2535 : : " -P, --server-proto Set the protocol (udp, tcp, http, tcpraw,\n"
2536 : : " icmp) for the outgoing SPA packet.\n"
2537 : : " Note: The 'tcpraw' and 'icmp' modes use raw\n"
2538 : : " sockets and thus require root access to use.\n"
2539 : : " -s, --source-ip Tell the fwknopd server to accept whatever\n"
2540 : : " source IP the SPA packet has as the IP that\n"
2541 : : " needs access (not recommended, and the\n"
2542 : : " fwknopd server can ignore such requests).\n"
2543 : : " -S, --source-port Set the source port for outgoing SPA packet.\n"
2544 : : " -Q, --spoof-source Set the source IP for outgoing SPA packet.\n"
2545 : : " -R, --resolve-ip-https Resolve the external network IP by\n"
2546 : : " connecting to a URL such as the default of:\n"
2547 : : " https://" HTTP_RESOLVE_HOST HTTP_RESOLVE_URL "\n"
2548 : : " with wget in --secure-protocol mode (SSL).\n"
2549 : : " The URL can be overridden with the\n"
2550 : : " --resolve-url option.\n"
2551 : : " --resolve-http-only Force external IP resolution via HTTP instead\n"
2552 : : " HTTPS (via the URL mentioned above). This is\n"
2553 : : " not recommended since it would open fwknop\n"
2554 : : " to potential MITM attacks if the IP resolution\n"
2555 : : " HTTP connection is altered en-route by a third\n"
2556 : : " party.\n"
2557 : : " --resolve-url Override the default URL used for resolving\n"
2558 : : " the source IP address.\n"
2559 : : " -u, --user-agent Set the HTTP User-Agent for resolving the\n"
2560 : : " external IP via -R, or for sending SPA\n"
2561 : : " packets over HTTP. The default is\n"
2562 : : " Fwknop/<version> if this option is not used.\n"
2563 : : " --use-wget-user-agent Use the default wget User-Agent string instead\n"
2564 : : " of Fwknop/<version>.\n"
2565 : : " -w, --wget-cmd Manually set the path to wget in -R mode.\n"
2566 : : " -H, --http-proxy Specify an HTTP proxy host through which the\n"
2567 : : " SPA packet will be sent. The port can also be\n"
2568 : : " specified here by following the host/ip with\n"
2569 : : " \":<port>\".\n"
2570 : : " -U, --spoof-user Set the username within outgoing SPA packet.\n"
2571 : : " -l, --last-cmd Run the fwknop client with the same command\n"
2572 : : " line args as the last time it was executed\n"
2573 : : " (args are read from the ~/.fwknop.run file).\n"
2574 : : " -G, --get-key Load an encryption key/password from a file.\n"
2575 : : " --stdin Read the encryption key/password from stdin\n"
2576 : : " --fd Specify the file descriptor to read the\n"
2577 : : " encryption key/password from.\n"
2578 : : " -k, --key-gen Generate SPA Rijndael + HMAC keys.\n"
2579 : : " -K, --key-gen-file Write generated Rijndael + HMAC keys to a\n"
2580 : : " file\n"
2581 : : " --key-rijndael Specify the Rijndael key. Since the password is\n"
2582 : : " visible to utilities (like 'ps' under Unix)\n"
2583 : : " this form should only be used where security is\n"
2584 : : " not important.\n"
2585 : : " --key-base64-rijndael Specify the base64 encoded Rijndael key. Since\n"
2586 : : " the password is visible to utilities (like 'ps'\n"
2587 : : " under Unix) this form should only be used where\n"
2588 : : " security is not important.\n"
2589 : : " --key-base64-hmac Specify the base64 encoded HMAC key. Since the\n"
2590 : : " password is visible to utilities (like 'ps'\n"
2591 : : " under Unix) this form should only be used where\n"
2592 : : " security is not important.\n"
2593 : : " -r, --rand-port Send the SPA packet over a randomly assigned\n"
2594 : : " port (requires a broader pcap filter on the\n"
2595 : : " server side than the default of udp 62201).\n"
2596 : : " -T, --test Build the SPA packet but do not send it over\n"
2597 : : " the network.\n"
2598 : : " -v, --verbose Set verbose mode (may specify multiple times).\n"
2599 : : " -V, --version Print version number.\n"
2600 : : " -m, --digest-type Specify the message digest algorithm to use.\n"
2601 : : " (md5, sha1, sha256, sha384, or sha512). The\n"
2602 : : " default is sha256.\n"
2603 : : " -M, --encryption-mode Specify the encryption mode when AES is used\n"
2604 : : " for encrypting SPA packets.The default is CBC\n"
2605 : : " mode, but others can be chosen such as CFB or\n"
2606 : : " OFB as long as this is also specified in the\n"
2607 : : " access.conf file on the server side. Note that\n"
2608 : : " the string ``legacy'' can be specified in order\n"
2609 : : " to generate SPA packets with the old initialization\n"
2610 : : " vector strategy used by versions of *fwknop*\n"
2611 : : " before 2.5.\n"
2612 : : " -f, --fw-timeout Specify SPA server firewall timeout from the\n"
2613 : : " client side.\n"
2614 : : " --hmac-digest-type Set the HMAC digest algorithm (default is\n"
2615 : : " sha256). Options are md5, sha1, sha256,\n"
2616 : : " sha384, or sha512.\n"
2617 : : " --icmp-type Set the ICMP type (used with '-P icmp')\n"
2618 : : " --icmp-code Set the ICMP code (used with '-P icmp')\n"
2619 : : " --gpg-encryption Use GPG encryption (default is Rijndael).\n"
2620 : : " --gpg-recipient-key Specify the recipient GPG key name or ID.\n"
2621 : : " --gpg-signer-key Specify the signer's GPG key name or ID.\n"
2622 : : " --gpg-no-signing-pw Allow no signing password if none associated\n"
2623 : : " with GPG key.\n"
2624 : : " --gpg-home-dir Specify the GPG home directory.\n"
2625 : : " --gpg-agent Use GPG agent if available.\n"
2626 : : " --gpg-exe Set path to GPG binary.\n"
2627 : : " --no-save-args Do not save fwknop command line args to the\n"
2628 : : " $HOME/fwknop.run file\n"
2629 : : " --rc-file Specify path to the fwknop rc file (default\n"
2630 : : " is $HOME/.fwknoprc)\n"
2631 : : " --server-resolve-ipv4 Force IPv4 address resolution from DNS for\n"
2632 : : " SPA server when using a hostname.\n"
2633 : : " --save-rc-stanza Save command line arguments to the\n"
2634 : : " $HOME/.fwknoprc stanza specified with the\n"
2635 : : " -n option.\n"
2636 : : " --force-stanza Used with --save-rc-stanza to overwrite all of\n"
2637 : : " the variables for the specified stanza\n"
2638 : : " --stanza-list Dump a list of the stanzas found in\n"
2639 : : " $HOME/.fwknoprc\n"
2640 : : " --nat-local Access a local service via a forwarded port\n"
2641 : : " on the fwknopd server system.\n"
2642 : : " --nat-port Specify the port to forward to access a\n"
2643 : : " service via NAT.\n"
2644 : : " --nat-rand-port Have the fwknop client assign a random port\n"
2645 : : " for NAT access.\n"
2646 : : " --no-home-dir Do not allow the fwknop client to look for\n"
2647 : : " the user home directory.\n"
2648 : : " --no-rc-file Perform fwknop client operations without\n"
2649 : : " referencing a ~/.fwknoprc file.\n"
2650 : : " --show-last Show the last fwknop command line arguments.\n"
2651 : : " --time-offset-plus Add time to outgoing SPA packet timestamp.\n"
2652 : : " --time-offset-minus Subtract time from outgoing SPA packet\n"
2653 : : " timestamp.\n"
2654 : : );
2655 : :
2656 : 3 : return;
2657 : : }
2658 : :
2659 : : #ifdef HAVE_C_UNIT_TESTS /* LCOV_EXCL_START */
2660 : :
2661 : : DECLARE_TEST_SUITE_INIT(config_init)
2662 : : {
2663 : : log_set_verbosity(LOG_VERBOSITY_ERROR);
2664 : : return 0;
2665 : : }
2666 : :
2667 : : DECLARE_TEST_SUITE_CLEANUP(config_init)
2668 : : {
2669 : : return 0;
2670 : : }
2671 : :
2672 : : DECLARE_UTEST(critical_var, "Check critcial vars")
2673 : : {
2674 : : CU_ASSERT(var_is_critical(FWKNOP_CLI_ARG_KEY_RIJNDAEL) == 1);
2675 : : CU_ASSERT(var_is_critical(FWKNOP_CLI_ARG_WGET_CMD) == 0);
2676 : : }
2677 : :
2678 : : DECLARE_UTEST(check_var_bitmask, "Check var_bitmask functions")
2679 : : {
2680 : : fko_var_bitmask_t var_bitmask;
2681 : :
2682 : : memset(&var_bitmask, 0x00, sizeof(fko_var_bitmask_t));
2683 : :
2684 : : add_var_to_bitmask(FWKNOP_CLI_FIRST_ARG, &var_bitmask);
2685 : : CU_ASSERT(bitmask_has_var(FWKNOP_CLI_FIRST_ARG, &var_bitmask) == 1);
2686 : : CU_ASSERT(var_bitmask.dw[0] == 1);
2687 : : remove_var_from_bitmask(FWKNOP_CLI_FIRST_ARG, &var_bitmask);
2688 : : CU_ASSERT(bitmask_has_var(FWKNOP_CLI_FIRST_ARG, &var_bitmask) == 0);
2689 : : CU_ASSERT(var_bitmask.dw[0] == 0);
2690 : :
2691 : : add_var_to_bitmask(FWKNOP_CLI_ARG_KEY_RIJNDAEL, &var_bitmask);
2692 : : CU_ASSERT(bitmask_has_var(FWKNOP_CLI_ARG_KEY_RIJNDAEL, &var_bitmask) == 1);
2693 : : remove_var_from_bitmask(FWKNOP_CLI_ARG_KEY_RIJNDAEL, &var_bitmask);
2694 : : CU_ASSERT(bitmask_has_var(FWKNOP_CLI_ARG_KEY_RIJNDAEL, &var_bitmask) == 0);
2695 : :
2696 : : add_var_to_bitmask(FWKNOP_CLI_LAST_ARG, &var_bitmask);
2697 : : CU_ASSERT(bitmask_has_var(FWKNOP_CLI_LAST_ARG, &var_bitmask) == 1);
2698 : : remove_var_from_bitmask(FWKNOP_CLI_LAST_ARG, &var_bitmask);
2699 : : CU_ASSERT(bitmask_has_var(FWKNOP_CLI_LAST_ARG, &var_bitmask) == 0);
2700 : :
2701 : : add_var_to_bitmask(FWKNOP_CLI_LAST_ARG+32, &var_bitmask);
2702 : : CU_ASSERT(bitmask_has_var(FWKNOP_CLI_LAST_ARG+32, &var_bitmask) == 0);
2703 : :
2704 : : add_var_to_bitmask(FWKNOP_CLI_LAST_ARG+34, &var_bitmask);
2705 : : CU_ASSERT(bitmask_has_var(FWKNOP_CLI_LAST_ARG+34, &var_bitmask) == 0);
2706 : : }
2707 : :
2708 : : int register_ts_config_init(void)
2709 : : {
2710 : : ts_init(&TEST_SUITE(config_init), TEST_SUITE_DESCR(config_init), TEST_SUITE_INIT(config_init), TEST_SUITE_CLEANUP(config_init));
2711 : : ts_add_utest(&TEST_SUITE(config_init), UTEST_FCT(critical_var), UTEST_DESCR(critical_var));
2712 : : ts_add_utest(&TEST_SUITE(config_init), UTEST_FCT(check_var_bitmask), UTEST_DESCR(check_var_bitmask));
2713 : :
2714 : : return register_ts(&TEST_SUITE(config_init));
2715 : : }
2716 : :
2717 : : #endif /* HAVE_C_UNIT_TESTS */ /* LCOV_EXCL_STOP */
|