/** * Read event for EPOLLIN on the telnetd protocol module. * * @param dcb The descriptor control block * @return */ static int telnetd_read_event(DCB* dcb) { int n; GWBUF *head = NULL; SESSION *session = dcb->session; ROUTER_OBJECT *router = session->service->router; ROUTER *router_instance = session->service->router_instance; void *rsession = session->router_session; TELNETD *telnetd = (TELNETD *)dcb->protocol; char *password, *t; if ((n = dcb_read(dcb, &head)) != -1) { if (head) { unsigned char *ptr = GWBUF_DATA(head); ptr = GWBUF_DATA(head); while (GWBUF_LENGTH(head) && *ptr == TELNET_IAC) { telnetd_command(dcb, ptr + 1); GWBUF_CONSUME(head, 3); ptr = GWBUF_DATA(head); } if (GWBUF_LENGTH(head)) { switch (telnetd->state) { case TELNETD_STATE_LOGIN: telnetd->username = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head)); /* Strip the cr/lf from the username */ t = strstr(telnetd->username, "\r\n"); if (t) *t = 0; telnetd->state = TELNETD_STATE_PASSWD; dcb_printf(dcb, "Password: "******"\r\n"); if (t) *t = 0; if (admin_verify(telnetd->username, password)) { telnetd_echo(dcb, 1); telnetd->state = TELNETD_STATE_DATA; dcb_printf(dcb, "\n\nMaxScale> "); } else { dcb_printf(dcb, "\n\rLogin incorrect\n\rLogin: "); telnetd_echo(dcb, 1); telnetd->state = TELNETD_STATE_LOGIN; free(telnetd->username); } gwbuf_consume(head, GWBUF_LENGTH(head)); free(password); break; case TELNETD_STATE_DATA: router->routeQuery(router_instance, rsession, head); break; } } else { // Force the free of the buffer header gwbuf_consume(head, 0); } } } return n; }
/** * Read the backend server MySQL handshake * * @param conn MySQL protocol structure * @return 0 on success, 1 on failure */ int gw_read_backend_handshake(MySQLProtocol *conn) { GWBUF *head = NULL; DCB *dcb = conn->owner_dcb; int n = -1; uint8_t *payload = NULL; int h_len = 0; int success = 0; int packet_len = 0; if ((n = dcb_read(dcb, &head)) != -1) { if (head) { payload = GWBUF_DATA(head); h_len = gwbuf_length(head); /* * The mysql packets content starts at byte fifth * just return with less bytes */ if (h_len <= 4) { /* log error this exit point */ conn->state = MYSQL_AUTH_FAILED; return 1; } //get mysql packet size, 3 bytes packet_len = gw_mysql_get_byte3(payload); if (h_len < (packet_len + 4)) { /* * data in buffer less than expected in the * packet. Log error this exit point */ conn->state = MYSQL_AUTH_FAILED; return 1; } // skip the 4 bytes header payload += 4; //Now decode mysql handshake success = gw_decode_mysql_server_handshake(conn, payload); if (success < 0) { /* MySQL handshake has not been properly decoded * we cannot continue * log error this exit point */ conn->state = MYSQL_AUTH_FAILED; return 1; } conn->state = MYSQL_AUTH_SENT; // consume all the data here head = gwbuf_consume(head, GWBUF_LENGTH(head)); return 0; } } // Nothing done here, log error this return 1; }
/** * 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; }
/** * Read event for EPOLLIN on the httpd protocol module. * * @param dcb The descriptor control block * @return */ static int httpd_read_event(DCB *dcb) { SESSION *session = dcb->session; GWBUF *buf = NULL; char *ptr, *sol; HTTPD_session *client_data = NULL; int n; // Read all the available data if ((n = dcb_read(dcb, &buf)) != -1) { client_data = dcb->data; if (client_data->saved) { buf = gwbuf_append(client_data->saved, buf); client_data->saved = NULL; } buf = gwbuf_make_contiguous(buf); ptr = GWBUF_DATA(buf); if (strncasecmp(ptr, "POST", 4)) { client_data->method = METHOD_POST; gwbuf_add_property(buf, "Method", "POST"); ptr = ptr + 4; } else if (strncasecmp(ptr, "PUT", 3)) { client_data->method = METHOD_PUT; gwbuf_add_property(buf, "Method", "PUT"); ptr = ptr + 3; } else if (strncasecmp(ptr, "GET", 3)) { client_data->method = METHOD_GET; gwbuf_add_property(buf, "Method", "GET"); ptr = ptr + 3; } else if (strncasecmp(ptr, "HEAD", 4)) { client_data->method = METHOD_HEAD; gwbuf_add_property(buf, "Method", "HEAD"); ptr = ptr + 4; } while (ptr < (char *)(buf->end) && isspace(*ptr)) ptr++; sol = ptr; while (ptr < (char *)(buf->end) && isspace(*ptr) == 0) ptr++; client_data->url = strndup(sol, ptr - sol); gwbuf_add_property(buf, "URL", client_data->url); while ((sol = httpd_nextline(buf, ptr)) != NULL && *sol != '\n' && *sol != '\r') { httpd_process_header(buf, sol, client_data); ptr = sol; } /* * We have read all the headers, or run out of data to * examine. */ if (sol == NULL) { client_data->saved = buf; return 0; } else { if (((char *)(buf->end) - sol) < client_data->request_len) { client_data->saved = buf; } else { LOGIF(LT, (skygw_log_write( LOGFILE_TRACE, "HTTPD: request %s.\n", client_data->url))); SESSION_ROUTE_QUERY(session, buf); if (client_data->url) { free(client_data->url); client_data->url = NULL; } } } } return 0; }