~ubuntu-branches/ubuntu/natty/amavisd-new/natty

« back to all changes in this revision

Viewing changes to helper-progs/amavis-milter-based-on-1.1.2.3.2.40-v2.c

  • Committer: Bazaar Package Importer
  • Author(s): Christian Perrier
  • Date: 2007-02-24 19:27:53 UTC
  • mfrom: (3.1.7 feisty)
  • Revision ID: james.westby@ubuntu.com-20070224192753-fvvima53q1jrp34x
Tags: 1:2.4.2-6.1
* Non-maintainer upload to fix pending l10n issues.
* Debconf translations
  - Remove extra debian/po/de.po~
  - Convert all translation files to UTF-8
  - Russian. Closes: #405243
  - Spanish. Closes: #408734
  - Italian. Closes: #409831
* Add very simple LSB headers to init scripts

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Based(V2.4) on amavis-milter.c,v 1.1.2.3.2.40 2003/06/06 12:34:58 lhecking Exp
3
 
 */
4
 
 
5
 
/*
6
 
 * sendmail/milter client for amavis
7
 
 * amavisd version
8
 
 *
9
 
 * Author: Geoff Winkless <gwinkless@users.sourceforge.net>
10
 
 * Additional work and patches by:
11
 
 *   Gregory Ade
12
 
 *   Anne Bennett
13
 
 *   Thomas Biege
14
 
 *   Pierre-Yves Bonnetain
15
 
 *   Lars Hecking
16
 
 *   Rainer Link
17
 
 *   Dale Perkel
18
 
 *   Julio Sanchez
19
 
 *   Stephane Lentz
20
 
 *   Mark Martinec
21
 
 */
22
 
 
23
 
/*
24
 
 * Add some copyright notice here ...
25
 
 *
26
 
 */
27
 
 
28
 
#include "config.h"
29
 
 
30
 
#include <time.h>
31
 
#include <sys/types.h>
32
 
#include <sys/wait.h>
33
 
#include <sys/stat.h>
34
 
#include <sys/utsname.h>
35
 
#include <errno.h>
36
 
#include <fcntl.h>
37
 
#include <stdio.h>
38
 
#include <stdarg.h>
39
 
#include <stdlib.h>
40
 
#include <string.h>
41
 
#include <sysexits.h>
42
 
#include <syslog.h>
43
 
#include <unistd.h>
44
 
#include <netinet/in.h>
45
 
#include <arpa/inet.h>
46
 
#include <sys/socket.h>
47
 
#include <sys/un.h>
48
 
#include <sys/file.h>
49
 
#include <limits.h>
50
 
#include <grp.h>
51
 
#include <pwd.h>
52
 
 
53
 
#ifdef HAVE_SM_GEN_H
54
 
# include "sm/gen.h"
55
 
#endif
56
 
#include "libmilter/mfapi.h"
57
 
 
58
 
#ifndef HAVE_SM_GEN_BOOL_TYPE
59
 
typedef int bool;
60
 
#endif
61
 
 
62
 
#define BUFFLEN 255
63
 
/* Must be the same as the buffer length for recv() in amavisd */
64
 
#define SOCKBUFLEN 8192
65
 
 
66
 
#ifndef RUNTIME_DIR
67
 
# define RUNTIME_DIR "/var/amavis"
68
 
#endif
69
 
 
70
 
#ifndef AMAVISD_SOCKET
71
 
# define AMAVISD_SOCKET RUNTIME_DIR ## "/amavisd.sock"
72
 
#endif
73
 
 
74
 
/* Activate the sendmail add-on features */
75
 
#define WITH_SENDMAIL_QUEUEID_TEMP_DNAME 1
76
 
#define WITH_SYNTHESIZED_RECEIVED_HEADER 1
77
 
 
78
 
#define D_TEMPPREFIX "/amavis-milter-"
79
 
#define D_TEMPLATE "XXXXXXXX"
80
 
#define F_TEMPLATE "/email.txt"
81
 
 
82
 
#define DEVNULL "/dev/null"
83
 
 
84
 
/* #ifndef AMAVIS_USER
85
 
 * # define AMAVIS_USER "amavis"
86
 
 * #endif
87
 
 * #ifndef MILTER_SOCKET_GROUP
88
 
 * # define MILTER_SOCKET_GROUP "amavis"
89
 
 * #endif
90
 
 */
91
 
 
92
 
/* Extracted from the code for better configurability
93
 
 * These will be set by configure/make eventually */
94
 
#ifndef X_HEADER_TAG
95
 
# define X_HEADER_TAG "X-Virus-Scanned"
96
 
#endif
97
 
#ifndef X_HEADER_LINE
98
 
# define X_HEADER_LINE "by amavisd-milter (http://www.amavis.org/)"
99
 
#endif
100
 
 
101
 
#define DBG_NONE    0
102
 
#define DBG_FATAL   1
103
 
#define DBG_WARN    2
104
 
#define DBG_INFO    3
105
 
#define DBG_DEBUG   4
106
 
 
107
 
typedef struct llstrct {
108
 
    char *str;
109
 
    struct llstrct *next;
110
 
} ll;
111
 
 
112
 
struct mlfiPriv {
113
 
    char *mlfi_fname;  /* temporary file name */
114
 
    FILE *mlfi_fp;     /* file descriptor of the temporary file */
115
 
    char *mlfi_helo;
116
 
    char *mlfi_client_addr;
117
 
    char *mlfi_client_name;
118
 
    char *mlfi_queueid;
119
 
    char *mlfi_envfrom;
120
 
    ll mlfi_envto;
121
 
    ll *mlfi_thisenvto;
122
 
    int mlfi_numto;
123
 
};
124
 
 
125
 
static int verbosity = DBG_WARN;
126
 
static int AM_DAEMON = 1;
127
 
 
128
 
static struct group *miltergroup;
129
 
static gid_t amavis_gid;
130
 
static struct utsname amavis_uts;
131
 
static int enable_x_header = 1;  /* enabled by default */
132
 
 
133
 
pid_t daemon_pid;
134
 
static char pidfile[] = "/var/run/amavis/amavisd-new-milter.pid";
135
 
 
136
 
static void amavis_syslog(const int, const char *, ...);
137
 
static char *amavis_mkdtemp(char *, int);
138
 
static int group_member(const char *);
139
 
static void freeenvto(ll *);
140
 
static sfsistat clearpriv(SMFICTX *, sfsistat, int);
141
 
static int allocmem(SMFICTX *);
142
 
static sfsistat mlfi_connect(SMFICTX *, char *, _SOCK_ADDR *);
143
 
static sfsistat mlfi_helo(SMFICTX *, char *);
144
 
static sfsistat mlfi_envfrom(SMFICTX *, char **);
145
 
static sfsistat mlfi_envto(SMFICTX *, char **);
146
 
static sfsistat mlfi_header(SMFICTX *, char *, char *);
147
 
static sfsistat mlfi_eoh(SMFICTX *);
148
 
static sfsistat mlfi_body(SMFICTX *, u_char *, size_t);
149
 
static sfsistat mlfi_eom(SMFICTX *);
150
 
static sfsistat mlfi_abort(SMFICTX *);
151
 
static sfsistat mlfi_close(SMFICTX *);
152
 
static sfsistat mlfi_cleanup(SMFICTX *, sfsistat, bool);
153
 
 
154
 
 
155
 
void
156
 
get_lock()
157
 
   /* check if another daemon is running */
158
 
