mirror of https://github.com/sipwise/kamailio.git
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.
379 lines
8.6 KiB
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;
|
|
}
|