Index: auth/auth.c
===================================================================
--- auth/auth.c	(revision 1938)
+++ auth/auth.c	(working copy)
@@ -95,6 +95,28 @@
         serf__validate_response_kerb_auth,
     },
 #endif
+#ifdef _WIN32
+    {
+        401,
+        "NTLM",
+        SERF_AUTHN_NTLM,
+        serf__init_ntlm,
+        serf__init_ntlm_connection,
+        serf__handle_ntlm_auth,
+        serf__setup_request_ntlm_auth,
+        serf__validate_response_ntlm_auth,
+    },
+    {
+        407,
+        "NTLM",
+        SERF_AUTHN_NTLM,
+        serf__init_ntlm,
+        serf__init_ntlm_connection,
+        serf__handle_ntlm_auth,
+        serf__setup_request_ntlm_auth,
+        serf__validate_response_ntlm_auth,
+    },
+#endif
     /* ADD NEW AUTHENTICATION IMPLEMENTATIONS HERE (as they're written) */
 
     /* sentinel */
Index: auth/auth.h
===================================================================
--- auth/auth.h	(revision 1938)
+++ auth/auth.h	(working copy)
@@ -104,8 +104,38 @@
                                                serf_request_t *request,
                                                serf_bucket_t *response,
                                                apr_pool_t *pool);
-#endif /* SERF_HAVE_SPNEGO */
+#endif /* SERF_HAVE_KERB */
 
+#ifdef _WIN32
+/** NTLM authentication **/
+apr_status_t serf__init_ntlm(int code,
+                             serf_context_t *ctx,
+                             apr_pool_t *pool);
+apr_status_t serf__init_ntlm_connection(int code,
+                                        serf_connection_t *conn,
+                                        apr_pool_t *pool);
+apr_status_t serf__handle_ntlm_auth(int code,
+                                    serf_request_t *request,
+                                    serf_bucket_t *response,
+                                    const char *auth_hdr,
+                                    const char *auth_attr,
+                                    void *baton,
+                                    apr_pool_t *pool);
+apr_status_t serf__setup_request_ntlm_auth(peer_t peer,
+                                           int code,
+                                           serf_connection_t *conn,
+                                           serf_request_t *request,
+                                           const char *method,
+                                           const char *uri,
+                                           serf_bucket_t *hdrs_bkt);
+apr_status_t serf__validate_response_kerb_auth(peer_t peer,
+                                               int code,
+                                               serf_connection_t *conn,
+                                               serf_request_t *request,
+                                               serf_bucket_t *response,
+                                               apr_pool_t *pool);
+#endif /* _WIN32 */
+
 #ifdef __cplusplus
 }
 #endif
