1
/* Copyright (C) 2004-2006 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
17
#pragma implementation
21
#include "exit_codes.h"
23
#include "portability.h"
25
User::User(const LEX_STRING *user_name_arg, const char *password)
27
user_length= (uint8) (strmake(user, user_name_arg->str,
28
USERNAME_LENGTH) - user);
29
set_password(password);
32
int User::init(const char *line)
34
const char *name_begin, *name_end, *password;
37
if (line[0] == '\'' || line[0] == '"')
40
name_end= strchr(name_begin, line[0]);
41
if (name_end == 0 || name_end[1] != ':')
43
log_error("Invalid format (unmatched quote) of user line (%s).",
47
password= name_end + 2;
52
name_end= strchr(name_begin, ':');
55
log_error("Invalid format (no delimiter) of user line (%s).",
59
password= name_end + 1;
62
user_length= (uint8) (name_end - name_begin);
63
if (user_length > USERNAME_LENGTH)
65
log_error("User name is too long (%d). Max length: %d. "
68
(int) USERNAME_LENGTH,
73
password_length= (int) strlen(password);
74
if (password_length > SCRAMBLED_PASSWORD_CHAR_LENGTH)
76
log_error("Password is too long (%d). Max length: %d."
78
(int) password_length,
79
(int) SCRAMBLED_PASSWORD_CHAR_LENGTH,
84
memcpy(user, name_begin, user_length);
87
memcpy(scrambled_password, password, password_length);
88
scrambled_password[password_length]= 0;
90
get_salt_from_password(salt, password);
92
log_info("Loaded user '%s'.", (const char *) user);
100
static uchar* get_user_key(const uchar* u, size_t* len,
101
my_bool __attribute__((unused)) t)
103
const User *user= (const User *) u;
104
*len= user->user_length;
105
return (uchar *) user->user;
108
static void delete_user(void *u)
110
User *user= (User *) u;
117
void User_map::Iterator::reset()
123
User *User_map::Iterator::next()
125
if (cur_idx < user_map->hash.records)
126
return (User *) hash_element(&user_map->hash, cur_idx++);
134
enum { START_HASH_SIZE= 16 };
135
if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
136
get_user_key, delete_user, 0))
151
User_map::~User_map()
159
Load password database.
163
password_file_name [IN] password file path
164
err_msg [OUT] error message
167
Load all users from the password file. Must be called once right after
168
construction. In case of failure, puts error message to the log file and
169
returns specific error code.
176
int User_map::load(const char *password_file_name, const char **err_msg)
178
static const int ERR_MSG_BUF_SIZE = 255;
179
static char err_msg_buf[ERR_MSG_BUF_SIZE];
182
char line[USERNAME_LENGTH + SCRAMBLED_PASSWORD_CHAR_LENGTH +
183
2 + /* for possible quotes */
185
2 + /* for newline */
186
1]; /* for trailing zero */
189
if (my_access(password_file_name, F_OK) != 0)
193
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
194
"password file (%s) does not exist",
195
(const char *) password_file_name);
196
*err_msg= err_msg_buf;
199
return ERR_PASSWORD_FILE_DOES_NOT_EXIST;
202
if ((file= my_fopen(password_file_name, O_RDONLY | O_BINARY, MYF(0))) == 0)
206
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
207
"can not open password file (%s): %s",
208
(const char *) password_file_name,
209
(const char *) strerror(errno));
210
*err_msg= err_msg_buf;
216
log_info("Loading the password database...");
218
while (fgets(line, sizeof(line), file))
220
char *user_line= line;
223
We need to skip EOL-symbols also from the beginning of the line, because
224
if the previous line was ended by \n\r sequence, we get \r in our line.
227
while (user_line[0] == '\r' || user_line[0] == '\n')
230
/* Skip EOL-symbols in the end of the line. */
235
if ((ptr= strchr(user_line, '\n')))
238
if ((ptr= strchr(user_line, '\r')))
242
/* skip comments and empty lines */
243
if (!user_line[0] || user_line[0] == '#')
246
if ((user= new User) == 0)
248
my_fclose(file, MYF(0));
252
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
253
"out of memory while parsing password file (%s)",
254
(const char *) password_file_name);
255
*err_msg= err_msg_buf;
258
return ERR_OUT_OF_MEMORY;
261
if (user->init(user_line))
264
my_fclose(file, MYF(0));
268
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
269
"password file (%s) corrupted",
270
(const char *) password_file_name);
271
*err_msg= err_msg_buf;
274
return ERR_PASSWORD_FILE_CORRUPTED;
277
if (my_hash_insert(&hash, (uchar *) user))
280
my_fclose(file, MYF(0));
284
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
285
"out of memory while parsing password file (%s)",
286
(const char *) password_file_name);
287
*err_msg= err_msg_buf;
290
return ERR_OUT_OF_MEMORY;
294
log_info("The password database loaded successfully.");
296
my_fclose(file, MYF(0));
305
int User_map::save(const char *password_file_name, const char **err_msg)
307
static const int ERR_MSG_BUF_SIZE = 255;
308
static char err_msg_buf[ERR_MSG_BUF_SIZE];
312
if ((file= my_fopen(password_file_name, O_WRONLY | O_TRUNC | O_BINARY,
317
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
318
"can not open password file (%s) for writing: %s",
319
(const char *) password_file_name,
320
(const char *) strerror(errno));
321
*err_msg= err_msg_buf;
328
User_map::Iterator it(this);
331
while ((user= it.next()))
333
if (fprintf(file, "%s:%s\n", (const char *) user->user,
334
(const char *) user->scrambled_password) < 0)
338
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
339
"can not write to password file (%s): %s",
340
(const char *) password_file_name,
341
(const char *) strerror(errno));
342
*err_msg= err_msg_buf;
345
my_fclose(file, MYF(0));
352
my_fclose(file, MYF(0));
359
Check if user exists and password is correct
361
0 - user found and password OK
362
1 - password mismatch
366
int User_map::authenticate(const LEX_STRING *user_name,
367
const char *scrambled_password,
368
const char *scramble) const
370
const User *user= find_user(user_name);
371
return user ? check_scramble(scrambled_password, scramble, user->salt) : 2;
375
User *User_map::find_user(const LEX_STRING *user_name)
377
return (User*) hash_search(&hash, (uchar*) user_name->str, user_name->length);
380
const User *User_map::find_user(const LEX_STRING *user_name) const
382
return const_cast<User_map *> (this)->find_user(user_name);
386
bool User_map::add_user(User *user)
388
return my_hash_insert(&hash, (uchar*) user) == 0 ? FALSE : TRUE;
392
bool User_map::remove_user(User *user)
394
return hash_delete(&hash, (uchar*) user) == 0 ? FALSE : TRUE;