jabberd2  2.3.6
filter.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2006 Tomasz Sterna
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
18  */
19 
20 #include "router.h"
21 #include <fnmatch.h>
22 
26  acl_t acl, tmp;
27 
28  acl = r->filter;
29 
30  while(acl != NULL) {
31  tmp = acl->next;
32  if(acl->from != NULL) free(acl->from);
33  if(acl->to != NULL) free(acl->to);
34  if(acl->what != NULL) free(acl->what);
35  if(acl->redirect != NULL) free(acl->redirect);
36  if(acl->dump != NULL) free(acl->dump);
37  free(acl);
38  acl = tmp;
39  }
40  r->filter = NULL;
41 }
42 
44  const char *filterfile;
45  FILE *f;
46  long size;
47  char *buf;
48  nad_t nad;
49  int i, nfilters, filter, from, to, what, redirect, error, log, dump;
50  acl_t list_tail, acl;
51 
52  log_debug(ZONE, "loading filter");
53 
54  if(r->filter != NULL)
55  filter_unload(r);
56 
57  filterfile = config_get_one(r->config, "aci.filter", 0);
58  if(filterfile == NULL)
59  filterfile = CONFIG_DIR "/router-filter.xml";
60 
61  f = fopen(filterfile, "rb");
62  if(f == NULL) {
63  log_write(r->log, LOG_NOTICE, "couldn't open filter file %s: %s", filterfile, strerror(errno));
64  r->filter_load = time(NULL);
65  return 0;
66  }
67 
68  fseek(f, 0, SEEK_END);
69  size = ftell(f);
70  fseek(f, 0, SEEK_SET);
71 
72  buf = (char *) malloc(sizeof(char) * size);
73 
74  if (fread(buf, 1, size, f) != size || ferror(f)) {
75  log_write(r->log, LOG_ERR, "couldn't read from filter file: %s", strerror(errno));
76  free(buf);
77  fclose(f);
78  return 1;
79  }
80 
81  fclose(f);
82 
83  nad = nad_parse(buf, size);
84  if(nad == NULL) {
85  log_write(r->log, LOG_ERR, "couldn't parse filter file");
86  free(buf);
87  return 1;
88  }
89 
90  free(buf);
91 
92  list_tail = NULL;
93 
94  log_debug(ZONE, "building filter list");
95 
96  nfilters = 0;
97  filter = nad_find_elem(nad, 0, -1, "rule", 1);
98  while(filter >= 0) {
99  from = nad_find_attr(nad, filter, -1, "from", NULL);
100  to = nad_find_attr(nad, filter, -1, "to", NULL);
101  what = nad_find_attr(nad, filter, -1, "what", NULL);
102  redirect = nad_find_attr(nad, filter, -1, "redirect", NULL);
103  error = nad_find_attr(nad, filter, -1, "error", NULL);
104  log = nad_find_attr(nad, filter, -1, "log", NULL);
105  dump = nad_find_attr(nad, filter, -1, "dump", NULL);
106 
107  acl = (acl_t) calloc(1, sizeof(struct acl_s));
108 
109  if(from >= 0) {
110  if (NAD_AVAL_L(nad, from) == 0 )
111  acl->from = NULL;
112  else {
113  acl->from = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, from) + 1));
114  sprintf(acl->from, "%.*s", NAD_AVAL_L(nad, from), NAD_AVAL(nad, from));
115  }
116  }
117  if(to >= 0) {
118  if (NAD_AVAL_L(nad, to) == 0 )
119  acl->to = NULL;
120  else {
121  acl->to = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, to) + 1));
122  sprintf(acl->to, "%.*s", NAD_AVAL_L(nad, to), NAD_AVAL(nad, to));
123  }
124  }
125  if(what >= 0) {
126  if (NAD_AVAL_L(nad, what) == 0 || strncmp(NAD_AVAL(nad, what), "*", NAD_AVAL_L(nad, what)) == 0)
127  acl->what = NULL;
128  else {
129  acl->what = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, what) + 1));
130  sprintf(acl->what, "%.*s", NAD_AVAL_L(nad, what), NAD_AVAL(nad, what));
131  }
132  }
133  if(redirect >= 0) {
134  if (NAD_AVAL_L(nad, redirect) == 0)
135  acl->redirect = NULL;
136  else {
137  acl->redirect_len = NAD_AVAL_L(nad, redirect);
138  acl->redirect = (char *) malloc(sizeof(char) * (acl->redirect_len + 1));
139  sprintf(acl->redirect, "%.*s", acl->redirect_len, NAD_AVAL(nad, redirect));
140  acl->error = stanza_err_REDIRECT;
141  }
142  }
143  if(error >= 0) {
145  for(i=0; _stanza_errors[i].code != NULL; i++) {
146  if(_stanza_errors[i].name != NULL && strncmp(_stanza_errors[i].name, NAD_AVAL(nad, error), NAD_AVAL_L(nad, error)) == 0) {
147  acl->error = stanza_err_BAD_REQUEST + i;
148  break;
149  }
150  }
151  }
152  if(log >= 0) {
153  acl->log = ! strncasecmp(NAD_AVAL(nad, log), "YES", NAD_AVAL_L(nad, log));
154  acl->log |= ! strncasecmp(NAD_AVAL(nad, log), "ON", NAD_AVAL_L(nad, log));
155  }
156  if(dump >= 0) {
157  if (NAD_AVAL_L(nad, dump) == 0)
158  acl->dump = NULL;
159  else {
160  acl->dump = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, dump) + 1));
161  sprintf(acl->dump, "%.*s", NAD_AVAL_L(nad, dump), NAD_AVAL(nad, dump));
162  }
163  }
164 
165  if(list_tail != NULL) {
166  list_tail->next = acl;
167  list_tail = acl;
168  }
169 
170  /* record the head of the list */
171  if(r->filter == NULL) {
172  r->filter = acl;
173  list_tail = acl;
174  }
175 
176  log_debug(ZONE, "added %s rule: from=%s, to=%s, what=%s, redirect=%s, error=%d, log=%s", (acl->error?"deny":"allow"), acl->from, acl->to, acl->what, acl->redirect, acl->error, (acl->log?"yes":"no"));
177 
178  nfilters++;
179 
180  filter = nad_find_elem(nad, filter, -1, "rule", 0);
181  }
182 
183  nad_free(nad);
184 
185  log_write(r->log, LOG_NOTICE, "loaded filters (%d rules)", nfilters);
186 
187  r->filter_load = time(NULL);
188 
189  return 0;
190 }
191 
193  acl_t acl;
194  int ato, afrom, error = 0;
195  char *cur, *to = NULL, *from = NULL;
196 
197  ato = nad_find_attr(nad, 1, -1, "to", NULL);
198  afrom = nad_find_attr(nad, 1, -1, "from", NULL);
199  if(ato >= 0 && NAD_AVAL_L(nad,ato) > 0) {
200  to = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, ato) + 1));
201  sprintf(to, "%.*s", NAD_AVAL_L(nad, ato), NAD_AVAL(nad, ato));
202  cur = strstr(to, "@"); /* skip node part */
203  if(cur != NULL)
204  cur = strstr(cur, "/");
205  else
206  cur = strstr(to, "/");
207  if(cur != NULL) *cur = '\0'; /* remove the resource part */
208  }
209  if(afrom >= 0 && NAD_AVAL_L(nad,afrom) > 0) {
210  from = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, afrom) + 1));
211  sprintf(from, "%.*s", NAD_AVAL_L(nad, afrom), NAD_AVAL(nad, afrom));
212  cur = strstr(from, "@");
213  if(cur != NULL)
214  cur = strstr(cur, "/");
215  else
216  cur = strstr(from, "/");
217  if(cur != NULL) *cur = '\0';
218  }
219 
220  for(acl = r->filter; acl != NULL; acl = acl->next) {
221  if( from == NULL && acl->from != NULL) continue; /* no match if NULL matched vs not-NULL */
222  if( to == NULL && acl->to != NULL ) continue;
223  if( from != NULL && acl->from == NULL) continue; /* no match if not-NULL matched vs NULL */
224  if( to != NULL && acl->to == NULL ) continue;
225  if( from != NULL && acl->from != NULL && fnmatch(acl->from, from, 0) != 0 ) continue; /* do filename-like match */
226  if( to != NULL && acl->to != NULL && fnmatch(acl->to, to, 0) != 0 ) continue;
227  if( acl->what != NULL && nad_find_elem_path(nad, 0, -1, acl->what) < 0 ) continue; /* match packet type */
228  log_debug(ZONE, "matched packet %s->%s vs rule (%s %s->%s)", from, to, acl->what, acl->from, acl->to);
229  if( acl->dump != NULL ) {
230  const char *out;
231  int len;
232  FILE *fd;
233  fd = fopen(acl->dump, "a");
234  if (fd == NULL) {
235  log_write(r->log, LOG_ERR, "filter: cannot open dump file %s: \"%s\", disabling dump for this rule.", acl->dump, strerror(errno));
236  free(acl->dump);
237  acl->dump = NULL;
238  } else {
239  nad_print(nad, 1, &out, &len);
240  fwrite(out, len, 1, fd);
241  /* Add newlines between the stanzas to improve human readability. */
242  fwrite("\n", 1, 1, fd);
243  fclose(fd);
244  }
245  }
246  if (acl->log) {
247  if (acl->redirect) log_write(r->log, LOG_NOTICE, "filter: redirect packet from=%s to=%s - rule (from=%s to=%s what=%s), new to=%s", from, to, acl->from, acl->to, acl->what, acl->redirect);
248  else log_write(r->log, LOG_NOTICE, "filter: %s packet from=%s to=%s - rule (from=%s to=%s what=%s)",(acl->error?"deny":"allow"), from, to, acl->from, acl->to, acl->what);
249  }
250  if (acl->redirect) nad_set_attr(nad, 0, -1, "to", acl->redirect, acl->redirect_len);
251  error = acl->error;
252  break;
253  }
254 
255  if(to != NULL) free(to);
256  if(from != NULL) free(from);
257  return error;
258 }
259 
Definition: nad.h:93
struct _stanza_error_st _stanza_errors[]
if you change these, reflect your changes in the defines in util.h
Definition: stanza.c:24
acl_t next
Definition: router.h:66
int filter_load(router_t r)
Definition: filter.c:43
char * what
Definition: router.h:61
char * to
Definition: router.h:63
int redirect_len
Definition: router.h:60
int nad_find_elem(nad_t nad, int elem, int ns, const char *name, int depth)
locate the next elem at a given depth with an optional matching name
Definition: nad.c:204
time_t filter_load
Definition: router.h:82
void log_write(log_t log, int level, const char *msgfmt,...)
Definition: log.c:104
const char * code
Definition: util.h:398
void nad_free(nad_t nad)
free that nad
Definition: nad.c:178
void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
create, update, or zap any matching attr on this elem
Definition: nad.c:403
nad_t nad_parse(const char *buf, int len)
create a nad from raw xml
Definition: nad.c:1414
log_t log
logging
Definition: router.h:85
#define stanza_err_BAD_REQUEST
Definition: util.h:367
#define stanza_err_REDIRECT
Definition: util.h:379
acl_t filter
user table
Definition: router.h:81
#define NAD_AVAL_L(N, A)
Definition: nad.h:190
#define log_debug(...)
Definition: log.h:65
#define stanza_err_NOT_ALLOWED
Definition: util.h:376
void filter_unload(router_t r)
filter manager
Definition: filter.c:25
#define NAD_AVAL(N, A)
Definition: nad.h:189
Definition: router.h:57
char * dump
Definition: router.h:64
int error
Definition: router.h:58
int filter_packet(router_t r, nad_t nad)
Definition: filter.c:192
#define ZONE
Definition: mio_impl.h:76
const char * config_get_one(config_t c, const char *key, int num)
get config value n for this key
Definition: config.c:277
int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val)
get a matching attr on this elem, both name and optional val
Definition: nad.c:235
int nad_find_elem_path(nad_t nad, int elem, int ns, const char *name)
find elem using XPath like query name – "name" for the child tag of that name "name/name" for a sub ...
Definition: nad.c:320
config_t config
config
Definition: router.h:74
int log
Definition: router.h:65
char * redirect
Definition: router.h:59
void nad_print(nad_t nad, int elem, const char **xml, int *len)
create a string representation of the given element (and children), point references to it ...
Definition: nad.c:1192
struct acl_s * acl_t
Definition: router.h:56
char * from
Definition: router.h:62