| // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/http/mock_gssapi_library_posix.h" |
| |
| #include "base/logging.h" |
| #include "base/string_util.h" |
| #include "base/stringprintf.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace net { |
| |
| namespace test { |
| |
| struct GssNameMockImpl { |
| std::string name; |
| gss_OID_desc name_type; |
| }; |
| |
| } // namespace test |
| |
| namespace { |
| |
| // gss_OID helpers. |
| // NOTE: gss_OID's do not own the data they point to, which should be static. |
| void ClearOid(gss_OID dest) { |
| if (!dest) |
| return; |
| dest->length = 0; |
| dest->elements = NULL; |
| } |
| |
| void SetOid(gss_OID dest, const void* src, size_t length) { |
| if (!dest) |
| return; |
| ClearOid(dest); |
| if (!src) |
| return; |
| dest->length = length; |
| if (length) |
| dest->elements = const_cast<void*>(src); |
| } |
| |
| void CopyOid(gss_OID dest, const gss_OID_desc* src) { |
| if (!dest) |
| return; |
| ClearOid(dest); |
| if (!src) |
| return; |
| SetOid(dest, src->elements, src->length); |
| } |
| |
| // gss_buffer_t helpers. |
| void ClearBuffer(gss_buffer_t dest) { |
| if (!dest) |
| return; |
| dest->length = 0; |
| delete [] reinterpret_cast<char*>(dest->value); |
| dest->value = NULL; |
| } |
| |
| void SetBuffer(gss_buffer_t dest, const void* src, size_t length) { |
| if (!dest) |
| return; |
| ClearBuffer(dest); |
| if (!src) |
| return; |
| dest->length = length; |
| if (length) { |
| dest->value = new char[length]; |
| memcpy(dest->value, src, length); |
| } |
| } |
| |
| void CopyBuffer(gss_buffer_t dest, const gss_buffer_t src) { |
| if (!dest) |
| return; |
| ClearBuffer(dest); |
| if (!src) |
| return; |
| SetBuffer(dest, src->value, src->length); |
| } |
| |
| std::string BufferToString(const gss_buffer_t src) { |
| std::string dest; |
| if (!src) |
| return dest; |
| const char* string = reinterpret_cast<char*>(src->value); |
| dest.assign(string, src->length); |
| return dest; |
| } |
| |
| void BufferFromString(const std::string& src, gss_buffer_t dest) { |
| if (!dest) |
| return; |
| SetBuffer(dest, src.c_str(), src.length()); |
| } |
| |
| // gss_name_t helpers. |
| void ClearName(gss_name_t dest) { |
| if (!dest) |
| return; |
| test::GssNameMockImpl* name = reinterpret_cast<test::GssNameMockImpl*>(dest); |
| name->name.clear(); |
| ClearOid(&name->name_type); |
| } |
| |
| void SetName(gss_name_t dest, const void* src, size_t length) { |
| if (!dest) |
| return; |
| ClearName(dest); |
| if (!src) |
| return; |
| test::GssNameMockImpl* name = reinterpret_cast<test::GssNameMockImpl*>(dest); |
| name->name.assign(reinterpret_cast<const char*>(src), length); |
| } |
| |
| std::string NameToString(const gss_name_t& src) { |
| std::string dest; |
| if (!src) |
| return dest; |
| test::GssNameMockImpl* string = |
| reinterpret_cast<test::GssNameMockImpl*>(src); |
| dest = string->name; |
| return dest; |
| } |
| |
| void NameFromString(const std::string& src, gss_name_t dest) { |
| if (!dest) |
| return; |
| SetName(dest, src.c_str(), src.length()); |
| } |
| |
| } // namespace |
| |
| namespace test { |
| |
| GssContextMockImpl::GssContextMockImpl() |
| : lifetime_rec(0), |
| ctx_flags(0), |
| locally_initiated(0), |
| open(0) { |
| ClearOid(&mech_type); |
| } |
| |
| GssContextMockImpl::GssContextMockImpl(const GssContextMockImpl& other) |
| : src_name(other.src_name), |
| targ_name(other.targ_name), |
| lifetime_rec(other.lifetime_rec), |
| ctx_flags(other.ctx_flags), |
| locally_initiated(other.locally_initiated), |
| open(other.open) { |
| CopyOid(&mech_type, &other.mech_type); |
| } |
| |
| GssContextMockImpl::GssContextMockImpl(const char* src_name_in, |
| const char* targ_name_in, |
| OM_uint32 lifetime_rec_in, |
| const gss_OID_desc& mech_type_in, |
| OM_uint32 ctx_flags_in, |
| int locally_initiated_in, |
| int open_in) |
| : src_name(src_name_in ? src_name_in : ""), |
| targ_name(targ_name_in ? targ_name_in : ""), |
| lifetime_rec(lifetime_rec_in), |
| ctx_flags(ctx_flags_in), |
| locally_initiated(locally_initiated_in), |
| open(open_in) { |
| CopyOid(&mech_type, &mech_type_in); |
| } |
| |
| GssContextMockImpl::~GssContextMockImpl() { |
| ClearOid(&mech_type); |
| } |
| |
| void GssContextMockImpl::Assign( |
| const GssContextMockImpl& other) { |
| if (&other == this) |
| return; |
| src_name = other.src_name; |
| targ_name = other.targ_name; |
| lifetime_rec = other.lifetime_rec; |
| CopyOid(&mech_type, &other.mech_type); |
| ctx_flags = other.ctx_flags; |
| locally_initiated = other.locally_initiated; |
| open = other.open; |
| } |
| |
| MockGSSAPILibrary::SecurityContextQuery::SecurityContextQuery() |
| : expected_package(), |
| response_code(0), |
| minor_response_code(0), |
| context_info() { |
| expected_input_token.length = 0; |
| expected_input_token.value = NULL; |
| output_token.length = 0; |
| output_token.value = NULL; |
| } |
| |
| MockGSSAPILibrary::SecurityContextQuery::SecurityContextQuery( |
| const std::string& in_expected_package, |
| OM_uint32 in_response_code, |
| OM_uint32 in_minor_response_code, |
| const test::GssContextMockImpl& in_context_info, |
| const char* in_expected_input_token, |
| const char* in_output_token) |
| : expected_package(in_expected_package), |
| response_code(in_response_code), |
| minor_response_code(in_minor_response_code), |
| context_info(in_context_info) { |
| if (in_expected_input_token) { |
| expected_input_token.length = strlen(in_expected_input_token); |
| expected_input_token.value = const_cast<char*>(in_expected_input_token); |
| } else { |
| expected_input_token.length = 0; |
| expected_input_token.value = NULL; |
| } |
| |
| if (in_output_token) { |
| output_token.length = strlen(in_output_token); |
| output_token.value = const_cast<char*>(in_output_token); |
| } else { |
| output_token.length = 0; |
| output_token.value = NULL; |
| } |
| } |
| |
| MockGSSAPILibrary::SecurityContextQuery::~SecurityContextQuery() {} |
| |
| MockGSSAPILibrary::MockGSSAPILibrary() { |
| } |
| |
| MockGSSAPILibrary::~MockGSSAPILibrary() { |
| } |
| |
| void MockGSSAPILibrary::ExpectSecurityContext( |
| const std::string& expected_package, |
| OM_uint32 response_code, |
| OM_uint32 minor_response_code, |
| const GssContextMockImpl& context_info, |
| const gss_buffer_desc& expected_input_token, |
| const gss_buffer_desc& output_token) { |
| SecurityContextQuery security_query; |
| security_query.expected_package = expected_package; |
| security_query.response_code = response_code; |
| security_query.minor_response_code = minor_response_code; |
| security_query.context_info.Assign(context_info); |
| security_query.expected_input_token = expected_input_token; |
| security_query.output_token = output_token; |
| expected_security_queries_.push_back(security_query); |
| } |
| |
| bool MockGSSAPILibrary::Init() { |
| return true; |
| } |
| |
| // These methods match the ones in the GSSAPI library. |
| OM_uint32 MockGSSAPILibrary::import_name( |
| OM_uint32* minor_status, |
| const gss_buffer_t input_name_buffer, |
| const gss_OID input_name_type, |
| gss_name_t* output_name) { |
| if (minor_status) |
| *minor_status = 0; |
| if (!output_name) |
| return GSS_S_BAD_NAME; |
| if (!input_name_buffer) |
| return GSS_S_CALL_BAD_STRUCTURE; |
| if (!input_name_type) |
| return GSS_S_BAD_NAMETYPE; |
| GssNameMockImpl* output = new GssNameMockImpl; |
| if (output == NULL) |
| return GSS_S_FAILURE; |
| output->name_type.length = 0; |
| output->name_type.elements = NULL; |
| |
| // Save the data. |
| output->name = BufferToString(input_name_buffer); |
| CopyOid(&output->name_type, input_name_type); |
| *output_name = reinterpret_cast<gss_name_t>(output); |
| |
| return GSS_S_COMPLETE; |
| } |
| |
| OM_uint32 MockGSSAPILibrary::release_name( |
| OM_uint32* minor_status, |
| gss_name_t* input_name) { |
| if (minor_status) |
| *minor_status = 0; |
| if (!input_name) |
| return GSS_S_BAD_NAME; |
| if (!*input_name) |
| return GSS_S_COMPLETE; |
| GssNameMockImpl* name = *reinterpret_cast<GssNameMockImpl**>(input_name); |
| ClearName(*input_name); |
| delete name; |
| *input_name = NULL; |
| return GSS_S_COMPLETE; |
| } |
| |
| OM_uint32 MockGSSAPILibrary::release_buffer( |
| OM_uint32* minor_status, |
| gss_buffer_t buffer) { |
| if (minor_status) |
| *minor_status = 0; |
| if (!buffer) |
| return GSS_S_BAD_NAME; |
| ClearBuffer(buffer); |
| return GSS_S_COMPLETE; |
| } |
| |
| OM_uint32 MockGSSAPILibrary::display_name( |
| OM_uint32* minor_status, |
| const gss_name_t input_name, |
| gss_buffer_t output_name_buffer, |
| gss_OID* output_name_type) { |
| if (minor_status) |
| *minor_status = 0; |
| if (!input_name) |
| return GSS_S_BAD_NAME; |
| if (!output_name_buffer) |
| return GSS_S_CALL_BAD_STRUCTURE; |
| if (!output_name_type) |
| return GSS_S_CALL_BAD_STRUCTURE; |
| std::string name(NameToString(input_name)); |
| BufferFromString(name, output_name_buffer); |
| GssNameMockImpl* internal_name = |
| *reinterpret_cast<GssNameMockImpl**>(input_name); |
| if (output_name_type) |
| *output_name_type = internal_name ? &internal_name->name_type : NULL; |
| return GSS_S_COMPLETE; |
| } |
| |
| OM_uint32 MockGSSAPILibrary::display_status( |
| OM_uint32* minor_status, |
| OM_uint32 status_value, |
| int status_type, |
| const gss_OID mech_type, |
| OM_uint32* message_context, |
| gss_buffer_t status_string) { |
| if (minor_status) |
| *minor_status = 0; |
| std::string msg = base::StringPrintf("Value: %u, Type %u", |
| status_value, |
| status_type); |
| if (message_context) |
| *message_context = 0; |
| BufferFromString(msg, status_string); |
| return GSS_S_COMPLETE; |
| } |
| |
| OM_uint32 MockGSSAPILibrary::init_sec_context( |
| OM_uint32* minor_status, |
| const gss_cred_id_t initiator_cred_handle, |
| gss_ctx_id_t* context_handle, |
| const gss_name_t target_name, |
| const gss_OID mech_type, |
| OM_uint32 req_flags, |
| OM_uint32 time_req, |
| const gss_channel_bindings_t input_chan_bindings, |
| const gss_buffer_t input_token, |
| gss_OID* actual_mech_type, |
| gss_buffer_t output_token, |
| OM_uint32* ret_flags, |
| OM_uint32* time_rec) { |
| if (minor_status) |
| *minor_status = 0; |
| if (!context_handle) |
| return GSS_S_CALL_BAD_STRUCTURE; |
| GssContextMockImpl** internal_context_handle = |
| reinterpret_cast<test::GssContextMockImpl**>(context_handle); |
| // Create it if necessary. |
| if (!*internal_context_handle) { |
| *internal_context_handle = new GssContextMockImpl; |
| } |
| EXPECT_TRUE(*internal_context_handle); |
| GssContextMockImpl& context = **internal_context_handle; |
| if (expected_security_queries_.empty()) { |
| return GSS_S_UNAVAILABLE; |
| } |
| SecurityContextQuery security_query = expected_security_queries_.front(); |
| expected_security_queries_.pop_front(); |
| EXPECT_EQ(std::string("Negotiate"), security_query.expected_package); |
| OM_uint32 major_status = security_query.response_code; |
| if (minor_status) |
| *minor_status = security_query.minor_response_code; |
| context.src_name = security_query.context_info.src_name; |
| context.targ_name = security_query.context_info.targ_name; |
| context.lifetime_rec = security_query.context_info.lifetime_rec; |
| CopyOid(&context.mech_type, &security_query.context_info.mech_type); |
| context.ctx_flags = security_query.context_info.ctx_flags; |
| context.locally_initiated = security_query.context_info.locally_initiated; |
| context.open = security_query.context_info.open; |
| if (!input_token) { |
| EXPECT_FALSE(security_query.expected_input_token.length); |
| } else { |
| EXPECT_EQ(input_token->length, security_query.expected_input_token.length); |
| if (input_token->length) { |
| EXPECT_EQ(0, memcmp(input_token->value, |
| security_query.expected_input_token.value, |
| input_token->length)); |
| } |
| } |
| CopyBuffer(output_token, &security_query.output_token); |
| if (actual_mech_type) |
| CopyOid(*actual_mech_type, mech_type); |
| if (ret_flags) |
| *ret_flags = req_flags; |
| return major_status; |
| } |
| |
| OM_uint32 MockGSSAPILibrary::wrap_size_limit( |
| OM_uint32* minor_status, |
| const gss_ctx_id_t context_handle, |
| int conf_req_flag, |
| gss_qop_t qop_req, |
| OM_uint32 req_output_size, |
| OM_uint32* max_input_size) { |
| if (minor_status) |
| *minor_status = 0; |
| ADD_FAILURE(); |
| return GSS_S_UNAVAILABLE; |
| } |
| |
| OM_uint32 MockGSSAPILibrary::delete_sec_context( |
| OM_uint32* minor_status, |
| gss_ctx_id_t* context_handle, |
| gss_buffer_t output_token) { |
| if (minor_status) |
| *minor_status = 0; |
| if (!context_handle) |
| return GSS_S_CALL_BAD_STRUCTURE; |
| GssContextMockImpl** internal_context_handle = |
| reinterpret_cast<GssContextMockImpl**>(context_handle); |
| if (*internal_context_handle) { |
| delete *internal_context_handle; |
| *internal_context_handle = NULL; |
| } |
| return GSS_S_COMPLETE; |
| } |
| |
| OM_uint32 MockGSSAPILibrary::inquire_context( |
| OM_uint32* minor_status, |
| const gss_ctx_id_t context_handle, |
| gss_name_t* src_name, |
| gss_name_t* targ_name, |
| OM_uint32* lifetime_rec, |
| gss_OID* mech_type, |
| OM_uint32* ctx_flags, |
| int* locally_initiated, |
| int* open) { |
| if (minor_status) |
| *minor_status = 0; |
| if (!context_handle) |
| return GSS_S_CALL_BAD_STRUCTURE; |
| GssContextMockImpl* internal_context_ptr = |
| reinterpret_cast<GssContextMockImpl*>(context_handle); |
| GssContextMockImpl& context = *internal_context_ptr; |
| if (src_name) |
| NameFromString(context.src_name, *src_name); |
| if (targ_name) |
| NameFromString(context.targ_name, *targ_name); |
| if (lifetime_rec) |
| *lifetime_rec = context.lifetime_rec; |
| if (mech_type) |
| CopyOid(*mech_type, &context.mech_type); |
| if (ctx_flags) |
| *ctx_flags = context.ctx_flags; |
| if (locally_initiated) |
| *locally_initiated = context.locally_initiated; |
| if (open) |
| *open = context.open; |
| return GSS_S_COMPLETE; |
| } |
| |
| } // namespace test |
| |
| } // namespace net |
| |