~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/sql_connect.cc

  • Committer: Brian Aker
  • Date: 2008-07-07 16:07:49 UTC
  • mfrom: (80.1.1 food)
  • Revision ID: brian@tangent.org-20080707160749-qj89fnnwufz4xgop
Clean up install, we no longer have system tables.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
/*
18
18
  Functions to autenticate and handle reqests for a connection
19
19
*/
20
 
#include <drizzled/server_includes.h>
21
 
#include <drizzled/authentication.h>
22
 
#include <drizzled/drizzled_error_messages.h>
 
20
 
 
21
#include "mysql_priv.h"
23
22
 
24
23
#define MIN_HANDSHAKE_SIZE      6
25
24
 
40
39
                         NULL, 0, NI_NUMERICHOST);
41
40
  if (gxi_error)
42
41
  {
 
42
    DBUG_PRINT("error",("getnameinfo returned %d", gxi_error));
43
43
    return NULL;
44
44
  }
 
45
  DBUG_PRINT("info",("resolved: %s", hostname_buff));
45
46
 
46
47
  if (!(name= my_strdup(hostname_buff, MYF(0))))
47
48
  {
 
49
    DBUG_PRINT("error",("out of memory"));
48
50
    return NULL;
49
51
  }
50
52
 
61
63
  @param  passwd      scrambled password received from client
62
64
  @param  passwd_len  length of scrambled password
63
65
  @param  db          database name to connect to, may be NULL
64
 
  @param  check_count true if establishing a new connection. In this case
 
66
  @param  check_count TRUE if establishing a new connection. In this case
65
67
                      check that we have not exceeded the global
66
68
                      max_connections limist
67
69
 
70
72
  should be done with this in mind; 'thd' is INOUT, all other params
71
73
  are 'IN'.
72
74
 
73
 
  @retval  0  OK
 
75
  @retval  0  OK; thd->security_ctx->user/master_access/priv_user/db_access and
 
76
              thd->db are updated; OK is sent to the client.
74
77
  @retval  1  error, e.g. access denied or handshake error, not sent to
75
78
              the client. A message is pushed into the error stack.
76
79
*/
77
80
 
78
81
int
79
 
check_user(THD *thd, const char *passwd,
80
 
           uint32_t passwd_len, const char *db,
81
 
           bool check_count)
 
82
check_user(THD *thd, enum enum_server_command command,
 
83
               const char *passwd, uint passwd_len, const char *db,
 
84
               bool check_count)
82
85
{
 
86
  DBUG_ENTER("check_user");
83
87
  LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
84
 
  bool is_authenticated;
85
88
 
86
89
  /*
87
90
    Clear thd->db as it points to something, that will be freed when
91
94
  */
92
95
  thd->reset_db(NULL, 0);
93
96
 
94
 
  if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH)
95
 
  {
96
 
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.ip);
97
 
    return(1);
98
 
  }
99
 
 
100
 
  is_authenticated= authenticate_user(thd, passwd);
101
 
 
102
 
  if (is_authenticated != true)
103
 
  {
104
 
    my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
105
 
             thd->main_security_ctx.user,
106
 
             thd->main_security_ctx.ip,
107
 
             passwd_len ? ER(ER_YES) : ER(ER_NO));
108
 
 
109
 
    return 1;
110
 
  }
111
 
 
 
97
  my_bool opt_secure_auth_local;
 
98
  pthread_mutex_lock(&LOCK_global_system_variables);
 
99
  opt_secure_auth_local= opt_secure_auth;
 
100
  pthread_mutex_unlock(&LOCK_global_system_variables);
 
101
 
 
102
  /*
 
103
    If the server is running in secure auth mode, short scrambles are 
 
104
    forbidden.
 
105
  */
 
106
  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
 
107
  {
 
108
    my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
 
109
    general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
 
110
    DBUG_RETURN(1);
 
111
  }
 
112
  if (passwd_len != 0 &&
 
113
      passwd_len != SCRAMBLE_LENGTH &&
 
114
      passwd_len != SCRAMBLE_LENGTH_323)
 
115
  {
 
116
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
 
117
    DBUG_RETURN(1);
 
118
  }
112
119
 
113
120
  USER_RESOURCES ur;
114
121
  thd->security_ctx->skip_grants();
115
122
  memset(&ur, 0, sizeof(USER_RESOURCES));
116
123
 
 
124
  DBUG_PRINT("info",
 
125
             ("Capabilities: %lu  packet_length: %ld  Host: '%s'  "
 
126
              "Login user: '%s' Priv_user: '%s'  Using password: %s "
 
127
              "db: '%s'",
 
128
              thd->client_capabilities,
 
129
              thd->max_client_packet_length,
 
130
              thd->main_security_ctx.host_or_ip,
 
131
              thd->main_security_ctx.user,
 
132
              thd->main_security_ctx.priv_user,
 
133
              passwd_len ? "yes": "no",
 
134
              (thd->db ? thd->db : "*none*")));
 
