From f858bb0d1f989694d562e7fe7818ee7189c18e28 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Wed, 11 Apr 2012 17:25:26 +0200 Subject: sspi: Refactored socks_sspi and schannel to use same error message functions Moved the error constant switch to curl_sspi.c and added two new helper functions to curl_sspi.[ch] which either return the constant or a fully translated message representing the SSPI security status. Updated socks_sspi.c and curl_schannel.c to use the new functions. --- lib/curl_schannel.c | 37 ++++++++----- lib/curl_sspi.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/curl_sspi.h | 2 + lib/socks_sspi.c | 90 ++----------------------------- 4 files changed, 180 insertions(+), 98 deletions(-) (limited to 'lib') diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c index 0ad1145f2..3de8e7c01 100644 --- a/lib/curl_schannel.c +++ b/lib/curl_schannel.c @@ -89,6 +89,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) { SCHANNEL_CRED schannel_cred; SECURITY_STATUS sspi_status = SEC_E_OK; curl_schannel_cred *old_cred = NULL; + char *sspi_msg = NULL; struct in_addr addr; #ifdef ENABLE_IPV6 struct in6_addr addr6; @@ -156,11 +157,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) { &connssl->cred->cred_handle, &connssl->cred->time_stamp); if(sspi_status != SEC_E_OK) { + sspi_msg = Curl_sspi_status_msg(sspi_status); if(sspi_status == SEC_E_WRONG_PRINCIPAL) - failf(data, "schannel: SNI or certificate check failed\n"); + failf(data, "schannel: SNI or certificate check failed: %s\n", + sspi_msg); else - failf(data, "schannel: AcquireCredentialsHandleA failed: %d\n", - sspi_status); + failf(data, "schannel: AcquireCredentialsHandleA failed: %s\n", + sspi_msg); + free(sspi_msg); free(connssl->cred); connssl->cred = NULL; return CURLE_SSL_CONNECT_ERROR; @@ -196,11 +200,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) { &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); if(sspi_status != SEC_I_CONTINUE_NEEDED) { + sspi_msg = Curl_sspi_status_msg(sspi_status); if(sspi_status == SEC_E_WRONG_PRINCIPAL) - failf(data, "schannel: SNI or certificate check failed\n"); + failf(data, "schannel: SNI or certificate check failed: %s\n", + sspi_msg); else - failf(data, "schannel: initial InitializeSecurityContextA failed: %d\n", - sspi_status); + failf(data, "schannel: initial InitializeSecurityContextA failed: %s\n", + sspi_msg); + free(sspi_msg); free(connssl->ctxt); connssl->ctxt = NULL; return CURLE_SSL_CONNECT_ERROR; @@ -236,6 +243,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) { SecBuffer inbuf[2]; SecBufferDesc inbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; + char *sspi_msg = NULL; infof(data, "schannel: connecting to %s:%d (step 2/3)\n", conn->host.name, conn->remote_port); @@ -320,8 +328,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) { /* check if the handshake was incomplete */ if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { connssl->connecting_state = ssl_connect_2_reading; - infof(data, "schannel: received incomplete message, need more data: %d\n", - sspi_status); + infof(data, "schannel: received incomplete message, need more data\n"); return CURLE_OK; } @@ -350,11 +357,14 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) { } } else { + sspi_msg = Curl_sspi_status_msg(sspi_status); if(sspi_status == SEC_E_WRONG_PRINCIPAL) - failf(data, "schannel: SNI or certificate check failed\n"); + failf(data, "schannel: SNI or certificate check failed: %s\n", + sspi_msg); else - failf(data, "schannel: next InitializeSecurityContextA failed: %d\n", - sspi_status); + failf(data, "schannel: next InitializeSecurityContextA failed: %s\n", + sspi_msg); + free(sspi_msg); return CURLE_SSL_CONNECT_ERROR; } @@ -653,6 +663,7 @@ schannel_recv(struct connectdata *conn, int sockindex, SecBuffer inbuf[4]; SecBufferDesc inbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; + char *sspi_msg = NULL; infof(data, "schannel: client wants to read %d\n", len); *err = CURLE_OK; @@ -853,7 +864,9 @@ schannel_recv(struct connectdata *conn, int sockindex, /* check if something went wrong and we need to return an error */ if(ret < 0 && sspi_status != SEC_E_OK) { - infof(data, "schannel: failed to read data from server\n"); + sspi_msg = Curl_sspi_status_msg(sspi_status); + infof(data, "schannel: failed to read data from server: %s\n", sspi_msg); + free(sspi_msg); *err = CURLE_RECV_ERROR; return -1; } diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c index b985dbceb..d915710f8 100644 --- a/lib/curl_sspi.c +++ b/lib/curl_sspi.c @@ -118,4 +118,153 @@ Curl_sspi_global_cleanup(void) } } + +/* + * Curl_sspi_status(SECURIY_STATUS status) + * + * This function returns a string representing an SSPI status. + * It will in any case return a usable string pointer which needs to be freed. + */ +char* +Curl_sspi_status(SECURITY_STATUS status) +{ + const char* status_const; + + switch(status) { + case SEC_I_COMPLETE_AND_CONTINUE: + status_const = "SEC_I_COMPLETE_AND_CONTINUE"; + break; + case SEC_I_COMPLETE_NEEDED: + status_const = "SEC_I_COMPLETE_NEEDED"; + break; + case SEC_I_CONTINUE_NEEDED: + status_const = "SEC_I_CONTINUE_NEEDED"; + break; + case SEC_I_CONTEXT_EXPIRED: + status_const = "SEC_I_CONTEXT_EXPIRED"; + break; + case SEC_I_INCOMPLETE_CREDENTIALS: + status_const = "SEC_I_INCOMPLETE_CREDENTIALS"; + break; + case SEC_I_RENEGOTIATE: + status_const = "SEC_I_RENEGOTIATE"; + break; + case SEC_E_BUFFER_TOO_SMALL: + status_const = "SEC_E_BUFFER_TOO_SMALL"; + break; + case SEC_E_CONTEXT_EXPIRED: + status_const = "SEC_E_CONTEXT_EXPIRED"; + break; + case SEC_E_CRYPTO_SYSTEM_INVALID: + status_const = "SEC_E_CRYPTO_SYSTEM_INVALID"; + break; + case SEC_E_INCOMPLETE_MESSAGE: + status_const = "SEC_E_INCOMPLETE_MESSAGE"; + break; + case SEC_E_INSUFFICIENT_MEMORY: + status_const = "SEC_E_INSUFFICIENT_MEMORY"; + break; + case SEC_E_INTERNAL_ERROR: + status_const = "SEC_E_INTERNAL_ERROR"; + break; + case SEC_E_INVALID_HANDLE: + status_const = "SEC_E_INVALID_HANDLE"; + break; + case SEC_E_INVALID_TOKEN: + status_const = "SEC_E_INVALID_TOKEN"; + break; + case SEC_E_LOGON_DENIED: + status_const = "SEC_E_LOGON_DENIED"; + break; + case SEC_E_MESSAGE_ALTERED: + status_const = "SEC_E_MESSAGE_ALTERED"; + break; + case SEC_E_NO_AUTHENTICATING_AUTHORITY: + status_const = "SEC_E_NO_AUTHENTICATING_AUTHORITY"; + break; + case SEC_E_NO_CREDENTIALS: + status_const = "SEC_E_NO_CREDENTIALS"; + break; + case SEC_E_NOT_OWNER: + status_const = "SEC_E_NOT_OWNER"; + break; + case SEC_E_OK: + status_const = "SEC_E_OK"; + break; + case SEC_E_OUT_OF_SEQUENCE: + status_const = "SEC_E_OUT_OF_SEQUENCE"; + break; + case SEC_E_QOP_NOT_SUPPORTED: + status_const = "SEC_E_QOP_NOT_SUPPORTED"; + break; + case SEC_E_SECPKG_NOT_FOUND: + status_const = "SEC_E_SECPKG_NOT_FOUND"; + break; + case SEC_E_TARGET_UNKNOWN: + status_const = "SEC_E_TARGET_UNKNOWN"; + break; + case SEC_E_UNKNOWN_CREDENTIALS: + status_const = "SEC_E_UNKNOWN_CREDENTIALS"; + break; + case SEC_E_UNSUPPORTED_FUNCTION: + status_const = "SEC_E_UNSUPPORTED_FUNCTION"; + break; + case SEC_E_WRONG_PRINCIPAL: + status_const = "SEC_E_WRONG_PRINCIPAL"; + break; + default: + status_const = "Unknown error"; + } + + return curl_maprintf("%s (0x%08X)", status_const, status); +} + +/* + * Curl_sspi_status_msg(SECURITY_STATUS status) + * + * This function returns a message representing an SSPI status. + * It will in any case return a usable string pointer which needs to be freed. + */ + +char* +Curl_sspi_status_msg(SECURITY_STATUS status) +{ + LPSTR format_msg = NULL; + char *status_msg = NULL, *status_const = NULL; + int status_len = 0; + + status_len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, status, 0, (LPTSTR)&format_msg, 0, NULL); + + if(status_len > 0 && format_msg) { + status_msg = strdup(format_msg); + LocalFree(format_msg); + + /* remove trailing CR+LF */ + if(status_len > 0) { + if(status_msg[status_len-1] == '\n') { + status_msg[status_len-1] = '\0'; + if(status_len > 1) { + if(status_msg[status_len-2] == '\r') { + status_msg[status_len-2] = '\0'; + } + } + } + } + } + + status_const = Curl_sspi_status(status); + if(status_msg) { + status_msg = curl_maprintf("%s [%s]", status_msg, status_const); + free(status_const); + } + else { + status_msg = status_const; + } + + return status_msg; +} + #endif /* USE_WINDOWS_SSPI */ diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h index c0e4f368f..817487830 100644 --- a/lib/curl_sspi.h +++ b/lib/curl_sspi.h @@ -63,6 +63,8 @@ CURLcode Curl_sspi_global_init(void); void Curl_sspi_global_cleanup(void); +char* Curl_sspi_status(SECURITY_STATUS status); +char* Curl_sspi_status_msg(SECURITY_STATUS status); /* Forward-declaration of global variables defined in curl_sspi.c */ diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index d96a82e8a..1e724bb06 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -53,98 +53,16 @@ static int check_sspi_err(struct SessionHandle *data, SECURITY_STATUS minor_status, const char* function) { - const char *txt; + char *sspi_msg = NULL; (void)minor_status; if(major_status != SEC_E_OK && major_status != SEC_I_COMPLETE_AND_CONTINUE && major_status != SEC_I_COMPLETE_NEEDED && major_status != SEC_I_CONTINUE_NEEDED) { - failf(data, "SSPI error: %s failed: %d\n", function, major_status); - switch (major_status) { - case SEC_I_COMPLETE_AND_CONTINUE: - txt="SEC_I_COMPLETE_AND_CONTINUE"; - break; - case SEC_I_COMPLETE_NEEDED: - txt="SEC_I_COMPLETE_NEEDED"; - break; - case SEC_I_CONTINUE_NEEDED: - txt="SEC_I_CONTINUE_NEEDED"; - break; - case SEC_I_CONTEXT_EXPIRED: - txt="SEC_I_CONTEXT_EXPIRED"; - break; - case SEC_I_INCOMPLETE_CREDENTIALS: - txt="SEC_I_INCOMPLETE_CREDENTIALS"; - break; - case SEC_I_RENEGOTIATE: - txt="SEC_I_RENEGOTIATE"; - break; - case SEC_E_BUFFER_TOO_SMALL: - txt="SEC_E_BUFFER_TOO_SMALL"; - break; - case SEC_E_CONTEXT_EXPIRED: - txt="SEC_E_CONTEXT_EXPIRED"; - break; - case SEC_E_CRYPTO_SYSTEM_INVALID: - txt="SEC_E_CRYPTO_SYSTEM_INVALID"; - break; - case SEC_E_INCOMPLETE_MESSAGE: - txt="SEC_E_INCOMPLETE_MESSAGE"; - break; - case SEC_E_INSUFFICIENT_MEMORY: - txt="SEC_E_INSUFFICIENT_MEMORY"; - break; - case SEC_E_INTERNAL_ERROR: - txt="SEC_E_INTERNAL_ERROR"; - break; - case SEC_E_INVALID_HANDLE: - txt="SEC_E_INVALID_HANDLE"; - break; - case SEC_E_INVALID_TOKEN: - txt="SEC_E_INVALID_TOKEN"; - break; - case SEC_E_LOGON_DENIED: - txt="SEC_E_LOGON_DENIED"; - break; - case SEC_E_MESSAGE_ALTERED: - txt="SEC_E_MESSAGE_ALTERED"; - break; - case SEC_E_NO_AUTHENTICATING_AUTHORITY: - txt="SEC_E_NO_AUTHENTICATING_AUTHORITY"; - break; - case SEC_E_NO_CREDENTIALS: - txt="SEC_E_NO_CREDENTIALS"; - break; - case SEC_E_NOT_OWNER: - txt="SEC_E_NOT_OWNER"; - break; - case SEC_E_OUT_OF_SEQUENCE: - txt="SEC_E_OUT_OF_SEQUENCE"; - break; - case SEC_E_QOP_NOT_SUPPORTED: - txt="SEC_E_QOP_NOT_SUPPORTED"; - break; - case SEC_E_SECPKG_NOT_FOUND: - txt="SEC_E_SECPKG_NOT_FOUND"; - break; - case SEC_E_TARGET_UNKNOWN: - txt="SEC_E_TARGET_UNKNOWN"; - break; - case SEC_E_UNKNOWN_CREDENTIALS: - txt="SEC_E_UNKNOWN_CREDENTIALS"; - break; - case SEC_E_UNSUPPORTED_FUNCTION: - txt="SEC_E_UNSUPPORTED_FUNCTION"; - break; - case SEC_E_WRONG_PRINCIPAL: - txt="SEC_E_WRONG_PRINCIPAL"; - break; - default: - txt="Unknown error"; - - } - failf(data, "SSPI error: %s failed: %s\n", function, txt); + sspi_msg = Curl_sspi_status_msg(major_status); + failf(data, "SSPI error: %s failed: %s\n", function, sspi_msg); + free(sspi_msg); return 1; } return 0; -- cgit v1.2.3