/* it was sent to me few months ago, but i can't remember the autor */
/* of this patch. if you wrote below code, contact me, i want to */
/* place credits here. */ 

/*
*
* sqlsyslogd
*
* $Log: sqlsyslogd.c,v $
* Revision 1.2  2002/01/05 16:29:36  venglin
* Bugfix
*
* Revision 1.1.1.1  2001/05/21 15:31:50  venglin
* initial import into CVS
*
*
*/

#define _STRPTIME_DONTZERO "use this for non-zeroing strptime behavior"

#include <mysql/mysql.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <pwd.h>
#include <time.h>
#include <sys/types.h>

#define CR		13
#define LF		10

MYSQL db;

static const char rcsid[] =
  "$Id: sqlsyslogd.c,v 1.2 2002/01/05 16:29:36 venglin Exp $";

void usage(av0)
char *av0;
{
	fprintf(stderr, "usage: %s [-h hostname] <-u username> [-p]"
				" <-t table> [database]\n\n", av0);
	exit(0);
}	

void cleanup(x)
int x;
{
	mysql_close(&db);
	exit(0);
}

char *password(void)
{
	FILE *fp;
	static char passwd[BUFSIZ/16];
	char *p;

	if ((fp=fopen(CONF, "r")) == NULL)
		return NULL;

	fgets(passwd, sizeof(passwd), fp);

	if ((p = index(passwd, CR)))
		*p = '\0';
	if ((p = index(passwd, LF)))
		*p = '\0';

	fclose(fp);

	return passwd;
}
	

int main(argc, argv)
int argc;
char **argv;
{
	FILE *debugFile = NULL;
	char theDate[32];
	extern char *optarg;
	extern int optind;
        int ch;
	char buf[BUFSIZ], querybuf[BUFSIZ+100];
	char *loghost, *host, *user, *passwd, *av0, *table, *logprog, *logid;
	char *loglevel, *logmesg, *logfacility;
	struct passwd *pw;
	gid_t nobodygid;
	uid_t nobodyuid;
	av0 = argv[0];
	loghost = host = user = passwd = table = logprog = logmesg = NULL;

	while ((ch = getopt(argc, argv, "d:h:u:pt:")) != -1)
		switch((char)ch)
		{
			case 'h':
				host = optarg;
				break;

			case 'u':
				user = optarg;
				break;

			case 'p':
				passwd = password();
				break;

			case 't':
				table = optarg;
				break;

			case 'd':
				debugFile = fopen(optarg, "a");
				break;

			case '?':
			default:
					(void)usage(av0);
		}

	argc -= optind;
	argv += optind;

	if (!user || !table)
		(void)usage(av0);

	if (argc < 1)
		(void)usage(av0);

	if ((pw = getpwnam("nobody")) == NULL)
	{
		perror("getpwnam");
		exit(1);
	}

	nobodyuid = pw->pw_uid;
	nobodygid = pw->pw_gid;

	if (setgid(nobodygid) == -1)
	{
		perror("setgid");
		exit(1);
        }

	if (getgid() != nobodygid)
	{
		fprintf(stderr, "getgid() != nobodygid\n");
		exit(1);
	}

	if (setuid(nobodyuid) == -1)
	{
		perror("setuid");
		exit(1);
	}

	if (getuid() != nobodyuid)
	{
		fprintf(stderr, "getuid() != nobodyuid\n");
		exit(1);
	}

	mysql_init(&db);

	if (!mysql_real_connect(&db, host, user, passwd, *argv, 0, NULL, 0))
	{
		fprintf(stderr, "failed to connect to database: %s\n",
			mysql_error(&db));
		exit(1);
	}

	signal(SIGHUP, cleanup);
	signal(SIGINT, cleanup);
	signal(SIGQUIT, cleanup);
	signal(SIGTERM, cleanup);
	signal(SIGSEGV, cleanup);
	signal(SIGBUS, cleanup);

	while(fgets(buf, sizeof(buf), stdin))
	{
		if (debugFile) fprintf(debugFile, "buffer: %s\n", buf);

		if (strlen(buf) > 18)
		{
			time_t theTime = time(NULL);
			struct tm *mytime = localtime(&theTime);
			char *theBuf = index(buf, '>') + 1;

			if (debugFile)
			{
				fprintf(debugFile, "  theBuf  : %s\n", theBuf);
			}

			loghost = strtok(theBuf + 16, " ");
			logprog = strtok(NULL, ":");
			logmesg = theBuf + 16 + strlen(loghost) +
				strlen(logprog) + 3;

			if (debugFile)
			{
				fprintf(debugFile, "  loghost : %s\n", loghost);
				fprintf(debugFile, "  logprog : %s\n", logprog);
				fprintf(debugFile, "  logmesg : %s\n", logmesg);
			}

			if (logmesg[0] == '[')
			{
				if (debugFile) fprintf(debugFile, "  parsing logid, facility, and level...\n");
				logid = logmesg+4;
				logfacility = index(logid, ' ');
				logfacility[0] = '\0';
				logfacility++;
				loglevel = index(logfacility, '.');
				loglevel[0] = '\0';
				loglevel++;
				logmesg = index(loglevel, ']');
				logmesg[0] = '\0';
				logmesg += 2;

				if (debugFile)
				{
					fprintf(debugFile, "  logid   : %s\n", logid);
					fprintf(debugFile, "  facility: %s\n", logfacility);
					fprintf(debugFile, "  level   : %s\n", loglevel);
					fprintf(debugFile, "  mesg    : %s\n", logmesg);
				}
			}
			else
			{
				if (debugFile) fprintf(debugFile, "  setting logid, facility, and level to null\n");
				logid = "null";
				logfacility = "null";
				loglevel = "null";

				if (debugFile)
				{
					fprintf(debugFile, "  logid   : null\n");
					fprintf(debugFile, "  facility: null\n");
					fprintf(debugFile, "  level   : null\n");
					fprintf(debugFile, "  mesg    : null\n");
				}
			}

			if (debugFile) fprintf(debugFile, "  parsing : %s\n", theBuf);

			strptime(theBuf, "%b %d %T", mytime);


			if (loghost && logprog && logmesg)
			{
				strftime(theDate, 32, "%Y-%m-%d %T", mytime);
				snprintf(querybuf, sizeof(querybuf),
					"INSERT INTO %s (timestamp, host, "
					"prog, logid, loglevel, logfacility, mesg) "
					"VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s')",
					table, theDate, loghost, logprog, logid, loglevel,
					logfacility, logmesg);

				if (debugFile) fprintf(debugFile, "  sql     : %s\n", querybuf);

				if (mysql_query(&db, querybuf) && debugFile)
				{
					fprintf(debugFile, "  failed to run "
						"query: %s\n",
						mysql_error(&db));
				}
			}
			else if (debugFile) fprintf(debugFile, "  no loghost, logprog, or logmest.\n");
		}
		else if (debugFile)
		{
			fprintf(debugFile, "buffer was too short\n");
		}

		if (debugFile) fflush(debugFile);
	}

	if (debugFile)
	{
		fclose(debugFile);
	}

	mysql_close(&db);

	exit(0);
}
