Branch data Line data Source code
1 : : /**
2 : : * \file server/access.c
3 : : *
4 : : * \brief Access.conf file processing for fwknop server.
5 : : */
6 : :
7 : : /* Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
8 : : * Copyright (C) 2009-2015 fwknop developers and contributors. For a full
9 : : * list of contributors, see the file 'CREDITS'.
10 : : *
11 : : * License (GNU General Public License):
12 : : *
13 : : * This program is free software; you can redistribute it and/or
14 : : * modify it under the terms of the GNU General Public License
15 : : * as published by the Free Software Foundation; either version 2
16 : : * of the License, or (at your option) any later version.
17 : : *
18 : : * This program is distributed in the hope that it will be useful,
19 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : : * GNU General Public License for more details.
22 : : *
23 : : * You should have received a copy of the GNU General Public License
24 : : * along with this program; if not, write to the Free Software
25 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 : : * USA
27 : : *
28 : : ******************************************************************************
29 : : */
30 : : #include <sys/stat.h>
31 : :
32 : : #if HAVE_SYS_SOCKET_H
33 : : #include <sys/socket.h>
34 : : #endif
35 : :
36 : : #include "fwknopd_common.h"
37 : : #include <arpa/inet.h>
38 : : #include "pwd.h"
39 : : #include "access.h"
40 : : #include "utils.h"
41 : : #include "log_msg.h"
42 : : #include "cmd_cycle.h"
43 : : #include <dirent.h>
44 : :
45 : : #define FATAL_ERR -1
46 : :
47 : : #ifndef SUCCESS
48 : : #define SUCCESS 1
49 : : #endif
50 : :
51 : : #ifdef HAVE_C_UNIT_TESTS /* LCOV_EXCL_START */
52 : : #include "cunit_common.h"
53 : : DECLARE_TEST_SUITE(access, "Access test suite");
54 : : #endif /* LCOV_EXCL_STOP */
55 : :
56 : : /**
57 : : * \brief include keys file
58 : : *
59 : : * This function loads only the crypto keys from a given file.
60 : : * It inserts these keys into the active access stanza.
61 : : *
62 : : * \param curr_acc pointer to the current access stanza
63 : : * \param access_filename Pointer to the file containing the keys
64 : : * \param opts fko_srv_options_t Server options struct
65 : : *
66 : : */
67 : : int
68 : : include_keys_file(acc_stanza_t *, const char *, fko_srv_options_t *);
69 : :
70 : : static int do_acc_stanza_init = 1;
71 : :
72 : 7068 : void enable_acc_stanzas_init(void)
73 : : {
74 : 7068 : do_acc_stanza_init = 1;
75 : 7068 : return;
76 : : }
77 : :
78 : : /* Add an access string entry
79 : : */
80 : : static void
81 : 4195 : add_acc_string(char **var, const char *val, FILE *file_ptr,
82 : : fko_srv_options_t *opts)
83 : : {
84 [ - + ]: 4195 : if(var == NULL)
85 : : {
86 : 0 : log_msg(LOG_ERR, "[*] add_acc_string() called with NULL variable");
87 [ # # ]: 0 : if(file_ptr != NULL)
88 : 0 : fclose(file_ptr);
89 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
90 : : }
91 : :
92 [ + + ]: 4195 : if(*var != NULL)
93 : 5 : free(*var);
94 : :
95 [ - + ]: 4195 : if((*var = strdup(val)) == NULL)
96 : : {
97 : 0 : log_msg(LOG_ERR,
98 : : "[*] Fatal memory allocation error adding access list entry: %s", *var
99 : : );
100 [ # # ]: 0 : if(file_ptr != NULL)
101 : 0 : fclose(file_ptr);
102 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
103 : : }
104 : 4195 : return;
105 : : }
106 : :
107 : : /* Add an access user entry
108 : : */
109 : : static void
110 : 22 : add_acc_user(char **user_var, uid_t *uid_var, struct passwd **upw,
111 : : const char *val, const char *var_name, FILE *file_ptr,
112 : : fko_srv_options_t *opts)
113 : : {
114 : 22 : struct passwd *pw = NULL;
115 : :
116 : 22 : add_acc_string(user_var, val, file_ptr, opts);
117 : :
118 : 22 : errno = 0;
119 : 22 : *upw = pw = getpwnam(val);
120 : :
121 [ + + ][ - + ]: 22 : if(*upw == NULL || pw == NULL)
122 : : {
123 [ - + ]: 1 : log_msg(LOG_ERR, "[*] Unable to determine UID for %s: %s.",
124 : 1 : var_name, errno ? strerror(errno) : "Not a user on this system");
125 : 1 : fclose(file_ptr);
126 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
127 : : }
128 : :
129 : 21 : *uid_var = pw->pw_uid;
130 : :
131 : 21 : return;
132 : : }
133 : :
134 : : /* Add an access group entry
135 : : */
136 : : static void
137 : 9 : add_acc_group(char **group_var, gid_t *gid_var,
138 : : const char *val, const char *var_name, FILE *file_ptr,
139 : : fko_srv_options_t *opts)
140 : : {
141 : 9 : struct passwd *pw = NULL;
142 : :
143 : 9 : add_acc_string(group_var, val, file_ptr, opts);
144 : :
145 : 9 : errno = 0;
146 : 9 : pw = getpwnam(val);
147 : :
148 [ + + ]: 9 : if(pw == NULL)
149 : : {
150 [ - + ]: 1 : log_msg(LOG_ERR, "[*] Unable to determine GID for %s: %s.",
151 : 1 : var_name, errno ? strerror(errno) : "Not a group on this system");
152 : 1 : fclose(file_ptr);
153 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
154 : : }
155 : :
156 : 8 : *gid_var = pw->pw_gid;
157 : :
158 : 8 : return;
159 : : }
160 : :
161 : : /* Decode base64 encoded string into access entry
162 : : */
163 : : static void
164 : 606 : add_acc_b64_string(char **var, int *len, const char *val, FILE *file_ptr,
165 : : fko_srv_options_t *opts)
166 : : {
167 [ - + ]: 606 : if(var == NULL)
168 : : {
169 : 0 : log_msg(LOG_ERR, "[*] add_acc_b64_string() called with NULL variable");
170 [ # # ]: 0 : if(file_ptr != NULL)
171 : 0 : fclose(file_ptr);
172 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
173 : : }
174 : :
175 [ + + ]: 606 : if(*var != NULL)
176 : 2 : free(*var);
177 : :
178 [ - + ]: 606 : if((*var = strdup(val)) == NULL)
179 : : {
180 : 0 : log_msg(LOG_ERR,
181 : : "[*] Fatal memory allocation error adding access list entry: %s", *var
182 : : );
183 [ # # ]: 0 : if(file_ptr != NULL)
184 : 0 : fclose(file_ptr);
185 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
186 : : }
187 : 606 : memset(*var, 0x0, strlen(val));
188 : 606 : *len = fko_base64_decode(val, (unsigned char *) *var);
189 : :
190 [ - + ]: 606 : if (*len < 0)
191 : : {
192 : 0 : log_msg(LOG_ERR,
193 : : "[*] base64 decoding returned error for: %s", *var
194 : : );
195 [ # # ]: 0 : if(file_ptr != NULL)
196 : 0 : fclose(file_ptr);
197 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
198 : : }
199 : 606 : return;
200 : : }
201 : :
202 : : /* Add an access bool entry (unsigned char of 1 or 0)
203 : : */
204 : : static unsigned char
205 : 1835 : add_acc_bool(unsigned char *var, const char *val)
206 : : {
207 : 1835 : return(*var = (strncasecmp(val, "Y", 1) == 0) ? 1 : 0);
208 : : }
209 : :
210 : : /* Add expiration time - convert date to epoch seconds
211 : : */
212 : : static int
213 : 6 : add_acc_expire_time(fko_srv_options_t *opts, time_t *access_expire_time, const char *val)
214 : : {
215 : : struct tm tm;
216 : :
217 : : memset(&tm, 0, sizeof(struct tm));
218 : :
219 [ + + ]: 3 : if (sscanf(val, "%2d/%2d/%4d", &tm.tm_mon, &tm.tm_mday, &tm.tm_year) != 3)
220 : : {
221 : :
222 : 1 : log_msg(LOG_ERR,
223 : : "[*] Fatal: invalid date value '%s' (need MM/DD/YYYY) for access stanza expiration time",
224 : : val
225 : : );
226 : : return FATAL_ERR;
227 : : }
228 : :
229 [ + - ]: 2 : if(tm.tm_mon > 0)
230 : 2 : tm.tm_mon -= 1; /* 0-11 */
231 : :
232 : : /* number of years since 1900
233 : : */
234 [ + + ]: 2 : if(tm.tm_year > 1900)
235 : 1 : tm.tm_year -= 1900;
236 : : else
237 [ + - ]: 1 : if(tm.tm_year < 100)
238 : 1 : tm.tm_year += 100;
239 : :
240 : 2 : *access_expire_time = mktime(&tm);
241 : :
242 : : return 1;
243 : : }
244 : :
245 : : /* Add expiration time via epoch seconds defined in access.conf
246 : : */
247 : : static void
248 : 2 : add_acc_expire_time_epoch(fko_srv_options_t *opts,
249 : : time_t *access_expire_time, const char *val, FILE *file_ptr)
250 : : {
251 : : char *endptr;
252 : 2 : unsigned long expire_time = 0;
253 : :
254 : 2 : errno = 0;
255 : :
256 : 2 : expire_time = (time_t) strtoul(val, &endptr, 10);
257 : :
258 [ + + ][ - + ]: 2 : if (errno == ERANGE || (errno != 0 && expire_time == 0))
[ # # ]
259 : : {
260 : 1 : log_msg(LOG_ERR,
261 : : "[*] Fatal: invalid epoch seconds value '%s' for access stanza expiration time",
262 : : val
263 : : );
264 : 1 : fclose(file_ptr);
265 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
266 : : }
267 : :
268 : 1 : *access_expire_time = (time_t) expire_time;
269 : :
270 : 1 : return;
271 : : }
272 : :
273 : : #if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES)
274 : : static void
275 : 28 : add_acc_force_nat(fko_srv_options_t *opts, acc_stanza_t *curr_acc,
276 : : const char *val, FILE *file_ptr)
277 : : {
278 : 28 : char ip_str[MAX_IPV4_STR_LEN] = {0};
279 : :
280 [ + + ]: 28 : if (sscanf(val, "%15s %5u", ip_str, &curr_acc->force_nat_port) != 2)
281 : : {
282 : 2 : log_msg(LOG_ERR,
283 : : "[*] Fatal: invalid FORCE_NAT arg '%s', need <IP> <PORT>",
284 : : val
285 : : );
286 [ + - ]: 2 : if(file_ptr != NULL)
287 : 2 : fclose(file_ptr);
288 : 2 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
289 : : }
290 : :
291 [ + + ]: 26 : if (curr_acc->force_nat_port > MAX_PORT)
292 : : {
293 : 1 : log_msg(LOG_ERR,
294 : : "[*] Fatal: invalid FORCE_NAT port '%d'", curr_acc->force_nat_port);
295 [ + - ]: 1 : if(file_ptr != NULL)
296 : 1 : fclose(file_ptr);
297 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
298 : : }
299 : :
300 [ + + ]: 25 : if(! is_valid_ipv4_addr(ip_str, strlen(ip_str)))
301 : : {
302 : 1 : log_msg(LOG_ERR,
303 : : "[*] Fatal: invalid FORCE_NAT IP '%s'", ip_str);
304 [ + - ]: 1 : if(file_ptr != NULL)
305 : 1 : fclose(file_ptr);
306 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
307 : : }
308 : :
309 : 24 : curr_acc->force_nat = 1;
310 : :
311 : 24 : add_acc_string(&(curr_acc->force_nat_ip), ip_str, file_ptr, opts);
312 : 24 : return;
313 : : }
314 : :
315 : : static void
316 : 12 : add_acc_force_snat(fko_srv_options_t *opts, acc_stanza_t *curr_acc,
317 : : const char *val, FILE *file_ptr)
318 : : {
319 : 12 : char ip_str[MAX_IPV4_STR_LEN] = {0};
320 : :
321 [ - + ]: 12 : if (sscanf(val, "%15s", ip_str) != 1)
322 : : {
323 : 0 : log_msg(LOG_ERR,
324 : : "[*] Fatal: invalid FORCE_SNAT arg '%s', need <IP>", val);
325 [ # # ]: 0 : if(file_ptr != NULL)
326 : 0 : fclose(file_ptr);
327 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
328 : : }
329 : :
330 [ + + ]: 12 : if(! is_valid_ipv4_addr(ip_str, strlen(ip_str)))
331 : : {
332 : 2 : log_msg(LOG_ERR,
333 : : "[*] Fatal: invalid FORCE_SNAT IP '%s'", ip_str);
334 [ + - ]: 2 : if(file_ptr != NULL)
335 : 2 : fclose(file_ptr);
336 : 2 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
337 : : }
338 : :
339 : 10 : curr_acc->force_snat = 1;
340 : :
341 : 10 : add_acc_string(&(curr_acc->force_snat_ip), ip_str, file_ptr, opts);
342 : 10 : return;
343 : : }
344 : :
345 : : #endif
346 : :
347 : : /* Take an IP or Subnet/Mask and convert it to mask for later
348 : : * comparisons of incoming source IPs against this mask.
349 : : */
350 : : static int
351 : 1809 : add_int_ent(acc_int_list_t **ilist, const char *ip)
352 : : {
353 : : char *ndx;
354 : 1809 : char ip_str[MAX_IPV4_STR_LEN] = {0};
355 : 1809 : char ip_mask_str[MAX_IPV4_STR_LEN] = {0};
356 : : uint32_t mask;
357 : 1809 : int is_err, mask_len = 0, need_shift = 1;
358 : :
359 : : struct in_addr in;
360 : : struct in_addr mask_in;
361 : :
362 : : acc_int_list_t *last_sle, *new_sle, *tmp_sle;
363 : :
364 [ + + ]: 1809 : if((new_sle = calloc(1, sizeof(acc_int_list_t))) == NULL)
365 : : {
366 : 2 : log_msg(LOG_ERR,
367 : : "[*] Fatal memory allocation error adding stanza source_list entry"
368 : : );
369 : 2 : exit(EXIT_FAILURE);
370 : : }
371 : :
372 : : /* Convert the IP data into the appropriate IP + (optional) mask
373 : : */
374 [ + + ]: 1807 : if(strcasecmp(ip, "ANY") == 0)
375 : : {
376 : 1582 : new_sle->maddr = 0x0;
377 : 1582 : new_sle->mask = 0x0;
378 : : }
379 : : else
380 : : {
381 : : /* See if we have a subnet component. If so pull out the IP and
382 : : * mask values, then create the final mask value.
383 : : */
384 [ + + ]: 225 : if((ndx = strchr(ip, '/')) != NULL)
385 : : {
386 [ + + ]: 142 : if(((ndx-ip)) >= MAX_IPV4_STR_LEN)
387 : : {
388 : 1 : log_msg(LOG_ERR, "[*] Error parsing string to IP");
389 : 1 : free(new_sle);
390 : 1 : new_sle = NULL;
391 : 1 : return 0;
392 : : }
393 : :
394 : 141 : mask_len = strlen(ip) - (ndx-ip+1);
395 : :
396 [ + + ]: 141 : if(mask_len > 2)
397 : : {
398 [ + + ]: 11 : if(mask_len >= MIN_IPV4_STR_LEN && mask_len < MAX_IPV4_STR_LEN)
399 : : {
400 : : /* IP formatted mask
401 : : */
402 : 9 : strlcpy(ip_mask_str, (ip + (ndx-ip) + 1), mask_len+1);
403 [ + + ]: 9 : if(inet_aton(ip_mask_str, &mask_in) == 0)
404 : : {
405 : 6 : log_msg(LOG_ERR,
406 : : "[*] Fatal error parsing IP mask to int for: %s", ip_mask_str
407 : : );
408 : 6 : free(new_sle);
409 : 6 : new_sle = NULL;
410 : 6 : return 0;
411 : : }
412 : 3 : mask = ntohl(mask_in.s_addr);
413 : 3 : need_shift = 0;
414 : : }
415 : : else
416 : : {
417 : 2 : log_msg(LOG_ERR, "[*] Invalid IP mask str '%s'.", ndx+1);
418 : 2 : free(new_sle);
419 : 2 : new_sle = NULL;
420 : 2 : return 0;
421 : : }
422 : : }
423 : : else
424 : : {
425 [ + + ]: 130 : if(mask_len > 0)
426 : : {
427 : : /* CIDR mask
428 : : */
429 : 128 : mask = strtol_wrapper(ndx+1, 1, 32, NO_EXIT_UPON_ERR, &is_err);
430 [ + + ]: 128 : if(is_err != FKO_SUCCESS)
431 : : {
432 : 6 : log_msg(LOG_ERR, "[*] Invalid IP mask str '%s'.", ndx+1);
433 : 6 : free(new_sle);
434 : 6 : new_sle = NULL;
435 : 6 : return 0;
436 : : }
437 : : }
438 : : else
439 : : {
440 : 2 : log_msg(LOG_ERR, "[*] Missing mask value.");
441 : 2 : free(new_sle);
442 : 2 : new_sle = NULL;
443 : 2 : return 0;
444 : : }
445 : : }
446 : :
447 : 125 : strlcpy(ip_str, ip, (ndx-ip)+1);
448 : : }
449 : : else
450 : : {
451 : 83 : mask = 32;
452 [ + + ]: 83 : if(strnlen(ip, MAX_IPV4_STR_LEN+1) >= MAX_IPV4_STR_LEN)
453 : : {
454 : 2 : log_msg(LOG_ERR, "[*] Error parsing string to IP");
455 : 2 : free(new_sle);
456 : 2 : new_sle = NULL;
457 : 2 : return 0;
458 : : }
459 : 81 : strlcpy(ip_str, ip, sizeof(ip_str));
460 : : }
461 : :
462 [ + + ]: 206 : if(inet_aton(ip_str, &in) == 0)
463 : : {
464 : 1 : log_msg(LOG_ERR,
465 : : "[*] Fatal error parsing IP to int for: %s", ip_str
466 : : );
467 : :
468 : 1 : free(new_sle);
469 : 1 : new_sle = NULL;
470 : :
471 : 1 : return 0;
472 : : }
473 : :
474 : : /* Store our mask converted from CIDR to a 32-bit value.
475 : : */
476 [ + + ]: 205 : if(mask == 32)
477 : 82 : new_sle->mask = 0xFFFFFFFF;
478 [ + + ][ + - ]: 123 : else if(need_shift && (mask > 0 && mask < 32))
479 : 120 : new_sle->mask = (0xFFFFFFFF << (32 - mask));
480 : : else
481 : 3 : new_sle->mask = mask;
482 : :
483 : : /* Store our masked address for comparisons with future incoming
484 : : * packets.
485 : : */
486 : 205 : new_sle->maddr = ntohl(in.s_addr) & new_sle->mask;
487 : : }
488 : :
489 : : /* If this is not the first entry, we walk our pointer to the
490 : : * end of the list.
491 : : */
492 [ + + ]: 1787 : if(*ilist == NULL)
493 : : {
494 : 1787 : *ilist = new_sle;
495 : : }
496 : : else
497 : : {
498 : : tmp_sle = *ilist;
499 : :
500 : : do {
501 : 276 : last_sle = tmp_sle;
502 [ + + ]: 276 : } while((tmp_sle = tmp_sle->next));
503 : :
504 : 125 : last_sle->next = new_sle;
505 : : }
506 : :
507 : : return 1;
508 : : }
509 : :
510 : : /* Expand the access SOURCE string to a list of masks.
511 : : */
512 : : static int
513 : 1682 : expand_acc_int_list(acc_int_list_t **ilist, char *ip)
514 : : {
515 : : char *ndx, *start;
516 : 1682 : char buf[ACCESS_BUF_LEN] = {0};
517 : 1682 : int res = 1;
518 : :
519 : 1682 : start = ip;
520 : :
521 [ + + ]: 9342 : for(ndx = start; *ndx; ndx++)
522 : : {
523 [ + + ]: 7663 : if(*ndx == ',')
524 : : {
525 : : /* Skip over any leading whitespace.
526 : : */
527 [ + + ]: 217 : while(isspace(*start))
528 : 87 : start++;
529 : :
530 [ + - ]: 130 : if(((ndx-start)+1) >= ACCESS_BUF_LEN)
531 : : return 0;
532 : :
533 : 130 : strlcpy(buf, start, (ndx-start)+1);
534 : :
535 : 130 : res = add_int_ent(ilist, buf);
536 [ + + ]: 130 : if(res == 0)
537 : 3 : return res;
538 : :
539 : 127 : start = ndx+1;
540 : : }
541 : : }
542 : :
543 : : /* Skip over any leading whitespace (once again for the last in the list).
544 : : */
545 [ + + ]: 1719 : while(isspace(*start))
546 : 40 : start++;
547 : :
548 [ + - ]: 1679 : if(((ndx-start)+1) >= ACCESS_BUF_LEN)
549 : : return 0;
550 : :
551 : 1679 : strlcpy(buf, start, (ndx-start)+1);
552 : :
553 : 1679 : res = add_int_ent(ilist, buf);
554 : :
555 : 1677 : return res;
556 : : }
557 : :
558 : : static int
559 : 1995 : parse_proto_and_port(char *pstr, int *proto, int *port)
560 : : {
561 : : char *ndx;
562 : 1995 : char proto_str[ACCESS_BUF_LEN] = {0};
563 : : int is_err;
564 : :
565 : : /* Parse the string into its components.
566 : : */
567 [ + + ]: 1995 : if((ndx = strchr(pstr, '/')) == NULL)
568 : : {
569 : 1 : log_msg(LOG_ERR,
570 : : "[*] Parse error on access port entry: %s", pstr);
571 : :
572 : 1 : return(-1);
573 : : }
574 : :
575 [ - + ]: 1994 : if(((ndx - pstr)+1) >= ACCESS_BUF_LEN)
576 : : {
577 : 0 : log_msg(LOG_ERR,
578 : : "[*] Parse error on access port entry: %s", pstr);
579 : 0 : return(-1);
580 : : }
581 : :
582 : 1994 : strlcpy(proto_str, pstr, (ndx - pstr)+1);
583 : :
584 : 1994 : *port = strtol_wrapper(ndx+1, 0, MAX_PORT, NO_EXIT_UPON_ERR, &is_err);
585 [ + + ]: 1994 : if(is_err != FKO_SUCCESS)
586 : : {
587 : 1 : log_msg(LOG_ERR,
588 : : "[*] Invalid port '%s' in access request, must be in [%d,%d]",
589 : : pstr, 0, MAX_PORT);
590 : 1 : return(-1);
591 : : }
592 : :
593 [ + + ]: 1993 : if(strcasecmp(proto_str, "tcp") == 0)
594 : 1878 : *proto = PROTO_TCP;
595 [ + + ]: 115 : else if(strcasecmp(proto_str, "udp") == 0)
596 : 113 : *proto = PROTO_UDP;
597 : : else
598 : : {
599 : 2 : log_msg(LOG_ERR,
600 : : "[*] Invalid protocol in access port entry: %s", pstr);
601 : 2 : return(-1);
602 : : }
603 : :
604 : : return(0);
605 : : }
606 : :
607 : : /* Take a proto/port string and convert it to appropriate integer values
608 : : * for comparisons of incoming SPA requests.
609 : : */
610 : : static int
611 : 1995 : add_port_list_ent(acc_port_list_t **plist, char *port_str)
612 : : {
613 : : int proto_int, port;
614 : :
615 : : acc_port_list_t *last_plist, *new_plist, *tmp_plist;
616 : :
617 : : /* Parse the string into its components and continue only if there
618 : : * are no problems with the incoming string.
619 : : */
620 [ + + ]: 1995 : if(parse_proto_and_port(port_str, &proto_int, &port) != 0)
621 : : return 0;
622 : :
623 [ - + ]: 1991 : if((new_plist = calloc(1, sizeof(acc_port_list_t))) == NULL)
624 : : {
625 : 0 : log_msg(LOG_ERR,
626 : : "[*] Fatal memory allocation error adding stanza port_list entry"
627 : : );
628 : 0 : exit(EXIT_FAILURE);
629 : : }
630 : :
631 : : /* If this is not the first entry, we walk our pointer to the
632 : : * end of the list.
633 : : */
634 [ + + ]: 1991 : if(*plist == NULL)
635 : : {
636 : 1991 : *plist = new_plist;
637 : : }
638 : : else
639 : : {
640 : : tmp_plist = *plist;
641 : :
642 : : do {
643 : 213 : last_plist = tmp_plist;
644 [ + + ]: 213 : } while((tmp_plist = tmp_plist->next));
645 : :
646 : 145 : last_plist->next = new_plist;
647 : : }
648 : :
649 : 1991 : new_plist->proto = proto_int;
650 : 1991 : new_plist->port = port;
651 : :
652 : 1991 : return 1;
653 : : }
654 : :
655 : : /* Add a string list entry to the given acc_string_list.
656 : : */
657 : : static int
658 : 127 : add_string_list_ent(acc_string_list_t **stlist, const char *str_str)
659 : : {
660 : : acc_string_list_t *last_stlist, *new_stlist, *tmp_stlist;
661 : :
662 [ - + ]: 127 : if((new_stlist = calloc(1, sizeof(acc_string_list_t))) == NULL)
663 : : {
664 : 0 : log_msg(LOG_ERR,
665 : : "[*] Fatal memory allocation error creating string list entry"
666 : : );
667 : 0 : return FATAL_ERR;
668 : : }
669 : :
670 : : /* If this is not the first entry, we walk our pointer to the
671 : : * end of the list.
672 : : */
673 [ + + ]: 127 : if(*stlist == NULL)
674 : : {
675 : 127 : *stlist = new_stlist;
676 : : }
677 : : else
678 : : {
679 : : tmp_stlist = *stlist;
680 : :
681 : : do {
682 : 75 : last_stlist = tmp_stlist;
683 [ + + ]: 75 : } while((tmp_stlist = tmp_stlist->next));
684 : :
685 : 50 : last_stlist->next = new_stlist;
686 : : }
687 : :
688 [ - + ]: 127 : if(new_stlist->str != NULL)
689 : 0 : free(new_stlist->str);
690 : :
691 : 127 : new_stlist->str = strdup(str_str);
692 : :
693 [ - + ]: 127 : if(new_stlist->str == NULL)
694 : : {
695 : 0 : log_msg(LOG_ERR,
696 : : "[*] Fatal memory allocation error adding string list entry item"
697 : : );
698 : 0 : return FATAL_ERR;
699 : : }
700 : : return SUCCESS;
701 : : }
702 : :
703 : : /* Expand a proto/port access string to a list of access proto-port struct.
704 : : */
705 : : int
706 : 1244 : expand_acc_port_list(acc_port_list_t **plist, char *plist_str)
707 : : {
708 : : char *ndx, *start;
709 : 1244 : char buf[ACCESS_BUF_LEN] = {0};
710 : :
711 : 1244 : start = plist_str;
712 : :
713 [ + + ]: 9573 : for(ndx = start; *ndx != '\0'; ndx++)
714 : : {
715 [ + + ]: 8330 : if(*ndx == ',')
716 : : {
717 : : /* Skip over any leading whitespace.
718 : : */
719 [ + + ]: 128 : while(isspace(*start))
720 : 47 : start++;
721 : :
722 [ + - ]: 81 : if(((ndx-start)+1) >= ACCESS_BUF_LEN)
723 : : return 0;
724 : :
725 : 81 : strlcpy(buf, start, (ndx-start)+1);
726 : :
727 [ + + ]: 81 : if(add_port_list_ent(plist, buf) == 0)
728 : : return 0;
729 : :
730 : 80 : start = ndx+1;
731 : : }
732 : : }
733 : :
734 : : /* Skip over any leading whitespace (once again for the last in the list).
735 : : */
736 [ + + ]: 1268 : while(isspace(*start))
737 : 25 : start++;
738 : :
739 [ + + ]: 1243 : if(((ndx-start)+1) >= ACCESS_BUF_LEN)
740 : : return 0;
741 : :
742 : 1242 : strlcpy(buf, start, (ndx-start)+1);
743 : :
744 [ + + ]: 1242 : if(add_port_list_ent(plist, buf) == 0)
745 : : return 0;
746 : :
747 : 1239 : return 1;
748 : : }
749 : :
750 : : /* Expand a comma-separated string into a simple acc_string_list.
751 : : */
752 : : static int
753 : 77 : expand_acc_string_list(acc_string_list_t **stlist, char *stlist_str)
754 : : {
755 : : char *ndx, *start;
756 : 77 : char buf[MAX_LINE_LEN] = {0};
757 : :
758 : 77 : start = stlist_str;
759 : :
760 [ + + ]: 1321 : for(ndx = start; *ndx; ndx++)
761 : : {
762 [ + + ]: 1244 : if(*ndx == ',')
763 : : {
764 : : /* Skip over any leading whitespace.
765 : : */
766 [ + + ]: 75 : while(isspace(*start))
767 : 25 : start++;
768 : :
769 [ + - ]: 50 : if(((ndx-start)+1) >= MAX_LINE_LEN)
770 : : return FATAL_ERR;
771 : :
772 : 50 : strlcpy(buf, start, (ndx-start)+1);
773 [ + - ]: 50 : if(add_string_list_ent(stlist, buf) != SUCCESS)
774 : : return FATAL_ERR;
775 : :
776 : 50 : start = ndx+1;
777 : : }
778 : : }
779 : :
780 : : /* Skip over any leading whitespace (once again for the last in the list).
781 : : */
782 [ + + ]: 102 : while(isspace(*start))
783 : 25 : start++;
784 : :
785 [ + - ]: 77 : if(((ndx-start)+1) >= MAX_LINE_LEN)
786 : : return FATAL_ERR;
787 : :
788 : 77 : strlcpy(buf, start, (ndx-start)+1);
789 : :
790 [ + - ]: 77 : if(add_string_list_ent(stlist, buf) != SUCCESS)
791 : : return FATAL_ERR;
792 : :
793 : 77 : return SUCCESS;
794 : : }
795 : :
796 : : /* Free the acc source_list
797 : : */
798 : : static void
799 : 1739 : free_acc_int_list(acc_int_list_t *sle)
800 : : {
801 : : acc_int_list_t *last_sle;
802 : :
803 [ + + ]: 3523 : while(sle != NULL)
804 : : {
805 : 1784 : last_sle = sle;
806 : 1784 : sle = last_sle->next;
807 : :
808 : 1784 : free(last_sle);
809 : : }
810 : 1739 : }
811 : :
812 : : /* Free a port_list
813 : : */
814 : : void
815 : 1851 : free_acc_port_list(acc_port_list_t *ple)
816 : : {
817 : : acc_port_list_t *last_ple;
818 : :
819 [ + + ]: 3833 : while(ple != NULL)
820 : : {
821 : 1982 : last_ple = ple;
822 : 1982 : ple = last_ple->next;
823 : :
824 : 1982 : free(last_ple);
825 : : }
826 : 1851 : }
827 : :
828 : : /* Free a string_list
829 : : */
830 : : static void
831 : 77 : free_acc_string_list(acc_string_list_t *stl)
832 : : {
833 : : acc_string_list_t *last_stl;
834 : :
835 [ + + ]: 204 : while(stl != NULL)
836 : : {
837 : 127 : last_stl = stl;
838 : 127 : stl = last_stl->next;
839 : :
840 : 127 : free(last_stl->str);
841 : 127 : free(last_stl);
842 : : }
843 : 77 : }
844 : :
845 : : static void
846 : 2561 : zero_buf_wrapper(char *buf, int len)
847 : : {
848 : :
849 [ - + ]: 2561 : if(zero_buf(buf, len) != FKO_SUCCESS)
850 : 0 : log_msg(LOG_ERR,
851 : : "[*] Could not zero out sensitive data buffer.");
852 : :
853 : 2561 : return;
854 : : }
855 : :
856 : : /* Free any allocated content of an access stanza.
857 : : *
858 : : * NOTE: If a new access.conf parameter is created, and it is a string
859 : : * value, it also needs to be added to the list of items to check
860 : : * and free below.
861 : : */
862 : : static void
863 : 1719 : free_acc_stanza_data(acc_stanza_t *acc)
864 : : {
865 : :
866 [ + - ]: 1719 : if(acc->source != NULL)
867 : : {
868 : 1719 : free(acc->source);
869 : 1719 : free_acc_int_list(acc->source_list);
870 : : }
871 : :
872 [ + + ]: 1719 : if(acc->destination != NULL)
873 : : {
874 : 20 : free(acc->destination);
875 : 20 : free_acc_int_list(acc->destination_list);
876 : : }
877 : :
878 [ + + ]: 1719 : if(acc->open_ports != NULL)
879 : : {
880 : 37 : free(acc->open_ports);
881 : 37 : free_acc_port_list(acc->oport_list);
882 : : }
883 : :
884 [ + + ]: 1719 : if(acc->restrict_ports != NULL)
885 : : {
886 : 1 : free(acc->restrict_ports);
887 : 1 : free_acc_port_list(acc->rport_list);
888 : : }
889 : :
890 [ + + ]: 1719 : if(acc->force_nat_ip != NULL)
891 : 24 : free(acc->force_nat_ip);
892 : :
893 [ + + ]: 1719 : if(acc->force_snat_ip != NULL)
894 : 10 : free(acc->force_snat_ip);
895 : :
896 [ + + ]: 1719 : if(acc->key != NULL)
897 : : {
898 : 1639 : zero_buf_wrapper(acc->key, acc->key_len);
899 : 1639 : free(acc->key);
900 : : }
901 : :
902 [ + + ]: 1719 : if(acc->key_base64 != NULL)
903 : : {
904 : 284 : zero_buf_wrapper(acc->key_base64, strlen(acc->key_base64));
905 : 284 : free(acc->key_base64);
906 : : }
907 : :
908 [ + + ]: 1719 : if(acc->hmac_key != NULL)
909 : : {
910 : 326 : zero_buf_wrapper(acc->hmac_key, acc->hmac_key_len);
911 : 326 : free(acc->hmac_key);
912 : : }
913 : :
914 [ + + ]: 1719 : if(acc->hmac_key_base64 != NULL)
915 : : {
916 : 312 : zero_buf_wrapper(acc->hmac_key_base64, strlen(acc->hmac_key_base64));
917 : 312 : free(acc->hmac_key_base64);
918 : : }
919 : :
920 [ + + ]: 1719 : if(acc->cmd_sudo_exec_user != NULL)
921 : 9 : free(acc->cmd_sudo_exec_user);
922 : :
923 [ + + ]: 1719 : if(acc->cmd_sudo_exec_group != NULL)
924 : 3 : free(acc->cmd_sudo_exec_group);
925 : :
926 [ + + ]: 1719 : if(acc->cmd_exec_user != NULL)
927 : 13 : free(acc->cmd_exec_user);
928 : :
929 [ + + ]: 1719 : if(acc->cmd_exec_group != NULL)
930 : 6 : free(acc->cmd_exec_group);
931 : :
932 [ + + ]: 1719 : if(acc->require_username != NULL)
933 : 15 : free(acc->require_username);
934 : :
935 [ + + ]: 1719 : if(acc->cmd_cycle_open != NULL)
936 : 25 : free(acc->cmd_cycle_open);
937 : :
938 [ + + ]: 1719 : if(acc->cmd_cycle_close != NULL)
939 : 25 : free(acc->cmd_cycle_close);
940 : :
941 [ + + ]: 1719 : if(acc->gpg_home_dir != NULL)
942 : 77 : free(acc->gpg_home_dir);
943 : :
944 [ + + ]: 1719 : if(acc->gpg_exe != NULL)
945 : 1 : free(acc->gpg_exe);
946 : :
947 [ + + ]: 1719 : if(acc->gpg_decrypt_id != NULL)
948 : 77 : free(acc->gpg_decrypt_id);
949 : :
950 [ + + ]: 1719 : if(acc->gpg_decrypt_pw != NULL)
951 : 79 : free(acc->gpg_decrypt_pw);
952 : :
953 [ + + ]: 1719 : if(acc->gpg_remote_id != NULL)
954 : : {
955 : 72 : free(acc->gpg_remote_id);
956 : 72 : free_acc_string_list(acc->gpg_remote_id_list);
957 : : }
958 [ + + ]: 1719 : if(acc->gpg_remote_fpr != NULL)
959 : : {
960 : 5 : free(acc->gpg_remote_fpr);
961 : 5 : free_acc_string_list(acc->gpg_remote_fpr_list);
962 : : }
963 : 1719 : return;
964 : : }
965 : :
966 : : /* Expand any access entries that may be multi-value.
967 : : */
968 : : static void
969 : 1613 : expand_acc_ent_lists(fko_srv_options_t *opts)
970 : : {
971 : 1613 : acc_stanza_t *acc = opts->acc_stanzas;
972 : :
973 : : /* We need to do this for each stanza.
974 : : */
975 [ + + ]: 3249 : while(acc)
976 : : {
977 : : /* Expand the source string to 32-bit integer IP + masks for each entry.
978 : : */
979 [ + + ]: 1663 : if(expand_acc_int_list(&(acc->source_list), acc->source) == 0)
980 : : {
981 : 11 : log_msg(LOG_ERR, "[*] Fatal invalid SOURCE in access stanza");
982 : 11 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
983 : : }
984 : :
985 [ + + ][ + - ]: 1650 : if(acc->destination != NULL && strlen(acc->destination))
986 : : {
987 [ + + ]: 19 : if(expand_acc_int_list(&(acc->destination_list), acc->destination) == 0)
988 : : {
989 : 9 : log_msg(LOG_ERR, "[*] Fatal invalid DESTINATION in access stanza");
990 : 9 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
991 : : }
992 : : }
993 : :
994 : : /* Now expand the open_ports string.
995 : : */
996 [ + + ][ + - ]: 1641 : if(acc->open_ports != NULL && strlen(acc->open_ports))
997 : : {
998 [ + + ]: 34 : if(expand_acc_port_list(&(acc->oport_list), acc->open_ports) == 0)
999 : : {
1000 : 4 : log_msg(LOG_ERR, "[*] Fatal invalid OPEN_PORTS in access stanza");
1001 : 4 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1002 : : }
1003 : : }
1004 : :
1005 [ + + ][ + - ]: 1637 : if(acc->restrict_ports != NULL && strlen(acc->restrict_ports))
1006 : : {
1007 [ + - ]: 1 : if(expand_acc_port_list(&(acc->rport_list), acc->restrict_ports) == 0)
1008 : : {
1009 : 1 : log_msg(LOG_ERR, "[*] Fatal invalid RESTRICT_PORTS in access stanza");
1010 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1011 : : }
1012 : : }
1013 : :
1014 : : /* Expand the GPG_REMOTE_ID string.
1015 : : */
1016 [ + + ][ + - ]: 1636 : if(acc->gpg_remote_id != NULL && strlen(acc->gpg_remote_id))
1017 : : {
1018 [ - + ]: 72 : if(expand_acc_string_list(&(acc->gpg_remote_id_list),
1019 : : acc->gpg_remote_id) != SUCCESS)
1020 : : {
1021 : 0 : log_msg(LOG_ERR, "[*] Fatal invalid GPG_REMOTE_ID list in access stanza");
1022 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1023 : : }
1024 : : }
1025 : :
1026 : : /* Expand the GPG_FINGERPRINT_ID string.
1027 : : */
1028 [ + + ][ + - ]: 1636 : if(acc->gpg_remote_fpr != NULL && strlen(acc->gpg_remote_fpr))
1029 : : {
1030 [ - + ]: 5 : if(expand_acc_string_list(&(acc->gpg_remote_fpr_list),
1031 : : acc->gpg_remote_fpr) != SUCCESS)
1032 : : {
1033 : 0 : log_msg(LOG_ERR, "[*] Fatal invalid GPG_FINGERPRINT_ID list in access stanza");
1034 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1035 : : }
1036 : : }
1037 : :
1038 : 1636 : acc = acc->next;
1039 : : }
1040 : 1586 : return;
1041 : : }
1042 : :
1043 : : void
1044 : 8782 : free_acc_stanzas(fko_srv_options_t *opts)
1045 : : {
1046 : : acc_stanza_t *acc, *last_acc;
1047 : :
1048 : : /* Free any resources first (in case of reconfig). Assume non-NULL
1049 : : * entry needs to be freed.
1050 : : */
1051 : 8782 : acc = opts->acc_stanzas;
1052 : :
1053 [ + + ]: 10489 : while(acc != NULL)
1054 : : {
1055 : 1707 : last_acc = acc;
1056 : 1707 : acc = last_acc->next;
1057 : :
1058 : 1707 : free_acc_stanza_data(last_acc);
1059 : 1707 : free(last_acc);
1060 : : }
1061 : :
1062 : 8782 : return;
1063 : : }
1064 : :
1065 : : /**
1066 : : * \brief Frees the final access stanza
1067 : : *
1068 : : * This function walks the access stanza list and frees the last member
1069 : : *
1070 : : * \param opts pointer to the server options struct
1071 : : *
1072 : : */
1073 : :
1074 : : void
1075 : 12 : free_last_acc_stanza(fko_srv_options_t *opts)
1076 : : {
1077 : 12 : acc_stanza_t *tmp_root = opts->acc_stanzas;
1078 : :
1079 : : //deal with edge cases first, like a null list
1080 [ + - ]: 12 : if (tmp_root == NULL)
1081 : : return;
1082 : :
1083 : : //check for only one element
1084 [ + + ]: 12 : if (tmp_root->next == NULL)
1085 : : {
1086 : 10 : free_acc_stanza_data(tmp_root);
1087 : 10 : free(tmp_root);
1088 : 10 : opts->acc_stanzas = NULL;
1089 : 10 : return;
1090 : : }
1091 : :
1092 : : //more than one element uses the general case
1093 [ - + ]: 2 : while (tmp_root->next->next != NULL)
1094 : : {
1095 : : tmp_root = tmp_root->next;
1096 : : }
1097 : :
1098 : 2 : free_acc_stanza_data(tmp_root->next);
1099 : 2 : free(tmp_root->next);
1100 : 2 : tmp_root->next = NULL;
1101 : 2 : return;
1102 : : }
1103 : :
1104 : : /* Wrapper for free_acc_stanzas(), we may put additional initialization
1105 : : * code here.
1106 : : */
1107 : : static void
1108 : 1687 : acc_stanza_init(fko_srv_options_t *opts)
1109 : : {
1110 [ + + ]: 1687 : if(do_acc_stanza_init)
1111 : : {
1112 : 1666 : log_msg(LOG_DEBUG, "Initialize access stanzas");
1113 : :
1114 : : /* Free any resources first (in case of reconfig). Assume non-NULL
1115 : : * entry needs to be freed.
1116 : : */
1117 : 1666 : free_acc_stanzas(opts);
1118 : :
1119 : : /* Make sure to only initialize access stanzas once.
1120 : : */
1121 : 1666 : do_acc_stanza_init = 0;
1122 : : }
1123 : :
1124 : 1687 : return;
1125 : : }
1126 : :
1127 : : /* Add a new stanza bay allocating the required memory at the required
1128 : : * location, yada-yada-yada.
1129 : : */
1130 : : static acc_stanza_t*
1131 : 1724 : acc_stanza_add(fko_srv_options_t *opts)
1132 : : {
1133 : 1724 : acc_stanza_t *acc = opts->acc_stanzas;
1134 : 1724 : acc_stanza_t *new_acc = calloc(1, sizeof(acc_stanza_t));
1135 : : acc_stanza_t *last_acc;
1136 : :
1137 [ + + ]: 1724 : if(new_acc == NULL)
1138 : : {
1139 : 4 : log_msg(LOG_ERR,
1140 : : "[*] Fatal memory allocation error adding access stanza"
1141 : : );
1142 : 4 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1143 : : }
1144 : :
1145 : : /* If this is not the first acc entry, we walk our acc pointer to the
1146 : : * end of the existing list.
1147 : : */
1148 [ + + ]: 1720 : if(acc == NULL)
1149 : : {
1150 : 1720 : opts->acc_stanzas = new_acc;
1151 : : }
1152 : : else
1153 : : {
1154 : : do {
1155 : 162 : last_acc = acc;
1156 [ + + ]: 162 : } while((acc = acc->next));
1157 : :
1158 : 58 : last_acc->next = new_acc;
1159 : : }
1160 : :
1161 : 1720 : return(new_acc);
1162 : : }
1163 : :
1164 : : /* Scan the access options for entries that have not been set, but need
1165 : : * a default value.
1166 : : */
1167 : : static void
1168 : 1586 : set_acc_defaults(fko_srv_options_t *opts)
1169 : : {
1170 : 1586 : acc_stanza_t *acc = opts->acc_stanzas;
1171 : 1586 : int i=1;
1172 : :
1173 [ + - ]: 1586 : if(!acc)
1174 : : return;
1175 : :
1176 [ + + ]: 3221 : while(acc)
1177 : : {
1178 : : /* set default fw_access_timeout if necessary
1179 : : */
1180 [ + + ]: 1636 : if(acc->fw_access_timeout < 1)
1181 : 67 : acc->fw_access_timeout = DEF_FW_ACCESS_TIMEOUT;
1182 : :
1183 : : /* set default gpg keyring path if necessary
1184 : : */
1185 [ + + ]: 1636 : if(acc->gpg_decrypt_pw != NULL)
1186 : : {
1187 [ + + ]: 77 : if(acc->gpg_home_dir == NULL)
1188 : 2 : add_acc_string(&(acc->gpg_home_dir),
1189 : 2 : opts->config[CONF_GPG_HOME_DIR], NULL, opts);
1190 : :
1191 [ + + ]: 77 : if(! acc->gpg_require_sig)
1192 : : {
1193 [ + + ]: 75 : if (acc->gpg_disable_sig)
1194 : : {
1195 : 1 : log_msg(LOG_INFO,
1196 : : "Warning: GPG_REQUIRE_SIG should really be enabled for stanza source: '%s' (#%d)",
1197 : : acc->source, i
1198 : : );
1199 : : }
1200 : : else
1201 : : {
1202 : : /* Make this the default unless explicitly disabled
1203 : : */
1204 : 74 : acc->gpg_require_sig = 1;
1205 : : }
1206 : : }
1207 : : else
1208 : : {
1209 [ + - ]: 2 : if (acc->gpg_disable_sig)
1210 : : {
1211 : 2 : log_msg(LOG_INFO,
1212 : : "Warning: GPG_REQUIRE_SIG and GPG_DISABLE_SIG are both set, will check sigs (stanza source: '%s' #%d)",
1213 : : acc->source, i
1214 : : );
1215 : : }
1216 : : }
1217 : :
1218 : : /* If signature checking is enabled, make sure we either have sig ID's or
1219 : : * fingerprint ID's to check
1220 : : */
1221 [ + + ]: 77 : if(! acc->gpg_disable_sig
1222 [ + + ][ + + ]: 74 : && (acc->gpg_remote_id == NULL && acc->gpg_remote_fpr == NULL))
1223 : : {
1224 : 1 : log_msg(LOG_INFO,
1225 : : "Warning: Must have either sig ID's or fingerprints to check via GPG_REMOTE_ID or GPG_FINGERPRINT_ID (stanza source: '%s' #%d)",
1226 : : acc->source, i
1227 : : );
1228 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1229 : : }
1230 : : }
1231 : :
1232 [ + + ]: 1635 : if(acc->encryption_mode == FKO_ENC_MODE_UNKNOWN)
1233 : 1607 : acc->encryption_mode = FKO_DEFAULT_ENC_MODE;
1234 : :
1235 : : /* if we're using an HMAC key and the HMAC digest type was not
1236 : : * set for HMAC_DIGEST_TYPE, then assume it's SHA256
1237 : : */
1238 : :
1239 [ + + ]: 1635 : if(acc->hmac_type == FKO_HMAC_UNKNOWN
1240 [ + + ][ + - ]: 1572 : && acc->hmac_key_len > 0 && acc->hmac_key != NULL)
1241 : : {
1242 : 260 : acc->hmac_type = FKO_DEFAULT_HMAC_MODE;
1243 : : }
1244 : :
1245 : 1635 : acc = acc->next;
1246 : 1635 : i++;
1247 : : }
1248 : : return;
1249 : : }
1250 : :
1251 : : /* Perform some sanity checks on an acc stanza data.
1252 : : */
1253 : : static int
1254 : 1703 : acc_data_is_valid(fko_srv_options_t *opts,
1255 : : struct passwd *user_pw, struct passwd *sudo_user_pw,
1256 : : acc_stanza_t * const acc)
1257 : : {
1258 [ - + ]: 1703 : if(acc == NULL)
1259 : : {
1260 : 0 : log_msg(LOG_ERR,
1261 : : "[*] acc_data_is_valid() called with NULL acc stanza");
1262 : 0 : return(0);
1263 : : }
1264 : :
1265 [ + + ][ - + ]: 1703 : if(((acc->key == NULL || acc->key_len == 0)
1266 [ + + ][ + + ]: 70 : && ((acc->gpg_decrypt_pw == NULL || !strlen(acc->gpg_decrypt_pw))
1267 [ + + ]: 54 : && acc->gpg_allow_no_pw == 0))
1268 [ + + ][ - + ]: 1687 : || (acc->use_rijndael == 0 && acc->use_gpg == 0 && acc->gpg_allow_no_pw == 0))
1269 : : {
1270 : 16 : log_msg(LOG_ERR,
1271 : : "[*] No keys found for access stanza source: '%s'", acc->source
1272 : : );
1273 : 16 : return(0);
1274 : : }
1275 : :
1276 [ + + ][ + - ]: 1687 : if(acc->use_rijndael && acc->key != NULL)
1277 : : {
1278 [ + + ]: 1633 : if((acc->encryption_mode == FKO_ENC_MODE_CBC_LEGACY_IV)
1279 [ + + ]: 23 : && (acc->key_len > 16))
1280 : : {
1281 : 1 : log_msg(LOG_INFO,
1282 : : "Warning: truncating encryption key in legacy mode to 16 bytes for access stanza source: '%s'",
1283 : : acc->source
1284 : : );
1285 : 1 : acc->key_len = 16;
1286 : : }
1287 : : }
1288 : :
1289 [ + + ][ + - ]: 1687 : if((acc->hmac_key_len) != 0 && (acc->hmac_key != NULL))
1290 : : {
1291 [ + + ][ + - ]: 331 : if((acc->key != NULL) && (acc->key_len != 0)
1292 [ + + ]: 301 : && (acc->key_len == acc->hmac_key_len))
1293 : : {
1294 [ + + ]: 5 : if(memcmp(acc->key, acc->hmac_key, acc->hmac_key_len) == 0)
1295 : : {
1296 : 1 : log_msg(LOG_ERR,
1297 : : "[*] The encryption passphrase and HMAC key should not be identical for access stanza source: '%s'",
1298 : : acc->source
1299 : : );
1300 : 1 : return(0);
1301 : : }
1302 : : }
1303 [ + + ]: 326 : else if((acc->gpg_allow_no_pw == 0)
1304 [ + + ]: 312 : && acc->gpg_decrypt_pw != NULL
1305 [ + + ]: 16 : && (strlen(acc->gpg_decrypt_pw) == acc->hmac_key_len))
1306 : : {
1307 [ + - ]: 1 : if(memcmp(acc->gpg_decrypt_pw, acc->hmac_key, acc->hmac_key_len) == 0)
1308 : : {
1309 : 1 : log_msg(LOG_ERR,
1310 : : "[*] The encryption passphrase and HMAC key should not be identical for access stanza source: '%s'",
1311 : : acc->source
1312 : : );
1313 : 1 : return(0);
1314 : : }
1315 : : }
1316 : : }
1317 : :
1318 : : #if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES)
1319 [ + + ][ - + ]: 1685 : if((acc->force_snat == 1 || acc->force_masquerade == 1)
1320 [ + + ]: 18 : && acc->force_nat == 0)
1321 : : {
1322 [ + + ]: 12 : if(acc->forward_all == 1)
1323 : : {
1324 : 8 : add_acc_force_nat(opts, acc, "0.0.0.0 0", NULL);
1325 : : }
1326 : : else
1327 : : {
1328 : 4 : log_msg(LOG_ERR,
1329 : : "[*] FORCE_SNAT/FORCE_MASQUERADE requires either FORCE_NAT or FORWARD_ALL: '%s'",
1330 : : acc->source
1331 : : );
1332 : 4 : return(0);
1333 : : }
1334 : : }
1335 : : #endif
1336 : :
1337 [ + + ]: 1681 : if(acc->require_source_address == 0)
1338 : : {
1339 : 1679 : log_msg(LOG_INFO,
1340 : : "Warning: REQUIRE_SOURCE_ADDRESS not enabled for access stanza source: '%s'",
1341 : : acc->source
1342 : : );
1343 : : }
1344 : :
1345 [ + + ][ + - ]: 1681 : if(user_pw != NULL && acc->cmd_exec_uid != 0 && acc->cmd_exec_gid == 0)
[ + + ]
1346 : : {
1347 : 8 : log_msg(LOG_INFO,
1348 : : "Setting gid to group associated with CMD_EXEC_USER '%s' for setgid() execution in stanza source: '%s'",
1349 : : acc->cmd_exec_user,
1350 : : acc->source
1351 : : );
1352 : 8 : acc->cmd_exec_gid = user_pw->pw_gid;
1353 : : }
1354 : :
1355 [ + + ]: 1681 : if(sudo_user_pw != NULL
1356 [ + - ][ + + ]: 9 : && acc->cmd_sudo_exec_uid != 0 && acc->cmd_sudo_exec_gid == 0)
1357 : : {
1358 : 7 : log_msg(LOG_INFO,
1359 : : "Setting gid to group associated with CMD_SUDO_EXEC_USER '%s' in stanza source: '%s'",
1360 : : acc->cmd_sudo_exec_user,
1361 : : acc->source
1362 : : );
1363 : 7 : acc->cmd_sudo_exec_gid = sudo_user_pw->pw_gid;
1364 : : }
1365 : :
1366 [ + + ]: 1681 : if(acc->cmd_cycle_open != NULL)
1367 : : {
1368 [ + + ]: 24 : if(acc->cmd_cycle_close == NULL)
1369 : : {
1370 : 1 : log_msg(LOG_ERR,
1371 : : "[*] Cannot set CMD_CYCLE_OPEN without also setting CMD_CYCLE_CLOSE: '%s'",
1372 : : acc->source
1373 : : );
1374 : 1 : return(0);
1375 : : }
1376 : :
1377 : : /* Allow the string "NONE" to short-circuit close command execution.
1378 : : */
1379 [ + + ]: 23 : if(strncmp(acc->cmd_cycle_close, "NONE", 4) == 0)
1380 : 1 : acc->cmd_cycle_do_close = 0;
1381 : :
1382 [ + + ][ + + ]: 23 : if(acc->cmd_cycle_timer == 0 && acc->cmd_cycle_do_close)
1383 : : {
1384 : 1 : log_msg(LOG_ERR,
1385 : : "[*] Must set the CMD_CYCLE_TIMER for command cycle functionality: '%s'",
1386 : : acc->source
1387 : : );
1388 : 1 : return(0);
1389 : : }
1390 [ + + ]: 22 : if(strlen(acc->cmd_cycle_open) >= CMD_CYCLE_BUFSIZE)
1391 : : {
1392 : 1 : log_msg(LOG_ERR,
1393 : : "[*] CMD_CYCLE_OPEN command is too long: '%s'",
1394 : : acc->source
1395 : : );
1396 : 1 : return(0);
1397 : : }
1398 : : }
1399 : :
1400 [ + + ]: 1678 : if(acc->cmd_cycle_close != NULL)
1401 : : {
1402 [ + + ]: 22 : if(acc->cmd_cycle_open == NULL)
1403 : : {
1404 : 1 : log_msg(LOG_ERR,
1405 : : "[*] Cannot set CMD_CYCLE_CLOSE without also setting CMD_CYCLE_OPEN: '%s'",
1406 : : acc->source
1407 : : );
1408 : 1 : return(0);
1409 : : }
1410 [ + + ]: 21 : if(strlen(acc->cmd_cycle_close) >= CMD_CYCLE_BUFSIZE)
1411 : : {
1412 : 1 : log_msg(LOG_ERR,
1413 : : "[*] CMD_CYCLE_CLOSE command is too long: '%s'",
1414 : : acc->source
1415 : : );
1416 : 1 : return(0);
1417 : : }
1418 : : }
1419 : :
1420 : : /* For any non-command cycle stanza, we enable global firewall handling
1421 : : */
1422 [ + + ]: 1676 : if(acc->cmd_cycle_open == NULL)
1423 : 1656 : opts->enable_fw = 1;
1424 : :
1425 : : return(1);
1426 : : }
1427 : :
1428 : : int
1429 : 8 : parse_access_folder(fko_srv_options_t *opts, char *access_folder, int *depth)
1430 : : {
1431 : : char *extension;
1432 : : DIR *dir_ptr;
1433 : :
1434 : 8 : char include_file[MAX_PATH_LEN] = {0};
1435 : : struct dirent *dp;
1436 : :
1437 : 8 : chop_char(access_folder, PATH_SEP);
1438 : :
1439 : 8 : dir_ptr = opendir(access_folder);
1440 : :
1441 : : //grab the file names in the directory and loop through them
1442 [ + + ]: 8 : if (dir_ptr == NULL)
1443 : : {
1444 : 2 : log_msg(LOG_ERR, "[*] Access folder: '%s' could not be opened.", access_folder);
1445 : 2 : return EXIT_FAILURE;
1446 : : }
1447 [ + + ]: 63 : while ((dp = readdir(dir_ptr)) != NULL) {
1448 : 57 : extension = (strrchr(dp->d_name, '.')); // Capture just the extension
1449 [ + + ][ + + ]: 57 : if (extension && !strncmp(extension, ".conf", 5))
1450 : : {
1451 [ - + ]: 2 : if (strlen(access_folder) + 1 + strlen(dp->d_name) > MAX_PATH_LEN - 1) //Bail out rather than write past the end of include_file
1452 : : {
1453 : 0 : closedir(dir_ptr);
1454 : 0 : return EXIT_FAILURE;
1455 : : }
1456 : 2 : strlcpy(include_file, access_folder, sizeof(include_file)); //construct the full path
1457 : 2 : strlcat(include_file, "/", sizeof(include_file));
1458 : 2 : strlcat(include_file, dp->d_name, sizeof(include_file));
1459 [ - + ]: 2 : if (parse_access_file(opts, include_file, depth) == EXIT_FAILURE)
1460 : : {
1461 : 0 : closedir(dir_ptr);
1462 : 57 : return EXIT_FAILURE;
1463 : : }
1464 : : }
1465 : : }
1466 : 6 : closedir(dir_ptr);
1467 : 6 : return EXIT_SUCCESS;
1468 : : }
1469 : :
1470 : : /* Read and parse the access file, popluating the access data as we go.
1471 : : */
1472 : : int
1473 : 1691 : parse_access_file(fko_srv_options_t *opts, char *access_filename, int *depth)
1474 : : {
1475 : : FILE *file_ptr;
1476 : : char *ndx;
1477 : : int is_err;
1478 : 1691 : unsigned int num_lines = 0;
1479 : :
1480 : 1691 : char access_line_buf[MAX_LINE_LEN] = {0};
1481 : 1691 : char var[MAX_LINE_LEN] = {0};
1482 : 1691 : char val[MAX_LINE_LEN] = {0};
1483 : :
1484 : 1691 : struct passwd *user_pw = NULL;
1485 : 1691 : struct passwd *sudo_user_pw = NULL;
1486 : : struct stat st;
1487 : :
1488 : 1691 : acc_stanza_t *curr_acc = NULL;
1489 : :
1490 : : /* This allows us to limit include depth, and also tracks when we've returned to the root access.conf file.
1491 : : */
1492 : 1691 : (*depth)++;
1493 : :
1494 : : /* First see if the access file exists. If it doesn't, complain
1495 : : * and bail.
1496 : : */
1497 : : #if HAVE_LSTAT
1498 [ + + ]: 1691 : if(lstat(access_filename, &st) != 0)
1499 : : {
1500 : 1 : log_msg(LOG_ERR, "[*] Access file: '%s' was not found.",
1501 : : access_filename);
1502 : :
1503 : 1 : return EXIT_FAILURE;
1504 : : }
1505 : : #elif HAVE_STAT
1506 : : if(stat(access_filename, &st) != 0)
1507 : : {
1508 : : log_msg(LOG_ERR, "[*] Access file: '%s' was not found.",
1509 : : access_filename);
1510 : :
1511 : : return EXIT_FAILURE;
1512 : : }
1513 : : #endif
1514 : :
1515 [ + - ]: 1690 : if(verify_file_perms_ownership(access_filename) != 1)
1516 : : return EXIT_FAILURE;
1517 : :
1518 : : /* A note on security here: Coverity flags the following fopen() as a
1519 : : * Time of check time of use (TOCTOU) bug with a low priority due to the
1520 : : * previous stat() call above. I.e., the access.conf file on disk could
1521 : : * have been changed between the stat() and the fopen() causing a TOCTOU
1522 : : * bug. While technically this is true, the return value of fopen() is
1523 : : * also checked below so stat() success does not imply we assume fopen()
1524 : : * success. Also, we could just remove the stat() and
1525 : : * verify_file_perms_ownership() calls above to "fix" the bug, but this
1526 : : * would actually make things easier for an attacker that has already
1527 : : * compromised the local system since access.conf could be changed to, say,
1528 : : * a symbolic link (for which verify_file_perms_ownership() throws a
1529 : : * warning), and then there is no race at all before the fopen(). I.e.
1530 : : * forcing an attacker to do the race makes things harder for them.
1531 : : */
1532 [ + + ]: 1690 : if ((file_ptr = fopen(access_filename, "r")) == NULL)
1533 : : {
1534 : 3 : log_msg(LOG_ERR, "[*] Could not open access file: %s",
1535 : : access_filename);
1536 : 3 : perror(NULL);
1537 : :
1538 : 3 : return EXIT_FAILURE;
1539 : : }
1540 : :
1541 : 1687 : log_msg(LOG_DEBUG, "Opened access file: %s", access_filename);
1542 : :
1543 : : /* Initialize the access list
1544 : : */
1545 : 1687 : acc_stanza_init(opts);
1546 : :
1547 : : /* Now walk through access file pulling the access entries into the
1548 : : * current stanza.
1549 : : */
1550 [ + + ]: 9382 : while ((fgets(access_line_buf, MAX_LINE_LEN, file_ptr)) != NULL)
1551 : : {
1552 : 6046 : num_lines++;
1553 : 6046 : access_line_buf[MAX_LINE_LEN-1] = '\0';
1554 : :
1555 : : /* Get past comments and empty lines (note: we only look at the
1556 : : * first character.
1557 : : */
1558 [ + + ][ + - ]: 6046 : if(IS_EMPTY_LINE(access_line_buf[0]))
[ + - ][ - + ]
1559 : 38 : continue;
1560 : :
1561 [ + + ]: 6008 : if(sscanf(access_line_buf, "%s %[^;\n\r]", var, val) != 2)
1562 : : {
1563 : 1 : log_msg(LOG_ERR,
1564 : : "[*] Invalid access file entry in %s at line %i.\n - '%s'",
1565 : : access_filename, num_lines, access_line_buf
1566 : : );
1567 : 1 : fclose(file_ptr);
1568 : 1 : return EXIT_FAILURE;
1569 : : }
1570 : :
1571 : : /* Remove any colon that may be on the end of the var
1572 : : */
1573 [ + + ]: 6007 : if((ndx = strrchr(var, ':')) != NULL)
1574 : 15 : *ndx = '\0';
1575 : :
1576 : : /* Even though sscanf should automatically add a terminating
1577 : : * NULL byte, an assumption is made that the input arrays are
1578 : : * big enough, so we'll force a terminating NULL byte regardless
1579 : : */
1580 : 6007 : var[MAX_LINE_LEN-1] = 0x0;
1581 : 6007 : val[MAX_LINE_LEN-1] = 0x0;
1582 : :
1583 [ + + ]: 6007 : if (opts->verbose > 3)
1584 : 31 : log_msg(LOG_DEBUG,
1585 : : "ACCESS FILE: %s, LINE: %s\tVar: %s, Val: '%s'",
1586 : : access_filename, access_line_buf, var, val
1587 : : );
1588 : :
1589 : : /* Process the entry.
1590 : : *
1591 : : * NOTE: If a new access.conf parameter is created. It also needs
1592 : : * to be accounted for in the following if/if else construct.
1593 : : */
1594 [ + + ]: 6007 : if(CONF_VAR_IS(var, "%include"))
1595 : : {
1596 [ + + ]: 22 : if ((*depth) < MAX_DEPTH)
1597 : : {
1598 : 21 : log_msg(LOG_DEBUG, "[+] Processing include directive for file: '%s'", val);
1599 [ + + ]: 21 : if (parse_access_file(opts, val, depth) == EXIT_FAILURE)
1600 : : {
1601 : 3 : fclose(file_ptr);
1602 : 3 : return EXIT_FAILURE;
1603 : : }
1604 : : }
1605 : : else
1606 : : {
1607 : 1 : log_msg(LOG_ERR, "[*] Refusing to go deeper than 3 levels. Lost in Limbo: '%s'",
1608 : : access_filename);
1609 : 1 : fclose(file_ptr);
1610 : 1 : return EXIT_FAILURE;
1611 : : }
1612 : : }
1613 [ + + ]: 5985 : else if(CONF_VAR_IS(var, "%include_folder"))
1614 : : {
1615 : 6 : log_msg(LOG_DEBUG, "[+] Processing include_folder directive for: '%s'", val);
1616 [ + + ]: 6 : if (parse_access_folder(opts, val, depth) == EXIT_FAILURE)
1617 : : {
1618 : 2 : fclose(file_ptr);
1619 : 2 : return EXIT_FAILURE;
1620 : : }
1621 : : }
1622 [ + + ]: 5979 : else if(CONF_VAR_IS(var, "SOURCE"))
1623 : : {
1624 : : /* If this is not the first stanza, sanity check the previous
1625 : : * stanza for the minimum required data.
1626 : : */
1627 [ + + ]: 1727 : if(curr_acc != NULL) {
1628 [ + + ]: 42 : if(!acc_data_is_valid(opts, user_pw, sudo_user_pw, curr_acc))
1629 : : {
1630 : 3 : log_msg(LOG_ERR, "[*] Data error in access file: '%s'",
1631 : : access_filename);
1632 : 3 : fclose(file_ptr);
1633 : 3 : return EXIT_FAILURE;
1634 : : }
1635 : : }
1636 : :
1637 : : /* Start new stanza.
1638 : : */
1639 : 1724 : curr_acc = acc_stanza_add(opts);
1640 : 1720 : add_acc_string(&(curr_acc->source), val, file_ptr, opts);
1641 : : }
1642 [ + + ]: 4252 : else if (curr_acc == NULL)
1643 : : {
1644 : : /* The stanza must start with the "SOURCE" variable
1645 : : */
1646 : 2 : continue;
1647 : : }
1648 [ + + ]: 4250 : else if(CONF_VAR_IS(var, "%include_keys")) //Only valid options from this file are those defining keys.
1649 : : {
1650 : : // This directive is only valid within a SOURCE stanza
1651 : 20 : log_msg(LOG_DEBUG, "[+] Processing include_keys directive for: '%s'", val);
1652 : 20 : include_keys_file(curr_acc, val, opts);
1653 [ + + ]: 20 : if(!acc_data_is_valid(opts, user_pw, sudo_user_pw, curr_acc))
1654 : : {
1655 : 12 : log_msg(LOG_DEBUG, "[*] Data error in included keyfile: '%s', skipping stanza.", val);
1656 : 12 : free_last_acc_stanza(opts);
1657 : 12 : curr_acc = NULL;
1658 : : }
1659 : : }
1660 [ + + ]: 4230 : else if(CONF_VAR_IS(var, "DESTINATION"))
1661 : 20 : add_acc_string(&(curr_acc->destination), val, file_ptr, opts);
1662 [ + + ]: 4210 : else if(CONF_VAR_IS(var, "OPEN_PORTS"))
1663 : 38 : add_acc_string(&(curr_acc->open_ports), val, file_ptr, opts);
1664 [ + + ]: 4172 : else if(CONF_VAR_IS(var, "RESTRICT_PORTS"))
1665 : 1 : add_acc_string(&(curr_acc->restrict_ports), val, file_ptr, opts);
1666 [ + + ]: 4171 : else if(CONF_VAR_IS(var, "KEY"))
1667 : : {
1668 [ + + ]: 1347 : if(strcasecmp(val, "__CHANGEME__") == 0)
1669 : : {
1670 : 1 : log_msg(LOG_ERR,
1671 : : "[*] KEY value is not properly set in stanza source '%s' in access file: '%s'",
1672 : : curr_acc->source, access_filename);
1673 : 1 : fclose(file_ptr);
1674 : 1 : return EXIT_FAILURE;
1675 : : }
1676 : 1346 : add_acc_string(&(curr_acc->key), val, file_ptr, opts);
1677 : 1346 : curr_acc->key_len = strlen(curr_acc->key);
1678 : 1346 : add_acc_bool(&(curr_acc->use_rijndael), "Y");
1679 : : }
1680 [ + + ]: 2824 : else if(CONF_VAR_IS(var, "KEY_BASE64"))
1681 : : {
1682 [ + + ]: 290 : if(strcasecmp(val, "__CHANGEME__") == 0)
1683 : : {
1684 : 1 : log_msg(LOG_ERR,
1685 : : "[*] KEY_BASE64 value is not properly set in stanza source '%s' in access file: '%s'",
1686 : : curr_acc->source, access_filename);
1687 : 1 : fclose(file_ptr);
1688 : 1 : return EXIT_FAILURE;
1689 : : }
1690 [ + + ]: 289 : if (! is_base64((unsigned char *) val, strlen(val)))
1691 : : {
1692 : 1 : log_msg(LOG_ERR,
1693 : : "[*] KEY_BASE64 argument '%s' doesn't look like base64-encoded data.",
1694 : : val);
1695 : 1 : fclose(file_ptr);
1696 : 1 : return EXIT_FAILURE;
1697 : : }
1698 : 288 : add_acc_string(&(curr_acc->key_base64), val, file_ptr, opts);
1699 : 288 : add_acc_b64_string(&(curr_acc->key), &(curr_acc->key_len),
1700 : 288 : curr_acc->key_base64, file_ptr, opts);
1701 : 288 : add_acc_bool(&(curr_acc->use_rijndael), "Y");
1702 : : }
1703 : : /* HMAC digest type */
1704 [ + + ]: 2534 : else if(CONF_VAR_IS(var, "HMAC_DIGEST_TYPE"))
1705 : : {
1706 : 64 : curr_acc->hmac_type = hmac_digest_strtoint(val);
1707 [ + + ]: 64 : if(curr_acc->hmac_type < 0)
1708 : : {
1709 : 1 : log_msg(LOG_ERR,
1710 : : "[*] HMAC_DIGEST_TYPE argument '%s' must be one of {md5,sha1,sha256,sha384,sha512,sha3_256,sha3_512}",
1711 : : val);
1712 : 1 : fclose(file_ptr);
1713 : 1 : return EXIT_FAILURE;
1714 : : }
1715 : : }
1716 [ + + ]: 2470 : else if(CONF_VAR_IS(var, "HMAC_KEY_BASE64"))
1717 : : {
1718 [ + + ]: 318 : if(strcasecmp(val, "__CHANGEME__") == 0)
1719 : : {
1720 : 1 : log_msg(LOG_ERR,
1721 : : "[*] HMAC_KEY_BASE64 value is not properly set in stanza source '%s' in access file: '%s'",
1722 : : curr_acc->source, opts->config[CONF_ACCESS_FILE]);
1723 : 1 : fclose(file_ptr);
1724 : 1 : return EXIT_FAILURE;
1725 : : }
1726 [ + + ]: 317 : if (! is_base64((unsigned char *) val, strlen(val)))
1727 : : {
1728 : 1 : log_msg(LOG_ERR,
1729 : : "[*] HMAC_KEY_BASE64 argument '%s' doesn't look like base64-encoded data.",
1730 : : val);
1731 : 1 : fclose(file_ptr);
1732 : 1 : return EXIT_FAILURE;
1733 : : }
1734 : 316 : add_acc_string(&(curr_acc->hmac_key_base64), val, file_ptr, opts);
1735 : 316 : add_acc_b64_string(&(curr_acc->hmac_key), &(curr_acc->hmac_key_len),
1736 : 316 : curr_acc->hmac_key_base64, file_ptr, opts);
1737 : : }
1738 [ + + ]: 2152 : else if(CONF_VAR_IS(var, "HMAC_KEY"))
1739 : : {
1740 [ + + ]: 13 : if(strcasecmp(val, "__CHANGEME__") == 0)
1741 : : {
1742 : 1 : log_msg(LOG_ERR,
1743 : : "[*] HMAC_KEY value is not properly set in stanza source '%s' in access file: '%s'",
1744 : : curr_acc->source, opts->config[CONF_ACCESS_FILE]);
1745 : 1 : fclose(file_ptr);
1746 : 1 : return EXIT_FAILURE;
1747 : : }
1748 : 12 : add_acc_string(&(curr_acc->hmac_key), val, file_ptr, opts);
1749 : 12 : curr_acc->hmac_key_len = strlen(curr_acc->hmac_key);
1750 : : }
1751 [ + + ]: 2139 : else if(CONF_VAR_IS(var, "FW_ACCESS_TIMEOUT"))
1752 : : {
1753 : 1582 : curr_acc->fw_access_timeout = strtol_wrapper(val, 0,
1754 : : RCHK_MAX_FW_TIMEOUT, NO_EXIT_UPON_ERR, &is_err);
1755 [ + + ]: 1582 : if(is_err != FKO_SUCCESS)
1756 : : {
1757 : 1 : log_msg(LOG_ERR,
1758 : : "[*] FW_ACCESS_TIMEOUT value not in range.");
1759 : 1 : fclose(file_ptr);
1760 : 1 : return EXIT_FAILURE;
1761 : : }
1762 : : }
1763 [ + + ]: 557 : else if(CONF_VAR_IS(var, "ENCRYPTION_MODE"))
1764 : : {
1765 [ + + ]: 28 : if((curr_acc->encryption_mode = enc_mode_strtoint(val)) < 0)
1766 : : {
1767 : 1 : log_msg(LOG_ERR,
1768 : : "[*] Unrecognized ENCRYPTION_MODE '%s', use {CBC,CTR,legacy,Asymmetric}",
1769 : : val);
1770 : 1 : fclose(file_ptr);
1771 : 1 : return EXIT_FAILURE;
1772 : : }
1773 : : }
1774 [ + + ]: 529 : else if(CONF_VAR_IS(var, "ENABLE_CMD_EXEC"))
1775 : : {
1776 : 21 : add_acc_bool(&(curr_acc->enable_cmd_exec), val);
1777 : : }
1778 [ + + ]: 508 : else if(CONF_VAR_IS(var, "ENABLE_CMD_SUDO_EXEC"))
1779 : : {
1780 : 9 : add_acc_bool(&(curr_acc->enable_cmd_sudo_exec), val);
1781 : : }
1782 [ + + ]: 499 : else if(CONF_VAR_IS(var, "CMD_SUDO_EXEC_USER"))
1783 : 9 : add_acc_user(&(curr_acc->cmd_sudo_exec_user),
1784 : : &(curr_acc->cmd_sudo_exec_uid), &sudo_user_pw,
1785 : : val, "CMD_SUDO_EXEC_USER", file_ptr, opts);
1786 [ + + ]: 490 : else if(CONF_VAR_IS(var, "CMD_SUDO_EXEC_GROUP"))
1787 : 3 : add_acc_group(&(curr_acc->cmd_sudo_exec_group),
1788 : : &(curr_acc->cmd_sudo_exec_gid), val,
1789 : : "CMD_SUDO_EXEC_GROUP", file_ptr, opts);
1790 [ + + ]: 487 : else if(CONF_VAR_IS(var, "CMD_EXEC_USER"))
1791 : 13 : add_acc_user(&(curr_acc->cmd_exec_user),
1792 : : &(curr_acc->cmd_exec_uid), &user_pw,
1793 : : val, "CMD_EXEC_USER", file_ptr, opts);
1794 [ + + ]: 474 : else if(CONF_VAR_IS(var, "CMD_EXEC_GROUP"))
1795 : 6 : add_acc_group(&(curr_acc->cmd_exec_group),
1796 : : &(curr_acc->cmd_exec_gid), val,
1797 : : "CMD_EXEC_GROUP", file_ptr, opts);
1798 [ + + ]: 468 : else if(CONF_VAR_IS(var, "CMD_CYCLE_OPEN"))
1799 : : {
1800 : 25 : add_acc_string(&(curr_acc->cmd_cycle_open), val, file_ptr, opts);
1801 : 25 : curr_acc->cmd_cycle_do_close = 1; /* default, will be validated */
1802 : : }
1803 [ + + ]: 443 : else if(CONF_VAR_IS(var, "CMD_CYCLE_CLOSE"))
1804 : 25 : add_acc_string(&(curr_acc->cmd_cycle_close), val, file_ptr, opts);
1805 [ + + ]: 418 : else if(CONF_VAR_IS(var, "CMD_CYCLE_TIMER"))
1806 : : {
1807 : 22 : curr_acc->cmd_cycle_timer = strtol_wrapper(val,
1808 : : RCHK_MIN_CMD_CYCLE_TIMER, RCHK_MAX_CMD_CYCLE_TIMER,
1809 : : NO_EXIT_UPON_ERR, &is_err);
1810 [ + + ]: 22 : if(is_err != FKO_SUCCESS)
1811 : : {
1812 : 1 : log_msg(LOG_ERR,
1813 : : "[*] CMD_CYCLE_TIMER value not in range [1,%d].",
1814 : : RCHK_MAX_CMD_CYCLE_TIMER);
1815 : 1 : fclose(file_ptr);
1816 : 1 : return EXIT_FAILURE;
1817 : : }
1818 : : }
1819 [ + + ]: 396 : else if(CONF_VAR_IS(var, "REQUIRE_USERNAME"))
1820 : 15 : add_acc_string(&(curr_acc->require_username), val, file_ptr, opts);
1821 [ + + ]: 381 : else if(CONF_VAR_IS(var, "REQUIRE_SOURCE_ADDRESS"))
1822 : 2 : add_acc_bool(&(curr_acc->require_source_address), val);
1823 [ + + ]: 379 : else if(CONF_VAR_IS(var, "REQUIRE_SOURCE")) /* synonym for REQUIRE_SOURCE_ADDRESS */
1824 : 1 : add_acc_bool(&(curr_acc->require_source_address), val);
1825 [ + + ]: 378 : else if(CONF_VAR_IS(var, "GPG_HOME_DIR"))
1826 : : {
1827 [ + + ]: 76 : if (is_valid_dir(val))
1828 : : {
1829 : 75 : add_acc_string(&(curr_acc->gpg_home_dir), val, file_ptr, opts);
1830 : : }
1831 : : else
1832 : : {
1833 : 1 : log_msg(LOG_ERR,
1834 : : "[*] GPG_HOME_DIR directory '%s' stat()/existence problem in stanza source '%s' in access file: '%s'",
1835 : : val, curr_acc->source, access_filename);
1836 : 1 : fclose(file_ptr);
1837 : 1 : return EXIT_FAILURE;
1838 : : }
1839 : : }
1840 [ + + ]: 302 : else if(CONF_VAR_IS(var, "GPG_EXE"))
1841 : 1 : add_acc_string(&(curr_acc->gpg_exe), val, file_ptr, opts);
1842 [ + + ]: 301 : else if(CONF_VAR_IS(var, "GPG_DECRYPT_ID"))
1843 : 76 : add_acc_string(&(curr_acc->gpg_decrypt_id), val, file_ptr, opts);
1844 [ + + ]: 225 : else if(CONF_VAR_IS(var, "GPG_DECRYPT_PW"))
1845 : : {
1846 [ + + ]: 43 : if(strcasecmp(val, "__CHANGEME__") == 0)
1847 : : {
1848 : 1 : log_msg(LOG_ERR,
1849 : : "[*] GPG_DECRYPT_PW value is not properly set in stanza source '%s' in access file: '%s'",
1850 : : curr_acc->source, access_filename);
1851 : 1 : fclose(file_ptr);
1852 : 1 : return EXIT_FAILURE;
1853 : : }
1854 : 42 : add_acc_string(&(curr_acc->gpg_decrypt_pw), val, file_ptr, opts);
1855 : 42 : add_acc_bool(&(curr_acc->use_gpg), "Y");
1856 : : }
1857 [ + + ]: 182 : else if(CONF_VAR_IS(var, "GPG_ALLOW_NO_PW"))
1858 : : {
1859 : 36 : add_acc_bool(&(curr_acc->gpg_allow_no_pw), val);
1860 [ + - ]: 36 : if(curr_acc->gpg_allow_no_pw == 1)
1861 : : {
1862 : 36 : add_acc_bool(&(curr_acc->use_gpg), "Y");
1863 : 36 : add_acc_string(&(curr_acc->gpg_decrypt_pw), "", file_ptr, opts);
1864 : : }
1865 : : }
1866 [ + + ]: 146 : else if(CONF_VAR_IS(var, "GPG_REQUIRE_SIG"))
1867 : : {
1868 : 2 : add_acc_bool(&(curr_acc->gpg_require_sig), val);
1869 : : }
1870 [ + + ]: 144 : else if(CONF_VAR_IS(var, "GPG_DISABLE_SIG"))
1871 : : {
1872 : 3 : add_acc_bool(&(curr_acc->gpg_disable_sig), val);
1873 : : }
1874 [ + + ]: 141 : else if(CONF_VAR_IS(var, "GPG_IGNORE_SIG_VERIFY_ERROR"))
1875 : : {
1876 : 1 : add_acc_bool(&(curr_acc->gpg_ignore_sig_error), val);
1877 : : }
1878 [ + + ]: 140 : else if(CONF_VAR_IS(var, "GPG_REMOTE_ID"))
1879 : 71 : add_acc_string(&(curr_acc->gpg_remote_id), val, file_ptr, opts);
1880 [ + + ]: 69 : else if(CONF_VAR_IS(var, "GPG_FINGERPRINT_ID"))
1881 : 4 : add_acc_string(&(curr_acc->gpg_remote_fpr), val, file_ptr, opts);
1882 [ + + ]: 65 : else if(CONF_VAR_IS(var, "ACCESS_EXPIRE"))
1883 : : {
1884 [ + + ]: 3 : if (add_acc_expire_time(opts, &(curr_acc->access_expire_time), val) != 1)
1885 : : {
1886 : 1 : fclose(file_ptr);
1887 : 1 : return EXIT_FAILURE;
1888 : : }
1889 : : }
1890 [ + + ]: 62 : else if(CONF_VAR_IS(var, "ACCESS_EXPIRE_EPOCH"))
1891 : 2 : add_acc_expire_time_epoch(opts,
1892 : : &(curr_acc->access_expire_time), val, file_ptr);
1893 [ + + ]: 60 : else if(CONF_VAR_IS(var, "FORCE_NAT"))
1894 : : {
1895 : : #if FIREWALL_FIREWALLD
1896 [ + + ]: 21 : if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1) !=0
1897 [ + + ]: 5 : && (strncasecmp(opts->config[CONF_ENABLE_FIREWD_LOCAL_NAT], "Y", 1) !=0 ))
1898 : : {
1899 : 1 : log_msg(LOG_ERR,
1900 : : "[*] FORCE_NAT requires either ENABLE_FIREWD_FORWARDING or ENABLE_FIREWD_LOCAL_NAT in fwknopd.conf");
1901 : 1 : fclose(file_ptr);
1902 : 1 : return EXIT_FAILURE;
1903 : : }
1904 : 20 : add_acc_force_nat(opts, curr_acc, val, file_ptr);
1905 : : #elif FIREWALL_IPTABLES
1906 : : if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0
1907 : : && (strncasecmp(opts->config[CONF_ENABLE_IPT_LOCAL_NAT], "Y", 1) !=0 ))
1908 : : {
1909 : : log_msg(LOG_ERR,
1910 : : "[*] FORCE_NAT requires either ENABLE_IPT_FORWARDING or ENABLE_IPT_LOCAL_NAT in fwknopd.conf");
1911 : : fclose(file_ptr);
1912 : : return EXIT_FAILURE;
1913 : : }
1914 : : add_acc_force_nat(opts, curr_acc, val, file_ptr);
1915 : : #else
1916 : : log_msg(LOG_ERR,
1917 : : "[*] FORCE_NAT not supported.");
1918 : : fclose(file_ptr);
1919 : : return EXIT_FAILURE;
1920 : : #endif
1921 : : }
1922 [ + + ]: 39 : else if(CONF_VAR_IS(var, "FORCE_SNAT"))
1923 : : {
1924 : : #if FIREWALL_FIREWALLD
1925 [ + + ]: 13 : if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1) !=0
1926 [ + - ]: 1 : && (strncasecmp(opts->config[CONF_ENABLE_FIREWD_LOCAL_NAT], "Y", 1) !=0 ))
1927 : : {
1928 : 1 : log_msg(LOG_ERR,
1929 : : "[*] FORCE_SNAT requires either ENABLE_FIREWD_FORWARDING or ENABLE_FIREWD_LOCAL_NAT in fwknopd.conf");
1930 : 1 : fclose(file_ptr);
1931 : 1 : return EXIT_FAILURE;
1932 : : }
1933 : 12 : add_acc_force_snat(opts, curr_acc, val, file_ptr);
1934 : : #elif FIREWALL_IPTABLES
1935 : : if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0
1936 : : && (strncasecmp(opts->config[CONF_ENABLE_IPT_LOCAL_NAT], "Y", 1) !=0 ))
1937 : : {
1938 : : log_msg(LOG_ERR,
1939 : : "[*] FORCE_SNAT requires either ENABLE_IPT_FORWARDING or ENABLE_IPT_LOCAL_NAT in fwknopd.conf");
1940 : : fclose(file_ptr);
1941 : : return EXIT_FAILURE;
1942 : : }
1943 : : add_acc_force_snat(opts, curr_acc, val, file_ptr);
1944 : : #else
1945 : : log_msg(LOG_ERR,
1946 : : "[*] FORCE_SNAT not supported.");
1947 : : fclose(file_ptr);
1948 : : return EXIT_FAILURE;
1949 : : #endif
1950 : : }
1951 [ + + ]: 26 : else if(CONF_VAR_IS(var, "FORCE_MASQUERADE"))
1952 : : {
1953 : 8 : add_acc_bool(&(curr_acc->force_masquerade), val);
1954 : 8 : add_acc_bool(&(curr_acc->force_snat), val);
1955 : : }
1956 [ + + ]: 18 : else if(CONF_VAR_IS(var, "DISABLE_DNAT"))
1957 : : {
1958 : 7 : add_acc_bool(&(curr_acc->disable_dnat), val);
1959 : : }
1960 [ + + ]: 11 : else if(CONF_VAR_IS(var, "FORWARD_ALL"))
1961 : : {
1962 : 10 : add_acc_bool(&(curr_acc->forward_all), val);
1963 : : }
1964 : : else
1965 : : {
1966 : 6008 : log_msg(LOG_ERR,
1967 : : "[*] Ignoring unknown access parameter: '%s' in %s",
1968 : : var, access_filename
1969 : : );
1970 : : }
1971 : : }
1972 : :
1973 : 1649 : fclose(file_ptr);
1974 [ + - ]: 1649 : if(*depth > 0)
1975 : 1649 : (*depth)--;
1976 : :
1977 [ + + ]: 1649 : if(*depth == 0) //means we just closed the root access.conf
1978 : : {
1979 [ + + ]: 1631 : if(curr_acc != NULL)
1980 : : {
1981 [ + + ]: 1623 : if(!acc_data_is_valid(opts, user_pw, sudo_user_pw, curr_acc))
1982 : : {
1983 : 12 : log_msg(LOG_ERR,
1984 : : "[*] Data error in access file: '%s'",
1985 : : access_filename);
1986 : 12 : return EXIT_FAILURE;
1987 : : }
1988 : : }
1989 [ + + ]: 8 : else if (opts->acc_stanzas == NULL)
1990 : : {
1991 : 6 : log_msg(LOG_ERR,
1992 : : "[*] Could not find valid SOURCE stanza in access file: '%s'",
1993 : : opts->config[CONF_ACCESS_FILE]);
1994 : 6 : return EXIT_FAILURE;
1995 : : }
1996 : :
1997 : : /* Expand our the expandable fields into their respective data buckets.
1998 : : */
1999 : 1613 : expand_acc_ent_lists(opts);
2000 : :
2001 : : /* Make sure default values are set where needed.
2002 : : */
2003 : 1586 : set_acc_defaults(opts);
2004 : : }
2005 : : else // this is an %included file
2006 : : {
2007 : : /* If this file had a stanza, check the last one.
2008 : : *
2009 : : *
2010 : : */
2011 [ + - ]: 18 : if(curr_acc != NULL)
2012 : : {
2013 [ - + ]: 18 : if(!acc_data_is_valid(opts, user_pw, sudo_user_pw, curr_acc))
2014 : : {
2015 : 0 : log_msg(LOG_ERR,
2016 : : "[*] Data error in access file: '%s'",
2017 : : access_filename);
2018 : 0 : return EXIT_FAILURE;
2019 : : }
2020 : : }
2021 : : }
2022 : :
2023 : : return EXIT_SUCCESS;
2024 : : }
2025 : :
2026 : 1585 : int valid_access_stanzas(acc_stanza_t *acc)
2027 : : {
2028 [ + + ]: 1585 : if(acc == NULL)
2029 : : return 0;
2030 : :
2031 : : /* This is a basic check to ensure at least one access stanza
2032 : : * with the "source" variable populated, and this function is only
2033 : : * called after all access.conf files are processed. This allows
2034 : : * %include_folder processing to proceed against directories that
2035 : : * have files that are not access.conf files. Additional stronger
2036 : : * validations are done in acc_data_is_valid(), but this function
2037 : : * is only called when a "SOURCE" variable has been parsed out of
2038 : : * the file.
2039 : : */
2040 [ + + ]: 3218 : while(acc)
2041 : : {
2042 [ + - ][ + - ]: 1634 : if(acc->source == NULL || acc->source[0] == '\0')
2043 : : return 0;
2044 : 1634 : acc = acc->next;
2045 : : }
2046 : : return 1;
2047 : : }
2048 : :
2049 : : int
2050 : 31706 : compare_addr_list(acc_int_list_t *ip_list, const uint32_t ip)
2051 : : {
2052 : 31706 : int match = 0;
2053 : :
2054 [ + + ]: 31790 : while(ip_list)
2055 : : {
2056 [ + + ]: 31777 : if((ip & ip_list->mask) == (ip_list->maddr & ip_list->mask))
2057 : : {
2058 : : match = 1;
2059 : : break;
2060 : : }
2061 : :
2062 : 84 : ip_list = ip_list->next;
2063 : : }
2064 : :
2065 : 31706 : return(match);
2066 : : }
2067 : :
2068 : : /**
2069 : : * \brief Compares port lists
2070 : : *
2071 : : * Compare the contents of 2 port lists. Return true on a match.
2072 : : * Match depends on the match_any flag. if match_any is 1 then any
2073 : : * entry in the incoming data need only match one item to return true.
2074 : : * Otherwise all entries in the incoming data must have a corresponding
2075 : : * match in the access port_list.
2076 : : *
2077 : : * \param acc Pointer to the acc_stanza_t struct that holds the access stanzas
2078 : : * \param port_str pointer to the
2079 : : *
2080 : : * \return Returns true on a match
2081 : : *
2082 : : */
2083 : : static int
2084 : 32 : compare_port_list(acc_port_list_t *in, acc_port_list_t *ac, const int match_any)
2085 : : {
2086 : 32 : int a_cnt = 0;
2087 : 32 : int i_cnt = 0;
2088 : :
2089 : : acc_port_list_t *tlist;
2090 [ + + ]: 65 : while(in)
2091 : : {
2092 : 35 : i_cnt++;
2093 : :
2094 : 35 : tlist = ac;
2095 [ + + ]: 131 : while(tlist)
2096 : : {
2097 [ + + ]: 98 : if(in->proto == tlist->proto && in->port == tlist->port)
2098 : : {
2099 : 31 : a_cnt++;
2100 [ + + ]: 31 : if(match_any == 1)
2101 : : return(1);
2102 : : }
2103 : 96 : tlist = tlist->next;
2104 : : }
2105 : 33 : in = in->next;
2106 : : }
2107 : :
2108 : 30 : return(i_cnt == a_cnt);
2109 : : }
2110 : :
2111 : : /* Take a proto/port string (or mulitple comma-separated strings) and check
2112 : : * them against the list for the given access stanza.
2113 : : *
2114 : : * Return 1 if we are allowed
2115 : : */
2116 : : int
2117 : 605 : acc_check_port_access(acc_stanza_t *acc, char *port_str)
2118 : : {
2119 : 605 : int res = 1, ctr = 0;
2120 : :
2121 : 605 : char buf[ACCESS_BUF_LEN] = {0};
2122 : : char *ndx, *start;
2123 : :
2124 : 605 : acc_port_list_t *o_pl = acc->oport_list;
2125 : 605 : acc_port_list_t *r_pl = acc->rport_list;
2126 : :
2127 : 605 : acc_port_list_t *in_pl = NULL;
2128 : :
2129 : 605 : start = port_str;
2130 : :
2131 : : /* Create our own internal port_list from the incoming SPA data
2132 : : * for comparison.
2133 : : */
2134 [ + + ]: 5127 : for(ndx = start; *ndx != '\0'; ndx++)
2135 : : {
2136 [ + + ]: 4522 : if(*ndx == ',')
2137 : : {
2138 [ + - ]: 67 : if((ctr >= ACCESS_BUF_LEN)
2139 [ - + ]: 67 : || (((ndx-start)+1) >= ACCESS_BUF_LEN))
2140 : : {
2141 : 0 : log_msg(LOG_ERR,
2142 : : "[*] Unable to create acc_port_list from incoming data: %s",
2143 : : port_str
2144 : : );
2145 : 0 : free_acc_port_list(in_pl);
2146 : 0 : return(0);
2147 : : }
2148 : 67 : strlcpy(buf, start, (ndx-start)+1);
2149 [ - + ]: 67 : if(add_port_list_ent(&in_pl, buf) == 0)
2150 : : {
2151 : 0 : log_msg(LOG_ERR, "[*] Invalid proto/port string");
2152 : 0 : free_acc_port_list(in_pl);
2153 : 0 : return(0);
2154 : : }
2155 : :
2156 : 67 : start = ndx+1;
2157 : 67 : ctr = 0;
2158 : : }
2159 : 4522 : ctr++;
2160 : : }
2161 [ + - ]: 605 : if((ctr >= ACCESS_BUF_LEN)
2162 [ - + ]: 605 : || (((ndx-start)+1) >= ACCESS_BUF_LEN))
2163 : : {
2164 : 0 : log_msg(LOG_ERR,
2165 : : "[*] Unable to create acc_port_list from incoming data: %s",
2166 : : port_str
2167 : : );
2168 : 0 : free_acc_port_list(in_pl);
2169 : 0 : return(0);
2170 : : }
2171 : 605 : strlcpy(buf, start, (ndx-start)+1);
2172 [ - + ]: 605 : if(add_port_list_ent(&in_pl, buf) == 0)
2173 : : {
2174 : 0 : log_msg(LOG_ERR, "[*] Invalid proto/port string");
2175 : 0 : free_acc_port_list(in_pl);
2176 : 0 : return 0;
2177 : : }
2178 : :
2179 [ - + ]: 605 : if(in_pl == NULL)
2180 : : {
2181 : 0 : log_msg(LOG_ERR,
2182 : : "[*] Unable to create acc_port_list from incoming data: %s", port_str
2183 : : );
2184 : 0 : return(0);
2185 : : }
2186 : :
2187 : : /* Start with restricted ports (if any). Any match (even if only one
2188 : : * entry) means not allowed.
2189 : : */
2190 [ - + ][ # # ]: 605 : if((acc->rport_list != NULL) && (compare_port_list(in_pl, r_pl, 1)))
2191 : : {
2192 : : res = 0;
2193 : : goto cleanup_and_bail;
2194 : : }
2195 : :
2196 : : /* For open port list, all must match.
2197 : : */
2198 [ + + ][ + + ]: 605 : if((acc->oport_list != NULL) && (!compare_port_list(in_pl, o_pl, 0)))
2199 : 3 : res = 0;
2200 : :
2201 : : cleanup_and_bail:
2202 : 605 : free_acc_port_list(in_pl);
2203 : 605 : return(res);
2204 : : }
2205 : :
2206 : : /* Dump the configuration
2207 : : */
2208 : : void
2209 : 523 : dump_access_list(const fko_srv_options_t *opts)
2210 : : {
2211 : 523 : int i = 0;
2212 : :
2213 : 523 : acc_stanza_t *acc = opts->acc_stanzas;
2214 : :
2215 : 523 : fprintf(stdout, "Current fwknopd access settings:\n");
2216 : :
2217 [ + - ]: 523 : if(!acc)
2218 : : {
2219 : 0 : fprintf(stderr, "\n ** No Access Settings Defined **\n\n");
2220 : 523 : return;
2221 : : }
2222 : :
2223 [ + + ]: 1083 : while(acc)
2224 : : {
2225 [ + + ][ + + ]: 581 : fprintf(stdout,
[ + - ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ - + ][ + + ]
[ + + ]
2226 : : "SOURCE (%i): %s\n"
2227 : : "==============================================================\n"
2228 : : " DESTINATION: %s\n"
2229 : : " OPEN_PORTS: %s\n"
2230 : : " RESTRICT_PORTS: %s\n"
2231 : : " KEY: %s\n"
2232 : : " KEY_BASE64: %s\n"
2233 : : " KEY_LEN: %d\n"
2234 : : " HMAC_KEY: %s\n"
2235 : : " HMAC_KEY_BASE64: %s\n"
2236 : : " HMAC_KEY_LEN: %d\n"
2237 : : " HMAC_DIGEST_TYPE: %d\n"
2238 : : " FW_ACCESS_TIMEOUT: %i\n"
2239 : : " ENABLE_CMD_EXEC: %s\n"
2240 : : " ENABLE_CMD_SUDO_EXEC: %s\n"
2241 : : " CMD_SUDO_EXEC_USER: %s\n"
2242 : : " CMD_SUDO_EXEC_GROUP: %s\n"
2243 : : " CMD_EXEC_USER: %s\n"
2244 : : " CMD_EXEC_GROUP: %s\n"
2245 : : " CMD_CYCLE_OPEN: %s\n"
2246 : : " CMD_CYCLE_CLOSE: %s\n"
2247 : : " CMD_CYCLE_TIMER: %i\n"
2248 : : " REQUIRE_USERNAME: %s\n"
2249 : : " REQUIRE_SOURCE_ADDRESS: %s\n"
2250 : : " FORCE_NAT (ip): %s\n"
2251 : : " FORCE_NAT (proto): %s\n"
2252 : : " FORCE_NAT (port): %d\n"
2253 : : " FORCE_SNAT (ip): %s\n"
2254 : : " FORCE_MASQUERADE: %s\n"
2255 : : " DISABLE_DNAT: %s\n"
2256 : : " FORWARD_ALL: %s\n"
2257 : : " ACCESS_EXPIRE: %s" /* asctime() adds a newline */
2258 : : " GPG_HOME_DIR: %s\n"
2259 : : " GPG_EXE: %s\n"
2260 : : " GPG_DECRYPT_ID: %s\n"
2261 : : " GPG_DECRYPT_PW: %s\n"
2262 : : " GPG_REQUIRE_SIG: %s\n"
2263 : : "GPG_IGNORE_SIG_VERIFY_ERROR: %s\n"
2264 : : " GPG_REMOTE_ID: %s\n"
2265 : : " GPG_FINGERPRINT_ID: %s\n",
2266 : : ++i,
2267 : : acc->source,
2268 : 560 : (acc->destination == NULL) ? "<not set>" : acc->destination,
2269 : 560 : (acc->open_ports == NULL) ? "<not set>" : acc->open_ports,
2270 : 560 : (acc->restrict_ports == NULL) ? "<not set>" : acc->restrict_ports,
2271 : 560 : (acc->key == NULL) ? "<not set>" : "<see the access.conf file>",
2272 : 560 : (acc->key_base64 == NULL) ? "<not set>" : "<see the access.conf file>",
2273 : : acc->key_len ? acc->key_len : 0,
2274 : 560 : (acc->hmac_key == NULL) ? "<not set>" : "<see the access.conf file>",
2275 : 560 : (acc->hmac_key_base64 == NULL) ? "<not set>" : "<see the access.conf file>",
2276 : : acc->hmac_key_len ? acc->hmac_key_len : 0,
2277 : : acc->hmac_type,
2278 : : acc->fw_access_timeout,
2279 : 560 : acc->enable_cmd_exec ? "Yes" : "No",
2280 : 560 : acc->enable_cmd_sudo_exec ? "Yes" : "No",
2281 : 560 : (acc->cmd_sudo_exec_user == NULL) ? "<not set>" : acc->cmd_sudo_exec_user,
2282 : 560 : (acc->cmd_sudo_exec_group == NULL) ? "<not set>" : acc->cmd_sudo_exec_group,
2283 : 560 : (acc->cmd_exec_user == NULL) ? "<not set>" : acc->cmd_exec_user,
2284 : 560 : (acc->cmd_exec_group == NULL) ? "<not set>" : acc->cmd_exec_group,
2285 : 560 : (acc->cmd_cycle_open == NULL) ? "<not set>" : acc->cmd_cycle_open,
2286 : 560 : (acc->cmd_cycle_close == NULL) ? "<not set>" : acc->cmd_cycle_close,
2287 : : acc->cmd_cycle_timer,
2288 : 560 : (acc->require_username == NULL) ? "<not set>" : acc->require_username,
2289 : 560 : acc->require_source_address ? "Yes" : "No",
2290 : : acc->force_nat ? acc->force_nat_ip : "<not set>",
2291 [ - + ]: 18 : acc->force_nat && acc->force_nat_proto != NULL ? acc->force_nat_proto : "<not set>",
2292 : 560 : acc->force_nat ? acc->force_nat_port : 0,
2293 : 560 : acc->force_snat ? acc->force_snat_ip : "<not set>",
2294 : 560 : acc->force_masquerade ? "Yes" : "No",
2295 : 560 : acc->disable_dnat ? "Yes" : "No",
2296 : 560 : acc->forward_all ? "Yes" : "No",
2297 : 3 : (acc->access_expire_time > 0) ? asctime(localtime(&acc->access_expire_time)) : "<not set>\n",
2298 : 560 : (acc->gpg_home_dir == NULL) ? "<not set>" : acc->gpg_home_dir,
2299 : 560 : (acc->gpg_exe == NULL) ? "<not set>" : acc->gpg_exe,
2300 : 560 : (acc->gpg_decrypt_id == NULL) ? "<not set>" : acc->gpg_decrypt_id,
2301 : 560 : (acc->gpg_decrypt_pw == NULL) ? "<not set>" : "<see the access.conf file>",
2302 : 560 : acc->gpg_require_sig ? "Yes" : "No",
2303 : 560 : acc->gpg_ignore_sig_error ? "Yes" : "No",
2304 : 560 : (acc->gpg_remote_id == NULL) ? "<not set>" : acc->gpg_remote_id,
2305 : 560 : (acc->gpg_remote_fpr == NULL) ? "<not set>" : acc->gpg_remote_fpr
2306 : : );
2307 : :
2308 : 560 : fprintf(stdout, "\n");
2309 : :
2310 : 560 : acc = acc->next;
2311 : : }
2312 : :
2313 : 523 : fprintf(stdout, "\n");
2314 : 523 : fflush(stdout);
2315 : : }
2316 : :
2317 : : int
2318 : 20 : include_keys_file(acc_stanza_t *curr_acc, const char *access_filename, fko_srv_options_t *opts)
2319 : : {
2320 : : FILE *file_ptr;
2321 : : struct stat st;
2322 : 20 : unsigned int num_lines = 0;
2323 : :
2324 : 20 : char access_line_buf[MAX_LINE_LEN] = {0};
2325 : 20 : char var[MAX_LINE_LEN] = {0};
2326 : 20 : char val[MAX_LINE_LEN] = {0};
2327 : : char *ndx;
2328 : :
2329 : 20 : log_msg(LOG_INFO, "Including key file: '%s'", access_filename);
2330 [ + + ]: 20 : if(stat(access_filename, &st) != 0)
2331 : : {
2332 : 2 : log_msg(LOG_ERR, "[*] Access file: '%s' was not found.",
2333 : : access_filename);
2334 : :
2335 : 2 : return EXIT_FAILURE;
2336 : : }
2337 : :
2338 [ + - ]: 18 : if ((file_ptr = fopen(access_filename, "r")) == NULL)
2339 : : {
2340 : 0 : log_msg(LOG_ERR, "[*] Could not open access file: %s",
2341 : : access_filename);
2342 : 0 : perror(NULL);
2343 : :
2344 : 0 : return EXIT_FAILURE;
2345 : : }
2346 : :
2347 [ + + ]: 44 : while ((fgets(access_line_buf, MAX_LINE_LEN, file_ptr)) != NULL)
2348 : : {
2349 : 34 : num_lines++;
2350 : 34 : access_line_buf[MAX_LINE_LEN-1] = '\0';
2351 : :
2352 : : /* Get past comments and empty lines (note: we only look at the
2353 : : * first character.
2354 : : */
2355 [ + - ][ + - ]: 34 : if(IS_EMPTY_LINE(access_line_buf[0]))
[ + - ][ - + ]
2356 : 0 : continue;
2357 : :
2358 [ + + ]: 34 : if(sscanf(access_line_buf, "%s %[^;\n\r]", var, val) != 2)
2359 : : {
2360 : 1 : log_msg(LOG_ERR,
2361 : : "[*] Invalid access file entry in %s at line %i.\n - '%s'",
2362 : : access_filename, num_lines, access_line_buf
2363 : : );
2364 : 1 : fclose(file_ptr);
2365 : 1 : return EXIT_FAILURE;
2366 : : }
2367 : :
2368 : : /* Remove the colon if present
2369 : : */
2370 [ + + ]: 33 : if((ndx = strrchr(var, ':')) != NULL)
2371 : 4 : *ndx = '\0';
2372 : :
2373 [ + + ]: 33 : if(CONF_VAR_IS(var, "KEY"))
2374 : : {
2375 [ + + ]: 9 : if(strcasecmp(val, "__CHANGEME__") == 0)
2376 : : {
2377 : 1 : log_msg(LOG_ERR,
2378 : : "[*] KEY value is not properly set in stanza source '%s' in access file: '%s'",
2379 : : curr_acc->source, access_filename);
2380 : 1 : fclose(file_ptr);
2381 : 1 : return EXIT_FAILURE;
2382 : : }
2383 : 8 : add_acc_string(&(curr_acc->key), val, file_ptr, opts);
2384 : 8 : curr_acc->key_len = strlen(curr_acc->key);
2385 : 8 : add_acc_bool(&(curr_acc->use_rijndael), "Y");
2386 : : }
2387 [ + + ]: 24 : else if(CONF_VAR_IS(var, "KEY_BASE64"))
2388 : : {
2389 [ + + ]: 3 : if(strcasecmp(val, "__CHANGEME__") == 0)
2390 : : {
2391 : 1 : log_msg(LOG_ERR,
2392 : : "[*] KEY_BASE64 value is not properly set in stanza source '%s' in access file: '%s'",
2393 : : curr_acc->source, access_filename);
2394 : 1 : fclose(file_ptr);
2395 : 1 : return EXIT_FAILURE;
2396 : : }
2397 [ + + ]: 2 : if (! is_base64((unsigned char *) val, strlen(val)))
2398 : : {
2399 : 1 : log_msg(LOG_ERR,
2400 : : "[*] KEY_BASE64 argument '%s' doesn't look like base64-encoded data.",
2401 : : val);
2402 : 1 : fclose(file_ptr);
2403 : 1 : return EXIT_FAILURE;
2404 : : }
2405 : 1 : add_acc_string(&(curr_acc->key_base64), val, file_ptr, opts);
2406 : 1 : add_acc_b64_string(&(curr_acc->key), &(curr_acc->key_len),
2407 : 1 : curr_acc->key_base64, file_ptr, opts);
2408 : 1 : add_acc_bool(&(curr_acc->use_rijndael), "Y");
2409 : : }
2410 [ + + ]: 21 : else if(CONF_VAR_IS(var, "HMAC_KEY_BASE64"))
2411 : : {
2412 [ + + ]: 3 : if(strcasecmp(val, "__CHANGEME__") == 0)
2413 : : {
2414 : 1 : log_msg(LOG_ERR,
2415 : : "[*] HMAC_KEY_BASE64 value is not properly set in stanza source '%s' in access file: '%s'",
2416 : : curr_acc->source, opts->config[CONF_ACCESS_FILE]);
2417 : 1 : fclose(file_ptr);
2418 : 1 : return EXIT_FAILURE;
2419 : : }
2420 [ + + ]: 2 : if (! is_base64((unsigned char *) val, strlen(val)))
2421 : : {
2422 : 1 : log_msg(LOG_ERR,
2423 : : "[*] HMAC_KEY_BASE64 argument '%s' doesn't look like base64-encoded data.",
2424 : : val);
2425 : 1 : fclose(file_ptr);
2426 : 1 : return EXIT_FAILURE;
2427 : : }
2428 : 1 : add_acc_string(&(curr_acc->hmac_key_base64), val, file_ptr, opts);
2429 : 1 : add_acc_b64_string(&(curr_acc->hmac_key), &(curr_acc->hmac_key_len),
2430 : 1 : curr_acc->hmac_key_base64, file_ptr, opts);
2431 : : }
2432 [ + + ]: 18 : else if(CONF_VAR_IS(var, "HMAC_KEY"))
2433 : : {
2434 [ + + ]: 3 : if(strcasecmp(val, "__CHANGEME__") == 0)
2435 : : {
2436 : 1 : log_msg(LOG_ERR,
2437 : : "[*] HMAC_KEY value is not properly set in stanza source '%s' in access file: '%s'",
2438 : : curr_acc->source, opts->config[CONF_ACCESS_FILE]);
2439 : 1 : fclose(file_ptr);
2440 : 1 : return EXIT_FAILURE;
2441 : : }
2442 : 2 : add_acc_string(&(curr_acc->hmac_key), val, file_ptr, opts);
2443 : 2 : curr_acc->hmac_key_len = strlen(curr_acc->hmac_key);
2444 : : }
2445 [ + + ]: 15 : else if(CONF_VAR_IS(var, "GPG_DECRYPT_ID"))
2446 : 1 : add_acc_string(&(curr_acc->gpg_decrypt_id), val, file_ptr, opts);
2447 [ + + ]: 14 : else if(CONF_VAR_IS(var, "GPG_DECRYPT_PW"))
2448 : : {
2449 [ + + ]: 2 : if(strcasecmp(val, "__CHANGEME__") == 0)
2450 : : {
2451 : 1 : log_msg(LOG_ERR,
2452 : : "[*] GPG_DECRYPT_PW value is not properly set in stanza source '%s' in access file: '%s'",
2453 : : curr_acc->source, access_filename);
2454 : 1 : fclose(file_ptr);
2455 : 1 : return EXIT_FAILURE;
2456 : : }
2457 : 1 : add_acc_string(&(curr_acc->gpg_decrypt_pw), val, file_ptr, opts);
2458 : 1 : add_acc_bool(&(curr_acc->use_gpg), "Y");
2459 : : }
2460 [ + + ]: 12 : else if(CONF_VAR_IS(var, "GPG_ALLOW_NO_PW"))
2461 : : {
2462 : 1 : add_acc_bool(&(curr_acc->gpg_allow_no_pw), val);
2463 [ + - ]: 1 : if(curr_acc->gpg_allow_no_pw == 1)
2464 : : {
2465 : 1 : add_acc_bool(&(curr_acc->use_gpg), "Y");
2466 : 1 : add_acc_string(&(curr_acc->gpg_decrypt_pw), "", file_ptr, opts);
2467 : : }
2468 : : }
2469 [ + + ]: 11 : else if(CONF_VAR_IS(var, "GPG_REQUIRE_SIG"))
2470 : : {
2471 : 1 : add_acc_bool(&(curr_acc->gpg_require_sig), val);
2472 : : }
2473 [ + + ]: 10 : else if(CONF_VAR_IS(var, "GPG_DISABLE_SIG"))
2474 : : {
2475 : 1 : add_acc_bool(&(curr_acc->gpg_disable_sig), val);
2476 : : }
2477 [ + + ]: 9 : else if(CONF_VAR_IS(var, "GPG_IGNORE_SIG_VERIFY_ERROR"))
2478 : : {
2479 : 1 : add_acc_bool(&(curr_acc->gpg_ignore_sig_error), val);
2480 : : }
2481 [ + + ]: 8 : else if(CONF_VAR_IS(var, "GPG_REMOTE_ID"))
2482 : 1 : add_acc_string(&(curr_acc->gpg_remote_id), val, file_ptr, opts);
2483 [ + + ]: 7 : else if(CONF_VAR_IS(var, "GPG_FINGERPRINT_ID"))
2484 : 1 : add_acc_string(&(curr_acc->gpg_remote_fpr), val, file_ptr, opts);
2485 : : else
2486 : 26 : log_msg(LOG_INFO, "Ignoring invalid entry: '%s'", var);
2487 : : }
2488 : 10 : fclose(file_ptr);
2489 : 10 : return EXIT_SUCCESS;
2490 : : }
2491 : :
2492 : : #ifdef HAVE_C_UNIT_TESTS /* LCOV_EXCL_START */
2493 : :
2494 : : DECLARE_UTEST(compare_port_list, "check compare_port_list function")
2495 : : {
2496 : : acc_port_list_t *in1_pl = NULL;
2497 : : acc_port_list_t *in2_pl = NULL;
2498 : : acc_port_list_t *acc_pl = NULL;
2499 : :
2500 : : /* Match any test */
2501 : : free_acc_port_list(in1_pl);
2502 : : free_acc_port_list(acc_pl);
2503 : : expand_acc_port_list(&in1_pl, "udp/6002");
2504 : : expand_acc_port_list(&in2_pl, "udp/6002, udp/6003");
2505 : : expand_acc_port_list(&acc_pl, "udp/6002, udp/6003");
2506 : : CU_ASSERT(compare_port_list(in1_pl, acc_pl, 1) == 1); /* Only one match is needed from access port list - 1 */
2507 : : CU_ASSERT(compare_port_list(in2_pl, acc_pl, 1) == 1); /* Only match is needed from access port list - 2 */
2508 : : CU_ASSERT(compare_port_list(in1_pl, acc_pl, 0) == 1); /* All ports must match access port list - 1 */
2509 : : CU_ASSERT(compare_port_list(in2_pl, acc_pl, 0) == 1); /* All ports must match access port list - 2 */
2510 : : CU_ASSERT(compare_port_list(acc_pl, in1_pl, 0) == 0); /* All ports must match in1 port list - 1 */
2511 : : CU_ASSERT(compare_port_list(acc_pl, in2_pl, 0) == 1); /* All ports must match in2 port list - 2 */
2512 : : }
2513 : :
2514 : : int register_ts_access(void)
2515 : : {
2516 : : ts_init(&TEST_SUITE(access), TEST_SUITE_DESCR(access), NULL, NULL);
2517 : : ts_add_utest(&TEST_SUITE(access), UTEST_FCT(compare_port_list), UTEST_DESCR(compare_port_list));
2518 : :
2519 : : return register_ts(&TEST_SUITE(access));
2520 : : }
2521 : : #endif /* HAVE_C_UNIT_TESTS */ /* LCOV_EXCL_STOP */
2522 : : /***EOF***/
|