Home | History | Annotate | Download | only in http
      1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/http/mock_gssapi_library_posix.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/string_util.h"
      9 #include "base/stringprintf.h"
     10 #include "net/third_party/gssapi/gssapi.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace net {
     14 
     15 namespace test {
     16 
     17 struct GssNameMockImpl {
     18   std::string name;
     19   gss_OID_desc name_type;
     20 };
     21 
     22 }  // namespace test
     23 
     24 namespace {
     25 
     26 // gss_OID helpers.
     27 // NOTE: gss_OID's do not own the data they point to, which should be static.
     28 void ClearOid(gss_OID dest) {
     29   if (!dest)
     30     return;
     31   dest->length = 0;
     32   dest->elements = NULL;
     33 }
     34 
     35 void SetOid(gss_OID dest, const void* src, size_t length) {
     36   if (!dest)
     37     return;
     38   ClearOid(dest);
     39   if (!src)
     40     return;
     41   dest->length = length;
     42   if (length)
     43     dest->elements = const_cast<void*>(src);
     44 }
     45 
     46 void CopyOid(gss_OID dest, const gss_OID_desc* src) {
     47   if (!dest)
     48     return;
     49   ClearOid(dest);
     50   if (!src)
     51     return;
     52   SetOid(dest, src->elements, src->length);
     53 }
     54 
     55 // gss_buffer_t helpers.
     56 void ClearBuffer(gss_buffer_t dest) {
     57   if (!dest)
     58     return;
     59   dest->length = 0;
     60   delete [] reinterpret_cast<char*>(dest->value);
     61   dest->value = NULL;
     62 }
     63 
     64 void SetBuffer(gss_buffer_t dest, const void* src, size_t length) {
     65   if (!dest)
     66     return;
     67   ClearBuffer(dest);
     68   if (!src)
     69     return;
     70   dest->length = length;
     71   if (length) {
     72     dest->value = new char[length];
     73     memcpy(dest->value, src, length);
     74   }
     75 }
     76 
     77 void CopyBuffer(gss_buffer_t dest, const gss_buffer_t src) {
     78   if (!dest)
     79     return;
     80   ClearBuffer(dest);
     81   if (!src)
     82     return;
     83   SetBuffer(dest, src->value, src->length);
     84 }
     85 
     86 std::string BufferToString(const gss_buffer_t src) {
     87   std::string dest;
     88   if (!src)
     89     return dest;
     90   const char* string = reinterpret_cast<char*>(src->value);
     91   dest.assign(string, src->length);
     92   return dest;
     93 }
     94 
     95 void BufferFromString(const std::string& src, gss_buffer_t dest) {
     96   if (!dest)
     97     return;
     98   SetBuffer(dest, src.c_str(), src.length());
     99 }
    100 
    101 // gss_name_t helpers.
    102 void ClearName(gss_name_t dest) {
    103   if (!dest)
    104     return;
    105   test::GssNameMockImpl* name = reinterpret_cast<test::GssNameMockImpl*>(dest);
    106   name->name.clear();
    107   ClearOid(&name->name_type);
    108 }
    109 
    110 void SetName(gss_name_t dest, const void* src, size_t length) {
    111   if (!dest)
    112     return;
    113   ClearName(dest);
    114   if (!src)
    115     return;
    116   test::GssNameMockImpl* name = reinterpret_cast<test::GssNameMockImpl*>(dest);
    117   name->name.assign(reinterpret_cast<const char*>(src), length);
    118 }
    119 
    120 std::string NameToString(const gss_name_t& src) {
    121   std::string dest;
    122   if (!src)
    123     return dest;
    124   test::GssNameMockImpl* string =
    125       reinterpret_cast<test::GssNameMockImpl*>(src);
    126   dest = string->name;
    127   return dest;
    128 }
    129 
    130 void NameFromString(const std::string& src, gss_name_t dest) {
    131   if (!dest)
    132     return;
    133   SetName(dest, src.c_str(), src.length());
    134 }
    135 
    136 }  // namespace
    137 
    138 namespace test {
    139 
    140 GssContextMockImpl::GssContextMockImpl()
    141   : lifetime_rec(0),
    142     ctx_flags(0),
    143     locally_initiated(0),
    144     open(0) {
    145   ClearOid(&mech_type);
    146 }
    147 
    148 GssContextMockImpl::GssContextMockImpl(const GssContextMockImpl& other)
    149   : src_name(other.src_name),
    150     targ_name(other.targ_name),
    151     lifetime_rec(other.lifetime_rec),
    152     ctx_flags(other.ctx_flags),
    153     locally_initiated(other.locally_initiated),
    154     open(other.open) {
    155   CopyOid(&mech_type, &other.mech_type);
    156 }
    157 
    158 GssContextMockImpl::GssContextMockImpl(const char* src_name_in,
    159                                        const char* targ_name_in,
    160                                        OM_uint32 lifetime_rec_in,
    161                                        const gss_OID_desc& mech_type_in,
    162                                        OM_uint32 ctx_flags_in,
    163                                        int locally_initiated_in,
    164                                        int open_in)
    165     : src_name(src_name_in ? src_name_in : ""),
    166       targ_name(targ_name_in ? targ_name_in : ""),
    167       lifetime_rec(lifetime_rec_in),
    168       ctx_flags(ctx_flags_in),
    169       locally_initiated(locally_initiated_in),
    170       open(open_in) {
    171   CopyOid(&mech_type, &mech_type_in);
    172 }
    173 
    174 GssContextMockImpl::~GssContextMockImpl() {
    175   ClearOid(&mech_type);
    176 }
    177 
    178 void GssContextMockImpl::Assign(
    179     const GssContextMockImpl& other) {
    180   if (&other == this)
    181     return;
    182   src_name = other.src_name;
    183   targ_name = other.targ_name;
    184   lifetime_rec = other.lifetime_rec;
    185   CopyOid(&mech_type, &other.mech_type);
    186   ctx_flags = other.ctx_flags;
    187   locally_initiated = other.locally_initiated;
    188   open = other.open;
    189 }
    190 
    191 MockGSSAPILibrary::SecurityContextQuery::SecurityContextQuery()
    192     : expected_package(),
    193       response_code(0),
    194       minor_response_code(0),
    195       context_info() {
    196   expected_input_token.length = 0;
    197   expected_input_token.value = NULL;
    198   output_token.length = 0;
    199   output_token.value = NULL;
    200 }
    201 
    202 MockGSSAPILibrary::SecurityContextQuery::SecurityContextQuery(
    203     const std::string& in_expected_package,
    204     OM_uint32 in_response_code,
    205     OM_uint32 in_minor_response_code,
    206     const test::GssContextMockImpl& in_context_info,
    207     const char* in_expected_input_token,
    208     const char* in_output_token)
    209     : expected_package(in_expected_package),
    210       response_code(in_response_code),
    211       minor_response_code(in_minor_response_code),
    212       context_info(in_context_info) {
    213   if (in_expected_input_token) {
    214     expected_input_token.length = strlen(in_expected_input_token);
    215     expected_input_token.value = const_cast<char*>(in_expected_input_token);
    216   } else {
    217     expected_input_token.length = 0;
    218     expected_input_token.value = NULL;
    219   }
    220 
    221   if (in_output_token) {
    222     output_token.length = strlen(in_output_token);
    223     output_token.value = const_cast<char*>(in_output_token);
    224   } else {
    225     output_token.length = 0;
    226     output_token.value = NULL;
    227   }
    228 }
    229 
    230 MockGSSAPILibrary::SecurityContextQuery::~SecurityContextQuery() {}
    231 
    232 MockGSSAPILibrary::MockGSSAPILibrary() {
    233 }
    234 
    235 MockGSSAPILibrary::~MockGSSAPILibrary() {
    236 }
    237 
    238 void MockGSSAPILibrary::ExpectSecurityContext(
    239     const std::string& expected_package,
    240     OM_uint32 response_code,
    241     OM_uint32 minor_response_code,
    242     const GssContextMockImpl& context_info,
    243     const gss_buffer_desc& expected_input_token,
    244     const gss_buffer_desc& output_token) {
    245   SecurityContextQuery security_query;
    246   security_query.expected_package = expected_package;
    247   security_query.response_code = response_code;
    248   security_query.minor_response_code = minor_response_code;
    249   security_query.context_info.Assign(context_info);
    250   security_query.expected_input_token = expected_input_token;
    251   security_query.output_token = output_token;
    252   expected_security_queries_.push_back(security_query);
    253 }
    254 
    255 bool MockGSSAPILibrary::Init() {
    256   return true;
    257 }
    258 
    259 // These methods match the ones in the GSSAPI library.
    260 OM_uint32 MockGSSAPILibrary::import_name(
    261       OM_uint32* minor_status,
    262       const gss_buffer_t input_name_buffer,
    263       const gss_OID input_name_type,
    264       gss_name_t* output_name) {
    265   if (minor_status)
    266     *minor_status = 0;
    267   if (!output_name)
    268     return GSS_S_BAD_NAME;
    269   if (!input_name_buffer)
    270     return GSS_S_CALL_BAD_STRUCTURE;
    271   if (!input_name_type)
    272     return GSS_S_BAD_NAMETYPE;
    273   GssNameMockImpl* output = new GssNameMockImpl;
    274   if (output == NULL)
    275     return GSS_S_FAILURE;
    276   output->name_type.length = 0;
    277   output->name_type.elements = NULL;
    278 
    279   // Save the data.
    280   output->name = BufferToString(input_name_buffer);
    281   CopyOid(&output->name_type, input_name_type);
    282   *output_name = output;
    283 
    284   return GSS_S_COMPLETE;
    285 }
    286 
    287 OM_uint32 MockGSSAPILibrary::release_name(
    288       OM_uint32* minor_status,
    289       gss_name_t* input_name) {
    290   if (minor_status)
    291     *minor_status = 0;
    292   if (!input_name)
    293     return GSS_S_BAD_NAME;
    294   if (!*input_name)
    295     return GSS_S_COMPLETE;
    296   GssNameMockImpl* name = *reinterpret_cast<GssNameMockImpl**>(input_name);
    297   ClearName(*input_name);
    298   delete name;
    299   *input_name = NULL;
    300   return GSS_S_COMPLETE;
    301 }
    302 
    303 OM_uint32 MockGSSAPILibrary::release_buffer(
    304       OM_uint32* minor_status,
    305       gss_buffer_t buffer) {
    306   if (minor_status)
    307     *minor_status = 0;
    308   if (!buffer)
    309     return GSS_S_BAD_NAME;
    310   ClearBuffer(buffer);
    311   return GSS_S_COMPLETE;
    312 }
    313 
    314 OM_uint32 MockGSSAPILibrary::display_name(
    315     OM_uint32* minor_status,
    316     const gss_name_t input_name,
    317     gss_buffer_t output_name_buffer,
    318     gss_OID* output_name_type) {
    319   if (minor_status)
    320     *minor_status = 0;
    321   if (!input_name)
    322     return GSS_S_BAD_NAME;
    323   if (!output_name_buffer)
    324     return GSS_S_CALL_BAD_STRUCTURE;
    325   if (!output_name_type)
    326     return GSS_S_CALL_BAD_STRUCTURE;
    327   std::string name(NameToString(input_name));
    328   BufferFromString(name, output_name_buffer);
    329   GssNameMockImpl* internal_name =
    330       *reinterpret_cast<GssNameMockImpl**>(input_name);
    331   if (output_name_type)
    332     *output_name_type = internal_name ? &internal_name->name_type : NULL;
    333   return GSS_S_COMPLETE;
    334 }
    335 
    336 OM_uint32 MockGSSAPILibrary::display_status(
    337       OM_uint32* minor_status,
    338       OM_uint32 status_value,
    339       int status_type,
    340       const gss_OID mech_type,
    341       OM_uint32* message_context,
    342       gss_buffer_t status_string) {
    343   if (minor_status)
    344     *minor_status = 0;
    345   std::string msg = base::StringPrintf("Value: %u, Type %u",
    346                                        status_value,
    347                                        status_type);
    348   if (message_context)
    349     *message_context = 0;
    350   BufferFromString(msg, status_string);
    351   return GSS_S_COMPLETE;
    352 }
    353 
    354 OM_uint32 MockGSSAPILibrary::init_sec_context(
    355       OM_uint32* minor_status,
    356       const gss_cred_id_t initiator_cred_handle,
    357       gss_ctx_id_t* context_handle,
    358       const gss_name_t target_name,
    359       const gss_OID mech_type,
    360       OM_uint32 req_flags,
    361       OM_uint32 time_req,
    362       const gss_channel_bindings_t input_chan_bindings,
    363       const gss_buffer_t input_token,
    364       gss_OID* actual_mech_type,
    365       gss_buffer_t output_token,
    366       OM_uint32* ret_flags,
    367       OM_uint32* time_rec) {
    368   if (minor_status)
    369     *minor_status = 0;
    370   if (!context_handle)
    371     return GSS_S_CALL_BAD_STRUCTURE;
    372   GssContextMockImpl** internal_context_handle =
    373       reinterpret_cast<test::GssContextMockImpl**>(context_handle);
    374   // Create it if necessary.
    375   if (!*internal_context_handle) {
    376     *internal_context_handle = new GssContextMockImpl;
    377   }
    378   EXPECT_TRUE(*internal_context_handle);
    379   GssContextMockImpl& context = **internal_context_handle;
    380   if (expected_security_queries_.empty()) {
    381     return GSS_S_UNAVAILABLE;
    382   }
    383   SecurityContextQuery security_query = expected_security_queries_.front();
    384   expected_security_queries_.pop_front();
    385   EXPECT_EQ(std::string("Negotiate"), security_query.expected_package);
    386   OM_uint32 major_status = security_query.response_code;
    387   if (minor_status)
    388     *minor_status = security_query.minor_response_code;
    389   context.src_name = security_query.context_info.src_name;
    390   context.targ_name = security_query.context_info.targ_name;
    391   context.lifetime_rec = security_query.context_info.lifetime_rec;
    392   CopyOid(&context.mech_type, &security_query.context_info.mech_type);
    393   context.ctx_flags = security_query.context_info.ctx_flags;
    394   context.locally_initiated = security_query.context_info.locally_initiated;
    395   context.open = security_query.context_info.open;
    396   if (!input_token) {
    397     EXPECT_FALSE(security_query.expected_input_token.length);
    398   } else {
    399     EXPECT_EQ(input_token->length, security_query.expected_input_token.length);
    400     if (input_token->length) {
    401       EXPECT_EQ(0, memcmp(input_token->value,
    402                           security_query.expected_input_token.value,
    403                           input_token->length));
    404     }
    405   }
    406   CopyBuffer(output_token, &security_query.output_token);
    407   if (actual_mech_type)
    408     CopyOid(*actual_mech_type, mech_type);
    409   if (ret_flags)
    410     *ret_flags = req_flags;
    411   return major_status;
    412 }
    413 
    414 OM_uint32 MockGSSAPILibrary::wrap_size_limit(
    415       OM_uint32* minor_status,
    416       const gss_ctx_id_t context_handle,
    417       int conf_req_flag,
    418       gss_qop_t qop_req,
    419       OM_uint32 req_output_size,
    420       OM_uint32* max_input_size) {
    421   if (minor_status)
    422     *minor_status = 0;
    423   ADD_FAILURE();
    424   return GSS_S_UNAVAILABLE;
    425 }
    426 
    427 OM_uint32 MockGSSAPILibrary::delete_sec_context(
    428       OM_uint32* minor_status,
    429       gss_ctx_id_t* context_handle,
    430       gss_buffer_t output_token) {
    431   if (minor_status)
    432     *minor_status = 0;
    433   if (!context_handle)
    434     return GSS_S_CALL_BAD_STRUCTURE;
    435   GssContextMockImpl** internal_context_handle =
    436       reinterpret_cast<GssContextMockImpl**>(context_handle);
    437   if (*internal_context_handle) {
    438     delete *internal_context_handle;
    439     *internal_context_handle = NULL;
    440   }
    441   return GSS_S_COMPLETE;
    442 }
    443 
    444 OM_uint32 MockGSSAPILibrary::inquire_context(
    445     OM_uint32* minor_status,
    446     const gss_ctx_id_t context_handle,
    447     gss_name_t* src_name,
    448     gss_name_t* targ_name,
    449     OM_uint32* lifetime_rec,
    450     gss_OID* mech_type,
    451     OM_uint32* ctx_flags,
    452     int* locally_initiated,
    453     int* open) {
    454   if (minor_status)
    455     *minor_status = 0;
    456   if (!context_handle)
    457     return GSS_S_CALL_BAD_STRUCTURE;
    458   GssContextMockImpl* internal_context_ptr =
    459       reinterpret_cast<GssContextMockImpl*>(context_handle);
    460   GssContextMockImpl& context = *internal_context_ptr;
    461   if (src_name)
    462     NameFromString(context.src_name, *src_name);
    463   if (targ_name)
    464     NameFromString(context.targ_name, *targ_name);
    465   if (lifetime_rec)
    466     *lifetime_rec = context.lifetime_rec;
    467   if (mech_type)
    468     CopyOid(*mech_type, &context.mech_type);
    469   if (ctx_flags)
    470     *ctx_flags = context.ctx_flags;
    471   if (locally_initiated)
    472     *locally_initiated = context.locally_initiated;
    473   if (open)
    474     *open = context.open;
    475   return GSS_S_COMPLETE;
    476 }
    477 
    478 }  // namespace test
    479 
    480 }  // namespace net
    481 
    482