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.
415 lines
8.7 KiB
415 lines
8.7 KiB
/*
|
|
* Domain table related functions
|
|
*
|
|
* Copyright (C) 2002-2003 Juha Heinanen
|
|
*
|
|
* This file is part of sip-router, a free SIP server.
|
|
*
|
|
* sip-router 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
|
|
*
|
|
* sip-router 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.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "uid_domain_mod.h"
|
|
#include "hash.h"
|
|
#include "../../dprint.h"
|
|
#include "../../mem/shm_mem.h"
|
|
#include "../../lib/srdb2/db.h"
|
|
#include "../../ut.h"
|
|
|
|
|
|
/*
|
|
* Search the list of domains for domain with given did
|
|
*/
|
|
static domain_t* domain_search(domain_t* list, str* did)
|
|
{
|
|
while(list) {
|
|
if (list->did.len == did->len &&
|
|
!memcmp(list->did.s, did->s, did->len)) {
|
|
return list;
|
|
}
|
|
list = list->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Add a new domain name to did
|
|
*/
|
|
static int domain_add(domain_t* d, str* domain, unsigned int flags)
|
|
{
|
|
str* p1;
|
|
unsigned int* p2;
|
|
str dom;
|
|
|
|
if (!d || !domain) {
|
|
ERR("Invalid parameter value\n");
|
|
return -1;
|
|
}
|
|
|
|
dom.s = shm_malloc(domain->len);
|
|
if (!dom.s) goto error;
|
|
memcpy(dom.s, domain->s, domain->len);
|
|
dom.len = domain->len;
|
|
strlower(&dom);
|
|
|
|
p1 = (str*)shm_realloc(d->domain, sizeof(str) * (d->n + 1));
|
|
if (!p1) goto error;
|
|
p2 = (unsigned int*)shm_realloc(d->flags,
|
|
sizeof(unsigned int) * (d->n + 1));
|
|
if (!p2) goto error;
|
|
|
|
d->domain = p1;
|
|
d->domain[d->n] = dom;
|
|
d->flags = p2;
|
|
d->flags[d->n] = flags;
|
|
d->n++;
|
|
return 0;
|
|
|
|
error:
|
|
ERR("Unable to add new domain name (out of memory)\n");
|
|
if (dom.s) shm_free(dom.s);
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*
|
|
* Release all memory allocated for given domain structure
|
|
*/
|
|
static void free_domain(domain_t* d)
|
|
{
|
|
int i;
|
|
if (!d) return;
|
|
if (d->did.s) shm_free(d->did.s);
|
|
|
|
for(i = 0; i < d->n; i++) {
|
|
if (d->domain[i].s) shm_free(d->domain[i].s);
|
|
}
|
|
shm_free(d->domain);
|
|
shm_free(d->flags);
|
|
if (d->attrs) destroy_avp_list(&d->attrs);
|
|
shm_free(d);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Create a new domain structure which will initialy have
|
|
* one domain name
|
|
*/
|
|
static domain_t* new_domain(str* did, str* domain, unsigned int flags)
|
|
{
|
|
domain_t* d;
|
|
int_str name, val;
|
|
str name_s = STR_STATIC_INIT(AVP_DID);
|
|
|
|
d = (domain_t*)shm_malloc(sizeof(domain_t));
|
|
if (!d) goto error;
|
|
memset(d, 0, sizeof(domain_t));
|
|
d->did.s = shm_malloc(did->len);
|
|
if (!d->did.s) goto error;
|
|
memcpy(d->did.s, did->s, did->len);
|
|
d->did.len = did->len;
|
|
|
|
d->domain = (str*)shm_malloc(sizeof(str));
|
|
if (!d->domain) goto error;
|
|
d->domain[0].s = shm_malloc(domain->len);
|
|
if (!d->domain[0].s) goto error;
|
|
memcpy(d->domain[0].s, domain->s, domain->len);
|
|
d->domain[0].len = domain->len;
|
|
strlower(d->domain);
|
|
|
|
d->flags = (unsigned int*)shm_malloc(sizeof(unsigned int));
|
|
if (!d->flags) goto error;
|
|
d->flags[0] = flags;
|
|
d->n = 1;
|
|
|
|
/* Create an attribute containing did of the domain */
|
|
name.s = name_s;
|
|
val.s = *did;
|
|
if (add_avp_list(&d->attrs, AVP_CLASS_DOMAIN | AVP_NAME_STR | AVP_VAL_STR,
|
|
name, val) < 0) goto error;
|
|
|
|
return d;
|
|
|
|
error:
|
|
ERR("Unable to create new domain structure\n");
|
|
free_domain(d);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Release all memory allocated for entire domain list
|
|
*/
|
|
void free_domain_list(domain_t* list)
|
|
{
|
|
domain_t* ptr;
|
|
if (!list) return;
|
|
|
|
while(list) {
|
|
ptr = list;
|
|
list = list->next;
|
|
free_domain(ptr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Load attributes from domain_attrs table
|
|
*/
|
|
int db_load_domain_attrs(domain_t* d)
|
|
{
|
|
int_str name, v;
|
|
str avp_val;
|
|
db_res_t* res;
|
|
db_rec_t* rec;
|
|
unsigned short flags;
|
|
|
|
load_attrs_cmd->match[0].v.lstr = d->did;
|
|
|
|
if (db_exec(&res, load_attrs_cmd) < 0) {
|
|
ERR("Error while querying database\n");
|
|
return -1;
|
|
}
|
|
|
|
rec = db_first(res);
|
|
while(rec) {
|
|
if (rec->fld[0].flags & DB_NULL ||
|
|
rec->fld[1].flags & DB_NULL ||
|
|
rec->fld[3].flags & DB_NULL) {
|
|
ERR("Skipping row containing NULL entries\n");
|
|
goto skip;
|
|
}
|
|
|
|
if ((rec->fld[3].v.int4 & SRDB_LOAD_SER) == 0) goto skip;
|
|
|
|
/* Get AVP name */
|
|
name.s = rec->fld[0].v.lstr;
|
|
|
|
/* Test for NULL value */
|
|
if (rec->fld[2].flags & DB_NULL) {
|
|
avp_val.s = 0;
|
|
avp_val.len = 0;
|
|
} else {
|
|
avp_val = rec->fld[2].v.lstr;
|
|
}
|
|
|
|
flags = AVP_CLASS_DOMAIN | AVP_NAME_STR;
|
|
if (rec->fld[1].v.int4 == AVP_VAL_STR) {
|
|
/* String AVP */
|
|
v.s = avp_val;
|
|
flags |= AVP_VAL_STR;
|
|
} else {
|
|
/* Integer AVP */
|
|
str2int(&avp_val, (unsigned*)&v.n);
|
|
}
|
|
|
|
if (add_avp_list(&d->attrs, flags, name, v) < 0) {
|
|
ERR("Error while adding domain attribute %.*s to domain %.*s, "
|
|
"skipping\n", name.s.len, ZSW(name.s.s),
|
|
d->did.len, ZSW(d->did.s));
|
|
}
|
|
|
|
skip:
|
|
rec = db_next(res);
|
|
}
|
|
db_res_free(res);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Create domain list from domain table
|
|
*/
|
|
int load_domains(domain_t** dest)
|
|
{
|
|
db_res_t* res = NULL;
|
|
db_rec_t* rec;
|
|
unsigned int flags;
|
|
domain_t* d, *list;
|
|
|
|
list = 0;
|
|
|
|
if (db_exec(&res, load_domains_cmd) < 0) {
|
|
ERR("Error while querying database\n");
|
|
return -1;
|
|
}
|
|
|
|
rec = db_first(res);
|
|
|
|
while(rec) {
|
|
/* Do not assume that the database server performs any constrain
|
|
* checking (dbtext does not) and perform sanity checks here to
|
|
* make sure that we only load good entried
|
|
*/
|
|
if (rec->fld[0].flags & DB_NULL ||
|
|
rec->fld[1].flags & DB_NULL ||
|
|
rec->fld[2].flags & DB_NULL) {
|
|
ERR("Row with NULL column(s), skipping\n");
|
|
goto skip;
|
|
}
|
|
|
|
flags = rec->fld[2].v.int4;
|
|
|
|
/* Skip entries that are disabled/scheduled for removal */
|
|
if (flags & SRDB_DISABLED) goto skip;
|
|
/* Skip entries that are for serweb/ser-ctl only */
|
|
if (!(flags & SRDB_LOAD_SER)) goto skip;
|
|
|
|
DBG("Processing entry (%.*s, %.*s, %u)\n",
|
|
rec->fld[0].v.lstr.len, ZSW(rec->fld[0].v.lstr.s),
|
|
rec->fld[1].v.lstr.len, ZSW(rec->fld[1].v.lstr.s),
|
|
flags);
|
|
|
|
d = domain_search(list, &rec->fld[0].v.lstr);
|
|
if (d) {
|
|
/* DID exists in the list, update it */
|
|
if (domain_add(d, &rec->fld[1].v.lstr, flags) < 0) goto error;
|
|
} else {
|
|
/* DID does not exist yet, create a new entry */
|
|
d = new_domain(&rec->fld[0].v.lstr, &rec->fld[1].v.lstr, flags);
|
|
if (!d) goto error;
|
|
d->next = list;
|
|
list = d;
|
|
}
|
|
|
|
skip:
|
|
rec = db_next(res);
|
|
}
|
|
|
|
db_res_free(res);
|
|
|
|
if (load_domain_attrs) {
|
|
d = list;
|
|
while(d) {
|
|
if (db_load_domain_attrs(d) < 0) goto error;
|
|
d = d->next;
|
|
}
|
|
}
|
|
|
|
*dest = list;
|
|
return 0;
|
|
|
|
error:
|
|
if (res) db_res_free(res);
|
|
free_domain_list(list);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Retrieve did directly from database, without using memory cache. Use 0 as
|
|
* the value of first parameter if you only want to know whether the entry is
|
|
* in the database. The function returns 1 if there is such entry, 0 if not,
|
|
* and -1 on error. The result is allocated using pkg_malloc and must be
|
|
* freed.
|
|
*/
|
|
int db_get_did(str* did, str* domain)
|
|
{
|
|
db_res_t* res = NULL;
|
|
db_rec_t* rec;
|
|
|
|
if (!domain) {
|
|
ERR("BUG:Invalid parameter value\n");
|
|
goto err;
|
|
}
|
|
|
|
get_did_cmd->match[0].v.lstr = *domain;
|
|
|
|
if (db_exec(&res, get_did_cmd) < 0) {
|
|
ERR("Error in database query\n");
|
|
goto err;
|
|
}
|
|
|
|
rec = db_first(res);
|
|
if (rec) {
|
|
/* Test flags first, we are only interested in rows
|
|
* that are not disabled
|
|
*/
|
|
if (rec->fld[1].flags & DB_NULL || (rec->fld[1].v.bitmap &
|
|
SRDB_DISABLED)) {
|
|
db_res_free(res);
|
|
return 0;
|
|
}
|
|
|
|
if (did) {
|
|
if (rec->fld[0].flags & DB_NULL) {
|
|
did->len = 0;
|
|
did->s = 0;
|
|
WARN("Domain '%.*s' has NULL did\n",
|
|
domain->len, ZSW(domain->s));
|
|
} else {
|
|
did->s = pkg_malloc(rec->fld[0].v.lstr.len);
|
|
if (!did->s) {
|
|
ERR("No memory left\n");
|
|
goto err;
|
|
}
|
|
memcpy(did->s, rec->fld[0].v.lstr.s, rec->fld[0].v.lstr.len);
|
|
did->len = rec->fld[0].v.lstr.len;
|
|
}
|
|
}
|
|
|
|
db_res_free(res);
|
|
return 1;
|
|
} else {
|
|
db_res_free(res);
|
|
return 0;
|
|
}
|
|
|
|
err:
|
|
if (res) db_res_free(res);
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* Check if the domain name given in the parameter is one
|
|
* of the locally configured domain names.
|
|
* Returns 1 if yes and -1 otherwise
|
|
*/
|
|
int is_domain_local(str* domain)
|
|
{
|
|
str tmp;
|
|
|
|
/* Make a temporary copy, domain name comparisons are always
|
|
* case insensitive
|
|
*/
|
|
tmp.s = pkg_malloc(domain->len);
|
|
if (!tmp.s) {
|
|
ERR("No memory left\n");
|
|
return -1;
|
|
}
|
|
memcpy(tmp.s, domain->s, domain->len);
|
|
tmp.len = domain->len;
|
|
strlower(&tmp);
|
|
|
|
if (!db_mode) {
|
|
switch(db_get_did(0, &tmp)) {
|
|
case 1: goto found;
|
|
default: goto not_found;
|
|
}
|
|
} else {
|
|
if (hash_lookup(0, *active_hash, &tmp) == 1) goto found;
|
|
else goto not_found;
|
|
}
|
|
|
|
found:
|
|
pkg_free(tmp.s);
|
|
return 1;
|
|
not_found:
|
|
pkg_free(tmp.s);
|
|
return -1;
|
|
}
|