List:Commits« Previous MessageNext Message »
From:Rafal Somla Date:April 29 2011 7:45pm
Subject:bzr push into mysql-trunk branch (rafal.somla:3345 to 3346) Bug#11766631
Bug#11879051
View as plain text  
 3346 Rafal Somla	2011-04-29 [merge]
      null merge of bug#11766631 and bug#11879051 from mysql-5.5

    added:
      libmysql/authentication_win/
      libmysql/authentication_win/CMakeLists.txt
      libmysql/authentication_win/common.cc
      libmysql/authentication_win/common.h
      libmysql/authentication_win/handshake.cc
      libmysql/authentication_win/handshake.h
      libmysql/authentication_win/handshake_client.cc
      libmysql/authentication_win/log_client.cc
      libmysql/authentication_win/plugin_client.cc
    modified:
      libmysql/CMakeLists.txt
      sql-common/client.c
 3345 Bjorn Munch	2011-04-29 [merge]
      null upmerge

=== modified file 'libmysql/CMakeLists.txt'
--- a/libmysql/CMakeLists.txt	2011-03-28 08:49:43 +0000
+++ b/libmysql/CMakeLists.txt	2011-04-28 19:17:29 +0000
@@ -1,4 +1,4 @@
-# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
 # 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -134,6 +134,12 @@ CACHE INTERNAL "Functions exported by cl
 
 )
 