{
159
 
       int otherpid = 0;
160
 
       FILE *daemon_lockfp = NULL;
161
 
       int fd;
162
 
 
163
 
        if (((fd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1 )
164
 
                        || ((daemon_lockfp = fdopen(fd, "r+"))) == NULL)
165
 
        {
166
 
                amavis_syslog(DBG_FATAL, "can't open or create %s", pidfile);
167
 
                exit(EX_UNAVAILABLE);
168
 
        }
169
 
       if ( flock(fd, LOCK_EX|LOCK_NB) != 0 )
170
 
       {
171
 
               fscanf(daemon_lockfp, "%d", &otherpid);
172
 
               amavis_syslog(DBG_INFO, "can't lock %s, running daemon's pid may be %d", pidfile, otherpid);
173
 
               exit(EX_UNAVAILABLE);
174
 
       }
175
 
 
176
 
       fcntl(fd, F_SETFD, 1);
177
 
 
178
 
       rewind(daemon_lockfp);
179
 
       fprintf(daemon_lockfp, "%d\n", (int) daemon_pid);
180
 
       fflush(daemon_lockfp);
181
 
       ftruncate(fileno(daemon_lockfp), ftell(daemon_lockfp));
182
 
       /* abandon fd and daemon_lockfp even though the file is open. we need to-
183
 
        * keep it open and locked, but we don't need the handles elsewhere.
184
 
        */
185
 
}
186
 
 
187
 
static void
188
 
amavis_syslog(const int level, const char *fmt, ...)
189
 
{
190
 
    time_t tmpt;
191
 
    char *timestamp;
192
 
    char buf[512];
193
 
    va_list ap;
194
 
    int loglevel;
195
 
 
196
 
    if (level > verbosity) return;
197
 
    switch (level) {  /* map internal log level to syslog priority */
198
 
        case DBG_FATAL: loglevel = LOG_ERR;     break;
199
 
        case DBG_WARN:  loglevel = LOG_WARNING; break;
200
 
        case DBG_INFO:  loglevel = LOG_INFO;    break;
201
 
        case DBG_DEBUG: loglevel = LOG_DEBUG;   break;
202
 
        default:        loglevel = LOG_INFO;
203
 
    }
204
 
    if (verbosity > 1 && loglevel == LOG_DEBUG) loglevel = LOG_INFO;
205
 
    buf[0] = 0;
206
 
    va_start(ap, fmt);
207
 
 
208
 
    if (AM_DAEMON == 0) {
209
 
        tmpt = time(NULL);
210
 
        timestamp = ctime(&tmpt);
211
 
        /* A 26 character string according ctime(3c)
212
 
         * we cut off the trailing \n\0 */
213
 
        timestamp[24] = 0;
214
 
 
215
 
        snprintf(buf,sizeof(buf),"%s %s amavis-milter[%ld]: ",
216
 
                 timestamp,
217
 
                 (amavis_uts.nodename ? amavis_uts.nodename : "localhost"),
218
 
                 (long) getpid());
219
 
    }
220
 
 
221
 
    vsnprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),fmt,ap);
222
 
    va_end(ap);
223
 
 
224
 
    if (AM_DAEMON == 0) {
225
 
        fprintf(stderr,"%s\n",buf);
226
 
    }
227
 
    
228
 
    /* HG: does it make sense to open and close the log each time? */
229
 
    openlog("amavis-milter", LOG_PID|LOG_CONS, LOG_MAIL);
230
 
    
231
 
    syslog(loglevel,"%s\n",buf);
232
 
    closelog();
233
 
}
234
 
 
235
 
static char *
236
 
amavis_mkdtemp(char *s, int use_fixed_name)
237
 
{
238
 
    char *stt;
239
 
    int count = 0;
240
 
 
241
 
    if (use_fixed_name) {
242
 
        if (!mkdir(s, S_IRWXU|S_IRGRP|S_IXGRP)) return s;  /*succeeded */
243
 
        amavis_syslog(DBG_FATAL, "(amavis_mkdtemp) creating directory %s failed: %s",
244
 
                      s, strerror(errno));
245
 
    }
246
 
    /* fall back to inventing temporary directory names */
247
 
    strcat(s, D_TEMPLATE);  /* storage has been preallocated */
248
 
 
249
 
#ifdef HAVE_MKDTEMP
250
 
    stt = mkdtemp(s);
251
 
    if (stt == NULL)
252
 
        amavis_syslog(DBG_FATAL, "(amavis_mkdtemp) mkdtemp %s failed: %s",
253
 
                      s, strerror(errno));
254
 
    return stt;
255
 
#else
256
 
    /* magic number alert */
257
 
    while (count++ < 20) {
258
 
# ifdef HAVE_MKTEMP
259
 
        stt = mktemp(s);
260
 
# else
261
 
        /* relies on template format */
262
 
        stt = strrchr(s, '-') + 1;
263
 
        if (stt) {
264
 
            /* more magic number alert */
265
 
            snprintf(stt, strlen(s) - 1 - (stt - s), "%08d", lrand48() / 215);
266
 
            stt = s;
267
 
        } else {
268
 
            /* invalid template */
269
 
            amavis_syslog(DBG_FATAL, "(amavis_mkdtemp) mktemp failed %s",s);
270
 
            return NULL;
271
 
        }
272
 
# endif
273
 
        if (stt) {
274
 
            if (!mkdir(s, S_IRWXU|S_IRGRP|S_IXGRP)) {
275
 
                return s;
276
 
            } else {
277
 
                continue;
278
 
            }
279
 
        }
280
 
    }
281
 
    amavis_syslog(DBG_FATAL, "(amavis_mkdtemp) creating (3) directory %s failed: %s",
282
 
                  s, strerror(errno));
283
 
    return NULL;
284
 
#endif /* HAVE_MKDTEMP */
285
 
}
286
 
 
287
 
static
288
 
int group_member(const char *group)
289
 
{
290
 
    int i, r, rc = -1;
291
 
    gid_t *grouplist = 0;
292
 
 
293
 
    if (!(miltergroup = getgrnam(group))) {
294
 
        perror("getgrnam");
295
 
        return rc;
296
 
    }
297
 
 
298
 
    if ((r = getgroups(0, grouplist)) < 0) {
299
 
        perror("getgroups");
300
 
    } else if ((grouplist = malloc (r*sizeof(gid_t))) == NULL) {
301
 
        perror("malloc");
302
 
        r = 0;
303
 
    } else if ((r = getgroups(r, grouplist)) < 0) {
304
 
        perror("getgroups");
305
 
        free(grouplist);
306
 
    }
307
 
 
308
 
    for (i=0;i<r;i++) {
309
 
        if (miltergroup->gr_gid == grouplist[i]) {
310
 
            rc = 0;
311
 
            break;
312
 
        }
313
 
    }
314
 
 
315
 
    if (grouplist)
316
 
        free(grouplist);
317
 
 
318
 
    return rc;
319
 
}
320
 
 
321
 
#define MLFIPRIV        ((struct mlfiPriv *) smfi_getpriv(ctx))
322
 
 
323
 
static void
324
 
freeenvto(ll * envto)
325
 
{
326
 
    while (envto) {
327
 
        ll *new = envto->next;
328
 
        if (envto->str) {
329
 
            free(envto->str);
330
 
            envto->str = NULL;
331
 
        }
332
 
        free(envto);
333
 
        envto = new;
334
 
    }
335
 
}
336
 
 
337
 
static sfsistat
338
 
clearpriv(SMFICTX *ctx, sfsistat retme, int clearall)
339
 
