Mon, 16 Jan 2012 22:56:52 +0100
Import original vendor code 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)
32 * 2010-01-18 UAC is able to construct credentials from request (msvb)
34 */
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
41 #include "../../sr_module.h"
42 #include "../../dprint.h"
43 #include "../../error.h"
44 #include "../../pvar.h"
45 #include "../../mem/mem.h"
46 #include "../../parser/parse_from.h"
47 #include "../tm/tm_load.h"
48 #include "../tm/t_hooks.h"
49 #include "../rr/api.h"
51 #include "replace.h"
52 #include "auth.h"
58 /* local variable used for init */
59 static char* restore_mode_str = NULL;
60 static char* auth_username_avp = NULL;
61 static char* auth_realm_avp = NULL;
62 static char* auth_password_avp = NULL;
64 /* global param variables */
65 str rr_from_param = str_init("vsf");
66 str rr_to_param = str_init("vst");
67 str uac_passwd = str_init("");
68 int restore_mode = UAC_AUTO_RESTORE;
69 struct tm_binds uac_tmb;
70 struct rr_binds uac_rrb;
71 pv_spec_t auth_username_spec;
72 pv_spec_t auth_realm_spec;
73 pv_spec_t auth_password_spec;
75 static int w_replace_from(struct sip_msg* msg, char* p1, char* p2);
76 static int w_restore_from(struct sip_msg* msg);
78 static int w_replace_to(struct sip_msg* msg, char* p1, char* p2);
79 static int w_restore_to(struct sip_msg* msg);
81 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2);
82 static int fixup_replace_uri(void** param, int param_no);
83 static int fixup_replace_disp_uri(void** param, int param_no);
84 static int mod_init(void);
85 static void mod_destroy(void);
88 /* Exported functions */
89 static cmd_export_t cmds[]={
90 {"uac_replace_from", (cmd_function)w_replace_from, 2,
91 fixup_replace_disp_uri, 0,
92 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
93 {"uac_replace_from", (cmd_function)w_replace_from, 1,
94 fixup_replace_uri, 0,
95 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
96 {"uac_restore_from", (cmd_function)w_restore_from, 0,
97 0, 0,
98 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
99 {"uac_replace_to", (cmd_function)w_replace_to, 2,
100 fixup_replace_disp_uri, 0,
101 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
102 {"uac_replace_to", (cmd_function)w_replace_to, 1,
103 fixup_replace_uri, 0,
104 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
105 {"uac_restore_to", (cmd_function)w_restore_to, 0,
106 0, 0,
107 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
108 {"uac_auth", (cmd_function)w_uac_auth, 0,
109 0, 0,
110 REQUEST_ROUTE|FAILURE_ROUTE },
111 {0,0,0,0,0,0}
112 };
116 /* Exported parameters */
117 static param_export_t params[] = {
118 {"rr_from_store_param", STR_PARAM, &rr_from_param.s },
119 {"rr_to_store_param", STR_PARAM, &rr_to_param.s },
120 {"restore_mode", STR_PARAM, &restore_mode_str },
121 {"restore_passwd", STR_PARAM, &uac_passwd.s },
122 {"credential", STR_PARAM|USE_FUNC_PARAM, (void*)&add_credential },
123 {"auth_username_avp", STR_PARAM, &auth_username_avp },
124 {"auth_realm_avp", STR_PARAM, &auth_realm_avp },
125 {"auth_password_avp", STR_PARAM, &auth_password_avp },
126 {0, 0, 0}
127 };
131 struct module_exports exports= {
132 "uac",
133 MODULE_VERSION,
134 DEFAULT_DLFLAGS, /* dlopen flags */
135 cmds, /* exported functions */
136 params, /* param exports */
137 0, /* exported statistics */
138 0, /* exported MI functions */
139 0, /* exported pseudo-variables */
140 0, /* extra processes */
141 mod_init, /* module initialization function */
142 (response_function) 0,
143 mod_destroy,
144 0 /* per-child init function */
145 };
148 inline static int parse_auth_avp( char *avp_spec, pv_spec_t *avp, char *txt)
149 {
150 str s;
151 s.s = avp_spec; s.len = strlen(s.s);
152 if (pv_parse_spec(&s, avp)==NULL) {
153 LM_ERR("malformed or non AVP %s AVP definition\n",txt);
154 return -1;
155 }
156 return 0;
157 }
160 static int mod_init(void)
161 {
162 LM_INFO("initializing...\n");
164 if (restore_mode_str && *restore_mode_str) {
165 if (strcasecmp(restore_mode_str,"none")==0) {
166 restore_mode = UAC_NO_RESTORE;
167 } else if (strcasecmp(restore_mode_str,"manual")==0) {
168 restore_mode = UAC_MANUAL_RESTORE;
169 } else if (strcasecmp(restore_mode_str,"auto")==0) {
170 restore_mode = UAC_AUTO_RESTORE;
171 } else {
172 LM_ERR("unsupported value '%s' for restore_mode\n",
173 restore_mode_str);
174 goto error;
175 }
176 }
178 rr_from_param.len = strlen(rr_from_param.s);
179 rr_to_param.len = strlen(rr_to_param.s);
180 if ( (rr_from_param.len==0 || rr_to_param.len==0) &&
181 restore_mode!=UAC_NO_RESTORE)
182 {
183 LM_ERR("rr_store_param cannot be empty if FROM is restoreable\n");
184 goto error;
185 }
187 uac_passwd.len = strlen(uac_passwd.s);
189 /* parse the auth AVP spesc, if any */
190 if ( auth_username_avp || auth_password_avp || auth_realm_avp) {
191 if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) {
192 LM_ERR("partial definition of auth AVP!");
193 goto error;
194 }
195 if ( parse_auth_avp(auth_realm_avp, &auth_realm_spec, "realm")<0
196 || parse_auth_avp(auth_username_avp, &auth_username_spec, "username")<0
197 || parse_auth_avp(auth_password_avp, &auth_password_spec, "password")<0
198 ) {
199 goto error;
200 }
201 } else {
202 memset( &auth_realm_spec, 0, sizeof(pv_spec_t));
203 memset( &auth_password_spec, 0, sizeof(pv_spec_t));
204 memset( &auth_username_spec, 0, sizeof(pv_spec_t));
205 }
207 /* load the TM API - FIXME it should be loaded only
208 * if NO_RESTORE and AUTH */
209 if (load_tm_api(&uac_tmb)!=0) {
210 LM_ERR("can't load TM API\n");
211 goto error;
212 }
214 if (restore_mode!=UAC_NO_RESTORE) {
215 /* load the RR API */
216 if (load_rr_api(&uac_rrb)!=0) {
217 LM_ERR("can't load RR API\n");
218 goto error;
219 }
221 if (restore_mode==UAC_AUTO_RESTORE) {
222 /* we need the append_fromtag on in RR */
223 if (!uac_rrb.append_fromtag) {
224 LM_ERR("'append_fromtag' RR param is not enabled!"
225 " - required by AUTO restore mode\n");
226 goto error;
227 }
228 /* get all requests doing loose route */
229 if (uac_rrb.register_rrcb( rr_checker, 0)!=0) {
230 LM_ERR("failed to install RR callback\n");
231 goto error;
232 }
233 }
234 }
236 init_from_replacer();
238 return 0;
239 error:
240 return -1;
241 }
244 static void mod_destroy(void)
245 {
246 destroy_credentials();
247 }
251 /************************** fixup functions ******************************/
253 static int fixup_replace_uri(void** param, int param_no)
254 {
255 pv_elem_t *model;
256 str s;
258 model=NULL;
259 s.s = (char*)(*param); s.len = strlen(s.s);
260 if(pv_parse_format(&s, &model)<0)
261 {
262 LM_ERR("wrong format[%s]!\n",(char*)(*param));
263 return E_UNSPEC;
264 }
265 if (model==NULL)
266 {
267 LM_ERR("empty parameter!\n");
268 return E_UNSPEC;
269 }
270 *param = (void*)model;
272 return 0;
273 }
276 static int fixup_replace_disp_uri(void** param, int param_no)
277 {
278 pv_elem_t *model;
279 char *p;
280 str s;
282 /* convert to str */
283 s.s = (char*)*param;
284 s.len = strlen(s.s);
286 model=NULL;
287 if (param_no==1 && s.len) {
288 /* put " around display name */
289 p = (char*)pkg_malloc(s.len+3);
290 if (p==0) {
291 LM_CRIT("no more pkg mem\n");
292 return E_OUT_OF_MEM;
293 }
294 p[0] = '\"';
295 memcpy(p+1, s.s, s.len);
296 p[s.len+1] = '\"';
297 p[s.len+2] = '\0';
298 pkg_free(s.s);
299 s.s = p;
300 s.len += 2;
301 }
302 if(pv_parse_format(&s ,&model)<0) {
303 LM_ERR("wrong format [%s] for param no %d!\n", s.s, param_no);
304 pkg_free(s.s);
305 return E_UNSPEC;
306 }
307 *param = (void*)model;
309 return 0;
310 }
314 /************************** wrapper functions ******************************/
316 static int w_restore_from(struct sip_msg *msg)
317 {
318 /* safety checks - must be a request */
319 if (msg->first_line.type!=SIP_REQUEST) {
320 LM_ERR("called for something not request\n");
321 return -1;
322 }
324 return (restore_uri(msg,&rr_from_param,1)==0)?1:-1;
325 }
328 static int w_replace_from(struct sip_msg* msg, char* p1, char* p2)
329 {
330 str uri_s;
331 str dsp_s;
332 str *uri;
333 str *dsp;
335 if (p2==NULL) {
336 p2 = p1;
337 p1 = NULL;
338 dsp = NULL;
339 }
341 /* p1 dispaly , p2 uri */
343 if ( p1!=NULL ) {
344 if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0)
345 return -1;
346 dsp = &dsp_s;
347 }
349 /* compute the URI string; if empty string -> make it NULL */
350 if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0)
351 return -1;
352 uri = uri_s.len?&uri_s:NULL;
354 if (parse_from_header(msg)<0 ) {
355 LM_ERR("failed to find/parse FROM hdr\n");
356 return -1;
357 }
359 LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n",
360 dsp,dsp?dsp->len:0,uri,uri?uri->len:0);
362 return (replace_uri(msg, dsp, uri, msg->from, &rr_from_param)==0)?1:-1;
363 }
366 static int w_restore_to(struct sip_msg *msg)
367 {
368 /* safety checks - must be a request */
369 if (msg->first_line.type!=SIP_REQUEST) {
370 LM_ERR("called for something not request\n");
371 return -1;
372 }
374 return (restore_uri(msg,&rr_to_param,0)==0)?1:-1;
375 }
378 static int w_replace_to(struct sip_msg* msg, char* p1, char* p2)
379 {
380 str uri_s;
381 str dsp_s;
382 str *uri;
383 str *dsp;
385 if (p2==NULL) {
386 p2 = p1;
387 p1 = NULL;
388 dsp = NULL;
389 }
391 /* p1 dispaly , p2 uri */
393 if ( p1!=NULL ) {
394 if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0)
395 return -1;
396 dsp = &dsp_s;
397 }
399 /* compute the URI string; if empty string -> make it NULL */
400 if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0)
401 return -1;
402 uri = uri_s.len?&uri_s:NULL;
404 /* parse TO hdr */
405 if ( msg->to==0 && (parse_headers(msg,HDR_TO_F,0)!=0 || msg->to==0) ) {
406 LM_ERR("failed to parse TO hdr\n");
407 return -1;
408 }
410 return (replace_uri(msg, dsp, uri, msg->to, &rr_to_param)==0)?1:-1;
411 }
416 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2)
417 {
418 return (uac_auth(msg)==0)?1:-1;
419 }