+IF(WIN32)
+  ADD_SUBDIRECTORY(authentication_win)
+  SET(WITH_AUTHENTICATION_WIN 1)
+  ADD_DEFINITIONS(-DAUTHENTICATION_WIN)
+ENDIF(WIN32)
+
 SET(CLIENT_SOURCES
   get_password.c 
   libmysql.c
@@ -150,6 +156,10 @@ DTRACE_INSTRUMENT(clientlib)
 ADD_DEPENDENCIES(clientlib GenError)
 
 SET(LIBS clientlib dbug strings vio mysys ${ZLIB_LIBRARY} ${SSL_LIBRARIES} ${LIBDL})
+
+IF(WITH_AUTHENTICATION_WIN)
+  LIST(APPEND LIBS auth_win_client)
+ENDIF(WITH_AUTHENTICATION_WIN)
 
 # Merge several convenience libraries into one big mysqlclient
 # and link them together into shared library.

=== added directory 'libmysql/authentication_win'
=== added file 'libmysql/authentication_win/CMakeLists.txt'
--- a/libmysql/authentication_win/CMakeLists.txt	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/CMakeLists.txt	2011-04-28 19:39:42 +0000
@@ -0,0 +1,33 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+#
+# Configuration for building Windows Authentication Plugin (client-side)
+#
+
+ADD_DEFINITIONS(-DSECURITY_WIN32)
+ADD_DEFINITIONS(-DDEBUG_ERRROR_LOG)  # no error logging in production builds
+ADD_DEFINITIONS(-DWINAUTH_USE_DBUG_LIB)      # it is OK to use dbug library in statically
+                                             # linked plugin
+
+SET(HEADERS common.h handshake.h)
+SET(PLUGIN_SOURCES plugin_client.cc handshake_client.cc log_client.cc common.cc handshake.cc)
+
+ADD_CONVENIENCE_LIBRARY(auth_win_client ${PLUGIN_SOURCES} ${HEADERS})
+TARGET_LINK_LIBRARIES(auth_win_client Secur32)
+
+# In IDE, group headers in a separate folder.
+
+SOURCE_GROUP(Headers REGULAR_EXPRESSION ".*h$")

=== added file 'libmysql/authentication_win/common.cc'
--- a/libmysql/authentication_win/common.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/common.cc	2011-04-28 19:17:29 +0000
@@ -0,0 +1,492 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include "common.h"
+#include <sddl.h>   // for ConvertSidToStringSid()
+#include <secext.h> // for GetUserNameEx()
+
+
+template <> void error_log_print<error_log_level::INFO>(const char *fmt, ...);
+template <> void error_log_print<error_log_level::WARNING>(const char *fmt, ...);
+template <> void error_log_print<error_log_level::ERROR>(const char *fmt, ...);
+
+
+/** Connection class **************************************************/
+
+/**
+  Create connection out of an active MYSQL_PLUGIN_VIO object.
+
+  @param[in] vio  pointer to a @c MYSQL_PLUGIN_VIO object used for
+                  connection - it can not be NULL
+*/
+
+Connection::Connection(MYSQL_PLUGIN_VIO *vio): m_vio(vio), m_error(0)
+{
+  DBUG_ASSERT(vio);
+}
+
+
+/**
+  Write data to the connection.
+
+  @param[in]  blob  data to be written
+
+  @return 0 on success, VIO error code on failure.
+
+  @note In case of error, VIO error code is stored in the connection object
+  and can be obtained with @c error() method.
+*/
+
+int Connection::write(const Blob &blob)
+{
+  m_error= m_vio->write_packet(m_vio, blob.ptr(), blob.len());
+
+#ifndef DBUG_OFF
+  if (m_error)
+    DBUG_PRINT("error", ("vio write error %d", m_error));
+#endif
+
+  return m_error;
+}
+
+
+/**
+  Read data from connection.
+
+  @return A Blob containing read packet or null Blob in case of error.
+
+  @note In case of error, VIO error code is stored in the connection object
+  and can be obtained with @c error() method.
+*/
+
+Blob Connection::read()
+{
+  unsigned char *ptr;
+  int len= m_vio->read_packet(m_vio, &ptr);
+
+  if (len < 0)
+  {
+    m_error= true;
+    return Blob();
+  }
+
+  return Blob(ptr, len);
+}
+
+
+/** Sid class *****************************************************/
+
+
+/**
+  Create Sid object corresponding to a given account name.
+
+  @param[in]  account_name  name of a Windows account
+
+  The account name can be in any form accepted by @c LookupAccountName()
+  function.
+
+  @note In case of errors created object is invalid and its @c is_valid()
+  method returns @c false.
+*/
+
+Sid::Sid(const wchar_t *account_name): m_data(NULL)
+#ifndef DBUG_OFF
+, m_as_string(NULL)
+#endif
+{
+  DWORD sid_size= 0, domain_size= 0;
+  bool success;
+
+  // Determine required buffer sizes
+
+  success= LookupAccountNameW(NULL, account_name, NULL, &sid_size,
+                             NULL, &domain_size, &m_type);
+
+  if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+  {
+#ifndef DBUG_OFF
+    Error_message_buf error_buf;
+    DBUG_PRINT("error", ("Could not determine SID buffer size, "
+                         "LookupAccountName() failed with error %X (%s)",
+                         GetLastError(), get_last_error_message(error_buf)));
+#endif
+    return;
+  }
+
+  // Query for SID (domain is ignored)
+
+  wchar_t *domain= new wchar_t[domain_size];
+  m_data= (TOKEN_USER*) new BYTE[sid_size + sizeof(TOKEN_USER)];
+  m_data->User.Sid= (BYTE*)m_data + sizeof(TOKEN_USER);
+
+  success= LookupAccountNameW(NULL, account_name,
+                             m_data->User.Sid, &sid_size,
+                             domain, &domain_size,
+                             &m_type);
+
+  if (!success || !is_valid())
+  {
+#ifndef DBUG_OFF
+    Error_message_buf error_buf;
+    DBUG_PRINT("error", ("Could not determine SID of '%S', "
+                         "LookupAccountName() failed with error %X (%s)",
+                         account_name, GetLastError(),
+                         get_last_error_message(error_buf)));
+#endif
+    goto fail;
+  }
+
+  goto end;
+
+fail:
+  if (m_data)
+    delete [] m_data;
+  m_data= NULL;
+
+end:
+  if (domain)
+    delete [] domain;
+}
+
+
+/**
+  Create Sid object corresponding to a given security token.
+
+  @param[in]  token   security token of a Windows account
+
+  @note In case of errors created object is invalid and its @c is_valid()
+  method returns @c false.
+*/
+
+Sid::Sid(HANDLE token): m_data(NULL)
+#ifndef DBUG_OFF
+, m_as_string(NULL)
+#endif
+{
+  DWORD             req_size= 0;
+  bool              success;
+
+  // Determine required buffer size
+
+  success= GetTokenInformation(token, TokenUser, NULL, 0, &req_size);
+  if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+  {
+#ifndef DBUG_OFF
+    Error_message_buf error_buf;
+    DBUG_PRINT("error", ("Could not determine SID buffer size, "
+                         "GetTokenInformation() failed with error %X (%s)",
+                         GetLastError(), get_last_error_message(error_buf)));
+#endif
+    return;
+  }
+
+  m_data= (TOKEN_USER*) new BYTE[req_size];
+  success= GetTokenInformation(token, TokenUser, m_data, req_size, &req_size);
+
+  if (!success || !is_valid())
+  {
+    delete [] m_data;
+    m_data= NULL;
+#ifndef DBUG_OFF
+    if (!success)
+    {
+      Error_message_buf error_buf;
+      DBUG_PRINT("error", ("Could not read SID from security token, "
+                           "GetTokenInformation() failed with error %X (%s)",
+                           GetLastError(), get_last_error_message(error_buf)));
+    }
+#endif
+  }
+}
+
+
+Sid::~Sid()
+{
+  if (m_data)
+    delete [] m_data;
+#ifndef DBUG_OFF
+  if (m_as_string)
+    LocalFree(m_as_string);
+#endif
+}
+
+/// Check if Sid object is valid.
+bool Sid::is_valid(void) const
+{
+  return m_data && m_data->User.Sid && IsValidSid(m_data->User.Sid);
+}
+
+
+#ifndef DBUG_OFF
+
+/**
+  Produces string representation of the SID.
+
+  @return String representation of the SID or NULL in case of errors.
+
+  @note Memory allocated for the string is automatically freed in Sid's
+  destructor.
+*/
+
+const char* Sid::as_string()
+{
+  if (!m_data)
+    return NULL;
+
+  if (!m_as_string)
+  {
+    bool success= ConvertSidToStringSid(m_data->User.Sid, &m_as_string);
+
+    if (!success)
+    {
+#ifndef DBUG_OFF
+      Error_message_buf error_buf;
+      DBUG_PRINT("error", ("Could not get textual representation of a SID, "
+                           "ConvertSidToStringSid() failed with error %X (%s)",
+                           GetLastError(), get_last_error_message(error_buf)));
+#endif
+      m_as_string= NULL;
+      return NULL;
+    }
+  }
+
+  return m_as_string;
+}
+
+#endif
+
+
+bool Sid::operator ==(const Sid &other)
+{
+  if (!is_valid() || !other.is_valid())
+    return false;
+
+  return EqualSid(m_data->User.Sid, other.m_data->User.Sid);
+}
+
+
+/** Generating User Principal Name *************************/
+
+/**
+  Call Windows API functions to get UPN of the current user and store it
+  in internal buffer.
+*/
+
+UPN::UPN(): m_buf(NULL)
+{
+  wchar_t  buf1[MAX_SERVICE_NAME_LENGTH];
+
+  // First we try to use GetUserNameEx.
+
+  m_len= sizeof(buf1)/sizeof(wchar_t);
+
+  if (!GetUserNameExW(NameUserPrincipal, buf1, (PULONG)&m_len))
+  {
+    if (GetLastError())
+    {
+#ifndef DBUG_OFF
+      Error_message_buf error_buf;
+      DBUG_PRINT("note", ("When determining UPN"
+                          ", GetUserNameEx() failed with error %X (%s)",
+                          GetLastError(), get_last_error_message(error_buf)));
+#endif
+      if (ERROR_MORE_DATA == GetLastError())
+        ERROR_LOG(INFO, ("Buffer overrun when determining UPN:"
+                         " need %ul characters but have %ul",
+                         m_len, sizeof(buf1)/sizeof(WCHAR)));
+    }
+
+    m_len= 0;   // m_len == 0 indicates invalid UPN
+    return;
+  }
+
+  /*
+    UPN is stored in buf1 in wide-char format - convert it to utf8
+    for sending over network.
+  */
+
+  m_buf= wchar_to_utf8(buf1, &m_len);
+
+  if(!m_buf)
+    ERROR_LOG(ERROR, ("Failed to convert UPN to utf8"));
+
+  // Note: possible error would be indicated by the fact that m_buf is NULL.
+  return;
+}
+
+
+UPN::~UPN()
+{
+  if (m_buf)
+    free(m_buf);
+}
+
+
+/**
+  Convert a wide-char string to utf8 representation.
+
+  @param[in]     string   null-terminated wide-char string to be converted
+  @param[in,out] len      length of the string to be converted or 0; on
+                          return length (in bytes, excluding terminating
+                          null character) of the converted string
+
+  If len is 0 then the length of the string will be computed by this function.
+
+  @return Pointer to a buffer containing utf8 representation or NULL in
+          case of error.
+
+  @note The returned buffer must be freed with @c free() call.          
+*/
+
+char* wchar_to_utf8(const wchar_t *string, size_t *len)
+{
+  char   *buf= NULL; 
+  size_t  str_len= len && *len ? *len : wcslen(string);
+
+  /*
+    A conversion from utf8 to wchar_t will never take more than 3 bytes per
+    character, so a buffer of length 3 * str_len schould be sufficient. 
+    We check that assumption with an assertion later.
+  */
+
+  size_t  buf_len= 3 * str_len;
+
+  buf= (char*)malloc(buf_len + 1);
+  if (!buf)
+  {
+    DBUG_PRINT("error",("Out of memory when converting string '%S' to utf8",
+                        string));
+    return NULL;
+  }
+
+  int res= WideCharToMultiByte(CP_UTF8,              // convert to UTF-8
+                               0,                    // conversion flags
+                               string,               // input buffer
+                               str_len,              // its length
+                               buf, buf_len,         // output buffer and its size
+                               NULL, NULL);          // default character (not used)
+
+  if (res)
+  {
+    buf[res]= '\0';
+    if (len)
+      *len= res;
+    return buf;
+  }
+
+  // res is 0 which indicates error
+
+#ifndef DBUG_OFF
+  Error_message_buf error_buf;
+  DBUG_PRINT("error", ("Could not convert string '%S' to utf8"
+                       ", WideCharToMultiByte() failed with error %X (%s)",
+                       string, GetLastError(), 
+                       get_last_error_message(error_buf)));
+#endif
+
+  // Let's check our assumption about sufficient buffer size
+  DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
+
+  return NULL;
+}
+
+
+/**
+  Convert an utf8 string to a wide-char string.
+
+  @param[in]     string   null-terminated utf8 string to be converted
+  @param[in,out] len      length of the string to be converted or 0; on
+                          return length (in chars) of the converted string
+
+  If len is 0 then the length of the string will be computed by this function.
+
+  @return Pointer to a buffer containing wide-char representation or NULL in
+          case of error.
+
+  @note The returned buffer must be freed with @c free() call.          
+*/
+
+wchar_t* utf8_to_wchar(const char *string, size_t *len)
+{
+  size_t buf_len;
+
+  /* 
+    Note: length (in bytes) of an utf8 string is always bigger than the
+    number of characters in this string. Hence a buffer of size len will
+    be sufficient. We add 1 for the terminating null character.
+  */
+
+  buf_len= len && *len ? *len : strlen(string);
+  wchar_t *buf=  (wchar_t*)malloc((buf_len+1)*sizeof(wchar_t));
+
+  if (!buf)
+  {
+    DBUG_PRINT("error",("Out of memory when converting utf8 string '%s'"
+                        " to wide-char representation", string));
+    return NULL;
+  }
+
+  size_t  res;
+  res= MultiByteToWideChar(CP_UTF8,            // convert from UTF-8
+                           0,                  // conversion flags
+                           string,             // input buffer
+                           buf_len,            // its size
+                           buf, buf_len);      // output buffer and its size
+  if (res)
+  {
+    buf[res]= '\0';
+    if (len)
+      *len= res;
+    return buf;
+  }
+
+  // error in MultiByteToWideChar()
+
+#ifndef DBUG_OFF
+  Error_message_buf error_buf;
+  DBUG_PRINT("error", ("Could not convert UPN from UTF-8"
+                       ", MultiByteToWideChar() failed with error %X (%s)",
+                       GetLastError(), get_last_error_message(error_buf)));
+#endif
+
+  // Let's check our assumption about sufficient buffer size
+  DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
+
+  return NULL;
+}
+
+
+/** Error handling ****************************************************/
+
+
+/**
+  Returns error message corresponding to the last Windows error given
+  by GetLastError().
+
+  @note Error message is overwritten by next call to
+  @c get_last_error_message().
+*/
+
+const char* get_last_error_message(Error_message_buf buf)
+{
+  int error= GetLastError();
+
+  buf[0]= '\0';
+  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+		NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+		(LPTSTR)buf, sizeof(buf), NULL );
+
+  return buf;
+}

