cpl.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2001-2003 FhG Fokus
  5. *
  6. * This file is part of Kamailio, a free SIP server.
  7. *
  8. * Kamailio is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * Kamailio is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 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-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan)
  27. * 2004-06-06 updated to the new DB api (andrei)
  28. * 2004-06-14: all global variables merged into cpl_env and cpl_fct;
  29. * case_sensitive and realm_prefix added for building AORs - see
  30. * build_userhost (bogdan)
  31. * 2004-10-09: added process_register_norpl to allow register processing
  32. * without sending the reply(bogdan) - based on a patch sent by
  33. * Christopher Crawford
  34. */
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <unistd.h>
  40. #include <fcntl.h>
  41. #include <signal.h>
  42. #include "../../mem/shm_mem.h"
  43. #include "../../mem/mem.h"
  44. #include "../../sr_module.h"
  45. #include "../../str.h"
  46. #include "../../ut.h"
  47. #include "../../dprint.h"
  48. #include "../../data_lump_rpl.h"
  49. #include "../../pvar.h"
  50. #include "../../mod_fix.h"
  51. #include "../../parser/parse_uri.h"
  52. #include "../../parser/parse_from.h"
  53. #include "../../parser/parse_content.h"
  54. #include "../../parser/parse_disposition.h"
  55. #include "../../lib/srdb1/db.h"
  56. #include "../../lib/kmi/mi.h"
  57. #include "../../modules/sl/sl.h"
  58. #include "cpl_run.h"
  59. #include "cpl_env.h"
  60. #include "cpl_db.h"
  61. #include "cpl_loader.h"
  62. #include "cpl_parser.h"
  63. #include "cpl_nonsig.h"
  64. #include "loc_set.h"
  65. #define MAX_PROXY_RECURSE 10
  66. #define MAX_USERHOST_LEN 256
  67. /* modules param variables */
  68. static str db_url = str_init(DEFAULT_DB_URL); /* database url */
  69. static str db_table = str_init("cpl"); /* database table */
  70. static char *dtd_file = 0; /* name of the DTD file for CPL parser */
  71. static char *lookup_domain = 0;
  72. static str timer_avp = STR_NULL; /* name of variable timer AVP */
  73. struct cpl_enviroment cpl_env = {
  74. 0, /* no cpl logging */
  75. 0, /* recurse proxy level is 0 */
  76. 0, /* no script route to be run before proxy */
  77. 0, /* user part is not case sensitive */
  78. {0,0}, /* no domain prefix to be ignored */
  79. {-1,-1}, /* communication pipe to aux_process */
  80. {0,0}, /* original TZ \0 terminated "TZ=value" format */
  81. 0, /* udomain */
  82. 0, /* no branches on lookup */
  83. 0, /* timer avp type */
  84. {0}, /* timer avp name/ID */
  85. 0 /* use_domain */
  86. };
  87. struct cpl_functions cpl_fct;
  88. static str cpl_ok_rpl = str_init("OK");
  89. MODULE_VERSION
  90. static int cpl_invoke_script (struct sip_msg* msg, char* str1, char* str2);
  91. static int cpl_invoke_script3 (struct sip_msg* msg, char* str1, char* str2, char* str3);
  92. static int w_process_register(struct sip_msg* msg, char* str1, char* str2);
  93. static int w_process_register_norpl(struct sip_msg* msg, char* str1,char* str2);
  94. static int cpl_process_register(struct sip_msg* msg, int no_rpl);
  95. static int fixup_cpl_run_script(void** param, int param_no);
  96. static int fixup_cpl_run_script3(void** param, int param_no);
  97. static int cpl_init(void);
  98. static int mi_child_init(void);
  99. static int cpl_child_init(int rank);
  100. static int cpl_exit(void);
  101. static void cpl_process(int rank);
  102. /*
  103. * Exported processes
  104. */
  105. static proc_export_t cpl_procs[] = {
  106. {"CPL Aux", 0, 0, cpl_process, 1 },
  107. {0,0,0,0,0}
  108. };
  109. /*
  110. * Exported functions
  111. */
  112. static cmd_export_t cmds[] = {
  113. {"cpl_run_script", (cmd_function)cpl_invoke_script, 2,
  114. fixup_cpl_run_script, 0, REQUEST_ROUTE},
  115. {"cpl_run_script", (cmd_function)cpl_invoke_script3, 3,
  116. fixup_cpl_run_script3, 0, REQUEST_ROUTE},
  117. {"cpl_process_register", (cmd_function)w_process_register, 0,
  118. 0, 0, REQUEST_ROUTE},
  119. {"cpl_process_register_norpl",(cmd_function)w_process_register_norpl, 0,
  120. 0, 0, REQUEST_ROUTE},
  121. {0, 0, 0, 0, 0, 0}
  122. };
  123. /*
  124. * Exported parameters
  125. */
  126. static param_export_t params[] = {
  127. {"db_url", PARAM_STR, &db_url },
  128. {"db_table", PARAM_STR, &db_table },
  129. {"cpl_dtd_file", PARAM_STRING, &dtd_file },
  130. {"proxy_recurse", INT_PARAM, &cpl_env.proxy_recurse },
  131. {"proxy_route", INT_PARAM, &cpl_env.proxy_route },
  132. {"log_dir", PARAM_STRING, &cpl_env.log_dir },
  133. {"case_sensitive", INT_PARAM, &cpl_env.case_sensitive },
  134. {"realm_prefix", PARAM_STR, &cpl_env.realm_prefix },
  135. {"lookup_domain", PARAM_STRING, &lookup_domain },
  136. {"lookup_append_branches", INT_PARAM, &cpl_env.lu_append_branches},
  137. {"timer_avp", PARAM_STR, &timer_avp },
  138. {"username_column",PARAM_STR, &cpl_username_col },
  139. {"domain_column", PARAM_STR, &cpl_domain_col },
  140. {"cpl_xml_column", PARAM_STR, &cpl_xml_col },
  141. {"cpl_bin_column", PARAM_STR, &cpl_bin_col },
  142. {"use_domain", INT_PARAM, &cpl_env.use_domain },
  143. {0, 0, 0}
  144. };
  145. /*
  146. * Exported MI functions
  147. */
  148. static mi_export_t mi_cmds[] = {
  149. { "LOAD_CPL", mi_cpl_load, 0, 0, mi_child_init },
  150. { "REMOVE_CPL", mi_cpl_remove, 0, 0, 0 },
  151. { "GET_CPL", mi_cpl_get, 0, 0, 0 },
  152. { 0, 0, 0, 0, 0}
  153. };
  154. struct module_exports exports = {
  155. "cpl-c",
  156. DEFAULT_DLFLAGS, /* dlopen flags */
  157. cmds, /* Exported functions */
  158. params, /* Exported parameters */
  159. 0, /* exported statistics */
  160. mi_cmds, /* exported MI functions */
  161. 0, /* exported pseudo-variables */
  162. cpl_procs,/* extra processes */
  163. cpl_init, /* Module initialization function */
  164. 0,
  165. (destroy_function) cpl_exit,
  166. (child_init_function) cpl_child_init /* per-child init function */
  167. };
  168. static int fixup_cpl_run_script(void** param, int param_no)
  169. {
  170. long flag;
  171. if (param_no==1) {
  172. if (!strcasecmp( "incoming", *param))
  173. flag = CPL_RUN_INCOMING;
  174. else if (!strcasecmp( "outgoing", *param))
  175. flag = CPL_RUN_OUTGOING;
  176. else {
  177. LM_ERR("script directive \"%s\" unknown!\n",(char*)*param);
  178. return E_UNSPEC;
  179. }
  180. pkg_free(*param);
  181. *param=(void*)flag;
  182. return 0;
  183. } else if (param_no==2) {
  184. if ( !strcasecmp("is_stateless", *param) ) {
  185. flag = 0;
  186. } else if ( !strcasecmp("is_stateful", *param) ) {
  187. flag = CPL_IS_STATEFUL;
  188. } else if ( !strcasecmp("force_stateful", *param) ) {
  189. flag = CPL_FORCE_STATEFUL;
  190. } else {
  191. LM_ERR("flag \"%s\" (second param) unknown!\n",(char*)*param);
  192. return E_UNSPEC;
  193. }
  194. pkg_free(*param);
  195. *param=(void*)flag;
  196. }
  197. return 0;
  198. }
  199. static int fixup_cpl_run_script3(void** param, int param_no)
  200. {
  201. if (param_no==1 || param_no==2) {
  202. return fixup_cpl_run_script(param, param_no);
  203. } else if (param_no==2) {
  204. return fixup_spve_null(param, 1);
  205. }
  206. return 0;
  207. }
  208. static int cpl_init(void)
  209. {
  210. bind_usrloc_t bind_usrloc;
  211. struct stat stat_t;
  212. char *ptr;
  213. int val;
  214. pv_spec_t avp_spec;
  215. unsigned short avp_type;
  216. if(register_mi_mod(exports.name, mi_cmds)!=0)
  217. {
  218. LM_ERR("failed to register MI commands\n");
  219. return -1;
  220. }
  221. if (cpl_env.proxy_recurse>MAX_PROXY_RECURSE) {
  222. LM_CRIT("value of proxy_recurse param (%d) exceeds "
  223. "the maximum safety value (%d)\n",
  224. cpl_env.proxy_recurse,MAX_PROXY_RECURSE);
  225. goto error;
  226. }
  227. /* fix the timer_avp name */
  228. if (timer_avp.s && timer_avp.len > 0) {
  229. if (pv_parse_spec(&timer_avp, &avp_spec)==0
  230. || avp_spec.type!=PVT_AVP) {
  231. LM_ERR("malformed or non AVP %.*s AVP definition\n", timer_avp.len, timer_avp.s);
  232. return -1;
  233. }
  234. if(pv_get_avp_name(0, &(avp_spec.pvp), &cpl_env.timer_avp,
  235. &avp_type)!=0)
  236. {
  237. LM_ERR("[%.*s]- invalid AVP definition\n", timer_avp.len, timer_avp.s);
  238. return -1;
  239. }
  240. cpl_env.timer_avp_type = avp_type;
  241. }
  242. if (dtd_file==0) {
  243. LM_CRIT("mandatory parameter \"cpl_dtd_file\" found empty\n");
  244. goto error;
  245. } else {
  246. /* check if the dtd file exists */
  247. if (stat( dtd_file, &stat_t)==-1) {
  248. LM_ERR("checking file \"%s\" status failed; stat returned %s\n",
  249. dtd_file,strerror(errno));
  250. goto error;
  251. }
  252. if ( !S_ISREG( stat_t.st_mode ) ) {
  253. LM_ERR("dir \"%s\" is not a regular file!\n", dtd_file);
  254. goto error;
  255. }
  256. if (access( dtd_file, R_OK )==-1) {
  257. LM_ERR("checking file \"%s\" for permissions "
  258. "failed; access returned %s\n",dtd_file,strerror(errno));
  259. goto error;
  260. }
  261. }
  262. if (cpl_env.log_dir==0) {
  263. LM_INFO("log_dir param found empty -> logging disabled!\n");
  264. } else {
  265. if ( strlen(cpl_env.log_dir)>MAX_LOG_DIR_SIZE ) {
  266. LM_ERR("dir \"%s\" has a too long name :-(!\n", cpl_env.log_dir);
  267. goto error;
  268. }
  269. /* check if the dir exists */
  270. if (stat( cpl_env.log_dir, &stat_t)==-1) {
  271. LM_ERR("checking dir \"%s\" status failed;"
  272. " stat returned %s\n",cpl_env.log_dir,strerror(errno));
  273. goto error;
  274. }
  275. if ( !S_ISDIR( stat_t.st_mode ) ) {
  276. LM_ERR("dir \"%s\" is not a directory!\n", cpl_env.log_dir);
  277. goto error;
  278. }
  279. if (access( cpl_env.log_dir, R_OK|W_OK )==-1) {
  280. LM_ERR("checking dir \"%s\" for permissions failed; access "
  281. "returned %s\n", cpl_env.log_dir, strerror(errno));
  282. goto error;
  283. }
  284. }
  285. /* bind to the mysql module */
  286. if (cpl_db_bind(&db_url, &db_table)<0) goto error;
  287. /* load TM API */
  288. if (load_tm_api(&cpl_fct.tmb)!=0) {
  289. LM_ERR("can't load TM API\n");
  290. goto error;
  291. }
  292. /* bind the SL API */
  293. if (sl_load_api(&cpl_fct.slb)!=0) {
  294. LM_ERR("cannot bind to SL API\n");
  295. return -1;
  296. }
  297. /* bind to usrloc module if requested */
  298. if (lookup_domain) {
  299. /* import all usrloc functions */
  300. bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0);
  301. if (!bind_usrloc) {
  302. LM_ERR("can't bind usrloc\n");
  303. goto error;
  304. }
  305. if (bind_usrloc( &(cpl_fct.ulb) ) < 0) {
  306. LM_ERR("importing usrloc failed\n");
  307. goto error;
  308. }
  309. /* convert lookup_domain from char* to udomain_t* pointer */
  310. if (cpl_fct.ulb.register_udomain( lookup_domain, &cpl_env.lu_domain)
  311. < 0) {
  312. LM_ERR("failed to register domain <%s>\n",lookup_domain);
  313. goto error;
  314. }
  315. } else {
  316. LM_NOTICE("no lookup_domain given -> disable lookup node\n");
  317. }
  318. /* build a pipe for sending commands to aux process */
  319. if ( pipe( cpl_env.cmd_pipe )==-1 ) {
  320. LM_CRIT("cannot create command pipe: %s!\n", strerror(errno) );
  321. goto error;
  322. }
  323. /* set the writing non blocking */
  324. if ( (val=fcntl(cpl_env.cmd_pipe[1], F_GETFL, 0))<0 ) {
  325. LM_ERR("getting flags from pipe[1] failed: fcntl said %s!\n",
  326. strerror(errno));
  327. goto error;
  328. }
  329. if ( fcntl(cpl_env.cmd_pipe[1], F_SETFL, val|O_NONBLOCK) ) {
  330. LM_ERR("setting flags to pipe[1] failed: fcntl said %s!\n",
  331. strerror(errno));
  332. goto error;
  333. }
  334. /* init the CPL parser */
  335. if (init_CPL_parser( dtd_file )!=1 ) {
  336. LM_ERR("init_CPL_parser failed!\n");
  337. goto error;
  338. }
  339. /* make a copy of the original TZ env. variable */
  340. ptr = getenv("TZ");
  341. cpl_env.orig_tz.len = 3/*"TZ="*/ + (ptr?(strlen(ptr)+1):0);
  342. if ( (cpl_env.orig_tz.s=shm_malloc( cpl_env.orig_tz.len ))==0 ) {
  343. LM_ERR("no more shm mem. for saving TZ!\n");
  344. goto error;
  345. }
  346. memcpy(cpl_env.orig_tz.s,"TZ=",3);
  347. if (ptr)
  348. strcpy(cpl_env.orig_tz.s+3,ptr);
  349. /* convert realm_prefix from string null terminated to str */
  350. if (cpl_env.realm_prefix.s) {
  351. /* convert the realm_prefix to lower cases */
  352. strlower( &cpl_env.realm_prefix );
  353. }
  354. return 0;
  355. error:
  356. return -1;
  357. }
  358. static int cpl_child_init(int rank)
  359. {
  360. if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
  361. return 0; /* do nothing for the main process */
  362. return cpl_db_init(&db_url, &db_table);
  363. }
  364. static int mi_child_init(void)
  365. {
  366. return cpl_db_init(&db_url, &db_table);
  367. }
  368. static void cpl_process(int rank)
  369. {
  370. cpl_aux_process( cpl_env.cmd_pipe[0], cpl_env.log_dir);
  371. exit(-1);
  372. }
  373. static int cpl_exit(void)
  374. {
  375. /* free the TZ orig */
  376. if (cpl_env.orig_tz.s)
  377. shm_free(cpl_env.orig_tz.s);
  378. return 0;
  379. }
  380. static inline int build_user_AOR(str *username, str *domain, str *uh, int sip)
  381. {
  382. unsigned char do_strip;
  383. char *p;
  384. int i;
  385. /* calculate the len (without terminating \0) */
  386. uh->len = 4*(sip!=0) + username->len;
  387. do_strip = 0;
  388. if (sip || cpl_env.use_domain) {
  389. /* do we need to strip realm prefix? */
  390. if (cpl_env.realm_prefix.len && cpl_env.realm_prefix.len<domain->len){
  391. for( i=cpl_env.realm_prefix.len-1 ; i>=0 ; i-- )
  392. if ( cpl_env.realm_prefix.s[i]!=tolower(domain->s[i]) )
  393. break;
  394. if (i==-1)
  395. do_strip = 1;
  396. }
  397. uh->len += 1 + domain->len - do_strip*cpl_env.realm_prefix.len;
  398. }
  399. uh->s = (char*)shm_malloc( uh->len + 1 );
  400. if (!uh->s) {
  401. LM_ERR("no more shm memory.\n");
  402. return -1;
  403. }
  404. /* build user@host */
  405. p = uh->s;
  406. if (sip) {
  407. memcpy( uh->s, "sip:", 4);
  408. p += 4;
  409. }
  410. /* user part */
  411. if (cpl_env.case_sensitive) {
  412. memcpy( p, username->s, username->len);
  413. p += username->len;
  414. } else {
  415. for(i=0;i<username->len;i++)
  416. *(p++) = tolower(username->s[i]);
  417. }
  418. if (sip || cpl_env.use_domain) {
  419. *(p++) = '@';
  420. /* host part in lower cases */
  421. for( i=do_strip*cpl_env.realm_prefix.len ; i< domain->len ; i++ )
  422. *(p++) = tolower(domain->s[i]);
  423. }
  424. *(p++) = 0;
  425. /* sanity check */
  426. if (p-uh->s!=uh->len+1) {
  427. LM_CRIT("buffer overflow l=%d,w=%ld\n", uh->len,(long)(p-uh->s));
  428. return -1;
  429. }
  430. return 0;
  431. }
  432. static inline int get_dest_user(struct sip_msg *msg, str *username, str *domain)
  433. {
  434. struct sip_uri uri;
  435. /* get the user_name from new_uri/RURI/To */
  436. LM_DBG("trying to get user from new_uri\n");
  437. if ( !msg->new_uri.s || parse_uri( msg->new_uri.s,msg->new_uri.len,&uri)<0
  438. || !uri.user.len )
  439. {
  440. LM_DBG("trying to get user from R_uri\n");
  441. if ( parse_uri( msg->first_line.u.request.uri.s,
  442. msg->first_line.u.request.uri.len ,&uri)==-1 || !uri.user.len )
  443. {
  444. LM_DBG("trying to get user from To\n");
  445. if ( (!msg->to&&((parse_headers(msg,HDR_TO_F,0)==-1)||!msg->to))||
  446. parse_uri( get_to(msg)->uri.s, get_to(msg)->uri.len, &uri)<0
  447. || !uri.user.len)
  448. {
  449. LM_ERR("unable to extract user name from RURI or To header!\n");
  450. return -1;
  451. }
  452. }
  453. }
  454. *username = uri.user;
  455. *domain = uri.host;
  456. return 0;
  457. }
  458. static inline int get_orig_user(struct sip_msg *msg, str *username, str *domain)
  459. {
  460. struct to_body *from;
  461. struct sip_uri uri;
  462. /* if it's outgoing -> get the user_name from From */
  463. /* parsing from header */
  464. LM_DBG("trying to get user from From\n");
  465. if ( parse_from_header( msg )==-1 ) {
  466. LM_ERR("unable to extract URI from FROM header\n");
  467. return -1;
  468. }
  469. from = (struct to_body*)msg->from->parsed;
  470. /* parse the extracted uri from From */
  471. if (parse_uri( from->uri.s, from->uri.len, &uri)||!uri.user.len) {
  472. LM_ERR("unable to extract user name from URI (From header)\n");
  473. return -1;
  474. }
  475. *username = uri.user;
  476. *domain = uri.host;
  477. return 0;
  478. }
  479. /* Params:
  480. * str1 - as unsigned int - can be CPL_RUN_INCOMING or CPL_RUN_OUTGOING
  481. * str2 - as unsigned int - flags regarding state(less)|(ful)
  482. * str3 - URI in SPVE structure
  483. */
  484. static int cpl_invoke_script3(struct sip_msg* msg, char* str1, char* str2, char *str3)
  485. {
  486. struct cpl_interpreter *cpl_intr;
  487. str username = {0,0};
  488. str domain = {0,0};
  489. str uri = {0,0};
  490. sip_uri_t puri;
  491. str loc;
  492. str script;
  493. /* get the user_name */
  494. if(str3==NULL) {
  495. if ( ((unsigned long)str1)&CPL_RUN_INCOMING ) {
  496. /* if it's incoming -> get the destination user name */
  497. if (get_dest_user( msg, &username, &domain)==-1)
  498. goto error0;
  499. } else {
  500. /* if it's outgoing -> get the origin user name */
  501. if (get_orig_user( msg, &username, &domain)==-1)
  502. goto error0;
  503. }
  504. } else {
  505. if(fixup_get_svalue(msg, (gparam_p)str3, &uri)!=0)
  506. {
  507. LM_ERR("invalid uri parameter");
  508. goto error0;
  509. }
  510. if (parse_uri(uri.s, uri.len, &puri) || !puri.user.len) {
  511. LM_ERR("unable to extract user name from URI param\n");
  512. return -1;
  513. }
  514. username = puri.user;
  515. domain = puri.host;
  516. }
  517. /* get the script for this user */
  518. if (get_user_script(&username, cpl_env.use_domain?&domain:0,
  519. &script, &cpl_bin_col)==-1)
  520. goto error0;
  521. /* has the user a non-empty script? if not, return normally, allowing the
  522. * script execution to continue */
  523. if ( !script.s || !script.len )
  524. return 1;
  525. /* build a new script interpreter */
  526. if ( (cpl_intr=new_cpl_interpreter(msg,&script))==0 )
  527. goto error1;
  528. /* set the flags */
  529. cpl_intr->flags =(unsigned int)((unsigned long)str1)|((unsigned long)str2);
  530. /* build user AOR */
  531. if (build_user_AOR( &username, &domain, &(cpl_intr->user), 0)!=0 )
  532. goto error2;
  533. /* for OUTGOING we need also the destination user for init. with him
  534. * the location set */
  535. if ( ((unsigned long)str1)&CPL_RUN_OUTGOING ) {
  536. /* build user initial location -> get the destination user name */
  537. if (get_dest_user( msg, &username, &domain)==-1)
  538. goto error2;
  539. if (build_user_AOR( &username, &domain, &loc, 1)!=0 )
  540. goto error2;
  541. if (add_location( &(cpl_intr->loc_set), &loc, 0, 10, 0/*no dup*/)==-1)
  542. goto error2;
  543. }
  544. /* run the script */
  545. switch (cpl_run_script( cpl_intr )) {
  546. case SCRIPT_DEFAULT:
  547. free_cpl_interpreter( cpl_intr );
  548. return 1; /* execution of ser's script will continue */
  549. case SCRIPT_END:
  550. free_cpl_interpreter( cpl_intr );
  551. case SCRIPT_TO_BE_CONTINUED:
  552. return 0; /* break the SER script */
  553. case SCRIPT_RUN_ERROR:
  554. case SCRIPT_FORMAT_ERROR:
  555. goto error2;
  556. }
  557. return 1;
  558. error2:
  559. free_cpl_interpreter( cpl_intr );
  560. return -1;
  561. error1:
  562. shm_free(script.s);
  563. error0:
  564. return -1;
  565. }
  566. /* Params:
  567. * str1 - as unsigned int - can be CPL_RUN_INCOMING or CPL_RUN_OUTGOING
  568. * str2 - as unsigned int - flags regarding state(less)|(ful)
  569. */
  570. static int cpl_invoke_script(struct sip_msg* msg, char* str1, char* str2)
  571. {
  572. return cpl_invoke_script3(msg, str1, str2, NULL);
  573. }
  574. #define CPL_SCRIPT "script"
  575. #define CPL_SCRIPT_LEN (sizeof(CPL_SCRIPT)-1)
  576. #define ACTION_PARAM "action"
  577. #define ACTION_PARAM_LEN (sizeof(ACTION_PARAM)-1)
  578. #define STORE_ACTION "store"
  579. #define STORE_ACTION_LEN (sizeof(STORE_ACTION)-1)
  580. #define REMOVE_ACTION "remove"
  581. #define REMOVE_ACTION_LEN (sizeof(REMOVE_ACTION)-1)
  582. #define REMOVE_SCRIPT 0xcaca
  583. #define STORE_SCRIPT 0xbebe
  584. #define CONTENT_TYPE_HDR ("Content-Type: application/cpl-xml"CRLF)
  585. #define CONTENT_TYPE_HDR_LEN (sizeof(CONTENT_TYPE_HDR)-1)
  586. struct cpl_error {
  587. int err_code;
  588. str err_msg;
  589. };
  590. static struct cpl_error bad_req = {400,str_init("Bad request")};
  591. static struct cpl_error intern_err = {500,str_init("Internal server error")};
  592. static struct cpl_error bad_cpl = {400,str_init("Bad CPL script")};
  593. static struct cpl_error *cpl_err = &bad_req;
  594. static inline int do_script_action(struct sip_msg *msg, int action)
  595. {
  596. str body = {0,0};
  597. str bin = {0,0};
  598. str log = {0,0};
  599. str username = {0,0};
  600. str domain = {0,0};
  601. /* content-length (if present) */
  602. if ( !msg->content_length &&
  603. ((parse_headers(msg,HDR_CONTENTLENGTH_F,0)==-1)||!msg->content_length)) {
  604. LM_ERR("no Content-Length hdr found!\n");
  605. goto error;
  606. }
  607. body.len = get_content_length( msg );
  608. /* get the user name */
  609. if (get_dest_user( msg, &username, &domain)==-1)
  610. goto error;
  611. /* we have the script and the user */
  612. switch (action) {
  613. case STORE_SCRIPT :
  614. /* check the len -> it must not be 0 */
  615. if (body.len==0) {
  616. LM_ERR("0 content-len found for store\n");
  617. goto error_1;
  618. }
  619. /* get the message's body */
  620. body.s = get_body( msg );
  621. if (body.s==0) {
  622. LM_ERR("cannot extract body from msg!\n");
  623. goto error_1;
  624. }
  625. /* now compile the script and place it into database */
  626. /* get the binary coding for the XML file */
  627. if ( encodeCPL( &body, &bin, &log)!=1) {
  628. cpl_err = &bad_cpl;
  629. goto error_1;
  630. }
  631. /* write both the XML and binary formats into database */
  632. if (write_to_db( &username, cpl_env.use_domain?&domain:0,
  633. &body,&bin)!=1) {
  634. cpl_err = &intern_err;
  635. goto error_1;
  636. }
  637. break;
  638. case REMOVE_SCRIPT:
  639. /* check the len -> it must be 0 */
  640. if (body.len!=0) {
  641. LM_ERR("non-0 content-len found for remove\n");
  642. goto error_1;
  643. }
  644. /* remove the script for the user */
  645. if (rmv_from_db( &username, cpl_env.use_domain?&domain:0)!=1) {
  646. cpl_err = &intern_err;
  647. goto error_1;
  648. }
  649. break;
  650. }
  651. if (log.s) pkg_free( log.s );
  652. return 0;
  653. error_1:
  654. if (log.s) pkg_free( log.s );
  655. error:
  656. return -1;
  657. }
  658. static inline int do_script_download(struct sip_msg *msg)
  659. {
  660. str username = {0,0};
  661. str domain = {0,0};
  662. str script = {0,0};
  663. /* get the destination user name */
  664. if (get_dest_user( msg, &username, &domain)!=0)
  665. goto error;
  666. /* get the user's xml script from the database */
  667. if (get_user_script( &username, cpl_env.use_domain?&domain:0,
  668. &script, &cpl_xml_col)==-1)
  669. goto error;
  670. /* add a lump with content-type hdr */
  671. if (add_lump_rpl( msg, CONTENT_TYPE_HDR, CONTENT_TYPE_HDR_LEN,
  672. LUMP_RPL_HDR)==0) {
  673. LM_ERR("cannot build hdr lump\n");
  674. cpl_err = &intern_err;
  675. goto error;
  676. }
  677. if (script.s!=0) {
  678. /* user has a script -> add a body lump */
  679. if ( add_lump_rpl( msg, script.s, script.len, LUMP_RPL_BODY)==0) {
  680. LM_ERR("cannot build body lump\n");
  681. cpl_err = &intern_err;
  682. goto error;
  683. }
  684. /* build_lump_rpl duplicates the added text, so free the original */
  685. shm_free( script.s );
  686. }
  687. return 0;
  688. error:
  689. if (script.s)
  690. shm_free(script.s);
  691. return -1;
  692. }
  693. static int w_process_register(struct sip_msg* msg, char* str, char* str2)
  694. {
  695. return cpl_process_register( msg, 0);
  696. }
  697. static int w_process_register_norpl(struct sip_msg* msg, char* str,char* str2)
  698. {
  699. return cpl_process_register( msg, 1);
  700. }
  701. static int cpl_process_register(struct sip_msg* msg, int no_rpl)
  702. {
  703. struct disposition *disp;
  704. struct disposition_param *param;
  705. int ret;
  706. int mime;
  707. int *mimes;
  708. /* make sure that is a REGISTER ??? */
  709. /* here should be the CONTACT- hack */
  710. /* is there a CONTENT-TYPE hdr ? */
  711. mime = parse_content_type_hdr( msg );
  712. if (mime==-1)
  713. goto error;
  714. /* check the mime type */
  715. LM_DBG("Content-Type mime found %u, %u\n",
  716. mime>>16,mime&0x00ff);
  717. if ( mime && mime==(TYPE_APPLICATION<<16)+SUBTYPE_CPLXML ) {
  718. /* can be an upload or remove -> check for the content-purpose and
  719. * content-action headers */
  720. LM_DBG("carrying CPL -> look at Content-Disposition\n");
  721. if (parse_content_disposition( msg )!=0) {
  722. LM_ERR("Content-Disposition missing or corrupted\n");
  723. goto error;
  724. }
  725. disp = get_content_disposition(msg);
  726. print_disposition( disp ); /* just for DEBUG */
  727. /* check if the type of disposition is SCRIPT */
  728. if (disp->type.len!=CPL_SCRIPT_LEN ||
  729. strncasecmp(disp->type.s,CPL_SCRIPT,CPL_SCRIPT_LEN) ) {
  730. LM_ERR("bogus message - Content-Type"
  731. "says CPL_SCRIPT, but Content-Disposition something else\n");
  732. goto error;
  733. }
  734. /* disposition type is OK -> look for action parameter */
  735. for(param=disp->params;param;param=param->next) {
  736. if (param->name.len==ACTION_PARAM_LEN &&
  737. !strncasecmp(param->name.s,ACTION_PARAM,ACTION_PARAM_LEN))
  738. break;
  739. }
  740. if (param==0) {
  741. LM_ERR("bogus message - "
  742. "Content-Disposition has no action param\n");
  743. goto error;
  744. }
  745. /* action param found -> check its value: store or remove */
  746. if (param->body.len==STORE_ACTION_LEN &&
  747. !strncasecmp( param->body.s, STORE_ACTION, STORE_ACTION_LEN)) {
  748. /* it's a store action -> get the script from body message and store
  749. * it into database (CPL and BINARY format) */
  750. if (do_script_action( msg, STORE_SCRIPT)==-1)
  751. goto error;
  752. } else
  753. if (param->body.len==REMOVE_ACTION_LEN &&
  754. !strncasecmp( param->body.s, REMOVE_ACTION, REMOVE_ACTION_LEN)) {
  755. /* it's a remove action -> remove the script from database */
  756. if (do_script_action( msg, REMOVE_SCRIPT)==-1)
  757. goto error;
  758. } else {
  759. LM_ERR("unknown action <%.*s>\n",
  760. param->body.len,param->body.s);
  761. goto error;
  762. }
  763. /* do I have to send to reply? */
  764. if (no_rpl)
  765. goto resume_script;
  766. /* send a 200 OK reply back */
  767. cpl_fct.slb.freply( msg, 200, &cpl_ok_rpl);
  768. /* I send the reply and I don't want to return to script execution, so
  769. * I return 0 to do break */
  770. goto stop_script;
  771. }
  772. /* is there an ACCEPT hdr ? */
  773. if ( (ret=parse_accept_hdr(msg))<0)
  774. goto error;
  775. if (ret==0 || (mimes=get_accept(msg))==0 )
  776. /* accept header not present or no mimes found */
  777. goto resume_script;
  778. /* looks if the REGISTER accepts cpl-xml or * */
  779. while (*mimes) {
  780. LM_DBG("accept mime found %u, %u\n",
  781. (*mimes)>>16,(*mimes)&0x00ff);
  782. if (*mimes==(TYPE_ALL<<16)+SUBTYPE_ALL ||
  783. *mimes==(TYPE_APPLICATION<<16)+SUBTYPE_CPLXML )
  784. break;
  785. mimes++;
  786. }
  787. if (*mimes==0)
  788. /* no accept mime that matched cpl */
  789. goto resume_script;
  790. /* get the user name from msg, retrieve the script from db
  791. * and appended to reply */
  792. if (do_script_download( msg )==-1)
  793. goto error;
  794. /* do I have to send to reply? */
  795. if (no_rpl)
  796. goto resume_script;
  797. /* send a 200 OK reply back */
  798. cpl_fct.slb.freply( msg, 200, &cpl_ok_rpl);
  799. stop_script:
  800. return 0;
  801. resume_script:
  802. return 1;
  803. error:
  804. /* send a error reply back */
  805. cpl_fct.slb.freply( msg, cpl_err->err_code, &cpl_err->err_msg);
  806. /* I don't want to return to script execution, so I return 0 to do break */
  807. return 0;
  808. }