[netfilter-cvslog] r6878 - trunk/ulog/ulogd/mysql

pablo at netfilter.org pablo at netfilter.org
Tue Jun 19 13:33:56 CEST 2007


Author: pablo at netfilter.org
Date: 2007-06-19 13:33:55 +0200 (Tue, 19 Jun 2007)
New Revision: 6878

Modified:
   trunk/ulog/ulogd/mysql/ulogd_MYSQL.c
Log:
Marius Tomaschewski <mt at suse.de>

- included inttypes.h and changed to use PRId64/PRIu64 format definitions
  to use correct number of l's on all platforms (WORDSIZE depending).

- added str flag to the struct _field - it is set in the mysql_get_columns
  function when the IP-Addr columns in the database are non-numeric/string
  and used to insert proper converted value.
  See also the --with-mysql-log-ip-as-string configure option and doc dir.

- changed to use snprintf instead of sprintf to take care about the
  allocated buffer length: STMT_ADD macro

- added global stmt_siz variable for the allocated size of the stmt buffer
  (set in mysql_createstmt, used in mysql_output; obsoletes local size
   variable in mysql_createstmt).

- Added guard at the beginning of mysql_output() triggering reconnect
  if stmt_val == NULL.

- Fixed to check in mysql_output() if the buffer contains enough place for
  mysql_*escape_string calls -- see mysql documentation.

- Fixed to close the old db handle before reconnect is initiated on failure
  of mysql_real_query() in mysql_output.

- Increased size of allocated stmt buffer in mysql_createstmt() to +1.

- Fixed strncpy calls in mysql_createstmt and mysql_get_columns;
  use ULOGD_MAX_KEYLEN-1, not ULOGD_MAX_KEYLEN and terminate the buffer
  explicitelly after (in case the source string was longer / not term.).

- Fixed mysql_open_db() to close db handle after connect failure.

- Fixed _mysql_init_db() to close db handle after mysql_get_columns failure.

- Fixed _mysql_fini to call mysql_close(dbh) only if dbh not NULL and reset
  it to NULL after.


Modified: trunk/ulog/ulogd/mysql/ulogd_MYSQL.c
===================================================================
--- trunk/ulog/ulogd/mysql/ulogd_MYSQL.c	2007-06-15 00:07:36 UTC (rev 6877)
+++ trunk/ulog/ulogd/mysql/ulogd_MYSQL.c	2007-06-19 11:33:55 UTC (rev 6878)
@@ -43,6 +43,7 @@
 #include <ulogd/ulogd.h>
 #include <ulogd/conffile.h>
 #include <mysql/mysql.h>
+#include <inttypes.h>
 
 #ifdef DEBUG_MYSQL
 #define DEBUGP(x, args...)	fprintf(stderr, x, ## args)
@@ -53,6 +54,7 @@
 struct _field {
 	char name[ULOGD_MAX_KEYLEN];
 	unsigned int id;
+	unsigned int str;
 	struct _field *next;
 };
 
@@ -68,12 +70,21 @@
 /* buffer for our insert statement */
 static char *stmt;
 
+/* size of our insert statement buffer */
+static size_t stmt_siz;
+
 /* pointer to the beginning of the "VALUES" part */
 static char *stmt_val;
 
 /* pointer to current inser position in statement */
 static char *stmt_ins;
 
+#define STMT_ADD(fmt...) \
+	do { 								      \
+		if (stmt_ins >= stmt && stmt_siz > stmt_ins - stmt)            \
+			snprintf(stmt_ins, stmt_siz-(stmt_ins-stmt), ##fmt); \
+	} while(0)
+
 /* Attempt to reconnect if connection is lost */
 time_t reconnect = 0;
 #define TIME_ERR		((time_t)-1)	/* Be paranoid */
@@ -132,6 +143,7 @@
 };
 
 static int _mysql_init_db(ulog_iret_t *result);
+static void _mysql_fini(void);
 
 /* our main output function, called by ulogd */
 static int mysql_output(ulog_iret_t *result)
@@ -142,7 +154,13 @@
 	char *tmpstr;		/* need this for --log-ip-as-string */
 	struct in_addr addr;
 #endif
+	size_t esclen;
 
