Branch data Line data Source code
1 : : /*
2 : : *****************************************************************************
3 : : *
4 : : * File: incoming_spa.c
5 : : *
6 : : * Purpose: Process an incoming SPA data packet for fwknopd.
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 "fwknopd_common.h"
32 : : #include "netinet_common.h"
33 : :
34 : : #if HAVE_SYS_WAIT_H
35 : : #include <sys/wait.h>
36 : : #endif
37 : :
38 : : #include "incoming_spa.h"
39 : : #include "access.h"
40 : : #include "extcmd.h"
41 : : #include "log_msg.h"
42 : : #include "utils.h"
43 : : #include "fw_util.h"
44 : : #include "fwknopd_errors.h"
45 : : #include "replay_cache.h"
46 : :
47 : : #define CTX_DUMP_BUFSIZE 4096 /*!< Maximum size allocated to a FKO context dump */
48 : :
49 : : /* Validate and in some cases preprocess/reformat the SPA data. Return an
50 : : * error code value if there is any indication the data is not valid spa data.
51 : : */
52 : : static int
53 : 14077 : preprocess_spa_data(fko_srv_options_t *opts, const char *src_ip)
54 : : {
55 : 14077 : spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
56 : :
57 : 14077 : char *ndx = (char *)&(spa_pkt->packet_data);
58 : 14077 : int pkt_data_len = spa_pkt->packet_data_len;
59 : : int i;
60 : :
61 : : /* At this point, we can reset the packet data length to 0. This is our
62 : : * indicator to the rest of the program that we do not have a current
63 : : * spa packet to process (after this one that is).
64 : : */
65 : 14077 : spa_pkt->packet_data_len = 0;
66 : :
67 : : /* These two checks are already done in process_packet(), but this is a
68 : : * defensive measure to run them again here
69 : : */
70 [ + - ]: 14077 : if(pkt_data_len < MIN_SPA_DATA_SIZE)
71 : : return(SPA_MSG_BAD_DATA);
72 : :
73 [ + - ]: 14077 : if(pkt_data_len > MAX_SPA_PACKET_LEN)
74 : : return(SPA_MSG_BAD_DATA);
75 : :
76 : : /* Ignore any SPA packets that contain the Rijndael or GnuPG prefixes
77 : : * since an attacker might have tacked them on to a previously seen
78 : : * SPA packet in an attempt to get past the replay check. And, we're
79 : : * no worse off since a legitimate SPA packet that happens to include
80 : : * a prefix after the outer one is stripped off won't decrypt properly
81 : : * anyway because libfko would not add a new one.
82 : : */
83 [ + + ]: 14077 : if(constant_runtime_cmp(ndx, B64_RIJNDAEL_SALT, B64_RIJNDAEL_SALT_STR_LEN) == 0)
84 : : return(SPA_MSG_BAD_DATA);
85 : :
86 [ + + ]: 14021 : if(pkt_data_len > MIN_GNUPG_MSG_SIZE
87 [ + + ]: 3079 : && constant_runtime_cmp(ndx, B64_GPG_PREFIX, B64_GPG_PREFIX_STR_LEN) == 0)
88 : : return(SPA_MSG_BAD_DATA);
89 : :
90 : : /* Detect and parse out SPA data from an HTTP request. If the SPA data
91 : : * starts with "GET /" and the user agent starts with "Fwknop", then
92 : : * assume it is a SPA over HTTP request.
93 : : */
94 [ + + ]: 13966 : if(strncasecmp(opts->config[CONF_ENABLE_SPA_OVER_HTTP], "Y", 1) == 0
95 [ + + ]: 2 : && strncasecmp(ndx, "GET /", 5) == 0
96 [ + - ]: 1 : && strstr(ndx, "User-Agent: Fwknop") != NULL)
97 : : {
98 : : /* This looks like an HTTP request, so let's see if we are
99 : : * configured to accept such request and if so, find the SPA
100 : : * data.
101 : : */
102 : :
103 : : /* Now extract, adjust (convert characters translated by the fwknop
104 : : * client), and reset the SPA message itself.
105 : : */
106 : 1 : strlcpy((char *)spa_pkt->packet_data, ndx+5, pkt_data_len);
107 : 1 : pkt_data_len -= 5;
108 : :
109 [ + - ]: 205 : for(i=0; i<pkt_data_len; i++)
110 : : {
111 [ + + ]: 205 : if(isspace(*ndx)) /* The first space marks the end of the req */
112 : : {
113 : 1 : *ndx = '\0';
114 : : break;
115 : : }
116 [ + + ]: 204 : else if(*ndx == '-') /* Convert '-' to '+' */
117 : 5 : *ndx = '+';
118 [ + + ]: 199 : else if(*ndx == '_') /* Convert '_' to '/' */
119 : 3 : *ndx = '/';
120 : :
121 : 204 : ndx++;
122 : : }
123 : :
124 [ + - ]: 1 : if(i < MIN_SPA_DATA_SIZE)
125 : : return(SPA_MSG_BAD_DATA);
126 : :
127 : 1 : spa_pkt->packet_data_len = pkt_data_len = i;
128 : : }
129 : :
130 : : /* Require base64-encoded data
131 : : */
132 [ + + ]: 13966 : if(! is_base64(spa_pkt->packet_data, pkt_data_len))
133 : : return(SPA_MSG_NOT_SPA_DATA);
134 : :
135 : :
136 : : /* --DSS: Are there other checks we can do here ??? */
137 : :
138 : : /* If we made it here, we have no reason to assume this is not SPA data
139 : : * (at least until we come up with more checks).
140 : : */
141 : : return(FKO_SUCCESS);
142 : : }
143 : :
144 : : /* For replay attack detection
145 : : */
146 : : static int
147 : 13929 : get_raw_digest(char **digest, char *pkt_data)
148 : : {
149 : 13929 : fko_ctx_t ctx = NULL;
150 : 13929 : char *tmp_digest = NULL;
151 : 13929 : int res = FKO_SUCCESS;
152 : 13929 : short raw_digest_type = -1;
153 : :
154 : : /* initialize an FKO context with no decryption key just so
155 : : * we can get the outer message digest
156 : : */
157 : 13929 : res = fko_new_with_data(&ctx, (char *)pkt_data, NULL, 0,
158 : : FKO_DEFAULT_ENC_MODE, NULL, 0, 0);
159 : :
160 [ + + ]: 13929 : if(res != FKO_SUCCESS)
161 : : {
162 : 67 : log_msg(LOG_WARNING, "Error initializing FKO context from SPA data: %s",
163 : : fko_errstr(res));
164 : 67 : fko_destroy(ctx);
165 : 67 : ctx = NULL;
166 : 67 : return(SPA_MSG_FKO_CTX_ERROR);
167 : : }
168 : :
169 : 13862 : res = fko_set_raw_spa_digest_type(ctx, FKO_DEFAULT_DIGEST);
170 [ + + ]: 13862 : if(res != FKO_SUCCESS)
171 : : {
172 : 2 : log_msg(LOG_WARNING, "Error setting digest type for SPA data: %s",
173 : : fko_errstr(res));
174 : 2 : fko_destroy(ctx);
175 : 2 : ctx = NULL;
176 : 2 : return(SPA_MSG_DIGEST_ERROR);
177 : : }
178 : :
179 : 13860 : res = fko_get_raw_spa_digest_type(ctx, &raw_digest_type);
180 [ + + ]: 13860 : if(res != FKO_SUCCESS)
181 : : {
182 : 1 : log_msg(LOG_WARNING, "Error getting digest type for SPA data: %s",
183 : : fko_errstr(res));
184 : 1 : fko_destroy(ctx);
185 : 1 : ctx = NULL;
186 : 1 : return(SPA_MSG_DIGEST_ERROR);
187 : : }
188 : :
189 : : /* Make sure the digest type is what we expect
190 : : */
191 [ - + ]: 13859 : if(raw_digest_type != FKO_DEFAULT_DIGEST)
192 : : {
193 : 0 : log_msg(LOG_WARNING, "Error setting digest type for SPA data: %s",
194 : : fko_errstr(res));
195 : 0 : fko_destroy(ctx);
196 : 0 : ctx = NULL;
197 : 0 : return(SPA_MSG_DIGEST_ERROR);
198 : : }
199 : :
200 : 13859 : res = fko_set_raw_spa_digest(ctx);
201 [ + + ]: 13859 : if(res != FKO_SUCCESS)
202 : : {
203 : 65 : log_msg(LOG_WARNING, "Error setting digest for SPA data: %s",
204 : : fko_errstr(res));
205 : 65 : fko_destroy(ctx);
206 : 65 : ctx = NULL;
207 : 65 : return(SPA_MSG_DIGEST_ERROR);
208 : : }
209 : :
210 : 13794 : res = fko_get_raw_spa_digest(ctx, &tmp_digest);
211 [ + + ]: 13794 : if(res != FKO_SUCCESS)
212 : : {
213 : 1 : log_msg(LOG_WARNING, "Error getting digest from SPA data: %s",
214 : : fko_errstr(res));
215 : 1 : fko_destroy(ctx);
216 : 1 : ctx = NULL;
217 : 1 : return(SPA_MSG_DIGEST_ERROR);
218 : : }
219 : :
220 : 13793 : *digest = strdup(tmp_digest);
221 : :
222 [ - + ]: 13793 : if (*digest == NULL)
223 : 0 : res = SPA_MSG_ERROR; /* really a strdup() memory allocation problem */
224 : :
225 : 13793 : fko_destroy(ctx);
226 : 13793 : ctx = NULL;
227 : :
228 : 13793 : return res;
229 : : }
230 : :
231 : :
232 : : /* Popluate a spa_data struct from an initialized (and populated) FKO context.
233 : : */
234 : : static int
235 : 977 : get_spa_data_fields(fko_ctx_t ctx, spa_data_t *spdat)
236 : : {
237 : 977 : int res = FKO_SUCCESS;
238 : :
239 : 977 : res = fko_get_username(ctx, &(spdat->username));
240 [ + + ]: 977 : if(res != FKO_SUCCESS)
241 : : return(res);
242 : :
243 : 975 : res = fko_get_timestamp(ctx, &(spdat->timestamp));
244 [ + + ]: 975 : if(res != FKO_SUCCESS)
245 : : return(res);
246 : :
247 : 973 : res = fko_get_version(ctx, &(spdat->version));
248 [ + + ]: 973 : if(res != FKO_SUCCESS)
249 : : return(res);
250 : :
251 : 971 : res = fko_get_spa_message_type(ctx, &(spdat->message_type));
252 [ + + ]: 971 : if(res != FKO_SUCCESS)
253 : : return(res);
254 : :
255 : 969 : res = fko_get_spa_message(ctx, &(spdat->spa_message));
256 [ + + ]: 969 : if(res != FKO_SUCCESS)
257 : : return(res);
258 : :
259 : 967 : res = fko_get_spa_nat_access(ctx, &(spdat->nat_access));
260 [ + + ]: 967 : if(res != FKO_SUCCESS)
261 : : return(res);
262 : :
263 : 965 : res = fko_get_spa_server_auth(ctx, &(spdat->server_auth));
264 [ + + ]: 965 : if(res != FKO_SUCCESS)
265 : : return(res);
266 : :
267 : 963 : res = fko_get_spa_client_timeout(ctx, (int *)&(spdat->client_timeout));
268 : : if(res != FKO_SUCCESS)
269 : : return(res);
270 : :
271 : : return(res);
272 : : }
273 : :
274 : : /* Check for access.conf stanza SOURCE match based on SPA packet
275 : : * source IP
276 : : */
277 : : static int
278 : 13932 : is_src_match(acc_stanza_t *acc, const uint32_t ip)
279 : : {
280 [ + + ]: 13939 : while (acc)
281 : : {
282 [ + + ]: 13936 : if(compare_addr_list(acc->source_list, ip))
283 : : return 1;
284 : :
285 : 7 : acc = acc->next;
286 : : }
287 : : return 0;
288 : : }
289 : :
290 : : /* Process the SPA packet data
291 : : */
292 : : void
293 : 14077 : incoming_spa(fko_srv_options_t *opts)
294 : : {
295 : : /* Always a good idea to initialize ctx to null if it will be used
296 : : * repeatedly (especially when using fko_new_with_data()).
297 : : */
298 : 14077 : fko_ctx_t ctx = NULL;
299 : :
300 : 14077 : char *spa_ip_demark, *gpg_id, *gpg_fpr, *raw_digest = NULL;
301 : : time_t now_ts;
302 : 14077 : int res, ts_diff, enc_type, stanza_num=0, pid_status=0;
303 : 14077 : int added_replay_digest = 0, pkt_data_len=0;
304 : 14077 : int is_err, cmd_exec_success = 0, attempted_decrypt = 0;
305 : 14077 : int conf_pkt_age = 0;
306 : : char dump_buf[CTX_DUMP_BUFSIZE];
307 : :
308 : 14077 : spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
309 : :
310 : : /* This will hold our pertinent SPA data.
311 : : */
312 : : spa_data_t spadat;
313 : :
314 : : /* Loop through all access stanzas looking for a match
315 : : */
316 : 14077 : acc_stanza_t *acc = opts->acc_stanzas;
317 : : acc_string_list_t *gpg_id_ndx;
318 : : acc_string_list_t *gpg_fpr_ndx;
319 : 14077 : unsigned char is_gpg_match = 0;
320 : :
321 : 14077 : inet_ntop(AF_INET, &(spa_pkt->packet_src_ip),
322 : : spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip));
323 : :
324 : : /* At this point, we want to validate and (if needed) preprocess the
325 : : * SPA data and/or to be reasonably sure we have a SPA packet (i.e
326 : : * try to eliminate obvious non-spa packets).
327 : : */
328 : 14077 : pkt_data_len = spa_pkt->packet_data_len;
329 : 14077 : res = preprocess_spa_data(opts, spadat.pkt_source_ip);
330 [ + + ]: 14077 : if(res != FKO_SUCCESS)
331 : : {
332 : 145 : log_msg(LOG_DEBUG, "[%s] preprocess_spa_data() returned error %i: '%s' for incoming packet.",
333 : : spadat.pkt_source_ip, res, get_errstr(res));
334 : 145 : return;
335 : : }
336 : :
337 [ + - ][ + + ]: 13932 : if(opts->foreground == 1 && opts->verbose > 2)
338 : : {
339 : : printf("[+] candidate SPA packet payload:\n");
340 : 109 : hex_dump(spa_pkt->packet_data, pkt_data_len);
341 : : }
342 : :
343 [ + + ]: 13932 : if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0)
344 : : {
345 : 346 : conf_pkt_age = strtol_wrapper(opts->config[CONF_MAX_SPA_PACKET_AGE],
346 : : 0, RCHK_MAX_SPA_PACKET_AGE, NO_EXIT_UPON_ERR, &is_err);
347 [ - + ]: 346 : if(is_err != FKO_SUCCESS)
348 : : {
349 : 0 : log_msg(LOG_ERR, "[*] [%s] invalid MAX_SPA_PACKET_AGE", spadat.pkt_source_ip);
350 : 0 : return;
351 : : }
352 : : }
353 : :
354 [ + + ]: 13932 : if (is_src_match(opts->acc_stanzas, ntohl(spa_pkt->packet_src_ip)))
355 : : {
356 [ + - ]: 13929 : if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
357 : : {
358 : : /* Check for a replay attack
359 : : */
360 : 13929 : res = get_raw_digest(&raw_digest, (char *)spa_pkt->packet_data);
361 [ + + ]: 13929 : if(res != FKO_SUCCESS)
362 : : {
363 [ - + ]: 136 : if (raw_digest != NULL)
364 : 0 : free(raw_digest);
365 : : return;
366 : : }
367 [ + - ]: 13793 : if (raw_digest == NULL)
368 : : return;
369 : :
370 [ + + ]: 13793 : if (is_replay(opts, raw_digest) != SPA_MSG_SUCCESS)
371 : : {
372 : 97 : free(raw_digest);
373 : 97 : return;
374 : : }
375 : : }
376 : : }
377 : : else
378 : : {
379 : 3 : log_msg(LOG_WARNING,
380 : : "No access data found for source IP: %s", spadat.pkt_source_ip
381 : : );
382 : 3 : return;
383 : : }
384 : :
385 : : /* Now that we know there is a matching access.conf stanza and the
386 : : * incoming SPA packet is not a replay, see if we should grant any
387 : : * access
388 : : */
389 [ + + ]: 27132 : while(acc)
390 : : {
391 : 13705 : res = FKO_SUCCESS;
392 : 13705 : cmd_exec_success = 0;
393 : 13705 : attempted_decrypt = 0;
394 : 13705 : stanza_num++;
395 : :
396 : : /* Start access loop with a clean FKO context
397 : : */
398 [ + + ]: 13705 : if(ctx != NULL)
399 : : {
400 [ - + ]: 2 : if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
401 : 0 : log_msg(LOG_WARNING,
402 : : "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
403 : : spadat.pkt_source_ip, stanza_num
404 : : );
405 : 2 : ctx = NULL;
406 : : }
407 : :
408 : : /* Check for a match for the SPA source IP and the access stanza
409 : : */
410 [ + + ]: 13705 : if(! compare_addr_list(acc->source_list, ntohl(spa_pkt->packet_src_ip)))
411 : : {
412 : 4 : acc = acc->next;
413 : 4 : continue;
414 : : }
415 : :
416 : 13701 : log_msg(LOG_INFO, "(stanza #%d) SPA Packet from IP: %s received with access source match",
417 : : stanza_num, spadat.pkt_source_ip);
418 : :
419 : 13701 : log_msg(LOG_DEBUG, "SPA Packet: '%s'", spa_pkt->packet_data);
420 : :
421 : : /* Make sure this access stanza has not expired
422 : : */
423 [ + + ]: 13701 : if(acc->access_expire_time > 0)
424 : : {
425 [ - + ]: 3 : if(acc->expired)
426 : : {
427 : 0 : acc = acc->next;
428 : 0 : continue;
429 : : }
430 : : else
431 : : {
432 [ + + ]: 3 : if(time(NULL) > acc->access_expire_time)
433 : : {
434 : 2 : log_msg(LOG_INFO, "[%s] (stanza #%d) Access stanza has expired",
435 : : spadat.pkt_source_ip, stanza_num);
436 : 2 : acc->expired = 1;
437 : 2 : acc = acc->next;
438 : 2 : continue;
439 : : }
440 : : }
441 : : }
442 : :
443 : : /* Get encryption type and try its decoding routine first (if the key
444 : : * for that type is set)
445 : : */
446 : 13699 : enc_type = fko_encryption_type((char *)spa_pkt->packet_data);
447 : :
448 [ + + ]: 13699 : if(acc->use_rijndael)
449 : : {
450 [ - + ]: 13661 : if (acc->key == NULL)
451 : : {
452 : 0 : log_msg(LOG_ERR,
453 : : "[%s] (stanza #%d) No KEY for RIJNDAEL encrypted messages",
454 : : spadat.pkt_source_ip, stanza_num
455 : : );
456 : 0 : acc = acc->next;
457 : 0 : continue;
458 : : }
459 : :
460 : : /* Command mode messages may be quite long
461 : : */
462 [ + + ][ + + ]: 13661 : if(acc->enable_cmd_exec || enc_type == FKO_ENCRYPTION_RIJNDAEL)
463 : : {
464 : 13631 : res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data,
465 : 13631 : acc->key, acc->key_len, acc->encryption_mode, acc->hmac_key,
466 : : acc->hmac_key_len, acc->hmac_type);
467 : 13631 : attempted_decrypt = 1;
468 [ + + ]: 13631 : if(res == FKO_SUCCESS)
469 : 926 : cmd_exec_success = 1;
470 : : }
471 : : }
472 : :
473 [ + + ][ + - ]: 13699 : if(acc->use_gpg && enc_type == FKO_ENCRYPTION_GPG && cmd_exec_success == 0)
474 : : {
475 : : /* For GPG we create the new context without decrypting on the fly
476 : : * so we can set some GPG parameters first.
477 : : */
478 [ - + ][ # # ]: 61 : if(acc->gpg_decrypt_pw != NULL || acc->gpg_allow_no_pw)
479 : : {
480 : 61 : res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data, NULL,
481 : 61 : 0, FKO_ENC_MODE_ASYMMETRIC, acc->hmac_key,
482 : : acc->hmac_key_len, acc->hmac_type);
483 : :
484 [ - + ]: 61 : if(res != FKO_SUCCESS)
485 : : {
486 : 0 : log_msg(LOG_WARNING,
487 : : "[%s] (stanza #%d) Error creating fko context (before decryption): %s",
488 : : spadat.pkt_source_ip, stanza_num, fko_errstr(res)
489 : : );
490 : 0 : acc = acc->next;
491 : 0 : continue;
492 : : }
493 : :
494 : : /* Set whatever GPG parameters we have.
495 : : */
496 [ + + ]: 61 : if(acc->gpg_exe != NULL)
497 : : {
498 : 1 : res = fko_set_gpg_exe(ctx, acc->gpg_exe);
499 [ + - ]: 1 : if(res != FKO_SUCCESS)
500 : : {
501 : 1 : log_msg(LOG_WARNING,
502 : : "[%s] (stanza #%d) Error setting GPG path %s: %s",
503 : : spadat.pkt_source_ip, stanza_num, acc->gpg_exe,
504 : : fko_errstr(res)
505 : : );
506 : 1 : acc = acc->next;
507 : 1 : continue;
508 : : }
509 : : }
510 : :
511 [ + - ]: 60 : if(acc->gpg_home_dir != NULL)
512 : : {
513 : 60 : res = fko_set_gpg_home_dir(ctx, acc->gpg_home_dir);
514 [ - + ]: 60 : if(res != FKO_SUCCESS)
515 : : {
516 : 0 : log_msg(LOG_WARNING,
517 : : "[%s] (stanza #%d) Error setting GPG keyring path to %s: %s",
518 : : spadat.pkt_source_ip, stanza_num, acc->gpg_home_dir,
519 : : fko_errstr(res)
520 : : );
521 : 0 : acc = acc->next;
522 : 0 : continue;
523 : : }
524 : : }
525 : :
526 [ + - ]: 60 : if(acc->gpg_decrypt_id != NULL)
527 : 60 : fko_set_gpg_recipient(ctx, acc->gpg_decrypt_id);
528 : :
529 : : /* If GPG_REQUIRE_SIG is set for this acc stanza, then set
530 : : * the FKO context accordingly and check the other GPG Sig-
531 : : * related parameters. This also applies when REMOTE_ID is
532 : : * set.
533 : : */
534 [ + + ]: 60 : if(acc->gpg_require_sig)
535 : : {
536 : 59 : fko_set_gpg_signature_verify(ctx, 1);
537 : :
538 : : /* Set whether or not to ignore signature verification errors.
539 : : */
540 : 59 : fko_set_gpg_ignore_verify_error(ctx, acc->gpg_ignore_sig_error);
541 : : }
542 : : else
543 : : {
544 : 1 : fko_set_gpg_signature_verify(ctx, 0);
545 : 1 : fko_set_gpg_ignore_verify_error(ctx, 1);
546 : : }
547 : :
548 : : /* Now decrypt the data.
549 : : */
550 : 60 : res = fko_decrypt_spa_data(ctx, acc->gpg_decrypt_pw, 0);
551 : 60 : attempted_decrypt = 1;
552 : : }
553 : : }
554 : :
555 [ + + ]: 13698 : if(attempted_decrypt == 0)
556 : : {
557 : 7 : log_msg(LOG_ERR,
558 : : "[%s] (stanza #%d) No stanza encryption mode match for encryption type: %i.",
559 : : spadat.pkt_source_ip, stanza_num, enc_type);
560 : 7 : acc = acc->next;
561 : 7 : continue;
562 : : }
563 : :
564 : : /* Do we have a valid FKO context? Did the SPA decrypt properly?
565 : : */
566 [ + + ]: 13691 : if(res != FKO_SUCCESS)
567 : : {
568 : 12712 : log_msg(LOG_WARNING, "[%s] (stanza #%d) Error creating fko context: %s",
569 : : spadat.pkt_source_ip, stanza_num, fko_errstr(res));
570 : :
571 [ + + ]: 12712 : if(IS_GPG_ERROR(res))
572 : 7 : log_msg(LOG_WARNING, "[%s] (stanza #%d) - GPG ERROR: %s",
573 : : spadat.pkt_source_ip, stanza_num, fko_gpg_errstr(ctx));
574 : :
575 : 12712 : acc = acc->next;
576 : 12712 : continue;
577 : : }
578 : :
579 : : /* Add this SPA packet into the replay detection cache
580 : : */
581 [ + + ][ + + ]: 979 : if (!opts->test && added_replay_digest == 0
582 [ + - ]: 294 : && strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
583 : : {
584 : :
585 : 294 : res = add_replay(opts, raw_digest);
586 [ - + ]: 294 : if (res != SPA_MSG_SUCCESS)
587 : : {
588 : 0 : log_msg(LOG_WARNING, "[%s] (stanza #%d) Could not add digest to replay cache",
589 : : spadat.pkt_source_ip, stanza_num);
590 : 0 : acc = acc->next;
591 : 0 : continue;
592 : : }
593 : : added_replay_digest = 1;
594 : : }
595 : :
596 : : /* At this point, we assume the SPA data is valid. Now we need to see
597 : : * if it meets our access criteria.
598 : : */
599 : 979 : log_msg(LOG_DEBUG, "[%s] (stanza #%d) SPA Decode (res=%i):",
600 : : spadat.pkt_source_ip, stanza_num, res);
601 : :
602 : 979 : res = dump_ctx_to_buffer(ctx, dump_buf, sizeof(dump_buf));
603 [ + + ]: 979 : if (res == FKO_SUCCESS)
604 : 959 : log_msg(LOG_DEBUG, "%s", dump_buf);
605 : : else
606 : 20 : log_msg(LOG_WARNING, "Unable to dump FKO context: %s", fko_errstr(res));
607 : :
608 : : /* First, if this is a GPG message, and GPG_REMOTE_ID list is not empty,
609 : : * then we need to make sure this incoming message is signer ID matches
610 : : * an entry in the list.
611 : : */
612 [ + + ][ + + ]: 979 : if(enc_type == FKO_ENCRYPTION_GPG && acc->gpg_require_sig)
613 : : {
614 : 52 : res = fko_get_gpg_signature_id(ctx, &gpg_id);
615 [ - + ]: 52 : if(res != FKO_SUCCESS)
616 : : {
617 : 0 : log_msg(LOG_WARNING,
618 : : "[%s] (stanza #%d) Error pulling the GPG signature ID from the context: %s",
619 : : spadat.pkt_source_ip, stanza_num, fko_gpg_errstr(ctx));
620 : 0 : acc = acc->next;
621 : 0 : continue;
622 : : }
623 : :
624 : 52 : res = fko_get_gpg_signature_fpr(ctx, &gpg_fpr);
625 [ - + ]: 52 : if(res != FKO_SUCCESS)
626 : : {
627 : 0 : log_msg(LOG_WARNING,
628 : : "[%s] (stanza #%d) Error pulling the GPG fingerprint from the context: %s",
629 : : spadat.pkt_source_ip, stanza_num, fko_gpg_errstr(ctx));
630 : 0 : acc = acc->next;
631 : 0 : continue;
632 : : }
633 : :
634 : 52 : log_msg(LOG_INFO, "[%s] (stanza #%d) Incoming SPA data signed by '%s' (fingerprint '%s').",
635 : : spadat.pkt_source_ip, stanza_num, gpg_id, gpg_fpr);
636 : :
637 : : /* prefer GnuPG fingerprint match if so configured
638 : : */
639 [ + + ]: 52 : if(acc->gpg_remote_fpr != NULL)
640 : : {
641 : 2 : is_gpg_match = 0;
642 [ + + ]: 3 : for(gpg_fpr_ndx = acc->gpg_remote_fpr_list;
643 : 1 : gpg_fpr_ndx != NULL; gpg_fpr_ndx=gpg_fpr_ndx->next)
644 : : {
645 : 2 : res = fko_gpg_signature_fpr_match(ctx,
646 : 2 : gpg_fpr_ndx->str, &is_gpg_match);
647 [ - + ]: 2 : if(res != FKO_SUCCESS)
648 : : {
649 : 0 : log_msg(LOG_WARNING,
650 : : "[%s] (stanza #%d) Error in GPG signature comparision: %s",
651 : : spadat.pkt_source_ip, stanza_num, fko_gpg_errstr(ctx));
652 : 0 : acc = acc->next;
653 : 0 : continue;
654 : : }
655 [ + + ]: 2 : if(is_gpg_match)
656 : : break;
657 : : }
658 [ + + ]: 2 : if(! is_gpg_match)
659 : : {
660 : 1 : log_msg(LOG_WARNING,
661 : : "[%s] (stanza #%d) Incoming SPA packet signed by: %s, but that fingerprint is not in the GPG_FINGERPRINT_ID list.",
662 : : spadat.pkt_source_ip, stanza_num, gpg_fpr);
663 : 1 : acc = acc->next;
664 : 1 : continue;
665 : : }
666 : : }
667 : :
668 [ + + ]: 51 : if(acc->gpg_remote_id != NULL)
669 : : {
670 : 50 : is_gpg_match = 0;
671 [ + + ]: 51 : for(gpg_id_ndx = acc->gpg_remote_id_list;
672 : 1 : gpg_id_ndx != NULL; gpg_id_ndx=gpg_id_ndx->next)
673 : : {
674 : 50 : res = fko_gpg_signature_id_match(ctx,
675 : 50 : gpg_id_ndx->str, &is_gpg_match);
676 [ - + ]: 50 : if(res != FKO_SUCCESS)
677 : : {
678 : 0 : log_msg(LOG_WARNING,
679 : : "[%s] (stanza #%d) Error in GPG signature comparision: %s",
680 : : spadat.pkt_source_ip, stanza_num, fko_gpg_errstr(ctx));
681 : 0 : acc = acc->next;
682 : 0 : continue;
683 : : }
684 [ + + ]: 50 : if(is_gpg_match)
685 : : break;
686 : : }
687 : :
688 [ + + ]: 50 : if(! is_gpg_match)
689 : : {
690 : 1 : log_msg(LOG_WARNING,
691 : : "[%s] (stanza #%d) Incoming SPA packet signed by ID: %s, but that ID is not in the GPG_REMOTE_ID list.",
692 : : spadat.pkt_source_ip, stanza_num, gpg_id);
693 : 1 : acc = acc->next;
694 : 1 : continue;
695 : : }
696 : : }
697 : : }
698 : :
699 : : /* Populate our spa data struct for future reference.
700 : : */
701 : 977 : res = get_spa_data_fields(ctx, &spadat);
702 : :
703 [ + + ]: 977 : if(res != FKO_SUCCESS)
704 : : {
705 : 16 : log_msg(LOG_ERR, "[%s] (stanza #%d) Unexpected error pulling SPA data from the context: %s",
706 : : spadat.pkt_source_ip, stanza_num, fko_errstr(res));
707 : :
708 : 16 : acc = acc->next;
709 : 16 : continue;
710 : : }
711 : :
712 : : /* Figure out what our timeout will be. If it is specified in the SPA
713 : : * data, then use that. If not, try the FW_ACCESS_TIMEOUT from the
714 : : * access.conf file (if there is one). Otherwise use the default.
715 : : */
716 [ + + ]: 961 : if(spadat.client_timeout > 0)
717 : 98 : spadat.fw_access_timeout = spadat.client_timeout;
718 [ + - ]: 863 : else if(acc->fw_access_timeout > 0)
719 : 863 : spadat.fw_access_timeout = acc->fw_access_timeout;
720 : : else
721 : 0 : spadat.fw_access_timeout = DEF_FW_ACCESS_TIMEOUT;
722 : :
723 : : /* Check packet age if so configured.
724 : : */
725 [ + + ]: 961 : if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0)
726 : : {
727 : 239 : time(&now_ts);
728 : :
729 : 239 : ts_diff = abs(now_ts - spadat.timestamp);
730 : :
731 [ + + ]: 239 : if(ts_diff > conf_pkt_age)
732 : : {
733 : 2 : log_msg(LOG_WARNING, "[%s] (stanza #%d) SPA data time difference is too great (%i seconds).",
734 : : spadat.pkt_source_ip, stanza_num, ts_diff);
735 : :
736 : 2 : acc = acc->next;
737 : 2 : continue;
738 : : }
739 : : }
740 : :
741 : : /* At this point, we have enough to check the embedded (or packet source)
742 : : * IP address against the defined access rights. We start by splitting
743 : : * the spa msg source IP from the remainder of the message.
744 : : */
745 : 959 : spa_ip_demark = strchr(spadat.spa_message, ',');
746 [ - + ]: 959 : if(spa_ip_demark == NULL)
747 : : {
748 : 0 : log_msg(LOG_WARNING, "[%s] (stanza #%d) Error parsing SPA message string: %s",
749 : : spadat.pkt_source_ip, stanza_num, fko_errstr(res));
750 : :
751 : 0 : acc = acc->next;
752 : 0 : continue;
753 : : }
754 : :
755 [ - + ]: 959 : if((spa_ip_demark-spadat.spa_message) < MIN_IPV4_STR_LEN-1
756 : 959 : || (spa_ip_demark-spadat.spa_message) > MAX_IPV4_STR_LEN)
757 : : {
758 : 0 : log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
759 : : spadat.pkt_source_ip, stanza_num);
760 : 0 : break;
761 : : }
762 : :
763 : 959 : strlcpy(spadat.spa_message_src_ip,
764 : 959 : spadat.spa_message, (spa_ip_demark-spadat.spa_message)+1);
765 : :
766 [ - + ]: 959 : if(! is_valid_ipv4_addr(spadat.spa_message_src_ip))
767 : : {
768 : 0 : log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
769 : : spadat.pkt_source_ip, stanza_num, fko_errstr(res));
770 : 0 : break;
771 : : }
772 : :
773 : 959 : strlcpy(spadat.spa_message_remain, spa_ip_demark+1, MAX_DECRYPTED_SPA_LEN);
774 : :
775 : : /* If use source IP was requested (embedded IP of 0.0.0.0), make sure it
776 : : * is allowed.
777 : : */
778 [ + + ]: 959 : if(strcmp(spadat.spa_message_src_ip, "0.0.0.0") == 0)
779 : : {
780 [ + + ]: 7 : if(acc->require_source_address)
781 : : {
782 : 1 : log_msg(LOG_WARNING,
783 : : "[%s] (stanza #%d) Got 0.0.0.0 when valid source IP was required.",
784 : : spadat.pkt_source_ip, stanza_num
785 : : );
786 : 1 : acc = acc->next;
787 : 1 : continue;
788 : : }
789 : :
790 : 6 : spadat.use_src_ip = spadat.pkt_source_ip;
791 : : }
792 : : else
793 : 952 : spadat.use_src_ip = spadat.spa_message_src_ip;
794 : :
795 : : /* If REQUIRE_USERNAME is set, make sure the username in this SPA data
796 : : * matches.
797 : : */
798 [ + + ]: 958 : if(acc->require_username != NULL)
799 : : {
800 [ + + ]: 2 : if(strcmp(spadat.username, acc->require_username) != 0)
801 : : {
802 : 1 : log_msg(LOG_WARNING,
803 : : "[%s] (stanza #%d) Username in SPA data (%s) does not match required username: %s",
804 : : spadat.pkt_source_ip, stanza_num, spadat.username, acc->require_username
805 : : );
806 : 1 : acc = acc->next;
807 : 1 : continue;
808 : : }
809 : : }
810 : :
811 : : /* Take action based on SPA message type.
812 : : */
813 [ + + ]: 957 : if(spadat.message_type == FKO_LOCAL_NAT_ACCESS_MSG
814 : : || spadat.message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
815 : 957 : || spadat.message_type == FKO_NAT_ACCESS_MSG
816 [ + + ]: 837 : || spadat.message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
817 : : {
818 : : #if FIREWALL_FIREWALLD
819 : : if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1)!=0)
820 : : {
821 : : log_msg(LOG_WARNING,
822 : : "(stanza #%d) SPA packet from %s requested NAT access, but is not enabled",
823 : : stanza_num, spadat.pkt_source_ip
824 : : );
825 : : acc = acc->next;
826 : : continue;
827 : : }
828 : : #elif FIREWALL_IPTABLES
829 [ + + ]: 188 : if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)!=0)
830 : : {
831 : 164 : log_msg(LOG_WARNING,
832 : : "(stanza #%d) SPA packet from %s requested NAT access, but is not enabled",
833 : : stanza_num, spadat.pkt_source_ip
834 : : );
835 : 164 : acc = acc->next;
836 : 164 : continue;
837 : : }
838 : : #else
839 : : log_msg(LOG_WARNING,
840 : : "(stanza #%d) SPA packet from %s requested unsupported NAT access",
841 : : stanza_num, spadat.pkt_source_ip
842 : : );
843 : : acc = acc->next;
844 : : continue;
845 : : #endif
846 : : }
847 : :
848 : : /* Command messages.
849 : : */
850 [ + + ]: 793 : if(spadat.message_type == FKO_COMMAND_MSG)
851 : : {
852 [ - + ]: 166 : if(!acc->enable_cmd_exec)
853 : : {
854 : 0 : log_msg(LOG_WARNING,
855 : : "[%s] (stanza #%d) SPA Command message are not allowed in the current configuration.",
856 : : spadat.pkt_source_ip, stanza_num
857 : : );
858 : 0 : acc = acc->next;
859 : 0 : continue;
860 : : }
861 [ + + ]: 166 : else if(opts->test)
862 : : {
863 : 156 : log_msg(LOG_WARNING,
864 : : "[%s] (stanza #%d) --test mode enabled, skipping command execution.",
865 : : spadat.pkt_source_ip, stanza_num
866 : : );
867 : 156 : acc = acc->next;
868 : 156 : continue;
869 : : }
870 : : else
871 : : {
872 : 10 : log_msg(LOG_INFO,
873 : : "[%s] (stanza #%d) Processing SPA Command message: command='%s'.",
874 : : spadat.pkt_source_ip, stanza_num, spadat.spa_message_remain
875 : : );
876 : :
877 : : /* Do we need to become another user? If so, we call
878 : : * run_extcmd_as and pass the cmd_exec_uid.
879 : : */
880 [ + + ][ + - ]: 10 : if(acc->cmd_exec_user != NULL && strncasecmp(acc->cmd_exec_user, "root", 4) != 0)
881 : : {
882 [ + + ]: 4 : log_msg(LOG_INFO,
883 : : "[%s] (stanza #%d) setuid/setgid user/group to %s/%s (UID=%i,GID=%i) before running command.",
884 : : spadat.pkt_source_ip, stanza_num, acc->cmd_exec_user,
885 : 4 : acc->cmd_exec_group == NULL ? acc->cmd_exec_user : acc->cmd_exec_group,
886 : : acc->cmd_exec_uid, acc->cmd_exec_gid);
887 : :
888 : 4 : res = run_extcmd_as(acc->cmd_exec_uid, acc->cmd_exec_gid,
889 : : spadat.spa_message_remain, NULL, 0,
890 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
891 : : }
892 : : else /* Just run it as we are (root that is). */
893 : 6 : res = run_extcmd(spadat.spa_message_remain, NULL, 0,
894 : : WANT_STDERR, 5, &pid_status, opts);
895 : :
896 : : /* should only call WEXITSTATUS() if WIFEXITED() is true
897 : : */
898 [ + - ]: 10 : log_msg(LOG_INFO,
899 : : "[%s] (stanza #%d) CMD_EXEC: command returned %i, pid_status: %d",
900 : : spadat.pkt_source_ip, stanza_num, res,
901 : 20 : WIFEXITED(pid_status) ? WEXITSTATUS(pid_status) : pid_status);
902 : :
903 : 10 : if(WIFEXITED(pid_status))
904 : : {
905 : : if(WEXITSTATUS(pid_status) != 0)
906 : : res = SPA_MSG_COMMAND_ERROR;
907 : : }
908 : : else
909 : : res = SPA_MSG_COMMAND_ERROR;
910 : :
911 : : /* we processed the command on a matching access stanza, so we
912 : : * don't look for anything else to do with this SPA packet
913 : : */
914 : : break;
915 : : }
916 : : }
917 : :
918 : : /* From this point forward, we have some kind of access message. So
919 : : * we first see if access is allowed by checking access against
920 : : * restrict_ports and open_ports.
921 : : *
922 : : * --DSS TODO: We should add BLACKLIST support here as well.
923 : : */
924 [ + + ]: 627 : if(! acc_check_port_access(acc, spadat.spa_message_remain))
925 : : {
926 : 3 : log_msg(LOG_WARNING,
927 : : "[%s] (stanza #%d) One or more requested protocol/ports was denied per access.conf.",
928 : : spadat.pkt_source_ip, stanza_num
929 : : );
930 : 3 : acc = acc->next;
931 : 3 : continue;
932 : : }
933 : :
934 : : /* At this point, we process the SPA request and break out of the
935 : : * access stanza loop (first valid access stanza stops us looking
936 : : * for others).
937 : : */
938 [ + + ]: 624 : if(opts->test) /* no firewall changes in --test mode */
939 : : {
940 : 365 : log_msg(LOG_WARNING,
941 : : "[%s] (stanza #%d) --test mode enabled, skipping firewall manipulation.",
942 : : spadat.pkt_source_ip, stanza_num
943 : : );
944 : 365 : acc = acc->next;
945 : 365 : continue;
946 : : }
947 : : else
948 : : {
949 : 259 : process_spa_request(opts, acc, &spadat);
950 : : }
951 : :
952 : 13695 : break;
953 : : }
954 : :
955 [ + - ]: 13696 : if (raw_digest != NULL)
956 : 13696 : free(raw_digest);
957 : :
958 [ + + ]: 13696 : if(ctx != NULL)
959 : : {
960 [ - + ]: 985 : if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
961 : 0 : log_msg(LOG_WARNING,
962 : : "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
963 : : spadat.pkt_source_ip, stanza_num
964 : : );
965 : 985 : ctx = NULL;
966 : : }
967 : :
968 : : return;
969 : : }
970 : :
971 : : /***EOF***/
|