jabberd2
2.2.16
|
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