Index: auth/win32_auth_ntlm.c
===================================================================
--- auth/win32_auth_ntlm.c	(revision 0)
+++ auth/win32_auth_ntlm.c	(working copy)
@@ -0,0 +1,343 @@
+/* Copyright 2009 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Rewrite based on win32_auth_sspi.c in pre-1.7 Subversion */
+
+/*
+ * NTLM authentication for HTTP
+ *
+ * 1. C  --> S:    GET
+ *
+ *    C <--  S:    401 Authentication Required
+ *                 WWW-Authenticate: NTLM
+ *
+ * -> Initialize the NTLM authentication handler.
+ *
+ * 2. C  --> S:    GET
+ *                 Authorization: NTLM <Base64 encoded Type 1 message>
+ *                 sspi_ctx->state = sspi_auth_in_progress;
+ *
+ *    C <--  S:    401 Authentication Required
+ *                 WWW-Authenticate: NTLM <Base64 encoded Type 2 message>
+ *
+ * 3. C  --> S:    GET
+ *                 Authorization: NTLM <Base64 encoded Type 3 message>
+ *                 sspi_ctx->state = sspi_auth_completed;
+ *
+ *    C <--  S:    200 Ok
+ *
+ * This handshake is required for every new connection. If the handshake is
+ * completed successfully, all other requested on the same connection will
+ * be authenticated without needing to pass the WWW-Authenticate header.
+ *
+ * Note: Step 1 of the handshake will only happen on the first connection, once
+ * we know the server requires NTLM authentication, the initial requests on the
+ * other connections will include the NTLM Type 1 message, so we start at
+ * step 2 in the handshake.
+ */
+
+#include "serf.h"
+#include "serf_private.h"
+#include "auth/auth.h"
+
+#include "win32_auth_ntlm.h"
+
+/*** Includes ***/
+#ifdef _WIN32
+
+#ifndef __SSPI_H__
+#define SECURITY_WIN32
+#include <sspi.h>
+#endif
+
+#include <assert.h>
+
+#include <apr.h>
+#include <apr_base64.h>
+#include <apr_strings.h>
+
+/* Calculates the maximum token size based on the authentication protocol. */
+static apr_status_t
+sspi_maxtokensize(unsigned int *size,
+                  const char *auth_pkg,
+                  serf__ntlm_ctx_t *ntlm_context,
+                  apr_pool_t *scratch_pool)
+{
+  SECURITY_STATUS status;
+  SecPkgInfo *sec_pkg_info = NULL;
+  SEC_CHAR *package_name = apr_pstrdup(scratch_pool, auth_pkg);
+  PSecurityFunctionTable sspi = ntlm_context->sspi;
+
+  status = sspi->QuerySecurityPackageInfo(package_name,
+                                          &sec_pkg_info);
+  if (status == SEC_E_OK)
+    {
+      *size = sec_pkg_info->cbMaxToken;
+      sspi->FreeContextBuffer(sec_pkg_info);
+    }
+  else
+    return APR_EGENERAL; /* _("NTLM Initialization failed.")); */
+
+  return APR_SUCCESS;
+}
+
+
+/* Provides the necessary information for the http authentication headers
+   for both the initial request to open an authentication connection, as
+   the response to the server's authentication challenge.
+ */
+static apr_status_t
+sspi_get_credentials(const char **buf, apr_size_t *buf_len,
+                     char *token, apr_size_t token_len,
+                     serf__ntlm_ctx_t *ntlm_context,
+					 apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  SecBuffer in_buf, out_buf;
+  SecBufferDesc in_buf_desc, out_buf_desc;
+  SECURITY_STATUS status;
+  DWORD ctx_attr;
+  TimeStamp expires;
+  CredHandle creds;
+  char *target = NULL;
+  CtxtHandle *ctx = &(ntlm_context->ctx);
+  PSecurityFunctionTable sspi = ntlm_context->sspi;
+
+  if (ntlm_context->ntlm_maxtokensize == 0)
+    sspi_maxtokensize(&ntlm_context->ntlm_maxtokensize, "NTLM", ntlm_context, scratch_pool);
+
+  /* Prepare inbound buffer. */
+  in_buf.BufferType = SECBUFFER_TOKEN;
+  in_buf.cbBuffer   = token_len;
+  in_buf.pvBuffer   = token;
+  in_buf_desc.cBuffers  = 1;
+  in_buf_desc.ulVersion = SECBUFFER_VERSION;
+  in_buf_desc.pBuffers  = &in_buf;
+
+  /* Prepare outbound buffer. */
+  out_buf.BufferType = SECBUFFER_TOKEN;
+  out_buf.cbBuffer   = ntlm_context->ntlm_maxtokensize;
+  out_buf.pvBuffer   = apr_palloc(result_pool,
+                                  ntlm_context->ntlm_maxtokensize);
+  out_buf_desc.cBuffers  = 1;
+  out_buf_desc.ulVersion = SECBUFFER_VERSION;
+  out_buf_desc.pBuffers  = &out_buf;
+
+  /* Try to accept the server token. */
+  status = sspi->AcquireCredentialsHandle(NULL, /* current user */
+                                          "NTLM",
+                                          SECPKG_CRED_OUTBOUND,
+                                          NULL, NULL,
+                                          NULL, NULL,
+                                          &creds,
+                                          &expires);
+
+  if (status != SEC_E_OK)
+    return APR_EGENERAL; /* _("SSPI Initialization failed.") */
+
+  status = sspi->InitializeSecurityContext(&creds,
+                                           ctx != NULL && ctx->dwLower != 0
+                                             ? ctx
+                                             : NULL,
+                                           target,
+                                           ISC_REQ_REPLAY_DETECT |
+                                           ISC_REQ_SEQUENCE_DETECT |
+                                           ISC_REQ_CONFIDENTIALITY |
+                                           ISC_REQ_DELEGATE,
+                                           0,
+                                           SECURITY_NATIVE_DREP,
+                                           &in_buf_desc,
+                                           0,
+                                           ctx,
+                                           &out_buf_desc,
+                                           &ctx_attr,
+                                           &expires);
+
+  /* Finish authentication if SSPI requires so. */
+  if (status == SEC_I_COMPLETE_NEEDED
+      || status == SEC_I_COMPLETE_AND_CONTINUE)
+    {
+      if (sspi->CompleteAuthToken != NULL)
+        sspi->CompleteAuthToken(ctx, &out_buf_desc);
+    }
+
+  *buf = out_buf.pvBuffer;
+  *buf_len = out_buf.cbBuffer;
+
+  switch (status)
+    {
+      case SEC_E_OK:
+      case SEC_I_COMPLETE_NEEDED:
+          ntlm_context->state = ntlm_auth_completed;
+          break;
+
+      case SEC_I_CONTINUE_NEEDED:
+      case SEC_I_COMPLETE_AND_CONTINUE:
+          ntlm_context->state = ntlm_auth_in_progress;
+          break;
+
+      default:
+          return APR_EGENERAL; /* "Authentication failed with error 0x%x." */
+    }
+
+  return APR_SUCCESS;
+}
+
+
+apr_status_t
+serf__init_ntlm(int code,
+                serf_context_t *ctx,
+                apr_pool_t *pool)
+{
+  return APR_SUCCESS;
+}
+
+apr_status_t
+serf__init_ntlm_connection(int code,
+                           serf_connection_t *conn,
+                           apr_pool_t *pool)
+{
+  serf__ntlm_ctx_t *ntlm_context;
+
+  if (strncmp(conn->host_url, "https://", 8))
+    return APR_EGENERAL; /* Only supported on secure connections */
+
+  ntlm_context = apr_pcalloc(pool, sizeof(*ntlm_context));
+  ntlm_context->ctx.dwLower = 0;
+  ntlm_context->ctx.dwUpper = 0;
+  ntlm_context->sspi = InitSecurityInterface();
+  ntlm_context->state = ntlm_auth_not_started;
+  ntlm_context->pool = pool;
+  ntlm_context->header = (code == 401) ? "Authorization"
+                                       : "Proxy-Authorization";
+
+  if (!ntlm_context->sspi)
+    return APR_EGENERAL;
+
+  if (code == 401)
+      conn->authn_baton = ntlm_context;
+  else
+      conn->proxy_authn_baton = ntlm_context;
+
+  /* Make serf send the initial requests one by one */
+  serf_connection_set_max_outstanding_requests(conn, 1);
+
+  return APR_SUCCESS;
+}
+
+apr_status_t
+serf__handle_ntlm_auth(int code,
+                       serf_request_t *request,
+                       serf_bucket_t *response,
+                       const char *auth_hdr,
+                       const char *auth_attr,
+                       void *baton,
+                       apr_pool_t *pool)
+{
+  char *token = NULL;
+  apr_size_t token_len = 0;
+  serf_connection_t *conn = request->conn;
+  apr_status_t status;
+  serf__ntlm_ctx_t *ntlm_context = (code == 401) ? conn->authn_baton
+                                                 : conn->proxy_authn_baton;
+
+  assert(ntlm_context != NULL);
+  if (!ntlm_context)
+    return APR_EGENERAL;
+
+  switch (ntlm_context->state)
+    {
+      case ntlm_auth_in_progress:
+        {
+          const char *base64_token;
+
+          if (!auth_attr)
+            return APR_EGENERAL;
+
+          base64_token = apr_pstrdup(pool, auth_attr);
+          token_len = apr_base64_decode_len(base64_token);
+          token = apr_palloc(pool, token_len);
+          apr_base64_decode(token, base64_token);
+        }
+        /* fall through */
+      case ntlm_auth_not_started:
+        {
+          const char *tmp;
+          apr_size_t tmp_len;
+
+          status = sspi_get_credentials(&tmp, &tmp_len,
+                                        token, token_len,
+                                        ntlm_context, pool, pool);
+          if (status)
+            return status;
+
+          serf__encode_auth_header(&ntlm_context->header_value, "NTLM", tmp, tmp_len,
+                                   ntlm_context->pool);
+          break;
+        }
+    }
+
+  /* If the handshake is finished remove the request limit. */
+  if (ntlm_context->state == ntlm_auth_completed)
+    serf_connection_set_max_outstanding_requests(conn, 0);
+
+  return APR_SUCCESS;
+}
+
+apr_status_t
+serf__setup_request_ntlm_auth(peer_t peer,
+                              int code,
+                              serf_connection_t *conn,
+                              serf_request_t *request,
+                              const char *method,
+                              const char *uri,
+                              serf_bucket_t *hdrs_bkt)
+{
+  serf__ntlm_ctx_t *ntlm_context = (peer == HOST) ? conn->authn_baton
+                                                  : conn->proxy_authn_baton;
+
+  if (ntlm_context && ntlm_context->header && ntlm_context->header_value)
+    {
+        serf_bucket_headers_setn(hdrs_bkt, ntlm_context->header,
+                                           ntlm_context->header_value);
+    }
+
+  return APR_SUCCESS;
+}
+
+apr_status_t
+serf__validate_response_ntlm_auth(peer_t peer,
+                                  int code,
+                                  serf_connection_t *conn,
+                                  serf_request_t *request,
+                                  serf_bucket_t *response,
+                                  apr_pool_t *pool)
+{
+  serf__ntlm_ctx_t *ntlm_context = (peer == HOST) ? conn->authn_baton
+                                                  : conn->proxy_authn_baton;
+
+  if (ntlm_context)
+    {
+      assert(ntlm_context->state == ntlm_auth_completed);
+
+      /* ### Disable further headers?
+      ntlm_context->header = NULL;
+      ntlm_context->header_value = NULL; */
+    }
+
+  return APR_SUCCESS;
+}
+
+#endif /* _WIN32 */
Index: auth/win32_auth_ntlm.h
===================================================================
--- auth/win32_auth_ntlm.h	(revision 0)
+++ auth/win32_auth_ntlm.h	(working copy)
@@ -0,0 +1,77 @@
+/*
+ * win32_auth_sspi.h : Private declarations for Windows SSPI authentication.
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+#ifndef SVN_LIBSVN_RA_SERF_WIN32_AUTH_SSPI_H
+#define SVN_LIBSVN_RA_SERF_WIN32_AUTH_SSPI_H
+
+/* Define this to use our fake_sspi.h header. This is handy for developers
+   on Unix to see if win32_auth_sspi.c will compile after changes are made.
+   It won't function, however, so don't keep it in your build.  */
+/* #define USE_FAKE_SSPI */
+
+#ifdef _WIN32
+
+#include "auth.h"
+
+#ifndef __SSPI_H__
+#define SECURITY_WIN32
+#include <sspi.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef enum ntlm_auth_state
+{
+  ntlm_auth_not_started,
+  ntlm_auth_in_progress,
+  ntlm_auth_completed,
+} ntlm_auth_state;
+
+/* Stores the context information related to SSPI. The context is per
+   connection, it enables SSPI to go through the challenge/response cycle
+   of the authentication protocols. */
+typedef struct serf__ntlm_ctx_t
+{
+  CtxtHandle ctx;
+  PSecurityFunctionTable sspi;
+  unsigned int ntlm_maxtokensize;
+
+  /* Current state of the authentication cycle. */
+  ntlm_auth_state state;
+
+  /* Authentication header, and pool to store it in */
+  const char *header;
+  const char *header_value;
+  apr_pool_t *pool;
+
+} serf__ntlm_ctx_t;
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SVN_RA_SERF_SSPI_ENABLED */
+
+#endif /* SVN_LIBSVN_RA_SERF_WIN32_AUTH_SSPI_H */