{
340
 
    /* clear or release private memory and return retme */
341
 
    struct mlfiPriv *priv = MLFIPRIV;
342
 
 
343
 
    if (priv) {
344
 
        if (priv->mlfi_fp) {
345
 
            if (fclose(priv->mlfi_fp) != 0)
346
 
                amavis_syslog(DBG_FATAL, "(clearpriv) close failed: %s",
347
 
                              strerror(errno));
348
 
            priv->mlfi_fp = NULL;
349
 
        }
350
 
        if (priv->mlfi_fname)
351
 
            { free(priv->mlfi_fname); priv->mlfi_fname = NULL; }
352
 
        if (priv->mlfi_queueid)
353
 
            { free(priv->mlfi_queueid); priv->mlfi_queueid = NULL; }
354
 
        if (priv->mlfi_envfrom)
355
 
            { free(priv->mlfi_envfrom); priv->mlfi_envfrom = NULL; }
356
 
        if (priv->mlfi_envto.next)
357
 
            { freeenvto(priv->mlfi_envto.next); priv->mlfi_envto.next = NULL; }
358
 
        if (priv->mlfi_envto.str)
359
 
            { free(priv->mlfi_envto.str); priv->mlfi_envto.str = NULL; }
360
 
        priv->mlfi_thisenvto = NULL;
361
 
        priv->mlfi_numto = 0;
362
 
        if (clearall) {
363
 
            if (priv->mlfi_client_addr)
364
 
               { free(priv->mlfi_client_addr); priv->mlfi_client_addr = NULL; }
365
 
            if (priv->mlfi_client_name)
366
 
               { free(priv->mlfi_client_name); priv->mlfi_client_name = NULL; }
367
 
            if (priv->mlfi_helo)
368
 
               { free(priv->mlfi_helo); priv->mlfi_helo = NULL; }
369
 
            free(priv); priv = NULL;
370
 
            if (smfi_setpriv(ctx, priv) != MI_SUCCESS) {
371
 
                /* Not sure what we need to do here */
372
 
                amavis_syslog(DBG_WARN, "(clearpriv) smfi_setpriv failed");
373
 
            }
374
 
        }
375
 
    }
376
 
    return retme;
377
 
}
378
 
 
379
 
/*
380
 
 * allocate some private memory if not already allocated
381
 
 * returns 0 if ok, 1 if not
382
 
 */
383
 
static int
384
 
allocmem(SMFICTX * ctx)
385
 
{
386
 
    struct mlfiPriv *priv = MLFIPRIV;
387
 
 
388
 
    if (priv != NULL) {
389
 
        /* amavis_syslog(DBG_DEBUG, "allocmem not needed"); */
390
 
    } else {
391
 
        amavis_syslog(DBG_DEBUG, "(allocmem) allocating private variables");
392
 
        priv = malloc(sizeof *priv);
393
 
        if (priv == NULL) {
394
 
            /* can't accept this message right now */
395
 
            amavis_syslog(DBG_FATAL, "failed to malloc %d bytes for private store: %s",
396
 
                    sizeof(*priv), strerror(errno));
397
 
            return 1;
398
 
        }
399
 
        memset(priv, 0, sizeof *priv);
400
 
        amavis_syslog(DBG_DEBUG, "malloced priv successfully");
401
 
        if (smfi_setpriv(ctx, priv) != MI_SUCCESS) {
402
 
            /* Not sure what we need to do here */
403
 
            amavis_syslog(DBG_WARN, "(allocmem) smfi_setpriv failed");
404
 
        }
405
 
    }
406
 
    return 0;
407
 
}
408
 
 
409
 
static sfsistat
410
 
mlfi_connect(SMFICTX * ctx, char *hostname, _SOCK_ADDR * gen_hostaddr)
411
 
{
412
 
    struct mlfiPriv *priv;
413
 
    /* discard any possible data from previous session */
414
 
    amavis_syslog(DBG_INFO, "(mlfi_connect) client connect: hostname %s; clearing all variables", hostname);
415
 
    clearpriv(ctx, SMFIS_CONTINUE, 1);  /* discard data if any, just in case */
416
 
    if (allocmem(ctx)) return SMFIS_TEMPFAIL;
417
 
    priv = MLFIPRIV;
418
 
 
419
 
    if (priv->mlfi_client_addr)
420
 
        { free(priv->mlfi_client_addr); priv->mlfi_client_addr = NULL; }
421
 
    if (priv->mlfi_client_name)
422
 
        { free(priv->mlfi_client_name); priv->mlfi_client_name = NULL; }
423
 
    if (gen_hostaddr) {
424
 
        char *s = inet_ntoa( ((struct sockaddr_in *)gen_hostaddr)->sin_addr );
425
 
        if (s && *s) {
426
 
            if ((priv->mlfi_client_addr = strdup(s)) == NULL)
427
 
                return (SMFIS_TEMPFAIL);
428
 
        }
429
 
    }
430
 
    if (hostname) {
431
 
        if ((priv->mlfi_client_name = strdup(hostname)) == NULL)
432
 
            return (SMFIS_TEMPFAIL);
433
 
    }
434
 
    return SMFIS_CONTINUE;
435
 
}
436
 
 
437
 
static sfsistat
438
 
mlfi_helo(SMFICTX * ctx, char *helohost)
439
 
{
440
 
    struct mlfiPriv *priv;
441
 
    amavis_syslog(DBG_INFO, "(mlfi_helo) HELO argument is %s", helohost);
442
 
    if (allocmem(ctx)) return SMFIS_TEMPFAIL;
443
 
    priv = MLFIPRIV;
444
 
    if (priv->mlfi_helo) { free(priv->mlfi_helo); priv->mlfi_helo = NULL; }
445
 
    if ((priv->mlfi_helo = strdup(helohost)) == NULL) return (SMFIS_TEMPFAIL);
446
 
    return SMFIS_CONTINUE;
447
 
}
448
 
 
449
 
/* write synthesized received header to temp file as the first header */
450
 
void write_received(SMFICTX *ctx)
451
 
{
452
 
#ifdef WITH_SYNTHESIZED_RECEIVED_HEADER
453
 
    char date_str[64];
454
 
    struct mlfiPriv *priv = MLFIPRIV;
455
 
    /* sendmail macros present by default */
456
 
    const char *quid      = smfi_getsymval(ctx, "i"); /* sendmail queue id */
457
 
    const char *hostname  = smfi_getsymval(ctx, "j"); /* sendmail's host */
458
 
    /* optional sendmail milter macros */
459
 
    const char *date      = smfi_getsymval(ctx, "b"); /* time of transaction */
460
 
    if (!date) {              /* fallback if milter macro {b} is not defined */
461
 
        time_t t; time(&t);
462
 
        date = date_str;
463
 
        if (!strftime(date_str, sizeof(date_str), "%a, %e %b %Y %H:%M:%S %z",
464
 
                      localtime(&t))) { date = NULL; }
465
 
    }
466
 
    if (fprintf(priv->mlfi_fp,
467
 
          "Received: from %s (%s [%s])\n\tby %s (amavis-milter) id %s; %s\n",
468
 
          priv->mlfi_helo && *(priv->mlfi_helo) ? priv->mlfi_helo : "unknown",
469
 
          priv->mlfi_client_name ? priv->mlfi_client_name : "",
470
 
          priv->mlfi_client_addr ? priv->mlfi_client_addr : "",
471
 
          hostname ? hostname : "(milter macro {j} not defined)",
472
 
          quid     ? quid     : "(milter macro {i} not defined)",
473
 
          date     ? date     : "(milter macro {b} not defined)"
474
 
                ) < 0
475
 
        ) amavis_syslog(DBG_FATAL,"(write_received) write of header failed: %s",
476
 
                        strerror(errno));
477
 
#endif
478
 
}
479
 
 
480
 
