Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 2007-2011 Frediano Ziglio
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Library General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Library General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Library General Public
15 : * License along with this library; if not, write to the
16 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : * Boston, MA 02111-1307, USA.
18 : */
19 :
20 : #include <config.h>
21 :
22 : #if HAVE_STDLIB_H
23 : #include <stdlib.h>
24 : #endif /* HAVE_STDLIB_H */
25 :
26 : #include <ctype.h>
27 :
28 : #if HAVE_STRING_H
29 : #include <string.h>
30 : #endif /* HAVE_STRING_H */
31 :
32 : #if HAVE_UNISTD_H
33 : #include <unistd.h>
34 : #endif /* HAVE_UNISTD_H */
35 :
36 : #if HAVE_NETDB_H
37 : #include <netdb.h>
38 : #endif /* HAVE_NETDB_H */
39 :
40 : #if HAVE_SYS_SOCKET_H
41 : #include <sys/socket.h>
42 : #endif /* HAVE_SYS_SOCKET_H */
43 :
44 : #if HAVE_SYS_TYPES_H
45 : #include <sys/types.h>
46 : #endif /* HAVE_SYS_TYPES_H */
47 :
48 : #if HAVE_NETINET_IN_H
49 : #include <netinet/in.h>
50 : #endif /* HAVE_NETINET_IN_H */
51 :
52 : #if HAVE_ARPA_INET_H
53 : #include <arpa/inet.h>
54 : #endif /* HAVE_ARPA_INET_H */
55 :
56 : #if HAVE_COM_ERR_H
57 : #include <com_err.h>
58 : #endif /* HAVE_COM_ERR_H */
59 :
60 : #ifdef ENABLE_KRB5
61 :
62 : #ifdef __APPLE__
63 : #define KERBEROS_APPLE_DEPRECATED(x)
64 : #define GSSKRB_APPLE_DEPRECATED(x)
65 : #undef __API_DEPRECATED
66 : #define __API_DEPRECATED(x, y)
67 : #endif
68 : #include <gssapi/gssapi_krb5.h>
69 :
70 : #include <freetds/tds.h>
71 : #include <freetds/utils/string.h>
72 : #include <freetds/replacements.h>
73 : #include <freetds/tls.h>
74 :
75 : /**
76 : * \ingroup libtds
77 : * \defgroup auth Authentication
78 : * Functions for handling authentication.
79 : */
80 :
81 : /**
82 : * \addtogroup auth
83 : * @{
84 : */
85 :
86 : typedef struct tds_gss_auth
87 : {
88 : TDSAUTHENTICATION tds_auth;
89 : gss_ctx_id_t gss_context;
90 : gss_name_t target_name;
91 : char *sname;
92 : OM_uint32 last_stat;
93 : } TDSGSSAUTH;
94 :
95 : static TDSRET
96 0 : tds_gss_free(TDSCONNECTION *conn TDS_UNUSED, TDSAUTHENTICATION *tds_auth)
97 : {
98 0 : TDSGSSAUTH *auth = (TDSGSSAUTH *) tds_auth;
99 : OM_uint32 min_stat;
100 :
101 0 : if (auth->tds_auth.packet) {
102 : gss_buffer_desc send_tok;
103 :
104 0 : send_tok.value = (void *) auth->tds_auth.packet;
105 0 : send_tok.length = auth->tds_auth.packet_len;
106 0 : gss_release_buffer(&min_stat, &send_tok);
107 : }
108 :
109 0 : gss_release_name(&min_stat, &auth->target_name);
110 0 : free(auth->sname);
111 0 : if (auth->gss_context != GSS_C_NO_CONTEXT)
112 0 : gss_delete_sec_context(&min_stat, &auth->gss_context, GSS_C_NO_BUFFER);
113 0 : free(auth);
114 :
115 0 : return TDS_SUCCESS;
116 : }
117 :
118 : static TDSRET tds_gss_continue(TDSSOCKET * tds, TDSGSSAUTH * auth, gss_buffer_desc * token_ptr);
119 :
120 : static TDSRET
121 0 : tds7_gss_handle_next(TDSSOCKET *tds, TDSAUTHENTICATION *auth, size_t len)
122 : {
123 : TDSRET res;
124 : gss_buffer_desc recv_tok;
125 :
126 0 : if (((TDSGSSAUTH *) auth)->last_stat != GSS_S_CONTINUE_NEEDED)
127 : return TDS_FAIL;
128 :
129 0 : if (auth->packet) {
130 : OM_uint32 min_stat;
131 : gss_buffer_desc send_tok;
132 :
133 0 : send_tok.value = (void *) auth->packet;
134 0 : send_tok.length = auth->packet_len;
135 0 : gss_release_buffer(&min_stat, &send_tok);
136 0 : auth->packet = NULL;
137 : }
138 :
139 0 : recv_tok.length = len;
140 0 : recv_tok.value = tds_new(char, len);
141 0 : if (!recv_tok.value)
142 : return TDS_FAIL;
143 0 : tds_get_n(tds, recv_tok.value, len);
144 :
145 0 : res = tds_gss_continue(tds, (TDSGSSAUTH *) auth, &recv_tok);
146 0 : free(recv_tok.value);
147 0 : TDS_PROPAGATE(res);
148 :
149 0 : if (auth->packet_len) {
150 0 : tds->out_flag = TDS7_AUTH;
151 0 : tds_put_n(tds, auth->packet, auth->packet_len);
152 0 : return tds_flush_packet(tds);
153 : }
154 : return TDS_SUCCESS;
155 : }
156 :
157 : static TDSRET
158 0 : tds5_gss_handle_next(TDSSOCKET *tds, TDSAUTHENTICATION *auth, size_t len TDS_UNUSED)
159 : {
160 : gss_buffer_desc recv_tok;
161 : TDSPARAMINFO *info;
162 : TDSCOLUMN *col;
163 :
164 0 : if (((TDSGSSAUTH *) auth)->last_stat != GSS_S_CONTINUE_NEEDED)
165 : return TDS_FAIL;
166 :
167 0 : if (auth->packet) {
168 : OM_uint32 min_stat;
169 : gss_buffer_desc send_tok;
170 :
171 0 : send_tok.value = (void *) auth->packet;
172 0 : send_tok.length = auth->packet_len;
173 0 : gss_release_buffer(&min_stat, &send_tok);
174 0 : auth->packet = NULL;
175 : }
176 :
177 : /* parse from saved message */
178 0 : if (auth->msg_type != TDS5_MSG_SEC_OPAQUE)
179 : goto error;
180 0 : auth->msg_type = 0;
181 :
182 0 : info = tds->param_info;
183 0 : if (!info || info->num_cols < 5)
184 : goto error;
185 :
186 : /* check first column is int and TDS5_SEC_VERSION */
187 0 : col = info->columns[0];
188 0 : if (tds_get_conversion_type(col->on_server.column_type, col->on_server.column_size) != SYBINT4)
189 : goto error;
190 0 : if (*((TDS_INT *) col->column_data) != TDS5_SEC_VERSION)
191 : goto error;
192 :
193 : /* check second column is int and TDS5_SEC_SECSESS */
194 0 : col = info->columns[1];
195 0 : if (tds_get_conversion_type(col->on_server.column_type, col->on_server.column_size) != SYBINT4)
196 : goto error;
197 0 : if (*((TDS_INT *) col->column_data) != TDS5_SEC_SECSESS)
198 : goto error;
199 :
200 0 : col = info->columns[3];
201 0 : if (col->column_type != SYBLONGBINARY)
202 : goto error;
203 0 : recv_tok.value = ((TDSBLOB*) col->column_data)->textvalue;
204 0 : recv_tok.length = col->column_size;
205 :
206 0 : TDS_PROPAGATE(tds_gss_continue(tds, (TDSGSSAUTH *) auth, &recv_tok));
207 :
208 0 : tds->out_flag = TDS_NORMAL;
209 0 : TDS_PROPAGATE(tds5_gss_send(tds));
210 :
211 0 : return tds_flush_packet(tds);
212 :
213 0 : error:
214 : return TDS_FAIL;
215 : }
216 :
217 : /**
218 : * Build a GSSAPI packet to send to server
219 : * @param tds A pointer to the TDSSOCKET structure managing a client/server operation.
220 : * @return size of packet
221 : */
222 : TDSAUTHENTICATION *
223 0 : tds_gss_get_auth(TDSSOCKET * tds)
224 : {
225 : /*
226 : * TODO
227 : * There are some differences between this implementation and MS on
228 : * - MS use SPNEGO with 3 mechnisms (MS KRB5, KRB5, NTLMSSP)
229 : * - MS seems to use MUTUAL flag
230 : * - name type is "Service and Instance (2)" and not "Principal (1)"
231 : * check for memory leaks
232 : * check for errors in many functions
233 : * a bit more verbose
234 : * dinamically load library ??
235 : */
236 : gss_buffer_desc send_tok;
237 : OM_uint32 maj_stat, min_stat;
238 : #ifdef __APPLE__
239 : /* some MacOS header defines gss_OID_desc with a wrong byte alignment, use external
240 : * library definition. */
241 : # define nt_principal (*(gss_OID_desc *) GSS_KRB5_NT_PRINCIPAL_NAME)
242 : #else
243 : /* same as GSS_KRB5_NT_PRINCIPAL_NAME but do not require .so library */
244 : static gss_OID_desc nt_principal = { 10, (void*) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01" };
245 : #endif
246 : const char *server_name;
247 : const char *realm_separator, *realm;
248 : /* Storage for getaddrinfo calls */
249 0 : struct addrinfo *addrs = NULL;
250 0 : int len = 0;
251 :
252 : TDSGSSAUTH *auth;
253 :
254 0 : if (!tds->login)
255 : return NULL;
256 :
257 0 : auth = tds_new0(TDSGSSAUTH, 1);
258 0 : if (!auth)
259 : return NULL;
260 :
261 0 : auth->tds_auth.free = tds_gss_free;
262 0 : auth->tds_auth.handle_next = IS_TDS50(tds->conn) ? tds5_gss_handle_next : tds7_gss_handle_next;
263 0 : auth->gss_context = GSS_C_NO_CONTEXT;
264 0 : auth->last_stat = GSS_S_COMPLETE;
265 :
266 0 : server_name = tds_dstr_cstr(&tds->login->server_host_name);
267 0 : if (IS_TDS7_PLUS(tds->conn) && strchr(server_name, '.') == NULL) {
268 : struct addrinfo hints;
269 0 : memset(&hints, 0, sizeof(hints));
270 : hints.ai_family = AF_UNSPEC;
271 0 : hints.ai_socktype = SOCK_STREAM;
272 0 : hints.ai_flags = AI_V4MAPPED|AI_ADDRCONFIG|AI_CANONNAME|AI_FQDN;
273 0 : if (!getaddrinfo(server_name, NULL, &hints, &addrs) && addrs->ai_canonname
274 0 : && strchr(addrs->ai_canonname, '.') != NULL)
275 0 : server_name = addrs->ai_canonname;
276 : }
277 :
278 0 : if (!tds_dstr_isempty(&tds->login->server_realm_name)) {
279 0 : realm_separator = "@";
280 0 : realm = tds_dstr_cstr(&tds->login->server_realm_name);
281 : } else {
282 : realm_separator = "";
283 : realm = "";
284 : }
285 0 : if (!tds_dstr_isempty(&tds->login->server_spn)) {
286 0 : auth->sname = strdup(tds_dstr_cstr(&tds->login->server_spn));
287 0 : } else if (IS_TDS7_PLUS(tds->conn)) {
288 0 : if (!tds_dstr_isempty(&tds->login->instance_name)) {
289 0 : len = asprintf(&auth->sname, "MSSQLSvc/%s:%s%s%s", server_name, tds_dstr_cstr(&tds->login->instance_name),
290 : realm_separator, realm);
291 : } else {
292 0 : len = asprintf(&auth->sname, "MSSQLSvc/%s:%d%s%s", server_name, tds->login->port, realm_separator, realm);
293 : }
294 : } else {
295 : /* TDS 5.0, Sybase */
296 0 : server_name = tds_dstr_cstr(&tds->login->server_name);
297 0 : len = asprintf(&auth->sname, "%s%s%s", server_name, realm_separator, realm);
298 : }
299 0 : if (addrs)
300 0 : freeaddrinfo(addrs);
301 0 : if (len < 0 || auth->sname == NULL) {
302 0 : tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth);
303 0 : return NULL;
304 : }
305 0 : tdsdump_log(TDS_DBG_NETWORK, "using kerberos name %s\n", auth->sname);
306 :
307 : /*
308 : * Import the name into target_name. Use send_tok to save
309 : * local variable space.
310 : */
311 0 : send_tok.value = auth->sname;
312 0 : send_tok.length = strlen(auth->sname);
313 0 : maj_stat = gss_import_name(&min_stat, &send_tok, &nt_principal, &auth->target_name);
314 :
315 0 : switch (maj_stat) {
316 0 : case GSS_S_COMPLETE:
317 0 : tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_COMPLETE: gss_import_name completed successfully.\n");
318 0 : if (TDS_FAILED(tds_gss_continue(tds, auth, GSS_C_NO_BUFFER))) {
319 0 : tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth);
320 0 : return NULL;
321 : }
322 : break;
323 0 : case GSS_S_BAD_NAMETYPE:
324 0 : tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_NAMETYPE: The input_name_type was unrecognized.\n");
325 : break;
326 0 : case GSS_S_BAD_NAME:
327 0 : tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_NAME: The input_name parameter could not be interpreted as a name of the specified type.\n");
328 : break;
329 0 : case GSS_S_BAD_MECH:
330 0 : tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_MECH: The input name-type was GSS_C_NT_EXPORT_NAME, but the mechanism contained within the input-name is not supported.\n");
331 : break;
332 0 : default:
333 0 : tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: unexpected error %d.\n", maj_stat);
334 : break;
335 : }
336 :
337 0 : if (GSS_ERROR(maj_stat)) {
338 0 : tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth);
339 0 : return NULL;
340 : }
341 :
342 : return (TDSAUTHENTICATION *) auth;
343 : }
344 :
345 : #ifndef HAVE_ERROR_MESSAGE
346 : static const char *
347 : tds_error_message(OM_uint32 e)
348 : {
349 0 : const char *m = strerror(e);
350 0 : if (m == NULL)
351 : return "";
352 : return m;
353 : }
354 : #define error_message tds_error_message
355 : #endif
356 :
357 : static gss_channel_bindings_t
358 0 : tds_gss_get_channel_binding(TDSSOCKET *tds)
359 : {
360 : /* Get tls-unique from OpenSSL */
361 : unsigned char tls_unique_buf[256];
362 : size_t tls_unique_len;
363 : gss_channel_bindings_t cb;
364 :
365 0 : tls_unique_len = tds_ssl_get_cb(tds->conn, tls_unique_buf, sizeof(tls_unique_buf));
366 0 : if (tls_unique_len == 0)
367 : return GSS_C_NO_CHANNEL_BINDINGS;
368 :
369 0 : cb = calloc(sizeof(struct gss_channel_bindings_struct) + 11 + tls_unique_len, sizeof(char));
370 :
371 0 : if (!cb) {
372 0 : tdsdump_log(TDS_DBG_NETWORK, "tds_gss_get_channel_binding: failed to allocate channel bindings\n");
373 : return GSS_C_NO_CHANNEL_BINDINGS;
374 : }
375 :
376 0 : cb->initiator_addrtype = GSS_C_AF_UNSPEC;
377 0 : cb->initiator_address.length = 0;
378 0 : cb->acceptor_addrtype = GSS_C_AF_UNSPEC;
379 0 : cb->acceptor_address.length = 0;
380 0 : cb->application_data.value = (void *) (cb + 1);
381 :
382 0 : cb->application_data.length = tls_unique_len + 11;
383 :
384 0 : memcpy(cb->application_data.value, "tls-unique:", 11);
385 0 : memcpy((char *) cb->application_data.value + 11, tls_unique_buf, tls_unique_len);
386 :
387 0 : tdsdump_dump_buf(TDS_DBG_NETWORK, "gss_channel_bindings_struct", cb, sizeof(struct gss_channel_bindings_struct));
388 0 : tdsdump_dump_buf(TDS_DBG_NETWORK,
389 0 : "gss_channel_bindings_struct.application_data", cb->application_data.value, cb->application_data.length);
390 : return cb;
391 : }
392 :
393 : static TDSRET
394 0 : tds_gss_continue(TDSSOCKET *tds, TDSGSSAUTH *auth, gss_buffer_desc *token_ptr)
395 : {
396 : gss_buffer_desc send_tok;
397 0 : OM_uint32 maj_stat, min_stat = 0;
398 : OM_uint32 ret_flags;
399 : int gssapi_flags;
400 0 : const char *msg = "???";
401 0 : gss_OID pmech = GSS_C_NULL_OID;
402 : gss_channel_bindings_t cb;
403 :
404 0 : auth->last_stat = GSS_S_COMPLETE;
405 :
406 0 : send_tok.value = NULL;
407 0 : send_tok.length = 0;
408 :
409 : /*
410 : * Perform the context-establishement loop.
411 : *
412 : * On each pass through the loop, token_ptr points to the token
413 : * to send to the server (or GSS_C_NO_BUFFER on the first pass).
414 : * Every generated token is stored in send_tok which is then
415 : * transmitted to the server; every received token is stored in
416 : * recv_tok, which token_ptr is then set to, to be processed by
417 : * the next call to gss_init_sec_context.
418 : *
419 : * GSS-API guarantees that send_tok's length will be non-zero
420 : * if and only if the server is expecting another token from us,
421 : * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
422 : * and only if the server has another token to send us.
423 : */
424 :
425 : /*
426 : * We always want to ask for the replay, and integ flags.
427 : * We may ask for delegation based on config in the tds.conf and other conf files.
428 : */
429 0 : gssapi_flags = GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG;
430 :
431 0 : if (tds->login->gssapi_use_delegation)
432 0 : gssapi_flags |= GSS_C_DELEG_FLAG;
433 0 : if (tds->login->mutual_authentication || IS_TDS7_PLUS(tds->conn))
434 0 : gssapi_flags |= GSS_C_MUTUAL_FLAG;
435 :
436 0 : cb = tds_gss_get_channel_binding(tds);
437 :
438 0 : maj_stat =
439 0 : gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &auth->gss_context, auth->target_name, GSS_C_NULL_OID,
440 : gssapi_flags, 0, cb, token_ptr, &pmech, &send_tok, &ret_flags, NULL /* ignore time_rec */ );
441 :
442 0 : free(cb);
443 :
444 0 : tdsdump_log(TDS_DBG_NETWORK, "gss_init_sec_context: actual mechanism at %p\n", pmech);
445 0 : if (pmech && pmech->elements) {
446 0 : tdsdump_dump_buf(TDS_DBG_NETWORK, "actual mechanism", pmech->elements, pmech->length);
447 : }
448 :
449 0 : auth->last_stat = maj_stat;
450 :
451 0 : switch (maj_stat) {
452 0 : case GSS_S_COMPLETE:
453 0 : msg = "GSS_S_COMPLETE: gss_init_sec_context completed successfully.";
454 0 : break;
455 0 : case GSS_S_CONTINUE_NEEDED:
456 0 : msg = "GSS_S_CONTINUE_NEEDED: gss_init_sec_context() routine must be called again.";
457 0 : break;
458 0 : case GSS_S_FAILURE:
459 0 : msg = "GSS_S_FAILURE: The routine failed for reasons that are not defined at the GSS level.";
460 0 : tdsdump_log(TDS_DBG_NETWORK, "gss_init_sec_context: min_stat %ld \"%s\"\n",
461 : (long) min_stat, error_message(min_stat));
462 : break;
463 0 : case GSS_S_BAD_BINDINGS:
464 0 : msg = "GSS_S_BAD_BINDINGS: The channel bindings are not valid.";
465 0 : break;
466 0 : case GSS_S_BAD_MECH:
467 0 : msg = "GSS_S_BAD_MECH: The request security mechanism is not supported.";
468 0 : break;
469 0 : case GSS_S_BAD_NAME:
470 0 : msg = "GSS_S_BAD_NAME: The target_name parameter is not valid.";
471 0 : break;
472 0 : case GSS_S_BAD_SIG:
473 0 : msg = "GSS_S_BAD_SIG: The input token contains an incorrect integrity check value.";
474 0 : break;
475 0 : case GSS_S_CREDENTIALS_EXPIRED:
476 0 : msg = "GSS_S_CREDENTIALS_EXPIRED: The supplied credentials are no longer valid.";
477 0 : break;
478 0 : case GSS_S_DEFECTIVE_CREDENTIAL:
479 0 : msg = "GSS_S_DEFECTIVE_CREDENTIAL: Consistency checks performed on the credential failed.";
480 0 : break;
481 0 : case GSS_S_DEFECTIVE_TOKEN:
482 0 : msg = "GSS_S_DEFECTIVE_TOKEN: Consistency checks performed on the input token failed.";
483 0 : break;
484 0 : case GSS_S_DUPLICATE_TOKEN:
485 0 : msg = "GSS_S_DUPLICATE_TOKEN: The token is a duplicate of a token that has already been processed.";
486 0 : break;
487 0 : case GSS_S_NO_CONTEXT:
488 0 : msg = "GSS_S_NO_CONTEXT: The context handle provided by the caller does not refer to a valid security context.";
489 0 : break;
490 0 : case GSS_S_NO_CRED:
491 0 : msg = "GSS_S_NO_CRED: The supplied credential handle does not refer to a valid credential, the supplied credential is not";
492 0 : break;
493 0 : case GSS_S_OLD_TOKEN:
494 0 : msg = "GSS_S_OLD_TOKEN: The token is too old to be checked for duplication against previous tokens which have already been processed.";
495 0 : break;
496 : }
497 :
498 0 : if (GSS_ERROR(maj_stat)) {
499 0 : gss_release_buffer(&min_stat, &send_tok);
500 0 : tdsdump_log(TDS_DBG_NETWORK, "gss_init_sec_context: %s\n", msg);
501 : return TDS_FAIL;
502 : }
503 :
504 0 : auth->tds_auth.packet = (uint8_t *) send_tok.value;
505 0 : auth->tds_auth.packet_len = (int) send_tok.length;
506 :
507 0 : return TDS_SUCCESS;
508 : }
509 :
510 : static void
511 0 : tds5_send_msg(TDSSOCKET *tds, uint16_t msg_type)
512 : {
513 0 : tds_put_tinyint(tds, TDS_MSG_TOKEN);
514 0 : tds_put_tinyint(tds, 3); /* length */
515 0 : tds_put_tinyint(tds, 1); /* status, 1=has params */
516 0 : tds_put_smallint(tds, msg_type);
517 0 : }
518 :
519 : TDSRET
520 0 : tds5_gss_send(TDSSOCKET *tds)
521 : {
522 0 : uint32_t flags = TDS5_SEC_NETWORK_AUTHENTICATION;
523 :
524 0 : if (!tds->conn->authentication)
525 : return TDS_FAIL;
526 :
527 0 : if (tds->login) {
528 0 : if (tds->login->gssapi_use_delegation)
529 0 : flags |= TDS5_SEC_DELEGATION;
530 0 : if (tds->login->mutual_authentication)
531 0 : flags |= TDS5_SEC_MUTUAL_AUTHENTICATION;
532 : }
533 :
534 0 : tds5_send_msg(tds, TDS5_MSG_SEC_OPAQUE);
535 :
536 0 : tds_put_byte(tds, TDS5_PARAMFMT_TOKEN);
537 0 : TDS_START_LEN_USMALLINT(tds) {
538 0 : tds_put_smallint(tds, 5); /* # parameters */
539 :
540 0 : tds_put_n(tds, NULL, 6); /* name len + output + usertype */
541 0 : tds_put_tinyint(tds, SYBINTN);
542 0 : tds_put_tinyint(tds, 4);
543 0 : tds_put_tinyint(tds, 0); /* locale len */
544 :
545 0 : tds_put_n(tds, NULL, 6); /* name len + output + usertype */
546 0 : tds_put_tinyint(tds, SYBINTN);
547 0 : tds_put_tinyint(tds, 4);
548 0 : tds_put_tinyint(tds, 0); /* locale len */
549 :
550 0 : tds_put_n(tds, NULL, 6); /* name len + output + usertype */
551 0 : tds_put_tinyint(tds, SYBVARBINARY);
552 0 : tds_put_tinyint(tds, 255);
553 0 : tds_put_tinyint(tds, 0); /* locale len */
554 :
555 0 : tds_put_n(tds, NULL, 6); /* name len + output + usertype */
556 0 : tds_put_tinyint(tds, SYBLONGBINARY);
557 0 : tds_put_int(tds, 0x7fffffff);
558 0 : tds_put_tinyint(tds, 0); /* locale len */
559 :
560 0 : tds_put_n(tds, NULL, 6); /* name len + output + usertype */
561 0 : tds_put_tinyint(tds, SYBINTN);
562 0 : tds_put_tinyint(tds, 4);
563 0 : tds_put_tinyint(tds, 0); /* locale len */
564 0 : } TDS_END_LEN
565 :
566 0 : tds_put_byte(tds, TDS5_PARAMS_TOKEN);
567 :
568 0 : tds_put_tinyint(tds, 4);
569 0 : tds_put_int(tds, TDS5_SEC_VERSION);
570 :
571 0 : tds_put_tinyint(tds, 4);
572 0 : tds_put_int(tds, TDS5_SEC_SECSESS);
573 :
574 0 : tds_put_tinyint(tds, 12);
575 0 : tds_put_n(tds, "\x06\x0a\x2b\x06\x01\x04\x01\x87\x01\x04\x06\x06", 12); /* KRB5 Sybase OID */
576 :
577 0 : tds_put_int(tds, tds->conn->authentication->packet_len);
578 0 : tds_put_n(tds, tds->conn->authentication->packet, tds->conn->authentication->packet_len);
579 :
580 0 : tds_put_tinyint(tds, 4);
581 0 : tds_put_int(tds, flags);
582 :
583 0 : return TDS_SUCCESS;
584 : }
585 :
586 : /** @} */
587 :
588 : #endif
|