2 * Copyright (c) 1999-2007 Proofpoint, Inc. and its suppliers.
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
12 SM_RCSID("@(#)$Id: smfi.c,v 8.84 2013-11-22 20:51:36 ca Exp $")
13 #include <sm/varargs.h>
14 #include "libmilter.h"
16 static int smfi_header __P((SMFICTX *, int, int, char *, char *));
17 static int myisenhsc __P((const char *, int));
19 /* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */
20 #define MAXREPLYLEN 980 /* max. length of a reply string */
21 #define MAXREPLIES 32 /* max. number of reply strings */
24 ** SMFI_HEADER -- send a header to the MTA
27 ** ctx -- Opaque context structure
28 ** cmd -- Header modification command
29 ** hdridx -- Header index
30 ** headerf -- Header field name
31 ** headerv -- Header field value
34 ** MI_SUCCESS/MI_FAILURE
38 smfi_header(ctx, cmd, hdridx, headerf, headerv)
45 size_t len, l1, l2, offset;
49 struct timeval timeout;
51 if (headerf == NULL || *headerf == '\0' || headerv == NULL)
53 timeout.tv_sec = ctx->ctx_timeout;
55 l1 = strlen(headerf) + 1;
56 l2 = strlen(headerv) + 1;
59 len += MILTER_LEN_BYTES;
67 (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
68 offset += MILTER_LEN_BYTES;
70 (void) memcpy(buf + offset, headerf, l1);
71 (void) memcpy(buf + offset + l1, headerv, l2);
72 r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
78 ** SMFI_ADDHEADER -- send a new header to the MTA
81 ** ctx -- Opaque context structure
82 ** headerf -- Header field name
83 ** headerv -- Header field value
86 ** MI_SUCCESS/MI_FAILURE
90 smfi_addheader(ctx, headerf, headerv)
95 if (!mi_sendok(ctx, SMFIF_ADDHDRS))
98 return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv);
102 ** SMFI_INSHEADER -- send a new header to the MTA (to be inserted)
105 ** ctx -- Opaque context structure
106 ** hdridx -- index into header list where insertion should occur
107 ** headerf -- Header field name
108 ** headerv -- Header field value
111 ** MI_SUCCESS/MI_FAILURE
115 smfi_insheader(ctx, hdridx, headerf, headerv)
121 if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0)
124 return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv);
128 ** SMFI_CHGHEADER -- send a changed header to the MTA
131 ** ctx -- Opaque context structure
132 ** headerf -- Header field name
133 ** hdridx -- Header index value
134 ** headerv -- Header field value
137 ** MI_SUCCESS/MI_FAILURE
141 smfi_chgheader(ctx, headerf, hdridx, headerv)
147 if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0)
152 return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv);
157 ** BUF_CRT_SEND -- construct buffer to send from arguments
160 ** ctx -- Opaque context structure
162 ** arg0 -- first argument
163 ** argv -- list of arguments (NULL terminated)
166 ** MI_SUCCESS/MI_FAILURE
170 buf_crt_send __P((SMFICTX *, int cmd, char *, char **));
173 buf_crt_send(ctx, cmd, arg0, argv)
179 size_t len, l0, l1, offset;
181 char *buf, *arg, **argvl;
182 struct timeval timeout;
184 if (arg0 == NULL || *arg0 == '\0')
186 timeout.tv_sec = ctx->ctx_timeout;
188 l0 = strlen(arg0) + 1;
191 while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0')
193 l1 = strlen(arg) + 1;
201 (void) memcpy(buf, arg0, l0);
205 while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0')
207 l1 = strlen(arg) + 1;
208 SM_ASSERT(offset < len);
209 SM_ASSERT(offset + l1 <= len);
210 (void) memcpy(buf + offset, arg, l1);
212 SM_ASSERT(offset > l1);
215 r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
222 ** SEND2 -- construct buffer to send from arguments
225 ** ctx -- Opaque context structure
227 ** arg0 -- first argument
228 ** argv -- list of arguments (NULL terminated)
231 ** MI_SUCCESS/MI_FAILURE
235 send2 __P((SMFICTX *, int cmd, char *, char *));
238 send2(ctx, cmd, arg0, arg1)
244 size_t len, l0, l1, offset;
247 struct timeval timeout;
249 if (arg0 == NULL || *arg0 == '\0')
251 timeout.tv_sec = ctx->ctx_timeout;
253 l0 = strlen(arg0) + 1;
257 l1 = strlen(arg1) + 1;
265 (void) memcpy(buf, arg0, l0);
270 SM_ASSERT(offset < len);
271 SM_ASSERT(offset + l1 <= len);
272 (void) memcpy(buf + offset, arg1, l1);
274 SM_ASSERT(offset > l1);
277 r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
283 ** SMFI_CHGFROM -- change enveloper sender ("from") address
286 ** ctx -- Opaque context structure
287 ** from -- new envelope sender address ("MAIL From")
288 ** args -- ESMTP arguments
291 ** MI_SUCCESS/MI_FAILURE
295 smfi_chgfrom(ctx, from, args)
300 if (from == NULL || *from == '\0')
302 if (!mi_sendok(ctx, SMFIF_CHGFROM))
304 return send2(ctx, SMFIR_CHGFROM, from, args);
308 ** SMFI_SETSYMLIST -- set list of macros that the MTA should send.
311 ** ctx -- Opaque context structure
312 ** where -- SMTP stage
313 ** macros -- list of macros
316 ** MI_SUCCESS/MI_FAILURE
320 smfi_setsymlist(ctx, where, macros)
325 SM_ASSERT(ctx != NULL);
329 if (where < SMFIM_FIRST || where > SMFIM_LAST)
331 if (where < 0 || where >= MAX_MACROS_ENTRIES)
334 if (ctx->ctx_mac_list[where] != NULL)
337 ctx->ctx_mac_list[where] = strdup(macros);
338 if (ctx->ctx_mac_list[where] == NULL)
345 ** SMFI_ADDRCPT_PAR -- send an additional recipient to the MTA
348 ** ctx -- Opaque context structure
349 ** rcpt -- recipient address
350 ** args -- ESMTP arguments
353 ** MI_SUCCESS/MI_FAILURE
357 smfi_addrcpt_par(ctx, rcpt, args)
362 if (rcpt == NULL || *rcpt == '\0')
364 if (!mi_sendok(ctx, SMFIF_ADDRCPT_PAR))
366 return send2(ctx, SMFIR_ADDRCPT_PAR, rcpt, args);
370 ** SMFI_ADDRCPT -- send an additional recipient to the MTA
373 ** ctx -- Opaque context structure
374 ** rcpt -- recipient address
377 ** MI_SUCCESS/MI_FAILURE
381 smfi_addrcpt(ctx, rcpt)
386 struct timeval timeout;
388 if (rcpt == NULL || *rcpt == '\0')
390 if (!mi_sendok(ctx, SMFIF_ADDRCPT))
392 timeout.tv_sec = ctx->ctx_timeout;
394 len = strlen(rcpt) + 1;
395 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
399 ** SMFI_DELRCPT -- send a recipient to be removed to the MTA
402 ** ctx -- Opaque context structure
403 ** rcpt -- recipient address
406 ** MI_SUCCESS/MI_FAILURE
410 smfi_delrcpt(ctx, rcpt)
415 struct timeval timeout;
417 if (rcpt == NULL || *rcpt == '\0')
419 if (!mi_sendok(ctx, SMFIF_DELRCPT))
421 timeout.tv_sec = ctx->ctx_timeout;
423 len = strlen(rcpt) + 1;
424 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
428 ** SMFI_REPLACEBODY -- send a body chunk to the MTA
431 ** ctx -- Opaque context structure
432 ** bodyp -- body chunk
433 ** bodylen -- length of body chunk
436 ** MI_SUCCESS/MI_FAILURE
440 smfi_replacebody(ctx, bodyp, bodylen)
442 unsigned char *bodyp;
446 struct timeval timeout;
449 (bodyp == NULL && bodylen > 0))
451 if (!mi_sendok(ctx, SMFIF_CHGBODY))
453 timeout.tv_sec = ctx->ctx_timeout;
456 /* split body chunk if necessary */
460 len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
462 if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
463 (char *) (bodyp + off), len)) != MI_SUCCESS)
467 } while (bodylen > 0);
472 ** SMFI_QUARANTINE -- quarantine an envelope
475 ** ctx -- Opaque context structure
479 ** MI_SUCCESS/MI_FAILURE
483 smfi_quarantine(ctx, reason)
490 struct timeval timeout;
492 if (reason == NULL || *reason == '\0')
494 if (!mi_sendok(ctx, SMFIF_QUARANTINE))
496 timeout.tv_sec = ctx->ctx_timeout;
498 len = strlen(reason) + 1;
502 (void) memcpy(buf, reason, len);
503 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len);
509 ** MYISENHSC -- check whether a string contains an enhanced status code
512 ** s -- string with possible enhanced status code.
513 ** delim -- delim for enhanced status code.
516 ** 0 -- no enhanced status code.
517 ** >4 -- length of enhanced status code.
532 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
536 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
538 if (h == 0 || s[l + h] != '.')
542 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
544 if (h == 0 || s[l + h] != delim)
550 ** SMFI_SETREPLY -- set the reply code for the next reply to the MTA
553 ** ctx -- Opaque context structure
554 ** rcode -- The three-digit (RFC 821) SMTP reply code.
555 ** xcode -- The extended (RFC 2034) reply code.
556 ** message -- The text part of the SMTP reply.
559 ** MI_SUCCESS/MI_FAILURE
563 smfi_setreply(ctx, rcode, xcode, message)
572 if (rcode == NULL || ctx == NULL)
576 len = strlen(rcode) + 2;
579 if ((rcode[0] != '4' && rcode[0] != '5') ||
580 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
581 !isascii(rcode[2]) || !isdigit(rcode[2]))
585 if (!myisenhsc(xcode, '\0'))
587 len += strlen(xcode) + 1;
593 /* XXX check also for unprintable chars? */
594 if (strpbrk(message, "\r\n") != NULL)
596 ml = strlen(message);
597 if (ml > MAXREPLYLEN)
603 return MI_FAILURE; /* oops */
604 (void) sm_strlcpy(buf, rcode, len);
605 (void) sm_strlcat(buf, " ", len);
607 (void) sm_strlcat(buf, xcode, len);
611 (void) sm_strlcat(buf, " ", len);
612 (void) sm_strlcat(buf, message, len);
614 if (ctx->ctx_reply != NULL)
615 free(ctx->ctx_reply);
616 ctx->ctx_reply = buf;
621 ** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA
624 ** ctx -- Opaque context structure
625 ** rcode -- The three-digit (RFC 821) SMTP reply code.
626 ** xcode -- The extended (RFC 2034) reply code.
627 ** txt, ... -- The text part of the SMTP reply,
628 ** MUST be terminated with NULL.
631 ** MI_SUCCESS/MI_FAILURE
636 smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
637 #else /* SM_VA_STD */
638 smfi_setmlreply(ctx, rcode, xcode, va_alist)
643 #endif /* SM_VA_STD */
653 if (rcode == NULL || ctx == NULL)
657 len = strlen(rcode) + 1;
660 if ((rcode[0] != '4' && rcode[0] != '5') ||
661 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
662 !isascii(rcode[2]) || !isdigit(rcode[2]))
666 if (!myisenhsc(xcode, '\0'))
678 /* add trailing space */
679 len += strlen(xc) + 1;
682 SM_VA_START(ap, xcode);
683 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
688 if (tl > MAXREPLYLEN)
691 /* this text, reply codes, \r\n */
692 len += tl + 2 + rlen;
693 if (++args > MAXREPLIES)
696 /* XXX check also for unprintable chars? */
697 if (strpbrk(txt, "\r\n") != NULL)
708 return MI_FAILURE; /* oops */
709 (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc);
710 (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-",
712 SM_VA_START(ap, xcode);
713 txt = SM_VA_ARG(ap, char *);
716 (void) sm_strlcat2(buf, " ", txt, len);
717 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
721 (void) sm_strlcat2(buf, "\r\n", repl, len);
722 (void) sm_strlcat(buf, txt, len);
725 if (ctx->ctx_reply != NULL)
726 free(ctx->ctx_reply);
727 ctx->ctx_reply = buf;
733 ** SMFI_SETPRIV -- set private data
736 ** ctx -- Opaque context structure
737 ** privatedata -- pointer to private data
740 ** MI_SUCCESS/MI_FAILURE
744 smfi_setpriv(ctx, privatedata)
750 ctx->ctx_privdata = privatedata;
755 ** SMFI_GETPRIV -- get private data
758 ** ctx -- Opaque context structure
761 ** pointer to private data
770 return ctx->ctx_privdata;
774 ** SMFI_GETSYMVAL -- get the value of a macro
776 ** See explanation in mfapi.h about layout of the structures.
779 ** ctx -- Opaque context structure
780 ** symname -- name of macro
783 ** value of macro (NULL in case of failure)
787 smfi_getsymval(ctx, symname)
796 if (ctx == NULL || symname == NULL || *symname == '\0')
799 if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
806 if (strlen(symname) == 1)
809 braces[1] = *symname;
816 /* search backwards through the macro array */
817 for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
819 if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
820 ctx->ctx_mac_buf[i] == NULL)
822 while (s != NULL && *s != NULL)
824 if (strcmp(*s, symname) == 0)
826 if (one[0] != '\0' && strcmp(*s, one) == 0)
828 if (braces[0] != '\0' && strcmp(*s, braces) == 0)
830 ++s; /* skip over macro value */
831 ++s; /* points to next macro name */
838 ** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature
839 ** timeouts during long milter-side operations
842 ** ctx -- Opaque context structure
845 ** MI_SUCCESS/MI_FAILURE
852 struct timeval timeout;
857 timeout.tv_sec = ctx->ctx_timeout;
860 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0);
864 ** SMFI_VERSION -- return (runtime) version of libmilter
867 ** major -- (pointer to) major version
868 ** minor -- (pointer to) minor version
869 ** patchlevel -- (pointer to) patchlevel version
876 smfi_version(major, minor, patchlevel)
879 unsigned int *patchlevel;
882 *major = SM_LM_VRS_MAJOR(SMFI_VERSION);
884 *minor = SM_LM_VRS_MINOR(SMFI_VERSION);
885 if (patchlevel != NULL)
886 *patchlevel = SM_LM_VRS_PLVL(SMFI_VERSION);