prisma / tiberius

TDS 7.2+ (Microsoft SQL Server) driver for Rust
Apache License 2.0
311 stars 113 forks source link

Connection Failure with MSSQL: Special Character Password #333

Open keithmss opened 5 months ago

keithmss commented 5 months ago

Summary

I'm encountering a connection issue when attempting to tiberius to connect to a Microsoft SQL Server. This issue does not arise when connecting via php or sqlcmd with the same credentials.

Detailed Description

I have successfully connected to the MSSQL server using both php and sqlcmd commands, indicating that the server is accessible and the credentials are correct. The connection details include a password that contains the special character $ followed by numbers, which I suspect might be related to the issue. Here are examples of the successful connection attempts for reference:

const CONNECTION_STRING: &str = r"Server=sql.foo.com,999;Database=Database;UID='User';PWD='Password$1337'";

[tokio::main]

async fn main() -> Result<()> { let mut config = Config::from_ado_string(CONNECTION_STRING)?; config.trust_cert(); let tcp = TcpStream::connect(config.get_addr()).await?; tcp.setnodelay(true)?; let = Client::connect(config, tcp.compat_write()).await?; Ok(()) }

Fails with the following error message:

Error: Token error: 'Login failed for user 'User'.' on server SERVER executing on line 1 (code: 18456, state: 1, class: 14)



## Environment
**Server**: Microsoft SQL Server 2019 (RTM-CU19) (KB5023049 - 15.0.4298.1 (X64))

## Issue Analysis
The error suggests a login failure, which is peculiar given that the same credentials work with other methods. The inclusion of a special character in the password and its handling within the Rust environment might be contributing factors but I'm not sure.
janpio commented 5 months ago

Does it work if you urlencode the special character?

keithmss commented 5 months ago

By hand:

use anyhow::Result;
use tiberius::Client;
use tiberius::Config;
use tokio::net::TcpStream;
use tokio_util::compat::TokioAsyncWriteCompatExt;

const CONNECTION_STRING: &str = r"Server=sql.foo.com,999;Database=Database;UID='User';PWD='Password%241337'";

#[tokio::main]
async fn main() -> Result<()> {
    let mut config = Config::from_ado_string(CONNECTION_STRING)?;
    config.trust_cert();
    let tcp = TcpStream::connect(config.get_addr()).await?;
    tcp.set_nodelay(true)?;
    let _ = Client::connect(config, tcp.compat_write()).await?;
    Ok(())
}

It does not.

keithmss commented 5 months ago

Update: By using wireshark and setting encryption to NotSupported I can confirm that the login packet contains the correct password. I can't compare packets because SqlCmd does encrypt the login.

What is interesting is that SqlCmd uses an older version of the pre login message.

SqlCmd uses version: 0.0.1537 Tiberius uses version: 0.2.3072

Should this be a cause for concern?