~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/mysql_protocol/oldlibdrizzle.cc

  • Committer: Monty Taylor
  • Date: 2009-12-25 02:37:09 UTC
  • mto: (1253.2.3 out-of-tree)
  • mto: This revision was merged to the branch mainline in revision 1258.
  • Revision ID: mordred@inaugust.com-20091225023709-r5xr0agiyzyfbhin
pandora-buildĀ v0.88

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems, Inc.
 
4
 *  Copyright (C) 2008 Sun Microsystems
5
5
 *
6
6
 * This program is free software; you can redistribute it and/or modify
7
7
 * it under the terms of the GNU General Public License as published by
14
14
 *
15
15
 * You should have received a copy of the GNU General Public License
16
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
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
 */
19
19
 
20
20
#include "config.h"
21
21
#include <drizzled/gettext.h>
22
22
#include <drizzled/error.h>
23
23
#include <drizzled/query_id.h>
24
 
#include <drizzled/error/sql_state.h>
 
24
#include <drizzled/sql_state.h>
25
25
#include <drizzled/session.h>
26
26
#include "drizzled/internal/m_string.h"
27
27
#include <algorithm>
28
 
#include <boost/program_options.hpp>
29
 
#include <drizzled/module/option_map.h>
30
 
#include "drizzled/util/tokenize.h"
 
28
 
 
29
#include "pack.h"
31
30
#include "errmsg.h"
32
 
#include "mysql_protocol.h"
33
 
#include "mysql_password.h"
 
31
#include "oldlibdrizzle.h"
34
32
#include "options.h"
35
33
 
36
 
#include "drizzled/identifier.h"
37
 
 
38
 
#define PROTOCOL_VERSION 10
39
 
 
40
 
namespace po= boost::program_options;
41
34
using namespace std;
42
35
using namespace drizzled;
43
36
 
44
 
namespace drizzle_plugin
45
 
{
46
 
 
47
 
std::vector<std::string> ClientMySQLProtocol::mysql_admin_ip_addresses;
 
37
#define PROTOCOL_VERSION 10
 
38
 
 
39
extern uint32_t global_thread_id;
 
40
 
48
41
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
49
 
 
50
 
static port_constraint port;
51
 
static timeout_constraint connect_timeout;
52
 
static timeout_constraint read_timeout;
53
 
static timeout_constraint write_timeout;
54
 
static retry_constraint retry_count;
55
 
static buffer_constraint buffer_length;
56
 
 
57
 
static uint32_t random_seed1;
58
 
static uint32_t random_seed2;
59
 
static const uint32_t random_max= 0x3FFFFFFF;
60
 
static const double random_max_double= (double)0x3FFFFFFF;
61
 
 
62
 
 
63
 
ProtocolCounters *ListenMySQLProtocol::mysql_counters= new ProtocolCounters();
64
 
 
65
 
ListenMySQLProtocol::~ListenMySQLProtocol()
66
 
{ }
67
 
 
68
 
void ListenMySQLProtocol::addCountersToTable()
69
 
{
70
 
  counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connection_count"), &getCounters()->connectionCount));
71
 
  counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connected"), &getCounters()->connected));
72
 
  counters.push_back(new drizzled::plugin::ListenCounter(new std::string("failed_connections"), &getCounters()->failedConnections));
73
 
}
74
 
 
75
 
const std::string ListenMySQLProtocol::getHost(void) const
76
 
{
77
 
  return _hostname;
 
42
static uint32_t port;
 
43
static uint32_t connect_timeout;
 
44
static uint32_t read_timeout;
 
45
static uint32_t write_timeout;
 
46
static uint32_t retry_count;
 
47
static uint32_t buffer_length;
 
48
static char* bind_address;
 
49
 
 
50
const char* ListenMySQLProtocol::getHost(void) const
 
51
{
 
52
  return bind_address;
78
53
}
79
54
 
80
55
in_port_t ListenMySQLProtocol::getPort(void) const
81
56
{
82
 
  return port.get();
 
57
  return (in_port_t) port;
83
58
}
84
59
 
85
60
plugin::Client *ListenMySQLProtocol::getClient(int fd)
89
64
  if (new_fd == -1)
90
65
    return NULL;
91
66
 
92
 
  return new ClientMySQLProtocol(new_fd, _using_mysql41_protocol, getCounters());
 
67
  return new (nothrow) ClientMySQLProtocol(new_fd, using_mysql41_protocol);
93
68
}
94
69
 
95
 
ClientMySQLProtocol::ClientMySQLProtocol(int fd, bool using_mysql41_protocol, ProtocolCounters *set_counters):
96
 
  is_admin_connection(false),
97
 
  _using_mysql41_protocol(using_mysql41_protocol),
98
 
  counters(set_counters)
 
70
ClientMySQLProtocol::ClientMySQLProtocol(int fd, bool using_mysql41_protocol_arg):
 
71
  using_mysql41_protocol(using_mysql41_protocol_arg)
99
72
{
100
 
  
101
73
  net.vio= 0;
102
74
 
103
75
  if (fd == -1)
104
76
    return;
105
77
 
106
 
  if (drizzleclient_net_init_sock(&net, fd, buffer_length.get()))
 
78
  if (drizzleclient_net_init_sock(&net, fd, 0, buffer_length))
107
79
    throw bad_alloc();
108
80
 
109
 
  drizzleclient_net_set_read_timeout(&net, read_timeout.get());
110
 
  drizzleclient_net_set_write_timeout(&net, write_timeout.get());
111
 
  net.retry_count=retry_count.get();
 
81
  drizzleclient_net_set_read_timeout(&net, read_timeout);
 
82
  drizzleclient_net_set_write_timeout(&net, write_timeout);
 
83
  net.retry_count=retry_count;
112
84
}
113
85
 
114
86
ClientMySQLProtocol::~ClientMySQLProtocol()
115
87
{
116
88
  if (net.vio)
117
 
    net.vio->close();
 
89
    drizzleclient_vio_close(net.vio);
118
90
}
119
91
 
120
92
int ClientMySQLProtocol::getFileDescriptor(void)
153
125
  { 
154
126
    drizzleclient_net_close(&net);
155
127
    drizzleclient_net_end(&net);
156
 
    if (is_admin_connection)
157
 
      counters->adminConnected.decrement();
158
 
    else
159
 
      counters->connected.decrement();
160
128
  }
161
129
}
162
130
 
