~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to server-tools/instance-manager/user_map.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2004-2006 MySQL AB
 
2
 
 
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.
 
6
 
 
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.
 
11
 
 
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 */
 
15
 
 
16
#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
 
17
#pragma implementation
 
18
#endif
 
19
 
 
20
#include "user_map.h"
 
21
#include "exit_codes.h"
 
22
#include "log.h"
 
23
#include "portability.h"
 
24
 
 
25
User::User(const LEX_STRING *user_name_arg, const char *password)
 
26
{
 
27
  user_length= (uint8) (strmake(user, user_name_arg->str,
 
28
                                USERNAME_LENGTH) - user);
 
29
  set_password(password);
 
30
}
 
31
 
 
32
int User::init(const char *line)
 
33
{
 
34
  const char *name_begin, *name_end, *password;
 
35
  int password_length;
 
36
 
 
37
  if (line[0] == '\'' || line[0] == '"')
 
38
  {
 
39
    name_begin= line + 1;
 
40
    name_end= strchr(name_begin, line[0]);
 
41
    if (name_end == 0 || name_end[1] != ':')
 
42
    {
 
43
      log_error("Invalid format (unmatched quote) of user line (%s).",
 
44
                (const char *) line);
 
45
      return 1;
 
46
    }
 
47
    password= name_end + 2;
 
48
  }
 
49
  else
 
50
  {
 
51
    name_begin= line;
 
52
    name_end= strchr(name_begin, ':');
 
53
    if (name_end == 0)
 
54
    {
 
55
      log_error("Invalid format (no delimiter) of user line (%s).",
 
56
                (const char *) line);
 
57
      return 1;
 
58
    }
 
59
    password= name_end + 1;
 
60
  }
 
61
 
 
62
  user_length= (uint8) (name_end - name_begin);
 
63
  if (user_length > USERNAME_LENGTH)
 
64
  {
 
65
    log_error("User name is too long (%d). Max length: %d. "
 
66
              "User line: '%s'.",
 
67
              (int) user_length,
 
68
              (int) USERNAME_LENGTH,
 
69
              (const char *) line);
 
70
    return 1;
 
71
  }
 
72
 
 
73
  password_length= (int) strlen(password);
 
74
  if (password_length > SCRAMBLED_PASSWORD_CHAR_LENGTH)
 
75
  {
 
76
    log_error("Password is too long (%d). Max length: %d."
 
77
              "User line: '%s'.",
 
78
              (int) password_length,
 
79
              (int) SCRAMBLED_PASSWORD_CHAR_LENGTH,
 
80
              (const char *) line);
 
81
    return 1;
 
82
  }
 
83
 
 
84
  memcpy(user, name_begin, user_length);
 
85
  user[user_length]= 0;
 
86
 
 
87
  memcpy(scrambled_password, password, password_length);
 
88
  scrambled_password[password_length]= 0;
 
89
 
 
90
  get_salt_from_password(salt, password);
 
91
 
 
92
  log_info("Loaded user '%s'.", (const char *) user);
 
93
 
 
94
  return 0;
 
95
}
 
96
 
 
97
 
 
98
C_MODE_START
 
99
 
 
100
static uchar* get_user_key(const uchar* u, size_t* len,
 
101
                           my_bool __attribute__((unused)) t)
 
102
{
 
103
  const User *user= (const User *) u;
 
104
  *len= user->user_length;
 
105
  return (uchar *) user->user;
 
106
}
 
107
 
 
108
static void delete_user(void *u)
 
109
{
 
110
  User *user= (User *) u;
 
111
  delete user;
 
112
}
 
113
 
 
114
C_MODE_END
 
115
 
 
116
 
 
117
void User_map::Iterator::reset()
 
118
{
 
119
  cur_idx= 0;
 
120
}
 
121
 
 
122
 
 
123
User *User_map::Iterator::next()
 
124
{
 
125
  if (cur_idx < user_map->hash.records)
 
126
    return (User *) hash_element(&user_map->hash, cur_idx++);
 
127
 
 
128
  return NULL;
 
129
}
 
130
 
 
131
 
 
132
int User_map::init()
 
133
{
 
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))
 
137
    return 1;
 
138
 
 
139
  initialized= TRUE;
 
140
 
 
141
  return 0;
 
142
}
 
143
 
 
144
 
 
145
User_map::User_map()
 
146
  :initialized(FALSE)
 
147
{
 
148
}
 
149
 
 
150
 
 
151
User_map::~User_map()
 
152
{
 
153
  if (initialized)
 
154
    hash_free(&hash);
 
155
}
 
156
 
 
157
 
 
158
/*
 
159
  Load password database.
 
160
 
 
161
  SYNOPSIS
 
162
    load()
 
163
    password_file_name  [IN] password file path
 
164
    err_msg             [OUT] error message
 
165
 
 
166
  DESCRIPTION
 
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.
 
170
 
 
171
  RETURN
 
172
    0   on success
 
173
    !0  on error
 
174
*/
 
175
 
 
176
int User_map::load(const char *password_file_name, const char **err_msg)
 
