summaryrefslogtreecommitdiffstats
path: root/src/msntab.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/msntab.c')
-rw-r--r--src/msntab.c303
1 files changed, 300 insertions, 3 deletions
diff --git a/src/msntab.c b/src/msntab.c
index bcd3030..09709cc 100644
--- a/src/msntab.c
+++ b/src/msntab.c
@@ -1,12 +1,39 @@
#include <stddef.h>
#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <libdaemon/dlog.h>
+
#include "msntab.h"
+#define MAX_ENTRIES 100
+#define MAX_INCLUDES 10
+
+static struct tabentry *first = NULL;
+static struct tabentry *last = NULL;
+static int n_entries = 0;
+
+static int n_includes = 0;
+
struct tabentry* msntab_check_call(const char *callee, const char *caller) {
- static char *args[] = { "/bin/cat", NULL };
- static struct tabentry ca = { CALL_ACTION_ACCEPT, 1, args };
+ struct tabentry *l = first;
- return msntab_ref(&ca);
+ while (l) {
+ assert(l->local && l->remote);
+
+ if (!fnmatch(l->local, callee, 0) && !fnmatch(l->remote, caller, 0)) {
+ daemon_log(LOG_INFO, "MSN table entry from '%s:%u' matched.", l->filename, l->line);
+ return msntab_ref(l);
+ }
+
+ l = l->next;
+ }
+
+ return NULL;
}
@@ -19,5 +46,275 @@ struct tabentry* msntab_ref(struct tabentry *t) {
void msntab_unref(struct tabentry *t) {
assert(t && t->ref_counter >= 1);
t->ref_counter--;
+
+ if (t->ref_counter == 0) {
+
+ if (t->args) {
+ char **a = t->args;
+ while (*a) {
+ free(*a);
+ a++;
+ }
+ free(t->args);
+ }
+
+ free(t->local);
+ free(t->remote);
+ free(t->filename);
+
+ free(t);
+ }
+}
+
+void msntab_flush(void) {
+ while (first) {
+ struct tabentry *l = first;
+ first = first->next;
+
+ if (first)
+ first->prev = NULL;
+
+ if (last == l)
+ last = NULL;
+
+ msntab_unref(l);
+ }
+
+ n_entries = 0;
+ n_includes++;
+}
+
+#define MAX_ARGS 16
+
+static char** parse_args(const char *s) {
+ char *o, **a;
+ char *c = (char*) s;
+ int i = 0;
+
+ a = malloc(sizeof(char *)*MAX_ARGS);
+ memset(a, 0, sizeof(char *)*MAX_ARGS);
+
+ while ((o = strsep(&c, " \t"))) {
+ a[i++] = strdup(o);
+
+ if (i >= MAX_ARGS-1)
+ break;
+ }
+
+ return a;
+}
+
+
+static int parse_options(const char *s, struct tabentry *t) {
+ char *o;
+ char *c = (char*) s;
+
+ assert(s && t);
+
+ while ((o = strsep(&c, ","))) {
+
+ if (!strcmp(o, "defaults"))
+ continue;
+ else if (!strcmp(o, "shbuf")) {
+ t->shbuf = 1;
+ continue;
+ } else if (!strncmp(o, "rings=", 6)) {
+ t->rings = atoi(o+6);
+ continue;
+ }
+
+ daemon_log(LOG_INFO, "Unknown option '%s'", o);
+ return -1;
+ }
+
+ return 0;
}
+
+int msntab_load(const char *fn) {
+ int n;
+ struct tabentry *t = NULL;
+ FILE *f = NULL;
+
+ daemon_log(LOG_INFO, "Loading MSN table '%s'.", fn);
+ if (!(f = fopen(fn, "r"))) {
+ daemon_log(LOG_ERR, "Failed to open MSN table '%s'.", fn);
+ goto fail;
+ }
+
+ n = 0;
+ while (!feof(f)) {
+ char l[256], *c, *e, *local, *remote, *options, *action;
+
+ n++;
+
+ if (!fgets(l, sizeof(l), f))
+ break;
+
+ c = l+strspn(l, " \t");
+ if ((e = strchr(c, '\r')))
+ *e = 0;
+ if ((e = strchr(c, '\n')))
+ *e = 0;
+ e = strchr(c, 0);
+
+ if (*c == '#' || *c == 0)
+ continue;
+
+ if (!(local = strsep(&c, " \t"))) {
+ daemon_log(LOG_ERR, "Parse failure on local MSN field in '%s:%i'.", fn, n);
+ goto fail;
+ }
+
+ if (c)
+ c+=strspn(c, " \t");
+
+ if (!strcmp(local, "@include")) {
+ char *include;
+
+ if (n_includes ++ >= MAX_INCLUDES) {
+ daemon_log(LOG_ERR, "Recursive include directive detected.");
+ goto fail;
+ }
+
+ if (!(include = strsep(&c, ""))) {
+ daemon_log(LOG_ERR, "Parse failure on include field in '%s:%i'.", fn, n);
+ goto fail;
+ }
+
+ if (msntab_load(include) < 0)
+ goto fail;
+
+ continue;
+ }
+
+ if (!(remote = strsep(&c, " \t"))) {
+ daemon_log(LOG_ERR, "Parse failure on remote MSN field in '%s:%i'.", fn, n);
+ goto fail;
+ }
+
+ if (c)
+ c+=strspn(c, " \t");
+
+ if (!(options = strsep(&c, " \t"))) {
+ daemon_log(LOG_ERR, "Parse failure on options field in '%s:%i'.", fn, n);
+ goto fail;
+ }
+
+ if (c)
+ c+=strspn(c, " \t");
+
+ if (!(action = strsep(&c, ""))) {
+ daemon_log(LOG_ERR, "Parse failure on action field in '%s:%i'.", fn, n);
+ goto fail;
+ }
+
+ t = malloc(sizeof(struct tabentry));
+ assert(t);
+ memset(t, 0, sizeof(struct tabentry));
+
+ t->line = n;
+ t->filename = strdup(fn);
+
+ t->ref_counter = 1;
+
+ t->local = strdup(local);
+ assert(t->local);
+
+ t->remote = strdup(remote);
+ assert(t->remote);
+
+ if (action[0] == '@') {
+ if (!strcmp(action, "@hangup"))
+ t->action = CALL_ACTION_HANGUP;
+ else if (!strcmp(action, "@ignore"))
+ t->action = CALL_ACTION_IGNORE;
+ else {
+ daemon_log(LOG_ERR, "Unknown action command '%s' in '%s:%i'.", action, fn, n);
+ goto fail;
+ }
+ } else {
+ t->action = CALL_ACTION_ACCEPT;
+ t->args = parse_args(action);
+ }
+
+ if (parse_options(options, t) < 0) {
+ daemon_log(LOG_ERR, "Parse failure on options field in '%s:%i'.", fn, n);
+ goto fail;
+ }
+
+ if (last) {
+ t->prev = last;
+ last->next = t;
+ last = t;
+ } else
+ last = first = t;
+
+ n_entries ++;
+
+ t = NULL;
+
+ if (n_entries > MAX_ENTRIES) {
+ daemon_log(LOG_INFO, "Too many MSN table entries");
+ goto fail;
+ }
+ }
+
+ fclose(f);
+ daemon_log(LOG_INFO, "MSN table '%s' successfully read.", fn);
+
+ return 0;
+
+fail:
+
+ if (t)
+ msntab_unref(t);
+
+ if (f)
+ fclose(f);
+
+ return -1;
+}
+
+
+static void dump_entry(struct tabentry *t) {
+ char s[256];
+ assert(t);
+
+ s[0] = 0;
+
+ if (t->args) {
+ char **a = t->args;
+
+ while (*a) {
+ char *p = strchr(s, 0);
+ snprintf(p, sizeof(s)-(p-s), a == t->args ? "%s" : " %s", *a);
+ a++;
+ }
+ } else
+ strncpy(s, "NOARGS", sizeof(s));
+
+ daemon_log(LOG_INFO, "[%s:%02u] %-12s -> %-12s; shbuf=%-3s; rings=%u; action=%s; args=<%s>",
+ t->filename,
+ t->line,
+ t->local,
+ t->remote,
+ t->shbuf ? "yes" : "no",
+ t->rings,
+ t->action == CALL_ACTION_ACCEPT ? "ACCEPT" : (t->action == CALL_ACTION_HANGUP ? "HANGUP" : "IGNORE"),
+ s);
+}
+
+void msntab_dump(void) {
+ struct tabentry *l;
+
+ daemon_log(LOG_INFO, "=== Dumping MSN table ===");
+
+ l = first;
+ while (l) {
+ dump_entry(l);
+ l = l->next;
+ }
+
+ daemon_log(LOG_INFO, "=== MSN table dump complete ===");
+}