+	if (stmt_val == NULL) {
+		_mysql_fini();
+		return _mysql_init_db(result);
+	}
+
 	stmt_ins = stmt_val;
 
 	for (f = fields; f; f = f->next) {
@@ -155,60 +173,74 @@
 			
 		if (!res || !IS_VALID((*res))) {
 			/* no result, we have to fake something */
-			sprintf(stmt_ins, "NULL,");
+			STMT_ADD("NULL,");
 			stmt_ins = stmt + strlen(stmt);
 			continue;
 		}
 		
 		switch (res->type) {
 			case ULOGD_RET_INT8:
-				sprintf(stmt_ins, "%d,", res->value.i8);
+				STMT_ADD("%d,", res->value.i8);
 				break;
 			case ULOGD_RET_INT16:
-				sprintf(stmt_ins, "%d,", res->value.i16);
+				STMT_ADD("%d,", res->value.i16);
 				break;
 			case ULOGD_RET_INT32:
-				sprintf(stmt_ins, "%d,", res->value.i32);
+				STMT_ADD("%d,", res->value.i32);
 				break;
 			case ULOGD_RET_INT64:
-				sprintf(stmt_ins, "%lld,", res->value.i64);
+				STMT_ADD("%"PRId64",", res->value.i64);
 				break;
 			case ULOGD_RET_UINT8:
-				sprintf(stmt_ins, "%u,", res->value.ui8);
+				STMT_ADD("%u,", res->value.ui8);
 				break;
 			case ULOGD_RET_UINT16:
-				sprintf(stmt_ins, "%u,", res->value.ui16);
+				STMT_ADD("%u,", res->value.ui16);
 				break;
 			case ULOGD_RET_IPADDR:
 #ifdef IP_AS_STRING
-				memset(&addr, 0, sizeof(addr));
-				addr.s_addr = ntohl(res->value.ui32);
-				*stmt_ins++ = '\'';
-				tmpstr = inet_ntoa(addr);
+				if (f->str) {
+					addr.s_addr = ntohl(res->value.ui32);
+					tmpstr = inet_ntoa(addr);
+					esclen = (strlen(tmpstr)*2) + 4;
+					if (stmt_siz <= (stmt_ins-stmt)+esclen){
+						STMT_ADD("'',");
+						break;
+					}
+
+					*stmt_ins++ = '\'';
 #ifdef OLD_MYSQL
-				mysql_escape_string(stmt_ins, tmpstr,
-						    strlen(tmpstr));
+					mysql_escape_string(stmt_ins,
+							    tmpstr,
+							    strlen(tmpstr));
 #else
-				mysql_real_escape_string(dbh, stmt_ins,
-							 tmpstr,
-							 strlen(tmpstr));
+					mysql_real_escape_string(dbh, 
+								stmt_ins,
+								tmpstr,
+								strlen(tmpstr));
 #endif /* OLD_MYSQL */
-                                stmt_ins = stmt + strlen(stmt);
-                                sprintf(stmt_ins, "',");
-                                break;
+	                                stmt_ins = stmt + strlen(stmt);
+					STMT_ADD("',");
+					break;
+				}
 #endif /* IP_AS_STRING */
 				/* EVIL: fallthrough when logging IP as
 				 * u_int32_t */
 			case ULOGD_RET_UINT32:
-				sprintf(stmt_ins, "%u,", res->value.ui32);
+				STMT_ADD("%u,", res->value.ui32);
 				break;
 			case ULOGD_RET_UINT64:
-				sprintf(stmt_ins, "%llu,", res->value.ui64);
+				STMT_ADD("%"PRIu64",", res->value.ui64);
 				break;
 			case ULOGD_RET_BOOL:
-				sprintf(stmt_ins, "'%d',", res->value.b);
+				STMT_ADD("'%d',", res->value.b);
 				break;
 			case ULOGD_RET_STRING:
+				esclen = (strlen(res->value.ptr)*2) + 4;
+				if (stmt_siz <= (stmt_ins-stmt) + esclen) {
+					STMT_ADD("'',");
+					break;
+				}
 				*stmt_ins++ = '\'';
 #ifdef OLD_MYSQL
 				mysql_escape_string(stmt_ins, res->value.ptr,
@@ -218,8 +250,7 @@
 					res->value.ptr, strlen(res->value.ptr));
 #endif
 				stmt_ins = stmt + strlen(stmt);
-				sprintf(stmt_ins, "',");
-			/* sprintf(stmt_ins, "'%s',", res->value.ptr); */
+				STMT_ADD("',");
 				break;
 			case ULOGD_RET_RAW:
 				ulogd_log(ULOGD_NOTICE,
@@ -235,6 +266,8 @@
 		stmt_ins = stmt + strlen(stmt);
 	}
 	*(stmt_ins - 1) = ')';
+	*stmt_ins = '\0';
+
 	DEBUGP("stmt=#%s#\n", stmt);
 
 	/* now we have created our statement, insert it */
@@ -242,6 +275,7 @@
 	if (mysql_real_query(dbh, stmt, strlen(stmt))) {
 		ulogd_log(ULOGD_ERROR, "sql error during insert: %s\n",
 				mysql_error(dbh));
+		_mysql_fini();
 		return _mysql_init_db(result);
 	}
 
@@ -261,7 +295,6 @@
 static int mysql_createstmt(void)
 {
 	struct _field *f;
-	unsigned int size;
 	char buf[ULOGD_MAX_KEYLEN];
 	char *underscore;
 
@@ -269,36 +302,40 @@
 		free(stmt);
 
 	/* caclulate the size for the insert statement */
-	size = strlen(MYSQL_INSERTTEMPL) + strlen(table_ce.u.string);
+	stmt_siz = strlen(MYSQL_INSERTTEMPL) + strlen(table_ce.u.string) + 1;
 
 	for (f = fields; f; f = f->next) {
 		/* we need space for the key and a comma, as well as
 		 * enough space for the values */
-		size += strlen(f->name) + 1 + MYSQL_VALSIZE;
+		stmt_siz += strlen(f->name) + 1 + MYSQL_VALSIZE;
 	}	
 
-	ulogd_log(ULOGD_DEBUG, "allocating %u bytes for statement\n", size);
+	ulogd_log(ULOGD_DEBUG, "allocating %zu bytes for statement\n",
+				stmt_siz);
 
-	stmt = (char *) malloc(size);
+	stmt = (char *) malloc(stmt_siz);
 
 	if (!stmt) {
+		stmt_val = NULL;
+		stmt_siz = 0;
 		ulogd_log(ULOGD_ERROR, "OOM!\n");
 		return -1;
 	}
 
-	sprintf(stmt, "insert into %s (", table_ce.u.string);
+	snprintf(stmt, stmt_siz, "insert into %s (", table_ce.u.string);
 	stmt_val = stmt + strlen(stmt);
 
 	for (f = fields; f; f = f->next) {
-		strncpy(buf, f->name, ULOGD_MAX_KEYLEN);	
+		strncpy(buf, f->name, ULOGD_MAX_KEYLEN-1);
+		buf[ULOGD_MAX_KEYLEN-1] = '\0';
 		while ((underscore = strchr(buf, '.')))
 			*underscore = '_';
-		sprintf(stmt_val, "%s,", buf);
+		STMT_ADD(stmt_val,stmt,stmt_siz, "%s,", buf);
 		stmt_val = stmt + strlen(stmt);
 	}
 	*(stmt_val - 1) = ')';
 
-	sprintf(stmt_val, " values (");
+	STMT_ADD(stmt_val,stmt,stmt_siz, " values (");
 	stmt_val = stmt + strlen(stmt);
 
 	ulogd_log(ULOGD_DEBUG, "stmt='%s'\n", stmt);
@@ -333,7 +370,9 @@
 	while ((field = mysql_fetch_field(result))) {
 
 		/* replace all underscores with dots */
-		strncpy(buf, field->name, ULOGD_MAX_KEYLEN);
+		strncpy(buf, field->name, ULOGD_MAX_KEYLEN-1);
+		buf[ULOGD_MAX_KEYLEN-1] = '\0';
+
 		while ((underscore = strchr(buf, '_')))
 			*underscore = '.';
 
@@ -352,8 +391,10 @@
 			ulogd_log(ULOGD_ERROR, "OOM!\n");
 			return -1;
 		}
-		strncpy(f->name, buf, ULOGD_MAX_KEYLEN);
+		strncpy(f->name, buf, ULOGD_MAX_KEYLEN-1);
+		f->name[ULOGD_MAX_KEYLEN-1] = '\0';
 		f->id = id;
+		f->str = !IS_NUM(field->type);
 		f->next = fields;
 		fields = f;	
 	}
@@ -371,10 +412,14 @@
 		return -1;
 
 	if (connect_timeout_ce.u.value)
-		mysql_options(dbh, MYSQL_OPT_CONNECT_TIMEOUT, (const char *) &connect_timeout_ce.u.value);
+		mysql_options(dbh, MYSQL_OPT_CONNECT_TIMEOUT,
+			(const char *) &connect_timeout_ce.u.value);
 
 	if (!mysql_real_connect(dbh, server, user, pass, db, port, NULL, 0))
+	{
+		_mysql_fini();
 		return -1;
+	}
 
 	return 0;
 }
@@ -413,10 +458,17 @@
 	/* read the fieldnames to know which values to insert */
 	if (mysql_get_columns(table_ce.u.string)) {
 		ulogd_log(ULOGD_ERROR, "unable to get mysql columns\n");
+		_mysql_fini();
 		return init_reconnect();
 	}
-	mysql_createstmt();
-	
+
+	if (mysql_createstmt())
+	{
+		ulogd_log(ULOGD_ERROR, "unable to create mysql statement\n");
+		_mysql_fini();
+		return init_reconnect();
+	}
+
 	/* enable plugin */
 	mysql_plugin.output = &mysql_output;
 
@@ -438,7 +490,10 @@
 
 static void _mysql_fini(void)
 {
-	mysql_close(dbh);
+	if (dbh) {
+		mysql_close(dbh);
+		dbh = NULL;
+	}
 }
 
 static ulog_output_t mysql_plugin = { 




More information about the netfilter-cvslog mailing list