blob: a24c0b20d83ef52c790c82322f73b6e07e4f45f9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <axutil_utils.h>
#include <axutil_linked_list.h>
#include <rampart_replay_detector.h>
#include <axutil_property.h>
#include <rampart_constants.h>
#include <rampart_sec_processed_result.h>
#include <rampart_util.h>
#include <stdlib.h>
#define BUFFER_LEN 10000
#define DELIMIT 16
#define INDICATOR_FILE "/indicator"
#define REPLAY_FILE "/replay.content"
static axis2_char_t *
rampart_replay_detector_file_dir(
const axutil_env_t* env)
{
#ifdef WIN32
char* axis_home = getenv("AXIS2C_HOME");
if (axis_home)
return axutil_strdup(env, axis_home);
else
return axutil_strdup(env, "c:\\logs\\");
#else
return axutil_strdup(env, "/tmp/");
#endif
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
rampart_replay_detector_free(
rampart_replay_detector_t *rrd,
const axutil_env_t* env)
{
if (rrd)
{
if (rrd->ops)
{
AXIS2_FREE(env->allocator, rrd->ops);
}
AXIS2_FREE(env->allocator, rrd);
}
return AXIS2_SUCCESS;
}
static axis2_status_t
rampart_replay_detector_read_file(
const axutil_env_t *env,
axutil_linked_list_t* ll)
{
FILE* temp_file = NULL;
FILE* file = NULL;
axis2_char_t buffer[sizeof(axis2_char_t) * (BUFFER_LEN + 1)];
int ch_read = 0;
char* key = NULL;
axis2_char_t *file_dir = NULL;
axis2_char_t *file_name = NULL;
char dilim[2];
dilim[0] = DELIMIT;
dilim[1] = 0;
/*
* check whether some other threads are using the file. In that case, the indicator file will
* not be empty. If no other threads are using it, then the file will not available
*/
file_dir = rampart_replay_detector_file_dir(env);
file_name = axutil_stracat(env, file_dir, INDICATOR_FILE);
temp_file = fopen(file_name, "r");
while (temp_file)
{
fclose (temp_file);
#ifdef WIN32
Sleep (5000);
#else
sleep (5);
#endif
temp_file = fopen(file_name, "r");
}
temp_file = fopen(file_name, "w+");
AXIS2_FREE(env->allocator, file_name);
if (!temp_file)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rampart]Creating indicator file failed" );
AXIS2_FREE(env->allocator, file_dir);
return AXIS2_FAILURE;
}
fclose (temp_file);
/*
* now we can safely read the actual replay content file
*/
file_name = axutil_stracat(env, file_dir, REPLAY_FILE);
file = fopen (file_name, "r");
AXIS2_FREE(env->allocator, file_dir);
AXIS2_FREE(env->allocator, file_name);
if (file)
{
axis2_char_t* whole_buffer = NULL;
do
{
ch_read = fread (buffer, sizeof(axis2_char_t), BUFFER_LEN, file);
buffer[ch_read] = 0;
if (!ch_read)
break;
if (whole_buffer)
{
axis2_char_t* temp_str = whole_buffer;
whole_buffer = axutil_stracat(env, temp_str, buffer);
AXIS2_FREE(env->allocator, temp_str);
}
else
{
whole_buffer = axutil_strdup(env, buffer);
}
}while (!feof(file));
fclose(file);
if (whole_buffer)
{
key = strtok(whole_buffer, dilim);
while (key)
{
axutil_linked_list_add(ll, env, (void*)axutil_strdup(env,key));
key = strtok(NULL, dilim);
}
AXIS2_FREE(env->allocator, whole_buffer);
}
}
return AXIS2_SUCCESS;
}
static axis2_status_t
rampart_replay_detector_write_file(
const axutil_env_t *env,
axutil_linked_list_t* ll,
axis2_bool_t write_content)
{
FILE* file = NULL;
axis2_char_t *file_dir = NULL;
axis2_char_t *file_name = NULL;
file_dir = rampart_replay_detector_file_dir(env);
if (write_content)
{
file_name = axutil_stracat(env, file_dir, REPLAY_FILE);
file = fopen (file_name, "w+");
if (!file)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rampart]Creating replay file failed" );
AXIS2_FREE(env->allocator, file_name);
file_name = axutil_stracat(env, file_dir, INDICATOR_FILE);
remove(file_name);
AXIS2_FREE(env->allocator, file_name);
AXIS2_FREE(env->allocator, file_dir);
return AXIS2_FAILURE;
}
#ifndef WIN32
else
{
axis2_char_t *command = NULL;
command = axutil_stracat(env, "chmod 666 ", file_name);
system(command);
AXIS2_FREE(env->allocator, command);
}
#endif
AXIS2_FREE(env->allocator, file_name);
}
while(axutil_linked_list_size(ll, env) > 0)
{
axis2_char_t *tmp_msg_id = NULL;
tmp_msg_id = (axis2_char_t*)axutil_linked_list_remove_first(ll, env);
if (file)
{
fwrite(tmp_msg_id, sizeof(axis2_char_t), axutil_strlen(tmp_msg_id), file);
fputc(DELIMIT, file);
}
AXIS2_FREE(env->allocator, tmp_msg_id);
tmp_msg_id = NULL;
}
if (file)
{
fclose(file);
}
file_name = axutil_stracat(env, file_dir, INDICATOR_FILE);
remove(file_name);
AXIS2_FREE(env->allocator, file_name);
AXIS2_FREE(env->allocator, file_dir);
return AXIS2_SUCCESS;
}
static axis2_bool_t
rampart_replay_detector_check_in_linked_list(
axutil_linked_list_t *linked_list,
const axutil_env_t *env,
axis2_char_t *id)
{
int count = 0;
int i = 0;
count = axutil_linked_list_size(linked_list, env);
for(i=0; i<count; i++)
{
axis2_char_t *tmp_id = NULL;
tmp_id = (axis2_char_t*)axutil_linked_list_get(linked_list, env, i);
if(0 == axutil_strcmp(id, tmp_id))
{
return AXIS2_TRUE;
}
}
return AXIS2_FALSE;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
rampart_replay_detector_with_flat_file(
rampart_replay_detector_t *rrd,
const axutil_env_t *env,
axis2_msg_ctx_t* msg_ctx,
rampart_context_t *rampart_context)
{
axutil_linked_list_t *ll = NULL;
const axis2_char_t *msg_id = NULL;
const axis2_char_t *ts = NULL;
const axis2_char_t *addr_msg_id = NULL;
int max_rcds = RAMPART_RD_DEF_MAX_RCDS;
axis2_status_t status = AXIS2_FAILURE;
axutil_hash_t *sec_process_result = NULL;
/*Get timestamp from security processed results */
sec_process_result = rampart_get_all_security_processed_results(env, msg_ctx);
ts = axutil_hash_get(sec_process_result, RAMPART_SPR_TS_CREATED, AXIS2_HASH_KEY_STRING);
/* get message id from addressing headers */
addr_msg_id = axis2_msg_ctx_get_wsa_message_id(msg_ctx, env);
if(!ts && addr_msg_id)
{
msg_id = addr_msg_id;
}
else if(ts && !addr_msg_id)
{
msg_id = ts;
}
else if(ts && addr_msg_id)
{
msg_id = axutil_strcat(env, addr_msg_id, ts, NULL);
}
else
{
msg_id = NULL;
}
if(!msg_id)
{
/* using default msg id */
msg_id = "RAMPART-DEFAULT-TS";
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI,
"[rampart]No msg_id specified, using default = %s", msg_id);
}
ll = axutil_linked_list_create(env);
if(!ll)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rampart]Linked list creation failed.");
return AXIS2_FAILURE;
}
status = rampart_replay_detector_read_file(env, ll);
if(status != AXIS2_SUCCESS)
{
/* we have to clear linked list. We don't need to write the contents. So pass false to
* denote whether to write the content */
rampart_replay_detector_write_file(env, ll, AXIS2_FALSE);
return AXIS2_FAILURE;
}
else
{
/* Get the number of records to be kept */
if(rampart_context_get_rd_val(rampart_context, env))
{
max_rcds = axutil_atoi(rampart_context_get_rd_val(rampart_context, env));
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI,
"[rampart]Using the specified max_rcds %d\n", max_rcds );
}
else
{
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI,
"[rampart]Using the default max_rcds %d\n", max_rcds );
}
/* If the table already have the same key it's a replay */
if(rampart_replay_detector_check_in_linked_list(ll, env, (void*)msg_id))
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rampart]For ID=%s, a replay detected", msg_id);
rampart_replay_detector_write_file(env, ll, AXIS2_FALSE);
return AXIS2_FAILURE;
}
/* if number of records saved are more than allowed, we have to remove them */
while(axutil_linked_list_size(ll, env) >= max_rcds)
{
axis2_char_t *tmp_msg_id = NULL;
tmp_msg_id = (axis2_char_t*)axutil_linked_list_remove_first(ll, env);
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[rampart]Deleting record %s\n", tmp_msg_id );
AXIS2_FREE(env->allocator, tmp_msg_id);
tmp_msg_id = NULL;
}
/* Add current record */
status = axutil_linked_list_add(ll, env, (void*)axutil_strdup(env,msg_id));
if(status == AXIS2_SUCCESS)
{
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[rampart]Adding record %s\n", msg_id );
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,"[rampart]Cannot add record %s\n", msg_id);
rampart_replay_detector_write_file(env, ll, AXIS2_FALSE);
return AXIS2_FAILURE;
}
status = rampart_replay_detector_write_file(env, ll, AXIS2_TRUE);
axutil_linked_list_free(ll, env);
if(status == AXIS2_SUCCESS)
{
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[rampart]Writing records to file succeed." );
return AXIS2_SUCCESS;
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,"[rampart]Writing records to file failed");
return AXIS2_FAILURE;
}
}
}
/**
* Following block distinguish the exposed part of the dll.
*/
AXIS2_EXPORT int
axis2_get_instance(
rampart_replay_detector_t **inst,
const axutil_env_t *env)
{
rampart_replay_detector_t* rd = NULL;
rd = AXIS2_MALLOC(env->allocator, sizeof(rampart_replay_detector_t));
if (!rd)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rampart]Cannot create replay detector module. Insufficient memory.");
return AXIS2_FAILURE;
}
rd->ops = AXIS2_MALLOC(env->allocator, sizeof(rampart_replay_detector_ops_t));
if (!rd->ops)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rampart]Cannot create replay detector module operations. Insufficient memory.");
return AXIS2_FAILURE;
}
/* assign function pointers */
rd->ops->is_replayed = rampart_replay_detector_with_flat_file;
rd->ops->free = rampart_replay_detector_free;
*inst = rd;
return AXIS2_SUCCESS;
}
AXIS2_EXPORT int
axis2_remove_instance(
rampart_replay_detector_t *inst,
const axutil_env_t *env)
{
axis2_status_t status = AXIS2_FAILURE;
if (inst)
{
status = RAMPART_REPLAY_DETECTOR_FREE(inst, env);
}
return status;
}