/** * Receive the MySQL authentication packet from backend, packet # is 2 * * @param protocol The MySQL protocol structure * @return -1 in case of failure, 0 if there was nothing to read, 1 if read * was successful. */ int gw_receive_backend_auth( MySQLProtocol *protocol) { int n = -1; GWBUF *head = NULL; DCB *dcb = protocol->owner_dcb; uint8_t *ptr = NULL; int rc = 0; n = dcb_read(dcb, &head); /*< * Read didn't fail and there is enough data for mysql packet. */ if (n != -1 && head != NULL && GWBUF_LENGTH(head) >= 5) { ptr = GWBUF_DATA(head); /*< * 5th byte is 0x0 if successful. */ if (ptr[4] == '\x00') { rc = 1; } else { uint8_t* tmpbuf = (uint8_t *)calloc(1, GWBUF_LENGTH(head)+1); memcpy(tmpbuf, ptr, GWBUF_LENGTH(head)); LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_receive_backend_auth] Invalid " "authentication message from backend dcb %p " "fd %d, ptr[4] = %p, msg %s.", pthread_self(), dcb, dcb->fd, tmpbuf[4], tmpbuf))); free(tmpbuf); rc = -1; } /*< * Remove data from buffer. */ head = gwbuf_consume(head, GWBUF_LENGTH(head)); } else if (n == 0) { /*< * This is considered as success because call didn't fail, * although no bytes was read. */ rc = 0; LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_receive_backend_auth] Read zero bytes from " "backend dcb %p fd %d in state %s. n %d, head %p, len %d", pthread_self(), dcb, dcb->fd, STRDCBSTATE(dcb->state), n, head, (head == NULL) ? 0 : GWBUF_LENGTH(head)))); } else { ss_dassert(n < 0 && head == NULL); rc = -1; LOGIF(LD, (skygw_log_write_flush( LOGFILE_DEBUG, "%lu [gw_receive_backend_auth] Reading from backend dcb %p " "fd %d in state %s failed. n %d, head %p, len %d", pthread_self(), dcb, dcb->fd, STRDCBSTATE(dcb->state), n, head, (head == NULL) ? 0 : GWBUF_LENGTH(head)))); } return rc; }
/** * Add a DCB to the set of descriptors within the polling * environment. * * @param dcb The descriptor to add to the poll * @return -1 on error or 0 on success */ int poll_add_dcb(DCB *dcb) { int rc = -1; dcb_state_t old_state = DCB_STATE_UNDEFINED; dcb_state_t new_state; struct epoll_event ev; CHK_DCB(dcb); #ifdef EPOLLRDHUP ev.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLHUP | EPOLLET; #else ev.events = EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLET; #endif ev.data.ptr = dcb; /*< * Choose new state according to the role of dcb. */ if (dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER) { new_state = DCB_STATE_POLLING; } else { ss_dassert(dcb->dcb_role == DCB_ROLE_SERVICE_LISTENER); new_state = DCB_STATE_LISTENING; } /*< * If dcb is in unexpected state, state change fails indicating that dcb * is not polling anymore. */ if (dcb_set_state(dcb, new_state, &old_state)) { rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev); if (rc != 0) { int eno = errno; errno = 0; LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Adding dcb %p in state %s " "to poll set failed. epoll_ctl failed due " "%d, %s.", dcb, STRDCBSTATE(dcb->state), eno, strerror(eno)))); } else { LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [poll_add_dcb] Added dcb %p in state %s to " "poll set.", pthread_self(), dcb, STRDCBSTATE(dcb->state)))); } ss_info_dassert(rc == 0, "Unable to add poll"); /*< trap in debug */ } else { LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Unable to set new state for dcb %p " "in state %s. Adding to poll set failed.", dcb, STRDCBSTATE(dcb->state)))); } return rc; }
/** * mysql_send_auth_error * * Send a MySQL protocol ERR message, for gateway authentication error to the dcb * * @param dcb descriptor Control Block for the connection to which the OK is sent * @param packet_number * @param in_affected_rows * @param mysql_message * @return packet length * */ int mysql_send_auth_error (DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message) { uint8_t *outbuf = NULL; uint8_t mysql_payload_size = 0; uint8_t mysql_packet_header[4]; uint8_t *mysql_payload = NULL; uint8_t field_count = 0; uint8_t mysql_err[2]; uint8_t mysql_statemsg[6]; unsigned int mysql_errno = 0; const char *mysql_error_msg = NULL; const char *mysql_state = NULL; GWBUF *buf; if (dcb->state != DCB_STATE_POLLING) { LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [mysql_send_auth_error] dcb %p is in a state %s, " "and it is not in epoll set anymore. Skip error sending.", pthread_self(), dcb, STRDCBSTATE(dcb->state)))); return 0; } mysql_errno = 1045; mysql_error_msg = "Access denied!"; mysql_state = "2800"; field_count = 0xff; gw_mysql_set_byte2(mysql_err, mysql_errno); mysql_statemsg[0]='#'; memcpy(mysql_statemsg+1, mysql_state, 5); if (mysql_message != NULL) { mysql_error_msg = mysql_message; } mysql_payload_size = sizeof(field_count) + sizeof(mysql_err) + sizeof(mysql_statemsg) + strlen(mysql_error_msg); // allocate memory for packet header + payload if ((buf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size)) == NULL) { return 0; } outbuf = GWBUF_DATA(buf); // write packet header with packet number gw_mysql_set_byte3(mysql_packet_header, mysql_payload_size); mysql_packet_header[3] = packet_number; // write header memcpy(outbuf, mysql_packet_header, sizeof(mysql_packet_header)); mysql_payload = outbuf + sizeof(mysql_packet_header); // write field memcpy(mysql_payload, &field_count, sizeof(field_count)); mysql_payload = mysql_payload + sizeof(field_count); // write errno memcpy(mysql_payload, mysql_err, sizeof(mysql_err)); mysql_payload = mysql_payload + sizeof(mysql_err); // write sqlstate memcpy(mysql_payload, mysql_statemsg, sizeof(mysql_statemsg)); mysql_payload = mysql_payload + sizeof(mysql_statemsg); // write err messg memcpy(mysql_payload, mysql_error_msg, strlen(mysql_error_msg)); // writing data in the Client buffer queue dcb->func.write(dcb, buf); return sizeof(mysql_packet_header) + mysql_payload_size; }