static sfsistat
481
 
mlfi_envfrom(SMFICTX * ctx, char **envfrom)
482
 
{
483
 
    struct mlfiPriv *priv;
484
 
    struct stat StatBuf;
485
 
    char *messagepath;
486
 
    const char *sendmail_queueid = NULL;
487
 
    int use_fixed_name;
488
 
 
489
 
    /* discard any message data from previous SMTP transaction */
490
 
    amavis_syslog(DBG_DEBUG, "(mlfi_envfrom) clearing message variables");
491
 
    clearpriv(ctx, SMFIS_CONTINUE, 0);  /* discard previos msg data if any */
492
 
    if (allocmem(ctx)) return SMFIS_TEMPFAIL;
493
 
    priv = MLFIPRIV;
494
 
 
495
 
    sendmail_queueid = smfi_getsymval(ctx, "i");
496
 
    if (!sendmail_queueid) sendmail_queueid = "";
497
 
    priv->mlfi_queueid = strdup(sendmail_queueid);
498
 
    if (!priv->mlfi_queueid) {
499
 
        amavis_syslog(DBG_FATAL,"%s: (mlfi_envfrom) failed to alloc mlfi_queueid", sendmail_queueid);
500
 
        return SMFIS_TEMPFAIL;
501
 
    }
502
 
    priv->mlfi_envfrom = strdup(*envfrom);
503
 
    if (!priv->mlfi_envfrom) {
504
 
        amavis_syslog(DBG_FATAL,"%s: (mlfi_envfrom) failed to alloc mlfi_envfrom", sendmail_queueid);
505
 
        return SMFIS_TEMPFAIL;
506
 
    }
507
 
 
508
 
    /* tmp dir */
509
 
    messagepath = malloc(strlen(RUNTIME_DIR) +
510
 
        strlen(D_TEMPPREFIX) + strlen(D_TEMPLATE) +  /*reserve for worst case*/
511
 
        (!sendmail_queueid ? 0 : strlen(sendmail_queueid)) +
512
 
        strlen(F_TEMPLATE) + 1);
513
 
    if (messagepath == NULL) {
514
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_envfrom) failed to allocate memory for temp file name: %s",
515
 
                                 sendmail_queueid, strerror(errno));
516
 
        return SMFIS_TEMPFAIL;
517
 
    }
518
 
 
519
 
    strcpy(messagepath, RUNTIME_DIR);
520
 
    strcat(messagepath, D_TEMPPREFIX);
521
 
    use_fixed_name = 0;
522
 
#ifdef WITH_SENDMAIL_QUEUEID_TEMP_DNAME
523
 
    if (sendmail_queueid && *sendmail_queueid) {
524
 
        strcat(messagepath, sendmail_queueid); use_fixed_name = 1;
525
 
    }
526
 
#endif
527
 
    if (amavis_mkdtemp(messagepath,use_fixed_name) == NULL) {
528
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_envfrom) failed to create temp dir %s: %s", messagepath,
529
 
                                 sendmail_queueid, strerror(errno));
530
 
        return SMFIS_TEMPFAIL;
531
 
    }
532
 
/*  if (chown(messagepath, (uid_t)-1, amavis_gid) < 0) {
533
 
 *      amavis_syslog(DBG_FATAL, "Failed to adjust %s group ownership (%d): %s",
534
 
 *                    messagepath, amavis_gid, strerror(errno));
535
 
 *      return SMFIS_TEMPFAIL;
536
 
 *  }
537
 
 */
538
 
    if (lstat(messagepath, &StatBuf) < 0) {
539
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_envfrom) lstat(%s) failed: %s",
540
 
                        sendmail_queueid, messagepath, strerror(errno));
541
 
        return SMFIS_TEMPFAIL;
542
 
    }
543
 
    /* may be too restrictive for you, but is good to avoid problems */
544
 
    if (!S_ISDIR(StatBuf.st_mode) ||
545
 
        StatBuf.st_uid != geteuid() || StatBuf.st_gid != getegid() ) {
546
 
        amavis_syslog(DBG_FATAL,
547
 
                "%s, Security Warning: %s must be a directory, owned by User %d "
548
 
                "and Group %d", messagepath, sendmail_queueid, geteuid(), getegid());
549
 
    } else if ( ((StatBuf.st_mode & 0777) != (S_IRWXU|S_IRGRP|S_IXGRP)) ) {
550
 
        amavis_syslog(DBG_FATAL,
551
 
                "%s, Security Warning: %s %o07 must be readable/writeable by the "
552
 
                "User %d and readable by Group %d only",
553
 
                sendmail_queueid, messagepath, StatBuf.st_mode, geteuid(), getegid());
554
 
    }
555
 
    /* there is still a race condition here if RUNTIME_DIR is writeable by the attacker :-\ */
556
 
 
557
 
    /* tmp file name */
558
 
    strcat(messagepath, F_TEMPLATE);
559
 
    amavis_syslog(DBG_INFO, "%s: (mlfi_envfrom) MAIL FROM: %s, tempdir: %s",
560
 
                            sendmail_queueid, *envfrom, messagepath);
561
 
    priv->mlfi_fname = messagepath; messagepath = NULL;
562
 
 
563
 
    if ((priv->mlfi_fp = fopen(priv->mlfi_fname, "w+")) == NULL) {
564
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_envfrom) creating file %s failed: %s",
565
 
                      sendmail_queueid, priv->mlfi_fname, strerror(errno));
566
 
        return SMFIS_TEMPFAIL;
567
 
    } else if (fchmod(fileno(priv->mlfi_fp), S_IRUSR|S_IWUSR|S_IRGRP) == -1) {
568
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_envfrom) fchmod on %s failed: %s",
569
 
                      sendmail_queueid, priv->mlfi_fname, strerror(errno));
570
 
        return SMFIS_TEMPFAIL;
571
 
    }
572
 
 
573
 
    /* prepend synthesized header to the temporary file */
574
 
    write_received(ctx);
575
 
 
576
 
    /* continue processing */
577
 
    return SMFIS_CONTINUE;
578
 
}
579
 
 
580
 
static sfsistat
581
 
mlfi_envto(SMFICTX * ctx, char **envto)
582
 
{
583
 
    struct mlfiPriv *priv;
584
 
    const char *sendmail_queueid;
585
 
    if (allocmem(ctx)) return SMFIS_TEMPFAIL;
586
 
    priv = MLFIPRIV;
587
 
    sendmail_queueid = !priv->mlfi_queueid ? "" : priv->mlfi_queueid;
588
 
    if (!(priv->mlfi_thisenvto)) {
589
 
        /* first one... */
590
 
        priv->mlfi_thisenvto = &(priv->mlfi_envto);
591
 
        priv->mlfi_numto = 1;
592
 
    } else {
593
 
        if ((priv->mlfi_thisenvto->next = malloc(sizeof(ll))) == NULL)
594
 
            return (SMFIS_TEMPFAIL);
595
 
        priv->mlfi_thisenvto = priv->mlfi_thisenvto->next;
596
 
        priv->mlfi_numto++;
597
 
    }
598
 
    priv->mlfi_thisenvto->next = NULL;
599
 
    priv->mlfi_thisenvto->str = NULL;
600
 
    if ((priv->mlfi_thisenvto->str = strdup(*envto)) == NULL)
601
 
        return (SMFIS_TEMPFAIL);
602
 
    amavis_syslog(DBG_INFO, "%s: (mlfi_envto) RCPT TO: %s",
603
 
                  (!priv->mlfi_queueid ? "" : priv->mlfi_queueid), *envto);
604
 
    return SMFIS_CONTINUE;
605
 
}
606
 
 
607
 
