Wed, 10 Feb 2010 21:25:01 +0100
Extend uac_auth() of the UAC module to workaround CSEQ problems.
This logic is meant to complement that of changeset 17, which
added rich authentication credentials to the gw table and its
associated logic in the LCR module.
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 }