#include #include #include #include #include #include #include #include #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) { struct tabentry *l = first; 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; } struct tabentry* msntab_ref(struct tabentry *t) { assert(t && t->ref_counter >= 1); t->ref_counter++; return 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 ==="); }