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
12namespace net {
13
14namespace test {
15
16struct GssNameMockImpl {
17  std::string name;
18  gss_OID_desc name_type;
19};
20
21}  // namespace test
22
23namespace {
24
25// gss_OID helpers.
26// NOTE: gss_OID's do not own the data they point to, which should be static.
27void ClearOid(gss_OID dest) {
28  if (!dest)
29    return;
30  dest->length = 0;
31  dest->elements = NULL;
32}
33
34void 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
45void 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.
55void 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
63void 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
76void 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
85std::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
94void 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.
101void 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
109void 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
119std::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
129void 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
137namespace test {
138
139GssContextMockImpl::GssContextMockImpl()
140  : lifetime_rec(0),
141    ctx_flags(0),
142    locally_initiated(0),
143    open(0) {
144  ClearOid(&mech_type);
145}
146
147GssContextMockImpl::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
157GssContextMockImpl::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
173GssContextMockImpl::~GssContextMockImpl() {
174  ClearOid(&mech_type);
175}
176
177void 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
190MockGSSAPILibrary::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
201MockGSSAPILibrary::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
229MockGSSAPILibrary::SecurityContextQuery::~SecurityContextQuery() {}
230
231MockGSSAPILibrary::MockGSSAPILibrary() {
232}
233
234MockGSSAPILibrary::~MockGSSAPILibrary() {
235}
236
237void 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
254bool MockGSSAPILibrary::Init() {
255  return true;
256}
257
258// These methods match the ones in the GSSAPI library.
259OM_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
286OM_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
302OM_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
313OM_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
335OM_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
353OM_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
413OM_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
426OM_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
443OM_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