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