=== added file 'libmysql/authentication_win/common.h'
--- a/libmysql/authentication_win/common.h	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/common.h	2011-04-28 19:39:42 +0000
@@ -0,0 +1,324 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <my_global.h>
+#include <windows.h>
+#include <sspi.h>              // for CtxtHandle
+#include <mysql/plugin_auth.h> // for MYSQL_PLUGIN_VIO
+
+/// Maximum length of the target service name.
+#define MAX_SERVICE_NAME_LENGTH  1024
+
+
+/** Debugging and error reporting infrastructure ***************************/
+
+/*
+  Note: We use plugin local logging and error reporting mechanisms until
+  WL#2940 (plugin service: error reporting) is available.
+*/
+
+#undef INFO
+#undef WARNING
+#undef ERROR
+
+struct error_log_level
+{
+  typedef enum {INFO, WARNING, ERROR}  type;
+};
+
+
+/*
+  If DEBUG_ERROR_LOG is defined then error logging happens only
+  in debug-copiled code. Otherwise ERROR_LOG() expands to 
+  error_log_print() even in production code. Note that in client
+  plugin, error_log_print() will print nothing if opt_auth_win_clinet_log
+  is 0.
+
+  Note: Macro ERROR_LOG() can use printf-like format string like this:
+
+    ERROR_LOG(Level, ("format string", args));
+
+  The implementation should handle it correctly. Currently it is passed 
+  to fprintf() (see error_log_vprint() function).
+*/
+
+extern "C" int opt_auth_win_client_log;
+
+#if defined(DEBUG_ERROR_LOG) && defined(DBUG_OFF)
+#define ERROR_LOG(Level, Msg)     do {} while (0)
+#else
+#define ERROR_LOG(Level, Msg)     error_log_print< error_log_level::Level > Msg
+#endif
+
+
+void error_log_vprint(error_log_level::type level,
+                        const char *fmt, va_list args);
+
+template <error_log_level::type Level>
+void error_log_print(const char *fmt, ...)
+{
+  va_list args;
+  va_start(args, fmt);
+  error_log_vprint(Level, fmt, args);
+  va_end(args);
+}
+
+typedef char Error_message_buf[1024];
+const char* get_last_error_message(Error_message_buf);
+
+
+/*
+  Internal implementation of debug message printing which does not use
+  dbug library. This is invoked via macro:
+
+    DBUG_PRINT_DO(Keyword, ("format string", args));
+
+  This is supposed to be used as an implementation of DBUG_PRINT() macro,
+  unless the dbug library implementation is used or debug messages are disabled.
+*/
+
+#ifndef DBUG_OFF
+
+#define DBUG_PRINT_DO(Keyword, Msg) \
+  do { \
+    if (2 > opt_auth_win_client_log) break; \
+    fprintf(stderr, "winauth: %s: ", Keyword); \
+    debug_msg Msg; \
+  } while (0)
+
+inline
+void debug_msg(const char *fmt, ...)
+{
+  va_list args;
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  fputc('\n', stderr);
+  fflush(stderr);
+  va_end(args);
+}
+
+#else
+#define DBUG_PRINT_DO(K, M)  do {} while (0)
+#endif
+
+
+#ifndef WINAUTH_USE_DBUG_LIB
+
+#undef  DBUG_PRINT
+#define DBUG_PRINT(Keyword, Msg)  DBUG_PRINT_DO(Keyword, Msg)
+
+/*
+  Redefine few more debug macros to make sure that no symbols from
+  dbug library are used.
+*/
+
+#undef DBUG_ENTER
+#define DBUG_ENTER(X)  do {} while (0)
+
+#undef DBUG_RETURN
+#define DBUG_RETURN(X) return (X)
+
+#undef DBUG_ASSERT
+#ifndef DBUG_OFF
+#define DBUG_ASSERT(X) assert (X)
+#else
+#define DBUG_ASSERT(X) do {} while (0)
+#endif
+
+#undef DBUG_DUMP
+#define DBUG_DUMP(A,B,C) do {} while (0)
+
+#endif
+
+
+/** Blob class *************************************************************/
+
+typedef unsigned char byte;
+
+/**
+  Class representing a region of memory (e.g., a string or binary buffer).
+
+  @note This class does not allocate memory. It merely describes a region
+  of memory which must be allocated externally (if it is dynamic memory).
+*/
+
+class Blob
+{
+  byte   *m_ptr;  ///< Pointer to the first byte of the memory region.
+  size_t  m_len;  ///< Length of the memory region.
+
+public:
+
+  Blob(): m_ptr(NULL), m_len(0)
+  {}
+
+  Blob(const byte *ptr, const size_t len)
+  : m_ptr(const_cast<byte*>(ptr)), m_len(len)
+  {}
+
+  Blob(const char *str): m_ptr((byte*)str)
+  {
+    m_len= strlen(str);
+  }
+
+  byte*  ptr() const
+  {
+    return m_ptr;
+  }
+
+  size_t len() const
+  {
+    return m_len;
+  }
+
+  byte& operator[](unsigned pos) const
+  {
+    static byte out_of_range= 0;  // alas, no exceptions...
+    return pos < len() ? m_ptr[pos] : out_of_range;
+  }
+
+  bool is_null() const
+  {
+    return m_ptr == NULL;
+  }
+
+  void trim(size_t l)
+  {
+    m_len= l;
+  }
+};
+
+
+/** Connection class *******************************************************/
+
+/**
+  Convenience wrapper around MYSQL_PLUGIN_VIO object providing basic
+  read/write operations.
+*/
+
+class Connection
+{
+  MYSQL_PLUGIN_VIO *m_vio;    ///< Pointer to @c MYSQL_PLUGIN_VIO structure.
+
+  /**
+    If non-zero, indicates that connection is broken. If this has happened
+    because of failed operation, stores non-zero error code from that failure.
+  */
+  int               m_error;
+
+public:
+
+  Connection(MYSQL_PLUGIN_VIO *vio);
+  int write(const Blob&);
+  Blob read();
+
+  int error() const
+  {
+    return m_error;
+  }
+};
+
+
+/** Sid class **************************************************************/
+
+/**
+  Class for storing and manipulating Windows security identifiers (SIDs).
+*/
+
+class Sid
+{
+  TOKEN_USER    *m_data;  ///< Pointer to structure holding identifier's data.
+  SID_NAME_USE   m_type;  ///< Type of identified entity.
+
+public:
+
+  Sid(const wchar_t*);
+  Sid(HANDLE sec_token);
+  ~Sid();
+
+  bool is_valid(void) const;
+
+  bool is_group(void) const
+  {
+    return m_type == SidTypeGroup
+           || m_type == SidTypeWellKnownGroup
+           || m_type == SidTypeAlias;
+  }
+
+  bool is_user(void) const
+  {
+    return m_type == SidTypeUser;
+  }
+
+  bool operator==(const Sid&);
+
+  operator PSID() const
+  {
+    return (PSID)m_data->User.Sid;
+  }
+
+#ifndef DBUG_OFF
+
+private:
+    char *m_as_string;  ///< Cached string representation of the SID.
+public:
+    const char* as_string();
+
+#endif
+};
+
+
+/** UPN class **************************************************************/
+
+/**
+  An object of this class obtains and stores User Principal Name of the
+  account under which current process is running.
+*/
+
+class UPN
+{
+  char   *m_buf;  ///< Pointer to UPN in utf8 representation.
+  size_t  m_len;  ///< Length of the name.
+
+public:
+
+  UPN();
+  ~UPN();
+
+  bool is_valid() const
+  {
+    return m_len > 0;
+  }
+
+  const Blob as_blob() const
+  {
+    return m_len ? Blob((byte*)m_buf, m_len) : Blob();
+  }
+
+  const char* as_string() const
+  {
+    return (const char*)m_buf;
+  }
+
+};
+
+
+char*     wchar_to_utf8(const wchar_t*, size_t*);
+wchar_t*  utf8_to_wchar(const char*, size_t*);
+
+#endif

