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

« back to all changes in this revision

Viewing changes to sql/sql_connect.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) 2007 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
 
 
17
/*
 
18
  Functions to autenticate and handle reqests for a connection
 
19
*/
 
20
 
 
21
#include "mysql_priv.h"
 
22
 
 
23
#ifdef HAVE_OPENSSL
 
24
/*
 
25
  Without SSL the handshake consists of one packet. This packet
 
26
  has both client capabilites and scrambled password.
 
27
  With SSL the handshake might consist of two packets. If the first
 
28
  packet (client capabilities) has CLIENT_SSL flag set, we have to
 
29
  switch to SSL and read the second packet. The scrambled password
 
30
  is in the second packet and client_capabilites field will be ignored.
 
31
  Maybe it is better to accept flags other than CLIENT_SSL from the
 
32
  second packet?
 
33
*/
 
34
#define SSL_HANDSHAKE_SIZE      2
 
35
#define NORMAL_HANDSHAKE_SIZE   6
 
36
#define MIN_HANDSHAKE_SIZE      2
 
37
#else
 
38
#define MIN_HANDSHAKE_SIZE      6
 
39
#endif /* HAVE_OPENSSL */
 
40
 
 
41
#ifdef __WIN__
 
42
extern void win_install_sigabrt_handler();
 
43
#endif
 
44
 
 
45
/*
 
46
  Get structure for logging connection data for the current user
 
47
*/
 
48
 
 
49
#ifndef NO_EMBEDDED_ACCESS_CHECKS
 
50
static HASH hash_user_connections;
 
51
 
 
52
static int get_or_create_user_conn(THD *thd, const char *user,
 
53
                                   const char *host,
 
54
                                   USER_RESOURCES *mqh)
 
55
{
 
56
  int return_val= 0;
 
57
  size_t temp_len, user_len;
 
58
  char temp_user[USER_HOST_BUFF_SIZE];
 
59
  struct  user_conn *uc;
 
60
 
 
61
  DBUG_ASSERT(user != 0);
 
62
  DBUG_ASSERT(host != 0);
 
63
 
 
64
  user_len= strlen(user);
 
65
  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
 
66
  (void) pthread_mutex_lock(&LOCK_user_conn);
 
67
  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
 
68
                                               (uchar*) temp_user, temp_len)))
 
69
  {
 
70
    /* First connection for user; Create a user connection object */
 
71
    if (!(uc= ((struct user_conn*)
 
72
               my_malloc(sizeof(struct user_conn) + temp_len+1,
 
73
                         MYF(MY_WME)))))
 
74
    {
 
75
      /* MY_WME ensures an error is set in THD. */
 
76
      return_val= 1;
 
77
      goto end;
 
78
    }
 
79
    uc->user=(char*) (uc+1);
 
80
    memcpy(uc->user,temp_user,temp_len+1);
 
81
    uc->host= uc->user + user_len +  1;
 
82
    uc->len= temp_len;
 
83
    uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
 
84
    uc->user_resources= *mqh;
 
85
    uc->reset_utime= thd->thr_create_utime;
 
86
    if (my_hash_insert(&hash_user_connections, (uchar*) uc))
 
87
    {
 
88
      /* The only possible error is out of memory, MY_WME sets an error. */
 
89
      my_free((char*) uc,0);
 
90
      return_val= 1;
 
91
      goto end;
 
92
    }
 
93
  }
 
94
  thd->user_connect=uc;
 
95
  uc->connections++;
 
96
end:
 
97
  (void) pthread_mutex_unlock(&LOCK_user_conn);
 
98
  return return_val;
 
99
 
 
100
}
 
101
 
 
102
 
 
103
/*
 
104
  check if user has already too many connections
 
105
  
 
106
  SYNOPSIS
 
107
  check_for_max_user_connections()
 
108
  thd                   Thread handle
 
109
  uc                    User connect object
 
110
 
 
111
  NOTES
 
112
    If check fails, we decrease user connection count, which means one
 
113
    shouldn't call decrease_user_connections() after this function.
 
114
 
 
115
  RETURN
 
116
    0   ok
 
117
    1   error
 
118
*/
 
119
 
 
120
static
 
121
int check_for_max_user_connections(THD *thd, USER_CONN *uc)
 
122
{
 
123
  int error=0;
 
124
  DBUG_ENTER("check_for_max_user_connections");
 
125
 
 
126
  (void) pthread_mutex_lock(&LOCK_user_conn);
 
127
  if (max_user_connections && !uc->user_resources.user_conn &&
 
128
      max_user_connections < (uint) uc->connections)
 
129
  {
 
130
    my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user);
 
131
    error=1;
 
132
    goto end;
 
133
  }
 
134
  time_out_user_resource_limits(thd, uc);
 
135
  if (uc->user_resources.user_conn &&
 
136
      uc->user_resources.user_conn < uc->connections)
 
137
  {
 
138
    my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user,
 
139
             "max_user_connections",
 
140
             (long) uc->user_resources.user_conn);
 
141
    error= 1;
 
142
    goto end;
 
143
  }
 
144
  if (uc->user_resources.conn_per_hour &&
 
145
      uc->user_resources.conn_per_hour <= uc->conn_per_hour)
 
146
  {
 
147
    my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user,
 
148
             "max_connections_per_hour",
 
149
             (long) uc->user_resources.conn_per_hour);
 
150
    error=1;
 
151
    goto end;
 
152
  }
 
153
  uc->conn_per_hour++;
 
154
 
 
155
end:
 
156
  if (error)
 