135
 
117
136
  if (check_count)
118
137
  {
119
138
    pthread_mutex_lock(&LOCK_connection_count);
120
139
    bool count_ok= connection_count <= max_connections;
121
 
    pthread_mutex_unlock(&LOCK_connection_count);
 
140
    VOID(pthread_mutex_unlock(&LOCK_connection_count));
122
141
 
123
142
    if (!count_ok)
124
143
    {                                         // too many connections
125
144
      my_error(ER_CON_COUNT_ERROR, MYF(0));
126
 
      return(1);
 
145
      DBUG_RETURN(1);
127
146
    }
128
147
  }
129
148
 
 
149
  /*
 
150
    Log the command before authentication checks, so that the user can
 
151
    check the log for the tried login tried and also to detect
 
152
    break-in attempts.
 
153
  */
 
154
  general_log_print(thd, command,
 
155
                    (thd->main_security_ctx.priv_user ==
 
156
                     thd->main_security_ctx.user ?
 
157
                     (char*) "%s@%s on %s" :
 
158
                     (char*) "%s@%s as anonymous on %s"),
 
159
                    thd->main_security_ctx.user,
 
160
                    thd->main_security_ctx.host_or_ip,
 
161
                    db ? db : (char*) "");
 
162
 
 
163
  /*
 
164
    This is the default access rights for the current database.  It's
 
165
    set to 0 here because we don't have an active database yet (and we
 
166
    may not have an active database to set.
 
167
  */
 
168
  thd->main_security_ctx.db_access=0;
 
169
 
130
170
  /* Change database if necessary */
131
171
  if (db && db[0])
132
172
  {
133
 
    if (mysql_change_db(thd, &db_str, false))
 
173
    if (mysql_change_db(thd, &db_str, FALSE))
134
174
    {
135
175
      /* mysql_change_db() has pushed the error message. */
136
 
      return(1);
 
176
      DBUG_RETURN(1);
137
177
    }
138
178
  }
139
179
  my_ok(thd);
140
180
  thd->password= test(passwd_len);          // remember for error messages 
141
181
  /* Ready to handle queries */
142
 
  return(0);
 
182
  DBUG_RETURN(0);
143
183
}
144
184
 
145
185
 
148
188
  started with corresponding variable that is greater then 0.
149
189
*/
150
190
 
151
 
extern "C" unsigned char *get_key_conn(user_conn *buff, size_t *length,
152
 
                               bool not_used __attribute__((unused)))
 
191
extern "C" uchar *get_key_conn(user_conn *buff, size_t *length,
 
192
                              my_bool not_used __attribute__((unused)))
153
193
{
154
194
  *length= buff->len;
155
 
  return (unsigned char*) buff->user;
 
195
  return (uchar*) buff->user;
156
196
}
157
197
 
158
198
 
159
199
extern "C" void free_user(struct user_conn *uc)
160
200
{
161
 
  free((char*) uc);
 
201
  my_free((char*) uc,MYF(0));
162
202
}
163
203
 
164
 
void thd_init_client_charset(THD *thd, uint32_t cs_number)
 
