|
@@ -32,8 +32,12 @@
|
|
|
|
|
|
#include "sr_module.h"
|
|
#include "sr_module.h"
|
|
#include "dprint.h"
|
|
#include "dprint.h"
|
|
|
|
+#include "str.h"
|
|
|
|
+#include "ut.h"
|
|
#include "mem/mem.h"
|
|
#include "mem/mem.h"
|
|
#include "db/db.h"
|
|
#include "db/db.h"
|
|
|
|
+#include "parser/parse_from.h"
|
|
|
|
+#include "parser/parse_uri.h"
|
|
#include "usr_avp.h"
|
|
#include "usr_avp.h"
|
|
|
|
|
|
|
|
|
|
@@ -49,7 +53,7 @@ static char* usr_type[] = {"ruri","from","to",0};
|
|
int init_avp_child( int rank )
|
|
int init_avp_child( int rank )
|
|
{
|
|
{
|
|
if ( rank>PROC_MAIN ) {
|
|
if ( rank>PROC_MAIN ) {
|
|
- if (avp_db_con==0) {
|
|
|
|
|
|
+ if (avp_db_url==0) {
|
|
LOG(L_NOTICE,"NOTICE:init_avp_child: no avp_db_url specified "
|
|
LOG(L_NOTICE,"NOTICE:init_avp_child: no avp_db_url specified "
|
|
"-> feature disabled\n");
|
|
"-> feature disabled\n");
|
|
return 0;
|
|
return 0;
|
|
@@ -64,17 +68,38 @@ int init_avp_child( int rank )
|
|
LOG(L_ERR,"ERROR:init_avp_child: unable to connect to database\n");
|
|
LOG(L_ERR,"ERROR:init_avp_child: unable to connect to database\n");
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
+ if (db_use_table( avp_db_con, AVP_DB_TABLE )<0) {
|
|
|
|
+ /* table selection failed */
|
|
|
|
+ LOG(L_ERR,"ERROR:init_avp_child: unable to select db table\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+void print_avps(struct usr_avp *avp)
|
|
|
|
+{
|
|
|
|
+ if (!avp)
|
|
|
|
+ return;
|
|
|
|
+ if (avp->val_type==AVP_TYPE_STR)
|
|
|
|
+ DBG("DEBUG:print_avp: %.*s=%.*s\n",
|
|
|
|
+ avp->attr.len,avp->attr.s,
|
|
|
|
+ avp->val.str_val.len,avp->val.str_val.s);
|
|
|
|
+ else
|
|
|
|
+ DBG("DEBUG:print_avp: %.*s=%u\n",
|
|
|
|
+ avp->attr.len,avp->attr.s,
|
|
|
|
+ avp->val.uint_val);
|
|
|
|
+ print_avps(avp->next);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
void destroy_avps( )
|
|
void destroy_avps( )
|
|
{
|
|
{
|
|
struct usr_avp *avp;
|
|
struct usr_avp *avp;
|
|
|
|
|
|
|
|
+ /*print_avps(users_avps);*/
|
|
while (users_avps) {
|
|
while (users_avps) {
|
|
avp = users_avps;
|
|
avp = users_avps;
|
|
users_avps = users_avps->next;
|
|
users_avps = users_avps->next;
|
|
@@ -98,9 +123,242 @@ int get_user_type( char *id )
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-int load_avp( struct sip_msg *msg, int type, char *attr, int use_dom)
|
|
|
|
|
|
+
|
|
|
|
+inline static unsigned int compute_ID( str *attr )
|
|
|
|
+{
|
|
|
|
+ char *p;
|
|
|
|
+ unsigned int id;
|
|
|
|
+
|
|
|
|
+ id=0;
|
|
|
|
+ for( p=attr->s+attr->len-1 ; p>=attr->s ; p-- )
|
|
|
|
+ id ^= *p;
|
|
|
|
+ return id;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+inline static db_res_t *do_db_query(struct sip_uri *uri,char *attr,int use_dom)
|
|
|
|
+{
|
|
|
|
+ static db_key_t keys_cmp[3] = {"username","domain","attribute"};
|
|
|
|
+ static db_key_t keys_ret[] = {"attribute","value","type"};
|
|
|
|
+ static db_val_t vals_cmp[3];
|
|
|
|
+ unsigned int nr_keys_cmp;
|
|
|
|
+ db_res_t *res;
|
|
|
|
+
|
|
|
|
+ /* prepare DB query */
|
|
|
|
+ nr_keys_cmp = 0;
|
|
|
|
+ keys_cmp[ nr_keys_cmp ] = "username";
|
|
|
|
+ vals_cmp[ nr_keys_cmp ].type = DB_STR;
|
|
|
|
+ vals_cmp[ nr_keys_cmp ].nul = 0;
|
|
|
|
+ vals_cmp[ nr_keys_cmp ].val.str_val = uri->user;
|
|
|
|
+ nr_keys_cmp++;
|
|
|
|
+ if (use_dom) {
|
|
|
|
+ keys_cmp[ nr_keys_cmp ] = "domain";
|
|
|
|
+ vals_cmp[ nr_keys_cmp ].type = DB_STR;
|
|
|
|
+ vals_cmp[ nr_keys_cmp ].nul = 0;
|
|
|
|
+ vals_cmp[ nr_keys_cmp ].val.str_val = uri->host;
|
|
|
|
+ nr_keys_cmp++;
|
|
|
|
+ }
|
|
|
|
+ if (attr) {
|
|
|
|
+ keys_cmp[ nr_keys_cmp ] = "attribute";
|
|
|
|
+ vals_cmp[ nr_keys_cmp ].type = DB_STRING;
|
|
|
|
+ vals_cmp[ nr_keys_cmp ].nul = 0;
|
|
|
|
+ vals_cmp[ nr_keys_cmp ].val.string_val = attr;
|
|
|
|
+ nr_keys_cmp++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* do the DB query */
|
|
|
|
+ if ( db_query( avp_db_con, keys_cmp, 0/*op*/, vals_cmp, keys_ret,
|
|
|
|
+ nr_keys_cmp, 3, 0/*order*/, &res) < 0)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ return res;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+inline static int validate_db_row(struct db_row *row, unsigned int *val_type,
|
|
|
|
+ unsigned int *uint_val)
|
|
|
|
+{
|
|
|
|
+ /* we don't accept null values */
|
|
|
|
+ if (row->values[0].nul || row->values[1].nul || row->values[2].nul ) {
|
|
|
|
+ LOG(L_ERR,"ERROR:avp:validat_db_row: DBreply contains NULL entryes\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ /* check the value types */
|
|
|
|
+ if (row->values[0].type!=DB_STRING || row->values[1].type!=DB_STRING ||
|
|
|
|
+ row->values[2].type!=DB_INT ) {
|
|
|
|
+ LOG(L_ERR,"ERROR:avp:validat_db_row: bad DB types in response\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ /* check the content of TYPE filed */
|
|
|
|
+ *val_type = (unsigned int)row->values[2].val.int_val;
|
|
|
|
+ if (*val_type!=AVP_TYPE_INT && *val_type!=AVP_TYPE_STR) {
|
|
|
|
+ LOG(L_ERR,"ERROR:avp:validat_db_row: bad val %d in type field\n",
|
|
|
|
+ *val_type);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ /* convert from DB_STRING to DB_STR */
|
|
|
|
+ row->values[0].val.str_val.s = (char*)row->values[0].val.string_val;
|
|
|
|
+ row->values[0].val.str_val.len = strlen(row->values[0].val.str_val.s);
|
|
|
|
+ row->values[1].val.str_val.s = (char*)row->values[1].val.string_val;
|
|
|
|
+ row->values[1].val.str_val.len = strlen(row->values[1].val.str_val.s);
|
|
|
|
+ /* if type is INT decode the value */
|
|
|
|
+ if ( *val_type==AVP_TYPE_INT &&
|
|
|
|
+ str2int( &row->values[1].val.str_val, uint_val)==-1 ) {
|
|
|
|
+ LOG(L_ERR,"ERROR:avp:validat_db_row: type is INT, but value not "
|
|
|
|
+ "<%s>\n",row->values[1].val.str_val.s);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+#define copy_str(_p_,_sd_,_ss_) \
|
|
|
|
+ do {\
|
|
|
|
+ (_sd_).s = (_p_);\
|
|
|
|
+ (_sd_).len = (_ss_).len;\
|
|
|
|
+ memcpy( _p_, (_ss_).s, (_ss_).len);\
|
|
|
|
+ (_p_) += (_ss_).len;\
|
|
|
|
+ }while(0)
|
|
|
|
+
|
|
|
|
+int load_avp( struct sip_msg *msg, int uri_type, char *attr, int use_dom)
|
|
|
|
+{
|
|
|
|
+ db_res_t *res;
|
|
|
|
+ struct sip_uri uri;
|
|
|
|
+ struct usr_avp *avp;
|
|
|
|
+ str *uri_s;
|
|
|
|
+ int n;
|
|
|
|
+ unsigned int val_type;
|
|
|
|
+ unsigned int uint_val;
|
|
|
|
+ int len;
|
|
|
|
+ char *p;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ DBG("----load_avp:%d,%s,%d\n",uri_type,attr?attr:"NULL",use_dom);
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ /* featch the user name [and domain] */
|
|
|
|
+ switch (uri_type) {
|
|
|
|
+ case 0: /* RURI */
|
|
|
|
+ uri_s = &(msg->first_line.u.request.uri);
|
|
|
|
+ break;
|
|
|
|
+ case 1: /* from */
|
|
|
|
+ if (parse_from_header( msg )<0 ) {
|
|
|
|
+ LOG(L_ERR,"ERROR:load_avp: failed to parse from\n");
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+ uri_s = &(get_from(msg)->uri);
|
|
|
|
+ break;
|
|
|
|
+ case 2: /* to */
|
|
|
|
+ if (parse_headers( msg, HDR_TO, 0)<0) {
|
|
|
|
+ LOG(L_ERR,"ERROR:load_avp: failed to parse to\n");
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+ uri_s = &(get_to(msg)->uri);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ LOG(L_CRIT,"BUG:load_avp: unknow username type <%d>\n",uri_type);
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* parse uri */
|
|
|
|
+ if (parse_uri( uri_s->s, uri_s->len , &uri )<0) {
|
|
|
|
+ LOG(L_ERR,"ERROR:load_avp: failed to parse uri\n");
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* check uri */
|
|
|
|
+ if (!uri.user.s||!uri.user.len||(use_dom&&(!uri.host.len||!uri.host.s))) {
|
|
|
|
+ LOG(L_ERR,"ERROR:load_avp: uri has no user/host part <%.*s>\n",
|
|
|
|
+ uri_s->len,uri_s->s);
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* do DB query */
|
|
|
|
+ if ( (res=do_db_query( &uri, attr,use_dom))==0 ) {
|
|
|
|
+ LOG(L_ERR,"ERROR:load_avp: db_query failed\n");
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* process DB response */
|
|
|
|
+ if (res->n==0) {
|
|
|
|
+ DBG("DEBUG:load_avp: no avp found for %.*s@%.*s <%s>\n",
|
|
|
|
+ uri.user.len,uri.user.s,(use_dom!=0)*uri.host.len,uri.host.s,
|
|
|
|
+ attr?attr:"NULL");
|
|
|
|
+ } else {
|
|
|
|
+ for( n=0 ; n<res->n ; n++) {
|
|
|
|
+ /* validate row */
|
|
|
|
+ if (validate_db_row( &res->rows[n] ,&val_type, &uint_val) < 0 )
|
|
|
|
+ continue;
|
|
|
|
+ /* what do we have here?! */
|
|
|
|
+ DBG("DEBUG:load_avp: found avp: <%s,%s,%d>\n",
|
|
|
|
+ res->rows[n].values[0].val.string_val,
|
|
|
|
+ res->rows[n].values[1].val.string_val,
|
|
|
|
+ res->rows[n].values[2].val.int_val);
|
|
|
|
+ /* build a new avp struct */
|
|
|
|
+ len = sizeof(struct usr_avp);
|
|
|
|
+ len += res->rows[n].values[0].val.str_val.len ;
|
|
|
|
+ if (val_type==AVP_TYPE_STR)
|
|
|
|
+ len += res->rows[n].values[1].val.str_val.len ;
|
|
|
|
+ avp = (struct usr_avp*)pkg_malloc( len );
|
|
|
|
+ if (avp==0) {
|
|
|
|
+ LOG(L_ERR,"ERROR:load_avp: no more pkg mem\n");
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ /* fill the structure in */
|
|
|
|
+ p = ((char*)avp) + sizeof(struct usr_avp);
|
|
|
|
+ avp->id = compute_ID( &res->rows[n].values[0].val.str_val );
|
|
|
|
+ avp->val_type = val_type;
|
|
|
|
+ /* attribute name */
|
|
|
|
+ copy_str( p, avp->attr, res->rows[n].values[0].val.str_val);
|
|
|
|
+ if (val_type==AVP_TYPE_INT) {
|
|
|
|
+ /* INT */
|
|
|
|
+ avp->val.uint_val = uint_val;
|
|
|
|
+ } else {
|
|
|
|
+ /* STRING */
|
|
|
|
+ copy_str( p, avp->val.str_val,
|
|
|
|
+ res->rows[n].values[1].val.str_val);
|
|
|
|
+ }
|
|
|
|
+ /* add avp to internal list */
|
|
|
|
+ avp->next = users_avps;
|
|
|
|
+ users_avps = avp;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ db_free_query( avp_db_con, res);
|
|
|
|
+ return 0;
|
|
|
|
+error:
|
|
|
|
+ return -1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+inline static struct usr_avp *internal_search_avp( unsigned int id, str *attr)
|
|
|
|
+{
|
|
|
|
+ struct usr_avp *avp;
|
|
|
|
+
|
|
|
|
+ for( avp=users_avps ; avp ; avp=avp->next )
|
|
|
|
+ if ( id==avp->id
|
|
|
|
+ && attr->len==avp->attr.len
|
|
|
|
+ && !strncasecmp( attr->s, avp->attr.s, attr->len)
|
|
|
|
+ ) {
|
|
|
|
+ return avp;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+struct usr_avp *search_avp( str *attr)
|
|
|
|
+{
|
|
|
|
+ return internal_search_avp( compute_ID( attr ), attr);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+struct usr_avp *search_next_avp( struct usr_avp *avp )
|
|
{
|
|
{
|
|
- DBG("----load_avp:%d,%s,%d\n",type,attr?attr:"NULL",use_dom);
|
|
|
|
- return 1;
|
|
|
|
|
|
+ return internal_search_avp( avp->id, &avp->attr);
|
|
}
|
|
}
|
|
|
|
|