jabberd2  2.2.17
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  free(acl);
37  acl = tmp;
38  }
39  r->filter = NULL;
40 }
41 
43  char *filterfile;
44  FILE *f;
45  long size;
46  char *buf;
47  nad_t nad;
48  int i, nfilters, filter, from, to, what, redirect, error, log;
49  acl_t list_tail, acl;
50 
51  log_debug(ZONE, "loading filter");
52 
53  if(r->filter != NULL)
54  filter_unload(r);
55 
56  filterfile = config_get_one(r->config, "aci.filter", 0);
57  if(filterfile == NULL)
58  filterfile = CONFIG_DIR "/router-filter.xml";
59 
60  f = fopen(filterfile, "rb");
61  if(f == NULL) {
62  log_write(r->log, LOG_NOTICE, "couldn't open filter file %s: %s", filterfile, strerror(errno));
63  r->filter_load = time(NULL);
64  return 0;
65  }
66 
67  fseek(f, 0, SEEK_END);
68  size = ftell(f);
69  fseek(f, 0, SEEK_SET);
70 
71  buf = (char *) malloc(sizeof(char) * size);
72 
73  if (fread(buf, 1, size, f) != size || ferror(f)) {
74  log_write(r->log, LOG_ERR, "couldn't read from filter file: %s", strerror(errno));
75  free(buf);
76  fclose(f);
77  return 1;
78  }
79 
80  fclose(f);
81 
82  nad = nad_parse(buf, size);
83  if(nad == NULL) {
84  log_write(r->log, LOG_ERR, "couldn't parse filter file");
85  free(buf);
86  return 1;
87  }
88 
89  free(buf);
90 
91  list_tail = NULL;
92 
93  log_debug(ZONE, "building filter list");
94 
95  nfilters = 0;
96  filter = nad_find_elem(nad, 0, -1, "rule", 1);
97  while(filter >= 0) {
98  from = nad_find_attr(nad, filter, -1, "from", NULL);
99  to = nad_find_attr(nad, filter, -1, "to", NULL);
100  what = nad_find_attr(nad, filter, -1, "what", NULL);
101  redirect = nad_find_attr(nad, filter, -1, "redirect", NULL);
102  error = nad_find_attr(nad, filter, -1, "error", NULL);
103  log = nad_find_attr(nad, filter, -1, "log", NULL);
104 
105  acl = (acl_t) calloc(1, sizeof(struct acl_s));
106 
107  if(from >= 0) {
108  if (NAD_AVAL_L(nad, from) == 0 )
109  acl->from = NULL;
110  else {
111  acl->from = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, from) + 1));
112  sprintf(acl->from, "%.*s", NAD_AVAL_L(nad, from), NAD_AVAL(nad, from));
113  }
114  }
115  if(to >= 0) {
116  if (NAD_AVAL_L(nad, to) == 0 )
117  acl->to = NULL;
118  else {
119  acl->to = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, to) + 1));
120  sprintf(acl->to, "%.*s", NAD_AVAL_L(nad, to), NAD_AVAL(nad, to));
121  }
122  }
123  if(what >= 0) {
124  if (NAD_AVAL_L(nad, what) == 0 || strncmp(NAD_AVAL(nad, what), "*", NAD_AVAL_L(nad, what)) == 0)
125  acl->what = NULL;
126  else {
127  acl->what = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, what) + 1));
128  sprintf(acl->what, "%.*s", NAD_AVAL_L(nad, what), NAD_AVAL(nad, what));
129  }
130  }
131  if(redirect >= 0) {
132  if (NAD_AVAL_L(nad, redirect) == 0)
133  acl->redirect = NULL;
134  else {
135  acl->redirect_len = NAD_AVAL_L(nad, redirect);
136  acl->redirect = (char *) malloc(sizeof(char) * (acl->redirect_len + 1));
137  sprintf(acl->redirect, "%.*s", acl->redirect_len, NAD_AVAL(nad, redirect));
138  acl->error = stanza_err_REDIRECT;
139  }
140  }
141  if(error >= 0) {
143  for(i=0; _stanza_errors[i].code != NULL; i++) {
144  if(_stanza_errors[i].name != NULL && strncmp(_stanza_errors[i].name, NAD_AVAL(nad, error), NAD_AVAL_L(nad, error)) == 0) {
145  acl->error = stanza_err_BAD_REQUEST + i;
146  break;
147  }
148  }
149  }
150  if(log >= 0) {
151  acl->log = ! strncasecmp(NAD_AVAL(nad, log), "YES", NAD_AVAL_L(nad, log));
152  acl->log |= ! strncasecmp(NAD_AVAL(nad, log), "ON", NAD_AVAL_L(nad, log));
153  }
154 
155  if(list_tail != NULL) {
156  list_tail->next = acl;
157  list_tail = acl;
158  }
159 
160  /* record the head of the list */
161  if(r->filter == NULL) {
162  r->filter = acl;
163  list_tail = acl;
164  }
165 
166  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"));
167 
168  nfilters++;
169 
170  filter = nad_find_elem(nad, filter, -1, "rule", 0);
171  }
172 
173  nad_free(nad);
174 
175  log_write(r->log, LOG_NOTICE, "loaded filters (%d rules)", nfilters);
176 
177  r->filter_load = time(NULL);
178 
179  return 0;
180 }
181 
183  acl_t acl;
184  int ato, afrom, error = 0;
185  unsigned char *cur, *to = NULL, *from = NULL;
186 
187  ato = nad_find_attr(nad, 1, -1, "to", NULL);
188  afrom = nad_find_attr(nad, 1, -1, "from", NULL);
189  if(ato >= 0 && NAD_AVAL_L(nad,ato) > 0) {
190  to = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, ato) + 1));
191  sprintf(to, "%.*s", NAD_AVAL_L(nad, ato), NAD_AVAL(nad, ato));
192  cur = strstr(to, "@"); /* skip node part */
193  if(cur != NULL)
194  cur = strstr(cur, "/");
195  else
196  cur = strstr(to, "/");
197  if(cur != NULL) *cur = '\0'; /* remove the resource part */
198  }
199  if(afrom >= 0 && NAD_AVAL_L(nad,afrom) > 0) {
200  from = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, afrom) + 1));
201  sprintf(from, "%.*s", NAD_AVAL_L(nad, afrom), NAD_AVAL(nad, afrom));
202  cur = strstr(from, "@");
203  if(cur != NULL)
204  cur = strstr(cur, "/");
205  else
206  cur = strstr(from, "/");
207  if(cur != NULL) *cur = '\0';
208  }
209 
210  for(acl = r->filter; acl != NULL; acl = acl->next) {
211  if( from == NULL && acl->from != NULL) continue; /* no match if NULL matched vs not-NULL */
212  if( to == NULL && acl->to != NULL ) continue;
213  if( from != NULL && acl->from == NULL) continue; /* no match if not-NULL matched vs NULL */
214  if( to != NULL && acl->to == NULL ) continue;
215  if( from != NULL && acl->from != NULL && fnmatch(acl->from, from, 0) != 0 ) continue; /* do filename-like match */
216  if( to != NULL && acl->to != NULL && fnmatch(acl->to, to, 0) != 0 ) continue;
217  if( acl->what != NULL && nad_find_elem_path(nad, 0, -1, acl->what) < 0 ) continue; /* match packet type */
218  log_debug(ZONE, "matched packet %s->%s vs rule (%s %s->%s)", from, to, acl->what, acl->from, acl->to);
219  if (acl->log) {
220  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);
221  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);
222  }
223  if (acl->redirect) nad_set_attr(nad, 0, -1, "to", acl->redirect, acl->redirect_len);
224  error = acl->error;
225  break;
226  }
227 
228  if(to != NULL) free(to);
229  if(from != NULL) free(from);
230  return error;
231 }
232