blob: 1944b203a7e1d82315717d3c5131d8de7f8e8449 [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 <axutil_linked_list.h>
#include <rampart_replay_detector.h>
#include <axutil_property.h>
#include <rampart_constants.h>
#include <rampart_sec_processed_result.h>
#include <axis2_conf_ctx.h>
#define RAMPART_RD_LL_PROP "Rampart_RD_LL_Prop"
/**
* Get replay detector storage from msg_ctx. If it is not yet created, it will create a new one and
* store it in conf_context.
*/
static axutil_linked_list_t *
rampart_replay_detector_get_linked_list(
const axutil_env_t *env,
axis2_msg_ctx_t* msg_ctx)
{
axis2_conf_ctx_t *conf_ctx = NULL;
axis2_ctx_t *ctx = NULL;
axutil_property_t *property = NULL;
axutil_linked_list_t *ll = NULL;
conf_ctx = axis2_msg_ctx_get_conf_ctx(msg_ctx, env);
if(!conf_ctx)
{
AXIS2_LOG_ERROR(env->log,AXIS2_LOG_SI,
"[rampart]Conf context is not valid. Could not get replay detector store.");
return NULL;
}
ctx = axis2_conf_ctx_get_base(conf_ctx,env);
if(!ctx)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rampart]Axis2 context is not valid. Could not get replay detector store.");
return NULL;
}
/* Get the Linked list property */
property = axis2_ctx_get_property(ctx, env, RAMPART_RD_LL_PROP);
if(property)
{
ll = (axutil_linked_list_t*)axutil_property_get_value(property, env);
return ll;
}
else
{
/* not found. Can create new */
ll = axutil_linked_list_create(env);
property = axutil_property_create(env);
axutil_property_set_value(property, env, ll);
axis2_ctx_set_property(ctx, env, RAMPART_RD_LL_PROP, property);
return ll;
}
}
/**
* Checks whether given id is available in the linked list
*/
static axis2_bool_t
rampart_replay_detector_linked_list_contains(
axutil_linked_list_t *linked_list,
const axutil_env_t *env,
const 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(!axutil_strcmp(id, tmp_id))
{
return AXIS2_TRUE;
}
}
return AXIS2_FALSE;
}
/**
* A linked list based implementation for replay detection.
* This doesnt require addressing headers to be present. If the user doesn't give any replay
* detection function, then this will be used.
* @param env pointer to environment struct,Must not be NULL.
* @param msg_ctx message context structure
* @param rampart_context rampart context structure
* @param user_params parameters given by user. (Not used in this method)
* @returns status of the op. AXIS2_SUCCESS on success and AXIS2_FAILURE on error
*/
AXIS2_EXTERN axis2_status_t AXIS2_CALL
rampart_replay_detector_default(
const axutil_env_t *env,
axis2_msg_ctx_t* msg_ctx,
rampart_context_t *rampart_context,
void *user_params)
{
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;
/* since replay details have to be stored until the application finished,
* they have to be created in golbal pool. If those are created in msg's pool,
* then it will be deleted after the request is served. (specially when using
* with apache, current_pool will denote the message's pool) */
axutil_allocator_switch_to_global_pool(env->allocator);
/* By using just Timestamps we dont need addressing. But there is a chance that
* two messages might generated exactly at the same time */
/* get the timestamp from security processed results */
ts = rampart_get_security_processed_result(env, msg_ctx, RAMPART_SPR_TS_CREATED);
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_stracat(env, addr_msg_id, ts);
}
else
{
msg_id = NULL;
}
if(!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 = rampart_replay_detector_get_linked_list(env, msg_ctx);
if(!ll)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rampart]Cannot get the linked list storage for replay detection from msg_ctx");
axutil_allocator_switch_to_local_pool(env->allocator);
return AXIS2_FAILURE;
}
else
{
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI,
"[rampart][rrd] Number of records =%d", axutil_linked_list_size(ll, env));
/* Get the number of records to be stored */
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_linked_list_contains(ll, env, msg_id))
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,"[rampart]For ID=%s, a replay detected", msg_id);
axutil_allocator_switch_to_local_pool(env->allocator);
return AXIS2_FAILURE;
}
/* If the number of records are more than allowed, delete old records */
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));
axutil_allocator_switch_to_local_pool(env->allocator);
if(AXIS2_SUCCESS == status)
{
AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "[rampart]Adding record %s\n", msg_id );
return AXIS2_SUCCESS;
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rampart]Cannot add record %s\n", msg_id);
return AXIS2_FAILURE;
}
}
}