/*
* $Id: uac.c 1394 2006-12-13 18:57:29Z bogdan_iancu $
*
* Copyright (C) 2005 Voice Sistem SRL
*
* This file is part of openser, a free SIP server.
*
* UAC OpenSER-module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* UAC OpenSER-module is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
* History:
* ---------
* 2005-01-31 first version (ramona)
* 2005-08-12 some TM callbacks replaced with RR callback - more efficient;
* (bogdan)
* 2006-03-02 UAC authentication looks first in AVPs for credential (bogdan)
* 2006-03-03 the RR parameter is encrypted via XOR with a password
* (bogdan)
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "../../sr_module.h"
#include "../../dprint.h"
#include "../../error.h"
#include "../../items.h"
#include "../../mem/mem.h"
#include "../tm/tm_load.h"
#include "../tm/t_hooks.h"
#include "../rr/api.h"
#include "from.h"
#include "auth.h"
MODULE_VERSION
/* local variable used for init */
static char* from_restore_mode_str = NULL;
static char* auth_username_avp = NULL;
static char* auth_realm_avp = NULL;
static char* auth_password_avp = NULL;
/* global param variables */
str rr_param = str_init("vsf");
str uac_passwd = str_init("");
int from_restore_mode = FROM_AUTO_RESTORE;
struct tm_binds uac_tmb;
struct rr_binds uac_rrb;
xl_spec_t auth_username_spec;
xl_spec_t auth_realm_spec;
xl_spec_t auth_password_spec;
static int w_replace_from1(struct sip_msg* msg, char* str, char* str2);
static int w_replace_from2(struct sip_msg* msg, char* str, char* str2);
static int w_restore_from(struct sip_msg* msg, char* foo, char* bar);
static int w_uac_auth(struct sip_msg* msg, char* str, char* str2);
static int fixup_replace_from1(void** param, int param_no);
static int fixup_replace_from2(void** param, int param_no);
static int mod_init(void);
static void mod_destroy();
/* Exported functions */
static cmd_export_t cmds[]={
{"uac_replace_from", w_replace_from2, 2, fixup_replace_from2,
REQUEST_ROUTE },
{"uac_replace_from", w_replace_from1, 1, fixup_replace_from1,
REQUEST_ROUTE },
{"uac_restore_from", w_restore_from, 0, 0,
REQUEST_ROUTE },
{"uac_auth", w_uac_auth, 0, 0,
FAILURE_ROUTE },
{0,0,0,0,0}
};
/* Exported parameters */
static param_export_t params[] = {
{"rr_store_param", STR_PARAM, &rr_param.s },
{"from_restore_mode", STR_PARAM, &from_restore_mode_str },
{"from_passwd", STR_PARAM, &uac_passwd.s },
{"credential", STR_PARAM|USE_FUNC_PARAM, (void*)&add_credential },
{"auth_username_avp", STR_PARAM, &auth_username_avp },
{"auth_realm_avp", STR_PARAM, &auth_realm_avp },
{"auth_password_avp", STR_PARAM, &auth_password_avp },
{0, 0, 0}
};
struct module_exports exports= {
"uac",
DEFAULT_DLFLAGS, /* dlopen flags */
cmds, /* exported functions */
params, /* param exports */
0, /* exported statistics */
0, /* exported MI functions */
0, /* exported pseudo-variables */
mod_init, /* module initialization function */
(response_function) 0,
mod_destroy,
0 /* per-child init function */
};
inline static int parse_auth_avp( char *avp_spec, xl_spec_t *avp, char *txt)
{
if (xl_parse_spec( avp_spec, avp, XL_THROW_ERROR|XL_DISABLE_MULTI|
XL_DISABLE_COLORS)==0 || avp->type!=XL_AVP) {
LOG(L_ERR, "ERROR:uac:parse_auth_avp: malformed or non AVP %s "
"AVP definition\n",txt);
return -1;
}
return 0;
}
static int mod_init(void)
{
LOG(L_INFO,"UAC - initializing\n");
if (from_restore_mode_str && *from_restore_mode_str) {
if (strcasecmp(from_restore_mode_str,"none")==0) {
from_restore_mode = FROM_NO_RESTORE;
} else if (strcasecmp(from_restore_mode_str,"manual")==0) {
from_restore_mode = FROM_MANUAL_RESTORE;
} else if (strcasecmp(from_restore_mode_str,"auto")==0) {
from_restore_mode = FROM_AUTO_RESTORE;
} else {
LOG(L_ERR,"ERROR:uac:mod_init: unsupported value '%s' for "
"from_restore_mode\n",from_restore_mode_str);
goto error;
}
}
rr_param.len = strlen(rr_param.s);
if (rr_param.len==0 && from_restore_mode!=FROM_NO_RESTORE)
{
LOG(L_ERR,"ERROR:uac:mod_init: rr_store_param cannot be empty "
"if FROM is restoreable\n");
goto error;
}
uac_passwd.len = strlen(uac_passwd.s);
/* parse the auth AVP spesc, if any */
if ( auth_username_avp || auth_password_avp || auth_realm_avp) {
if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) {
LOG(L_ERR,"ERROR:uac:mod_init: partial definition of auth AVP!");
goto error;
}
if ( parse_auth_avp(auth_realm_avp, &auth_realm_spec, "realm")<0
|| parse_auth_avp(auth_username_avp, &auth_username_spec, "username")<0
|| parse_auth_avp(auth_password_avp, &auth_password_spec, "password")<0
) {
goto error;
}
} else {
memset( &auth_realm_spec, 0, sizeof(xl_spec_t));
memset( &auth_password_spec, 0, sizeof(xl_spec_t));
memset( &auth_username_spec, 0, sizeof(xl_spec_t));
}
/* load the TM API - FIXME it should be loaded only
* if NO_RESTORE and AUTH */
if (load_tm_api(&uac_tmb)!=0) {
LOG(L_ERR, "ERROR:uac:mod_init: can't load TM API\n");
goto error;
}
if (from_restore_mode!=FROM_NO_RESTORE) {
/* load the RR API */
if (load_rr_api(&uac_rrb)!=0) {
LOG(L_ERR, "ERROR:uac:mod_init: can't load RR API\n");
goto error;
}
if (from_restore_mode==FROM_AUTO_RESTORE) {
/* get all requests doing loose route */
if (uac_rrb.register_rrcb( rr_checker, 0)!=0) {
LOG(L_ERR,"ERROR:uac:mod_init: failed to install "
"RR callback\n");
goto error;
}
}
}
init_from_replacer();
return 0;
error:
return -1;
}
static void mod_destroy()
{
destroy_credentials();
}
/************************** fixup functions ******************************/
static int fixup_replace_from1(void** param, int param_no)
{
xl_elem_t *model;
model=NULL;
if(xl_parse_format((char*)(*param),&model,XL_DISABLE_COLORS)<0)
{
LOG(L_ERR, "ERROR:uac:fixup_replace_from1: wrong format[%s]!\n",
(char*)(*param));
return E_UNSPEC;
}
if (model==NULL)
{
LOG(L_ERR, "ERROR:uac:fixup_replace_from1: empty parameter!\n");
return E_UNSPEC;
}
*param = (void*)model;
return 0;
}
static int fixup_replace_from2(void** param, int param_no)
{
xl_elem_t *model;
char *p;
str s;
/* convert to str */
s.s = (char*)*param;
s.len = strlen(s.s);
model=NULL;
if (param_no==1)
{
if (s.len)
{
/* put " around display name */
p = (char*)pkg_malloc(s.len+3);
if (p==0)
{
LOG(L_CRIT,"ERROR:uac:fixup_replace_from2: no more pkg mem\n");
return E_OUT_OF_MEM;
}
p[0] = '\"';
memcpy(p+1, s.s, s.len);
p[s.len+1] = '\"';
p[s.len+2] = '\0';
pkg_free(s.s);
s.s = p;
s.len += 2;
}
}
if(s.len!=0)
{
if(xl_parse_format(s.s,&model,XL_DISABLE_COLORS)<0)
{
LOG(L_ERR, "ERROR:uac:fixup_replace_from2: wrong format [%s] "
"for param no %d!\n", s.s, param_no);
pkg_free(s.s);
return E_UNSPEC;
}
}
*param = (void*)model;
return 0;
}
/************************** wrapper functions ******************************/
static int w_restore_from(struct sip_msg *msg, char* foo, char* bar)
{
/* safety checks - must be a request */
if (msg->first_line.type!=SIP_REQUEST) {
LOG(L_ERR,"ERROR:uac:w_restore_from: called for something "
"not request\n");
return -1;
}
return (restore_from(msg,0)==0)?1:-1;
}
static int w_replace_from1(struct sip_msg* msg, char* uri, char* str2)
{
str uri_s;
if(xl_printf_s( msg, (xl_elem_p)uri, &uri_s)!=0)
return -1;
return (replace_from(msg, 0, &uri_s)==0)?1:-1;
}
static int w_replace_from2(struct sip_msg* msg, char* dsp, char* uri)
{
str uri_s;
str dsp_s;
if (dsp!=NULL)
{
if(dsp!=NULL)
if(xl_printf_s( msg, (xl_elem_p)dsp, &dsp_s)!=0)
return -1;
} else {
dsp_s.s = 0;
dsp_s.len = 0;
}
if(uri!=NULL)
{
if(xl_printf_s( msg, (xl_elem_p)uri, &uri_s)!=0)
return -1;
}
return (replace_from(msg, &dsp_s, (uri)?&uri_s:0)==0)?1:-1;
}
static int w_uac_auth(struct sip_msg* msg, char* str, char* str2)
{
return (uac_auth(msg)==0)?1:-1;
}
syntax highlighted by Code2HTML, v. 0.9.1