73 #ifdef FREETDS_PRE_0_62
74 #warning "You have older TDS, you should upgrade!"
77 #define DATE_FORMAT "%Y/%m/%d %T"
79 #define TDS_BACKEND_NAME "CEL TDS logging backend"
81 static char *config =
"cel_tds.conf";
94 unsigned int connected:1;
97 AST_MUTEX_DEFINE_STATIC(tds_lock);
101 static char *anti_injection(
const char *,
int);
102 static void get_date(
char *,
size_t len,
struct timeval);
104 static int execute_and_consume(DBPROCESS *dbproc,
const char *fmt, ...)
105 __attribute__((format(printf, 2, 3)));
107 static
int mssql_connect(
void);
108 static
int mssql_disconnect(
void);
113 char *accountcode_ai, *clidnum_ai, *exten_ai, *context_ai, *clid_ai, *channel_ai, *app_ai, *appdata_ai, *uniqueid_ai, *linkedid_ai, *cidani_ai, *cidrdnis_ai, *ciddnid_ai, *peer_ai, *userfield_ai;
124 ast_mutex_lock(&tds_lock);
126 accountcode_ai = anti_injection(record.account_code, 20);
127 clidnum_ai = anti_injection(record.caller_id_num, 80);
128 clid_ai = anti_injection(record.caller_id_name, 80);
129 cidani_ai = anti_injection(record.caller_id_ani, 80);
130 cidrdnis_ai = anti_injection(record.caller_id_rdnis, 80);
131 ciddnid_ai = anti_injection(record.caller_id_dnid, 80);
132 exten_ai = anti_injection(record.extension, 80);
133 context_ai = anti_injection(record.context, 80);
134 channel_ai = anti_injection(record.channel_name, 80);
135 app_ai = anti_injection(record.application_name, 80);
136 appdata_ai = anti_injection(record.application_data, 80);
137 uniqueid_ai = anti_injection(record.unique_id, 32);
138 linkedid_ai = anti_injection(record.linked_id, 32);
139 userfield_ai = anti_injection(record.user_field, 32);
140 peer_ai = anti_injection(record.peer, 32);
142 get_date(start,
sizeof(start), record.event_time);
146 if (!settings->connected) {
147 ast_log(LOG_NOTICE,
"Attempting to reconnect to %s (Attempt %d)\n", settings->connection, attempt);
148 if (mssql_connect()) {
157 erc = dbfcmd(settings->dbproc,
200 settings->table, accountcode_ai, clidnum_ai, clid_ai, cidani_ai, cidrdnis_ai,
201 ciddnid_ai, exten_ai, context_ai, channel_ai, app_ai, appdata_ai, start,
203 ? record.user_defined_name : record.event_name,
205 userfield_ai, peer_ai);
209 ast_log(LOG_NOTICE,
"Failed to build INSERT statement, retrying...\n");
213 ast_log(LOG_ERROR,
"Failed to build INSERT statement, no CEL was logged.\n");
218 if (dbsqlexec(settings->dbproc) == FAIL) {
220 ast_log(LOG_NOTICE,
"Failed to execute INSERT statement, retrying...\n");
224 ast_log(LOG_ERROR,
"Failed to execute INSERT statement, no CEL was logged.\n");
231 while (dbresults(settings->dbproc) != NO_MORE_RESULTS) {
232 while (dbnextrow(settings->dbproc) != NO_MORE_ROWS);
236 ast_mutex_unlock(&tds_lock);
238 ast_free(accountcode_ai);
239 ast_free(clidnum_ai);
242 ast_free(cidrdnis_ai);
243 ast_free(ciddnid_ai);
245 ast_free(context_ai);
246 ast_free(channel_ai);
248 ast_free(appdata_ai);
249 ast_free(uniqueid_ai);
250 ast_free(linkedid_ai);
251 ast_free(userfield_ai);
257 static char *anti_injection(
const char *str,
int len)
261 char *buf_ptr, *srh_ptr;
262 char *known_bad[] = {
"select",
"insert",
"update",
"delete",
"drop",
";",
"--",
"\0"};
266 ast_log(LOG_ERROR,
"Out of memory\n");
273 for (; *str && strlen(buf) < len; str++) {
282 for (idx = 0; *known_bad[idx]; idx++) {
283 while ((srh_ptr = strcasestr(buf, known_bad[idx]))) {
284 memmove(srh_ptr, srh_ptr + strlen(known_bad[idx]), strlen(srh_ptr + strlen(known_bad[idx])) + 1);
290 static void get_date(
char *dateField,
size_t len,
struct timeval when)
302 static int execute_and_consume(DBPROCESS *dbproc,
const char *fmt, ...)
314 if (dbfcmd(dbproc, buffer) == FAIL) {
321 if (dbsqlexec(dbproc) == FAIL) {
326 while (dbresults(dbproc) != NO_MORE_RESULTS) {
327 while (dbnextrow(dbproc) != NO_MORE_ROWS);
333 static int mssql_disconnect(
void)
335 if (settings->dbproc) {
336 dbclose(settings->dbproc);
337 settings->dbproc = NULL;
339 settings->connected = 0;
344 static int mssql_connect(
void)
348 if ((login = dblogin()) == NULL) {
349 ast_log(LOG_ERROR,
"Unable to allocate login structure for db-lib\n");
353 DBSETLAPP(login,
"TSQL");
354 DBSETLUSER(login, (
char *) settings->username);
355 DBSETLPWD(login, (
char *) settings->password);
357 if (!ast_strlen_zero(settings->charset)) {
358 DBSETLCHARSET(login, (
char *) settings->charset);
361 if (!ast_strlen_zero(settings->language)) {
362 DBSETLNATLANG(login, (
char *) settings->language);
365 if ((settings->dbproc = dbopen(login, (
char *) settings->connection)) == NULL) {
366 ast_log(LOG_ERROR,
"Unable to connect to %s\n", settings->connection);
373 if (dbuse(settings->dbproc, (
char *) settings->database) == FAIL) {
374 ast_log(LOG_ERROR,
"Unable to select database %s\n", settings->database);
378 if (execute_and_consume(settings->dbproc,
"SELECT 1 FROM [%s]", settings->table)) {
379 ast_log(LOG_ERROR,
"Unable to find table '%s'\n", settings->table);
383 settings->connected = 1;
388 dbclose(settings->dbproc);
389 settings->dbproc = NULL;
393 static int tds_unload_module(
void)
398 ast_mutex_lock(&tds_lock);
400 ast_mutex_unlock(&tds_lock);
411 static int tds_error_handler(DBPROCESS *dbproc,
int severity,
int dberr,
int oserr,
char *dberrstr,
char *oserrstr)
413 ast_log(LOG_ERROR,
"%s (%d)\n", dberrstr, dberr);
415 if (oserr != DBNOERR) {
416 ast_log(LOG_ERROR,
"%s (%d)\n", oserrstr, oserr);
422 static int tds_message_handler(DBPROCESS *dbproc, DBINT msgno,
int msgstate,
int severity,
char *msgtext,
char *srvname,
char *procname,
int line)
424 ast_debug(1,
"Msg %d, Level %d, State %d, Line %d\n", msgno, severity, msgstate, line);
425 ast_log(LOG_NOTICE,
"%s\n", msgtext);
430 static int tds_load_module(
int reload)
433 const char *ptr = NULL;
437 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
438 ast_log(LOG_NOTICE,
"Unable to load TDS config for CELs: %s\n", config);
440 }
else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
444 if (!ast_variable_browse(cfg,
"global")) {
447 ast_log(LOG_NOTICE,
"cel_tds has no global category, nothing to configure.\n");
451 ast_mutex_lock(&tds_lock);
456 ptr = ast_variable_retrieve(cfg,
"global",
"connection");
460 ast_log(LOG_ERROR,
"Failed to connect: Database connection name not specified.\n");
464 ptr = ast_variable_retrieve(cfg,
"global",
"dbname");
468 ast_log(LOG_ERROR,
"Failed to connect: Database dbname not specified.\n");
472 ptr = ast_variable_retrieve(cfg,
"global",
"user");
476 ast_log(LOG_ERROR,
"Failed to connect: Database dbuser not specified.\n");
480 ptr = ast_variable_retrieve(cfg,
"global",
"password");
484 ast_log(LOG_ERROR,
"Failed to connect: Database password not specified.\n");
488 ptr = ast_variable_retrieve(cfg,
"global",
"charset");
493 ptr = ast_variable_retrieve(cfg,
"global",
"language");
498 ptr = ast_variable_retrieve(cfg,
"global",
"table");
502 ast_log(LOG_NOTICE,
"Table name not specified, using 'cel' by default.\n");
508 if (mssql_connect()) {
513 ast_mutex_unlock(&tds_lock);
519 ast_mutex_unlock(&tds_lock);
525 static int reload(
void)
527 return tds_load_module(1);
530 static int load_module(
void)
532 if (dbinit() == FAIL) {
533 ast_log(LOG_ERROR,
"Failed to initialize FreeTDS db-lib\n");
537 dberrhandle(tds_error_handler);
538 dbmsghandle(tds_message_handler);
547 if (!tds_load_module(0)) {
552 ast_log(LOG_WARNING,
"cel_tds module had config problems; declining load\n");
558 ast_log(LOG_ERROR,
"Unable to register MSSQL CEL handling\n");
569 static int unload_module(
void)
571 return tds_unload_module();
574 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"FreeTDS CEL Backend",
575 .support_level = AST_MODULE_SUPPORT_EXTENDED,
577 .unload = unload_module,
Helper struct for getting the fields out of a CEL event.
Asterisk main include file. File version handling, generic pbx functions.
Time-related functions and macros.
int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
Register a CEL backend.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define ast_vasprintf(ret, fmt, ap)
A wrapper for vasprintf()
static int get_date(char *s, int len)
Gets the current date and time, as formatted string.
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
General Asterisk PBX channel definitions.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define AST_STRING_FIELD(name)
Declare a string field.
uint32_t version
struct ABI version
#define ast_debug(level,...)
Log a DEBUG message.
int ast_cel_backend_unregister(const char *name)
Unregister a CEL backend.
#define ast_calloc(num, len)
A wrapper for calloc()
Support for logging to various files, console and syslog Configuration in file logger.conf.
Module has failed to load, may be in an inconsistent state.
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
#define AST_CEL_EVENT_RECORD_VERSION
struct ABI version
Structure used to handle boolean flags.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
a user-defined event, the event name field should be set
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
int ast_cel_fill_record(const struct ast_event *event, struct ast_cel_event_record *r)
Fill in an ast_cel_event_record from a CEL event.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.