157
    uc->connections--; // no need for decrease_user_connections() here
 
158
  (void) pthread_mutex_unlock(&LOCK_user_conn);
 
159
  DBUG_RETURN(error);
 
160
}
 
161
 
 
162
 
 
163
/*
 
164
  Decrease user connection count
 
165
 
 
166
  SYNOPSIS
 
167
    decrease_user_connections()
 
168
    uc                  User connection object
 
169
 
 
170
  NOTES
 
171
    If there is a n user connection object for a connection
 
172
    (which only happens if 'max_user_connections' is defined or
 
173
    if someone has created a resource grant for a user), then
 
174
    the connection count is always incremented on connect.
 
175
 
 
176
    The user connect object is not freed if some users has
 
177
    'max connections per hour' defined as we need to be able to hold
 
178
    count over the lifetime of the connection.
 
179
*/
 
180
 
 
181
void decrease_user_connections(USER_CONN *uc)
 
182
{
 
183
  DBUG_ENTER("decrease_user_connections");
 
184
  (void) pthread_mutex_lock(&LOCK_user_conn);
 
185
  DBUG_ASSERT(uc->connections);
 
186
  if (!--uc->connections && !mqh_used)
 
187
  {
 
188
    /* Last connection for user; Delete it */
 
189
    (void) hash_delete(&hash_user_connections,(uchar*) uc);
 
190
  }
 
191
  (void) pthread_mutex_unlock(&LOCK_user_conn);
 
192
  DBUG_VOID_RETURN;
 
193
}
 
194
 
 
195
 
 
196
/*
 
197
  Reset per-hour user resource limits when it has been more than
 
198
  an hour since they were last checked
 
199
 
 
200
  SYNOPSIS:
 
201
    time_out_user_resource_limits()
 
202
    thd                 Thread handler
 
203
    uc                  User connection details
 
204
 
 
205
  NOTE:
 
206
    This assumes that the LOCK_user_conn mutex has been acquired, so it is
 
207
    safe to test and modify members of the USER_CONN structure.
 
208
*/
 
209
 
 
210
void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
 
211
{
 
212
  ulonglong check_time= thd->start_utime;
 
213
  DBUG_ENTER("time_out_user_resource_limits");
 
214
 
 
215
  /* If more than a hour since last check, reset resource checking */
 
216
  if (check_time  - uc->reset_utime >= LL(3600000000))
 
217
  {
 
218
    uc->questions=1;
 
219
    uc->updates=0;
 
220
    uc->conn_per_hour=0;
 
221
    uc->reset_utime= check_time;
 
222
  }
 
223
 
 
224
  DBUG_VOID_RETURN;
 
225
}
 
226
 
 
227
/*
 
228
  Check if maximum queries per hour limit has been reached
 
229
  returns 0 if OK.
 
230
*/
 
231
 
 
232
bool check_mqh(THD *thd, uint check_command)
 
233
{
 
234
  bool error= 0;
 
235
  USER_CONN *uc=thd->user_connect;
 
236
  DBUG_ENTER("check_mqh");
 
237
  DBUG_ASSERT(uc != 0);
 
238
 
 
239
  (void) pthread_mutex_lock(&LOCK_user_conn);
 
240
 
 
241
  time_out_user_resource_limits(thd, uc);
 
242
 
 
243
  /* Check that we have not done too many questions / hour */
 
244
  if (uc->user_resources.questions &&
 
245
      uc->questions++ >= uc->user_resources.questions)
 
246
  {
 
247
    my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions",
 
248
             (long) uc->user_resources.questions);
 
249
    error=1;
 
250
    goto end;
 
251
  }
 
252
  if (check_command < (uint) SQLCOM_END)
 
253
  {
 
254
    /* Check that we have not done too many updates / hour */
 
255
    if (uc->user_resources.updates &&
 
256
        (sql_command_flags[check_command] & CF_CHANGES_DATA) &&
 
257
        uc->updates++ >= uc->user_resources.updates)
 
258
    {
 
259
      my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates",
 
260
               (long) uc->user_resources.updates);
 
261
      error=1;
 
262
      goto end;
 
263
    }
 
264
  }
 
265
end:
 
266
  (void) pthread_mutex_unlock(&LOCK_user_conn);
 
267
  DBUG_RETURN(error);
 
268
}
 
269
 
 
270
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
 
271
 
 
272
 
 
273
/**
 
274
  Check if user exist and password supplied is correct.
 
275
 
 
276
  @param  thd         thread handle, thd->security_ctx->{host,user,ip} are used
 
277
  @param  command     originator of the check: now check_user is called
 
278
                      during connect and change user procedures; used for
 
279
                      logging.
 
280
  @param  passwd      scrambled password received from client
 
281
  @param  passwd_len  length of scrambled password
 
282
  @param  db          database name to connect to, may be NULL
 
283
  @param  check_count TRUE if establishing a new connection. In this case
 
284
                      check that we have not exceeded the global
 
285
                      max_connections limist
 
286
 
 
287
  @note Host, user and passwd may point to communication buffer.
 
288
  Current implementation does not depend on that, but future changes
 
289
  should be done with this in mind; 'thd' is INOUT, all other params
 
290
  are 'IN'.
 
291
 
 
292
  @retval  0  OK; thd->security_ctx->user/master_access/priv_user/db_access and
 
293
              thd->db are updated; OK is sent to the client.
 
294
  @retval  1  error, e.g. access denied or handshake error, not sent to
 
295
              the client. A message is pushed into the error stack.
 
296
*/
 
