: "@(#)shar.sh 1.8" #! /bin/sh # # This is a shell archive. # Remove everything above this line and run sh on the resulting file. # If this archive is complete, you will see this message at the end: # "All files extracted" # # Created: Mon Feb 7 16:26:14 GMT 2000 by root # # Files archived in this archive: # README.1st # hv_inflog.c # hv_socket.c # hv_socket.h # infspy.c # makespy.sh # #-------------------- if [ -f README.1st -a "$1" != "-c" ] then echo shar: README.1st already exists else echo 'x - README.1st (1660 characters)' sed -e 's/^X//' >README.1st <<'SHAR-EOF' X XUtility: infspy.c X XSynopsis: This utility, was written to log sql statements executed from X third party applications where no source code was available. X SQL EXPLAIN was not available or simply to slow. X The Informix product called ISPY was not available yet. X X SQL Statements can be analyzed to make sure all necessary indexes are there X Join tables tables can be structured to be on deferent disks. X Programs to analyze the output is not currently available. X X XAuthor(s): Hannes Visagie XRevision: 1.0 XVersion(s) supported: 7x+ XFile(s): infspy.c hv_socket.c hv_socket.h hv_inflog.c makespy.sh README.1st X XRelease Notes: X XThis initial release. Portnumbers and hostnames are hardcoded in infspy.c X XKnow bugs: X Xuse dbaccess "database_name" and not just dbaccess X X XQuiq Start: X---------- XEdit infspy.c and replace INFHOST, INFPORT, PORTNUM with your settings X./makespy.sh X XCleen Compile OK. X XSet up Informix: X Requires you to set up two sqlhosts files. X One will be the spy version. X Start the engine with a valid SQLHOSTS file eg: X Xsqlhosts: Xinfdb onipcshm 109.1.6.2 1525 Xinfdb_tcp ontlitcp 109.1.6.2 1526 Xinfdb_spy ontlitcp 109.1.6.2 1527 X X Change the env to reflect the sqlhosts.spy file Xsqlhosts.spy: Xinfdb onipcshm 109.1.6.2 1525 Xinfdb_tcp ontlitcp 109.1.6.2 1526 Xinfdb_spy ontlitcp 109.1.6.2 1510 X X Change INFORMIXSERVER to infdeb_spy X Start ./infspy or ./infsy & {This will listen to port 1510} X Now connect dbaccess dbn -> port 1510 infspy -> 1526 inf listen X XLogs will go to /var/log/sql.username X SHAR-EOF if [ `wc -c hv_inflog.c <<'SHAR-EOF' X/*------------------------------------------------------------------------------ X * File name : hv_inflog.c X * Purpose : Functions to log informix sql X * Author : Hannes Visagie X * Date written : 1998-11-01 X * Port : Unixware 7, Also to SUNOS 7 X * Version : Ver 1.0 X * TabSize : 4 X *----------------------------------------------------------------------------*/ X X X#include "hv_socket.h" X X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X Xtypedef short int16; /* 16 bit Integer */ Xtypedef struct X{ X int16 func; X int16 pare; X int16 len; X} Xinf_header; X Xtypedef struct X{ X int16 h1; X int16 inf_err; X int16 isam_err; X int16 h4; X int16 len; X char str; X} Xinf_header1; X Xvoid connect_db_nolog(int client, int server); Xvoid connect_db_log(int client, int server, char *fname); X X/*------------------------------------------------------------------------------ X * Function : int connect_informix(int client, char *infhost, u_short infport) X * Description : Check if socket1 is a informix product trying to connect X * : If so then depending on code, {user version} connect to X * : a informix listener {socket2} with loggin or no logging X * Returns : Returns 1 if data, else 0 no data X * Notes : Still give problems when not using dbaccess dbname X *----------------------------------------------------------------------------*/ Xint connect_informix(int client, char *infhost, u_short infport) X{ X int server; X char buf[1024]; X char *ptr; X int j; X int n; X int i; X char user[100]; X char version[10]; X char infserial[15]; X char fname[100]; X X X /*--- Get sqlexec version ---*/ X if (isdatafast(client)) X { X bzero(&buf,sizeof(buf)); X j = read(client, buf, sizeof(buf)-1); X if (j < 0) X { X errlog("No data from sender\n"); X return(1); X } X } X /* for (i=0; i 10)) return; X if (j > 0) {z = 0; write(client, buf, j);} X } X X if (isdatafast(client)) X { X bzero(&buf,sizeof(buf)); X j = read(client, buf, sizeof(buf)-1); X if (j == 0) z++; X if ((j < 0) || (z > 10)) return; X if (j > 0) {z = 0; write(server, buf, j);} X } X } X} X X X X/*------------------------------------------------------------------------------ X * Function : void connect_db_log(int client, int server, char *fname); X * Description : Be a gateway between client and server; X * : Log all sucsessful sql to fname X * Returns : Returns nothing X * Notes : This function is based on "connect_db_nolog" X * : We hardcoded to take fourgen internal codengs out X * : This function needs to be slimplefied in next version X *----------------------------------------------------------------------------*/ Xvoid connect_db_log(int client, int server, char *fname) X{ X char buf[1024]; X char sqlbuf[32000]; X int i; X int j; X inf_header *hptr; X inf_header1 *hp1; X int newsql = 0; X int fgen = 0; X int z = 0; X X sqlbuf[0] = 0; X Xloop2: X X if (isdatafast(server)) X { X bzero(&buf,sizeof(buf)); X j = read(server, buf, sizeof(buf)-1); X/* printf("\nR[%d]:", j); */ X if (j < 0) return; X if (j > 0) write(client, buf, j); X/* if (j >= 16) for (i=0; i<16; i++) printf("%x ", buf[i]); X printf("\n"); */ X hp1 = (inf_header1 *)buf; X if (newsql) X { X newsql = 0; X if (hp1->h1 != 13) X { X /*--- Ignore fourgen sql ---*/ X /* if (strstr(sqlbuf, "d_") != NULL) */ X { X/* if (strstr(sqlbuf, "systables") != NULL) fgen = 1; X else if (strstr(sqlbuf, "sysusers") != NULL) fgen = 1; X else if (strstr(sqlbuf, "sysindexes") != NULL) fgen = 1; X else if (strstr(sqlbuf, "syscolumns") != NULL) fgen = 1; X else if (strstr(sqlbuf, "from stx") != NULL) fgen = 1; X else if (strstr(sqlbuf, "t1rmessg") != NULL) fgen = 1; X else if (strstr(sqlbuf, "tmpnoted") != NULL) fgen = 1; X else if (strstr(sqlbuf, "table browse") != NULL) fgen = 1; X else if (strstr(sqlbuf, "into browse") != NULL) fgen = 1; X else if (strstr(sqlbuf, "from browse") != NULL) fgen = 1; X else if (strstr(sqlbuf, "on browse") != NULL) fgen = 1; X else errlog1(fname, "%s\n", sqlbuf); */ X errlog1(fname, "%s\n", sqlbuf); X } X } X } X X/* if ((hp1->h1 == 13) && (newsql)) X { X newsql = 0; X printf("%d %d %d %d %d %s\n", hp1->h1, hp1->inf_err, hp1->isam_err, hp1->h4, hp1->len, &hp1->str); X } X if (j >= 16) for (i=0; i<16; i++) X { X if (isprint(buf[i])) printf("%c ", buf[i]); X else printf("XX"); X } X printf("\n"); */ X } X X X if (isdatafast(client)) X { X bzero(&buf,sizeof(buf)); X j = read(client, buf, sizeof(buf)-1); X if (j == 0) z++; X if ((j < 0) || (z > 5)) return; X if (j > 0) X { X z = 0; X write(server, buf, j); X/* printf("\nS[%d]:", j); */ X X hptr = (inf_header *)buf; X if (hptr->func == 2) X { X newsql = 1; X sprintf(sqlbuf, "%s", buf+6); X/* if (strstr(sqlbuf, "close database") != NULL) return; X puts(buf+6); */ X } X/* else X { X for (i=0; ihv_socket.c <<'SHAR-EOF' X/*------------------------------------------------------------------------------ X * File name : hv_socket.c X * Purpose : Functions to create connections {sockets} X * Author : Hannes Visagie X * Date written : 1998-11-01 X * Port : Unixware 7, Also to SUNOS 7 X * Version : Ver 1.0 X * TabSize : 4 X *----------------------------------------------------------------------------*/ X X#include "hv_socket.h" X X X/*------------------------------------------------------------------------------ X * Function : void errlog(const char *fmt, ...) X * Description : Logs to stderr and to logfile X * Returns : Nothing X *----------------------------------------------------------------------------*/ Xint _errlog_first = 1; X Xvoid errlog(char *fmt, ...) X{ X va_list ap; X FILE * fout; X time_t t; X char str[100]; X struct tm *timeptr; X X str[0] = 0; X t = time(NULL); X timeptr = localtime(&t); X if (_errlog_first) X { X _errlog_first = 0; X strftime(str, sizeof(str), "%Y-%m-%d %T", timeptr); X/* cftime(str, "%N", &t); */ X } X/* else cftime(str, "%T", &t); */ X else strftime(str, sizeof(str), "%T", timeptr); X X fout = fopen(errlogfile, "a"); X if (fout == NULL) X { X perror(errlogfile); X exit(1); X } X X va_start(ap, fmt); X fprintf(stderr, "%s ", str); X vfprintf(stderr, fmt, ap); X fprintf(fout, "%s ", str); X vfprintf(fout, fmt, ap); X va_end(ap); X X fflush(stderr); X fflush(fout); X fclose(fout); X} X X X Xvoid errlog1(char *fname, char *fmt, ...) X{ X va_list ap; X FILE * fout; X char str[100]; X X X fout = fopen(fname, "a"); X if (fout == NULL) X { X perror(fname); X exit(1); X } X X va_start(ap, fmt); X vfprintf(stderr, fmt, ap); X vfprintf(fout, fmt, ap); X va_end(ap); X X fflush(stderr); X fflush(fout); X fclose(fout); X} X X X X/*------------------------------------------------------------------------------ X * Function : int _isdata(int s, int sec, int usec) X * Description : Check if there is any data readable on socket, timing out X * : after seconds, milliseconds. X * Returns : Returns 1 if data, else 0 no data X *----------------------------------------------------------------------------*/ Xint _isdata(int s, int sec, int usec) X{ X int res = 0; X struct timeval timeout; X fd_set readmask; X X X /*--- Setup the readmask and the timeout values ---*/ X readmask.fds_bits[0] = 1 << s; X FD_ZERO(&readmask); X FD_SET(s, &readmask); X timeout.tv_sec = sec; X timeout.tv_usec = usec; X X res = select(s+1, &readmask, 0, 0, &timeout); X if (res < 0) res = 0; X X if (FD_ISSET(s, &readmask)) return(res); X return(0); X} X X X/*------------------------------------------------------------------------------ X * Same as _isdata, times out after 10 seconds X *----------------------------------------------------------------------------*/ Xint isdata(int s) X{ X return(_isdata(s, 10, 0)); X} X X X/*------------------------------------------------------------------------------ X * Same as _isdata, times out after 500 milliseconds X *----------------------------------------------------------------------------*/ Xint isdatafast(int s) X{ X return(_isdata(s, 0, 500)); X} X X X/*------------------------------------------------------------------------------ X * Same as _isdata, times out after 1 minute X *----------------------------------------------------------------------------*/ Xint isdataslow(int s) X{ X return(_isdata(s, 60, 0)); X} X X X X/*------------------------------------------------------------------------------ X * Function : int open_socket(char *hostname, u_short portnum) X * Description : Opens a socket a remote host on portnumber X * Returns : Returns the socket, or -1 if a error X *----------------------------------------------------------------------------*/ Xint open_socket(char *hostname, u_short portnum) X{ X char *fn = "open_socket:"; X struct sockaddr_in sa; X struct hostent *hp; int a, s; X X X /*--- Get our address info ---*/ X hp = gethostbyname(hostname); X if (hp == NULL) X { X errno = ECONNREFUSED; X /* errlog("%s gethostbyname error %d\n", fn, h_errno); */ X errlog("%s gethostbyname error %d\n", fn, errno); X return(-1); X } X X X bzero(&sa,sizeof(sa)); X bcopy(hp->h_addr,(char *)&sa.sin_addr,hp->h_length); /* set address */ X X sa.sin_family= hp->h_addrtype; X sa.sin_port= htons(portnum); X s = socket(hp->h_addrtype,SOCK_STREAM,0); X if (s == -1) X { X errlog("%s socket error %d\n", fn, errno); X return(-1); X } X X X /*--- Connect, 0 OK, -1 err ---*/ X if (connect(s, (struct sockaddr *)&sa,sizeof(sa)) < 0) X { X errlog("%s connect error %d\n", fn,errno); X close(s); X return(-1); X } X X return(s); X} X X X X/*------------------------------------------------------------------------------ X * Function : int open_socket_rx( u_short portnum) X * Description : Opens a socket and listen on portnumber X * Returns : Returns the socket, or -1 if a error X *----------------------------------------------------------------------------*/ Xint open_socket_rx(u_short portnum) X{ X char *fn = "open_socket_rx:"; X char myname[MAXHOSTNAME+1]; X int s; X struct sockaddr_in sa; X struct hostent *hp; X X bzero(&sa,sizeof(sa)); /* clear our address */ X X /* Who are we? , 0 OK, -1 error */ X if (gethostname(myname, MAXHOSTNAME)) X { X errlog("%s gethostname\n", fn); X return(-1); X } X X /* Get our address info */ X hp = gethostbyname(myname); X if (hp == NULL) X { X errno = ECONNREFUSED; X /* errlog("%s gethostbyname error %d\n", fn, h_errno); */ X errlog("%s gethostbyname error %d\n", fn, errno); X return(-1); X } X X /* Create Socket, -1 Error, > 0 OK */ X sa.sin_family = hp->h_addrtype; /* this is our host address */ X sa.sin_port = htons(portnum); /* this is our port number */ X s = socket(AF_INET,SOCK_STREAM,0); X if (s == -1) X { X errlog("%s socket error %d\n", fn, errno); X return(-1); X } X X /* Bind address to socket, 0 OK, -1 error */ X if (bind(s, (struct sockaddr *)&sa, sizeof(sa))) X { X errlog("%s bind error %d\n", fn, errno); X close(s); X return(-1); X } X X listen(s, 3); /* max # of queued connects */ X return(s); X} X X X X/*------------------------------------------------------------------------------ X * Function : int accept_connection(int s) X * Description : Accept a connection, socket created with establish. X * Returns : Returns the socket, or -1 if a error X *----------------------------------------------------------------------------*/ Xint accept_connection(int s) X{ X struct sockaddr_in isa; /* address of socket */ X size_t i; /* size of address */ X int t; /* socket of connection */ X X i = sizeof(isa); /* find socket's address */ X getsockname(s,(struct sockaddr *)&isa,&i); /* for accept() */ X t = accept(s,(struct sockaddr *)&isa,&i); X if (t < 0) return(-1); /* No connection */ X X return(t); /* accept connection if there is one */ X} X X X X/* END OF FILE */ SHAR-EOF if [ `wc -c hv_socket.h <<'SHAR-EOF' X/*----------------------------------------------------------------------------- X * File name : hv_socket.h X * Purpose : A header file for hv_socket.c {socket functions} X * Author : Hannes Visagie X * Date written : 1998-11-01 X * Port : Unixware 7.01, SUNOS 7 X * Version : Ver 1.0 X * TabSize : 4 X * Notes : Some of the include files might not be on your system. X *----------------------------------------------------------------------------*/ X X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X X X#define MAXHOSTNAME 255 Xextern char *errlogfile; /* This must be defined global someware */ X Xtypedef int int32; /* 32 bit Integer */ Xtypedef unsigned char uint8; Xtypedef char int8; X X Xvoid errlog(char *fmt, ...); Xint _isdata(int s, int sec, int usec); Xint isdata(int s); Xint isdatafast(int s); Xint isdataslow(int s); Xint open_socket(char *hostname, u_short portnum); Xint open_socket_rx(u_short portnum); Xint accept_connection(int s); X X/* END OF FILE */ SHAR-EOF if [ `wc -c infspy.c <<'SHAR-EOF' X/*------------------------------------------------------------------------------ X * File name : infspy.c X * Purpose : To log informix SQL statements for all users/programs where X * : we cannot use SQL explain such as third party apps with no X * : source code. The SQL can be annalized to check for correct X * : indexes, primary keys, etc ... X * Author : Hannes Visagie X * Date written : 1998-11-01 X * Port : Unixware 7, Also to SUNOS 7 X * Version : Ver 1.0 X * TabSize : 4 X *----------------------------------------------------------------------------*/ X X X#include "hv_socket.h" /* All socket related system calls */ X//#include "hv_inflog.h" /* All the informix log functions */ X X X/*--- Extra include files that may ne be needed on your OS --- */ X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X X X/*--- Some defines ---*/ X#define PORTNUM 5010 /* random port number, we need something */ X#define INFPORT 1526 /* Informix read tcp listen in sql hosts */ X#define INFHOST "199.1.6.2" /* Informix read tcp listen in sql hosts */ X Xchar *errlogfile = "/var/log/sql.log"; /* All logs go here + stdio */ X X X/*--- Fuction prototypes ---*/ Xvoid fireman(); Xvoid do_something(); Xvoid cleanup(); X X X/*--- Only one global var needed for cleanup purposes ---*/ Xint global_s; /* Global var socket listen */ X X X X/*----------------------------------- MAIN -----------------------------------*/ X X X/*------------------------------------------------------------------------------ X * Function : main() X * Description : The start of the main program. Will open a socket on PORTNUM X * : and wait for a connection. Accept and fork a child that will X * : try to connect to a Informix Database TCP listener. X * Returns : Nothing X * Notes : Sometimes when we break the listener, it will not close the X * : socket. When we try to run the listener again, we get socket X * : in use. It takes a wile for the socket to be free by the OS. X * : Workaround to use a new PORTNUM. X * : Next release it will be fixed. X *----------------------------------------------------------------------------*/ Xmain() X{ X X int s; X X errlog("--- Informix SQL Logger, Listen to port:%d ---\n", PORTNUM); X X if ((global_s = open_socket_rx(PORTNUM)) < 0) /* plug in the phone */ X { X perror("establish"); X exit(1); X } X X if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, cleanup); X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) signal(SIGQUIT, cleanup); X if (signal(SIGTERM, SIG_IGN) != SIG_IGN) signal(SIGTERM, cleanup); X signal(SIGCHLD, fireman); /* this eliminates zombies */ X X X for (;;) /* loop for phone calls */ X { X signal(SIGCHLD, fireman); /* this eliminates zombies */ X X X if ((s= accept_connection(global_s)) < 0) /* get a connection */ X { X if (errno == EINTR) /* EINTR might happen on accept(), */ X continue; /* try again */ X perror("accept"); /* bad */ X exit(1); X } X X switch(fork()) /* try to handle connection */ X { X case -1 : /* bad news. scream and die */ X perror("fork"); X close(global_s); X close(s); X exit(1); X case 0 : /* we're the child, do something */ X do_something(s); X close(s); X exit(0); X default : /* we're the parent so look for */ X close(s); /* another connection */ X continue; X } X } X} X X X/*------------------------------------------------------------------------------ X * Function : void fireman(); X * Description : As children die we should get catch their returns, X * : or else we get zombies. Bad thing. X * : fireman() catches falling children. X * Returns : Nothing X *----------------------------------------------------------------------------*/ Xvoid fireman() X{ X int wstatus; X X while(wait3(&wstatus,WNOHANG,NULL) > 0) ; X} X X X/*------------------------------------------------------------------------------ X * Function : void cleanup(); X * Description : Close the global socket that is listening for connections. X * Returns : Nothing X *----------------------------------------------------------------------------*/ Xvoid cleanup() X{ X close(global_s); X exit(0); X} X X X/*------------------------------------------------------------------------------ X * Function : void do_something(int s) X * Description : This is the function that plays with the socket. X * : It will be called after getting a connection. X * Returns : Nothing X *----------------------------------------------------------------------------*/ Xvoid do_something(int s) X{ X /* do your thing with the socket here : : */ X connect_informix(s, INFHOST, INFPORT); X} X X X/* END OF FILE */ SHAR-EOF if [ `wc -c makespy.sh <<'SHAR-EOF' Xgcc infspy.c hv_socket.c hv_inflog.c -lnsl -lsocket -oinfspy SHAR-EOF if [ `wc -c