164562Sgshapiro/* 2173340Sgshapiro * Copyright (c) 1999-2007 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 464562Sgshapiro * 564562Sgshapiro * By using this file, you agree to the terms and conditions set 664562Sgshapiro * forth in the LICENSE file which can be found at the top level of 764562Sgshapiro * the sendmail distribution. 864562Sgshapiro * 964562Sgshapiro */ 1064562Sgshapiro 1190792Sgshapiro#include <sm/gen.h> 12173340SgshapiroSM_RCSID("@(#)$Id: smfi.c,v 8.83 2007/04/23 16:44:39 ca Exp $") 1390792Sgshapiro#include <sm/varargs.h> 1464562Sgshapiro#include "libmilter.h" 1564562Sgshapiro 16132943Sgshapirostatic int smfi_header __P((SMFICTX *, int, int, char *, char *)); 17141858Sgshapirostatic int myisenhsc __P((const char *, int)); 18132943Sgshapiro 1990792Sgshapiro/* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */ 2090792Sgshapiro#define MAXREPLYLEN 980 /* max. length of a reply string */ 2190792Sgshapiro#define MAXREPLIES 32 /* max. number of reply strings */ 2290792Sgshapiro 2364562Sgshapiro/* 24132943Sgshapiro** SMFI_HEADER -- send a header to the MTA 2564562Sgshapiro** 2664562Sgshapiro** Parameters: 2764562Sgshapiro** ctx -- Opaque context structure 28132943Sgshapiro** cmd -- Header modification command 29132943Sgshapiro** hdridx -- Header index 3064562Sgshapiro** headerf -- Header field name 3164562Sgshapiro** headerv -- Header field value 3264562Sgshapiro** 3364562Sgshapiro** Returns: 3464562Sgshapiro** MI_SUCCESS/MI_FAILURE 3564562Sgshapiro*/ 3664562Sgshapiro 37132943Sgshapirostatic int 38132943Sgshapirosmfi_header(ctx, cmd, hdridx, headerf, headerv) 3964562Sgshapiro SMFICTX *ctx; 40132943Sgshapiro int cmd; 41132943Sgshapiro int hdridx; 4264562Sgshapiro char *headerf; 4364562Sgshapiro char *headerv; 4464562Sgshapiro{ 45132943Sgshapiro size_t len, l1, l2, offset; 4664562Sgshapiro int r; 47132943Sgshapiro mi_int32 v; 4864562Sgshapiro char *buf; 4964562Sgshapiro struct timeval timeout; 5064562Sgshapiro 5164562Sgshapiro if (headerf == NULL || *headerf == '\0' || headerv == NULL) 5264562Sgshapiro return MI_FAILURE; 5364562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 5464562Sgshapiro timeout.tv_usec = 0; 55132943Sgshapiro l1 = strlen(headerf) + 1; 56132943Sgshapiro l2 = strlen(headerv) + 1; 57132943Sgshapiro len = l1 + l2; 58132943Sgshapiro if (hdridx >= 0) 59132943Sgshapiro len += MILTER_LEN_BYTES; 6064562Sgshapiro buf = malloc(len); 6164562Sgshapiro if (buf == NULL) 6264562Sgshapiro return MI_FAILURE; 63132943Sgshapiro offset = 0; 64132943Sgshapiro if (hdridx >= 0) 65132943Sgshapiro { 66132943Sgshapiro v = htonl(hdridx); 67132943Sgshapiro (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES); 68132943Sgshapiro offset += MILTER_LEN_BYTES; 69132943Sgshapiro } 70132943Sgshapiro (void) memcpy(buf + offset, headerf, l1); 71132943Sgshapiro (void) memcpy(buf + offset + l1, headerv, l2); 72132943Sgshapiro r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len); 7364562Sgshapiro free(buf); 7464562Sgshapiro return r; 7564562Sgshapiro} 7664562Sgshapiro 7764562Sgshapiro/* 78132943Sgshapiro** SMFI_ADDHEADER -- send a new header to the MTA 79132943Sgshapiro** 80132943Sgshapiro** Parameters: 81132943Sgshapiro** ctx -- Opaque context structure 82132943Sgshapiro** headerf -- Header field name 83132943Sgshapiro** headerv -- Header field value 84132943Sgshapiro** 85132943Sgshapiro** Returns: 86132943Sgshapiro** MI_SUCCESS/MI_FAILURE 87132943Sgshapiro*/ 88132943Sgshapiro 89132943Sgshapiroint 90132943Sgshapirosmfi_addheader(ctx, headerf, headerv) 91132943Sgshapiro SMFICTX *ctx; 92132943Sgshapiro char *headerf; 93132943Sgshapiro char *headerv; 94132943Sgshapiro{ 95132943Sgshapiro if (!mi_sendok(ctx, SMFIF_ADDHDRS)) 96132943Sgshapiro return MI_FAILURE; 97132943Sgshapiro 98132943Sgshapiro return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv); 99132943Sgshapiro} 100132943Sgshapiro 101132943Sgshapiro/* 102132943Sgshapiro** SMFI_INSHEADER -- send a new header to the MTA (to be inserted) 103132943Sgshapiro** 104132943Sgshapiro** Parameters: 105132943Sgshapiro** ctx -- Opaque context structure 106132943Sgshapiro** hdridx -- index into header list where insertion should occur 107132943Sgshapiro** headerf -- Header field name 108132943Sgshapiro** headerv -- Header field value 109132943Sgshapiro** 110132943Sgshapiro** Returns: 111132943Sgshapiro** MI_SUCCESS/MI_FAILURE 112132943Sgshapiro*/ 113132943Sgshapiro 114132943Sgshapiroint 115132943Sgshapirosmfi_insheader(ctx, hdridx, headerf, headerv) 116132943Sgshapiro SMFICTX *ctx; 117132943Sgshapiro int hdridx; 118132943Sgshapiro char *headerf; 119132943Sgshapiro char *headerv; 120132943Sgshapiro{ 121132943Sgshapiro if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0) 122132943Sgshapiro return MI_FAILURE; 123132943Sgshapiro 124132943Sgshapiro return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv); 125132943Sgshapiro} 126132943Sgshapiro 127132943Sgshapiro/* 12864562Sgshapiro** SMFI_CHGHEADER -- send a changed header to the MTA 12964562Sgshapiro** 13064562Sgshapiro** Parameters: 13164562Sgshapiro** ctx -- Opaque context structure 13264562Sgshapiro** headerf -- Header field name 13364562Sgshapiro** hdridx -- Header index value 13464562Sgshapiro** headerv -- Header field value 13564562Sgshapiro** 13664562Sgshapiro** Returns: 13764562Sgshapiro** MI_SUCCESS/MI_FAILURE 13864562Sgshapiro*/ 13964562Sgshapiro 14064562Sgshapiroint 14164562Sgshapirosmfi_chgheader(ctx, headerf, hdridx, headerv) 14264562Sgshapiro SMFICTX *ctx; 14364562Sgshapiro char *headerf; 14464562Sgshapiro mi_int32 hdridx; 14564562Sgshapiro char *headerv; 14664562Sgshapiro{ 147132943Sgshapiro if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0) 14864562Sgshapiro return MI_FAILURE; 14964562Sgshapiro if (headerv == NULL) 15064562Sgshapiro headerv = ""; 151132943Sgshapiro 152132943Sgshapiro return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv); 15364562Sgshapiro} 15494334Sgshapiro 155168515Sgshapiro#if 0 15690792Sgshapiro/* 157168515Sgshapiro** BUF_CRT_SEND -- construct buffer to send from arguments 158168515Sgshapiro** 159168515Sgshapiro** Parameters: 160168515Sgshapiro** ctx -- Opaque context structure 161168515Sgshapiro** cmd -- command 162168515Sgshapiro** arg0 -- first argument 163168515Sgshapiro** argv -- list of arguments (NULL terminated) 164168515Sgshapiro** 165168515Sgshapiro** Returns: 166168515Sgshapiro** MI_SUCCESS/MI_FAILURE 167168515Sgshapiro*/ 168168515Sgshapiro 169168515Sgshapirostatic int 170168515Sgshapirobuf_crt_send __P((SMFICTX *, int cmd, char *, char **)); 171168515Sgshapiro 172168515Sgshapirostatic int 173168515Sgshapirobuf_crt_send(ctx, cmd, arg0, argv) 174168515Sgshapiro SMFICTX *ctx; 175168515Sgshapiro int cmd; 176168515Sgshapiro char *arg0; 177168515Sgshapiro char **argv; 178168515Sgshapiro{ 179168515Sgshapiro size_t len, l0, l1, offset; 180168515Sgshapiro int r; 181168515Sgshapiro char *buf, *arg, **argvl; 182168515Sgshapiro struct timeval timeout; 183168515Sgshapiro 184168515Sgshapiro if (arg0 == NULL || *arg0 == '\0') 185168515Sgshapiro return MI_FAILURE; 186168515Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 187168515Sgshapiro timeout.tv_usec = 0; 188168515Sgshapiro l0 = strlen(arg0) + 1; 189168515Sgshapiro len = l0; 190168515Sgshapiro argvl = argv; 191168515Sgshapiro while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0') 192168515Sgshapiro { 193168515Sgshapiro l1 = strlen(arg) + 1; 194168515Sgshapiro len += l1; 195168515Sgshapiro SM_ASSERT(len > l1); 196168515Sgshapiro } 197168515Sgshapiro 198168515Sgshapiro buf = malloc(len); 199168515Sgshapiro if (buf == NULL) 200168515Sgshapiro return MI_FAILURE; 201168515Sgshapiro (void) memcpy(buf, arg0, l0); 202168515Sgshapiro offset = l0; 203168515Sgshapiro 204168515Sgshapiro argvl = argv; 205168515Sgshapiro while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0') 206168515Sgshapiro { 207168515Sgshapiro l1 = strlen(arg) + 1; 208168515Sgshapiro SM_ASSERT(offset < len); 209168515Sgshapiro SM_ASSERT(offset + l1 <= len); 210168515Sgshapiro (void) memcpy(buf + offset, arg, l1); 211168515Sgshapiro offset += l1; 212168515Sgshapiro SM_ASSERT(offset > l1); 213168515Sgshapiro } 214168515Sgshapiro 215168515Sgshapiro r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len); 216168515Sgshapiro free(buf); 217168515Sgshapiro return r; 218168515Sgshapiro} 219168515Sgshapiro#endif /* 0 */ 220168515Sgshapiro 221168515Sgshapiro/* 222168515Sgshapiro** SEND2 -- construct buffer to send from arguments 223168515Sgshapiro** 224168515Sgshapiro** Parameters: 225168515Sgshapiro** ctx -- Opaque context structure 226168515Sgshapiro** cmd -- command 227168515Sgshapiro** arg0 -- first argument 228168515Sgshapiro** argv -- list of arguments (NULL terminated) 229168515Sgshapiro** 230168515Sgshapiro** Returns: 231168515Sgshapiro** MI_SUCCESS/MI_FAILURE 232168515Sgshapiro*/ 233168515Sgshapiro 234168515Sgshapirostatic int 235168515Sgshapirosend2 __P((SMFICTX *, int cmd, char *, char *)); 236168515Sgshapiro 237168515Sgshapirostatic int 238168515Sgshapirosend2(ctx, cmd, arg0, arg1) 239168515Sgshapiro SMFICTX *ctx; 240168515Sgshapiro int cmd; 241168515Sgshapiro char *arg0; 242168515Sgshapiro char *arg1; 243168515Sgshapiro{ 244168515Sgshapiro size_t len, l0, l1, offset; 245168515Sgshapiro int r; 246168515Sgshapiro char *buf; 247168515Sgshapiro struct timeval timeout; 248168515Sgshapiro 249168515Sgshapiro if (arg0 == NULL || *arg0 == '\0') 250168515Sgshapiro return MI_FAILURE; 251168515Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 252168515Sgshapiro timeout.tv_usec = 0; 253168515Sgshapiro l0 = strlen(arg0) + 1; 254168515Sgshapiro len = l0; 255168515Sgshapiro if (arg1 != NULL) 256168515Sgshapiro { 257168515Sgshapiro l1 = strlen(arg1) + 1; 258168515Sgshapiro len += l1; 259168515Sgshapiro SM_ASSERT(len > l1); 260168515Sgshapiro } 261168515Sgshapiro 262168515Sgshapiro buf = malloc(len); 263168515Sgshapiro if (buf == NULL) 264168515Sgshapiro return MI_FAILURE; 265168515Sgshapiro (void) memcpy(buf, arg0, l0); 266168515Sgshapiro offset = l0; 267168515Sgshapiro 268168515Sgshapiro if (arg1 != NULL) 269168515Sgshapiro { 270168515Sgshapiro l1 = strlen(arg1) + 1; 271168515Sgshapiro SM_ASSERT(offset < len); 272168515Sgshapiro SM_ASSERT(offset + l1 <= len); 273168515Sgshapiro (void) memcpy(buf + offset, arg1, l1); 274168515Sgshapiro offset += l1; 275168515Sgshapiro SM_ASSERT(offset > l1); 276168515Sgshapiro } 277168515Sgshapiro 278168515Sgshapiro r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len); 279168515Sgshapiro free(buf); 280168515Sgshapiro return r; 281168515Sgshapiro} 282168515Sgshapiro 283168515Sgshapiro/* 284168515Sgshapiro** SMFI_CHGFROM -- change enveloper sender ("from") address 285168515Sgshapiro** 286168515Sgshapiro** Parameters: 287168515Sgshapiro** ctx -- Opaque context structure 288168515Sgshapiro** from -- new envelope sender address ("MAIL From") 289168515Sgshapiro** args -- ESMTP arguments 290168515Sgshapiro** 291168515Sgshapiro** Returns: 292168515Sgshapiro** MI_SUCCESS/MI_FAILURE 293168515Sgshapiro*/ 294168515Sgshapiro 295168515Sgshapiroint 296168515Sgshapirosmfi_chgfrom(ctx, from, args) 297168515Sgshapiro SMFICTX *ctx; 298168515Sgshapiro char *from; 299168515Sgshapiro char *args; 300168515Sgshapiro{ 301168515Sgshapiro if (from == NULL || *from == '\0') 302168515Sgshapiro return MI_FAILURE; 303168515Sgshapiro if (!mi_sendok(ctx, SMFIF_CHGFROM)) 304168515Sgshapiro return MI_FAILURE; 305168515Sgshapiro return send2(ctx, SMFIR_CHGFROM, from, args); 306168515Sgshapiro} 307168515Sgshapiro 308168515Sgshapiro/* 309168515Sgshapiro** SMFI_SETSYMLIST -- set list of macros that the MTA should send. 310168515Sgshapiro** 311168515Sgshapiro** Parameters: 312168515Sgshapiro** ctx -- Opaque context structure 313168515Sgshapiro** where -- SMTP stage 314168515Sgshapiro** macros -- list of macros 315168515Sgshapiro** 316168515Sgshapiro** Returns: 317168515Sgshapiro** MI_SUCCESS/MI_FAILURE 318168515Sgshapiro*/ 319168515Sgshapiro 320168515Sgshapiroint 321168515Sgshapirosmfi_setsymlist(ctx, where, macros) 322168515Sgshapiro SMFICTX *ctx; 323168515Sgshapiro int where; 324168515Sgshapiro char *macros; 325168515Sgshapiro{ 326168515Sgshapiro SM_ASSERT(ctx != NULL); 327168515Sgshapiro 328168515Sgshapiro if (macros == NULL || *macros == '\0') 329168515Sgshapiro return MI_FAILURE; 330168515Sgshapiro if (where < SMFIM_FIRST || where > SMFIM_LAST) 331168515Sgshapiro return MI_FAILURE; 332168515Sgshapiro if (where < 0 || where >= MAX_MACROS_ENTRIES) 333168515Sgshapiro return MI_FAILURE; 334168515Sgshapiro 335168515Sgshapiro if (ctx->ctx_mac_list[where] != NULL) 336168515Sgshapiro return MI_FAILURE; 337168515Sgshapiro 338168515Sgshapiro ctx->ctx_mac_list[where] = strdup(macros); 339168515Sgshapiro if (ctx->ctx_mac_list[where] == NULL) 340168515Sgshapiro return MI_FAILURE; 341168515Sgshapiro 342168515Sgshapiro return MI_SUCCESS; 343168515Sgshapiro} 344168515Sgshapiro 345168515Sgshapiro/* 346168515Sgshapiro** SMFI_ADDRCPT_PAR -- send an additional recipient to the MTA 347168515Sgshapiro** 348168515Sgshapiro** Parameters: 349168515Sgshapiro** ctx -- Opaque context structure 350168515Sgshapiro** rcpt -- recipient address 351168515Sgshapiro** args -- ESMTP arguments 352168515Sgshapiro** 353168515Sgshapiro** Returns: 354168515Sgshapiro** MI_SUCCESS/MI_FAILURE 355168515Sgshapiro*/ 356168515Sgshapiro 357168515Sgshapiroint 358168515Sgshapirosmfi_addrcpt_par(ctx, rcpt, args) 359168515Sgshapiro SMFICTX *ctx; 360168515Sgshapiro char *rcpt; 361168515Sgshapiro char *args; 362168515Sgshapiro{ 363168515Sgshapiro if (rcpt == NULL || *rcpt == '\0') 364168515Sgshapiro return MI_FAILURE; 365168515Sgshapiro if (!mi_sendok(ctx, SMFIF_ADDRCPT_PAR)) 366168515Sgshapiro return MI_FAILURE; 367168515Sgshapiro return send2(ctx, SMFIR_ADDRCPT_PAR, rcpt, args); 368168515Sgshapiro} 369168515Sgshapiro 370168515Sgshapiro/* 37164562Sgshapiro** SMFI_ADDRCPT -- send an additional recipient to the MTA 37264562Sgshapiro** 37364562Sgshapiro** Parameters: 37464562Sgshapiro** ctx -- Opaque context structure 37564562Sgshapiro** rcpt -- recipient address 37664562Sgshapiro** 37764562Sgshapiro** Returns: 37864562Sgshapiro** MI_SUCCESS/MI_FAILURE 37964562Sgshapiro*/ 38064562Sgshapiro 38164562Sgshapiroint 38264562Sgshapirosmfi_addrcpt(ctx, rcpt) 38364562Sgshapiro SMFICTX *ctx; 38464562Sgshapiro char *rcpt; 38564562Sgshapiro{ 38664562Sgshapiro size_t len; 38764562Sgshapiro struct timeval timeout; 38864562Sgshapiro 38964562Sgshapiro if (rcpt == NULL || *rcpt == '\0') 39064562Sgshapiro return MI_FAILURE; 39164562Sgshapiro if (!mi_sendok(ctx, SMFIF_ADDRCPT)) 39264562Sgshapiro return MI_FAILURE; 39364562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 39464562Sgshapiro timeout.tv_usec = 0; 39564562Sgshapiro len = strlen(rcpt) + 1; 39664562Sgshapiro return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len); 39764562Sgshapiro} 39894334Sgshapiro 39990792Sgshapiro/* 40064562Sgshapiro** SMFI_DELRCPT -- send a recipient to be removed to the MTA 40164562Sgshapiro** 40264562Sgshapiro** Parameters: 40364562Sgshapiro** ctx -- Opaque context structure 40464562Sgshapiro** rcpt -- recipient address 40564562Sgshapiro** 40664562Sgshapiro** Returns: 40764562Sgshapiro** MI_SUCCESS/MI_FAILURE 40864562Sgshapiro*/ 40964562Sgshapiro 41064562Sgshapiroint 41164562Sgshapirosmfi_delrcpt(ctx, rcpt) 41264562Sgshapiro SMFICTX *ctx; 41364562Sgshapiro char *rcpt; 41464562Sgshapiro{ 41564562Sgshapiro size_t len; 41664562Sgshapiro struct timeval timeout; 41764562Sgshapiro 41864562Sgshapiro if (rcpt == NULL || *rcpt == '\0') 41964562Sgshapiro return MI_FAILURE; 42064562Sgshapiro if (!mi_sendok(ctx, SMFIF_DELRCPT)) 42164562Sgshapiro return MI_FAILURE; 42264562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 42364562Sgshapiro timeout.tv_usec = 0; 42464562Sgshapiro len = strlen(rcpt) + 1; 42564562Sgshapiro return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len); 42664562Sgshapiro} 42794334Sgshapiro 42890792Sgshapiro/* 42964562Sgshapiro** SMFI_REPLACEBODY -- send a body chunk to the MTA 43064562Sgshapiro** 43164562Sgshapiro** Parameters: 43264562Sgshapiro** ctx -- Opaque context structure 43364562Sgshapiro** bodyp -- body chunk 43464562Sgshapiro** bodylen -- length of body chunk 43564562Sgshapiro** 43664562Sgshapiro** Returns: 43764562Sgshapiro** MI_SUCCESS/MI_FAILURE 43864562Sgshapiro*/ 43964562Sgshapiro 44064562Sgshapiroint 44164562Sgshapirosmfi_replacebody(ctx, bodyp, bodylen) 44264562Sgshapiro SMFICTX *ctx; 44390792Sgshapiro unsigned char *bodyp; 44464562Sgshapiro int bodylen; 44564562Sgshapiro{ 44664562Sgshapiro int len, off, r; 44764562Sgshapiro struct timeval timeout; 44864562Sgshapiro 44990792Sgshapiro if (bodylen < 0 || 45090792Sgshapiro (bodyp == NULL && bodylen > 0)) 45164562Sgshapiro return MI_FAILURE; 45264562Sgshapiro if (!mi_sendok(ctx, SMFIF_CHGBODY)) 45364562Sgshapiro return MI_FAILURE; 45464562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 45564562Sgshapiro timeout.tv_usec = 0; 45664562Sgshapiro 45764562Sgshapiro /* split body chunk if necessary */ 45864562Sgshapiro off = 0; 459157001Sgshapiro do 46064562Sgshapiro { 46164562Sgshapiro len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE : 46264562Sgshapiro bodylen; 46364562Sgshapiro if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY, 46464562Sgshapiro (char *) (bodyp + off), len)) != MI_SUCCESS) 46564562Sgshapiro return r; 46664562Sgshapiro off += len; 46764562Sgshapiro bodylen -= len; 468157001Sgshapiro } while (bodylen > 0); 46964562Sgshapiro return MI_SUCCESS; 47064562Sgshapiro} 47194334Sgshapiro 47290792Sgshapiro/* 47390792Sgshapiro** SMFI_QUARANTINE -- quarantine an envelope 47490792Sgshapiro** 47590792Sgshapiro** Parameters: 47690792Sgshapiro** ctx -- Opaque context structure 47790792Sgshapiro** reason -- why? 47890792Sgshapiro** 47990792Sgshapiro** Returns: 48090792Sgshapiro** MI_SUCCESS/MI_FAILURE 48190792Sgshapiro*/ 48290792Sgshapiro 48390792Sgshapiroint 48490792Sgshapirosmfi_quarantine(ctx, reason) 48590792Sgshapiro SMFICTX *ctx; 48690792Sgshapiro char *reason; 48790792Sgshapiro{ 48890792Sgshapiro size_t len; 48990792Sgshapiro int r; 49090792Sgshapiro char *buf; 49190792Sgshapiro struct timeval timeout; 49290792Sgshapiro 49390792Sgshapiro if (reason == NULL || *reason == '\0') 49490792Sgshapiro return MI_FAILURE; 49590792Sgshapiro if (!mi_sendok(ctx, SMFIF_QUARANTINE)) 49690792Sgshapiro return MI_FAILURE; 49790792Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 49890792Sgshapiro timeout.tv_usec = 0; 49990792Sgshapiro len = strlen(reason) + 1; 50090792Sgshapiro buf = malloc(len); 50190792Sgshapiro if (buf == NULL) 50290792Sgshapiro return MI_FAILURE; 50390792Sgshapiro (void) memcpy(buf, reason, len); 50490792Sgshapiro r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len); 50590792Sgshapiro free(buf); 50690792Sgshapiro return r; 50790792Sgshapiro} 50890792Sgshapiro 50990792Sgshapiro/* 51064562Sgshapiro** MYISENHSC -- check whether a string contains an enhanced status code 51164562Sgshapiro** 51264562Sgshapiro** Parameters: 51364562Sgshapiro** s -- string with possible enhanced status code. 51464562Sgshapiro** delim -- delim for enhanced status code. 51564562Sgshapiro** 51664562Sgshapiro** Returns: 51764562Sgshapiro** 0 -- no enhanced status code. 51864562Sgshapiro** >4 -- length of enhanced status code. 51964562Sgshapiro** 52064562Sgshapiro** Side Effects: 52164562Sgshapiro** none. 52264562Sgshapiro*/ 52398121Sgshapiro 52464562Sgshapirostatic int 52564562Sgshapiromyisenhsc(s, delim) 52664562Sgshapiro const char *s; 52764562Sgshapiro int delim; 52864562Sgshapiro{ 52964562Sgshapiro int l, h; 53064562Sgshapiro 53164562Sgshapiro if (s == NULL) 53264562Sgshapiro return 0; 53364562Sgshapiro if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 53464562Sgshapiro return 0; 53564562Sgshapiro h = 0; 53664562Sgshapiro l = 2; 53764562Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 53864562Sgshapiro ++h; 53964562Sgshapiro if (h == 0 || s[l + h] != '.') 54064562Sgshapiro return 0; 54164562Sgshapiro l += h + 1; 54264562Sgshapiro h = 0; 54364562Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 54464562Sgshapiro ++h; 54564562Sgshapiro if (h == 0 || s[l + h] != delim) 54664562Sgshapiro return 0; 54764562Sgshapiro return l + h; 54864562Sgshapiro} 54990792Sgshapiro 55090792Sgshapiro/* 55164562Sgshapiro** SMFI_SETREPLY -- set the reply code for the next reply to the MTA 55264562Sgshapiro** 55364562Sgshapiro** Parameters: 55464562Sgshapiro** ctx -- Opaque context structure 55564562Sgshapiro** rcode -- The three-digit (RFC 821) SMTP reply code. 55664562Sgshapiro** xcode -- The extended (RFC 2034) reply code. 55764562Sgshapiro** message -- The text part of the SMTP reply. 55864562Sgshapiro** 55964562Sgshapiro** Returns: 56064562Sgshapiro** MI_SUCCESS/MI_FAILURE 56164562Sgshapiro*/ 56264562Sgshapiro 56364562Sgshapiroint 56464562Sgshapirosmfi_setreply(ctx, rcode, xcode, message) 56564562Sgshapiro SMFICTX *ctx; 56664562Sgshapiro char *rcode; 56764562Sgshapiro char *xcode; 56864562Sgshapiro char *message; 56964562Sgshapiro{ 57090792Sgshapiro size_t len; 57164562Sgshapiro char *buf; 57264562Sgshapiro 57364562Sgshapiro if (rcode == NULL || ctx == NULL) 57464562Sgshapiro return MI_FAILURE; 57590792Sgshapiro 57690792Sgshapiro /* ### <sp> \0 */ 57790792Sgshapiro len = strlen(rcode) + 2; 57890792Sgshapiro if (len != 5) 57964562Sgshapiro return MI_FAILURE; 58064562Sgshapiro if ((rcode[0] != '4' && rcode[0] != '5') || 58164562Sgshapiro !isascii(rcode[1]) || !isdigit(rcode[1]) || 58264562Sgshapiro !isascii(rcode[2]) || !isdigit(rcode[2])) 58364562Sgshapiro return MI_FAILURE; 58490792Sgshapiro if (xcode != NULL) 58590792Sgshapiro { 58690792Sgshapiro if (!myisenhsc(xcode, '\0')) 58790792Sgshapiro return MI_FAILURE; 58890792Sgshapiro len += strlen(xcode) + 1; 58990792Sgshapiro } 59090792Sgshapiro if (message != NULL) 59190792Sgshapiro { 59290792Sgshapiro size_t ml; 59390792Sgshapiro 59490792Sgshapiro /* XXX check also for unprintable chars? */ 59590792Sgshapiro if (strpbrk(message, "\r\n") != NULL) 59690792Sgshapiro return MI_FAILURE; 59790792Sgshapiro ml = strlen(message); 59890792Sgshapiro if (ml > MAXREPLYLEN) 59990792Sgshapiro return MI_FAILURE; 60090792Sgshapiro len += ml + 1; 60190792Sgshapiro } 60290792Sgshapiro buf = malloc(len); 60390792Sgshapiro if (buf == NULL) 60490792Sgshapiro return MI_FAILURE; /* oops */ 60590792Sgshapiro (void) sm_strlcpy(buf, rcode, len); 60690792Sgshapiro (void) sm_strlcat(buf, " ", len); 60790792Sgshapiro if (xcode != NULL) 60890792Sgshapiro (void) sm_strlcat(buf, xcode, len); 60990792Sgshapiro if (message != NULL) 61090792Sgshapiro { 61190792Sgshapiro if (xcode != NULL) 61290792Sgshapiro (void) sm_strlcat(buf, " ", len); 61390792Sgshapiro (void) sm_strlcat(buf, message, len); 61490792Sgshapiro } 61590792Sgshapiro if (ctx->ctx_reply != NULL) 61690792Sgshapiro free(ctx->ctx_reply); 61790792Sgshapiro ctx->ctx_reply = buf; 61890792Sgshapiro return MI_SUCCESS; 61990792Sgshapiro} 62090792Sgshapiro 62190792Sgshapiro/* 62290792Sgshapiro** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA 62390792Sgshapiro** 62490792Sgshapiro** Parameters: 62590792Sgshapiro** ctx -- Opaque context structure 62690792Sgshapiro** rcode -- The three-digit (RFC 821) SMTP reply code. 62790792Sgshapiro** xcode -- The extended (RFC 2034) reply code. 62890792Sgshapiro** txt, ... -- The text part of the SMTP reply, 62990792Sgshapiro** MUST be terminated with NULL. 63090792Sgshapiro** 63190792Sgshapiro** Returns: 63290792Sgshapiro** MI_SUCCESS/MI_FAILURE 63390792Sgshapiro*/ 63490792Sgshapiro 63590792Sgshapiroint 63690792Sgshapiro#if SM_VA_STD 63790792Sgshapirosmfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...) 63890792Sgshapiro#else /* SM_VA_STD */ 63990792Sgshapirosmfi_setmlreply(ctx, rcode, xcode, va_alist) 64090792Sgshapiro SMFICTX *ctx; 64190792Sgshapiro const char *rcode; 64290792Sgshapiro const char *xcode; 64390792Sgshapiro va_dcl 64490792Sgshapiro#endif /* SM_VA_STD */ 64590792Sgshapiro{ 64690792Sgshapiro size_t len; 64790792Sgshapiro size_t rlen; 64890792Sgshapiro int args; 64990792Sgshapiro char *buf, *txt; 65090792Sgshapiro const char *xc; 65190792Sgshapiro char repl[16]; 65290792Sgshapiro SM_VA_LOCAL_DECL 65390792Sgshapiro 65490792Sgshapiro if (rcode == NULL || ctx == NULL) 65564562Sgshapiro return MI_FAILURE; 65690792Sgshapiro 65790792Sgshapiro /* ### <sp> */ 65890792Sgshapiro len = strlen(rcode) + 1; 65990792Sgshapiro if (len != 4) 66090792Sgshapiro return MI_FAILURE; 66190792Sgshapiro if ((rcode[0] != '4' && rcode[0] != '5') || 66290792Sgshapiro !isascii(rcode[1]) || !isdigit(rcode[1]) || 66390792Sgshapiro !isascii(rcode[2]) || !isdigit(rcode[2])) 66490792Sgshapiro return MI_FAILURE; 66590792Sgshapiro if (xcode != NULL) 66690792Sgshapiro { 66790792Sgshapiro if (!myisenhsc(xcode, '\0')) 66890792Sgshapiro return MI_FAILURE; 66990792Sgshapiro xc = xcode; 67090792Sgshapiro } 67190792Sgshapiro else 67290792Sgshapiro { 67390792Sgshapiro if (rcode[0] == '4') 67490792Sgshapiro xc = "4.0.0"; 67590792Sgshapiro else 67690792Sgshapiro xc = "5.0.0"; 67790792Sgshapiro } 67890792Sgshapiro 67990792Sgshapiro /* add trailing space */ 68090792Sgshapiro len += strlen(xc) + 1; 68190792Sgshapiro rlen = len; 68290792Sgshapiro args = 0; 68390792Sgshapiro SM_VA_START(ap, xcode); 68490792Sgshapiro while ((txt = SM_VA_ARG(ap, char *)) != NULL) 68590792Sgshapiro { 68690792Sgshapiro size_t tl; 68790792Sgshapiro 68890792Sgshapiro tl = strlen(txt); 68990792Sgshapiro if (tl > MAXREPLYLEN) 69094334Sgshapiro break; 69190792Sgshapiro 69290792Sgshapiro /* this text, reply codes, \r\n */ 69390792Sgshapiro len += tl + 2 + rlen; 69490792Sgshapiro if (++args > MAXREPLIES) 69594334Sgshapiro break; 69690792Sgshapiro 69790792Sgshapiro /* XXX check also for unprintable chars? */ 69890792Sgshapiro if (strpbrk(txt, "\r\n") != NULL) 69994334Sgshapiro break; 70090792Sgshapiro } 70190792Sgshapiro SM_VA_END(ap); 70294334Sgshapiro if (txt != NULL) 70394334Sgshapiro return MI_FAILURE; 70490792Sgshapiro 70590792Sgshapiro /* trailing '\0' */ 70690792Sgshapiro ++len; 70764562Sgshapiro buf = malloc(len); 70864562Sgshapiro if (buf == NULL) 70964562Sgshapiro return MI_FAILURE; /* oops */ 71090792Sgshapiro (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc); 71190792Sgshapiro (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-", 71290792Sgshapiro xc, " "); 71390792Sgshapiro SM_VA_START(ap, xcode); 71490792Sgshapiro txt = SM_VA_ARG(ap, char *); 71590792Sgshapiro if (txt != NULL) 71690792Sgshapiro { 71790792Sgshapiro (void) sm_strlcat2(buf, " ", txt, len); 71890792Sgshapiro while ((txt = SM_VA_ARG(ap, char *)) != NULL) 71990792Sgshapiro { 72090792Sgshapiro if (--args <= 1) 72190792Sgshapiro repl[3] = ' '; 72290792Sgshapiro (void) sm_strlcat2(buf, "\r\n", repl, len); 72390792Sgshapiro (void) sm_strlcat(buf, txt, len); 72490792Sgshapiro } 72590792Sgshapiro } 72664562Sgshapiro if (ctx->ctx_reply != NULL) 72764562Sgshapiro free(ctx->ctx_reply); 72864562Sgshapiro ctx->ctx_reply = buf; 72990792Sgshapiro SM_VA_END(ap); 73064562Sgshapiro return MI_SUCCESS; 73164562Sgshapiro} 73290792Sgshapiro 73390792Sgshapiro/* 73464562Sgshapiro** SMFI_SETPRIV -- set private data 73564562Sgshapiro** 73664562Sgshapiro** Parameters: 73764562Sgshapiro** ctx -- Opaque context structure 73864562Sgshapiro** privatedata -- pointer to private data 73964562Sgshapiro** 74064562Sgshapiro** Returns: 74164562Sgshapiro** MI_SUCCESS/MI_FAILURE 74264562Sgshapiro*/ 74364562Sgshapiro 74464562Sgshapiroint 74564562Sgshapirosmfi_setpriv(ctx, privatedata) 74664562Sgshapiro SMFICTX *ctx; 74764562Sgshapiro void *privatedata; 74864562Sgshapiro{ 74964562Sgshapiro if (ctx == NULL) 75064562Sgshapiro return MI_FAILURE; 75164562Sgshapiro ctx->ctx_privdata = privatedata; 75264562Sgshapiro return MI_SUCCESS; 75364562Sgshapiro} 75494334Sgshapiro 75590792Sgshapiro/* 75664562Sgshapiro** SMFI_GETPRIV -- get private data 75764562Sgshapiro** 75864562Sgshapiro** Parameters: 75964562Sgshapiro** ctx -- Opaque context structure 76064562Sgshapiro** 76164562Sgshapiro** Returns: 76264562Sgshapiro** pointer to private data 76364562Sgshapiro*/ 76464562Sgshapiro 76564562Sgshapirovoid * 76664562Sgshapirosmfi_getpriv(ctx) 76764562Sgshapiro SMFICTX *ctx; 76864562Sgshapiro{ 76964562Sgshapiro if (ctx == NULL) 77064562Sgshapiro return NULL; 77164562Sgshapiro return ctx->ctx_privdata; 77264562Sgshapiro} 77394334Sgshapiro 77490792Sgshapiro/* 77564562Sgshapiro** SMFI_GETSYMVAL -- get the value of a macro 77664562Sgshapiro** 77764562Sgshapiro** See explanation in mfapi.h about layout of the structures. 77864562Sgshapiro** 77964562Sgshapiro** Parameters: 78064562Sgshapiro** ctx -- Opaque context structure 78164562Sgshapiro** symname -- name of macro 78264562Sgshapiro** 78364562Sgshapiro** Returns: 78464562Sgshapiro** value of macro (NULL in case of failure) 78564562Sgshapiro*/ 78664562Sgshapiro 78764562Sgshapirochar * 78864562Sgshapirosmfi_getsymval(ctx, symname) 78964562Sgshapiro SMFICTX *ctx; 79064562Sgshapiro char *symname; 79164562Sgshapiro{ 79264562Sgshapiro int i; 79364562Sgshapiro char **s; 79464562Sgshapiro char one[2]; 79564562Sgshapiro char braces[4]; 79664562Sgshapiro 79764562Sgshapiro if (ctx == NULL || symname == NULL || *symname == '\0') 79864562Sgshapiro return NULL; 79964562Sgshapiro 80064562Sgshapiro if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}') 80164562Sgshapiro { 80264562Sgshapiro one[0] = symname[1]; 80364562Sgshapiro one[1] = '\0'; 80464562Sgshapiro } 80564562Sgshapiro else 80664562Sgshapiro one[0] = '\0'; 80764562Sgshapiro if (strlen(symname) == 1) 80864562Sgshapiro { 80964562Sgshapiro braces[0] = '{'; 81064562Sgshapiro braces[1] = *symname; 81164562Sgshapiro braces[2] = '}'; 81264562Sgshapiro braces[3] = '\0'; 81364562Sgshapiro } 81464562Sgshapiro else 81564562Sgshapiro braces[0] = '\0'; 81664562Sgshapiro 81764562Sgshapiro /* search backwards through the macro array */ 81864562Sgshapiro for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i) 81964562Sgshapiro { 82064562Sgshapiro if ((s = ctx->ctx_mac_ptr[i]) == NULL || 82164562Sgshapiro ctx->ctx_mac_buf[i] == NULL) 82264562Sgshapiro continue; 82364562Sgshapiro while (s != NULL && *s != NULL) 82464562Sgshapiro { 82564562Sgshapiro if (strcmp(*s, symname) == 0) 82664562Sgshapiro return *++s; 82764562Sgshapiro if (one[0] != '\0' && strcmp(*s, one) == 0) 82864562Sgshapiro return *++s; 82964562Sgshapiro if (braces[0] != '\0' && strcmp(*s, braces) == 0) 83064562Sgshapiro return *++s; 83164562Sgshapiro ++s; /* skip over macro value */ 83264562Sgshapiro ++s; /* points to next macro name */ 83364562Sgshapiro } 83464562Sgshapiro } 83564562Sgshapiro return NULL; 83664562Sgshapiro} 83794334Sgshapiro 83894334Sgshapiro/* 83994334Sgshapiro** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature 84094334Sgshapiro** timeouts during long milter-side operations 84194334Sgshapiro** 84294334Sgshapiro** Parameters: 84394334Sgshapiro** ctx -- Opaque context structure 84494334Sgshapiro** 84594334Sgshapiro** Return value: 84694334Sgshapiro** MI_SUCCESS/MI_FAILURE 84794334Sgshapiro*/ 84894334Sgshapiro 84994334Sgshapiroint 85094334Sgshapirosmfi_progress(ctx) 85194334Sgshapiro SMFICTX *ctx; 85294334Sgshapiro{ 85394334Sgshapiro struct timeval timeout; 85494334Sgshapiro 85594334Sgshapiro if (ctx == NULL) 85694334Sgshapiro return MI_FAILURE; 85794334Sgshapiro 85894334Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 85994334Sgshapiro timeout.tv_usec = 0; 86094334Sgshapiro 86194334Sgshapiro return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0); 86294334Sgshapiro} 863168515Sgshapiro 864168515Sgshapiro/* 865168515Sgshapiro** SMFI_VERSION -- return (runtime) version of libmilter 866168515Sgshapiro** 867168515Sgshapiro** Parameters: 868168515Sgshapiro** major -- (pointer to) major version 869168515Sgshapiro** minor -- (pointer to) minor version 870168515Sgshapiro** patchlevel -- (pointer to) patchlevel version 871168515Sgshapiro** 872168515Sgshapiro** Return value: 873168515Sgshapiro** MI_SUCCESS 874168515Sgshapiro*/ 875168515Sgshapiro 876168515Sgshapiroint 877168515Sgshapirosmfi_version(major, minor, patchlevel) 878168515Sgshapiro unsigned int *major; 879168515Sgshapiro unsigned int *minor; 880168515Sgshapiro unsigned int *patchlevel; 881168515Sgshapiro{ 882168515Sgshapiro if (major != NULL) 883168515Sgshapiro *major = SM_LM_VRS_MAJOR(SMFI_VERSION); 884168515Sgshapiro if (minor != NULL) 885168515Sgshapiro *minor = SM_LM_VRS_MINOR(SMFI_VERSION); 886168515Sgshapiro if (patchlevel != NULL) 887173340Sgshapiro *patchlevel = SM_LM_VRS_PLVL(SMFI_VERSION); 888168515Sgshapiro return MI_SUCCESS; 889168515Sgshapiro} 890