Wed, 10 Feb 2010 21:14:04 +0100
Import unmodified vendor sources for correction and improvement.
1 /*
2 * $Id: uac.c 6481 2009-12-29 13:49:37Z bogdan_iancu $
3 *
4 * Copyright (C) 2005-2009 Voice Sistem SRL
5 *
6 * This file is part of opensips, a free SIP server.
7 *
8 * UAC OpenSIPS-module is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * UAC OpenSIPS-module is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 *
23 * History:
24 * ---------
25 * 2005-01-31 first version (ramona)
26 * 2005-08-12 some TM callbacks replaced with RR callback - more efficient;
27 * (bogdan)
28 * 2006-03-02 UAC authentication looks first in AVPs for credential (bogdan)
29 * 2006-03-03 the RR parameter is encrypted via XOR with a password
30 * (bogdan)
31 * 2009-08-22 TO header replacement added (bogdan)
33 */
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
40 #include "../../sr_module.h"
41 #include "../../dprint.h"
42 #include "../../error.h"
43 #include "../../pvar.h"
44 #include "../../mem/mem.h"
45 #include "../../parser/parse_from.h"
46 #include "../tm/tm_load.h"
47 #include "../tm/t_hooks.h"
48 #include "../rr/api.h"
50 #include "replace.h"
51 #include "auth.h"
57 /* local variable used for init */
58 static char* restore_mode_str = NULL;
59 static char* auth_username_avp = NULL;
60 static char* auth_realm_avp = NULL;
61 static char* auth_password_avp = NULL;
63 /* global param variables */
64 str rr_from_param = str_init("vsf");
65 str rr_to_param = str_init("vst");
66 str uac_passwd = str_init("");
67 int restore_mode = UAC_AUTO_RESTORE;
68 struct tm_binds uac_tmb;
69 struct rr_binds uac_rrb;
70 pv_spec_t auth_username_spec;
71 pv_spec_t auth_realm_spec;
72 pv_spec_t auth_password_spec;
74 static int w_replace_from(struct sip_msg* msg, char* p1, char* p2);
75 static int w_restore_from(struct sip_msg* msg);
77 static int w_replace_to(struct sip_msg* msg, char* p1, char* p2);
78 static int w_restore_to(struct sip_msg* msg);
80 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2);
81 static int fixup_replace_uri(void** param, int param_no);
82 static int fixup_replace_disp_uri(void** param, int param_no);
83 static int mod_init(void);
84 static void mod_destroy(void);
87 /* Exported functions */
88 static cmd_export_t cmds[]={
89 {"uac_replace_from", (cmd_function)w_replace_from, 2,
90 fixup_replace_disp_uri, 0,
91 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
92 {"uac_replace_from", (cmd_function)w_replace_from, 1,
93 fixup_replace_uri, 0,
94 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
95 {"uac_restore_from", (cmd_function)w_restore_from, 0,
96 0, 0,
97 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
98 {"uac_replace_to", (cmd_function)w_replace_to, 2,
99 fixup_replace_disp_uri, 0,
100 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
101 {"uac_replace_to", (cmd_function)w_replace_to, 1,
102 fixup_replace_uri, 0,
103 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
104 {"uac_restore_to", (cmd_function)w_restore_to, 0,
105 0, 0,
106 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
107 {"uac_auth", (cmd_function)w_uac_auth, 0,
108 0, 0,
109 FAILURE_ROUTE },
110 {0,0,0,0,0,0}
111 };
115 /* Exported parameters */
116 static param_export_t params[] = {
117 {"rr_from_store_param", STR_PARAM, &rr_from_param.s },
118 {"rr_to_store_param", STR_PARAM, &rr_to_param.s },
119 {"restore_mode", STR_PARAM, &restore_mode_str },
120 {"restore_passwd", STR_PARAM, &uac_passwd.s },
121 {"credential", STR_PARAM|USE_FUNC_PARAM, (void*)&add_credential },
122 {"auth_username_avp", STR_PARAM, &auth_username_avp },
123 {"auth_realm_avp", STR_PARAM, &auth_realm_avp },
124 {"auth_password_avp", STR_PARAM, &auth_password_avp },
125 {0, 0, 0}
126 };
130 struct module_exports exports= {
131 "uac",
132 MODULE_VERSION,
133 DEFAULT_DLFLAGS, /* dlopen flags */
134 cmds, /* exported functions */
135 params, /* param exports */
136 0, /* exported statistics */
137 0, /* exported MI functions */
138 0, /* exported pseudo-variables */
139 0, /* extra processes */
140 mod_init, /* module initialization function */
141 (response_function) 0,
142 mod_destroy,
143 0 /* per-child init function */
144 };
147 inline static int parse_auth_avp( char *avp_spec, pv_spec_t *avp, char *txt)
148 {
149 str s;
150 s.s = avp_spec; s.len = strlen(s.s);
151 if (pv_parse_spec(&s, avp)==NULL) {
152 LM_ERR("malformed or non AVP %s AVP definition\n",txt);
153 return -1;
154 }
155 return 0;
156 }
159 static int mod_init(void)
160 {
161 LM_INFO("initializing...\n");
163 if (restore_mode_str && *restore_mode_str) {
164 if (strcasecmp(restore_mode_str,"none")==0) {
165 restore_mode = UAC_NO_RESTORE;
166 } else if (strcasecmp(restore_mode_str,"manual")==0) {
167 restore_mode = UAC_MANUAL_RESTORE;
168 } else if (strcasecmp(restore_mode_str,"auto")==0) {
169 restore_mode = UAC_AUTO_RESTORE;
170 } else {
171 LM_ERR("unsupported value '%s' for restore_mode\n",
172 restore_mode_str);
173 goto error;
174 }
175 }
177 rr_from_param.len = strlen(rr_from_param.s);
178 rr_to_param.len = strlen(rr_to_param.s);
179 if ( (rr_from_param.len==0 || rr_to_param.len==0) &&
180 restore_mode!=UAC_NO_RESTORE)
181 {
182 LM_ERR("rr_store_param cannot be empty if FROM is restoreable\n");
183 goto error;
184 }
186 uac_passwd.len = strlen(uac_passwd.s);
188 /* parse the auth AVP spesc, if any */
189 if ( auth_username_avp || auth_password_avp || auth_realm_avp) {
190 if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) {
191 LM_ERR("partial definition of auth AVP!");
192 goto error;
193 }
194 if ( parse_auth_avp(auth_realm_avp, &auth_realm_spec, "realm")<0
195 || parse_auth_avp(auth_username_avp, &auth_username_spec, "username")<0
196 || parse_auth_avp(auth_password_avp, &auth_password_spec, "password")<0
197 ) {
198 goto error;
199 }
200 } else {
201 memset( &auth_realm_spec, 0, sizeof(pv_spec_t));
202 memset( &auth_password_spec, 0, sizeof(pv_spec_t));
203 memset( &auth_username_spec, 0, sizeof(pv_spec_t));
204 }
206 /* load the TM API - FIXME it should be loaded only
207 * if NO_RESTORE and AUTH */
208 if (load_tm_api(&uac_tmb)!=0) {
209 LM_ERR("can't load TM API\n");
210 goto error;
211 }
213 if (restore_mode!=UAC_NO_RESTORE) {
214 /* load the RR API */
215 if (load_rr_api(&uac_rrb)!=0) {
216 LM_ERR("can't load RR API\n");
217 goto error;
218 }
220 if (restore_mode==UAC_AUTO_RESTORE) {
221 /* we need the append_fromtag on in RR */
222 if (!uac_rrb.append_fromtag) {
223 LM_ERR("'append_fromtag' RR param is not enabled!"
224 " - required by AUTO restore mode\n");
225 goto error;
226 }
227 /* get all requests doing loose route */
228 if (uac_rrb.register_rrcb( rr_checker, 0)!=0) {
229 LM_ERR("failed to install RR callback\n");
230 goto error;
231 }
232 }
233 }
235 init_from_replacer();
237 return 0;
238 error:
239 return -1;
240 }
243 static void mod_destroy(void)
244 {
245 destroy_credentials();
246 }
250 /************************** fixup functions ******************************/
252 static int fixup_replace_uri(void** param, int param_no)
253 {
254 pv_elem_t *model;
255 str s;
257 model=NULL;
258 s.s = (char*)(*param); s.len = strlen(s.s);
259 if(pv_parse_format(&s, &model)<0)
260 {
261 LM_ERR("wrong format[%s]!\n",(char*)(*param));
262 return E_UNSPEC;
263 }
264 if (model==NULL)
265 {
266 LM_ERR("empty parameter!\n");
267 return E_UNSPEC;
268 }
269 *param = (void*)model;
271 return 0;
272 }
275 static int fixup_replace_disp_uri(void** param, int param_no)
276 {
277 pv_elem_t *model;
278 char *p;
279 str s;
281 /* convert to str */
282 s.s = (char*)*param;
283 s.len = strlen(s.s);
285 model=NULL;
286 if (param_no==1 && s.len) {
287 /* put " around display name */
288 p = (char*)pkg_malloc(s.len+3);
289 if (p==0) {
290 LM_CRIT("no more pkg mem\n");
291 return E_OUT_OF_MEM;
292 }
293 p[0] = '\"';
294 memcpy(p+1, s.s, s.len);
295 p[s.len+1] = '\"';
296 p[s.len+2] = '\0';
297 pkg_free(s.s);
298 s.s = p;
299 s.len += 2;
300 }
301 if(pv_parse_format(&s ,&model)<0) {
302 LM_ERR("wrong format [%s] for param no %d!\n", s.s, param_no);
303 pkg_free(s.s);
304 return E_UNSPEC;
305 }
306 *param = (void*)model;
308 return 0;
309 }
313 /************************** wrapper functions ******************************/
315 static int w_restore_from(struct sip_msg *msg)
316 {
317 /* safety checks - must be a request */
318 if (msg->first_line.type!=SIP_REQUEST) {
319 LM_ERR("called for something not request\n");
320 return -1;
321 }
323 return (restore_uri(msg,&rr_from_param,1)==0)?1:-1;
324 }
327 static int w_replace_from(struct sip_msg* msg, char* p1, char* p2)
328 {
329 str uri_s;
330 str dsp_s;
331 str *uri;
332 str *dsp;
334 if (p2==NULL) {
335 p2 = p1;
336 p1 = NULL;
337 dsp = NULL;
338 }
340 /* p1 dispaly , p2 uri */
342 if ( p1!=NULL ) {
343 if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0)
344 return -1;
345 dsp = &dsp_s;
346 }
348 /* compute the URI string; if empty string -> make it NULL */
349 if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0)
350 return -1;
351 uri = uri_s.len?&uri_s:NULL;
353 if (parse_from_header(msg)<0 ) {
354 LM_ERR("failed to find/parse FROM hdr\n");
355 return -1;
356 }
358 LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n",
359 dsp,dsp?dsp->len:0,uri,uri?uri->len:0);
361 return (replace_uri(msg, dsp, uri, msg->from, &rr_from_param)==0)?1:-1;
362 }
365 static int w_restore_to(struct sip_msg *msg)
366 {
367 /* safety checks - must be a request */
368 if (msg->first_line.type!=SIP_REQUEST) {
369 LM_ERR("called for something not request\n");
370 return -1;
371 }
373 return (restore_uri(msg,&rr_to_param,0)==0)?1:-1;
374 }
377 static int w_replace_to(struct sip_msg* msg, char* p1, char* p2)
378 {
379 str uri_s;
380 str dsp_s;
381 str *uri;
382 str *dsp;
384 if (p2==NULL) {
385 p2 = p1;
386 p1 = NULL;
387 dsp = NULL;
388 }
390 /* p1 dispaly , p2 uri */
392 if ( p1!=NULL ) {
393 if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0)
394 return -1;
395 dsp = &dsp_s;
396 }
398 /* compute the URI string; if empty string -> make it NULL */
399 if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0)
400 return -1;
401 uri = uri_s.len?&uri_s:NULL;
403 /* parse TO hdr */
404 if ( msg->to==0 && (parse_headers(msg,HDR_TO_F,0)!=0 || msg->to==0) ) {
405 LM_ERR("failed to parse TO hdr\n");
406 return -1;
407 }
409 return (replace_uri(msg, dsp, uri, msg->to, &rr_to_param)==0)?1:-1;
410 }
415 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2)
416 {
417 return (uac_auth(msg)==0)?1:-1;
418 }