#include <string.h>
#include <stdlib.h>
#include "../../ut.h"
#include "../../str.h"
#include "../../db/db.h"
#include "../../dprint.h"
#include "../../parser/digest/digest.h"
#include "../../parser/parse_from.h"
#include "../../parser/parse_uri.h"
#include "../../parser/hf.h"
#include "../../parser/parser_f.h"
#include "../../usr_avp.h"
#include "../../mem/mem.h"
#include "authdb_mod.h"
#include "rfc2617.h"
#define MESSAGE_500 "Server Internal Error"
#define MOUNT_COL "Amount"
#define MOUNT_COL_LEN (sizeof(MOUNT_COL)-1)
#define STATUS_COL "Status"
#define STATUS_COL_LEN (sizeof(STATUS_COL)-1)
#define ACCT_CODE_COL "ACCT_CODE"
#define ACCT_CODE_COL_LEN (sizeof(ACCT_CODE_COL)-1)
#define AGENT_CODE "Agent_Code"
#define AGENT_CODE_LEN (sizeof(AGENT_CODE)-1)
#define ROOT_AGENT "Agent_Code_Root"
#define ROOT_AGENT_LEN (sizeof(ROOT_AGENT)-1)
#define CARDNO "Card_No"
#define CARDNOLEN (sizeof(CARDNO)-1)
#define DOMAIN "domain"
#define DOMAINLEN (sizeof(DOMAIN)-1)
#define LOCALDOMAIN "
xtox.org"
static db_con_t* db_handle=0; /* database connection handle */
static db_func_t auth_dbf;
/************************************************************
get user agent a mount from CASH_ACCT_INTO table
select Amount,Status from CASH_ACCT_INFO where acct_code = '10agent';
select Amount,Status from CASH_ACCT_INFO where acct_code_root = '10agentroor'
**********************************************************/
static inline int getagentmount(str agent)
{
db_key_t key[1];
db_val_t val[1];
db_key_t* col;
db_res_t* res;
double mount=0.0;
int status=3;
int n,nc;
str acct_code = {ACCT_CODE_COL,ACCT_CODE_COL_LEN}; //CASH_ACCT_INFO.ACCT_CODE
str mount_col = {MOUNT_COL,MOUNT_COL_LEN};//CASH_ACCT_INFO.Amount
str status_col = {STATUS_COL,STATUS_COL_LEN};//CASH_ACCT_INFO.Status
col = pkg_malloc(sizeof(*col)*2);
if(col == NULL)
{
return -1;
}
col[0] = mount_col.s;
col[1] = status_col.s;
key[0] = acct_code.s;
char agentcode[2000];
bzero(agentcode,sizeof(agentcode));
strcpy(agentcode,"1000");
strncat(agentcode,agent.s,agent.len);
VAL_TYPE(val) = DB_STR;
VAL_NULL(val) = 0;
VAL_STR(val).s = (char*)agentcode;
VAL_STR(val).len = strlen(agentcode);
n=1;
nc=2;
if (auth_dbf.use_table(db_handle, "CASH_ACCT_INFO") < 0) {
pkg_free(col);
return -1;
}
if (auth_dbf.query(db_handle, key, 0, val, col, n, nc, 0, &res) < 0) {
pkg_free(col);
auth_dbf.free_result(db_handle,res);
return -1;
}
if ((RES_ROW_N(res) == 0)) {
pkg_free(col);
auth_dbf.free_result(db_handle,res);
return 1;
}
pkg_free(col);
mount = ROW_VALUES(RES_ROWS(res))[0].val.double_val;
status = ROW_VALUES(RES_ROWS(res))[1].val.int_val;
if((mount > 1)&&(status>0))
{
auth_dbf.free_result(db_handle,res);
return 2;
}
auth_dbf.free_result(db_handle,res);
return 0;
}
/*************************************************************
get username from tblDOMAIN_ACCT
Function name:getusername
Parameters:
str domain[in];
char* acct[in/out]:if get acct ,stored in this field
Return Value:
if find domain from tblDOMAIN_ACCT AND GetAccount return 1;
if find no acct return 0;
IF SOME ERROR OCCORS RETURN -1;
***********************************************************/
static inline int getusername(char* domain,char* acct)
{
db_key_t key[1];
db_val_t val[1];
db_key_t *col;
db_res_t *res;
str cardnocol = {CARDNO,CARDNOLEN};
str domaincol = {DOMAIN,DOMAINLEN};
col = pkg_malloc(sizeof(*col) * 1);//only one column (Card_No) to select from tblDOMAIN_ACCT
if(col == NULL)
{
return -1;
}
col[0] = cardnocol.s;
key[0] = domaincol.s;
VAL_TYPE(val) = DB_STR;
VAL_NULL(val) = 0;
VAL_STR(val).s = domain;
VAL_STR(val).len = strlen(domain);
if (auth_dbf.use_table(db_handle, "tblDOMAIN_ACCT") < 0) {
pkg_free(col);
return -1;
}
if (auth_dbf.query(db_handle, key, 0, val, col, 1, 1, 0, &res) < 0) {
pkg_free(col);
return -1;
}
if ((RES_ROW_N(res) == 0)) {
pkg_free(col);
auth_dbf.free_result(db_handle,res);
return 0;
}
pkg_free(col);
strcpy(acct,(char*)ROW_VALUES(RES_ROWS(res))[0].val.string_val);
auth_dbf.free_result(db_handle,res);
return 1;
}
/**************************************************************
get user amount from CASH_ACCT_INFO table
it's sql is
select amount,status,Agent_Code,Agent_Code_Root from CASH_ACCT_INFO where acct_code = '20user'
************************************************************/
static inline int getmount(/*str username*/char* username,char* agent,char* agentroot)
{
db_key_t key[1];
db_val_t val[1];
db_key_t* col;
db_res_t* res;
double mount;
int n,nc;
int status;
str mount_col = {MOUNT_COL,MOUNT_COL_LEN};//CASH_ACCT_INFO.AMOUNT
str status_col = {STATUS_COL,STATUS_COL_LEN};//CASH_ACCT_INFO.Status
str acct_code = {ACCT_CODE_COL,ACCT_CODE_COL_LEN}; //CASH_ACCT_INFO.ACCT_CODE
str agent_code = {AGENT_CODE,AGENT_CODE_LEN};//CASH_ACCT_INFO.Agent_Code
str root_agent = {ROOT_AGENT,ROOT_AGENT_LEN};//CASH_ACCT_INFO.Agent_Code_Root
col = pkg_malloc(sizeof(*col) * 4 );//4 column to select Amout,Status,Agent_Code,Agent_Code_Root
if (col == NULL) {
LOG(L_ERR, "getmount: Error while allocating memory\n");
return -1;
}
col[0] = mount_col.s;
col[1] = status_col.s;
col[2] = agent_code.s;
col[3] = root_agent.s;
key[0] = acct_code.s;
char user[2500];
bzero(user,sizeof(user));
strcpy(user,"2000");
strcat(user,username);
VAL_TYPE(val) = DB_STR;
VAL_NULL(val) = 0;
VAL_STR(val).s = (char*)user;
VAL_STR(val).len = strlen(user);
n = 1;
//nc = credentials_n + 1;
nc = 4;
if (auth_dbf.use_table(db_handle, "CASH_ACCT_INFO") < 0) {
pkg_free(col);
return -1;
}
if (auth_dbf.query(db_handle, key, 0, val, col, n, nc, 0, &res) < 0) {
pkg_free(col);
return -1;
}
if ((RES_ROW_N(res) == 0)) {
pkg_free(col);
auth_dbf.free_result(db_handle,res);
return 1;
}
pkg_free(col);
mount = ROW_VALUES(RES_ROWS(res))[0].val.double_val;
status = ROW_VALUES(RES_ROWS(res))[1].val.int_val;
if((mount > 1)&&(status>0))
{
str agent1,agentroot1;
agent1.s = (char*)ROW_VALUES(RES_ROWS(res))[2].val.string_val;
agent1.len = strlen(agent1.s);
agentroot1.s = (char*)ROW_VALUES(RES_ROWS(res))[3].val.string_val;
agentroot1.len = strlen(agentroot1.s);
strncpy(agent,agent1.s,agent1.len);
strncpy(agentroot,agentroot1.s,agentroot1.len);
auth_dbf.free_result(db_handle,res);
return 2;
}
else
{
auth_dbf.free_result(db_handle,res);
return 0;
}
}
/*
* Calculate the response and compare with the given response string
* Authorization is successful if this two strings are same
*/
static inline int check_response(dig_cred_t* _cred, str* _method, char* _ha1)
{
HASHHEX resp, hent;
/*
* First, we have to verify that the response received has
* the same length as responses created by us
*/
if (_cred->response.len != 32) {
DBG("check_response(): Receive response len != 32\n");
return 1;
}
/*
* Now, calculate our response from parameters received
* from the user agent
*/
calc_response(_ha1, &(_cred->nonce),
&(_cred->nc), &(_cred->cnonce),
&(_cred->
qop.qop_str), _cred->qop.qop_parsed == QOP_AUTHINT,
_method, &(_cred->uri), hent, resp);
DBG("check_response(): Our result = \'%s\'\n", resp);
/*
* And simply compare the strings, the user is
* authorized if they match
*/
if (!memcmp(resp, _cred->response.s, 32)) {
DBG("check_response(): Authorization is OK\n");
return 0;
} else {
DBG("check_response(): Authorization failed\n");
return 2;
}
}
/*
* Authorize digest credentials
*/
static inline int authorize(struct sip_msg* _m, str* _realm, char* _table, int _hftype)
{
char ha1[256];
int res, i;
struct hdr_field* h;
auth_body_t* cred;
auth_result_t ret;
str domain, value;
int_str iname, ivalue;
db_res_t* result;
str rpid;
domain = *_realm;
ret = pre_auth_func(_m, &domain, _hftype, &h);
switch(ret) {
case ERROR: return 0;
case NOT_AUTHORIZED: return -1;
case DO_AUTHORIZATION: break;
case AUTHORIZED: return 1;
}
str furi;
struct sip_uri puri;
if(parse_from_header(_m)<0)
{
return -1;
}
furi = get_from(_m)->uri;
if(parse_uri(furi.s,furi.len,&puri) < 0)
{
return -1;
}
char msgdomain[2055];
bzero(msgdomain,sizeof(msgdomain));
strncpy(msgdomain,puri.host.s,puri.host.len);
int m,len;
int p=0;
len=strlen(msgdomain);
for(m=0;m<len;m++)
{
if(msgdomain[m]!='@')
msgdomain[p++]=msgdomain[m];
}
msgdomain[p]='\0';
cred = (auth_body_t*)h->parsed;
char acct[2000];
bzero(acct,sizeof(acct));
struct username* tmp = &cred->digest.username;
if(strncmp(msgdomain,domain.s,strlen(msgdomain)))//domain is not local domain
{
if((res = getusername(msgdomain,acct)) == 1)
{
tmp->user.s = (char*)acct;
tmp->user.len = strlen(acct);
}
else
{
return -1;
}
}
else
{
strncpy(acct,tmp->
user.s,tmp->user.len);
}
res = get_ha1(tmp, &domain, _table, ha1, &result);
//res = get_ha1(&cred->digest.username, &domain, _table, ha1, &result);
if (res < 0) {
/* Error while accessing the database */
if (sl_reply(_m, (char*)500, MESSAGE_500) == -1) {
LOG(L_ERR, "authorize(): Error while sending 500 reply\n");
}
return 0;
}
if (res > 0) {
/* Username not found in the database */
auth_dbf.free_result(db_handle, result);
return -1;
}
char agent[2000],agentroot[2000];
bzero(agent,sizeof(agent));
bzero(agentroot,sizeof(agentroot));
res = getmount(acct,agent,agentroot);
if(res < 0)
{
auth_dbf.free_result(db_handle, result);
return 0;
}
if(res == 0)
{
auth_dbf.free_result(db_handle, result);
return -1;
}
if(res == 1)
{
auth_dbf.free_result(db_handle, result);
return -1;
}
if(res == 2)
{
str ll,ss;
ll.s = (char*)agent;
ll.len = strlen(ll.s);
ss.s = (char*)agentroot;
ss.len = strlen(ss.s);
if(getagentmount(ll) != 2)
{
auth_dbf.free_result(db_handle, result);
return -1;
}
if(strcmp(agent,agentroot))
{
if(getagentmount(ss) != 2)
{
auth_dbf.free_result(db_handle, result);
return -1;
}
}
}
/* Recalculate response, it must be same to authorize successfully */
if (!check_response(&(cred->digest), &_m->first_line.u.request.method, ha1)) {
rpid.s = NULL;
rpid.len = 0;
for (i = 0; i < avps_str_n; i++) {
if (avps_str[i].len != 4
|| VAL_NULL(&(result->rows[0].values[1 + avps_int_n + i]))
|| memcmp(avps_str[i].s, "rpid", 4) != 0)
continue;
rpid.s = (char*)VAL_STRING(&(result->rows[0].values[1 + avps_int_n + i]));
if(rpid.s!=NULL)
rpid.len = strlen(rpid.s);
}
ret = post_auth_func(_m, h, &rpid);
switch(ret) {
case ERROR:
auth_dbf.free_result(db_handle, result);
return 0;
case NOT_AUTHORIZED:
auth_dbf.free_result(db_handle, result);
return -1;
case AUTHORIZED:
for (i = 0; i < avps_int_n; i++) {
if(VAL_NULL(&(result->rows[0].values[1 + i])))
continue;
iname.s = &(avps_int[i]);
ivalue.n = VAL_INT(&(result->rows[0].values[1 + i]));
add_avp(AVP_NAME_STR, iname, ivalue);
DBG("authorize(): set integer AVP \'%.*s = %d\'\n",
iname.s->len, ZSW(iname.s->s), ivalue.n);
}
for (i = 0; i < avps_str_n; i++) {
value.s = (char*)VAL_STRING(&(result->rows[0].values[1 + avps_int_n + i]));
if(VAL_NULL(&(result->rows[0].values[1 + avps_int_n + i]))
|| value.s==NULL)
continue;
iname.s = &(avps_str[i]);
value.len = strlen(value.s);
ivalue.s = &value;
add_avp(AVP_NAME_STR | AVP_VAL_STR, iname, ivalue);
DBG("authorize(): set string AVP \'%.*s = %.*s\'\n",
iname.s->len, ZSW(iname.s->s), value.len, ZSW(value.s));
}
auth_dbf.free_result(db_handle, result);
return 1;
default:
auth_dbf.free_result(db_handle, result);
return -1;
}
}
auth_dbf.free_result(db_handle, result);
return -1;
}
/*
* Authorize using Proxy-Authorize header field
*/
int proxy_authorize(struct sip_msg* _m, char* _realm, char* _table)
{
/* realm parameter is converted to str* in str_fixup */
return authorize(_m, (str*)_realm, _table, HDR_PROXYAUTH);
}
/*
* Authorize using WWW-Authorize header field
*/
int www_authorize(struct sip_msg* _m, char* _realm, char* _table)
{
return authorize(_m, (str*)_realm, _table, HDR_AUTHORIZATION);
}
int auth_db_init(char* db_url)
{
if (auth_dbf.init==0){
LOG(L_CRIT, "BUG: auth_db_bind: null dbf\n");
goto error;
}
db_handle=auth_dbf.init(db_url);
if (db_handle==0){
LOG(L_ERR, "ERROR: auth_db_bind: unable to connect to the database\n");
goto error;
}
return 0;
error:
return -1;
}
int auth_db_bind(char* db_url)
{
if (bind_dbmod(db_url, &auth_dbf)<0){
LOG(L_ERR, "ERROR: auth_db_bind: unable to bind to the database"
" module\n");
return -1;
}
return 0;
}
void auth_db_close()
{
if (db_handle && auth_dbf.close){
auth_dbf.close(db_handle);
db_handle=0;
}
}
int auth_db_ver(char* db_url, str* name)
{
db_con_t* dbh;
int ver;
if (auth_dbf.init==0){
LOG(L_CRIT, "BUG: auth_db_ver: unbound database\n");
return -1;
}
dbh=auth_dbf.init(db_url);
if (dbh==0){
LOG(L_ERR, "ERROR: auth_db_ver: unable to open database connection\n");
return -1;
}
ver=table_version(&auth_dbf, dbh, name);
auth_dbf.close(dbh);
return ver;
}
##########################################################