07073a198a
Fixes a problem that was noticed when working on bnc#805901, which is about documents opened from WebDAV (using https) not being locked (in the WebDAV sense). For some reason, at least in the 3.6 branch, I noticed that LibreOffice did not manage to open any connection to the WebDAV server. The error message "Server error message: Server certificate verification failed: issuer is not trusted" was displayed. Turning on Neon logging I saw the OpenSSL error code 19 (X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) passing by. Some googling turned up http://stackoverflow.com/questions/4103472/ssl-handshake-fails-with-a-verisign-chain-certificate-that-contains-two-ca-s . If I understand correctly, root certificates (which are the final ones in a certificate chain) are by definition self-signed. One can try this on Linux (or even on Windows, using the openssl command built as part of the LibreOffice built): openssl s_client -connect vibe.novell.com:443 -showcerts and see that it also displays a message about this "error": "verify error:num=19:self signed certificate in certificate chain" One can get around that by passing the -CApath option: openssl s_client -connect vibe.novell.com:443 -showcerts -CApath /etc/ssl/certs on Linux. There is no corresponding directory with trusted certificates as files on Windows. This tells OpenSSL where to find a list of trusted root certificates. Apparently when OpenSSL is used by LibreOffice it does not use the list of trusted root certificates that Windows knows automatically. This patch makes it do that when ne_ssl_trust_default_ca() is called. Change-Id: Iddbd3d61413aa52adbed3f9a0239a364e70668d8 Reviewed-on: https://gerrit.libreoffice.org/2741 Reviewed-by: Fridrich Strba <fridrich@documentfoundation.org> Tested-by: Fridrich Strba <fridrich@documentfoundation.org>
423 lines
14 KiB
Diff
423 lines
14 KiB
Diff
--- src/ne_auth.c 2010-10-14 17:00:53.000000000 +0200
|
|
+++ src/ne_auth.c 2011-02-03 10:31:22.000000000 +0100
|
|
@@ -367,7 +367,7 @@
|
|
static int get_credentials(auth_session *sess, ne_buffer **errmsg, int attempt,
|
|
struct auth_challenge *chall, char *pwbuf)
|
|
{
|
|
- if (chall->handler->creds(chall->handler->userdata, sess->realm,
|
|
+ if (chall->handler->creds(chall->handler->userdata, chall->protocol->name, sess->realm,
|
|
chall->handler->attempt++, sess->username, pwbuf) == 0) {
|
|
return 0;
|
|
} else {
|
|
@@ -385,15 +385,19 @@
|
|
{
|
|
char *tmp, password[NE_ABUFSIZ];
|
|
|
|
+#if 0 /* Workaround - IIS sends challenge without realm. */
|
|
+
|
|
/* Verify challenge... must have a realm */
|
|
if (parms->realm == NULL) {
|
|
challenge_error(errmsg, _("missing realm in Basic challenge"));
|
|
return -1;
|
|
}
|
|
+#endif
|
|
|
|
clean_session(sess);
|
|
|
|
- sess->realm = ne_strdup(parms->realm);
|
|
+ if (parms->realm != NULL)
|
|
+ sess->realm = ne_strdup(parms->realm);
|
|
|
|
if (get_credentials(sess, errmsg, attempt, parms, password)) {
|
|
/* Failed to get credentials */
|
|
@@ -610,10 +614,12 @@
|
|
return NULL;
|
|
}
|
|
|
|
-static int continue_sspi(auth_session *sess, int ntlm, const char *hdr)
|
|
+static int continue_sspi(auth_session *sess, int ntlm, const char *hdr,
|
|
+ int attempt, struct auth_challenge *parms, ne_buffer **errmsg)
|
|
{
|
|
int status;
|
|
char *response = NULL;
|
|
+ char password[NE_ABUFSIZ];
|
|
|
|
NE_DEBUG(NE_DBG_HTTPAUTH, "auth: SSPI challenge.\n");
|
|
|
|
@@ -630,8 +636,17 @@
|
|
return status;
|
|
}
|
|
}
|
|
-
|
|
- status = ne_sspi_authenticate(sess->sspi_context, hdr, &response);
|
|
+
|
|
+ /* Authentification needs more than one http request.
|
|
+ * As long as authentification in progress use the existing credentials.
|
|
+ * Otherwise get new credentials.*/
|
|
+ if (!hdr)
|
|
+ if (get_credentials(sess, errmsg, attempt, parms, password)) {
|
|
+ /* Failed to get credentials */
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ status = ne_sspi_authenticate(sess->sspi_context, hdr, &response, sess->username, password);
|
|
if (status) {
|
|
return status;
|
|
}
|
|
@@ -651,7 +666,7 @@
|
|
{
|
|
int ntlm = ne_strcasecmp(parms->protocol->name, "NTLM") == 0;
|
|
|
|
- return continue_sspi(sess, ntlm, parms->opaque);
|
|
+ return continue_sspi(sess, ntlm, parms->opaque, attempt, parms, errmsg);
|
|
}
|
|
|
|
static int verify_sspi(struct auth_request *req, auth_session *sess,
|
|
@@ -674,7 +689,7 @@
|
|
return NE_OK;
|
|
}
|
|
|
|
- return continue_sspi(sess, ntlm, ptr);
|
|
+ return continue_sspi(sess, ntlm, ptr, 0, NULL, NULL);
|
|
}
|
|
|
|
#endif
|
|
--- src/ne_auth.h 2009-09-01 22:13:12.000000000 +0200
|
|
+++ src/ne_auth.h 2011-02-03 10:26:20.000000000 +0100
|
|
@@ -47,8 +47,8 @@
|
|
* Hint: if you just wish to attempt authentication just once (even if
|
|
* the user gets the username/password wrong), have the callback
|
|
* function use 'attempt' value as the function return value. */
|
|
-typedef int (*ne_auth_creds)(void *userdata, const char *realm, int attempt,
|
|
- char *username, char *password);
|
|
+typedef int (*ne_auth_creds)(void *userdata, const char * auth_protocol,
|
|
+ const char *realm, int attempt, char *username, char *password);
|
|
|
|
/* Set callbacks to provide credentials for server and proxy
|
|
* authentication, using the default set of authentication protocols.
|
|
--- src/ne_defs.h 2010-01-11 23:57:34.000000000 +0100
|
|
+++ src/ne_defs.h 2011-02-03 10:26:20.000000000 +0100
|
|
@@ -41,7 +41,7 @@
|
|
#endif
|
|
|
|
/* define ssize_t for Win32 */
|
|
-#if defined(WIN32) && !defined(ssize_t)
|
|
+#if defined(WIN32) && !defined(ssize_t) && !defined(__MINGW32__)
|
|
#define ssize_t int
|
|
#endif
|
|
|
|
--- src/ne_locks.c 2007-02-05 11:09:27.000000000 +0100
|
|
+++ src/ne_locks.c 2011-02-03 10:26:21.000000000 +0100
|
|
@@ -579,6 +579,23 @@
|
|
const char *token = ne_get_response_header(ctx->req, "Lock-Token");
|
|
/* at the root element; retrieve the Lock-Token header,
|
|
* and bail if it wasn't given. */
|
|
+#ifdef IIS_LOCK_BUG_WORKAROUND
|
|
+ /* MS IIS violates RFC 2518/4918. It does not send a Lock-Token response
|
|
+ header upon successful creation of a new lock. As a workaround, we
|
|
+ will try to pick the lock token from the response body (although
|
|
+ this is not 100% safe in case of multiple activelocks). */
|
|
+ if (token == NULL)
|
|
+ NE_DEBUG(NE_DBG_LOCKS,
|
|
+ "Ignoring missing LOCK response Lock-Token header\n");
|
|
+
|
|
+ if (token != NULL) {
|
|
+ if (token[0] == '<') token++;
|
|
+ ctx->token = ne_strdup(token);
|
|
+ ne_shave(ctx->token, ">");
|
|
+ NE_DEBUG(NE_DBG_LOCKS, "lk_startelm: Finding token %s\n",
|
|
+ ctx->token);
|
|
+ }
|
|
+#else
|
|
if (token == NULL) {
|
|
ne_xml_set_error(ctx->parser,
|
|
_("LOCK response missing Lock-Token header"));
|
|
@@ -590,12 +607,28 @@
|
|
ne_shave(ctx->token, ">");
|
|
NE_DEBUG(NE_DBG_LOCKS, "lk_startelm: Finding token %s\n",
|
|
ctx->token);
|
|
+#endif
|
|
}
|
|
|
|
/* TODO: only accept 'prop' as root for LOCK response */
|
|
if (!can_accept(parent, id))
|
|
return NE_XML_DECLINE;
|
|
|
|
+#ifdef IIS_LOCK_BUG_WORKAROUND
|
|
+ if (id == ELM_activelock && ctx->found) {
|
|
+ /* Found another activelock... */
|
|
+ const char *token = ne_get_response_header(ctx->req, "Lock-Token");
|
|
+ if (token == NULL) {
|
|
+ /* Response contains more than one activelock and no Lock-Token
|
|
+ * response header. We are doomed. No safe workaround for IIS
|
|
+ * lock bug possible. */
|
|
+ ne_xml_set_error(ctx->parser,
|
|
+ _("LOCK response missing Lock-Token header and more than one activelock"));
|
|
+ return NE_XML_ABORT;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (id == ELM_activelock && !ctx->found) {
|
|
/* a new activelock */
|
|
ne_lock_free(&ctx->active);
|
|
@@ -621,7 +654,12 @@
|
|
return -1;
|
|
|
|
if (state == ELM_activelock) {
|
|
+#ifdef IIS_LOCK_BUG_WORKAROUND
|
|
+ if (ctx->active.token) {
|
|
+ ctx->token = ne_strdup(ctx->active.token);
|
|
+#else
|
|
if (ctx->active.token && strcmp(ctx->active.token, ctx->token) == 0) {
|
|
+#endif
|
|
ctx->found = 1;
|
|
}
|
|
}
|
|
--- src/ne_locks.h 2006-01-02 12:43:19.000000000 +0100
|
|
+++ src/ne_locks.h 2011-02-03 10:26:21.000000000 +0100
|
|
@@ -22,6 +22,10 @@
|
|
#ifndef NE_LOCKS_H
|
|
#define NE_LOCKS_H
|
|
|
|
+# if defined __GNUC__
|
|
+# pragma GCC system_header
|
|
+# endif
|
|
+
|
|
#include "ne_request.h" /* for ne_session + ne_request */
|
|
#include "ne_uri.h" /* for ne_uri */
|
|
|
|
--- src/ne_sspi.c 2007-08-10 17:26:08.000000000 +0200
|
|
+++ src/ne_sspi.c 2011-02-03 10:26:21.000000000 +0100
|
|
@@ -206,6 +206,45 @@
|
|
}
|
|
|
|
/*
|
|
+ * Simplification wrapper arround AcquireCredentialsHandle as most of
|
|
+ * the parameters do not change.
|
|
+ */
|
|
+static int acquireCredentialsHandleForUsername(CredHandle * credentials, char *package, const char *username, const char *password)
|
|
+{
|
|
+ SECURITY_STATUS status;
|
|
+ TimeStamp timestamp;
|
|
+
|
|
+ const char *domain = "";
|
|
+
|
|
+ int rc, rcISC;
|
|
+ SecPkgInfo *secPackInfo;
|
|
+ SEC_WINNT_AUTH_IDENTITY *nameAndPwd = NULL;
|
|
+ int bytesReceived = 0, bytesSent = 0;
|
|
+
|
|
+ nameAndPwd = (SEC_WINNT_AUTH_IDENTITY *) malloc( sizeof(SEC_WINNT_AUTH_IDENTITY) );
|
|
+ memset( nameAndPwd, '\0', sizeof (*nameAndPwd) );
|
|
+ nameAndPwd->Domain = (unsigned char *) _strdup( domain? domain: "" );
|
|
+ nameAndPwd->DomainLength = domain? strlen( domain ): 0;
|
|
+ nameAndPwd->User = (unsigned char *) _strdup( username? username: "" );
|
|
+ nameAndPwd->UserLength = username? strlen( username ): 0;
|
|
+ nameAndPwd->Password = (unsigned char *) _strdup( password? password: "" );
|
|
+ nameAndPwd->PasswordLength = password? strlen( password ): 0;
|
|
+ nameAndPwd->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
|
+
|
|
+ status = pSFT->AcquireCredentialsHandle( NULL, package, SECPKG_CRED_OUTBOUND,
|
|
+ NULL, nameAndPwd, NULL, NULL, credentials, ×tamp );
|
|
+
|
|
+ if (status != SEC_E_OK) {
|
|
+ NE_DEBUG(NE_DBG_HTTPAUTH,
|
|
+ "sspi: AcquireCredentialsHandle [fail] [%x].\n", status);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
* Wrapper arround initializeSecurityContext. Supplies several
|
|
* default parameters as well as logging in case of errors.
|
|
*/
|
|
@@ -483,7 +522,7 @@
|
|
* Processes received authentication tokens as well as supplies the
|
|
* response token.
|
|
*/
|
|
-int ne_sspi_authenticate(void *context, const char *base64Token, char **responseToken)
|
|
+int ne_sspi_authenticate(void *context, const char *base64Token, char **responseToken, const char* username, const char* password)
|
|
{
|
|
SecBufferDesc outBufferDesc;
|
|
SecBuffer outBuffer;
|
|
@@ -561,13 +600,22 @@
|
|
/* Reset any existing context since we are starting over */
|
|
resetContext(sspiContext);
|
|
|
|
- if (acquireCredentialsHandle
|
|
- (&sspiContext->credentials, sspiContext->mechanism) != SEC_E_OK) {
|
|
- freeBuffer(&outBufferDesc);
|
|
- NE_DEBUG(NE_DBG_HTTPAUTH,
|
|
- "sspi: acquireCredentialsHandle failed.\n");
|
|
- return -1;
|
|
- }
|
|
+ if (strlen(username) != 0) {
|
|
+ if (acquireCredentialsHandleForUsername
|
|
+ (&sspiContext->credentials, sspiContext->mechanism, username, password) != SEC_E_OK) {
|
|
+ freeBuffer(&outBufferDesc);
|
|
+ NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: acquireCredentialsHandleForUsername failed.\n");
|
|
+ return -1;
|
|
+ }
|
|
+ } else {
|
|
+ if (acquireCredentialsHandle
|
|
+ (&sspiContext->credentials, sspiContext->mechanism) != SEC_E_OK) {
|
|
+ freeBuffer(&outBufferDesc);
|
|
+ NE_DEBUG(NE_DBG_HTTPAUTH, "sspi: acquireCredentialsHandle failed.\n");
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
|
|
securityStatus =
|
|
initializeSecurityContext(&sspiContext->credentials, NULL,
|
|
--- src/ne_sspi.h 2006-02-12 13:05:14.000000000 +0100
|
|
+++ src/ne_sspi.h 2011-02-03 10:26:21.000000000 +0100
|
|
@@ -41,7 +41,7 @@
|
|
int ne_sspi_clear_context(void *context);
|
|
|
|
int ne_sspi_authenticate(void *context, const char *base64Token,
|
|
- char **responseToken);
|
|
+ char **responseToken, const char* username, const char* password);
|
|
|
|
#endif /* HAVE_SSPI */
|
|
|
|
--- src/ne_uri.c 2007-12-05 12:04:47.000000000 +0100
|
|
+++ src/ne_uri.c 2011-02-03 10:26:21.000000000 +0100
|
|
@@ -42,7 +42,7 @@
|
|
#include "ne_alloc.h"
|
|
#include "ne_uri.h"
|
|
|
|
-/* URI ABNF from RFC 3986: */
|
|
+/* URI ABNF from RFC 3986: (TKR: SharePoint is contradictory to this RFC. So I fix it here. )*/
|
|
|
|
#define PS (0x0001) /* "+" */
|
|
#define PC (0x0002) /* "%" */
|
|
@@ -67,6 +67,9 @@
|
|
|
|
#define OT (0x4000) /* others */
|
|
|
|
+/* TKR new symbol */
|
|
+#define WS (0x8000) /* Whitespaces ( Space, Tab ) */
|
|
+
|
|
#define URI_ALPHA (AL)
|
|
#define URI_DIGIT (DG)
|
|
|
|
@@ -83,20 +86,21 @@
|
|
/* pchar = unreserved / pct-encoded / sub-delims / ":" / "@" */
|
|
#define URI_PCHAR (URI_UNRESERVED | PC | URI_SUBDELIM | CL | AT)
|
|
/* invented: segchar = pchar / "/" */
|
|
-#define URI_SEGCHAR (URI_PCHAR | FS)
|
|
+/* (TKR) WS added */
|
|
+#define URI_SEGCHAR (URI_PCHAR | FS | WS)
|
|
/* query = *( pchar / "/" / "?" ) */
|
|
#define URI_QUERY (URI_PCHAR | FS | QU)
|
|
/* fragment == query */
|
|
#define URI_FRAGMENT URI_QUERY
|
|
|
|
/* any characters which should be path-escaped: */
|
|
-#define URI_ESCAPE ((URI_GENDELIM & ~(FS)) | URI_SUBDELIM | OT | PC)
|
|
+#define URI_ESCAPE ((URI_GENDELIM & ~(FS)) | URI_SUBDELIM | OT | WS | PC)
|
|
|
|
static const unsigned int uri_chars[256] = {
|
|
/* 0xXX x0 x2 x4 x6 x8 xA xC xE */
|
|
-/* 0x */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT,
|
|
+/* 0x */ OT, OT, OT, OT, OT, OT, OT, OT, OT, WS, OT, OT, OT, OT, OT, OT,
|
|
/* 1x */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT,
|
|
-/* 2x */ OT, SD, OT, GD, SD, PC, SD, SD, SD, SD, SD, PS, SD, DS, DT, FS,
|
|
+/* 2x */ WS, SD, OT, GD, SD, PC, SD, SD, SD, SD, SD, PS, SD, DS, DT, FS,
|
|
/* 3x */ DG, DG, DG, DG, DG, DG, DG, DG, DG, DG, CL, SD, OT, SD, OT, QU,
|
|
/* 4x */ AT, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,
|
|
/* 5x */ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, GD, OT, GD, OT, US,
|
|
--- src/ne_utils.c 2006-03-07 10:36:43.000000000 +0100
|
|
+++ src/ne_utils.c 2011-02-03 10:26:21.000000000 +0100
|
|
@@ -118,6 +118,9 @@
|
|
#ifdef HAVE_GNUTLS
|
|
", GNU TLS " LIBGNUTLS_VERSION
|
|
#endif /* HAVE_GNUTLS */
|
|
+#ifdef HAVE_SSPI
|
|
+ ", SSPI"
|
|
+#endif /* HAVE_SSPI */
|
|
"."
|
|
;
|
|
|
|
@@ -137,7 +140,7 @@
|
|
switch (feature) {
|
|
#if defined(NE_HAVE_SSL) || defined(NE_HAVE_ZLIB) || defined(NE_HAVE_IPV6) \
|
|
|| defined(NE_HAVE_SOCKS) || defined(NE_HAVE_LFS) \
|
|
- || defined(NE_HAVE_TS_SSL) || defined(NE_HAVE_I18N)
|
|
+ || defined(NE_HAVE_TS_SSL) || defined(NE_HAVE_I18N) || defined(HAVE_SSPI)
|
|
#ifdef NE_HAVE_SSL
|
|
case NE_FEATURE_SSL:
|
|
#endif
|
|
@@ -159,6 +162,9 @@
|
|
#ifdef NE_HAVE_I18N
|
|
case NE_FEATURE_I18N:
|
|
#endif
|
|
+#ifdef HAVE_SSPI
|
|
+ case NE_FEATURE_SSPI:
|
|
+#endif
|
|
return 1;
|
|
#endif /* NE_HAVE_* */
|
|
default:
|
|
--- src/ne_utils.h 2007-07-16 08:54:57.000000000 +0200
|
|
+++ src/ne_utils.h 2011-02-03 10:26:21.000000000 +0100
|
|
@@ -54,6 +54,7 @@
|
|
#define NE_FEATURE_SOCKS (5) /* SOCKSv5 support */
|
|
#define NE_FEATURE_TS_SSL (6) /* Thread-safe SSL/TLS support */
|
|
#define NE_FEATURE_I18N (7) /* i18n error message support */
|
|
+#define NE_FEATURE_SSPI (8) /* NTLM/Negotiate authentication protocol via SSPI */
|
|
|
|
/* Returns non-zero if library is built with support for the given
|
|
* NE_FEATURE_* feature code 'code'. */
|
|
--- src/ne_openssl.c
|
|
+++ src/ne_openssl.c
|
|
@@ -41,6 +41,13 @@
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
+#ifdef WIN32
|
|
+#define X509_NAME WIN32_X509_NAME
|
|
+#include <windows.h>
|
|
+#include <wincrypt.h>
|
|
+#undef X509_NAME
|
|
+#endif
|
|
+
|
|
#include "ne_ssl.h"
|
|
#include "ne_string.h"
|
|
#include "ne_session.h"
|
|
@@ -798,6 +798,31 @@
|
|
X509_STORE_load_locations(store, NE_SSL_CA_BUNDLE, NULL);
|
|
#else
|
|
X509_STORE_set_default_paths(store);
|
|
+#ifdef WIN32
|
|
+ {
|
|
+ HCERTSTORE hStore;
|
|
+ PCCERT_CONTEXT pContext = NULL;
|
|
+ X509 *x509;
|
|
+
|
|
+ hStore = CertOpenSystemStore(0, "ROOT");
|
|
+ if (hStore)
|
|
+ {
|
|
+ while (pContext = CertEnumCertificatesInStore(hStore, pContext))
|
|
+ {
|
|
+ x509 = d2i_X509(NULL, &pContext->pbCertEncoded, pContext->cbCertEncoded);
|
|
+ if (x509)
|
|
+ {
|
|
+ X509_STORE_add_cert(store, x509);
|
|
+ X509_free(x509);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ CertFreeCertificateContext(pContext);
|
|
+ CertCloseStore(hStore, 0);
|
|
+ }
|
|
+#endif
|
|
+
|
|
#endif
|
|
}
|
|
|