jabberd2  2.2.16
router/filter.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2006 Tomasz Sterna
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00018  */
00019 
00020 #include "router.h"
00021 #include <fnmatch.h>
00022 
00025 void filter_unload(router_t r) {
00026     acl_t acl, tmp;
00027 
00028     acl = r->filter;
00029 
00030     while(acl != NULL) {
00031         tmp = acl->next;
00032         if(acl->from != NULL) free(acl->from);
00033         if(acl->to != NULL) free(acl->to);
00034         if(acl->what != NULL) free(acl->what);
00035         if(acl->redirect != NULL) free(acl->redirect);
00036         free(acl);
00037         acl = tmp;
00038     }
00039     r->filter = NULL;
00040 }
00041 
00042 int filter_load(router_t r) {
00043     char *filterfile;
00044     FILE *f;
00045     long size;
00046     char *buf;
00047     nad_t nad;
00048     int i, nfilters, filter, from, to, what, redirect, error, log;
00049     acl_t list_tail, acl;
00050 
00051     log_debug(ZONE, "loading filter");
00052     
00053     if(r->filter != NULL)
00054         filter_unload(r);
00055 
00056     filterfile = config_get_one(r->config, "aci.filter", 0);
00057     if(filterfile == NULL)
00058         filterfile = CONFIG_DIR "/router-filter.xml";
00059 
00060     f = fopen(filterfile, "rb");
00061     if(f == NULL) {
00062         log_write(r->log, LOG_NOTICE, "couldn't open filter file %s: %s", filterfile, strerror(errno));
00063         r->filter_load = time(NULL);
00064         return 0;
00065     }
00066 
00067     fseek(f, 0, SEEK_END);
00068     size = ftell(f);
00069     fseek(f, 0, SEEK_SET);
00070 
00071     buf = (char *) malloc(sizeof(char) * size);
00072 
00073     if (fread(buf, 1, size, f) != size || ferror(f)) {
00074         log_write(r->log, LOG_ERR, "couldn't read from filter file: %s", strerror(errno));
00075         free(buf);
00076         fclose(f);
00077         return 1;
00078     }
00079 
00080     fclose(f);
00081 
00082     nad = nad_parse(buf, size);
00083     if(nad == NULL) {
00084         log_write(r->log, LOG_ERR, "couldn't parse filter file");
00085         free(buf);
00086         return 1;
00087     }
00088 
00089     free(buf);
00090 
00091     list_tail = NULL;
00092 
00093     log_debug(ZONE, "building filter list");
00094 
00095     nfilters = 0;
00096     filter = nad_find_elem(nad, 0, -1, "rule", 1);
00097     while(filter >= 0) {
00098         from = nad_find_attr(nad, filter, -1, "from", NULL);
00099         to = nad_find_attr(nad, filter, -1, "to", NULL);
00100         what = nad_find_attr(nad, filter, -1, "what", NULL);
00101         redirect = nad_find_attr(nad, filter, -1, "redirect", NULL);
00102         error = nad_find_attr(nad, filter, -1, "error", NULL);
00103         log = nad_find_attr(nad, filter, -1, "log", NULL);
00104 
00105         acl = (acl_t) calloc(1, sizeof(struct acl_s));
00106 
00107         if(from >= 0) {
00108             if (NAD_AVAL_L(nad, from) == 0 )
00109                 acl->from = NULL;
00110             else {
00111                 acl->from = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, from) + 1));
00112                 sprintf(acl->from, "%.*s", NAD_AVAL_L(nad, from), NAD_AVAL(nad, from));
00113             }
00114         }
00115         if(to >= 0) {
00116             if (NAD_AVAL_L(nad, to) == 0 )
00117                 acl->to = NULL;
00118             else {
00119                 acl->to = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, to) + 1));
00120                 sprintf(acl->to, "%.*s", NAD_AVAL_L(nad, to), NAD_AVAL(nad, to));
00121             }
00122         }
00123         if(what >= 0) {
00124             if (NAD_AVAL_L(nad, what) == 0 || strncmp(NAD_AVAL(nad, what), "*", NAD_AVAL_L(nad, what)) == 0)
00125                 acl->what = NULL;
00126             else {
00127                 acl->what = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, what) + 1));
00128                 sprintf(acl->what, "%.*s", NAD_AVAL_L(nad, what), NAD_AVAL(nad, what));
00129             }
00130         }
00131         if(redirect >= 0) {
00132             if (NAD_AVAL_L(nad, redirect) == 0)
00133                 acl->redirect = NULL;
00134             else {
00135                 acl->redirect_len = NAD_AVAL_L(nad, redirect);
00136                 acl->redirect = (char *) malloc(sizeof(char) * (acl->redirect_len + 1));
00137                 sprintf(acl->redirect, "%.*s", acl->redirect_len, NAD_AVAL(nad, redirect));
00138                 acl->error = stanza_err_REDIRECT;
00139             }
00140         }
00141         if(error >= 0) {
00142             acl->error = stanza_err_NOT_ALLOWED;
00143             for(i=0; _stanza_errors[i].code != NULL; i++) {
00144                 if(_stanza_errors[i].name != NULL && strncmp(_stanza_errors[i].name, NAD_AVAL(nad, error), NAD_AVAL_L(nad, error)) == 0) {
00145                     acl->error = stanza_err_BAD_REQUEST + i;
00146                     break;
00147                 }
00148             }
00149         }
00150         if(log >= 0) {
00151             acl->log = ! strncasecmp(NAD_AVAL(nad, log), "YES", NAD_AVAL_L(nad, log));
00152             acl->log |= ! strncasecmp(NAD_AVAL(nad, log), "ON", NAD_AVAL_L(nad, log));
00153         }
00154 
00155         if(list_tail != NULL) {
00156            list_tail->next = acl;
00157            list_tail = acl;
00158         }
00159 
00160         /* record the head of the list */
00161         if(r->filter == NULL) {
00162            r->filter = acl;
00163            list_tail = acl;
00164         }
00165         
00166         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"));
00167 
00168         nfilters++;
00169 
00170         filter = nad_find_elem(nad, filter, -1, "rule", 0);
00171     }
00172 
00173     nad_free(nad);
00174 
00175     log_write(r->log, LOG_NOTICE, "loaded filters (%d rules)", nfilters);
00176 
00177     r->filter_load = time(NULL);
00178 
00179     return 0;
00180 }
00181 
00182 int filter_packet(router_t r, nad_t nad) {
00183     acl_t acl;
00184     int ato, afrom, error = 0;
00185     unsigned char *cur, *to = NULL, *from = NULL;
00186 
00187     ato = nad_find_attr(nad, 1, -1, "to", NULL);
00188     afrom = nad_find_attr(nad, 1, -1, "from", NULL);
00189     if(ato >= 0 && NAD_AVAL_L(nad,ato) > 0) {
00190         to = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, ato) + 1));
00191         sprintf(to, "%.*s", NAD_AVAL_L(nad, ato), NAD_AVAL(nad, ato));
00192         cur = strstr(to, "@");       /* skip node part */
00193         if(cur != NULL)
00194             cur = strstr(cur, "/");
00195         else
00196             cur = strstr(to, "/");
00197         if(cur != NULL) *cur = '\0'; /* remove the resource part */
00198     }
00199     if(afrom >= 0 && NAD_AVAL_L(nad,afrom) > 0) {
00200         from = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, afrom) + 1));
00201         sprintf(from, "%.*s", NAD_AVAL_L(nad, afrom), NAD_AVAL(nad, afrom));
00202         cur = strstr(from, "@");
00203         if(cur != NULL)
00204             cur = strstr(cur, "/");
00205         else
00206             cur = strstr(from, "/");
00207         if(cur != NULL) *cur = '\0';
00208     }
00209 
00210     for(acl = r->filter; acl != NULL; acl = acl->next) {
00211         if( from == NULL && acl->from != NULL) continue;        /* no match if NULL matched vs not-NULL */
00212         if( to == NULL && acl->to != NULL ) continue;
00213         if( from != NULL && acl->from == NULL) continue;        /* no match if not-NULL matched vs NULL */
00214         if( to != NULL && acl->to == NULL ) continue;
00215         if( from != NULL && acl->from != NULL && fnmatch(acl->from, from, 0) != 0 ) continue;        /* do filename-like match */
00216         if( to != NULL && acl->to != NULL && fnmatch(acl->to, to, 0) != 0 ) continue;
00217         if( acl->what != NULL && nad_find_elem_path(nad, 0, -1, acl->what) < 0 ) continue;        /* match packet type */
00218         log_debug(ZONE, "matched packet %s->%s vs rule (%s %s->%s)", from, to, acl->what, acl->from, acl->to);
00219         if (acl->log) {
00220             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);
00221             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);
00222         }
00223         if (acl->redirect) nad_set_attr(nad, 0, -1, "to", acl->redirect, acl->redirect_len);
00224         error = acl->error;
00225         break;
00226     }
00227 
00228     if(to != NULL) free(to);
00229     if(from != NULL) free(from);
00230     return error;
00231 }
00232