1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright 2011 Daniel Nichter
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; version 2 of the License.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
#include <drizzled/identifier.h>
22
#include <drizzled/util/convert.h>
23
#include <drizzled/algorithm/sha1.h>
24
#include <drizzled/execute.h>
25
#include <drizzled/sql/result_set.h>
26
#include <drizzled/plugin/listen.h>
27
#include <drizzled/plugin/client.h>
28
#include <drizzled/catalog/local.h>
29
#include "auth_schema.h"
32
using namespace drizzled;
33
using namespace plugin;
35
AuthSchema::AuthSchema() :
36
plugin::Authentication("auth_schema")
40
bool AuthSchema::setTable(const char *table)
46
bool AuthSchema::verifyMySQLPassword(const string &real_password,
47
const string &scramble_bytes,
48
const string &client_password)
50
if (scramble_bytes.size() != SHA1_DIGEST_LENGTH
51
|| client_password.size() != SHA1_DIGEST_LENGTH)
54
uint8_t real_password_hash[SHA1_DIGEST_LENGTH];
55
drizzled_hex_to_string(
56
reinterpret_cast<char *>(real_password_hash),
57
real_password.c_str(),
58
SHA1_DIGEST_LENGTH * 2);
60
/* Hash the scramble that was sent to client with the local password. */
62
uint8_t temp_hash[SHA1_DIGEST_LENGTH];
64
SHA1Update(&ctx, reinterpret_cast<const uint8_t*>(scramble_bytes.c_str()), SHA1_DIGEST_LENGTH);
65
SHA1Update(&ctx, real_password_hash, SHA1_DIGEST_LENGTH);
66
SHA1Final(temp_hash, &ctx);
68
/* Next, XOR the result with what the client sent to get the original
69
single-hashed password. */
70
for (int x= 0; x < SHA1_DIGEST_LENGTH; x++)
71
temp_hash[x]= temp_hash[x] ^ client_password[x];
73
/* Hash this result once more to get the double-hashed password again. */
74
uint8_t client_password_hash[SHA1_DIGEST_LENGTH];
76
SHA1Update(&ctx, temp_hash, SHA1_DIGEST_LENGTH);
77
SHA1Final(client_password_hash, &ctx);
79
/* These should match for a successful auth. */
80
return memcmp(real_password_hash, client_password_hash, SHA1_DIGEST_LENGTH) == 0;
83
bool AuthSchema::authenticate(const identifier::User &sctx, const string &password)
85
if (sctx.getPasswordType() != identifier::User::MYSQL_HASH)
88
string user= sctx.username();
93
_session= Session::make_shared(Listen::getNullClient(), catalog::local());
94
identifier::user::mptr user_id= identifier::User::make_shared();
95
user_id->setUser("auth_schema");
96
_session->setUser(user_id);
99
/* Execute wraps the SQL to run within a transaction */
100
string sql= "SELECT password FROM " + _table +
101
" WHERE user='" + user + "'"
103
Execute execute(*(_session.get()), true);
104
sql::ResultSet result_set(1);
105
execute.run(sql, result_set);
106
sql::Exception exception= result_set.getException();
107
drizzled::error_t err= exception.getErrorCode();
108
if ((err != EE_OK) && (err != ER_EMPTY_QUERY))
110
errmsg_printf(error::ERROR,
111
_("Error querying authentication schema: %s (error code %d)"),
112
exception.getErrorMessage().c_str(), exception.getErrorCode());
116
if (result_set.next() and not result_set.isNull(0))
118
string real_password= result_set.getString(0);
119
return verifyMySQLPassword(
121
sctx.getPasswordContext(),