163
131
bool ClientMySQLProtocol::authenticate()
164
132
{
165
133
  bool connection_is_valid;
166
 
  if (is_admin_connection)
167
 
  {
168
 
    counters->adminConnectionCount.increment();
169
 
    counters->adminConnected.increment();
170
 
  }
171
 
  else
172
 
  {
173
 
    counters->connectionCount.increment();
174
 
    counters->connected.increment();
175
 
  }
176
134
 
177
135
  /* Use "connect_timeout" value during connection phase */
178
 
  drizzleclient_net_set_read_timeout(&net, connect_timeout.get());
179
 
  drizzleclient_net_set_write_timeout(&net, connect_timeout.get());
 
136
  drizzleclient_net_set_read_timeout(&net, connect_timeout);
 
137
  drizzleclient_net_set_write_timeout(&net, connect_timeout);
180
138
 
181
139
  connection_is_valid= checkConnection();
182
140
 
183
141
  if (connection_is_valid)
184
 
  {
185
 
    if (not is_admin_connection and (counters->connected > counters->max_connections))
186
 
    {
187
 
      std::string errmsg(ER(ER_CON_COUNT_ERROR));
188
 
      sendError(ER_CON_COUNT_ERROR, errmsg.c_str());
189
 
      counters->failedConnections.increment();
190
 
    }
191
 
    else
192
 
    {
193
 
      sendOK();
194
 
    }
195
 
  }
 
142
    sendOK();
196
143
  else
197
144
  {
198
145
    sendError(session->main_da.sql_errno(), session->main_da.message());
199
 
    counters->failedConnections.increment();
200
146
    return false;
201
147
  }
202
148
 
203
149
  /* Connect completed, set read/write timeouts back to default */
204
 
  drizzleclient_net_set_read_timeout(&net, read_timeout.get());
205
 
  drizzleclient_net_set_write_timeout(&net, write_timeout.get());
 
150
  drizzleclient_net_set_read_timeout(&net, read_timeout);
 
151
  drizzleclient_net_set_write_timeout(&net, write_timeout);
206
152
  return true;
207
153
}
208
154
 
228
174
  {
229
175
    /* Check if we can continue without closing the connection */
230
176
 
231
 
    if(net.last_errno== ER_NET_PACKET_TOO_LARGE)
 
177
    if(net.last_errno== CR_NET_PACKET_TOO_LARGE)
232
178
      my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
233
179
    if (session->main_da.status() == Diagnostics_area::DA_ERROR)
234
180
      sendError(session->main_da.sql_errno(), session->main_da.message());
239
185
      return false;                       // We have to close it.
240
186
 
241
187
    net.error= 0;
 
188
    *packet_length= 0;
 
189
    return true;
242
190
  }
