1 /*
2  * Copyright (C) 2005 Voice Sistem SRL
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  */
21 
22 #include <sys/types.h> /* for regex */
23 #include <regex.h>
24 
25 #include "../../core/sr_module.h"
26 #include "../../core/str.h"
27 #include "../../core/dprint.h"
28 #include "../../core/mem/mem.h"
29 #include "../../core/utils/sruid.h"
30 #include "../../modules/tm/tm_load.h"
31 #include "../../core/kemi.h"
32 #include "rd_funcs.h"
33 #include "rd_filter.h"
34 
35 MODULE_VERSION
36 
37 /* internal global variables */
38 struct tm_binds rd_tmb;           /*imported functions from tm */
39 cmd_function    rd_acc_fct = 0;   /*imported function from acc */
40 
41 /* global parameter variables */
42 char *acc_db_table = "acc";
43 char *acc_fct_s    = "acc_log_request";
44 
45 /* private parameter variables */
46 char *deny_filter_s = 0;
47 char *accept_filter_s = 0;
48 char *def_filter_s = 0;
49 
50 unsigned int bflags = 0;
51 int flags_hdr_mode = 0;
52 
53 #define ACCEPT_RULE_STR "accept"
54 #define DENY_RULE_STR   "deny"
55 
56 /* sruid to get internal uid */
57 sruid_t _redirect_sruid;
58 
59 
60 static int redirect_init(void);
61 static int child_init(int rank);
62 static int w_set_deny(struct sip_msg* msg, char *dir, char *foo);
63 static int w_set_accept(struct sip_msg* msg, char *dir, char *foo);
64 static int w_get_redirect1(struct sip_msg* msg, char *dir, char *foo);
65 static int w_get_redirect2(struct sip_msg* msg, char *dir, char *foo);
66 static int regexp_compile(char *re_s, regex_t **re);
67 static int get_redirect_fixup(void** param, int param_no);
68 static int setf_fixup(void** param, int param_no);
69 
70 
71 static cmd_export_t cmds[] = {
72 	{"set_deny_filter",   (cmd_function)w_set_deny,      2,  setf_fixup, 0,
73 			FAILURE_ROUTE },
74 	{"set_accept_filter", (cmd_function)w_set_accept,    2,  setf_fixup, 0,
75 			FAILURE_ROUTE },
76 	{"get_redirects",     (cmd_function)w_get_redirect2,  2,  get_redirect_fixup, 0,
77 			FAILURE_ROUTE },
78 	{"get_redirects",     (cmd_function)w_get_redirect1,  1,  get_redirect_fixup, 0,
79 			FAILURE_ROUTE },
80 	{0, 0, 0, 0, 0, 0}
81 };
82 
83 static param_export_t params[] = {
84 	{"deny_filter",     PARAM_STRING,  &deny_filter_s    },
85 	{"accept_filter",   PARAM_STRING,  &accept_filter_s  },
86 	{"default_filter",  PARAM_STRING,  &def_filter_s     },
87 	{"acc_function",    PARAM_STRING,  &acc_fct_s        },
88 	{"acc_db_table",    PARAM_STRING,  &acc_db_table     },
89 	{"bflags",    		INT_PARAM,  &bflags			  },
90 	{"flags_hdr_mode",	INT_PARAM,  &flags_hdr_mode	  },
91 	{0, 0, 0}
92 };
93 
94 
95 struct module_exports exports = {
96 	"uac_redirect",  /* module name */
97 	DEFAULT_DLFLAGS, /* dlopen flags */
98 	cmds,            /* exported functions */
99 	params,          /* exported parameters */
100 	0,               /* exported RPC functions */
101 	0,               /* exported pseudo-variables */
102 	0,               /* response handling function */
103 	redirect_init,   /* module initialization function */
104 	child_init,      /* per-child init function */
105 	0                /* module destroy function */
106 };
107 
108 
109 
get_nr_max(char * s,unsigned char * max)110 int get_nr_max(char *s, unsigned char *max)
111 {
112 	unsigned short nr;
113 	int err;
114 
115 	if ( s[0]=='*' && s[1]==0 ) {
116 		/* is '*' -> infinit ;-) */
117 		*max = 0;
118 		return 0;
119 	} else {
120 		/* must be a positive number less than 255 */
121 		nr = str2s(s, strlen(s), &err);
122 		if (err==0){
123 			if (nr>255){
124 				LM_ERR("number too big <%d> (max=255)\n",nr);
125 				return -1;
126 			}
127 			*max = (unsigned char)nr;
128 			return 0;
129 		}else{
130 			LM_ERR("bad  number <%s>\n",s);
131 			return -1;
132 		}
133 	}
134 }
135 
136 
get_redirect_fixup(void ** param,int param_no)137 static int get_redirect_fixup(void** param, int param_no)
138 {
139 	unsigned char maxb,maxt;
140 	struct acc_param *accp;
141 	cmd_function fct;
142 	char *p;
143 	char *s;
144 
145 	s = (char*)*param;
146 	if (param_no==1) {
147 		if ( (p=strchr(s,':'))!=0 ) {
148 			/* have max branch also */
149 			*p = 0;
150 			if (get_nr_max(p+1, &maxb)!=0)
151 				return E_UNSPEC;
152 		} else {
153 			maxb = 0; /* infinit */
154 		}
155 
156 		/* get max total */
157 		if (get_nr_max(s, &maxt)!=0)
158 			return E_UNSPEC;
159 
160 		pkg_free(*param);
161 		*param=(void*)(long)( (((unsigned short)maxt)<<8) | maxb);
162 	} else if (param_no==2) {
163 		/* acc function loaded? */
164 		if (rd_acc_fct==0) {
165 			/* must import the acc stuff */
166 			if (acc_fct_s==0 || acc_fct_s[0]==0) {
167 				LM_ERR("acc support enabled, but no acc function defined\n");
168 				return E_UNSPEC;
169 			}
170 			fct = find_export(acc_fct_s, 2, REQUEST_ROUTE);
171 			if ( fct==0 )
172 				fct = find_export(acc_fct_s, 1, REQUEST_ROUTE);
173 			if ( fct==0 ) {
174 				LM_ERR("cannot import %s function; is acc loaded and proper "
175 					"compiled?\n", acc_fct_s);
176 				return E_UNSPEC;
177 			}
178 			rd_acc_fct = fct;
179 		}
180 		/* set the reason str */
181 		accp = (struct acc_param*)pkg_malloc(sizeof(struct acc_param));
182 		if (accp==0) {
183 			PKG_MEM_ERROR;
184 			return E_UNSPEC;
185 		}
186 		memset( accp, 0, sizeof(struct acc_param));
187 		if (s!=0 && *s!=0) {
188 			accp->reason.s = s;
189 			accp->reason.len = strlen(s);
190 		} else {
191 			accp->reason.s = "n/a";
192 			accp->reason.len = 3;
193 		}
194 		*param=(void*)accp;
195 	}
196 
197 	return 0;
198 }
199 
200 
setf_fixup(void ** param,int param_no)201 static int setf_fixup(void** param, int param_no)
202 {
203 	unsigned short nr;
204 	regex_t *filter;
205 	char *s;
206 
207 	s = (char*)*param;
208 	if (param_no==1) {
209 		/* compile the filter */
210 		if (regexp_compile( s, &filter)<0) {
211 			LM_ERR("cannot init filter <%s>\n", s);
212 			return E_BAD_RE;
213 		}
214 		pkg_free(*param);
215 		*param = (void*)filter;
216 	} else if (param_no==2) {
217 		if (s==0 || s[0]==0) {
218 			nr = 0;
219 		} else if (strcasecmp(s,"reset_all")==0) {
220 			nr = RESET_ADDED|RESET_DEFAULT;
221 		} else if (strcasecmp(s,"reset_default")==0) {
222 			nr = RESET_DEFAULT;
223 		} else if (strcasecmp(s,"reset_added")==0) {
224 			nr = RESET_ADDED;
225 		} else {
226 			LM_ERR("unknown reset type <%s>\n",s);
227 			return E_UNSPEC;
228 		}
229 		pkg_free(*param);
230 		*param = (void*)(long)nr;
231 	}
232 
233 	return 0;
234 }
235 
236 
237 
regexp_compile(char * re_s,regex_t ** re)238 static int regexp_compile(char *re_s, regex_t **re)
239 {
240 	*re = 0;
241 	if (re_s==0 || strlen(re_s)==0 ) {
242 		return 0;
243 	} else {
244 		if ((*re=pkg_malloc(sizeof(regex_t)))==0) {
245 			PKG_MEM_ERROR;
246 			return E_OUT_OF_MEM;
247 		}
248 		if (regcomp(*re, re_s, REG_EXTENDED|REG_ICASE|REG_NEWLINE) ){
249 			pkg_free(*re);
250 			*re = 0;
251 			LM_ERR("regexp_compile:bad regexp <%s>\n", re_s);
252 			return E_BAD_RE;
253 		}
254 	}
255 	return 0;
256 }
257 
258 
259 
redirect_init(void)260 static int redirect_init(void)
261 {
262 	regex_t *filter;
263 	void *p;
264 	cmd_function fct;
265 
266 	/* load the TM API */
267 	if (load_tm_api(&rd_tmb)!=0) {
268 		LM_ERR("failed to load TM API\n");
269 		goto error;
270 	}
271 
272 	p = (void*)acc_db_table;
273 	/* fixup table name */
274 	if(fixup_var_pve_str_12(&p, 1)<0) {
275 		LM_ERR("failed to fixup acc db table\n");
276 		goto error;
277 	}
278 	acc_db_table = p;
279 
280 	/* init filter */
281 	init_filters();
282 
283 	/* what's the default rule? */
284 	if (def_filter_s) {
285 		if ( !strcasecmp(def_filter_s,ACCEPT_RULE_STR) ) {
286 			set_default_rule( ACCEPT_RULE );
287 		} else if ( !strcasecmp(def_filter_s,DENY_RULE_STR) ) {
288 			set_default_rule( DENY_RULE );
289 		} else {
290 			LM_ERR("unknown default filter <%s>\n",def_filter_s);
291 		}
292 	}
293 
294 	/* if accept filter specify, compile it */
295 	if (regexp_compile(accept_filter_s, &filter)<0) {
296 		LM_ERR("failed to init accept filter\n");
297 		goto error;
298 	}
299 	add_default_filter( ACCEPT_FILTER, filter);
300 
301 	/* if deny filter specify, compile it */
302 	if (regexp_compile(deny_filter_s, &filter)<0) {
303 		LM_ERR("failed to init deny filter\n");
304 		goto error;
305 	}
306 	add_default_filter( DENY_FILTER, filter);
307 
308 	if(sruid_init(&_redirect_sruid, '-', "rdir", SRUID_INC)<0)
309 		return -1;
310 
311 	if(rd_acc_fct == 0) {
312 		/* import the acc stuff */
313 		if(acc_fct_s != 0 && acc_fct_s[0] == '\0') {
314 			fct = find_export(acc_fct_s, 2, REQUEST_ROUTE);
315 			if(fct == 0)
316 				fct = find_export(acc_fct_s, 1, REQUEST_ROUTE);
317 			if(fct == 0) {
318 				LM_ERR("cannot import %s function; is acc loaded and"
319 						" configured\n", acc_fct_s);
320 				return E_UNSPEC;
321 			}
322 			rd_acc_fct = fct;
323 		}
324 	}
325 
326 	return 0;
327 error:
328 	return -1;
329 }
330 
child_init(int rank)331 static int child_init(int rank)
332 {
333 	if(sruid_init(&_redirect_sruid, '-', "rdir", SRUID_INC)<0)
334 		return -1;
335 	return 0;
336 }
337 
msg_tracer(struct sip_msg * msg,int reset)338 static inline void msg_tracer(struct sip_msg* msg, int reset)
339 {
340 	static unsigned int id  = 0;
341 	static unsigned int set = 0;
342 
343 	if (reset) {
344 		set = 0;
345 	} else {
346 		if (set) {
347 			if (id!=msg->id) {
348 				LM_WARN("filters set but not used -> resetting to default\n");
349 				reset_filters();
350 				id = msg->id;
351 			}
352 		} else {
353 			id = msg->id;
354 			set = 1;
355 		}
356 	}
357 }
358 
359 
w_set_deny(struct sip_msg * msg,char * re,char * flags)360 static int w_set_deny(struct sip_msg* msg, char *re, char *flags)
361 {
362 	msg_tracer( msg, 0);
363 	return (add_filter( DENY_FILTER, (regex_t*)re, (int)(long)flags)==0)?1:-1;
364 }
365 
366 
w_set_accept(struct sip_msg * msg,char * re,char * flags)367 static int w_set_accept(struct sip_msg* msg, char *re, char *flags)
368 {
369 	msg_tracer( msg, 0);
370 	return (add_filter( ACCEPT_FILTER, (regex_t*)re, (int)(long)flags)==0)?1:-1;
371 }
372 
373 
w_get_redirect2(struct sip_msg * msg,char * max_c,char * reason)374 static int w_get_redirect2(struct sip_msg* msg, char *max_c, char *reason)
375 {
376 	int n;
377 	unsigned short max;
378 
379 	msg_tracer( msg, 0);
380 	/* get the contacts */
381 	max = (unsigned short)(long)max_c;
382 	n = get_redirect(msg , (max>>8)&0xff, max&0xff, (struct acc_param*)reason, bflags);
383 	reset_filters();
384 	/* reset the tracer */
385 	msg_tracer( msg, 1);
386 
387 	return n;
388 }
389 
390 
w_get_redirect1(struct sip_msg * msg,char * max_c,char * foo)391 static int w_get_redirect1(struct sip_msg* msg, char *max_c, char *foo)
392 {
393 	return w_get_redirect2(msg, max_c, 0);
394 }
395 
ki_get_redirects_acc(sip_msg_t * msg,int max_c,int max_b,str * reason)396 static int ki_get_redirects_acc(sip_msg_t* msg, int max_c, int max_b,
397 		str *reason)
398 {
399 	int n;
400 	acc_param_t accp;
401 
402 	if(reason && reason->len>0) {
403 		memset(&accp, 0, sizeof(acc_param_t));
404 		accp.reason.s = reason->s;
405 		accp.reason.len = reason->len;
406 	}
407 	msg_tracer(msg, 0);
408 	/* get the contacts */
409 	n = get_redirect(msg, max_c, max_b, (reason && reason->len>0)?&accp:NULL,
410 			bflags);
411 	reset_filters();
412 	/* reset the tracer */
413 	msg_tracer(msg, 1);
414 
415 	return n;
416 }
417 
ki_get_redirects(sip_msg_t * msg,int max_c,int max_b)418 static int ki_get_redirects(sip_msg_t* msg, int max_c, int max_b)
419 {
420 	int n;
421 
422 	msg_tracer(msg, 0);
423 	/* get the contacts */
424 	n = get_redirect(msg, max_c, max_b, NULL, bflags);
425 	reset_filters();
426 	/* reset the tracer */
427 	msg_tracer(msg, 1);
428 
429 	return n;
430 }
431 
ki_get_redirects_all(sip_msg_t * msg)432 static int ki_get_redirects_all(sip_msg_t* msg)
433 {
434 	int n;
435 
436 	msg_tracer(msg, 0);
437 	/* get the contacts */
438 	n = get_redirect(msg, 0, 0, NULL, bflags);
439 	reset_filters();
440 	/* reset the tracer */
441 	msg_tracer(msg, 1);
442 
443 	return n;
444 }
445 
446 /**
447  *
448  */
449 /* clang-format off */
450 static sr_kemi_t sr_kemi_uac_redirect_exports[] = {
451 	{ str_init("uac_redirect"), str_init("get_redirects_all"),
452 		SR_KEMIP_INT, ki_get_redirects_all,
453 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
454 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
455 	},
456 	{ str_init("uac_redirect"), str_init("get_redirects"),
457 		SR_KEMIP_INT, ki_get_redirects,
458 		{ SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_NONE,
459 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
460 	},
461 	{ str_init("uac_redirect"), str_init("get_redirects_acc"),
462 		SR_KEMIP_INT, ki_get_redirects_acc,
463 		{ SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_STR,
464 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
465 	},
466 
467 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
468 };
469 /* clang-format on */
470 
mod_register(char * path,int * dlflags,void * p1,void * p2)471 int mod_register(char *path, int *dlflags, void *p1, void *p2)
472 {
473 	sr_kemi_modules_add(sr_kemi_uac_redirect_exports);
474 	return 0;
475 }
476