2020-04-24 23:06:34 +02:00
|
|
|
/*
|
|
|
|
* Mailattach - a program to remove attachments and replace them with links.
|
|
|
|
* Licensed under the Apache 2.0 License. Parts taken from the sendmail
|
|
|
|
* libmilter sample. License restrictions from their license may apply.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sysexits.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <libmilter/mfapi.h>
|
|
|
|
#include <libmilter/mfdef.h>
|
|
|
|
|
2020-04-25 00:53:36 +02:00
|
|
|
#include "version.h"
|
|
|
|
#include "config.h"
|
2020-04-25 01:37:15 +02:00
|
|
|
#include "attach.h"
|
2020-04-24 23:06:34 +02:00
|
|
|
|
|
|
|
struct mlfiPriv
|
|
|
|
{
|
|
|
|
char *mlfi_fname;
|
|
|
|
FILE *mlfi_fp;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx))
|
|
|
|
|
|
|
|
static unsigned long mta_caps = 0;
|
|
|
|
|
|
|
|
sfsistat mlfi_cleanup(SMFICTX* ctx, bool ok) {
|
|
|
|
sfsistat rstat = SMFIS_CONTINUE;
|
|
|
|
struct mlfiPriv *priv = MLFIPRIV;
|
|
|
|
|
2020-04-25 00:53:36 +02:00
|
|
|
if (priv == NULL){
|
|
|
|
/* Something weired mus have happened... Maybe a crash? */
|
2020-04-24 23:06:34 +02:00
|
|
|
return rstat;
|
2020-04-25 00:53:36 +02:00
|
|
|
}
|
2020-04-24 23:06:34 +02:00
|
|
|
|
2020-04-25 01:55:49 +02:00
|
|
|
if (ok){
|
2020-04-25 00:53:36 +02:00
|
|
|
|
2020-04-24 23:06:34 +02:00
|
|
|
/* add a header to the message announcing our presence */
|
2020-04-25 00:53:36 +02:00
|
|
|
smfi_addheader(ctx, "X-Mail-Attached", VERSION);
|
2020-04-25 01:50:44 +02:00
|
|
|
|
|
|
|
/* replace body if attachements have been found */
|
2020-04-25 01:55:49 +02:00
|
|
|
|
2020-04-25 01:50:44 +02:00
|
|
|
char* new_body = attach_files(priv->mlfi_fp);
|
|
|
|
if(new_body != NULL){
|
2020-04-25 17:48:13 +02:00
|
|
|
const char* head = "REPLACED:";
|
|
|
|
size_t new_bodylen = strlen(new_body)+10;
|
2020-04-25 01:50:44 +02:00
|
|
|
unsigned char * replacement = malloc(new_bodylen+1);
|
|
|
|
memset(replacement, 0, new_bodylen+1);
|
2020-04-25 17:48:13 +02:00
|
|
|
strcat(replacement, head);
|
|
|
|
strcat(replacement, new_body);
|
2020-04-25 01:50:44 +02:00
|
|
|
free(new_body);
|
2020-04-25 17:48:13 +02:00
|
|
|
printf("Replacing body of mail message with len %lu\n",
|
|
|
|
strlen(replacement));
|
|
|
|
printf("Content: [%s]\n",replacement);
|
|
|
|
if(smfi_replacebody(ctx, replacement, strlen(replacement)) ==
|
2020-04-25 01:50:44 +02:00
|
|
|
MI_FAILURE){
|
|
|
|
printf("Failed to replace body of message...\n"
|
|
|
|
);
|
|
|
|
free(replacement);
|
|
|
|
}
|
|
|
|
}
|
2020-04-25 17:48:13 +02:00
|
|
|
|
2020-04-24 23:06:34 +02:00
|
|
|
}
|
2020-04-25 01:55:49 +02:00
|
|
|
/* close the archive file */
|
|
|
|
if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF){
|
|
|
|
/* failed; we have to wait until later */
|
|
|
|
rstat = SMFIS_TEMPFAIL;
|
|
|
|
(void) unlink(priv->mlfi_fname);
|
|
|
|
}
|
2020-04-25 00:53:36 +02:00
|
|
|
/* In any case release the temporary data storage file */
|
|
|
|
(void) unlink(priv->mlfi_fname);
|
|
|
|
|
|
|
|
|
2020-04-24 23:06:34 +02:00
|
|
|
/* release private memory */
|
|
|
|
free(priv->mlfi_fname);
|
|
|
|
free(priv);
|
|
|
|
smfi_setpriv(ctx, NULL);
|
|
|
|
|
|
|
|
return rstat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-25 00:53:36 +02:00
|
|
|
sfsistat mlfi_envfrom(SMFICTX *ctx, char** envfrom) {
|
2020-04-24 23:06:34 +02:00
|
|
|
struct mlfiPriv *priv;
|
|
|
|
int fd = -1;
|
|
|
|
|
|
|
|
/* allocate some private memory */
|
|
|
|
priv = malloc(sizeof *priv);
|
|
|
|
if (priv == NULL)
|
|
|
|
{
|
2020-04-25 00:53:36 +02:00
|
|
|
/* can't accept this message right now, memory has run out */
|
2020-04-24 23:06:34 +02:00
|
|
|
return SMFIS_TEMPFAIL;
|
|
|
|
}
|
|
|
|
memset(priv, '\0', sizeof *priv);
|
|
|
|
|
|
|
|
/* open a file to store this message */
|
|
|
|
priv->mlfi_fname = strdup("/tmp/msg.XXXXXXXX");
|
2020-04-25 00:53:36 +02:00
|
|
|
if (priv->mlfi_fname == NULL){
|
|
|
|
|
2020-04-24 23:06:34 +02:00
|
|
|
free(priv);
|
|
|
|
return SMFIS_TEMPFAIL;
|
|
|
|
}
|
2020-04-25 00:53:36 +02:00
|
|
|
|
2020-04-24 23:06:34 +02:00
|
|
|
if ((fd = mkstemp(priv->mlfi_fname)) < 0 ||
|
2020-04-25 00:53:36 +02:00
|
|
|
(priv->mlfi_fp = fdopen(fd, "w+")) == NULL) {
|
|
|
|
if (fd >= 0){
|
2020-04-24 23:06:34 +02:00
|
|
|
(void) close(fd);
|
2020-04-25 00:53:36 +02:00
|
|
|
}
|
2020-04-24 23:06:34 +02:00
|
|
|
free(priv->mlfi_fname);
|
|
|
|
free(priv);
|
|
|
|
return SMFIS_TEMPFAIL;
|
|
|
|
}
|
2020-04-25 00:53:36 +02:00
|
|
|
printf("Storing temp message to %s\n", priv->mlfi_fname);
|
2020-04-24 23:06:34 +02:00
|
|
|
|
|
|
|
/* save the private data */
|
|
|
|
smfi_setpriv(ctx, priv);
|
|
|
|
|
|
|
|
/* continue processing */
|
|
|
|
return SMFIS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2020-04-25 00:53:36 +02:00
|
|
|
sfsistat mlfi_header(SMFICTX *ctx, char * headerf,char * headerv)
|
2020-04-24 23:06:34 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
/* continue processing */
|
|
|
|
return ((mta_caps & SMFIP_NR_HDR) != 0)
|
|
|
|
? SMFIS_NOREPLY : SMFIS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2020-04-25 00:53:36 +02:00
|
|
|
sfsistat mlfi_eoh(SMFICTX *ctx) {
|
2020-04-24 23:06:34 +02:00
|
|
|
|
|
|
|
/* continue processing */
|
|
|
|
return SMFIS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
sfsistat mlfi_body(SMFICTX* ctx, unsigned char * bodyp, size_t bodylen) {
|
|
|
|
|
|
|
|
/* output body block to log file */
|
2020-04-25 00:53:36 +02:00
|
|
|
if (fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp) <= 0){
|
|
|
|
perror("Failed to write body to file...");
|
|
|
|
|
2020-04-24 23:06:34 +02:00
|
|
|
(void) mlfi_cleanup(ctx, false);
|
|
|
|
return SMFIS_TEMPFAIL;
|
|
|
|
}
|
|
|
|
/* continue processing */
|
|
|
|
return SMFIS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
sfsistat mlfi_eom(ctx)
|
|
|
|
SMFICTX *ctx;
|
|
|
|
{
|
|
|
|
return mlfi_cleanup(ctx, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
sfsistat mlfi_close(ctx)
|
|
|
|
SMFICTX *ctx;
|
|
|
|
{
|
|
|
|
return SMFIS_ACCEPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
sfsistat mlfi_abort(ctx)
|
|
|
|
SMFICTX *ctx;
|
|
|
|
{
|
|
|
|
return mlfi_cleanup(ctx, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
sfsistat mlfi_unknown(ctx, cmd)
|
|
|
|
SMFICTX *ctx;
|
|
|
|
char *cmd;
|
|
|
|
{
|
|
|
|
return SMFIS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
sfsistat mlfi_data(ctx)
|
|
|
|
SMFICTX *ctx;
|
|
|
|
{
|
|
|
|
return SMFIS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2020-04-25 00:53:36 +02:00
|
|
|
sfsistat mlfi_negotiate(ctx, f0, f1, f2, f3, pf0, pf1, pf2, pf3)
|
2020-04-24 23:06:34 +02:00
|
|
|
SMFICTX *ctx;
|
|
|
|
unsigned long f0;
|
|
|
|
unsigned long f1;
|
|
|
|
unsigned long f2;
|
|
|
|
unsigned long f3;
|
|
|
|
unsigned long *pf0;
|
|
|
|
unsigned long *pf1;
|
|
|
|
unsigned long *pf2;
|
|
|
|
unsigned long *pf3;
|
|
|
|
{
|
|
|
|
/* milter actions: add headers */
|
|
|
|
*pf0 = SMFIF_ADDHDRS;
|
|
|
|
|
|
|
|
/* milter protocol steps: all but connect, HELO, RCPT */
|
|
|
|
*pf1 = SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NORCPT;
|
|
|
|
mta_caps = f1;
|
|
|
|
if ((mta_caps & SMFIP_NR_HDR) != 0)
|
|
|
|
*pf1 |= SMFIP_NR_HDR;
|
|
|
|
*pf2 = 0;
|
|
|
|
*pf3 = 0;
|
|
|
|
return SMFIS_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct smfiDesc smfilter =
|
|
|
|
{
|
|
|
|
"mailattach", /* filter name */
|
|
|
|
SMFI_VERSION, /* version code -- do not change */
|
2020-04-25 18:13:59 +02:00
|
|
|
SMFIF_ADDHDRS|SMFIF_CHGFROM|SMFIF_ADDRCPT|SMFIF_DELRCPT|0b01|SMFIF_NONE, /* flags */
|
2020-04-24 23:06:34 +02:00
|
|
|
NULL, /* connection info filter */
|
|
|
|
NULL, /* SMTP HELO command filter */
|
|
|
|
mlfi_envfrom, /* envelope sender filter */
|
|
|
|
NULL, /* envelope recipient filter */
|
|
|
|
mlfi_header, /* header filter */
|
|
|
|
mlfi_eoh, /* end of header */
|
|
|
|
mlfi_body, /* body block filter */
|
|
|
|
mlfi_eom, /* end of message */
|
|
|
|
mlfi_abort, /* message aborted */
|
|
|
|
mlfi_close, /* connection cleanup */
|
|
|
|
mlfi_unknown, /* unknown/unimplemented SMTP commands */
|
|
|
|
mlfi_data, /* DATA command filter */
|
|
|
|
mlfi_negotiate /* option negotiation at connection startup */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* The actual entry point for the program. Performs initialisation routines and
|
|
|
|
* then hands over to the libmilter main function */
|
|
|
|
int main(){
|
|
|
|
|
2020-04-25 00:53:36 +02:00
|
|
|
printf("INIT\n");
|
2020-04-24 23:06:34 +02:00
|
|
|
|
2020-04-25 17:48:13 +02:00
|
|
|
const char* conn_prefix = "local:";
|
|
|
|
size_t conn_len = strlen(socket_location)+strlen(conn_prefix)+1;
|
|
|
|
char * conn_str = malloc(conn_len);
|
|
|
|
memset(conn_str, 0, conn_len);
|
|
|
|
|
|
|
|
strcat(conn_str, conn_prefix);
|
|
|
|
strcat(conn_str, socket_location);
|
|
|
|
|
|
|
|
printf("Using socket for milter communication at [%s]\n",
|
|
|
|
conn_str);
|
2020-04-24 23:06:34 +02:00
|
|
|
|
2020-04-25 17:48:13 +02:00
|
|
|
smfi_setconn(conn_str);
|
2020-04-24 23:06:34 +02:00
|
|
|
|
|
|
|
if (smfi_register(smfilter) == MI_FAILURE)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "smfi_register failed\n");
|
2020-04-25 00:53:36 +02:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(smfi_opensocket(true) == MI_FAILURE){
|
|
|
|
fprintf(stderr, "smfi_opensocket failed at location [%s]\n",
|
|
|
|
socket_location);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
if(chmod(socket_location,0x1FF) < 0){
|
|
|
|
perror("Failed to change socket permissions");
|
|
|
|
|
2020-04-24 23:06:34 +02:00
|
|
|
}
|
2020-04-25 00:53:36 +02:00
|
|
|
printf("READY, handing over to libmilter\n");
|
2020-04-24 23:06:34 +02:00
|
|
|
return smfi_main();
|
|
|
|
}
|