LCOV - code coverage report
Current view: top level - src/tds - gssapi.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 0 233 0.0 %
Date: 2024-03-23 08:24:27 Functions: 0 7 0.0 %

          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             : #endif
      66             : #include <gssapi/gssapi_krb5.h>
      67             : 
      68             : #include <freetds/tds.h>
      69             : #include <freetds/utils/string.h>
      70             : #include <freetds/replacements.h>
      71             : 
      72             : /**
      73             :  * \ingroup libtds
      74             :  * \defgroup auth Authentication
      75             :  * Functions for handling authentication.
      76             :  */
      77             : 
      78             : /**
      79             :  * \addtogroup auth
      80             :  * @{ 
      81             :  */
      82             : 
      83             : typedef struct tds_gss_auth
      84             : {
      85             :         TDSAUTHENTICATION tds_auth;
      86             :         gss_ctx_id_t gss_context;
      87             :         gss_name_t target_name;
      88             :         char *sname;
      89             :         OM_uint32 last_stat;
      90             : } TDSGSSAUTH;
      91             : 
      92             : static TDSRET
      93           0 : tds_gss_free(TDSCONNECTION * conn TDS_UNUSED, struct tds_authentication * tds_auth)
      94             : {
      95           0 :         TDSGSSAUTH *auth = (TDSGSSAUTH *) tds_auth;
      96             :         OM_uint32 min_stat;
      97             : 
      98           0 :         if (auth->tds_auth.packet) {
      99             :                 gss_buffer_desc send_tok;
     100             : 
     101           0 :                 send_tok.value = (void *) auth->tds_auth.packet;
     102           0 :                 send_tok.length = auth->tds_auth.packet_len;
     103           0 :                 gss_release_buffer(&min_stat, &send_tok);
     104             :         }
     105             : 
     106           0 :         gss_release_name(&min_stat, &auth->target_name);
     107           0 :         free(auth->sname);
     108           0 :         if (auth->gss_context != GSS_C_NO_CONTEXT)
     109           0 :                 gss_delete_sec_context(&min_stat, &auth->gss_context, GSS_C_NO_BUFFER);
     110           0 :         free(auth);
     111             : 
     112           0 :         return TDS_SUCCESS;
     113             : }
     114             : 
     115             : static TDSRET tds_gss_continue(TDSSOCKET * tds, struct tds_gss_auth *auth, gss_buffer_desc *token_ptr);
     116             : 
     117             : static TDSRET
     118           0 : tds7_gss_handle_next(TDSSOCKET * tds, struct tds_authentication * auth, size_t len)
     119             : {
     120             :         TDSRET res;
     121             :         gss_buffer_desc recv_tok;
     122             : 
     123           0 :         if (((struct tds_gss_auth *) auth)->last_stat != GSS_S_CONTINUE_NEEDED)
     124             :                 return TDS_FAIL;
     125             : 
     126           0 :         if (auth->packet) {
     127             :                 OM_uint32 min_stat;
     128             :                 gss_buffer_desc send_tok;
     129             : 
     130           0 :                 send_tok.value = (void *) auth->packet;
     131           0 :                 send_tok.length = auth->packet_len;
     132           0 :                 gss_release_buffer(&min_stat, &send_tok);
     133           0 :                 auth->packet = NULL;
     134             :         }
     135             : 
     136           0 :         recv_tok.length = len;
     137           0 :         recv_tok.value = tds_new(char, len);
     138           0 :         if (!recv_tok.value)
     139             :                 return TDS_FAIL;
     140           0 :         tds_get_n(tds, recv_tok.value, len);
     141             : 
     142           0 :         res = tds_gss_continue(tds, (struct tds_gss_auth *) auth, &recv_tok);
     143           0 :         free(recv_tok.value);
     144           0 :         if (TDS_FAILED(res))
     145             :                 return res;
     146             : 
     147           0 :         if (auth->packet_len) {
     148           0 :                 tds->out_flag = TDS7_AUTH;
     149           0 :                 tds_put_n(tds, auth->packet, auth->packet_len);
     150           0 :                 return tds_flush_packet(tds);
     151             :         }
     152             :         return TDS_SUCCESS;
     153             : }
     154             : 
     155             : static TDSRET
     156           0 : tds5_gss_handle_next(TDSSOCKET * tds, struct tds_authentication * auth, size_t len TDS_UNUSED)
     157             : {
     158             :         TDSRET res;
     159             :         gss_buffer_desc recv_tok;
     160             :         TDSPARAMINFO *info;
     161             :         TDSCOLUMN *col;
     162             : 
     163           0 :         if (((struct tds_gss_auth *) auth)->last_stat != GSS_S_CONTINUE_NEEDED)
     164             :                 return TDS_FAIL;
     165             : 
     166           0 :         if (auth->packet) {
     167             :                 OM_uint32 min_stat;
     168             :                 gss_buffer_desc send_tok;
     169             : 
     170           0 :                 send_tok.value = (void *) auth->packet;
     171           0 :                 send_tok.length = auth->packet_len;
     172           0 :                 gss_release_buffer(&min_stat, &send_tok);
     173           0 :                 auth->packet = NULL;
     174             :         }
     175             : 
     176             :         /* parse from saved message */
     177           0 :         if (auth->msg_type != TDS5_MSG_SEC_OPAQUE)
     178             :                 goto error;
     179           0 :         auth->msg_type = 0;
     180             : 
     181           0 :         info = tds->param_info;
     182           0 :         if (!info || info->num_cols < 5)
     183             :                 goto error;
     184             : 
     185             :         /* check first column is int and TDS5_SEC_VERSION */
     186           0 :         col = info->columns[0];
     187           0 :         if (tds_get_conversion_type(col->on_server.column_type, col->on_server.column_size) != SYBINT4)
     188             :                 goto error;
     189           0 :         if (*((TDS_INT *) col->column_data) != TDS5_SEC_VERSION)
     190             :                 goto error;
     191             : 
     192             :         /* check second column is int and TDS5_SEC_SECSESS */
     193           0 :         col = info->columns[1];
     194           0 :         if (tds_get_conversion_type(col->on_server.column_type, col->on_server.column_size) != SYBINT4)
     195             :                 goto error;
     196           0 :         if (*((TDS_INT *) col->column_data) != TDS5_SEC_SECSESS)
     197             :                 goto error;
     198             : 
     199           0 :         col = info->columns[3];
     200           0 :         if (col->column_type != SYBLONGBINARY)
     201             :                 goto error;
     202           0 :         recv_tok.value = ((TDSBLOB*) col->column_data)->textvalue;
     203           0 :         recv_tok.length = col->column_size;
     204             : 
     205           0 :         res = tds_gss_continue(tds, (struct tds_gss_auth *) auth, &recv_tok);
     206           0 :         if (TDS_FAILED(res))
     207             :                 return res;
     208             : 
     209           0 :         tds->out_flag = TDS_NORMAL;
     210           0 :         res = tds5_gss_send(tds);
     211           0 :         if (TDS_FAILED(res))
     212             :                 return res;
     213             : 
     214           0 :         return tds_flush_packet(tds);
     215             : 
     216           0 : error:
     217             :         return TDS_FAIL;
     218             : }
     219             : 
     220             : /**
     221             :  * Build a GSSAPI packet to send to server
     222             :  * @param tds     A pointer to the TDSSOCKET structure managing a client/server operation.
     223             :  * @return size of packet
     224             :  */
     225             : TDSAUTHENTICATION * 
     226           0 : tds_gss_get_auth(TDSSOCKET * tds)
     227             : {
     228             :         /*
     229             :          * TODO
     230             :          * There are some differences between this implementation and MS on
     231             :          * - MS use SPNEGO with 3 mechnisms (MS KRB5, KRB5, NTLMSSP)
     232             :          * - MS seems to use MUTUAL flag
     233             :          * - name type is "Service and Instance (2)" and not "Principal (1)"
     234             :          * check for memory leaks
     235             :          * check for errors in many functions
     236             :          * a bit more verbose
     237             :          * dinamically load library ??
     238             :          */
     239             :         gss_buffer_desc send_tok;
     240             :         OM_uint32 maj_stat, min_stat;
     241             :         /* same as GSS_KRB5_NT_PRINCIPAL_NAME but do not require .so library */
     242             :         static gss_OID_desc nt_principal = { 10, (void*) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01" };
     243             :         const char *server_name;
     244             :         /* Storage for getaddrinfo calls */
     245           0 :         struct addrinfo *addrs = NULL;
     246           0 :         int len = 0;
     247             : 
     248             :         struct tds_gss_auth *auth;
     249             : 
     250           0 :         if (!tds->login)
     251             :                 return NULL;
     252             : 
     253           0 :         auth = tds_new0(struct tds_gss_auth, 1);
     254           0 :         if (!auth)
     255             :                 return NULL;
     256             : 
     257           0 :         auth->tds_auth.free = tds_gss_free;
     258           0 :         auth->tds_auth.handle_next = IS_TDS50(tds->conn) ? tds5_gss_handle_next : tds7_gss_handle_next;
     259           0 :         auth->gss_context = GSS_C_NO_CONTEXT;
     260           0 :         auth->last_stat = GSS_S_COMPLETE;
     261             : 
     262           0 :         server_name = tds_dstr_cstr(&tds->login->server_host_name);
     263           0 :         if (IS_TDS7_PLUS(tds->conn) && strchr(server_name, '.') == NULL) {
     264             :                 struct addrinfo hints;
     265           0 :                 memset(&hints, 0, sizeof(hints));
     266             :                 hints.ai_family = AF_UNSPEC;
     267           0 :                 hints.ai_socktype = SOCK_STREAM;
     268           0 :                 hints.ai_flags = AI_V4MAPPED|AI_ADDRCONFIG|AI_CANONNAME|AI_FQDN;
     269           0 :                 if (!getaddrinfo(server_name, NULL, &hints, &addrs) && addrs->ai_canonname
     270           0 :                     && strchr(addrs->ai_canonname, '.') != NULL)
     271           0 :                         server_name = addrs->ai_canonname;
     272             :         }
     273             : 
     274           0 :         if (!tds_dstr_isempty(&tds->login->server_spn)) {
     275           0 :                 auth->sname = strdup(tds_dstr_cstr(&tds->login->server_spn));
     276           0 :         } else if (IS_TDS7_PLUS(tds->conn)) {
     277           0 :                 if (tds_dstr_isempty(&tds->login->server_realm_name)) {
     278           0 :                         len = asprintf(&auth->sname, "MSSQLSvc/%s:%d", server_name, tds->login->port);
     279             :                 } else {
     280           0 :                         len = asprintf(&auth->sname, "MSSQLSvc/%s:%d@%s", server_name, tds->login->port,
     281           0 :                                        tds_dstr_cstr(&tds->login->server_realm_name));
     282             :                 }
     283             :         } else {
     284             :                 /* TDS 5.0, Sybase */
     285           0 :                 server_name = tds_dstr_cstr(&tds->login->server_name);
     286           0 :                 if (tds_dstr_isempty(&tds->login->server_realm_name)) {
     287           0 :                         len = asprintf(&auth->sname, "%s", server_name);
     288             :                 } else {
     289           0 :                         len = asprintf(&auth->sname, "%s@%s", server_name,
     290           0 :                                        tds_dstr_cstr(&tds->login->server_realm_name));
     291             :                 }
     292             :         }
     293           0 :         if (addrs)
     294           0 :                 freeaddrinfo(addrs);
     295           0 :         if (len < 0 || auth->sname == NULL) {
     296           0 :                 tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth);
     297           0 :                 return NULL;
     298             :         }
     299           0 :         tdsdump_log(TDS_DBG_NETWORK, "using kerberos name %s\n", auth->sname);
     300             : 
     301             :         /*
     302             :          * Import the name into target_name.  Use send_tok to save
     303             :          * local variable space.
     304             :          */
     305           0 :         send_tok.value = auth->sname;
     306           0 :         send_tok.length = strlen(auth->sname);
     307           0 :         maj_stat = gss_import_name(&min_stat, &send_tok, &nt_principal, &auth->target_name);
     308             : 
     309           0 :         switch (maj_stat) {
     310           0 :         case GSS_S_COMPLETE: 
     311           0 :                 tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_COMPLETE: gss_import_name completed successfully.\n");
     312           0 :                 if (TDS_FAILED(tds_gss_continue(tds, auth, GSS_C_NO_BUFFER))) {
     313           0 :                         tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth);
     314           0 :                         return NULL;
     315             :                 }
     316             :                 break;
     317           0 :         case GSS_S_BAD_NAMETYPE: 
     318           0 :                 tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_NAMETYPE: The input_name_type was unrecognized.\n");
     319             :                 break;
     320           0 :         case GSS_S_BAD_NAME: 
     321           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");
     322             :                 break;
     323           0 :         case GSS_S_BAD_MECH:
     324           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");
     325             :                 break;
     326           0 :         default:
     327           0 :                 tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: unexpected error %d.\n", maj_stat);
     328             :                 break;
     329             :         }
     330             : 
     331           0 :         if (GSS_ERROR(maj_stat)) {
     332           0 :                 tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth);
     333           0 :                 return NULL;
     334             :         }
     335             : 
     336             :         return (TDSAUTHENTICATION *) auth;
     337             : }
     338             : 
     339             : #ifndef HAVE_ERROR_MESSAGE
     340             : static const char *
     341             : tds_error_message(OM_uint32 e)
     342             : {
     343           0 :         const char *m = strerror(e);
     344           0 :         if (m == NULL)
     345             :                 return "";
     346             :         return m;
     347             : }
     348             : #define error_message tds_error_message
     349             : #endif
     350             : 
     351             : static TDSRET
     352           0 : tds_gss_continue(TDSSOCKET * tds, struct tds_gss_auth *auth, gss_buffer_desc *token_ptr)
     353             : {
     354             :         gss_buffer_desc send_tok;
     355           0 :         OM_uint32 maj_stat, min_stat = 0;
     356             :         OM_uint32 ret_flags;
     357             :         int gssapi_flags;
     358           0 :         const char *msg = "???";
     359           0 :         gss_OID pmech = GSS_C_NULL_OID;
     360             : 
     361           0 :         auth->last_stat = GSS_S_COMPLETE;
     362             : 
     363           0 :         send_tok.value = NULL;
     364           0 :         send_tok.length = 0;
     365             : 
     366             :         /*
     367             :          * Perform the context-establishement loop.
     368             :          *
     369             :          * On each pass through the loop, token_ptr points to the token
     370             :          * to send to the server (or GSS_C_NO_BUFFER on the first pass).
     371             :          * Every generated token is stored in send_tok which is then
     372             :          * transmitted to the server; every received token is stored in
     373             :          * recv_tok, which token_ptr is then set to, to be processed by
     374             :          * the next call to gss_init_sec_context.
     375             :          * 
     376             :          * GSS-API guarantees that send_tok's length will be non-zero
     377             :          * if and only if the server is expecting another token from us,
     378             :          * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
     379             :          * and only if the server has another token to send us.
     380             :          */
     381             : 
     382             :         /*
     383             :          * We always want to ask for the replay, and integ flags.
     384             :          * We may ask for delegation based on config in the tds.conf and other conf files.
     385             :          */
     386           0 :         gssapi_flags = GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG;
     387             : 
     388           0 :         if (tds->login->gssapi_use_delegation)
     389           0 :                 gssapi_flags |= GSS_C_DELEG_FLAG;
     390           0 :         if (tds->login->mutual_authentication || IS_TDS7_PLUS(tds->conn))
     391           0 :                 gssapi_flags |= GSS_C_MUTUAL_FLAG;
     392             : 
     393           0 :         maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &auth->gss_context, auth->target_name, 
     394             :                                         GSS_C_NULL_OID,
     395             :                                         gssapi_flags,
     396             :                                         0, NULL,        /* no channel bindings */
     397             :                                         token_ptr, 
     398             :                                         &pmech,     
     399             :                                         &send_tok, &ret_flags, NULL);   /* ignore time_rec */
     400             : 
     401           0 :         tdsdump_log(TDS_DBG_NETWORK, "gss_init_sec_context: actual mechanism at %p\n", pmech);
     402           0 :         if (pmech && pmech->elements) {
     403           0 :                 tdsdump_dump_buf(TDS_DBG_NETWORK, "actual mechanism", pmech->elements, pmech->length);
     404             :         }
     405             :         
     406           0 :         auth->last_stat = maj_stat;
     407             :         
     408           0 :         switch (maj_stat) {
     409           0 :         case GSS_S_COMPLETE: 
     410           0 :                 msg = "GSS_S_COMPLETE: gss_init_sec_context completed successfully.";
     411           0 :                 break;
     412           0 :         case GSS_S_CONTINUE_NEEDED: 
     413           0 :                 msg = "GSS_S_CONTINUE_NEEDED: gss_init_sec_context() routine must be called again.";
     414           0 :                 break;
     415           0 :         case GSS_S_FAILURE: 
     416           0 :                 msg = "GSS_S_FAILURE: The routine failed for reasons that are not defined at the GSS level.";
     417           0 :                 tdsdump_log(TDS_DBG_NETWORK, "gss_init_sec_context: min_stat %ld \"%s\"\n", 
     418             :                                                 (long) min_stat, error_message(min_stat));
     419             :                 break;
     420           0 :         case GSS_S_BAD_BINDINGS: 
     421           0 :                 msg = "GSS_S_BAD_BINDINGS: The channel bindings are not valid.";
     422           0 :                 break;
     423           0 :         case GSS_S_BAD_MECH: 
     424           0 :                 msg = "GSS_S_BAD_MECH: The request security mechanism is not supported.";
     425           0 :                 break;
     426           0 :         case GSS_S_BAD_NAME: 
     427           0 :                 msg = "GSS_S_BAD_NAME: The target_name parameter is not valid.";
     428           0 :                 break;
     429           0 :         case GSS_S_BAD_SIG: 
     430           0 :                 msg = "GSS_S_BAD_SIG: The input token contains an incorrect integrity check value.";
     431           0 :                 break;
     432           0 :         case GSS_S_CREDENTIALS_EXPIRED: 
     433           0 :                 msg = "GSS_S_CREDENTIALS_EXPIRED: The supplied credentials are no longer valid.";
     434           0 :                 break;
     435           0 :         case GSS_S_DEFECTIVE_CREDENTIAL: 
     436           0 :                 msg = "GSS_S_DEFECTIVE_CREDENTIAL: Consistency checks performed on the credential failed.";
     437           0 :                 break;
     438           0 :         case GSS_S_DEFECTIVE_TOKEN: 
     439           0 :                 msg = "GSS_S_DEFECTIVE_TOKEN: Consistency checks performed on the input token failed.";
     440           0 :                 break;
     441           0 :         case GSS_S_DUPLICATE_TOKEN: 
     442           0 :                 msg = "GSS_S_DUPLICATE_TOKEN: The token is a duplicate of a token that has already been processed.";
     443           0 :                 break;
     444           0 :         case GSS_S_NO_CONTEXT: 
     445           0 :                 msg = "GSS_S_NO_CONTEXT: The context handle provided by the caller does not refer to a valid security context.";
     446           0 :                 break;
     447           0 :         case GSS_S_NO_CRED: 
     448           0 :                 msg = "GSS_S_NO_CRED: The supplied credential handle does not refer to a valid credential, the supplied credential is not";
     449           0 :                 break;
     450           0 :         case GSS_S_OLD_TOKEN: 
     451           0 :                 msg = "GSS_S_OLD_TOKEN: The token is too old to be checked for duplication against previous tokens which have already been processed.";
     452           0 :                 break;
     453             :         }
     454             :         
     455           0 :         if (GSS_ERROR(maj_stat)) {
     456           0 :                 gss_release_buffer(&min_stat, &send_tok);
     457           0 :                 tdsdump_log(TDS_DBG_NETWORK, "gss_init_sec_context: %s\n", msg);
     458             :                 return TDS_FAIL;
     459             :         }
     460             : 
     461           0 :         auth->tds_auth.packet = (uint8_t *) send_tok.value;
     462           0 :         auth->tds_auth.packet_len = send_tok.length;
     463             : 
     464           0 :         return TDS_SUCCESS;
     465             : }
     466             : 
     467             : static void
     468           0 : tds5_send_msg(TDSSOCKET *tds, uint16_t msg_type)
     469             : {
     470           0 :         tds_put_tinyint(tds, TDS_MSG_TOKEN);
     471           0 :         tds_put_tinyint(tds, 3); /* length */
     472           0 :         tds_put_tinyint(tds, 1); /* status, 1=has params */
     473           0 :         tds_put_smallint(tds, msg_type);
     474           0 : }
     475             : 
     476             : TDSRET
     477           0 : tds5_gss_send(TDSSOCKET *tds)
     478             : {
     479           0 :         uint32_t flags = TDS5_SEC_NETWORK_AUTHENTICATION;
     480             : 
     481           0 :         if (!tds->conn->authentication)
     482             :                 return TDS_FAIL;
     483             : 
     484           0 :         if (tds->login) {
     485           0 :                 if (tds->login->gssapi_use_delegation)
     486           0 :                         flags |= TDS5_SEC_DELEGATION;
     487           0 :                 if (tds->login->mutual_authentication)
     488           0 :                         flags |= TDS5_SEC_MUTUAL_AUTHENTICATION;
     489             :         }
     490             : 
     491           0 :         tds5_send_msg(tds, TDS5_MSG_SEC_OPAQUE);
     492             : 
     493           0 :         tds_put_byte(tds, TDS5_PARAMFMT_TOKEN);
     494           0 :         TDS_START_LEN_USMALLINT(tds) {
     495           0 :                 tds_put_smallint(tds, 5); /* # parameters */
     496             : 
     497           0 :                 tds_put_n(tds, NULL, 6); /* name len + output + usertype */
     498           0 :                 tds_put_tinyint(tds, SYBINTN);
     499           0 :                 tds_put_tinyint(tds, 4);
     500           0 :                 tds_put_tinyint(tds, 0); /* locale len */
     501             : 
     502           0 :                 tds_put_n(tds, NULL, 6); /* name len + output + usertype */
     503           0 :                 tds_put_tinyint(tds, SYBINTN);
     504           0 :                 tds_put_tinyint(tds, 4);
     505           0 :                 tds_put_tinyint(tds, 0); /* locale len */
     506             : 
     507           0 :                 tds_put_n(tds, NULL, 6); /* name len + output + usertype */
     508           0 :                 tds_put_tinyint(tds, SYBVARBINARY);
     509           0 :                 tds_put_tinyint(tds, 255);
     510           0 :                 tds_put_tinyint(tds, 0); /* locale len */
     511             : 
     512           0 :                 tds_put_n(tds, NULL, 6); /* name len + output + usertype */
     513           0 :                 tds_put_tinyint(tds, SYBLONGBINARY);
     514           0 :                 tds_put_int(tds, 0x7fffffff);
     515           0 :                 tds_put_tinyint(tds, 0); /* locale len */
     516             : 
     517           0 :                 tds_put_n(tds, NULL, 6); /* name len + output + usertype */
     518           0 :                 tds_put_tinyint(tds, SYBINTN);
     519           0 :                 tds_put_tinyint(tds, 4);
     520           0 :                 tds_put_tinyint(tds, 0); /* locale len */
     521           0 :         } TDS_END_LEN
     522             : 
     523           0 :         tds_put_byte(tds, TDS5_PARAMS_TOKEN);
     524             : 
     525           0 :         tds_put_tinyint(tds, 4);
     526           0 :         tds_put_int(tds, TDS5_SEC_VERSION);
     527             : 
     528           0 :         tds_put_tinyint(tds, 4);
     529           0 :         tds_put_int(tds, TDS5_SEC_SECSESS);
     530             : 
     531           0 :         tds_put_tinyint(tds, 12);
     532           0 :         tds_put_n(tds, "\x06\x0a\x2b\x06\x01\x04\x01\x87\x01\x04\x06\x06", 12); /* KRB5 Sybase OID */
     533             : 
     534           0 :         tds_put_int(tds, tds->conn->authentication->packet_len);
     535           0 :         tds_put_n(tds, tds->conn->authentication->packet, tds->conn->authentication->packet_len);
     536             : 
     537           0 :         tds_put_tinyint(tds, 4);
     538           0 :         tds_put_int(tds, flags);
     539             : 
     540           0 :         return TDS_SUCCESS;
     541             : }
     542             : 
     543             : /** @} */
     544             : 
     545             : #endif

Generated by: LCOV version 1.13