static sfsistat
608
 
mlfi_header(SMFICTX *ctx, char *headerf, char *headerv)
609
 
{
610
 
    struct mlfiPriv *priv = MLFIPRIV;
611
 
 
612
 
    /* write the header to the temporary file */
613
 
    if (fprintf(priv->mlfi_fp, "%s: %s\n", headerf, headerv) < 0)
614
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_header) write of header failed: %s",
615
 
            (!priv->mlfi_queueid ? "" : priv->mlfi_queueid), strerror(errno));
616
 
 
617
 
    /* continue processing */
618
 
    return SMFIS_CONTINUE;
619
 
}
620
 
 
621
 
static sfsistat
622
 
mlfi_eoh(SMFICTX *ctx)
623
 
{
624
 
    struct mlfiPriv *priv = MLFIPRIV;
625
 
    const char *sendmail_queueid;
626
 
 
627
 
    sendmail_queueid = !priv->mlfi_queueid ? "" : priv->mlfi_queueid;
628
 
    amavis_syslog(DBG_DEBUG, "%s: (mlfi_eoh)", sendmail_queueid);
629
 
    /* output the blank line between the header and the body */
630
 
    if (fprintf(priv->mlfi_fp, "\n") < 0)
631
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_eoh) writing an empty line failed: %s",
632
 
                                 sendmail_queueid, strerror(errno));
633
 
    /* continue processing */
634
 
    return SMFIS_CONTINUE;
635
 
}
636
 
 
637
 
static sfsistat
638
 
mlfi_body(SMFICTX *ctx, u_char *bodyp, size_t bodylen)
639
 
{
640
 
    struct mlfiPriv *priv = MLFIPRIV;
641
 
    /* output body block to log file */
642
 
    u_char *d = bodyp, *s = bodyp;
643
 
    u_char *lastc = bodyp + bodylen - 1;
644
 
 
645
 
    /* convert crlf to lf */
646
 
    while (s <= lastc) {
647
 
        if (s != lastc && *s == 13 && *(s+1) == 10)
648
 
            s++;
649
 
 
650
 
        *d++ = *s++;
651
 
    }
652
 
    bodylen = (size_t)(d - bodyp);
653
 
 
654
 
    if (bodylen && fwrite(bodyp, bodylen, 1, priv->mlfi_fp) <= 0) {
655
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_body) write of %d bytes failed: %s",
656
 
                      (!priv->mlfi_queueid ? "" : priv->mlfi_queueid),
657
 
                      bodylen, strerror(errno));
658
 
        (void) fclose(priv->mlfi_fp); priv->mlfi_fp = NULL;
659
 
        return mlfi_cleanup(ctx, SMFIS_TEMPFAIL, 0);  /* write failed */
660
 
    }
661
 
 
662
 
    /* continue processing */
663
 
    return SMFIS_CONTINUE;
664
 
}
665
 
 
666
 
/* Simple "protocol" */
667
 
const char _EOT = '\3';
668
 
 
669
 
static sfsistat
670
 
mlfi_eom(SMFICTX *ctx)
671
 
{
672
 
    struct mlfiPriv *priv = MLFIPRIV;
673
 
    char buff[7];
674
 
    int sock, r;
675
 
    char *sender;
676
 
    char retval;
677
 
    struct sockaddr_un saddr;
678
 
    sfsistat rstat = SMFIS_CONTINUE;
679
 
    const char *sendmail_queueid;
680
 
 
681
 
    if (!priv) {        /* no priv object */
682
 
        amavis_syslog(DBG_FATAL, "(mlfi_eom) no private object");
683
 
        rstat = SMFIS_TEMPFAIL;
684
 
        return rstat;
685
 
    }
686
 
    sendmail_queueid = !priv->mlfi_queueid ? "" : priv->mlfi_queueid;
687
 
    amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom)", sendmail_queueid);
688
 
    /* close the file so we can run checks on it */
689
 
    if (priv->mlfi_fp) {
690
 
        if (fclose(priv->mlfi_fp) != 0)
691
 
            amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) close failed: %s",
692
 
                          sendmail_queueid, strerror(errno));
693
 
        priv->mlfi_fp = NULL;
694
 
    }
695
 
    /* AFAIK, AF_UNIX is obsolete. POSIX defines AF_LOCAL */
696
 
    saddr.sun_family = AF_UNIX;
697
 
    if (strlen(AMAVISD_SOCKET)+1 > sizeof(saddr.sun_path)) {
698
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) socket path too long: %d",
699
 
                                 sendmail_queueid, strlen(AMAVISD_SOCKET));
700
 
        exit(EX_TEMPFAIL);
701
 
    }
702
 
    strcpy(saddr.sun_path, AMAVISD_SOCKET);
703
 
    amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) allocate socket()", sendmail_queueid);
704
 
    r = (sock = socket(PF_UNIX, SOCK_STREAM, 0));
705
 
    if (r < 0) {
706
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) failed to allocate socket: %s",
707
 
                                 sendmail_queueid, strerror(errno));
708
 
    }
709
 
    if (r >= 0) {
710
 
        amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) connect", sendmail_queueid);
711
 
        r = connect(sock, (struct sockaddr *) (&saddr), sizeof(saddr));
712
 
        if (r < 0)
713
 
            amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) failed to connect(): %s",
714
 
                                     sendmail_queueid, strerror(errno));
715
 
    }
716
 
    if (r >= 0) {
717
 
        char *p = strrchr(priv->mlfi_fname, '/');
718
 
        amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) sendfile", sendmail_queueid);
719
 
        /* amavisd wants the directory, not the filename */
720
 
        *p = '\0';
721
 
        r = send(sock, priv->mlfi_fname, strlen(priv->mlfi_fname), 0);
722
 
        *p = '/';
723
 
        if (r < 0)
724
 
            amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) failed to send() file name: %s",
725
 
                                     sendmail_queueid, strerror(errno));
726
 
    }
727
 
    if (r >= 0) {
728
 
        r = recv(sock, &retval, 1, 0);
729
 
        if (r < 0)
730
 
            amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) failed to recv() file name confirmation: %s",
731
 
                                     sendmail_queueid, strerror(errno));
732
 
    }
733
 
    if (r >= 0) {
734
 
        size_t sender_l;
735
 
        sender = (strlen(priv->mlfi_envfrom) > 0) ? priv->mlfi_envfrom : "<>";
736
 
        amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) sendfrom() %s", sendmail_queueid, sender);
737
 
        sender_l = strlen(sender);
738
 
        if (sender_l > SOCKBUFLEN) {
739
 
            amavis_syslog(DBG_WARN, "%s: (mlfi_eom) Sender too long (%d), truncated to %d characters",
740
 
                                    sendmail_queueid, sender_l, SOCKBUFLEN);
741
 
            sender_l = SOCKBUFLEN;
742
 
        }
743
 
        r = send(sock, sender, sender_l, 0);
744
 
        if (r < 0)
745
 
            amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) failed to send() Sender: %s",
746
 
                                    sendmail_queueid, strerror(errno));
747
 
        else if (r < sender_l)
748
 
            amavis_syslog(DBG_WARN, "%s: (mlfi_eom) failed to send() complete Sender, truncated to %d characters",
749
 
                                    sendmail_queueid, r);