=== added file 'libmysql/authentication_win/handshake.cc'
--- a/libmysql/authentication_win/handshake.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/handshake.cc	2011-04-28 19:39:42 +0000
@@ -0,0 +1,289 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include "handshake.h"
+
+
+/** Handshake class implementation **********************************/
+
+/**
+  Create common part of handshake context.
+
+  @param[in]  ssp   name of the SSP (Security Service Provider) to
+                    be used for authentication
+  @param[in]  side  is this handshake object used for server- or
+                    client-side handshake
+
+  Prepare for handshake using the @c ssp security module. We use
+  "Negotiate" which picks best available module. Parameter @c side
+  tells if this is preparing for server or client side authentication
+  and is used to prepare appropriate credentials.
+*/
+
+Handshake::Handshake(const char *ssp, side_t side)
+: m_atts(0L), m_error(0), m_complete(FALSE),
+  m_have_credentials(false), m_have_sec_context(false)
+#ifndef DBUG_OFF
+  , m_ssp_info(NULL)
+#endif
+{
+  SECURITY_STATUS ret;
+
+  // Obtain credentials for the authentication handshake.
+
+  ret= AcquireCredentialsHandle(NULL, (SEC_CHAR*)ssp,
+         side == SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
+         NULL, NULL, NULL, NULL, &m_cred, &m_expire);
+
+  if (ret != SEC_E_OK)
+  {
+    DBUG_PRINT("error", ("AcqireCredentialsHandle() failed"
+                         " with error %X", ret));
+    ERROR_LOG(ERROR, ("Could not obtain local credentials"
+                      " required for authentication"));
+    m_error= ret;
+  }
+
+  m_have_credentials= true;
+}
+
+
+Handshake::~Handshake()
+{
+  if (m_have_credentials)
+    FreeCredentialsHandle(&m_cred);
+  if (m_have_sec_context)
+    DeleteSecurityContext(&m_sctx);
+  m_output.free();
+
+#ifndef DBUG_OFF
+  if (m_ssp_info)
+    FreeContextBuffer(m_ssp_info);
+#endif
+}
+
+
+/**
+  Read and process data packets from the other end of a connection.
+
+  @param[IN] con  a connection to read packets from
+
+  Packets are read and processed until authentication handshake is 
+  complete. It is assumed that the peer will send at least one packet. 
+  Packets are processed with @c process_data() method. If new data is
+  generated during packet processing, this data is sent to the peer and
+  another round of packet exchange starts.
+
+  @return 0 on success.
+
+  @note In case of error, appropriate error message is logged.
+*/
+int Handshake::packet_processing_loop()
+{
+  m_round= 0;
+
+  do {
+    ++m_round;
+    // Read packet send by the peer
+
+    DBUG_PRINT("info", ("Waiting for packet"));
+    Blob packet= read_packet();
+    if (error())
+    {
+      ERROR_LOG(ERROR, ("Error reading packet in round %d", m_round));
+      return 1;
+    }
+    DBUG_PRINT("info", ("Got packet of length %d", packet.len()));
+
+    /*
+      Process received data, possibly generating new data to be sent.
+    */
+
+    Blob new_data= process_data(packet);
+
+    if (error())
+    {
+      ERROR_LOG(ERROR, ("Error processing packet in round %d", m_round));
+      return 1;
+    }
+
+    /*
+      If new data has been generated, send it to the peer. Otherwise
+      handshake must be completed.
+    */
+
+    if (!new_data.is_null())
+    {
+      DBUG_PRINT("info", ("Round %d started", m_round));
+
+      DBUG_PRINT("info", ("Sending packet of length %d", new_data.len()));
+      int ret= write_packet(new_data);
+      if (ret)
+      {
+        ERROR_LOG(ERROR, ("Error writing packet in round %d", m_round));
+        return 1;
+      }
+      DBUG_PRINT("info", ("Data sent"));
+    }
+    else if (!is_complete())
+    {
+      ERROR_LOG(ERROR, ("No data to send in round %d"
+                        " but handshake is not complete", m_round));
+      return 1;
+    }
+
+    /*
+      To protect against malicious clients, break handshake exchange if
+      too many rounds.
+    */
+
+    if (m_round > MAX_HANDSHAKE_ROUNDS)
+    {
+      ERROR_LOG(ERROR, ("Authentication handshake could not be completed"
+                        " after %d rounds", m_round));
+      return 1;
+    }
+
+  } while(!is_complete());
+
+  ERROR_LOG(INFO, ("Handshake completed after %d rounds", m_round));
+  return 0;
+}
+
+
+#ifndef DBUG_OFF
+
+/**
+  Get name of the security package which was used in authentication.
+
+  This method should be called only after handshake was completed. It is
+  available only in debug builds.
+
+  @return Name of security package or NULL if it can not be obtained.
+*/
+
+const char* Handshake::ssp_name()
+{
+  if (!m_ssp_info && m_complete)
+  {
+    SecPkgContext_PackageInfo pinfo;
+
+    int ret= QueryContextAttributes(&m_sctx, SECPKG_ATTR_PACKAGE_INFO, &pinfo);
+
+    if (SEC_E_OK == ret)
+    {
+      m_ssp_info= pinfo.PackageInfo;
+    }
+    else
+      DBUG_PRINT("error",
+                 ("Could not obtain SSP info from authentication context"
+                  ", QueryContextAttributes() failed with error %X", ret));
+  }
+
+  return m_ssp_info ? m_ssp_info->Name : NULL;
+}
+
+#endif
+
+
+/**
+  Process result of @c {Initialize,Accept}SecurityContext() function.
+
+  @param[in]  ret   return code from @c {Initialize,Accept}SecurityContext()
+                    function
+
+  This function analyses return value of Windows
+  @c {Initialize,Accept}SecurityContext() function. A call to
+  @c CompleteAuthToken() is done if requested. If authentication is complete,
+  this fact is marked in the internal state of the Handshake object.
+  If errors are detected the object is moved to error state.
+
+  @return True if error has been detected.
+*/
+
+bool Handshake::process_result(int ret)
+{
+  /*
+    First check for errors and set the m_complete flag if the result
+    indicates that handshake is complete.
+  */
+
+  switch (ret)
+  {
+  case SEC_E_OK:
+  case SEC_I_COMPLETE_NEEDED:
+    // Handshake completed
+    m_complete= true;
+    break;
+
+  case SEC_I_CONTINUE_NEEDED:
+  case SEC_I_COMPLETE_AND_CONTINUE:
+    break;
+
+  default:
+    m_error= ret;
+    return true;
+  }
+
+  m_have_sec_context= true;
+
+  /*
+    If the result indicates a need for this, complete the authentication
+    token.
+  */
+
+  switch (ret)
+  {
+  case SEC_I_COMPLETE_NEEDED:
+  case SEC_I_COMPLETE_AND_CONTINUE:
+    ret= CompleteAuthToken(&m_sctx, &m_output);
+    if (ret != 0)
+    {
+      DBUG_PRINT("error", ("CompleteAuthToken() failed with error %X", ret));
+      m_error= ret;
+      return true;
+    }
+  default:
+    break;
+  }
+
+  return false;
+}
+
+
+/** Security_buffer class implementation **********************************/
+
+
+Security_buffer::Security_buffer(const Blob &blob): m_allocated(false)
+{
+  init(blob.ptr(), blob.len());
+}
+
+
+Security_buffer::Security_buffer(): m_allocated(true)
+{
+  init(NULL, 0);
+}
+
+
+void Security_buffer::free(void)
+{
+  if (!m_allocated)
+    return;
+  if (!ptr())
+    return;
+  FreeContextBuffer(ptr());
+  m_allocated= false;
+}

