2 * Asterisk -- A telephony toolkit for Linux.
6 * This program is free software, distributed under the terms of
7 * the GNU General Public License.
10 * Table Structure for `cdr`
12 * Created on: 05/20/2004 16:16
13 * Last changed on: 07/27/2004 20:01
15 CREATE TABLE [dbo].[cdr] (
16 [accountcode] [varchar] (20) NULL ,
17 [src] [varchar] (80) NULL ,
18 [dst] [varchar] (80) NULL ,
19 [dcontext] [varchar] (80) NULL ,
20 [clid] [varchar] (80) NULL ,
21 [channel] [varchar] (80) NULL ,
22 [dstchannel] [varchar] (80) NULL ,
23 [lastapp] [varchar] (80) NULL ,
24 [lastdata] [varchar] (80) NULL ,
25 [start] [datetime] NULL ,
26 [answer] [datetime] NULL ,
27 [end] [datetime] NULL ,
28 [duration] [int] NULL ,
29 [billsec] [int] NULL ,
30 [disposition] [varchar] (20) NULL ,
31 [amaflags] [varchar] (16) NULL ,
32 [uniqueid] [varchar] (32) NULL
37 #include <sys/types.h>
38 #include <asterisk/config.h>
39 #include <asterisk/options.h>
40 #include <asterisk/channel.h>
41 #include <asterisk/cdr.h>
42 #include <asterisk/module.h>
43 #include <asterisk/logger.h>
44 #include "../asterisk.h"
54 #include <tdsconvert.h>
57 #define DATE_FORMAT "%Y/%m/%d %T"
59 static char *desc = "MSSQL CDR Backend";
60 static char *name = "mssql";
61 static char *config = "cdr_tds.conf";
63 AST_MUTEX_DEFINE_STATIC(tds_lock);
65 static TDSSOCKET *tds;
66 static TDSLOGIN *login;
67 static TDSCONTEXT *context;
69 static char *stristr(const char*, const char*);
70 static char *anti_injection(const char *, int);
71 static void get_date(char *, struct timeval);
73 static int tds_log(struct ast_cdr *cdr)
75 char sqlcmd[2048], start[80], answer[80], end[80];
76 char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid;
79 ast_mutex_lock(&tds_lock);
81 memset(sqlcmd, 0, 2048);
83 accountcode = anti_injection(cdr->accountcode, 20);
84 src = anti_injection(cdr->src, 80);
85 dst = anti_injection(cdr->dst, 80);
86 dcontext = anti_injection(cdr->dcontext, 80);
87 clid = anti_injection(cdr->clid, 80);
88 channel = anti_injection(cdr->channel, 80);
89 dstchannel = anti_injection(cdr->dstchannel, 80);
90 lastapp = anti_injection(cdr->lastapp, 80);
91 lastdata = anti_injection(cdr->lastdata, 80);
92 uniqueid = anti_injection(cdr->uniqueid, 32);
94 get_date(start, cdr->start);
95 get_date(answer, cdr->answer);
96 get_date(end, cdr->end);
122 "'%s', " /* accountcode */
125 "'%s', " /* dcontext */
127 "'%s', " /* channel */
128 "'%s', " /* dstchannel */
129 "'%s', " /* lastapp */
130 "'%s', " /* lastdata */
134 "%i, " /* duration */
136 "'%s', " /* disposition */
137 "'%s', " /* amaflags */
138 "'%s'" /* uniqueid */
154 ast_cdr_disp2str(cdr->disposition),
155 ast_cdr_flags2str(cdr->amaflags),
159 if ((tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
161 ast_log(LOG_ERROR, "Failed to insert record into database.\n");
177 ast_mutex_unlock(&tds_lock);
182 /* Return the offset of one string within another.
183 Copyright (C) 1994, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
184 This file is part of the GNU C Library.
186 The GNU C Library is free software; you can redistribute it and/or
187 modify it under the terms of the GNU Lesser General Public
188 License as published by the Free Software Foundation; either
189 version 2.1 of the License, or (at your option) any later version.
191 The GNU C Library is distributed in the hope that it will be useful,
192 but WITHOUT ANY WARRANTY; without even the implied warranty of
193 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
194 Lesser General Public License for more details.
196 You should have received a copy of the GNU Lesser General Public
197 License along with the GNU C Library; if not, write to the Free
198 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
202 * My personal strstr() implementation that beats most other algorithms.
203 * Until someone tells me otherwise, I assume that this is the
204 * fastest implementation of strstr() in C.
205 * I deliberately chose not to comment it. You should have at least
206 * as much fun trying to understand it, as I had to write it :-).
208 * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
211 stristr (phaystack, pneedle)
212 const char *phaystack;
215 typedef unsigned chartype;
217 const unsigned char *haystack, *needle;
219 const unsigned char *rneedle;
221 haystack = (const unsigned char *) phaystack;
223 if ((b = toupper(*(needle = (const unsigned char *) pneedle))))
226 haystack--; /* possible ANSI violation */
231 if (!(a = toupper(*++haystack)))
236 if (!(c = toupper(*++needle)))
247 if ((a = toupper(*++haystack)) == c)
251 a = toupper(*++haystack);
254 for (; a != b; a = toupper(*++haystack))
258 if ((a = toupper(*++haystack)) == b)
264 while ((a = toupper(*++haystack)) != c);
270 const unsigned char *rhaystack;
271 if (toupper(*(rhaystack = haystack-- + 1)) == (a = toupper(*(rneedle = needle))))
276 if (toupper(*++rhaystack) != (a = toupper(*++needle)))
281 while (toupper(*++rhaystack) == (a = toupper(*++needle)));
282 needle = rneedle; /* took the register-poor aproach */
290 return (char *) haystack;
295 static char *anti_injection(const char *str, int len)
297 /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */
300 char *buf_ptr, *srh_ptr;
301 char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"};
304 if ((buf = malloc(len + 1)) == NULL)
306 ast_log(LOG_ERROR, "cdr_tds: Out of memory error\n");
313 /* Escape single quotes */
314 for (; *str && strlen(buf) < len; str++)
322 /* Erase known bad input */
323 for (idx=0; *known_bad[idx]; idx++)
325 while((srh_ptr = stristr(buf, known_bad[idx]))) /* fix me! */
327 memmove(srh_ptr, srh_ptr+strlen(known_bad[idx]), strlen(srh_ptr+strlen(known_bad[idx]))+1);
334 static void get_date(char *dateField, struct timeval tv)
340 /* To make sure we have date variable if not insert null to SQL */
341 if (tv.tv_sec && tv.tv_usec)
344 localtime_r(&t, &tm);
345 strftime(buf, 80, DATE_FORMAT, &tm);
346 sprintf(dateField, "'%s'", buf);
350 strcpy(dateField, "null");
354 char *description(void)
359 int unload_module(void)
361 tds_free_socket(tds);
362 tds_free_login(login);
363 tds_free_context(context);
365 ast_cdr_unregister(name);
370 int load_module(void)
372 TDSCONNECTINFO *connection;
374 struct ast_config *cfg;
375 struct ast_variable *var;
376 char query[1024], *ptr = NULL;
377 char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *charset = NULL, *language = NULL;
379 cfg = ast_load(config);
382 ast_log(LOG_NOTICE, "Unable to load config for MSSQL CDR's: %s\n", config);
386 var = ast_variable_browse(cfg, "global");
387 if (!var) /* nothing configured */
390 ptr = ast_variable_retrieve(cfg, "global", "hostname");
393 hostname = strdupa(ptr);
397 ast_log(LOG_ERROR,"Database server hostname not specified.\n");
400 ptr = ast_variable_retrieve(cfg, "global", "dbname");
403 dbname = strdupa(ptr);
407 ast_log(LOG_ERROR,"Database dbname not specified.\n");
410 ptr = ast_variable_retrieve(cfg, "global", "user");
413 dbuser = strdupa(ptr);
417 ast_log(LOG_ERROR,"Database dbuser not specified.\n");
420 ptr = ast_variable_retrieve(cfg, "global", "password");
423 password = strdupa(ptr);
427 ast_log(LOG_ERROR,"Database password not specified.\n");
430 ptr = ast_variable_retrieve(cfg, "global", "charset");
433 charset = strdupa(ptr);
437 charset = strdupa("iso_1");
440 ptr = ast_variable_retrieve(cfg, "global", "language");
443 language = strdupa(ptr);
447 language = strdupa("us_english");
452 /* Connect to M$SQL Server */
453 if (!(login = tds_alloc_login()))
455 ast_log(LOG_ERROR, "tds_alloc_login() failed.\n");
460 tds_set_server(login, hostname);
461 tds_set_user(login, dbuser);
462 tds_set_passwd(login, password);
463 tds_set_app(login, "TSQL");
464 tds_set_library(login, "TDS-Library");
465 tds_set_client_charset(login, charset);
466 tds_set_language(login, language);
467 tds_set_packet(login, 512);
468 tds_set_version(login, 7, 0);
470 context = tds_alloc_context();
471 tds = tds_alloc_socket(context, 512);
473 tds_set_parent(tds, NULL);
474 connection = tds_read_config_info(NULL, login, context->locale);
475 if (!connection || tds_connect(tds, connection) == TDS_FAIL)
477 ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n");
480 tds_free_connect(connection);
484 memset(query, 0, sizeof(query));
485 sprintf(query, "USE %s", dbname);
486 if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED))
488 ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname);
493 /* Register MSSQL CDR handler */
494 res = ast_cdr_register(name, desc, tds_log);
497 ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n");
517 return ASTERISK_GPL_KEY;