243
191
 
244
192
  *l_packet= (char*) net.read_pos;
258
206
    (*l_packet)[0]= (unsigned char) COM_SLEEP;
259
207
    *packet_length= 1;
260
208
  }
261
 
  else if (_using_mysql41_protocol)
 
209
  else if (using_mysql41_protocol)
262
210
  {
263
211
    /* Map from MySQL commands to Drizzle commands. */
264
212
    switch ((int)(*l_packet)[0])
274
222
      break;
275
223
 
276
224
    case 14: /* PING */
277
 
      (*l_packet)[0]= (unsigned char) COM_PING;
 
225
      (*l_packet)[0]= (unsigned char) COM_SHUTDOWN;
278
226
      break;
279
227
 
280
228
 
281
229
    default:
282
 
      /* Respond with unknown command for MySQL commands we don't support. */
283
 
      (*l_packet)[0]= (unsigned char) COM_END;
 
230
      /* Just drop connection for MySQL commands we don't support. */
 
231
      (*l_packet)[0]= (unsigned char) COM_QUIT;
284
232
      *packet_length= 1;
285
233
      break;
286
234
    }
335
283
  if (session->main_da.status() == Diagnostics_area::DA_OK)
336
284
  {
337
285
    if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da.found_rows())
338
 
      pos=storeLength(buff+1,session->main_da.found_rows());
 
286
      pos=drizzleclient_net_store_length(buff+1,session->main_da.found_rows());
339
287
    else
340
 
      pos=storeLength(buff+1,session->main_da.affected_rows());
341
 
    pos=storeLength(pos, session->main_da.last_insert_id());
 
288
      pos=drizzleclient_net_store_length(buff+1,session->main_da.affected_rows());
 
289
    pos=drizzleclient_net_store_length(pos, session->main_da.last_insert_id());
342
290
    int2store(pos, session->main_da.server_status());
343
291
    pos+=2;
344
292
    tmp= min(session->main_da.total_warn_count(), (uint32_t)65535);
346
294
  }
347
295
  else
348
296
  {
349
 
    pos=storeLength(buff+1,0);
350
 
    pos=storeLength(pos, 0);
 
297
    pos=drizzleclient_net_store_length(buff+1,0);
 
298
    pos=drizzleclient_net_store_length(pos, 0);
351
299
    int2store(pos, session->server_status);
352
300
    pos+=2;
353
301
    tmp= min(session->total_warn_count, (uint32_t)65535);
362
310
  if (message && message[0])
363
311
  {
364
312
    size_t length= strlen(message);
365
 
    pos=storeLength(pos,length);
 
313
    pos=drizzleclient_net_store_length(pos,length);
366
314
    memcpy(pos,(unsigned char*) message,length);
367
315
    pos+=length;
368
316
  }
398
346
    drizzleclient_net_flush(&net);
399
347
    session->main_da.can_overwrite_status= false;
400
348
  }
401
 
  packet.shrink(buffer_length.get());
 
349
  packet.shrink(buffer_length);
402
350
}
403
351
 
404
352
 
405
 
void ClientMySQLProtocol::sendError(drizzled::error_t sql_errno, const char *err)
 
353
void ClientMySQLProtocol::sendError(uint32_t sql_errno, const char *err)
406
354
{
407
355
  uint32_t length;
408
356
  /*
410
358
  */
411
359
  unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
412
360
 
413
 
  assert(sql_errno != EE_OK);
 
361
  assert(sql_errno);
414
362
  assert(err && err[0]);
415
363
 
416
364
  /*
435
383
    return;
436
384
  }
437
385
 
438
 
  int2store(buff, static_cast<uint16_t>(sql_errno));
 
386
  int2store(buff,sql_errno);
439
387
  pos= buff+2;
440
388
 
441
389
  /* The first # is to make the client backward compatible */
442
390
  buff[2]= '#';
443
 
  pos= (unsigned char*) strcpy((char*) buff+3, error::convert_to_sqlstate(sql_errno));
444
 
  pos+= strlen(error::convert_to_sqlstate(sql_errno));
 
391
  pos= (unsigned char*) strcpy((char*) buff+3, drizzle_errno_to_sqlstate(sql_errno));
 
392
  pos+= strlen(drizzle_errno_to_sqlstate(sql_errno));
445
393
 
446
394
  char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
447
395
  tmp+= strlen((char*)pos);
451
399
 
452
400
  drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
453
401
 
454
 
  drizzleclient_net_flush(&net);
455
 
 
456
402
  session->main_da.can_overwrite_status= false;
457
403
}
458
404
 
