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