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