Skip to content

Commit

Permalink
Add support for TDS 8.0
Browse files Browse the repository at this point in the history
TDS 8.0 is very similar to 7.4.
The protocol difference is that TLS layer is not wrapped inside TDS
during login.
The other difference is that the usage of TDS 8.0 by default requires
certificate validation.

Signed-off-by: Frediano Ziglio <[email protected]>
  • Loading branch information
freddy77 committed Dec 22, 2024
1 parent 6ef2846 commit f26b1cd
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 33 deletions.
21 changes: 18 additions & 3 deletions doc/userguide.xml
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ The <quote>TDS</quote> part of the name comes from name of the protocol used to
<listitem><para>Introduced for <productname>SQL Server 2012</productname>. Includes support for session recovery.</para></listitem>
</varlistentry>

<varlistentry>
<term>TDS 8.0 Microsoft</term>
<listitem><para>Introduced for <productname>SQL Server 2022</productname>.
Includes support for TLS 1.3.</para></listitem>
</varlistentry>

</variablelist>
</sect1>

Expand Down Expand Up @@ -820,6 +826,11 @@ or
<entry>7.4</entry>
<entry>Includes support for session recovery.</entry>
</row>
<row>
<entry>Microsoft SQL Server 2022</entry>
<entry>8.0</entry>
<entry>Includes support for TLS 1.3.</entry>
</row>
</tbody>
</tgroup>
</table></para>
Expand Down Expand Up @@ -933,7 +944,9 @@ So the &freetds; developers adopted that version for &freetds;.
Years later, when Microsoft started releasing official specs of the protocol, it became obvious that the TDS
versions that &freetds; had labeled 8.0 and 9.0 were actually versions 7.1 and 7.2 respectively.</para>

<para>Version 8.0 cannot be used from &freetds; version 1.3.</para>
<para>Version 8.0 cannot be used from &freetds; version 1.3.
With &freetds; version 1.5 you can again specify protocol 8.0 but it's the protocol
for MSSQL 2022.</para>

<para><itemizedlist>
<title>TDS 4.2 has limitations</title>
Expand Down Expand Up @@ -1066,7 +1079,7 @@ versions that &freetds; had labeled 8.0 and 9.0 were actually versions 7.1 and 7
<tbody>
<row>
<entry><literal>tds version</literal></entry>
<entry>4.2, 5.0, 7.0, 7.1, 7.2, 7.3, 7.4, <literal>auto</literal></entry>
<entry>4.2, 5.0, 7.0, 7.1, 7.2, 7.3, 7.4, 8.0, <literal>auto</literal></entry>
<entry><parameter>--with-tdsver</parameter> value (<literal>auto</literal> if unspecified)
Overridden by <link linkend="TDSVER">TDSVER</link>.</entry>
<entry>The <acronym>TDS</acronym> protocol version to use when connecting. <quote><literal>auto</literal></quote> tells &freetds; to use an autodetection (trial-and-error) algorithm to choose the protocol version. </entry>
Expand Down Expand Up @@ -1509,7 +1522,9 @@ This is supported from MSSQL 2012.
<term id="TDSPORT"><envar>TDSPORT</envar></term>
<listitem>

<para>specifies a TCP port number at which the servername is listening. It overrides the default port (1433 for TDS 4.2/7.0/7.1/7.2/7.3/7.4, 4000 for TDS 5.0) as well as any port specified in the &freetdsconf; file.</para>
<para>specifies a TCP port number at which the servername is listening.
It overrides the default port (1433 for TDS 4.2/7.0/7.1/7.2/7.3/7.4/8.0, 4000 for TDS 5.0)
as well as any port specified in the &freetdsconf; file.</para>
</listitem>
</varlistentry>
<varlistentry>
Expand Down
3 changes: 2 additions & 1 deletion include/freetds/tds.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ typedef struct tds_compiletime_settings
const char *freetds_version; /* release version of FreeTDS */
const tds_dir_char *sysconfdir; /* location of freetds.conf */
const char *last_update; /* latest software_version date among the modules */
const char *tdsver; /* TDS protocol version (4.2/4.6/5.0/7.0/7.1) 5.0 */
const char *tdsver; /* TDS protocol version (4.2/4.6/5.0/7.0/7.1/8.0) 5.0 */
bool msdblib; /* for MS style dblib */
bool sybase_compat; /* enable increased Open Client binary compatibility */
bool threadsafe; /* compile for thread safety default=no */
Expand Down Expand Up @@ -1310,6 +1310,7 @@ TDSDYNAMIC *tds_lookup_dynamic(TDSCONNECTION * conn, const char *id);
/*@observer@*/ const char *tds_prtype(int token);
int tds_get_varint_size(TDSCONNECTION * conn, int datatype);
TDS_SERVER_TYPE tds_get_cardinal_type(TDS_SERVER_TYPE datatype, int usertype);
TDSRET tds8_adjust_login(TDSLOGIN *login);


