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

Generated by: LCOV version 1.13