401 lines
8.2 KiB
C
401 lines
8.2 KiB
C
/*
|
||
* Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
|
||
* All rights reserved.
|
||
*
|
||
* By using this file, you agree to the terms and conditions set
|
||
* forth in the LICENSE file which can be found at the top level of
|
||
* the sendmail distribution.
|
||
*
|
||
*/
|
||
|
||
#ifndef lint
|
||
static char id[] = "@(#)Id: smfi.c,v 8.28.4.6 2000/06/28 23:48:56 gshapiro Exp";
|
||
#endif /* ! lint */
|
||
|
||
#if _FFR_MILTER
|
||
#include "libmilter.h"
|
||
#include "sendmail/useful.h"
|
||
|
||
/*
|
||
** SMFI_ADDHEADER -- send a new header to the MTA
|
||
**
|
||
** Parameters:
|
||
** ctx -- Opaque context structure
|
||
** headerf -- Header field name
|
||
** headerv -- Header field value
|
||
**
|
||
** Returns:
|
||
** MI_SUCCESS/MI_FAILURE
|
||
*/
|
||
|
||
int
|
||
smfi_addheader(ctx, headerf, headerv)
|
||
SMFICTX *ctx;
|
||
char *headerf;
|
||
char *headerv;
|
||
{
|
||
/* do we want to copy the stuff or have a special mi_wr_cmd call? */
|
||
size_t len, l1, l2;
|
||
int r;
|
||
char *buf;
|
||
struct timeval timeout;
|
||
|
||
if (headerf == NULL || *headerf == '\0' || headerv == NULL)
|
||
return MI_FAILURE;
|
||
if (!mi_sendok(ctx, SMFIF_ADDHDRS))
|
||
return MI_FAILURE;
|
||
timeout.tv_sec = ctx->ctx_timeout;
|
||
timeout.tv_usec = 0;
|
||
l1 = strlen(headerf);
|
||
l2 = strlen(headerv);
|
||
len = l1 + l2 + 2;
|
||
buf = malloc(len);
|
||
if (buf == NULL)
|
||
return MI_FAILURE;
|
||
(void) memcpy(buf, headerf, l1 + 1);
|
||
(void) memcpy(buf + l1 + 1, headerv, l2 + 1);
|
||
r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDHEADER, buf, len);
|
||
free(buf);
|
||
return r;
|
||
}
|
||
|
||
/*
|
||
** SMFI_CHGHEADER -- send a changed header to the MTA
|
||
**
|
||
** Parameters:
|
||
** ctx -- Opaque context structure
|
||
** headerf -- Header field name
|
||
** hdridx -- Header index value
|
||
** headerv -- Header field value
|
||
**
|
||
** Returns:
|
||
** MI_SUCCESS/MI_FAILURE
|
||
*/
|
||
|
||
int
|
||
smfi_chgheader(ctx, headerf, hdridx, headerv)
|
||
SMFICTX *ctx;
|
||
char *headerf;
|
||
mi_int32 hdridx;
|
||
char *headerv;
|
||
{
|
||
/* do we want to copy the stuff or have a special mi_wr_cmd call? */
|
||
size_t len, l1, l2;
|
||
int r;
|
||
mi_int32 v;
|
||
char *buf;
|
||
struct timeval timeout;
|
||
|
||
if (headerf == NULL || *headerf == '\0')
|
||
return MI_FAILURE;
|
||
if (hdridx < 0)
|
||
return MI_FAILURE;
|
||
if (!mi_sendok(ctx, SMFIF_CHGHDRS))
|
||
return MI_FAILURE;
|
||
timeout.tv_sec = ctx->ctx_timeout;
|
||
timeout.tv_usec = 0;
|
||
if (headerv == NULL)
|
||
headerv = "";
|
||
l1 = strlen(headerf);
|
||
l2 = strlen(headerv);
|
||
len = l1 + l2 + 2 + MILTER_LEN_BYTES;
|
||
buf = malloc(len);
|
||
if (buf == NULL)
|
||
return MI_FAILURE;
|
||
v = htonl(hdridx);
|
||
(void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
|
||
(void) memcpy(buf + MILTER_LEN_BYTES, headerf, l1 + 1);
|
||
(void) memcpy(buf + MILTER_LEN_BYTES + l1 + 1, headerv, l2 + 1);
|
||
r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_CHGHEADER, buf, len);
|
||
free(buf);
|
||
return r;
|
||
}
|
||
/*
|
||
** SMFI_ADDRCPT -- send an additional recipient to the MTA
|
||
**
|
||
** Parameters:
|
||
** ctx -- Opaque context structure
|
||
** rcpt -- recipient address
|
||
**
|
||
** Returns:
|
||
** MI_SUCCESS/MI_FAILURE
|
||
*/
|
||
|
||
int
|
||
smfi_addrcpt(ctx, rcpt)
|
||
SMFICTX *ctx;
|
||
char *rcpt;
|
||
{
|
||
size_t len;
|
||
struct timeval timeout;
|
||
|
||
if (rcpt == NULL || *rcpt == '\0')
|
||
return MI_FAILURE;
|
||
if (!mi_sendok(ctx, SMFIF_ADDRCPT))
|
||
return MI_FAILURE;
|
||
timeout.tv_sec = ctx->ctx_timeout;
|
||
timeout.tv_usec = 0;
|
||
len = strlen(rcpt) + 1;
|
||
return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
|
||
}
|
||
/*
|
||
** SMFI_DELRCPT -- send a recipient to be removed to the MTA
|
||
**
|
||
** Parameters:
|
||
** ctx -- Opaque context structure
|
||
** rcpt -- recipient address
|
||
**
|
||
** Returns:
|
||
** MI_SUCCESS/MI_FAILURE
|
||
*/
|
||
|
||
int
|
||
smfi_delrcpt(ctx, rcpt)
|
||
SMFICTX *ctx;
|
||
char *rcpt;
|
||
{
|
||
size_t len;
|
||
struct timeval timeout;
|
||
|
||
if (rcpt == NULL || *rcpt == '\0')
|
||
return MI_FAILURE;
|
||
if (!mi_sendok(ctx, SMFIF_DELRCPT))
|
||
return MI_FAILURE;
|
||
timeout.tv_sec = ctx->ctx_timeout;
|
||
timeout.tv_usec = 0;
|
||
len = strlen(rcpt) + 1;
|
||
return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
|
||
}
|
||
/*
|
||
** SMFI_REPLACEBODY -- send a body chunk to the MTA
|
||
**
|
||
** Parameters:
|
||
** ctx -- Opaque context structure
|
||
** bodyp -- body chunk
|
||
** bodylen -- length of body chunk
|
||
**
|
||
** Returns:
|
||
** MI_SUCCESS/MI_FAILURE
|
||
*/
|
||
|
||
int
|
||
smfi_replacebody(ctx, bodyp, bodylen)
|
||
SMFICTX *ctx;
|
||
u_char *bodyp;
|
||
int bodylen;
|
||
{
|
||
int len, off, r;
|
||
struct timeval timeout;
|
||
|
||
if (bodyp == NULL && bodylen > 0)
|
||
return MI_FAILURE;
|
||
if (!mi_sendok(ctx, SMFIF_CHGBODY))
|
||
return MI_FAILURE;
|
||
timeout.tv_sec = ctx->ctx_timeout;
|
||
timeout.tv_usec = 0;
|
||
|
||
/* split body chunk if necessary */
|
||
off = 0;
|
||
while (bodylen > 0)
|
||
{
|
||
len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
|
||
bodylen;
|
||
if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
|
||
(char *) (bodyp + off), len)) != MI_SUCCESS)
|
||
return r;
|
||
off += len;
|
||
bodylen -= len;
|
||
}
|
||
return MI_SUCCESS;
|
||
}
|
||
/*
|
||
** MYISENHSC -- check whether a string contains an enhanced status code
|
||
**
|
||
** Parameters:
|
||
** s -- string with possible enhanced status code.
|
||
** delim -- delim for enhanced status code.
|
||
**
|
||
** Returns:
|
||
** 0 -- no enhanced status code.
|
||
** >4 -- length of enhanced status code.
|
||
**
|
||
** Side Effects:
|
||
** none.
|
||
*/
|
||
static int
|
||
myisenhsc(s, delim)
|
||
const char *s;
|
||
int delim;
|
||
{
|
||
int l, h;
|
||
|
||
if (s == NULL)
|
||
return 0;
|
||
if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
|
||
return 0;
|
||
h = 0;
|
||
l = 2;
|
||
while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
|
||
++h;
|
||
if (h == 0 || s[l + h] != '.')
|
||
return 0;
|
||
l += h + 1;
|
||
h = 0;
|
||
while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
|
||
++h;
|
||
if (h == 0 || s[l + h] != delim)
|
||
return 0;
|
||
return l + h;
|
||
}
|
||
/*
|
||
** SMFI_SETREPLY -- set the reply code for the next reply to the MTA
|
||
**
|
||
** Parameters:
|
||
** ctx -- Opaque context structure
|
||
** rcode -- The three-digit (RFC 821) SMTP reply code.
|
||
** xcode -- The extended (RFC 2034) reply code.
|
||
** message -- The text part of the SMTP reply.
|
||
**
|
||
** Returns:
|
||
** MI_SUCCESS/MI_FAILURE
|
||
*/
|
||
|
||
int
|
||
smfi_setreply(ctx, rcode, xcode, message)
|
||
SMFICTX *ctx;
|
||
char *rcode;
|
||
char *xcode;
|
||
char *message;
|
||
{
|
||
size_t len, l1, l2, l3;
|
||
char *buf;
|
||
|
||
if (rcode == NULL || ctx == NULL)
|
||
return MI_FAILURE;
|
||
l1 = strlen(rcode) + 1;
|
||
if (l1 != 4)
|
||
return MI_FAILURE;
|
||
if ((rcode[0] != '4' && rcode[0] != '5') ||
|
||
!isascii(rcode[1]) || !isdigit(rcode[1]) ||
|
||
!isascii(rcode[2]) || !isdigit(rcode[2]))
|
||
return MI_FAILURE;
|
||
l2 = xcode == NULL ? 1 : strlen(xcode) + 1;
|
||
if (xcode != NULL && !myisenhsc(xcode, '\0'))
|
||
return MI_FAILURE;
|
||
l3 = message == NULL ? 1 : strlen(message) + 1;
|
||
len = l1 + l2 + l3;
|
||
buf = malloc(len);
|
||
if (buf == NULL)
|
||
return MI_FAILURE; /* oops */
|
||
(void) snprintf(buf, len, "%s %s %s", rcode,
|
||
xcode == NULL ? "" : xcode,
|
||
message == NULL ? "" : message);
|
||
if (ctx->ctx_reply != NULL)
|
||
free(ctx->ctx_reply);
|
||
ctx->ctx_reply = buf;
|
||
return MI_SUCCESS;
|
||
}
|
||
/*
|
||
** SMFI_SETPRIV -- set private data
|
||
**
|
||
** Parameters:
|
||
** ctx -- Opaque context structure
|
||
** privatedata -- pointer to private data
|
||
**
|
||
** Returns:
|
||
** MI_SUCCESS/MI_FAILURE
|
||
*/
|
||
|
||
int
|
||
smfi_setpriv(ctx, privatedata)
|
||
SMFICTX *ctx;
|
||
void *privatedata;
|
||
{
|
||
if (ctx == NULL)
|
||
return MI_FAILURE;
|
||
ctx->ctx_privdata = privatedata;
|
||
return MI_SUCCESS;
|
||
}
|
||
/*
|
||
** SMFI_GETPRIV -- get private data
|
||
**
|
||
** Parameters:
|
||
** ctx -- Opaque context structure
|
||
**
|
||
** Returns:
|
||
** pointer to private data
|
||
*/
|
||
|
||
void *
|
||
smfi_getpriv(ctx)
|
||
SMFICTX *ctx;
|
||
{
|
||
if (ctx == NULL)
|
||
return NULL;
|
||
return ctx->ctx_privdata;
|
||
}
|
||
/*
|
||
** SMFI_GETSYMVAL -- get the value of a macro
|
||
**
|
||
** See explanation in mfapi.h about layout of the structures.
|
||
**
|
||
** Parameters:
|
||
** ctx -- Opaque context structure
|
||
** symname -- name of macro
|
||
**
|
||
** Returns:
|
||
** value of macro (NULL in case of failure)
|
||
*/
|
||
|
||
char *
|
||
smfi_getsymval(ctx, symname)
|
||
SMFICTX *ctx;
|
||
char *symname;
|
||
{
|
||
int i;
|
||
char **s;
|
||
char one[2];
|
||
char braces[4];
|
||
|
||
if (ctx == NULL || symname == NULL || *symname == '\0')
|
||
return NULL;
|
||
|
||
if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
|
||
{
|
||
one[0] = symname[1];
|
||
one[1] = '\0';
|
||
}
|
||
else
|
||
one[0] = '\0';
|
||
if (strlen(symname) == 1)
|
||
{
|
||
braces[0] = '{';
|
||
braces[1] = *symname;
|
||
braces[2] = '}';
|
||
braces[3] = '\0';
|
||
}
|
||
else
|
||
braces[0] = '\0';
|
||
|
||
/* search backwards through the macro array */
|
||
for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
|
||
{
|
||
if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
|
||
ctx->ctx_mac_buf[i] == NULL)
|
||
continue;
|
||
while (s != NULL && *s != NULL)
|
||
{
|
||
if (strcmp(*s, symname) == 0)
|
||
return *++s;
|
||
if (one[0] != '\0' && strcmp(*s, one) == 0)
|
||
return *++s;
|
||
if (braces[0] != '\0' && strcmp(*s, braces) == 0)
|
||
return *++s;
|
||
++s; /* skip over macro value */
|
||
++s; /* points to next macro name */
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
#endif /* _FFR_MILTER */
|