aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/curl_schannel.c91
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)