diff options
author | Alexey Yurchenko <ayurchen@gmail.com> | 2015-06-06 01:08:41 +0300 |
---|---|---|
committer | Nirbhay Choubey <nirbhay@mariadb.com> | 2015-09-09 17:02:26 -0400 |
commit | d78110e7fae1588afcb6bc5ea08be0d84ee18857 (patch) | |
tree | 470b8791eddc944fd2408de44ccf80546452fba1 /sql | |
parent | 4f4f3a5e328524bf1b467a1885b0a21a4e995d9b (diff) | |
download | mariadb-git-d78110e7fae1588afcb6bc5ea08be0d84ee18857.tar.gz |
Refs codership/mysql-wsrep#141: this commit
1. Passes wsrep_sst_auth_value to SST scripts via WSREP_SST_OPT_AUTH envronmental variable, so it never appears on the command line
2. In mysqldump and xtrabackup* SST scripts which rely on MySQL authentication, instead of passing password on the command line, SST script sets MYSQL_PWD environment variable, so that password also never appears on the mysqldump/innobackupex command line.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/wsrep_notify.cc | 2 | ||||
-rw-r--r-- | sql/wsrep_sst.cc | 188 | ||||
-rw-r--r-- | sql/wsrep_utils.cc | 94 | ||||
-rw-r--r-- | sql/wsrep_utils.h | 24 |
4 files changed, 235 insertions, 73 deletions
diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc index 6eefb961b62..e7d30d5a9c1 100644 --- a/sql/wsrep_notify.cc +++ b/sql/wsrep_notify.cc @@ -97,7 +97,7 @@ void wsrep_notify_status (wsrep_member_status_t status, return; } - wsp::process p(cmd_ptr, "r"); + wsp::process p(cmd_ptr, "r", NULL); p.wait(); int err = p.error(); diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 4167740236f..5e1a4973c2a 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -270,12 +270,14 @@ void wsrep_sst_continue () struct sst_thread_arg { const char* cmd; - int err; + char** env; char* ret_str; + int err; mysql_mutex_t lock; mysql_cond_t cond; - sst_thread_arg (const char* c) : cmd(c), err(-1), ret_str(0) + sst_thread_arg (const char* c, char** e) + : cmd(c), env(e), ret_str(0), err(-1) { mysql_mutex_init(key_LOCK_wsrep_sst_thread, &lock, MY_MUTEX_INIT_FAST); mysql_cond_init(key_COND_wsrep_sst_thread, &cond, NULL); @@ -333,7 +335,7 @@ static void* sst_joiner_thread (void* a) WSREP_INFO("Running: '%s'", arg->cmd); - wsp::process proc (arg->cmd, "r"); + wsp::process proc (arg->cmd, "r", arg->env); if (proc.pipe() && !proc.error()) { @@ -407,23 +409,54 @@ static void* sst_joiner_thread (void* a) return NULL; } +#define WSREP_SST_AUTH_ENV "WSREP_SST_OPT_AUTH" + +static int sst_append_auth_env(wsp::env& env, const char* sst_auth) +{ + int const sst_auth_size= strlen(WSREP_SST_AUTH_ENV) + 1 /* = */ + + (sst_auth ? strlen(sst_auth) : 0) + 1 /* \0 */; + + wsp::string sst_auth_str(sst_auth_size); // for automatic cleanup on return + if (!sst_auth_str()) return -ENOMEM; + + int ret= snprintf(sst_auth_str(), sst_auth_size, "%s=%s", + WSREP_SST_AUTH_ENV, sst_auth ? sst_auth : ""); + + if (ret < 0 || ret >= sst_auth_size) + { + WSREP_ERROR("sst_append_auth_env(): snprintf() failed: %d", ret); + return (ret < 0 ? ret : -EMSGSIZE); + } + + env.append(sst_auth_str()); + return -env.error(); +} + static ssize_t sst_prepare_other (const char* method, + const char* sst_auth, const char* addr_in, const char** addr_out) { - char cmd_str[1024]; - const char* sst_dir= mysql_real_data_home; + int const cmd_len= 4096; + wsp::string cmd_str(cmd_len); + + if (!cmd_str()) + { + WSREP_ERROR("sst_prepare_other(): could not allocate cmd buffer of %d bytes", + cmd_len); + return -ENOMEM; + } - int ret= snprintf (cmd_str, sizeof(cmd_str), + int ret= snprintf (cmd_str(), cmd_len, "wsrep_sst_%s " WSREP_SST_OPT_ROLE" 'joiner' " WSREP_SST_OPT_ADDR" '%s' " - WSREP_SST_OPT_AUTH" '%s' " WSREP_SST_OPT_DATA" '%s' " WSREP_SST_OPT_CONF" '%s' " WSREP_SST_OPT_PARENT" '%d'", - method, addr_in, (sst_auth_real) ? sst_auth_real : "", - sst_dir, wsrep_defaults_file, (int)getpid()); + method, addr_in, + mysql_real_data_home, + wsrep_defaults_file, (int)getpid()); if (ret < 0 || ret >= (int)sizeof(cmd_str)) { @@ -431,8 +464,21 @@ static ssize_t sst_prepare_other (const char* method, return (ret < 0 ? ret : -EMSGSIZE); } + wsp::env env(NULL); + if (env.error()) + { + WSREP_ERROR("sst_prepare_other(): env. var ctor failed: %d", -env.error()); + return -env.error(); + } + + if ((ret= sst_append_auth_env(env, sst_auth))) + { + WSREP_ERROR("sst_prepare_other(): appending auth failed: %d", ret); + return ret; + } + pthread_t tmp; - sst_thread_arg arg(cmd_str); + sst_thread_arg arg(cmd_str(), env()); mysql_mutex_lock (&arg.lock); ret = pthread_create (&tmp, NULL, sst_joiner_thread, &arg); if (ret) @@ -582,7 +628,8 @@ ssize_t wsrep_sst_prepare (void** msg) return 0; } - addr_len = sst_prepare_other (wsrep_sst_method, addr_in, &addr_out); + addr_len = sst_prepare_other (wsrep_sst_method, sst_auth_real, + addr_in, &addr_out); if (addr_len < 0) { WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.", @@ -615,13 +662,13 @@ ssize_t wsrep_sst_prepare (void** msg) } // helper method for donors -static int sst_run_shell (const char* cmd_str, int max_tries) +static int sst_run_shell (const char* cmd_str, char** env, int max_tries) { int ret = 0; for (int tries=1; tries <= max_tries; tries++) { - wsp::process proc (cmd_str, "r"); + wsp::process proc (cmd_str, "r", env); if (NULL != proc.pipe()) { @@ -651,17 +698,12 @@ static void sst_reject_queries(my_bool close_conn) if (TRUE == close_conn) wsrep_close_client_connections(FALSE); } -static int sst_mysqldump_check_addr (const char* user, const char* pswd, - const char* host, const char* port) -{ - return 0; -} - static int sst_donate_mysqldump (const char* addr, const wsrep_uuid_t* uuid, const char* uuid_str, wsrep_seqno_t seqno, - bool bypass) + bool bypass, + char** env) // carries auth info { size_t host_len; const char* port = strchr (addr, ':'); @@ -682,54 +724,42 @@ static int sst_donate_mysqldump (const char* addr, strncpy (host, addr, host_len - 1); host[host_len - 1] = '\0'; - const char* auth = sst_auth_real; - const char* pswd = (auth) ? strchr (auth, ':') : NULL; - size_t user_len; + int const cmd_len= 4096; + wsp::string cmd_str(cmd_len); - if (pswd) - { - pswd += 1; - user_len = pswd - auth; - } - else + if (!cmd_str()) { - pswd = ""; - user_len = (auth) ? strlen (auth) + 1 : 1; + WSREP_ERROR("sst_donate_mysqldump(): " + "could not allocate cmd buffer of %d bytes", cmd_len); + return -ENOMEM; } - char *user= (char *) alloca(user_len); + if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE); - strncpy (user, (auth) ? auth : "", user_len - 1); - user[user_len - 1] = '\0'; + int ret= snprintf (cmd_str(), cmd_len, + "wsrep_sst_mysqldump " + WSREP_SST_OPT_HOST" '%s' " + WSREP_SST_OPT_PORT" '%s' " + WSREP_SST_OPT_LPORT" '%u' " + WSREP_SST_OPT_SOCKET" '%s' " + WSREP_SST_OPT_DATA" '%s' " + WSREP_SST_OPT_CONF" '%s' " + WSREP_SST_OPT_GTID" '%s:%lld'" + "%s", + host, port, mysqld_port, mysqld_unix_port, + mysql_real_data_home, wsrep_defaults_file, uuid_str, + (long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : ""); - int ret = sst_mysqldump_check_addr (user, pswd, host, port); - if (!ret) + if (ret < 0 || ret >= cmd_len) { - char cmd_str[1024]; - - if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE); - - snprintf (cmd_str, sizeof(cmd_str), - "wsrep_sst_mysqldump " - WSREP_SST_OPT_USER" '%s' " - WSREP_SST_OPT_PSWD" '%s' " - WSREP_SST_OPT_HOST" '%s' " - WSREP_SST_OPT_PORT" '%s' " - WSREP_SST_OPT_LPORT" '%u' " - WSREP_SST_OPT_SOCKET" '%s' " - WSREP_SST_OPT_DATA" '%s' " - WSREP_SST_OPT_CONF" '%s' " - WSREP_SST_OPT_GTID" '%s:%lld'" - "%s", - user, pswd, host, port, mysqld_port, mysqld_unix_port, - mysql_real_data_home, wsrep_defaults_file, uuid_str, - (long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : ""); - - WSREP_DEBUG("Running: '%s'", cmd_str); - - ret= sst_run_shell (cmd_str, 3); + WSREP_ERROR("sst_donate_mysqldump(): snprintf() failed: %d", ret); + return (ret < 0 ? ret : -EMSGSIZE); } + WSREP_DEBUG("Running: '%s'", cmd_str()); + + ret= sst_run_shell (cmd_str(), env, 3); + wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)}; wsrep->sst_sent (wsrep, &state_id, ret); @@ -883,7 +913,7 @@ static void* sst_donor_thread (void* a) wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can // operate with wsrep_ready == OFF - wsp::process proc(arg->cmd, "r"); + wsp::process proc(arg->cmd, "r", arg->env); err= proc.error(); @@ -968,21 +998,29 @@ static int sst_donate_other (const char* method, const char* addr, const char* uuid, wsrep_seqno_t seqno, - bool bypass) + bool bypass, + char** env) // carries auth info { - char cmd_str[4096]; + int const cmd_len= 4096; + wsp::string cmd_str(cmd_len); + + if (!cmd_str()) + { + WSREP_ERROR("sst_donate_other(): " + "could not allocate cmd buffer of %d bytes", cmd_len); + return -ENOMEM; + } - int ret= snprintf (cmd_str, sizeof(cmd_str), + int ret= snprintf (cmd_str(), cmd_len, "wsrep_sst_%s " WSREP_SST_OPT_ROLE" 'donor' " WSREP_SST_OPT_ADDR" '%s' " - WSREP_SST_OPT_AUTH" '%s' " WSREP_SST_OPT_SOCKET" '%s' " WSREP_SST_OPT_DATA" '%s' " WSREP_SST_OPT_CONF" '%s' " WSREP_SST_OPT_GTID" '%s:%lld'" "%s", - method, addr, sst_auth_real, mysqld_unix_port, + method, addr, mysqld_unix_port, mysql_real_data_home, wsrep_defaults_file, uuid, (long long) seqno, bypass ? " "WSREP_SST_OPT_BYPASS : ""); @@ -996,7 +1034,7 @@ static int sst_donate_other (const char* method, if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE); pthread_t tmp; - sst_thread_arg arg(cmd_str); + sst_thread_arg arg(cmd_str(), env); mysql_mutex_lock (&arg.lock); ret = pthread_create (&tmp, NULL, sst_donor_thread, &arg); if (ret) @@ -1029,15 +1067,29 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx, char uuid_str[37]; wsrep_uuid_print (¤t_gtid->uuid, uuid_str, sizeof(uuid_str)); + wsp::env env(NULL); + if (env.error()) + { + WSREP_ERROR("sst_donate_other(): env var ctor failed: %d", -env.error()); + return WSREP_CB_FAILURE; + } + int ret; + if ((ret= sst_append_auth_env(env, sst_auth_real))) + { + WSREP_ERROR("sst_donate_other(): appending auth env failed: %d", ret); + return WSREP_CB_FAILURE; + } + if (!strcmp (WSREP_SST_MYSQLDUMP, method)) { ret = sst_donate_mysqldump(data, ¤t_gtid->uuid, uuid_str, - current_gtid->seqno, bypass); + current_gtid->seqno, bypass, env()); } else { - ret = sst_donate_other(method, data, uuid_str, current_gtid->seqno,bypass); + ret = sst_donate_other(method, data, uuid_str, + current_gtid->seqno, bypass, env()); } return (ret > 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE); diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc index ee87b9615a8..13a3b4a7438 100644 --- a/sql/wsrep_utils.cc +++ b/sql/wsrep_utils.cc @@ -63,7 +63,7 @@ wsrep_prepend_PATH (const char* path) size_t const new_path_len(strlen(old_path) + strlen(":") + strlen(path) + 1); - char* const new_path (reinterpret_cast<char*>(malloc(new_path_len))); + char* const new_path (static_cast<char*>(malloc(new_path_len))); if (new_path) { @@ -89,6 +89,91 @@ wsrep_prepend_PATH (const char* path) namespace wsp { +bool +env::ctor_common(char** e) +{ + env_ = static_cast<char**>(malloc((len_ + 1) * sizeof(char*))); + + if (env_) + { + for (size_t i(0); i < len_; ++i) + { + assert(e[i]); // caller should make sure about len_ + env_[i] = strdup(e[i]); + if (!env_[i]) + { + errno_ = errno; + WSREP_ERROR("Failed to allocate env. var: %s", e[i]); + return true; + } + } + + env_[len_] = NULL; + return false; + } + else + { + errno_ = errno; + WSREP_ERROR("Failed to allocate env. var vector of length: %zu", len_); + return true; + } +} + +void +env::dtor() +{ + if (env_) + { + /* don't need to go beyond the first NULL */ + for (size_t i(0); env_[i] != NULL; ++i) { free(env_[i]); } + free(env_); + env_ = NULL; + } + len_ = 0; +} + +env::env(char** e) + : len_(0), env_(NULL), errno_(0) +{ + if (!e) { e = environ; } + /* count the size of the vector */ + while (e[len_]) { ++len_; } + + if (ctor_common(e)) dtor(); +} + +env::env(const env& e) + : len_(e.len_), env_(0), errno_(0) +{ + if (ctor_common(e.env_)) dtor(); +} + +env::~env() { dtor(); } + +int +env::append(const char* val) +{ + char** tmp = static_cast<char**>(realloc(env_, (len_ + 2)*sizeof(char*))); + + if (tmp) + { + env_ = tmp; + env_[len_] = strdup(val); + + if (env_[len_]) + { + ++len_; + env_[len_] = NULL; + } + } + + /* if either realloc() or strdup() failed, errno had been set */ + errno_ = errno; + + return errno_; +} + + #define PIPE_READ 0 #define PIPE_WRITE 1 #define STDIN_FD 0 @@ -98,7 +183,7 @@ namespace wsp # define POSIX_SPAWN_USEVFORK 0 #endif -process::process (const char* cmd, const char* type) +process::process (const char* cmd, const char* type, char** env) : str_(cmd ? strdup(cmd) : strdup("")), io_(NULL), err_(EINVAL), pid_(0) { if (0 == str_) @@ -120,6 +205,8 @@ process::process (const char* cmd, const char* type) return; } + if (NULL == env) { env = environ; } // default to global environment + int pipe_fds[2] = { -1, }; if (::pipe(pipe_fds)) { @@ -215,7 +302,7 @@ process::process (const char* cmd, const char* type) goto cleanup_fact; } - err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, environ); + err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, env); if (err_) { WSREP_ERROR ("posix_spawnp(%s) failed: %d (%s)", @@ -309,6 +396,7 @@ process::wait () { case 126: err_ = EACCES; break; /* Permission denied */ case 127: err_ = ENOENT; break; /* No such file or directory */ + case 143: err_ = EINTR; break; /* Subprocess killed */ } WSREP_ERROR("Process completed with error: %s: %d (%s)", str_, err_, strerror(err_)); diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h index dfb68bcd1b7..c43febf249a 100644 --- a/sql/wsrep_utils.h +++ b/sql/wsrep_utils.h @@ -44,6 +44,25 @@ private: extern wsp::node_status local_status; namespace wsp { +/* a class to manage env vars array */ +class env +{ +private: + size_t len_; + char** env_; + int errno_; + bool ctor_common(char** e); + void dtor(); + env& operator =(env); +public: + explicit env(char** env); + explicit env(const env&); + ~env(); + int append(const char* var); /* add a new env. var */ + int error() const { return errno_; } + char** operator()() { return env_; } +}; + /* A small class to run external programs. */ class process { @@ -56,8 +75,9 @@ private: public: /*! @arg type is a pointer to a null-terminated string which must contain either the letter 'r' for reading or the letter 'w' for writing. + @arg env optional null-terminated vector of environment variables */ - process (const char* cmd, const char* type); + process (const char* cmd, const char* type, char** env); ~process (); FILE* pipe () { return io_; } @@ -90,6 +110,8 @@ class string { public: string() : string_(0) {} + explicit string(size_t s) : string_(static_cast<char*>(malloc(s))) {} + char* operator()() { return string_; } void set(char* str) { if (string_) free (string_); string_ = str; } ~string() { set (0); } private: |