177
{
 
178
  static const int ERR_MSG_BUF_SIZE = 255;
 
179
  static char err_msg_buf[ERR_MSG_BUF_SIZE];
 
180
 
 
181
  FILE *file;
 
182
  char line[USERNAME_LENGTH + SCRAMBLED_PASSWORD_CHAR_LENGTH +
 
183
            2 +                               /* for possible quotes */
 
184
            1 +                               /* for ':' */
 
185
            2 +                               /* for newline */
 
186
            1];                               /* for trailing zero */
 
187
  User *user;
 
188
 
 
189
  if (my_access(password_file_name, F_OK) != 0)
 
190
  {
 
191
    if (err_msg)
 
192
    {
 
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;
 
197
    }
 
198
 
 
199
    return ERR_PASSWORD_FILE_DOES_NOT_EXIST;
 
200
  }
 
201
 
 
202
  if ((file= my_fopen(password_file_name, O_RDONLY | O_BINARY, MYF(0))) == 0)
 
203
  {
 
204
    if (err_msg)
 
205
    {
 
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;
 
211
    }
 
212
 
 
213
    return ERR_IO_ERROR;
 
214
  }
 
215
 
 
216
  log_info("Loading the password database...");
 
217
 
 
218
  while (fgets(line, sizeof(line), file))
 
219
  {
 
220
    char *user_line= line;
 
221
 
 
222
    /*
 
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.
 
225
    */
 
226
 
 
227
    while (user_line[0] == '\r' || user_line[0] == '\n')
 
228
      ++user_line;
 
229
 
 
230
    /* Skip EOL-symbols in the end of the line. */
 
231
 
 
232
    {
 
233
      char *ptr;
 
234
 
 
235
      if ((ptr= strchr(user_line, '\n')))
 
236
        *ptr= 0;
 
237
 
 
238
      if ((ptr= strchr(user_line, '\r')))
 
239
        *ptr= 0;
 
240
    }
 
241
 
 
242
    /* skip comments and empty lines */
 
243
    if (!user_line[0] || user_line[0] == '#')
 
244
      continue;
 
245
 
 
246
    if ((user= new User) == 0)
 
247
    {
 
248
      my_fclose(file, MYF(0));
 
249
 
 
250
      if (err_msg)
 
251
      {
 
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;
 
256
      }
 
257
 
 
258
      return ERR_OUT_OF_MEMORY;
 
259
    }
 
260
 
 
261
    if (user->init(user_line))
 
262
    {
 
263
      delete user;
 
264
      my_fclose(file, MYF(0));
 
265
 
 
266
      if (err_msg)
 
267
      {
 
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;
 
272
      }
 
273
 
 
274
      return ERR_PASSWORD_FILE_CORRUPTED;
 
275
    }
 
276
 
 
277
    if (my_hash_insert(&hash, (uchar *) user))
 
278
    {
 
279
      delete user;
 
280
      my_fclose(file, MYF(0));
 
281
 
 
282
      if (err_msg)
 
283
      {
 
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;
 
288
      }
 
289
 
 
290
      return ERR_OUT_OF_MEMORY;
 
291
    }
 
292
  }
 
293
 
 
294
  log_info("The password database loaded successfully.");
 
295
 
 
296
  my_fclose(file, MYF(0));
 
297
 
 
298
  if (err_msg)
 
299
    *err_msg= NULL;
 
300
 
 
301
  return ERR_OK;
 
302
}
 
303
 
 
304
 
 
305
int User_map::save(const char *password_file_name, const char **err_msg)
 
306
{
 
307
  static const int ERR_MSG_BUF_SIZE = 255;
 
308
  static char err_msg_buf[ERR_MSG_BUF_SIZE];
 
309
 
 
310
  FILE *file;
 
311
 
 
312
  if ((file= my_fopen(password_file_name, O_WRONLY | O_TRUNC | O_BINARY,
 
313
                      MYF(0))) == 0)
 
314
  {
 
315
    if (err_msg)
 
316
    {
 
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;
 
322
    }
 
323
 
 
324
    return ERR_IO_ERROR;
 
325
  }
 
326
 
 
327
  {
 
328
    User_map::Iterator it(this);
 
329
    User *user;
 
330
 
 
331
    while ((user= it.next()))
 
332
    {
 
333
      if (fprintf(file, "%s:%s\n", (const char *) user->user,
 
334
                  (const char *) user->scrambled_password) < 0)
 
335
      {
 
336
        if (err_msg)
 
337
        {
 
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;
 
343
        }
 
344
 
 
345
        my_fclose(file, MYF(0));
 
346
 
 
347
        return ERR_IO_ERROR;
 
348
      }
 
349
    }
 
350
  }
 
351
 
 
352
  my_fclose(file, MYF(0));
 
353
 
 
354
  return ERR_OK;
 
355
}
 
356
 
 
357
 
 
358
/*
 
359
    Check if user exists and password is correct
 
360
  RETURN VALUE
 
361
    0 - user found and password OK
 
362
    1 - password mismatch
 
363
    2 - user not found
 
364
*/
 
365
 
 
366
int User_map::authenticate(const LEX_STRING *user_name,
 
367
                           const char *scrambled_password,
 
368
                           const char *scramble) const
 
369
{
 
370
  const User *user= find_user(user_name);
 
371
  return user ? check_scramble(scrambled_password, scramble, user->salt) : 2;
 
372
}
 
373
 
 
374
 
 
375
User *User_map::find_user(const LEX_STRING *user_name)
 
376
{
 
377
  return (User*) hash_search(&hash, (uchar*) user_name->str, user_name->length);
 
378
}
 
379
 
 
380
const User *User_map::find_user(const LEX_STRING *user_name) const
 
381
{
 
382
  return const_cast<User_map *> (this)->find_user(user_name);
 
383
}
 
384
 
 
385
 
 
386
bool User_map::add_user(User *user)
 
387
{
 
388
  return my_hash_insert(&hash, (uchar*) user) == 0 ? FALSE : TRUE;
 
389
}
 
390
 
 
391
 
 
392
bool User_map::remove_user(User *user)
 
393
{
 
394
  return hash_delete(&hash, (uchar*) user) == 0 ? FALSE : TRUE;
 
395
}