Skip to content

Restore Windows SSPI for the rustls and windows-static-ssl backends - #667

Open
ns-ylambert wants to merge 2 commits into
sagebind:mainfrom
ns-ylambert:fix-sspi-non-schannel
Open

ns-ylambert wants to merge 2 commits into
sagebind:mainfrom
ns-ylambert:fix-sspi-non-schannel

Conversation

@ns-ylambert

Copy link
Copy Markdown

Summary

libcurl's Windows SSPI infrastructure — the machinery for integrated Windows auth (NTLM-SSO, Negotiate/Kerberos-SSO) — is currently compiled only under feature = "ssl" on Windows (which also enables Schannel). Users on rustls (curl+rustls-ffi) or windows-static-ssl (curl+OpenSSL) silently lose that capability, even though SSPI is TLS-backend-independent at the C level.

Additionally, the spnego feature is broken on Windows for non-Schannel backends: the upstream USE_SPNEGO define is unconditional on all platforms and activates code in http_negotiate.c referencing struct negotiatedata::context — a field only defined when USE_WINDOWS_SSPI is set. Under rustls or windows-static-ssl (no USE_WINDOWS_SSPI), this fails to compile with C2039 'context' is not a member of 'negotiatedata'.

This PR fixes both.

What lands

Two commits:

  • curl-sys: fix spnego + rustls compile error on Windows: guards USE_SPNEGO to non-Windows only (on Windows, curl_setup.h auto-defines it from USE_WINDOWS_SSPI when that's set). Refactors SPNEGO source gating so http_negotiate.c and spnego_sspi.c compile correctly regardless of TLS backend. Removes duplicate file entries from the Schannel per-backend block.
  • curl-sys: compile Windows SSPI in the rustls/windows-static-ssl branches: adds USE_WINDOWS_SSPI + the three SSPI infrastructure files to the rustls and windows-static-ssl branches, without pulling in Schannel-specific sources. Widens the windows_sspi guard to cover all three Windows TLS backends.

Verification

  • cargo check -p curl-sys --features static-curl,rustls,spnego --target x86_64-pc-windows-msvc: succeeds on this PR; fails with C2039 on origin/main.
  • cargo check -p curl-sys --features static-curl,rustls --target x86_64-pc-windows-msvc: compiles cleanly with SSPI now included.
  • cargo check -p curl-sys --features static-curl --target x86_64-pc-windows-msvc (default Schannel): unchanged behavior.

Compile-check matrix

Feature combination main this PR CI mode¹ Fixed by
static-curl,rustls,spnego ❌ C2039 ✅ — 351987c
static-curl,rustls ✅ ✅ (SSPI now compiled) test-compile (existing) 307eb3d
static-curl,windows-static-ssl (behind #666) ❌ C1083 baseline² ✅ (SSPI now compiled) — 307eb3d
static-curl (default Schannel) ✅ ✅ (unchanged) test-execute —

¹ CI mode = what ci/run.sh does with this combination on Test (win64). test-execute runs the test binaries, test-compile is --no-run, — means this combo isn't directly exercised by CI on origin/main but compiles when checked locally.

² Baseline behavior on origin/main: the C1083 opensslv.h failure static-curl,windows-static-ssl hits without this fix is orthogonal to this PR's concern; it's what #666 (fix-windows-static-ssl) addresses. Once #666 merges, the windows-static-ssl row would gain a proper CI signal via the win64-static-ssl matrix entry.

Note on CI coverage of the C2039 fix

ci/run.sh currently does not exercise --features rustls,static-curl,spnego on any target. Commit 307eb3d's SSPI-beside-rustls addition IS exercised by the existing Test (win64) --features rustls,static-curl invocation (SSPI files compile as part of that build now), but commit 351987c's specific C2039 fix has no CI-executed guard. Adding

if [ "$TARGET" = "x86_64-pc-windows-msvc" ]; then
    cargo test --target $TARGET --no-run --features rustls,static-curl,spnego $features
fi

around line 34 of ci/run.sh would promote the C2039 fix from a locally-verified reproducer to a CI-executed guard against future regressions. Windows-msvc-gated because the C2039 bug is Windows-specific. Enabling spnego on the Linux docker targets would pull in GSSAPI sources that need libkrb5-dev, a build dep the current Linux docker images don't install. Kept out of this PR to keep the diff minimal; happy to add if desired.

Related

  • Add support for enabling SPNEGO when building curl #233 (merged, 2018-10-27). Original introduction of the spnego feature. SSPI was always the intended Windows integration; the C2039 regression this PR fixes accumulated later when the rustls (Add experimental support for rustls #374) and windows-static-ssl (Adding the possibility to use windows openssl backend instead of schannel #466) backends landed without keeping SSPI wiring in sync.
  • Avoid compiling duplicate curl sources  #664 (open, 2026-09-16). Partially overlaps with this PR's commit 1: both dedup the SPNEGO/SSPI file entries from the Schannel per-backend block with the same outcome. It additionally dedups ftp.c and bufref.c (unrelated to SPNEGO/SSPI) to fix a parallel-build C1083: Permission denied race, which this PR does not touch. It does not gate USE_SPNEGO by platform, so it does not itself fix the C2039 bug this PR addresses. The two PRs are complementary; a merge conflict is likely on the SPNEGO/SSPI block regardless of order.
  • Vendor libgss when static-curl and spnego features are set  #481 (open, 2022-11-28). Related but distinct: covers the Linux/GSSAPI side of spnego build ergonomics (missing libgss at build time); this PR fixes the Windows/SSPI side. It remains open for the Linux/GSSAPI side.
  • Full validation of this PR's windows-static-ssl + SSPI code path requires Fix and cover the windows-static-ssl feature (curl+OpenSSL on Windows) #666 to land first. On origin/main, no matrix entry exercises --features windows-static-ssl; commit 2's addition to that branch is compiled locally but not by CI on this PR. Once merged, this PR's windows-static-ssl changes gain end-to-end coverage from the win64-static-ssl matrix entry.
  • Silent NTLM-SSO / Negotiate-SSO loss on rustls / windows-static-ssl backends: behavior gap not tracked as a public issue yet.

The upstream `spnego` feature defined `USE_SPNEGO` unconditionally on all
platforms, including Windows. On Windows, `USE_SPNEGO` activates code in
`http_negotiate.c` that references `struct negotiatedata::context` (a field
only defined when `USE_WINDOWS_SSPI` is present). Under the `rustls` or
`windows-static-ssl` TLS backends, `USE_WINDOWS_SSPI` is not defined,
causing `C2039 'context' is not a member of 'negotiatedata'` errors.

Fix: guard the `USE_SPNEGO` define to non-Windows only. On Windows,
`curl_setup.h` auto-defines `USE_SPNEGO` from `USE_WINDOWS_SSPI` whenever
that is set. `http_negotiate.c` is still compiled on Windows when `spnego`
is requested (it contains valid stub paths for non-SSPI builds), but without
`USE_SPNEGO` the `context`-field access at line 203 is inside a dead `#ifdef`
block.

`spnego_sspi.c` genuinely requires `USE_WINDOWS_SSPI` to compile (it is a
Windows-SSPI-specific file). Introduce `windows_sspi` — true when `ssl` /
Schannel is the active backend on Windows — and gate `spnego_sspi.c`
exclusively on it.

Summary of SPNEGO source gating after this commit:
- `USE_SPNEGO` define: non-Windows `spnego` only.
- `http_negotiate.c`: `windows_sspi` OR `spnego` (any platform/backend).
- `spnego_sspi.c`: `windows_sspi` only.

Also removes the duplicate `http_negotiate.c` / `spnego_sspi.c` /
`vauth.c` entries from the Schannel per-backend block (`vauth.c` is
already in the unconditional base source set).
The SSPI infrastructure (`curl_sspi.c`, `socks_sspi.c`,
`vauth/krb5_sspi.c`) and `USE_WINDOWS_SSPI` are compiled only under
`feature = "ssl"` on Windows, which also enables Schannel.

A `rustls` (curl+rustls-ffi) or `windows-static-ssl` (curl+OpenSSL) build
therefore silently loses libcurl's SSPI-backed integrated Windows
authentication (NTLM-SSO / Negotiate-SSO), even though SSPI is
TLS-backend-independent at the C level.

Add `USE_WINDOWS_SSPI` and the same three SSPI infrastructure files to the
`rustls` / `windows-static-ssl` branches on Windows, without `USE_SCHANNEL`
or the Schannel-only sources (`schannel.c`, `schannel_verify.c`).

Also widen the `windows_sspi` guard (introduced by the companion
"fix spnego + rustls" commit) from `ssl`-only to cover both `rustls` and
`windows-static-ssl`, so the shared SPNEGO sources (`http_negotiate.c`,
`vauth/spnego_sspi.c`) are compiled for all three Windows TLS backends
(OpenSSL / Rustls / Schannel).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant