e3aaff8e |
/* |
4c237bcf |
* Copyright (C)2008 Sourcefire, Inc. |
e3aaff8e |
* |
4c237bcf |
* Author: aCaB <acab@clamav.net> |
e3aaff8e |
*
* This program is free software; you can redistribute it and/or modify |
4c237bcf |
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. |
e3aaff8e |
*
* 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 |
48b7b4a7 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA. |
e3aaff8e |
*/
|
7908713f |
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
|
e3aaff8e |
#include <stdio.h> |
4c237bcf |
#include <sys/types.h>
#include <unistd.h> |
e004f1c5 |
#include <pwd.h> |
3aa15b4c |
#include <grp.h> |
4c237bcf |
#include <string.h> |
aa633fa0 |
#ifdef USE_SYSLOG
#include <syslog.h>
#endif |
4c237bcf |
#include <time.h>
#include <libmilter/mfapi.h> |
eef726b0 |
|
4c237bcf |
#include "clamav.h" |
e3aaff8e |
|
4c237bcf |
#include "shared/output.h" |
278dc6b3 |
#include "shared/optparser.h" |
4c237bcf |
#include "shared/misc.h" |
ec34b80f |
#include "libclamav/default.h" |
4c237bcf |
#include "connpool.h"
#include "netcode.h"
#include "clamfi.h" |
3eb16511 |
#include "whitelist.h" |
4c237bcf |
|
82d4fa94 |
struct smfiDesc descr; |
e004f1c5 |
|
4c237bcf |
int main(int argc, char **argv) { |
278dc6b3 |
char *my_socket, *pt;
const struct optstruct *opt;
struct optstruct *opts; |
e9c4dd09 |
time_t currtime; |
e394c513 |
mode_t umsk; |
4c237bcf |
int ret;
|
82d4fa94 |
memset(&descr, 0, sizeof(struct smfiDesc));
descr.xxfi_name = "ClamAV"; /* filter name */
descr.xxfi_version = SMFI_VERSION; /* milter version */ |
3521624b |
descr.xxfi_flags = SMFIF_QUARANTINE; /* flags */ |
82d4fa94 |
descr.xxfi_connect = clamfi_connect; /* connection info filter */
descr.xxfi_envfrom = clamfi_envfrom; /* envelope sender filter */
descr.xxfi_envrcpt = clamfi_envrcpt; /* envelope recipient filter */
descr.xxfi_header = clamfi_header; /* header filter */
descr.xxfi_body = clamfi_body; /* body block */
descr.xxfi_eom = clamfi_eom; /* end of message */
descr.xxfi_abort = clamfi_abort; /* message aborted */
|
278dc6b3 |
opts = optparse(NULL, argc, argv, 1, OPT_MILTER, 0, NULL);
if (!opts) {
mprintf("!Can't parse command line options\n"); |
a4371160 |
return 1; |
4c237bcf |
}
|
278dc6b3 |
if(optget(opts, "help")->enabled) { |
4c237bcf |
printf("Usage: %s [-c <config-file>]\n\n", argv[0]);
printf(" --help -h Show this help\n");
printf(" --version -V Show version and exit\n");
printf(" --config-file <file> -c Read configuration from file\n\n"); |
278dc6b3 |
optfree(opts); |
44d08756 |
return 0; |
4c237bcf |
} |
19c17946 |
if(opts->filename) {
int x;
for(x = 0; opts->filename[x]; x++)
mprintf("^Ignoring option %s\n", opts->filename[x]);
} |
4c237bcf |
|
278dc6b3 |
if(optget(opts, "version")->enabled) { |
4c237bcf |
printf("clamav-milter %s\n", get_version()); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 0;
} |
44ba5c0e |
|
278dc6b3 |
pt = strdup(optget(opts, "config-file")->strarg);
if((opts = optparse(pt, 0, NULL, 1, OPT_MILTER, 0, opts)) == NULL) {
printf("%s: cannot parse config file %s\n", argv[0], pt);
free(pt); |
4c237bcf |
return 1;
} |
278dc6b3 |
free(pt); |
684d3122 |
|
278dc6b3 |
if((opt = optget(opts, "Chroot"))->enabled) {
if(chdir(opt->strarg) != 0) {
logg("!Cannot change directory to %s\n", opt->strarg); |
f7203529 |
return 1;
} |
278dc6b3 |
if(chroot(opt->strarg) != 0) {
logg("!chroot to %s failed. Are you root?\n", opt->strarg); |
f7203529 |
return 1;
}
}
|
278dc6b3 |
if(geteuid() == 0 && (opt = optget(opts, "User"))->enabled) { |
4c237bcf |
struct passwd *user = NULL; |
278dc6b3 |
if((user = getpwnam(opt->strarg)) == NULL) {
fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg);
optfree(opts); |
4c237bcf |
return 1; |
684d3122 |
} |
28071296 |
|
278dc6b3 |
if(optget(opts, "AllowSupplementaryGroups")->enabled) { |
4c237bcf |
#ifdef HAVE_INITGROUPS |
278dc6b3 |
if(initgroups(opt->strarg, user->pw_gid)) { |
4c237bcf |
fprintf(stderr, "ERROR: initgroups() failed.\n"); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 1;
} |
4c5e69c8 |
#else |
4c237bcf |
mprintf("!AllowSupplementaryGroups: initgroups() is not available, please disable AllowSupplementaryGroups\n"); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 1; |
4c5e69c8 |
#endif |
31ee8076 |
} else { |
4c237bcf |
#ifdef HAVE_SETGROUPS
if(setgroups(1, &user->pw_gid)) {
fprintf(stderr, "ERROR: setgroups() failed.\n"); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 1;
} |
8ac80fb8 |
#endif |
e3aaff8e |
}
|
4c237bcf |
if(setgid(user->pw_gid)) {
fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 1; |
ebc4ec8f |
} |
66ff992e |
|
4c237bcf |
if(setuid(user->pw_uid)) {
fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 1; |
66ff992e |
} |
4c237bcf |
} |
ebc4ec8f |
|
278dc6b3 |
logg_lock = !optget(opts, "LogFileUnlock")->enabled;
logg_time = optget(opts, "LogTime")->enabled;
logg_size = optget(opts, "LogFileMaxSize")->numarg;
logg_verbose = mprintf_verbose = optget(opts, "LogVerbose")->enabled; |
fe3d8be8 |
|
278dc6b3 |
if((opt = optget(opts, "LogFile"))->enabled) {
logg_file = opt->strarg; |
58481352 |
if(!cli_is_abspath(logg_file)) { |
4c237bcf |
fprintf(stderr, "ERROR: LogFile requires full path.\n");
logg_close(); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 1; |
fe3d8be8 |
} |
4c237bcf |
} else
logg_file = NULL; |
fe3d8be8 |
|
4c237bcf |
#if defined(USE_SYSLOG) && !defined(C_AIX) |
278dc6b3 |
if(optget(opts, "LogSyslog")->enabled) { |
4c237bcf |
int fac; |
54a9f64e |
|
278dc6b3 |
opt = optget(opts, "LogFacility");
if((fac = logg_facility(opt->strarg)) == -1) {
logg("!LogFacility: %s: No such facility.\n", opt->strarg); |
4c237bcf |
logg_close(); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 1; |
736c8d91 |
} |
f7ab4278 |
|
aa633fa0 |
openlog("clamav-milter", LOG_PID, fac); |
4c237bcf |
logg_syslog = 1;
} |
06bfd678 |
#endif |
7089d180 |
|
e9c4dd09 |
time(&currtime);
if(logg("#+++ Started at %s", ctime(&currtime))) {
fprintf(stderr, "ERROR: Can't initialize the internal logger\n");
logg_close();
optfree(opts);
return 1;
} |
278dc6b3 |
if((opt = optget(opts, "TemporaryDirectory"))->enabled)
tempdir = opt->strarg; |
87620def |
|
278dc6b3 |
if(localnets_init(opts) || init_actions(opts)) { |
6840d862 |
logg_close(); |
278dc6b3 |
optfree(opts); |
6840d862 |
return 1;
}
|
278dc6b3 |
if((opt = optget(opts, "Whitelist"))->enabled && whitelist_init(opt->strarg)) { |
3eb16511 |
localnets_free();
logg_close(); |
278dc6b3 |
optfree(opts); |
3eb16511 |
return 1;
} |
ce34c246 |
|
57aa0269 |
if((opt = optget(opts, "SkipAuthenticated"))->enabled && smtpauth_init(opt->strarg)) {
localnets_free();
whitelist_free();
logg_close();
optfree(opts);
return 1;
}
|
3521624b |
pt = optget(opts, "AddHeader")->strarg;
if(strcasecmp(pt, "No")) { |
ce34c246 |
char myname[255];
|
b955dae4 |
if(((opt = optget(opts, "ReportHostname"))->enabled && strncpy(myname, opt->strarg, sizeof(myname))) || !gethostname(myname, sizeof(myname))) { |
ce34c246 |
myname[sizeof(myname)-1] = '\0';
snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s at %s", get_version(), myname); |
b955dae4 |
} else |
ce34c246 |
snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s", get_version()); |
b955dae4 |
xvirushdr[sizeof(xvirushdr)-1] = '\0';
|
3521624b |
descr.xxfi_flags |= SMFIF_ADDHDRS;
if(strcasecmp(pt, "Add")) { /* Replace or Yes */
descr.xxfi_flags |= SMFIF_CHGHDRS;
addxvirus = 1;
} else { /* Add */
addxvirus = 2;
} |
ce34c246 |
} |
e9747a42 |
|
278dc6b3 |
if(!(my_socket = optget(opts, "MilterSocket")->strarg)) { |
4c237bcf |
logg("!Please configure the MilterSocket directive\n"); |
3eb16511 |
localnets_free();
whitelist_free(); |
4c237bcf |
logg_close(); |
278dc6b3 |
optfree(opts); |
7089d180 |
return 1; |
4c237bcf |
} |
41f5623e |
if(!optget(opts, "Foreground")->enabled) {
if(daemonize() == -1) {
logg("!daemonize() failed\n");
localnets_free();
whitelist_free();
cpool_free();
logg_close();
optfree(opts);
return 1;
}
if(chdir("/") == -1)
logg("^Can't change current working directory to root\n");
}
|
4c237bcf |
if(smfi_setconn(my_socket) == MI_FAILURE) {
logg("!smfi_setconn failed\n"); |
3eb16511 |
localnets_free();
whitelist_free(); |
4c237bcf |
logg_close(); |
278dc6b3 |
optfree(opts); |
f7ab4278 |
return 1; |
4c237bcf |
}
if(smfi_register(descr) == MI_FAILURE) {
logg("!smfi_register failed\n"); |
3eb16511 |
localnets_free();
whitelist_free(); |
83ed1043 |
logg_close(); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 1;
} |
278dc6b3 |
opt = optget(opts, "FixStaleSocket"); |
e394c513 |
umsk = umask(0777); /* socket is created with 000 to avoid races */ |
278dc6b3 |
if(smfi_opensocket(opt->enabled) == MI_FAILURE) { |
4c237bcf |
logg("!Failed to create socket %s\n", my_socket); |
3eb16511 |
localnets_free();
whitelist_free(); |
040708a3 |
logg_close(); |
278dc6b3 |
optfree(opts); |
19575eba |
return 1; |
4c237bcf |
} |
e394c513 |
umask(umsk); /* restore umask */
if(strncmp(my_socket, "inet:", 5) && strncmp(my_socket, "inet6:", 6)) {
/* set group ownership and perms on the local socket */
char *sock_name = my_socket;
mode_t sock_mode;
if(!strncmp(my_socket, "unix:", 5))
sock_name += 5;
if(!strncmp(my_socket, "local:", 6))
sock_name += 6;
if(*my_socket == ':')
sock_name ++;
if(optget(opts, "MilterSocketGroup")->enabled) {
char *gname = optget(opts, "MilterSocketGroup")->strarg, *end;
gid_t sock_gid = strtol(gname, &end, 10);
if(*end) {
struct group *pgrp = getgrnam(gname);
if(!pgrp) {
logg("!Unknown group %s\n", gname);
localnets_free();
whitelist_free();
logg_close();
optfree(opts);
return 1;
}
sock_gid = pgrp->gr_gid;
}
if(chown(sock_name, -1, sock_gid)) {
logg("!Failed to change socket ownership to group %s\n", gname);
localnets_free();
whitelist_free();
logg_close();
optfree(opts);
return 1;
}
}
if(optget(opts, "MilterSocketMode")->enabled) {
char *end;
sock_mode = strtol(optget(opts, "MilterSocketMode")->strarg, &end, 8);
if(*end) {
logg("!Invalid MilterSocketMode %s\n", optget(opts, "MilterSocketMode")->strarg);
localnets_free();
whitelist_free();
logg_close();
optfree(opts);
return 1;
}
} else
sock_mode = 0777 & ~umsk;
if(chmod(sock_name, sock_mode & 0666)) {
logg("!Cannot set milter socket permission to %s\n", optget(opts, "MilterSocketMode")->strarg);
localnets_free();
whitelist_free();
logg_close();
optfree(opts);
return 1;
}
} |
835c9751 |
|
278dc6b3 |
maxfilesize = optget(opts, "MaxFileSize")->numarg; |
ec34b80f |
if(!maxfilesize) {
logg("^Invalid MaxFileSize, using default (%d)\n", CLI_DEFAULT_MAXFILESIZE);
maxfilesize = CLI_DEFAULT_MAXFILESIZE;
} |
278dc6b3 |
readtimeout = optget(opts, "ReadTimeout")->numarg; |
36f79c60 |
|
278dc6b3 |
cpool_init(opts); |
4c237bcf |
if (!cp) {
logg("!Failed to init the socket pool\n"); |
3eb16511 |
localnets_free();
whitelist_free(); |
4c237bcf |
logg_close(); |
278dc6b3 |
optfree(opts); |
4c237bcf |
return 1;
} |
530999cb |
|
278dc6b3 |
if((opt = optget(opts, "PidFile"))->enabled) { |
87620def |
FILE *fd; |
cd0d6a0b |
mode_t old_umask = umask(0002); |
87620def |
|
278dc6b3 |
if((fd = fopen(opt->strarg, "w")) == NULL) {
logg("!Can't save PID in file %s\n", opt->strarg); |
87620def |
} else {
if (fprintf(fd, "%u", (unsigned int)getpid())<0) { |
278dc6b3 |
logg("!Can't save PID in file %s\n", opt->strarg); |
87620def |
}
fclose(fd);
}
umask(old_umask);
} |
530999cb |
|
4c237bcf |
ret = smfi_main(); |
93928eab |
|
278dc6b3 |
optfree(opts); |
bca134bc |
|
4c237bcf |
logg_close();
cpool_free(); |
6840d862 |
localnets_free(); |
3eb16511 |
whitelist_free();
|
4c237bcf |
return ret; |
93928eab |
} |
3eb16511 |
|
9fe789f8 |
/* |
4c237bcf |
* Local Variables:
* mode: c
* c-basic-offset: 4
* tab-width: 8
* End:
* vim: set cindent smartindent autoindent softtabstop=4 shiftwidth=4 tabstop=8: |
9fe789f8 |
*/ |