750
 
    }
751
 
    if (r >= 0) {
752
 
        r = recv(sock, &retval, 1, 0);
753
 
        if (r < 0)
754
 
            amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) failed to recv() ok for Sender info: %s",
755
 
                                     sendmail_queueid, strerror(errno));
756
 
    }
757
 
    if (r >= 0) {
758
 
        int x;
759
 
        priv->mlfi_thisenvto = &(priv->mlfi_envto);
760
 
        for (x = 0; (r >= 0) && (x < priv->mlfi_numto); x++) {
761
 
            size_t recipient_l;
762
 
            amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) sendto() %s",
763
 
                                  sendmail_queueid, priv->mlfi_thisenvto->str);
764
 
            recipient_l = strlen(priv->mlfi_thisenvto->str);
765
 
            if (recipient_l > SOCKBUFLEN) {
766
 
                amavis_syslog(DBG_WARN, "%s: (mlfi_eom) Recipient too long (%d), truncated to %d characters",
767
 
                                    sendmail_queueid, recipient_l, SOCKBUFLEN);
768
 
                recipient_l = SOCKBUFLEN;
769
 
            }
770
 
            r = send(sock, priv->mlfi_thisenvto->str, recipient_l, 0);
771
 
            if (r < 0)
772
 
                amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) failed to send() Recipient: %s",
773
 
                                            sendmail_queueid, strerror(errno));
774
 
            else {
775
 
                if (r < recipient_l)
776
 
                    amavis_syslog(DBG_WARN, "%s: (mlfi_eom) failed to send() complete Recipient, truncated to %d characters ",
777
 
                                            sendmail_queueid, r);
778
 
                r = recv(sock, &retval, 1, 0);
779
 
                if (r < 0)
780
 
                    amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) failed to recv() ok for recip info: %s",
781
 
                                            sendmail_queueid, strerror(errno));
782
 
                priv->mlfi_thisenvto = priv->mlfi_thisenvto->next;
783
 
            }
784
 
        }
785
 
    }
786
 
    if (r >= 0) {
787
 
        amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) send() EOT", sendmail_queueid);
788
 
        r = send(sock, &_EOT, 1, 0);
789
 
        /* send "end of args" msg */
790
 
        if (r < 0) {
791
 
            amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) failed to send() EOT: %s",
792
 
                                     sendmail_queueid, strerror(errno));
793
 
        } else {
794
 
            /* get result from amavisd */
795
 
            r = recv(sock, buff, 6, 0);
796
 
            amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) received %s from daemon", sendmail_queueid, buff);
797
 
            if (r < 0)
798
 
                amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) Failed to recv() final result: %s",
799
 
                                        sendmail_queueid, strerror(errno));
800
 
            else if (!r)
801
 
                amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) Failed to recv() final result: empty status string",
802
 
                                         sendmail_queueid);
803
 
            /* get back final result */
804
 
        }
805
 
    }
806
 
    close(sock);
807
 
 
808
 
    if (r < 0) {
809
 
        /* some point of the communication failed miserably - so give up */
810
 
        amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) communication failure", sendmail_queueid);
811
 
        return mlfi_cleanup(ctx, SMFIS_TEMPFAIL, 0);
812
 
    }
813
 
    amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) finished conversation", sendmail_queueid);
814
 
 
815
 
    /* Protect against empty return string */
816
 
    if (*buff)
817
 
        retval = atoi(buff);
818
 
    else
819
 
        retval = 1;
820
 
 
821
 
    if (retval == 99) {
822
 
        amavis_syslog(DBG_INFO, "%s: (mlfi_eom) discarding mail, retval is %d",
823
 
                                sendmail_queueid, retval);
824
 
        rstat = SMFIS_DISCARD;
825
 
    } else if (retval == EX_UNAVAILABLE) {  /* REJECT handling */
826
 
                                    /* by Didi Rieder and Mark Martinec */
827
 
        amavis_syslog(DBG_INFO, "%s: (mlfi_eom) rejecting mail, retval is %d",
828
 
                                sendmail_queueid, retval);
829
 
        if (smfi_setreply(ctx, "550", "5.7.1", "Message content rejected") != MI_SUCCESS) {
830
 
            /* Not sure what we need to do here */
831
 
            amavis_syslog(DBG_FATAL, "%s: (mlfi_eom) smfi_setreply failed",
832
 
                                     sendmail_queueid);
833
 
        }
834
 
        rstat = SMFIS_REJECT;
835
 
    } else if (retval == 0) {
836
 
        if (enable_x_header) {
837
 
            amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) adding/changing header", sendmail_queueid);
838
 
            if (smfi_chgheader(ctx, X_HEADER_TAG, 1, X_HEADER_LINE) == MI_FAILURE) {
839
 
                amavis_syslog(DBG_DEBUG, "%s: (mlfi_eom) adding header", sendmail_queueid);
840
 
                if (smfi_addheader(ctx, X_HEADER_TAG, X_HEADER_LINE) != MI_SUCCESS) {
841
 
                    amavis_syslog(DBG_FATAL,
842
 
                        "%s: (mlfi_eom) smfi_addheader failed, perhaps milter session timed out",
843
 
                        sendmail_queueid);
844
 
                }
845
 
            }
846
 
        }
847
 
        amavis_syslog(DBG_INFO, "%s: (mlfi_eom) CONTINUE delivery", sendmail_queueid);
848
 
        rstat = SMFIS_CONTINUE;
849
 
    } else {
850
 
        /* if we got any unexpected exit status, we didn't check the file...
851
 
         * so don't add the header. We return TEMPFAIL instead */
852
 
        amavis_syslog(DBG_WARN, "%s: (mlfi_eom) TEMPFAIL, retval is %d",
853
 
                                sendmail_queueid, retval);
854
 
        rstat = SMFIS_TEMPFAIL;
855
 
    }
856
 
 /* return mlfi_cleanup(ctx, rstat, 0); */    /* _we_ must delete dir & file */
857
 
    return mlfi_cleanup(ctx, rstat, 1); /* server will delete the dir & file */
858
 
}
859
 
 
860
 
static sfsistat
861
 
mlfi_abort(SMFICTX *ctx)
862
 
{
863
 
    struct mlfiPriv *priv = MLFIPRIV;
864
 
    amavis_syslog(DBG_DEBUG, "%s: (mlfi_abort)",
865
 
                (!priv || !priv->mlfi_queueid ? "?" : priv->mlfi_queueid) );
866
 
    return mlfi_cleanup(ctx, SMFIS_CONTINUE, 0);
867
 
}
868
 
 
869
 
static sfsistat
870
 
mlfi_close(SMFICTX *ctx)
871
 
{
872
 
    struct mlfiPriv *priv = MLFIPRIV;
873
 
    amavis_syslog(DBG_DEBUG, "(mlfi_close) %sclearing all variables",
874
 
                (!priv || !priv->mlfi_queueid ? "" : priv->mlfi_queueid) );
875
 
    return clearpriv(ctx, SMFIS_CONTINUE, 1);  /* discard all data */
876
 
}
877
 
 
878
 
static sfsistat
879
 
mlfi_cleanup(SMFICTX *ctx, sfsistat rstat, bool keep)
880
 
