1// Copyright (c) 2012 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#ifndef NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_
6#define NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_
7
8#include <string>
9
10#include "base/gtest_prod_util.h"
11#include "base/native_library.h"
12#include "net/base/net_export.h"
13#include "net/http/http_auth.h"
14
15#if defined(OS_MACOSX) && defined(MAC_OS_X_VERSION_10_9) && \
16    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
17// Including gssapi.h directly is deprecated in the 10.9 SDK.
18#include <GSS/gssapi.h>
19#else
20#include <gssapi.h>
21#endif
22
23namespace net {
24
25// Mechanism OID for GSSAPI. We always use SPNEGO.
26NET_EXPORT_PRIVATE extern gss_OID CHROME_GSS_SPNEGO_MECH_OID_DESC;
27
28// GSSAPILibrary is introduced so unit tests can mock the calls to the GSSAPI
29// library. The default implementation attempts to load one of the standard
30// GSSAPI library implementations, then simply passes the arguments on to
31// that implementation.
32class NET_EXPORT_PRIVATE GSSAPILibrary {
33 public:
34  virtual ~GSSAPILibrary() {}
35
36  // Initializes the library, including any necessary dynamic libraries.
37  // This is done separately from construction (which happens at startup time)
38  // in order to delay work until the class is actually needed.
39  virtual bool Init() = 0;
40
41  // These methods match the ones in the GSSAPI library.
42  virtual OM_uint32 import_name(
43      OM_uint32* minor_status,
44      const gss_buffer_t input_name_buffer,
45      const gss_OID input_name_type,
46      gss_name_t* output_name) = 0;
47  virtual OM_uint32 release_name(
48      OM_uint32* minor_status,
49      gss_name_t* input_name) = 0;
50  virtual OM_uint32 release_buffer(
51      OM_uint32* minor_status,
52      gss_buffer_t buffer) = 0;
53  virtual OM_uint32 display_name(
54      OM_uint32* minor_status,
55      const gss_name_t input_name,
56      gss_buffer_t output_name_buffer,
57      gss_OID* output_name_type) = 0;
58  virtual OM_uint32 display_status(
59      OM_uint32* minor_status,
60      OM_uint32 status_value,
61      int status_type,
62      const gss_OID mech_type,
63      OM_uint32* message_contex,
64      gss_buffer_t status_string) = 0;
65  virtual OM_uint32 init_sec_context(
66      OM_uint32* minor_status,
67      const gss_cred_id_t initiator_cred_handle,
68      gss_ctx_id_t* context_handle,
69      const gss_name_t target_name,
70      const gss_OID mech_type,
71      OM_uint32 req_flags,
72      OM_uint32 time_req,
73      const gss_channel_bindings_t input_chan_bindings,
74      const gss_buffer_t input_token,
75      gss_OID* actual_mech_type,
76      gss_buffer_t output_token,
77      OM_uint32* ret_flags,
78      OM_uint32* time_rec) = 0;
79  virtual OM_uint32 wrap_size_limit(
80      OM_uint32* minor_status,
81      const gss_ctx_id_t context_handle,
82      int conf_req_flag,
83      gss_qop_t qop_req,
84      OM_uint32 req_output_size,
85      OM_uint32* max_input_size) = 0;
86  virtual OM_uint32 delete_sec_context(
87      OM_uint32* minor_status,
88      gss_ctx_id_t* context_handle,
89      gss_buffer_t output_token) = 0;
90  virtual OM_uint32 inquire_context(
91      OM_uint32* minor_status,
92      const gss_ctx_id_t context_handle,
93      gss_name_t* src_name,
94      gss_name_t* targ_name,
95      OM_uint32* lifetime_rec,
96      gss_OID* mech_type,
97      OM_uint32* ctx_flags,
98      int* locally_initiated,
99      int* open) = 0;
100
101};
102
103// GSSAPISharedLibrary class is defined here so that unit tests can access it.
104class NET_EXPORT_PRIVATE GSSAPISharedLibrary : public GSSAPILibrary {
105 public:
106  // If |gssapi_library_name| is empty, hard-coded default library names are
107  // used.
108  explicit GSSAPISharedLibrary(const std::string& gssapi_library_name);
109  virtual ~GSSAPISharedLibrary();
110
111  // GSSAPILibrary methods:
112  virtual bool Init() OVERRIDE;
113  virtual OM_uint32 import_name(
114      OM_uint32* minor_status,
115      const gss_buffer_t input_name_buffer,
116      const gss_OID input_name_type,
117      gss_name_t* output_name) OVERRIDE;
118  virtual OM_uint32 release_name(
119      OM_uint32* minor_status,
120      gss_name_t* input_name) OVERRIDE;
121  virtual OM_uint32 release_buffer(
122      OM_uint32* minor_status,
123      gss_buffer_t buffer) OVERRIDE;
124  virtual OM_uint32 display_name(
125      OM_uint32* minor_status,
126      const gss_name_t input_name,
127      gss_buffer_t output_name_buffer,
128      gss_OID* output_name_type) OVERRIDE;
129  virtual OM_uint32 display_status(
130      OM_uint32* minor_status,
131      OM_uint32 status_value,
132      int status_type,
133      const gss_OID mech_type,
134      OM_uint32* message_contex,
135      gss_buffer_t status_string) OVERRIDE;
136  virtual OM_uint32 init_sec_context(
137      OM_uint32* minor_status,
138      const gss_cred_id_t initiator_cred_handle,
139      gss_ctx_id_t* context_handle,
140      const gss_name_t target_name,
141      const gss_OID mech_type,
142      OM_uint32 req_flags,
143      OM_uint32 time_req,
144      const gss_channel_bindings_t input_chan_bindings,
145      const gss_buffer_t input_token,
146      gss_OID* actual_mech_type,
147      gss_buffer_t output_token,
148      OM_uint32* ret_flags,
149      OM_uint32* time_rec) OVERRIDE;
150  virtual OM_uint32 wrap_size_limit(
151      OM_uint32* minor_status,
152      const gss_ctx_id_t context_handle,
153      int conf_req_flag,
154      gss_qop_t qop_req,
155      OM_uint32 req_output_size,
156      OM_uint32* max_input_size) OVERRIDE;
157  virtual OM_uint32 delete_sec_context(
158      OM_uint32* minor_status,
159      gss_ctx_id_t* context_handle,
160      gss_buffer_t output_token) OVERRIDE;
161  virtual OM_uint32 inquire_context(
162      OM_uint32* minor_status,
163      const gss_ctx_id_t context_handle,
164      gss_name_t* src_name,
165      gss_name_t* targ_name,
166      OM_uint32* lifetime_rec,
167      gss_OID* mech_type,
168      OM_uint32* ctx_flags,
169      int* locally_initiated,
170      int* open) OVERRIDE;
171
172 private:
173  typedef typeof(&gss_import_name) gss_import_name_type;
174  typedef typeof(&gss_release_name) gss_release_name_type;
175  typedef typeof(&gss_release_buffer) gss_release_buffer_type;
176  typedef typeof(&gss_display_name) gss_display_name_type;
177  typedef typeof(&gss_display_status) gss_display_status_type;
178  typedef typeof(&gss_init_sec_context) gss_init_sec_context_type;
179  typedef typeof(&gss_wrap_size_limit) gss_wrap_size_limit_type;
180  typedef typeof(&gss_delete_sec_context) gss_delete_sec_context_type;
181  typedef typeof(&gss_inquire_context) gss_inquire_context_type;
182
183  FRIEND_TEST_ALL_PREFIXES(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup);
184
185  bool InitImpl();
186  // Finds a usable dynamic library for GSSAPI and loads it.  The criteria are:
187  //   1. The library must exist.
188  //   2. The library must export the functions we need.
189  base::NativeLibrary LoadSharedLibrary();
190  bool BindMethods(base::NativeLibrary lib);
191
192  bool initialized_;
193
194  std::string gssapi_library_name_;
195  // Need some way to invalidate the library.
196  base::NativeLibrary gssapi_library_;
197
198  // Function pointers
199  gss_import_name_type import_name_;
200  gss_release_name_type release_name_;
201  gss_release_buffer_type release_buffer_;
202  gss_display_name_type display_name_;
203  gss_display_status_type display_status_;
204  gss_init_sec_context_type init_sec_context_;
205  gss_wrap_size_limit_type wrap_size_limit_;
206  gss_delete_sec_context_type delete_sec_context_;
207  gss_inquire_context_type inquire_context_;
208};
209
210// ScopedSecurityContext releases a gss_ctx_id_t when it goes out of
211// scope.
212class ScopedSecurityContext {
213 public:
214  explicit ScopedSecurityContext(GSSAPILibrary* gssapi_lib);
215  ~ScopedSecurityContext();
216
217  gss_ctx_id_t get() const { return security_context_; }
218  gss_ctx_id_t* receive() { return &security_context_; }
219
220 private:
221  gss_ctx_id_t security_context_;
222  GSSAPILibrary* gssapi_lib_;
223
224  DISALLOW_COPY_AND_ASSIGN(ScopedSecurityContext);
225};
226
227
228// TODO(ahendrickson): Share code with HttpAuthSSPI.
229class NET_EXPORT_PRIVATE HttpAuthGSSAPI {
230 public:
231  HttpAuthGSSAPI(GSSAPILibrary* library,
232                 const std::string& scheme,
233                 const gss_OID gss_oid);
234  ~HttpAuthGSSAPI();
235
236  bool Init();
237
238  bool NeedsIdentity() const;
239
240  bool AllowsExplicitCredentials() const;
241
242  HttpAuth::AuthorizationResult ParseChallenge(
243      HttpAuth::ChallengeTokenizer* tok);
244
245  // Generates an authentication token.
246  // The return value is an error code. If it's not |OK|, the value of
247  // |*auth_token| is unspecified.
248  // |spn| is the Service Principal Name of the server that the token is
249  // being generated for.
250  // If this is the first round of a multiple round scheme, credentials are
251  // obtained using |*credentials|. If |credentials| is NULL, the default
252  // credentials are used instead.
253  int GenerateAuthToken(const AuthCredentials* credentials,
254                        const std::wstring& spn,
255                        std::string* auth_token);
256
257  // Delegation is allowed on the Kerberos ticket. This allows certain servers
258  // to act as the user, such as an IIS server retrieiving data from a
259  // Kerberized MSSQL server.
260  void Delegate();
261
262 private:
263  int GetNextSecurityToken(const std::wstring& spn,
264                           gss_buffer_t in_token,
265                           gss_buffer_t out_token);
266
267  std::string scheme_;
268  gss_OID gss_oid_;
269  GSSAPILibrary* library_;
270  std::string decoded_server_auth_token_;
271  ScopedSecurityContext scoped_sec_context_;
272  bool can_delegate_;
273};
274
275}  // namespace net
276
277#endif  // NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_
278