297
 
 
298
int
 
299
check_user(THD *thd, enum enum_server_command command,
 
300
               const char *passwd, uint passwd_len, const char *db,
 
301
               bool check_count)
 
302
{
 
303
  DBUG_ENTER("check_user");
 
304
  LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
 
305
 
 
306
  /*
 
307
    Clear thd->db as it points to something, that will be freed when
 
308
    connection is closed. We don't want to accidentally free a wrong
 
309
    pointer if connect failed. Also in case of 'CHANGE USER' failure,
 
310
    current database will be switched to 'no database selected'.
 
311
  */
 
312
  thd->reset_db(NULL, 0);
 
313
 
 
314
#ifdef NO_EMBEDDED_ACCESS_CHECKS
 
315
  thd->main_security_ctx.master_access= GLOBAL_ACLS;       // Full rights
 
316
  /* Change database if necessary */
 
317
  if (db && db[0])
 
318
  {
 
319
    if (mysql_change_db(thd, &db_str, FALSE))
 
320
      DBUG_RETURN(1);
 
321
  }
 
322
  my_ok(thd);
 
323
  DBUG_RETURN(0);
 
324
#else
 
325
 
 
326
  my_bool opt_secure_auth_local;
 
327
  pthread_mutex_lock(&LOCK_global_system_variables);
 
328
  opt_secure_auth_local= opt_secure_auth;
 
329
  pthread_mutex_unlock(&LOCK_global_system_variables);
 
330
  
 
331
  /*
 
332
    If the server is running in secure auth mode, short scrambles are 
 
333
    forbidden.
 
334
  */
 
335
  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
 
336
  {
 
337
    my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
 
338
    general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
 
339
    DBUG_RETURN(1);
 
340
  }
 
341
  if (passwd_len != 0 &&
 
342
      passwd_len != SCRAMBLE_LENGTH &&
 
343
      passwd_len != SCRAMBLE_LENGTH_323)
 
344
  {
 
345
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
 
346
    DBUG_RETURN(1);
 
347
  }
 
348
 
 
349
  USER_RESOURCES ur;
 
350
  int res= acl_getroot(thd, &ur, passwd, passwd_len);
 
351
#ifndef EMBEDDED_LIBRARY
 
352
  if (res == -1)
 
353
  {
 
354
    /*
 
355
      This happens when client (new) sends password scrambled with
 
356
      scramble(), but database holds old value (scrambled with
 
357
      scramble_323()). Here we please client to send scrambled_password
 
358
      in old format.
 
359
    */
 
360
    NET *net= &thd->net;
 
361
    if (opt_secure_auth_local)
 
362
    {
 
363
      my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
 
364
               thd->main_security_ctx.user,
 
365
               thd->main_security_ctx.host_or_ip);
 
366
      general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
 
367
                        thd->main_security_ctx.user,
 
368
                        thd->main_security_ctx.host_or_ip);
 
369
      DBUG_RETURN(1);
 
370
    }
 
371
    /* We have to read very specific packet size */
 
372
    if (send_old_password_request(thd) ||
 
373
        my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
 
374
    {
 
375
      inc_host_errors(&thd->remote.sin_addr);
 
376
      my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
 
377
      DBUG_RETURN(1);
 
378
    }
 
379
    /* Final attempt to check the user based on reply */
 
380
    /* So as passwd is short, errcode is always >= 0 */
 
381
    res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
 
382
  }
 
383
#endif /*EMBEDDED_LIBRARY*/
 
384
  /* here res is always >= 0 */
 
385
  if (res == 0)
 
386
  {
 
387
    if (!(thd->main_security_ctx.master_access &
 
388
          NO_ACCESS)) // authentication is OK
 
389
    {
 
390
      DBUG_PRINT("info",
 
391
                 ("Capabilities: %lu  packet_length: %ld  Host: '%s'  "
 
392
                  "Login user: '%s' Priv_user: '%s'  Using password: %s "
 
393
                  "Access: %lu  db: '%s'",
 
394
                  thd->client_capabilities,
 
395
                  thd->max_client_packet_length,
 
396
                  thd->main_security_ctx.host_or_ip,
 
397
                  thd->main_security_ctx.user,
 
398
                  thd->main_security_ctx.priv_user,
 
399
                  passwd_len ? "yes": "no",
 
400
                  thd->main_security_ctx.master_access,
 
401
                  (thd->db ? thd->db : "*none*")));
 
402
 
 
403
      if (check_count)
 
404
      {
 
405
        pthread_mutex_lock(&LOCK_connection_count);
 
406
        bool count_ok= connection_count <= max_connections ||
 
407
                       (thd->main_security_ctx.master_access & SUPER_ACL);
 
408
        VOID(pthread_mutex_unlock(&LOCK_connection_count));
 
409
 
 
410
        if (!count_ok)
 
411
        {                                         // too many connections
 
412
          my_error(ER_CON_COUNT_ERROR, MYF(0));
 
413
          DBUG_RETURN(1);
 
414
        }
 
415
      }
 
416
 
 
417
      /*
 
418
        Log the command before authentication checks, so that the user can
 
419
        check the log for the tried login tried and also to detect
 
420
        break-in attempts.
 
421
      */
 
422
      general_log_print(thd, command,
 
423
                        (thd->main_security_ctx.priv_user ==
 
424
                         thd->main_security_ctx.user ?
 
425
                         (char*) "%s@%s on %s" :
 
426
                         (char*) "%s@%s as anonymous on %s"),
 
427
                        thd->main_security_ctx.user,
 
428
                        thd->main_security_ctx.host_or_ip,
 
429
                        db ? db : (char*) "");
 
430
 
 
431
      /*
 
432
        This is the default access rights for the current database.  It's
 
433
        set to 0 here because we don't have an active database yet (and we
 
434
        may not have an active database to set.
 
435
      */
 
436
      thd->main_security_ctx.db_access=0;
 
437
 
 
438
      /* Don't allow user to connect if he has done too many queries */
 
439
      if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
 
440
           max_user_connections) &&
 
441
          get_or_create_user_conn(thd,
 
442
            (opt_old_style_user_limits ? thd->main_security_ctx.user :
 
443
             thd->main_security_ctx.priv_user),
 
444
            (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
 
445
             thd->main_security_ctx.priv_host),
 
446
            &ur))
 
