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