dse-driver 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ M2YwYzhhNTk0YzgxZTFkMzg2NGQyZWI0MDkyYmIxZTg4OWQ3OGZhZA==
5
+ data.tar.gz: !binary |-
6
+ YTQ2NWY1NDJjMTRiY2U5OGVhNWVjNTYxYTc3YjAxOTM3NmEyMDA3ZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NGEyZTY1NmMxMThiZTY0YjJlZmQxMzE2MmUxY2ZkODUwNGUyOWVmZjZkNTIw
10
+ NjQ3OWI3NDJiMjJhMTM3ODkxOGEzMGZhNmRjYjdhMzI5YjMzNWY0ZjZiZTFj
11
+ ZjcyNzlkMTU0YjIyNDRmODQ2Yjk3ODU3ODc3Yzk1NDdkY2ZmNzk=
12
+ data.tar.gz: !binary |-
13
+ OGU0MTJkOTNmMzQ0YzgzNGNlNWMwMjQ1MDllNzhkNTcxYWQ5NTFhZTc4NTc2
14
+ NTc4NTljNDczNzQyOThlNDk5NTc3NjcwNzAwYmI0MjUyMjc1YTkyNjFmM2M5
15
+ YTVmZTZjZGMzMGU5ZTY2NzcwNzVmY2JhYWQ0ZGRhZTQ0YzRmODM=
data/.yardopts ADDED
@@ -0,0 +1,13 @@
1
+ --no-private
2
+ --markup markdown
3
+ --type-tag expected_errors:"Expected Errors"
4
+ --tag jira_ticket:"JIRA Ticket"
5
+ --type-tag expected_result:"Expected Result"
6
+ --tag test_assumptions:"Test Assumptions"
7
+ --tag test_category:"Test Category"
8
+
9
+ lib/**/*.rb
10
+ integration/**/*.rb
11
+ -- README
12
+
13
+ load_plugins: true
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # DataStax Enterprise Ruby Driver
2
+
3
+ *NOTE: The DataStax Enterprise Ruby Driver can be used solely with DataStax Enterprise. Please consult [the license](http://www.datastax.com/terms/datastax-dse-driver-license-terms).*
4
+
5
+ This driver is built on top of the [DataStax Ruby driver for Apache Cassandra](http://docs.datastax.com/en/latest-ruby-driver/ruby-driver/whatsNew.html)
6
+ and enhanced for the adaptive data management and mixed workload capabilities
7
+ provided by DSE. Therefore a lot of the underlying concepts are the same.
8
+
9
+ ## Documentation
10
+ Driver documentation can be found [here](http://docs.datastax.com/en/latest-dse-ruby-driver/ruby-driver/whatsNew.html).
11
+
12
+ In particular, you'll find our [Features](http://docs.datastax.com/en/latest-dse-ruby-driver/supplemental/features) and
13
+ [API](http://docs.datastax.com/en/latest-dse-ruby-driver/supplemental/api) sections very enlightening.
14
+
15
+ ## Feedback Requested
16
+ *Help us focus our efforts!* [Provide your input](http://goo.gl/forms/pCs8PTpHLf) on the Ruby Driver
17
+ Platform and Runtime Survey (we kept it short).
18
+
19
+ If you find an issue, please file an issue in our [public JIRA](https://datastax-oss.atlassian.net/browse/RUBY).
20
+ *Please be sure to specify the affects-version (DSE-1.X.Y).*
21
+
22
+ You can also post questions in [our forum](https://groups.google.com/a/lists.datastax.com/forum/#!forum/ruby-driver-user).
23
+
24
+ ## Features
25
+
26
+ This driver exposes the following features of DSE 5.0:
27
+
28
+ * <a href="features/graph#graph">Graph</a>
29
+ * <a href="features/authentication#authentication">Authentication</a> with nodes running DSE
30
+ * <a href="features/geospatial#geospatial-types">Geospatial types</a>
31
+
32
+ Note that this driver is fully compatible with previous versions of DataStax Enterprise.
33
+
34
+ ## Installation
35
+ The driver is named dse-driver on rubygems.org and can easily be installed with Bundler or the gem program. It will
36
+ download the appropriate Cassandra driver as well.
37
+
38
+ ## Upgrade
39
+ The driver is intended to have the same look and feel as the core driver to make upgrading from the core driver
40
+ trivial. The only change is to replace references to the <code>Cassandra</code> module with <code>Dse</code> when
41
+ creating the cluster object:
42
+
43
+ ```ruby
44
+ require 'dse'
45
+
46
+ # This returns a Dse::Cluster instance
47
+ cluster = Dse.cluster
48
+
49
+ # This returns a Dse::Session instance
50
+ session = cluster.connect
51
+ rs = session.execute('select * from system.local')
52
+ ```
53
+
54
+ ## Determining driver versions
55
+ Within a script or irb, you can determine the exact versions of the dse and core drivers by accessing the VERSION
56
+ constant of the appropriate module:
57
+
58
+ ```ruby
59
+ require 'dse'
60
+
61
+ puts "Dse Driver Version: #{Dse::VERSION}"
62
+ puts "Cassandra Driver Version: #{Cassandra::VERSION}"
63
+ ```
64
+
65
+ ## Compatibility
66
+ Although this driver exposes new features introduced in DSE 5.0, it is fully compatible and supported for use with
67
+ previous versions of DSE.
68
+
69
+ ## License
70
+ Copyright (C) 2016 DataStax Inc.
71
+
72
+ The full license terms are available at http://www.datastax.com/terms/datastax-dse-driver-license-terms
@@ -0,0 +1,27 @@
1
+ #--
2
+ # Copyright (C) 2016 DataStax Inc.
3
+ #
4
+ # This software can be used solely with DataStax Enterprise. Please consult the license at
5
+ # http://www.datastax.com/terms/datastax-dse-driver-license-terms
6
+ #++
7
+
8
+ require 'mkmf'
9
+
10
+ LIBDIR = RbConfig::CONFIG['libdir']
11
+ INCLUDEDIR = RbConfig::CONFIG['includedir']
12
+
13
+ HEADER_DIRS = [INCLUDEDIR, '/usr/include'].freeze
14
+
15
+ LIB_DIRS = [LIBDIR, '/usr/lib'].freeze
16
+
17
+ dir_config('gssapi', HEADER_DIRS, LIB_DIRS)
18
+
19
+ abort 'no gssapi header' unless find_header('gssapi/gssapi.h')
20
+
21
+ abort 'gssapi library not found' unless find_library('gssapi_krb5', 'gss_release_buffer')
22
+
23
+ # On Mac at least, there are a lot of deprecated api warnings for gss_* functions. Disable that!
24
+ # rubocop:disable Style/GlobalVars
25
+ $CFLAGS << ' -Wno-deprecated'
26
+
27
+ create_makefile('gss_api_context')
@@ -0,0 +1,129 @@
1
+ //--
2
+ // Copyright (C) 2016 DataStax Inc.
3
+ //
4
+ // This software can be used solely with DataStax Enterprise. Please consult the license at
5
+ // http://www.datastax.com/terms/datastax-dse-driver-license-terms
6
+ //++
7
+
8
+ #include <ruby.h>
9
+
10
+ #include "kerberosgss.h"
11
+
12
+ //-----------------------------------------------------------------------------
13
+ // Platform-specific functions and macros
14
+
15
+ #ifdef _MSC_VER
16
+ typedef unsigned __int64 uint64_t;
17
+ typedef __int64 int64_t;
18
+
19
+ #else
20
+ #include <stdint.h>
21
+ #endif
22
+
23
+ VALUE e_GssError;
24
+ static void rb_free_context(gss_client_state* state);
25
+
26
+ static gss_client_state* get_state(VALUE self) {
27
+ gss_client_state* p;
28
+ Data_Get_Struct(self, gss_client_state, p);
29
+ return p;
30
+ }
31
+
32
+ static VALUE
33
+ rb_context_alloc(VALUE klass)
34
+ {
35
+ gss_client_state* state = ALLOC(gss_client_state);
36
+ state->response = NULL;
37
+ return Data_Wrap_Struct(klass, 0, rb_free_context, state);
38
+ }
39
+
40
+ static VALUE
41
+ rb_context_initialize(VALUE self, VALUE _service, VALUE _principal, VALUE _ticket_cache)
42
+ {
43
+ const char* service = StringValuePtr(_service);
44
+ const char* principal = _principal == Qnil ? NULL : StringValuePtr(_principal);
45
+ const char* ticket_cache = _ticket_cache == Qnil ? NULL : StringValuePtr(_ticket_cache);
46
+
47
+ long int gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
48
+ gss_client_state* state = get_state(self);
49
+
50
+ authenticate_gss_client_init(service, principal, ticket_cache, gss_flags, NULL, GSS_C_NO_OID, state);
51
+
52
+ return self;
53
+ }
54
+
55
+ static void
56
+ rb_free_context(gss_client_state* state)
57
+ {
58
+ if (state) {
59
+ authenticate_gss_client_clean(state);
60
+ xfree(state);
61
+ }
62
+ }
63
+
64
+ static VALUE
65
+ rb_context_response(VALUE self)
66
+ {
67
+ gss_client_state* state = get_state(self);
68
+ return state->response ? rb_str_new(state->response, state->responseLen) : Qnil;
69
+ }
70
+
71
+ static VALUE
72
+ rb_context_step(VALUE self, VALUE rb_challenge)
73
+ {
74
+ const char* challenge = StringValuePtr(rb_challenge);
75
+ int challenge_len = RSTRING_LEN(rb_challenge);
76
+
77
+ gss_client_state* state = get_state(self);
78
+ VALUE rc = INT2NUM(authenticate_gss_client_step(state, challenge, challenge_len));
79
+ return rb_ary_new3(2, rc, rb_context_response(self));
80
+ }
81
+
82
+ static VALUE
83
+ rb_context_wrap(VALUE self, VALUE rb_challenge)
84
+ {
85
+ const char* challenge = StringValuePtr(rb_challenge);
86
+ int challenge_len = RSTRING_LEN(rb_challenge);
87
+
88
+ gss_client_state* state = get_state(self);
89
+ authenticate_gss_client_wrap(state, challenge, challenge_len);
90
+ return rb_context_response(self);
91
+ }
92
+
93
+ static VALUE
94
+ rb_context_unwrap(VALUE self, VALUE rb_challenge)
95
+ {
96
+ const char* challenge = StringValuePtr(rb_challenge);
97
+ int challenge_len = RSTRING_LEN(rb_challenge);
98
+
99
+ gss_client_state* state = get_state(self);
100
+ authenticate_gss_client_unwrap(state, challenge, challenge_len);
101
+ return rb_context_response(self);
102
+ }
103
+
104
+ static VALUE
105
+ rb_context_user_name(VALUE self)
106
+ {
107
+ gss_client_state* state = get_state(self);
108
+ return state->username ? rb_str_new2(state->username) : Qnil;
109
+ }
110
+
111
+ void
112
+ Init_gss_api_context()
113
+ {
114
+ VALUE currentContainer;
115
+
116
+ currentContainer = rb_define_module_under(rb_cObject, "Dse");
117
+ currentContainer = rb_define_module_under(currentContainer, "Auth");
118
+ currentContainer = rb_define_module_under(currentContainer, "Providers");
119
+ currentContainer = rb_define_class_under(currentContainer, "GssApiContext", rb_cObject);
120
+ rb_define_alloc_func(currentContainer, rb_context_alloc);
121
+ rb_define_method(currentContainer, "initialize", rb_context_initialize, 3);
122
+ rb_define_method(currentContainer, "step", rb_context_step, 1);
123
+ rb_define_method(currentContainer, "response", rb_context_response, 0);
124
+ rb_define_method(currentContainer, "wrap", rb_context_wrap, 1);
125
+ rb_define_method(currentContainer, "unwrap", rb_context_unwrap, 1);
126
+ rb_define_method(currentContainer, "user_name", rb_context_user_name, 0);
127
+
128
+ e_GssError = rb_define_class_under(currentContainer, "Error", rb_eStandardError);
129
+ }
@@ -0,0 +1,407 @@
1
+ /**
2
+ * Copyright (c) 2006-2016 Apple Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ **/
16
+
17
+ #include "kerberosgss.h"
18
+
19
+ #include <stdio.h>
20
+ #include <stdlib.h>
21
+ #include <string.h>
22
+ #include <arpa/inet.h>
23
+
24
+ #include <ruby.h>
25
+
26
+ /* This is allocated in gss_api_context.c. */
27
+ extern VALUE e_GssError;
28
+
29
+ static void raise_gss_error(OM_uint32 err_maj, OM_uint32 err_min)
30
+ {
31
+ OM_uint32 maj_stat, min_stat;
32
+ OM_uint32 msg_ctx = 0;
33
+ gss_buffer_desc status_string;
34
+ char buf_maj[512];
35
+ char buf_min[512];
36
+
37
+ do {
38
+ maj_stat = gss_display_status(
39
+ &min_stat,
40
+ err_maj,
41
+ GSS_C_GSS_CODE,
42
+ GSS_C_NO_OID,
43
+ &msg_ctx,
44
+ &status_string
45
+ );
46
+ if (GSS_ERROR(maj_stat)) {
47
+ break;
48
+ }
49
+ strncpy(buf_maj, (char*) status_string.value, sizeof(buf_maj));
50
+ gss_release_buffer(&min_stat, &status_string);
51
+
52
+ if (!err_min) {
53
+ // There is no minor error to report.
54
+ break;
55
+ }
56
+
57
+ maj_stat = gss_display_status(
58
+ &min_stat,
59
+ err_min,
60
+ GSS_C_MECH_CODE,
61
+ GSS_C_NULL_OID,
62
+ &msg_ctx,
63
+ &status_string
64
+ );
65
+ if (! GSS_ERROR(maj_stat)) {
66
+ strncpy(buf_min, (char*) status_string.value, sizeof(buf_min));
67
+ gss_release_buffer(&min_stat, &status_string);
68
+ }
69
+ } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
70
+
71
+ if (err_min) {
72
+ rb_raise(e_GssError, "%s: %s", buf_maj, buf_min);
73
+ } else {
74
+ rb_raise(e_GssError, "%s", buf_maj);
75
+ }
76
+ }
77
+
78
+ void clear_response(gss_client_state* state)
79
+ {
80
+ if (state->response != NULL) {
81
+ free(state->response);
82
+ state->response = NULL;
83
+ state->responseLen = 0;
84
+ state->responseConf = 0;
85
+ }
86
+ }
87
+
88
+ static void save_response(gss_client_state* state, gss_buffer_desc* output_token, int conf)
89
+ {
90
+ OM_uint32 min_stat, maj_stat;
91
+
92
+ if (output_token->length) {
93
+ state->response = malloc(output_token->length);
94
+ memcpy(state->response, output_token->value, output_token->length);
95
+ state->responseLen = output_token->length;
96
+ state->responseConf = conf;
97
+
98
+ maj_stat = gss_release_buffer(&min_stat, output_token);
99
+ }
100
+ }
101
+
102
+ static void copy_challenge_to_token(const char* challenge, int challenge_len, gss_buffer_desc* token)
103
+ {
104
+ if (challenge && *challenge) {
105
+ // It would be great to just send the challenge along straight, but
106
+ // token->value is a non-const void*, so gss_* functions might
107
+ // mutate it.
108
+
109
+ token->value = malloc(challenge_len);
110
+ memcpy(token->value, challenge, challenge_len);
111
+ token->length = challenge_len;
112
+ }
113
+ }
114
+
115
+ void authenticate_gss_client_init(
116
+ const char* service, const char* principal, const char* ticket_cache, long int gss_flags,
117
+ gss_server_state* delegatestate, gss_OID mech_oid, gss_client_state* state
118
+ )
119
+ {
120
+ OM_uint32 maj_stat;
121
+ OM_uint32 min_stat;
122
+ gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
123
+ gss_buffer_desc principal_token = GSS_C_EMPTY_BUFFER;
124
+
125
+ state->server_name = GSS_C_NO_NAME;
126
+ state->mech_oid = mech_oid;
127
+ state->context = GSS_C_NO_CONTEXT;
128
+ state->gss_flags = gss_flags;
129
+ state->client_creds = GSS_C_NO_CREDENTIAL;
130
+ state->username = NULL;
131
+ clear_response(state);
132
+
133
+ // Import server name first
134
+ name_token.length = strlen(service);
135
+ name_token.value = (char *)service;
136
+
137
+ maj_stat = gss_import_name(
138
+ &min_stat, &name_token, gss_krb5_nt_service_name, &state->server_name
139
+ );
140
+
141
+ if (GSS_ERROR(maj_stat)) {
142
+ raise_gss_error(maj_stat, min_stat);
143
+ }
144
+
145
+ if (ticket_cache && *ticket_cache) {
146
+ maj_stat = gss_krb5_ccache_name(&min_stat, ticket_cache, NULL);
147
+ if (GSS_ERROR(maj_stat)) {
148
+ raise_gss_error(maj_stat, min_stat);
149
+ }
150
+ }
151
+
152
+ // Use the delegate credentials if they exist
153
+ if (delegatestate && delegatestate->client_creds != GSS_C_NO_CREDENTIAL) {
154
+ state->client_creds = delegatestate->client_creds;
155
+ }
156
+ // If available use the principal to extract its associated credentials
157
+ else if (principal && *principal) {
158
+ gss_name_t name;
159
+ principal_token.length = strlen(principal);
160
+ principal_token.value = (char *)principal;
161
+
162
+ maj_stat = gss_import_name(
163
+ &min_stat, &principal_token, GSS_C_NT_USER_NAME, &name
164
+ );
165
+ if (GSS_ERROR(maj_stat)) {
166
+ raise_gss_error(maj_stat, min_stat);
167
+ }
168
+ maj_stat = gss_acquire_cred(
169
+ &min_stat, name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
170
+ GSS_C_INITIATE, &state->client_creds, NULL, NULL
171
+ );
172
+ if (GSS_ERROR(maj_stat)) {
173
+ raise_gss_error(maj_stat, min_stat);
174
+ }
175
+
176
+ maj_stat = gss_release_name(&min_stat, &name);
177
+ if (GSS_ERROR(maj_stat)) {
178
+ raise_gss_error(maj_stat, min_stat);
179
+ }
180
+ }
181
+ }
182
+
183
+ int authenticate_gss_client_clean(gss_client_state *state)
184
+ {
185
+ OM_uint32 maj_stat;
186
+ OM_uint32 min_stat;
187
+ int ret = AUTH_GSS_COMPLETE;
188
+
189
+ if (state->context != GSS_C_NO_CONTEXT) {
190
+ maj_stat = gss_delete_sec_context(
191
+ &min_stat, &state->context, GSS_C_NO_BUFFER
192
+ );
193
+ }
194
+ if (state->server_name != GSS_C_NO_NAME) {
195
+ maj_stat = gss_release_name(&min_stat, &state->server_name);
196
+ }
197
+ if (
198
+ state->client_creds != GSS_C_NO_CREDENTIAL &&
199
+ ! (state->gss_flags & GSS_C_DELEG_FLAG)
200
+ ) {
201
+ maj_stat = gss_release_cred(&min_stat, &state->client_creds);
202
+ }
203
+ if (state->username != NULL) {
204
+ free(state->username);
205
+ state->username = NULL;
206
+ }
207
+ clear_response(state);
208
+
209
+ return ret;
210
+ }
211
+
212
+ int authenticate_gss_client_step(
213
+ gss_client_state* state, const char* challenge, int challenge_len
214
+ ) {
215
+ OM_uint32 maj_stat;
216
+ OM_uint32 min_stat;
217
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
218
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
219
+ int ret = AUTH_GSS_CONTINUE;
220
+
221
+ // Always clear out the old response
222
+ clear_response(state);
223
+
224
+ // If there is a challenge (data from the server) we need to give it to GSS
225
+ copy_challenge_to_token(challenge, challenge_len, &input_token);
226
+
227
+ // Do GSSAPI step
228
+ maj_stat = gss_init_sec_context(
229
+ &min_stat,
230
+ state->client_creds,
231
+ &state->context,
232
+ state->server_name,
233
+ state->mech_oid,
234
+ (OM_uint32)state->gss_flags,
235
+ 0,
236
+ GSS_C_NO_CHANNEL_BINDINGS,
237
+ &input_token,
238
+ NULL,
239
+ &output_token,
240
+ NULL,
241
+ NULL
242
+ );
243
+
244
+ if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED)) {
245
+ if (output_token.value) {
246
+ gss_release_buffer(&min_stat, &output_token);
247
+ }
248
+ if (input_token.value) {
249
+ free(input_token.value);
250
+ }
251
+ raise_gss_error(maj_stat, min_stat);
252
+ }
253
+
254
+ ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE;
255
+
256
+ // Grab the client response to send back to the server
257
+ save_response(state, &output_token, 0);
258
+
259
+ // Try to get the user name if we have completed all GSS operations
260
+ if (ret == AUTH_GSS_COMPLETE) {
261
+ gss_name_t gssuser = GSS_C_NO_NAME;
262
+ maj_stat = gss_inquire_context(&min_stat, state->context, &gssuser, NULL, NULL, NULL, NULL, NULL, NULL);
263
+ if (GSS_ERROR(maj_stat)) {
264
+ if (input_token.value) {
265
+ free(input_token.value);
266
+ }
267
+ if (output_token.value) {
268
+ gss_release_buffer(&min_stat, &output_token);
269
+ }
270
+ raise_gss_error(maj_stat, min_stat);
271
+ }
272
+
273
+ gss_buffer_desc name_token;
274
+ name_token.length = 0;
275
+ maj_stat = gss_display_name(&min_stat, gssuser, &name_token, NULL);
276
+ if (GSS_ERROR(maj_stat)) {
277
+ if (name_token.value) {
278
+ gss_release_buffer(&min_stat, &name_token);
279
+ }
280
+ gss_release_name(&min_stat, &gssuser);
281
+
282
+ if (input_token.value) {
283
+ free(input_token.value);
284
+ }
285
+ if (output_token.value) {
286
+ gss_release_buffer(&min_stat, &output_token);
287
+ }
288
+ raise_gss_error(maj_stat, min_stat);
289
+ } else {
290
+ if (state->username != NULL) {
291
+ free(state->username);
292
+ state->username = NULL;
293
+ }
294
+ state->username = (char *)malloc(name_token.length + 1);
295
+ strncpy(state->username, (char*) name_token.value, name_token.length);
296
+ state->username[name_token.length] = 0;
297
+ gss_release_buffer(&min_stat, &name_token);
298
+ gss_release_name(&min_stat, &gssuser);
299
+ }
300
+ }
301
+
302
+ end:
303
+ if (output_token.value) {
304
+ gss_release_buffer(&min_stat, &output_token);
305
+ }
306
+ if (input_token.value) {
307
+ free(input_token.value);
308
+ }
309
+ return ret;
310
+ }
311
+
312
+ int authenticate_gss_client_unwrap(
313
+ gss_client_state *state, const char *challenge, int challenge_len
314
+ ) {
315
+ OM_uint32 maj_stat;
316
+ OM_uint32 min_stat;
317
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
318
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
319
+ int ret = AUTH_GSS_CONTINUE;
320
+ int conf = 0;
321
+
322
+ // Always clear out the old response
323
+ clear_response(state);
324
+
325
+ // If there is a challenge (data from the server) we need to give it to GSS
326
+ copy_challenge_to_token(challenge, challenge_len, &input_token);
327
+
328
+ // Do GSSAPI step
329
+ maj_stat = gss_unwrap(
330
+ &min_stat,
331
+ state->context,
332
+ &input_token,
333
+ &output_token,
334
+ &conf,
335
+ NULL
336
+ );
337
+
338
+ if (maj_stat != GSS_S_COMPLETE) {
339
+ if (output_token.value) {
340
+ gss_release_buffer(&min_stat, &output_token);
341
+ }
342
+ if (input_token.value) {
343
+ free(input_token.value);
344
+ }
345
+ raise_gss_error(maj_stat, min_stat);
346
+ } else {
347
+ ret = AUTH_GSS_COMPLETE;
348
+ }
349
+
350
+ // Grab the client response
351
+ save_response(state, &output_token, conf);
352
+
353
+ end:
354
+ if (output_token.value) {
355
+ gss_release_buffer(&min_stat, &output_token);
356
+ }
357
+ if (input_token.value) {
358
+ free(input_token.value);
359
+ }
360
+ return ret;
361
+ }
362
+
363
+ int authenticate_gss_client_wrap(
364
+ gss_client_state* state, const char* challenge, int challenge_len
365
+ ) {
366
+ OM_uint32 maj_stat;
367
+ OM_uint32 min_stat;
368
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
369
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
370
+ int ret = AUTH_GSS_CONTINUE;
371
+ char buf[4096], server_conf_flags;
372
+ unsigned long buf_size;
373
+
374
+ // Always clear out the old response
375
+ clear_response(state);
376
+
377
+ copy_challenge_to_token(challenge, challenge_len, &input_token);
378
+
379
+ // Do GSSAPI wrap
380
+ maj_stat = gss_wrap(
381
+ &min_stat,
382
+ state->context,
383
+ 0,
384
+ GSS_C_QOP_DEFAULT,
385
+ &input_token,
386
+ NULL,
387
+ &output_token
388
+ );
389
+
390
+ if (maj_stat != GSS_S_COMPLETE) {
391
+ if (output_token.value) {
392
+ gss_release_buffer(&min_stat, &output_token);
393
+ }
394
+ raise_gss_error(maj_stat, min_stat);
395
+ } else {
396
+ ret = AUTH_GSS_COMPLETE;
397
+ }
398
+
399
+ // Grab the client response to send back to the server
400
+ save_response(state, &output_token, 0);
401
+
402
+ end:
403
+ if (output_token.value) {
404
+ gss_release_buffer(&min_stat, &output_token);
405
+ }
406
+ return ret;
407
+ }