2
* Copyright (C)2008 Sourcefire, Inc.
4
* Author: aCaB <acab@clamav.net>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License version 2 as
8
* published by the Free Software Foundation.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22
#include "clamav-config.h"
26
#include <sys/types.h>
35
#include <libmilter/mfapi.h>
37
#include <openssl/ssl.h>
38
#include <openssl/err.h>
39
#include "libclamav/crypto.h"
43
#include "shared/output.h"
44
#include "shared/optparser.h"
45
#include "shared/misc.h"
46
#include "libclamav/default.h"
51
#include "whitelist.h"
53
struct smfiDesc descr;
55
int main(int argc, char **argv) {
57
const struct optstruct *opt;
58
struct optstruct *opts;
63
memset(&descr, 0, sizeof(struct smfiDesc));
64
descr.xxfi_name = "ClamAV"; /* filter name */
65
descr.xxfi_version = SMFI_VERSION; /* milter version */
66
descr.xxfi_flags = SMFIF_QUARANTINE; /* flags */
67
descr.xxfi_connect = clamfi_connect; /* connection info filter */
68
descr.xxfi_envfrom = clamfi_envfrom; /* envelope sender filter */
69
descr.xxfi_envrcpt = clamfi_envrcpt; /* envelope recipient filter */
70
descr.xxfi_header = clamfi_header; /* header filter */
71
descr.xxfi_body = clamfi_body; /* body block */
72
descr.xxfi_eom = clamfi_eom; /* end of message */
73
descr.xxfi_abort = clamfi_abort; /* message aborted */
75
opts = optparse(NULL, argc, argv, 1, OPT_MILTER, 0, NULL);
77
mprintf("!Can't parse command line options\n");
81
if(optget(opts, "help")->enabled) {
82
printf("Usage: %s [-c <config-file>]\n\n", argv[0]);
83
printf(" --help -h Show this help\n");
84
printf(" --version -V Show version and exit\n");
85
printf(" --config-file <file> -c Read configuration from file\n\n");
92
for(x = 0; opts->filename[x]; x++)
93
mprintf("^Ignoring option %s\n", opts->filename[x]);
96
if(optget(opts, "version")->enabled) {
97
printf("clamav-milter %s\n", get_version());
102
pt = strdup(optget(opts, "config-file")->strarg);
103
if((opts = optparse(pt, 0, NULL, 1, OPT_MILTER, 0, opts)) == NULL) {
104
printf("%s: cannot parse config file %s\n", argv[0], pt);
110
if((opt = optget(opts, "Chroot"))->enabled) {
111
if(chdir(opt->strarg) != 0) {
112
logg("!Cannot change directory to %s\n", opt->strarg);
115
if(chroot(opt->strarg) != 0) {
116
logg("!chroot to %s failed. Are you root?\n", opt->strarg);
121
if(geteuid() == 0 && (opt = optget(opts, "User"))->enabled) {
122
struct passwd *user = NULL;
123
if((user = getpwnam(opt->strarg)) == NULL) {
124
fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg);
129
if(optget(opts, "AllowSupplementaryGroups")->enabled) {
130
#ifdef HAVE_INITGROUPS
131
if(initgroups(opt->strarg, user->pw_gid)) {
132
fprintf(stderr, "ERROR: initgroups() failed.\n");
137
mprintf("!AllowSupplementaryGroups: initgroups() is not available, please disable AllowSupplementaryGroups\n");
142
#ifdef HAVE_SETGROUPS
143
if(setgroups(1, &user->pw_gid)) {
144
fprintf(stderr, "ERROR: setgroups() failed.\n");
151
if(setgid(user->pw_gid)) {
152
fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid);
157
if(setuid(user->pw_uid)) {
158
fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid);
164
logg_lock = !optget(opts, "LogFileUnlock")->enabled;
165
logg_time = optget(opts, "LogTime")->enabled;
166
logg_size = optget(opts, "LogFileMaxSize")->numarg;
167
logg_verbose = mprintf_verbose = optget(opts, "LogVerbose")->enabled;
169
logg_rotate = optget(opts, "LogRotate")->enabled;
171
if((opt = optget(opts, "LogFile"))->enabled) {
172
logg_file = opt->strarg;
173
if(!cli_is_abspath(logg_file)) {
174
fprintf(stderr, "ERROR: LogFile requires full path.\n");
182
#if defined(USE_SYSLOG) && !defined(C_AIX)
183
if(optget(opts, "LogSyslog")->enabled) {
186
opt = optget(opts, "LogFacility");
187
if((fac = logg_facility(opt->strarg)) == -1) {
188
logg("!LogFacility: %s: No such facility.\n", opt->strarg);
194
openlog("clamav-milter", LOG_PID, fac);
200
if(logg("#+++ Started at %s", ctime(&currtime))) {
201
fprintf(stderr, "ERROR: Can't initialize the internal logger\n");
206
if((opt = optget(opts, "TemporaryDirectory"))->enabled)
207
tempdir = opt->strarg;
209
if(localnets_init(opts) || init_actions(opts)) {
215
if((opt = optget(opts, "Whitelist"))->enabled && whitelist_init(opt->strarg)) {
222
if((opt = optget(opts, "SkipAuthenticated"))->enabled && smtpauth_init(opt->strarg)) {
230
pt = optget(opts, "AddHeader")->strarg;
231
if(strcasecmp(pt, "No")) {
234
if(((opt = optget(opts, "ReportHostname"))->enabled && strncpy(myname, opt->strarg, sizeof(myname))) || !gethostname(myname, sizeof(myname))) {
235
myname[sizeof(myname)-1] = '\0';
236
snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s at %s", get_version(), myname);
238
snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s", get_version());
239
xvirushdr[sizeof(xvirushdr)-1] = '\0';
241
descr.xxfi_flags |= SMFIF_ADDHDRS;
243
if(strcasecmp(pt, "Add")) { /* Replace or Yes */
244
descr.xxfi_flags |= SMFIF_CHGHDRS;
251
multircpt = optget(opts, "SupportMultipleRecipients")->enabled;
253
if(!(my_socket = optget(opts, "MilterSocket")->strarg)) {
254
logg("!Please configure the MilterSocket directive\n");
262
if(!optget(opts, "Foreground")->enabled) {
263
if(daemonize() == -1) {
264
logg("!daemonize() failed\n");
273
logg("^Can't change current working directory to root\n");
276
if(smfi_setconn(my_socket) == MI_FAILURE) {
277
logg("!smfi_setconn failed\n");
284
if(smfi_register(descr) == MI_FAILURE) {
285
logg("!smfi_register failed\n");
292
opt = optget(opts, "FixStaleSocket");
293
umsk = umask(0777); /* socket is created with 000 to avoid races */
294
if(smfi_opensocket(opt->enabled) == MI_FAILURE) {
295
logg("!Failed to create socket %s\n", my_socket);
302
umask(umsk); /* restore umask */
303
if(strncmp(my_socket, "inet:", 5) && strncmp(my_socket, "inet6:", 6)) {
304
/* set group ownership and perms on the local socket */
305
char *sock_name = my_socket;
307
if(!strncmp(my_socket, "unix:", 5))
309
if(!strncmp(my_socket, "local:", 6))
311
if(*my_socket == ':')
314
if(optget(opts, "MilterSocketGroup")->enabled) {
315
char *gname = optget(opts, "MilterSocketGroup")->strarg, *end;
316
gid_t sock_gid = strtol(gname, &end, 10);
318
struct group *pgrp = getgrnam(gname);
320
logg("!Unknown group %s\n", gname);
327
sock_gid = pgrp->gr_gid;
329
if(chown(sock_name, -1, sock_gid)) {
330
logg("!Failed to change socket ownership to group %s\n", gname);
338
if(optget(opts, "MilterSocketMode")->enabled) {
340
sock_mode = strtol(optget(opts, "MilterSocketMode")->strarg, &end, 8);
342
logg("!Invalid MilterSocketMode %s\n", optget(opts, "MilterSocketMode")->strarg);
350
sock_mode = 0777 & ~umsk;
352
if(chmod(sock_name, sock_mode & 0666)) {
353
logg("!Cannot set milter socket permission to %s\n", optget(opts, "MilterSocketMode")->strarg);
362
maxfilesize = optget(opts, "MaxFileSize")->numarg;
364
logg("^Invalid MaxFileSize, using default (%d)\n", CLI_DEFAULT_MAXFILESIZE);
365
maxfilesize = CLI_DEFAULT_MAXFILESIZE;
367
readtimeout = optget(opts, "ReadTimeout")->numarg;
371
logg("!Failed to init the socket pool\n");
379
if((opt = optget(opts, "PidFile"))->enabled) {
381
mode_t old_umask = umask(0002);
383
if((fd = fopen(opt->strarg, "w")) == NULL) {
384
logg("!Can't save PID in file %s\n", opt->strarg);
386
if (fprintf(fd, "%u", (unsigned int)getpid())<0) {
387
logg("!Can't save PID in file %s\n", opt->strarg);
412
* vim: set cindent smartindent autoindent softtabstop=4 shiftwidth=4 tabstop=8: