Reformat telnetd.c

This commit is contained in:
Johan Wikman
2016-01-12 15:49:09 +02:00
parent fd9698e705
commit 183202466d

View File

@ -38,11 +38,12 @@
#include <log_manager.h> #include <log_manager.h>
#include <modinfo.h> #include <modinfo.h>
MODULE_INFO info = { MODULE_INFO info =
MODULE_API_PROTOCOL, {
MODULE_GA, MODULE_API_PROTOCOL,
GWPROTOCOL_VERSION, MODULE_GA,
"A telnet deamon protocol for simple administration interface" GWPROTOCOL_VERSION,
"A telnet deamon protocol for simple administration interface"
}; };
/** /**
@ -54,14 +55,14 @@ MODULE_INFO info = {
* databases. * databases.
* *
* In the first instance it is intended to allow a debug connection to access * In the first instance it is intended to allow a debug connection to access
* internal data structures, however it may also be used to manage the * internal data structures, however it may also be used to manage the
* configuration of the gateway. * configuration of the gateway.
* *
* @verbatim * @verbatim
* Revision History * Revision History
* Date Who Description * Date Who Description
* 17/06/2013 Mark Riddoch Initial version * 17/06/2013 Mark Riddoch Initial version
* 17/07/2013 Mark Riddoch Addition of login phase * 17/07/2013 Mark Riddoch Addition of login phase
* 07/07/2015 Martin Brampton Call unified dcb_close on error * 07/07/2015 Martin Brampton Call unified dcb_close on error
* *
* @endverbatim * @endverbatim
@ -81,40 +82,39 @@ static int telnetd_listen(DCB *dcb, char *config);
/** /**
* The "module object" for the telnetd protocol module. * The "module object" for the telnetd protocol module.
*/ */
static GWPROTOCOL MyObject = { static GWPROTOCOL MyObject =
telnetd_read_event, /**< Read - EPOLLIN handler */ {
telnetd_write, /**< Write - data from gateway */ telnetd_read_event, /**< Read - EPOLLIN handler */
telnetd_write_event, /**< WriteReady - EPOLLOUT handler */ telnetd_write, /**< Write - data from gateway */
telnetd_error, /**< Error - EPOLLERR handler */ telnetd_write_event, /**< WriteReady - EPOLLOUT handler */
telnetd_hangup, /**< HangUp - EPOLLHUP handler */ telnetd_error, /**< Error - EPOLLERR handler */
telnetd_accept, /**< Accept */ telnetd_hangup, /**< HangUp - EPOLLHUP handler */
NULL, /**< Connect */ telnetd_accept, /**< Accept */
telnetd_close, /**< Close */ NULL, /**< Connect */
telnetd_listen, /**< Create a listener */ telnetd_close, /**< Close */
NULL, /**< Authentication */ telnetd_listen, /**< Create a listener */
NULL /**< Session */ NULL, /**< Authentication */
}; NULL /**< Session */
};
static void telnetd_command(DCB *, unsigned char *cmd); static void telnetd_command(DCB *, unsigned char *cmd);
static void telnetd_echo(DCB *dcb, int enable); static void telnetd_echo(DCB *dcb, int enable);
/** /**
* Implementation of the mandatory version entry point * Implementation of the mandatory version entry point
* *
* @return version string of the module * @return version string of the module
*/ */
char * char* version()
version()
{ {
return version_str; return version_str;
} }
/** /**
* The module initialisation routine, called when the module * The module initialisation routine, called when the module
* is first loaded. * is first loaded.
*/ */
void void ModuleInit()
ModuleInit()
{ {
MXS_INFO("Initialise Telnetd Protocol module."); MXS_INFO("Initialise Telnetd Protocol module.");
} }
@ -127,102 +127,102 @@ ModuleInit()
* *
* @return The module object * @return The module object
*/ */
GWPROTOCOL * GWPROTOCOL* GetModuleObject()
GetModuleObject()
{ {
return &MyObject; return &MyObject;
} }
/** /**
* Read event for EPOLLIN on the telnetd protocol module. * Read event for EPOLLIN on the telnetd protocol module.
* *
* @param dcb The descriptor control block * @param dcb The descriptor control block
* @return * @return
*/ */
static int static int telnetd_read_event(DCB* dcb)
telnetd_read_event(DCB* dcb)
{ {
int n; int n;
GWBUF *head = NULL; GWBUF *head = NULL;
SESSION *session = dcb->session; SESSION *session = dcb->session;
TELNETD *telnetd = (TELNETD *)dcb->protocol; TELNETD *telnetd = (TELNETD *)dcb->protocol;
char *password, *t; char *password, *t;
if ((n = dcb_read(dcb, &head, 0)) != -1) if ((n = dcb_read(dcb, &head, 0)) != -1)
{ {
if (head)
if (head) {
{ unsigned char *ptr = GWBUF_DATA(head);
unsigned char *ptr = GWBUF_DATA(head); ptr = GWBUF_DATA(head);
ptr = GWBUF_DATA(head); while (GWBUF_LENGTH(head) && *ptr == TELNET_IAC)
while (GWBUF_LENGTH(head) && *ptr == TELNET_IAC) {
{ telnetd_command(dcb, ptr + 1);
telnetd_command(dcb, ptr + 1); GWBUF_CONSUME(head, 3);
GWBUF_CONSUME(head, 3); ptr = GWBUF_DATA(head);
ptr = GWBUF_DATA(head); }
} if (GWBUF_LENGTH(head))
if (GWBUF_LENGTH(head)) {
{ switch (telnetd->state)
switch (telnetd->state) {
{ case TELNETD_STATE_LOGIN:
case TELNETD_STATE_LOGIN: telnetd->username = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head));
telnetd->username = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head)); /* Strip the cr/lf from the username */
/* Strip the cr/lf from the username */ t = strstr(telnetd->username, "\r\n");
t = strstr(telnetd->username, "\r\n"); if (t)
if (t) {
*t = 0; *t = 0;
telnetd->state = TELNETD_STATE_PASSWD; }
dcb_printf(dcb, "Password: "); telnetd->state = TELNETD_STATE_PASSWD;
telnetd_echo(dcb, 0); dcb_printf(dcb, "Password: ");
gwbuf_consume(head, GWBUF_LENGTH(head)); telnetd_echo(dcb, 0);
break; gwbuf_consume(head, GWBUF_LENGTH(head));
case TELNETD_STATE_PASSWD: break;
password = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head)); case TELNETD_STATE_PASSWD:
/* Strip the cr/lf from the username */ password = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head));
t = strstr(password, "\r\n"); /* Strip the cr/lf from the username */
if (t) t = strstr(password, "\r\n");
*t = 0; if (t)
if (admin_verify(telnetd->username, password)) {
{ *t = 0;
telnetd_echo(dcb, 1); }
telnetd->state = TELNETD_STATE_DATA; if (admin_verify(telnetd->username, password))
dcb_printf(dcb, "\n\nMaxScale> "); {
} telnetd_echo(dcb, 1);
else telnetd->state = TELNETD_STATE_DATA;
{ dcb_printf(dcb, "\n\nMaxScale> ");
dcb_printf(dcb, "\n\rLogin incorrect\n\rLogin: "); }
telnetd_echo(dcb, 1); else
telnetd->state = TELNETD_STATE_LOGIN; {
free(telnetd->username); dcb_printf(dcb, "\n\rLogin incorrect\n\rLogin: ");
} telnetd_echo(dcb, 1);
gwbuf_consume(head, GWBUF_LENGTH(head)); telnetd->state = TELNETD_STATE_LOGIN;
free(password); free(telnetd->username);
break; }
case TELNETD_STATE_DATA: gwbuf_consume(head, GWBUF_LENGTH(head));
SESSION_ROUTE_QUERY(session, head); free(password);
break; break;
} case TELNETD_STATE_DATA:
} SESSION_ROUTE_QUERY(session, head);
else break;
{ }
// Force the free of the buffer header }
gwbuf_consume(head, 0); else
} {
} // Force the free of the buffer header
} gwbuf_consume(head, 0);
return n; }
}
}
return n;
} }
/** /**
* EPOLLOUT handler for the telnetd protocol module. * EPOLLOUT handler for the telnetd protocol module.
* *
* @param dcb The descriptor control block * @param dcb The descriptor control block
* @return * @return
*/ */
static int static int telnetd_write_event(DCB *dcb)
telnetd_write_event(DCB *dcb)
{ {
return dcb_drain_writeq(dcb); return dcb_drain_writeq(dcb);
} }
/** /**
@ -231,188 +231,189 @@ telnetd_write_event(DCB *dcb)
* Writes the content of the buffer queue to the socket * Writes the content of the buffer queue to the socket
* observing the non-blocking principles of the gateway. * observing the non-blocking principles of the gateway.
* *
* @param dcb Descriptor Control Block for the socket * @param dcb Descriptor Control Block for the socket
* @param queue Linked list of buffes to write * @param queue Linked list of buffes to write
*/ */
static int static int telnetd_write(DCB *dcb, GWBUF *queue)
telnetd_write(DCB *dcb, GWBUF *queue)
{ {
int rc; int rc;
rc = dcb_write(dcb, queue); rc = dcb_write(dcb, queue);
return rc; return rc;
} }
/** /**
* Handler for the EPOLLERR event. * Handler for the EPOLLERR event.
* *
* @param dcb The descriptor control block * @param dcb The descriptor control block
*/ */
static int static int telnetd_error(DCB *dcb)
telnetd_error(DCB *dcb)
{ {
return 0; return 0;
} }
/** /**
* Handler for the EPOLLHUP event. * Handler for the EPOLLHUP event.
* *
* @param dcb The descriptor control block * @param dcb The descriptor control block
*/ */
static int static int telnetd_hangup(DCB *dcb)
telnetd_hangup(DCB *dcb)
{ {
return 0; return 0;
} }
/** /**
* Handler for the EPOLLIN event when the DCB refers to the listening * Handler for the EPOLLIN event when the DCB refers to the listening
* socket for the protocol. * socket for the protocol.
* *
* @param dcb The descriptor control block * @param dcb The descriptor control block
* @return The number of new connections created * @return The number of new connections created
*/ */
static int static int telnetd_accept(DCB *dcb)
telnetd_accept(DCB *dcb)
{ {
int n_connect = 0; int n_connect = 0;
while (1) while (1)
{ {
int so; int so;
struct sockaddr_in addr; struct sockaddr_in addr;
socklen_t addrlen = sizeof(struct sockaddr); socklen_t addrlen = sizeof(struct sockaddr);
DCB *client_dcb; DCB *client_dcb;
TELNETD* telnetd_pr = NULL; TELNETD* telnetd_pr = NULL;
so = accept(dcb->fd, (struct sockaddr *)&addr, &addrlen); so = accept(dcb->fd, (struct sockaddr *)&addr, &addrlen);
if (so == -1)
return n_connect;
else
{
atomic_add(&dcb->stats.n_accepts, 1);
client_dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
if (client_dcb == NULL) if (so == -1)
{
return n_connect;
}
else
{
atomic_add(&dcb->stats.n_accepts, 1);
client_dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
{ if (client_dcb == NULL)
close(so); {
return n_connect; close(so);
} return n_connect;
client_dcb->fd = so; }
client_dcb->remote = strdup(inet_ntoa(addr.sin_addr)); client_dcb->fd = so;
memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL)); client_dcb->remote = strdup(inet_ntoa(addr.sin_addr));
client_dcb->session = memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL));
session_alloc(dcb->session->service, client_dcb); client_dcb->session = session_alloc(dcb->session->service, client_dcb);
if (NULL == client_dcb->session)
{
dcb_close(client_dcb);
return n_connect;
}
telnetd_pr = (TELNETD *)malloc(sizeof(TELNETD));
client_dcb->protocol = (void *)telnetd_pr;
if (telnetd_pr == NULL) if (NULL == client_dcb->session)
{ {
dcb_close(client_dcb); dcb_close(client_dcb);
return n_connect; return n_connect;
} }
telnetd_pr = (TELNETD *)malloc(sizeof(TELNETD));
client_dcb->protocol = (void *)telnetd_pr;
if (poll_add_dcb(client_dcb)) if (telnetd_pr == NULL)
{ {
dcb_close(dcb); dcb_close(client_dcb);
return n_connect; return n_connect;
} }
n_connect++;
telnetd_pr->state = TELNETD_STATE_LOGIN; if (poll_add_dcb(client_dcb))
telnetd_pr->username = NULL; {
dcb_printf(client_dcb, "MaxScale login: "); dcb_close(dcb);
} return n_connect;
} }
return n_connect; n_connect++;
telnetd_pr->state = TELNETD_STATE_LOGIN;
telnetd_pr->username = NULL;
dcb_printf(client_dcb, "MaxScale login: ");
}
}
return n_connect;
} }
/** /**
* The close handler for the descriptor. Called by the gateway to * The close handler for the descriptor. Called by the gateway to
* explicitly close a connection. * explicitly close a connection.
* *
* @param dcb The descriptor control block * @param dcb The descriptor control block
*/ */
static int static int telnetd_close(DCB *dcb)
telnetd_close(DCB *dcb)
{ {
TELNETD *telnetd = dcb->protocol; TELNETD *telnetd = dcb->protocol;
if (telnetd && telnetd->username) if (telnetd && telnetd->username)
free(telnetd->username); {
free(telnetd->username);
}
return 0; return 0;
} }
/** /**
* Telnet daemon listener entry point * Telnet daemon listener entry point
* *
* @param listener The Listener DCB * @param listener The Listener DCB
* @param config Configuration (ip:port) * @param config Configuration (ip:port)
*/ */
static int static int telnetd_listen(DCB *listener, char *config)
telnetd_listen(DCB *listener, char *config)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
int one = 1; int one = 1;
int rc; int rc;
int syseno = 0; int syseno = 0;
memcpy(&listener->func, &MyObject, sizeof(GWPROTOCOL)); memcpy(&listener->func, &MyObject, sizeof(GWPROTOCOL));
if (!parse_bindconfig(config, 4442, &addr)) if (!parse_bindconfig(config, 4442, &addr))
return 0; {
return 0;
}
if ((listener->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
return 0;
}
if ((listener->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) // socket options
{ syseno = setsockopt(listener->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
return 0;
}
// socket options if (syseno != 0)
syseno = setsockopt(listener->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); {
char errbuf[STRERROR_BUFLEN];
if(syseno != 0){ MXS_ERROR("Failed to set socket options. Error %d: %s",
char errbuf[STRERROR_BUFLEN]; errno, strerror_r(errno, errbuf, sizeof(errbuf)));
MXS_ERROR("Failed to set socket options. Error %d: %s", return 0;
errno, strerror_r(errno, errbuf, sizeof(errbuf))); }
return 0; // set NONBLOCKING mode
} setnonblocking(listener->fd);
// set NONBLOCKING mode // bind address and port
setnonblocking(listener->fd); if (bind(listener->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
// bind address and port {
if (bind(listener->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) return 0;
{ }
return 0;
}
rc = listen(listener->fd, SOMAXCONN); rc = listen(listener->fd, SOMAXCONN);
if (rc == 0) {
MXS_NOTICE("Listening telnet connections at %s", config);
} else {
int eno = errno;
errno = 0;
char errbuf[STRERROR_BUFLEN];
fprintf(stderr,
"\n* Failed to start listening telnet due error %d, %s\n\n",
eno,
strerror_r(eno, errbuf, sizeof(errbuf)));
return 0;
}
if (rc == 0)
if (poll_add_dcb(listener) == -1) {
{ MXS_NOTICE("Listening telnet connections at %s", config);
return 0; }
} else
return 1; {
int eno = errno;
errno = 0;
char errbuf[STRERROR_BUFLEN];
fprintf(stderr,
"\n* Failed to start listening telnet due error %d, %s\n\n",
eno,
strerror_r(eno, errbuf, sizeof(errbuf)));
return 0;
}
if (poll_add_dcb(listener) == -1)
{
return 0;
}
return 1;
} }
/** /**
@ -422,31 +423,31 @@ int syseno = 0;
* *
* Currently we do no command execution * Currently we do no command execution
* *
* @param dcb The client DCB * @param dcb The client DCB
* @param cmd The command stream * @param cmd The command stream
*/ */
static void static void telnetd_command(DCB *dcb, unsigned char *cmd)
telnetd_command(DCB *dcb, unsigned char *cmd)
{ {
} }
/** /**
* Enable or disable telnet protocol echo * Enable or disable telnet protocol echo
* *
* @param dcb DCB of the telnet connection * @param dcb DCB of the telnet connection
* @param enable Enable or disable echo functionality * @param enable Enable or disable echo functionality
*/ */
static void static void telnetd_echo(DCB *dcb, int enable)
telnetd_echo(DCB *dcb, int enable)
{ {
GWBUF *gwbuf; GWBUF *gwbuf;
char *buf; char *buf;
if ((gwbuf = gwbuf_alloc(3)) == NULL) if ((gwbuf = gwbuf_alloc(3)) == NULL)
return; {
buf = GWBUF_DATA(gwbuf); return;
buf[0] = TELNET_IAC; }
buf[1] = enable ? TELNET_WONT : TELNET_WILL; buf = GWBUF_DATA(gwbuf);
buf[2] = TELNET_ECHO; buf[0] = TELNET_IAC;
dcb_write(dcb, gwbuf); buf[1] = enable ? TELNET_WONT : TELNET_WILL;
buf[2] = TELNET_ECHO;
dcb_write(dcb, gwbuf);
} }