diff options
Diffstat (limited to 'accel-pptpd/cli')
-rw-r--r-- | accel-pptpd/cli/cli.c | 151 | ||||
-rw-r--r-- | accel-pptpd/cli/cli.h | 37 | ||||
-rw-r--r-- | accel-pptpd/cli/std_cmd.c | 102 | ||||
-rw-r--r-- | accel-pptpd/cli/telnet.c | 120 | ||||
-rw-r--r-- | accel-pptpd/cli/telnet.h | 21 |
5 files changed, 416 insertions, 15 deletions
diff --git a/accel-pptpd/cli/cli.c b/accel-pptpd/cli/cli.c new file mode 100644 index 00000000..92df1c38 --- /dev/null +++ b/accel-pptpd/cli/cli.c @@ -0,0 +1,151 @@ +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "triton.h" + +#include "telnet.h" +#include "cli.h" +#include "log.h" + +#define MAX_CMD_ITEMS 100 +#define MSG_SYNTAX_ERROR "syntax error\r\n" +#define MSG_UNKNOWN_CMD "command unknown\r\n" + +static LIST_HEAD(simple_cmd_list); +static LIST_HEAD(regexp_cmd_list); + +void __export cli_register_simple_cmd(struct cli_simple_cmd_t *cmd) +{ + list_add_tail(&cmd->entry, &simple_cmd_list); +} + +void __export cli_register_regexp_cmd(struct cli_regexp_cmd_t *cmd) +{ + int err; + cmd->re = pcre_compile2(cmd->pattern, cmd->options, &err, NULL, NULL, NULL); + if (!cmd->re) { + log_emerg("cli: failed to compile regexp %s: %i\n", cmd->pattern, err); + _exit(EXIT_FAILURE); + } + list_add_tail(&cmd->entry, &simple_cmd_list); +} + +int __export cli_send(void *client, const char *data) +{ + struct client_t *cln = (struct client_t *)client; + + return telnet_send(cln, data, strlen(data)); +} + + +static char *skip_word(char *ptr) +{ + for(; *ptr; ptr++) + if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') + break; + return ptr; +} +static char *skip_space(char *ptr) +{ + for(; *ptr; ptr++) + if (*ptr != ' ' && *ptr != '\t') + break; + return ptr; +} +static int split(char *buf, char **ptr) +{ + int i; + + ptr[0] = buf; + + for (i = 1; i <= MAX_CMD_ITEMS; i++) { + buf = skip_word(buf); + if (!*buf) + return i; + + *buf = 0; + + buf = skip_space(buf + 1); + if (!*buf) + return i; + + ptr[i] = buf; + } + + buf = skip_word(buf); + *buf = 0; + + return i; +} + +int process_cmd(struct client_t *cln) +{ + struct cli_simple_cmd_t *cmd1; + struct cli_regexp_cmd_t *cmd2; + char *f[MAX_CMD_ITEMS]; + int r, i, n, found = 0; + + n = split((char *)cln->recv_buf, f); + + if (n >= 1 && !strcmp(f[0], "help")) { + list_for_each_entry(cmd1, &simple_cmd_list, entry) { + if (cmd1->help && cmd1->help(f, n, cln)) + return -1; + } + list_for_each_entry(cmd2, ®exp_cmd_list, entry) { + if (cmd2->help && cmd1->help(f, n, cln)) + return -1; + } + + return 0; + } + + list_for_each_entry(cmd1, &simple_cmd_list, entry) { + if (cmd1->hdr_len && n >= cmd1->hdr_len) { + for (i = 0; i < cmd1->hdr_len; i++) { + if (strcmp(cmd1->hdr[i], f[i])) + break; + } + if (i < cmd1->hdr_len) + continue; + r = cmd1->exec((char *)cln->recv_buf, f, n, cln); + switch (r) { + case CLI_CMD_EXIT: + telnet_disconnect(cln); + case CLI_CMD_FAILED: + return -1; + case CLI_CMD_SYNTAX: + if (telnet_send(cln, MSG_SYNTAX_ERROR, sizeof(MSG_SYNTAX_ERROR))) + return -1; + return 0; + case CLI_CMD_OK: + found = 1; + } + } + } + + list_for_each_entry(cmd2, ®exp_cmd_list, entry) { + r = cmd2->exec((char *)cln->recv_buf, cln); + switch (r) { + case CLI_CMD_EXIT: + telnet_disconnect(cln); + case CLI_CMD_FAILED: + return -1; + case CLI_CMD_SYNTAX: + if (telnet_send(cln, MSG_SYNTAX_ERROR, sizeof(MSG_SYNTAX_ERROR))) + return -1; + return 0; + case CLI_CMD_OK: + found = 1; + } + } + + if (!found) { + if (telnet_send(cln, MSG_UNKNOWN_CMD, sizeof(MSG_UNKNOWN_CMD))) + return -1; + } + + return 0; +} + diff --git a/accel-pptpd/cli/cli.h b/accel-pptpd/cli/cli.h new file mode 100644 index 00000000..aec62fd3 --- /dev/null +++ b/accel-pptpd/cli/cli.h @@ -0,0 +1,37 @@ +#ifndef __CLI_H +#define __CLI_H + +#include <pcre.h> +#include <list.h> + +#define CLI_CMD_OK 0 +#define CLI_CMD_FAILED -1 +#define CLI_CMD_EXIT -2 +#define CLI_CMD_SYNTAX 1 + +struct cli_simple_cmd_t +{ + struct list_head entry; + int hdr_len; + const char **hdr; + int (*exec)(const char *cmd, char * const *fields, int fields_cnt, void *client); + int (*help)(char * const *fields, int field_cnt, void *client); +}; + +struct cli_regexp_cmd_t +{ + struct list_head entry; + pcre *re; + const char *pattern; + int options; + int (*exec)(const char *cmd, void *client); + int (*help)(char * const *fields, int field_cnt, void *client); +}; + +void cli_register_simple_cmd(struct cli_simple_cmd_t *cmd); +void cli_register_regexp_cmd(struct cli_regexp_cmd_t *cmd); + +int cli_send(void *client, const char *data); + +#endif + diff --git a/accel-pptpd/cli/std_cmd.c b/accel-pptpd/cli/std_cmd.c new file mode 100644 index 00000000..2239bef3 --- /dev/null +++ b/accel-pptpd/cli/std_cmd.c @@ -0,0 +1,102 @@ +#include <stdio.h> + +#include "triton.h" +#include "cli.h" + +int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) +{ + char buf[128]; + + if (cli_send(client, "core:\r\n")) + return CLI_CMD_FAILED; + + sprintf(buf, "\tmempool_allocated: %u\r\n", triton_stat.mempool_allocated); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\tmempool_available: %u\r\n", triton_stat.mempool_available); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\tthread_count: %u\r\n", triton_stat.thread_count); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\tthread_active: %u\r\n", triton_stat.thread_active); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\tcontext_count: %u\r\n", triton_stat.context_count); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\tcontext_sleeping: %u\r\n", triton_stat.context_sleeping); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\tcontext_pending: %u\r\n", triton_stat.context_pending); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\tmd_handler_count: %u\r\n", triton_stat.md_handler_count); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\tmd_handler_pending: %u\r\n", triton_stat.md_handler_pending); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\ttimer_count: %u\r\n", triton_stat.timer_count); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + sprintf(buf, "\ttimer_pending: %u\r\n", triton_stat.timer_pending); + if (cli_send(client, buf)) + return CLI_CMD_FAILED; + + return CLI_CMD_OK; +} + +int show_stat_help(char * const *fields, int fields_cnt, void *client) +{ + if (cli_send(client, "show stat - shows various statistics information\r\n")) + return -1; + + return 0; +} + +int exit_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) +{ + return CLI_CMD_EXIT; +} + +int exit_help(char * const *fields, int fields_cnt, void *client) +{ + if (cli_send(client, "exit - exit cli\r\n")) + return -1; + + return 0; +} + +const char *show_stat_hdr[] = {"show","stat"}; +static struct cli_simple_cmd_t show_stat_cmd = { + .hdr_len = 2, + .hdr = show_stat_hdr, + .exec = show_stat_exec, + .help = show_stat_help, +}; + +const char *exit_hdr[] = {"exit"}; +static struct cli_simple_cmd_t exit_cmd = { + .hdr_len = 1, + .hdr = exit_hdr, + .exec = exit_exec, + .help = exit_help, +}; + + +static void __init init(void) +{ + cli_register_simple_cmd(&show_stat_cmd); + cli_register_simple_cmd(&exit_cmd); +} diff --git a/accel-pptpd/cli/telnet.c b/accel-pptpd/cli/telnet.c index 50ef9240..30ec02b2 100644 --- a/accel-pptpd/cli/telnet.c +++ b/accel-pptpd/cli/telnet.c @@ -16,20 +16,11 @@ #include "list.h" #include "memdebug.h" +#include "telnet.h" + #define RECV_BUF_SIZE 4096 #define BANNER "accel-pptp-1.3-rc1\r\n" - -struct client_t -{ - struct list_head entry; - struct triton_md_handler_t hnd; - uint8_t *recv_buf; - int recv_pos; - struct list_head xmit_queue; - struct buffer_t *xmit_buf; - int xmit_pos; - int auth:1; -}; +#define AUTH_FAILED "\r\nAuthentication failed\r\n" struct buffer_t { @@ -38,6 +29,9 @@ 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; @@ -63,6 +57,11 @@ static void disconnect(struct client_t *cln) _free(cln); } +void telnet_disconnect(struct client_t *cln) +{ + disconnect(cln); +} + static void queue_buffer(struct client_t *cln, struct buffer_t *b) { if (cln->xmit_buf) @@ -71,7 +70,7 @@ static void queue_buffer(struct client_t *cln, struct buffer_t *b) cln->xmit_buf = b; } -static int telnet_send(struct client_t *cln, const void *_buf, int size) +int telnet_send(struct client_t *cln, const void *_buf, int size) { int n, k; struct buffer_t *b; @@ -103,11 +102,25 @@ static int send_banner(struct client_t *cln) return telnet_send(cln, BANNER, sizeof(BANNER)); } -static int send_auth_request(struct client_t *cln) +static int send_password_request(struct client_t *cln) { + uint8_t buf0[] = {IAC, WILL, TELOPT_ECHO}; + uint8_t buf1[] = "Password: "; + + if (telnet_send(cln, buf0, sizeof(buf0))) + return -1; + + if (telnet_send(cln, buf1, sizeof(buf1))) + return -1; + return 0; } +static int send_prompt(struct client_t *cln) +{ + return telnet_send(cln, conf_prompt, strlen(conf_prompt)); +} + static void print_buf(const uint8_t *buf, int size) { int i; @@ -117,6 +130,69 @@ static void print_buf(const uint8_t *buf, int size) log_debug("\n"); } +static int process_data(struct client_t *cln) +{ + int i, n; + char *eof; + uint8_t buf[] = {IAC, DONT, 0, '\r', '\n'}; + + eof = strstr((const char*)cln->recv_buf, "\r\n"); + if (!eof) + return 0; + + *eof = 0; + + for (i = 0; i < cln->recv_pos; i++) { + if (cln->recv_buf[i] == 0xff) { + if (i >= cln->recv_pos - 1) + return 0; + if (cln->recv_buf[i + 1] == WILL || cln->recv_buf[i + 1] == WONT) { + if (i >= cln->recv_pos - 2) + return 0; + buf[2] = cln->recv_buf[i + 2]; + if (telnet_send(cln, buf, 3)) + return -1; + } + + if (cln->recv_buf[i + 1] >= 251 && cln->recv_buf[i + 1] <= 254) { + if (i >= cln->recv_pos - 2) + return 0; + n = 3; + } else + n = 2; + + memmove(cln->recv_buf + i, cln->recv_buf + i + n, cln->recv_pos - i - n); + cln->recv_pos -= n; + i--; + } + } + + if (!cln->auth) { + if (strcmp((const char*)cln->recv_buf, conf_passwd)) { + if (telnet_send(cln, AUTH_FAILED, sizeof(AUTH_FAILED))) + return -1; + disconnect(cln); + return -1; + } + cln->auth = 1; + buf[1] = WONT; + buf[2] = TELOPT_ECHO; + if (telnet_send(cln, buf, 5)) + return -1; + + } else { + if (process_cmd(cln)) + return -1; + } + + if (send_prompt(cln)) + return -1; + + cln->recv_pos = 0; + + return 0; +} + static int cln_read(struct triton_md_handler_t *h) { struct client_t *cln = container_of(h, typeof(*cln), hnd); @@ -135,6 +211,9 @@ static int cln_read(struct triton_md_handler_t *h) } log_debug("cli: read(%i): ", n); print_buf(cln->recv_buf + cln->recv_pos, n); + cln->recv_pos += n; + if (process_data(cln)) + return -1; } return 0; @@ -210,7 +289,13 @@ static int serv_read(struct triton_md_handler_t *h) if (send_banner(conn)) continue; - send_auth_request(conn); + + if (conf_passwd) + send_password_request(conn); + else { + conn->auth = 1; + send_prompt(conn); + } } return 0; } @@ -294,6 +379,11 @@ static void __init init(void) return; } + conf_passwd = conf_get_opt("cli", "passwd"); + opt = conf_get_opt("cli", "prompt"); + if (opt) + conf_prompt = opt; + start_server(host, port); } diff --git a/accel-pptpd/cli/telnet.h b/accel-pptpd/cli/telnet.h new file mode 100644 index 00000000..eab156c5 --- /dev/null +++ b/accel-pptpd/cli/telnet.h @@ -0,0 +1,21 @@ +#ifndef __TELNET_H +#define __TELNET_H + +struct client_t +{ + struct list_head entry; + struct triton_md_handler_t hnd; + uint8_t *recv_buf; + int recv_pos; + struct list_head xmit_queue; + struct buffer_t *xmit_buf; + int xmit_pos; + int auth:1; +}; + +int telnet_send(struct client_t *cln, const void *buf, int size); +void telnet_disconnect(struct client_t *cln); +int process_cmd(struct client_t *cln); + +#endif + |