summaryrefslogtreecommitdiff
path: root/accel-pptpd/cli
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pptpd/cli')
-rw-r--r--accel-pptpd/cli/cli.c151
-rw-r--r--accel-pptpd/cli/cli.h37
-rw-r--r--accel-pptpd/cli/std_cmd.c102
-rw-r--r--accel-pptpd/cli/telnet.c120
-rw-r--r--accel-pptpd/cli/telnet.h21
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, &regexp_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, &regexp_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
+