Branch data Line data Source code
1 : : /*
2 : : ******************************************************************************
3 : : *
4 : : * File: access.c
5 : : *
6 : : * Purpose: Access.conf file processing for fwknop server.
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 : : #include <sys/stat.h>
32 : :
33 : : #if HAVE_SYS_SOCKET_H
34 : : #include <sys/socket.h>
35 : : #endif
36 : :
37 : : #include "fwknopd_common.h"
38 : : #include <arpa/inet.h>
39 : : #include "pwd.h"
40 : : #include "access.h"
41 : : #include "utils.h"
42 : : #include "log_msg.h"
43 : :
44 : : #define FATAL_ERR -1
45 : :
46 : : #ifndef SUCCESS
47 : : #define SUCCESS 1
48 : : #endif
49 : :
50 : : /* Add an access string entry
51 : : */
52 : : static int
53 : 3884 : add_acc_string(char **var, const char *val)
54 : : {
55 [ - + ]: 3884 : if(var == NULL)
56 : : {
57 : 0 : log_msg(LOG_ERR, "[*] add_acc_string() called with NULL variable");
58 : 0 : return FATAL_ERR;
59 : : }
60 : :
61 [ - + ]: 3884 : if(*var != NULL)
62 : 0 : free(*var);
63 : :
64 [ - + ]: 3884 : if((*var = strdup(val)) == NULL)
65 : : {
66 : 0 : log_msg(LOG_ERR,
67 : : "[*] Fatal memory allocation error adding access list entry: %s", *var
68 : : );
69 : 0 : return FATAL_ERR;
70 : : }
71 : : return SUCCESS;
72 : : }
73 : :
74 : : /* Decode base64 encoded string into access entry
75 : : */
76 : : static int
77 : 524 : add_acc_b64_string(char **var, int *len, const char *val)
78 : : {
79 [ - + ]: 524 : if((*var = strdup(val)) == NULL)
80 : : {
81 : 0 : log_msg(LOG_ERR,
82 : : "[*] Fatal memory allocation error adding access list entry: %s", *var
83 : : );
84 : 0 : return FATAL_ERR;
85 : : }
86 : 524 : memset(*var, 0x0, strlen(val));
87 : 524 : *len = fko_base64_decode(val, (unsigned char *) *var);
88 : :
89 [ - + ]: 524 : if (*len < 0)
90 : : {
91 : 0 : log_msg(LOG_ERR,
92 : : "[*] base64 decoding returned error for: %s", *var
93 : : );
94 : 0 : return FATAL_ERR;
95 : : }
96 : : return SUCCESS;
97 : : }
98 : :
99 : : /* Add an access bool entry (unsigned char of 1 or 0)
100 : : */
101 : : static unsigned char
102 : 1730 : add_acc_bool(unsigned char *var, const char *val)
103 : : {
104 : 1730 : return(*var = (strncasecmp(val, "Y", 1) == 0) ? 1 : 0);
105 : : }
106 : :
107 : : /* Add expiration time - convert date to epoch seconds
108 : : */
109 : : static int
110 : 6 : add_acc_expire_time(fko_srv_options_t *opts, time_t *access_expire_time, const char *val)
111 : : {
112 : : struct tm tm;
113 : :
114 : : memset(&tm, 0, sizeof(struct tm));
115 : :
116 [ + + ]: 3 : if (sscanf(val, "%2d/%2d/%4d", &tm.tm_mon, &tm.tm_mday, &tm.tm_year) != 3)
117 : : {
118 : :
119 : 1 : log_msg(LOG_ERR,
120 : : "[*] Fatal: invalid date value '%s' (need MM/DD/YYYY) for access stanza expiration time",
121 : : val
122 : : );
123 : : return FATAL_ERR;
124 : : }
125 : :
126 [ + - ]: 2 : if(tm.tm_mon > 0)
127 : 2 : tm.tm_mon -= 1; /* 0-11 */
128 : :
129 : : /* number of years since 1900
130 : : */
131 [ + + ]: 2 : if(tm.tm_year > 1900)
132 : 1 : tm.tm_year -= 1900;
133 : : else
134 [ + - ]: 1 : if(tm.tm_year < 100)
135 : 1 : tm.tm_year += 100;
136 : :
137 : 2 : *access_expire_time = mktime(&tm);
138 : :
139 : : return 1;
140 : : }
141 : :
142 : : /* Add expiration time via epoch seconds defined in access.conf
143 : : */
144 : : static int
145 : 1 : add_acc_expire_time_epoch(fko_srv_options_t *opts, time_t *access_expire_time, const char *val)
146 : : {
147 : : char *endptr;
148 : 1 : unsigned long expire_time = 0;
149 : :
150 : 1 : errno = 0;
151 : :
152 : 1 : expire_time = (time_t) strtoul(val, &endptr, 10);
153 : :
154 [ + - ][ - + ]: 1 : if (errno == ERANGE || (errno != 0 && expire_time == 0))
[ # # ]
155 : : {
156 : 0 : log_msg(LOG_ERR,
157 : : "[*] Fatal: invalid epoch seconds value '%s' for access stanza expiration time",
158 : : val
159 : : );
160 : : return FATAL_ERR;
161 : : }
162 : :
163 : 1 : *access_expire_time = (time_t) expire_time;
164 : :
165 : : return 1;
166 : : }
167 : :
168 : : #if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES)
169 : : static int
170 : 28 : add_acc_force_nat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, const char *val)
171 : : {
172 : 14 : char ip_str[MAX_IPV4_STR_LEN] = {0};
173 : :
174 [ + + ]: 14 : if (sscanf(val, "%15s %5u", ip_str, &curr_acc->force_nat_port) != 2)
175 : : {
176 : 1 : log_msg(LOG_ERR,
177 : : "[*] Fatal: invalid FORCE_NAT arg '%s', need <IP> <PORT>",
178 : : val
179 : : );
180 : : return FATAL_ERR;
181 : : }
182 : :
183 [ + + ]: 13 : if (curr_acc->force_nat_port > MAX_PORT)
184 : : {
185 : 1 : log_msg(LOG_ERR,
186 : : "[*] Fatal: invalid FORCE_NAT port '%d'", curr_acc->force_nat_port);
187 : : return FATAL_ERR;
188 : : }
189 : :
190 [ + + ]: 12 : if(! is_valid_ipv4_addr(ip_str))
191 : : {
192 : 1 : log_msg(LOG_ERR,
193 : : "[*] Fatal: invalid FORCE_NAT IP '%s'", ip_str);
194 : : return FATAL_ERR;
195 : : }
196 : :
197 : 11 : curr_acc->force_nat = 1;
198 : :
199 : 11 : return add_acc_string(&(curr_acc->force_nat_ip), ip_str);
200 : : }
201 : :
202 : : static int
203 : 10 : add_acc_force_snat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, const char *val)
204 : : {
205 : 5 : char ip_str[MAX_IPV4_STR_LEN] = {0};
206 : :
207 [ - + ]: 5 : if (sscanf(val, "%15s", ip_str) != 1)
208 : : {
209 : 0 : log_msg(LOG_ERR,
210 : : "[*] Fatal: invalid FORCE_SNAT arg '%s', need <IP>", val);
211 : : return FATAL_ERR;
212 : : }
213 : :
214 [ + + ]: 5 : if(! is_valid_ipv4_addr(ip_str))
215 : : {
216 : 2 : log_msg(LOG_ERR,
217 : : "[*] Fatal: invalid FORCE_SNAT IP '%s'", ip_str);
218 : : return FATAL_ERR;
219 : : }
220 : :
221 : 3 : curr_acc->force_snat = 1;
222 : :
223 : 3 : return add_acc_string(&(curr_acc->force_snat_ip), ip_str);
224 : : }
225 : :
226 : : #endif
227 : :
228 : : /* Take an IP or Subnet/Mask and convert it to mask for later
229 : : * comparisons of incoming source IPs against this mask.
230 : : */
231 : : static int
232 : 1712 : add_source_mask(fko_srv_options_t *opts, acc_stanza_t *acc, const char *ip)
233 : : {
234 : : char *ndx;
235 : 1712 : char ip_str[MAX_IPV4_STR_LEN] = {0};
236 : 1712 : char ip_mask_str[MAX_IPV4_STR_LEN] = {0};
237 : : uint32_t mask;
238 : 1712 : int is_err, mask_len = 0, need_shift = 1;
239 : :
240 : : struct in_addr in;
241 : : struct in_addr mask_in;
242 : :
243 : : acc_int_list_t *last_sle, *new_sle, *tmp_sle;
244 : :
245 [ + + ]: 1712 : if((new_sle = calloc(1, sizeof(acc_int_list_t))) == NULL)
246 : : {
247 : 11 : log_msg(LOG_ERR,
248 : : "[*] Fatal memory allocation error adding stanza source_list entry"
249 : : );
250 : 11 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
251 : : }
252 : :
253 : : /* Convert the IP data into the appropriate IP + (optional) mask
254 : : */
255 [ + + ]: 1701 : if(strcasecmp(ip, "ANY") == 0)
256 : : {
257 : 1573 : new_sle->maddr = 0x0;
258 : 1573 : new_sle->mask = 0x0;
259 : : }
260 : : else
261 : : {
262 : : /* See if we have a subnet component. If so pull out the IP and
263 : : * mask values, then create the final mask value.
264 : : */
265 [ + + ]: 128 : if((ndx = strchr(ip, '/')) != NULL)
266 : : {
267 [ + + ]: 93 : if(((ndx-ip)) >= MAX_IPV4_STR_LEN)
268 : : {
269 : 1 : log_msg(LOG_ERR, "[*] Error parsing string to IP");
270 : 1 : free(new_sle);
271 : 1 : new_sle = NULL;
272 : : return 0;
273 : : }
274 : :
275 : 92 : mask_len = strlen(ip) - (ndx-ip+1);
276 : :
277 [ + + ]: 92 : if(mask_len > 2)
278 : : {
279 [ + + ]: 6 : if(mask_len >= MIN_IPV4_STR_LEN && mask_len < MAX_IPV4_STR_LEN)
280 : : {
281 : : /* IP formatted mask
282 : : */
283 : 5 : strlcpy(ip_mask_str, (ip + (ndx-ip) + 1), mask_len+1);
284 [ + + ]: 5 : if(inet_aton(ip_mask_str, &mask_in) == 0)
285 : : {
286 : 3 : log_msg(LOG_ERR,
287 : : "[*] Fatal error parsing IP mask to int for: %s", ip_mask_str
288 : : );
289 : 3 : free(new_sle);
290 : 3 : new_sle = NULL;
291 : : return 0;
292 : : }
293 : 2 : mask = ntohl(mask_in.s_addr);
294 : 2 : need_shift = 0;
295 : : }
296 : : else
297 : : {
298 : 1 : log_msg(LOG_ERR, "[*] Invalid IP mask str '%s'.", ndx+1);
299 : 1 : free(new_sle);
300 : 1 : new_sle = NULL;
301 : : return 0;
302 : : }
303 : : }
304 : : else
305 : : {
306 [ + + ]: 86 : if(mask_len > 0)
307 : : {
308 : : /* CIDR mask
309 : : */
310 : 85 : mask = strtol_wrapper(ndx+1, 1, 32, NO_EXIT_UPON_ERR, &is_err);
311 [ + + ]: 85 : if(is_err != FKO_SUCCESS)
312 : : {
313 : 3 : log_msg(LOG_ERR, "[*] Invalid IP mask str '%s'.", ndx+1);
314 : 3 : free(new_sle);
315 : 3 : new_sle = NULL;
316 : : return 0;
317 : : }
318 : : }
319 : : else
320 : : {
321 : 1 : log_msg(LOG_ERR, "[*] Missing mask value.");
322 : 1 : free(new_sle);
323 : 1 : new_sle = NULL;
324 : : return 0;
325 : : }
326 : : }
327 : :
328 : 84 : strlcpy(ip_str, ip, (ndx-ip)+1);
329 : : }
330 : : else
331 : : {
332 : 35 : mask = 32;
333 [ + + ]: 35 : if(strnlen(ip, MAX_IPV4_STR_LEN+1) >= MAX_IPV4_STR_LEN)
334 : : {
335 : 1 : log_msg(LOG_ERR, "[*] Error parsing string to IP");
336 : 1 : free(new_sle);
337 : 1 : new_sle = NULL;
338 : : return 0;
339 : : }
340 : 34 : strlcpy(ip_str, ip, sizeof(ip_str));
341 : : }
342 : :
343 [ + + ]: 118 : if(inet_aton(ip_str, &in) == 0)
344 : : {
345 : 1 : log_msg(LOG_ERR,
346 : : "[*] Fatal error parsing IP to int for: %s", ip_str
347 : : );
348 : :
349 : 1 : free(new_sle);
350 : 1 : new_sle = NULL;
351 : :
352 : : return 0;
353 : : }
354 : :
355 : : /* Store our mask converted from CIDR to a 32-bit value.
356 : : */
357 [ + + ]: 117 : if(mask == 32)
358 : 33 : new_sle->mask = 0xFFFFFFFF;
359 [ + + ][ + - ]: 84 : else if(need_shift && (mask > 0 && mask < 32))
360 : 82 : new_sle->mask = (0xFFFFFFFF << (32 - mask));
361 : : else
362 : 2 : new_sle->mask = mask;
363 : :
364 : : /* Store our masked address for comparisons with future incoming
365 : : * packets.
366 : : */
367 : 117 : new_sle->maddr = ntohl(in.s_addr) & new_sle->mask;
368 : : }
369 : :
370 : : /* If this is not the first entry, we walk our pointer to the
371 : : * end of the list.
372 : : */
373 [ + + ]: 1690 : if(acc->source_list == NULL)
374 : : {
375 : 1690 : acc->source_list = new_sle;
376 : : }
377 : : else
378 : : {
379 : : tmp_sle = acc->source_list;
380 : :
381 : : do {
382 : 181 : last_sle = tmp_sle;
383 [ + + ]: 181 : } while((tmp_sle = tmp_sle->next));
384 : :
385 : 82 : last_sle->next = new_sle;
386 : : }
387 : :
388 : : return 1;
389 : : }
390 : :
391 : : /* Expand the access SOURCE string to a list of masks.
392 : : */
393 : : static int
394 : 1628 : expand_acc_source(fko_srv_options_t *opts, acc_stanza_t *acc)
395 : : {
396 : : char *ndx, *start;
397 : 1628 : char buf[ACCESS_BUF_LEN] = {0};
398 : 1628 : int res = 1;
399 : :
400 : 1628 : start = acc->source;
401 : :
402 [ + + ]: 8131 : for(ndx = start; *ndx; ndx++)
403 : : {
404 [ + + ]: 6505 : if(*ndx == ',')
405 : : {
406 : : /* Skip over any leading whitespace.
407 : : */
408 [ + + ]: 144 : while(isspace(*start))
409 : 58 : start++;
410 : :
411 [ + - ]: 86 : if(((ndx-start)+1) >= ACCESS_BUF_LEN)
412 : : return 0;
413 : :
414 : 86 : strlcpy(buf, start, (ndx-start)+1);
415 : :
416 : 86 : res = add_source_mask(opts, acc, buf);
417 [ + + ]: 86 : if(res == 0)
418 : : return res;
419 : :
420 : 84 : start = ndx+1;
421 : : }
422 : : }
423 : :
424 : : /* Skip over any leading whitespace (once again for the last in the list).
425 : : */
426 [ + + ]: 1652 : while(isspace(*start))
427 : 26 : start++;
428 : :
429 [ + - ]: 1626 : if(((ndx-start)+1) >= ACCESS_BUF_LEN)
430 : : return 0;
431 : :
432 : 1626 : strlcpy(buf, start, (ndx-start)+1);
433 : :
434 : 1626 : res = add_source_mask(opts, acc, buf);
435 : :
436 : 1615 : return res;
437 : : }
438 : :
439 : : static int
440 : 1077 : parse_proto_and_port(char *pstr, int *proto, int *port)
441 : : {
442 : : char *ndx;
443 : 1077 : char proto_str[ACCESS_BUF_LEN] = {0};
444 : : int is_err;
445 : :
446 : : /* Parse the string into its components.
447 : : */
448 [ + + ]: 1077 : if((ndx = strchr(pstr, '/')) == NULL)
449 : : {
450 : 1 : log_msg(LOG_ERR,
451 : : "[*] Parse error on access port entry: %s", pstr);
452 : :
453 : 1 : return(-1);
454 : : }
455 : :
456 [ - + ]: 1076 : if(((ndx - pstr)+1) >= ACCESS_BUF_LEN)
457 : : {
458 : 0 : log_msg(LOG_ERR,
459 : : "[*] Parse error on access port entry: %s", pstr);
460 : 0 : return(-1);
461 : : }
462 : :
463 : 1076 : strlcpy(proto_str, pstr, (ndx - pstr)+1);
464 : :
465 : 1076 : *port = strtol_wrapper(ndx+1, 0, MAX_PORT, NO_EXIT_UPON_ERR, &is_err);
466 [ + + ]: 1076 : if(is_err != FKO_SUCCESS)
467 : : {
468 : 1 : log_msg(LOG_ERR,
469 : : "[*] Invalid port '%s' in access request, must be in [%d,%d]",
470 : : pstr, 0, MAX_PORT);
471 : 1 : return(-1);
472 : : }
473 : :
474 [ + + ]: 1075 : if(strcasecmp(proto_str, "tcp") == 0)
475 : 928 : *proto = PROTO_TCP;
476 [ + + ]: 147 : else if(strcasecmp(proto_str, "udp") == 0)
477 : 145 : *proto = PROTO_UDP;
478 : : else
479 : : {
480 : 2 : log_msg(LOG_ERR,
481 : : "[*] Invalid protocol in access port entry: %s", pstr);
482 : 2 : return(-1);
483 : : }
484 : :
485 : : return(0);
486 : : }
487 : :
488 : : /* Take a proto/port string and convert it to appropriate integer values
489 : : * for comparisons of incoming SPA requests.
490 : : */
491 : : static int
492 : 1077 : add_port_list_ent(acc_port_list_t **plist, char *port_str)
493 : : {
494 : : int proto_int, port;
495 : :
496 : : acc_port_list_t *last_plist, *new_plist, *tmp_plist;
497 : :
498 : : /* Parse the string into its components and continue only if there
499 : : * are no problems with the incoming string.
500 : : */
501 [ + + ]: 1077 : if(parse_proto_and_port(port_str, &proto_int, &port) != 0)
502 : : return 0;
503 : :
504 [ - + ]: 1073 : if((new_plist = calloc(1, sizeof(acc_port_list_t))) == NULL)
505 : : {
506 : 0 : log_msg(LOG_ERR,
507 : : "[*] Fatal memory allocation error adding stanza source_list entry"
508 : : );
509 : 0 : exit(EXIT_FAILURE);
510 : : }
511 : :
512 : : /* If this is not the first entry, we walk our pointer to the
513 : : * end of the list.
514 : : */
515 [ + + ]: 1073 : if(*plist == NULL)
516 : : {
517 : 1073 : *plist = new_plist;
518 : : }
519 : : else
520 : : {
521 : : tmp_plist = *plist;
522 : :
523 : : do {
524 : 208 : last_plist = tmp_plist;
525 [ + + ]: 208 : } while((tmp_plist = tmp_plist->next));
526 : :
527 : 163 : last_plist->next = new_plist;
528 : : }
529 : :
530 : 1073 : new_plist->proto = proto_int;
531 : 1073 : new_plist->port = port;
532 : :
533 : 1073 : return 1;
534 : : }
535 : :
536 : : /* Add a string list entry to the given acc_string_list.
537 : : */
538 : : static int
539 : 122 : add_string_list_ent(acc_string_list_t **stlist, const char *str_str)
540 : : {
541 : : acc_string_list_t *last_stlist, *new_stlist, *tmp_stlist;
542 : :
543 [ - + ]: 122 : if((new_stlist = calloc(1, sizeof(acc_string_list_t))) == NULL)
544 : : {
545 : 0 : log_msg(LOG_ERR,
546 : : "[*] Fatal memory allocation error creating string list entry"
547 : : );
548 : 0 : return FATAL_ERR;
549 : : }
550 : :
551 : : /* If this is not the first entry, we walk our pointer to the
552 : : * end of the list.
553 : : */
554 [ + + ]: 122 : if(*stlist == NULL)
555 : : {
556 : 122 : *stlist = new_stlist;
557 : : }
558 : : else
559 : : {
560 : : tmp_stlist = *stlist;
561 : :
562 : : do {
563 : 75 : last_stlist = tmp_stlist;
564 [ + + ]: 75 : } while((tmp_stlist = tmp_stlist->next));
565 : :
566 : 50 : last_stlist->next = new_stlist;
567 : : }
568 : :
569 [ - + ]: 122 : if(new_stlist->str != NULL)
570 : 0 : free(new_stlist->str);
571 : :
572 : 122 : new_stlist->str = strdup(str_str);
573 : :
574 [ - + ]: 122 : if(new_stlist->str == NULL)
575 : : {
576 : 0 : log_msg(LOG_ERR,
577 : : "[*] Fatal memory allocation error adding string list entry item"
578 : : );
579 : 0 : return FATAL_ERR;
580 : : }
581 : : return SUCCESS;
582 : : }
583 : :
584 : : /* Expand a proto/port access string to a list of access proto-port struct.
585 : : */
586 : : int
587 : 286 : expand_acc_port_list(acc_port_list_t **plist, char *plist_str)
588 : : {
589 : : char *ndx, *start;
590 : 286 : char buf[ACCESS_BUF_LEN] = {0};
591 : :
592 : 286 : start = plist_str;
593 : :
594 [ + + ]: 2567 : for(ndx = start; *ndx != '\0'; ndx++)
595 : : {
596 [ + + ]: 2282 : if(*ndx == ',')
597 : : {
598 : : /* Skip over any leading whitespace.
599 : : */
600 [ + + ]: 82 : while(isspace(*start))
601 : 31 : start++;
602 : :
603 [ + - ]: 51 : if(((ndx-start)+1) >= ACCESS_BUF_LEN)
604 : : return 0;
605 : :
606 : 51 : strlcpy(buf, start, (ndx-start)+1);
607 : :
608 [ + + ]: 51 : if(add_port_list_ent(plist, buf) == 0)
609 : : return 0;
610 : :
611 : 50 : start = ndx+1;
612 : : }
613 : : }
614 : :
615 : : /* Skip over any leading whitespace (once again for the last in the list).
616 : : */
617 [ + + ]: 300 : while(isspace(*start))
618 : 15 : start++;
619 : :
620 [ + + ]: 285 : if(((ndx-start)+1) >= ACCESS_BUF_LEN)
621 : : return 0;
622 : :
623 : 284 : strlcpy(buf, start, (ndx-start)+1);
624 : :
625 [ + + ]: 284 : if(add_port_list_ent(plist, buf) == 0)
626 : : return 0;
627 : :
628 : 281 : return 1;
629 : : }
630 : :
631 : : /* Expand a comma-separated string into a simple acc_string_list.
632 : : */
633 : : static int
634 : 72 : expand_acc_string_list(acc_string_list_t **stlist, char *stlist_str)
635 : : {
636 : : char *ndx, *start;
637 : 72 : char buf[MAX_LINE_LEN] = {0};
638 : :
639 : 72 : start = stlist_str;
640 : :
641 [ + + ]: 1276 : for(ndx = start; *ndx; ndx++)
642 : : {
643 [ + + ]: 1204 : if(*ndx == ',')
644 : : {
645 : : /* Skip over any leading whitespace.
646 : : */
647 [ + + ]: 75 : while(isspace(*start))
648 : 25 : start++;
649 : :
650 [ + - ]: 50 : if(((ndx-start)+1) >= MAX_LINE_LEN)
651 : : return FATAL_ERR;
652 : :
653 : 50 : strlcpy(buf, start, (ndx-start)+1);
654 [ + - ]: 50 : if(add_string_list_ent(stlist, buf) != SUCCESS)
655 : : return FATAL_ERR;
656 : :
657 : 50 : start = ndx+1;
658 : : }
659 : : }
660 : :
661 : : /* Skip over any leading whitespace (once again for the last in the list).
662 : : */
663 [ + + ]: 97 : while(isspace(*start))
664 : 25 : start++;
665 : :
666 [ + - ]: 72 : if(((ndx-start)+1) >= MAX_LINE_LEN)
667 : : return FATAL_ERR;
668 : :
669 : 72 : strlcpy(buf, start, (ndx-start)+1);
670 : :
671 [ + - ]: 72 : if(add_string_list_ent(stlist, buf) != SUCCESS)
672 : : return FATAL_ERR;
673 : :
674 : 72 : return SUCCESS;
675 : : }
676 : :
677 : : /* Free the acc source_list
678 : : */
679 : : static void
680 : 1651 : free_acc_source_list(acc_int_list_t *sle)
681 : : {
682 : : acc_int_list_t *last_sle;
683 : :
684 [ + + ]: 3335 : while(sle != NULL)
685 : : {
686 : 1684 : last_sle = sle;
687 : 1684 : sle = last_sle->next;
688 : :
689 : 1684 : free(last_sle);
690 : : }
691 : 1651 : }
692 : :
693 : : /* Free a port_list
694 : : */
695 : : void
696 : 916 : free_acc_port_list(acc_port_list_t *ple)
697 : : {
698 : : acc_port_list_t *last_ple;
699 : :
700 [ + + ]: 1989 : while(ple != NULL)
701 : : {
702 : 1073 : last_ple = ple;
703 : 1073 : ple = last_ple->next;
704 : :
705 : 1073 : free(last_ple);
706 : : }
707 : 916 : }
708 : :
709 : : /* Free a string_list
710 : : */
711 : : static void
712 : 72 : free_acc_string_list(acc_string_list_t *stl)
713 : : {
714 : : acc_string_list_t *last_stl;
715 : :
716 [ + + ]: 194 : while(stl != NULL)
717 : : {
718 : 122 : last_stl = stl;
719 : 122 : stl = last_stl->next;
720 : :
721 : 122 : free(last_stl->str);
722 : 122 : free(last_stl);
723 : : }
724 : 72 : }
725 : :
726 : : static void
727 : 2376 : zero_buf_wrapper(char *buf, int len)
728 : : {
729 : :
730 [ - + ]: 2376 : if(zero_buf(buf, len) != FKO_SUCCESS)
731 : 0 : log_msg(LOG_ERR,
732 : : "[*] Could not zero out sensitive data buffer.");
733 : :
734 : 2376 : return;
735 : : }
736 : :
737 : : /* Free any allocated content of an access stanza.
738 : : *
739 : : * NOTE: If a new access.conf parameter is created, and it is a string
740 : : * value, it also needs to be added to the list of items to check
741 : : * and free below.
742 : : */
743 : : static void
744 : 1651 : free_acc_stanza_data(acc_stanza_t *acc)
745 : : {
746 : :
747 [ + - ]: 1651 : if(acc->source != NULL)
748 : : {
749 : 1651 : free(acc->source);
750 : 1651 : free_acc_source_list(acc->source_list);
751 : : }
752 : :
753 [ + + ]: 1651 : if(acc->open_ports != NULL)
754 : : {
755 : 29 : free(acc->open_ports);
756 : 29 : free_acc_port_list(acc->oport_list);
757 : : }
758 : :
759 [ + + ]: 1651 : if(acc->restrict_ports != NULL)
760 : : {
761 : 1 : free(acc->restrict_ports);
762 : 1 : free_acc_port_list(acc->rport_list);
763 : : }
764 : :
765 [ + + ]: 1651 : if(acc->force_nat_ip != NULL)
766 : 11 : free(acc->force_nat_ip);
767 : :
768 [ + + ]: 1651 : if(acc->force_snat_ip != NULL)
769 : 3 : free(acc->force_snat_ip);
770 : :
771 [ + + ]: 1651 : if(acc->key != NULL)
772 : : {
773 : 1590 : zero_buf_wrapper(acc->key, acc->key_len);
774 : 1590 : free(acc->key);
775 : : }
776 : :
777 [ + + ]: 1651 : if(acc->key_base64 != NULL)
778 : : {
779 : 241 : zero_buf_wrapper(acc->key_base64, strlen(acc->key_base64));
780 : 241 : free(acc->key_base64);
781 : : }
782 : :
783 [ + + ]: 1651 : if(acc->hmac_key != NULL)
784 : : {
785 : 276 : zero_buf_wrapper(acc->hmac_key, acc->hmac_key_len);
786 : 276 : free(acc->hmac_key);
787 : : }
788 : :
789 [ + + ]: 1651 : if(acc->hmac_key_base64 != NULL)
790 : : {
791 : 269 : zero_buf_wrapper(acc->hmac_key_base64, strlen(acc->hmac_key_base64));
792 : 269 : free(acc->hmac_key_base64);
793 : : }
794 : :
795 [ + + ]: 1651 : if(acc->cmd_exec_user != NULL)
796 : 5 : free(acc->cmd_exec_user);
797 : :
798 [ + + ]: 1651 : if(acc->cmd_exec_group != NULL)
799 : 3 : free(acc->cmd_exec_group);
800 : :
801 [ + + ]: 1651 : if(acc->require_username != NULL)
802 : 2 : free(acc->require_username);
803 : :
804 [ + + ]: 1651 : if(acc->gpg_home_dir != NULL)
805 : 73 : free(acc->gpg_home_dir);
806 : :
807 [ + + ]: 1651 : if(acc->gpg_exe != NULL)
808 : 1 : free(acc->gpg_exe);
809 : :
810 [ + + ]: 1651 : if(acc->gpg_decrypt_id != NULL)
811 : 73 : free(acc->gpg_decrypt_id);
812 : :
813 [ + + ]: 1651 : if(acc->gpg_decrypt_pw != NULL)
814 : 75 : free(acc->gpg_decrypt_pw);
815 : :
816 [ + + ]: 1651 : if(acc->gpg_remote_id != NULL)
817 : : {
818 : 68 : free(acc->gpg_remote_id);
819 : 68 : free_acc_string_list(acc->gpg_remote_id_list);
820 : : }
821 [ + + ]: 1651 : if(acc->gpg_remote_fpr != NULL)
822 : : {
823 : 4 : free(acc->gpg_remote_fpr);
824 : 4 : free_acc_string_list(acc->gpg_remote_fpr_list);
825 : : }
826 : 1651 : return;
827 : : }
828 : :
829 : : /* Expand any access entries that may be multi-value.
830 : : */
831 : : static void
832 : 1617 : expand_acc_ent_lists(fko_srv_options_t *opts)
833 : : {
834 : 1617 : acc_stanza_t *acc = opts->acc_stanzas;
835 : :
836 : : /* We need to do this for each stanza.
837 : : */
838 [ + + ]: 3218 : while(acc)
839 : : {
840 : : /* Expand the source string to 32-bit integer IP + masks for each entry.
841 : : */
842 [ + + ]: 1628 : if(expand_acc_source(opts, acc) == 0)
843 : : {
844 : 11 : log_msg(LOG_ERR, "[*] Fatal invalid SOURCE in access stanza");
845 : 11 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
846 : : }
847 : :
848 : : /* Now expand the open_ports string.
849 : : */
850 [ + + ][ + - ]: 1606 : if(acc->open_ports != NULL && strlen(acc->open_ports))
851 : : {
852 [ + + ]: 26 : if(expand_acc_port_list(&(acc->oport_list), acc->open_ports) == 0)
853 : : {
854 : 4 : log_msg(LOG_ERR, "[*] Fatal invalid OPEN_PORTS in access stanza");
855 : 4 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
856 : : }
857 : : }
858 : :
859 [ + + ][ + - ]: 1602 : if(acc->restrict_ports != NULL && strlen(acc->restrict_ports))
860 : : {
861 [ + - ]: 1 : if(expand_acc_port_list(&(acc->rport_list), acc->restrict_ports) == 0)
862 : : {
863 : 1 : log_msg(LOG_ERR, "[*] Fatal invalid RESTRICT_PORTS in access stanza");
864 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
865 : : }
866 : : }
867 : :
868 : : /* Expand the GPG_REMOTE_ID string.
869 : : */
870 [ + + ][ + - ]: 1601 : if(acc->gpg_remote_id != NULL && strlen(acc->gpg_remote_id))
871 : : {
872 [ - + ]: 68 : if(expand_acc_string_list(&(acc->gpg_remote_id_list),
873 : : acc->gpg_remote_id) != SUCCESS)
874 : : {
875 : 0 : log_msg(LOG_ERR, "[*] Fatal invalid GPG_REMOTE_ID list in access stanza");
876 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
877 : : }
878 : : }
879 : :
880 : : /* Expand the GPG_FINGERPRINT_ID string.
881 : : */
882 [ + + ][ + - ]: 1601 : if(acc->gpg_remote_fpr != NULL && strlen(acc->gpg_remote_fpr))
883 : : {
884 [ - + ]: 4 : if(expand_acc_string_list(&(acc->gpg_remote_fpr_list),
885 : : acc->gpg_remote_fpr) != SUCCESS)
886 : : {
887 : 0 : log_msg(LOG_ERR, "[*] Fatal invalid GPG_FINGERPRINT_ID list in access stanza");
888 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
889 : : }
890 : : }
891 : :
892 : 1601 : acc = acc->next;
893 : : }
894 : 1590 : return;
895 : : }
896 : :
897 : : void
898 : 7159 : free_acc_stanzas(fko_srv_options_t *opts)
899 : : {
900 : : acc_stanza_t *acc, *last_acc;
901 : :
902 : : /* Free any resources first (in case of reconfig). Assume non-NULL
903 : : * entry needs to be freed.
904 : : */
905 : 7159 : acc = opts->acc_stanzas;
906 : :
907 [ + + ]: 8810 : while(acc != NULL)
908 : : {
909 : 1651 : last_acc = acc;
910 : 1651 : acc = last_acc->next;
911 : :
912 : 1651 : free_acc_stanza_data(last_acc);
913 : 1651 : free(last_acc);
914 : : }
915 : :
916 : 7159 : return;
917 : : }
918 : :
919 : : /* Wrapper for free_acc_stanzas(), we may put additional initialization
920 : : * code here.
921 : : */
922 : : static void
923 : 1654 : acc_stanza_init(fko_srv_options_t *opts)
924 : : {
925 : : /* Free any resources first (in case of reconfig). Assume non-NULL
926 : : * entry needs to be freed.
927 : : */
928 : 1654 : free_acc_stanzas(opts);
929 : :
930 : 1654 : return;
931 : : }
932 : :
933 : : /* Add a new stanza bay allocating the required memory at the required
934 : : * location, yada-yada-yada.
935 : : */
936 : : static acc_stanza_t*
937 : 1666 : acc_stanza_add(fko_srv_options_t *opts)
938 : : {
939 : 1666 : acc_stanza_t *acc = opts->acc_stanzas;
940 : 1666 : acc_stanza_t *new_acc = calloc(1, sizeof(acc_stanza_t));
941 : : acc_stanza_t *last_acc;
942 : :
943 [ + + ]: 1666 : if(new_acc == NULL)
944 : : {
945 : 9 : log_msg(LOG_ERR,
946 : : "[*] Fatal memory allocation error adding access stanza"
947 : : );
948 : 9 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
949 : : }
950 : :
951 : : /* If this is not the first acc entry, we walk our acc pointer to the
952 : : * end of the existing list.
953 : : */
954 [ + + ]: 1657 : if(acc == NULL)
955 : : {
956 : 1657 : opts->acc_stanzas = new_acc;
957 : : }
958 : : else
959 : : {
960 : : do {
961 : 22 : last_acc = acc;
962 [ + + ]: 22 : } while((acc = acc->next));
963 : :
964 : 13 : last_acc->next = new_acc;
965 : : }
966 : :
967 : 1657 : return(new_acc);
968 : : }
969 : :
970 : : /* Scan the access options for entries that have not been set, but need
971 : : * a default value.
972 : : */
973 : : static void
974 : 1590 : set_acc_defaults(fko_srv_options_t *opts)
975 : : {
976 : 1590 : acc_stanza_t *acc = opts->acc_stanzas;
977 : 1590 : int i=1;
978 : :
979 [ + - ]: 1590 : if(!acc)
980 : : return;
981 : :
982 [ + + ]: 3190 : while(acc)
983 : : {
984 : : /* set default fw_access_timeout if necessary
985 : : */
986 [ + + ]: 1601 : if(acc->fw_access_timeout < 1)
987 : 14 : acc->fw_access_timeout = DEF_FW_ACCESS_TIMEOUT;
988 : :
989 : : /* set default gpg keyring path if necessary
990 : : */
991 [ + + ]: 1601 : if(acc->gpg_decrypt_pw != NULL)
992 : : {
993 [ + + ]: 73 : if(acc->gpg_home_dir == NULL)
994 [ - + ]: 1 : if(add_acc_string(&(acc->gpg_home_dir), opts->config[CONF_GPG_HOME_DIR]) != SUCCESS)
995 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
996 : :
997 [ + + ]: 73 : if(! acc->gpg_require_sig)
998 : : {
999 [ + + ]: 72 : if (acc->gpg_disable_sig)
1000 : : {
1001 : 1 : log_msg(LOG_INFO,
1002 : : "Warning: GPG_REQUIRE_SIG should really be enabled for stanza source: '%s' (#%d)",
1003 : : acc->source, i
1004 : : );
1005 : : }
1006 : : else
1007 : : {
1008 : : /* Make this the default unless explicitly disabled
1009 : : */
1010 : 71 : acc->gpg_require_sig = 1;
1011 : : }
1012 : : }
1013 : : else
1014 : : {
1015 [ + - ]: 1 : if (acc->gpg_disable_sig)
1016 : : {
1017 : 1 : log_msg(LOG_INFO,
1018 : : "Warning: GPG_REQUIRE_SIG and GPG_DISABLE_SIG are both set, will check sigs (stanza source: '%s' #%d)",
1019 : : acc->source, i
1020 : : );
1021 : : }
1022 : : }
1023 : :
1024 : : /* If signature checking is enabled, make sure we either have sig ID's or
1025 : : * fingerprint ID's to check
1026 : : */
1027 [ + + ]: 73 : if(! acc->gpg_disable_sig
1028 [ + + ][ + + ]: 71 : && (acc->gpg_remote_id == NULL && acc->gpg_remote_fpr == NULL))
1029 : : {
1030 : 1 : log_msg(LOG_INFO,
1031 : : "Warning: Must have either sig ID's or fingerprints to check via GPG_REMOTE_ID or GPG_FINGERPRINT_ID (stanza source: '%s' #%d)",
1032 : : acc->source, i
1033 : : );
1034 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1035 : : }
1036 : : }
1037 : :
1038 [ + + ]: 1600 : if(acc->encryption_mode == FKO_ENC_MODE_UNKNOWN)
1039 : 1573 : acc->encryption_mode = FKO_DEFAULT_ENC_MODE;
1040 : :
1041 : : /* if we're using an HMAC key and the HMAC digest type was not
1042 : : * set for HMAC_DIGEST_TYPE, then assume it's SHA256
1043 : : */
1044 : :
1045 [ + + ]: 1600 : if(acc->hmac_type == FKO_HMAC_UNKNOWN
1046 [ + + ][ + - ]: 1547 : && acc->hmac_key_len > 0 && acc->hmac_key != NULL)
1047 : : {
1048 : 219 : acc->hmac_type = FKO_DEFAULT_HMAC_MODE;
1049 : : }
1050 : :
1051 : 1600 : acc = acc->next;
1052 : 1600 : i++;
1053 : : }
1054 : : return;
1055 : : }
1056 : :
1057 : : /* Perform some sanity checks on an acc stanza data.
1058 : : */
1059 : : static int
1060 : 1635 : acc_data_is_valid(struct passwd *user_pw, acc_stanza_t * const acc)
1061 : : {
1062 [ - + ]: 1635 : if(acc == NULL)
1063 : : {
1064 : 0 : log_msg(LOG_ERR,
1065 : : "[*] acc_data_is_valid() called with NULL acc stanza");
1066 : 0 : return(0);
1067 : : }
1068 : :
1069 [ + + ][ - + ]: 1635 : if(((acc->key == NULL || acc->key_len == 0)
1070 [ + + ][ + + ]: 50 : && ((acc->gpg_decrypt_pw == NULL || !strlen(acc->gpg_decrypt_pw))
1071 [ + + ]: 34 : && acc->gpg_allow_no_pw == 0))
1072 [ + + ][ - + ]: 1634 : || (acc->use_rijndael == 0 && acc->use_gpg == 0 && acc->gpg_allow_no_pw == 0))
1073 : : {
1074 : 1 : log_msg(LOG_ERR,
1075 : : "[*] No keys found for access stanza source: '%s'", acc->source
1076 : : );
1077 : 1 : return(0);
1078 : : }
1079 : :
1080 [ + + ][ + - ]: 1634 : if(acc->use_rijndael && acc->key != NULL)
1081 : : {
1082 [ + + ]: 1585 : if((acc->encryption_mode == FKO_ENC_MODE_CBC_LEGACY_IV)
1083 [ + + ]: 23 : && (acc->key_len > 16))
1084 : : {
1085 : 1 : log_msg(LOG_INFO,
1086 : : "Warning: truncating encryption key in legacy mode to 16 bytes for access stanza source: '%s'",
1087 : : acc->source
1088 : : );
1089 : 1 : acc->key_len = 16;
1090 : : }
1091 : : }
1092 : :
1093 [ + + ][ + - ]: 1634 : if((acc->hmac_key_len) != 0 && (acc->hmac_key != NULL))
1094 : : {
1095 [ + + ][ + - ]: 281 : if((acc->key != NULL) && (acc->key_len != 0)
1096 [ + + ]: 251 : && (acc->key_len == acc->hmac_key_len))
1097 : : {
1098 [ + + ]: 3 : if(memcmp(acc->key, acc->hmac_key, acc->hmac_key_len) == 0)
1099 : : {
1100 : 1 : log_msg(LOG_ERR,
1101 : : "[*] The encryption passphrase and HMAC key should not be identical for access stanza source: '%s'",
1102 : : acc->source
1103 : : );
1104 : 1 : return(0);
1105 : : }
1106 : : }
1107 [ + + ]: 278 : else if((acc->gpg_allow_no_pw == 0)
1108 [ + + ]: 264 : && acc->gpg_decrypt_pw != NULL
1109 [ + + ]: 16 : && (strlen(acc->gpg_decrypt_pw) == acc->hmac_key_len))
1110 : : {
1111 [ + - ]: 1 : if(memcmp(acc->gpg_decrypt_pw, acc->hmac_key, acc->hmac_key_len) == 0)
1112 : : {
1113 : 1 : log_msg(LOG_ERR,
1114 : : "[*] The encryption passphrase and HMAC key should not be identical for access stanza source: '%s'",
1115 : : acc->source
1116 : : );
1117 : 1 : return(0);
1118 : : }
1119 : : }
1120 : : }
1121 : :
1122 [ + + ][ - + ]: 1632 : if((acc->force_snat == 1 || acc->force_masquerade == 1) && acc->force_nat == 0)
[ + + ]
1123 : : {
1124 : 2 : log_msg(LOG_ERR,
1125 : : "[*] FORCE_SNAT/FORCE_MASQUERADE implies FORCE_NAT must also be used for access stanza source: '%s'",
1126 : : acc->source
1127 : : );
1128 : 2 : return(0);
1129 : : }
1130 : :
1131 [ + + ]: 1630 : if(acc->require_source_address == 0)
1132 : : {
1133 : 1628 : log_msg(LOG_INFO,
1134 : : "Warning: REQUIRE_SOURCE_ADDRESS not enabled for access stanza source: '%s'",
1135 : : acc->source
1136 : : );
1137 : : }
1138 : :
1139 [ + + ][ + - ]: 1630 : if(user_pw != NULL && acc->cmd_exec_uid != 0 && acc->cmd_exec_gid == 0)
[ + + ]
1140 : : {
1141 : 2 : log_msg(LOG_INFO,
1142 : : "Setting gid to group associated with CMD_EXEC_USER '%s' for setgid() execution in stanza source: '%s'",
1143 : : acc->cmd_exec_user,
1144 : : acc->source
1145 : : );
1146 : 2 : acc->cmd_exec_gid = user_pw->pw_gid;
1147 : : }
1148 : :
1149 : : return(1);
1150 : : }
1151 : :
1152 : : /* Read and parse the access file, popluating the access data as we go.
1153 : : */
1154 : : void
1155 : 1670 : parse_access_file(fko_srv_options_t *opts)
1156 : : {
1157 : : FILE *file_ptr;
1158 : : char *ndx;
1159 : 1670 : int got_source = 0, is_err;
1160 : 1670 : unsigned int num_lines = 0;
1161 : :
1162 : 1670 : char access_line_buf[MAX_LINE_LEN] = {0};
1163 : 1670 : char var[MAX_LINE_LEN] = {0};
1164 : 1670 : char val[MAX_LINE_LEN] = {0};
1165 : :
1166 : 1670 : struct passwd *pw = NULL;
1167 : 1670 : struct passwd *user_pw = NULL;
1168 : : struct stat st;
1169 : :
1170 : 1670 : acc_stanza_t *curr_acc = NULL;
1171 : :
1172 : : /* First see if the access file exists. If it doesn't, complain
1173 : : * and bail.
1174 : : */
1175 [ + + ]: 1670 : if(stat(opts->config[CONF_ACCESS_FILE], &st) != 0)
1176 : : {
1177 : 1 : log_msg(LOG_ERR, "[*] Access file: '%s' was not found.",
1178 : : opts->config[CONF_ACCESS_FILE]);
1179 : :
1180 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1181 : : }
1182 : :
1183 [ - + ]: 1669 : if(verify_file_perms_ownership(opts->config[CONF_ACCESS_FILE]) != 1)
1184 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1185 : :
1186 : : /* A note on security here: Coverity flags the following fopen() as a
1187 : : * Time of check time of use (TOCTOU) bug with a low priority due to the
1188 : : * previous stat() call above. I.e., the access.conf file on disk could
1189 : : * have been changed between the stat() and the fopen() causing a TOCTOU
1190 : : * bug. While technically this is true, the return value of fopen() is
1191 : : * also checked below so stat() success does not imply we assume fopen()
1192 : : * success. Also, we could just remove the stat() and
1193 : : * verify_file_perms_ownership() calls above to "fix" the bug, but this
1194 : : * would actually make things easier for an attacker that has already
1195 : : * compromised the local system since access.conf could be changed to, say,
1196 : : * a symbolic link (for which verify_file_perms_ownership() throws a
1197 : : * warning), and then there is no race at all before the fopen(). I.e.
1198 : : * forcing an attacker to do the race makes things harder for them.
1199 : : */
1200 [ + + ]: 1669 : if ((file_ptr = fopen(opts->config[CONF_ACCESS_FILE], "r")) == NULL)
1201 : : {
1202 : 15 : log_msg(LOG_ERR, "[*] Could not open access file: %s",
1203 : : opts->config[CONF_ACCESS_FILE]);
1204 : 15 : perror(NULL);
1205 : :
1206 : 15 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1207 : : }
1208 : :
1209 : : /* Initialize the access list.
1210 : : */
1211 : 1654 : acc_stanza_init(opts);
1212 : :
1213 : : /* Now walk through access file pulling the access entries into the
1214 : : * current stanza.
1215 : : */
1216 [ + + ]: 8912 : while ((fgets(access_line_buf, MAX_LINE_LEN, file_ptr)) != NULL)
1217 : : {
1218 : 5636 : num_lines++;
1219 : 5636 : access_line_buf[MAX_LINE_LEN-1] = '\0';
1220 : :
1221 : : /* Get past comments and empty lines (note: we only look at the
1222 : : * first character.
1223 : : */
1224 [ + + ][ + - ]: 5636 : if(IS_EMPTY_LINE(access_line_buf[0]))
[ + - ][ - + ]
1225 : 9 : continue;
1226 : :
1227 [ + + ]: 5627 : if(sscanf(access_line_buf, "%s %[^;\n\r]", var, val) != 2)
1228 : : {
1229 : 1 : log_msg(LOG_ERR,
1230 : : "[*] Invalid access file entry in %s at line %i.\n - '%s'",
1231 : : opts->config[CONF_ACCESS_FILE], num_lines, access_line_buf
1232 : : );
1233 : 1 : fclose(file_ptr);
1234 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1235 : : }
1236 : :
1237 : : /* Remove any colon that may be on the end of the var
1238 : : */
1239 [ + + ]: 5626 : if((ndx = strrchr(var, ':')) != NULL)
1240 : 15 : *ndx = '\0';
1241 : :
1242 : : /* Even though sscanf should automatically add a terminating
1243 : : * NULL byte, an assumption is made that the input arrays are
1244 : : * big enough, so we'll force a terminating NULL byte regardless
1245 : : */
1246 : 5626 : var[MAX_LINE_LEN-1] = 0x0;
1247 : 5626 : val[MAX_LINE_LEN-1] = 0x0;
1248 : :
1249 [ + + ]: 5626 : if (opts->verbose > 3)
1250 : 24 : log_msg(LOG_DEBUG,
1251 : : "ACCESS FILE: %s, LINE: %s\tVar: %s, Val: '%s'",
1252 : : opts->config[CONF_ACCESS_FILE], access_line_buf, var, val
1253 : : );
1254 : :
1255 : : /* Process the entry.
1256 : : *
1257 : : * NOTE: If a new access.conf parameter is created. It also needs
1258 : : * to be accounted for in the following if/if else construct.
1259 : : */
1260 [ + + ]: 5626 : if(CONF_VAR_IS(var, "SOURCE"))
1261 : : {
1262 : : /* If this is not the first stanza, sanity check the previous
1263 : : * stanza for the minimum required data.
1264 : : */
1265 [ + + ]: 1667 : if(curr_acc != NULL) {
1266 [ + + ]: 14 : if(!acc_data_is_valid(user_pw, curr_acc))
1267 : : {
1268 : 1 : log_msg(LOG_ERR, "[*] Data error in access file: '%s'",
1269 : : opts->config[CONF_ACCESS_FILE]);
1270 : 1 : fclose(file_ptr);
1271 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1272 : : }
1273 : : }
1274 : :
1275 : : /* Start new stanza.
1276 : : */
1277 : 1666 : curr_acc = acc_stanza_add(opts);
1278 : :
1279 [ - + ]: 1657 : if(add_acc_string(&(curr_acc->source), val) != SUCCESS)
1280 : : {
1281 : 0 : fclose(file_ptr);
1282 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1283 : : }
1284 : :
1285 : 1657 : got_source++;
1286 : : }
1287 [ + + ]: 3959 : else if (curr_acc == NULL)
1288 : : {
1289 : : /* The stanza must start with the "SOURCE" variable
1290 : : */
1291 : 1 : continue;
1292 : : }
1293 [ + + ]: 3958 : else if(CONF_VAR_IS(var, "OPEN_PORTS"))
1294 : : {
1295 [ - + ]: 29 : if(add_acc_string(&(curr_acc->open_ports), val) != SUCCESS)
1296 : : {
1297 : 0 : fclose(file_ptr);
1298 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1299 : : }
1300 : : }
1301 [ + + ]: 3929 : else if(CONF_VAR_IS(var, "RESTRICT_PORTS"))
1302 : : {
1303 [ - + ]: 1 : if(add_acc_string(&(curr_acc->restrict_ports), val) != SUCCESS)
1304 : : {
1305 : 0 : fclose(file_ptr);
1306 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1307 : : }
1308 : : }
1309 [ + + ]: 3928 : else if(CONF_VAR_IS(var, "KEY"))
1310 : : {
1311 [ + + ]: 1349 : if(strcasecmp(val, "__CHANGEME__") == 0)
1312 : : {
1313 : 1 : log_msg(LOG_ERR,
1314 : : "[*] KEY value is not properly set in stanza source '%s' in access file: '%s'",
1315 : : curr_acc->source, opts->config[CONF_ACCESS_FILE]);
1316 : 1 : fclose(file_ptr);
1317 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1318 : : }
1319 [ - + ]: 1348 : if(add_acc_string(&(curr_acc->key), val) != SUCCESS)
1320 : : {
1321 : 0 : fclose(file_ptr);
1322 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1323 : : }
1324 : 1348 : curr_acc->key_len = strlen(curr_acc->key);
1325 : 1348 : add_acc_bool(&(curr_acc->use_rijndael), "Y");
1326 : : }
1327 [ + + ]: 2579 : else if(CONF_VAR_IS(var, "KEY_BASE64"))
1328 : : {
1329 [ + + ]: 250 : if(strcasecmp(val, "__CHANGEME__") == 0)
1330 : : {
1331 : 1 : log_msg(LOG_ERR,
1332 : : "[*] KEY_BASE64 value is not properly set in stanza source '%s' in access file: '%s'",
1333 : : curr_acc->source, opts->config[CONF_ACCESS_FILE]);
1334 : 1 : fclose(file_ptr);
1335 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1336 : : }
1337 [ + + ]: 249 : if (! is_base64((unsigned char *) val, strlen(val)))
1338 : : {
1339 : 1 : log_msg(LOG_ERR,
1340 : : "[*] KEY_BASE64 argument '%s' doesn't look like base64-encoded data.",
1341 : : val);
1342 : 1 : fclose(file_ptr);
1343 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1344 : : }
1345 [ - + ]: 248 : if(add_acc_string(&(curr_acc->key_base64), val) != SUCCESS)
1346 : : {
1347 : 0 : fclose(file_ptr);
1348 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1349 : : }
1350 [ - + ]: 248 : if(add_acc_b64_string(&(curr_acc->key),
1351 : 248 : &(curr_acc->key_len), curr_acc->key_base64) != SUCCESS)
1352 : : {
1353 : 0 : fclose(file_ptr);
1354 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1355 : : }
1356 : 248 : add_acc_bool(&(curr_acc->use_rijndael), "Y");
1357 : : }
1358 : : /* HMAC digest type */
1359 [ + + ]: 2329 : else if(CONF_VAR_IS(var, "HMAC_DIGEST_TYPE"))
1360 : : {
1361 : 54 : curr_acc->hmac_type = hmac_digest_strtoint(val);
1362 [ + + ]: 54 : if(curr_acc->hmac_type < 0)
1363 : : {
1364 : 1 : log_msg(LOG_ERR,
1365 : : "[*] HMAC_DIGEST_TYPE argument '%s' must be one of {md5,sha1,sha256,sha384,sha512}",
1366 : : val);
1367 : 1 : fclose(file_ptr);
1368 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1369 : : }
1370 : : }
1371 [ + + ]: 2275 : else if(CONF_VAR_IS(var, "HMAC_KEY_BASE64"))
1372 : : {
1373 [ + + ]: 278 : if(strcasecmp(val, "__CHANGEME__") == 0)
1374 : : {
1375 : 1 : log_msg(LOG_ERR,
1376 : : "[*] HMAC_KEY_BASE64 value is not properly set in stanza source '%s' in access file: '%s'",
1377 : : curr_acc->source, opts->config[CONF_ACCESS_FILE]);
1378 : 1 : fclose(file_ptr);
1379 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1380 : : }
1381 [ + + ]: 277 : if (! is_base64((unsigned char *) val, strlen(val)))
1382 : : {
1383 : 1 : log_msg(LOG_ERR,
1384 : : "[*] HMAC_KEY_BASE64 argument '%s' doesn't look like base64-encoded data.",
1385 : : val);
1386 : 1 : fclose(file_ptr);
1387 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1388 : : }
1389 [ - + ]: 276 : if(add_acc_string(&(curr_acc->hmac_key_base64), val) != SUCCESS)
1390 : : {
1391 : 0 : fclose(file_ptr);
1392 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1393 : : }
1394 [ - + ]: 276 : if(add_acc_b64_string(&(curr_acc->hmac_key),
1395 : 276 : &(curr_acc->hmac_key_len), curr_acc->hmac_key_base64) != SUCCESS)
1396 : : {
1397 : 0 : fclose(file_ptr);
1398 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1399 : : }
1400 : : }
1401 [ + + ]: 1997 : else if(CONF_VAR_IS(var, "HMAC_KEY"))
1402 : : {
1403 [ + + ]: 8 : if(strcasecmp(val, "__CHANGEME__") == 0)
1404 : : {
1405 : 1 : log_msg(LOG_ERR,
1406 : : "[*] HMAC_KEY value is not properly set in stanza source '%s' in access file: '%s'",
1407 : : curr_acc->source, opts->config[CONF_ACCESS_FILE]);
1408 : 1 : fclose(file_ptr);
1409 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1410 : : }
1411 [ - + ]: 7 : if(add_acc_string(&(curr_acc->hmac_key), val) != SUCCESS)
1412 : : {
1413 : 0 : fclose(file_ptr);
1414 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1415 : : }
1416 : 7 : curr_acc->hmac_key_len = strlen(curr_acc->hmac_key);
1417 : : }
1418 [ + + ]: 1989 : else if(CONF_VAR_IS(var, "FW_ACCESS_TIMEOUT"))
1419 : : {
1420 : 1607 : curr_acc->fw_access_timeout = strtol_wrapper(val, 0,
1421 : : RCHK_MAX_FW_TIMEOUT, NO_EXIT_UPON_ERR, &is_err);
1422 [ + + ]: 1607 : if(is_err != FKO_SUCCESS)
1423 : : {
1424 : 1 : log_msg(LOG_ERR,
1425 : : "[*] FW_ACCESS_TIMEOUT value not in range.");
1426 : 1 : fclose(file_ptr);
1427 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1428 : : }
1429 : : }
1430 [ + + ]: 382 : else if(CONF_VAR_IS(var, "ENCRYPTION_MODE"))
1431 : : {
1432 [ + + ]: 28 : if((curr_acc->encryption_mode = enc_mode_strtoint(val)) < 0)
1433 : : {
1434 : 1 : log_msg(LOG_ERR,
1435 : : "[*] Unrecognized ENCRYPTION_MODE '%s', use {CBC,CTR,legacy,Asymmetric}",
1436 : : val);
1437 : 1 : fclose(file_ptr);
1438 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1439 : : }
1440 : : }
1441 [ + + ]: 354 : else if(CONF_VAR_IS(var, "ENABLE_CMD_EXEC"))
1442 : : {
1443 : 11 : add_acc_bool(&(curr_acc->enable_cmd_exec), val);
1444 : : }
1445 [ + + ]: 343 : else if(CONF_VAR_IS(var, "CMD_EXEC_USER"))
1446 : : {
1447 [ - + ]: 5 : if(add_acc_string(&(curr_acc->cmd_exec_user), val) != SUCCESS)
1448 : : {
1449 : 0 : fclose(file_ptr);
1450 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1451 : : }
1452 : :
1453 : 5 : errno = 0;
1454 : 5 : user_pw = pw = getpwnam(val);
1455 : :
1456 [ + + ]: 5 : if(pw == NULL)
1457 : : {
1458 [ - + ]: 1 : log_msg(LOG_ERR, "[*] Unable to determine UID for CMD_EXEC_USER: %s.",
1459 : 1 : errno ? strerror(errno) : "Not a user on this system");
1460 : 1 : fclose(file_ptr);
1461 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1462 : : }
1463 : :
1464 : 4 : curr_acc->cmd_exec_uid = pw->pw_uid;
1465 : : }
1466 [ + + ]: 338 : else if(CONF_VAR_IS(var, "CMD_EXEC_GROUP"))
1467 : : {
1468 [ - + ]: 3 : if(add_acc_string(&(curr_acc->cmd_exec_group), val) != SUCCESS)
1469 : : {
1470 : 0 : fclose(file_ptr);
1471 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1472 : : }
1473 : :
1474 : 3 : errno = 0;
1475 : 3 : pw = getpwnam(val);
1476 : :
1477 [ + + ]: 3 : if(pw == NULL)
1478 : : {
1479 [ - + ]: 1 : log_msg(LOG_ERR, "[*] Unable to determine GID for CMD_EXEC_GROUP: %s.",
1480 : 1 : errno ? strerror(errno) : "Not a group on this system");
1481 : 1 : fclose(file_ptr);
1482 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1483 : : }
1484 : :
1485 : 2 : curr_acc->cmd_exec_gid = pw->pw_gid;
1486 : : }
1487 [ + + ]: 335 : else if(CONF_VAR_IS(var, "REQUIRE_USERNAME"))
1488 : : {
1489 [ - + ]: 2 : if(add_acc_string(&(curr_acc->require_username), val) != SUCCESS)
1490 : : {
1491 : 0 : fclose(file_ptr);
1492 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1493 : : }
1494 : : }
1495 [ + + ]: 333 : else if(CONF_VAR_IS(var, "REQUIRE_SOURCE_ADDRESS"))
1496 : : {
1497 : 2 : add_acc_bool(&(curr_acc->require_source_address), val);
1498 : : }
1499 [ + + ]: 331 : else if(CONF_VAR_IS(var, "REQUIRE_SOURCE")) /* synonym for REQUIRE_SOURCE_ADDRESS */
1500 : : {
1501 : 1 : add_acc_bool(&(curr_acc->require_source_address), val);
1502 : : }
1503 [ + + ]: 330 : else if(CONF_VAR_IS(var, "GPG_HOME_DIR"))
1504 : : {
1505 [ + + ]: 73 : if (is_valid_dir(val))
1506 : : {
1507 [ - + ]: 72 : if(add_acc_string(&(curr_acc->gpg_home_dir), val) != SUCCESS)
1508 : : {
1509 : 0 : fclose(file_ptr);
1510 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1511 : : }
1512 : : }
1513 : : else
1514 : : {
1515 : 1 : log_msg(LOG_ERR,
1516 : : "[*] GPG_HOME_DIR directory '%s' stat()/existence problem in stanza source '%s' in access file: '%s'",
1517 : : val, curr_acc->source, opts->config[CONF_ACCESS_FILE]);
1518 : 1 : fclose(file_ptr);
1519 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1520 : : }
1521 : : }
1522 [ + + ]: 257 : else if(CONF_VAR_IS(var, "GPG_EXE"))
1523 : : {
1524 [ - + ]: 1 : if(add_acc_string(&(curr_acc->gpg_exe), val) != SUCCESS)
1525 : : {
1526 : 0 : fclose(file_ptr);
1527 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1528 : : }
1529 : : }
1530 [ + + ]: 256 : else if(CONF_VAR_IS(var, "GPG_DECRYPT_ID"))
1531 : : {
1532 [ - + ]: 73 : if(add_acc_string(&(curr_acc->gpg_decrypt_id), val) != SUCCESS)
1533 : : {
1534 : 0 : fclose(file_ptr);
1535 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1536 : : }
1537 : : }
1538 [ + + ]: 183 : else if(CONF_VAR_IS(var, "GPG_DECRYPT_PW"))
1539 : : {
1540 [ + + ]: 43 : if(strcasecmp(val, "__CHANGEME__") == 0)
1541 : : {
1542 : 1 : log_msg(LOG_ERR,
1543 : : "[*] GPG_DECRYPT_PW value is not properly set in stanza source '%s' in access file: '%s'",
1544 : : curr_acc->source, opts->config[CONF_ACCESS_FILE]);
1545 : 1 : fclose(file_ptr);
1546 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1547 : : }
1548 [ - + ]: 42 : if(add_acc_string(&(curr_acc->gpg_decrypt_pw), val) != SUCCESS)
1549 : : {
1550 : 0 : fclose(file_ptr);
1551 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1552 : : }
1553 : 42 : add_acc_bool(&(curr_acc->use_gpg), "Y");
1554 : : }
1555 [ + + ]: 140 : else if(CONF_VAR_IS(var, "GPG_ALLOW_NO_PW"))
1556 : : {
1557 : 33 : add_acc_bool(&(curr_acc->gpg_allow_no_pw), val);
1558 [ + - ]: 33 : if(curr_acc->gpg_allow_no_pw == 1)
1559 : : {
1560 : 33 : add_acc_bool(&(curr_acc->use_gpg), "Y");
1561 [ - + ]: 33 : if(add_acc_string(&(curr_acc->gpg_decrypt_pw), "") != SUCCESS)
1562 : : {
1563 : 0 : fclose(file_ptr);
1564 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1565 : : }
1566 : : }
1567 : : }
1568 [ + + ]: 107 : else if(CONF_VAR_IS(var, "GPG_REQUIRE_SIG"))
1569 : : {
1570 : 2 : add_acc_bool(&(curr_acc->gpg_require_sig), val);
1571 : : }
1572 [ + + ]: 105 : else if(CONF_VAR_IS(var, "GPG_DISABLE_SIG"))
1573 : : {
1574 : 3 : add_acc_bool(&(curr_acc->gpg_disable_sig), val);
1575 : : }
1576 [ + + ]: 102 : else if(CONF_VAR_IS(var, "GPG_IGNORE_SIG_VERIFY_ERROR"))
1577 : : {
1578 : 1 : add_acc_bool(&(curr_acc->gpg_ignore_sig_error), val);
1579 : : }
1580 [ + + ]: 101 : else if(CONF_VAR_IS(var, "GPG_REMOTE_ID"))
1581 : : {
1582 [ - + ]: 68 : if(add_acc_string(&(curr_acc->gpg_remote_id), val) != SUCCESS)
1583 : : {
1584 : 0 : fclose(file_ptr);
1585 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1586 : : }
1587 : : }
1588 [ + + ]: 33 : else if(CONF_VAR_IS(var, "GPG_FINGERPRINT_ID"))
1589 : : {
1590 [ - + ]: 4 : if(add_acc_string(&(curr_acc->gpg_remote_fpr), val) != SUCCESS)
1591 : : {
1592 : 0 : fclose(file_ptr);
1593 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1594 : : }
1595 : : }
1596 [ + + ]: 29 : else if(CONF_VAR_IS(var, "ACCESS_EXPIRE"))
1597 : : {
1598 [ + + ]: 3 : if (add_acc_expire_time(opts, &(curr_acc->access_expire_time), val) != 1)
1599 : : {
1600 : 1 : fclose(file_ptr);
1601 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1602 : : }
1603 : : }
1604 [ + + ]: 26 : else if(CONF_VAR_IS(var, "ACCESS_EXPIRE_EPOCH"))
1605 : : {
1606 [ - + ]: 1 : if (add_acc_expire_time_epoch(opts, &(curr_acc->access_expire_time), val) != 1)
1607 : : {
1608 : 0 : fclose(file_ptr);
1609 : 0 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1610 : : }
1611 : : }
1612 [ + + ]: 25 : else if(CONF_VAR_IS(var, "FORCE_NAT"))
1613 : : {
1614 : : #if FIREWALL_FIREWALLD
1615 : : if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1) !=0 )
1616 : : {
1617 : : log_msg(LOG_ERR,
1618 : : "[*] FORCE_NAT requires ENABLE_FIREWD_FORWARDING to be enabled in fwknopd.conf");
1619 : : fclose(file_ptr);
1620 : : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1621 : : }
1622 : : if(add_acc_force_nat(opts, curr_acc, val) != SUCCESS)
1623 : : {
1624 : : fclose(file_ptr);
1625 : : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1626 : : }
1627 : : #elif FIREWALL_IPTABLES
1628 [ + + ]: 15 : if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0 )
1629 : : {
1630 : 1 : log_msg(LOG_ERR,
1631 : : "[*] FORCE_NAT requires ENABLE_IPT_FORWARDING to be enabled in fwknopd.conf");
1632 : 1 : fclose(file_ptr);
1633 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1634 : : }
1635 [ + + ]: 14 : if(add_acc_force_nat(opts, curr_acc, val) != SUCCESS)
1636 : : {
1637 : 3 : fclose(file_ptr);
1638 : 3 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1639 : : }
1640 : : #else
1641 : : log_msg(LOG_ERR,
1642 : : "[*] FORCE_NAT not supported.");
1643 : : fclose(file_ptr);
1644 : : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1645 : : #endif
1646 : : }
1647 [ + + ]: 10 : else if(CONF_VAR_IS(var, "FORCE_SNAT"))
1648 : : {
1649 : : #if FIREWALL_FIREWALLD
1650 : : if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1) !=0 )
1651 : : {
1652 : : log_msg(LOG_ERR,
1653 : : "[*] FORCE_SNAT requires ENABLE_FIREWD_FORWARDING to be enabled in fwknopd.conf");
1654 : : fclose(file_ptr);
1655 : : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1656 : : }
1657 : : if(add_acc_force_snat(opts, curr_acc, val) != SUCCESS)
1658 : : {
1659 : : fclose(file_ptr);
1660 : : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1661 : : }
1662 : : #elif FIREWALL_IPTABLES
1663 [ + + ]: 6 : if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0 )
1664 : : {
1665 : 1 : log_msg(LOG_ERR,
1666 : : "[*] FORCE_SNAT requires ENABLE_IPT_FORWARDING to be enabled in fwknopd.conf");
1667 : 1 : fclose(file_ptr);
1668 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1669 : : }
1670 [ + + ]: 5 : if(add_acc_force_snat(opts, curr_acc, val) != SUCCESS)
1671 : : {
1672 : 2 : fclose(file_ptr);
1673 : 2 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1674 : : }
1675 : : #else
1676 : : log_msg(LOG_ERR,
1677 : : "[*] FORCE_SNAT not supported.");
1678 : : fclose(file_ptr);
1679 : : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1680 : : #endif
1681 : : }
1682 [ + + ]: 4 : else if(CONF_VAR_IS(var, "FORCE_MASQUERADE"))
1683 : : {
1684 : 3 : add_acc_bool(&(curr_acc->force_masquerade), val);
1685 : 3 : add_acc_bool(&(curr_acc->force_snat), val);
1686 : : }
1687 : : else
1688 : : {
1689 : 5604 : log_msg(LOG_ERR,
1690 : : "[*] Ignoring unknown access parameter: '%s' in %s",
1691 : : var, opts->config[CONF_ACCESS_FILE]
1692 : : );
1693 : : }
1694 : : }
1695 : :
1696 : 1622 : fclose(file_ptr);
1697 : :
1698 : : /* Basic check to ensure that we got at least one SOURCE stanza with
1699 : : * a valid KEY defined (valid meaning it has a value that is not
1700 : : * "__CHANGEME__".
1701 : : */
1702 [ + + ]: 1622 : if (got_source == 0)
1703 : : {
1704 : 1 : log_msg(LOG_ERR,
1705 : : "[*] Could not find valid SOURCE stanza in access file: '%s'",
1706 : : opts->config[CONF_ACCESS_FILE]);
1707 : 1 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1708 : : }
1709 : :
1710 : : /* Sanity check the last stanza
1711 : : */
1712 [ + + ]: 1621 : if(!acc_data_is_valid(user_pw, curr_acc))
1713 : : {
1714 : 4 : log_msg(LOG_ERR,
1715 : : "[*] Data error in access file: '%s'",
1716 : : opts->config[CONF_ACCESS_FILE]);
1717 : 4 : clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
1718 : : }
1719 : :
1720 : : /* Expand our the expandable fields into their respective data buckets.
1721 : : */
1722 : 1617 : expand_acc_ent_lists(opts);
1723 : :
1724 : : /* Make sure default values are set where needed.
1725 : : */
1726 : 1590 : set_acc_defaults(opts);
1727 : :
1728 : 1589 : return;
1729 : : }
1730 : :
1731 : : int
1732 : 27641 : compare_addr_list(acc_int_list_t *source_list, const uint32_t ip)
1733 : : {
1734 : 27641 : int match = 0;
1735 : :
1736 [ + + ]: 27702 : while(source_list)
1737 : : {
1738 [ + + ]: 27691 : if((ip & source_list->mask) == (source_list->maddr & source_list->mask))
1739 : : {
1740 : : match = 1;
1741 : : break;
1742 : : }
1743 : :
1744 : 61 : source_list = source_list->next;
1745 : : }
1746 : :
1747 : 27641 : return(match);
1748 : : }
1749 : :
1750 : : /* Compare the contents of 2 port lists. Return true on a match.
1751 : : * Match depends on the match_any flag. if match_any is 1 then any
1752 : : * entry in the incoming data need only match one item to return true.
1753 : : * Otherwise all entries in the incoming data must have a corresponding
1754 : : * match in the access port_list.
1755 : : */
1756 : : static int
1757 : 18 : compare_port_list(acc_port_list_t *in, acc_port_list_t *ac, const int match_any)
1758 : : {
1759 : 18 : int a_cnt = 0;
1760 : 18 : int i_cnt = 0;
1761 : :
1762 : : acc_port_list_t *tlist;
1763 [ + + ]: 36 : while(in)
1764 : : {
1765 : 18 : i_cnt++;
1766 : :
1767 : 18 : tlist = ac;
1768 [ + + ]: 70 : while(tlist)
1769 : : {
1770 [ + + ]: 52 : if(in->proto == tlist->proto && in->port == tlist->port)
1771 : : {
1772 : 15 : a_cnt++;
1773 [ + - ]: 15 : if(match_any == 1)
1774 : : return(1);
1775 : : }
1776 : 52 : tlist = tlist->next;
1777 : : }
1778 : 18 : in = in->next;
1779 : : }
1780 : :
1781 : 18 : return(i_cnt == a_cnt);
1782 : : }
1783 : :
1784 : : /* Take a proto/port string (or mulitple comma-separated strings) and check
1785 : : * them against the list for the given access stanza.
1786 : : *
1787 : : * Return 1 if we are allowed
1788 : : */
1789 : : int
1790 : 627 : acc_check_port_access(acc_stanza_t *acc, char *port_str)
1791 : : {
1792 : 627 : int res = 1, ctr = 0;
1793 : :
1794 : 627 : char buf[ACCESS_BUF_LEN] = {0};
1795 : : char *ndx, *start;
1796 : :
1797 : 627 : acc_port_list_t *o_pl = acc->oport_list;
1798 : 627 : acc_port_list_t *r_pl = acc->rport_list;
1799 : :
1800 : 627 : acc_port_list_t *in_pl = NULL;
1801 : :
1802 : 627 : start = port_str;
1803 : :
1804 : : /* Create our own internal port_list from the incoming SPA data
1805 : : * for comparison.
1806 : : */
1807 [ + + ]: 5908 : for(ndx = start; *ndx != '\0'; ndx++)
1808 : : {
1809 [ + + ]: 5281 : if(*ndx == ',')
1810 : : {
1811 [ + - ]: 115 : if((ctr >= ACCESS_BUF_LEN)
1812 [ - + ]: 115 : || (((ndx-start)+1) >= ACCESS_BUF_LEN))
1813 : : {
1814 : 0 : log_msg(LOG_ERR,
1815 : : "[*] Unable to create acc_port_list from incoming data: %s",
1816 : : port_str
1817 : : );
1818 : 0 : free_acc_port_list(in_pl);
1819 : 0 : return(0);
1820 : : }
1821 : 115 : strlcpy(buf, start, (ndx-start)+1);
1822 [ - + ]: 115 : if(add_port_list_ent(&in_pl, buf) == 0)
1823 : : {
1824 : 0 : log_msg(LOG_ERR, "[*] Invalid proto/port string");
1825 : 0 : free_acc_port_list(in_pl);
1826 : 0 : return(0);
1827 : : }
1828 : :
1829 : 115 : start = ndx+1;
1830 : 115 : ctr = 0;
1831 : : }
1832 : 5281 : ctr++;
1833 : : }
1834 [ + - ]: 627 : if((ctr >= ACCESS_BUF_LEN)
1835 [ - + ]: 627 : || (((ndx-start)+1) >= ACCESS_BUF_LEN))
1836 : : {
1837 : 0 : log_msg(LOG_ERR,
1838 : : "[*] Unable to create acc_port_list from incoming data: %s",
1839 : : port_str
1840 : : );
1841 : 0 : free_acc_port_list(in_pl);
1842 : 0 : return(0);
1843 : : }
1844 : 627 : strlcpy(buf, start, (ndx-start)+1);
1845 [ - + ]: 627 : if(add_port_list_ent(&in_pl, buf) == 0)
1846 : : {
1847 : 0 : log_msg(LOG_ERR, "[*] Invalid proto/port string");
1848 : 0 : free_acc_port_list(in_pl);
1849 : 0 : return 0;
1850 : : }
1851 : :
1852 [ - + ]: 627 : if(in_pl == NULL)
1853 : : {
1854 : 0 : log_msg(LOG_ERR,
1855 : : "[*] Unable to create acc_port_list from incoming data: %s", port_str
1856 : : );
1857 : 0 : return(0);
1858 : : }
1859 : :
1860 : : /* Start with restricted ports (if any). Any match (even if only one
1861 : : * entry) means not allowed.
1862 : : */
1863 [ - + ][ # # ]: 627 : if((acc->rport_list != NULL) && (compare_port_list(in_pl, r_pl, 1)))
1864 : : {
1865 : : res = 0;
1866 : : goto cleanup_and_bail;
1867 : : }
1868 : :
1869 : : /* For open port list, all must match.
1870 : : */
1871 [ + + ][ + + ]: 627 : if((acc->oport_list != NULL) && (!compare_port_list(in_pl, o_pl, 0)))
1872 : 3 : res = 0;
1873 : :
1874 : : cleanup_and_bail:
1875 : 627 : free_acc_port_list(in_pl);
1876 : 627 : return(res);
1877 : : }
1878 : :
1879 : : /* Dump the configuration
1880 : : */
1881 : : void
1882 : 1582 : dump_access_list(const fko_srv_options_t *opts)
1883 : : {
1884 : 1582 : int i = 0;
1885 : :
1886 : 1582 : acc_stanza_t *acc = opts->acc_stanzas;
1887 : :
1888 : 1582 : fprintf(stdout, "Current fwknopd access settings:\n");
1889 : :
1890 [ + - ]: 1582 : if(!acc)
1891 : : {
1892 : 0 : fprintf(stderr, "\n ** No Access Settings Defined **\n\n");
1893 : 1582 : return;
1894 : : }
1895 : :
1896 [ + + ]: 3175 : while(acc)
1897 : : {
1898 [ + + ][ + + ]: 1607 : fprintf(stdout,
[ + - ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ - + ][ + + ]
1899 : : "SOURCE (%i): %s\n"
1900 : : "==============================================================\n"
1901 : : " OPEN_PORTS: %s\n"
1902 : : " RESTRICT_PORTS: %s\n"
1903 : : " KEY: %s\n"
1904 : : " KEY_BASE64: %s\n"
1905 : : " KEY_LEN: %d\n"
1906 : : " HMAC_KEY: %s\n"
1907 : : " HMAC_KEY_BASE64: %s\n"
1908 : : " HMAC_KEY_LEN: %d\n"
1909 : : " HMAC_DIGEST_TYPE: %d\n"
1910 : : " FW_ACCESS_TIMEOUT: %i\n"
1911 : : " ENABLE_CMD_EXEC: %s\n"
1912 : : " CMD_EXEC_USER: %s\n"
1913 : : " REQUIRE_USERNAME: %s\n"
1914 : : " REQUIRE_SOURCE_ADDRESS: %s\n"
1915 : : " FORCE_NAT (ip): %s\n"
1916 : : " FORCE_NAT (proto): %s\n"
1917 : : " FORCE_NAT (port): %d\n"
1918 : : " FORCE_SNAT (ip): %s\n"
1919 : : " FORCE_MASQUERADE: %s\n"
1920 : : " ACCESS_EXPIRE: %s" /* asctime() adds a newline */
1921 : : " GPG_HOME_DIR: %s\n"
1922 : : " GPG_EXE: %s\n"
1923 : : " GPG_DECRYPT_ID: %s\n"
1924 : : " GPG_DECRYPT_PW: %s\n"
1925 : : " GPG_REQUIRE_SIG: %s\n"
1926 : : "GPG_IGNORE_SIG_VERIFY_ERROR: %s\n"
1927 : : " GPG_REMOTE_ID: %s\n"
1928 : : " GPG_FINGERPRINT_ID: %s\n",
1929 : : ++i,
1930 : : acc->source,
1931 : 1593 : (acc->open_ports == NULL) ? "<not set>" : acc->open_ports,
1932 : 1593 : (acc->restrict_ports == NULL) ? "<not set>" : acc->restrict_ports,
1933 : 1593 : (acc->key == NULL) ? "<not set>" : "<see the access.conf file>",
1934 : 1593 : (acc->key_base64 == NULL) ? "<not set>" : "<see the access.conf file>",
1935 : : acc->key_len ? acc->key_len : 0,
1936 : 1593 : (acc->hmac_key == NULL) ? "<not set>" : "<see the access.conf file>",
1937 : 1593 : (acc->hmac_key_base64 == NULL) ? "<not set>" : "<see the access.conf file>",
1938 : : acc->hmac_key_len ? acc->hmac_key_len : 0,
1939 : : acc->hmac_type,
1940 : : acc->fw_access_timeout,
1941 : 1593 : acc->enable_cmd_exec ? "Yes" : "No",
1942 : 1593 : (acc->cmd_exec_user == NULL) ? "<not set>" : acc->cmd_exec_user,
1943 : 1593 : (acc->require_username == NULL) ? "<not set>" : acc->require_username,
1944 : 1593 : acc->require_source_address ? "Yes" : "No",
1945 : : acc->force_nat ? acc->force_nat_ip : "<not set>",
1946 [ - + ]: 11 : acc->force_nat && acc->force_nat_proto != NULL ? acc->force_nat_proto : "<not set>",
1947 : 1593 : acc->force_nat ? acc->force_nat_port : 0,
1948 : 1593 : acc->force_snat ? acc->force_snat_ip : "<not set>",
1949 : 1593 : acc->force_masquerade ? "Yes" : "No",
1950 : 3 : (acc->access_expire_time > 0) ? asctime(localtime(&acc->access_expire_time)) : "<not set>\n",
1951 : 1593 : (acc->gpg_home_dir == NULL) ? "<not set>" : acc->gpg_home_dir,
1952 : 1593 : (acc->gpg_exe == NULL) ? "<not set>" : acc->gpg_exe,
1953 : 1593 : (acc->gpg_decrypt_id == NULL) ? "<not set>" : acc->gpg_decrypt_id,
1954 : 1593 : (acc->gpg_decrypt_pw == NULL) ? "<not set>" : "<see the access.conf file>",
1955 : 1593 : acc->gpg_require_sig ? "Yes" : "No",
1956 : 1593 : acc->gpg_ignore_sig_error ? "Yes" : "No",
1957 : 1593 : (acc->gpg_remote_id == NULL) ? "<not set>" : acc->gpg_remote_id,
1958 : 1593 : (acc->gpg_remote_fpr == NULL) ? "<not set>" : acc->gpg_remote_fpr
1959 : : );
1960 : :
1961 : 1593 : fprintf(stdout, "\n");
1962 : :
1963 : 1593 : acc = acc->next;
1964 : : }
1965 : :
1966 : 1582 : fprintf(stdout, "\n");
1967 : 1582 : fflush(stdout);
1968 : : }
1969 : :
1970 : : /***EOF***/
|