204
void thd_init_client_charset(THD *thd, uint cs_number)
165
205
{
166
206
  /*
167
207
   Use server character set and collation if
172
212
  */
173
213
  if (!opt_character_set_client_handshake ||
174
214
      !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
175
 
      !my_strcasecmp(&my_charset_utf8_general_ci,
 
215
      !my_strcasecmp(&my_charset_latin1,
176
216
                     global_system_variables.character_set_client->name,
177
217
                     thd->variables.character_set_client->name))
178
218
  {
221
261
static int check_connection(THD *thd)
222
262
{
223
263
  NET *net= &thd->net;
224
 
  uint32_t pkt_len= 0;
 
264
  ulong pkt_len= 0;
225
265
  char *end;
226
266
 
227
 
  // TCP/IP connection
 
267
  DBUG_PRINT("info",
 
268
             ("New connection received on %s", vio_description(net->vio)));
 
269
#ifdef SIGNAL_WITH_VIO_CLOSE
 
270
  thd->set_active_vio(net->vio);
 
271
#endif
 
272
 
 
273
  if (!thd->main_security_ctx.host)         // If TCP/IP connection
228
274
  {
229
275
    char ip[NI_MAXHOST];
230
276
 
231
 
    if (net_peer_addr(net, ip, &thd->peer_port, NI_MAXHOST))
 
277
    if (vio_peer_addr(net->vio, ip, &thd->peer_port, NI_MAXHOST))
232
278
    {
233
 
      my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.ip);
 
279
      my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
234
280
      return 1;
235
281
    }
236
282
    if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
237
283
      return 1; /* The error is set by my_strdup(). */
238
 
  }
239
 
  net_keepalive(net, true);
 
284
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
 
285
    thd->main_security_ctx.host= ip_to_hostname(&net->vio->remote, 
 
286
                                                net->vio->addrLen);
 
287
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
 
288
    DBUG_PRINT("info",("Host: %s  ip: %s",
 
289
                       (thd->main_security_ctx.host ?
 
290
                        thd->main_security_ctx.host : "unknown host"),
 
291
                       (thd->main_security_ctx.ip ?
 
292
                        thd->main_security_ctx.ip : "unknown ip")));
 
293
  }
 
294
  else /* Hostname given means that the connection was on a socket */
 
295
  {
 
296
    DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
 
297
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
 
298
    thd->main_security_ctx.ip= 0;
 
299
    /* Reset sin_addr */
 
300
    bzero((char*) &net->vio->remote, sizeof(net->vio->remote));
 
301
  }
 
302
  vio_keepalive(net->vio, TRUE);
240
303
  
241
 
  uint32_t server_capabilites;
 
304
  ulong server_capabilites;
242
305
  {
243
306
    /* buff[] needs to big enough to hold the server_version variable */
244
307
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
250
313
    server_capabilites|= CLIENT_COMPRESS;
251
314
#endif /* HAVE_COMPRESS */
252
315
 
253
 
    end= my_stpncpy(buff, server_version, SERVER_VERSION_LENGTH) + 1;
254
 
    int4store((unsigned char*) end, thd->thread_id);
 
316
    end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
 
317
    int4store((uchar*) end, thd->thread_id);
255
318
    end+= 4;
256
319
    /*
257
320
      So as check_connection is the only entry point to authorization
270
333
    /* write server characteristics: up to 16 bytes allowed */
271
334
    end[2]=(char) default_charset_info->number;
272
335
    int2store(end+3, thd->server_status);
273
 
    memset(end+5, 0, 13);
 
336
    bzero(end+5, 13);
274
337
    end+= 18;
275
338
    /* write scramble tail */
276
339
    end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, 
277
340
                 SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
278
341
 
279
342
    /* At this point we write connection message and read reply */
280
 
    if (net_write_command(net, (unsigned char) protocol_version, (unsigned char*) "", 0,
281
 
                          (unsigned char*) buff, (size_t) (end-buff)) ||
 
343
    if (net_write_command(net, (uchar) protocol_version, (uchar*) "", 0,
 
344
                          (uchar*) buff, (size_t) (end-buff)) ||
282
345
        (pkt_len= my_net_read(net)) == packet_error ||
283
346
        pkt_len < MIN_HANDSHAKE_SIZE)
284
347
    {
285
348
      my_error(ER_HANDSHAKE_ERROR, MYF(0),
286
 
               thd->main_security_ctx.ip);
 
349
               thd->main_security_ctx.host_or_ip);
287
350
      return 1;
288
351
    }
289
352
  }
 
353
#ifdef _CUSTOMCONFIG_
 
354
#include "_cust_sql_parse.h"
 
355
#endif
290
356
  if (thd->packet.alloc(thd->variables.net_buffer_length))
291
357
    return 1; /* The error is set by alloc(). */
292
358
 
293
359
  thd->client_capabilities= uint2korr(net->read_pos);
294
 
 
295
 
 
296
 
  thd->client_capabilities|= ((uint32_t) uint2korr(net->read_pos+2)) << 16;
297
 
  thd->max_client_packet_length= uint4korr(net->read_pos+4);
298
 
  thd_init_client_charset(thd, (uint) net->read_pos[8]);
299
 
  thd->update_charset();
300
 
  end= (char*) net->read_pos+32;
301
 
 
 
360
  if (thd->client_capabilities & CLIENT_PROTOCOL_41)
 
361
  {
 
362
    thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
 
363
    thd->max_client_packet_length= uint4korr(net->read_pos+4);
 
364
    DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
 
365
    thd_init_client_charset(thd, (uint) net->read_pos[8]);
 
366
    thd->update_charset();
 
367
    end= (char*) net->read_pos+32;
 
368
  }
 
369
  else
 
370
  {
 
371
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
 
372
    end= (char*) net->read_pos+5;
 
373
  }
302
374
  /*
303
375
    Disable those bits which are not supported by the server.
304
376
    This is a precautionary measure, if the client lies. See Bug#27944.
305
377
  */
306
378
  thd->client_capabilities&= server_capabilites;
307
379
 
 
380
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
 
381
    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
 
382
 
308
383
  if (end >= (char*) net->read_pos+ pkt_len +2)
309
384
  {
310
385
 
311
 
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.ip);
 
386
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
312
387
    return 1;
313
388
  }
314
389
 
319
394
    net->return_status= &thd->server_status;
320
395
 
321
396
  char *user= end;
322
 
  char *passwd= strchr(user, '\0')+1;
323
 
  uint32_t user_len= passwd - user - 1;
 
397
  char *passwd= strend(user)+1;
 
398
  uint user_len= passwd - user - 1;
324
399
  char *db= passwd;
325
400
  char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
326
401
  char user_buff[USERNAME_LENGTH + 1];  // buffer to store user in utf8
327
 
  uint32_t dummy_errors;
 
402
  uint dummy_errors;
328
403
 
329
404
  /*
330
405
    Old clients send null-terminated string as password; new clients send
336
411
    Cast *passwd to an unsigned char, so that it doesn't extend the sign for
337
412
    *passwd > 127 and become 2**32-127+ after casting to uint.
338
413
  */
339
 
  uint32_t passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
340
 
    (unsigned char)(*passwd++) : strlen(passwd);
 
414
  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
 
415
    (uchar)(*passwd++) : strlen(passwd);
341
416
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
342
417
    db + passwd_len + 1 : 0;
343
418
  /* strlen() can't be easily deleted without changing protocol */
344
 
  uint32_t db_len= db ? strlen(db) : 0;
 
419
  uint db_len= db ? strlen(db) : 0;
345
420
 
346
421
  if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
347
422
  {
348
 
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.ip);
 
423
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
349
424
    return 1;
350
425
  }