481
427
  unsigned char buff[80];
482
428
  String tmp((char*) buff,sizeof(buff),&my_charset_bin);
483
429
 
484
 
  unsigned char *row_pos= storeLength(buff, list->elements);
 
430
  unsigned char *row_pos= drizzleclient_net_store_length(buff, list->elements);
485
431
  (void) drizzleclient_net_write(&net, buff, (size_t) (row_pos-buff));
486
432
 
487
433
  while ((item=it++))
508
454
    int2store(pos, field.charsetnr);
509
455
    int4store(pos+2, field.length);
510
456
 
511
 
    if (_using_mysql41_protocol)
 
457
    if (using_mysql41_protocol)
512
458
    {
513
459
      /* Switch to MySQL field numbering. */
514
460
      switch (field.type)
537
483
        pos[6]= 12;
538
484
        break;
539
485
 
540
 
      case DRIZZLE_TYPE_TIME:
541
 
        pos[6]= 13;
542
 
        break;
543
 
 
544
486
      case DRIZZLE_TYPE_DATE:
545
487
        pos[6]= 14;
546
488
        break;
549
491
        pos[6]= 15;
550
492
        break;
551
493
 
552
 
      case DRIZZLE_TYPE_MICROTIME:
553
 
        pos[6]= 15;
554
 
        break;
555
 
 
556
 
      case DRIZZLE_TYPE_UUID:
557
 
        pos[6]= 15;
558
 
        break;
559
 
 
560
 
      case DRIZZLE_TYPE_BOOLEAN:
561
 
        pos[6]= 15;
562
 
        break;
563
 
 
564
494
      case DRIZZLE_TYPE_DECIMAL:
565
495
        pos[6]= (char)246;
566
496
        break;
612
542
  char buff[MAX_FIELD_WIDTH];
613
543
  String str(buff,sizeof(buff), &my_charset_bin);
614
544
 
615
 
  from->val_str_internal(&str);
 
545
  from->val_str(&str);
616
546
 
617
547
  return netStoreData((const unsigned char *)str.ptr(), str.length());
618
548
}
628
558
{
629
559
  char buff[12];
630
560
  return netStoreData((unsigned char*) buff,
631
 
                      (size_t) (internal::int10_to_str(from, buff, -10) - buff));
 
561
                      (size_t) (int10_to_str(from, buff, -10) - buff));
632
562
}
633
563
 
634
564
bool ClientMySQLProtocol::store(uint32_t from)
635
565
{
636
566
  char buff[11];
637
567
  return netStoreData((unsigned char*) buff,
638
 
                      (size_t) (internal::int10_to_str(from, buff, 10) - buff));
 
568
                      (size_t) (int10_to_str(from, buff, 10) - buff));
639
569
}
640
570
 
641
571
bool ClientMySQLProtocol::store(int64_t from)
642
572
{
643
573
  char buff[22];
644
574
  return netStoreData((unsigned char*) buff,
645
 
                      (size_t) (internal::int64_t10_to_str(from, buff, -10) - buff));
 
575
                      (size_t) (int64_t10_to_str(from, buff, -10) - buff));
646
576
}
647
577
 
648
578
bool ClientMySQLProtocol::store(uint64_t from)
649
579
{
650
580
  char buff[21];
651
581
  return netStoreData((unsigned char*) buff,
652
 
                      (size_t) (internal::int64_t10_to_str(from, buff, 10) - buff));
 
582
                      (size_t) (int64_t10_to_str(from, buff, 10) - buff));
653
583
}
654
584
 
