diff options
-rw-r--r-- | lib/curl_schannel.c | 91 |
1 files changed, 79 insertions, 12 deletions
diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c index 3ea6b4d66..06286a72b 100644 --- a/lib/curl_schannel.c +++ b/lib/curl_schannel.c @@ -41,7 +41,6 @@ /* * TODO list for TLS/SSL implementation: * - implement write buffering - * - implement SSL/TLS shutdown * - implement client certificate authentication * - implement custom server certificate validation * - implement cipher/algorithm option @@ -946,17 +945,90 @@ bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) void Curl_schannel_close(struct connectdata *conn, int sockindex) { + if(conn->ssl[sockindex].use) + /* if the SSL channel hasn't been shut down yet, do that now. */ + Curl_ssl_shutdown(conn, sockindex); +} + +int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) +{ +/* See +http://msdn.microsoft.com/en-us/library/windows/desktop/aa380138(v=vs.85).aspx + Shutting Down an Schannel Connection */ struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - infof(data, "schannel: Closing connection with %s:%hu\n", + infof(data, "schannel: shutting down SSL connection with %s:%hu\n", conn->host.name, conn->remote_port); - /* free SSPI Schannel API security context handle */ if(connssl->ctxt) { - s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle); - free(connssl->ctxt); - connssl->ctxt = NULL; + SecBufferDesc BuffDesc; + SecBuffer Buffer; + SECURITY_STATUS sspi_status; + SecBuffer outbuf; + SecBufferDesc outbuf_desc; + CURLcode code; + TCHAR *host_name; + DWORD dwshut = SCHANNEL_SHUTDOWN; + + InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); + InitSecBufferDesc(&BuffDesc, &Buffer, 1); + + sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle, + &BuffDesc); + + if(sspi_status != SEC_E_OK) + failf(data, "schannel: ApplyControlToken failure: %s", + Curl_sspi_strerror(conn, sspi_status)); + +#ifdef UNICODE + host_name = Curl_convert_UTF8_to_wchar(conn->host.name); + if(!host_name) + return CURLE_OUT_OF_MEMORY; +#else + host_name = conn->host.name; +#endif + + /* setup output buffer */ + InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, &outbuf, 1); + + sspi_status = s_pSecFn->InitializeSecurityContext( + &connssl->cred->cred_handle, + &connssl->ctxt->ctxt_handle, + host_name, + connssl->req_flags, + 0, + 0, + NULL, + 0, + &connssl->ctxt->ctxt_handle, + &outbuf_desc, + &connssl->ret_flags, + &connssl->ctxt->time_stamp); + +#ifdef UNICODE + free(host_name); +#endif + + if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { + /* send close message which is in output buffer */ + ssize_t written; + code = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, + outbuf.cbBuffer, &written); + + s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); + if((code != CURLE_OK) || (outbuf.cbBuffer != (size_t)written)) { + infof(data, "schannel: failed to send close msg: %s" + " (bytes written: %zd)\n", curl_easy_strerror(code), written); + } + } + /* free SSPI Schannel API security context handle */ + if(connssl->ctxt) { + s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle); + free(connssl->ctxt); + connssl->ctxt = NULL; + } } /* free internal buffer for received encrypted data */ @@ -974,13 +1046,8 @@ void Curl_schannel_close(struct connectdata *conn, int sockindex) connssl->decdata_length = 0; connssl->decdata_offset = 0; } -} -int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) -{ - (void)conn; - (void)sockindex; - return CURLE_NOT_BUILT_IN; /* TODO: implement SSL/TLS shutdown */ + return CURLE_OK; } void Curl_schannel_session_free(void *ptr) |