merged usage() information from master
This commit is contained in:
+127
-25
@@ -110,6 +110,64 @@ preprocess_spa_data(fko_srv_options_t *opts, const char *src_ip)
|
||||
return(FKO_SUCCESS);
|
||||
}
|
||||
|
||||
/* For replay attack detection
|
||||
*/
|
||||
static int
|
||||
get_raw_digest(char **digest, char *pkt_data)
|
||||
{
|
||||
fko_ctx_t ctx = NULL;
|
||||
char *tmp_digest = NULL;
|
||||
int res = FKO_SUCCESS;
|
||||
|
||||
/* initialize an FKO context with no decryption key just so
|
||||
* we can get the outer message digest
|
||||
*/
|
||||
res = fko_new_with_data(&ctx, (char *)pkt_data, NULL);
|
||||
if(res != FKO_SUCCESS)
|
||||
{
|
||||
log_msg(LOG_WARNING, "Error initializing FKO context from SPA data: %s",
|
||||
fko_errstr(res));
|
||||
fko_destroy(ctx);
|
||||
return(SPA_MSG_FKO_CTX_ERROR);
|
||||
}
|
||||
|
||||
res = fko_set_raw_spa_digest_type(ctx, FKO_DEFAULT_DIGEST);
|
||||
if(res != FKO_SUCCESS)
|
||||
{
|
||||
log_msg(LOG_WARNING, "Error setting digest type for SPA data: %s",
|
||||
fko_errstr(res));
|
||||
fko_destroy(ctx);
|
||||
return(SPA_MSG_DIGEST_ERROR);
|
||||
}
|
||||
|
||||
res = fko_set_raw_spa_digest(ctx);
|
||||
if(res != FKO_SUCCESS)
|
||||
{
|
||||
log_msg(LOG_WARNING, "Error setting digest for SPA data: %s",
|
||||
fko_errstr(res));
|
||||
fko_destroy(ctx);
|
||||
return(SPA_MSG_DIGEST_ERROR);
|
||||
}
|
||||
|
||||
res = fko_get_raw_spa_digest(ctx, &tmp_digest);
|
||||
if(res != FKO_SUCCESS)
|
||||
{
|
||||
log_msg(LOG_WARNING, "Error getting digest from SPA data: %s",
|
||||
fko_errstr(res));
|
||||
fko_destroy(ctx);
|
||||
return(SPA_MSG_DIGEST_ERROR);
|
||||
}
|
||||
|
||||
*digest = strdup(tmp_digest);
|
||||
|
||||
if (digest == NULL)
|
||||
return SPA_MSG_ERROR;
|
||||
|
||||
fko_destroy(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Popluate a spa_data struct from an initialized (and populated) FKO context.
|
||||
*/
|
||||
static int
|
||||
@@ -152,6 +210,22 @@ get_spa_data_fields(fko_ctx_t ctx, spa_data_t *spdat)
|
||||
return(res);
|
||||
}
|
||||
|
||||
/* Check for access.conf stanza SOURCE match based on SPA packet
|
||||
* source IP
|
||||
*/
|
||||
static int
|
||||
is_src_match(acc_stanza_t *acc, const uint32_t ip)
|
||||
{
|
||||
while (acc)
|
||||
{
|
||||
if(compare_addr_list(acc->source_list, ip))
|
||||
return 1;
|
||||
|
||||
acc = acc->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Process the SPA packet data
|
||||
*/
|
||||
void
|
||||
@@ -162,9 +236,10 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
*/
|
||||
fko_ctx_t ctx = NULL;
|
||||
|
||||
char *spa_ip_demark, *gpg_id;
|
||||
char *spa_ip_demark, *gpg_id, *raw_digest = NULL;
|
||||
time_t now_ts;
|
||||
int res, status, ts_diff, enc_type, found_acc_sip=0, stanza_num=0;
|
||||
int res, status, ts_diff, enc_type, stanza_num=0;
|
||||
int added_replay_digest = 0;
|
||||
|
||||
spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
|
||||
|
||||
@@ -192,6 +267,36 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_src_match(opts->acc_stanzas, ntohl(spa_pkt->packet_src_ip)))
|
||||
{
|
||||
if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
|
||||
/* Check for a replay attack
|
||||
*/
|
||||
res = get_raw_digest(&raw_digest, (char *)spa_pkt->packet_data);
|
||||
if(res != FKO_SUCCESS)
|
||||
{
|
||||
if (raw_digest != NULL)
|
||||
free(raw_digest);
|
||||
return;
|
||||
}
|
||||
if (raw_digest == NULL)
|
||||
return;
|
||||
|
||||
if (is_replay(opts, raw_digest) != SPA_MSG_SUCCESS)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_msg(LOG_WARNING,
|
||||
"No access data found for source IP: %s", spadat.pkt_source_ip
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now that we know there is a matching access.conf stanza and the
|
||||
* incoming SPA packet is not a replay, see if we should grant any
|
||||
* access
|
||||
*/
|
||||
while(acc)
|
||||
{
|
||||
stanza_num++;
|
||||
@@ -204,8 +309,6 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
continue;
|
||||
}
|
||||
|
||||
found_acc_sip = 1;
|
||||
|
||||
log_msg(LOG_INFO, "(stanza #%d) SPA Packet from IP: %s received with access source match",
|
||||
stanza_num, spadat.pkt_source_ip);
|
||||
|
||||
@@ -332,7 +435,7 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Do we have a valid FKO context?
|
||||
/* Do we have a valid FKO context? Did the SPA decrypt properly?
|
||||
*/
|
||||
if(res != FKO_SUCCESS)
|
||||
{
|
||||
@@ -349,6 +452,23 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add this SPA packet into the replay detection cache
|
||||
*/
|
||||
if (! added_replay_digest)
|
||||
{
|
||||
res = add_replay(opts, raw_digest);
|
||||
if (res != SPA_MSG_SUCCESS)
|
||||
{
|
||||
log_msg(LOG_WARNING, "(stanza #%d) Could not add digest to replay cache",
|
||||
stanza_num);
|
||||
if(ctx != NULL)
|
||||
fko_destroy(ctx);
|
||||
acc = acc->next;
|
||||
continue;
|
||||
}
|
||||
added_replay_digest = 1;
|
||||
}
|
||||
|
||||
/* At this point, we assume the SPA data is valid. Now we need to see
|
||||
* if it meets our access criteria.
|
||||
*/
|
||||
@@ -389,20 +509,6 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for replays if so configured.
|
||||
*/
|
||||
if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
|
||||
{
|
||||
res = replay_check(opts, ctx);
|
||||
if(res != 0) /* non-zero means we have seen this packet before. */
|
||||
{
|
||||
if(ctx != NULL)
|
||||
fko_destroy(ctx);
|
||||
acc = acc->next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate our spa data struct for future reference.
|
||||
*/
|
||||
res = get_spa_data_fields(ctx, &spadat);
|
||||
@@ -636,12 +742,8 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
break;
|
||||
}
|
||||
|
||||
if(! found_acc_sip)
|
||||
{
|
||||
log_msg(LOG_WARNING,
|
||||
"No access data found for source IP: %s", spadat.pkt_source_ip
|
||||
);
|
||||
}
|
||||
if (raw_digest != NULL)
|
||||
free(raw_digest);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+100
-40
@@ -420,44 +420,45 @@ replay_db_cache_init(fko_srv_options_t *opts)
|
||||
#endif /* USE_FILE_CACHE */
|
||||
|
||||
/* Take an fko context, pull the digest and use it as the key to check the
|
||||
* replay db (digest cache). Returns 1 if there was a match (a replay),
|
||||
* 0 for no match, and -1 on error.
|
||||
* replay db (digest cache).
|
||||
*/
|
||||
int
|
||||
replay_check(fko_srv_options_t *opts, fko_ctx_t ctx)
|
||||
is_replay(fko_srv_options_t *opts, char *digest)
|
||||
{
|
||||
#ifdef NO_DIGEST_CACHE
|
||||
return(-1);
|
||||
#else
|
||||
|
||||
#if USE_FILE_CACHE
|
||||
return replay_check_file_cache(opts, ctx);
|
||||
return is_replay_file_cache(opts, digest);
|
||||
#else
|
||||
return replay_check_dbm_cache(opts, ctx);
|
||||
return is_replay_dbm_cache(opts, digest);
|
||||
#endif
|
||||
#endif /* NO_DIGEST_CACHE */
|
||||
}
|
||||
|
||||
int
|
||||
add_replay(fko_srv_options_t *opts, char *digest)
|
||||
{
|
||||
#ifdef NO_DIGEST_CACHE
|
||||
return(-1);
|
||||
#else
|
||||
|
||||
#if USE_FILE_CACHE
|
||||
return add_replay_file_cache(opts, digest);
|
||||
#else
|
||||
return add_replay_dbm_cache(opts, digest);
|
||||
#endif
|
||||
#endif /* NO_DIGEST_CACHE */
|
||||
}
|
||||
|
||||
#if USE_FILE_CACHE
|
||||
int
|
||||
replay_check_file_cache(fko_srv_options_t *opts, fko_ctx_t ctx)
|
||||
is_replay_file_cache(fko_srv_options_t *opts, char *digest)
|
||||
{
|
||||
char *digest = NULL;
|
||||
char src_ip[INET_ADDRSTRLEN+1] = {0};
|
||||
char dst_ip[INET_ADDRSTRLEN+1] = {0};
|
||||
int res = 0, digest_len = 0;
|
||||
FILE *digest_file_ptr = NULL;
|
||||
int digest_len = 0;
|
||||
|
||||
struct digest_cache_list *digest_list_ptr = NULL, *digest_elm = NULL;
|
||||
|
||||
res = fko_get_spa_digest(ctx, &digest);
|
||||
if(res != FKO_SUCCESS)
|
||||
{
|
||||
log_msg(LOG_WARNING, "Error getting digest from SPA data: %s",
|
||||
fko_errstr(res));
|
||||
|
||||
return(SPA_MSG_DIGEST_ERROR);
|
||||
}
|
||||
struct digest_cache_list *digest_list_ptr = NULL;
|
||||
|
||||
digest_len = strlen(digest);
|
||||
|
||||
@@ -474,11 +475,21 @@ replay_check_file_cache(fko_srv_options_t *opts, fko_ctx_t ctx)
|
||||
return(SPA_MSG_REPLAY);
|
||||
}
|
||||
}
|
||||
return(SPA_MSG_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
add_replay_file_cache(fko_srv_options_t *opts, char *digest)
|
||||
{
|
||||
FILE *digest_file_ptr = NULL;
|
||||
int digest_len = 0;
|
||||
char src_ip[INET_ADDRSTRLEN+1] = {0};
|
||||
char dst_ip[INET_ADDRSTRLEN+1] = {0};
|
||||
|
||||
struct digest_cache_list *digest_elm = NULL;
|
||||
|
||||
digest_len = strlen(digest);
|
||||
|
||||
/* If we make it here, then this is a new SPA packet that needs to be
|
||||
* added to the cache. We've already decrypted the data, so we know that
|
||||
* the contents are valid.
|
||||
*/
|
||||
if ((digest_elm = calloc(1, sizeof(struct digest_cache_list))) == NULL)
|
||||
{
|
||||
log_msg(LOG_WARNING, "Error calloc() returned NULL for digest cache element",
|
||||
@@ -537,7 +548,7 @@ replay_check_file_cache(fko_srv_options_t *opts, fko_ctx_t ctx)
|
||||
|
||||
#if !USE_FILE_CACHE
|
||||
int
|
||||
replay_check_dbm_cache(fko_srv_options_t *opts, fko_ctx_t ctx)
|
||||
is_replay_dbm_cache(fko_srv_options_t *opts, char *digest)
|
||||
{
|
||||
#ifdef NO_DIGEST_CACHE
|
||||
return 0;
|
||||
@@ -550,20 +561,11 @@ replay_check_dbm_cache(fko_srv_options_t *opts, fko_ctx_t ctx)
|
||||
#endif
|
||||
datum db_key, db_ent;
|
||||
|
||||
char *digest;
|
||||
int digest_len, res;
|
||||
char *digest = NULL;
|
||||
int digest_len, res = SPA_MSG_SUCCESS;
|
||||
|
||||
digest_cache_info_t dc_info;
|
||||
|
||||
res = fko_get_spa_digest(ctx, &digest);
|
||||
if(res != FKO_SUCCESS)
|
||||
{
|
||||
log_msg(LOG_WARNING, "Error getting digest from SPA data: %s",
|
||||
fko_errstr(res));
|
||||
|
||||
return(SPA_MSG_DIGEST_ERROR);
|
||||
}
|
||||
|
||||
digest_len = strlen(digest);
|
||||
|
||||
db_key.dptr = digest;
|
||||
@@ -609,9 +611,65 @@ replay_check_dbm_cache(fko_srv_options_t *opts, fko_ctx_t ctx)
|
||||
#ifdef HAVE_LIBGDBM
|
||||
free(db_ent.dptr);
|
||||
#endif
|
||||
|
||||
res = SPA_MSG_REPLAY;
|
||||
} else {
|
||||
}
|
||||
|
||||
MY_DBM_CLOSE(rpdb);
|
||||
|
||||
return(res);
|
||||
#endif /* NO_DIGEST_CACHE */
|
||||
}
|
||||
|
||||
int
|
||||
add_replay_dbm_cache(fko_srv_options_t *opts, char *digest)
|
||||
{
|
||||
#ifdef NO_DIGEST_CACHE
|
||||
return 0;
|
||||
#else
|
||||
|
||||
#ifdef HAVE_LIBGDBM
|
||||
GDBM_FILE rpdb;
|
||||
#elif HAVE_LIBNDBM
|
||||
DBM *rpdb;
|
||||
#endif
|
||||
datum db_key, db_ent;
|
||||
|
||||
char *digest = NULL;
|
||||
int digest_len, res = SPA_MSG_SUCCESS;
|
||||
|
||||
digest_cache_info_t dc_info;
|
||||
|
||||
digest_len = strlen(digest);
|
||||
|
||||
db_key.dptr = digest;
|
||||
db_key.dsize = digest_len;
|
||||
|
||||
/* Check the db for the key
|
||||
*/
|
||||
#ifdef HAVE_LIBGDBM
|
||||
rpdb = gdbm_open(
|
||||
opts->config[CONF_DIGEST_DB_FILE], 512, GDBM_WRCREAT, S_IRUSR|S_IWUSR, 0
|
||||
);
|
||||
#elif HAVE_LIBNDBM
|
||||
rpdb = dbm_open(opts->config[CONF_DIGEST_DB_FILE], O_RDWR, 0);
|
||||
#endif
|
||||
|
||||
if(!rpdb)
|
||||
{
|
||||
log_msg(LOG_WARNING, "Error opening digest_cache: '%s': %s",
|
||||
opts->config[CONF_DIGEST_DB_FILE],
|
||||
MY_DBM_STRERROR(errno)
|
||||
);
|
||||
|
||||
return(SPA_MSG_DIGEST_CACHE_ERROR);
|
||||
}
|
||||
|
||||
db_ent = MY_DBM_FETCH(rpdb, db_key);
|
||||
|
||||
/* If the datum is null, we have a new entry.
|
||||
*/
|
||||
if(db_ent.dptr == NULL)
|
||||
{
|
||||
/* This is a new SPA packet that needs to be added to the cache.
|
||||
*/
|
||||
dc_info.src_ip = opts->spa_pkt.packet_src_ip;
|
||||
@@ -636,12 +694,14 @@ replay_check_dbm_cache(fko_srv_options_t *opts, fko_ctx_t ctx)
|
||||
|
||||
res = SPA_MSG_SUCCESS;
|
||||
}
|
||||
else
|
||||
res = SPA_MSG_DIGEST_CACHE_ERROR;
|
||||
|
||||
MY_DBM_CLOSE(rpdb);
|
||||
|
||||
return(res);
|
||||
#endif /* NO_DIGEST_CACHE */
|
||||
}
|
||||
|
||||
#endif /* USE_FILE_CACHE */
|
||||
|
||||
#if USE_FILE_CACHE
|
||||
|
||||
@@ -59,14 +59,17 @@ struct digest_cache_list {
|
||||
/* Prototypes
|
||||
*/
|
||||
int replay_cache_init(fko_srv_options_t *opts);
|
||||
int replay_check(fko_srv_options_t *opts, fko_ctx_t ctx);
|
||||
int is_replay(fko_srv_options_t *opts, char *digest);
|
||||
int add_replay(fko_srv_options_t *opts, char *digest);
|
||||
#ifdef USE_FILE_CACHE
|
||||
int replay_file_cache_init(fko_srv_options_t *opts);
|
||||
int replay_check_file_cache(fko_srv_options_t *opts, fko_ctx_t ctx);
|
||||
int is_replay_file_cache(fko_srv_options_t *opts, char *digest);
|
||||
int add_replay_file_cache(fko_srv_options_t *opts, char *digest);
|
||||
void free_replay_list(fko_srv_options_t *opts);
|
||||
#else
|
||||
int replay_db_cache_init(fko_srv_options_t *opts);
|
||||
int replay_check_dbm_cache(fko_srv_options_t *opts, fko_ctx_t ctx);
|
||||
int is_replay_dbm_cache(fko_srv_options_t *opts, char *digest);
|
||||
int add_replay_dbm_cache(fko_srv_options_t *opts, char *digest);
|
||||
#endif
|
||||
|
||||
#endif /* REPLAY_CACHE_H */
|
||||
|
||||
Reference in New Issue
Block a user