diff options
Diffstat (limited to 'pki/base/tps/src/modules/tps')
-rw-r--r-- | pki/base/tps/src/modules/tps/AP_Context.cpp | 83 | ||||
-rw-r--r-- | pki/base/tps/src/modules/tps/AP_Session.cpp | 1146 | ||||
-rw-r--r-- | pki/base/tps/src/modules/tps/mod_tps.cpp | 584 |
3 files changed, 1813 insertions, 0 deletions
diff --git a/pki/base/tps/src/modules/tps/AP_Context.cpp b/pki/base/tps/src/modules/tps/AP_Context.cpp new file mode 100644 index 000000000..cde314254 --- /dev/null +++ b/pki/base/tps/src/modules/tps/AP_Context.cpp @@ -0,0 +1,83 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "httpd/httpd.h" +#include "httpd/http_log.h" +#include "nspr.h" + +#include "modules/tps/AP_Context.h" + +#define MAX_LOG_MSG_SIZE 4096 + + +AP_Context::AP_Context( server_rec *sv ) +{ + m_sv = sv; +} + + +AP_Context::~AP_Context() +{ + /* no clean up */ +} + + +void AP_Context::LogError( const char *func, int line, const char *fmt, ... ) +{ + char buf[MAX_LOG_MSG_SIZE]; + + va_list argp; + va_start( argp, fmt ); + PR_vsnprintf( buf, MAX_LOG_MSG_SIZE, fmt, argp ); + va_end( argp ); + + ap_log_error( func, line, APLOG_ERR, 0, m_sv, buf ); +} + + +void AP_Context::LogInfo( const char *func, int line, const char *fmt, ... ) +{ + char buf[MAX_LOG_MSG_SIZE]; + + va_list argp; + va_start( argp, fmt ); + PR_vsnprintf( buf, MAX_LOG_MSG_SIZE, fmt, argp ); + va_end( argp ); + + ap_log_error( func, line, APLOG_INFO, 0, m_sv, buf ); +} + + +void AP_Context::InitializationError( const char *func, int line ) +{ + ap_log_error( func, line, APLOG_INFO, 0, m_sv, + "The nss module must be initialized " + "prior to calling the tps module." ); +} + +#ifdef __cplusplus +} +#endif + diff --git a/pki/base/tps/src/modules/tps/AP_Session.cpp b/pki/base/tps/src/modules/tps/AP_Session.cpp new file mode 100644 index 000000000..ff33330b9 --- /dev/null +++ b/pki/base/tps/src/modules/tps/AP_Session.cpp @@ -0,0 +1,1146 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include "nspr.h" +#include "httpd/httpd.h" +#include "httpd/http_protocol.h" + +#include "engine/RA.h" +#include "main/Util.h" +#include "main/RA_Msg.h" +#include "main/RA_pblock.h" +#include "main/RA_Session.h" +#include "msg/RA_Begin_Op_Msg.h" +#include "msg/RA_Login_Response_Msg.h" +#include "msg/RA_Extended_Login_Response_Msg.h" +#include "msg/RA_SecureId_Response_Msg.h" +#include "msg/RA_ASQ_Response_Msg.h" +#include "msg/RA_New_Pin_Response_Msg.h" +#include "msg/RA_Token_PDU_Response_Msg.h" +#include "msg/RA_Login_Request_Msg.h" +#include "msg/RA_Extended_Login_Request_Msg.h" +#include "msg/RA_SecureId_Request_Msg.h" +#include "msg/RA_ASQ_Request_Msg.h" +#include "msg/RA_New_Pin_Request_Msg.h" +#include "msg/RA_Token_PDU_Request_Msg.h" +#include "msg/RA_End_Op_Msg.h" +#include "msg/RA_Status_Update_Request_Msg.h" +#include "msg/RA_Status_Update_Response_Msg.h" +#include "modules/tps/AP_Session.h" +#include "main/Memory.h" + +/** + * http parameters used in the protocol + */ +#define PARAM_MSG_TYPE "msg_type" +#define PARAM_OPERATION "operation" +#define PARAM_INVALID_PW "invalid_pw" +#define PARAM_BLOCKED "blocked" +#define PARAM_SCREEN_NAME "screen_name" +#define PARAM_PASSWORD "password" +#define PARAM_PIN_REQUIRED "pin_required" +#define PARAM_NEXT_VALUE "next_value" +#define PARAM_VALUE "value" +#define PARAM_PIN "pin" +#define PARAM_QUESTION "question" +#define PARAM_ANSWER "answer" +#define PARAM_MINIMUM_LENGTH "minimum_length" +#define PARAM_MAXIMUM_LENGTH "maximum_length" +#define PARAM_NEW_PIN "new_pin" +#define PARAM_PDU_SIZE "pdu_size" +#define PARAM_PDU_DATA "pdu_data" +#define PARAM_RESULT "result" +#define PARAM_MESSAGE "message" +#define PARAM_STATUS "current_state" +#define PARAM_INFO "next_task_name" +#define PARAM_EXTENSIONS "extensions" + +#define MAX_RA_MSG_SIZE 4096 +#define MAX_LOG_MSG_SIZE 4096 + +// maximum number of digits for message length +#define MAX_LEN_DIGITS 4 + + +static int contains_sensitive_keywords(char *msg) +{ + if (strstr(msg, "password" ) != NULL ) { + return 1; + } + if (strstr(msg, "PASSWORD" ) != NULL ) { + return 1; + } + if (strstr(msg, "new_pin" ) != NULL ) { + return 1; + } + return 0; +} + + +/** + * AP_Session represents an active connection between the + * Registration authority and the token client. + * + * Note that AP_Session encapsulates all the glue logic + * between Apache and the RA. If we need to go to anther platform + * (i.e. NPE, NES, or other web servers) later, we just need + * to implement a new Session implementation. + */ +AP_Session::AP_Session( request_rec *rq ) +{ + m_rq = rq; + /* REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me */ + ap_setup_client_block( rq, REQUEST_CHUNKED_DECHUNK); +} + + +AP_Session::~AP_Session() +{ + /* no clean up */ +} + + +char *AP_Session::GetRemoteIP() +{ + return ( m_rq->connection->remote_ip ); +} + + +/** + * reads from network "s=xx" where xx is the length of the message + * that follows. The length is returned as int. + * @return length in int + */ +static int GetMsgLen( request_rec *rq ) +{ + int len=0; + char msg_len[MAX_LEN_DIGITS]; // msg_len can't take more than 4 digits + char *p_msg_len = msg_len; + int sum = 0; + + /* read msg size */ + len = ( int ) ap_get_client_block( rq, p_msg_len, + ( apr_size_t ) 1 ); /* s */ + if( len != 1 ) { + RA::Error( "AP_Session::GetMsgLen", + "ap_get_client_block returned error: %d", len ); + + return 0; + } + + len = ( int ) ap_get_client_block( rq, p_msg_len, + ( apr_size_t ) 1 ); /* = */ + + if( len != 1 ) { + RA::Error( "AP_Session::GetMsgLen", + "ap_get_client_block returned error: %d", len ); + + return 0; + } + + while( 1 ) { + if( sum > ( MAX_LEN_DIGITS -1 ) ) { + /* the length is too large */ + RA::Error( "AP_Session::ReadMsg", "Message Size is too large." ); + return -1; + } + + len = ( int ) ap_get_client_block( rq, p_msg_len, ( apr_size_t ) 1 ); + + if( len != 1 ) { + break; + } + + if( len != 0 ) { + if( *p_msg_len == '&' ) { + break; + } + + p_msg_len++; + sum++; + } + } + + *p_msg_len = '\0'; + + return atoi( msg_len ); +} + +static int GetMsg( request_rec *rq, char *buf, int size ) +{ + int len; + int sum = 0; + char *p_msg = buf; + + while( 1 ) { + len = ( int ) ap_get_client_block( rq, p_msg, ( apr_size_t ) 1 ); + if( len != 1 ) { + return -1; + } + p_msg += len; + sum += len; + buf[sum] = '\0'; + if( sum == size ) { + break; + } + } + + buf[sum] = '\0'; + + return sum; +} + +char *stripEmptyArgs( char *data ) +{ + char *n_data = ( char * ) PR_Malloc( strlen( data ) + 2 ); + n_data[0] = '\0'; + int nv_count = 0; + + if( data != NULL && strlen( data ) > 0 ) { + char *lasts = NULL; + char *tok = PL_strtok_r( data, " ", &lasts ); + + while( tok != NULL ) { + if( tok[strlen( tok )-1] != '=' ) { + n_data = strcat( n_data, tok ); + n_data = strcat( n_data, " " ); + nv_count++; + } + + tok = PL_strtok_r( NULL, " ", &lasts ); + } + int len = strlen( n_data ); + n_data[len-1] = '\0'; + } + + if( ( nv_count > MAX_NVS ) || ( n_data[0] == '\0' ) ) { + PR_Free( n_data ); + n_data = NULL; + } + + return n_data; +} + + +int pblock_str2pblock( char *n_data, apr_array_header_t *tm_pblock ) +{ + int element = 0; + + if( n_data != NULL && strlen( n_data ) > 0 ) { + char *lasts = NULL; + char *tok = PL_strtok_r( n_data, " ", &lasts ); + + /* store each name/value pair in the string into the pblock array */ + while( tok != NULL ) { + char name[4096]; + char value[4096]; + + for( int i = 0; i < ( int ) strlen( tok ); i++ ) { + if( tok[i] != '=' ) { + /* extract and add to the name portion */ + name[i] = tok[i]; + } else { + /* null terminate the name portion */ + name[i] = '\0'; + /* extract the entire value portion */ + strcpy( value, &tok[i+1] ); + break; + } + } + + /* store the name/value pair as an entry in the pblock array */ + ( ( apr_table_entry_t * ) tm_pblock->elts )[element].key = + PL_strdup(name); + ( ( apr_table_entry_t * ) tm_pblock->elts )[element].val = + PL_strdup(value); + + /* increment the entry to the pblock array */ + element++; + + /* get the next name/value pair from the string */ + tok = PL_strtok_r( NULL, " ", &lasts ); + } + } + + return element; +} + + +/** + * Parses the data and creates an RA_pblock to store name/value pairs + * @param data null-terminated string containing a string with format: + * n1=v1&n2=v2&n3=v3&... + * @return + * pointer to RA_pblock if success + * NULL if failure; + */ +RA_pblock *AP_Session::create_pblock( char *data ) +{ + if( ( data == NULL ) || ( data[0] == '\0' ) ) { + RA::Error( "AP_Session::create_pblock", + "data is NULL" ); + return NULL; + } + + if(contains_sensitive_keywords(data)) { + RA::Debug( LL_PER_PDU, + "AP_Session::create_pblock", + "Data '(sensitive)'"); + } else { + RA::Debug( LL_PER_PDU, + "AP_Session::create_pblock", + "Data '%s'", data); + } + + // + // The data contains a set of name value pairs separated by an '&' + // (i. e. - n1=v1&n2=v2...). Replace each '&' with a ' '. + // + // Note that since the values are expected to have been url-encoded, + // they must be url-decoded within the subclass method. + // + int i, j; + int len = strlen( data ); + + for( i = 0; i < len; i++ ) { + // need to check if data[i] is a valid url-encoded char...later + if( data[i] == '&' ) { + data[i] = ' '; + } + } + + apr_array_header_t *tm_pblock = apr_array_make( m_rq->pool, + MAX_NVS, + sizeof( apr_table_entry_t ) + ); + + if( tm_pblock == NULL ) { + RA::Error( "AP_Session::create_pblock", + "apr_array_make returns NULL" ); + return NULL; + } + + // + // The data is in the format of "name=v1 name=v2 name=v3". If the data + // has content like "name=v1 name= name=v3", the pblock_str2pblock will + // return (-1). This is because pblock_str2pblock does not know how to + // handle the case of an empty value. Therefore, before we invoke + // pblock_str2pblock, we make sure to remove any input data which + // contains an empty value. + // + char *n_data = stripEmptyArgs( data ); + if( n_data == NULL ) { + RA::Error( "AP_Session::create_pblock", + "stripEmptyArgs was either empty or " + "contained more than %d name/value pairs!", + MAX_NVS ); + return NULL; + } + + int tm_nargs = pblock_str2pblock( n_data, tm_pblock ); + apr_table_entry_t *pe = NULL; + + RA::Debug( LL_PER_PDU, + "AP_Session::create_pblock", + "Found Arguments=%d, nalloc=%d", + tm_nargs, + tm_pblock->nalloc ); + + // url decode all values and place into Buffer_nv's + Buffer_nv *tm_nvs[MAX_NVS]; + + for( i = 0, j = 0; i < tm_nargs; i++, j++ ) { + tm_nvs[j] = NULL; + + pe = ( apr_table_entry_t * ) tm_pblock->elts; + + if( pe == NULL ) { + continue; + } + + if( ( pe[i].key == NULL ) || + ( ( PR_CompareStrings( pe[i].key, "" ) == 1 ) ) || + ( pe[i].val == NULL ) || + ( ( PR_CompareStrings( pe[i].val, "" ) == 1 ) ) ) { + RA::Debug( LL_ALL_DATA_IN_PDU, + "AP_Session::create_pblock", + "name/value pair contains NULL...skip" ); + continue; + } + + if(contains_sensitive_keywords(pe[i].key)) { + RA::Debug( LL_PER_PDU, + "AP_Session::create_pblock", + "entry name=%s, value=<...do not print...>", + pe[i].key ); + } else { + RA::Debug( LL_PER_PDU, + "AP_Session::create_pblock", + "entry name=%s, value=%s", + pe[i].key, + pe[i].val ); + } + + Buffer *decoded = NULL; + + decoded = Util::URLDecode( pe[i].val ); + + tm_nvs[j] = ( struct Buffer_nv * ) + PR_Malloc( sizeof( struct Buffer_nv ) ); + + if( tm_nvs[j] != NULL ) { + tm_nvs[j]->name = PL_strdup( pe[i].key ); + tm_nvs[j]->value_s = PL_strdup( pe[i].val ); + tm_nvs[j]->value = decoded; + } else { + RA::Debug( LL_PER_PDU, + "AP_Session::create_pblock", + "tm_nvs[%d] is NULL", + j ); + } + } // for + + RA_pblock *ra_pb = new RA_pblock( tm_nargs, tm_nvs ); + + if( n_data != NULL ) { + PR_Free( n_data ); + n_data = NULL; + } + + if( ra_pb == NULL ) { + RA::Error( "AP_Session::create_pblock", + "RA_pblock is NULL" ); + return NULL; + } + + return ra_pb; +} + +RA_Msg *AP_Session::ReadMsg() +{ + int len; + int msg_len = 0; + char msg[MAX_RA_MSG_SIZE]; + char *msg_type = NULL; + int i_msg_type; + Buffer *msg_type_b = NULL; + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "========== ReadMsg Begins =======" ); + + msg_len = GetMsgLen( m_rq ); + + if( ( msg_len <= 0 ) || ( msg_len > MAX_RA_MSG_SIZE ) ) { + RA::Error( "AP_Session::ReadMsg", + "Message Size not in range. size =%d. Operation may have been cancelled.", msg_len ); + return NULL; + } + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", "msg_len=%d", msg_len ); + + len = GetMsg( m_rq, msg, msg_len ); + + if( len != msg_len ) { + RA::Error( "AP_Session::ReadMsg", + "Message Size Mismatch. Expected '%d' Received '%d'", + msg_len, len ); + return NULL; + } + + if(!contains_sensitive_keywords(msg)) { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Received len='%d' msg='%s'", len, msg ); + } else { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Received len='%d' msg='<Password or new pin>'", len ); + } + + RA_Msg *ret_msg = NULL; + + // format into array of name/value pair with value Buffer's + RA_pblock *ra_pb = ( RA_pblock * ) create_pblock( msg ); + + if( ra_pb == NULL ) { + goto loser; + } + + // msg_type_b will be freed by destructor of RA_pblock + msg_type_b = ra_pb->find_val( PARAM_MSG_TYPE ); + if( msg_type_b == NULL ) { + goto loser; + } + + // msg_type should be freed when done using + msg_type = msg_type_b->string(); + + if( msg_type == NULL ) { + RA::Error( "AP_Session::ReadMsg", + "Parameter Not Found %s", PARAM_MSG_TYPE ); + goto loser; + } + + i_msg_type = atoi( msg_type ); + + switch( i_msg_type ) + { + case MSG_BEGIN_OP: /* BEGIN_OP */ + { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Found %s=%s (%s)", PARAM_MSG_TYPE, + "BEGIN_OP", msg_type ); + + Buffer *opB = ra_pb->find_val( PARAM_OPERATION ); + + if( opB == NULL ) { + goto loser; + } + + RA::DebugBuffer( "AP_Session::ReadMsg", "content=", opB ); + + char *op_c = opB->string(); + + if( op_c == NULL ) { + goto loser; + } + + int i_op = atoi( op_c ); + + if( op_c != NULL ) { + PR_Free( op_c ); + op_c = NULL; + } + + NameValueSet *exts = NULL; + + Buffer *opE = ra_pb->find_val( PARAM_EXTENSIONS ); // optional + + if( opE != NULL ) { + char *op_e = opE->string(); + if( op_e == NULL ) { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "No extensions" ); + } else { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Extensions %s", op_e ); + exts = NameValueSet::Parse( op_e, "&" ); + if( op_e != NULL ) { + PR_Free( op_e ); + op_e = NULL; + } + } + } + + switch( i_op ) + { + case OP_ENROLL: + { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "begin_op_msg msg_type=ENROLL" ); + ret_msg = new RA_Begin_Op_Msg( OP_ENROLL, exts ); + break; + } + case OP_UNBLOCK: + { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "begin_op_msg msg_type=UNBLOCK" ); + ret_msg = new RA_Begin_Op_Msg( OP_UNBLOCK, exts ); + break; + } + case OP_RESET_PIN: + { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "begin_op_msg msg_type=RESET_PIN" ); + ret_msg = new RA_Begin_Op_Msg( OP_RESET_PIN, exts ); + break; + } + case OP_RENEW: + { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "begin_op_msg msg_type=RENEW" ); + ret_msg = new RA_Begin_Op_Msg( OP_RENEW, exts ); + break; + } + case OP_FORMAT: + { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "begin_op_msg msg_type=FORMAT" ); + ret_msg = new RA_Begin_Op_Msg( OP_FORMAT, exts ); + break; + } + default: + { + break; + /* error */ + } + } // switch( i_op ) + + break; + } + case MSG_EXTENDED_LOGIN_RESPONSE: /* LOGIN_RESPONSE */ + { + char *name = NULL; + Buffer* value = NULL; + AuthParams *params = new AuthParams(); + int i; + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Found %s=%s (%s)", PARAM_MSG_TYPE, + "EXTENDED_LOGIN_RESPONSE", msg_type ); + + i = ra_pb->get_num_of_names(); + + for( i = 0; i < ra_pb->get_num_of_names(); i++ ) { + name = ra_pb->get_name( i ); + if( name != NULL ) { + value = ra_pb->find_val( ( const char * ) name ); + if( value != NULL ) { + params->Add( name, value->string() ); + } + } + } + + ret_msg = new RA_Extended_Login_Response_Msg( params ); + + break; + } + case MSG_LOGIN_RESPONSE: /* LOGIN_RESPONSE */ + { + char *uid = NULL, *password = NULL; + Buffer *uid_b, *pwd_b = NULL; + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Found %s=%s (%s)", PARAM_MSG_TYPE, + "LOGIN_RESPONSE", msg_type ); + + uid_b = ra_pb->find_val( PARAM_SCREEN_NAME ); + + if( uid_b == NULL ) { + goto aloser; + } + + uid = uid_b->string(); + + if( uid == NULL ) { + goto aloser; + } + + pwd_b = ra_pb->find_val( PARAM_PASSWORD ); + + if( pwd_b == NULL ) { + goto aloser; + } + + password = pwd_b->string(); + + if( password == NULL ) { + goto aloser; + } + + ret_msg = new RA_Login_Response_Msg( uid, password ); + + aloser: + if( uid != NULL ) { + PR_Free( uid ); + uid = NULL; + } + + if( password != NULL ) { + PR_Free( password ); + password = NULL; + } + + goto loser; + + break; + } + case MSG_STATUS_UPDATE_RESPONSE: /* SECUREID_RESPONSE */ + { + char *value = NULL; + Buffer *value_b; + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Found %s=%s (%s)", PARAM_MSG_TYPE, + "STATUS_UPDATE_RESPONSE", msg_type ); + + value_b = ra_pb->find_val( PARAM_STATUS ); + + if( value_b == NULL ) { + goto zloser; + } + + value = value_b->string(); + + if( value == NULL ) { + goto zloser; + } + + ret_msg = new RA_Status_Update_Response_Msg( atoi( value ) ); + + zloser: + if( value != NULL ) { + PR_Free( value ); + value = NULL; + } + + goto loser; + + break; + } + case MSG_SECUREID_RESPONSE: /* SECUREID_RESPONSE */ + { + char *value = NULL, *pin = NULL; + Buffer *value_b = NULL, *pin_b = NULL; + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Found %s=%s (%s)", PARAM_MSG_TYPE, + "SECUREID_RESPONSE", msg_type ); + + value_b = ra_pb->find_val( PARAM_VALUE ); + + if( value_b == NULL ) { + goto bloser; + } + + value = value_b->string(); + + if( value == NULL ) { + goto bloser; + } + + pin_b = ra_pb->find_val( PARAM_PIN ); + + if( pin_b == NULL ) { + goto bloser; + } + + pin = pin_b->string(); + + if( pin == NULL ) { + pin_b->zeroize(); + goto bloser; + } + + ret_msg = new RA_SecureId_Response_Msg( value, pin ); + + if( pin != NULL ) { + // zeroize memory before releasing + unsigned int i = 0; + for( i = 0; i < strlen( pin ); i++ ) { + pin[i] = '\0'; + } + if( pin != NULL ) { + PR_Free( pin ); + pin = NULL; + } + } + + pin_b->zeroize(); + + bloser: + if( value != NULL ) { + PR_Free( value ); + value = NULL; + } + + if( pin != NULL ) { + PR_Free( pin ); + pin = NULL; + } + + goto loser; + + break; + } + case MSG_ASQ_RESPONSE: /* ASQ_RESPONSE */ + { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Found %s=%s (%s)", PARAM_MSG_TYPE, + "ASQ_RESPONSE", msg_type ); + + Buffer *ans_b = ra_pb->find_val( PARAM_ANSWER ); + + if( ans_b == NULL ) { + goto loser; + } + + char *answer = ans_b->string(); + + if( answer == NULL ) { + goto loser; + } + + ret_msg = new RA_ASQ_Response_Msg( answer ); + + if( answer != NULL ) { + PR_Free( answer ); + answer = NULL; + } + + break; + } + case MSG_TOKEN_PDU_RESPONSE: /* TOKEN_PDU_RESPONSE */ + { + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Found %s=%s (%s)", PARAM_MSG_TYPE, + "TOKEN_PDU_RESPONSE", msg_type ); + + unsigned int pdu_size =0; + + Buffer *pdu_size_b = ra_pb->find_val( PARAM_PDU_SIZE ); + + if( pdu_size_b == NULL ) { + goto loser; + } + + char *p = pdu_size_b->string(); + + pdu_size = atoi( p ); + + if( p != NULL ) { + PR_Free( p ); + p = NULL; + } + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Found %s=%d", PARAM_PDU_SIZE, pdu_size ); + + if( pdu_size > 261 ) { + RA::Error( LL_PER_PDU, "AP_Session::ReadMsg", + "%s exceeds limit", PARAM_PDU_SIZE ); + goto loser; + } + + Buffer *decoded_pdu = ra_pb->find_val( PARAM_PDU_DATA ); + + if( decoded_pdu == NULL ) { + goto loser; + } + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "decoded_pdu size= %d", decoded_pdu->size() ); + + if( pdu_size != decoded_pdu->size() ) { + goto loser; + } + + RA::DebugBuffer( "AP_Session::ReadMsg", + "decoded pdu = ", decoded_pdu ); + + APDU_Response *response = new APDU_Response( *decoded_pdu ); + + ret_msg = new RA_Token_PDU_Response_Msg( response ); + + break; + } + case MSG_NEW_PIN_RESPONSE: /* NEW_PIN_RESPONSE */ + { + char *new_pin = NULL; + Buffer *new_pin_b = NULL; + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "Found %s=%s (%s)", PARAM_MSG_TYPE, + "NEW_PIN_RESPONSE", msg_type ); + + new_pin_b = ra_pb->find_val( PARAM_NEW_PIN ); + + if( new_pin_b == NULL ) { + goto loser; + } + + new_pin = new_pin_b->string(); + + if( new_pin == NULL ) { + new_pin_b->zeroize(); + goto loser; + } + + ret_msg = new RA_New_Pin_Response_Msg( new_pin ); + + if( new_pin != NULL ) { + // zeroize memory before releasing + unsigned int i = 0; + + for( i = 0; i< strlen( new_pin ); i++ ) { + new_pin[i] = '\0'; + } + + if( new_pin != NULL ) { + PR_Free( new_pin ); + new_pin = NULL; + } + } + + new_pin_b->zeroize(); + + break; + } + default: + { + RA::Error( "AP_Session::ReadMsg", "Found %s=%s", + PARAM_MSG_TYPE, "UNDEFINED" ); + /* error */ + break; + } + } // switch( i_msg_type ) + +loser: + if( msg_type != NULL ) { + PR_Free( msg_type ); + msg_type = NULL; + } + + if( ra_pb != NULL ) { + delete ra_pb; + ra_pb = NULL; + } + + RA::Debug( LL_PER_PDU, "AP_Session::ReadMsg", + "========= ReadMsg Ends =========" ); + + return ret_msg; +} + +static void CreateChunk( char *msgbuf, char *buf, int buflen ) +{ + int len; + + len = strlen( msgbuf ); + sprintf( buf, "s=%d&%s", len, msgbuf ); +} + +void AP_Session::WriteMsg( RA_Msg *msg ) +{ + char msgbuf[MAX_RA_MSG_SIZE]; + char buf[MAX_RA_MSG_SIZE]; + + switch( msg->GetType() ) + { + case MSG_EXTENDED_LOGIN_REQUEST: + { + RA_Extended_Login_Request_Msg *login_request_msg = + ( RA_Extended_Login_Request_Msg * ) msg; + int invalid_password = login_request_msg->IsInvalidPassword(); + int is_blocked = login_request_msg->IsBlocked(); + + sprintf( msgbuf, "%s=%d&%s=%d&%s=%d&%s=%s&%s=%s", + PARAM_MSG_TYPE, MSG_EXTENDED_LOGIN_REQUEST, + "invalid_login", invalid_password, + PARAM_BLOCKED, is_blocked, + "title", Util::URLEncode( login_request_msg->GetTitle() ), + "description", + Util::URLEncode( login_request_msg->GetDescription() ) ); + + for( int i = 0; i < login_request_msg->GetLen(); i++ ) { + char *p = login_request_msg->GetParam( i ); + sprintf( msgbuf, "%s&required_parameter%d=%s", + msgbuf, i, Util::URLEncode1( p ) ); + } + + CreateChunk( msgbuf, buf, MAX_RA_MSG_SIZE ); + + RA::Debug( "AP_Session::WriteMsg", "Sent '%s'", buf ); + + ( void ) ap_rwrite( ( const void * ) buf, strlen( buf ), m_rq ); + break; + } + case MSG_LOGIN_REQUEST: + { + RA_Login_Request_Msg *login_request_msg = + ( RA_Login_Request_Msg * ) msg; + int invalid_password = login_request_msg->IsInvalidPassword(); + int is_blocked = login_request_msg->IsBlocked(); + + sprintf( msgbuf, "%s=%d&%s=%d&%s=%d", + PARAM_MSG_TYPE, MSG_LOGIN_REQUEST, + PARAM_INVALID_PW, invalid_password, + PARAM_BLOCKED, is_blocked ); + + CreateChunk( msgbuf, buf, MAX_RA_MSG_SIZE ); + + RA::Debug( "AP_Session::WriteMsg", "Sent '%s'", buf ); + + ( void ) ap_rwrite( ( const void * ) buf, strlen( buf ), m_rq ); + + break; + } + case MSG_END_OP: + { + RA_End_Op_Msg *end_op = ( RA_End_Op_Msg * ) msg; + int result = end_op->GetResult(); + int local_msg = end_op->GetMsg(); + int op = end_op->GetOpType(); + + sprintf( msgbuf, "%s=%d&%s=%d&%s=%d&%s=%d", + PARAM_MSG_TYPE, MSG_END_OP, + PARAM_OPERATION, op, + PARAM_RESULT, result, + PARAM_MESSAGE, local_msg ); + + CreateChunk( msgbuf, buf, MAX_RA_MSG_SIZE ); + + RA::Debug( "AP_Session::WriteMsg", "Sent '%s'", buf ); + + ( void ) ap_rwrite( ( const void * ) buf, strlen( buf ), m_rq ); + + break; + } + case MSG_STATUS_UPDATE_REQUEST: + { + RA_Status_Update_Request_Msg *status_update_request_msg = + ( RA_Status_Update_Request_Msg * ) msg; + int status = status_update_request_msg->GetStatus(); + char *info = status_update_request_msg->GetInfo(); + + sprintf( msgbuf, "%s=%d&%s=%d&%s=%s", + PARAM_MSG_TYPE, MSG_STATUS_UPDATE_REQUEST, + PARAM_STATUS, status, + PARAM_INFO, info ); + + CreateChunk( msgbuf, buf, MAX_RA_MSG_SIZE ); + + RA::Debug( "AP_Session::WriteMsg", "Sent '%s'", buf ); + + ( void ) ap_rwrite( ( const void * ) buf, strlen( buf ), m_rq ); + + break; + } + case MSG_SECUREID_REQUEST: + { + RA_SecureId_Request_Msg *secureid_request_msg = + ( RA_SecureId_Request_Msg * ) msg; + int is_pin_required = secureid_request_msg->IsPinRequired(); + int is_next_value = secureid_request_msg->IsNextValue(); + + sprintf( msgbuf, "%s=%d&%s=%d&%s=%d", + PARAM_MSG_TYPE, MSG_SECUREID_REQUEST, + PARAM_PIN_REQUIRED, is_pin_required, + PARAM_NEXT_VALUE, is_next_value ); + + CreateChunk( msgbuf, buf, MAX_RA_MSG_SIZE ); + + RA::Debug( "AP_Session::WriteMsg", "Sent '%s'", buf ); + + ( void ) ap_rwrite( ( const void * ) buf, strlen( buf ), m_rq ); + + break; + } + case MSG_ASQ_REQUEST: + { + RA_ASQ_Request_Msg *asq_request_msg = ( RA_ASQ_Request_Msg * ) msg; + char *question = asq_request_msg->GetQuestion(); + + sprintf( msgbuf, "%s=%d&%s=%s", + PARAM_MSG_TYPE, MSG_ASQ_REQUEST, + PARAM_QUESTION, question ); + + CreateChunk( msgbuf, buf, MAX_RA_MSG_SIZE ); + + RA::Debug( "AP_Session::WriteMsg", "Sent '%s'", buf ); + + ( void ) ap_rwrite( ( const void * ) buf, strlen( buf ), m_rq ); + + break; + } + case MSG_NEW_PIN_REQUEST: + { + RA_New_Pin_Request_Msg *new_pin_request_msg = + ( RA_New_Pin_Request_Msg * ) msg; + int min = new_pin_request_msg->GetMinLen(); + int max = new_pin_request_msg->GetMaxLen(); + + sprintf( msgbuf, "%s=%d&%s=%d&%s=%d", + PARAM_MSG_TYPE, MSG_NEW_PIN_REQUEST, + PARAM_MINIMUM_LENGTH, min, + PARAM_MAXIMUM_LENGTH, max ); + + CreateChunk( msgbuf, buf, MAX_RA_MSG_SIZE ); + + RA::Debug( "AP_Session::WriteMsg", "Sent '%s'", buf ); + + ( void ) ap_rwrite( ( const void * ) buf, strlen( buf ), m_rq ); + + break; + } + case MSG_TOKEN_PDU_REQUEST: + { + RA_Token_PDU_Request_Msg *token_pdu_request_msg = + ( RA_Token_PDU_Request_Msg * ) msg; + APDU *apdu = token_pdu_request_msg->GetAPDU(); + Buffer encoding; + + apdu->GetEncoding( encoding ); + + int pdu_len = encoding.size(); + + RA::Debug( LL_PER_CONNECTION, "AP_Session::WriteMsg", + "pdu_len='%d'", pdu_len ); + + Buffer pdu = encoding; + char *pdu_encoded = NULL; + + if( RA::GetConfigStore()->GetConfigAsBool( "pdu_encoding.hex_mode", + 1 ) ) { + // pdu will be encoded in Hex mode which is easier to read + pdu_encoded = Util::URLEncodeInHex( pdu ); + } else { + pdu_encoded = Util::URLEncode( pdu ); + } + + sprintf( msgbuf, "%s=%d&%s=%d&%s=%s", + PARAM_MSG_TYPE, MSG_TOKEN_PDU_REQUEST, + PARAM_PDU_SIZE, pdu_len, + PARAM_PDU_DATA, pdu_encoded ); + + CreateChunk( msgbuf, buf, MAX_RA_MSG_SIZE ); + + if( pdu_encoded != NULL ) { + PR_Free( pdu_encoded ); + pdu_encoded = NULL; + } + + RA::Debug( "AP_Session::WriteMsg", "Sent '%s'", buf ); + + ( void ) ap_rwrite( ( const void * ) buf, strlen( buf ), m_rq ); + + break; + } + default: + { + break; + /* error */ + } + } // switch( msg->GetType() ) + + ap_rflush(m_rq); + +} + +#ifdef __cplusplus +} +#endif + diff --git a/pki/base/tps/src/modules/tps/mod_tps.cpp b/pki/base/tps/src/modules/tps/mod_tps.cpp new file mode 100644 index 000000000..47e3194fb --- /dev/null +++ b/pki/base/tps/src/modules/tps/mod_tps.cpp @@ -0,0 +1,584 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef XP_WIN32 +#define TPS_PUBLIC __declspec(dllexport) +#else /* !XP_WIN32 */ +#define TPS_PUBLIC +#endif /* !XP_WIN32 */ + + + +/* _________________________________________________________________ +** +** TPS Module Headers +** _________________________________________________________________ +*/ + +#include <stdio.h> +#include "nspr.h" + +#include "httpd/httpd.h" +#include "httpd/http_config.h" +#include "httpd/http_log.h" +#include "httpd/http_protocol.h" +#include "httpd/http_main.h" + +#include "apr_strings.h" + +#include "engine/RA.h" +#include "main/Memory.h" +#include "main/RA_Msg.h" +#include "main/RA_Session.h" +#include "modules/tps/AP_Context.h" +#include "modules/tps/AP_Session.h" +#include "msg/RA_Begin_Op_Msg.h" +#include "msg/RA_End_Op_Msg.h" +#include "processor/RA_Enroll_Processor.h" +#include "processor/RA_Format_Processor.h" +#include "processor/RA_Pin_Reset_Processor.h" +#include "processor/RA_Renew_Processor.h" +#include "processor/RA_Unblock_Processor.h" + + +/* _________________________________________________________________ +** +** TPS Module Request Data +** _________________________________________________________________ +*/ + +/** + * Processors for different operations. + */ +static RA_Enroll_Processor m_enroll_processor; +static RA_Unblock_Processor m_unblock_processor; +static RA_Pin_Reset_Processor m_pin_reset_processor; +static RA_Renew_Processor m_renew_processor; +static RA_Format_Processor m_format_processor; + + +/* _________________________________________________________________ +** +** TPS Module Command Data +** _________________________________________________________________ +*/ + +static const char MOD_TPS_CONFIGURATION_FILE_PARAMETER[] = "TPSConfigPathFile"; + +static const char MOD_TPS_CONFIGURATION_FILE_USAGE[] = +"TPS Configuration Filename prefixed by a complete path, or\n" +"a path that is relative to the Apache server root."; + + + +/* _________________________________________________________________ +** +** TPS Module Server Configuration Creation Data +** _________________________________________________________________ +*/ + +typedef struct { + char *TPS_Configuration_File; + AP_Context *context; +} mod_tps_server_configuration; + + + +/* _________________________________________________________________ +** +** TPS Module Registration Data +** _________________________________________________________________ +*/ + +#define MOD_TPS_CONFIG_KEY tps_module + +static const char MOD_TPS_CONFIG_KEY_NAME[] = "tps_module"; + +extern module TPS_PUBLIC MOD_TPS_CONFIG_KEY; + + + +/* _________________________________________________________________ +** +** TPS Module Helper Functions +** _________________________________________________________________ +*/ + +/** + * Terminate Apache + */ +void tps_die( void ) +{ + /* + * This is used for fatal errors and here + * it is common module practice to really + * exit from the complete program. + */ + exit( 1 ); +} + + +/** + * Creates an RA_Session from the RA framework. + * + * Centralize the allocation of the session object here so that + * we can provide our own session management here in the future. + */ +static RA_Session * +mod_tps_create_session( request_rec *rq ) +{ + return new AP_Session( rq ); +} /* mod_tps_create_session */ + + +/** + * Returns RA_Session to the RA framework. + */ +static void +mod_tps_destroy_session( RA_Session *session ) +{ + if( session != NULL ) { + delete session; + session = NULL; + } +} /* mod_tps_destroy_session */ + + + +/* _________________________________________________________________ +** +** TPS Module Request Phase +** _________________________________________________________________ +*/ + +/** + * Terminate the TPS module + */ +static apr_status_t +mod_tps_terminate( void *data ) +{ + /* This routine is ONLY called when this server's */ + /* pool has been cleared or destroyed. */ + + /* Log TPS module debug information. */ + RA::Debug( "mod_tps::mod_tps_terminate", + "The TPS module has been terminated!" ); + + /* Free TPS resources. */ + RA::Shutdown(); + + /* Since all members of mod_tps_server_configuration are allocated */ + /* from a pool, there is no need to unset any of these members. */ + +#ifdef MEM_PROFILING + /* If memory profiling is enabled, turn off memory profiling. */ + MEM_shutdown(); +#endif + + /* Shutdown all APR library routines. */ + /* NOTE: This automatically destroys all memory pools. */ + /* Allow the NSS Module to perform this task. */ + /* apr_terminate(); */ + + + /* Terminate the entire Apache server */ + /* NOTE: Allow the NSS Module to perform this task. */ + /* tps_die(); */ + + return OK; +} + + +/** + * Initialize the TPS module (Context) + */ +static int +mod_tps_initialize( apr_pool_t *p, + apr_pool_t *plog, + apr_pool_t *ptemp, + server_rec *sv ) +{ + mod_tps_server_configuration *sc = NULL; + char *cfg_path_file = NULL; + int status; + + /* Retrieve the TPS module. */ + sc = ( ( mod_tps_server_configuration * ) + ap_get_module_config( sv->module_config, + &MOD_TPS_CONFIG_KEY ) ); + + /* Check to see if the TPS module has been loaded. */ + if( sc->context != NULL ) { + return OK; + } + + /* Load the TPS module. */ + +#ifdef MEM_PROFILING + /* If memory profiling is enabled, turn on memory profiling. */ + MEM_init( MEM_AUDIT_FILE, MEM_DUMP_FILE ); +#endif + + /* Retrieve the path to where the configuration files are located, */ + /* and insure that the TPS module configuration file is located here. */ + if( sc->TPS_Configuration_File != NULL ) { + /* provide TPS Config File from <apache_server_root>/conf/httpd.conf */ + if( sc->TPS_Configuration_File[0] == '/' ) { + /* Complete path to TPS Config File is denoted */ + cfg_path_file = apr_psprintf( p, + "%s", + ( char * ) + sc->TPS_Configuration_File ); + } else { + /* TPS Config File is located relative to the Apache server root */ + cfg_path_file = apr_psprintf( p, + "%s/%s", + ( char * ) ap_server_root, + ( char * ) + sc->TPS_Configuration_File ); + } + } else { + /* Log information regarding this failure. */ + ap_log_error( "mod_tps_initialize", + __LINE__, APLOG_ERR, 0, sv, + "The tps module was installed incorrectly since the " + "parameter named '%s' is missing from the Apache " + "Configuration file!", + ( char * ) MOD_TPS_CONFIGURATION_FILE_PARAMETER ); + + /* Display information on the screen regarding this failure. */ + printf( "\nUnable to start Apache:\n" + " The tps module is missing the required parameter named\n" + " '%s' in the Apache Configuration file!\n", + ( char * ) MOD_TPS_CONFIGURATION_FILE_PARAMETER ); + + goto loser; + } + + /* Initialize the "server" member of mod_tps_server_configuration. */ + sc->context = new AP_Context( sv ); + + status = RA::Initialize( cfg_path_file, sc->context ); + if( status != RA_INITIALIZATION_SUCCESS ) { + /* Log information regarding this failure. */ + ap_log_error( "mod_tps_initialize", + __LINE__, APLOG_ERR, 0, sv, + "The tps module was installed incorrectly " + "since the file named '%s' does not exist!", + cfg_path_file ); + + /* Display information on the screen regarding this failure. */ + printf( "\nUnable to start Apache:\n" + " The tps module configuration file called\n" + " '%s' does not exist!\n", + cfg_path_file ); + + /* Since all members of mod_tps_server_configuration are allocated */ + /* from a pool, there is no need to unset any of these members. */ + + goto loser; + } + + /* Register a server termination routine. */ + apr_pool_cleanup_register( p, + sv, + mod_tps_terminate, + apr_pool_cleanup_null ); + + /* Log TPS module debug information. */ + RA::Debug( "mod_tps::mod_tps_initialize", + "The TPS module has been successfully loaded!" ); + + return OK; + +loser: + /* Log TPS module debug information. */ + RA::Debug( "mod_tps::mod_tps_initialize", + "Failed loading the TPS module!" ); + + if( sc->context != NULL ) { + /* Free TPS resources. */ + RA::Shutdown(); + + /* Since all members of mod_tps_server_configuration are allocated */ + /* from a pool, there is no need to unset any of these members. */ + } + +#ifdef MEM_PROFILING + /* If memory profiling is enabled, turn off memory profiling. */ + MEM_shutdown(); +#endif + + /* Shutdown all APR library routines. */ + /* NOTE: This automatically destroys all memory pools. */ + apr_terminate(); + + /* Terminate the entire Apache server */ + tps_die(); + + return DECLINED; +} + + +/** + * mod_tps_handler handles the protocol between the token client + * and the RA (Session) + */ +static int +mod_tps_handler( request_rec *rq ) +{ + char buf[1024]; + int ret_code = DECLINED; + int status = DECLINED; + RA_Session *session = NULL; + RA_Begin_Op_Msg *begin_op_msg = NULL; + NameValueSet *extensions = NULL; + const char *tenc = apr_table_get(rq->headers_in, "Transfer-Encoding"); + + /* Log TPS module debug information. */ + RA::Debug( "mod_tps::mod_tps_handler", + "mod_tps::mod_tps_handler" ); + + RA::Debug( "mod_tps::mod_tps_handler", + "uri '%s'", rq->uri); + + /* XXX: We need to change "nk_service" to "tps", + and need to update ESC. */ + if (strcmp(rq->handler,"nk_service") != 0) { + RA::Debug( "mod_tps::mod_tps_handler", + "DECLINED uri '%s'", rq->uri); + return DECLINED; + } + + RA::Debug( "mod_tps::mod_tps_handler", + "uri '%s' DONE", rq->uri); + + /* + * check to see if the http request contains + * "transfer-encoding: chunked" + */ + /* XXX: rq->chunked not set to true even in the chunked mode */ + if(!tenc || PL_strcasecmp(tenc, "chunked") != 0) { + /* print the following when browser accesses directly */ + strcpy( buf, "<HTML>Registration Authority</HTML>" ); + + /* write out the data */ + ( void ) ap_rwrite( ( const void * ) buf, strlen( buf ), rq ); + + ret_code = OK; + + return ret_code; + } + + /* request contains chunked encoding */ + session = mod_tps_create_session( rq ); + + /* read in the data present on the connection */ + begin_op_msg = ( RA_Begin_Op_Msg * ) session->ReadMsg(); + if( begin_op_msg == NULL ) { + /* Log TPS module error information. */ + RA::Error( "mod_tps::mod_tps_handler", + "no begin op found" ); + goto loser; + } + + /* retrieve the extensions */ + extensions = begin_op_msg->GetExtensions(); + + /* perform the appropriate processing based upon the type of operation */ + if( begin_op_msg->GetOpType() == OP_ENROLL ) { + status = m_enroll_processor.Process( session, extensions ); + } else if( begin_op_msg->GetOpType() == OP_UNBLOCK ) { + status = m_unblock_processor.Process( session, extensions ); + } else if( begin_op_msg->GetOpType() == OP_RESET_PIN ) { + status = m_pin_reset_processor.Process( session, extensions ); + } else if( begin_op_msg->GetOpType() == OP_RENEW ) { + status = m_renew_processor.Process( session, extensions ); + } else if( begin_op_msg->GetOpType() == OP_FORMAT ) { + status = m_format_processor.Process( session, extensions ); + } else { + /* Log TPS module error information. */ + RA::Error( "mod_tps::mod_tps_handler", + "unknown operation requested (op='%d')", + begin_op_msg->GetOpType() ); + goto loser; + } /* if */ + + ret_code = OK; + +loser: + /* determine the results of the operation and report it */ + if( begin_op_msg != NULL ) { + int result; + + if( status == 0 ) { + result = RESULT_GOOD; + } else { + result = RESULT_ERROR; + } + + RA_End_Op_Msg *end_op = new RA_End_Op_Msg( begin_op_msg->GetOpType(), + result, + status ); + + session->WriteMsg( end_op ); + + if( end_op != NULL ) { + delete end_op; + end_op = NULL; + } + } + + /* remove any operational messages */ + if( begin_op_msg != NULL ) { + delete begin_op_msg; + begin_op_msg = NULL; + } + + /* remove any sessions */ + if( session != NULL ) { + mod_tps_destroy_session( session ); + session = NULL; + } + + return ret_code; +} /* mod_tps_handler */ + + + +/* _________________________________________________________________ +** +** TPS Module Command Phase +** _________________________________________________________________ +*/ + +static const char *mod_tps_get_config_path_file( cmd_parms *cmd, + void *mconfig, + const char *tpsconf ) +{ + if( cmd->path ) { + ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, + "The %s config param cannot be specified " + "in a Directory section.", + cmd->directive->directive ); + } else { + mod_tps_server_configuration *sc = NULL; + + /* Retrieve the TPS module. */ + sc = ( ( mod_tps_server_configuration * ) + ap_get_module_config( cmd->server->module_config, + &MOD_TPS_CONFIG_KEY ) ); + + /* Initialize the "TPS Configuration File" */ + /* member of mod_tps_server_configuration. */ + sc->TPS_Configuration_File = apr_pstrdup( cmd->pool, tpsconf ); + } + + return NULL; +} + + +static const command_rec mod_tps_config_cmds[] = { + AP_INIT_TAKE1( MOD_TPS_CONFIGURATION_FILE_PARAMETER, + ( const char*(*)() ) mod_tps_get_config_path_file, + NULL, + RSRC_CONF, + MOD_TPS_CONFIGURATION_FILE_USAGE ), + { NULL } +}; + + + +/* _________________________________________________________________ +** +** TPS Module Server Configuration Creation Phase +** _________________________________________________________________ +*/ + +/** + * Create TPS module server configuration + */ +static void * +mod_tps_config_server_create( apr_pool_t *p, server_rec *sv ) +{ + /* Initialize all APR library routines. */ + apr_initialize(); + + /* Create a memory pool for this server. */ + mod_tps_server_configuration *sc = ( mod_tps_server_configuration * ) + apr_pcalloc( p, + ( apr_size_t ) + sizeof( *sc ) ); + + /* Initialize all members of mod_tps_server_configuration. */ + sc->TPS_Configuration_File = NULL; + sc->context = NULL; + + return sc; +} + + + +/* _________________________________________________________________ +** +** TPS Module Registration Phase +** _________________________________________________________________ +*/ + +static void +mod_tps_register_hooks( apr_pool_t *p ) +{ + static const char *const mod_tps_preloaded_modules[] = { "mod_nss.c", + NULL }; + static const char *const mod_tps_postloaded_modules[] = { NULL }; + + ap_hook_post_config( mod_tps_initialize, + mod_tps_preloaded_modules, + mod_tps_postloaded_modules, + APR_HOOK_MIDDLE ); + + ap_hook_handler( mod_tps_handler, + mod_tps_preloaded_modules, + mod_tps_postloaded_modules, + APR_HOOK_MIDDLE ); +} + + +module TPS_PUBLIC MOD_TPS_CONFIG_KEY = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + mod_tps_config_server_create, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + mod_tps_config_cmds, /* table of configuration directives */ + mod_tps_register_hooks /* register hooks */ +}; + + + +#ifdef __cplusplus +} +#endif + |