LCOV - code coverage report
Current view: top level - server - incoming_spa.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 368 417 88.2 %
Date: 2015-08-23 Functions: 21 21 100.0 %
Branches: 228 274 83.2 %

           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                 :      17337 : preprocess_spa_data(const fko_srv_options_t *opts, spa_pkt_info_t *spa_pkt)
      54                 :            : {
      55                 :            : 
      56                 :      17337 :     char    *ndx = (char *)&(spa_pkt->packet_data);
      57                 :      17337 :     int      i, pkt_data_len = 0;
      58                 :            : 
      59                 :      17337 :     pkt_data_len = spa_pkt->packet_data_len;
      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                 :      17337 :     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         [ +  - ]:      17337 :     if(pkt_data_len < MIN_SPA_DATA_SIZE)
      71                 :            :         return(SPA_MSG_BAD_DATA);
      72                 :            : 
      73         [ +  - ]:      17337 :     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         [ +  + ]:      17337 :     if(constant_runtime_cmp(ndx, B64_RIJNDAEL_SALT, B64_RIJNDAEL_SALT_STR_LEN) == 0)
      84                 :            :         return(SPA_MSG_BAD_DATA);
      85                 :            : 
      86         [ +  + ]:      17283 :     if(pkt_data_len > MIN_GNUPG_MSG_SIZE
      87         [ +  + ]:       4360 :             && 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         [ +  + ]:      17232 :     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         [ +  + ]:      17232 :     if(! is_base64(spa_pkt->packet_data, pkt_data_len))
     133                 :            :         return(SPA_MSG_NOT_SPA_DATA);
     134                 :            : 
     135                 :            : 
     136                 :            :     /* If we made it here, we have no reason to assume this is not SPA data.
     137                 :            :      * The ultimate test will be whether the SPA data authenticates via an
     138                 :            :      * HMAC anyway.
     139                 :            :     */
     140                 :            :     return(FKO_SUCCESS);
     141                 :            : }
     142                 :            : 
     143                 :            : /* For replay attack detection
     144                 :            : */
     145                 :            : static int
     146                 :      17195 : get_raw_digest(char **digest, char *pkt_data)
     147                 :            : {
     148                 :      17195 :     fko_ctx_t    ctx = NULL;
     149                 :      17195 :     char        *tmp_digest = NULL;
     150                 :      17195 :     int          res = FKO_SUCCESS;
     151                 :      17195 :     short        raw_digest_type = -1;
     152                 :            : 
     153                 :            :     /* initialize an FKO context with no decryption key just so
     154                 :            :      * we can get the outer message digest
     155                 :            :     */
     156                 :      17195 :     res = fko_new_with_data(&ctx, (char *)pkt_data, NULL, 0,
     157                 :            :             FKO_DEFAULT_ENC_MODE, NULL, 0, 0);
     158                 :            : 
     159         [ +  + ]:      17195 :     if(res != FKO_SUCCESS)
     160                 :            :     {
     161                 :         57 :         log_msg(LOG_WARNING, "Error initializing FKO context from SPA data: %s",
     162                 :            :             fko_errstr(res));
     163                 :         57 :         fko_destroy(ctx);
     164                 :         57 :         ctx = NULL;
     165                 :         57 :         return(SPA_MSG_FKO_CTX_ERROR);
     166                 :            :     }
     167                 :            : 
     168                 :      17138 :     res = fko_set_raw_spa_digest_type(ctx, FKO_DEFAULT_DIGEST);
     169         [ +  + ]:      17138 :     if(res != FKO_SUCCESS)
     170                 :            :     {
     171                 :          2 :         log_msg(LOG_WARNING, "Error setting digest type for SPA data: %s",
     172                 :            :             fko_errstr(res));
     173                 :          2 :         fko_destroy(ctx);
     174                 :          2 :         ctx = NULL;
     175                 :          2 :         return(SPA_MSG_DIGEST_ERROR);
     176                 :            :     }
     177                 :            : 
     178                 :      17136 :     res = fko_get_raw_spa_digest_type(ctx, &raw_digest_type);
     179         [ +  + ]:      17136 :     if(res != FKO_SUCCESS)
     180                 :            :     {
     181                 :          1 :         log_msg(LOG_WARNING, "Error getting digest type for SPA data: %s",
     182                 :            :             fko_errstr(res));
     183                 :          1 :         fko_destroy(ctx);
     184                 :          1 :         ctx = NULL;
     185                 :          1 :         return(SPA_MSG_DIGEST_ERROR);
     186                 :            :     }
     187                 :            : 
     188                 :            :     /* Make sure the digest type is what we expect
     189                 :            :     */
     190         [ -  + ]:      17135 :     if(raw_digest_type != FKO_DEFAULT_DIGEST)
     191                 :            :     {
     192                 :          0 :         log_msg(LOG_WARNING, "Error setting digest type for SPA data: %s",
     193                 :            :             fko_errstr(res));
     194                 :          0 :         fko_destroy(ctx);
     195                 :          0 :         ctx = NULL;
     196                 :          0 :         return(SPA_MSG_DIGEST_ERROR);
     197                 :            :     }
     198                 :            : 
     199                 :      17135 :     res = fko_set_raw_spa_digest(ctx);
     200         [ +  + ]:      17135 :     if(res != FKO_SUCCESS)
     201                 :            :     {
     202                 :         71 :         log_msg(LOG_WARNING, "Error setting digest for SPA data: %s",
     203                 :            :             fko_errstr(res));
     204                 :         71 :         fko_destroy(ctx);
     205                 :         71 :         ctx = NULL;
     206                 :         71 :         return(SPA_MSG_DIGEST_ERROR);
     207                 :            :     }
     208                 :            : 
     209                 :      17064 :     res = fko_get_raw_spa_digest(ctx, &tmp_digest);
     210         [ +  + ]:      17064 :     if(res != FKO_SUCCESS)
     211                 :            :     {
     212                 :          1 :         log_msg(LOG_WARNING, "Error getting digest from SPA data: %s",
     213                 :            :             fko_errstr(res));
     214                 :          1 :         fko_destroy(ctx);
     215                 :          1 :         ctx = NULL;
     216                 :          1 :         return(SPA_MSG_DIGEST_ERROR);
     217                 :            :     }
     218                 :            : 
     219                 :      17063 :     *digest = strdup(tmp_digest);
     220                 :            : 
     221         [ -  + ]:      17063 :     if (*digest == NULL)
     222                 :          0 :         res = SPA_MSG_ERROR;  /* really a strdup() memory allocation problem */
     223                 :            : 
     224                 :      17063 :     fko_destroy(ctx);
     225                 :      17063 :     ctx = NULL;
     226                 :            : 
     227                 :      17063 :     return res;
     228                 :            : }
     229                 :            : 
     230                 :            : /* Popluate a spa_data struct from an initialized (and populated) FKO context.
     231                 :            : */
     232                 :            : static int
     233                 :       1128 : get_spa_data_fields(fko_ctx_t ctx, spa_data_t *spdat)
     234                 :            : {
     235                 :       1128 :     int res = FKO_SUCCESS;
     236                 :            : 
     237                 :       1128 :     res = fko_get_username(ctx, &(spdat->username));
     238         [ +  + ]:       1128 :     if(res != FKO_SUCCESS)
     239                 :            :         return(res);
     240                 :            : 
     241                 :       1126 :     res = fko_get_timestamp(ctx, &(spdat->timestamp));
     242         [ +  + ]:       1126 :     if(res != FKO_SUCCESS)
     243                 :            :         return(res);
     244                 :            : 
     245                 :       1124 :     res = fko_get_version(ctx, &(spdat->version));
     246         [ +  + ]:       1124 :     if(res != FKO_SUCCESS)
     247                 :            :         return(res);
     248                 :            : 
     249                 :       1122 :     res = fko_get_spa_message_type(ctx, &(spdat->message_type));
     250         [ +  + ]:       1122 :     if(res != FKO_SUCCESS)
     251                 :            :         return(res);
     252                 :            : 
     253                 :       1120 :     res = fko_get_spa_message(ctx, &(spdat->spa_message));
     254         [ +  + ]:       1120 :     if(res != FKO_SUCCESS)
     255                 :            :         return(res);
     256                 :            : 
     257                 :       1118 :     res = fko_get_spa_nat_access(ctx, &(spdat->nat_access));
     258         [ +  + ]:       1118 :     if(res != FKO_SUCCESS)
     259                 :            :         return(res);
     260                 :            : 
     261                 :       1116 :     res = fko_get_spa_server_auth(ctx, &(spdat->server_auth));
     262         [ +  + ]:       1116 :     if(res != FKO_SUCCESS)
     263                 :            :         return(res);
     264                 :            : 
     265                 :       1114 :     res = fko_get_spa_client_timeout(ctx, (int *)&(spdat->client_timeout));
     266                 :            :     if(res != FKO_SUCCESS)
     267                 :            :         return(res);
     268                 :            : 
     269                 :            :     return(res);
     270                 :            : }
     271                 :            : 
     272                 :            : static int
     273                 :       1112 : check_pkt_age(const fko_srv_options_t *opts, spa_data_t *spadat,
     274                 :            :         const int stanza_num, const int conf_pkt_age)
     275                 :            : {
     276                 :            :     int         ts_diff;
     277                 :            :     time_t      now_ts;
     278                 :            : 
     279         [ +  + ]:       1112 :     if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0)
     280                 :            :     {
     281                 :        282 :         time(&now_ts);
     282                 :            : 
     283                 :        282 :         ts_diff = labs(now_ts - spadat->timestamp);
     284                 :            : 
     285         [ +  + ]:        282 :         if(ts_diff > conf_pkt_age)
     286                 :            :         {
     287                 :          2 :             log_msg(LOG_WARNING, "[%s] (stanza #%d) SPA data time difference is too great (%i seconds).",
     288                 :          2 :                 spadat->pkt_source_ip, stanza_num, ts_diff);
     289                 :            :             return 0;
     290                 :            :         }
     291                 :            :     }
     292                 :            :     return 1;
     293                 :            : }
     294                 :            : 
     295                 :            : static int
     296                 :      33946 : check_stanza_expiration(acc_stanza_t *acc, spa_data_t *spadat,
     297                 :            :         const int stanza_num)
     298                 :            : {
     299         [ +  + ]:      16973 :     if(acc->access_expire_time > 0)
     300                 :            :     {
     301         [ +  - ]:          3 :         if(acc->expired)
     302                 :            :         {
     303                 :            :             return 0;
     304                 :            :         }
     305                 :            :         else
     306                 :            :         {
     307         [ +  + ]:          3 :             if(time(NULL) > acc->access_expire_time)
     308                 :            :             {
     309                 :          2 :                 log_msg(LOG_INFO, "[%s] (stanza #%d) Access stanza has expired",
     310                 :          2 :                     spadat->pkt_source_ip, stanza_num);
     311                 :          2 :                 acc->expired = 1;
     312                 :            :                 return 0;
     313                 :            :             }
     314                 :            :         }
     315                 :            :     }
     316                 :            :     return 1;
     317                 :            : }
     318                 :            : 
     319                 :            : /* Check for access.conf stanza SOURCE match based on SPA packet
     320                 :            :  * source IP
     321                 :            : */
     322                 :            : static int
     323                 :      17198 : is_src_match(acc_stanza_t *acc, const uint32_t ip)
     324                 :            : {
     325         [ +  + ]:      17205 :     while (acc)
     326                 :            :     {
     327         [ +  + ]:      17202 :         if(compare_addr_list(acc->source_list, ip))
     328                 :            :             return 1;
     329                 :            : 
     330                 :          7 :         acc = acc->next;
     331                 :            :     }
     332                 :            :     return 0;
     333                 :            : }
     334                 :            : 
     335                 :            : static int
     336                 :      17198 : src_check(fko_srv_options_t *opts, spa_pkt_info_t *spa_pkt,
     337                 :            :         spa_data_t *spadat, char **raw_digest)
     338                 :            : {
     339         [ +  + ]:      17198 :     if (is_src_match(opts->acc_stanzas, ntohl(spa_pkt->packet_src_ip)))
     340                 :            :     {
     341         [ +  - ]:      17195 :         if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
     342                 :            :         {
     343                 :            :             /* Check for a replay attack
     344                 :            :             */
     345         [ +  + ]:      17195 :             if(get_raw_digest(raw_digest, (char *)spa_pkt->packet_data) != FKO_SUCCESS)
     346                 :            :             {
     347         [ -  + ]:        132 :                 if (*raw_digest != NULL)
     348                 :          0 :                     free(*raw_digest);
     349                 :            :                 return 0;
     350                 :            :             }
     351         [ +  - ]:      17063 :             if (*raw_digest == NULL)
     352                 :            :                 return 0;
     353                 :            : 
     354         [ +  + ]:      17063 :             if (is_replay(opts, *raw_digest) != SPA_MSG_SUCCESS)
     355                 :            :             {
     356                 :         93 :                 free(*raw_digest);
     357                 :         93 :                 return 0;
     358                 :            :             }
     359                 :            :         }
     360                 :            :     }
     361                 :            :     else
     362                 :            :     {
     363                 :          3 :         log_msg(LOG_WARNING,
     364                 :          3 :             "No access data found for source IP: %s", spadat->pkt_source_ip
     365                 :            :         );
     366                 :          3 :         return 0;
     367                 :            :     }
     368                 :            :     return 1;
     369                 :            : }
     370                 :            : 
     371                 :            : static int
     372                 :      17337 : precheck_pkt(fko_srv_options_t *opts, spa_pkt_info_t *spa_pkt,
     373                 :            :         spa_data_t *spadat, char **raw_digest)
     374                 :            : {
     375                 :      17337 :     int res = 0, packet_data_len = 0;
     376                 :            : 
     377                 :      17337 :     packet_data_len = spa_pkt->packet_data_len;
     378                 :            : 
     379                 :      17337 :     res = preprocess_spa_data(opts, spa_pkt);
     380         [ +  + ]:      17337 :     if(res != FKO_SUCCESS)
     381                 :            :     {
     382                 :        139 :         log_msg(LOG_DEBUG, "[%s] preprocess_spa_data() returned error %i: '%s' for incoming packet.",
     383                 :        139 :             spadat->pkt_source_ip, res, get_errstr(res));
     384                 :        139 :         return 0;
     385                 :            :     }
     386                 :            : 
     387 [ +  - ][ +  + ]:      17198 :     if(opts->foreground == 1 && opts->verbose > 2)
     388                 :            :     {
     389                 :            :         printf("[+] candidate SPA packet payload:\n");
     390                 :        109 :         hex_dump(spa_pkt->packet_data, packet_data_len);
     391                 :            :     }
     392                 :            : 
     393         [ +  + ]:      17198 :     if(! src_check(opts, spa_pkt, spadat, raw_digest))
     394                 :            :         return 0;
     395                 :            : 
     396                 :      16970 :     return 1;
     397                 :            : }
     398                 :            : 
     399                 :            : static int
     400                 :      16979 : src_dst_check(acc_stanza_t *acc, spa_pkt_info_t *spa_pkt,
     401                 :            :         spa_data_t *spadat, const int stanza_num)
     402                 :            : {
     403 [ +  + ][ +  + ]:      16979 :     if(! compare_addr_list(acc->source_list, ntohl(spa_pkt->packet_src_ip)) ||
     404                 :      16975 :        (acc->destination_list != NULL
     405         [ +  + ]:          5 :         && ! compare_addr_list(acc->destination_list, ntohl(spa_pkt->packet_dst_ip))))
     406                 :            :     {
     407                 :          6 :         log_msg(LOG_DEBUG,
     408                 :            :                 "(stanza #%d) SPA packet (%s -> %s) filtered by SOURCE and/or DESTINATION criteria",
     409                 :          6 :                 stanza_num, spadat->pkt_source_ip, spadat->pkt_destination_ip);
     410                 :            :         return 0;
     411                 :            :     }
     412                 :            :     return 1;
     413                 :            : }
     414                 :            : 
     415                 :            : /* Process command messages
     416                 :            : */
     417                 :            : static int
     418                 :        219 : process_cmd_msg(fko_srv_options_t *opts, acc_stanza_t *acc,
     419                 :            :         spa_data_t *spadat, const int stanza_num, int *res)
     420                 :            : {
     421                 :        219 :     int             pid_status=0;
     422                 :        219 :     char            cmd_buf[MAX_SPA_CMD_LEN] = {0};
     423                 :            : 
     424         [ +  + ]:        219 :     if(!acc->enable_cmd_exec)
     425                 :            :     {
     426                 :          1 :         log_msg(LOG_WARNING,
     427                 :            :             "[%s] (stanza #%d) SPA Command messages are not allowed in the current configuration.",
     428                 :          1 :             spadat->pkt_source_ip, stanza_num
     429                 :            :         );
     430                 :          1 :         return 0;
     431                 :            :     }
     432         [ +  + ]:        218 :     else if(opts->test)
     433                 :            :     {
     434                 :        199 :         log_msg(LOG_WARNING,
     435                 :            :             "[%s] (stanza #%d) --test mode enabled, skipping command execution.",
     436                 :        199 :             spadat->pkt_source_ip, stanza_num
     437                 :            :         );
     438                 :        199 :         return 0;
     439                 :            :     }
     440                 :            :     else
     441                 :            :     {
     442                 :         19 :         log_msg(LOG_INFO,
     443                 :            :             "[%s] (stanza #%d) Processing SPA Command message: command='%s'.",
     444                 :         19 :             spadat->pkt_source_ip, stanza_num, spadat->spa_message_remain
     445                 :            :         );
     446                 :            : 
     447                 :            :         memset(cmd_buf, 0x0, sizeof(cmd_buf));
     448         [ +  + ]:         19 :         if(acc->enable_cmd_sudo_exec)
     449                 :            :         {
     450                 :            :             /* Run the command via sudo - this allows sudo filtering
     451                 :            :              * to apply to the incoming command
     452                 :            :             */
     453                 :          8 :             strlcpy(cmd_buf, opts->config[CONF_SUDO_EXE],
     454                 :            :                     sizeof(cmd_buf));
     455         [ +  + ]:          8 :             if(acc->cmd_sudo_exec_user != NULL
     456         [ +  - ]:          7 :                     && strncasecmp(acc->cmd_sudo_exec_user, "root", 4) != 0)
     457                 :            :             {
     458                 :          7 :                 strlcat(cmd_buf, " -u ", sizeof(cmd_buf));
     459                 :          7 :                 strlcat(cmd_buf, acc->cmd_sudo_exec_user, sizeof(cmd_buf));
     460                 :            :             }
     461         [ -  + ]:          8 :             if(acc->cmd_exec_group != NULL
     462         [ #  # ]:          0 :                     && strncasecmp(acc->cmd_sudo_exec_group, "root", 4) != 0)
     463                 :            :             {
     464                 :          0 :                 strlcat(cmd_buf, " -g ", sizeof(cmd_buf));
     465                 :          0 :                 strlcat(cmd_buf,
     466                 :          0 :                         acc->cmd_sudo_exec_group, sizeof(cmd_buf));
     467                 :            :             }
     468                 :          8 :             strlcat(cmd_buf, " ",  sizeof(cmd_buf));
     469                 :          8 :             strlcat(cmd_buf, spadat->spa_message_remain, sizeof(cmd_buf));
     470                 :            :         }
     471                 :            :         else
     472                 :         11 :             strlcpy(cmd_buf, spadat->spa_message_remain, sizeof(cmd_buf));
     473                 :            : 
     474         [ +  + ]:         19 :         if(acc->cmd_exec_user != NULL
     475         [ +  - ]:         10 :                 && strncasecmp(acc->cmd_exec_user, "root", 4) != 0)
     476                 :            :         {
     477         [ +  + ]:         10 :             log_msg(LOG_INFO,
     478                 :            :                     "[%s] (stanza #%d) Running command '%s' setuid/setgid user/group to %s/%s (UID=%i,GID=%i)",
     479                 :            :                 spadat->pkt_source_ip, stanza_num, cmd_buf, acc->cmd_exec_user,
     480                 :         10 :                 acc->cmd_exec_group == NULL ? acc->cmd_exec_user : acc->cmd_exec_group,
     481                 :            :                 acc->cmd_exec_uid, acc->cmd_exec_gid);
     482                 :            : 
     483                 :         10 :             *res = run_extcmd_as(acc->cmd_exec_uid, acc->cmd_exec_gid,
     484                 :            :                     cmd_buf, NULL, 0, WANT_STDERR, NO_TIMEOUT,
     485                 :            :                     &pid_status, opts);
     486                 :            :         }
     487                 :            :         else /* Just run it as we are (root that is). */
     488                 :            :         {
     489                 :          9 :             log_msg(LOG_INFO,
     490                 :            :                     "[%s] (stanza #%d) Running command '%s'",
     491                 :            :                 spadat->pkt_source_ip, stanza_num, cmd_buf);
     492                 :          9 :             *res = run_extcmd(cmd_buf, NULL, 0, WANT_STDERR,
     493                 :            :                     5, &pid_status, opts);
     494                 :            :         }
     495                 :            : 
     496                 :            :         /* should only call WEXITSTATUS() if WIFEXITED() is true
     497                 :            :         */
     498         [ +  - ]:         19 :         log_msg(LOG_INFO,
     499                 :            :             "[%s] (stanza #%d) CMD_EXEC: command returned %i, pid_status: %d",
     500                 :            :             spadat->pkt_source_ip, stanza_num, *res,
     501                 :         38 :             WIFEXITED(pid_status) ? WEXITSTATUS(pid_status) : pid_status);
     502                 :            : 
     503         [ +  - ]:         19 :         if(WIFEXITED(pid_status))
     504                 :            :         {
     505         [ -  + ]:         19 :             if(WEXITSTATUS(pid_status) != 0)
     506                 :          0 :                 *res = SPA_MSG_COMMAND_ERROR;
     507                 :            :         }
     508                 :            :         else
     509                 :          0 :             *res = SPA_MSG_COMMAND_ERROR;
     510                 :            :     }
     511                 :            :     return 1;
     512                 :            : }
     513                 :            : 
     514                 :            : static int
     515                 :      16970 : check_mode_ctx(spa_data_t *spadat, fko_ctx_t *ctx, int attempted_decrypt,
     516                 :            :         const int enc_type, const int stanza_num, const int res)
     517                 :            : {
     518         [ +  + ]:      16970 :     if(attempted_decrypt == 0)
     519                 :            :     {
     520                 :          7 :         log_msg(LOG_ERR,
     521                 :            :             "[%s] (stanza #%d) No stanza encryption mode match for encryption type: %i.",
     522                 :          7 :             spadat->pkt_source_ip, stanza_num, enc_type);
     523                 :          7 :         return 0;
     524                 :            :     }
     525                 :            : 
     526                 :            :     /* Do we have a valid FKO context?  Did the SPA decrypt properly?
     527                 :            :     */
     528         [ +  + ]:      16963 :     if(res != FKO_SUCCESS)
     529                 :            :     {
     530                 :      15833 :         log_msg(LOG_WARNING, "[%s] (stanza #%d) Error creating fko context: %s",
     531                 :      15833 :             spadat->pkt_source_ip, stanza_num, fko_errstr(res));
     532                 :            : 
     533         [ +  + ]:      15833 :         if(IS_GPG_ERROR(res))
     534                 :          7 :             log_msg(LOG_WARNING, "[%s] (stanza #%d) - GPG ERROR: %s",
     535                 :            :                 spadat->pkt_source_ip, stanza_num, fko_gpg_errstr(*ctx));
     536                 :            :         return 0;
     537                 :            :     }
     538                 :            : 
     539                 :            :     return 1;
     540                 :            : }
     541                 :            : 
     542                 :            : static int
     543                 :      16971 : handle_rijndael_enc(acc_stanza_t *acc, spa_pkt_info_t *spa_pkt,
     544                 :            :         spa_data_t *spadat, fko_ctx_t *ctx, int *attempted_decrypt,
     545                 :            :         int *cmd_exec_success, const int enc_type, const int stanza_num,
     546                 :            :         int *res)
     547                 :            : {
     548         [ +  + ]:      16971 :     if(acc->use_rijndael)
     549                 :            :     {
     550         [ -  + ]:      16930 :         if(acc->key == NULL)
     551                 :            :         {
     552                 :          0 :             log_msg(LOG_ERR,
     553                 :            :                 "[%s] (stanza #%d) No KEY for RIJNDAEL encrypted messages",
     554                 :          0 :                 spadat->pkt_source_ip, stanza_num
     555                 :            :             );
     556                 :          0 :             return 0;
     557                 :            :         }
     558                 :            : 
     559                 :            :         /* Command mode messages may be quite long
     560                 :            :         */
     561 [ +  + ][ +  + ]:      16930 :         if(acc->enable_cmd_exec || enc_type == FKO_ENCRYPTION_RIJNDAEL)
     562                 :            :         {
     563                 :      16900 :             *res = fko_new_with_data(ctx, (char *)spa_pkt->packet_data,
     564                 :      16900 :                 acc->key, acc->key_len, acc->encryption_mode, acc->hmac_key,
     565                 :            :                 acc->hmac_key_len, acc->hmac_type);
     566                 :      16900 :             *attempted_decrypt = 1;
     567         [ +  + ]:      16900 :             if(*res == FKO_SUCCESS)
     568                 :       1074 :                 *cmd_exec_success = 1;
     569                 :            :         }
     570                 :            :     }
     571                 :            :     return 1;
     572                 :            : }
     573                 :            : 
     574                 :            : static int
     575                 :      16971 : handle_gpg_enc(acc_stanza_t *acc, spa_pkt_info_t *spa_pkt,
     576                 :            :         spa_data_t *spadat, fko_ctx_t *ctx, int *attempted_decrypt,
     577                 :            :         const int cmd_exec_success, const int enc_type,
     578                 :            :         const int stanza_num, int *res)
     579                 :            : {
     580 [ +  + ][ +  - ]:      16971 :     if(acc->use_gpg && enc_type == FKO_ENCRYPTION_GPG && cmd_exec_success == 0)
     581                 :            :     {
     582                 :            :         /* For GPG we create the new context without decrypting on the fly
     583                 :            :          * so we can set some GPG parameters first.
     584                 :            :         */
     585 [ -  + ][ #  # ]:         64 :         if(acc->gpg_decrypt_pw != NULL || acc->gpg_allow_no_pw)
     586                 :            :         {
     587                 :         64 :             *res = fko_new_with_data(ctx, (char *)spa_pkt->packet_data, NULL,
     588                 :         64 :                     0, FKO_ENC_MODE_ASYMMETRIC, acc->hmac_key,
     589                 :            :                     acc->hmac_key_len, acc->hmac_type);
     590                 :            : 
     591         [ -  + ]:         64 :             if(*res != FKO_SUCCESS)
     592                 :            :             {
     593                 :          0 :                 log_msg(LOG_WARNING,
     594                 :            :                     "[%s] (stanza #%d) Error creating fko context (before decryption): %s",
     595                 :          0 :                     spadat->pkt_source_ip, stanza_num, fko_errstr(*res)
     596                 :            :                 );
     597                 :          0 :                 return 0;
     598                 :            :             }
     599                 :            : 
     600                 :            :             /* Set whatever GPG parameters we have.
     601                 :            :             */
     602         [ +  + ]:         64 :             if(acc->gpg_exe != NULL)
     603                 :            :             {
     604                 :          1 :                 *res = fko_set_gpg_exe(*ctx, acc->gpg_exe);
     605         [ +  - ]:          1 :                 if(*res != FKO_SUCCESS)
     606                 :            :                 {
     607                 :          1 :                     log_msg(LOG_WARNING,
     608                 :            :                         "[%s] (stanza #%d) Error setting GPG path %s: %s",
     609                 :          1 :                         spadat->pkt_source_ip, stanza_num, acc->gpg_exe,
     610                 :            :                         fko_errstr(*res)
     611                 :            :                     );
     612                 :          1 :                     return 0;
     613                 :            :                 }
     614                 :            :             }
     615                 :            : 
     616         [ +  - ]:         63 :             if(acc->gpg_home_dir != NULL)
     617                 :            :             {
     618                 :         63 :                 *res = fko_set_gpg_home_dir(*ctx, acc->gpg_home_dir);
     619         [ -  + ]:         63 :                 if(*res != FKO_SUCCESS)
     620                 :            :                 {
     621                 :          0 :                     log_msg(LOG_WARNING,
     622                 :            :                         "[%s] (stanza #%d) Error setting GPG keyring path to %s: %s",
     623                 :          0 :                         spadat->pkt_source_ip, stanza_num, acc->gpg_home_dir,
     624                 :            :                         fko_errstr(*res)
     625                 :            :                     );
     626                 :          0 :                     return 0;
     627                 :            :                 }
     628                 :            :             }
     629                 :            : 
     630         [ +  - ]:         63 :             if(acc->gpg_decrypt_id != NULL)
     631                 :         63 :                 fko_set_gpg_recipient(*ctx, acc->gpg_decrypt_id);
     632                 :            : 
     633                 :            :             /* If GPG_REQUIRE_SIG is set for this acc stanza, then set
     634                 :            :              * the FKO context accordingly and check the other GPG Sig-
     635                 :            :              * related parameters. This also applies when REMOTE_ID is
     636                 :            :              * set.
     637                 :            :             */
     638         [ +  + ]:         63 :             if(acc->gpg_require_sig)
     639                 :            :             {
     640                 :         62 :                 fko_set_gpg_signature_verify(*ctx, 1);
     641                 :            : 
     642                 :            :                 /* Set whether or not to ignore signature verification errors.
     643                 :            :                 */
     644                 :         62 :                 fko_set_gpg_ignore_verify_error(*ctx, acc->gpg_ignore_sig_error);
     645                 :            :             }
     646                 :            :             else
     647                 :            :             {
     648                 :          1 :                 fko_set_gpg_signature_verify(*ctx, 0);
     649                 :          1 :                 fko_set_gpg_ignore_verify_error(*ctx, 1);
     650                 :            :             }
     651                 :            : 
     652                 :            :             /* Now decrypt the data.
     653                 :            :             */
     654                 :         63 :             *res = fko_decrypt_spa_data(*ctx, acc->gpg_decrypt_pw, 0);
     655                 :         63 :             *attempted_decrypt = 1;
     656                 :            :         }
     657                 :            :     }
     658                 :            :     return 1;
     659                 :            : }
     660                 :            : 
     661                 :            : static int
     662                 :       1130 : handle_gpg_sigs(acc_stanza_t *acc, spa_data_t *spadat,
     663                 :            :         fko_ctx_t *ctx, const int enc_type, const int stanza_num, int *res)
     664                 :            : {
     665                 :            :     char                *gpg_id, *gpg_fpr;
     666                 :            :     acc_string_list_t   *gpg_id_ndx;
     667                 :            :     acc_string_list_t   *gpg_fpr_ndx;
     668                 :       1130 :     unsigned char        is_gpg_match = 0;
     669                 :            : 
     670 [ +  + ][ +  + ]:       1130 :     if(enc_type == FKO_ENCRYPTION_GPG && acc->gpg_require_sig)
     671                 :            :     {
     672                 :         55 :         *res = fko_get_gpg_signature_id(*ctx, &gpg_id);
     673         [ -  + ]:         55 :         if(*res != FKO_SUCCESS)
     674                 :            :         {
     675                 :          0 :             log_msg(LOG_WARNING,
     676                 :            :                 "[%s] (stanza #%d) Error pulling the GPG signature ID from the context: %s",
     677                 :          0 :                 spadat->pkt_source_ip, stanza_num, fko_gpg_errstr(*ctx));
     678                 :          0 :             return 0;
     679                 :            :         }
     680                 :            : 
     681                 :         55 :         *res = fko_get_gpg_signature_fpr(*ctx, &gpg_fpr);
     682         [ -  + ]:         55 :         if(*res != FKO_SUCCESS)
     683                 :            :         {
     684                 :          0 :             log_msg(LOG_WARNING,
     685                 :            :                 "[%s] (stanza #%d) Error pulling the GPG fingerprint from the context: %s",
     686                 :          0 :                 spadat->pkt_source_ip, stanza_num, fko_gpg_errstr(*ctx));
     687                 :          0 :             return 0;
     688                 :            :         }
     689                 :            : 
     690                 :         55 :         log_msg(LOG_INFO,
     691                 :            :                 "[%s] (stanza #%d) Incoming SPA data signed by '%s' (fingerprint '%s').",
     692                 :         55 :                 spadat->pkt_source_ip, stanza_num, gpg_id, gpg_fpr);
     693                 :            : 
     694                 :            :         /* prefer GnuPG fingerprint match if so configured
     695                 :            :         */
     696         [ +  + ]:         55 :         if(acc->gpg_remote_fpr != NULL)
     697                 :            :         {
     698                 :          2 :             is_gpg_match = 0;
     699         [ +  + ]:          3 :             for(gpg_fpr_ndx = acc->gpg_remote_fpr_list;
     700                 :          1 :                     gpg_fpr_ndx != NULL; gpg_fpr_ndx=gpg_fpr_ndx->next)
     701                 :            :             {
     702                 :          2 :                 *res = fko_gpg_signature_fpr_match(*ctx,
     703                 :          2 :                         gpg_fpr_ndx->str, &is_gpg_match);
     704         [ -  + ]:          2 :                 if(*res != FKO_SUCCESS)
     705                 :            :                 {
     706                 :          0 :                     log_msg(LOG_WARNING,
     707                 :            :                         "[%s] (stanza #%d) Error in GPG signature comparision: %s",
     708                 :            :                         spadat->pkt_source_ip, stanza_num, fko_gpg_errstr(*ctx));
     709                 :          0 :                     return 0;
     710                 :            :                 }
     711         [ +  + ]:          2 :                 if(is_gpg_match)
     712                 :            :                     break;
     713                 :            :             }
     714         [ +  + ]:          2 :             if(! is_gpg_match)
     715                 :            :             {
     716                 :          1 :                 log_msg(LOG_WARNING,
     717                 :            :                     "[%s] (stanza #%d) Incoming SPA packet signed by: %s, but that fingerprint is not in the GPG_FINGERPRINT_ID list.",
     718                 :            :                     spadat->pkt_source_ip, stanza_num, gpg_fpr);
     719                 :          1 :                 return 0;
     720                 :            :             }
     721                 :            :         }
     722                 :            : 
     723         [ +  + ]:         54 :         if(acc->gpg_remote_id != NULL)
     724                 :            :         {
     725                 :         53 :             is_gpg_match = 0;
     726         [ +  + ]:         54 :             for(gpg_id_ndx = acc->gpg_remote_id_list;
     727                 :          1 :                     gpg_id_ndx != NULL; gpg_id_ndx=gpg_id_ndx->next)
     728                 :            :             {
     729                 :         53 :                 *res = fko_gpg_signature_id_match(*ctx,
     730                 :         53 :                         gpg_id_ndx->str, &is_gpg_match);
     731         [ -  + ]:         53 :                 if(*res != FKO_SUCCESS)
     732                 :            :                 {
     733                 :          0 :                     log_msg(LOG_WARNING,
     734                 :            :                         "[%s] (stanza #%d) Error in GPG signature comparision: %s",
     735                 :            :                         spadat->pkt_source_ip, stanza_num, fko_gpg_errstr(*ctx));
     736                 :          0 :                     return 0;
     737                 :            :                 }
     738         [ +  + ]:         53 :                 if(is_gpg_match)
     739                 :            :                     break;
     740                 :            :             }
     741                 :            : 
     742         [ +  + ]:         53 :             if(! is_gpg_match)
     743                 :            :             {
     744                 :          1 :                 log_msg(LOG_WARNING,
     745                 :            :                     "[%s] (stanza #%d) Incoming SPA packet signed by ID: %s, but that ID is not in the GPG_REMOTE_ID list.",
     746                 :            :                     spadat->pkt_source_ip, stanza_num, gpg_id);
     747                 :          1 :                 return 0;
     748                 :            :             }
     749                 :            :         }
     750                 :            :     }
     751                 :            :     return 1;
     752                 :            : }
     753                 :            : 
     754                 :            : static int
     755                 :       1110 : check_src_access(acc_stanza_t *acc, spa_data_t *spadat, const int stanza_num)
     756                 :            : {
     757         [ +  + ]:       1110 :     if(strcmp(spadat->spa_message_src_ip, "0.0.0.0") == 0)
     758                 :            :     {
     759         [ +  + ]:          7 :         if(acc->require_source_address)
     760                 :            :         {
     761                 :          1 :             log_msg(LOG_WARNING,
     762                 :            :                 "[%s] (stanza #%d) Got 0.0.0.0 when valid source IP was required.",
     763                 :          1 :                 spadat->pkt_source_ip, stanza_num
     764                 :            :             );
     765                 :            :             return 0;
     766                 :            :         }
     767                 :          6 :         spadat->use_src_ip = spadat->pkt_source_ip;
     768                 :            :     }
     769                 :            :     else
     770                 :       1103 :         spadat->use_src_ip = spadat->spa_message_src_ip;
     771                 :            : 
     772                 :            :     return 1;
     773                 :            : }
     774                 :            : 
     775                 :            : static int
     776                 :       1109 : check_username(acc_stanza_t *acc, spa_data_t *spadat, const int stanza_num)
     777                 :            : {
     778         [ +  + ]:       1109 :     if(acc->require_username != NULL)
     779                 :            :     {
     780         [ +  + ]:          2 :         if(strcmp(spadat->username, acc->require_username) != 0)
     781                 :            :         {
     782                 :          1 :             log_msg(LOG_WARNING,
     783                 :            :                 "[%s] (stanza #%d) Username in SPA data (%s) does not match required username: %s",
     784                 :          1 :                 spadat->pkt_source_ip, stanza_num, spadat->username, acc->require_username
     785                 :            :             );
     786                 :            :             return 0;
     787                 :            :         }
     788                 :            :     }
     789                 :            :     return 1;
     790                 :            : }
     791                 :            : 
     792                 :            : static int
     793                 :       1108 : check_nat_access_types(fko_srv_options_t *opts, acc_stanza_t *acc,
     794                 :            :         spa_data_t *spadat, const int stanza_num)
     795                 :            : {
     796         [ +  + ]:       1108 :     if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
     797                 :            :           || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
     798                 :       1108 :           || spadat->message_type == FKO_NAT_ACCESS_MSG
     799         [ +  + ]:        865 :           || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
     800                 :            :     {
     801                 :            : #if FIREWALL_FIREWALLD
     802         [ +  + ]:        316 :         if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1)!=0)
     803                 :            :         {
     804                 :        288 :             log_msg(LOG_WARNING,
     805                 :            :                 "(stanza #%d) SPA packet from %s requested NAT access, but is not enabled",
     806                 :        288 :                 stanza_num, spadat->pkt_source_ip
     807                 :            :             );
     808                 :            :             return 0;
     809                 :            :         }
     810                 :            : #elif FIREWALL_IPTABLES
     811                 :            :         if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)!=0)
     812                 :            :         {
     813                 :            :             log_msg(LOG_WARNING,
     814                 :            :                 "(stanza #%d) SPA packet from %s requested NAT access, but is not enabled",
     815                 :            :                 stanza_num, spadat->pkt_source_ip
     816                 :            :             );
     817                 :            :             return 0;
     818                 :            :         }
     819                 :            : #else
     820                 :            :         log_msg(LOG_WARNING,
     821                 :            :             "(stanza #%d) SPA packet from %s requested unsupported NAT access",
     822                 :            :             stanza_num, spadat->pkt_source_ip
     823                 :            :         );
     824                 :            :         return 0;
     825                 :            : #endif
     826                 :            :     }
     827                 :            :     return 1;
     828                 :            : }
     829                 :            : 
     830                 :            : static int
     831                 :       1130 : add_replay_cache(fko_srv_options_t *opts, acc_stanza_t *acc,
     832                 :            :         spa_data_t *spadat, char *raw_digest, int *added_replay_digest,
     833                 :            :         const int stanza_num, int *res)
     834                 :            : {
     835 [ +  + ][ +  + ]:       1130 :     if (!opts->test && *added_replay_digest == 0
     836         [ +  - ]:        341 :             && strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
     837                 :            :     {
     838                 :            : 
     839                 :        341 :         *res = add_replay(opts, raw_digest);
     840         [ -  + ]:        341 :         if (*res != SPA_MSG_SUCCESS)
     841                 :            :         {
     842                 :          0 :             log_msg(LOG_WARNING, "[%s] (stanza #%d) Could not add digest to replay cache",
     843                 :          0 :                 spadat->pkt_source_ip, stanza_num);
     844                 :            :             return 0;
     845                 :            :         }
     846                 :        341 :         *added_replay_digest = 1;
     847                 :            :     }
     848                 :            : 
     849                 :            :     return 1;
     850                 :            : }
     851                 :            : 
     852                 :            : static void
     853                 :       2224 : set_timeout(acc_stanza_t *acc, spa_data_t *spadat)
     854                 :            : {
     855         [ +  + ]:       1112 :     if(spadat->client_timeout > 0)
     856                 :        175 :         spadat->fw_access_timeout = spadat->client_timeout;
     857         [ +  - ]:        937 :     else if(acc->fw_access_timeout > 0)
     858                 :        937 :         spadat->fw_access_timeout = acc->fw_access_timeout;
     859                 :            :     else
     860                 :          0 :         spadat->fw_access_timeout = DEF_FW_ACCESS_TIMEOUT;
     861                 :       1112 :     return;
     862                 :            : }
     863                 :            : 
     864                 :            : static int
     865                 :        601 : check_port_proto(acc_stanza_t *acc, spa_data_t *spadat, const int stanza_num)
     866                 :            : {
     867         [ +  + ]:        601 :     if(! acc_check_port_access(acc, spadat->spa_message_remain))
     868                 :            :     {
     869                 :          3 :         log_msg(LOG_WARNING,
     870                 :            :             "[%s] (stanza #%d) One or more requested protocol/ports was denied per access.conf.",
     871                 :          3 :             spadat->pkt_source_ip, stanza_num
     872                 :            :         );
     873                 :          3 :         return 0;
     874                 :            :     }
     875                 :            :     return 1;
     876                 :            : }
     877                 :            : 
     878                 :            : /* Process the SPA packet data
     879                 :            : */
     880                 :            : void
     881                 :      17337 : incoming_spa(fko_srv_options_t *opts)
     882                 :            : {
     883                 :            :     /* Always a good idea to initialize ctx to null if it will be used
     884                 :            :      * repeatedly (especially when using fko_new_with_data()).
     885                 :            :     */
     886                 :      17337 :     fko_ctx_t       ctx = NULL;
     887                 :            : 
     888                 :      17337 :     char            *spa_ip_demark, *raw_digest = NULL;
     889                 :      17337 :     int             res, enc_type, stanza_num=0;
     890                 :      17337 :     int             added_replay_digest = 0;
     891                 :      17337 :     int             is_err, cmd_exec_success = 0, attempted_decrypt = 0;
     892                 :      17337 :     int             conf_pkt_age = 0;
     893                 :            :     char            dump_buf[CTX_DUMP_BUFSIZE];
     894                 :            : 
     895                 :      17337 :     spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
     896                 :            : 
     897                 :            :     /* This will hold our pertinent SPA data.
     898                 :            :     */
     899                 :            :     spa_data_t spadat;
     900                 :            : 
     901                 :            :     /* Loop through all access stanzas looking for a match
     902                 :            :     */
     903                 :      17337 :     acc_stanza_t        *acc = opts->acc_stanzas;
     904                 :            : 
     905                 :      17337 :     inet_ntop(AF_INET, &(spa_pkt->packet_src_ip),
     906                 :            :         spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip));
     907                 :            : 
     908                 :      17337 :     inet_ntop(AF_INET, &(spa_pkt->packet_dst_ip),
     909                 :            :         spadat.pkt_destination_ip, sizeof(spadat.pkt_destination_ip));
     910                 :            : 
     911                 :            :     /* At this point, we want to validate and (if needed) preprocess the
     912                 :            :      * SPA data and/or to be reasonably sure we have a SPA packet (i.e
     913                 :            :      * try to eliminate obvious non-spa packets).
     914                 :            :     */
     915         [ +  + ]:      17337 :     if(!precheck_pkt(opts, spa_pkt, &spadat, &raw_digest))
     916                 :            :         return;
     917                 :            : 
     918         [ +  + ]:      17282 :     if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0)
     919                 :            :     {
     920                 :        312 :         conf_pkt_age = strtol_wrapper(opts->config[CONF_MAX_SPA_PACKET_AGE],
     921                 :            :                 0, RCHK_MAX_SPA_PACKET_AGE, NO_EXIT_UPON_ERR, &is_err);
     922         [ +  - ]:        312 :         if(is_err != FKO_SUCCESS)
     923                 :            :         {
     924                 :          0 :             log_msg(LOG_ERR, "[*] [%s] invalid MAX_SPA_PACKET_AGE", spadat.pkt_source_ip);
     925                 :          0 :             return;
     926                 :            :         }
     927                 :            :     }
     928                 :            : 
     929                 :            :     /* Now that we know there is a matching access.conf stanza and the
     930                 :            :      * incoming SPA packet is not a replay, see if we should grant any
     931                 :            :      * access
     932                 :            :     */
     933         [ +  + ]:      33634 :     while(acc)
     934                 :            :     {
     935                 :      16979 :         res = FKO_SUCCESS;
     936                 :      16979 :         cmd_exec_success  = 0;
     937                 :      16979 :         attempted_decrypt = 0;
     938                 :      16979 :         stanza_num++;
     939                 :            : 
     940                 :            :         /* Start access loop with a clean FKO context
     941                 :            :         */
     942         [ +  + ]:      16979 :         if(ctx != NULL)
     943                 :            :         {
     944         [ -  + ]:          2 :             if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
     945                 :          0 :                 log_msg(LOG_WARNING,
     946                 :            :                     "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
     947                 :            :                     spadat.pkt_source_ip, stanza_num
     948                 :            :                 );
     949                 :          2 :             ctx = NULL;
     950                 :            :         }
     951                 :            : 
     952                 :            :         /* Check for a match for the SPA source and destination IP and the access stanza
     953                 :            :         */
     954         [ +  + ]:      16979 :         if(! src_dst_check(acc, spa_pkt, &spadat, stanza_num))
     955                 :            :         {
     956                 :          6 :             acc = acc->next;
     957                 :          6 :             continue;
     958                 :            :         }
     959                 :            : 
     960                 :      16973 :         log_msg(LOG_INFO, "(stanza #%d) SPA Packet from IP: %s received with access source match",
     961                 :            :             stanza_num, spadat.pkt_source_ip);
     962                 :            : 
     963                 :      16973 :         log_msg(LOG_DEBUG, "SPA Packet: '%s'", spa_pkt->packet_data);
     964                 :            : 
     965                 :            :         /* Make sure this access stanza has not expired
     966                 :            :         */
     967         [ +  + ]:      16973 :         if(! check_stanza_expiration(acc, &spadat, stanza_num))
     968                 :            :         {
     969                 :          2 :             acc = acc->next;
     970                 :          2 :             continue;
     971                 :            :         }
     972                 :            : 
     973                 :            :         /* Get encryption type and try its decoding routine first (if the key
     974                 :            :          * for that type is set)
     975                 :            :         */
     976                 :      16971 :         enc_type = fko_encryption_type((char *)spa_pkt->packet_data);
     977                 :            : 
     978         [ -  + ]:      16971 :         if(! handle_rijndael_enc(acc, spa_pkt, &spadat, &ctx,
     979                 :            :                     &attempted_decrypt, &cmd_exec_success, enc_type,
     980                 :            :                     stanza_num, &res))
     981                 :            :         {
     982                 :          0 :             acc = acc->next;
     983                 :          0 :             continue;
     984                 :            :         }
     985                 :            : 
     986         [ +  + ]:      16971 :         if(! handle_gpg_enc(acc, spa_pkt, &spadat, &ctx, &attempted_decrypt,
     987                 :            :                     cmd_exec_success, enc_type, stanza_num, &res))
     988                 :            :         {
     989                 :          1 :             acc = acc->next;
     990                 :          1 :             continue;
     991                 :            :         }
     992                 :            : 
     993         [ +  + ]:      16970 :         if(! check_mode_ctx(&spadat, &ctx, attempted_decrypt,
     994                 :            :                     enc_type, stanza_num, res))
     995                 :            :         {
     996                 :      15840 :             acc = acc->next;
     997                 :      15840 :             continue;
     998                 :            :         }
     999                 :            : 
    1000                 :            :         /* Add this SPA packet into the replay detection cache
    1001                 :            :         */
    1002         [ -  + ]:       1130 :         if(! add_replay_cache(opts, acc, &spadat, raw_digest,
    1003                 :            :                     &added_replay_digest, stanza_num, &res))
    1004                 :            :         {
    1005                 :          0 :             acc = acc->next;
    1006                 :          0 :             continue;
    1007                 :            :         }
    1008                 :            : 
    1009                 :            :         /* At this point the SPA data is authenticated via the HMAC (if used
    1010                 :            :          * for now). Next we need to see if it meets our access criteria which
    1011                 :            :          * the server imposes regardless of the content of the SPA packet.
    1012                 :            :         */
    1013                 :       1130 :         log_msg(LOG_DEBUG, "[%s] (stanza #%d) SPA Decode (res=%i):",
    1014                 :            :             spadat.pkt_source_ip, stanza_num, res);
    1015                 :            : 
    1016                 :       1130 :         res = dump_ctx_to_buffer(ctx, dump_buf, sizeof(dump_buf));
    1017         [ +  + ]:       1130 :         if (res == FKO_SUCCESS)
    1018                 :       1110 :             log_msg(LOG_DEBUG, "%s", dump_buf);
    1019                 :            :         else
    1020                 :         20 :             log_msg(LOG_WARNING, "Unable to dump FKO context: %s", fko_errstr(res));
    1021                 :            : 
    1022                 :            :         /* First, if this is a GPG message, and GPG_REMOTE_ID list is not empty,
    1023                 :            :          * then we need to make sure this incoming message is signer ID matches
    1024                 :            :          * an entry in the list.
    1025                 :            :         */
    1026                 :            : 
    1027         [ +  + ]:       1130 :         if(! handle_gpg_sigs(acc, &spadat, &ctx, enc_type, stanza_num, &res))
    1028                 :            :         {
    1029                 :          2 :             acc = acc->next;
    1030                 :          2 :             continue;
    1031                 :            :         }
    1032                 :            : 
    1033                 :            :         /* Populate our spa data struct for future reference.
    1034                 :            :         */
    1035                 :       1128 :         res = get_spa_data_fields(ctx, &spadat);
    1036                 :            : 
    1037         [ +  + ]:       1128 :         if(res != FKO_SUCCESS)
    1038                 :            :         {
    1039                 :         16 :             log_msg(LOG_ERR, "[%s] (stanza #%d) Unexpected error pulling SPA data from the context: %s",
    1040                 :            :                 spadat.pkt_source_ip, stanza_num, fko_errstr(res));
    1041                 :            : 
    1042                 :         16 :             acc = acc->next;
    1043                 :         16 :             continue;
    1044                 :            :         }
    1045                 :            : 
    1046                 :            :         /* Figure out what our timeout will be. If it is specified in the SPA
    1047                 :            :          * data, then use that.  If not, try the FW_ACCESS_TIMEOUT from the
    1048                 :            :          * access.conf file (if there is one).  Otherwise use the default.
    1049                 :            :         */
    1050                 :       1112 :         set_timeout(acc, &spadat);
    1051                 :            : 
    1052                 :            :         /* Check packet age if so configured.
    1053                 :            :         */
    1054         [ +  + ]:       1112 :         if(! check_pkt_age(opts, &spadat, stanza_num, conf_pkt_age))
    1055                 :            :         {
    1056                 :          2 :             acc = acc->next;
    1057                 :          2 :             continue;
    1058                 :            :         }
    1059                 :            : 
    1060                 :            :         /* At this point, we have enough to check the embedded (or packet source)
    1061                 :            :          * IP address against the defined access rights.  We start by splitting
    1062                 :            :          * the spa msg source IP from the remainder of the message.
    1063                 :            :         */
    1064                 :       1110 :         spa_ip_demark = strchr(spadat.spa_message, ',');
    1065         [ -  + ]:       1110 :         if(spa_ip_demark == NULL)
    1066                 :            :         {
    1067                 :          0 :             log_msg(LOG_WARNING, "[%s] (stanza #%d) Error parsing SPA message string: %s",
    1068                 :            :                 spadat.pkt_source_ip, stanza_num, fko_errstr(res));
    1069                 :            : 
    1070                 :          0 :             acc = acc->next;
    1071                 :          0 :             continue;
    1072                 :            :         }
    1073                 :            : 
    1074         [ -  + ]:       1110 :         if((spa_ip_demark-spadat.spa_message) < MIN_IPV4_STR_LEN-1
    1075                 :       1110 :                 || (spa_ip_demark-spadat.spa_message) > MAX_IPV4_STR_LEN)
    1076                 :            :         {
    1077                 :          0 :             log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
    1078                 :            :                 spadat.pkt_source_ip, stanza_num);
    1079                 :          0 :             break;
    1080                 :            :         }
    1081                 :            : 
    1082                 :       1110 :         strlcpy(spadat.spa_message_src_ip,
    1083                 :       1110 :             spadat.spa_message, (spa_ip_demark-spadat.spa_message)+1);
    1084                 :            : 
    1085         [ -  + ]:       1110 :         if(! is_valid_ipv4_addr(spadat.spa_message_src_ip))
    1086                 :            :         {
    1087                 :          0 :             log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
    1088                 :            :                 spadat.pkt_source_ip, stanza_num, fko_errstr(res));
    1089                 :          0 :             break;
    1090                 :            :         }
    1091                 :            : 
    1092                 :       1110 :         strlcpy(spadat.spa_message_remain, spa_ip_demark+1, MAX_DECRYPTED_SPA_LEN);
    1093                 :            : 
    1094                 :            :         /* If use source IP was requested (embedded IP of 0.0.0.0), make sure it
    1095                 :            :          * is allowed.
    1096                 :            :         */
    1097         [ +  + ]:       1110 :         if(! check_src_access(acc, &spadat, stanza_num))
    1098                 :            :         {
    1099                 :          1 :             acc = acc->next;
    1100                 :          1 :             continue;
    1101                 :            :         }
    1102                 :            : 
    1103                 :            :         /* If REQUIRE_USERNAME is set, make sure the username in this SPA data
    1104                 :            :          * matches.
    1105                 :            :         */
    1106         [ +  + ]:       1109 :         if(! check_username(acc, &spadat, stanza_num))
    1107                 :            :         {
    1108                 :          1 :             acc = acc->next;
    1109                 :          1 :             continue;
    1110                 :            :         }
    1111                 :            : 
    1112                 :            :         /* Take action based on SPA message type.
    1113                 :            :         */
    1114         [ +  + ]:       1108 :         if(! check_nat_access_types(opts, acc, &spadat, stanza_num))
    1115                 :            :         {
    1116                 :        288 :             acc = acc->next;
    1117                 :        288 :             continue;
    1118                 :            :         }
    1119                 :            : 
    1120                 :            :         /* Command messages.
    1121                 :            :         */
    1122         [ +  + ]:        820 :         if(spadat.message_type == FKO_COMMAND_MSG)
    1123                 :            :         {
    1124         [ +  + ]:        219 :             if(process_cmd_msg(opts, acc, &spadat, stanza_num, &res))
    1125                 :            :             {
    1126                 :            :                 /* we processed the command on a matching access stanza, so we
    1127                 :            :                  * don't look for anything else to do with this SPA packet
    1128                 :            :                 */
    1129                 :            :                 break;
    1130                 :            :             }
    1131                 :            :             else
    1132                 :            :             {
    1133                 :        200 :                 acc = acc->next;
    1134                 :        200 :                 continue;
    1135                 :            :             }
    1136                 :            :         }
    1137                 :            : 
    1138                 :            :         /* From this point forward, we have some kind of access message. So
    1139                 :            :          * we first see if access is allowed by checking access against
    1140                 :            :          * restrict_ports and open_ports.
    1141                 :            :          *
    1142                 :            :          *  --DSS TODO: We should add BLACKLIST support here as well.
    1143                 :            :         */
    1144         [ +  + ]:        601 :         if(! check_port_proto(acc, &spadat, stanza_num))
    1145                 :            :         {
    1146                 :          3 :             acc = acc->next;
    1147                 :          3 :             continue;
    1148                 :            :         }
    1149                 :            : 
    1150                 :            :         /* At this point, we process the SPA request and break out of the
    1151                 :            :          * access stanza loop (first valid access stanza stops us looking
    1152                 :            :          * for others).
    1153                 :            :         */
    1154         [ +  + ]:        598 :         if(opts->test)  /* no firewall changes in --test mode */
    1155                 :            :         {
    1156                 :        302 :             log_msg(LOG_WARNING,
    1157                 :            :                 "[%s] (stanza #%d) --test mode enabled, skipping firewall manipulation.",
    1158                 :            :                 spadat.pkt_source_ip, stanza_num
    1159                 :            :             );
    1160                 :        302 :             acc = acc->next;
    1161                 :        302 :             continue;
    1162                 :            :         }
    1163                 :            :         else
    1164                 :            :         {
    1165                 :        296 :             process_spa_request(opts, acc, &spadat);
    1166                 :            :         }
    1167                 :            : 
    1168                 :            :         /* If we made it here, then the SPA packet was processed according
    1169                 :            :          * to a matching access.conf stanza, so we're done with this packet.
    1170                 :            :         */
    1171                 :      16960 :         break;
    1172                 :            :     }
    1173                 :            : 
    1174         [ +  - ]:      16970 :     if (raw_digest != NULL)
    1175                 :      16970 :         free(raw_digest);
    1176                 :            : 
    1177         [ +  + ]:      16970 :     if(ctx != NULL)
    1178                 :            :     {
    1179         [ -  + ]:       1136 :         if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
    1180                 :          0 :             log_msg(LOG_WARNING,
    1181                 :            :                 "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
    1182                 :            :                 spadat.pkt_source_ip, stanza_num
    1183                 :            :             );
    1184                 :       1136 :         ctx = NULL;
    1185                 :            :     }
    1186                 :            : 
    1187                 :            :     return;
    1188                 :            : }
    1189                 :            : 
    1190                 :            : /***EOF***/

Generated by: LCOV version 1.10