You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules_s/permissions/trusted.c

379 lines
8.6 KiB

/*
* $Id$
*
* allow_trusted related functions
*
* Copyright (C) 2003 Juha Heinanen
*
* This file is part of ser, a free SIP server.
*
* ser 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
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser 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:
* --------
* 2004-06-07 updated to the new DB api, moved reload_trusted_table (andrei)
* 2006-08-14: DB handlers are moved to permission.c (Miklos)
*/
#include <sys/types.h>
#include <regex.h>
#include <string.h>
#include "trusted.h"
#include "permissions.h"
#include "trusted_hash.h"
#include "../../config.h"
#include "../../lib/srdb2/db.h"
#include "../../ip_addr.h"
#include "../../mem/shm_mem.h"
#include "../../parser/msg_parser.h"
#include "../../parser/parse_from.h"
struct trusted_list ***hash_table = NULL; /* Pointer to current hash table pointer */
struct trusted_list **hash_table_1 = NULL; /* Pointer to hash table 1 */
struct trusted_list **hash_table_2 = NULL;; /* Pointer to hash table 2 */
/* DB commands to query and load the table */
static db_cmd_t *cmd_load_trusted = NULL;
static db_cmd_t *cmd_query_trusted = NULL;
/*
* Initialize data structures
*/
int init_trusted(void)
{
if (db_mode == ENABLE_CACHE) {
hash_table_1 = new_hash_table();
if (!hash_table_1) return -1;
hash_table_2 = new_hash_table();
if (!hash_table_2) goto error;
hash_table = (struct trusted_list ***)shm_malloc(sizeof(struct trusted_list **));
if (!hash_table) goto error;
*hash_table = hash_table_1;
if (reload_trusted_table() == -1) {
LOG(L_CRIT, "init_trusted(): Reload of trusted table failed\n");
goto error;
}
}
return 0;
error:
clean_trusted();
return -1;
}
/*
* Close connections and release memory
*/
void clean_trusted(void)
{
if (hash_table_1) {
free_hash_table(hash_table_1);
hash_table_1 = NULL;
}
if (hash_table_2) {
free_hash_table(hash_table_2);
hash_table_2 = NULL;
}
if (hash_table) {
shm_free(hash_table);
hash_table = NULL;
}
}
/* prepare the DB cmds */
int init_trusted_db(void)
{
db_fld_t load_res_cols[] = {
{.name = source_col, .type = DB_CSTR},
{.name = proto_col, .type = DB_CSTR},
{.name = from_col, .type = DB_CSTR},
{.name = NULL}
};
db_fld_t query_match[] = {
{.name = source_col, .type = DB_CSTR},
{.name = NULL}
};
db_fld_t query_res_cols[] = {
{.name = proto_col, .type = DB_CSTR},
{.name = from_col, .type = DB_CSTR},
{.name = NULL}
};
if (!db_conn) return -1;
if (db_mode == ENABLE_CACHE) {
cmd_load_trusted =
db_cmd(DB_GET, db_conn, trusted_table, load_res_cols, NULL, NULL);
if (!cmd_load_trusted)
goto error;
} else {
cmd_query_trusted =
db_cmd(DB_GET, db_conn, trusted_table, query_res_cols, query_match, NULL);
if (!cmd_query_trusted)
goto error;
}
return 0;
error:
LOG(L_ERR, "init_trusted_db(): failed to prepare DB commands\n");
return -1;
}
/* destroy the DB cmds */
void destroy_trusted_db(void)
{
if (cmd_load_trusted) {
db_cmd_free(cmd_load_trusted);
cmd_load_trusted = NULL;
}
if (cmd_query_trusted) {
db_cmd_free(cmd_query_trusted);
cmd_query_trusted = NULL;
}
}
/*
* Matches protocol string against the protocol of the request. Returns 1 on
* success and 0 on failure.
*/
static inline int match_proto(char *proto_string, int proto_int)
{
if (strcasecmp(proto_string, "any") == 0) return 1;
if (proto_int == PROTO_UDP) {
if (strcasecmp(proto_string, "udp") == 0) {
return 1;
} else {
return 0;
}
}
if (proto_int == PROTO_TCP) {
if (strcasecmp(proto_string, "tcp") == 0) {
return 1;
} else {
return 0;
}
}
if (proto_int == PROTO_TLS) {
if (strcasecmp(proto_string, "tls") == 0) {
return 1;
} else {
return 0;
}
}
if (proto_int == PROTO_SCTP) {
if (strcasecmp(proto_string, "sctp") == 0) {
return 1;
} else {
return 0;
}
}
LOG(L_ERR, "match_proto(): Unknown request protocol\n");
return 0;
}
#define VAL_NULL_STR(fld) ( \
((fld).flags & DB_NULL) \
|| (((fld).type == DB_CSTR) && ((fld).v.cstr[0] == '\0')) \
|| (((fld).type == DB_STR) && \
(((fld).v.lstr.len == 0) || ((fld).v.lstr.s[0] == '\0'))) \
)
/*
* Matches from uri against patterns returned from database. Returns 1 when
* first pattern matches and -1 if none of the patterns match.
*/
static int match_res(struct sip_msg* msg, db_res_t* _r)
{
str uri;
char uri_string[MAX_URI_SIZE+1];
db_rec_t *rec;
regex_t preg;
if (!_r) return -1;
if (parse_from_header(msg) < 0) return -1;
uri = get_from(msg)->uri;
if (uri.len > MAX_URI_SIZE) {
LOG(L_ERR, "match_res(): From URI too large\n");
return -1;
}
memcpy(uri_string, uri.s, uri.len);
uri_string[uri.len] = (char)0;
rec = db_first(_r);
while (rec) {
if (VAL_NULL_STR(rec->fld[0])
|| VAL_NULL_STR(rec->fld[1]))
goto next;
/* check the protocol */
if (match_proto(rec->fld[0].v.cstr, msg->rcv.proto) <= 0)
goto next;
/* check the from uri */
if (regcomp(&preg, rec->fld[1].v.cstr, REG_NOSUB)) {
LOG(L_ERR, "match_res(): Error in regular expression: %s\n",
rec->fld[0].v.cstr);
goto next;
}
if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
regfree(&preg);
goto next;
}
regfree(&preg);
/* everything matched */
return 1;
next:
rec = db_next(_r);
}
return -1;
}
/*
* Checks based on request's source address, protocol, and from field
* if request can be trusted without authentication. Possible protocol
* values are "any" (that matches any protocol), "tcp", "udp", "tls",
* and "sctp".
*/
int allow_trusted(struct sip_msg* _msg, char* str1, char* str2)
{
int result;
db_res_t *res = NULL;
if (!db_url) {
LOG(L_ERR, "allow_trusted(): ERROR set db_mode parameter of permissions module first !\n");
return -1;
}
if (db_mode == DISABLE_CACHE) {
if (!cmd_query_trusted) return -1;
if (!(cmd_query_trusted->match[0].v.cstr =
ip_addr2a(&(_msg->rcv.src_ip)))
) {
LOG(L_ERR, "allow_trusted(): Error in ip address\n");
return -1;
}
if (db_exec(&res, cmd_query_trusted) < 0) {
LOG(L_ERR, "allow_trusted(): Error while querying database\n");
return -1;
}
result = match_res(_msg, res);
if (res) db_res_free(res);
return result;
} else if (db_mode == ENABLE_CACHE) {
return match_hash_table(*hash_table, _msg);
} else {
LOG(L_ERR, "allow_trusted(): Error - set db_mode parameter of permissions module properly\n");
return -1;
}
}
/*
* Reload trusted table to new hash table and when done, make new hash table
* current one.
*/
int reload_trusted_table(void)
{
db_res_t *res = NULL;
db_rec_t *rec;
struct trusted_list **new_hash_table;
int row;
char *source, *proto, *from;
if (!cmd_load_trusted) return -1;
if (db_exec(&res, cmd_load_trusted) < 0) {
LOG(L_ERR, "ERROR: permissions: reload_trusted_table():"
" Error while querying database\n");
return -1;
}
/* Choose new hash table and free its old contents */
if (*hash_table == hash_table_1) {
empty_hash_table(hash_table_2);
new_hash_table = hash_table_2;
} else {
empty_hash_table(hash_table_1);
new_hash_table = hash_table_1;
}
row = 0;
rec = db_first(res);
while (rec) {
if (VAL_NULL_STR(rec->fld[0])
|| VAL_NULL_STR(rec->fld[1])
|| VAL_NULL_STR(rec->fld[2])) {
LOG(L_ERR, "ERROR: permissions: trusted_reload():"
" Database problem, NULL filed is not allowed\n");
goto error;
}
source = rec->fld[0].v.cstr;
proto = rec->fld[1].v.cstr;
from = rec->fld[2].v.cstr;
if (hash_table_insert(new_hash_table,
source,
proto,
from) == -1) {
LOG(L_ERR, "ERROR: permissions: "
"trusted_reload(): Hash table problem\n");
goto error;
}
DBG("Tuple <%s, %s, %s> inserted into trusted hash table\n",
source, proto, from);
row++;
rec = db_next(res);
}
DBG("Number of rows in trusted table: %d\n", row);
*hash_table = new_hash_table;
DBG("Trusted table reloaded successfully.\n");
if (res) db_res_free(res);
return 1;
error:
if (res) db_res_free(res);
return -1;
}