/* * Copyright (C) 2006 Tony Sin(x) '76 * All rights reserved. * */ /* * GNU GENERAL PUBLIC LICENSE * Version 2, June 1991 * * Copyright (C) 1989, 1991 Free Software Foundation, Inc. * 675 Mass Ave, Cambridge, MA 02139, USA * Everyone is permitted to copy and distribute verbatim copies * of this license document, but changing it is not allowed. * * 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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifdef HAVE_CONFIG_H #ifndef __main_config_h__ #define __main_config_h__ #include "../config.h" #endif #include #include #include #include #include #include #include #include #include #ifdef TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif #endif #endif #include "message.h" #include "exception.h" #include "util.h" struct msgLineType *cMessage::msgLines; bool cMessage::message_en = false; char *cMessage::sender = NULL; char *cMessage::subject = NULL; int cMessage::counter = 0; cMessage::cMessage(const char *fileName) { int i; if (!(counter++)) loadMessage(fileName); recipients_num = 0; bg_sender = date = host = NULL; for (i = 0; i < MAX_RECIPIENTS; recipients[i++] = NULL); } cMessage::~cMessage() { int i; struct msgLineType *msgPtr = NULL; if (!(--counter)) { while (msgLines != NULL) { msgPtr = msgLines; msgLines = msgLines->next; if (msgPtr->type == _fixed) delete [] msgPtr->data; delete msgPtr; } msgLines = NULL; if (sender != NULL) delete [] sender, sender = NULL; if (subject != NULL) delete [] subject, subject = NULL; message_en = false; } else { if (bg_sender != NULL) delete [] bg_sender, bg_sender = NULL; if (date != NULL) delete [] date, date = NULL; if (host != NULL) delete [] host, host = NULL; for (i = 0; i < recipients_num; delete [] recipients[i], recipients[i++] = NULL); } } void cMessage::loadMessage(const char *fileName) { FILE *fp; char *fileLine, *bufLine; int cPtr, bufPtr, len; stateType state; struct msgLineType *msgPtr = NULL; bool is_an_error = false; try { msgLines = NULL; if (fileName != NULL) { fileLine = new char[BUF_LEN]; bufLine = new char[BUF_LEN]; if ((fp = fopen(fileName,"rt")) == NULL) throw cException(MESSAGE_CLASS_NAME,MESSAGE_CLASS_NAME,"fopen",errno); if (fgets(fileLine,BUF_LEN,fp) != NULL) { purgeEscapeChars(fileLine); sender = new char[strlen(fileLine)+1]; strcpy(sender,fileLine); } else throw cException(MESSAGE_CLASS_NAME,MESSAGE_CLASS_NAME,"fgets",ferror(fp)); if (fgets(fileLine,BUF_LEN,fp) != NULL) { purgeEscapeChars(fileLine); subject = new char[strlen(fileLine)+1]; strcpy(subject,fileLine); } else throw cException(MESSAGE_CLASS_NAME,MESSAGE_CLASS_NAME,"fgets",ferror(fp)); bufPtr = 0; state = _reset; while (fgets(fileLine,BUF_LEN,fp) != NULL) { purgeEscapeChars(fileLine); strcat(fileLine,"\r\n"); len = strlen(fileLine); for (cPtr = 0; cPtr < len; cPtr++) switch (state) { case _reset: if (fileLine[cPtr] == '%') state = _startTag; else { state = _outsideTag; bufLine[bufPtr++] = fileLine[cPtr]; } break; case _startTag: state = ((fileLine[cPtr] == '%')? _outsideTag : _insideTag); bufLine[bufPtr++] = toupper(fileLine[cPtr]); break; case _insideTag: if (fileLine[cPtr] == '%') { bufLine[bufPtr++] = '\0'; if (msgLines == NULL) msgLines = msgPtr = new msgLineType; else msgPtr = msgPtr->next = new msgLineType; msgPtr->data = NULL; if (!strcmp(bufLine,"SENDER")) msgPtr->type = _sender; else if (!strcmp(bufLine,"HOST")) msgPtr->type = _host; else if (!strcmp(bufLine,"VIRNAME")) msgPtr->type = _virname; else if (!strcmp(bufLine,"DATE")) msgPtr->type = _date; else { msgPtr->type = _error; is_an_error = true; } msgPtr->next = NULL; state = _reset; bufPtr = 0; } else bufLine[bufPtr++] = toupper(fileLine[cPtr]); break; case _outsideTag: if (fileLine[cPtr] == '%') { bufLine[bufPtr++] = '\0'; if (msgLines == NULL) msgLines = msgPtr = new msgLineType; else msgPtr = msgPtr->next = new msgLineType; msgPtr->data = new char[bufPtr]; strcpy(msgPtr->data,bufLine); msgPtr->type = _fixed; msgPtr->next = NULL; state = _startTag; bufPtr = 0; } else bufLine[bufPtr++] = fileLine[cPtr]; break; } } if (state == _outsideTag) { bufLine[bufPtr++] = '\0'; if (msgLines == NULL) msgLines = msgPtr = new msgLineType; else msgPtr = msgPtr->next = new msgLineType; msgPtr->data = new char[bufPtr]; strcpy(msgPtr->data,bufLine); msgPtr->type = _fixed; msgPtr->next = NULL; bufPtr = 0; } if (fclose(fp)) throw cException(MESSAGE_CLASS_NAME,MESSAGE_CLASS_NAME,"fclose",errno); delete [] fileLine; delete [] bufLine; if ((sender == NULL) || (subject == NULL) || (msgLines == NULL) || is_an_error) throw cException(MESSAGE_CLASS_NAME,MESSAGE_CLASS_NAME,"wrong message file",0); else { message_en = true; syslog(LOG_INFO,"User message enabled"); } } } catch (cException c_e) { syslog(LOG_ERR,"%s",c_e.str); } } void cMessage::loadControlFile(const char *fileName) { FILE *fp; char *fileLine; struct stat f_stat; struct tm f_time; char *p; if (message_en) { try { if ((fp = fopen(fileName,"rt")) == NULL) throw cException(MESSAGE_CLASS_NAME,"loadControlFile","fopen",errno); fileLine = new char[BUF_LEN]; while (fgets(fileLine,BUF_LEN,fp) != NULL) { purgeEscapeChars(fileLine); switch (fileLine[0]) { case 's': if ((bg_sender == NULL) && strlen(fileLine+1)) { bg_sender = new char[strlen(fileLine+1)+1]; strcpy(bg_sender,fileLine+1); } break; case 'f': if (host == NULL) { p = strchr(fileLine,';'); host = new char[strlen(p+2)+1]; strcpy(host,p+2); } break; case 'r': recipients[recipients_num] = new char[strlen(fileLine+1)+1]; strcpy(recipients[recipients_num++],fileLine+1); break; default: break; } } if (fclose(fp)) throw cException(MESSAGE_CLASS_NAME,"loadControlFile","fclose",errno); if (date == NULL) { if (stat(fileName,&f_stat) == -1) throw cException(MESSAGE_CLASS_NAME,"loadControlFile","stat",errno); if (localtime_r(&(f_stat.st_mtime),&f_time) == NULL) throw cException(MESSAGE_CLASS_NAME,"loadControlFile","localtime_r",errno); strftime(fileLine,BUF_LEN,"%a, %d %b %Y %H:%M:%S %Z",&f_time); date = new char[strlen(fileLine)+1]; strcpy(date,fileLine); } delete [] fileLine; } catch (cException c_e) { syslog(LOG_ERR,"%s",c_e.str); } } } void cMessage::sendMessage(const char *virName) { int i; char *cmdLine; FILE *pipe_fp; time_t now_t; struct tm now; struct msgLineType *msgPtr; char locDate[LOC_DATE_SIZE]; if (message_en) { cmdLine = new char[BUF_LEN]; try { if (msgLines != NULL) { if (time(&now_t) == ((time_t) -1)) throw cException(MESSAGE_CLASS_NAME,"sendMessage","time",errno); if (localtime_r(&now_t,&now) == NULL) throw cException(MESSAGE_CLASS_NAME,"sendMessage","localtime_r",errno); strftime(locDate,LOC_DATE_SIZE,"%a, %d %b %Y %H:%M:%S %z",&now); for (i = 0; i < recipients_num; i++) { if (sprintf(cmdLine,"%s -F \"ClamCour Virus Notify\" -f %s %s",COURIER_SENDMAIL,sender,recipients[i]) < 0) throw cException(MESSAGE_CLASS_NAME,"sendMessage","sprintf",errno); if ((pipe_fp = popen(cmdLine,"w")) == NULL) throw cException(MESSAGE_CLASS_NAME,"sendMessage","popen",errno); if (fprintf(pipe_fp,"Subject: %s\r\n" \ "From: \"ClamCour Virus Notify\" <%s>\r\n" \ "To: \"User\" <%s>\r\n" \ "Date: %s\r\n" \ "User-Agent: %s\r\n" \ "Content-Type: text/plain; format=flowed; charset=us-ascii\r\n" \ "Content-Transfer-Encoding: 7bit\r\n" \ "MIME-Version: 1.0\r\n" \ "X-Priority: 1\r\n" \ "Priority: Urgent\r\n" \ "Importance: High\r\n" \ "\r\n", subject, sender, recipients[i], locDate, PACKAGE_STRING) < 0) throw cException(MESSAGE_CLASS_NAME,"sendMessage","fprintf(mail)",errno); for (msgPtr = msgLines; msgPtr != NULL; msgPtr = msgPtr->next) switch (msgPtr->type) { case _fixed: if (fprintf(pipe_fp,"%s",msgPtr->data) < 0) throw cException(MESSAGE_CLASS_NAME,"sendMessage","fprintf(fixed)",errno); break; case _host: if (fprintf(pipe_fp,"%s",host) < 0) throw cException(MESSAGE_CLASS_NAME,"sendMessage","fprintf(host)",errno); break; case _virname: if (fprintf(pipe_fp,"%s",virName) < 0) throw cException(MESSAGE_CLASS_NAME,"sendMessage","fprintf(virName)",errno); break; case _sender: if (fprintf(pipe_fp,"%s",((bg_sender != NULL)? bg_sender : UNKNOWN_SENDER)) < 0) throw cException(MESSAGE_CLASS_NAME,"sendMessage","fprintf(bg_sender)",errno); break; case _date: if (fprintf(pipe_fp,"%s",date) < 0) throw cException(MESSAGE_CLASS_NAME,"sendMessage","fprintf(date)",errno); break; case _error: throw cException(MESSAGE_CLASS_NAME,"sendMessage","wrong tag",0); break; } if (fprintf(pipe_fp,"\r\n") < 0) throw cException(MESSAGE_CLASS_NAME,"sendMessage","fprintf(end)",errno); if (fflush(pipe_fp)) throw cException(MESSAGE_CLASS_NAME,"sendMessage","fflush",errno); if (pclose(pipe_fp) == -1) throw cException(MESSAGE_CLASS_NAME,"sendMessage","pclose",errno); } } } catch (cException c_e) { syslog(LOG_ERR,"%s",c_e.str); } delete [] cmdLine; } }