=== added file 'libmysql/authentication_win/handshake.h'
--- a/libmysql/authentication_win/handshake.h	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/handshake.h	2011-04-28 19:39:42 +0000
@@ -0,0 +1,181 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef HANDSHAKE_H
+#define HANDSHAKE_H
+
+#include "common.h"
+
+/**
+  Name of the SSP (Security Support Provider) to be used for authentication.
+
+  We use "Negotiate" which will find the most secure SSP which can be used
+  and redirect to that SSP.
+*/
+#define SSP_NAME  "Negotiate"
+
+/**
+  Maximal number of rounds in authentication handshake.
+
+  Server will interrupt authentication handshake with error if client's
+  identity can not be determined within this many rounds.
+*/
+#define MAX_HANDSHAKE_ROUNDS  50
+
+
+/// Convenience wrapper around @c SecBufferDesc.
+
+class Security_buffer: public SecBufferDesc
+{
+  SecBuffer m_buf;        ///< A @c SecBuffer instance.
+
+  void init(byte *ptr, size_t len)
+  {
+    ulVersion= 0;
+    cBuffers=  1;
+    pBuffers=  &m_buf;
+
+    m_buf.BufferType= SECBUFFER_TOKEN;
+    m_buf.pvBuffer= ptr;
+    m_buf.cbBuffer= len;
+  }
+
+  /// If @c false, no deallocation will be done in the destructor.
+  bool m_allocated;
+
+ public:
+
+  Security_buffer(const Blob&);
+  Security_buffer();
+
+  ~Security_buffer()
+  {
+    free();
+  }
+
+  byte*  ptr() const
+  {
+    return (byte*)m_buf.pvBuffer;
+  }
+
+  size_t len() const
+  {
+    return m_buf.cbBuffer;
+  }
+
+  bool is_valid() const
+  {
+    return ptr() != NULL;
+  }
+
+  const Blob as_blob() const
+  {
+    return Blob(ptr(), len());
+  }
+
+  void free(void);
+};
+
+
+/// Common base for Handshake_{server,client}.
+
+class Handshake
+{
+public:
+
+  typedef enum {CLIENT, SERVER} side_t;
+
+  Handshake(const char *ssp, side_t side);
+  virtual ~Handshake();
+
+  int Handshake::packet_processing_loop();
+
+  bool virtual is_complete() const
+  {
+    return m_complete;
+  }
+
+  int error() const
+  {
+    return m_error;
+  }
+
+protected:
+
+  /// Security context object created during the handshake.
+  CtxtHandle  m_sctx;
+
+  /// Credentials of the principal performing this handshake.
+  CredHandle  m_cred;
+
+  /// Stores expiry date of the created security context.
+  TimeStamp  m_expire;
+
+  /// Stores attributes of the created security context.
+  ULONG  m_atts;
+
+  /**
+    Round of the handshake (starting from round 1). One round
+    consist of reading packet from the other side, processing it and
+    optionally sending a reply (see @c packet_processing_loop()).
+  */
+  unsigned int m_round;
+
+  /// If non-zero, stores error code of the last failed operation.
+  int  m_error;
+
+  /// @c true when handshake is complete.
+  bool  m_complete;
+
+  /// @c true when the principal credentials has been determined.
+  bool  m_have_credentials;
+
+  /// @c true when the security context has been created.
+  bool  m_have_sec_context;
+
+  /// Buffer for data to be send to the other side.
+  Security_buffer  m_output;
+
+  bool process_result(int);
+
+  /**
+    This method is used inside @c packet_processing_loop to process
+    data packets received from the other end.
+
+    @param[IN]  data  data to be processed
+
+    @return A blob with data to be sent to the other end or null blob if
+    no more data needs to be exchanged.
+  */
+  virtual Blob process_data(const Blob &data) =0;
+
+  /// Read packet from the other end.
+  virtual Blob read_packet()  =0;
+
+  /// Write packet to the other end.
+  virtual int  write_packet(Blob &data) =0;
+
+#ifndef DBUG_OFF
+
+private:
+  SecPkgInfo  *m_ssp_info;
+public:
+  const char* ssp_name();
+
+#endif
+};
+
+
+#endif