351
426
 
373
448
  }
374
449
 
375
450
  if (thd->main_security_ctx.user)
376
 
    if (thd->main_security_ctx.user)
377
 
      free(thd->main_security_ctx.user);
 
451
    x_free(thd->main_security_ctx.user);
378
452
  if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME))))
379
453
    return 1; /* The error is set by my_strdup(). */
380
 
  return check_user(thd, passwd, passwd_len, db, true);
 
454
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
381
455
}
382
456
 
383
457
 
427
501
{
428
502
  NET *net= &thd->net;
429
503
  int error;
 
504
  DBUG_ENTER("login_connection");
 
505
  DBUG_PRINT("info", ("login_connection called by thread %lu",
 
506
                      thd->thread_id));
430
507
 
431
508
  /* Use "connect_timeout" value during connection phase */
432
509
  my_net_set_read_timeout(net, connect_timeout);
440
517
  if (error)
441
518
  {                                             // Wrong permissions
442
519
    statistic_increment(aborted_connects,&LOCK_status);
443
 
    return(1);
 
520
    DBUG_RETURN(1);
444
521
  }
445
522
  /* Connect completed, set read/write timeouts back to default */
446
523
  my_net_set_read_timeout(net, thd->variables.net_read_timeout);
447
524
  my_net_set_write_timeout(net, thd->variables.net_write_timeout);
448
 
  return(0);
 
525
  DBUG_RETURN(0);
449
526
}
450
527
 
451
528
 
475
552
      sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
476
553
                        thd->thread_id,(thd->db ? thd->db : "unconnected"),
477
554
                        sctx->user ? sctx->user : "unauthenticated",
478
 
                        sctx->ip,
 
555
                        sctx->host_or_ip,
479
556
                        (thd->main_da.is_error() ? thd->main_da.message() :
480
557
                         ER(ER_UNKNOWN_ERROR)));
481
558
    }
502
579
    TODO: refactor this to avoid code duplication there
503
580
  */
504
581
  thd->version= refresh_version;
505
 
  thd->set_proc_info(0);
 
582
  thd->proc_info= 0;
506
583
  thd->command= COM_SLEEP;
507
584
  thd->set_time();
508
585
  thd->init_for_queries();
517
594
      sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
518
595
                        thd->thread_id,(thd->db ? thd->db : "unconnected"),
519
596
                        sctx->user ? sctx->user : "unauthenticated",
520
 
                        sctx->ip, "init_connect command failed");
 
597
                        sctx->host_or_ip, "init_connect command failed");
521
598
      sql_print_warning("%s", thd->main_da.message());
522
599
    }
523
 
    thd->set_proc_info(0);
 
600
    thd->proc_info=0;
524
601
    thd->set_time();
525
602
    thd->init_for_queries();
526
603
  }
547
624
pthread_handler_t handle_one_connection(void *arg)
548
625
{
549
626
  THD *thd= (THD*) arg;
550
 
  uint32_t launch_time= (uint32_t) ((thd->thr_create_utime= my_micro_time()) -
 
627
  ulong launch_time= (ulong) ((thd->thr_create_utime= my_micro_time()) -
551
628
                              thd->connect_utime);
552
629
 
553
630
  if (thread_scheduler.init_new_connection_thread())