447
      {
 
448
        /* The error is set by get_or_create_user_conn(). */
 
449
        DBUG_RETURN(1);
 
450
      }
 
451
      if (thd->user_connect &&
 
452
          (thd->user_connect->user_resources.conn_per_hour ||
 
453
           thd->user_connect->user_resources.user_conn ||
 
454
           max_user_connections) &&
 
455
          check_for_max_user_connections(thd, thd->user_connect))
 
456
      {
 
457
        /* The error is set in check_for_max_user_connections(). */
 
458
        DBUG_RETURN(1);
 
459
      }
 
460
 
 
461
      /* Change database if necessary */
 
462
      if (db && db[0])
 
463
      {
 
464
        if (mysql_change_db(thd, &db_str, FALSE))
 
465
        {
 
466
          /* mysql_change_db() has pushed the error message. */
 
467
          if (thd->user_connect)
 
468
            decrease_user_connections(thd->user_connect);
 
469
          DBUG_RETURN(1);
 
470
        }
 
471
      }
 
472
      my_ok(thd);
 
473
      thd->password= test(passwd_len);          // remember for error messages 
 
474
      /* Ready to handle queries */
 
475
      DBUG_RETURN(0);
 
476
    }
 
477
  }
 
478
  else if (res == 2) // client gave short hash, server has long hash
 
479
  {
 
480
    my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
 
481
    general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
 
482
    DBUG_RETURN(1);
 
483
  }
 
484
  my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
 
485
           thd->main_security_ctx.user,
 
486
           thd->main_security_ctx.host_or_ip,
 
487
           passwd_len ? ER(ER_YES) : ER(ER_NO));
 
488
  general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
 
489
                    thd->main_security_ctx.user,
 
490
                    thd->main_security_ctx.host_or_ip,
 
491
                    passwd_len ? ER(ER_YES) : ER(ER_NO));
 
492
  DBUG_RETURN(1);
 
493
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
 
494
}
 
495
 
 
496
 
 
497
/*
 
498
  Check for maximum allowable user connections, if the mysqld server is
 
499
  started with corresponding variable that is greater then 0.
 
500
*/
 
501
 
 
502
extern "C" uchar *get_key_conn(user_conn *buff, size_t *length,
 
503
                              my_bool not_used __attribute__((unused)))
 
504
{
 
505
  *length= buff->len;
 
506
  return (uchar*) buff->user;
 
507
}
 
508
 
 
509
 
 
510
extern "C" void free_user(struct user_conn *uc)
 
511
{
 
512
  my_free((char*) uc,MYF(0));
 
513
}
 
514
 
 
515
 
 
516
void init_max_user_conn(void)
 
517
{
 
518
#ifndef NO_EMBEDDED_ACCESS_CHECKS
 
519
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
 
520
                   0,0,
 
521
                   (hash_get_key) get_key_conn, (hash_free_key) free_user,
 
522
                   0);
 
523
#endif
 
524
}
 
525
 
 
526
 
 
527
void free_max_user_conn(void)
 
528
{
 
529
#ifndef NO_EMBEDDED_ACCESS_CHECKS
 
530
  hash_free(&hash_user_connections);
 
531
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
 
532
}
 
533
 
 
534
 
 
535
void reset_mqh(LEX_USER *lu, bool get_them= 0)
 
536
{
 
537
#ifndef NO_EMBEDDED_ACCESS_CHECKS
 
538
  (void) pthread_mutex_lock(&LOCK_user_conn);
 
539
  if (lu)  // for GRANT
 
540
  {
 
541
    USER_CONN *uc;
 
542
    uint temp_len=lu->user.length+lu->host.length+2;
 
543
    char temp_user[USER_HOST_BUFF_SIZE];
 
544
 
 
545
    memcpy(temp_user,lu->user.str,lu->user.length);
 
546
    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
 
547
    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
 
548
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
 
549
                                                (uchar*) temp_user, temp_len)))
 
550
    {
 
551
      uc->questions=0;
 
552
      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
 
553
      uc->updates=0;
 
554
      uc->conn_per_hour=0;
 
555
    }
 
556
  }
 
557
  else
 
558
  {
 
559
    /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
 
560
    for (uint idx=0;idx < hash_user_connections.records; idx++)
 
561
    {
 
562
      USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
 
563
                                                      idx);
 
564
      if (get_them)
 
565
        get_mqh(uc->user,uc->host,uc);
 
566
      uc->questions=0;
 
567
      uc->updates=0;
 
568
      uc->conn_per_hour=0;
 
569
    }
 
570
  }
 
571
  (void) pthread_mutex_unlock(&LOCK_user_conn);
 
572
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
 
573
}
 
574
 
 
575
 
 
576
void thd_init_client_charset(THD *thd, uint cs_number)
 