=== added file 'libmysql/authentication_win/handshake_client.cc'
--- a/libmysql/authentication_win/handshake_client.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/handshake_client.cc	2011-04-28 19:39:42 +0000
@@ -0,0 +1,378 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include "handshake.h"
+
+#include <mysql.h> // for MYSQL structure
+
+
+/// Client-side context for authentication handshake
+
+class Handshake_client: public Handshake
+{
+  /**
+    Name of the server's service for which we authenticate.
+
+    The service name is sent by server in the initial packet. If no
+    service name is used, this member is @c NULL.
+  */
+  SEC_WCHAR  *m_service_name;
+
+  /// Buffer for storing service name obtained from server.
+  SEC_WCHAR   m_service_name_buf[MAX_SERVICE_NAME_LENGTH];
+
+  Connection &m_con;
+
+public:
+
+  Handshake_client(Connection &con, const char *target, size_t len);
+  ~Handshake_client();
+
+  Blob  first_packet();
+  Blob  process_data(const Blob&);
+
+  Blob read_packet();
+  int write_packet(Blob &data);
+};
+
+
+/**
+  Create authentication handshake context for client.
+
+  @param con     connection for communication with the peer 
+  @param target  name of the target service with which we will authenticate
+                 (can be NULL if not used)
+
+  Some security packages (like Kerberos) require providing explicit name
+  of the service with which a client wants to authenticate. The server-side
+  authentication plugin sends this name in the greeting packet
+  (see @c win_auth_handshake_{server,client}() functions).
+*/
+
+Handshake_client::Handshake_client(Connection &con, 
+                                   const char *target, size_t len)
+: Handshake(SSP_NAME, CLIENT), m_service_name(NULL), m_con(con)
+{
+  if (!target || 0 == len)
+    return;
+
+  // Convert received UPN to internal WCHAR representation.
+
+  m_service_name= utf8_to_wchar(target, &len);
+
+  if (m_service_name)
+    DBUG_PRINT("info", ("Using target service: %S\n", m_service_name));
+  else
+  {
+    /*
+      Note: we ignore errors here - m_target will be NULL, the target name
+      will not be used and system will fall-back to NTLM authentication. But
+      we leave trace in error log.
+    */
+    ERROR_LOG(WARNING, ("Could not decode UPN sent by the server"
+                        "; target service name will not be used"
+                        " and Kerberos authentication will not work"));
+  }
+}
+
+
+Handshake_client::~Handshake_client()
+{
+  if (m_service_name)
+    free(m_service_name);
+}
+
+
+Blob Handshake_client::read_packet()
+{
+  /*
+    We do a fake read in the first round because first
+    packet from the server containing UPN must be read
+    before the handshake context is created and the packet
+    processing loop starts. We return an empty blob here
+    and process_data() function will ignore it.
+  */
+  if (m_round == 1)
+    return Blob();
+
+  // Otherwise we read packet from the connection.
+
+  Blob packet= m_con.read();
+  m_error= m_con.error();
+  if (!m_error && packet.is_null())
+    m_error= true;  // (no specific error code assigned)
+
+  if (m_error)
+    return Blob();
+
+  DBUG_PRINT("dump", ("Got the following bytes"));
+  DBUG_DUMP("dump", packet.ptr(), packet.len());
+  return packet;
+}
+
+
+
+int Handshake_client::write_packet(Blob &data)
+{
+  /*
+   Length of the first data payload send by client authentication plugin is
+   limited to 255 bytes (because it is wrapped inside client authentication
+   packet and is length-encoded with 1 byte for the length).
+
+   If the data payload is longer than 254 bytes, then it is sent in two parts:
+   first part of length 255 will be embedded in the authentication packet, 
+   second part will be sent in the following packet. Byte 255 of the first 
+   part contains information about the total length of the payload. It is a
+   number of blocks of size 512 bytes which is sufficient to store the
+   combined packets.
+
+   Server's logic for reading first client's payload is as follows
+   (see Handshake_server::read_packet()):
+   1. Read data from the authentication packet, if it is shorter than 255 bytes 
+      then that is all data sent by client.
+   2. If there is 255 bytes of data in the authentication packet, read another
+      packet and append it to the data, skipping byte 255 of the first packet
+      which can be used to allocate buffer of appropriate size.
+  */
+
+  size_t len2= 0;   // length of the second part of first data payload
+  byte saved_byte;  // for saving byte 255 in which data length is stored
+
+  if (m_round == 1 && data.len() > 254)
+  {
+    len2= data.len() - 254;
+    DBUG_PRINT("info", ("Splitting first packet of length %lu"
+                        ", %lu bytes will be sent in a second part", 
+                        data.len(), len2));
+    /* 
+      Store in byte 255 the number of 512b blocks that are needed to
+      keep all the data.
+    */
+    unsigned block_count= data.len()/512 + ((data.len() % 512) ? 1 : 0);
+    DBUG_ASSERT(block_count < (unsigned)0x100);
+    saved_byte= data[254];
+    data[254] = block_count;
+
+    data.trim(255);
+  }
+
+  DBUG_PRINT("dump", ("Sending the following data"));
+  DBUG_DUMP("dump", data.ptr(), data.len());
+  int ret= m_con.write(data);
+
+  if (ret)
+    return ret;
+
+  // Write second part if it is present.
+  if (len2)
+  {
+    data[254]= saved_byte;
+    Blob data2(data.ptr() + 254, len2);
+    DBUG_PRINT("info", ("Sending second part of data"));
+    DBUG_DUMP("info", data2.ptr(), data2.len());
+    ret= m_con.write(data2);
+  }
+
+  return ret;
+}
+
+
+/**
+  Process data sent by server.
+
+  @param[in]  data  blob with data from server
+
+  This method analyses data sent by server during authentication handshake.
+  If client should continue packet exchange, this method returns data to
+  be sent to the server next. If no more data needs to be exchanged, an
+  empty blob is returned and @c is_complete() is @c true. In case of error
+  an empty blob is returned and @c error() gives non-zero error code.
+
+  When invoked for the first time (in the first round of the handshake)
+  there is no data from the server (data blob is null) and the intial
+  packet is generated without an input.
+
+  @return Data to be sent to the server next or null blob if no more data
+  needs to be exchanged or in case of error.
+*/
+
+Blob Handshake_client::process_data(const Blob &data)
+{
+#if !defined(DBUG_OFF) && defined(WINAUTH_USE_DBUG_LIB)
+  /*
+    Code for testing the logic for sending the first client payload.
+
+    A fake data of length given by environment variable TEST_PACKET_LENGTH
+    (or default 255 bytes) is sent to the server. First 2 bytes of the
+    payload contain its total length (LSB first). The length of test data
+    is limited to 2048 bytes.
+
+    Upon receiving test data, server will check that data is correct and
+    refuse connection. If server detects data errors it will crash on 
+    assertion.
+
+    This code is executed if debug flag "winauth_first_packet_test" is
+    set, e.g. using client option:
+
+     --debug="d,winauth_first_packet_test"
+
+     The same debug flag must be enabled in the server, e.g. using 
+     statement:
+
+     SET GLOBAL debug= '+d,winauth_first_packet_test'; 
+  */
+
+  static byte test_buf[2048];
+
+  if (m_round == 1 
+      && DBUG_EVALUATE_IF("winauth_first_packet_test", true, false))
+  {
+    const char *env= getenv("TEST_PACKET_LENGTH");
+    size_t len= env ? atoi(env) : 0;
+    if (!len)
+      len= 255;
+    if (len > sizeof(test_buf))
+      len= sizeof(test_buf);
+
+    // Store data length in first 2 bytes.
+    byte *ptr= test_buf;
+    *ptr++= len & 0xFF;
+    *ptr++= len >> 8;
+
+    // Fill remaining bytes with known values.
+    for (byte b= 0; ptr < test_buf + len; ++ptr, ++b)
+      *ptr= b;
+
+    return Blob(test_buf, len);
+  };
+
+#endif
+
+  Security_buffer  input(data);
+  SECURITY_STATUS  ret;
+
+  m_output.free();
+
+  ret= InitializeSecurityContextW(
+         &m_cred,
+         m_round == 1 ? NULL : &m_sctx,        // partial context
+         m_service_name,                       // service name
+         ASC_REQ_ALLOCATE_MEMORY,              // requested attributes
+         0,                                    // reserved
+         SECURITY_NETWORK_DREP,                // data representation
+         m_round == 1 ? NULL : &input,         // input data
+         0,                                    // reserved
+         &m_sctx,                              // context
+         &m_output,                            // output data
+         &m_atts,                              // attributes
+         &m_expire);                           // expire date
+
+  if (process_result(ret))
+  {
+    DBUG_PRINT("error",
+               ("InitializeSecurityContext() failed with error %X", ret));
+    return Blob();
+  }
+
+  return m_output.as_blob();
+}
+
+
+/**********************************************************************/
+
+
+/**
+  Perform authentication handshake from client side.
+
+  @param[in]  vio    pointer to @c MYSQL_PLUGIN_VIO instance to be used
+                     for communication with the server
+  @param[in]  mysql  pointer to a MySQL connection for which we authenticate
+
+  After reading the initial packet from server, containing its UPN to be
+  used as service name, client starts packet exchange by sending the first
+  packet in this exchange. While handshake is not yet completed, client
+  reads packets sent by the server and process them, possibly generating new
+  data to be sent to the server.
+
+  This function reports errors.
+
+  @return 0 on success.
+*/
+
+int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+  DBUG_ENTER("win_auth_handshake_client");
+
+  /*
+    Check if we should enable logging.
+  */
+  {
+    const char *opt= getenv("AUTHENTICATION_WIN_LOG");
+    int opt_val= opt ? atoi(opt) : 0;
+    if (opt && !opt_val)
+    {
+      if (!strncasecmp("on", opt, 2))    opt_val= 1;
+      if (!strncasecmp("yes", opt, 3))   opt_val= 1;
+      if (!strncasecmp("true", opt, 4))  opt_val= 1;
+      if (!strncasecmp("debug", opt, 5)) opt_val= 2;
+      if (!strncasecmp("dbug", opt, 4))  opt_val= 2;
+    }
+    opt_auth_win_client_log= opt_val;
+  }
+
+  ERROR_LOG(INFO, ("Authentication handshake for account %s", mysql->user));
+
+  // Create connection object.
+
+  Connection con(vio);
+  DBUG_ASSERT(!con.error());
+
+  // Read initial packet from server containing service name.
+
+  Blob service_name= con.read();
+
+  if (con.error() || service_name.is_null())
+  {
+    ERROR_LOG(ERROR, ("Error reading initial packet"));
+    DBUG_RETURN(CR_ERROR);
+  }
+  DBUG_PRINT("info", ("Got initial packet of length %d", service_name.len()));
+
+  // Create authentication handshake context using the given service name.
+
+  Handshake_client hndshk(con,
+                          service_name[0] ? (char *)service_name.ptr() : NULL,
+                          service_name.len());
+  if (hndshk.error())
+  {
+    ERROR_LOG(ERROR, ("Could not create authentication handshake context"));
+    DBUG_RETURN(CR_ERROR);
+  }
+
+  DBUG_ASSERT(!hndshk.error());
+
+  /*
+    Read and process packets from server until handshake is complete.
+    Note that the first read from server is dummy 
+    (see Handshake_client::read_packet()) as we already have read the 
+    first packet to establish service name.
+  */
+  if (hndshk.packet_processing_loop())
+    DBUG_RETURN(CR_ERROR);
+
+  DBUG_ASSERT(!hndshk.error() && hndshk.is_complete());
+
+  DBUG_RETURN(CR_OK);
+}

