00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "config.h"
00019 #include "defines.h"
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <time.h>
00024
00025 #include <string.h>
00026 #include <ctype.h>
00027 #include <pcre.h>
00028 #include <sys/types.h>
00029
00030 #include "readline.h"
00031 #include "hashlib.h"
00032 #include "utils.h"
00033 #include "configparser.h"
00034 #include "cfcgi.h"
00035 #include "template.h"
00036 #include "clientlib.h"
00037
00038
00039 #define DEFAULT_URLREWRITE_SIZE 5
00040
00041 #define MACRO_NODE_OPERATOR 0
00042 #define MACRO_NODE_VALUE 1
00043
00044 #define MACRO_OP_NOT 0
00045 #define MACRO_OP_AND 1
00046 #define MACRO_OP_OR 2
00047
00048 typedef struct s_macro_node {
00049 int type;
00050 union {
00051 void *ptr_data;
00052 int int_data;
00053 } data;
00054
00055 struct s_macro_node *left,
00056 *right,
00057 *parent;
00058
00059 } t_macro_node;
00060
00061 typedef struct s_urlrewrite {
00062 pcre *regexp;
00063 pcre_extra *regexp_extra;
00064 t_macro_node *macro_tree;
00065 const u_char *replacement;
00066 unsigned long int match_count;
00067 int *match_arr;
00068 } t_urlrewrite;
00069
00070 t_urlrewrite **UrlRewrites = NULL;
00071 int UrlRewriteCount = 0;
00072 int UrlRewriteSize = 0;
00073
00074 int is_macro_true(t_macro_node *tree) {
00075 t_string *data;
00076 int op_type;
00077
00078 if(!tree)
00079 return 0;
00080
00081 switch(tree->type) {
00082 case MACRO_NODE_VALUE:
00083 data = (t_string *)tree->data.ptr_data;
00084 if(!data->len)
00085 return 0;
00086 if(!cf_strcmp(data->content, "true")) {
00087 return 1;
00088 } else if(!cf_strcmp(data->content, "logged_in")) {
00089 return cf_hash_get(GlobalValues,"UserName",8) ? 1 : 0;
00090 }
00091 return 0;
00092 break;
00093 case MACRO_NODE_OPERATOR: {
00094 op_type = tree->data.int_data;
00095 switch(op_type) {
00096 case MACRO_OP_NOT:
00097 return !is_macro_true(tree->right);
00098 case MACRO_OP_AND:
00099 return is_macro_true(tree->left) && is_macro_true(tree->right);
00100 case MACRO_OP_OR:
00101 return is_macro_true(tree->left) || is_macro_true(tree->right);
00102 default:
00103 return 0;
00104 }
00105 break;
00106 default:
00107 return 0;
00108 }
00109 }
00110 }
00111
00112 void free_macro_tree(t_macro_node *tree) {
00113 if(!tree)
00114 return;
00115 if(tree->left)
00116 free_macro_tree(tree->left);
00117 if(tree->right)
00118 free_macro_tree(tree->right);
00119 switch(tree->type) {
00120 case MACRO_NODE_VALUE:
00121 str_cleanup((t_string *)tree->data.ptr_data);
00122 free(tree->data.ptr_data);
00123 break;
00124 default:
00125 break;
00126 }
00127 free(tree);
00128 }
00129
00130 t_macro_node *parse_macro(const u_char *str) {
00131 t_macro_node *cur_node;
00132 t_string left_side;
00133 int n_braces;
00134 int had_zero_brace;
00135 u_char op;
00136 u_char *buf;
00137 u_char *nstr;
00138 u_char *ptr;
00139
00140 n_braces = 0;
00141 had_zero_brace = 0;
00142
00143
00144 for(ptr = (u_char *)str; *ptr; ptr++) {
00145 if(*ptr == ')') {
00146 if(n_braces == 1 && *(ptr+1))
00147 had_zero_brace = 1;
00148 n_braces--;
00149 if(n_braces < 0) {
00150 return NULL;
00151 }
00152 } else if(*ptr == '(') {
00153 n_braces++;
00154 }
00155 }
00156
00157 if(n_braces != 0) {
00158 return NULL;
00159 }
00160
00161
00162 nstr = strdup(str);
00163
00164
00165 if(!had_zero_brace && nstr[0] == '(' && nstr[strlen(nstr)-1] == ')') {
00166 nstr[strlen(nstr)-1] = 0;
00167 }
00168
00169 cur_node = (t_macro_node *)fo_alloc(NULL,1,sizeof(t_macro_node),FO_ALLOC_MALLOC);
00170 if(!cur_node) {
00171 free(nstr);
00172 return NULL;
00173 }
00174
00175 str_init(&left_side);
00176
00177 n_braces = 0;
00178
00179 if(!had_zero_brace && nstr[0] == '(' && nstr[strlen(nstr)-1] == ')') {
00180 ptr = nstr + 1;
00181 } else {
00182 ptr = nstr;
00183 }
00184
00185 for(; *ptr; ptr++) {
00186 if(n_braces > 0) {
00187 if(*ptr == ')') {
00188 str_char_append(&left_side, *ptr);
00189 n_braces--;
00190 continue;
00191 } else if(!isspace(*ptr)) {
00192 str_char_append(&left_side, *ptr);
00193 }
00194 continue;
00195 }
00196 if(*ptr == '!') {
00197 if(left_side.len) {
00198 free(nstr);
00199 free(cur_node);
00200 str_cleanup(&left_side);
00201 return NULL;
00202 }
00203 break;
00204 } else if(*ptr == '(') {
00205 str_char_append(&left_side, *ptr);
00206 n_braces++;
00207 continue;
00208 } else if(*ptr == '&' || *ptr == '|') {
00209 break;
00210 } else if(!isalpha(*ptr) && !isspace(*ptr) && *ptr != '_') {
00211 free(nstr);
00212 free(cur_node);
00213 str_cleanup(&left_side);
00214 return NULL;
00215 } else if(isspace(*ptr)) {
00216 continue;
00217 }
00218 str_char_append(&left_side, *ptr);
00219 }
00220
00221 cur_node->parent = NULL;
00222
00223
00224 if(!*ptr) {
00225
00226 if(!left_side.len) {
00227 free(nstr);
00228 free(cur_node);
00229 str_cleanup(&left_side);
00230 return NULL;
00231 }
00232
00233
00234 if(left_side.content[0] == '(' && left_side.content[left_side.len-1] == ')') {
00235 if(left_side.len == 2) {
00236 free(nstr);
00237 free(cur_node);
00238 str_cleanup(&left_side);
00239 return NULL;
00240 }
00241 buf = strdup(left_side.content);
00242 str_char_set(&left_side, buf + 1, left_side.len - 2);
00243 free(buf);
00244 }
00245
00246 cur_node->type = MACRO_NODE_VALUE;
00247 cur_node->left = NULL;
00248 cur_node->right = NULL;
00249 cur_node->data.ptr_data = fo_alloc(NULL,1,sizeof(t_string),FO_ALLOC_MALLOC);
00250 str_init((t_string *)cur_node->data.ptr_data);
00251 str_str_set((t_string *)cur_node->data.ptr_data, &left_side);
00252 str_cleanup(&left_side);
00253 free(nstr);
00254
00255 return cur_node;
00256 }
00257
00258 op = *ptr++;
00259
00260 cur_node->type = MACRO_NODE_OPERATOR;
00261
00262 switch(op) {
00263 case '!':
00264 str_cleanup(&left_side);
00265 cur_node->data.int_data = MACRO_OP_NOT;
00266 cur_node->left = NULL;
00267 cur_node->right = parse_macro((const u_char *)ptr);
00268 if(!cur_node->right) {
00269 free(nstr);
00270 free(cur_node);
00271 return NULL;
00272 }
00273 cur_node->right->parent = cur_node;
00274 break;
00275 case '&':
00276 cur_node->data.int_data = MACRO_OP_AND;
00277 cur_node->left = parse_macro((const u_char *)left_side.content);
00278 str_cleanup(&left_side);
00279 if(!cur_node->left) {
00280 free(nstr);
00281 free(cur_node);
00282 return NULL;
00283 }
00284 cur_node->left->parent = cur_node;
00285 cur_node->right = parse_macro((const u_char *)ptr);
00286 if(!cur_node->right) {
00287 free(cur_node->left);
00288 free(nstr);
00289 free(cur_node);
00290 return NULL;
00291 }
00292 cur_node->right->parent = cur_node;
00293 break;
00294 case '|':
00295 cur_node->data.int_data = MACRO_OP_OR;
00296 cur_node->left = parse_macro((const u_char *)left_side.content);
00297 str_cleanup(&left_side);
00298 if(!cur_node->left) {
00299 free(nstr);
00300 free(cur_node);
00301 return NULL;
00302 }
00303 cur_node->left->parent = cur_node;
00304 cur_node->right = parse_macro((const u_char *)ptr);
00305 if(!cur_node->right) {
00306 free(cur_node->left);
00307 free(nstr);
00308 free(cur_node);
00309 return NULL;
00310 }
00311 cur_node->right->parent = cur_node;
00312 break;
00313 default:
00314 str_cleanup(&left_side);
00315 break;
00316 }
00317
00318 free(nstr);
00319 return cur_node;
00320 }
00321
00322 int treat_link(t_string *dest, u_char *src) {
00323 int i, j;
00324 int res;
00325 int nbr;
00326 u_char buf[3];
00327 u_char *ptr;
00328
00329 for(i = 0; i < UrlRewriteCount; i++) {
00330 if(!is_macro_true(UrlRewrites[i]->macro_tree)) {
00331 continue;
00332 }
00333 res = pcre_exec(UrlRewrites[i]->regexp, UrlRewrites[i]->regexp_extra, src, strlen(src), 0, 0, UrlRewrites[i]->match_arr,(UrlRewrites[i]->match_count + 1) * 3);
00334 if(res >= 0) {
00335 break;
00336 }
00337 }
00338
00339 if(i == UrlRewriteCount) {
00340 str_char_set(dest, src, strlen(src));
00341 return 0;
00342 }
00343
00344 for(j = 0; j < strlen(UrlRewrites[i]->replacement); j++) {
00345 if(UrlRewrites[i]->replacement[j] == '$') {
00346 if(isdigit(UrlRewrites[i]->replacement[j+1])) {
00347 if(isdigit(UrlRewrites[i]->replacement[j+2])) {
00348 strncpy(buf, &UrlRewrites[i]->replacement[j+1], 2);
00349 buf[2] = 0;
00350 } else {
00351 strncpy(buf, &UrlRewrites[i]->replacement[j+1], 1);
00352 buf[1] = 0;
00353 }
00354 nbr = atoi(buf);
00355 res = pcre_get_substring(src, UrlRewrites[i]->match_arr,(UrlRewrites[i]->match_count + 1) * 3, nbr,(const char **)&ptr);
00356
00357 if(res < 0) {
00358 str_char_append(dest, UrlRewrites[i]->replacement[j]);
00359 continue;
00360 }
00361 str_chars_append(dest, ptr, res);
00362 pcre_free_substring(ptr);
00363 if(isdigit(UrlRewrites[i]->replacement[j+2])) {
00364 j += 2;
00365 } else {
00366 j++;
00367 }
00368 continue;
00369 }
00370 }
00371 str_char_append(dest, UrlRewrites[i]->replacement[j]);
00372 }
00373
00374 return 0;
00375 }
00376
00377 int execute_filter(t_cf_hash *head,t_configuration *dc,t_configuration *vc,t_cl_thread *thread,t_cf_template *tpl) {
00378 const t_cf_tpl_variable *msg_content;
00379 t_string content, link;
00380 u_char *ptr, *ptr_end_attr, *ptr_end_tag, *ptr_end_elem, *ptr_link;
00381 int res;
00382
00383 str_init(&content);
00384
00385
00386 msg_content = tpl_cf_getvar(tpl, "message");
00387
00388 if(!msg_content)
00389 return FLT_OK;
00390
00391 ptr = msg_content->data->content;
00392
00393 for(; *ptr; ptr++) {
00394 if(!cf_strncmp(ptr, "<a href=\"", 9)) {
00395 str_init(&link);
00396
00397 ptr += 9;
00398 ptr_end_attr = strchr(ptr, '"');
00399 ptr_end_tag = strchr(ptr_end_attr, '>');
00400 ptr_end_elem = strchr(ptr_end_tag, '<');
00401
00402
00403 if(!ptr_end_attr || !ptr_end_tag || !ptr_end_elem) {
00404
00405 str_cleanup(&link);
00406 str_chars_append(&content, "<a href=\"", 9);
00407 continue;
00408 }
00409
00410 ptr_link = strndup(ptr,(int)(ptr_end_attr - ptr));
00411 if(!ptr_link) {
00412 str_cleanup(&link);
00413 str_chars_append(&content, "<a href=\"", 9);
00414 continue;
00415 }
00416
00417 res = treat_link(&link, ptr_link);
00418 free(ptr_link);
00419
00420 if(res < 0) {
00421 str_cleanup(&link);
00422 str_chars_append(&content, "<a href=\"", 9);
00423 continue;
00424 }
00425
00426 str_chars_append(&content, "<a href=\"", 9);
00427 str_str_append(&content, &link);
00428 str_chars_append(&content, ptr_end_attr,(int)(ptr_end_tag - ptr_end_attr + 1));
00429 str_str_append(&content, &link);
00430
00431 ptr = ptr_end_elem - 1;
00432
00433 str_cleanup(&link);
00434 } else {
00435 str_char_append(&content, *ptr);
00436 }
00437 }
00438
00439 tpl_cf_setvar(tpl,"message", content.content, content.len, 0);
00440 str_cleanup(&content);
00441
00442 return FLT_OK;
00443 }
00444
00445
00446 int add_rewriterule(t_configfile *cfile,t_conf_opt *opt,u_char **args,int argnum) {
00447 t_urlrewrite **n_rewrites;
00448 t_urlrewrite *n_rewrite;
00449 int alloc_type;
00450 const u_char *error;
00451 int err_offset;
00452
00453 if(UrlRewriteCount + 1 > UrlRewriteSize) {
00454 if(!UrlRewriteSize) {
00455 alloc_type = FO_ALLOC_MALLOC;
00456 } else {
00457 alloc_type = FO_ALLOC_REALLOC;
00458 }
00459 UrlRewriteSize += DEFAULT_URLREWRITE_SIZE;
00460 n_rewrites = fo_alloc(UrlRewrites, sizeof(t_urlrewrite *), UrlRewriteSize, alloc_type);
00461 if(!n_rewrites) {
00462 return 1;
00463 }
00464 UrlRewrites = n_rewrites;
00465 }
00466 n_rewrite = fo_alloc(NULL, sizeof(t_urlrewrite), 1, FO_ALLOC_MALLOC);
00467 if(!n_rewrite)
00468 return 1;
00469
00470 n_rewrite->macro_tree = parse_macro(args[2]);
00471 if(!n_rewrite->macro_tree) {
00472 free(n_rewrite);
00473 return 1;
00474 }
00475
00476 n_rewrite->replacement = strdup(args[1]);
00477 if(!n_rewrite->replacement) {
00478 free_macro_tree(n_rewrite->macro_tree);
00479 free(n_rewrite);
00480 }
00481
00482 n_rewrite->regexp = pcre_compile(args[0], 0, (const char **)&error, &err_offset, NULL);
00483 if(!n_rewrite->regexp) {
00484 fprintf(stderr,"flt_urlrewrite: Regexp error with \"%s\": %s\n", args[0], error);
00485 free_macro_tree(n_rewrite->macro_tree);
00486 free((void *)n_rewrite->replacement);
00487 free(n_rewrite);
00488 return 1;
00489 }
00490 n_rewrite->regexp_extra = pcre_study(n_rewrite->regexp, 0, (const char **)&error);
00491 if(error) {
00492 printf("Regexp study error with \"%s\": %s\n", args[0], error);
00493 pcre_free(n_rewrite->regexp);
00494 free_macro_tree(n_rewrite->macro_tree);
00495 free((void *)n_rewrite->replacement);
00496 free(n_rewrite);
00497 return 1;
00498 }
00499 n_rewrite->match_count = 0;
00500 pcre_fullinfo(n_rewrite->regexp, n_rewrite->regexp_extra, PCRE_INFO_CAPTURECOUNT, &(n_rewrite->match_count));
00501 n_rewrite->match_arr = (int *)fo_alloc(NULL, sizeof(int),(n_rewrite->match_count + 1) * 3, FO_ALLOC_MALLOC);
00502 if(!n_rewrite->match_arr) {
00503 pcre_free(n_rewrite->regexp_extra);
00504 pcre_free(n_rewrite->regexp);
00505 free_macro_tree(n_rewrite->macro_tree);
00506 free((void *)n_rewrite->replacement);
00507 free(n_rewrite);
00508 }
00509
00510 UrlRewrites[UrlRewriteCount++] = n_rewrite;
00511
00512 return 0;
00513 }
00514
00515 void flt_urlrewrite_cleanup(void) {
00516
00517 int i;
00518
00519 for(i = 0; i < UrlRewriteCount; i++) {
00520 pcre_free(UrlRewrites[i]->regexp_extra);
00521 pcre_free(UrlRewrites[i]->regexp);
00522 free_macro_tree(UrlRewrites[i]->macro_tree);
00523 free((void *)UrlRewrites[i]->replacement);
00524 free(UrlRewrites[i]->match_arr);
00525 free(UrlRewrites[i]);
00526 }
00527
00528 if(UrlRewrites)
00529 free(UrlRewrites);
00530 }
00531
00532 t_conf_opt flt_urlrewrite_config[] = {
00533 { "URLRewrite", add_rewriterule, NULL },
00534 { NULL, NULL, NULL }
00535 };
00536
00537 t_handler_config flt_urlrewrite_handlers[] = {
00538 { POSTING_HANDLER, execute_filter },
00539 { 0, NULL }
00540 };
00541
00542 t_module_config flt_urlrewrite = {
00543 flt_urlrewrite_config,
00544 flt_urlrewrite_handlers,
00545 NULL,
00546 NULL,
00547 NULL,
00548 flt_urlrewrite_cleanup
00549 };
00550
00551