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.
ClearOid(gss_OID dest)28 void ClearOid(gss_OID dest) {
29 if (!dest)
30 return;
31 dest->length = 0;
32 dest->elements = NULL;
33 }
34
SetOid(gss_OID dest,const void * src,size_t length)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
CopyOid(gss_OID dest,const gss_OID_desc * src)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.
ClearBuffer(gss_buffer_t dest)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
SetBuffer(gss_buffer_t dest,const void * src,size_t length)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
CopyBuffer(gss_buffer_t dest,const gss_buffer_t src)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
BufferToString(const gss_buffer_t src)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
BufferFromString(const std::string & src,gss_buffer_t dest)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.
ClearName(gss_name_t dest)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
SetName(gss_name_t dest,const void * src,size_t length)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
NameToString(const gss_name_t & src)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
NameFromString(const std::string & src,gss_name_t dest)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
GssContextMockImpl()140 GssContextMockImpl::GssContextMockImpl()
141 : lifetime_rec(0),
142 ctx_flags(0),
143 locally_initiated(0),
144 open(0) {
145 ClearOid(&mech_type);
146 }
147
GssContextMockImpl(const GssContextMockImpl & other)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
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)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
~GssContextMockImpl()174 GssContextMockImpl::~GssContextMockImpl() {
175 ClearOid(&mech_type);
176 }
177
Assign(const GssContextMockImpl & other)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
SecurityContextQuery()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
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)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
~SecurityContextQuery()230 MockGSSAPILibrary::SecurityContextQuery::~SecurityContextQuery() {}
231
MockGSSAPILibrary()232 MockGSSAPILibrary::MockGSSAPILibrary() {
233 }
234
~MockGSSAPILibrary()235 MockGSSAPILibrary::~MockGSSAPILibrary() {
236 }
237
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)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
Init()255 bool MockGSSAPILibrary::Init() {
256 return true;
257 }
258
259 // These methods match the ones in the GSSAPI library.
import_name(OM_uint32 * minor_status,const gss_buffer_t input_name_buffer,const gss_OID input_name_type,gss_name_t * output_name)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
release_name(OM_uint32 * minor_status,gss_name_t * input_name)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
release_buffer(OM_uint32 * minor_status,gss_buffer_t buffer)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
display_name(OM_uint32 * minor_status,const gss_name_t input_name,gss_buffer_t output_name_buffer,gss_OID * output_name_type)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
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)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
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)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
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)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
delete_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_buffer_t output_token)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
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)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