=== added file 'libmysql/authentication_win/log_client.cc'
--- a/libmysql/authentication_win/log_client.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/log_client.cc	2011-04-28 19:17:29 +0000
@@ -0,0 +1,55 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include <my_global.h>
+#include "common.h"
+
+/**
+  This option is set in win_auth_handshake_client() function 
+  in handshake_client.cc.
+
+  Values:
+  0 - no logging
+  1 - log error/warning/info messages
+  2 - also log debug messages
+
+  Note: No error or debug messages are logged in production code
+  (see logging macros in common.h).
+*/
+int opt_auth_win_client_log= 0;
+
+
+// Client-side logging function
+
+void error_log_vprint(error_log_level::type level,
+                        const char *fmt, va_list args)
+{
+  if (0 == opt_auth_win_client_log)
+    return;
+
+  const char *level_string= "";
+
+  switch (level)
+  {
+  case error_log_level::INFO:    level_string= "Note"; break;
+  case error_log_level::WARNING: level_string= "Warning"; break;
+  case error_log_level::ERROR:   level_string= "ERROR"; break;
+  }
+
+  fprintf(stderr, "Windows Authentication Plugin %s: ", level_string);
+  vfprintf(stderr, fmt, args);
+  fputc('\n', stderr);
+  fflush(stderr);
+}