655
585
bool ClientMySQLProtocol::store(double from, uint32_t decimals, String *buffer)
682
612
{
683
613
  uint32_t pkt_len= 0;
684
614
  char *end;
685
 
  char scramble[SCRAMBLE_LENGTH];
686
 
  identifier::User::shared_ptr user_identifier= identifier::User::make_shared();
687
 
 
688
 
  makeScramble(scramble);
689
615
 
690
616
  // TCP/IP connection
691
617
  {
694
620
 
695
621
    if (drizzleclient_net_peer_addr(&net, ip, &peer_port, NI_MAXHOST))
696
622
    {
697
 
      my_error(ER_BAD_HOST_ERROR, MYF(0), ip);
 
623
      my_error(ER_BAD_HOST_ERROR, MYF(0), session->security_ctx.ip.c_str());
698
624
      return false;
699
625
    }
700
626
 
701
 
    user_identifier->setAddress(ip);
 
627
    session->security_ctx.ip.assign(ip);
702
628
  }
703
629
  drizzleclient_net_keepalive(&net, true);
704
630
 
709
635
 
710
636
    server_capabilites= CLIENT_BASIC_FLAGS;
711
637
 
712
 
    if (_using_mysql41_protocol)
 
638
    if (using_mysql41_protocol)
713
639
      server_capabilites|= CLIENT_PROTOCOL_MYSQL41;
714
640
 
715
641
#ifdef HAVE_COMPRESS
716
642
    server_capabilites|= CLIENT_COMPRESS;
717
643
#endif /* HAVE_COMPRESS */
718
644
 
719
 
    end= buff + strlen(PANDORA_RELEASE_VERSION);
 
645
    end= buff + strlen(VERSION);
720
646
    if ((end - buff) >= SERVER_VERSION_LENGTH)
721
647
      end= buff + (SERVER_VERSION_LENGTH - 1);
722
 
    memcpy(buff, PANDORA_RELEASE_VERSION, end - buff);
 
648
    memcpy(buff, VERSION, end - buff);
723
649
    *end= 0;
724
650
    end++;
725
651
 
726
 
    int4store((unsigned char*) end, session->variables.pseudo_thread_id);
 
652
    int4store((unsigned char*) end, global_thread_id);
727
653
    end+= 4;
728
654
 
729
655
    /* We don't use scramble anymore. */
730
 
    memcpy(end, scramble, SCRAMBLE_LENGTH_323);
 
656
    memset(end, 'X', SCRAMBLE_LENGTH_323);
731
657
    end+= SCRAMBLE_LENGTH_323;
732
658
    *end++= 0; /* an empty byte for some reason */
733
659
 
739
665
    end+= 18;
740
666
 
741
667
    /* Write scramble tail. */
742
 
    memcpy(end, scramble + SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
 
668
    memset(end, 'X', SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
743
669
    end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
744
670
    *end++= 0; /* an empty byte for some reason */
745
671
 
753
679
        ||    (pkt_len= drizzleclient_net_read(&net)) == packet_error 
754
680
        || pkt_len < MIN_HANDSHAKE_SIZE)
755
681
    {
756
 
      my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
 
682
      my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
757
683
      return false;
758
684
    }
759
685
  }
760
 
  if (packet.alloc(buffer_length.get()))
 
686
  if (packet.alloc(buffer_length))
761
687
    return false; /* The error is set by alloc(). */
762
688
 
763
689
  client_capabilities= uint2korr(net.read_pos);
764
 
  if (!(client_capabilities & CLIENT_PROTOCOL_MYSQL41))
765
 
  {
766
 
    my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
767
 
    return false;
768
 
  }
 
690
 
769
691
 
770
692
  client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
771
693
  session->max_client_packet_length= uint4korr(net.read_pos + 4);
779
701
 
780
702
  if (end >= (char*) net.read_pos + pkt_len + 2)
781
703
  {
782
 
    my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
 
704
    my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
783
705
    return false;
784
706
  }
785
707
 
791
713
  char *l_db= passwd;
792
714
 
793
715
  /*
794
 
    Only support new password format.
 
716
    Old clients send null-terminated string as password; new clients send
 
717
    the size (1 byte) + string (not null-terminated). Hence in case of empty
 
718
    password both send '\0'.
 
719
 
 
720
    This strlen() can't be easily deleted without changing client.
795
721
 
796
722
    Cast *passwd to an unsigned char, so that it doesn't extend the sign for
797
723
    *passwd > 127 and become 2**32-127+ after casting to uint.
798
724
  */
799
 
  uint32_t passwd_len;
800
 
  if (client_capabilities & CLIENT_SECURE_CONNECTION &&
801
 
      passwd < (char *) net.read_pos + pkt_len)
802
 
  {
803
 
    passwd_len= (unsigned char)(*passwd++);
804
 
    if (passwd_len > 0)
805
 
    {
806
 
      user_identifier->setPasswordType(identifier::User::MYSQL_HASH);
807
 
      user_identifier->setPasswordContext(scramble, SCRAMBLE_LENGTH);
808
 
    }
809
 
  }
810
 
  else
811
 
  {
812
 
    passwd_len= 0;
813
 
  }
814
 
 
815
 
  if (client_capabilities & CLIENT_CONNECT_WITH_DB &&
816
 
      passwd < (char *) net.read_pos + pkt_len)
817
 
  {
818
 
    l_db= l_db + passwd_len + 1;
819
 
  }
820
 
  else
821
 
  {
822
 
    l_db= NULL;
823
 
  }
 
725
  uint32_t passwd_len= client_capabilities & CLIENT_SECURE_CONNECTION ?
 
726
    (unsigned char)(*passwd++) : strlen(passwd);
 
727
  l_db= client_capabilities & CLIENT_CONNECT_WITH_DB ? l_db + passwd_len + 1 : 0;
824
728
 
825
729
  /* strlen() can't be easily deleted without changing client */
826
730
  uint32_t db_len= l_db ? strlen(l_db) : 0;
827
731
 
828
732
  if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
829
733
  {
830
 
    my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
 
734
    my_error(ER_HANDSHAKE_ERROR, MYF(0), session->security_ctx.ip.c_str());
831
735
    return false;
832
736
  }
833
737
 
839
743
    user_len-= 2;
840
744
  }
