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