=== added file 'libmysql/authentication_win/plugin_client.cc'
--- a/libmysql/authentication_win/plugin_client.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/plugin_client.cc	2011-04-28 19:17:29 +0000
@@ -0,0 +1,58 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include <my_global.h>
+#include <mysql.h>
+#include <mysql/plugin_auth.h>
+#include <mysql/client_plugin.h>
+
+#include "common.h"
+
+static int win_auth_client_plugin_init(char*, size_t, int, va_list)
+{
+  return 0;
+}
+
+
+static int win_auth_client_plugin_deinit()
+{
+  return 0;
+}
+
+
+int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+
+
+/*
+  Client plugin declaration. This is added to mysql_client_builtins[]
+  in sql-common/client.c
+*/
+
+extern "C"
+st_mysql_client_plugin_AUTHENTICATION win_auth_client_plugin=
+{
+  MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
+  MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
+  "authentication_windows_client",
+  "Rafal Somla",
+  "Windows Authentication Plugin - client side",
+  {0,1,0},
+  "GPL",
+  NULL,
+  win_auth_client_plugin_init,
+  win_auth_client_plugin_deinit,
+  NULL,                            // option handling
+  win_auth_handshake_client
+};

=== modified file 'sql-common/client.c'
--- a/sql-common/client.c	2011-04-15 09:33:58 +0000
+++ b/sql-common/client.c	2011-04-29 15:09:13 +0000
@@ -2318,11 +2318,18 @@ static auth_plugin_t clear_password_clie
   clear_password_auth_client
 };
 
+#ifdef AUTHENTICATION_WIN
+extern auth_plugin_t win_auth_client_plugin;
+#endif
+
 struct st_mysql_client_plugin *mysql_client_builtins[]=
 {
   (struct st_mysql_client_plugin *)&native_password_client_plugin,
   (struct st_mysql_client_plugin *)&old_password_client_plugin,
   (struct st_mysql_client_plugin *)&clear_password_client_plugin,
+#ifdef AUTHENTICATION_WIN
+  (struct st_mysql_client_plugin *)&win_auth_client_plugin,
+#endif
   0
 };
 

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (rafal.somla:3345 to 3346) Bug#11766631Bug#11879051Rafal Somla29 Apr
  • Re: bzr push into mysql-trunk branch (rafal.somla:3345 to 3346) Bug#11766631Bug#11879051Davi Arnaut29 Apr
    • Re: bzr push into mysql-trunk branch (rafal.somla:3345 to 3346) Bug#11766631Bug#11879051Rafal Somla2 May
      • Re: bzr push into mysql-trunk branch (rafal.somla:3345 to 3346) Bug#11766631Bug#11879051Davi Arnaut2 May