Commit f858bb0d authored by Marc Hoersken's avatar Marc Hoersken Committed by Daniel Stenberg
Browse files

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.
parent 15ca80c8
Loading
Loading
Loading
Loading
+25 −12
Original line number Diff line number Diff line
@@ -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;
  }
+149 −0
Original line number Diff line number Diff line
@@ -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 */
+2 −0
Original line number Diff line number Diff line
@@ -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 */

+4 −86
Original line number Diff line number Diff line
@@ -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;