diff options
Diffstat (limited to 'accel-pptpd/cli/telnet.c')
-rw-r--r-- | accel-pptpd/cli/telnet.c | 153 |
1 files changed, 102 insertions, 51 deletions
diff --git a/accel-pptpd/cli/telnet.c b/accel-pptpd/cli/telnet.c index 97e85d0c..69e484f5 100644 --- a/accel-pptpd/cli/telnet.c +++ b/accel-pptpd/cli/telnet.c @@ -17,7 +17,7 @@ #include "list.h" #include "memdebug.h" -#include "telnet.h" +#include "cli_p.h" #define RECV_BUF_SIZE 1024 #define BANNER "accel-pptp-1.3-rc1\r\n" @@ -28,6 +28,27 @@ #define ESC_UP "[A" #define ESC_DOWN "[B" +struct telnet_client_t +{ + struct cli_client_t cli_client; + struct list_head entry; + struct triton_md_handler_t hnd; + struct list_head xmit_queue; + struct buffer_t *xmit_buf; + int xmit_pos; + struct list_head history; + struct list_head *history_pos; + uint8_t *cmdline; + int cmdline_pos; + int cmdline_pos2; + int cmdline_len; + int auth:1; + int echo:1; + int telcmd:1; + int esc:1; + int disconnect:1; +}; + struct buffer_t { struct list_head entry; @@ -35,21 +56,21 @@ struct buffer_t uint8_t buf[0]; }; -static const char *conf_passwd; -static const char *conf_prompt = "accel-pptp# "; - static struct triton_context_t serv_ctx; static struct triton_md_handler_t serv_hnd; +static LIST_HEAD(clients); static uint8_t *recv_buf; static uint8_t *temp_buf; -static void disconnect(struct client_t *cln) +static void disconnect(struct telnet_client_t *cln) { struct buffer_t *b; log_debug("cli: disconnect\n"); + list_del(&cln->entry); + triton_md_unregister_handler(&cln->hnd); close(cln->hnd.fd); @@ -72,12 +93,13 @@ static void disconnect(struct client_t *cln) _free(cln); } -void telnet_disconnect(struct client_t *cln) +static void cli_client_disconnect(struct cli_client_t *tcln) { + struct telnet_client_t *cln = container_of(tcln, typeof(*cln), cli_client); disconnect(cln); } -static void queue_buffer(struct client_t *cln, struct buffer_t *b) +static void queue_buffer(struct telnet_client_t *cln, struct buffer_t *b) { if (cln->xmit_buf) list_add_tail(&b->entry, &cln->xmit_queue); @@ -85,7 +107,7 @@ static void queue_buffer(struct client_t *cln, struct buffer_t *b) cln->xmit_buf = b; } -int telnet_send(struct client_t *cln, const void *_buf, int size) +static int telnet_send(struct telnet_client_t *cln, const void *_buf, int size) { int n, k; struct buffer_t *b; @@ -93,6 +115,14 @@ int telnet_send(struct client_t *cln, const void *_buf, int size) if (cln->disconnect) return -1; + + if (!list_empty(&cln->xmit_queue)) { + b = _malloc(sizeof(*b) + size); + b->size = size; + memcpy(b->buf, buf, size); + queue_buffer(cln, b); + return 0; + } for (n = 0; n < size; n += k) { k = write(cln->hnd.fd, buf + n, size - n); @@ -116,8 +146,15 @@ int telnet_send(struct client_t *cln, const void *_buf, int size) return 0; } -int telnet_sendv(struct client_t *cln, const char *fmt, va_list ap) +static int cli_client_send(struct cli_client_t *tcln, const void *buf, int size) +{ + struct telnet_client_t *cln = container_of(tcln, typeof(*cln), cli_client); + return telnet_send(cln, buf, size); +} + +static int cli_client_sendv(struct cli_client_t *tcln, const char *fmt, va_list ap) { + struct telnet_client_t *cln = container_of(tcln, typeof(*cln), cli_client); int r = vsnprintf((char *)temp_buf, RECV_BUF_SIZE, fmt, ap); if (r >= RECV_BUF_SIZE) { @@ -128,18 +165,18 @@ int telnet_sendv(struct client_t *cln, const char *fmt, va_list ap) return telnet_send(cln, temp_buf, r); } -static int send_banner(struct client_t *cln) +static int send_banner(struct telnet_client_t *cln) { return telnet_send(cln, BANNER, sizeof(BANNER)); } -static int send_config(struct client_t *cln) +static int send_config(struct telnet_client_t *cln) { uint8_t buf[] = {IAC, WILL, TELOPT_ECHO, IAC, WILL, TELOPT_SGA, IAC, DONT, TELOPT_LINEMODE}; return telnet_send(cln, buf, sizeof(buf)); } -static int send_password_request(struct client_t *cln) +static int send_password_request(struct telnet_client_t *cln) { uint8_t buf0[] = {IAC, WILL, TELOPT_ECHO}; uint8_t buf1[] = "Password: "; @@ -153,9 +190,9 @@ static int send_password_request(struct client_t *cln) return 0; } -static int send_prompt(struct client_t *cln) +static int send_prompt(struct telnet_client_t *cln) { - return telnet_send(cln, conf_prompt, strlen(conf_prompt)); + return telnet_send(cln, conf_cli_prompt, strlen(conf_cli_prompt)); } /*static void print_buf(const uint8_t *buf, int size) @@ -167,7 +204,7 @@ static int send_prompt(struct client_t *cln) log_debug("\n"); }*/ -static int send_cmdline_tail(struct client_t *cln, int corr) +static int send_cmdline_tail(struct telnet_client_t *cln, int corr) { if (telnet_send(cln, cln->cmdline + cln->cmdline_pos, cln->cmdline_len - cln->cmdline_pos)) return -1; @@ -180,7 +217,7 @@ static int send_cmdline_tail(struct client_t *cln, int corr) return 0; } -static int load_history(struct client_t *cln) +static int load_history(struct telnet_client_t *cln) { struct buffer_t *b = list_entry(cln->history_pos, typeof(*b), entry); if (b->size < cln->cmdline_len) { @@ -202,7 +239,7 @@ static int load_history(struct client_t *cln) return 0; } -static int telnet_input_char(struct client_t *cln, uint8_t c) +static int telnet_input_char(struct telnet_client_t *cln, uint8_t c) { uint8_t buf[] = {IAC, DONT, 0}; struct buffer_t *b; @@ -219,7 +256,7 @@ static int telnet_input_char(struct client_t *cln, uint8_t c) } if (!cln->auth) { - if (strcmp((char *)cln->cmdline, conf_passwd)) { + if (strcmp((char *)cln->cmdline, conf_cli_passwd)) { if (telnet_send(cln, AUTH_FAILED, sizeof(AUTH_FAILED))) return -1; disconnect(cln); @@ -233,7 +270,7 @@ static int telnet_input_char(struct client_t *cln, uint8_t c) list_add(&b->entry, cln->history.next); cln->history_pos = cln->history.next; - if (process_cmd(cln)) + if (cli_process_cmd(&cln->cli_client)) return -1; } @@ -394,7 +431,7 @@ static int telnet_input_char(struct client_t *cln, uint8_t c) static int cln_read(struct triton_md_handler_t *h) { - struct client_t *cln = container_of(h, typeof(*cln), hnd); + struct telnet_client_t *cln = container_of(h, typeof(*cln), hnd); int i, n; while (1) { @@ -405,7 +442,7 @@ static int cln_read(struct triton_md_handler_t *h) } if (n < 0) { if (errno != EAGAIN) - log_error("cli: read: %s\n", strerror(errno)); + log_error("cli: telnet: read: %s\n", strerror(errno)); return 0; } /*log_debug("cli: read(%i): ", n); @@ -425,7 +462,7 @@ static int cln_read(struct triton_md_handler_t *h) static int cln_write(struct triton_md_handler_t *h) { - struct client_t *cln = container_of(h, typeof(*cln), hnd); + struct telnet_client_t *cln = container_of(h, typeof(*cln), hnd); int k; while (1) { @@ -435,7 +472,7 @@ static int cln_write(struct triton_md_handler_t *h) if (errno == EAGAIN) return 0; if (errno != EPIPE) - log_error("cli: write: %s\n", strerror(errno)); + log_error("cli: telnet: write: %s\n", strerror(errno)); disconnect(cln); return -1; } @@ -461,7 +498,7 @@ static int serv_read(struct triton_md_handler_t *h) struct sockaddr_in addr; socklen_t size = sizeof(addr); int sock; - struct client_t *conn; + struct telnet_client_t *conn; struct buffer_t *b; while(1) { @@ -469,14 +506,14 @@ static int serv_read(struct triton_md_handler_t *h) if (sock < 0) { if (errno == EAGAIN) return 0; - log_error("cli: accept failed: %s\n", strerror(errno)); + log_error("cli: telnet: accept failed: %s\n", strerror(errno)); continue; } - log_info("cli: new connection from %s\n", inet_ntoa(addr.sin_addr)); + log_info("cli: telnet: new connection from %s\n", inet_ntoa(addr.sin_addr)); if (fcntl(sock, F_SETFL, O_NONBLOCK)) { - log_error("cli: failed to set nonblocking mode: %s, closing connection...\n", strerror(errno)); + log_error("cli: telnet: failed to set nonblocking mode: %s, closing connection...\n", strerror(errno)); close(sock); continue; } @@ -495,16 +532,23 @@ static int serv_read(struct triton_md_handler_t *h) list_add_tail(&b->entry, &conn->history); conn->history_pos = conn->history.next; + conn->cli_client.cmdline = conn->cmdline; + conn->cli_client.send = cli_client_send; + conn->cli_client.sendv = cli_client_sendv; + conn->cli_client.disconnect = cli_client_disconnect; + triton_md_register_handler(&serv_ctx, &conn->hnd); triton_md_enable_handler(&conn->hnd,MD_MODE_READ); + list_add_tail(&conn->entry, &clients); + if (send_banner(conn)) continue; if (send_config(conn)) continue; - if (conf_passwd) + if (conf_cli_passwd) send_password_request(conn); else { conn->auth = 1; @@ -515,6 +559,13 @@ static int serv_read(struct triton_md_handler_t *h) } static void serv_close(struct triton_context_t *ctx) { + struct telnet_client_t *cln; + + while (!list_empty(&clients)) { + cln = list_entry(clients.next, typeof(*cln), entry); + disconnect(cln); + } + triton_md_unregister_handler(&serv_hnd); close(serv_hnd.fd); triton_context_unregister(ctx); @@ -534,7 +585,7 @@ static void start_server(const char *host, int port) serv_hnd.fd = socket(PF_INET, SOCK_STREAM, 0); if (serv_hnd.fd < 0) { - log_emerg("cli: failed to create server socket: %s\n", strerror(errno)); + log_emerg("cli: telnet: failed to create server socket: %s\n", strerror(errno)); return; } @@ -548,19 +599,19 @@ static void start_server(const char *host, int port) setsockopt(serv_hnd.fd, SOL_SOCKET, SO_REUSEADDR, &serv_hnd.fd, 4); if (bind (serv_hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { - log_emerg("cli: failed to bind socket: %s\n", strerror(errno)); + log_emerg("cli: telnet: failed to bind socket: %s\n", strerror(errno)); close(serv_hnd.fd); return; } if (listen (serv_hnd.fd, 1) < 0) { - log_emerg("cli: failed to listen socket: %s\n", strerror(errno)); + log_emerg("cli: telnet: failed to listen socket: %s\n", strerror(errno)); close(serv_hnd.fd); return; } if (fcntl(serv_hnd.fd, F_SETFL, O_NONBLOCK)) { - log_emerg("cli: failed to set nonblocking mode: %s\n", strerror(errno)); + log_emerg("cli: telnet: failed to set nonblocking mode: %s\n", strerror(errno)); close(serv_hnd.fd); return; } @@ -578,30 +629,30 @@ static void start_server(const char *host, int port) static void __init init(void) { const char *opt; - int port = 0; - const char *host="127.0.0.1"; - - opt = conf_get_opt("cli", "port"); - if (opt && atoi(opt) > 0) - port = atoi(opt); - - opt = conf_get_opt("cli", "bind"); - if (opt) - host = opt; - - if (!port) { - log_emerg("cli: disabled\n"); - return; + char *host, *d; + int port; + + opt = conf_get_opt("cli", "telnet"); + if (opt) { + host = strdup(opt); + d = strstr(host, ":"); + if (!d) { + return; + } + *d = 0; + port = atoi(d + 1); + if (port <= 0) + goto err_fmt; } - conf_passwd = conf_get_opt("cli", "passwd"); - opt = conf_get_opt("cli", "prompt"); - if (opt) - conf_prompt = opt; - recv_buf = malloc(RECV_BUF_SIZE); temp_buf = malloc(RECV_BUF_SIZE); start_server(host, port); + + return; +err_fmt: + log_emerg("cli: telnet: invalid format\n"); + free(host); } |