577
{
 
578
  /*
 
579
   Use server character set and collation if
 
580
   - opt_character_set_client_handshake is not set
 
581
   - client has not specified a character set
 
582
   - client character set is the same as the servers
 
583
   - client character set doesn't exists in server
 
584
  */
 
585
  if (!opt_character_set_client_handshake ||
 
586
      !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
 
587
      !my_strcasecmp(&my_charset_latin1,
 
588
                     global_system_variables.character_set_client->name,
 
589
                     thd->variables.character_set_client->name))
 
590
  {
 
591
    thd->variables.character_set_client=
 
592
      global_system_variables.character_set_client;
 
593
    thd->variables.collation_connection=
 
594
      global_system_variables.collation_connection;
 
595
    thd->variables.character_set_results=
 
596
      global_system_variables.character_set_results;
 
597
  }
 
598
  else
 
599
  {
 
600
    thd->variables.character_set_results=
 
601
      thd->variables.collation_connection= 
 
602
      thd->variables.character_set_client;
 
603
  }
 
604
}
 
605
 
 
606
 
 
607
/*
 
608
  Initialize connection threads
 
609
*/
 
610
 
 
611
bool init_new_connection_handler_thread()
 
612
{
 
613
  pthread_detach_this_thread();
 
614
#if defined(__WIN__)
 
615
  win_install_sigabrt_handler();
 
616
#else
 
617
  /* Win32 calls this in pthread_create */
 
618
  if (my_thread_init())
 
619
    return 1;
 
620
#endif /* __WIN__ */
 
621
  return 0;
 
622
}
 
623
 
 
624
/*
 
625
  Perform handshake, authorize client and update thd ACL variables.
 
626
 
 
627
  SYNOPSIS
 
628
    check_connection()
 
629
    thd  thread handle
 
630
 
 
631
  RETURN
 
632
     0  success, OK is sent to user, thd is updated.
 
633
    -1  error, which is sent to user
 
634
   > 0  error code (not sent to user)
 
635
*/
 
636
 
 
637
#ifndef EMBEDDED_LIBRARY
 
638
static int check_connection(THD *thd)
 
639
{
 
640
  uint connect_errors= 0;
 
641
  NET *net= &thd->net;
 
642
  ulong pkt_len= 0;
 
643
  char *end;
 
644
 
 
645
  DBUG_PRINT("info",
 
646
             ("New connection received on %s", vio_description(net->vio)));
 
647
#ifdef SIGNAL_WITH_VIO_CLOSE
 
648
  thd->set_active_vio(net->vio);
 
649
#endif
 
650
 
 
651
  if (!thd->main_security_ctx.host)         // If TCP/IP connection
 
652
  {
 
653
    char ip[30];
 
654
 
 
655
    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
 
656
    {
 
657
      my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
 
658
      return 1;
 
659
    }
 
660
    if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
 
661
      return 1; /* The error is set by my_strdup(). */
 
662
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
 
663
    vio_in_addr(net->vio,&thd->remote.sin_addr);
 
664
    if (!(specialflag & SPECIAL_NO_RESOLVE))
 
665
    {
 
666
      vio_in_addr(net->vio,&thd->remote.sin_addr);
 
667
      thd->main_security_ctx.host=
 
668
        ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
 
669
      /* Cut very long hostnames to avoid possible overflows */
 
670
      if (thd->main_security_ctx.host)
 
671
      {
 
672
        if (thd->main_security_ctx.host != my_localhost)
 
673
          thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
 
674
                                          HOSTNAME_LENGTH)]= 0;
 
675
        thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
 
676
      }
 
677
      if (connect_errors > max_connect_errors)
 
678
      {
 
679
        my_error(ER_HOST_IS_BLOCKED, MYF(0), thd->main_security_ctx.host_or_ip);
 
680
        return 1;
 
681
      }
 
682
    }
 
683
    DBUG_PRINT("info",("Host: %s  ip: %s",
 
684
                       (thd->main_security_ctx.host ?
 
685
                        thd->main_security_ctx.host : "unknown host"),
 
686
                       (thd->main_security_ctx.ip ?
 
687
                        thd->main_security_ctx.ip : "unknown ip")));
 
688
    if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
 
689
    {
 
690
      my_error(ER_HOST_NOT_PRIVILEGED, MYF(0),
 
691
               thd->main_security_ctx.host_or_ip);
 
692
      return 1;
 
693
    }
 
694
  }
 
695
  else /* Hostname given means that the connection was on a socket */
 
696
  {
 
697
    DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
 
698
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
 
699
    thd->main_security_ctx.ip= 0;
 
700
    /* Reset sin_addr */
 
701
    bzero((char*) &thd->remote, sizeof(thd->remote));
 
702
  }
 
703
  vio_keepalive(net->vio, TRUE);
 
704
  
 
705
  ulong server_capabilites;
 
