uid_domain_mod.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * Domain module
  3. *
  4. * Copyright (C) 2002-2003 Juha Heinanen
  5. *
  6. * This file is part of sip-router, a free SIP server.
  7. *
  8. * sip-router is free software; you can redistribute it and/or modify it under
  9. * the terms of the GNU General Public License as published by the Free
  10. * Software Foundation; either version 2 of the License, or (at your option)
  11. * any later version
  12. *
  13. * sip-router is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. * more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * History:
  23. * -------
  24. * 2003-03-11: New module interface (janakj)
  25. * 2003-03-16: flags export parameter added (janakj)
  26. * 2003-04-05: default_uri #define used (jiri)
  27. * 2003-04-06: db connection closed in mod_init (janakj)
  28. * 2004-06-06 updated to the new DB api, cleanup: static dbf & handler,
  29. * calls to domain_db_{bind,init,close,ver} (andrei)
  30. */
  31. #include "uid_domain_mod.h"
  32. #include <stdio.h>
  33. #include "../../mem/shm_mem.h"
  34. #include "../../mem/mem.h"
  35. #include "../../sr_module.h"
  36. #include "../../ut.h"
  37. #include "../../parser/parse_from.h"
  38. #include "../../parser/parse_uri.h"
  39. #include "../../usr_avp.h"
  40. #include "domain_api.h"
  41. #include "domain_rpc.h"
  42. #include "hash.h"
  43. #include "domain.h"
  44. /*
  45. * Module management function prototypes
  46. */
  47. static int mod_init(void);
  48. static void destroy(void);
  49. static int child_init(int rank);
  50. static int is_local(struct sip_msg* msg, char* s1, char* s2);
  51. static int lookup_domain(struct sip_msg* msg, char* s1, char* s2);
  52. static int get_did(str* did, str* domain);
  53. static int lookup_domain_fixup(void** param, int param_no);
  54. MODULE_VERSION
  55. /*
  56. * Version of domain table required by the module, increment this value if you
  57. * change the table in an backwards incompatible way
  58. */
  59. #define DOMAIN_TABLE_VERSION 2
  60. #define DOMATTR_TABLE_VERSION 1
  61. #define DOMAIN_TABLE "uid_domain"
  62. #define DOMAIN_COL "domain"
  63. #define DID_COL "did"
  64. #define FLAGS_COL "flags"
  65. #define DOMATTR_TABLE "uid_domain_attrs"
  66. #define DOMATTR_DID "did"
  67. #define DOMATTR_NAME "name"
  68. #define DOMATTR_TYPE "type"
  69. #define DOMATTR_VALUE "value"
  70. #define DOMATTR_FLAGS "flags"
  71. #define DOMAIN_COL "domain"
  72. int db_mode = 1; /* Enable/disable domain cache */
  73. /*
  74. * Module parameter variables
  75. */
  76. static str db_url = STR_STATIC_INIT(DEFAULT_RODB_URL);
  77. str domain_table = STR_STATIC_INIT(DOMAIN_TABLE); /* Name of domain table */
  78. str domain_col = STR_STATIC_INIT(DOMAIN_COL); /* Name of domain column */
  79. str did_col = STR_STATIC_INIT(DID_COL); /* Domain id */
  80. str flags_col = STR_STATIC_INIT(FLAGS_COL); /* Domain flags */
  81. str domattr_table = STR_STATIC_INIT(DOMATTR_TABLE);
  82. str domattr_did = STR_STATIC_INIT(DOMATTR_DID);
  83. str domattr_name = STR_STATIC_INIT(DOMATTR_NAME);
  84. str domattr_type = STR_STATIC_INIT(DOMATTR_TYPE);
  85. str domattr_value = STR_STATIC_INIT(DOMATTR_VALUE);
  86. str domattr_flags = STR_STATIC_INIT(DOMATTR_FLAGS);
  87. int load_domain_attrs = 0; /* Load attributes for each domain by default */
  88. static db_ctx_t* db = NULL;
  89. db_cmd_t* load_domains_cmd = NULL, *get_did_cmd = NULL, *load_attrs_cmd = NULL;
  90. struct hash_entry*** active_hash = 0; /* Pointer to current hash table */
  91. struct hash_entry** hash_1 = 0; /* Pointer to hash table 1 */
  92. struct hash_entry** hash_2 = 0; /* Pointer to hash table 2 */
  93. domain_t** domains_1 = 0; /* List of domains 1 */
  94. domain_t** domains_2 = 0; /* List of domains 2 */
  95. /* Global domain structure, this one is used to store data retrieved from
  96. * database when memory cache is disabled. There is one buffer for from and
  97. * one buffer for to track.
  98. */
  99. static domain_t dom_buf[2];
  100. /*
  101. * Exported functions
  102. */
  103. static cmd_export_t cmds[] = {
  104. {"is_local", is_local, 1, fixup_var_str_1,
  105. REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
  106. {"lookup_domain", lookup_domain, 2, lookup_domain_fixup,
  107. REQUEST_ROUTE|FAILURE_ROUTE },
  108. {"get_did", (cmd_function)get_did, 0, 0, 0},
  109. {"bind_domain", (cmd_function)bind_domain, 0, 0, 0},
  110. {0, 0, 0, 0, 0}
  111. };
  112. /*
  113. * Exported parameters
  114. */
  115. static param_export_t params[] = {
  116. {"db_url", PARAM_STR, &db_url },
  117. {"db_mode", PARAM_INT, &db_mode },
  118. {"domain_table", PARAM_STR, &domain_table },
  119. {"domain_col", PARAM_STR, &domain_col },
  120. {"did_col", PARAM_STR, &did_col },
  121. {"flags_col", PARAM_STR, &flags_col },
  122. {"domattr_table", PARAM_STR, &domattr_table },
  123. {"domattr_did", PARAM_STR, &domattr_did },
  124. {"domattr_name", PARAM_STR, &domattr_name },
  125. {"domattr_type", PARAM_STR, &domattr_type },
  126. {"domattr_value", PARAM_STR, &domattr_value },
  127. {"domattr_flags", PARAM_STR, &domattr_flags },
  128. {"load_domain_attrs", PARAM_INT, &load_domain_attrs},
  129. {0, 0, 0}
  130. };
  131. /*
  132. * Module interface
  133. */
  134. struct module_exports exports = {
  135. "uid_domain",
  136. cmds, /* Exported functions */
  137. domain_rpc, /* RPC methods */
  138. params, /* Exported parameters */
  139. mod_init, /* module initialization function */
  140. 0, /* response function*/
  141. destroy, /* destroy function */
  142. 0, /* cancel function */
  143. child_init /* per-child init function */
  144. };
  145. static int init_db(void)
  146. {
  147. db_fld_t load_domains_columns[] = {
  148. {.name = did_col.s, DB_STR},
  149. {.name = domain_col.s, DB_STR},
  150. {.name = flags_col.s, DB_BITMAP},
  151. {.name = NULL}
  152. };
  153. db_fld_t get_did_columns[] = {
  154. {.name = did_col.s, DB_STR},
  155. {.name = NULL}
  156. };
  157. db_fld_t load_attrs_columns[] = {
  158. {.name = domattr_name.s, .type = DB_STR},
  159. {.name = domattr_type.s, .type = DB_INT},
  160. {.name = domattr_value.s, .type = DB_STR},
  161. {.name = domattr_flags.s, .type = DB_BITMAP},
  162. {.name = NULL}
  163. };
  164. db_fld_t get_did_match[] = {
  165. {.name = domain_col.s, DB_STR},
  166. {.name = NULL}
  167. };
  168. db_fld_t load_attrs_match[] = {
  169. {.name = domattr_did.s, .type = DB_STR},
  170. {.name = NULL}
  171. };
  172. db = db_ctx("domain");
  173. if (db == NULL) {
  174. ERR("Error while initializing database layer\n");
  175. return -1;
  176. }
  177. if (db_add_db(db, db_url.s) < 0) return -1;
  178. if (db_connect(db) < 0) return -1;
  179. DBG("prepare load_domains_cmd\n");
  180. load_domains_cmd = db_cmd(DB_GET, db, domain_table.s, load_domains_columns,
  181. NULL, NULL);
  182. if (load_domains_cmd == NULL) {
  183. ERR("Error while preparing load_domains database command\n");
  184. return -1;
  185. }
  186. DBG("prepare get_did_cmd\n");
  187. get_did_cmd = db_cmd(DB_GET, db, domain_table.s, get_did_columns,
  188. get_did_match, NULL);
  189. if (get_did_cmd == NULL) {
  190. ERR("Error while preparing get_did database command\n");
  191. return -1;
  192. }
  193. if (load_domain_attrs) {
  194. DBG("prepare load_attrs_cmd\n");
  195. load_attrs_cmd = db_cmd(DB_GET, db, domattr_table.s,
  196. load_attrs_columns, load_attrs_match, NULL);
  197. if (load_attrs_cmd == NULL) {
  198. ERR("Error while preparing load_attrs database command\n");
  199. return -1;
  200. }
  201. }
  202. return 0;
  203. }
  204. static int allocate_tables(void)
  205. {
  206. active_hash = (struct hash_entry***)shm_malloc(sizeof(struct hash_entry**));
  207. hash_1 = (struct hash_entry**)shm_malloc(sizeof(struct hash_entry*)
  208. * HASH_SIZE);
  209. hash_2 = (struct hash_entry**)shm_malloc(sizeof(struct hash_entry*)
  210. * HASH_SIZE);
  211. domains_1 = (domain_t**)shm_malloc(sizeof(domain_t*));
  212. domains_2 = (domain_t**)shm_malloc(sizeof(domain_t*));
  213. if (!hash_1 || !hash_2 || !active_hash || !domains_1 || !domains_2) {
  214. ERR("No memory left\n");
  215. return -1;
  216. }
  217. memset(hash_1, 0, sizeof(struct hash_entry*) * HASH_SIZE);
  218. memset(hash_2, 0, sizeof(struct hash_entry*) * HASH_SIZE);
  219. *active_hash = hash_1;
  220. *domains_1 = 0;
  221. *domains_2 = 0;
  222. return 0;
  223. }
  224. static void destroy_tables(void)
  225. {
  226. free_table(hash_1);
  227. free_table(hash_2);
  228. if (active_hash) shm_free(active_hash);
  229. if (domains_1) {
  230. free_domain_list(*domains_1);
  231. shm_free(domains_1);
  232. }
  233. if (domains_2) {
  234. free_domain_list(*domains_2);
  235. shm_free(domains_2);
  236. }
  237. }
  238. static int mod_init(void)
  239. {
  240. /* Check if cache needs to be loaded from domain table */
  241. if (db_mode) {
  242. if (init_db() < 0) goto error;
  243. if (allocate_tables() < 0) goto error;
  244. if (reload_domain_list() < 0) goto error;
  245. db_cmd_free(load_domains_cmd);
  246. load_domains_cmd = NULL;
  247. db_cmd_free(load_attrs_cmd);
  248. load_attrs_cmd = NULL;
  249. db_cmd_free(get_did_cmd);
  250. get_did_cmd = NULL;
  251. if (db) db_disconnect(db);
  252. db_ctx_free(db);
  253. db = NULL;
  254. }
  255. return 0;
  256. error:
  257. if (get_did_cmd) {
  258. db_cmd_free(get_did_cmd);
  259. get_did_cmd = NULL;
  260. }
  261. if (load_domains_cmd) {
  262. db_cmd_free(load_domains_cmd);
  263. load_domains_cmd = NULL;
  264. }
  265. if (load_attrs_cmd) {
  266. db_cmd_free(load_attrs_cmd);
  267. load_attrs_cmd = NULL;
  268. }
  269. if (db) db_disconnect(db);
  270. db_ctx_free(db);
  271. db = NULL;
  272. return -1;
  273. }
  274. static int child_init(int rank)
  275. {
  276. /* Check if database is needed by child */
  277. if (rank > 0 || rank == PROC_RPC || rank == PROC_UNIXSOCK) {
  278. if (init_db() < 0) return -1;
  279. }
  280. return 0;
  281. }
  282. static void free_old_domain(domain_t* d)
  283. {
  284. int i;
  285. if (!d) return;
  286. if (d->did.s) {
  287. pkg_free(d->did.s);
  288. d->did.s = NULL;
  289. }
  290. if (d->domain) {
  291. for(i = 0; i < d->n; i++) {
  292. if (d->domain[i].s) pkg_free(d->domain[i].s);
  293. }
  294. pkg_free(d->domain);
  295. d->domain = NULL;
  296. }
  297. if (d->flags) {
  298. pkg_free(d->flags);
  299. d->flags = NULL;
  300. }
  301. if (d->attrs) {
  302. destroy_avp_list(&d->attrs);
  303. }
  304. }
  305. static void destroy(void)
  306. {
  307. /* Destroy is called from the main process only, there is no need to close
  308. * database here because it is closed in mod_init already
  309. */
  310. if (!db_mode) {
  311. free_old_domain(&dom_buf[0]);
  312. free_old_domain(&dom_buf[1]);
  313. }
  314. if (load_domains_cmd) db_cmd_free(load_domains_cmd);
  315. if (get_did_cmd) db_cmd_free(get_did_cmd);
  316. if (load_attrs_cmd) db_cmd_free(load_attrs_cmd);
  317. if (db) {
  318. db_disconnect(db);
  319. db_ctx_free(db);
  320. }
  321. destroy_tables();
  322. }
  323. /*
  324. * Check if domain is local
  325. */
  326. static int is_local(struct sip_msg* msg, char* fp, char* s2)
  327. {
  328. str domain;
  329. if (get_str_fparam(&domain, msg, (fparam_t*)fp) != 0) {
  330. ERR("Unable to get domain to check\n");
  331. return -1;
  332. }
  333. return is_domain_local(&domain);
  334. }
  335. static int db_load_domain(domain_t** d, unsigned long flags, str* domain)
  336. {
  337. int ret;
  338. int_str name, val;
  339. domain_t* p;
  340. str name_s = STR_STATIC_INIT(AVP_DID);
  341. if (flags & AVP_TRACK_FROM) {
  342. p = &dom_buf[0];
  343. } else {
  344. p = &dom_buf[1];
  345. }
  346. free_old_domain(p);
  347. ret = db_get_did(&p->did, domain);
  348. if (ret != 1) return ret;
  349. if (load_domain_attrs) {
  350. if (db_load_domain_attrs(p) < 0) return -1;
  351. }
  352. /* Create an attribute containing did of the domain */
  353. name.s = name_s;
  354. val.s = p->did;
  355. if (add_avp_list(&p->attrs, AVP_CLASS_DOMAIN | AVP_NAME_STR | AVP_VAL_STR,
  356. name, val) < 0) return -1;
  357. *d = p;
  358. return 0;
  359. }
  360. static int lookup_domain(struct sip_msg* msg, char* flags, char* fp)
  361. {
  362. str domain, tmp;
  363. domain_t* d;
  364. int ret = -1;
  365. if (get_str_fparam(&domain, msg, (fparam_t*)fp) != 0) {
  366. DBG("lookup_domain: Cannot get the domain name to lookup\n");
  367. return -1;
  368. }
  369. tmp.s = pkg_malloc(domain.len);
  370. if (!tmp.s) {
  371. ERR("No memory left\n");
  372. return -1;
  373. }
  374. memcpy(tmp.s, domain.s, domain.len);
  375. tmp.len = domain.len;
  376. strlower(&tmp);
  377. if (db_mode) {
  378. if (hash_lookup(&d, *active_hash, &tmp) == 1) {
  379. set_avp_list((unsigned long)flags, &d->attrs);
  380. ret = 1;
  381. }
  382. } else {
  383. if (db_load_domain(&d, (unsigned long)flags, &tmp) == 0) {
  384. set_avp_list((unsigned long)flags, &d->attrs);
  385. ret = 1;
  386. }
  387. }
  388. pkg_free(tmp.s);
  389. return ret;
  390. }
  391. static int get_did(str* did, str* domain)
  392. {
  393. str tmp;
  394. domain_t* d;
  395. if (!db_mode) {
  396. ERR("lookup_domain only works in cache mode\n");
  397. return -1;
  398. }
  399. tmp.s = pkg_malloc(domain->len);
  400. if (!tmp.s) {
  401. ERR("No memory left\n");
  402. return -1;
  403. }
  404. memcpy(tmp.s, domain->s, domain->len);
  405. tmp.len = domain->len;
  406. strlower(&tmp);
  407. if (hash_lookup(&d, *active_hash, &tmp) == 1) {
  408. *did = d->did;
  409. pkg_free(tmp.s);
  410. return 1;
  411. } else {
  412. pkg_free(tmp.s);
  413. return -1;
  414. }
  415. }
  416. int reload_domain_list(void)
  417. {
  418. struct hash_entry** new_table;
  419. domain_t** new_list;
  420. /* Choose new hash table and free its old contents */
  421. if (*active_hash == hash_1) {
  422. free_table(hash_2);
  423. new_table = hash_2;
  424. new_list = domains_2;
  425. } else {
  426. free_table(hash_1);
  427. new_table = hash_1;
  428. new_list = domains_1;
  429. }
  430. if (load_domains(new_list) < 0) goto error;
  431. if (gen_domain_table(new_table, *new_list) < 0) goto error;
  432. *active_hash = new_table;
  433. return 0;
  434. error:
  435. free_table(new_table);
  436. free_domain_list(*new_list);
  437. return -1;
  438. }
  439. static int lookup_domain_fixup(void** param, int param_no)
  440. {
  441. unsigned long flags;
  442. char* s;
  443. if (param_no == 1) {
  444. /* Determine the track and class of attributes to be loaded */
  445. s = (char*)*param;
  446. flags = 0;
  447. if (*s != '$' || (strlen(s) != 3)) {
  448. ERR("Invalid parameter value, $xy expected\n");
  449. return -1;
  450. }
  451. switch((s[1] << 8) + s[2]) {
  452. case 0x4644: /* $fd */
  453. case 0x6664:
  454. case 0x4664:
  455. case 0x6644:
  456. flags = AVP_TRACK_FROM | AVP_CLASS_DOMAIN;
  457. break;
  458. case 0x5444: /* $td */
  459. case 0x7464:
  460. case 0x5464:
  461. case 0x7444:
  462. flags = AVP_TRACK_TO | AVP_CLASS_DOMAIN;
  463. break;
  464. default:
  465. ERR("Invalid parameter value: '%s'\n", s);
  466. return -1;
  467. }
  468. pkg_free(*param);
  469. *param = (void*)flags;
  470. } else if (param_no == 2) {
  471. return fixup_var_str_12(param, 2);
  472. }
  473. return 0;
  474. }