841
745
 
842
 
  if (client_capabilities & CLIENT_ADMIN)
843
 
  {
844
 
    if ((strncmp(user, "root", 4) == 0) and isAdminAllowed())
845
 
    {
846
 
      is_admin_connection= true;
847
 
    }
848
 
    else
849
 
    {
850
 
      my_error(ER_ADMIN_ACCESS, MYF(0));
851
 
      return false;
852
 
    }
853
 
  }
854
 
 
855
 
  user_identifier->setUser(user);
856
 
  session->setUser(user_identifier);
857
 
 
858
 
  return session->checkUser(string(passwd, passwd_len),
859
 
                            string(l_db ? l_db : ""));
860
 
 
861
 
}
862
 
 
863
 
bool ClientMySQLProtocol::isAdminAllowed(void)
864
 
{
865
 
  if (std::find(mysql_admin_ip_addresses.begin(), mysql_admin_ip_addresses.end(), session->user()->address()) != mysql_admin_ip_addresses.end())
866
 
    return true;
867
 
 
868
 
  return false;
 
746
  session->security_ctx.user.assign(user);
 
747
 
 
748
  return session->checkUser(passwd, passwd_len, l_db);
869
749
}
870
750
 
871
751
bool ClientMySQLProtocol::netStoreData(const unsigned char *from, size_t length)
873
753
  size_t packet_length= packet.length();
874
754
  /*
875
755
     The +9 comes from that strings of length longer than 16M require
876
 
     9 bytes to be stored (see storeLength).
 
756
     9 bytes to be stored (see drizzleclient_net_store_length).
877
757
  */
878
758
  if (packet_length+9+length > packet.alloced_length() &&
879
759
      packet.realloc(packet_length+9+length))
880
760
    return 1;
881
 
  unsigned char *to= storeLength((unsigned char*) packet.ptr()+packet_length, length);
 
761
  unsigned char *to= drizzleclient_net_store_length((unsigned char*) packet.ptr()+packet_length, length);
882
762
  memcpy(to,from,length);
883
763
  packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
884
764
  return 0;
911
791
  drizzleclient_net_write(&net, buff, 5);
912
792
}
913
793
 
914
 
/*
915
 
  Store an integer with simple packing into a output package
916
 
 
917
 
  buffer      Store the packed integer here
918
 
  length    integers to store
919
 
 
920
 
  This is mostly used to store lengths of strings.  We have to cast
921
 
  the result for the LL() becasue of a bug in Forte CC compiler.
922
 
 
923
 
  RETURN
924
 
  Position in 'buffer' after the packed length
925
 
*/
926
 
 
927
 
unsigned char *ClientMySQLProtocol::storeLength(unsigned char *buffer, uint64_t length)
928
 
{
929
 
  if (length < (uint64_t) 251LL)
930
 
  {
931
 
    *buffer=(unsigned char) length;
932
 
    return buffer+1;
933
 
  }
934
 
  /* 251 is reserved for NULL */
935
 
  if (length < (uint64_t) 65536LL)
936
 
  {
937
 
    *buffer++=252;
938
 
    int2store(buffer,(uint32_t) length);
939
 
    return buffer+2;
940
 
  }
941
 
  if (length < (uint64_t) 16777216LL)
942
 
  {
943
 
    *buffer++=253;
944
 
    int3store(buffer,(uint32_t) length);
945
 
    return buffer+3;
946
 
  }
947
 
  *buffer++=254;
948
 
  int8store(buffer,length);
949
 
  return buffer+8;
950
 
}
951
 
 
952
 