706
  {
 
707
    /* buff[] needs to big enough to hold the server_version variable */
 
708
    char buff[SERVER_VERSION_LENGTH + 1 + SCRAMBLE_LENGTH + 1 + 64];
 
709
    server_capabilites= CLIENT_BASIC_FLAGS;
 
710
 
 
711
    if (opt_using_transactions)
 
712
      server_capabilites|= CLIENT_TRANSACTIONS;
 
713
#ifdef HAVE_COMPRESS
 
714
    server_capabilites|= CLIENT_COMPRESS;
 
715
#endif /* HAVE_COMPRESS */
 
716
#ifdef HAVE_OPENSSL
 
717
    if (ssl_acceptor_fd)
 
718
    {
 
719
      server_capabilites |= CLIENT_SSL;       /* Wow, SSL is available! */
 
720
      server_capabilites |= CLIENT_SSL_VERIFY_SERVER_CERT;
 
721
    }
 
722
#endif /* HAVE_OPENSSL */
 
723
 
 
724
    end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
 
725
    int4store((uchar*) end, thd->thread_id);
 
726
    end+= 4;
 
727
    /*
 
728
      So as check_connection is the only entry point to authorization
 
729
      procedure, scramble is set here. This gives us new scramble for
 
730
      each handshake.
 
731
    */
 
732
    create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
 
733
    /*
 
734
      Old clients does not understand long scrambles, but can ignore packet
 
735
      tail: that's why first part of the scramble is placed here, and second
 
736
      part at the end of packet.
 
737
    */
 
738
    end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
 
739
   
 
740
    int2store(end, server_capabilites);
 
741
    /* write server characteristics: up to 16 bytes allowed */
 
742
    end[2]=(char) default_charset_info->number;
 
743
    int2store(end+3, thd->server_status);
 
744
    bzero(end+5, 13);
 
745
    end+= 18;
 
746
    /* write scramble tail */
 
747
    end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, 
 
748
                 SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
 
749
 
 
750
    /* At this point we write connection message and read reply */
 
751
    if (net_write_command(net, (uchar) protocol_version, (uchar*) "", 0,
 
752
                          (uchar*) buff, (size_t) (end-buff)) ||
 
753
        (pkt_len= my_net_read(net)) == packet_error ||
 
754
        pkt_len < MIN_HANDSHAKE_SIZE)
 
755
    {
 
756
      inc_host_errors(&thd->remote.sin_addr);
 
757
      my_error(ER_HANDSHAKE_ERROR, MYF(0),
 
758
               thd->main_security_ctx.host_or_ip);
 
759
      return 1;
 
760
    }
 
761
  }
 
762
#ifdef _CUSTOMCONFIG_
 
763
#include "_cust_sql_parse.h"
 
764
#endif
 
765
  if (connect_errors)
 
766
    reset_host_errors(&thd->remote.sin_addr);
 
767
  if (thd->packet.alloc(thd->variables.net_buffer_length))
 
768
    return 1; /* The error is set by alloc(). */
 
769
 
 
770
  thd->client_capabilities= uint2korr(net->read_pos);
 
771
  if (thd->client_capabilities & CLIENT_PROTOCOL_41)
 
772
  {
 
773
    thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
 
774
    thd->max_client_packet_length= uint4korr(net->read_pos+4);
 
775
    DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
 
776
    thd_init_client_charset(thd, (uint) net->read_pos[8]);
 
777
    thd->update_charset();
 
778
    end= (char*) net->read_pos+32;
 
779
  }
 
780
  else
 
781
  {
 
782
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
 
783
    end= (char*) net->read_pos+5;
 
784
  }
 
785
  /*
 
786
    Disable those bits which are not supported by the server.
 
787
    This is a precautionary measure, if the client lies. See Bug#27944.
 
788
  */
 
789
  thd->client_capabilities&= server_capabilites;
 
790
 
 
791
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
 
792
    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
 
793
#ifdef HAVE_OPENSSL
 
794
  DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
 
795
  if (thd->client_capabilities & CLIENT_SSL)
 
796
  {
 
797
    /* Do the SSL layering. */
 
798
    if (!ssl_acceptor_fd)
 
799
    {
 
800
      inc_host_errors(&thd->remote.sin_addr);
 
801
      my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
 
802
      return 1;
 
803
    }
 
804
    DBUG_PRINT("info", ("IO layer change in progress..."));
 
805
    if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
 
806
    {
 
807
      DBUG_PRINT("error", ("Failed to accept new SSL connection"));
 
808
      inc_host_errors(&thd->remote.sin_addr);
 
809
      my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
 
810
      return 1;
 
811
    }
 
812
    DBUG_PRINT("info", ("Reading user information over SSL layer"));
 
813
    if ((pkt_len= my_net_read(net)) == packet_error ||
 
814
        pkt_len < NORMAL_HANDSHAKE_SIZE)
 
815
    {
 
816
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
 
817
                           pkt_len));
 
818
      inc_host_errors(&thd->remote.sin_addr);
 
819
      my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
 
820
      return 1;
 
821
    }
 
822
  }
 
823
#endif /* HAVE_OPENSSL */
 
824
 
 
825
  if (end >= (char*) net->read_pos+ pkt_len +2)
 
826
  {
 
827
    inc_host_errors(&thd->remote.sin_addr);
 
828
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
 
829
    return 1;
 
830
  }
 
831
 
 
832
  if (thd->client_capabilities & CLIENT_INTERACTIVE)
 
833
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
 
834
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
 
835
      opt_using_transactions)
 
836
    net->return_status= &thd->server_status;
 
837
 
 
838
  char *user= end;
 
839
  char *passwd= strend(user)+1;
 
840
  uint user_len= passwd - user - 1;
 
841
  char *db= passwd;
 
842
  char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
 
843
  char user_buff[USERNAME_LENGTH + 1];  // buffer to store user in utf8
 
844
  uint dummy_errors;
 
845
 
 
846
  /*
 
847
    Old clients send null-terminated string as password; new clients send
 
848
    the size (1 byte) + string (not null-terminated). Hence in case of empty
 
849
    password both send '\0'.
 
850
 
 
851
    This strlen() can't be easily deleted without changing protocol.
 
852
 
 
853
    Cast *passwd to an unsigned char, so that it doesn't extend the sign for
 
854
    *passwd > 127 and become 2**32-127+ after casting to uint.
 
855
  */
 