/* iconv.c */
Expand Down
5 changes: 3 additions & 2 deletions include/sybdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,13 @@ extern "C"
#define DBTDS_4_9_5 6 /* 4.9.5 (NCR) SQL Server */
#define DBTDS_5_0 7 /* 5.0 SQL Server */
#define DBTDS_7_0 8 /* Microsoft SQL Server 7.0 */
#define DBTDS_8_0 9 /* Microsoft SQL Server 2000 */
#define DBTDS_9_0 10 /* Microsoft SQL Server 2005 */
#define DBTDS_8_0 ("Use DBTDS_7_1 instead"*x) /* Microsoft SQL Server 2000 */
#define DBTDS_9_0 ("Use DBTDS_7_2 instead"*x) /* Microsoft SQL Server 2005 */
#define DBTDS_7_1 9 /* Microsoft SQL Server 2000 */
#define DBTDS_7_2 10 /* Microsoft SQL Server 2005 */
#define DBTDS_7_3 11 /* Microsoft SQL Server 2008 */
#define DBTDS_7_4 12 /* Microsoft SQL Server 2012/2014 */
#define DBTDS_8_0_ 13 /* Microsoft SQL Server 2022 */

#define DBTXPLEN 16

Expand Down
2 changes: 2 additions & 0 deletions src/dblib/dblib.c
Original file line number Diff line number Diff line change
Expand Up @@ -6861,6 +6861,8 @@ dbtds(DBPROCESS * dbproc)
return DBTDS_7_3;
case 0x704:
return DBTDS_7_4;
case 0x800:
return DBTDS_8_0_;
default:
return DBTDS_UNKNOWN;
}
Expand Down
6 changes: 4 additions & 2 deletions src/dblib/unittests/t0022.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,15 @@ main(int argc, char **argv)
assert(erc == NO_MORE_ROWS);
}

#if defined(DBTDS_7_0) && defined(DBTDS_7_1) && defined(DBTDS_7_2) && defined(DBTDS_7_3) && defined(DBTDS_7_4)
#if defined(DBTDS_7_0) && defined(DBTDS_7_1) && defined(DBTDS_7_2) && defined(DBTDS_7_3) \
&& defined(DBTDS_7_4) && defined(DBTDS_8_0_)
if ((dbnumrets(dbproc) == 0)
&& ((DBTDS(dbproc) == DBTDS_7_0)
|| (DBTDS(dbproc) == DBTDS_7_1)
|| (DBTDS(dbproc) == DBTDS_7_2)
|| (DBTDS(dbproc) == DBTDS_7_3)
|| (DBTDS(dbproc) == DBTDS_7_4))) {
|| (DBTDS(dbproc) == DBTDS_7_4)
|| (DBTDS(dbproc) == DBTDS_8_0_))) {
printf("WARNING: Received no return parameters from server!\n");
printf("WARNING: This is likely due to a bug in Microsoft\n");
printf("WARNING: SQL Server 7.0 SP3 and later.\n");
Expand Down
4 changes: 3 additions & 1 deletion src/odbc/unixodbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ static const char *const aTDSver[] = {
"7.2",
"7.3",
"7.4",
"8.0",
NULL
};

Expand Down Expand Up @@ -203,7 +204,8 @@ ODBCINSTGetProperties(HODBCINSTPROPERTY hLastProperty)
" 7.1 MSSQL 2000\n"
" 7.2 MSSQL 2005\n"
" 7.3 MSSQL 2008\n"
" 7.4 MSSQL 2012, 2014, 2016 or 2019"
" 7.4 MSSQL 2012, 2014, 2016 or 2019\n"
" 8.0 MSSQL 2022"
);

hLastProperty = definePropertyList(hLastProperty, odbc_param_Language, "us_english", (void*) aLanguage, sizeof(aLanguage),
Expand Down
3 changes: 2 additions & 1 deletion src/odbc/winsetup.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ DSNDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
const char *pstr;
int major, minor, i;
static const char *protocols[] = {
"TDS 4.2", "TDS 4.6", "TDS 5.0", "TDS 7.0", "TDS 7.1", "TDS 7.2", "TDS 7.3", "TDS 7.4", NULL
"TDS 4.2", "TDS 4.6", "TDS 5.0", "TDS 7.0", "TDS 7.1", "TDS 7.2", "TDS 7.3", "TDS 7.4",
"TDS 8.0", NULL
};

switch (message) {
Expand Down
22 changes: 22 additions & 0 deletions src/tds/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,7 @@ tds_config_verstr(const char *tdsver, TDSLOGIN * login)
, { "7.2", 0x702 }
, { "7.3", 0x703 }
, { "7.4", 0x704 }
, { "8.0", 0x800 }
};
const struct tdsvername_t *pver;

Expand Down Expand Up @@ -1444,4 +1445,25 @@ tds_get_compiletime_settings(void)
return &settings;
}

/**
* Make sure proper setting are in place for TDS 8.0
*/
TDSRET
tds8_adjust_login(TDSLOGIN *login)
{
if (!IS_TDS80_PLUS(login) && login->encryption_level != TDS_ENCRYPTION_STRICT)
return TDS_SUCCESS;

login->tds_version = 0x800;
login->encryption_level = TDS_ENCRYPTION_STRICT;

/* we must have certificates */
if (tds_dstr_isempty(&login->cafile)) {
if (!tds_dstr_copy(&login->cafile, "system"))
return -TDSEMEM;
}

return TDS_SUCCESS;
}

/** @} */
8 changes: 7 additions & 1 deletion src/tds/login.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,9 @@ TDSRET
tds_connect_and_login(TDSSOCKET * tds, TDSLOGIN * login)
{
int oserr = 0;

TDS_PROPAGATE(tds8_adjust_login(login));

return tds_connect(tds, login, &oserr);
}

Expand Down Expand Up @@ -1165,6 +1168,9 @@ tds7_send_login(TDSSOCKET * tds, const TDSLOGIN * login)
case 0x703:
tds7version = tds73Version;
break;
case 0x800:
/* for TDS 8.0 version should be ignored and ALPN used,
* practically clients/servers usually set this to 7.4 */
case 0x704:
tds7version = tds74Version;
break;
Expand Down Expand Up @@ -1456,7 +1462,7 @@ tds71_do_login(TDSSOCKET * tds, TDSLOGIN* login)

tdsdump_log(TDS_DBG_INFO1, "detected crypt flag %d\n", crypt_flag);

if (!mars_replied)
if (!mars_replied && encryption_level != TDS_ENCRYPTION_STRICT)
tds->conn->tds_version = 0x701;

/* if server does not have certificate or TLS already setup do normal login */
Expand Down
62 changes: 40 additions & 22 deletions src/tds/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,11 +383,10 @@ tds_certificate_set_x509_system_trust(gnutls_certificate_credentials_t cred)
#endif

static int
tds_verify_certificate(gnutls_session_t session)
tds_verify_certificate(gnutls_session_t session, TDSSOCKET *tds)
{
unsigned int status;
int ret;
TDSSOCKET *tds = (TDSSOCKET *) gnutls_transport_get_ptr(session);

#ifdef ENABLE_DEVELOPING
unsigned int list_size;
Expand Down Expand Up @@ -470,13 +469,30 @@ tds_verify_certificate(gnutls_session_t session)
return 0;
}

static int
tds_verify_certificate_tds(gnutls_session_t session)
{
TDSSOCKET *tds = (TDSSOCKET *) gnutls_transport_get_ptr(session);

return tds_verify_certificate(session, tds);
}

static int
tds_verify_certificate_conn(gnutls_session_t session)
{
TDSCONNECTION *conn = (TDSCONNECTION*) gnutls_transport_get_ptr(session);

return tds_verify_certificate(session, CONN2TDS(conn));
}