{
881
 
    struct mlfiPriv *priv = MLFIPRIV;
882
 
    const char *sendmail_queueid;
883
 
 
884
 
    if (!priv)
885
 
        return rstat;
886
 
    sendmail_queueid = !priv->mlfi_queueid ? "" : priv->mlfi_queueid;
887
 
 
888
 
    if (keep) {
889
 
        /* don't delete the file */
890
 
    } else {
891
 
        /* message was aborted -- delete the archive file */
892
 
        if (priv->mlfi_fp) {
893
 
            if (fclose(priv->mlfi_fp) != 0)
894
 
                amavis_syslog(DBG_FATAL, "%s: (mlfi_cleanup) close failed: %s",
895
 
                              sendmail_queueid, strerror(errno));
896
 
            priv->mlfi_fp = NULL;
897
 
        }
898
 
        if (priv->mlfi_fname) {
899
 
            char *p;
900
 
            amavis_syslog(DBG_DEBUG, "%s: (mlfi_cleanup) deleting temp file",
901
 
                                     sendmail_queueid);
902
 
            if (unlink(priv->mlfi_fname) < 0)
903
 
                amavis_syslog(DBG_FATAL, "%s: (mlfi_cleanup) unlinking %s failed: %s",
904
 
                        sendmail_queueid, priv->mlfi_fname, strerror(errno));
905
 
            p = strrchr(priv->mlfi_fname, '/');
906
 
            if (!p) {
907
 
                amavis_syslog(DBG_FATAL, "%s: (mlfi_cleanup) no '/' in %s",
908
 
                                         sendmail_queueid, priv->mlfi_fname);
909
 
            } else {
910
 
                *p = '\0';
911
 
                if (rmdir(priv->mlfi_fname) < 0)
912
 
                    amavis_syslog(DBG_FATAL, "%s: (mlfi_cleanup) rmdir of %s failed: %s",
913
 
                        sendmail_queueid, priv->mlfi_fname, strerror(errno));
914
 
                *p = '/';
915
 
            }
916
 
        }
917
 
    }
918
 
 
919
 
    /* clear message data, return status */
920
 
    amavis_syslog(DBG_DEBUG, "%s: (mlfi_cleanup) clearing message variables",
921
 
                             sendmail_queueid);
922
 
    return clearpriv(ctx, rstat, 0);  /* discard message data if any */
923
 
}
924
 
 
925
 
 
926
 
struct smfiDesc smfilter = {
927
 
    "amavis-milter",            /* filter name */
928
 
    SMFI_VERSION,               /* version code -- do not change */
929
 
    SMFIF_ADDHDRS|SMFIF_CHGHDRS,/* flags */
930
 
    mlfi_connect,               /* connection info filter */
931
 
    mlfi_helo,                  /* SMTP HELO command filter */
932
 
    mlfi_envfrom,               /* envelope sender filter */
933
 
    mlfi_envto,                 /* envelope recipient filter */
934
 
    mlfi_header,                /* header filter */
935
 
    mlfi_eoh,                   /* end of header */
936
 
    mlfi_body,                  /* body block filter */
937
 
    mlfi_eom,                   /* end of message */
938
 
    mlfi_abort,                 /* message aborted */
939
 
    mlfi_close                  /* connection cleanup */
940
 
};
941
 
 
942
 
 
943
 
void
944
 
usage(void)
945
 
{
946
 
    fprintf(stderr, "usage:\n");
947
 
    fprintf(stderr, "  amavis-milter -p local:<unix-socket> [-d] [-v]\n");
948
 
    fprintf(stderr, "  amavis-milter -p inet:port@0.0.0.0 [-d] [-v]\n");
949
 
    fprintf(stderr, "  amavis-milter -h\n");
950
 
    fprintf(stderr, "\n");
951
 
    fprintf(stderr, "-p specifies a milter socket on which amavis-milter\n");
952
 
    fprintf(stderr, "   will listen for connections from sendmail.\n");
953
 
    fprintf(stderr, "   The argument is passed directly to libmilter, see sendmail milter\n");
954
 
    fprintf(stderr, "   documentation for details. The socket specified must match the\n");
955
 
    fprintf(stderr, "   INPUT_MAIL_FILTER macro call in the sendmail configuration file.\n");
956
 
    fprintf(stderr, "-d debug: disables daemonisation and turns log level fully up (-vvvv) \n");
957
 
    fprintf(stderr, "-v increases logging level by one, may be specified up to 4 times\n");
958
 
    fprintf(stderr, "-h help: displays this usage text and exits\n");
959
 
    fprintf(stderr, "\n");
960
 
    fprintf(stderr, "Options -g, -x, -D are allowed for compatibility but ignored.\n");
961
 
    fprintf(stderr, "\n");
962
 
    fprintf(stderr, "This helper prgram (milter daemon) is normally started as:\n");
963
 
    fprintf(stderr, "# su amavis -c '/usr/local/sbin/amavis-milter -p local:/var/amavis/amavis-milter.sock'\n");
964
 
};
965
 
 
966
 
int
967
 
main(int argc, char *argv[])
968
 