856
  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
 
857
    (uchar)(*passwd++) : strlen(passwd);
 
858
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
 
859
    db + passwd_len + 1 : 0;
 
860
  /* strlen() can't be easily deleted without changing protocol */
 
861
  uint db_len= db ? strlen(db) : 0;
 
862
 
 
863
  if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
 
864
  {
 
865
    inc_host_errors(&thd->remote.sin_addr);
 
866
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
 
867
    return 1;
 
868
  }
 
869
 
 
870
  /* Since 4.1 all database names are stored in utf8 */
 
871
  if (db)
 
872
  {
 
873
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
 
874
                             system_charset_info,
 
875
                             db, db_len,
 
876
                             thd->charset(), &dummy_errors)]= 0;
 
877
    db= db_buff;
 
878
  }
 
879
 
 
880
  user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
 
881
                                       system_charset_info, user, user_len,
 
882
                                       thd->charset(), &dummy_errors)]= '\0';
 
883
  user= user_buff;
 
884
 
 
885
  /* If username starts and ends in "'", chop them off */
 
886
  if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
 
887
  {
 
888
    user[user_len-1]= 0;
 
889
    user++;
 
890
    user_len-= 2;
 
891
  }
 
892
 
 
893
  if (thd->main_security_ctx.user)
 
894
    x_free(thd->main_security_ctx.user);
 
895
  if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME))))
 
896
    return 1; /* The error is set by my_strdup(). */
 
897
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
 
898
}
 
899
 
 
900
 
 
901
/*
 
902
  Setup thread to be used with the current thread
 
903
 
 
904
  SYNOPSIS
 
905
    bool setup_connection_thread_globals()
 
906
    thd    Thread/connection handler
 
907
 
 
908
  RETURN
 
909
    0   ok
 
910
    1   Error (out of memory)
 
911
        In this case we will close the connection and increment status
 
912
*/
 
913
 
 
914
bool setup_connection_thread_globals(THD *thd)
 
915
{
 
916
  if (thd->store_globals())
 
917
  {
 
918
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
 
919
    statistic_increment(aborted_connects,&LOCK_status);
 
920
    thread_scheduler.end_thread(thd, 0);
 
921
    return 1;                                   // Error
 
922
  }
 
923
  return 0;
 
924
}
 
925
 
 
926
 
 
927
/*
 
928
  Autenticate user, with error reporting
 
929
 
 
930
  SYNOPSIS
 
931
   login_connection()
 
932
   thd        Thread handler
 
933
 
 
934
  NOTES
 
935
    Connection is not closed in case of errors
 
936
 
 
937
  RETURN
 
938
    0    ok
 
939
    1    error
 
940
*/
 
941
 
 
942
 
 
943
static bool login_connection(THD *thd)
 
944
{
 
945
  NET *net= &thd->net;
 
946
  int error;
 
947
  DBUG_ENTER("login_connection");
 
948
  DBUG_PRINT("info", ("login_connection called by thread %lu",
 
949
                      thd->thread_id));
 
950
 
 
951
  /* Use "connect_timeout" value during connection phase */
 
952
  my_net_set_read_timeout(net, connect_timeout);
 
953
  my_net_set_write_timeout(net, connect_timeout);
 
954
 
 
955
  error= check_connection(thd);
 
956
  net_end_statement(thd);
 
957
 
 
958
  if (error)
 
959
  {                                             // Wrong permissions
 
960
#ifdef __NT__
 
961
    if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
 
962
      my_sleep(1000);                           /* must wait after eof() */
 
963
#endif
 
964
    statistic_increment(aborted_connects,&LOCK_status);
 
965
    DBUG_RETURN(1);
 
966
  }
 
967
  /* Connect completed, set read/write timeouts back to default */
 
968
  my_net_set_read_timeout(net, thd->variables.net_read_timeout);
 
969
  my_net_set_write_timeout(net, thd->variables.net_write_timeout);
 
970
  DBUG_RETURN(0);
 
971
}
 
972
 
 
973
 
 
974
/*
 
975
  Close an established connection
 
976
 
 
977
  NOTES
 
978
    This mainly updates status variables
 
979
*/
 
980
 
 
981
static void end_connection(THD *thd)
 
982
{
 
983
  NET *net= &thd->net;
 
984
  plugin_thdvar_cleanup(thd);
 
985
  if (thd->user_connect)
 
986
    decrease_user_connections(thd->user_connect);
 
987
 
 
988
  if (thd->killed || (net->error && net->vio != 0))
 
989
  {
 
990
    statistic_increment(aborted_threads,&LOCK_status);
 
991
  }
 
992
 
 
993
  if (net->error && net->vio != 0)
 
994
  {
 
995
    if (!thd->killed && thd->variables.log_warnings > 1)
 
996
    {
 
997
      Security_context *sctx= thd->security_ctx;
 
998
 
 
999
      sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
 
1000
                        thd->thread_id,(thd->db ? thd->db : "unconnected"),
 
1001
                        sctx->user ? sctx->user : "unauthenticated",
 
1002
                        sctx->host_or_ip,
 
1003
                        (thd->main_da.is_error() ? thd->main_da.message() :
 
1004
                         ER(ER_UNKNOWN_ERROR)));
 
1005
    }
 
1006
  }
 
1007
}
 