void ClientMySQLProtocol::makeScramble(char *scramble)
953
 
{
954
 
  /* This is the MySQL algorithm with minimal changes. */
955
 
  random_seed1= (random_seed1 * 3 + random_seed2) % random_max;
956
 
  random_seed2= (random_seed1 + random_seed2 + 33) % random_max;
957
 
  uint32_t seed= static_cast<uint32_t>((static_cast<double>(random_seed1) / random_max_double) * 0xffffffff);
958
 
 
959
 
  void *pointer= this;
960
 
  uint32_t pointer_seed;
961
 
  memcpy(&pointer_seed, &pointer, 4);
962
 
  uint32_t random1= (seed + pointer_seed) % random_max;
963
 
  uint32_t random2= (seed + session->variables.pseudo_thread_id + net.vio->get_fd()) % random_max;
964
 
 
965
 
  for (char *end= scramble + SCRAMBLE_LENGTH; scramble != end; scramble++)
966
 
  {
967
 
    random1= (random1 * 3 + random2) % random_max;
968
 
    random2= (random1 + random2 + 33) % random_max;
969
 
    *scramble= static_cast<char>((static_cast<double>(random1) / random_max_double) * 94 + 33);
970
 
  }
971
 
}
972
 
 
973
 
void ClientMySQLProtocol::mysql_compose_ip_addresses(vector<string> options)
974
 
{
975
 
  for (vector<string>::iterator it= options.begin();
976
 
       it != options.end();
977
 
       ++it)
978
 
  {
979
 
    tokenize(*it, mysql_admin_ip_addresses, ",", true);
980
 
  }
981
 
}
982
 
 
983
794
static ListenMySQLProtocol *listen_obj= NULL;
984
 
plugin::Create_function<MySQLPassword> *mysql_password= NULL;
985
 
 
986
 
static int init(drizzled::module::Context &context)
987
 
{  
988
 
  /* Initialize random seeds for the MySQL algorithm with minimal changes. */
989
 
  time_t seed_time= time(NULL);
990
 
  random_seed1= seed_time % random_max;
991
 
  random_seed2= (seed_time / 2) % random_max;
992
 
 
993
 
  const module::option_map &vm= context.getOptions();
994
 
 
995
 
  mysql_password= new plugin::Create_function<MySQLPassword>(MySQLPasswordName);
996
 
  context.add(mysql_password);
997
 
 
998
 
  listen_obj= new ListenMySQLProtocol("mysql_protocol", vm["bind-address"].as<std::string>(), true);
999
 
  listen_obj->addCountersToTable();
1000
 
  context.add(listen_obj); 
1001
 
  context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
1002
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("connect_timeout", connect_timeout));
1003
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("read_timeout", read_timeout));
1004
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("write_timeout", write_timeout));
1005
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("retry_count", retry_count));
1006
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("buffer_length", buffer_length));
1007
 
  context.registerVariable(new sys_var_const_string_val("bind_address",
1008
 
                                                        vm["bind-address"].as<std::string>()));
1009
 
 
1010
 
  context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &ListenMySQLProtocol::mysql_counters->max_connections));
1011
 
 
1012
 
  return 0;
1013
 
}
1014
 
 
1015
 
static void init_options(drizzled::module::option_context &context)
1016
 
{
1017
 
  context("port",
1018
 
          po::value<port_constraint>(&port)->default_value(3306),
1019
 
          _("Port number to use for connection or 0 for default to with MySQL "
1020
 
                              "protocol."));
1021
 
  context("connect-timeout",
1022
 
          po::value<timeout_constraint>(&connect_timeout)->default_value(10),
1023
 
          _("Connect Timeout."));
1024
 
  context("read-timeout",
1025
 
          po::value<timeout_constraint>(&read_timeout)->default_value(30),
1026
 
          _("Read Timeout."));
1027
 
  context("write-timeout",
1028
 
          po::value<timeout_constraint>(&write_timeout)->default_value(60),
1029
 
          _("Write Timeout."));
1030
 
  context("retry-count",
1031
 
          po::value<retry_constraint>(&retry_count)->default_value(10),
1032
 
          _("Retry Count."));
1033
 
  context("buffer-length",
1034
 
          po::value<buffer_constraint>(&buffer_length)->default_value(16384),
1035
 
          _("Buffer length."));
1036
 
  context("bind-address",
1037
 
          po::value<string>()->default_value(""),
1038
 
          _("Address to bind to."));
1039
 
  context("max-connections",
1040
 
          po::value<uint32_t>(&ListenMySQLProtocol::mysql_counters->max_connections)->default_value(1000),
1041
 
          _("Maximum simultaneous connections."));
1042
 
  context("admin-ip-addresses",
1043
 
          po::value<vector<string> >()->composing()->notifier(&ClientMySQLProtocol::mysql_compose_ip_addresses),
1044
 
          _("A restrictive IP address list for incoming admin connections."));
1045
 
}
1046
 
 
1047
 
} /* namespace drizzle_plugin */
 
795
 
 
796
static int init(drizzled::plugin::Registry &registry)
 
797
{
 
798
  listen_obj= new ListenMySQLProtocol("mysql_protocol", true);
 
799
  registry.add(listen_obj); 
 
800
  return 0;
 
801
}
 
802
 
 
803
static int deinit(drizzled::plugin::Registry &registry)
 
804
{
 
805
  registry.remove(listen_obj);
 
806
  delete listen_obj;
 
807
  return 0;
 
808
}
 
809
 
 
810
static DRIZZLE_SYSVAR_UINT(port, port, PLUGIN_VAR_RQCMDARG,
 
811
                           N_("Port number to use for connection or 0 for default to with MySQL "
 
812
                              "protocol."),
 
813
                           NULL, NULL, 3306, 0, 65535, 0);
 
814
static DRIZZLE_SYSVAR_UINT(connect_timeout, connect_timeout,
 
815
                           PLUGIN_VAR_RQCMDARG, N_("Connect Timeout."),
 
816
                           NULL, NULL, 10, 1, 300, 0);
 
817
static DRIZZLE_SYSVAR_UINT(read_timeout, read_timeout, PLUGIN_VAR_RQCMDARG,
 
818
                           N_("Read Timeout."), NULL, NULL, 30, 1, 300, 0);
 
819
static DRIZZLE_SYSVAR_UINT(write_timeout, write_timeout, PLUGIN_VAR_RQCMDARG,
 
820
                           N_("Write Timeout."), NULL, NULL, 60, 1, 300, 0);
 
821
static DRIZZLE_SYSVAR_UINT(retry_count, retry_count, PLUGIN_VAR_RQCMDARG,
 
822
                           N_("Retry Count."), NULL, NULL, 10, 1, 100, 0);
 
823
static DRIZZLE_SYSVAR_UINT(buffer_length, buffer_length, PLUGIN_VAR_RQCMDARG,
 
824
                           N_("Buffer length."), NULL, NULL, 16384, 1024,
 
825
                           1024*1024, 0);
 
826
static DRIZZLE_SYSVAR_STR(bind_address, bind_address, PLUGIN_VAR_READONLY,
 
827
                          N_("Address to bind to."), NULL, NULL, NULL);
 
828
 
 
829
static drizzle_sys_var* system_variables[]= {
 
830
  DRIZZLE_SYSVAR(port),
 
831
  DRIZZLE_SYSVAR(connect_timeout),
 
832
  DRIZZLE_SYSVAR(read_timeout),
 
833
  DRIZZLE_SYSVAR(write_timeout),
 
834
  DRIZZLE_SYSVAR(retry_count),
 
835
  DRIZZLE_SYSVAR(buffer_length),
 
836
  DRIZZLE_SYSVAR(bind_address),
 
837
  NULL
 
838
};
1048
839
 
1049
840
DRIZZLE_DECLARE_PLUGIN
1050
841
{
1051
842
  DRIZZLE_VERSION_ID,
1052
 
  "mysql-protocol",
 
843
  "mysql_protocol",
1053
844
  "0.1",
1054
845
  "Eric Day",
1055
846
  "MySQL Protocol Module",
1056
847
  PLUGIN_LICENSE_GPL,
1057
 
  drizzle_plugin::init,             /* Plugin Init */
1058
 
  NULL, /* depends */
1059
 
  drizzle_plugin::init_options    /* config options */
 
848
  init,             /* Plugin Init */
 
849
  deinit,           /* Plugin Deinit */
 
850
  NULL,             /* status variables */
 
851
  system_variables, /* system variables */
 
852
  NULL              /* config options */
1060
853
}
1061
854
DRIZZLE_DECLARE_PLUGIN_END;