#include "asterisk.h"
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <math.h>
#include <tds.h>
#include <tdsconvert.h>
#include <ctype.h>
#include "asterisk/config.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
Go to the source code of this file.
Defines | |
#define | DATE_FORMAT "%Y/%m/%d %T" |
Functions | |
static char * | anti_injection (const char *, int) |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"MSSQL CDR Backend",.load=load_module,.unload=unload_module,.reload=reload,) | |
AST_MUTEX_DEFINE_STATIC (tds_lock) | |
static void | get_date (char *, size_t, struct timeval) |
static int | load_module (void) |
static int | mssql_connect (void) |
static int | mssql_disconnect (void) |
static int | reload (void) |
static int | tds_load_module (void) |
static int | tds_log (struct ast_cdr *cdr) |
static int | tds_unload_module (void) |
static int | unload_module (void) |
Variables | |
static char * | charset = NULL |
static char * | config = "cdr_tds.conf" |
static int | connected = 0 |
static TDSCONTEXT * | context |
static char * | dbname = NULL |
static char * | dbuser = NULL |
static int | has_userfield = 0 |
static char * | hostname = NULL |
static char * | language = NULL |
static TDSLOGIN * | login |
static char * | name = "mssql" |
static char * | password = NULL |
static char * | table = NULL |
static TDSSOCKET * | tds |
See also
Definition in file cdr_tds.c.
#define DATE_FORMAT "%Y/%m/%d %T" |
* * Table Structure for `cdr` * * Created on: 05/20/2004 16:16 * Last changed on: 07/27/2004 20:01 CREATE TABLE [dbo].[cdr] ( [accountcode] [varchar] (20) NULL , [src] [varchar] (80) NULL , [dst] [varchar] (80) NULL , [dcontext] [varchar] (80) NULL , [clid] [varchar] (80) NULL , [channel] [varchar] (80) NULL , [dstchannel] [varchar] (80) NULL , [lastapp] [varchar] (80) NULL , [lastdata] [varchar] (80) NULL , [start] [datetime] NULL , [answer] [datetime] NULL , [end] [datetime] NULL , [duration] [int] NULL , [billsec] [int] NULL , [disposition] [varchar] (20) NULL , [amaflags] [varchar] (16) NULL , [uniqueid] [varchar] (32) NULL , [userfield] [varchar] (256) NULL ) ON [PRIMARY]
static char * anti_injection | ( | const char * | , | |
int | ||||
) | [static] |
Definition at line 318 of file cdr_tds.c.
References ast_log(), LOG_ERROR, malloc, and strcasestr().
Referenced by tds_log().
00319 { 00320 /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */ 00321 00322 char *buf; 00323 char *buf_ptr, *srh_ptr; 00324 char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"}; 00325 int idx; 00326 00327 if ((buf = malloc(len + 1)) == NULL) 00328 { 00329 ast_log(LOG_ERROR, "cdr_tds: Out of memory error\n"); 00330 return NULL; 00331 } 00332 memset(buf, 0, len); 00333 00334 buf_ptr = buf; 00335 00336 /* Escape single quotes */ 00337 for (; *str && strlen(buf) < len; str++) 00338 { 00339 if (*str == '\'') 00340 *buf_ptr++ = '\''; 00341 *buf_ptr++ = *str; 00342 } 00343 *buf_ptr = '\0'; 00344 00345 /* Erase known bad input */ 00346 for (idx=0; *known_bad[idx]; idx++) 00347 { 00348 while((srh_ptr = strcasestr(buf, known_bad[idx]))) 00349 { 00350 memmove(srh_ptr, srh_ptr+strlen(known_bad[idx]), strlen(srh_ptr+strlen(known_bad[idx]))+1); 00351 } 00352 } 00353 00354 return buf; 00355 }
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT | , | |||
"MSSQL CDR Backend" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
AST_MUTEX_DEFINE_STATIC | ( | tds_lock | ) |
static void get_date | ( | char * | , | |
size_t | , | |||
struct | timeval | |||
) | [static] |
Definition at line 357 of file cdr_tds.c.
References ast_localtime(), DATE_FORMAT, and t.
00358 { 00359 struct tm tm; 00360 time_t t; 00361 char buf[80]; 00362 00363 /* To make sure we have date variable if not insert null to SQL */ 00364 if (!ast_tvzero(tv)) 00365 { 00366 t = tv.tv_sec; 00367 ast_localtime(&t, &tm, NULL); 00368 strftime(buf, sizeof(buf), DATE_FORMAT, &tm); 00369 snprintf(dateField, length, "'%s'", buf); 00370 } 00371 else 00372 { 00373 ast_copy_string(dateField, "null", length); 00374 } 00375 }
static int load_module | ( | void | ) | [static] |
Definition at line 613 of file cdr_tds.c.
References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and tds_load_module().
00614 { 00615 if(!tds_load_module()) 00616 return AST_MODULE_LOAD_DECLINE; 00617 else 00618 return AST_MODULE_LOAD_SUCCESS; 00619 }
static int mssql_connect | ( | void | ) | [static] |
Definition at line 399 of file cdr_tds.c.
References ast_log(), LOG_ERROR, LOG_NOTICE, and mssql_disconnect().
Referenced by tds_load_module(), and tds_log().
00400 { 00401 #if (defined(FREETDS_0_63) || defined(FREETDS_0_64)) 00402 TDSCONNECTION *connection = NULL; 00403 #else 00404 TDSCONNECTINFO *connection = NULL; 00405 #endif 00406 char query[512]; 00407 00408 /* Connect to M$SQL Server */ 00409 if (!(login = tds_alloc_login())) 00410 { 00411 ast_log(LOG_ERROR, "tds_alloc_login() failed.\n"); 00412 return -1; 00413 } 00414 00415 tds_set_server(login, hostname); 00416 tds_set_user(login, dbuser); 00417 tds_set_passwd(login, password); 00418 tds_set_app(login, "TSQL"); 00419 tds_set_library(login, "TDS-Library"); 00420 #ifndef FREETDS_PRE_0_62 00421 tds_set_client_charset(login, charset); 00422 #endif 00423 tds_set_language(login, language); 00424 tds_set_packet(login, 512); 00425 tds_set_version(login, 7, 0); 00426 00427 #ifdef FREETDS_0_64 00428 if (!(context = tds_alloc_context(NULL))) 00429 #else 00430 if (!(context = tds_alloc_context())) 00431 #endif 00432 { 00433 ast_log(LOG_ERROR, "tds_alloc_context() failed.\n"); 00434 goto connect_fail; 00435 } 00436 00437 if (!(tds = tds_alloc_socket(context, 512))) { 00438 ast_log(LOG_ERROR, "tds_alloc_socket() failed.\n"); 00439 goto connect_fail; 00440 } 00441 00442 tds_set_parent(tds, NULL); 00443 connection = tds_read_config_info(tds, login, context->locale); 00444 if (!connection) 00445 { 00446 ast_log(LOG_ERROR, "tds_read_config() failed.\n"); 00447 goto connect_fail; 00448 } 00449 00450 if (tds_connect(tds, connection) == TDS_FAIL) 00451 { 00452 ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n"); 00453 tds = NULL; /* freed by tds_connect() on error */ 00454 #if (defined(FREETDS_0_63) || defined(FREETDS_0_64)) 00455 tds_free_connection(connection); 00456 #else 00457 tds_free_connect(connection); 00458 #endif 00459 connection = NULL; 00460 goto connect_fail; 00461 } 00462 #if (defined(FREETDS_0_63) || defined(FREETDS_0_64)) 00463 tds_free_connection(connection); 00464 #else 00465 tds_free_connect(connection); 00466 #endif 00467 connection = NULL; 00468 00469 snprintf(query, sizeof(query), "USE %s", dbname); 00470 #ifdef FREETDS_PRE_0_62 00471 if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) 00472 #else 00473 if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) 00474 #endif 00475 { 00476 ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname); 00477 goto connect_fail; 00478 } 00479 00480 snprintf(query, sizeof(query), "SELECT 1 FROM %s", table); 00481 #ifdef FREETDS_PRE_0_62 00482 if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) 00483 #else 00484 if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) 00485 #endif 00486 { 00487 ast_log(LOG_ERROR, "Could not find table '%s' in database '%s'\n", table, dbname); 00488 goto connect_fail; 00489 } 00490 00491 has_userfield = 1; 00492 snprintf(query, sizeof(query), "SELECT userfield FROM %s WHERE 1 = 0", table); 00493 #ifdef FREETDS_PRE_0_62 00494 if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) 00495 #else 00496 if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) 00497 #endif 00498 { 00499 ast_log(LOG_NOTICE, "Unable to find 'userfield' column in table '%s'\n", table); 00500 has_userfield = 0; 00501 } 00502 00503 connected = 1; 00504 return 0; 00505 00506 connect_fail: 00507 mssql_disconnect(); 00508 return -1; 00509 }
static int mssql_disconnect | ( | void | ) | [static] |
Definition at line 377 of file cdr_tds.c.
Referenced by mssql_connect(), tds_log(), and tds_unload_module().
00378 { 00379 if (tds) { 00380 tds_free_socket(tds); 00381 tds = NULL; 00382 } 00383 00384 if (context) { 00385 tds_free_context(context); 00386 context = NULL; 00387 } 00388 00389 if (login) { 00390 tds_free_login(login); 00391 login = NULL; 00392 } 00393 00394 connected = 0; 00395 00396 return 0; 00397 }
static int reload | ( | void | ) | [static] |
Definition at line 607 of file cdr_tds.c.
References tds_load_module(), and tds_unload_module().
00608 { 00609 tds_unload_module(); 00610 return tds_load_module(); 00611 }
static int tds_load_module | ( | void | ) | [static] |
Definition at line 528 of file cdr_tds.c.
References ast_cdr_register(), ast_config_destroy(), ast_config_load(), ast_log(), ast_variable_browse(), ast_variable_retrieve(), LOG_DEBUG, LOG_ERROR, LOG_NOTICE, mssql_connect(), strdup, tds_log(), and var.
Referenced by load_module(), and reload().
00529 { 00530 int res = 0; 00531 struct ast_config *cfg; 00532 struct ast_variable *var; 00533 const char *ptr = NULL; 00534 #ifdef FREETDS_PRE_0_62 00535 TDS_INT result_type; 00536 #endif 00537 00538 cfg = ast_config_load(config); 00539 if (!cfg) { 00540 ast_log(LOG_NOTICE, "Unable to load config for MSSQL CDR's: %s\n", config); 00541 return 0; 00542 } 00543 00544 var = ast_variable_browse(cfg, "global"); 00545 if (!var) /* nothing configured */ { 00546 ast_config_destroy(cfg); 00547 return 0; 00548 } 00549 00550 ptr = ast_variable_retrieve(cfg, "global", "hostname"); 00551 if (ptr) 00552 hostname = strdup(ptr); 00553 else 00554 ast_log(LOG_ERROR,"Database server hostname not specified.\n"); 00555 00556 ptr = ast_variable_retrieve(cfg, "global", "dbname"); 00557 if (ptr) 00558 dbname = strdup(ptr); 00559 else 00560 ast_log(LOG_ERROR,"Database dbname not specified.\n"); 00561 00562 ptr = ast_variable_retrieve(cfg, "global", "user"); 00563 if (ptr) 00564 dbuser = strdup(ptr); 00565 else 00566 ast_log(LOG_ERROR,"Database dbuser not specified.\n"); 00567 00568 ptr = ast_variable_retrieve(cfg, "global", "password"); 00569 if (ptr) 00570 password = strdup(ptr); 00571 else 00572 ast_log(LOG_ERROR,"Database password not specified.\n"); 00573 00574 ptr = ast_variable_retrieve(cfg, "global", "charset"); 00575 if (ptr) 00576 charset = strdup(ptr); 00577 else 00578 charset = strdup("iso_1"); 00579 00580 ptr = ast_variable_retrieve(cfg, "global", "language"); 00581 if (ptr) 00582 language = strdup(ptr); 00583 else 00584 language = strdup("us_english"); 00585 00586 ptr = ast_variable_retrieve(cfg,"global","table"); 00587 if (ptr == NULL) { 00588 ast_log(LOG_DEBUG,"cdr_tds: table not specified. Assuming cdr\n"); 00589 ptr = "cdr"; 00590 } 00591 table = strdup(ptr); 00592 00593 ast_config_destroy(cfg); 00594 00595 mssql_connect(); 00596 00597 /* Register MSSQL CDR handler */ 00598 res = ast_cdr_register(name, ast_module_info->description, tds_log); 00599 if (res) 00600 { 00601 ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n"); 00602 } 00603 00604 return res; 00605 }
static int tds_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 113 of file cdr_tds.c.
References ast_cdr::accountcode, accountcode, ast_cdr::amaflags, ast_cdr::answer, answer, anti_injection(), ast_cdr_disp2str(), ast_cdr_flags2str(), ast_log(), AST_MAX_USER_FIELD, ast_mutex_lock(), ast_mutex_unlock(), ast_cdr::billsec, ast_cdr::channel, ast_cdr::clid, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, free, get_date(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_ERROR, LOG_WARNING, mssql_connect(), mssql_disconnect(), ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.
Referenced by tds_load_module().
00114 { 00115 char sqlcmd[2048], start[80], answer[80], end[80]; 00116 char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid, *userfield = NULL; 00117 int res = 0; 00118 int retried = 0; 00119 #ifdef FREETDS_PRE_0_62 00120 TDS_INT result_type; 00121 #endif 00122 00123 ast_mutex_lock(&tds_lock); 00124 00125 memset(sqlcmd, 0, 2048); 00126 00127 accountcode = anti_injection(cdr->accountcode, 20); 00128 src = anti_injection(cdr->src, 80); 00129 dst = anti_injection(cdr->dst, 80); 00130 dcontext = anti_injection(cdr->dcontext, 80); 00131 clid = anti_injection(cdr->clid, 80); 00132 channel = anti_injection(cdr->channel, 80); 00133 dstchannel = anti_injection(cdr->dstchannel, 80); 00134 lastapp = anti_injection(cdr->lastapp, 80); 00135 lastdata = anti_injection(cdr->lastdata, 80); 00136 uniqueid = anti_injection(cdr->uniqueid, 32); 00137 00138 if (has_userfield) { 00139 userfield = anti_injection(cdr->userfield, AST_MAX_USER_FIELD); 00140 } 00141 00142 get_date(start, sizeof(start), cdr->start); 00143 get_date(answer, sizeof(answer), cdr->answer); 00144 get_date(end, sizeof(end), cdr->end); 00145 00146 if (has_userfield) { 00147 snprintf( 00148 sqlcmd, 00149 sizeof(sqlcmd), 00150 "INSERT INTO %s " 00151 "(" 00152 "accountcode, " 00153 "src, " 00154 "dst, " 00155 "dcontext, " 00156 "clid, " 00157 "channel, " 00158 "dstchannel, " 00159 "lastapp, " 00160 "lastdata, " 00161 "start, " 00162 "answer, " 00163 "[end], " 00164 "duration, " 00165 "billsec, " 00166 "disposition, " 00167 "amaflags, " 00168 "uniqueid, " 00169 "userfield" 00170 ") " 00171 "VALUES " 00172 "(" 00173 "'%s', " /* accountcode */ 00174 "'%s', " /* src */ 00175 "'%s', " /* dst */ 00176 "'%s', " /* dcontext */ 00177 "'%s', " /* clid */ 00178 "'%s', " /* channel */ 00179 "'%s', " /* dstchannel */ 00180 "'%s', " /* lastapp */ 00181 "'%s', " /* lastdata */ 00182 "%s, " /* start */ 00183 "%s, " /* answer */ 00184 "%s, " /* end */ 00185 "%ld, " /* duration */ 00186 "%ld, " /* billsec */ 00187 "'%s', " /* disposition */ 00188 "'%s', " /* amaflags */ 00189 "'%s', " /* uniqueid */ 00190 "'%s'" /* userfield */ 00191 ")", 00192 table, 00193 accountcode, 00194 src, 00195 dst, 00196 dcontext, 00197 clid, 00198 channel, 00199 dstchannel, 00200 lastapp, 00201 lastdata, 00202 start, 00203 answer, 00204 end, 00205 cdr->duration, 00206 cdr->billsec, 00207 ast_cdr_disp2str(cdr->disposition), 00208 ast_cdr_flags2str(cdr->amaflags), 00209 uniqueid, 00210 userfield 00211 ); 00212 } else { 00213 snprintf( 00214 sqlcmd, 00215 sizeof(sqlcmd), 00216 "INSERT INTO %s " 00217 "(" 00218 "accountcode, " 00219 "src, " 00220 "dst, " 00221 "dcontext, " 00222 "clid, " 00223 "channel, " 00224 "dstchannel, " 00225 "lastapp, " 00226 "lastdata, " 00227 "start, " 00228 "answer, " 00229 "[end], " 00230 "duration, " 00231 "billsec, " 00232 "disposition, " 00233 "amaflags, " 00234 "uniqueid" 00235 ") " 00236 "VALUES " 00237 "(" 00238 "'%s', " /* accountcode */ 00239 "'%s', " /* src */ 00240 "'%s', " /* dst */ 00241 "'%s', " /* dcontext */ 00242 "'%s', " /* clid */ 00243 "'%s', " /* channel */ 00244 "'%s', " /* dstchannel */ 00245 "'%s', " /* lastapp */ 00246 "'%s', " /* lastdata */ 00247 "%s, " /* start */ 00248 "%s, " /* answer */ 00249 "%s, " /* end */ 00250 "%ld, " /* duration */ 00251 "%ld, " /* billsec */ 00252 "'%s', " /* disposition */ 00253 "'%s', " /* amaflags */ 00254 "'%s'" /* uniqueid */ 00255 ")", 00256 table, 00257 accountcode, 00258 src, 00259 dst, 00260 dcontext, 00261 clid, 00262 channel, 00263 dstchannel, 00264 lastapp, 00265 lastdata, 00266 start, 00267 answer, 00268 end, 00269 cdr->duration, 00270 cdr->billsec, 00271 ast_cdr_disp2str(cdr->disposition), 00272 ast_cdr_flags2str(cdr->amaflags), 00273 uniqueid 00274 ); 00275 } 00276 00277 do { 00278 if (!connected) { 00279 if (mssql_connect()) 00280 ast_log(LOG_ERROR, "Failed to reconnect to SQL database.\n"); 00281 else 00282 ast_log(LOG_WARNING, "Reconnected to SQL database.\n"); 00283 00284 retried = 1; /* note that we have now tried */ 00285 } 00286 00287 #ifdef FREETDS_PRE_0_62 00288 if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) 00289 #else 00290 if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) 00291 #endif 00292 { 00293 ast_log(LOG_ERROR, "Failed to insert Call Data Record into SQL database.\n"); 00294 00295 mssql_disconnect(); /* this is ok even if we are already disconnected */ 00296 } 00297 } while (!connected && !retried); 00298 00299 free(accountcode); 00300 free(src); 00301 free(dst); 00302 free(dcontext); 00303 free(clid); 00304 free(channel); 00305 free(dstchannel); 00306 free(lastapp); 00307 free(lastdata); 00308 free(uniqueid); 00309 if (userfield) { 00310 free(userfield); 00311 } 00312 00313 ast_mutex_unlock(&tds_lock); 00314 00315 return res; 00316 }
static int tds_unload_module | ( | void | ) | [static] |
Definition at line 511 of file cdr_tds.c.
References ast_cdr_unregister(), free, and mssql_disconnect().
Referenced by reload(), and unload_module().
00512 { 00513 mssql_disconnect(); 00514 00515 ast_cdr_unregister(name); 00516 00517 if (hostname) free(hostname); 00518 if (dbname) free(dbname); 00519 if (dbuser) free(dbuser); 00520 if (password) free(password); 00521 if (charset) free(charset); 00522 if (language) free(language); 00523 if (table) free(table); 00524 00525 return 0; 00526 }
static int unload_module | ( | void | ) | [static] |
Definition at line 621 of file cdr_tds.c.
References tds_unload_module().
00622 { 00623 return tds_unload_module(); 00624 }
char * dbname = NULL [static] |
Definition at line 95 of file cdr_tds.c.
Referenced by lookupcidname_exec(), parse_config(), pgsql_reconnect(), and realtime_pgsql_status().
char * dbuser = NULL [static] |
Definition at line 95 of file cdr_tds.c.
Referenced by parse_config(), pgsql_reconnect(), and realtime_pgsql_status().
int has_userfield = 0 [static] |