{
969
 
/*  struct passwd *userinfo;    *amavis uid*  */
970
 
    int c, i;
971
 
    char *p, *milter_socket = NULL, *milter_socket_group = NULL;
972
 
/*  const char *args = "dg:p:vx";  */
973
 
    const char *args = ":hdg:p:Dvx";  /* some mix of old and new options!!! */
974
 
 
975
 
    pid_t pid;
976
 
    int devnull;
977
 
    int result;
978
 
 
979
 
#if !defined(HAVE_MKDTEMP) && !defined(HAVE_MKTEMP)
980
 
    int mypid = getpid();
981
 
 
982
 
    srand48(time(NULL) ^ (mypid + (mypid << 15)));
983
 
#endif
984
 
 
985
 
    umask(0007);
986
 
 
987
 
    /* Process command line options */
988
 
    while ((c = getopt(argc, argv, args)) != -1) {
989
 
        switch (c) {
990
 
        case 'd':
991
 
            /* don't daemonise, log to stderr */
992
 
            verbosity = DBG_DEBUG;  /* full debugging log level */
993
 
            AM_DAEMON = 0;
994
 
            break;
995
 
        case 'g':
996
 
            /* name of milter socket group owner */
997
 
            if (optarg == NULL || *optarg == '\0') {
998
 
                fprintf(stderr, "%s: Illegal group: %s\n", argv[0], optarg);
999
 
            }
1000
 
            fprintf(stderr, "%s: group specification ignored (not implemented)\n", argv[0]);
1001
 
            milter_socket_group = strdup(optarg);
1002
 
            break;
1003
 
        case 'p':
1004
 
            /* socket name - see smfi_setconn man page */
1005
 
            if (optarg == NULL || *optarg == '\0') {
1006
 
                fprintf(stderr, "%s: Illegal conn: %s\n", argv[0], optarg);
1007
 
                exit(EXIT_FAILURE);
1008
 
            }
1009
 
            milter_socket = strdup(optarg);
1010
 
            break;
1011
 
        case 'v':
1012
 
            verbosity++;
1013
 
            break;
1014
 
        case 'D':
1015
 
            AM_DAEMON = 1;   /* which is also a default, unless debugging */
1016
 
            break;
1017
 
        case 'x':
1018
 
         /* enable_x_header++; */    /* older versions */
1019
 
         /* enable_x_header = 0;*/   /* since 1.1.2.3.2.40 */
1020
 
            fprintf(stderr, "%s: option -x ignored to avoid confusion with older versions\n", argv[0]);
1021
 
            break;
1022
 
        case 'h':
1023
 
            usage();
1024
 
            exit(EXIT_SUCCESS);
1025
 
            break;
1026
 
        default:
1027
 
            usage();
1028
 
            exit(EXIT_FAILURE);
1029
 
        }
1030
 
    }
1031
 
 
1032
 
    if (smfi_register(smfilter) == MI_FAILURE) {
1033
 
        fprintf(stderr, "%s: smfi_register failed\n", argv[0]);
1034
 
        exit(EXIT_FAILURE);
1035
 
    }
1036
 
 
1037
 
    uname(&amavis_uts);
1038
 
 
1039
 
    /* check user and group */
1040
 
/*  if (!(userinfo = getpwnam(AMAVIS_USER))) {
1041
 
 *      perror("getpwnam");
1042
 
 *      exit(EXIT_FAILURE);
1043
 
 *  }
1044
 
 *  amavis_gid = userinfo->pw_gid;
1045
 
 *  if (!milter_socket_group) {
1046
 
 *      milter_socket_group = strdup(MILTER_SOCKET_GROUP);
1047
 
 *      if (!milter_socket_group) {
1048
 
 *          perror("strdup");
1049
 
 *          exit(EXIT_FAILURE);
1050
 
 *      }
1051
 
 *  }
1052
 
 *  if (group_member(milter_socket_group) < 0) {
1053
 
 *      fprintf(stderr, "%s not member of %s group\n", AMAVIS_USER, milter_socket_group);
1054
 
 *      exit(EXIT_FAILURE);
1055
 
 *  }
1056
 
 */
1057
 
    if (!milter_socket) {
1058
 
        fprintf(stderr, "%s: no milter socket specified (missing option -p)\n\n", argv[0]);
1059
 
        usage();
1060
 
        exit(EXIT_FAILURE);
1061
 
    }
1062
 
 
1063
 
    /* check socket */
1064
 
    if ((p = strchr(milter_socket,'/'))) {
1065
 
        /* Unlink any existing file that might be in place of
1066
 
         * the socket we want to create.  This might not exactly
1067
 
         * be safe, or friendly, but I'll deal with that later.
1068
 
         * Be nice and issue a warning if we have a problem, but
1069
 
         * other than that, ignore it. */
1070
 
        if (unlink(p) < 0) {
1071
 
            amavis_syslog(DBG_INFO, "INFO: Cannot unlink old socket %s: %s", milter_socket, strerror(errno));
1072
 
        }
1073
 
    }
1074
 
 
1075
 
    /* Errors are detected in smfi_main */
1076
 
    if (smfi_setconn(milter_socket) != MI_SUCCESS) {
1077
 
        amavis_syslog(DBG_FATAL, "(main) smfi_setconn failed");
1078
 
    }
1079
 
 
1080
 
    /* See if we're supposed to become a daemonized process */
1081
 
    if (AM_DAEMON == 1) {
1082
 
 
1083
 
        /* 2001/11/09 Anne Bennett: daemonize properly.
1084
 
         * OK, let's be a real daemon.  Taken from page 417
1085
 
         * of Stevens' "Advanced Programming in the UNIX Environment".
1086
 
         */
1087
 
 
1088
 
        /* Step 1: Fork and have parent exit.  This not only
1089
 
         * backgrounds us but makes sure we are not a process group
1090
 
         * leader.
1091
 
         */
1092
 
 
1093
 
        /* Fork ourselves into the background, and see if it worked */
1094
 
        if ((pid = fork()) > 0) {
1095
 
 
1096
 
            amavis_syslog(DBG_INFO, "amavis-milter forked into background");
1097
 
            /* We are the parent; exit. */
1098
 
            exit(EXIT_SUCCESS);
1099
 
 
1100
 
        } else if (pid == -1) {
1101
 
            perror("fork");
1102
 
            exit(EXIT_FAILURE);
1103
 
        }
1104
 
 
1105
 
        /* OK, we're backgrounded.
1106
 
         * Step 2: Call setsid to create a new session.  This makes
1107
 
         * sure among other things that we have no controlling
1108
 
         * terminal.
1109
 
         */
1110
 
        if (setsid() < (pid_t)0) {
1111
 
            amavis_syslog(DBG_FATAL, "setsid() returned error: %s", strerror(errno));
1112
 
            exit(EXIT_FAILURE);
1113
 
        }
1114
 
 
1115
 
        /* Step 3: Set the working directory appropriately. */
1116
 
        if (chdir("/") < 0 ) {
1117
 
            amavis_syslog(DBG_FATAL, "chdir(/) returned error: %s", strerror(errno));
1118
 
            exit(EXIT_FAILURE);
1119
 
        }
1120
 
 
1121
 
        /* Step 4: Close all file descriptors. */
1122
 
        for (i = 0; i < _POSIX_OPEN_MAX ; i++) {
1123
 
            close(i);
1124
 
        }
1125
 
 
1126
 
        /* Open /dev/null read-only (fd 0 = STDIN) */
1127
 
        if ((devnull = open(DEVNULL, O_RDONLY, 0)) < 0) {
1128
 
             amavis_syslog(DBG_FATAL, "Could not open %s as STDIN: %s", DEVNULL, strerror(errno));
1129
 
             exit(EXIT_FAILURE);
1130
 
        }
1131
 
        if (devnull != 0) {
1132
 
             amavis_syslog(DBG_FATAL, "Got wrong file descriptor as STDIN: %s != 0", DEVNULL);
1133
 
             exit(EXIT_FAILURE);
1134
 
        }
1135
 
 
1136
 
        /* Open /dev/null write-only (fd 1 = STDOUT) */
1137
 
        if ((devnull = open(DEVNULL, O_WRONLY, 0)) < 0) {
1138
 
             amavis_syslog(DBG_FATAL, "Could not open %s as STDOUT: %s", DEVNULL, strerror(errno));
1139
 
             exit(EXIT_FAILURE);
1140
 
        }
1141
 
        if (devnull != 1) {
1142
 
             amavis_syslog(DBG_FATAL, "Got wrong file descriptor as STDOUT: %s != 1", DEVNULL);
1143
 
             exit(EXIT_FAILURE);
1144
 
        }
1145
 
 
1146
 
        /* Open /dev/null write-only (fd 2 = STDERR) */
1147
 
        if ((devnull = open(DEVNULL, O_WRONLY, 0)) < 0) {
1148
 
             amavis_syslog(DBG_FATAL, "Could not open %s as STDERR: %s", DEVNULL, strerror(errno));
1149
 
             exit(EXIT_FAILURE);
1150
 
        }
1151
 
        if (devnull != 2) {
1152
 
             amavis_syslog(DBG_FATAL, "Got wrong file descriptor as STDERR: %s != 2", DEVNULL);
1153
 
             exit(EXIT_FAILURE);
1154
 
        }
1155
 
    }
1156
 
 
1157
 
    /* change process group id */
1158
 
    if (miltergroup && (setgid(miltergroup->gr_gid)) < 0) {
1159
 
        amavis_syslog(DBG_FATAL, "setgid(%d): %s", miltergroup->gr_gid, strerror(errno));
1160
 
        exit(EX_UNAVAILABLE);
1161
 
    }
1162
 
 
1163
 
    /* smfi_settimeout(1800); */     /* defaults to 7210 seconds */
1164
 
 
1165
 
    daemon_pid = getpid();
1166
 
    get_lock();
1167
 
 
1168
 
    /* hand control over to libmilter */
1169
 
    amavis_syslog(DBG_INFO, "Starting, handing off to smfi_main");
1170
 
    result=smfi_main();
1171
 
 
1172
 
    remove(pidfile);
1173
 
    return(result);
1174
 
}
1175
 
 
1176
 
/* eof */