📄 trophie.c
字号:
#include "trophie.h"int PROC_COUNT = 0;int TROPHIE_TIMEOUT = 30;int vs_ret;int vs_addr;/* Print the usage */void usage(void){ fprintf(stdout, "\n(Version: %s)\n\n", TROPHIE_VERSION); fprintf(stdout, "USAGE: %s [options]\n", program_name); fprintf(stdout, "Options:\n"); fprintf(stdout, " -c Show some of compiled-in VSAPI engine configuration options\n"); fprintf(stdout, " -D Daemon mode (forks into background)\n"); fprintf(stdout, " -d Debug mode (shows debugging output, does not fork into background)\n"); fprintf(stdout, " -f [path] Filename to scan for viruses\n"); fprintf(stdout, " -s [path] Directory to scan for viruses\n"); fprintf(stdout, " -h Help (this screen)\n"); fprintf(stdout, " -v VSAPI version (engine and patterns)\n");}/* We don't want any zombies Hope this is the right way to do it :)*/void sig_chld(int sig){ /* Suggested by philipp@corpex.de (Philipp Gasch黷z) */ int stat; pid_t pid; int serrno = errno; /* while there are any children that have exited... */#if (defined(HPUX1020) || defined(SLOWARIS)) while((pid = waitpid (-1, &stat, WNOHANG)) && PROC_COUNT)#else while((pid = waitpid (WAIT_ANY, &stat, WNOHANG)) && PROC_COUNT)#endif { if (pid == 0) { } /* no children here... */ if (pid == -1) { trophie_print(1, "There has been a problem catching a child: %s", strerror(errno)); break; } if (pid > 0) { PROC_COUNT--; trophie_print(1, "child finished/exited"); } } errno = serrno;}/* Cleanup and exit */void sig_exit(int sig){ trophie_print(0, "SIGNAL [%d] caught - cleaning up and exiting.\n", sig); trophie_end(); close(sock); unlink(TROPHIE_SOCKET_NAME); exit(0);}/* Reload VSAPI */void sig_reload(int sig){ trophie_print(0, "Initializing : Received -HUP signal [%d] - restarting (reloading config/data)", sig); trophie_end(); trophie_init(); trophie_version();}void trophie_timeout(int sig){ syslog(LOG_ERR, "Trophie child has timed-out (no data received in %d seconds) - process killed\n", TROPHIE_TIMEOUT); exit(-1);}/* Here we go... */int main(int argc, char *argv[]){ /* Result returned by SAVI */ int vsapi_result; /* Related to socket */ int msgsock; /* Related to other stuff */ int c, pid, cpid; /* 'Read' buffer */ char buf[256]; /* Pathfile to scan */ char scan[MAXPATHLEN]; /* Directory to scan */ char dir_scan[MAXPATHLEN]; /* Response to send back */ char sock_response[256]; /* fileInfo used to check if the socket is really a socket (for IS_SOCK()) */ struct stat fileInfo; /* socket structure... */ struct sockaddr_un server; /* Used when changing the group of the socket */ struct passwd *userInfo; /* Stupid signal handling code */ int sig_ret; struct sigaction sa_chld; struct sigaction sa_hup; struct sigaction sa_exit; /* Copy the name of the program (as supplied on the command line) */ program_name = argv[0]; /* Clear the scan (path to the filename to scan */ memset(scan, 0, sizeof(scan)); memset(dir_scan, 0, sizeof(dir_scan)); /* Parse cmdline arguments */ while ((c = getopt(argc, argv, "cDdf:s:hv")) != EOF) { switch(c) { case 'c': trophie_init(); trophie_show_settings(); trophie_end(); exit(0); break; case 'D': TROPHIE_DAEMON = 1; break; case 'd': TROPHIE_DEBUG = 1; break; case 'f': if (optarg[0] != '\0') /* Filename to scan from command line */ strncpy(scan, optarg, sizeof(scan)-1); break; case 's': if (optarg[0] != '\0') strncpy(dir_scan, optarg, sizeof(dir_scan)); break; case 'h': usage(); exit(0); break; case 'v': TROPHIE_DAEMON = 0; TROPHIE_DEBUG = 0; trophie_init(); trophie_version(); trophie_end(); exit(0); break; default: TROPHIE_DAEMON = 0; TROPHIE_DEBUG = 0; break; } } /* We will check if the TROPHIE_SOCKET_GROUP exists first */ if (!getpwnam(TROPHIE_SOCKET_GROUP)) { trophie_print(0, "ERROR: TROPHIE_SOCKET_GROUP user (%s) does not exist - exiting", TROPHIE_SOCKET_GROUP); if (TROPHIE_DAEMON == 1) fprintf(stderr, "ERROR: TROPHIE_SOCKET_GROUP user (%s) does not exist - exiting\n", TROPHIE_SOCKET_GROUP); exit(1); } /* If TROPHIE_DEBUG/TROPHIE_DAEMON are not set (0 or 1) = set to 0 */ if (TROPHIE_DEBUG != 0 && TROPHIE_DEBUG != 1) TROPHIE_DEBUG = 0; if (TROPHIE_DAEMON != 0 && TROPHIE_DAEMON != 1) TROPHIE_DAEMON = 0; /* Initialize VSAPI engine/data */ trophie_init(); /* Spit out the version number(s) */ trophie_version(); /* If file is specified on a command line, scan it and return result */ /* When scan is finished, exit */ if (scan[0] != '\0') { trophie_print(0, "Scanning file : '%s' ", scan); vsapi_result = trophie_scanfile(scan); trophie_end(); exit(0); } /* NOTE: directory scanning is implemented just for command line - it won't be implemented for socket usage */ /* If directory is specified on a command line, scan it and return results */ /* When scan is finished, exit */ if (dir_scan[0] != '\0') { trophie_print(0, "Scanning dir : '%s' ", dir_scan); vsapi_result = trophie_scandir(dir_scan); trophie_end(); exit(0); } /* Create a socket */ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { trophie_print(0, "ERROR: socket() failed in main()"); exit(1); } /* Check if the socket already exists */ if (stat(TROPHIE_SOCKET_NAME, &fileInfo) == 0) { if (S_ISSOCK(fileInfo.st_mode)) { trophie_print(0, "ERROR: Socket '%s' already exists!", TROPHIE_SOCKET_NAME); trophie_print(0, "NOTE: Removing existing socket (ouch!)"); if (unlink(TROPHIE_SOCKET_NAME) == -1) { trophie_print(0, "ERROR: Could not remove socket '%s'. Aborting!", TROPHIE_SOCKET_NAME); exit(1); } } } /* Set the umask */ umask(0007); /* Set the socket properties (family, name) */ server.sun_family = AF_UNIX; strncpy(server.sun_path, TROPHIE_SOCKET_NAME, sizeof(server.sun_path)-1); trophie_print(1, "server.sun_path has a name: [%s]", TROPHIE_SOCKET_NAME); /* Bind a socket */ if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) == -1) { trophie_print(0, "ERROR: bind() failed in main()"); exit(1); } /* Change the owner/group of the socket */ userInfo = getpwnam(TROPHIE_SOCKET_GROUP); if (chown(TROPHIE_SOCKET_NAME, -1, (gid_t)userInfo->pw_gid) == -1) { trophie_print(0, "ERROR: failed to chown() the socket - socket remains owned by root:root"); } /* Start listening */ if (listen(sock, TROPHIE_LISTEN_QUEUE) == -1) { trophie_print(0, "ERROR: listen() failed in main()"); exit(1); } /* If TROPHIE_DAEMON is set, show some message */ /* Argh - at this point, everything already goes to syslog (if TROPHIE_DAEMON is set) - will change this later :) */ if (TROPHIE_DAEMON == 1) { if ((pid = fork()) > 0) { trophie_print(0, "%s placed in the background [PID: %d]", program_name, pid); exit(0); } else if (pid == -1) { perror("fork"); trophie_print(0, "ERROR: Could not fork() - aborting"); exit(1); } fprintf(stderr, "%s placed in the background\n", program_name); } /* Catch SIGCHLD */ sa_chld.sa_handler = sig_chld; sigfillset(&sa_chld.sa_mask); sa_chld.sa_flags = SA_RESTART; sig_ret = sigaction(SIGCHLD, &sa_chld, NULL); if (sig_ret < 0) trophie_print(0, "ERROR: Could not install SIGCHLD signal handler (sig_ret = [%d])", sig_ret); /* Reload VSAPI on HUP signal */ sa_hup.sa_handler = sig_reload; sigfillset(&sa_hup.sa_mask); sa_hup.sa_flags = SA_RESTART; sig_ret = sigaction(SIGHUP, &sa_hup, NULL); if (sig_ret < 0) trophie_print(0, "ERROR: Could not install SIGHUP signal handler (sig_ret = [%d])", sig_ret); /* Try to cleanup if one of these gets caught... */ sa_exit.sa_handler = sig_exit; sigfillset(&sa_exit.sa_mask); sa_exit.sa_flags = 0; sig_ret = sigaction(SIGINT, &sa_exit, NULL); if (sig_ret < 0) trophie_print(0, "ERROR: Could not install SIGINT signal handler (sig_ret = [%d])", sig_ret); sig_ret = sigaction(SIGTERM, &sa_exit, NULL); if (sig_ret < 0) trophie_print(0, "ERROR: Could not install SIGTERM signal handler (sig_ret = [%d])", sig_ret); sig_ret = sigaction(SIGQUIT, &sa_exit, NULL); if (sig_ret < 0) trophie_print(0, "ERROR: Could not install SIGQUIT signal handler (sig_ret = [%d])", sig_ret); sig_ret = sigaction(SIGSEGV, &sa_exit, NULL); if (sig_ret < 0) trophie_print(0, "ERROR: Could not install SIGSEGV signal handler (sig_ret = [%d])", sig_ret); trophie_print(1, "Signal handlers set"); /* Fun begins... */ for (;;) { /* Accept the connection(s) */ msgsock = accept(sock, 0, 0); trophie_print(1, "accept() set"); /* If we got EINTR, it means some signal is caught - on HUP, we'll reload (and ignore this error), and on other signal we'll die anyway (probably :) */ if (msgsock == -1 && errno != EINTR) { trophie_print(0, "error in accept() - exiting"); } else if (msgsock == -1) /* this should be EINTR now */ { trophie_print(1, "EINTR set/caught in accept() loop - some signal received"); continue; } else { /* Suggested by philipp@corpex.de (Philipp Gasch黷z) */ while(PROC_COUNT >= MAX_PROC) usleep(10); /* Fork */ if ((cpid = fork())) { trophie_print(1, "forked() a child - everything seems ok"); close(msgsock); PROC_COUNT++; continue; } else { /* child */ struct sigaction sa_handle; FILE *msgfp; struct stat reqstat; /* bzero((char *)(&sa_exit), sizeof(sa_exit)); */ sigemptyset(&sa_handle.sa_mask); sa_handle.sa_handler = trophie_timeout; if ((sig_ret = sigaction(SIGALRM, &sa_handle, NULL)) < 0) trophie_print(0, "Error setting handler for SIGINT"); /* Set the priority - try to 'save' the system :) */ setpriority(PRIO_PROCESS, 0, PRIORITY); /* Clean the buffer */ memset(buf, 0, sizeof(buf)); trophie_print(1, "cleared buf using memset()"); /* We will set the alarm (timeout) If Trophie doesn't receive anythin within TROPHIE_TIMEOUT seconds - quit */ alarm(TROPHIE_TIMEOUT); /* We will 'reopen' the socket, for fgets */ msgfp = fdopen(msgsock, "r"); while (fgets(buf, sizeof(buf)-1, msgfp)) { /* If it is end of file, ferror() should return 0 - but if it is an error... we better try to catch it */ if (buf == NULL) { if (ferror(msgfp)) { trophie_print(0, "fgets() error in main() [while reading from socket] - exiting"); exit(-1); } } trophie_print(1, "read %d bytes from socket", strlen(buf)); /* Clear the virus name */ memset(VIR_NAME, 0, sizeof(VIR_NAME)); /* Remove the newline (if it exists) */ if (strchr(buf, '\n')) *strchr(buf, '\n') = '\0'; trophie_print(1, "[%d] data read [%s]", getpid(), buf); /* Now, let's decide if we'll scan file or a dir... */ if ((stat(buf, &reqstat)) == 0) { if (S_ISDIR(reqstat.st_mode)) { vsapi_result = trophie_scandir(buf); } else if (S_ISREG(reqstat.st_mode)) { vsapi_result = trophie_scanfile(buf); } else { trophie_print(0, "Error : What was requested is not file or directory - aborting"); vsapi_result = -1; } } else { /* File/dir doesn't exist */ vsapi_result = -1; } /* Clear the response buffer */ memset(sock_response, 0, sizeof(sock_response)); /* "Craft" the response (this is so lame) - FIXME */ if ( (VIR_NAME[0] != '\0') && (REPORT_VIRUSNAME == 1) ) snprintf(sock_response, sizeof(sock_response)-1, "%d:%s", vsapi_result, VIR_NAME); else snprintf(sock_response, sizeof(sock_response)-1, "%d", vsapi_result); trophie_print(1, "response = [%s]", sock_response); trophie_print(1, "sending the response [%s] to socket", sock_response); /* Complain on errors - do nothing if everything is okay */ if (write(msgsock, sock_response, sizeof(sock_response)) > 0) trophie_print(1, "response [%s] sent!", sock_response); else trophie_print(0, "ERROR: write() to remove socket failed!"); trophie_print(1, "closing the socket"); } alarm(0); trophie_print(1, "I am gone..."); exit(0); } } close(msgsock); } /* This will never be reached, but we'll add it for 'just in case' factor */ close(sock); unlink(TROPHIE_SOCKET_NAME); trophie_end(); trophie_print(0, "Cleanup : VSAPI cleaned up and terminated (by itself, huh?)"); /* Bye, bye... */ exit(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -