dse-driver 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }