Skip to content

mssql-tds: public SSPI context provider extension point (enables NTLM on Linux/macOS) #707

Open

Description

@egertaia

Problem statement

On Linux/macOS, integrated authentication is Kerberos-only via GSSAPI (mssql-tds/src/security/unix/mod.rs: "NTLM is not supported on Unix platforms"). There is no way to authenticate with a Windows/AD login when Kerberos is not usable, for example when:

  • the SQL Server service has no MSSQLSvc/... SPN registered (common when the service account lacks permission to self-register SPNs, and fixing it requires a domain admin),
  • the client machine has no ticket or cannot reach a KDC.

In that situation the GSSAPI handshake fails with:

Failed to initialize security context (code=0x000D0000): Major: Miscellaneous failure (see text);
Minor: Server (MSSQLSvc/<host>@<REALM>) unknown while looking up 'MSSQLSvc/<host>@<REALM>'

The same server is reachable from:

  • Windows clients, because SSPI Negotiate falls back to NTLM,
  • the Microsoft JDBC driver on macOS, via integratedSecurity=true;authenticationScheme=NTLM with a domain user and password.

Downstream crates also can't supply their own implementation:

  • SecurityContext is public, but the handler always builds its context through the platform create_security_context.
  • SspiAuthHandler::with_context exists, but it is #[cfg(test)] and pub(crate). This is still the case in 0.2.0.

Proposed solution

A public extension point, equivalent to SqlConnection.SspiContextProvider in Microsoft.Data.SqlClient:

  • Accept a user-supplied provider in ClientContext (for example Arc<dyn SecurityContextProvider>, or a factory closure) that creates a Box<dyn SecurityContext> per connection attempt, given the server, port and SPN.
  • When a provider is set, SspiAuthHandler uses it instead of the built-in SSPI/GSSAPI context. When it isn't set, nothing changes.
  • Pass channel bindings to the provider, so custom contexts work against servers with Extended Protection enabled.

This keeps NTLM out of mssql-tds itself. Downstream crates can implement it, for example with the pure-Rust sspi crate (Devolutions sspi-rs), which tiberius 0.13 uses for the same purpose. The same hook would serve other custom schemes and test doubles.

Affected crate

mssql-tds

Alternatives considered

  • Register the SPN. This is the right fix for Kerberos, but it needs a domain admin and isn't always possible for the person connecting.
  • SQL authentication. Not available when the server only grants access to AD logins.
  • Built-in opt-in NTLMv2 on Unix. IntegratedAuthConfig would carry explicit credentials, and SecurityPackage::Ntlm would be honored on Unix. It would never be an automatic fallback from Kerberos. This is more convenient for users, but more surface for mssql-tds to own.
  • Fork mssql-tds downstream. Works, but every consumer then maintains a patched fork.

Additional context

Downstream consumer: the Tabularis SQL Server plugin, which uses mssql-tds 0.2.0 through mssql-tiberius-bridge 0.2.0. The bridge would need to pass the provider through as well. Suggested by Saurabh Singh (@saurabh500). Happy to test a branch against a real AD-joined SQL Server from macOS.

Activity

  1. saurabh500 commented on Oct 16, 2026

    @saurabh500
    Contributor

    Egert (@egertaia) can you take a stab at the implementation?

  2. egertaia commented on Oct 16, 2026

    @egertaia
    Author
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions