00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021 #include <drizzled/gettext.h>
00022 #include <drizzled/error.h>
00023 #include <drizzled/query_id.h>
00024 #include <drizzled/error/sql_state.h>
00025 #include <drizzled/session.h>
00026 #include <drizzled/internal/m_string.h>
00027 #include <algorithm>
00028 #include <boost/program_options.hpp>
00029 #include <drizzled/module/option_map.h>
00030 #include <drizzled/util/tokenize.h>
00031 #include "errmsg.h"
00032 #include "mysql_protocol.h"
00033 #include "mysql_password.h"
00034 #include "options.h"
00035 #include <drizzled/identifier.h>
00036 #include <drizzled/plugin/function.h>
00037 #include <libdrizzle/constants.h>
00038
00039 #define PROTOCOL_VERSION 10
00040
00041 namespace po= boost::program_options;
00042 using namespace std;
00043 using namespace drizzled;
00044
00045 namespace drizzle_plugin
00046 {
00047
00048 std::vector<std::string> ClientMySQLProtocol::mysql_admin_ip_addresses;
00049 static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
00050
00051 static port_constraint port;
00052 static timeout_constraint connect_timeout;
00053 static timeout_constraint read_timeout;
00054 static timeout_constraint write_timeout;
00055 static retry_constraint retry_count;
00056 static buffer_constraint buffer_length;
00057
00058 static uint32_t random_seed1;
00059 static uint32_t random_seed2;
00060 static const uint32_t random_max= 0x3FFFFFFF;
00061 static const double random_max_double= (double)0x3FFFFFFF;
00062
00063
00064 ProtocolCounters *ListenMySQLProtocol::mysql_counters= new ProtocolCounters();
00065
00066 ListenMySQLProtocol::~ListenMySQLProtocol()
00067 { }
00068
00069 void ListenMySQLProtocol::addCountersToTable()
00070 {
00071 counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connection_count"), &getCounters()->connectionCount));
00072 counters.push_back(new drizzled::plugin::ListenCounter(new std::string("connected"), &getCounters()->connected));
00073 counters.push_back(new drizzled::plugin::ListenCounter(new std::string("failed_connections"), &getCounters()->failedConnections));
00074 }
00075
00076 const std::string ListenMySQLProtocol::getHost(void) const
00077 {
00078 return _hostname;
00079 }
00080
00081 in_port_t ListenMySQLProtocol::getPort(void) const
00082 {
00083 return port.get();
00084 }
00085
00086 plugin::Client *ListenMySQLProtocol::getClient(int fd)
00087 {
00088 int new_fd;
00089 new_fd= acceptTcp(fd);
00090 if (new_fd == -1)
00091 return NULL;
00092
00093 return new ClientMySQLProtocol(new_fd, _using_mysql41_protocol, getCounters());
00094 }
00095
00096 ClientMySQLProtocol::ClientMySQLProtocol(int fd, bool using_mysql41_protocol, ProtocolCounters *set_counters):
00097 is_admin_connection(false),
00098 _using_mysql41_protocol(using_mysql41_protocol),
00099 _is_interactive(false),
00100 counters(set_counters)
00101 {
00102
00103 net.vio= 0;
00104
00105 if (fd == -1)
00106 return;
00107
00108 if (drizzleclient_net_init_sock(&net, fd, buffer_length.get()))
00109 throw bad_alloc();
00110
00111 drizzleclient_net_set_read_timeout(&net, read_timeout.get());
00112 drizzleclient_net_set_write_timeout(&net, write_timeout.get());
00113 net.retry_count=retry_count.get();
00114 }
00115
00116 ClientMySQLProtocol::~ClientMySQLProtocol()
00117 {
00118 if (net.vio)
00119 net.vio->close();
00120 }
00121
00122 int ClientMySQLProtocol::getFileDescriptor(void)
00123 {
00124 return drizzleclient_net_get_sd(&net);
00125 }
00126
00127 bool ClientMySQLProtocol::isConnected()
00128 {
00129 return net.vio != 0;
00130 }
00131
00132 bool ClientMySQLProtocol::isReading(void)
00133 {
00134 return net.reading_or_writing == 1;
00135 }
00136
00137 bool ClientMySQLProtocol::isWriting(void)
00138 {
00139 return net.reading_or_writing == 2;
00140 }
00141
00142 bool ClientMySQLProtocol::flush()
00143 {
00144 if (net.vio == NULL)
00145 return false;
00146 bool ret= drizzleclient_net_write(&net, (unsigned char*) packet.ptr(),
00147 packet.length());
00148 packet.length(0);
00149 return ret;
00150 }
00151
00152 void ClientMySQLProtocol::close(void)
00153 {
00154 if (net.vio)
00155 {
00156 drizzleclient_net_close(&net);
00157 drizzleclient_net_end(&net);
00158 if (is_admin_connection)
00159 {
00160 counters->adminConnected.decrement();
00161 }
00162 else
00163 {
00164 counters->connected.decrement();
00165 }
00166 }
00167 }
00168
00169 bool ClientMySQLProtocol::authenticate()
00170 {
00171 bool connection_is_valid;
00172 if (is_admin_connection)
00173 {
00174 counters->adminConnectionCount.increment();
00175 counters->adminConnected.increment();
00176 }
00177 else
00178 {
00179 counters->connectionCount.increment();
00180 counters->connected.increment();
00181 }
00182
00183
00184 drizzleclient_net_set_read_timeout(&net, connect_timeout.get());
00185 drizzleclient_net_set_write_timeout(&net, connect_timeout.get());
00186
00187 connection_is_valid= checkConnection();
00188
00189 if (connection_is_valid)
00190 {
00191 if (not is_admin_connection and (counters->connected > counters->max_connections))
00192 {
00193 std::string errmsg(ER(ER_CON_COUNT_ERROR));
00194 sendError(ER_CON_COUNT_ERROR, errmsg.c_str());
00195 counters->failedConnections.increment();
00196 }
00197 else
00198 {
00199 sendOK();
00200 }
00201 }
00202 else
00203 {
00204 sendError(session->main_da.sql_errno(), session->main_da.message());
00205 counters->failedConnections.increment();
00206 return false;
00207 }
00208
00209
00210 drizzleclient_net_set_read_timeout(&net, read_timeout.get());
00211 drizzleclient_net_set_write_timeout(&net, write_timeout.get());
00212 return true;
00213 }
00214
00215 bool ClientMySQLProtocol::readCommand(char **l_packet, uint32_t *packet_length)
00216 {
00217
00218
00219
00220
00221
00222
00223 #ifdef NEVER
00224
00225
00226 drizzleclient_net_set_read_timeout(&net,
00227 session->variables.net_wait_timeout);
00228 #endif
00229
00230 net.pkt_nr=0;
00231
00232 *packet_length= drizzleclient_net_read(&net);
00233 if (*packet_length == packet_error)
00234 {
00235
00236
00237 if(net.last_errno== ER_NET_PACKET_TOO_LARGE)
00238 my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
00239 if (session->main_da.status() == Diagnostics_area::DA_ERROR)
00240 sendError(session->main_da.sql_errno(), session->main_da.message());
00241 else
00242 sendOK();
00243
00244 if (net.error != 3)
00245 return false;
00246
00247 net.error= 0;
00248 }
00249
00250 *l_packet= (char*) net.read_pos;
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 if (*packet_length == 0)
00262 {
00263
00264 (*l_packet)[0]= (unsigned char) COM_SLEEP;
00265 *packet_length= 1;
00266 }
00267 else if (_using_mysql41_protocol)
00268 {
00269
00270 switch ((int)(*l_packet)[0])
00271 {
00272 case 0:
00273 case 1:
00274 case 2:
00275 case 3:
00276 break;
00277
00278 case 8:
00279 (*l_packet)[0]= (unsigned char) COM_SHUTDOWN;
00280 break;
00281
00282 case 12:
00283 (*l_packet)[0]= (unsigned char) COM_KILL;
00284 break;
00285
00286 case 14:
00287 (*l_packet)[0]= (unsigned char) COM_PING;
00288 break;
00289
00290
00291 default:
00292
00293 (*l_packet)[0]= (unsigned char) COM_END;
00294 *packet_length= 1;
00295 break;
00296 }
00297 }
00298
00299
00300 (*l_packet)[*packet_length]= '\0';
00301
00302 #ifdef NEVER
00303
00304
00305 drizzleclient_net_set_read_timeout(&net,
00306 session->variables.net_read_timeout);
00307 #endif
00308
00309 return true;
00310 }
00311
00333 void ClientMySQLProtocol::sendOK()
00334 {
00335 unsigned char buff[DRIZZLE_ERRMSG_SIZE+10],*pos;
00336 const char *message= NULL;
00337 uint32_t tmp;
00338
00339 if (!net.vio)
00340 {
00341 return;
00342 }
00343
00344 buff[0]=0;
00345 if (session->main_da.status() == Diagnostics_area::DA_OK)
00346 {
00347 if (client_capabilities & CLIENT_FOUND_ROWS && session->main_da.found_rows())
00348 pos=storeLength(buff+1,session->main_da.found_rows());
00349 else
00350 pos=storeLength(buff+1,session->main_da.affected_rows());
00351 pos=storeLength(pos, session->main_da.last_insert_id());
00352 int2store(pos, session->main_da.server_status());
00353 pos+=2;
00354 tmp= min(session->main_da.total_warn_count(), (uint32_t)65535);
00355 message= session->main_da.message();
00356 }
00357 else
00358 {
00359 pos=storeLength(buff+1,0);
00360 pos=storeLength(pos, 0);
00361 int2store(pos, session->server_status);
00362 pos+=2;
00363 tmp= min(session->total_warn_count, (uint32_t)65535);
00364 }
00365
00366
00367 int2store(pos, tmp);
00368 pos+= 2;
00369
00370 session->main_da.can_overwrite_status= true;
00371
00372 if (message && message[0])
00373 {
00374 size_t length= strlen(message);
00375 pos=storeLength(pos,length);
00376 memcpy(pos,(unsigned char*) message,length);
00377 pos+=length;
00378 }
00379 drizzleclient_net_write(&net, buff, (size_t) (pos-buff));
00380 drizzleclient_net_flush(&net);
00381
00382 session->main_da.can_overwrite_status= false;
00383 }
00384
00400 void ClientMySQLProtocol::sendEOF()
00401 {
00402
00403 if (net.vio != 0)
00404 {
00405 session->main_da.can_overwrite_status= true;
00406 writeEOFPacket(session->main_da.server_status(),
00407 session->main_da.total_warn_count());
00408 drizzleclient_net_flush(&net);
00409 session->main_da.can_overwrite_status= false;
00410 }
00411 packet.shrink(buffer_length.get());
00412 }
00413
00414
00415 void ClientMySQLProtocol::sendError(drizzled::error_t sql_errno, const char *err)
00416 {
00417 uint32_t length;
00418
00419
00420
00421 unsigned char buff[2+1+SQLSTATE_LENGTH+DRIZZLE_ERRMSG_SIZE], *pos;
00422
00423 assert(sql_errno != EE_OK);
00424 assert(err && err[0]);
00425
00426
00427
00428
00429
00430 session->main_da.can_overwrite_status= true;
00431
00432
00433 session->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
00434
00443 if (net.vio == 0)
00444 {
00445 return;
00446 }
00447
00448 int2store(buff, static_cast<uint16_t>(sql_errno));
00449 pos= buff+2;
00450
00451
00452 buff[2]= '#';
00453 pos= (unsigned char*) strcpy((char*) buff+3, error::convert_to_sqlstate(sql_errno));
00454 pos+= strlen(error::convert_to_sqlstate(sql_errno));
00455
00456 char *tmp= strncpy((char*)pos, err, DRIZZLE_ERRMSG_SIZE-1);
00457 tmp+= strlen((char*)pos);
00458 tmp[0]= '\0';
00459 length= (uint32_t)(tmp-(char*)buff);
00460 err= (char*) buff;
00461
00462 drizzleclient_net_write_command(&net,(unsigned char) 255, (unsigned char*) "", 0, (unsigned char*) err, length);
00463
00464 drizzleclient_net_flush(&net);
00465
00466 session->main_da.can_overwrite_status= false;
00467 }
00468
00487 bool ClientMySQLProtocol::sendFields(List<Item> *list)
00488 {
00489 List<Item>::iterator it(list->begin());
00490 Item *item;
00491 unsigned char buff[80];
00492 String tmp((char*) buff,sizeof(buff),&my_charset_bin);
00493
00494 unsigned char *row_pos= storeLength(buff, list->size());
00495 (void) drizzleclient_net_write(&net, buff, (size_t) (row_pos-buff));
00496
00497 while ((item=it++))
00498 {
00499 char *pos;
00500 SendField field;
00501 item->make_field(&field);
00502
00503 packet.length(0);
00504
00505 if (store(STRING_WITH_LEN("def")) ||
00506 store(field.db_name) ||
00507 store(field.table_name) ||
00508 store(field.org_table_name) ||
00509 store(field.col_name) ||
00510 store(field.org_col_name) ||
00511 packet.realloc(packet.length()+12))
00512 goto err;
00513
00514
00515 pos= (char*) packet.ptr()+packet.length();
00516 *pos++= 12;
00517
00518 int2store(pos, field.charsetnr);
00519 int4store(pos+2, field.length);
00520
00521 if (_using_mysql41_protocol)
00522 {
00523
00524 switch (field.type)
00525 {
00526 case DRIZZLE_TYPE_LONG:
00527 pos[6]= DRIZZLE_COLUMN_TYPE_LONG;
00528 break;
00529
00530 case DRIZZLE_TYPE_DOUBLE:
00531 pos[6]= DRIZZLE_COLUMN_TYPE_DOUBLE;
00532 break;
00533
00534 case DRIZZLE_TYPE_NULL:
00535 pos[6]= DRIZZLE_COLUMN_TYPE_NULL;
00536 break;
00537
00538 case DRIZZLE_TYPE_TIMESTAMP:
00539 pos[6]= DRIZZLE_COLUMN_TYPE_TIMESTAMP;
00540 break;
00541
00542 case DRIZZLE_TYPE_LONGLONG:
00543 pos[6]= DRIZZLE_COLUMN_TYPE_LONGLONG;
00544 break;
00545
00546 case DRIZZLE_TYPE_DATETIME:
00547 pos[6]= DRIZZLE_COLUMN_TYPE_DATETIME;
00548 break;
00549
00550 case DRIZZLE_TYPE_TIME:
00551 pos[6]= DRIZZLE_COLUMN_TYPE_TIME;
00552 break;
00553
00554 case DRIZZLE_TYPE_DATE:
00555 pos[6]= DRIZZLE_COLUMN_TYPE_DATE;
00556 break;
00557
00558 case DRIZZLE_TYPE_VARCHAR:
00559 pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
00560 break;
00561
00562 case DRIZZLE_TYPE_MICROTIME:
00563 pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
00564 break;
00565
00566 case DRIZZLE_TYPE_UUID:
00567 pos[6]= DRIZZLE_COLUMN_TYPE_VARCHAR;
00568 break;
00569
00570 case DRIZZLE_TYPE_BOOLEAN:
00571 pos[6]= DRIZZLE_COLUMN_TYPE_TINY;
00572 break;
00573
00574 case DRIZZLE_TYPE_DECIMAL:
00575 pos[6]= (char)DRIZZLE_COLUMN_TYPE_NEWDECIMAL;
00576 break;
00577
00578 case DRIZZLE_TYPE_ENUM:
00579 pos[6]= (char)DRIZZLE_COLUMN_TYPE_ENUM;
00580 break;
00581
00582 case DRIZZLE_TYPE_BLOB:
00583 pos[6]= (char)DRIZZLE_COLUMN_TYPE_BLOB;
00584 break;
00585 }
00586 }
00587 else
00588 {
00589
00590 pos[6]= field.type + 1;
00591 }
00592
00593 int2store(pos+7,field.flags);
00594 pos[9]= (char) field.decimals;
00595 pos[10]= 0;
00596 pos[11]= 0;
00597 pos+= 12;
00598
00599 packet.length((uint32_t) (pos - packet.ptr()));
00600 if (flush())
00601 break;
00602 }
00603
00604
00605
00606
00607
00608
00609 writeEOFPacket(session->server_status, session->total_warn_count);
00610 return 0;
00611
00612 err:
00613 my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
00614 MYF(0));
00615 return 1;
00616 }
00617
00618 bool ClientMySQLProtocol::store(Field *from)
00619 {
00620 if (from->is_null())
00621 return store();
00622 if (from->type() == DRIZZLE_TYPE_BOOLEAN)
00623 {
00624 return store(from->val_int());
00625 }
00626
00627 char buff[MAX_FIELD_WIDTH];
00628 String str(buff,sizeof(buff), &my_charset_bin);
00629
00630 from->val_str_internal(&str);
00631
00632 return netStoreData((const unsigned char *)str.ptr(), str.length());
00633 }
00634
00635 bool ClientMySQLProtocol::store(void)
00636 {
00637 char buff[1];
00638 buff[0]= (char)251;
00639 return packet.append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
00640 }
00641
00642 bool ClientMySQLProtocol::store(int32_t from)
00643 {
00644 char buff[12];
00645 return netStoreData((unsigned char*) buff,
00646 (size_t) (internal::int10_to_str(from, buff, -10) - buff));
00647 }
00648
00649 bool ClientMySQLProtocol::store(uint32_t from)
00650 {
00651 char buff[11];
00652 return netStoreData((unsigned char*) buff,
00653 (size_t) (internal::int10_to_str(from, buff, 10) - buff));
00654 }
00655
00656 bool ClientMySQLProtocol::store(int64_t from)
00657 {
00658 char buff[22];
00659 return netStoreData((unsigned char*) buff,
00660 (size_t) (internal::int64_t10_to_str(from, buff, -10) - buff));
00661 }
00662
00663 bool ClientMySQLProtocol::store(uint64_t from)
00664 {
00665 char buff[21];
00666 return netStoreData((unsigned char*) buff,
00667 (size_t) (internal::int64_t10_to_str(from, buff, 10) - buff));
00668 }
00669
00670 bool ClientMySQLProtocol::store(double from, uint32_t decimals, String *buffer)
00671 {
00672 buffer->set_real(from, decimals, session->charset());
00673 return netStoreData((unsigned char*) buffer->ptr(), buffer->length());
00674 }
00675
00676 bool ClientMySQLProtocol::store(const char *from, size_t length)
00677 {
00678 return netStoreData((const unsigned char *)from, length);
00679 }
00680
00681 bool ClientMySQLProtocol::wasAborted(void)
00682 {
00683 return net.error && net.vio != 0;
00684 }
00685
00686 bool ClientMySQLProtocol::haveMoreData(void)
00687 {
00688 return drizzleclient_net_more_data(&net);
00689 }
00690
00691 bool ClientMySQLProtocol::haveError(void)
00692 {
00693 return net.error || net.vio == 0;
00694 }
00695
00696 bool ClientMySQLProtocol::checkConnection(void)
00697 {
00698 uint32_t pkt_len= 0;
00699 char *end;
00700 char scramble[SCRAMBLE_LENGTH];
00701 identifier::User::shared_ptr user_identifier= identifier::User::make_shared();
00702
00703 makeScramble(scramble);
00704
00705
00706 {
00707 char ip[NI_MAXHOST];
00708 uint16_t peer_port;
00709
00710 if (drizzleclient_net_peer_addr(&net, ip, &peer_port, NI_MAXHOST))
00711 {
00712 my_error(ER_BAD_HOST_ERROR, MYF(0), ip);
00713 return false;
00714 }
00715
00716 user_identifier->setAddress(ip);
00717 }
00718 drizzleclient_net_keepalive(&net, true);
00719
00720 uint32_t server_capabilites;
00721 {
00722
00723 char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
00724
00725 server_capabilites= CLIENT_BASIC_FLAGS;
00726
00727 if (_using_mysql41_protocol)
00728 {
00729 server_capabilites|= CLIENT_PROTOCOL_MYSQL41;
00730 }
00731
00732 #ifdef HAVE_COMPRESS
00733 server_capabilites|= CLIENT_COMPRESS;
00734 #endif
00735
00736 end= buff + strlen(PANDORA_RELEASE_VERSION);
00737 if ((end - buff) >= SERVER_VERSION_LENGTH)
00738 end= buff + (SERVER_VERSION_LENGTH - 1);
00739 memcpy(buff, PANDORA_RELEASE_VERSION, end - buff);
00740 *end= 0;
00741 end++;
00742
00743 int4store((unsigned char*) end, session->variables.pseudo_thread_id);
00744 end+= 4;
00745
00746
00747 memcpy(end, scramble, SCRAMBLE_LENGTH_323);
00748 end+= SCRAMBLE_LENGTH_323;
00749 *end++= 0;
00750
00751 int2store(end, server_capabilites);
00752
00753 end[2]=(char) default_charset_info->number;
00754 int2store(end+3, session->server_status);
00755 memset(end+5, 0, 13);
00756 end+= 18;
00757
00758
00759 memcpy(end, scramble + SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
00760 end+= (SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
00761 *end++= 0;
00762
00763
00764 if (drizzleclient_net_write_command(&net
00765 , (unsigned char) PROTOCOL_VERSION
00766 , (unsigned char*) ""
00767 , 0
00768 , (unsigned char*) buff
00769 , (size_t) (end-buff))
00770 || (pkt_len= drizzleclient_net_read(&net)) == packet_error
00771 || pkt_len < MIN_HANDSHAKE_SIZE)
00772 {
00773 my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
00774 return false;
00775 }
00776 }
00777 if (packet.alloc(buffer_length.get()))
00778 return false;
00779
00780 client_capabilities= uint2korr(net.read_pos);
00781 if (!(client_capabilities & CLIENT_PROTOCOL_MYSQL41))
00782 {
00783 my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
00784 return false;
00785 }
00786
00787 client_capabilities|= ((uint32_t) uint2korr(net.read_pos + 2)) << 16;
00788 session->max_client_packet_length= uint4korr(net.read_pos + 4);
00789 end= (char*) net.read_pos + 32;
00790
00791
00792
00793
00794
00795 client_capabilities&= server_capabilites;
00796
00797 if (end >= (char*) net.read_pos + pkt_len + 2)
00798 {
00799 my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
00800 return false;
00801 }
00802
00803 net.return_status= &session->server_status;
00804
00805 char *user= end;
00806 char *passwd= strchr(user, '\0')+1;
00807 uint32_t user_len= passwd - user - 1;
00808 char *l_db= passwd;
00809
00810
00811
00812
00813
00814
00815
00816 uint32_t passwd_len;
00817 if (client_capabilities & CLIENT_SECURE_CONNECTION &&
00818 passwd < (char *) net.read_pos + pkt_len)
00819 {
00820 passwd_len= (unsigned char)(*passwd++);
00821 if (passwd_len > 0 and client_capabilities & CLIENT_CAPABILITIES_PLUGIN_AUTH)
00822 {
00823 user_identifier->setPasswordType(identifier::User::PLAIN_TEXT);
00824 }
00825 else if (passwd_len > 0)
00826 {
00827 user_identifier->setPasswordType(identifier::User::MYSQL_HASH);
00828 user_identifier->setPasswordContext(scramble, SCRAMBLE_LENGTH);
00829 }
00830 }
00831 else
00832 {
00833 passwd_len= 0;
00834 }
00835
00836 if (client_capabilities & CLIENT_CONNECT_WITH_DB &&
00837 passwd < (char *) net.read_pos + pkt_len)
00838 {
00839 l_db= l_db + passwd_len + 1;
00840 }
00841 else
00842 {
00843 l_db= NULL;
00844 }
00845
00846
00847 uint32_t db_len= l_db ? strlen(l_db) : 0;
00848
00849 if (passwd + passwd_len + db_len > (char *) net.read_pos + pkt_len)
00850 {
00851 my_error(ER_HANDSHAKE_ERROR, MYF(0), user_identifier->address().c_str());
00852 return false;
00853 }
00854
00855
00856 if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
00857 {
00858 user[user_len-1]= 0;
00859 user++;
00860 user_len-= 2;
00861 }
00862
00863 if (client_capabilities & CLIENT_ADMIN)
00864 {
00865 if ((strncmp(user, "root", 4) == 0) and isAdminAllowed())
00866 {
00867 is_admin_connection= true;
00868 }
00869 else
00870 {
00871 my_error(ER_ADMIN_ACCESS, MYF(0));
00872 return false;
00873 }
00874 }
00875
00876 if (client_capabilities & CLIENT_INTERACTIVE)
00877 {
00878 _is_interactive= true;
00879 }
00880
00881 if (client_capabilities & CLIENT_CAPABILITIES_PLUGIN_AUTH)
00882 {
00883 passwd_len= strlen(passwd);
00884 }
00885
00886 user_identifier->setUser(user);
00887 session->setUser(user_identifier);
00888
00889 return session->checkUser(string(passwd, passwd_len),
00890 string(l_db ? l_db : ""));
00891
00892 }
00893
00894 bool ClientMySQLProtocol::isAdminAllowed(void)
00895 {
00896 if (std::find(mysql_admin_ip_addresses.begin(), mysql_admin_ip_addresses.end(), session->user()->address()) != mysql_admin_ip_addresses.end())
00897 return true;
00898
00899 return false;
00900 }
00901
00902 bool ClientMySQLProtocol::netStoreData(const unsigned char *from, size_t length)
00903 {
00904 size_t packet_length= packet.length();
00905
00906
00907
00908
00909 if (packet_length+9+length > packet.alloced_length() &&
00910 packet.realloc(packet_length+9+length))
00911 return 1;
00912 unsigned char *to= storeLength((unsigned char*) packet.ptr()+packet_length, length);
00913 memcpy(to,from,length);
00914 packet.length((size_t) (to+length-(unsigned char*) packet.ptr()));
00915 return 0;
00916 }
00917
00923 void ClientMySQLProtocol::writeEOFPacket(uint32_t server_status,
00924 uint32_t total_warn_count)
00925 {
00926 unsigned char buff[5];
00927
00928
00929
00930
00931 uint32_t tmp= min(total_warn_count, (uint32_t)65535);
00932 buff[0]= DRIZZLE_PROTOCOL_NO_MORE_DATA;
00933 int2store(buff+1, tmp);
00934
00935
00936
00937
00938
00939 if (session->is_fatal_error)
00940 server_status&= ~SERVER_MORE_RESULTS_EXISTS;
00941 int2store(buff + 3, server_status);
00942 drizzleclient_net_write(&net, buff, 5);
00943 }
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958 unsigned char *ClientMySQLProtocol::storeLength(unsigned char *buffer, uint64_t length)
00959 {
00960 if (length < (uint64_t) 251LL)
00961 {
00962 *buffer=(unsigned char) length;
00963 return buffer+1;
00964 }
00965
00966 if (length < (uint64_t) 65536LL)
00967 {
00968 *buffer++=252;
00969 int2store(buffer,(uint32_t) length);
00970 return buffer+2;
00971 }
00972 if (length < (uint64_t) 16777216LL)
00973 {
00974 *buffer++=253;
00975 int3store(buffer,(uint32_t) length);
00976 return buffer+3;
00977 }
00978 *buffer++=254;
00979 int8store(buffer,length);
00980 return buffer+8;
00981 }
00982
00983 void ClientMySQLProtocol::makeScramble(char *scramble)
00984 {
00985
00986 random_seed1= (random_seed1 * 3 + random_seed2) % random_max;
00987 random_seed2= (random_seed1 + random_seed2 + 33) % random_max;
00988 uint32_t seed= static_cast<uint32_t>((static_cast<double>(random_seed1) / random_max_double) * 0xffffffff);
00989
00990 void *pointer= this;
00991 uint32_t pointer_seed;
00992 memcpy(&pointer_seed, &pointer, 4);
00993 uint32_t random1= (seed + pointer_seed) % random_max;
00994 uint32_t random2= (seed + session->variables.pseudo_thread_id + net.vio->get_fd()) % random_max;
00995
00996 for (char *end= scramble + SCRAMBLE_LENGTH; scramble != end; scramble++)
00997 {
00998 random1= (random1 * 3 + random2) % random_max;
00999 random2= (random1 + random2 + 33) % random_max;
01000 *scramble= static_cast<char>((static_cast<double>(random1) / random_max_double) * 94 + 33);
01001 }
01002 }
01003
01004 void ClientMySQLProtocol::mysql_compose_ip_addresses(vector<string> options)
01005 {
01006 for (vector<string>::iterator it= options.begin();
01007 it != options.end();
01008 ++it)
01009 {
01010 tokenize(*it, mysql_admin_ip_addresses, ",", true);
01011 }
01012 }
01013
01014 static ListenMySQLProtocol *listen_obj= NULL;
01015 plugin::Create_function<MySQLPassword> *mysql_password= NULL;
01016
01017 static int init(drizzled::module::Context &context)
01018 {
01019
01020 time_t seed_time= time(NULL);
01021 random_seed1= seed_time % random_max;
01022 random_seed2= (seed_time / 2) % random_max;
01023
01024 const module::option_map &vm= context.getOptions();
01025
01026 mysql_password= new plugin::Create_function<MySQLPassword>(MySQLPasswordName);
01027 context.add(mysql_password);
01028
01029 listen_obj= new ListenMySQLProtocol("mysql_protocol", vm["bind-address"].as<std::string>(), true);
01030 listen_obj->addCountersToTable();
01031 context.add(listen_obj);
01032 context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
01033 context.registerVariable(new sys_var_constrained_value<uint32_t>("connect_timeout", connect_timeout));
01034 context.registerVariable(new sys_var_constrained_value<uint32_t>("read_timeout", read_timeout));
01035 context.registerVariable(new sys_var_constrained_value<uint32_t>("write_timeout", write_timeout));
01036 context.registerVariable(new sys_var_constrained_value<uint32_t>("retry_count", retry_count));
01037 context.registerVariable(new sys_var_constrained_value<uint32_t>("buffer_length", buffer_length));
01038 context.registerVariable(new sys_var_const_string_val("bind_address",
01039 vm["bind-address"].as<std::string>()));
01040
01041 context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &ListenMySQLProtocol::mysql_counters->max_connections));
01042
01043 return 0;
01044 }
01045
01046 static void init_options(drizzled::module::option_context &context)
01047 {
01048 context("port",
01049 po::value<port_constraint>(&port)->default_value(3306),
01050 _("Port number to use for connection or 0 for default to with MySQL "
01051 "protocol."));
01052 context("connect-timeout",
01053 po::value<timeout_constraint>(&connect_timeout)->default_value(10),
01054 _("Connect Timeout."));
01055 context("read-timeout",
01056 po::value<timeout_constraint>(&read_timeout)->default_value(30),
01057 _("Read Timeout."));
01058 context("write-timeout",
01059 po::value<timeout_constraint>(&write_timeout)->default_value(60),
01060 _("Write Timeout."));
01061 context("retry-count",
01062 po::value<retry_constraint>(&retry_count)->default_value(10),
01063 _("Retry Count."));
01064 context("buffer-length",
01065 po::value<buffer_constraint>(&buffer_length)->default_value(16384),
01066 _("Buffer length."));
01067 context("bind-address",
01068 po::value<string>()->default_value("localhost"),
01069 _("Address to bind to."));
01070 context("max-connections",
01071 po::value<uint32_t>(&ListenMySQLProtocol::mysql_counters->max_connections)->default_value(1000),
01072 _("Maximum simultaneous connections."));
01073 context("admin-ip-addresses",
01074 po::value<vector<string> >()->composing()->notifier(&ClientMySQLProtocol::mysql_compose_ip_addresses),
01075 _("A restrictive IP address list for incoming admin connections."));
01076 }
01077
01078 }
01079
01080 DRIZZLE_DECLARE_PLUGIN
01081 {
01082 DRIZZLE_VERSION_ID,
01083 "mysql-protocol",
01084 "0.1",
01085 "Eric Day",
01086 "MySQL Protocol Module",
01087 PLUGIN_LICENSE_GPL,
01088 drizzle_plugin::init,
01089 NULL,
01090 drizzle_plugin::init_options
01091 }
01092 DRIZZLE_DECLARE_PLUGIN_END;