/* * Copyright (c) 2000-2004 QoSient, LLC * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * Copyright (c) 1993, 1994 Carnegie Mellon University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation, and that the name of CMU not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * */ /* * * written by Carter Bullard * QoSient, LLC * */ #ifndef ArgusOutput #define ArgusOutput #endif #include #include #include #define HOSTS_ACCESS 200 extern int ArgusFilterCompile(struct bpf_program *, char *, int, unsigned int); struct ArgusOutputStruct * ArgusNewOutput (void) { struct ArgusOutputStruct *retn = NULL; int i; if ((retn = (struct ArgusOutputStruct *) ArgusCalloc (1, sizeof (struct ArgusOutputStruct))) != NULL) { retn->clienttags = 0; for (i = 0; i < ARGUS_MAXLISTEN; i++) { retn->client[i].fd = -1; retn->client[i].pid = -1; retn->client[i].pipe[0] = -1; retn->client[i].pipe[1] = -1; retn->client[i].sock = NULL; } ArgusReportTime.tv_sec = ArgusGlobalTime.tv_sec + ArgusMarReportInterval.tv_sec; ArgusReportTime.tv_usec += ArgusMarReportInterval.tv_usec; ArgusLastMarUpdateTime = ArgusGlobalTime; } #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusNewOutput() returning retn 0x%x\n", retn); #endif return (retn); } void ArgusDeleteOutput () { if (ArgusOutputTask) { ArgusCloseClients(); ArgusFree (ArgusOutputTask); ArgusOutputTask = NULL; } #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusDeleteOutput() returning\n"); #endif } void ArgusInitOutput () { int result; if ((result = pipe(ArgusOutputPipe)) != 0) ArgusLog (LOG_ERR, "ArgusInitOutput pipe() error %s\n", strerror(errno)); if ((fcntl (ArgusOutputPipe[PARENTSIDE], F_SETFL, O_NONBLOCK)) < 0) ArgusLog (LOG_ERR, "ArgusInitOutput: fcntl failed %s\n", strerror(errno)); if ((fcntl (ArgusOutputPipe[CLIENTSIDE], F_SETFL, O_NONBLOCK)) < 0) ArgusLog (LOG_ERR, "ArgusInitOutput: fcntl failed %s\n", strerror(errno)); if (getArgusrfile() != NULL) { setArgusPortNum(0, 0); } else if (getArgusPortNum() == -1) setArgusPortNum(ARGUS_MONITORPORT, ArgusBindIP); if ((ArgusOutputTask->pid = fork()) == 0) { ArgusOutputProcess(); } else { #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusOutputProcess[%d] created\n", ArgusOutputTask->pid); #endif } #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusInitOutput() returning\n"); #endif } void ArgusGenerateInitialMar () { int i; ArgusSystemMar->ahdr.type = ARGUS_MAR; ArgusSystemMar->ahdr.cause = ARGUS_START; ArgusSystemMar->ahdr.length = (unsigned short) sizeof(struct ArgusRecord); ArgusSystemMar->ahdr.argusid = ARGUS_COOKIE; ArgusSystemMar->ahdr.seqNumber = 0; ArgusSystemMar->argus_mar.startime = ArgusStartTime; ArgusSystemMar->argus_mar.now = ArgusGlobalTime; ArgusSystemMar->argus_mar.major_version = getArgusMajorVersion(); ArgusSystemMar->argus_mar.minor_version = getArgusMinorVersion(); ArgusSystemMar->argus_mar.interfaceType = getArgusInterfaceType(); ArgusSystemMar->argus_mar.interfaceStatus = getArgusInterfaceStatus(); ArgusSystemMar->argus_mar.reportInterval = getArgusFarReportInterval()->tv_sec; ArgusSystemMar->argus_mar.argusMrInterval = getArgusMarReportInterval()->tv_sec; ArgusSystemMar->argus_mar.argusid = getArgusID(); ArgusSystemMar->ahdr.status |= getArgusIDType(); ArgusSystemMar->argus_mar.localnet = ArgusInterface[0].ArgusLocalNet; ArgusSystemMar->argus_mar.netmask = ArgusInterface[0].ArgusNetMask; ArgusSystemMar->argus_mar.pktsRcvd = 0; ArgusSystemMar->argus_mar.bytesRcvd = 0; ArgusSystemMar->argus_mar.pktsDrop = 0; for (i = 0; i < ARGUS_MAXINTERFACE; i++) { if (ArgusPd[i] != NULL) { ArgusSystemMar->argus_mar.pktsRcvd += ArgusInterface[i].ArgusTotalPkts; ArgusSystemMar->argus_mar.bytesRcvd += ArgusInterface[i].ArgusTotalBytes; ArgusSystemMar->argus_mar.pktsDrop += ArgusInterface[i].ArgusTotalDrop; } } ArgusSystemMar->argus_mar.nextMrSequenceNum = ArgusOutputSequence; ArgusSystemMar->argus_mar.record_len = -1; #ifdef ARGUSDEBUG ArgusDebug (4, "ArgusGenerateInitialMar() returning\n"); #endif } void ArgusGenerateStatusMar () { int i; ArgusSystemMar->ahdr.type = ARGUS_MAR; ArgusSystemMar->ahdr.cause = ARGUS_STATUS; ArgusSystemMar->ahdr.length = (unsigned short) sizeof(struct ArgusRecord); ArgusSystemMar->ahdr.argusid = getArgusID(); ArgusSystemMar->ahdr.seqNumber = 0; ArgusSystemMar->argus_mar.startime = ArgusLastMarUpdateTime; ArgusSystemMar->argus_mar.now = ArgusGlobalTime; ArgusSystemMar->argus_mar.major_version = getArgusMajorVersion(); ArgusSystemMar->argus_mar.minor_version = getArgusMinorVersion(); ArgusSystemMar->argus_mar.interfaceType = getArgusInterfaceType(); ArgusSystemMar->argus_mar.interfaceStatus = getArgusInterfaceStatus(); ArgusSystemMar->argus_mar.reportInterval = getArgusFarReportInterval()->tv_sec; ArgusSystemMar->argus_mar.argusMrInterval = getArgusMarReportInterval()->tv_sec; ArgusSystemMar->argus_mar.argusid = getArgusID(); ArgusSystemMar->ahdr.status |= getArgusIDType(); ArgusSystemMar->argus_mar.localnet = getArgusLocalNet(); ArgusSystemMar->argus_mar.netmask = getArgusNetMask(); ArgusSystemMar->argus_mar.pktsRcvd = 0; ArgusSystemMar->argus_mar.bytesRcvd = 0; ArgusSystemMar->argus_mar.pktsDrop = 0; for (i = 0; i < ARGUS_MAXINTERFACE; i++) { if (ArgusPd[i] != NULL) { ArgusSystemMar->argus_mar.pktsRcvd += ArgusInterface[i].ArgusTotalPkts; ArgusSystemMar->argus_mar.bytesRcvd += ArgusInterface[i].ArgusTotalBytes; ArgusSystemMar->argus_mar.pktsDrop += ArgusInterface[i].ArgusTotalDrop; ArgusInterface[i].ArgusTotalPkts = 0; ArgusInterface[i].ArgusTotalBytes = 0; ArgusInterface[i].ArgusTotalDrop = 0; } } ArgusSystemMar->argus_mar.flows = ArgusGetQueueCount(ArgusFlowQueue); ArgusSystemMar->argus_mar.flowsClosed = ArgusTotalClosedFlows - ArgusLastClosedFlows; ArgusSystemMar->argus_mar.nextMrSequenceNum = ArgusOutputSequence; ArgusSystemMar->argus_mar.record_len = -1; ArgusLastNewFlows = ArgusTotalNewFlows; ArgusLastClosedFlows = ArgusTotalClosedFlows; ArgusLastMarUpdateTime = ArgusGlobalTime; #ifdef ARGUSDEBUG ArgusDebug (4, "ArgusGenerateStatusMar() returning\n"); #endif } void ArgusGenerateClosingMar (unsigned char status) { gettimeofday (&ArgusGlobalTime, 0L); ArgusGenerateStatusMar(); ArgusSystemMar->ahdr.cause = status; #ifdef ARGUSDEBUG ArgusDebug (4, "ArguGenerateClosingMar() returning\n"); #endif } #define MAXBUFSIZE (sizeof(struct ArgusRecord) * 16) #include void ArgusOutputCleanUp (int); void ArgusInitOutputProcess() { struct ArgusWfileStruct *wfile; int i, retn; if (ArgusWfileList) { while (!ArgusListEmpty(ArgusWfileList)) { if ((wfile = ArgusFrontList(ArgusWfileList)) != NULL) { for (i = 0; i < ARGUS_MAXLISTEN; i++) { if (ArgusOutputTask->client[i].pid == -1) { if ((retn = pipe(ArgusOutputTask->client[i].pipe)) == 0) { pid_t pid; if ((ArgusOutputTask->client[i].sock = ArgusNewSocket (ArgusOutputTask->client[i].pipe[CLIENTSIDE])) != NULL) { ArgusOutputTask->clienttags |= (1 << i); if ((pid = fork()) != 0) { ArgusOutputTask->client[i].pid = pid; ArgusSendInitialMar(ArgusOutputTask->client[i].pipe[CLIENTSIDE]); } else { ArgusOutputTask->client[i].pid = getpid(); ArgusClientProcess(&ArgusOutputTask->client[i], wfile); _exit(0); } } break; } } else { int status; waitpid(ArgusOutputTask->client[i].pid, &status, WNOHANG); if ((retn = kill(ArgusOutputTask->client[i].pid, 0)) < 0) { ArgusCloseSocket(i); i--; } } } ArgusFree(wfile); ArgusPopFrontList(ArgusWfileList); } } ArgusDeleteList(ArgusWfileList); } ArgusUpdateInterval.tv_usec = 100000; #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusInitOutputProcess() returning\n"); #endif } void ArgusUsr1Sig (int sig) { #ifdef ARGUSDEBUG Argusdflag = (Argusdflag++ > 30) ? 30 : Argusdflag; ArgusDebug (0, "ArgusUsr1Sig: debug %d enabled\n", Argusdflag); #endif } void ArgusUsr2Sig (int sig) { #ifdef ARGUSDEBUG Argusdflag = 0; ArgusDebug (0, "ArgusUsr2Sig: debug disabled\n"); #endif } void ArgusChildExit (int sig) { int retn; if (ArgusOutputTask->clienttags) { int status, i; for (i = 0; i < ARGUS_MAXLISTEN; i++) if (ArgusOutputTask->client[i].pid != -1) { waitpid(ArgusOutputTask->client[i].pid, &status, WNOHANG); if ((retn = kill(ArgusOutputTask->client[i].pid, 0)) < 0) ArgusCloseSocket(i); } } #ifdef ARGUSDEBUG ArgusDebug (4, "ArgusChildExit\n"); #endif } int ArgusProcessRemoteSocket(struct ArgusClientData *, int); int ArgusProcessOutputSocket(struct ArgusClientData *, int); int ArgusParentPid = 0; void ArgusOutputProcess() { struct ArgusSocketStruct *ArgusInputSocket; fd_set readmask, writemask, exceptmask; int retn = 0, width = 0; int lfd = ArgusOutputPipe[PARENTSIDE]; int ArgusLfd = getArgusLfd(); struct timeval wait; #if defined(HAVE_SOLARIS) sigignore(SIGPIPE); sigignore(SIGHUP); sigignore(SIGINT); sigignore(SIGTERM); #else (void) signal (SIGPIPE, SIG_IGN); (void) signal (SIGHUP, SIG_IGN); (void) signal (SIGINT, SIG_IGN); (void) signal (SIGTERM, SIG_IGN); #endif (void) signal (SIGUSR1, (void (*)(int)) ArgusUsr1Sig); (void) signal (SIGUSR2, (void (*)(int)) ArgusUsr2Sig); (void) signal (SIGCHLD, (void (*)(int)) ArgusChildExit); if ((ArgusInputSocket = ArgusNewSocket (lfd)) != NULL) { ArgusInputSocket->ahdr = (struct ArgusRecordHeader *) ArgusInputSocket->buf; ArgusInputSocket->ptr = (u_char *) ArgusInputSocket->ahdr; ArgusInputSocket->ArgusReadState = ARGUS_READINGHDR; ArgusInputSocket->expectedSize = sizeof(*ArgusInputSocket->ahdr); ArgusInputSocket->fd = lfd; } else ArgusLog (LOG_ERR, "ArgusOutputProcess() ArgusNewSocket error %s\n", strerror(errno)); ArgusInitOutputProcess(); ArgusParentPid = getppid(); wait.tv_sec = 0; wait.tv_usec = 100000; width = ((lfd > ArgusLfd) ? lfd : ArgusLfd) + 1; FD_ZERO(&readmask); FD_ZERO(&writemask); FD_ZERO(&exceptmask); if (lfd >= 0) FD_SET(lfd, &readmask); if (ArgusLfd >= 0) FD_SET(ArgusLfd, &readmask); while (ArgusInputSocket && !(ArgusInputSocket->ArgusLastRecord)) { if ((retn = select (width, &readmask, NULL, NULL, &wait)) >= 0) { gettimeofday (&ArgusGlobalTime, 0L); if (((lfd >= 0) && FD_ISSET(lfd, &readmask)) || ((ArgusLfd >= 0) && FD_ISSET(ArgusLfd, &readmask))) { if ((ArgusLfd >= 0) && FD_ISSET(ArgusLfd, &readmask)) ArgusCheckClientStatus (); if ((lfd >= 0) && FD_ISSET(lfd, &readmask)) { if ((retn = ArgusReadSocket (ArgusInputSocket, ArgusHandleData, NULL)) < 0) { ArgusDeleteSocket(ArgusInputSocket); ArgusInputSocket = NULL; } } else if (!(ArgusReadingOffLine)) gettimeofday(&ArgusGlobalTime, 0L); } else { if (ArgusOutputTask->clienttags) { int status, i; for (i = 0; i < ARGUS_MAXLISTEN; i++) if (ArgusOutputTask->client[i].pid != -1) { waitpid(ArgusOutputTask->client[i].pid, &status, WNOHANG); if ((retn = kill(ArgusOutputTask->client[i].pid, 0)) < 0) ArgusCloseSocket(i); } } if (ArgusUpdateTime()) ArgusHandleData(NULL, NULL, 0, NULL); if ((kill (ArgusParentPid, 0)) < 0) { ArgusOutputCleanUp(0); } } } else { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusOutputProcess() select returned %s\n", strerror(errno)); #endif if (errno != EINTR) break; } if (lfd >= 0) FD_SET(lfd, &readmask); if (ArgusLfd >= 0) FD_SET(ArgusLfd, &readmask); wait.tv_sec = 0; wait.tv_usec = 100000; width = ((lfd > ArgusLfd) ? lfd : ArgusLfd) + 1; } #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusOutputProcess() done\n"); #endif if (ArgusInputSocket && (ArgusInputSocket->ArgusLastRecord)) { int i, status; while (ArgusOutputTask->clienttags) { for (i = 0; i < ARGUS_MAXLISTEN; i++) if (ArgusOutputTask->client[i].pid != -1) { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusOutputProcess() killing client %d pid %d\n", i, ArgusOutputTask->client[i].pid); #endif if (ArgusOutputTask->client[i].sock != NULL) while (!ArgusListEmpty(ArgusOutputTask->client[i].sock->ArgusOutputList)) if (ArgusWriteOutSocket(ArgusOutputTask->client[i].sock) < 0) { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusOutputProcess() ArgusWriteOutSocket failed\n"); #endif break; } waitpid(ArgusOutputTask->client[i].pid, &status, 0); ArgusCloseSocket(i); } } } else { #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusOutputProcess() break select without Last Record.\n"); #endif } #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusOutputProcess() exiting\n"); #endif _exit(0); } int ArgusWriteStdOut = 0; struct ArgusRecord ArgusInitMar; struct bpf_program ArgusBPFcode; int ArgusFilterInitialized = 0; extern int ArgusAuthenticateClient (struct ArgusClientData *); struct ArgusSocketStruct *ArgusOutputSocket = NULL; void ArgusInitClientProcess(struct ArgusClientData *client, struct ArgusWfileStruct *wfile) { int len; len = ntohs(ArgusInitMar.ahdr.length); if (wfile) { setuid(getuid()); if (strcmp (wfile->filename, "-")) { #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusInitClientProcess: wfile->filename %s\n", wfile->filename); #endif if ((client->fd = open (wfile->filename, O_WRONLY|O_APPEND|O_CREAT|O_NONBLOCK, 0644)) < 0) ArgusLog (LOG_ERR, "ArgusInitClientProcess: open: %s", strerror(errno)); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusInitClientProcess: created outfile %s\n", wfile->filename); #endif if (write (client->fd, (char *) &ArgusInitMar, len) != len) { close (client->fd); unlink (wfile->filename); ArgusLog (LOG_ERR, "ArgusInitClientProcess: write(): %s", strerror(errno)); } } else { ArgusWriteStdOut++; len = ntohs(ArgusInitMar.ahdr.length); if (!(fwrite ((unsigned char *) &ArgusInitMar, len, 1, stdout))) ArgusLog (LOG_ERR, "ArgusInitClientProcess: fwrite error to stdout. %s", strerror(errno)); } if (wfile->filter) { if (!(ArgusFilterCompile (&ArgusBPFcode, wfile->filter, 0, 0) < 0)) { ArgusFilterInitialized++; } } } else { } if ((ArgusOutputSocket = ArgusNewSocket (client->fd)) == NULL) ArgusLog (LOG_ERR, "ArgusInitClientProcess: ArgusNewSocket failed\n"); if (!(wfile)) { if (!(ArgusAuthenticateClient (client))) ArgusLog (LOG_ERR, "ArgusInitClientProcess: ArgusAuthenticateClient failed\n"); } else ArgusOutputSocket->filename = strdup(wfile->filename); #ifdef ARGUSDEBUG if (wfile) ArgusDebug (1, "ArgusInitClientProcess(0x%x, %s) returning\n", client, wfile->filename); else ArgusDebug (1, "ArgusInitClientProcess(0x%x, %s) returning\n", client, wfile); #endif } #define MAXSTRLEN 2048 int ArgusProcessRemoteSocket(struct ArgusClientData *client, int fd) { char buf[MAXBUFSIZE]; int retn = 0, cnt; bzero (buf, sizeof(buf)); if ((cnt = recv (fd, buf, MAXBUFSIZE, 0)) != 0) { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusProcessRemoteSocket: read '%s' from remote\n", buf); #endif if ((strncmp (buf, "DONE: ", 6)) == 0) retn = -4; if ((strncmp (buf, "FILTER: ", 8)) == 0) { if (ArgusFilterCompile (&ArgusBPFcode, &buf[7], 0, 0) < 0) { retn = -2; } else { ArgusFilterInitialized++; retn = 0; if (Argusbpflag) Argusbpf_dump (&ArgusBPFcode, Argusbpflag); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusProcessRemoteSocket: ArgusFilter %s initialized.\n", &buf[7]); #endif } } } else { close (fd); fd = -1; retn = -1; } #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusProcessRemoteSocket: returning %d\n", retn); #endif return (retn); } void * ArgusClientProcess(struct ArgusClientData *client, struct ArgusWfileStruct *wfile) { struct ArgusSocketStruct *ArgusInputSocket; int retn = 0, width = 0; struct timeval wait; fd_set readmask; int fd = -1; ArgusLfd = client->pipe[PARENTSIDE]; ArgusParentPid = getppid(); if ((retn = read (ArgusLfd, &ArgusInitMar, sizeof(ArgusInitMar))) != sizeof(ArgusInitMar)) ArgusLog (LOG_ERR, "ArgusClientProcess: did not read inital Mar"); else { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusClientProcess: received start record, len %d\n", retn); #endif } if ((ArgusInputSocket = ArgusNewSocket (ArgusLfd)) != NULL) { ArgusInputSocket->ahdr = (struct ArgusRecordHeader *) ArgusInputSocket->buf; ArgusInputSocket->ptr = (u_char *) ArgusInputSocket->ahdr; ArgusInputSocket->ArgusReadState = ARGUS_READINGHDR; ArgusInputSocket->expectedSize = sizeof(*ArgusInputSocket->ahdr); ArgusInputSocket->fd = ArgusLfd; } else ArgusLog (LOG_ERR, "ArgusClientProcess() ArgusNewSocket error %s\n", strerror(errno)); ArgusInitClientProcess (client, wfile); if (!wfile) fd = client->fd; width = ((ArgusLfd > fd) ? ArgusLfd : fd ) + 2; wait.tv_sec = 0; wait.tv_usec = 200000; FD_ZERO(&readmask); if (ArgusLfd >= 0) FD_SET(ArgusLfd, &readmask); if (fd >= 0) FD_SET(fd, &readmask); while (ArgusInputSocket && !(ArgusInputSocket->ArgusLastRecord)) { if ((retn = select (width, &readmask, NULL, NULL, &wait)) >= 0) { gettimeofday (&ArgusGlobalTime, 0L); if (((ArgusLfd >= 0) && FD_ISSET(ArgusLfd, &readmask)) || ((fd >= 0) && FD_ISSET(fd, &readmask))) { if ((ArgusLfd >= 0) && FD_ISSET(ArgusLfd, &readmask)) if ((retn = ArgusReadSocket(ArgusInputSocket, ArgusHandleClientData, client)) < 0) break; if ((fd >= 0) && (FD_ISSET(fd, &readmask))) { if ((retn = ArgusProcessRemoteSocket(client, fd)) < 0) break; } } if (ArgusUpdateTime ()) { if (ArgusWriteStdOut) fflush(stdout); else { if ((ArgusWriteOutSocket (ArgusOutputSocket)) < 0) { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusOutputProcess() ArgusWriteOutSocket failed\n"); #endif break; } } if ((kill (ArgusParentPid, 0)) < 0) { if (ArgusInputSocket) ArgusInputSocket->ArgusLastRecord++; } } } else { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusClientProcess() select returned %s\n", strerror(errno)); #endif if (errno != EINTR) break; } FD_ZERO(&readmask); if (ArgusLfd >= 0) FD_SET(ArgusLfd, &readmask); if (fd >= 0) FD_SET(fd, &readmask); width = ((ArgusLfd > fd) ? ArgusLfd : fd ) + 1; wait.tv_sec = 0; wait.tv_usec = 200000; } if (ArgusWriteStdOut) fflush(stdout); if (ArgusOutputSocket->ArgusOutputList) while (ArgusOutputSocket->ArgusOutputList->count) if (ArgusWriteOutSocket(ArgusOutputSocket) < 0) break; if (daemonflag) { if (wfile != NULL) ArgusLog (LOG_ERR, "client(%s) done.\n", wfile->filename); else ArgusLog (LOG_ERR, "client done.\n"); } return (0); /* return statement for when not daemonflag */ } void ArgusOutputCleanUp (int param) { if (ArgusOutputTask->clienttags) { int i, fd; for (i = 0; i < ARGUS_MAXLISTEN; i++) if ((fd = ArgusOutputTask->client[i].fd) != -1) ArgusSendClosingMar(fd, ARGUS_SHUTDOWN); } #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusOutputCleanup(%d) returning\n", param); #endif _exit (0); } unsigned int Wlastseqnum = 0; void ArgusSendOutputData(int fd, struct ArgusRecord *argus) { int cnt, len = argus->ahdr.length; #ifdef _LITTLE_ENDIAN ArgusHtoN(argus); #endif if ((cnt = write (fd, (char *) argus, len)) != len) ArgusLog (LOG_WARNING, "ArgusSendOutputData: wrote wrong number of bytes: %d\n", cnt); #ifdef _LITTLE_ENDIAN ArgusNtoH(argus); #endif #ifdef ARGUSDEBUG ArgusDebug (4, "ArgusSendOutputData(%d, 0x%x) wrote %d bytes returning\n", fd, argus, cnt); #endif } void ArgusSendInitialMar (int fd) { ArgusGenerateInitialMar (); ArgusSendOutputData(fd, ArgusSystemMar); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusSendInitialMar(%d) returning\n"); #endif } void ArgusSendStatusMar (int fd) { ArgusGenerateStatusMar(); ArgusSendOutputData(fd, ArgusSystemMar); #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusSendStatusMar(%d) returning\n", fd); #endif } void ArgusSendClosingMar (int fd, unsigned char status) { ArgusGenerateClosingMar(status); ArgusSendOutputData(fd, ArgusSystemMar); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusSendClosingMar(%d, %d) returning\n", fd, status); #endif } int firstWrite = 1; unsigned int Rlastseqnum = 0; int ArgusHandleData(struct ArgusSocketStruct *asock, unsigned char *buf, int len, void *client) { int retn = 0, i, status, pid; struct ArgusRecord *argus = (struct ArgusRecord *) buf; if (ArgusOutputTask->clienttags) { for (i = 0; i < ARGUS_MAXLISTEN; i++) { if (ArgusOutputTask->client[i].pid != -1) { if ((len > 0) && (ArgusOutputTask->client[i].sock != NULL)) { if ((retn = ArgusWriteSocket (ArgusOutputTask->client[i].sock, buf, len)) < 0) { ArgusLog (LOG_WARNING, "ArgusHandleData: ArgusWriteSocket failed %s\n", strerror(errno)); if ((pid = ArgusOutputTask->client[i].pid) > 0) { ArgusLog (LOG_WARNING, "ArgusHandleData: Terminating process %d\n", pid); kill(pid, SIGKILL); waitpid(pid, &status, 0); } ArgusCloseSocket(i); } } if (!(retn < 0) && (ArgusOutputTask->client[i].sock != NULL)) { if ((retn = ArgusWriteOutSocket(ArgusOutputTask->client[i].sock)) < 0) { ArgusLog (LOG_WARNING, "ArgusHandleData: ArgusWriteOutSocket failed\n"); if ((pid = ArgusOutputTask->client[i].pid) > 0) { ArgusLog (LOG_WARNING, "ArgusHandleData: Terminating process %d\n", pid); kill(pid, SIGKILL); waitpid(pid, &status, 0); } } } } } } retn = 0; if (argus != NULL) { if ((argus->ahdr.type & ARGUS_MAR) && (argus->ahdr.cause & (ARGUS_STOP | ARGUS_SHUTDOWN))) { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusHandleData() final record\n"); #endif asock->ArgusLastRecord++; retn = 1; } } #ifdef ARGUSDEBUG ArgusDebug (5, "ArgusHandleData(0x%x, %d) returning %d\n", buf, len, retn); #endif return (retn); } int ArgusHandleClientData(struct ArgusSocketStruct *asock, unsigned char *buf, int len, void *clientdata) { int retn = 0, ArgusWriteThisOut = 1; struct ArgusRecordHeader *ahdr = (struct ArgusRecordHeader *) buf; if (ahdr->type == ARGUS_MAR) { switch (ahdr->cause) { case ARGUS_START: #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusHandleClientData: received start record\n"); #endif break; case ARGUS_STATUS: #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusHandleClientData: received status record\n"); #endif break; case ARGUS_STOP: case ARGUS_SHUTDOWN: #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusHandleClientData: received last record\n"); #endif asock->ArgusLastRecord++; break; } } else { if (ArgusFilterInitialized) { if (argus_filter (ArgusBPFcode.bf_insns, (unsigned char *) ahdr) == 0) { #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusHandleClientData: output record rejected by filter\n"); #endif ArgusWriteThisOut = 0; } } } if (ArgusWriteThisOut) { int len = ntohs(ahdr->length); if (ArgusWriteStdOut) { if (!(retn = fwrite ((unsigned char *) ahdr, len, 1, stdout))) { #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusHandleClientData: fwrite stdout error %s\n", strerror(errno)); #endif } else { #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusHandleClientData: fwrite stdout %d items %d length\n", retn, len); #endif fflush (stdout); } } else { #ifdef ARGUS_SASL struct ArgusClientData *client = clientdata; char outputbuf[MAXSTRLEN], *output = outputbuf; if (client->sasl_conn) { unsigned int outputlen; #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusHandleClientData: sasl_encode(0x%x, 0x%x, %d, 0x%x, 0x%x)\n", client->sasl_conn, ahdr, len, &output, &outputlen); #endif if ((retn = sasl_encode(client->sasl_conn, (const char *) ahdr, (unsigned int) len, &output, &outputlen)) == SASL_OK) { ahdr = (struct ArgusRecordHeader *) output; len = outputlen; } else ArgusLog (LOG_ERR, "sasl_encode: failed returned %d\n", retn); } #endif if ((retn = ArgusWriteSocket (ArgusOutputSocket, (unsigned char *)ahdr, len)) < 0) { ArgusLog (LOG_ERR, "ArgusHandleClientData: ArgusWriteSocket failed %s\n", strerror(errno)); } else { if ((retn = ArgusWriteOutSocket(ArgusOutputSocket)) < 0) { ArgusLog (LOG_ERR, "ArgusHandleClientData: ArgusWriteOutSocket failed\n"); } } #ifdef ARGUS_SASL if (output != outputbuf) free(output); #endif } } #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusHandleClientData(0x%x, 0x%x, %d) returning %d\n", asock, buf, len, retn); #endif return (retn); } int getArgusLfd(void) { return(ArgusLfd); } int getArgusPortNum(void) { return(ArgusPortNum); } void setArgusPortNum(int value, char *bindIP) { char errbuf[MAXSTRLEN]; int retn = 0; if ((ArgusPortNum = value)) { if ((retn = ArgusEstablishListen (value, bindIP, errbuf)) < 0) ArgusLog (LOG_ERR, "%s", errbuf); } #ifdef ARGUSDEBUG ArgusDebug (2, "setArgusPortNum(%d) returning\n", value); #endif } struct timeval * getArgusMarReportInterval(void) { return (&ArgusMarReportInterval); } #include #include void setArgusMarReportInterval(char *value) { struct timeval *tvp = getArgusMarReportInterval(); struct timeval ovalue; double thisvalue = 0.0, iptr, fptr; int ivalue = 0; char *ptr = NULL;; if (tvp != NULL) { ovalue = *tvp; tvp->tv_sec = 0; tvp->tv_usec = 0; } else { ovalue.tv_sec = 0; ovalue.tv_usec = 0; } if (((ptr = strchr (value, '.')) != NULL) || isdigit((int)*value)) { if (ptr != NULL) { thisvalue = atof(value); } else { if (isdigit((int)*value)) { ivalue = atoi(value); thisvalue = ivalue * 1.0; } } fptr = modf(thisvalue, &iptr); tvp->tv_sec = iptr; tvp->tv_usec = fptr * 1000000; ArgusReportTime.tv_sec = ArgusGlobalTime.tv_sec + tvp->tv_sec; ArgusReportTime.tv_usec = tvp->tv_usec; } else *tvp = ovalue; #ifdef ARGUSDEBUG ArgusDebug (2, "setArgusMarReportInterval(%d) returning\n", value); #endif } void clearArgusWfile(char *file, char *filter) { ArgusDeleteList (ArgusWfileList); ArgusWfileList = NULL; } void setArgusWfile(char *file, char *filter) { FILE *fd = NULL; struct ArgusWfileStruct *wfile = NULL; char realpathname[PATH_MAX], *ptr = NULL; int euid = geteuid(); if (ArgusWfileList == NULL) ArgusWfileList = ArgusNewList(); if (file) { if (strcmp (file, "-")) { setuid(getuid()); if ((fd = fopen (file, "a+")) != NULL) { bzero (realpathname, PATH_MAX); if ((ptr = realpath (file, realpathname)) == NULL) ArgusLog (LOG_ERR, "setArgusWfile, realpath %s %s\n", file, strerror(errno)); else ptr = strdup(ptr); fclose (fd); } else { #ifdef ARGUSDEBUG ArgusDebug (1, "setArgusWfile, open %s %s\n", file, strerror(errno)); #endif } setuid(euid); } else ptr = strdup(file); if ((wfile = (struct ArgusWfileStruct *) ArgusCalloc (1, sizeof (*wfile))) != NULL) { wfile->filename = ptr; if (filter) wfile->filter = strdup(filter); ArgusPushFrontList(ArgusWfileList, wfile); } else ArgusLog (LOG_ERR, "setArgusWfile, ArgusCalloc %s\n", strerror(errno)); } else ArgusLog (LOG_ERR, "setArgusWfile, file is null\n"); } #include int ArgusEstablishListen (int port, char *bindIP, char *errbuf) { int s = -1; struct sockaddr_in sin; struct timeval tvpbuf, *tvp = &tvpbuf; struct hostent *host; gettimeofday (tvp, 0L); if (port) { sin.sin_addr.s_addr = INADDR_ANY; if (bindIP) { #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusEstablishListen(%d, 0x%x) inet_pton: %s\n", port, errbuf, bindIP); #endif if ((host = gethostbyname (bindIP)) != NULL) { if ((host->h_addrtype == AF_INET) && (host->h_length == 4)) { bcopy ((char *) *host->h_addr_list, (char *)&sin.sin_addr.s_addr, host->h_length); } else ArgusLog (LOG_ERR, "ArgusEstablishListen() unsupported bind address %s", bindIP); } else ArgusLog (LOG_ERR, "ArgusEstablishListen() bind address %s error %s", bindIP, strerror(errno)); } sin.sin_port = htons((u_short) port); sin.sin_family = AF_INET; #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusEstablishListen(%d, 0x%x) binding: %d\n", port, errbuf, sin.sin_addr.s_addr); #endif if ((s = socket (AF_INET, SOCK_STREAM, 0)) != -1) { if ((fcntl (s, F_SETFL, O_NDELAY)) >= 0) { if (!(bind (s, (struct sockaddr *)&sin, sizeof(sin)))) { if ((listen (s, ARGUS_MAXLISTEN)) >= 0) { ArgusLfd = s; } else { close (s); s = -1; snprintf(errbuf, MAXSTRLEN - 1, "%s: ArgusEstablishListen: listen() failure", ArgusProgramName); } } else { close (s); s = -1; snprintf(errbuf, MAXSTRLEN - 1, "%s: ArgusEstablishListen: bind() error", ArgusProgramName); } } else snprintf(errbuf, MAXSTRLEN - 1, "%s: ArgusEstablishListen: fcntl() error", ArgusProgramName); } else snprintf(errbuf, MAXSTRLEN - 1, "%s: ArgusEstablishListen: socket() error", ArgusProgramName); } #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusEstablishListen(%d, 0x%x) returning %d\n", port, errbuf, s); #endif return (s); } void ArgusCheckClientStatus () { int retn, fd; struct sockaddr from; int len = sizeof (from); if ((fd = accept (ArgusLfd, (struct sockaddr *)&from, &len)) > 0) { if ((fcntl (fd, F_SETFL, O_NONBLOCK)) >= 0) { if (ArgusTcpWrapper (fd, &from) >= 0) { int i; for (i = 0; i < ARGUS_MAXLISTEN; i++) { if (ArgusOutputTask->client[i].pid == -1) { if ((retn = pipe(ArgusOutputTask->client[i].pipe)) == 0) { pid_t pid; ArgusOutputTask->clienttags |= (1 << i); ArgusOutputTask->client[i].fd = fd; if ((ArgusOutputTask->client[i].sock = ArgusNewSocket (ArgusOutputTask->client[i].pipe[CLIENTSIDE])) != NULL) { bcopy ((char *)&from, (char *)&ArgusOutputTask->client[i].sock->sock, sizeof (struct sockaddr)); if ((pid = fork()) != 0) { ArgusOutputTask->client[i].pid = pid; ArgusSendInitialMar(ArgusOutputTask->client[i].pipe[CLIENTSIDE]); } else { ArgusOutputTask->client[i].pid = getpid(); ArgusClientProcess(&ArgusOutputTask->client[i], NULL); _exit(0); } } else ArgusLog (LOG_ERR, "ArgusCheckClientStatus() ArgusNewSocket returned %s", strerror(errno)); break; } else { close (fd); break; } } else { int status; waitpid(ArgusOutputTask->client[i].pid, &status, WNOHANG); if ((retn = kill(ArgusOutputTask->client[i].pid, 0)) < 0) { ArgusCloseSocket(i); i--; } } } if (i == ARGUS_MAXLISTEN) { ArgusGenerateClosingMar(ARGUS_ERROR); ArgusSystemMar->ahdr.status |= ARGUS_MAXLISTENEXCD; ArgusSendOutputData(fd, ArgusSystemMar); close(fd); } } else close (fd); } else { ArgusLog (LOG_WARNING, "ArgusCheckClientStatus: fcntl: %s", strerror(errno)); close (fd); } } else { ArgusLog (LOG_WARNING, "ArgusCheckClientStatus: accept: %s", strerror(errno)); close (fd); } #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusCheckClientStatus() returning\n"); #endif } void ArgusCloseSocket (int i) { struct ArgusListStruct *list = NULL; struct ArgusRecordStruct *rec; if (ArgusOutputTask->client[i].fd >= 0) { close (ArgusOutputTask->client[i].fd); ArgusOutputTask->client[i].fd = -1; } if (ArgusOutputTask->client[i].sock != NULL) { if ((list = ArgusOutputTask->client[i].sock->ArgusOutputList) != NULL) { while ((rec = ArgusFrontList (list)) != NULL) { ArgusPopFrontList (list); if (rec->buf != NULL) ArgusFree(rec->buf); ArgusFree(rec); } ArgusFree(list); } ArgusFree (ArgusOutputTask->client[i].sock); ArgusOutputTask->client[i].sock = NULL; } if (ArgusOutputTask->client[i].pipe[0] >= 0) { close(ArgusOutputTask->client[i].pipe[0]); ArgusOutputTask->client[i].pipe[0] = -1; } if (ArgusOutputTask->client[i].pipe[1] >= 0) { close(ArgusOutputTask->client[i].pipe[1]); ArgusOutputTask->client[i].pipe[1] = -1; } ArgusOutputTask->client[i].pid = -1; ArgusOutputTask->clienttags &= ~(1 << i); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusCloseSocket(%d) returning\n", i); #endif } void ArgusCloseClients () { int status; #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusCloseClients() waiting for Output Task %d\n", ArgusOutputTask->pid); #endif waitpid(ArgusOutputTask->pid, &status, 0); close(ArgusOutputPipe[0]); close(ArgusOutputPipe[1]); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusCloseClients() returning\n"); #endif } #if defined(HAVE_TCP_WRAPPER) #include #include #ifndef MAXPATHNAMELEN #define MAXPATHNAMELEN BUFSIZ #endif int allow_severity = LOG_INFO; /* run-time adjustable */ int deny_severity = LOG_WARNING; /* ditto */ #endif int ArgusTcpWrapper (int fd, struct sockaddr *from) { #if defined(HAVE_TCP_WRAPPER) int retn = 0; struct request_info request; /* * Find out the endpoint addresses of this conversation. Host name * lookups and double checks will be done on demand. */ request_init(&request, RQ_DAEMON, ArgusProgramName, RQ_FILE, STDIN_FILENO, 0); request.fd = fd; fromhost(&request); /* * Optionally look up and double check the remote host name. Sites * concerned with security may choose to refuse connections from hosts * that pretend to have someone elses host name. */ #ifdef PARANOID if (STR_EQ(eval_hostname(request.client), paranoid)) { ArgusLog (deny_severity, "refused connect from %s", eval_client(&request)); if (request.sink) request.sink(request.fd); return -1; } #endif /* * The BSD rlogin and rsh daemons that came out after 4.3 BSD disallow * socket options at the IP level. They do so for a good reason. * Unfortunately, we cannot use this with SunOS 4.1.x because the * getsockopt() system call can panic the system. */ #if defined(KILL_IP_OPTIONS) fix_options(&request); #endif /* * Find out and verify the remote host name. Sites concerned with * security may choose to refuse connections from hosts that pretend to * have someone elses host name. */ #ifdef HOSTS_ACCESS if (!hosts_access(&request)) { ArgusLog (deny_severity, "refused connect from %s", eval_client(&request)); if (request.sink) request.sink(request.fd); return -1; } else #endif /* Report remote client */ ArgusLog (allow_severity, "connect from %s", eval_client(&request)); return (retn); #else return (1); #endif }