cpl.c 26 KB

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