123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- #include "php.h"
- #include "mysqlnd.h"
- #include "mysqlnd_wireprotocol.h"
- #include "mysqlnd_priv.h"
- #include "mysqlnd_debug.h"
- static
- int mysqlnd_local_infile_init(void ** ptr, const char * const filename)
- {
- MYSQLND_INFILE_INFO *info;
- php_stream_context *context = NULL;
- DBG_ENTER("mysqlnd_local_infile_init");
- info = ((MYSQLND_INFILE_INFO *)mnd_ecalloc(1, sizeof(MYSQLND_INFILE_INFO)));
- if (!info) {
- DBG_RETURN(1);
- }
- *ptr = info;
-
- if (PG(open_basedir)) {
- if (php_check_open_basedir_ex(filename, 0) == -1) {
- strcpy(info->error_msg, "open_basedir restriction in effect. Unable to open file");
- info->error_no = CR_UNKNOWN_ERROR;
- DBG_RETURN(1);
- }
- }
- info->filename = filename;
- info->fd = php_stream_open_wrapper_ex((char *)filename, "r", 0, NULL, context);
- if (info->fd == NULL) {
- snprintf((char *)info->error_msg, sizeof(info->error_msg), "Can't find file '%-.64s'.", filename);
- info->error_no = MYSQLND_EE_FILENOTFOUND;
- DBG_RETURN(1);
- }
- DBG_RETURN(0);
- }
- static
- int mysqlnd_local_infile_read(void * ptr, zend_uchar * buf, unsigned int buf_len)
- {
- MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
- int count;
- DBG_ENTER("mysqlnd_local_infile_read");
- count = (int) php_stream_read(info->fd, (char *) buf, buf_len);
- if (count < 0) {
- strcpy(info->error_msg, "Error reading file");
- info->error_no = CR_UNKNOWN_ERROR;
- }
- DBG_RETURN(count);
- }
- static
- int mysqlnd_local_infile_error(void * ptr, char *error_buf, unsigned int error_buf_len)
- {
- MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
- DBG_ENTER("mysqlnd_local_infile_error");
- if (info) {
- strlcpy(error_buf, info->error_msg, error_buf_len);
- DBG_INF_FMT("have info, %d", info->error_no);
- DBG_RETURN(info->error_no);
- }
- strlcpy(error_buf, "Unknown error", error_buf_len);
- DBG_INF_FMT("no info, %d", CR_UNKNOWN_ERROR);
- DBG_RETURN(CR_UNKNOWN_ERROR);
- }
- static
- void mysqlnd_local_infile_end(void * ptr)
- {
- MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
- if (info) {
-
- if (info->fd) {
- php_stream_close(info->fd);
- info->fd = NULL;
- }
- mnd_efree(info);
- }
- }
- PHPAPI void
- mysqlnd_local_infile_default(MYSQLND_CONN_DATA * conn)
- {
- conn->infile.local_infile_init = mysqlnd_local_infile_init;
- conn->infile.local_infile_read = mysqlnd_local_infile_read;
- conn->infile.local_infile_error = mysqlnd_local_infile_error;
- conn->infile.local_infile_end = mysqlnd_local_infile_end;
- }
- static const char *lost_conn = "Lost connection to MySQL server during LOAD DATA of a local file";
- enum_func_status
- mysqlnd_handle_local_infile(MYSQLND_CONN_DATA * conn, const char * const filename, bool * is_warning)
- {
- zend_uchar *buf = NULL;
- zend_uchar empty_packet[MYSQLND_HEADER_SIZE];
- enum_func_status result = FAIL;
- unsigned int buflen = 4096;
- void *info = NULL;
- int bufsize;
- size_t ret;
- MYSQLND_INFILE infile;
- MYSQLND_PFC * net = conn->protocol_frame_codec;
- MYSQLND_VIO * vio = conn->vio;
- bool is_local_infile_enabled = (conn->options->flags & CLIENT_LOCAL_FILES) == CLIENT_LOCAL_FILES;
- const char* local_infile_directory = conn->options->local_infile_directory;
- bool is_local_infile_dir_set = local_infile_directory != NULL;
- bool prerequisities_ok = TRUE;
- DBG_ENTER("mysqlnd_handle_local_infile");
-
- if (!is_local_infile_enabled && !is_local_infile_dir_set) {
- SET_CLIENT_ERROR(conn->error_info, CR_LOAD_DATA_LOCAL_INFILE_REJECTED, UNKNOWN_SQLSTATE,
- "LOAD DATA LOCAL INFILE is forbidden, check related settings like "
- "mysqli.allow_local_infile|mysqli.local_infile_directory or "
- "PDO::MYSQL_ATTR_LOCAL_INFILE|PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY");
- prerequisities_ok = FALSE;
- }
-
- if (is_local_infile_dir_set) {
- php_stream *stream = php_stream_opendir(local_infile_directory, REPORT_ERRORS, NULL);
- if (stream) {
- php_stream_closedir(stream);
- } else {
- SET_CLIENT_ERROR(conn->error_info, CR_LOAD_DATA_LOCAL_INFILE_REJECTED, UNKNOWN_SQLSTATE, "cannot open local_infile_directory");
- prerequisities_ok = FALSE;
- }
- }
-
- if (prerequisities_ok && !is_local_infile_enabled && is_local_infile_dir_set) {
- if (php_check_specific_open_basedir(local_infile_directory, filename) == -1) {
- SET_CLIENT_ERROR(conn->error_info, CR_LOAD_DATA_LOCAL_INFILE_REJECTED, UNKNOWN_SQLSTATE,
- "LOAD DATA LOCAL INFILE DIRECTORY restriction in effect. Unable to open file");
- prerequisities_ok = FALSE;
- }
- }
- if (!prerequisities_ok) {
-
- ret = net->data->m.send(net, vio, empty_packet, 0, conn->stats, conn->error_info);
- *is_warning = TRUE;
- goto infile_error;
- }
- infile = conn->infile;
-
- buf = (zend_uchar *) mnd_ecalloc(1, buflen);
- *is_warning = FALSE;
-
- if (infile.local_infile_init(&info, (char *)filename)) {
- char tmp_buf[sizeof(conn->error_info->error)];
- int tmp_error_no;
- *is_warning = TRUE;
-
- tmp_error_no = infile.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
- SET_CLIENT_ERROR(conn->error_info, tmp_error_no, UNKNOWN_SQLSTATE, tmp_buf);
-
- ret = net->data->m.send(net, vio, empty_packet, 0, conn->stats, conn->error_info);
- goto infile_error;
- }
-
- while ((bufsize = infile.local_infile_read (info, buf + MYSQLND_HEADER_SIZE, buflen - MYSQLND_HEADER_SIZE)) > 0) {
- if ((ret = net->data->m.send(net, vio, buf, bufsize, conn->stats, conn->error_info)) == 0) {
- DBG_ERR_FMT("Error during read : %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
- SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
- goto infile_error;
- }
- }
-
- if ((ret = net->data->m.send(net, vio, empty_packet, 0, conn->stats, conn->error_info)) == 0) {
- SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
- goto infile_error;
- }
-
- if (bufsize < 0) {
- char tmp_buf[sizeof(conn->error_info->error)];
- int tmp_error_no;
- *is_warning = TRUE;
- DBG_ERR_FMT("Bufsize < 0, warning, %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
- tmp_error_no = infile.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
- SET_CLIENT_ERROR(conn->error_info, tmp_error_no, UNKNOWN_SQLSTATE, tmp_buf);
- goto infile_error;
- }
- result = PASS;
- infile_error:
-
- if (FAIL == conn->payload_decoder_factory->m.send_command_handle_response(
- conn->payload_decoder_factory,
- PROT_OK_PACKET, FALSE, COM_QUERY, FALSE,
- conn->error_info,
- conn->upsert_status,
- &conn->last_message)) {
- result = FAIL;
- }
- (*conn->infile.local_infile_end)(info);
- if (buf) {
- mnd_efree(buf);
- }
- DBG_INF_FMT("%s", result == PASS? "PASS":"FAIL");
- DBG_RETURN(result);
- }
|