# HG changeset patch # User Michael Schloh von Bennewitz # Date 1265833284 -3600 # Node ID 733187d496d07c079213753cc5fbdd214c4f2876 # Parent c5c55937e44c357caf9360b216fda64ce61e126e Introduce authentication credential logic into the LCR module. This logic is meant to complement that of changeset 18, adding additional authentication flexibility to the UAC module. diff -r c5c55937e44c -r 733187d496d0 opensips/lcr-auth.diff --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/opensips/lcr-auth.diff Wed Feb 10 21:21:24 2010 +0100 @@ -0,0 +1,450 @@ +Index: modules/lcr/lcr_mod.c +diff -Nau modules/lcr/lcr_mod.c.orig modules/lcr/lcr_mod.c +--- modules/lcr/lcr_mod.c.orig 2010-01-18 12:32:29.697648000 +0100 ++++ modules/lcr/lcr_mod.c 2010-02-10 19:52:14.838272303 +0100 +@@ -114,9 +114,18 @@ + + #define PRIORITY_COL "priority" + ++#define USER_COL "user" ++ ++#define REALM_COL "realm" ++ ++#define PASSWD_COL "passwd" ++ + #define MAX_NO_OF_GWS 32 + #define MAX_NO_OF_LCRS 256 + #define MAX_PREFIX_LEN 256 ++#define MAX_USER_LEN 64 ++#define MAX_REALM_LEN 64 ++#define MAX_PASSWD_LEN 64 + #define MAX_TAG_LEN 16 + #define MAX_FROM_URI_LEN 256 + +@@ -141,6 +150,12 @@ + char tag[MAX_TAG_LEN + 1]; + unsigned short tag_len; + unsigned int flags; ++ char user[MAX_USER_LEN]; ++ unsigned short user_len; ++ char realm[MAX_REALM_LEN]; ++ unsigned short realm_len; ++ char passwd[MAX_PASSWD_LEN]; ++ unsigned short passwd_len; + }; + + struct lcr_info { +@@ -196,6 +211,9 @@ + static str prefix_col = str_init(PREFIX_COL); + static str from_uri_col = str_init(FROM_URI_COL); + static str priority_col = str_init(PRIORITY_COL); ++static str user_col = str_init(USER_COL); ++static str realm_col = str_init(REALM_COL); ++static str passwd_col = str_init(PASSWD_COL); + + /* timer */ + int fr_inv_timer = DEF_FR_INV_TIMER; +@@ -208,6 +226,9 @@ + static char *contact_avp_param = NULL; + static char *rpid_avp_param = NULL; + static char *flags_avp_param = NULL; ++static char *user_avp_param = NULL; ++static char *realm_avp_param = NULL; ++static char *passwd_avp_param = NULL; + + /* prefix mode */ + int prefix_mode_param = DEF_PREFIX_MODE; +@@ -239,6 +260,12 @@ + static int_str rpid_avp; + static int flags_avp_type; + static int_str flags_avp; ++static int user_avp_type; ++static int_str user_avp; ++static int realm_avp_type; ++static int_str realm_avp; ++static int passwd_avp_type; ++static int_str passwd_avp; + + struct gw_info **gws; /* Pointer to current gw table pointer */ + struct gw_info *gws_1; /* Pointer to gw table 1 */ +@@ -327,6 +354,12 @@ + {"fr_inv_timer", INT_PARAM, &fr_inv_timer }, + {"fr_inv_timer_next", INT_PARAM, &fr_inv_timer_next }, + {"prefix_mode", INT_PARAM, &prefix_mode_param }, ++ {"user_column", STR_PARAM, &user_col.s }, ++ {"realm_column", STR_PARAM, &realm_col.s }, ++ {"passwd_column", STR_PARAM, &passwd_col.s }, ++ {"auth_username_avp", STR_PARAM, &user_avp_param }, ++ {"auth_realm_avp", STR_PARAM, &realm_avp_param }, ++ {"auth_password_avp", STR_PARAM, &passwd_avp_param }, + {0, 0, 0} + }; + +@@ -438,6 +471,9 @@ + prefix_col.len = strlen(prefix_col.s); + from_uri_col.len = strlen(from_uri_col.s); + priority_col.len = strlen(priority_col.s); ++ user_col.len = strlen(user_col.s); ++ realm_col.len = strlen(realm_col.s); ++ passwd_col.len = strlen(passwd_col.s); + + /* Bind database */ + if (lcr_db_bind(&db_url)) { +@@ -563,6 +599,60 @@ + return -1; + } + ++ if (user_avp_param && *user_avp_param) { ++ s.s = user_avp_param; s.len = strlen(s.s); ++ if (pv_parse_spec(&s, &avp_spec)==0 ++ || avp_spec.type!=PVT_AVP) { ++ LM_ERR("Malformed or non AVP definition <%s>\n", user_avp_param); ++ return -1; ++ } ++ ++ if(pv_get_avp_name(0, &(avp_spec.pvp), &user_avp, &avp_flags)!=0) { ++ LM_ERR("Invalid AVP definition <%s>\n", user_avp_param); ++ return -1; ++ } ++ user_avp_type = avp_flags; ++ } else { ++ LM_ERR("AVP user_avp has not been defined\n"); ++ return -1; ++ } ++ ++ if (realm_avp_param && *realm_avp_param) { ++ s.s = realm_avp_param; s.len = strlen(s.s); ++ if (pv_parse_spec(&s, &avp_spec)==0 ++ || avp_spec.type!=PVT_AVP) { ++ LM_ERR("Malformed or non AVP definition <%s>\n", realm_avp_param); ++ return -1; ++ } ++ ++ if(pv_get_avp_name(0, &(avp_spec.pvp), &realm_avp, &avp_flags)!=0) { ++ LM_ERR("Invalid AVP definition <%s>\n", realm_avp_param); ++ return -1; ++ } ++ realm_avp_type = avp_flags; ++ } else { ++ LM_ERR("AVP realm_avp has not been defined\n"); ++ return -1; ++ } ++ ++ if (passwd_avp_param && *passwd_avp_param) { ++ s.s = passwd_avp_param; s.len = strlen(s.s); ++ if (pv_parse_spec(&s, &avp_spec)==0 ++ || avp_spec.type!=PVT_AVP) { ++ LM_ERR("Malformed or non AVP definition <%s>\n", passwd_avp_param); ++ return -1; ++ } ++ ++ if(pv_get_avp_name(0, &(avp_spec.pvp), &passwd_avp, &avp_flags)!=0) { ++ LM_ERR("Invalid AVP definition <%s>\n", passwd_avp_param); ++ return -1; ++ } ++ passwd_avp_type = avp_flags; ++ } else { ++ LM_ERR("AVP passwd_avp has not been defined\n"); ++ return -1; ++ } ++ + /* Check table version */ + db_con_t* dbh; + if (lcr_dbf.init==0){ +@@ -801,16 +891,17 @@ + int reload_gws(void) + { + unsigned int i, port, strip, tag_len, prefix_len, from_uri_len, +- grp_id, priority; ++ user_len, realm_len, passwd_len, grp_id, priority; + struct in_addr ip_addr; + unsigned int flags; + uri_type scheme; + uri_transport transport; + db_con_t* dbh; + char *tag, *prefix, *from_uri; ++ char *user, *realm, *passwd; + db_res_t* res = NULL; + db_row_t* row; +- db_key_t gw_cols[8]; ++ db_key_t gw_cols[11]; + db_key_t lcr_cols[4]; + + gw_cols[0] = &ip_addr_col; +@@ -823,6 +914,9 @@ + in the two tables? (ge vw lcr) */ + gw_cols[6] = &grp_id_col; + gw_cols[7] = &flags_col; ++ gw_cols[8] = &user_col; ++ gw_cols[9] = &realm_col; ++ gw_cols[10] = &passwd_col; + + lcr_cols[0] = &prefix_col; + lcr_cols[1] = &from_uri_col; +@@ -846,7 +940,7 @@ + return -1; + } + +- if (lcr_dbf.query(dbh, NULL, 0, NULL, gw_cols, 0, 8, 0, &res) < 0) { ++ if (lcr_dbf.query(dbh, NULL, 0, NULL, gw_cols, 0, 11, 0, &res) < 0) { + LM_ERR("Failed to query gw data\n"); + lcr_dbf.close(dbh); + return -1; +@@ -938,6 +1032,45 @@ + lcr_dbf.close(dbh); + return -1; + } ++ if (VAL_NULL(ROW_VALUES(row) + 8) == 1) { ++ user_len = 0; ++ user = (char *)0; ++ } else { ++ user = (char *)VAL_STRING(ROW_VALUES(row) + 8); ++ user_len = strlen(user); ++ if (user_len > MAX_USER_LEN) { ++ LM_ERR("Too long gw user <%u>\n", user_len); ++ lcr_dbf.free_result(dbh, res); ++ lcr_dbf.close(dbh); ++ return -1; ++ } ++ } ++ if (VAL_NULL(ROW_VALUES(row) + 9) == 1) { ++ realm_len = 0; ++ realm = (char *)0; ++ } else { ++ realm = (char *)VAL_STRING(ROW_VALUES(row) + 9); ++ realm_len = strlen(realm); ++ if (realm_len > MAX_REALM_LEN) { ++ LM_ERR("Too long gw realm <%u>\n", realm_len); ++ lcr_dbf.free_result(dbh, res); ++ lcr_dbf.close(dbh); ++ return -1; ++ } ++ } ++ if (VAL_NULL(ROW_VALUES(row) + 10) == 1) { ++ passwd_len = 0; ++ passwd = (char *)0; ++ } else { ++ passwd = (char *)VAL_STRING(ROW_VALUES(row) + 10); ++ passwd_len = strlen(passwd); ++ if (passwd_len > MAX_PASSWD_LEN) { ++ LM_ERR("Too long gw passwd <%u>\n", passwd_len); ++ lcr_dbf.free_result(dbh, res); ++ lcr_dbf.close(dbh); ++ return -1; ++ } ++ } + if (*gws == gws_1) { + gws_2[i].ip_addr = (unsigned int)ip_addr.s_addr; + gws_2[i].port = port; +@@ -949,6 +1082,15 @@ + gws_2[i].tag_len = tag_len; + if (tag_len) + memcpy(&(gws_2[i].tag[0]), tag, tag_len); ++ gws_2[i].user_len = user_len; ++ if (user_len) ++ memcpy(&(gws_2[i].user[0]), user, user_len); ++ gws_2[i].realm_len = realm_len; ++ if (realm_len) ++ memcpy(&(gws_2[i].realm[0]), realm, realm_len); ++ gws_2[i].passwd_len = passwd_len; ++ if (passwd_len) ++ memcpy(&(gws_2[i].passwd[0]), passwd, passwd_len); + } else { + gws_1[i].ip_addr = (unsigned int)ip_addr.s_addr; + gws_1[i].port = port; +@@ -960,6 +1102,15 @@ + gws_1[i].tag_len = tag_len; + if (tag_len) + memcpy(&(gws_1[i].tag[0]), tag, tag_len); ++ gws_1[i].user_len = user_len; ++ if (user_len) ++ memcpy(&(gws_1[i].user[0]), user, user_len); ++ gws_1[i].realm_len = realm_len; ++ if (realm_len) ++ memcpy(&(gws_1[i].realm[0]), realm, realm_len); ++ gws_1[i].passwd_len = passwd_len; ++ if (passwd_len) ++ memcpy(&(gws_1[i].passwd[0]), passwd, passwd_len); + } + } + +@@ -1141,6 +1292,21 @@ + attr = add_mi_attr(node, MI_DUP_VALUE, "FLAGS", 5, p, len); + if(attr == NULL) + return -1; ++ ++ attr = add_mi_attr(node, MI_DUP_VALUE, "USER", 6, ++ (*gws)[i].user, (*gws)[i].user_len ); ++ if(attr == NULL) ++ return -1; ++ ++ attr = add_mi_attr(node, MI_DUP_VALUE, "REALM", 6, ++ (*gws)[i].realm, (*gws)[i].realm_len ); ++ if(attr == NULL) ++ return -1; ++ ++ attr = add_mi_attr(node, MI_DUP_VALUE, "PASSWD", 6, ++ (*gws)[i].passwd, (*gws)[i].passwd_len ); ++ if(attr == NULL) ++ return -1; + } + + for (i = 0; i < MAX_NO_OF_LCRS; i++) { +@@ -1184,6 +1350,9 @@ + char ruri[MAX_URI_SIZE]; + unsigned int i, j, k, index, addr, port, strip, gw_index, + duplicated_gw, flags, have_rpid_avp; ++ char *user; ++ char *realm; ++ char *passwd; + uri_type scheme; + uri_transport transport; + struct ip_addr address; +@@ -1407,6 +1576,9 @@ + transport = (*gws)[index].transport; + flags = (*gws)[index].flags; + strip = (*gws)[index].strip; ++ user = (*gws)[index].user; ++ realm = (*gws)[index].realm; ++ passwd = (*gws)[index].passwd; + if (strip > ruri_user.len) { + LM_ERR("Strip count of gw is too large <%u>\n", strip); + goto skip; +@@ -1476,6 +1648,25 @@ + val.s = value; + add_avp(gw_uri_avp_type|AVP_VAL_STR, gw_uri_avp, val); + LM_DBG("Added gw_uri_avp <%.*s>\n", value.len, value.s); ++ ++ value.s = user; ++ value.len = strlen(value.s); ++ val.s = value; ++ add_avp(user_avp_type|AVP_VAL_STR, user_avp, val); ++ LM_DBG("Added user_avp <%.*s>\n", value.len, value.s); ++ ++ value.s = realm; ++ value.len = strlen(value.s); ++ val.s = value; ++ add_avp(realm_avp_type|AVP_VAL_STR, realm_avp, val); ++ LM_DBG("Added realm_avp <%.*s>\n", value.len, value.s); ++ ++ value.s = passwd; ++ value.len = strlen(value.s); ++ val.s = value; ++ add_avp(passwd_avp_type|AVP_VAL_STR, passwd_avp, val); ++ LM_DBG("Added passwd_avp <%.*s>\n", value.len, value.s); ++ + skip: + continue; + } +@@ -1558,7 +1749,8 @@ + static int next_gw(struct sip_msg* _m, char* _s1, char* _s2) + { + int_str gw_uri_val, ruri_user_val, val; +- struct usr_avp *gu_avp, *ru_avp; ++ int_str user_val, realm_val, passwd_val; ++ struct usr_avp *gu_avp, *ru_avp, *usr_avp, *rlm_avp, *pwd_avp; + int rval; + str new_ruri; + char *at, *at_char, *strip_char, *endptr; +@@ -1575,6 +1767,35 @@ + gw_uri_val.s.len = gw_uri_val.s.len - (at - gw_uri_val.s.s); + gw_uri_val.s.s = at; + ++ /* Save gateway AVPs for use in script */ ++ usr_avp = search_first_avp(user_avp_type, user_avp, &user_val, 0); ++ rlm_avp = search_first_avp(realm_avp_type, realm_avp, &realm_val, 0); ++ pwd_avp = search_first_avp(passwd_avp_type, passwd_avp, &passwd_val, 0); ++ if (!usr_avp) { ++ LM_DBG("User AVP no set\n"); ++ return -1; ++ } ++ else { ++ add_avp(user_avp_type|AVP_VAL_STR, user_avp, user_val); ++ LM_DBG("Added user_avp <%.*s>\n", user_val.s.len, user_val.s.s); ++ } ++ if (!rlm_avp) { ++ LM_DBG("Realm AVP no set\n"); ++ return -1; ++ } ++ else { ++ add_avp(realm_avp_type|AVP_VAL_STR, realm_avp, realm_val); ++ LM_DBG("Added realm_avp <%.*s>\n", realm_val.s.len, realm_val.s.s); ++ } ++ if (!pwd_avp) { ++ LM_DBG("Passwd AVP no set\n"); ++ return -1; ++ } ++ else { ++ add_avp(passwd_avp_type|AVP_VAL_STR, passwd_avp, passwd_val); ++ LM_DBG("Added passwd_avp <%.*s>\n", passwd_val.s.len, passwd_val.s.s); ++ } ++ + /* Create new Request-URI taking URI user from ruri_user AVP + and other parts of from gateway URI AVP. */ + ru_avp = search_first_avp(ruri_user_avp_type, ruri_user_avp, +Index: scripts/db_berkeley/opensips/gw +diff -Nau scripts/db_berkeley/opensips/gw.orig scripts/db_berkeley/opensips/gw +--- scripts/db_berkeley/opensips/gw.orig 2010-01-18 12:31:09.312068000 +0100 ++++ scripts/db_berkeley/opensips/gw 2010-02-10 19:57:18.467214268 +0100 +@@ -1,5 +1,5 @@ + METADATA_COLUMNS +-id(int) gw_name(str) grp_id(int) ip_addr(str) port(int) uri_scheme(int) transport(int) strip(int) tag(str) flags(int) ++id(int) gw_name(str) grp_id(int) ip_addr(str) port(int) uri_scheme(int) transport(int) strip(int) tag(str) flags(int) user(str) realm(str) passwd(str) + METADATA_KEY + 1 + METADATA_READONLY +@@ -7,4 +7,4 @@ + METADATA_LOGFLAGS + 0 + METADATA_DEFAULTS +-NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NULL|0 ++NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NULL|0|NULL|NULL|NULL +Index: scripts/dbtext/opensips/gw +diff -Nau scripts/dbtext/opensips/gw.orig scripts/dbtext/opensips/gw +--- scripts/dbtext/opensips/gw.orig 2010-01-18 12:31:01.221183000 +0100 ++++ scripts/dbtext/opensips/gw 2010-02-10 19:57:19.099512686 +0100 +@@ -1 +1 @@ +-id(int,auto) gw_name(string) grp_id(int) ip_addr(string) port(int,null) uri_scheme(int,null) transport(int,null) strip(int,null) tag(string,null) flags(int) ++id(int,auto) gw_name(string) grp_id(int) ip_addr(string) port(int,null) uri_scheme(int,null) transport(int,null) strip(int,null) tag(string,null) flags(int) user(string,null) realm(string,null) passwd(string,null) +Index: scripts/mysql/lcr-create.sql +diff -Nau scripts/mysql/lcr-create.sql.orig scripts/mysql/lcr-create.sql +--- scripts/mysql/lcr-create.sql.orig 2010-01-18 12:31:05.995635000 +0100 ++++ scripts/mysql/lcr-create.sql 2010-02-10 20:00:24.123864285 +0100 +@@ -10,6 +10,9 @@ + strip TINYINT UNSIGNED, + tag CHAR(16) DEFAULT NULL, + flags INT UNSIGNED DEFAULT 0 NOT NULL, ++ user CHAR(16) DEFAULT NULL, ++ realm CHAR(16) DEFAULT NULL, ++ passwd CHAR(16) DEFAULT NULL, + CONSTRAINT gw_name_idx UNIQUE (gw_name) + ) ENGINE=MyISAM; + +Index: scripts/oracle/lcr-create.sql +diff -Nau scripts/oracle/lcr-create.sql.orig scripts/oracle/lcr-create.sql +--- scripts/oracle/lcr-create.sql.orig 2010-01-18 12:31:09.035730000 +0100 ++++ scripts/oracle/lcr-create.sql 2010-02-10 20:00:23.643867960 +0100 +@@ -10,6 +10,9 @@ + strip NUMBER(5), + tag VARCHAR2(16) DEFAULT NULL, + flags NUMBER(10) DEFAULT 0 NOT NULL, ++ user VARCHAR2(16) DEFAULT NULL, ++ realm VARCHAR2(16) DEFAULT NULL, ++ passwd VARCHAR2(16) DEFAULT NULL, + CONSTRAINT gw_gw_name_idx UNIQUE (gw_name) + ); + +Index: scripts/postgres/lcr-create.sql +diff -Nau scripts/postgres/lcr-create.sql.orig scripts/postgres/lcr-create.sql +--- scripts/postgres/lcr-create.sql.orig 2010-01-18 12:31:09.151881000 +0100 ++++ scripts/postgres/lcr-create.sql 2010-02-10 19:59:19.649196584 +0100 +@@ -10,6 +10,9 @@ + strip SMALLINT, + tag VARCHAR(16) DEFAULT NULL, + flags INTEGER DEFAULT 0 NOT NULL, ++ user VARCHAR(16) DEFAULT NULL, ++ realm VARCHAR(16) DEFAULT NULL, ++ passwd VARCHAR(16) DEFAULT NULL, + CONSTRAINT gw_gw_name_idx UNIQUE (gw_name) + ); + diff -r c5c55937e44c -r 733187d496d0 opensips/lcr-auth.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/opensips/lcr-auth.txt Wed Feb 10 21:21:24 2010 +0100 @@ -0,0 +1,73 @@ +LCR module authentication extention (contribution) + +Rationale + +An orthoganal approach to abstract authentication logic out of the +routing script improves administration by keeping unnecessarily hard +coded authentication credentials out of the routing script. + +Usage + +The new lcr module parameters which achieve this are 'auth_realm_avp', +'auth_username_avp', and 'auth_password_avp'. To specify where the lcr +module should write these values set the parameters like so: + + modparam("lcr", "auth_realm_avp", "$avp(s:arealm)") + modparam("lcr", "auth_username_avp", "$avp(s:auser)") + modparam("lcr", "auth_password_avp", "$avp(s:apass)") + +Typically these parameters are used in conjunction with the uac modules +uac_auth() function, which uses similar variables which are specified in +a similar manner. In fact, the parameters of both lcr and uac modules +can be specified at the same time like so: + + modparam("uac|lcr", "auth_realm_avp", "$avp(s:arealm)") + modparam("uac|lcr", "auth_username_avp", "$avp(s:auser)") + modparam("uac|lcr", "auth_password_avp", "$avp(s:apass)") + +In addition to the existing column module parameters, specify the name +of each of the new gw table columns like so: + + modparam("lcr", "user_column", "user") + modparam("lcr", "realm_column", "realm") + modparam("lcr", "passwd_column", "passwd") + +At this point the new functionality of the lcr module is ready to be +used. Enter values into the gw table with its new columns and call the +standard lcr module functions load_gws() and next_gw(). + +Result + +After calling load_gws() and next_gw(), inspect the variables associated +with the user, realm, and password columns (see the modparam entries) to +find that the lcr module can now hand off authentication credentials to +other modules with ease. + +Location + +http://scm.europalab.com/contrib/opensips/ +http://scm.europalab.com/contrib/file/tip/opensips/ +http://scm.europalab.com/contrib/file/tip/opensips/lcr-auth.txt +http://scm.europalab.com/contrib/file/tip/opensips/lcr-auth.diff + +Instructions + +To integrate this contributed logic into the source code tree of +a OpenSIPS distribution, download the unified diff and use the +patch(1) command: + + $ cd /tmp && mkdir lcr-patch && cd lcr-patch + $ wget http://scm.europalab.com/contrib/raw-file/tip/opensips/lcr-auth.diff + $ tar zxf /tmp/opensips--tls.tar.gz + $ cd opensips--tls + $ patch -p0 <../lcr-auth.diff + +Disclaimer + +This software contribution is based on source code from OpenSIPS SVN +revision 6590. The author makes no guarantees as to this contribution. +A user who downloads and executes it does so at his own risk. + +Michael Schloh von Bennewitz +http://michael.schloh.com/ +Wednsday, 10. February 2010 diff -r c5c55937e44c -r 733187d496d0 opensips/modules/lcr/lcr_mod.c --- a/opensips/modules/lcr/lcr_mod.c Wed Feb 10 21:14:04 2010 +0100 +++ b/opensips/modules/lcr/lcr_mod.c Wed Feb 10 21:21:24 2010 +0100 @@ -114,9 +114,18 @@ #define PRIORITY_COL "priority" +#define USER_COL "user" + +#define REALM_COL "realm" + +#define PASSWD_COL "passwd" + #define MAX_NO_OF_GWS 32 #define MAX_NO_OF_LCRS 256 #define MAX_PREFIX_LEN 256 +#define MAX_USER_LEN 64 +#define MAX_REALM_LEN 64 +#define MAX_PASSWD_LEN 64 #define MAX_TAG_LEN 16 #define MAX_FROM_URI_LEN 256 @@ -141,6 +150,12 @@ char tag[MAX_TAG_LEN + 1]; unsigned short tag_len; unsigned int flags; + char user[MAX_USER_LEN]; + unsigned short user_len; + char realm[MAX_REALM_LEN]; + unsigned short realm_len; + char passwd[MAX_PASSWD_LEN]; + unsigned short passwd_len; }; struct lcr_info { @@ -196,6 +211,9 @@ static str prefix_col = str_init(PREFIX_COL); static str from_uri_col = str_init(FROM_URI_COL); static str priority_col = str_init(PRIORITY_COL); +static str user_col = str_init(USER_COL); +static str realm_col = str_init(REALM_COL); +static str passwd_col = str_init(PASSWD_COL); /* timer */ int fr_inv_timer = DEF_FR_INV_TIMER; @@ -208,6 +226,9 @@ static char *contact_avp_param = NULL; static char *rpid_avp_param = NULL; static char *flags_avp_param = NULL; +static char *user_avp_param = NULL; +static char *realm_avp_param = NULL; +static char *passwd_avp_param = NULL; /* prefix mode */ int prefix_mode_param = DEF_PREFIX_MODE; @@ -239,6 +260,12 @@ static int_str rpid_avp; static int flags_avp_type; static int_str flags_avp; +static int user_avp_type; +static int_str user_avp; +static int realm_avp_type; +static int_str realm_avp; +static int passwd_avp_type; +static int_str passwd_avp; struct gw_info **gws; /* Pointer to current gw table pointer */ struct gw_info *gws_1; /* Pointer to gw table 1 */ @@ -327,6 +354,12 @@ {"fr_inv_timer", INT_PARAM, &fr_inv_timer }, {"fr_inv_timer_next", INT_PARAM, &fr_inv_timer_next }, {"prefix_mode", INT_PARAM, &prefix_mode_param }, + {"user_column", STR_PARAM, &user_col.s }, + {"realm_column", STR_PARAM, &realm_col.s }, + {"passwd_column", STR_PARAM, &passwd_col.s }, + {"auth_username_avp", STR_PARAM, &user_avp_param }, + {"auth_realm_avp", STR_PARAM, &realm_avp_param }, + {"auth_password_avp", STR_PARAM, &passwd_avp_param }, {0, 0, 0} }; @@ -438,6 +471,9 @@ prefix_col.len = strlen(prefix_col.s); from_uri_col.len = strlen(from_uri_col.s); priority_col.len = strlen(priority_col.s); + user_col.len = strlen(user_col.s); + realm_col.len = strlen(realm_col.s); + passwd_col.len = strlen(passwd_col.s); /* Bind database */ if (lcr_db_bind(&db_url)) { @@ -563,6 +599,60 @@ return -1; } + if (user_avp_param && *user_avp_param) { + s.s = user_avp_param; s.len = strlen(s.s); + if (pv_parse_spec(&s, &avp_spec)==0 + || avp_spec.type!=PVT_AVP) { + LM_ERR("Malformed or non AVP definition <%s>\n", user_avp_param); + return -1; + } + + if(pv_get_avp_name(0, &(avp_spec.pvp), &user_avp, &avp_flags)!=0) { + LM_ERR("Invalid AVP definition <%s>\n", user_avp_param); + return -1; + } + user_avp_type = avp_flags; + } else { + LM_ERR("AVP user_avp has not been defined\n"); + return -1; + } + + if (realm_avp_param && *realm_avp_param) { + s.s = realm_avp_param; s.len = strlen(s.s); + if (pv_parse_spec(&s, &avp_spec)==0 + || avp_spec.type!=PVT_AVP) { + LM_ERR("Malformed or non AVP definition <%s>\n", realm_avp_param); + return -1; + } + + if(pv_get_avp_name(0, &(avp_spec.pvp), &realm_avp, &avp_flags)!=0) { + LM_ERR("Invalid AVP definition <%s>\n", realm_avp_param); + return -1; + } + realm_avp_type = avp_flags; + } else { + LM_ERR("AVP realm_avp has not been defined\n"); + return -1; + } + + if (passwd_avp_param && *passwd_avp_param) { + s.s = passwd_avp_param; s.len = strlen(s.s); + if (pv_parse_spec(&s, &avp_spec)==0 + || avp_spec.type!=PVT_AVP) { + LM_ERR("Malformed or non AVP definition <%s>\n", passwd_avp_param); + return -1; + } + + if(pv_get_avp_name(0, &(avp_spec.pvp), &passwd_avp, &avp_flags)!=0) { + LM_ERR("Invalid AVP definition <%s>\n", passwd_avp_param); + return -1; + } + passwd_avp_type = avp_flags; + } else { + LM_ERR("AVP passwd_avp has not been defined\n"); + return -1; + } + /* Check table version */ db_con_t* dbh; if (lcr_dbf.init==0){ @@ -801,16 +891,17 @@ int reload_gws(void) { unsigned int i, port, strip, tag_len, prefix_len, from_uri_len, - grp_id, priority; + user_len, realm_len, passwd_len, grp_id, priority; struct in_addr ip_addr; unsigned int flags; uri_type scheme; uri_transport transport; db_con_t* dbh; char *tag, *prefix, *from_uri; + char *user, *realm, *passwd; db_res_t* res = NULL; db_row_t* row; - db_key_t gw_cols[8]; + db_key_t gw_cols[11]; db_key_t lcr_cols[4]; gw_cols[0] = &ip_addr_col; @@ -823,6 +914,9 @@ in the two tables? (ge vw lcr) */ gw_cols[6] = &grp_id_col; gw_cols[7] = &flags_col; + gw_cols[8] = &user_col; + gw_cols[9] = &realm_col; + gw_cols[10] = &passwd_col; lcr_cols[0] = &prefix_col; lcr_cols[1] = &from_uri_col; @@ -846,7 +940,7 @@ return -1; } - if (lcr_dbf.query(dbh, NULL, 0, NULL, gw_cols, 0, 8, 0, &res) < 0) { + if (lcr_dbf.query(dbh, NULL, 0, NULL, gw_cols, 0, 11, 0, &res) < 0) { LM_ERR("Failed to query gw data\n"); lcr_dbf.close(dbh); return -1; @@ -938,6 +1032,45 @@ lcr_dbf.close(dbh); return -1; } + if (VAL_NULL(ROW_VALUES(row) + 8) == 1) { + user_len = 0; + user = (char *)0; + } else { + user = (char *)VAL_STRING(ROW_VALUES(row) + 8); + user_len = strlen(user); + if (user_len > MAX_USER_LEN) { + LM_ERR("Too long gw user <%u>\n", user_len); + lcr_dbf.free_result(dbh, res); + lcr_dbf.close(dbh); + return -1; + } + } + if (VAL_NULL(ROW_VALUES(row) + 9) == 1) { + realm_len = 0; + realm = (char *)0; + } else { + realm = (char *)VAL_STRING(ROW_VALUES(row) + 9); + realm_len = strlen(realm); + if (realm_len > MAX_REALM_LEN) { + LM_ERR("Too long gw realm <%u>\n", realm_len); + lcr_dbf.free_result(dbh, res); + lcr_dbf.close(dbh); + return -1; + } + } + if (VAL_NULL(ROW_VALUES(row) + 10) == 1) { + passwd_len = 0; + passwd = (char *)0; + } else { + passwd = (char *)VAL_STRING(ROW_VALUES(row) + 10); + passwd_len = strlen(passwd); + if (passwd_len > MAX_PASSWD_LEN) { + LM_ERR("Too long gw passwd <%u>\n", passwd_len); + lcr_dbf.free_result(dbh, res); + lcr_dbf.close(dbh); + return -1; + } + } if (*gws == gws_1) { gws_2[i].ip_addr = (unsigned int)ip_addr.s_addr; gws_2[i].port = port; @@ -949,6 +1082,15 @@ gws_2[i].tag_len = tag_len; if (tag_len) memcpy(&(gws_2[i].tag[0]), tag, tag_len); + gws_2[i].user_len = user_len; + if (user_len) + memcpy(&(gws_2[i].user[0]), user, user_len); + gws_2[i].realm_len = realm_len; + if (realm_len) + memcpy(&(gws_2[i].realm[0]), realm, realm_len); + gws_2[i].passwd_len = passwd_len; + if (passwd_len) + memcpy(&(gws_2[i].passwd[0]), passwd, passwd_len); } else { gws_1[i].ip_addr = (unsigned int)ip_addr.s_addr; gws_1[i].port = port; @@ -960,6 +1102,15 @@ gws_1[i].tag_len = tag_len; if (tag_len) memcpy(&(gws_1[i].tag[0]), tag, tag_len); + gws_1[i].user_len = user_len; + if (user_len) + memcpy(&(gws_1[i].user[0]), user, user_len); + gws_1[i].realm_len = realm_len; + if (realm_len) + memcpy(&(gws_1[i].realm[0]), realm, realm_len); + gws_1[i].passwd_len = passwd_len; + if (passwd_len) + memcpy(&(gws_1[i].passwd[0]), passwd, passwd_len); } } @@ -1141,6 +1292,21 @@ attr = add_mi_attr(node, MI_DUP_VALUE, "FLAGS", 5, p, len); if(attr == NULL) return -1; + + attr = add_mi_attr(node, MI_DUP_VALUE, "USER", 6, + (*gws)[i].user, (*gws)[i].user_len ); + if(attr == NULL) + return -1; + + attr = add_mi_attr(node, MI_DUP_VALUE, "REALM", 6, + (*gws)[i].realm, (*gws)[i].realm_len ); + if(attr == NULL) + return -1; + + attr = add_mi_attr(node, MI_DUP_VALUE, "PASSWD", 6, + (*gws)[i].passwd, (*gws)[i].passwd_len ); + if(attr == NULL) + return -1; } for (i = 0; i < MAX_NO_OF_LCRS; i++) { @@ -1184,6 +1350,9 @@ char ruri[MAX_URI_SIZE]; unsigned int i, j, k, index, addr, port, strip, gw_index, duplicated_gw, flags, have_rpid_avp; + char *user; + char *realm; + char *passwd; uri_type scheme; uri_transport transport; struct ip_addr address; @@ -1407,6 +1576,9 @@ transport = (*gws)[index].transport; flags = (*gws)[index].flags; strip = (*gws)[index].strip; + user = (*gws)[index].user; + realm = (*gws)[index].realm; + passwd = (*gws)[index].passwd; if (strip > ruri_user.len) { LM_ERR("Strip count of gw is too large <%u>\n", strip); goto skip; @@ -1476,6 +1648,25 @@ val.s = value; add_avp(gw_uri_avp_type|AVP_VAL_STR, gw_uri_avp, val); LM_DBG("Added gw_uri_avp <%.*s>\n", value.len, value.s); + + value.s = user; + value.len = strlen(value.s); + val.s = value; + add_avp(user_avp_type|AVP_VAL_STR, user_avp, val); + LM_DBG("Added user_avp <%.*s>\n", value.len, value.s); + + value.s = realm; + value.len = strlen(value.s); + val.s = value; + add_avp(realm_avp_type|AVP_VAL_STR, realm_avp, val); + LM_DBG("Added realm_avp <%.*s>\n", value.len, value.s); + + value.s = passwd; + value.len = strlen(value.s); + val.s = value; + add_avp(passwd_avp_type|AVP_VAL_STR, passwd_avp, val); + LM_DBG("Added passwd_avp <%.*s>\n", value.len, value.s); + skip: continue; } @@ -1558,7 +1749,8 @@ static int next_gw(struct sip_msg* _m, char* _s1, char* _s2) { int_str gw_uri_val, ruri_user_val, val; - struct usr_avp *gu_avp, *ru_avp; + int_str user_val, realm_val, passwd_val; + struct usr_avp *gu_avp, *ru_avp, *usr_avp, *rlm_avp, *pwd_avp; int rval; str new_ruri; char *at, *at_char, *strip_char, *endptr; @@ -1575,6 +1767,35 @@ gw_uri_val.s.len = gw_uri_val.s.len - (at - gw_uri_val.s.s); gw_uri_val.s.s = at; + /* Save gateway AVPs for use in script */ + usr_avp = search_first_avp(user_avp_type, user_avp, &user_val, 0); + rlm_avp = search_first_avp(realm_avp_type, realm_avp, &realm_val, 0); + pwd_avp = search_first_avp(passwd_avp_type, passwd_avp, &passwd_val, 0); + if (!usr_avp) { + LM_DBG("User AVP no set\n"); + return -1; + } + else { + add_avp(user_avp_type|AVP_VAL_STR, user_avp, user_val); + LM_DBG("Added user_avp <%.*s>\n", user_val.s.len, user_val.s.s); + } + if (!rlm_avp) { + LM_DBG("Realm AVP no set\n"); + return -1; + } + else { + add_avp(realm_avp_type|AVP_VAL_STR, realm_avp, realm_val); + LM_DBG("Added realm_avp <%.*s>\n", realm_val.s.len, realm_val.s.s); + } + if (!pwd_avp) { + LM_DBG("Passwd AVP no set\n"); + return -1; + } + else { + add_avp(passwd_avp_type|AVP_VAL_STR, passwd_avp, passwd_val); + LM_DBG("Added passwd_avp <%.*s>\n", passwd_val.s.len, passwd_val.s.s); + } + /* Create new Request-URI taking URI user from ruri_user AVP and other parts of from gateway URI AVP. */ ru_avp = search_first_avp(ruri_user_avp_type, ruri_user_avp, diff -r c5c55937e44c -r 733187d496d0 opensips/scripts/db_berkeley/opensips/gw --- a/opensips/scripts/db_berkeley/opensips/gw Wed Feb 10 21:14:04 2010 +0100 +++ b/opensips/scripts/db_berkeley/opensips/gw Wed Feb 10 21:21:24 2010 +0100 @@ -1,5 +1,5 @@ METADATA_COLUMNS -id(int) gw_name(str) grp_id(int) ip_addr(str) port(int) uri_scheme(int) transport(int) strip(int) tag(str) flags(int) +id(int) gw_name(str) grp_id(int) ip_addr(str) port(int) uri_scheme(int) transport(int) strip(int) tag(str) flags(int) user(str) realm(str) passwd(str) METADATA_KEY 1 METADATA_READONLY @@ -7,4 +7,4 @@ METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NULL|0 +NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NULL|0|NULL|NULL|NULL diff -r c5c55937e44c -r 733187d496d0 opensips/scripts/dbtext/opensips/gw --- a/opensips/scripts/dbtext/opensips/gw Wed Feb 10 21:14:04 2010 +0100 +++ b/opensips/scripts/dbtext/opensips/gw Wed Feb 10 21:21:24 2010 +0100 @@ -1,1 +1,1 @@ -id(int,auto) gw_name(string) grp_id(int) ip_addr(string) port(int,null) uri_scheme(int,null) transport(int,null) strip(int,null) tag(string,null) flags(int) +id(int,auto) gw_name(string) grp_id(int) ip_addr(string) port(int,null) uri_scheme(int,null) transport(int,null) strip(int,null) tag(string,null) flags(int) user(string,null) realm(string,null) passwd(string,null) diff -r c5c55937e44c -r 733187d496d0 opensips/scripts/mysql/lcr-create.sql --- a/opensips/scripts/mysql/lcr-create.sql Wed Feb 10 21:14:04 2010 +0100 +++ b/opensips/scripts/mysql/lcr-create.sql Wed Feb 10 21:21:24 2010 +0100 @@ -10,6 +10,9 @@ strip TINYINT UNSIGNED, tag CHAR(16) DEFAULT NULL, flags INT UNSIGNED DEFAULT 0 NOT NULL, + user CHAR(16) DEFAULT NULL, + realm CHAR(16) DEFAULT NULL, + passwd CHAR(16) DEFAULT NULL, CONSTRAINT gw_name_idx UNIQUE (gw_name) ) ENGINE=MyISAM; diff -r c5c55937e44c -r 733187d496d0 opensips/scripts/oracle/lcr-create.sql --- a/opensips/scripts/oracle/lcr-create.sql Wed Feb 10 21:14:04 2010 +0100 +++ b/opensips/scripts/oracle/lcr-create.sql Wed Feb 10 21:21:24 2010 +0100 @@ -10,6 +10,9 @@ strip NUMBER(5), tag VARCHAR2(16) DEFAULT NULL, flags NUMBER(10) DEFAULT 0 NOT NULL, + user VARCHAR2(16) DEFAULT NULL, + realm VARCHAR2(16) DEFAULT NULL, + passwd VARCHAR2(16) DEFAULT NULL, CONSTRAINT gw_gw_name_idx UNIQUE (gw_name) ); diff -r c5c55937e44c -r 733187d496d0 opensips/scripts/postgres/lcr-create.sql --- a/opensips/scripts/postgres/lcr-create.sql Wed Feb 10 21:14:04 2010 +0100 +++ b/opensips/scripts/postgres/lcr-create.sql Wed Feb 10 21:21:24 2010 +0100 @@ -10,6 +10,9 @@ strip SMALLINT, tag VARCHAR(16) DEFAULT NULL, flags INTEGER DEFAULT 0 NOT NULL, + user VARCHAR(16) DEFAULT NULL, + realm VARCHAR(16) DEFAULT NULL, + passwd VARCHAR(16) DEFAULT NULL, CONSTRAINT gw_gw_name_idx UNIQUE (gw_name) );