#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.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 | |
char * | anti_injection (const char *, int) |
AST_MUTEX_DEFINE_STATIC (tds_lock) | |
char * | description (void) |
Provides a description of the module. | |
void | get_date (char *, struct timeval) |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
int | load_module (void) |
Initialize the module. | |
int | mssql_connect (void) |
int | mssql_disconnect (void) |
int | reload (void) |
Reload stuff. | |
int | tds_load_module (void) |
int | tds_log (struct ast_cdr *cdr) |
int | tds_unload_module (void) |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
int | usecount (void) |
Provides a usecount. | |
Variables | |
char * | config = "cdr_tds.conf" |
int | connected = 0 |
TDSCONTEXT * | context |
char * | desc = "MSSQL CDR Backend" |
char * | hostname = NULL *dbname = NULL *dbuser = NULL *password = NULL *charset = NULL *language = NULL |
TDSLOGIN * | login |
char * | name = "mssql" |
TDSSOCKET * | tds |
See also
Definition in file cdr_tds.c.
|
* * 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 ) ON [PRIMARY] |
|
Definition at line 235 of file cdr_tds.c. References ast_log(), LOG_ERROR, malloc, and strcasestr(). Referenced by tds_log(). 00236 { 00237 /* Reference to http://www.nextgenss.com/papers/advanced_sql_injection.pdf */ 00238 00239 char *buf; 00240 char *buf_ptr, *srh_ptr; 00241 char *known_bad[] = {"select", "insert", "update", "delete", "drop", ";", "--", "\0"}; 00242 int idx; 00243 00244 if ((buf = malloc(len + 1)) == NULL) 00245 { 00246 ast_log(LOG_ERROR, "cdr_tds: Out of memory error\n"); 00247 return NULL; 00248 } 00249 memset(buf, 0, len); 00250 00251 buf_ptr = buf; 00252 00253 /* Escape single quotes */ 00254 for (; *str && strlen(buf) < len; str++) 00255 { 00256 if (*str == '\'') 00257 *buf_ptr++ = '\''; 00258 *buf_ptr++ = *str; 00259 } 00260 *buf_ptr = '\0'; 00261 00262 /* Erase known bad input */ 00263 for (idx=0; *known_bad[idx]; idx++) 00264 { 00265 while((srh_ptr = strcasestr(buf, known_bad[idx]))) 00266 { 00267 memmove(srh_ptr, srh_ptr+strlen(known_bad[idx]), strlen(srh_ptr+strlen(known_bad[idx]))+1); 00268 } 00269 } 00270 00271 return buf; 00272 }
|
|
|
|
Provides a description of the module.
Definition at line 294 of file cdr_tds.c. 00295 {
00296 return desc;
00297 }
|
|
Definition at line 274 of file cdr_tds.c. References DATE_FORMAT, and tv. Referenced by leave_voicemail(), and tds_log(). 00275 { 00276 struct tm tm; 00277 time_t t; 00278 char buf[80]; 00279 00280 /* To make sure we have date variable if not insert null to SQL */ 00281 if (!ast_tvzero(tv)) 00282 { 00283 t = tv.tv_sec; 00284 localtime_r(&t, &tm); 00285 strftime(buf, 80, DATE_FORMAT, &tm); 00286 sprintf(dateField, "'%s'", buf); 00287 } 00288 else 00289 { 00290 strcpy(dateField, "null"); 00291 } 00292 }
|
|
Returns the ASTERISK_GPL_KEY. This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:
char *key(void) { return ASTERISK_GPL_KEY; }
Definition at line 519 of file cdr_tds.c. 00520 {
00521 return ASTERISK_GPL_KEY;
00522 }
|
|
Initialize the module. Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
Definition at line 498 of file cdr_tds.c. References tds_load_module(). 00499 { 00500 return tds_load_module(); 00501 }
|
|
Definition at line 321 of file cdr_tds.c. References ast_log(), connected, context, hostname, LOG_ERROR, login, mssql_disconnect(), and tds. Referenced by tds_load_module(), and tds_log(). 00322 { 00323 #ifdef FREETDS_0_63 00324 TDSCONNECTION *connection = NULL; 00325 #else 00326 TDSCONNECTINFO *connection = NULL; 00327 #endif 00328 char query[128]; 00329 00330 /* Connect to M$SQL Server */ 00331 if (!(login = tds_alloc_login())) 00332 { 00333 ast_log(LOG_ERROR, "tds_alloc_login() failed.\n"); 00334 return -1; 00335 } 00336 00337 tds_set_server(login, hostname); 00338 tds_set_user(login, dbuser); 00339 tds_set_passwd(login, password); 00340 tds_set_app(login, "TSQL"); 00341 tds_set_library(login, "TDS-Library"); 00342 #ifndef FREETDS_PRE_0_62 00343 tds_set_client_charset(login, charset); 00344 #endif 00345 tds_set_language(login, language); 00346 tds_set_packet(login, 512); 00347 tds_set_version(login, 7, 0); 00348 00349 if (!(context = tds_alloc_context())) 00350 { 00351 ast_log(LOG_ERROR, "tds_alloc_context() failed.\n"); 00352 goto connect_fail; 00353 } 00354 00355 if (!(tds = tds_alloc_socket(context, 512))) { 00356 ast_log(LOG_ERROR, "tds_alloc_socket() failed.\n"); 00357 goto connect_fail; 00358 } 00359 00360 tds_set_parent(tds, NULL); 00361 connection = tds_read_config_info(tds, login, context->locale); 00362 if (!connection) 00363 { 00364 ast_log(LOG_ERROR, "tds_read_config() failed.\n"); 00365 goto connect_fail; 00366 } 00367 00368 if (tds_connect(tds, connection) == TDS_FAIL) 00369 { 00370 ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n"); 00371 tds = NULL; /* freed by tds_connect() on error */ 00372 #ifdef FREETDS_0_63 00373 tds_free_connection(connection); 00374 #else 00375 tds_free_connect(connection); 00376 #endif 00377 connection = NULL; 00378 goto connect_fail; 00379 } 00380 #ifdef FREETDS_0_63 00381 tds_free_connection(connection); 00382 #else 00383 tds_free_connect(connection); 00384 #endif 00385 connection = NULL; 00386 00387 sprintf(query, "USE %s", dbname); 00388 #ifdef FREETDS_PRE_0_62 00389 if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) 00390 #else 00391 if ((tds_submit_query(tds, query) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) 00392 #endif 00393 { 00394 ast_log(LOG_ERROR, "Could not change database (%s)\n", dbname); 00395 goto connect_fail; 00396 } 00397 00398 connected = 1; 00399 return 0; 00400 00401 connect_fail: 00402 mssql_disconnect(); 00403 return -1; 00404 }
|
|
Definition at line 299 of file cdr_tds.c. References connected, context, login, and tds. Referenced by mssql_connect(), tds_log(), and tds_unload_module(). 00300 { 00301 if (tds) { 00302 tds_free_socket(tds); 00303 tds = NULL; 00304 } 00305 00306 if (context) { 00307 tds_free_context(context); 00308 context = NULL; 00309 } 00310 00311 if (login) { 00312 tds_free_login(login); 00313 login = NULL; 00314 } 00315 00316 connected = 0; 00317 00318 return 0; 00319 }
|
|
Reload stuff. This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.
Definition at line 492 of file cdr_tds.c. References tds_load_module(), and tds_unload_module(). 00493 { 00494 tds_unload_module(); 00495 return tds_load_module(); 00496 }
|
|
Definition at line 422 of file cdr_tds.c. References ast_cdr_register(), ast_config_destroy(), ast_config_load(), ast_log(), ast_variable_browse(), ast_variable_retrieve(), cfg, config, desc, hostname, LOG_ERROR, LOG_NOTICE, mssql_connect(), name, strdup, tds_log(), and var. Referenced by load_module(), and reload(). 00423 { 00424 int res = 0; 00425 struct ast_config *cfg; 00426 struct ast_variable *var; 00427 char *ptr = NULL; 00428 #ifdef FREETDS_PRE_0_62 00429 TDS_INT result_type; 00430 #endif 00431 00432 cfg = ast_config_load(config); 00433 if (!cfg) { 00434 ast_log(LOG_NOTICE, "Unable to load config for MSSQL CDR's: %s\n", config); 00435 return 0; 00436 } 00437 00438 var = ast_variable_browse(cfg, "global"); 00439 if (!var) /* nothing configured */ 00440 return 0; 00441 00442 ptr = ast_variable_retrieve(cfg, "global", "hostname"); 00443 if (ptr) 00444 hostname = strdup(ptr); 00445 else 00446 ast_log(LOG_ERROR,"Database server hostname not specified.\n"); 00447 00448 ptr = ast_variable_retrieve(cfg, "global", "dbname"); 00449 if (ptr) 00450 dbname = strdup(ptr); 00451 else 00452 ast_log(LOG_ERROR,"Database dbname not specified.\n"); 00453 00454 ptr = ast_variable_retrieve(cfg, "global", "user"); 00455 if (ptr) 00456 dbuser = strdup(ptr); 00457 else 00458 ast_log(LOG_ERROR,"Database dbuser not specified.\n"); 00459 00460 ptr = ast_variable_retrieve(cfg, "global", "password"); 00461 if (ptr) 00462 password = strdup(ptr); 00463 else 00464 ast_log(LOG_ERROR,"Database password not specified.\n"); 00465 00466 ptr = ast_variable_retrieve(cfg, "global", "charset"); 00467 if (ptr) 00468 charset = strdup(ptr); 00469 else 00470 charset = strdup("iso_1"); 00471 00472 ptr = ast_variable_retrieve(cfg, "global", "language"); 00473 if (ptr) 00474 language = strdup(ptr); 00475 else 00476 language = strdup("us_english"); 00477 00478 ast_config_destroy(cfg); 00479 00480 mssql_connect(); 00481 00482 /* Register MSSQL CDR handler */ 00483 res = ast_cdr_register(name, desc, tds_log); 00484 if (res) 00485 { 00486 ast_log(LOG_ERROR, "Unable to register MSSQL CDR handling\n"); 00487 } 00488 00489 return res; 00490 }
|
|
Definition at line 107 of file cdr_tds.c. References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, anti_injection(), ast_cdr_disp2str(), ast_cdr_flags2str(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_cdr::billsec, ast_cdr::channel, ast_cdr::clid, connected, 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, tds, and ast_cdr::uniqueid. Referenced by tds_load_module(). 00108 { 00109 char sqlcmd[2048], start[80], answer[80], end[80]; 00110 char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid; 00111 int res = 0; 00112 int retried = 0; 00113 #ifdef FREETDS_PRE_0_62 00114 TDS_INT result_type; 00115 #endif 00116 00117 ast_mutex_lock(&tds_lock); 00118 00119 memset(sqlcmd, 0, 2048); 00120 00121 accountcode = anti_injection(cdr->accountcode, 20); 00122 src = anti_injection(cdr->src, 80); 00123 dst = anti_injection(cdr->dst, 80); 00124 dcontext = anti_injection(cdr->dcontext, 80); 00125 clid = anti_injection(cdr->clid, 80); 00126 channel = anti_injection(cdr->channel, 80); 00127 dstchannel = anti_injection(cdr->dstchannel, 80); 00128 lastapp = anti_injection(cdr->lastapp, 80); 00129 lastdata = anti_injection(cdr->lastdata, 80); 00130 uniqueid = anti_injection(cdr->uniqueid, 32); 00131 00132 get_date(start, cdr->start); 00133 get_date(answer, cdr->answer); 00134 get_date(end, cdr->end); 00135 00136 sprintf( 00137 sqlcmd, 00138 "INSERT INTO cdr " 00139 "(" 00140 "accountcode, " 00141 "src, " 00142 "dst, " 00143 "dcontext, " 00144 "clid, " 00145 "channel, " 00146 "dstchannel, " 00147 "lastapp, " 00148 "lastdata, " 00149 "start, " 00150 "answer, " 00151 "[end], " 00152 "duration, " 00153 "billsec, " 00154 "disposition, " 00155 "amaflags, " 00156 "uniqueid" 00157 ") " 00158 "VALUES " 00159 "(" 00160 "'%s', " /* accountcode */ 00161 "'%s', " /* src */ 00162 "'%s', " /* dst */ 00163 "'%s', " /* dcontext */ 00164 "'%s', " /* clid */ 00165 "'%s', " /* channel */ 00166 "'%s', " /* dstchannel */ 00167 "'%s', " /* lastapp */ 00168 "'%s', " /* lastdata */ 00169 "%s, " /* start */ 00170 "%s, " /* answer */ 00171 "%s, " /* end */ 00172 "%ld, " /* duration */ 00173 "%ld, " /* billsec */ 00174 "'%s', " /* disposition */ 00175 "'%s', " /* amaflags */ 00176 "'%s'" /* uniqueid */ 00177 ")", 00178 accountcode, 00179 src, 00180 dst, 00181 dcontext, 00182 clid, 00183 channel, 00184 dstchannel, 00185 lastapp, 00186 lastdata, 00187 start, 00188 answer, 00189 end, 00190 cdr->duration, 00191 cdr->billsec, 00192 ast_cdr_disp2str(cdr->disposition), 00193 ast_cdr_flags2str(cdr->amaflags), 00194 uniqueid 00195 ); 00196 00197 do { 00198 if (!connected) { 00199 if (mssql_connect()) 00200 ast_log(LOG_ERROR, "Failed to reconnect to SQL database.\n"); 00201 else 00202 ast_log(LOG_WARNING, "Reconnected to SQL database.\n"); 00203 00204 retried = 1; /* note that we have now tried */ 00205 } 00206 00207 #ifdef FREETDS_PRE_0_62 00208 if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) 00209 #else 00210 if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) 00211 #endif 00212 { 00213 ast_log(LOG_ERROR, "Failed to insert Call Data Record into SQL database.\n"); 00214 00215 mssql_disconnect(); /* this is ok even if we are already disconnected */ 00216 } 00217 } while (!connected && !retried); 00218 00219 free(accountcode); 00220 free(src); 00221 free(dst); 00222 free(dcontext); 00223 free(clid); 00224 free(channel); 00225 free(dstchannel); 00226 free(lastapp); 00227 free(lastdata); 00228 free(uniqueid); 00229 00230 ast_mutex_unlock(&tds_lock); 00231 00232 return res; 00233 }
|
|
Definition at line 406 of file cdr_tds.c. References ast_cdr_unregister(), free, hostname, mssql_disconnect(), and name. Referenced by reload(), and unload_module(). 00407 { 00408 mssql_disconnect(); 00409 00410 ast_cdr_unregister(name); 00411 00412 if (hostname) free(hostname); 00413 if (dbname) free(dbname); 00414 if (dbuser) free(dbuser); 00415 if (password) free(password); 00416 if (charset) free(charset); 00417 if (language) free(language); 00418 00419 return 0; 00420 }
|
|
Cleanup all module structures, sockets, etc. This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).
Definition at line 503 of file cdr_tds.c. References tds_unload_module(). 00504 { 00505 return tds_unload_module(); 00506 }
|
|
Provides a usecount. This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.
Definition at line 508 of file cdr_tds.c. References ast_mutex_trylock(), and ast_mutex_unlock(). 00509 { 00510 /* Simplistic use count */ 00511 if (ast_mutex_trylock(&tds_lock)) { 00512 return 1; 00513 } else { 00514 ast_mutex_unlock(&tds_lock); 00515 return 0; 00516 } 00517 }
|
|
Definition at line 89 of file cdr_tds.c. Referenced by tds_load_module(). |
|
Definition at line 93 of file cdr_tds.c. Referenced by mssql_connect(), mssql_disconnect(), and tds_log(). |
|
Definition at line 99 of file cdr_tds.c. Referenced by mssql_connect(), and mssql_disconnect(). |
|
Definition at line 87 of file cdr_tds.c. Referenced by tds_load_module(). |
|
Definition at line 91 of file cdr_tds.c. Referenced by mssql_connect(), tds_load_module(), and tds_unload_module(). |
|
Definition at line 98 of file cdr_tds.c. Referenced by mssql_connect(), and mssql_disconnect(). |
|
|
|
Definition at line 97 of file cdr_tds.c. Referenced by mssql_connect(), mssql_disconnect(), and tds_log(). |