TDSRET
tds_ssl_init(TDSSOCKET *tds, bool full)
{
gnutls_session_t session;
gnutls_certificate_credentials_t xcred;
int ret;
const char *tls_msg;
int (*verify_func)(gnutls_session_t session);

xcred = NULL;
session = NULL;
Expand Down Expand Up @@ -507,6 +523,24 @@ tds_ssl_init(TDSSOCKET *tds, bool full)
if (ret != 0)
goto cleanup;

/* Initialize TLS session */
tls_msg = "initializing session";
ret = gnutls_init(&session, GNUTLS_CLIENT);
if (ret != 0)
goto cleanup;

if (!full) {
gnutls_transport_set_ptr(session, tds);
gnutls_transport_set_pull_function(session, tds_pull_func_login);
gnutls_transport_set_push_function(session, tds_push_func_login);
verify_func = tds_verify_certificate_tds;
} else {
gnutls_transport_set_ptr(session, tds->conn);
gnutls_transport_set_pull_function(session, tds_pull_func);
gnutls_transport_set_push_function(session, tds_push_func);
verify_func = tds_verify_certificate_conn;
}

if (!tds_dstr_isempty(&tds->login->cafile)) {
tls_msg = "loading CA file";
if (strcasecmp(tds_dstr_cstr(&tds->login->cafile), "system") == 0)
Expand All @@ -522,26 +556,10 @@ tds_ssl_init(TDSSOCKET *tds, bool full)
goto cleanup;
}
#ifdef HAVE_GNUTLS_CERTIFICATE_SET_VERIFY_FUNCTION
gnutls_certificate_set_verify_function(xcred, tds_verify_certificate);
gnutls_certificate_set_verify_function(xcred, verify_func);
#endif
}

/* Initialize TLS session */
tls_msg = "initializing session";
ret = gnutls_init(&session, GNUTLS_CLIENT);
if (ret != 0)
goto cleanup;

if (!full) {
gnutls_transport_set_ptr(session, tds);
gnutls_transport_set_pull_function(session, tds_pull_func_login);
gnutls_transport_set_push_function(session, tds_push_func_login);
} else {
gnutls_transport_set_ptr(session, tds->conn);
gnutls_transport_set_pull_function(session, tds_pull_func);
gnutls_transport_set_push_function(session, tds_push_func);
}

/* NOTE: these functions return int however they cannot fail */

/* use default priorities... */
Expand Down Expand Up @@ -585,7 +603,7 @@ tds_ssl_init(TDSSOCKET *tds, bool full)

#ifndef HAVE_GNUTLS_CERTIFICATE_SET_VERIFY_FUNCTION
if (!tds_dstr_isempty(&tds->login->cafile)) {
ret = tds_verify_certificate(session);
ret = tds_verify_certificate(session, tds);
if (ret != 0)
goto cleanup;
}
Expand All @@ -610,9 +628,9 @@ tds_ssl_init(TDSSOCKET *tds, bool full)
return TDS_SUCCESS;

cleanup:
set_current_tds(tds->conn, NULL);
if (session)
gnutls_deinit(session);
set_current_tds(tds->conn, NULL);
if (xcred)
gnutls_certificate_free_credentials(xcred);
tdsdump_log(TDS_DBG_ERROR, "%s failed: %s\n", tls_msg, gnutls_strerror (ret));
Expand Down Expand Up @@ -1137,7 +1155,6 @@ tds_ssl_init(TDSSOCKET *tds, bool full)
return TDS_SUCCESS;

cleanup:
set_current_tds(tds->conn, NULL);
if (b2)
BIO_free(b2);
if (b)
Expand All @@ -1146,6 +1163,7 @@ tds_ssl_init(TDSSOCKET *tds, bool full)
SSL_shutdown(con);
SSL_free(con);
}
set_current_tds(tds->conn, NULL);
SSL_CTX_free(ctx);
tdsdump_log(TDS_DBG_ERROR, "%s failed\n", tls_msg);
return TDS_FAIL;
Expand Down
5 changes: 5 additions & 0 deletions src/tds/token.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ tds_process_loginack(TDSSOCKET *tds, TDSRET *login_succeeded)
unsigned char ack;
TDS_UINT product_version;
int memrc = 0;
TDS_USMALLINT orig_tds_version = tds->conn->tds_version;

struct { unsigned char major, minor, tiny[2];
unsigned int reported;
Expand Down Expand Up @@ -383,6 +384,10 @@ tds_process_loginack(TDSSOCKET *tds, TDSRET *login_succeeded)
tds->conn->product_version = product_version;
tdsdump_log(TDS_DBG_FUNC, "Product version %lX\n", (unsigned long) product_version);

/* internal version is ignored for TDS 8.0+ */
if (orig_tds_version >= 0x800)
tds->conn->tds_version = orig_tds_version;

/*
* TDS 5.0 reports 5 on success 6 on failure
* TDS 4.2 reports 1 on success and is not
Expand Down

0 comments on commit f26b1cd

Please sign in to comment.