|
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 |
|
33 */ |
|
34 |
|
35 |
|
36 #include <stdio.h> |
|
37 #include <string.h> |
|
38 #include <stdlib.h> |
|
39 |
|
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" |
|
49 |
|
50 #include "replace.h" |
|
51 #include "auth.h" |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
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; |
|
62 |
|
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; |
|
73 |
|
74 static int w_replace_from(struct sip_msg* msg, char* p1, char* p2); |
|
75 static int w_restore_from(struct sip_msg* msg); |
|
76 |
|
77 static int w_replace_to(struct sip_msg* msg, char* p1, char* p2); |
|
78 static int w_restore_to(struct sip_msg* msg); |
|
79 |
|
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); |
|
85 |
|
86 |
|
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 }; |
|
112 |
|
113 |
|
114 |
|
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 }; |
|
127 |
|
128 |
|
129 |
|
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 }; |
|
145 |
|
146 |
|
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 } |
|
157 |
|
158 |
|
159 static int mod_init(void) |
|
160 { |
|
161 LM_INFO("initializing...\n"); |
|
162 |
|
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 } |
|
176 |
|
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 } |
|
185 |
|
186 uac_passwd.len = strlen(uac_passwd.s); |
|
187 |
|
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 } |
|
205 |
|
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 } |
|
212 |
|
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 } |
|
219 |
|
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 } |
|
234 |
|
235 init_from_replacer(); |
|
236 |
|
237 return 0; |
|
238 error: |
|
239 return -1; |
|
240 } |
|
241 |
|
242 |
|
243 static void mod_destroy(void) |
|
244 { |
|
245 destroy_credentials(); |
|
246 } |
|
247 |
|
248 |
|
249 |
|
250 /************************** fixup functions ******************************/ |
|
251 |
|
252 static int fixup_replace_uri(void** param, int param_no) |
|
253 { |
|
254 pv_elem_t *model; |
|
255 str s; |
|
256 |
|
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; |
|
270 |
|
271 return 0; |
|
272 } |
|
273 |
|
274 |
|
275 static int fixup_replace_disp_uri(void** param, int param_no) |
|
276 { |
|
277 pv_elem_t *model; |
|
278 char *p; |
|
279 str s; |
|
280 |
|
281 /* convert to str */ |
|
282 s.s = (char*)*param; |
|
283 s.len = strlen(s.s); |
|
284 |
|
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; |
|
307 |
|
308 return 0; |
|
309 } |
|
310 |
|
311 |
|
312 |
|
313 /************************** wrapper functions ******************************/ |
|
314 |
|
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 } |
|
322 |
|
323 return (restore_uri(msg,&rr_from_param,1)==0)?1:-1; |
|
324 } |
|
325 |
|
326 |
|
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; |
|
333 |
|
334 if (p2==NULL) { |
|
335 p2 = p1; |
|
336 p1 = NULL; |
|
337 dsp = NULL; |
|
338 } |
|
339 |
|
340 /* p1 dispaly , p2 uri */ |
|
341 |
|
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 } |
|
347 |
|
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; |
|
352 |
|
353 if (parse_from_header(msg)<0 ) { |
|
354 LM_ERR("failed to find/parse FROM hdr\n"); |
|
355 return -1; |
|
356 } |
|
357 |
|
358 LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n", |
|
359 dsp,dsp?dsp->len:0,uri,uri?uri->len:0); |
|
360 |
|
361 return (replace_uri(msg, dsp, uri, msg->from, &rr_from_param)==0)?1:-1; |
|
362 } |
|
363 |
|
364 |
|
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 } |
|
372 |
|
373 return (restore_uri(msg,&rr_to_param,0)==0)?1:-1; |
|
374 } |
|
375 |
|
376 |
|
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; |
|
383 |
|
384 if (p2==NULL) { |
|
385 p2 = p1; |
|
386 p1 = NULL; |
|
387 dsp = NULL; |
|
388 } |
|
389 |
|
390 /* p1 dispaly , p2 uri */ |
|
391 |
|
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 } |
|
397 |
|
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; |
|
402 |
|
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 } |
|
408 |
|
409 return (replace_uri(msg, dsp, uri, msg->to, &rr_to_param)==0)?1:-1; |
|
410 } |
|
411 |
|
412 |
|
413 |
|
414 |
|
415 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2) |
|
416 { |
|
417 return (uac_auth(msg)==0)?1:-1; |
|
418 } |
|
419 |
|
420 |