summaryrefslogtreecommitdiffstats
path: root/plugin/auth_gssapi/sspi_client.cc
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/auth_gssapi/sspi_client.cc')
-rw-r--r--plugin/auth_gssapi/sspi_client.cc183
1 files changed, 183 insertions, 0 deletions
diff --git a/plugin/auth_gssapi/sspi_client.cc b/plugin/auth_gssapi/sspi_client.cc
new file mode 100644
index 00000000..61249dd1
--- /dev/null
+++ b/plugin/auth_gssapi/sspi_client.cc
@@ -0,0 +1,183 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define SECURITY_WIN32
+#include <windows.h>
+#include <sspi.h>
+#include <SecExt.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <mysql/plugin_auth.h>
+#include <mysql.h>
+#include <mysqld_error.h>
+
+#include "sspi.h"
+
+extern void log_client_error(MYSQL *mysql, const char *fmt, ...);
+static void log_error(MYSQL *mysql, SECURITY_STATUS err, const char *msg)
+{
+ if (err)
+ {
+ char buf[1024];
+ sspi_errmsg(err, buf, sizeof(buf));
+ log_client_error(mysql, "SSPI client error 0x%x - %s - %s", err, msg, buf);
+ }
+ else
+ {
+ log_client_error(mysql, "SSPI client error %s", msg);
+ }
+}
+
+
+/** Client side authentication*/
+int auth_client(char *principal_name, char *mech, MYSQL *mysql, MYSQL_PLUGIN_VIO *vio)
+{
+
+ int ret;
+ CredHandle cred;
+ CtxtHandle ctxt;
+ ULONG attribs = 0;
+ TimeStamp lifetime;
+ SECURITY_STATUS sspi_err;
+
+ SecBufferDesc inbuf_desc;
+ SecBuffer inbuf;
+ SecBufferDesc outbuf_desc;
+ SecBuffer outbuf;
+ PBYTE out = NULL;
+
+ ret= CR_ERROR;
+ SecInvalidateHandle(&ctxt);
+ SecInvalidateHandle(&cred);
+
+ if (!mech || strcmp(mech, "Negotiate") != 0)
+ {
+ mech= "Kerberos";
+ }
+
+ sspi_err = AcquireCredentialsHandle(
+ NULL,
+ mech,
+ SECPKG_CRED_OUTBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred,
+ &lifetime);
+
+ if (SEC_ERROR(sspi_err))
+ {
+ log_error(mysql, sspi_err, "AcquireCredentialsHandle");
+ return CR_ERROR;
+ }
+
+ out = (PBYTE)malloc(SSPI_MAX_TOKEN_SIZE);
+ if (!out)
+ {
+ log_error(mysql, SEC_E_OK, "memory allocation error");
+ goto cleanup;
+ }
+
+ /* Prepare buffers */
+ inbuf_desc.ulVersion = SECBUFFER_VERSION;
+ inbuf_desc.cBuffers = 1;
+ inbuf_desc.pBuffers = &inbuf;
+ inbuf.BufferType = SECBUFFER_TOKEN;
+ inbuf.cbBuffer = 0;
+ inbuf.pvBuffer = NULL;
+
+ outbuf_desc.ulVersion = SECBUFFER_VERSION;
+ outbuf_desc.cBuffers = 1;
+ outbuf_desc.pBuffers = &outbuf;
+ outbuf.BufferType = SECBUFFER_TOKEN;
+ outbuf.pvBuffer = out;
+
+ do
+ {
+ outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
+ sspi_err= InitializeSecurityContext(
+ &cred,
+ SecIsValidHandle(&ctxt) ? &ctxt : NULL,
+ principal_name,
+ 0,
+ 0,
+ SECURITY_NATIVE_DREP,
+ inbuf.cbBuffer ? &inbuf_desc : NULL,
+ 0,
+ &ctxt,
+ &outbuf_desc,
+ &attribs,
+ &lifetime);
+ if (SEC_ERROR(sspi_err))
+ {
+ log_error(mysql, sspi_err, "InitializeSecurityContext");
+ goto cleanup;
+ }
+ if (sspi_err != SEC_E_OK && sspi_err != SEC_I_CONTINUE_NEEDED)
+ {
+ log_error(mysql, sspi_err, "Unexpected response from InitializeSecurityContext");
+ goto cleanup;
+ }
+
+ if (outbuf.cbBuffer)
+ {
+ /* send credential to server */
+ if (vio->write_packet(vio, (unsigned char *)outbuf.pvBuffer, outbuf.cbBuffer))
+ {
+ /* Server error packet contains detailed message. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ goto cleanup;
+ }
+ }
+
+ if (sspi_err == SEC_I_CONTINUE_NEEDED)
+ {
+ int len= vio->read_packet(vio, (unsigned char **)&inbuf.pvBuffer);
+ if (len <= 0)
+ {
+ /* Server side error is in the last server packet. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ goto cleanup;
+ }
+ inbuf.cbBuffer= len;
+ }
+ } while (sspi_err == SEC_I_CONTINUE_NEEDED);
+
+ ret= CR_OK;
+
+cleanup:
+
+ if (SecIsValidHandle(&ctxt))
+ DeleteSecurityContext(&ctxt);
+ if (SecIsValidHandle(&cred))
+ FreeCredentialsHandle(&cred);
+ free(out);
+ return ret;
+}