diff --git a/handlersocket/database.cpp b/handlersocket/database.cpp index 66706e6..0f965c4 100644 --- a/handlersocket/database.cpp +++ b/handlersocket/database.cpp @@ -140,6 +140,7 @@ struct dbcontext : public dbcontext_i, private noncopyable { virtual void cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn, const char *tbl, const char *idx, const char *retflds); virtual void cmd_exec_on_index(dbcallback_i& cb, const cmd_exec_args& args); + virtual void cmd_authorization(dbcallback_i& cb, int type, const char *key ); virtual void set_statistics(size_t num_conns, size_t num_active); private: int set_thread_message(const char *fmt, ...) @@ -378,7 +379,7 @@ dbcontext::lock_tables_if() size_t num_open = 0; for (size_t i = 0; i < num_max; ++i) { if (table_vec[i].refcount > 0) { - tables[num_open++] = table_vec[i].table; + tables[num_open++] = table_vec[i].table; } } #if MYSQL_VERSION_ID >= 50505 @@ -395,7 +396,7 @@ dbcontext::lock_tables_if() if (lock == 0) { lock_failed = true; DENA_VERBOSE(10, fprintf(stderr, "HNDSOCK failed to lock tables %p\n", - thd)); + thd)); } if (for_write_flag) { #if MYSQL_VERSION_ID >= 50505 @@ -421,9 +422,9 @@ dbcontext::unlock_tables_if() suc = (ha_autocommit_or_rollback(thd, 0) == 0); #endif if (!suc) { - commit_error = true; - DENA_VERBOSE(10, fprintf(stderr, - "HNDSOCK unlock tables: commit failed\n")); + commit_error = true; + DENA_VERBOSE(10, fprintf(stderr, + "HNDSOCK unlock tables: commit failed\n")); } } mysql_unlock_tables(thd, lock); @@ -498,12 +499,12 @@ dbcontext::resp_record(dbcallback_i& cb, TABLE *const table, fld->val_str(&rwpstr, &rwpstr); const size_t len = rwpstr.length(); if (len != 0) { - /* non-empty */ - cb.dbcb_resp_entry(rwpstr.ptr(), rwpstr.length()); + /* non-empty */ + cb.dbcb_resp_entry(rwpstr.ptr(), rwpstr.length()); } else { - /* empty */ - static const char empty_str[] = ""; - cb.dbcb_resp_entry(empty_str, 0); + /* empty */ + static const char empty_str[] = ""; + cb.dbcb_resp_entry(empty_str, 0); } } } @@ -646,9 +647,9 @@ dbcontext::cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst, const KEY_PART_INFO & kpt = kinfo.key_part[i]; const string_ref& kval = args.kvals[i]; if (kval.begin() == 0) { - kpt.field->set_null(); + kpt.field->set_null(); } else { - kpt.field->set_notnull(); + kpt.field->set_notnull(); } kpt.field->store(kval.begin(), kval.size(), &my_charset_bin); kplen_sum += kpt.length; @@ -682,24 +683,24 @@ dbcontext::cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst, switch (find_flag) { case HA_READ_BEFORE_KEY: case HA_READ_KEY_OR_PREV: - r = hnd->index_prev(table->record[0]); - break; + r = hnd->index_prev(table->record[0]); + break; case HA_READ_AFTER_KEY: case HA_READ_KEY_OR_NEXT: - r = hnd->index_next(table->record[0]); - break; + r = hnd->index_next(table->record[0]); + break; case HA_READ_KEY_EXACT: - r = hnd->index_next_same(table->record[0], key_buf, kplen_sum); - break; + r = hnd->index_next_same(table->record[0], key_buf, kplen_sum); + break; default: - r = HA_ERR_END_OF_FILE; /* to finish the loop */ - break; + r = HA_ERR_END_OF_FILE; /* to finish the loop */ + break; } } if (debug_out) { fprintf(stderr, "r=%d\n", r); - if (r == 0 || r == HA_ERR_RECORD_DELETED) { - dump_record(cb, table, pst); + if (r == 0 || r == HA_ERR_RECORD_DELETED) { + dump_record(cb, table, pst); } } if (r != 0) { @@ -708,9 +709,9 @@ dbcontext::cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst, --skip; } else { if (!modify_op_flag) { - resp_record(cb, table, pst); + resp_record(cb, table, pst); } else { - r = modify_record(cb, table, pst, args, mod_op, mod_success_count); + r = modify_record(cb, table, pst, args, mod_op, mod_success_count); } } if (r != 0 && r != HA_ERR_RECORD_DELETED) { @@ -768,8 +769,8 @@ dbcontext::cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn, #endif if (table == 0) { DENA_VERBOSE(10, fprintf(stderr, - "HNDSOCK failed to open %p [%s] [%s] [%d]\n", - thd, dbn, tbl, static_cast(refresh))); + "HNDSOCK failed to open %p [%s] [%s] [%d]\n", + thd, dbn, tbl, static_cast(refresh))); return cb.dbcb_resp_short(2, "open_table"); } statistic_increment(open_tables_count, &LOCK_status); @@ -795,8 +796,8 @@ dbcontext::cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn, for (uint i = 0; i < table->s->keys; ++i) { KEY& kinfo = table->key_info[i]; if (strcmp(kinfo.name, idx_name_to_open) == 0) { - idxnum = i; - break; + idxnum = i; + break; } } } @@ -817,12 +818,12 @@ dbcontext::cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn, DBG_FLD(fprintf(stderr, "f %s\n", (*fld)->field_name)); string_ref fn((*fld)->field_name, strlen((*fld)->field_name)); if (fn == fldnms[i]) { - break; + break; } } if (*fld == 0) { DBG_FLD(fprintf(stderr, "UNKNOWN FLD %s [%s]\n", retflds, - std::string(fldnms[i].begin(), fldnms[i].size()).c_str())); + std::string(fldnms[i].begin(), fldnms[i].size()).c_str())); return cb.dbcb_resp_short(2, "fld"); } DBG_FLD(fprintf(stderr, "FLD %s %zu\n", (*fld)->field_name, j)); @@ -895,6 +896,34 @@ dbcontext::cmd_exec_on_index(dbcallback_i& cb, const cmd_exec_args& args) } } +void +dbcontext::cmd_authorization(dbcallback_i& cb, int type, const char* key ) +{ + std::string secret; + if (for_write_flag && dbref->get_conf().get_str("secret_wr" , "" )!="") { + secret = dbref->get_conf().get_str("secret_wr" , "" ); + } else { + secret = dbref->get_conf().get_str("secret" , "" ); + } + switch (type) { + case 1: + if (secret == key) { + cb.set_authorization(true); + cb.dbcb_resp_short(0 , "" ); + } else { + /* authenticated failed */ + cb.set_authorization(false); + cb.dbcb_resp_short(2, "authorization" ); + } + break; + default: + cb.set_authorization(false); + cb.dbcb_resp_short(2, "authtype"); + break; + } + return; +} + void dbcontext::set_statistics(size_t num_conns, size_t num_active) { diff --git a/handlersocket/database.hpp b/handlersocket/database.hpp index 0ea878d..04883bb 100644 --- a/handlersocket/database.hpp +++ b/handlersocket/database.hpp @@ -63,6 +63,8 @@ struct dbcallback_i { virtual void dbcb_resp_entry(const char *fld, size_t fldlen) = 0; virtual void dbcb_resp_end() = 0; virtual void dbcb_resp_cancel() = 0; + virtual void set_authorization( bool authorization ) = 0; + virtual bool get_authorization() = 0; }; struct cmd_exec_args { @@ -94,6 +96,8 @@ struct dbcontext_i { const char *tbl, const char *idx, const char *retflds) = 0; virtual void cmd_exec_on_index(dbcallback_i& cb, const cmd_exec_args& args) = 0; + virtual void cmd_authorization(dbcallback_i& cb, int type, const char *key ) + = 0; virtual void set_statistics(size_t num_conns, size_t num_active) = 0; }; diff --git a/handlersocket/handlersocket.cpp b/handlersocket/handlersocket.cpp index 20a3ea9..4e1dc3c 100644 --- a/handlersocket/handlersocket.cpp +++ b/handlersocket/handlersocket.cpp @@ -38,6 +38,8 @@ static unsigned int handlersocket_rcvbuf = 0; static unsigned int handlersocket_readsize = 0; static unsigned int handlersocket_accept_balance = 0; static unsigned int handlersocket_wrlock_timeout = 0; +static char *handlersocket_secret = 0; +static char *handlersocket_secret_wr = 0; struct daemon_handlersocket_data { hstcpsvr_ptr hssvr_rd; @@ -73,6 +75,8 @@ daemon_handlersocket_init(void *p) conf["readsize"] = to_stdstring(handlersocket_readsize); conf["accept_balance"] = to_stdstring(handlersocket_accept_balance); conf["wrlock_timeout"] = to_stdstring(handlersocket_wrlock_timeout); + if(handlersocket_secret) + conf["secret"] = handlersocket_secret; std::auto_ptr ap(new daemon_handlersocket_data); if (handlersocket_port != 0 && handlersocket_port_wr != handlersocket_port) { conf["port"] = handlersocket_port; @@ -85,6 +89,8 @@ daemon_handlersocket_init(void *p) } conf["port"] = handlersocket_port_wr; conf["for_write"] = "1"; + if(handlersocket_secret_wr) + conf["secret_wr"] = handlersocket_secret_wr; ap->hssvr_wr = hstcpsvr_i::create(conf); ap->hssvr_wr->start_listen(); } @@ -136,6 +142,10 @@ static MYSQL_SYSVAR_UINT(accept_balance, handlersocket_accept_balance, PLUGIN_VAR_READONLY, "0..10000", 0, 0, 0 /* default */, 0, 10000, 0); static MYSQL_SYSVAR_UINT(wrlock_timeout, handlersocket_wrlock_timeout, PLUGIN_VAR_READONLY, "0..3600", 0, 0, 12 /* default */, 0, 3600, 0); +static MYSQL_SYSVAR_STR(secret, handlersocket_secret, PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC, + "", NULL, NULL, NULL); +static MYSQL_SYSVAR_STR(secret_wr, handlersocket_secret_wr, PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC, + "", NULL, NULL, NULL); /* warning: type-punning to incomplete type might break strict-aliasing * rules */ @@ -154,6 +164,8 @@ static struct st_mysql_sys_var *daemon_handlersocket_system_variables[] = { MYSQL_SYSVAR(readsize), MYSQL_SYSVAR(accept_balance), MYSQL_SYSVAR(wrlock_timeout), + MYSQL_SYSVAR(secret), + MYSQL_SYSVAR(secret_wr), 0 }; diff --git a/handlersocket/hstcpsvr_worker.cpp b/handlersocket/hstcpsvr_worker.cpp index e2c72f8..a094610 100644 --- a/handlersocket/hstcpsvr_worker.cpp +++ b/handlersocket/hstcpsvr_worker.cpp @@ -64,6 +64,7 @@ struct hstcpsvr_conn : public dbcallback_i { bool write_finished; time_t nb_last_io; hstcpsvr_conns_type::iterator conns_iter; + bool authorization; public: bool closed() const; bool ok_to_close() const; @@ -80,10 +81,12 @@ struct hstcpsvr_conn : public dbcallback_i { virtual void dbcb_resp_entry(const char *fld, size_t fldlen); virtual void dbcb_resp_end(); virtual void dbcb_resp_cancel(); + virtual void set_authorization(bool authorization); + virtual bool get_authorization(); public: hstcpsvr_conn() : addr_len(sizeof(addr)), readsize(4096), nonblocking(false), read_finished(false), write_finished(false), - nb_last_io(0) { } + nb_last_io(0), authorization(false) { } }; bool @@ -237,6 +240,18 @@ hstcpsvr_conn::dbcb_resp_cancel() cstate.resp_begin_pos = 0; } +void +hstcpsvr_conn::set_authorization(bool authorization) +{ + this->authorization = authorization; +} + +bool +hstcpsvr_conn::get_authorization() +{ + return this->authorization; +} + struct hstcpsvr_worker : public hstcpsvr_worker_i, private noncopyable { hstcpsvr_worker(const hstcpsvr_worker_arg& arg); virtual void run(); @@ -254,6 +269,8 @@ struct hstcpsvr_worker : public hstcpsvr_worker_i, private noncopyable { #endif bool accept_enabled; int accept_balance; + bool need_authorization; + bool need_authorization_wr; private: int run_one_nb(); int run_one_ep(); @@ -262,6 +279,7 @@ struct hstcpsvr_worker : public hstcpsvr_worker_i, private noncopyable { void do_open_index(char *start, char *finish, hstcpsvr_conn& conn); void do_exec_on_index(char *cmd_begin, char *cmd_end, char *start, char *finish, hstcpsvr_conn& conn); + void do_authorization(char *start, char *finish, hstcpsvr_conn& conn); }; hstcpsvr_worker::hstcpsvr_worker(const hstcpsvr_worker_arg& arg) @@ -285,6 +303,12 @@ hstcpsvr_worker::hstcpsvr_worker(const hstcpsvr_worker_arg& arg) events_vec.resize(10240); } #endif + if (cshared.conf.get_str("secret" , "" ) !="") { + need_authorization = true; + need_authorization_wr = true; + } else if ( cshared.conf.get_str("secret_wr" , "" ) !="") { + need_authorization_wr = true; + } accept_balance = cshared.conf.get_int("accept_balance", 0); } @@ -375,15 +399,15 @@ hstcpsvr_worker::run_one_nb() hstcpsvr_conn& conn = **i; if (conn.read_more()) { if (conn.cstate.readbuf.size() > 0) { - const char ch = conn.cstate.readbuf.begin()[0]; - if (ch == 'Q') { - vshared.shutdown = 1; - } else if (ch == '/') { - conn.cstate.readbuf.clear(); - conn.cstate.writebuf.clear(); - conn.read_finished = true; - conn.write_finished = true; - } + const char ch = conn.cstate.readbuf.begin()[0]; + if (ch == 'Q') { + vshared.shutdown = 1; + } else if (ch == '/') { + conn.cstate.readbuf.clear(); + conn.cstate.writebuf.clear(); + conn.read_finished = true; + conn.write_finished = true; + } } conn.nb_last_io = now; } @@ -416,7 +440,7 @@ hstcpsvr_worker::run_one_nb() } if ((pfd.revents & (mask_out | mask_in)) != 0) { if (conn.write_more()) { - conn.nb_last_io = now; + conn.nb_last_io = now; } } if (cshared.sockargs.timeout != 0 && @@ -436,15 +460,15 @@ hstcpsvr_worker::run_one_nb() c->readsize = cshared.readsize; c->accept(cshared); if (c->fd.get() >= 0) { - if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) { - fatal_abort("F_SETFL O_NONBLOCK"); - } - c->nb_last_io = now; - conns.push_back_ptr(c); + if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) { + fatal_abort("F_SETFL O_NONBLOCK"); + } + c->nb_last_io = now; + conns.push_back_ptr(c); } else { - /* errno == 11 (EAGAIN) is not a fatal error. */ - DENA_VERBOSE(100, fprintf(stderr, - "accept failed: errno=%d (not fatal)\n", errno)); + /* errno == 11 (EAGAIN) is not a fatal error. */ + DENA_VERBOSE(100, fprintf(stderr, + "accept failed: errno=%d (not fatal)\n", errno)); } } } @@ -483,22 +507,22 @@ hstcpsvr_worker::run_one_ep() c->readsize = cshared.readsize; c->accept(cshared); if (c->fd.get() >= 0) { - if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) { - fatal_abort("F_SETFL O_NONBLOCK"); - } - epoll_event cev = { }; - cev.events = EPOLLIN | EPOLLOUT | EPOLLET; - cev.data.ptr = c.get(); - c->nb_last_io = now; - const int fd = c->fd.get(); - conns.push_back_ptr(c); - conns.back()->conns_iter = --conns.end(); - if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, fd, &cev) != 0) { - fatal_abort("epoll_ctl EPOLL_CTL_ADD"); - } + if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) { + fatal_abort("F_SETFL O_NONBLOCK"); + } + epoll_event cev = { }; + cev.events = EPOLLIN | EPOLLOUT | EPOLLET; + cev.data.ptr = c.get(); + c->nb_last_io = now; + const int fd = c->fd.get(); + conns.push_back_ptr(c); + conns.back()->conns_iter = --conns.end(); + if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, fd, &cev) != 0) { + fatal_abort("epoll_ctl EPOLL_CTL_ADD"); + } } else { - DENA_VERBOSE(100, fprintf(stderr, - "accept failed: errno=%d (not fatal)\n", errno)); + DENA_VERBOSE(100, fprintf(stderr, + "accept failed: errno=%d (not fatal)\n", errno)); } } else { /* client connection */ @@ -506,11 +530,11 @@ hstcpsvr_worker::run_one_ep() DBG_EP(fprintf(stderr, "IN client\n")); bool more_data = false; while (conn->read_more(&more_data)) { - DBG_EP(fprintf(stderr, "IN client read_more\n")); - conn->nb_last_io = now; - if (!more_data) { - break; - } + DBG_EP(fprintf(stderr, "IN client read_more\n")); + conn->nb_last_io = now; + if (!more_data) { + break; + } } } } @@ -558,11 +582,11 @@ hstcpsvr_worker::run_one_ep() DBG_EP(fprintf(stderr, "OUT client\n")); bool more_data = false; while (conn->write_more(&more_data)) { - DBG_EP(fprintf(stderr, "OUT client write_more\n")); - conn->nb_last_io = now; - if (!more_data) { - break; - } + DBG_EP(fprintf(stderr, "OUT client write_more\n")); + conn->nb_last_io = now; + if (!more_data) { + break; + } } } } @@ -582,8 +606,8 @@ hstcpsvr_worker::run_one_ep() hstcpsvr_conns_type::iterator icur = i; ++i; if (cshared.sockargs.timeout != 0 && - (*icur)->nb_last_io + cshared.sockargs.timeout < now) { - conns.erase_ptr((*icur)->conns_iter); + (*icur)->nb_last_io + cshared.sockargs.timeout < now) { + conns.erase_ptr((*icur)->conns_iter); } } last_check_time = now; @@ -616,20 +640,20 @@ hstcpsvr_worker::run_one_ep() if (e_acc == accept_enabled) { } else if (e_acc) { if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, cshared.listen_fd.get(), &ev) - != 0) { - fatal_abort("epoll_ctl EPOLL_CTL_ADD"); + != 0) { + fatal_abort("epoll_ctl EPOLL_CTL_ADD"); } } else { if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_DEL, cshared.listen_fd.get(), &ev) - != 0) { - fatal_abort("epoll_ctl EPOLL_CTL_ADD"); + != 0) { + fatal_abort("epoll_ctl EPOLL_CTL_ADD"); } } accept_enabled = e_acc; } return 0; } -#endif +#endif void hstcpsvr_worker::execute_lines(hstcpsvr_conn& conn) @@ -663,6 +687,8 @@ hstcpsvr_worker::execute_line(char *start, char *finish, hstcpsvr_conn& conn) if (cmd_begin + 1 == cmd_end) { if (cmd_begin[0] == 'P') { return do_open_index(start, finish, conn); + } else if(cmd_begin[0] == 'A') { + return do_authorization(start, finish, conn); } } if (cmd_begin[0] >= '0' && cmd_begin[0] <= '9') { @@ -674,6 +700,9 @@ hstcpsvr_worker::execute_line(char *start, char *finish, hstcpsvr_conn& conn) void hstcpsvr_worker::do_open_index(char *start, char *finish, hstcpsvr_conn& conn) { + if (need_authorization && !conn.authorization) { + return conn.dbcb_resp_short(2, "no_authorization"); + } const size_t pst_id = read_ui32(start, finish); skip_one(start, finish); /* dbname */ @@ -707,6 +736,9 @@ void hstcpsvr_worker::do_exec_on_index(char *cmd_begin, char *cmd_end, char *start, char *finish, hstcpsvr_conn& conn) { + if (need_authorization && !conn.authorization) { + return conn.dbcb_resp_short(2, "no_authorization"); + } cmd_exec_args args; const size_t pst_id = read_ui32(cmd_begin, cmd_end); if (pst_id >= conn.cstate.prep_stmts.size()) { @@ -743,9 +775,15 @@ hstcpsvr_worker::do_exec_on_index(char *cmd_begin, char *cmd_end, char *start, args.skip = read_ui32(start, finish); if (start == finish) { /* no modification */ + if (args.op == "+" && need_authorization_wr && !conn.authorization) { + return conn.dbcb_resp_short(2, "no_authorization"); + } return dbctx->cmd_exec_on_index(conn, args); } else { /* update or delete */ + if ( need_authorization_wr && !conn.authorization) { + return conn.dbcb_resp_short(2, "no_authorization"); + } skip_one(start, finish); char *const mod_op_begin = start; read_token(start, finish); @@ -767,6 +805,26 @@ hstcpsvr_worker::do_exec_on_index(char *cmd_begin, char *cmd_end, char *start, } } +void +hstcpsvr_worker::do_authorization(char *start, char *finish, hstcpsvr_conn& conn) +{ + /* auth type */ + char *const authtype_begin = start; + read_token(start, finish); + char *const authtype_end = start; + skip_one(start, finish); + /* key */ + char *const key_begin = start; + read_token(start, finish); + char *const key_end = start; + authtype_end[0] = 0; + key_end[0] = 0; + int auth_type = atoi(authtype_begin); + char *wp = key_begin; + unescape_string(wp, key_begin, key_end); + return dbctx->cmd_authorization(conn, auth_type, key_begin); +} + hstcpsvr_worker_ptr hstcpsvr_worker_i::create(const hstcpsvr_worker_arg& arg) {