Hello Joe,
I tested your patch and it didn't work (as reported before). Therefore I
cleaned up my own hack. With this patch (on my system at least) the reported
problems do not occur. I based my patch on 0.26.3. The patch, in diff -c
format, follows at the end of this mail.
My tests consists of:
svn lock
svn unlock --force
where my apache uses SSPI/NTLM, with maxkeepalives = 2
This handles the 2 scenarios described in my original bug-report. With my
patch they succeed without problems (afaict)
Hope to help,
Robert van der Boon
On 2/5/07, Robert van der Boon <[EMAIL PROTECTED]> wrote:
>> I tracked the problem down to this:
>> 1. neon doesnot clear its sspi context / token if a connection is
>> closed. Therefore the old token is used on the new connection, and the
>> server does not accept that.
2. neon should not close the connection if it is in the sspi/auth
>> negotiation for the non-idempotent messages (line 1216 in
>> ne_request.c). The NTLM authentication is a multi-leg authentication,
>> meaning we need at least 2 requests to do authentication. neon closes
>> the connection after the first request, resulting in problem 1..
In my patch I introduced a connection_closed hook and a
new "please do not disconnect, I'm in auth negotiation"-flag.
My patch is:
###############################################
diff -cr neon-0.26.3\src\ne_auth.c neon-0.26.3.rjvdboon\src\ne_auth.c
*** neon-0.26.3\src\ne_auth.c Mon Jan 22 17:12:24 2007
--- neon-0.26.3.rjvdboon\src\ne_auth.c Thu Feb 15 12:58:13 2007
***************
*** 238,243 ****
--- 238,253 ----
int flags; /* AUTH_FLAG_* flags */
};
+ #ifdef HAVE_SSPI
+ static void clean_session_sspi(auth_session *sess)
+ {
+ if (sess->sspi_token) ne_free(sess->sspi_token);
+ sess->sspi_token = NULL;
+ ne_sspi_destroy_context(sess->sspi_context);
+ sess->sspi_context = NULL;
+ }
+ #endif
+
static void clean_session(auth_session *sess)
{
if (sess->basic) ne_free(sess->basic);
***************
*** 263,272 ****
sess->gssapi_token = NULL;
#endif
#ifdef HAVE_SSPI
! if (sess->sspi_token) ne_free(sess->sspi_token);
! sess->sspi_token = NULL;
! ne_sspi_destroy_context(sess->sspi_context);
! sess->sspi_context = NULL;
#endif
}
--- 273,279 ----
sess->gssapi_token = NULL;
#endif
#ifdef HAVE_SSPI
! clean_session_sspi(sess);
#endif
}
***************
*** 551,557 ****
#ifdef HAVE_SSPI
static char *request_sspi(auth_session *sess, struct auth_request
*request)
{
! return ne_concat(sess->protocol->name, " ", sess->sspi_token, "\r\n",
NULL);
}
static int sspi_challenge(auth_session *sess, int attempt,
--- 558,566 ----
#ifdef HAVE_SSPI
static char *request_sspi(auth_session *sess, struct auth_request
*request)
{
! if (sess->sspi_token == NULL)
! return NULL;
! return ne_concat(sess->protocol->name, " ", sess->sspi_token, "\r\n",
NULL);
}
static int sspi_challenge(auth_session *sess, int attempt,
***************
*** 1211,1217 ****
&& (sess->protocol->flags & AUTH_FLAG_VERIFY_NON40x) == 0) {
ret = sess->protocol->verify(areq, sess, auth_info_hdr);
}
! else if (sess->protocol
&& sess->protocol->flags && AUTH_FLAG_VERIFY_NON40x
&& (status->klass == 2 || status->klass == 3)
&& auth_hdr) {
--- 1220,1226 ----
&& (sess->protocol->flags & AUTH_FLAG_VERIFY_NON40x) == 0) {
ret = sess->protocol->verify(areq, sess, auth_info_hdr);
}
! else if (sess->protocol && sess->protocol->verify
&& sess->protocol->flags && AUTH_FLAG_VERIFY_NON40x
&& (status->klass == 2 || status->klass == 3)
&& auth_hdr) {
***************
*** 1234,1239 ****
--- 1243,1251 ----
else if (sess->sspi_context) {
ne_sspi_clear_context(sess->sspi_context);
}
+ if (sess->protocol && sess->protocol->id == NE_AUTH_NEGOTIATE &&
sess->sspi_context) {
+ ne_set_request_flag(req, NE_REQFLAG_IN_AUTH_NEGOTIATION,
ne_sspi_is_in_negotiation(sess->sspi_context));
+ }
#endif
return ret;
***************
*** 1269,1274 ****
--- 1281,1292 ----
clean_session(sess);
ne_free(sess);
}
+ static void ah_close_conn(void *cookie)
+ {
+ #ifdef HAVE_SSPI
+ clean_session_sspi((auth_session*)cookie);
+ #endif
+ }
static void auth_register(ne_session *sess, int isproxy, unsigned
protomask,
const struct auth_class *ahc, const char *id,
***************
*** 1296,1302 ****
ne_hook_post_send(sess, ah_post_send, ahs);
ne_hook_destroy_request(sess, ah_destroy, ahs);
ne_hook_destroy_session(sess, free_auth, ahs);
!
ne_set_session_private(sess, id, ahs);
}
--- 1314,1322 ----
ne_hook_post_send(sess, ah_post_send, ahs);
ne_hook_destroy_request(sess, ah_destroy, ahs);
ne_hook_destroy_session(sess, free_auth, ahs);
! #ifdef HAVE_SSPI
! ne_hook_connection_close(sess, ah_close_conn, ahs);
! #endif
ne_set_session_private(sess, id, ahs);
}
diff -cr neon-0.26.3\src\ne_private.h neon-0.26.3.rjvdboon\src\ne_private.h
*** neon-0.26.3\src\ne_private.h Tue Mar 07 22:38:22 2006
--- neon-0.26.3.rjvdboon\src\ne_private.h Wed Feb 14 10:00:46 2007
***************
*** 87,93 ****
int rdtimeout; /* read timeout. */
struct hook *create_req_hooks, *pre_send_hooks, *post_send_hooks;
! struct hook *destroy_req_hooks, *destroy_sess_hooks, *private;
char *user_agent; /* full User-Agent: header field */
--- 87,93 ----
int rdtimeout; /* read timeout. */
struct hook *create_req_hooks, *pre_send_hooks, *post_send_hooks;
! struct hook *destroy_req_hooks, *destroy_sess_hooks,
*conn_close_hooks, *private;
char *user_agent; /* full User-Agent: header field */
diff -cr neon-0.26.3\src\ne_request.c neon-0.26.3.rjvdboon\src\ne_request.c
*** neon-0.26.3\src\ne_request.c Tue Mar 07 22:38:22 2006
--- neon-0.26.3.rjvdboon\src\ne_request.c Wed Feb 14 10:00:46 2007
***************
*** 1210,1216 ****
* then it is impossible to distinguish between a server failure
* and a connection timeout if an EOF/RST is received. So don't
* do that. */
! if (!req->flags[NE_REQFLAG_IDEMPOTENT] && req->session->persisted) {
NE_DEBUG(NE_DBG_HTTP, "req: Closing connection for non-idempotent
"
"request.\n");
ne_close_connection(req->session);
--- 1210,1217 ----
* then it is impossible to distinguish between a server failure
* and a connection timeout if an EOF/RST is received. So don't
* do that. */
! if (!req->flags[NE_REQFLAG_IDEMPOTENT] && req->session->persisted &&
! !req->flags[NE_REQFLAG_IN_AUTH_NEGOTIATION]) {
NE_DEBUG(NE_DBG_HTTP, "req: Closing connection for non-idempotent
"
"request.\n");
ne_close_connection(req->session);
diff -cr neon-0.26.3\src\ne_request.h neon-0.26.3.rjvdboon\src\ne_request.h
*** neon-0.26.3\src\ne_request.h Sun Feb 26 00:16:12 2006
--- neon-0.26.3.rjvdboon\src\ne_request.h Wed Feb 14 10:00:46 2007
***************
*** 231,236 ****
--- 231,239 ----
NE_REQFLAG_IDEMPOTENT, /* disable this flag if the request uses a
* non-idempotent method such as POST. */
+ NE_REQFLAG_IN_AUTH_NEGOTIATION, /* enable this flag if the request is
part of auth
+ * negotiation. i.e. please do not
close the connection
+ * or all my work was in vain... */
NE_REQFLAG_LAST /* enum sentinel value */
} ne_request_flag;
***************
*** 284,289 ****
--- 287,297 ----
void ne_hook_destroy_session(ne_session *sess,
ne_destroy_sess_fn fn, void *userdata);
+ typedef void (*ne_connection_close_fn)(void *userdata);
+ /* Hook called when the connection is closed. */
+ void ne_hook_connection_close(ne_session *sess,
+ ne_connection_close_fn fn, void *userdata);
+
/* The ne_unhook_* functions remove a hook registered with the given
* session. If a hook is found which was registered with a given
* function 'fn', and userdata pointer 'userdata', then it will be
***************
*** 299,304 ****
--- 307,314 ----
ne_destroy_req_fn fn, void *userdata);
void ne_unhook_destroy_session(ne_session *sess,
ne_destroy_sess_fn fn, void *userdata);
+ void ne_unhook_connection_close(ne_session *sess,
+ ne_connection_close_fn fn, void *userdata);
/* Store an opaque context for the request, 'priv' is returned by a
* call to ne_request_get_private with the same ID. */
diff -cr neon-0.26.3\src\ne_session.c neon-0.26.3.rjvdboon\src\ne_session.c
*** neon-0.26.3\src\ne_session.c Wed Mar 01 18:45:02 2006
--- neon-0.26.3.rjvdboon\src\ne_session.c Thu Feb 15 12:57:20 2007
***************
*** 71,76 ****
--- 71,78 ----
destroy_hooks(sess->post_send_hooks);
destroy_hooks(sess->destroy_req_hooks);
destroy_hooks(sess->destroy_sess_hooks);
+ destroy_hooks(sess->conn_close_hooks);
+ sess->conn_close_hooks = NULL; // Set to NULL explicitly, else would
be called by the close_connection below.
destroy_hooks(sess->private);
ne_free(sess->scheme);
***************
*** 256,263 ****
void ne_close_connection(ne_session *sess)
{
! if (sess->connected) {
NE_DEBUG(NE_DBG_SOCKET, "Closing connection.\n");
ne_sock_close(sess->socket);
sess->socket = NULL;
NE_DEBUG(NE_DBG_SOCKET, "Connection closed.\n");
--- 258,272 ----
void ne_close_connection(ne_session *sess)
{
! struct hook *hk, *next_hk;
NE_DEBUG(NE_DBG_SOCKET, "Closing connection.\n");
+ if (sess->connected) {
+ NE_DEBUG(NE_DBG_HTTP, "Running connection close hooks.\n");
+ for (hk = sess->conn_close_hooks; hk; hk = next_hk) {
+ ne_connection_close_fn fn = (ne_connection_close_fn)hk->fn;
+ next_hk = hk->next;
+ fn(hk->userdata);
+ }
ne_sock_close(sess->socket);
sess->socket = NULL;
NE_DEBUG(NE_DBG_SOCKET, "Connection closed.\n");
***************
*** 396,401 ****
--- 405,416 ----
ADD_HOOK(sess->destroy_sess_hooks, fn, userdata);
}
+ void ne_hook_connection_close(ne_session *sess,
+ ne_connection_close_fn fn, void *userdata)
+ {
+ ADD_HOOK(sess->conn_close_hooks, fn, userdata);
+ }
+
void ne_set_session_private(ne_session *sess, const char *id, void
*userdata)
{
add_hook(&sess->private, id, NULL, userdata);
***************
*** 444,447 ****
--- 459,468 ----
ne_destroy_sess_fn fn, void *userdata)
{
REMOVE_HOOK(sess->destroy_sess_hooks, fn, userdata);
+ }
+
+ void ne_unhook_connection_close(ne_session *sess,
+ ne_connection_close_fn fn, void *userdata)
+ {
+ REMOVE_HOOK(sess->conn_close_hooks, fn, userdata);
}
diff -cr neon-0.26.3\src\ne_sspi.c neon-0.26.3.rjvdboon\src\ne_sspi.c
*** neon-0.26.3\src\ne_sspi.c Tue Sep 05 16:43:48 2006
--- neon-0.26.3.rjvdboon\src\ne_sspi.c Wed Feb 14 10:00:46 2007
***************
*** 29,39 ****
#define SEC_SUCCESS(Status) ((Status) >= 0)
struct SSPIContextStruct {
CtxtHandle context;
char *serverName;
CredHandle credentials;
! int continueNeeded;
int authfinished;
char *mechanism;
int ntlm;
--- 29,46 ----
#define SEC_SUCCESS(Status) ((Status) >= 0)
+ /* Defined session flags: */
+ typedef enum {
+ ne_sspistatus_unknown = 0, /* unknown state, sspi unused */
+ ne_sspistatus_continueneeded, /* authentication in progress */
+ ne_sspistatus_authfinishedthisrequest /* authentication succeeded in
last request */
+ } ne_sspi_status;
+
struct SSPIContextStruct {
CtxtHandle context;
char *serverName;
CredHandle credentials;
! ne_sspi_status authState;
int authfinished;
char *mechanism;
int ntlm;
***************
*** 338,344 ****
}
sspiContext = ne_calloc(sizeof(SSPIContext));
- sspiContext->continueNeeded = 0;
if (ntlm) {
sspiContext->mechanism = "NTLM";
--- 345,350 ----
***************
*** 352,357 ****
--- 358,364 ----
sspiContext->ntlm = ntlm;
sspiContext->authfinished = 0;
+ sspiContext->authState = ne_sspistatus_unknown;
*context = sspiContext;
return 0;
}
***************
*** 367,373 ****
#else
pSFT->FreeCredentialsHandle(&(sspiContext->credentials));
#endif
! sspiContext->continueNeeded = 0;
}
/*
--- 374,380 ----
#else
pSFT->FreeCredentialsHandle(&(sspiContext->credentials));
#endif
! sspiContext->authState = ne_sspistatus_unknown;
}
/*
***************
*** 428,433 ****
--- 435,441 ----
return status;
}
sspiContext->authfinished = 0;
+ sspiContext->authState = ne_sspistatus_unknown;
return 0;
}
/*
***************
*** 441,446 ****
--- 449,455 ----
int status;
SECURITY_STATUS securityStatus;
ULONG contextFlags;
+ int continueNeeded = 0;
SSPIContext *sspiContext;
if (initialized <= 0) {
***************
*** 463,473 ****
return status;
}
if (base64Token) {
SecBufferDesc inBufferDesc;
SecBuffer inBuffer;
! if (!sspiContext->continueNeeded) {
freeBuffer(&outBufferDesc);
NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Got an unexpected token.\n");
return -1;
--- 472,485 ----
return status;
}
+ if (sspiContext->authState == ne_sspistatus_continueneeded)
+ continueNeeded = 1;
+ sspiContext->authState = ne_sspistatus_unknown;
if (base64Token) {
SecBufferDesc inBufferDesc;
SecBuffer inBuffer;
! if (!continueNeeded) {
freeBuffer(&outBufferDesc);
NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Got an unexpected token.\n");
return -1;
***************
*** 490,499 ****
if (securityStatus == SEC_E_OK)
{
sspiContext->authfinished = 1;
}
freeBuffer(&inBufferDesc);
} else {
! if (sspiContext->continueNeeded) {
freeBuffer(&outBufferDesc);
NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Expected a token from
server.\n");
return -1;
--- 502,512 ----
if (securityStatus == SEC_E_OK)
{
sspiContext->authfinished = 1;
+ sspiContext->authState =
ne_sspistatus_authfinishedthisrequest;
}
freeBuffer(&inBufferDesc);
} else {
! if (continueNeeded) {
freeBuffer(&outBufferDesc);
NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: Expected a token from
server.\n");
return -1;
***************
*** 541,549 ****
if (securityStatus == SEC_I_COMPLETE_AND_CONTINUE
|| securityStatus == SEC_I_CONTINUE_NEEDED) {
! sspiContext->continueNeeded = 1;
} else {
! sspiContext->continueNeeded = 0;
}
if (!(securityStatus == SEC_I_COMPLETE_AND_CONTINUE
--- 554,563 ----
if (securityStatus == SEC_I_COMPLETE_AND_CONTINUE
|| securityStatus == SEC_I_CONTINUE_NEEDED) {
! sspiContext->authState = ne_sspistatus_continueneeded;
} else {
! if (securityStatus == SEC_I_COMPLETE_NEEDED || securityStatus ==
SEC_E_OK)
! sspiContext->authState =
ne_sspistatus_authfinishedthisrequest;
}
if (!(securityStatus == SEC_I_COMPLETE_AND_CONTINUE
***************
*** 562,566 ****
--- 576,601 ----
freeBuffer(&outBufferDesc);
return 0;
+ }
+
+ int ne_sspi_is_in_negotiation(void *context)
+ {
+ int status;
+ SSPIContext *sspiContext;
+ if (initialized <= 0) {
+ return 0;
+ }
+
+ status = getContext(context, &sspiContext);
+ if (status) {
+ return 0;
+ }
+
+ NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: ne_sspi_is_in_negotiation. (%d)\n",
sspiContext->authState);
+
+ if (sspiContext->authState == ne_sspistatus_continueneeded ||
+ sspiContext->authState == ne_sspistatus_authfinishedthisrequest)
+ return 1;
+ return 0;
}
#endif /* HAVE_SSPI */
diff -cr neon-0.26.3\src\ne_sspi.h neon-0.26.3.rjvdboon\src\ne_sspi.h
*** neon-0.26.3\src\ne_sspi.h Sun Feb 12 13:05:14 2006
--- neon-0.26.3.rjvdboon\src\ne_sspi.h Wed Feb 14 10:00:46 2007
***************
*** 43,48 ****
--- 43,50 ----
int ne_sspi_authenticate(void *context, const char *base64Token,
char **responseToken);
+ int ne_sspi_is_in_negotiation(void *context);
+
#endif /* HAVE_SSPI */
#endif /* NE_SSPI_H */
_______________________________________________
neon mailing list
[email protected]
http://mailman.webdav.org/mailman/listinfo/neon