1008
 
 
1009
 
 
1010
/*
 
1011
  Initialize THD to handle queries
 
1012
*/
 
1013
 
 
1014
static void prepare_new_connection_state(THD* thd)
 
1015
{
 
1016
  Security_context *sctx= thd->security_ctx;
 
1017
 
 
1018
#ifdef __NETWARE__
 
1019
  netware_reg_user(sctx->ip, sctx->user, "MySQL");
 
1020
#endif
 
1021
 
 
1022
  if (thd->variables.max_join_size == HA_POS_ERROR)
 
1023
    thd->options |= OPTION_BIG_SELECTS;
 
1024
  if (thd->client_capabilities & CLIENT_COMPRESS)
 
1025
    thd->net.compress=1;                                // Use compression
 
1026
 
 
1027
  /*
 
1028
    Much of this is duplicated in create_embedded_thd() for the
 
1029
    embedded server library.
 
1030
    TODO: refactor this to avoid code duplication there
 
1031
  */
 
1032
  thd->version= refresh_version;
 
1033
  thd->proc_info= 0;
 
1034
  thd->command= COM_SLEEP;
 
1035
  thd->set_time();
 
1036
  thd->init_for_queries();
 
1037
 
 
1038
  if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
 
1039
  {
 
1040
    execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
 
1041
    if (thd->is_error())
 
1042
    {
 
1043
      thd->killed= THD::KILL_CONNECTION;
 
1044
      sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
 
1045
                        thd->thread_id,(thd->db ? thd->db : "unconnected"),
 
1046
                        sctx->user ? sctx->user : "unauthenticated",
 
1047
                        sctx->host_or_ip, "init_connect command failed");
 
1048
      sql_print_warning("%s", thd->main_da.message());
 
1049
    }
 
1050
    thd->proc_info=0;
 
1051
    thd->set_time();
 
1052
    thd->init_for_queries();
 
1053
  }
 
1054
}
 
1055
 
 
1056
 
 
1057
/*
 
1058
  Thread handler for a connection
 
1059
 
 
1060
  SYNOPSIS
 
1061
    handle_one_connection()
 
1062
    arg         Connection object (THD)
 
1063
 
 
1064
  IMPLEMENTATION
 
1065
    This function (normally) does the following:
 
1066
    - Initialize thread
 
1067
    - Initialize THD to be used with this thread
 
1068
    - Authenticate user
 
1069
    - Execute all queries sent on the connection
 
1070
    - Take connection down
 
1071
    - End thread  / Handle next connection using thread from thread cache
 
1072
*/
 
1073
 
 
1074
pthread_handler_t handle_one_connection(void *arg)
 
1075
{
 
1076
  THD *thd= (THD*) arg;
 
1077
 
 
1078
  thd->thr_create_utime= my_micro_time();
 
1079
 
 
1080
  if (thread_scheduler.init_new_connection_thread())
 
1081
  {
 
1082
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
 
1083
    statistic_increment(aborted_connects,&LOCK_status);
 
1084
    thread_scheduler.end_thread(thd,0);
 
1085
    return 0;
 
1086
  }
 
1087
 
 
1088
  /*
 
1089
    If a thread was created to handle this connection:
 
1090
    increment slow_launch_threads counter if it took more than
 
1091
    slow_launch_time seconds to create the thread.
 
1092
  */
 
1093
  if (thd->prior_thr_create_utime)
 
1094
  {
 
1095
    ulong launch_time= (ulong) (thd->thr_create_utime -
 
1096
                                thd->prior_thr_create_utime);
 
1097
    if (launch_time >= slow_launch_time*1000000L)
 
1098
      statistic_increment(slow_launch_threads, &LOCK_status);
 
1099
    thd->prior_thr_create_utime= 0;
 
1100
  }
 
1101
 
 
1102
  /*
 
1103
    handle_one_connection() is normally the only way a thread would
 
1104
    start and would always be on the very high end of the stack ,
 
1105
    therefore, the thread stack always starts at the address of the
 
1106
    first local variable of handle_one_connection, which is thd. We
 
1107
    need to know the start of the stack so that we could check for
 
1108
    stack overruns.
 
1109
  */
 
1110
  thd->thread_stack= (char*) &thd;
 
1111
  if (setup_connection_thread_globals(thd))
 
1112
    return 0;
 
1113
 
 
1114
  for (;;)
 
1115
  {
 
1116
    NET *net= &thd->net;
 
1117
 
 
1118
    lex_start(thd);
 
1119
    if (login_connection(thd))
 
1120
      goto end_thread;
 
1121
 
 
1122
    prepare_new_connection_state(thd);
 
1123
 
 
1124
    while (!net->error && net->vio != 0 &&
 
1125
           !(thd->killed == THD::KILL_CONNECTION))
 
1126
    {
 
1127
      if (do_command(thd))
 
1128
        break;
 
1129
    }
 
1130
    end_connection(thd);
 
1131
   
 
1132
end_thread:
 
1133
    close_connection(thd, 0, 1);
 
1134
    if (thread_scheduler.end_thread(thd,1))
 
1135
      return 0;                                 // Probably no-threads
 
1136
 
 
1137
    /*
 
1138
      If end_thread() returns, we are either running with
 
1139
      thread-handler=no-threads or this thread has been schedule to
 
1140
      handle the next connection.
 
1141
    */
 
1142
    thd= current_thd;
 
1143
    thd->thread_stack= (char*) &thd;
 
1144
  }
 
1145
}
 
1146
#endif /* EMBEDDED_LIBRARY */