int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, const char *data_plugin, const char *db) { const char *auth_plugin_name; auth_plugin_t *auth_plugin; MCPVIO_EXT mpvio; ulong pkt_length; int res; /* determine the default/initial plugin to use */ if (mysql->options.extension && mysql->options.extension->default_auth && mysql->server_capabilities & CLIENT_PLUGIN_AUTH) { auth_plugin_name= mysql->options.extension->default_auth; if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql, auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) return 1; /* oops, not found */ } else { auth_plugin= mysql->server_capabilities & CLIENT_PROTOCOL_41 ? &native_password_client_plugin : &old_password_client_plugin; auth_plugin_name= auth_plugin->name; } mysql->net.last_errno= 0; /* just in case */ if (data_plugin && strcmp(data_plugin, auth_plugin_name)) { /* data was prepared for a different plugin, don't show it to this one */ data= 0; data_len= 0; } mpvio.mysql_change_user= data_plugin == 0; mpvio.cached_server_reply.pkt= (uchar*)data; mpvio.cached_server_reply.pkt_len= data_len; mpvio.read_packet= client_mpvio_read_packet; mpvio.write_packet= client_mpvio_write_packet; mpvio.info= client_mpvio_info; mpvio.mysql= mysql; mpvio.packets_read= mpvio.packets_written= 0; mpvio.db= db; mpvio.plugin= auth_plugin; res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql); compile_time_assert(CR_OK == -1); compile_time_assert(CR_ERROR == 0); if (res > CR_OK && mysql->net.read_pos[0] != 254) { /* the plugin returned an error. write it down in mysql, unless the error code is CR_ERROR and mysql->net.last_errno is already set (the plugin has done it) */ if (res > CR_ERROR) my_set_error(mysql, res, SQLSTATE_UNKNOWN, 0); else if (!mysql->net.last_errno) my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0); return 1; } /* read the OK packet (or use the cached value in mysql->net.read_pos */ if (res == CR_OK) pkt_length= net_safe_read(mysql); else /* res == CR_OK_HANDSHAKE_COMPLETE */ pkt_length= mpvio.last_read_packet_len; if (pkt_length == packet_error) { if (mysql->net.last_errno == CR_SERVER_LOST) my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, ER(CR_SERVER_LOST_EXTENDED), "reading authorization packet", errno); return 1; } if (mysql->net.read_pos[0] == 254) { /* The server asked to use a different authentication plugin */ if (pkt_length == 1) { /* old "use short scramble" packet */ auth_plugin_name= old_password_plugin_name; mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble_buff; mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1; } else { /* new "use different plugin" packet */ uint len; auth_plugin_name= (char*)mysql->net.read_pos + 1; len= (uint)strlen(auth_plugin_name); /* safe as my_net_read always appends \0 */ mpvio.cached_server_reply.pkt_len= pkt_length - len - 2; mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2; } if (!(auth_plugin= (auth_plugin_t *) mysql_client_find_plugin(mysql, auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) return 1; mpvio.plugin= auth_plugin; res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql); if (res > CR_OK) { if (res > CR_ERROR) my_set_error(mysql, res, SQLSTATE_UNKNOWN, 0); else if (!mysql->net.last_errno) my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0); return 1; } if (res != CR_OK_HANDSHAKE_COMPLETE) { /* Read what server thinks about out new auth message report */ if (net_safe_read(mysql) == packet_error) { if (mysql->net.last_errno == CR_SERVER_LOST) my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, ER(CR_SERVER_LOST_EXTENDED), "reading final connect information", errno); return 1; } } } /* net->read_pos[0] should always be 0 here if the server implements the protocol correctly */ return mysql->net.read_pos[0] != 0; }
/* {{{ MARIADB_PVIO *ma_pvio_init */ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo) { /* check connection type and load the required plugin. * Currently we support the following pvio types: * pvio_socket * pvio_namedpipe * pvio_sharedmed */ const char *pvio_plugins[] = {"pvio_socket", "pvio_npipe", "pvio_shmem"}; int type; MARIADB_PVIO_PLUGIN *pvio_plugin; MARIADB_PVIO *pvio= NULL; switch (cinfo->type) { case PVIO_TYPE_UNIXSOCKET: case PVIO_TYPE_SOCKET: type= 0; break; #ifdef _WIN32 case PVIO_TYPE_NAMEDPIPE: type= 1; break; case PVIO_TYPE_SHAREDMEM: type= 2; break; #endif default: return NULL; } if (!(pvio_plugin= (MARIADB_PVIO_PLUGIN *) mysql_client_find_plugin(cinfo->mysql, pvio_plugins[type], MARIADB_CLIENT_PVIO_PLUGIN))) { /* error already set in mysql_client_find_plugin */ return NULL; } if (!(pvio= (MARIADB_PVIO *)calloc(1, sizeof(MARIADB_PVIO)))) { PVIO_SET_ERROR(cinfo->mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); return NULL; } /* register error routine and methods */ pvio->methods= pvio_plugin->methods; pvio->set_error= my_set_error; pvio->type= cinfo->type; /* set timeout to connect timeout - after successfull connect we will set * correct values for read and write */ if (pvio->methods->set_timeout) { pvio->methods->set_timeout(pvio, PVIO_CONNECT_TIMEOUT, cinfo->mysql->options.connect_timeout); pvio->methods->set_timeout(pvio, PVIO_READ_TIMEOUT, cinfo->mysql->options.connect_timeout); pvio->methods->set_timeout(pvio, PVIO_WRITE_TIMEOUT, cinfo->mysql->options.connect_timeout); } if (!(pvio->cache= calloc(1, PVIO_READ_AHEAD_CACHE_SIZE))) { PVIO_SET_ERROR(cinfo->mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); free(pvio); return NULL; } pvio->cache_size= 0; pvio->cache_pos= pvio->cache; return pvio; }
/* {{{ ma_open */ MA_FILE *ma_open(const char *location, const char *mode, MYSQL *mysql) { int CodePage= -1; FILE *fp= NULL; MA_FILE *ma_file= NULL; if (!location || !location[0]) return NULL; #ifdef HAVE_REMOTEIO if (strstr(location, "://")) goto remote; #endif #ifdef _WIN32 if (mysql && mysql->charset) CodePage= madb_get_windows_cp(mysql->charset->csname); #endif if (CodePage == -1) { if (!(fp= fopen(location, mode))) { #ifdef _WIN32 my_errno= GetLastError(); #else my_errno= errno; #endif return NULL; } } #ifdef _WIN32 /* See CONC-44: we need to support non ascii filenames too, so we convert current character set to wchar_t and try to open the file via _wsopen */ else { wchar_t *w_filename= NULL; wchar_t *w_mode= NULL; int len; DWORD Length; len= MultiByteToWideChar(CodePage, 0, location, (int)strlen(location), NULL, 0); if (!len) return NULL; if (!(w_filename= (wchar_t *)my_malloc((len + 1) * sizeof(wchar_t), MYF(MY_ZEROFILL)))) { my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); return NULL; } Length= len; len= MultiByteToWideChar(CodePage, 0, location, (int)strlen(location), w_filename, (int)Length); if (!len) { /* todo: error handling */ my_free(w_filename); return NULL; } len= (int)strlen(mode); if (!(w_mode= (wchar_t *)my_malloc((len + 1) * sizeof(wchar_t), MYF(MY_ZEROFILL)))) { my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); my_free(w_filename); return NULL; } Length= len; len= MultiByteToWideChar(CodePage, 0, mode, (int)strlen(mode), w_mode, (int)Length); if (!len) { /* todo: error handling */ my_free(w_filename); my_free(w_mode); return NULL; } fp= _wfopen(w_filename, w_mode); my_errno= GetLastError(); my_free(w_filename); my_free(w_mode); } #endif if (fp) { ma_file= (MA_FILE *)my_malloc(sizeof(MA_FILE), MYF(0)); if (!ma_file) { my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); return NULL; } ma_file->type= MA_FILE_LOCAL; ma_file->ptr= (void *)fp; } return ma_file; #ifdef HAVE_REMOTEIO remote: /* check if plugin for remote io is available and try * to open location */ { MYSQL mysql; if (rio_plugin ||(rio_plugin= (struct st_mysql_client_plugin_REMOTEIO *) mysql_client_find_plugin(&mysql, NULL, MARIADB_CLIENT_REMOTEIO_PLUGIN))) return rio_plugin->methods->open(location, mode); return NULL; } #endif }