2 * Copyright (c) 1999-2007 Sendmail, 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.83 2007/04/23 16:44:39 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 l1 = strlen(arg1) + 1;
271 SM_ASSERT(offset < len);
272 SM_ASSERT(offset + l1 <= len);
273 (void) memcpy(buf + offset, arg1, l1);
275 SM_ASSERT(offset > l1);
278 r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
284 ** SMFI_CHGFROM -- change enveloper sender ("from") address
287 ** ctx -- Opaque context structure
288 ** from -- new envelope sender address ("MAIL From")
289 ** args -- ESMTP arguments
292 ** MI_SUCCESS/MI_FAILURE
296 smfi_chgfrom(ctx, from, args)
301 if (from == NULL || *from == '\0')
303 if (!mi_sendok(ctx, SMFIF_CHGFROM))
305 return send2(ctx, SMFIR_CHGFROM, from, args);
309 ** SMFI_SETSYMLIST -- set list of macros that the MTA should send.
312 ** ctx -- Opaque context structure
313 ** where -- SMTP stage
314 ** macros -- list of macros
317 ** MI_SUCCESS/MI_FAILURE
321 smfi_setsymlist(ctx, where, macros)
326 SM_ASSERT(ctx != NULL);
328 if (macros == NULL || *macros == '\0')
330 if (where < SMFIM_FIRST || where > SMFIM_LAST)
332 if (where < 0 || where >= MAX_MACROS_ENTRIES)
335 if (ctx->ctx_mac_list[where] != NULL)
338 ctx->ctx_mac_list[where] = strdup(macros);
339 if (ctx->ctx_mac_list[where] == NULL)
346 ** SMFI_ADDRCPT_PAR -- send an additional recipient to the MTA
349 ** ctx -- Opaque context structure
350 ** rcpt -- recipient address
351 ** args -- ESMTP arguments
354 ** MI_SUCCESS/MI_FAILURE
358 smfi_addrcpt_par(ctx, rcpt, args)
363 if (rcpt == NULL || *rcpt == '\0')
365 if (!mi_sendok(ctx, SMFIF_ADDRCPT_PAR))
367 return send2(ctx, SMFIR_ADDRCPT_PAR, rcpt, args);
371 ** SMFI_ADDRCPT -- send an additional recipient to the MTA
374 ** ctx -- Opaque context structure
375 ** rcpt -- recipient address
378 ** MI_SUCCESS/MI_FAILURE
382 smfi_addrcpt(ctx, rcpt)
387 struct timeval timeout;
389 if (rcpt == NULL || *rcpt == '\0')
391 if (!mi_sendok(ctx, SMFIF_ADDRCPT))
393 timeout.tv_sec = ctx->ctx_timeout;
395 len = strlen(rcpt) + 1;
396 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
400 ** SMFI_DELRCPT -- send a recipient to be removed to the MTA
403 ** ctx -- Opaque context structure
404 ** rcpt -- recipient address
407 ** MI_SUCCESS/MI_FAILURE
411 smfi_delrcpt(ctx, rcpt)
416 struct timeval timeout;
418 if (rcpt == NULL || *rcpt == '\0')
420 if (!mi_sendok(ctx, SMFIF_DELRCPT))
422 timeout.tv_sec = ctx->ctx_timeout;
424 len = strlen(rcpt) + 1;
425 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
429 ** SMFI_REPLACEBODY -- send a body chunk to the MTA
432 ** ctx -- Opaque context structure
433 ** bodyp -- body chunk
434 ** bodylen -- length of body chunk
437 ** MI_SUCCESS/MI_FAILURE
441 smfi_replacebody(ctx, bodyp, bodylen)
443 unsigned char *bodyp;
447 struct timeval timeout;
450 (bodyp == NULL && bodylen > 0))
452 if (!mi_sendok(ctx, SMFIF_CHGBODY))
454 timeout.tv_sec = ctx->ctx_timeout;
457 /* split body chunk if necessary */
461 len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
463 if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
464 (char *) (bodyp + off), len)) != MI_SUCCESS)
468 } while (bodylen > 0);
473 ** SMFI_QUARANTINE -- quarantine an envelope
476 ** ctx -- Opaque context structure
480 ** MI_SUCCESS/MI_FAILURE
484 smfi_quarantine(ctx, reason)
491 struct timeval timeout;
493 if (reason == NULL || *reason == '\0')
495 if (!mi_sendok(ctx, SMFIF_QUARANTINE))
497 timeout.tv_sec = ctx->ctx_timeout;
499 len = strlen(reason) + 1;
503 (void) memcpy(buf, reason, len);
504 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len);
510 ** MYISENHSC -- check whether a string contains an enhanced status code
513 ** s -- string with possible enhanced status code.
514 ** delim -- delim for enhanced status code.
517 ** 0 -- no enhanced status code.
518 ** >4 -- length of enhanced status code.
533 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
537 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
539 if (h == 0 || s[l + h] != '.')
543 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
545 if (h == 0 || s[l + h] != delim)
551 ** SMFI_SETREPLY -- set the reply code for the next reply to the MTA
554 ** ctx -- Opaque context structure
555 ** rcode -- The three-digit (RFC 821) SMTP reply code.
556 ** xcode -- The extended (RFC 2034) reply code.
557 ** message -- The text part of the SMTP reply.
560 ** MI_SUCCESS/MI_FAILURE
564 smfi_setreply(ctx, rcode, xcode, message)
573 if (rcode == NULL || ctx == NULL)
577 len = strlen(rcode) + 2;
580 if ((rcode[0] != '4' && rcode[0] != '5') ||
581 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
582 !isascii(rcode[2]) || !isdigit(rcode[2]))
586 if (!myisenhsc(xcode, '\0'))
588 len += strlen(xcode) + 1;
594 /* XXX check also for unprintable chars? */
595 if (strpbrk(message, "\r\n") != NULL)
597 ml = strlen(message);
598 if (ml > MAXREPLYLEN)
604 return MI_FAILURE; /* oops */
605 (void) sm_strlcpy(buf, rcode, len);
606 (void) sm_strlcat(buf, " ", len);
608 (void) sm_strlcat(buf, xcode, len);
612 (void) sm_strlcat(buf, " ", len);
613 (void) sm_strlcat(buf, message, len);
615 if (ctx->ctx_reply != NULL)
616 free(ctx->ctx_reply);
617 ctx->ctx_reply = buf;
622 ** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA
625 ** ctx -- Opaque context structure
626 ** rcode -- The three-digit (RFC 821) SMTP reply code.
627 ** xcode -- The extended (RFC 2034) reply code.
628 ** txt, ... -- The text part of the SMTP reply,
629 ** MUST be terminated with NULL.
632 ** MI_SUCCESS/MI_FAILURE
637 smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
638 #else /* SM_VA_STD */
639 smfi_setmlreply(ctx, rcode, xcode, va_alist)
644 #endif /* SM_VA_STD */
654 if (rcode == NULL || ctx == NULL)
658 len = strlen(rcode) + 1;
661 if ((rcode[0] != '4' && rcode[0] != '5') ||
662 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
663 !isascii(rcode[2]) || !isdigit(rcode[2]))
667 if (!myisenhsc(xcode, '\0'))
679 /* add trailing space */
680 len += strlen(xc) + 1;
683 SM_VA_START(ap, xcode);
684 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
689 if (tl > MAXREPLYLEN)
692 /* this text, reply codes, \r\n */
693 len += tl + 2 + rlen;
694 if (++args > MAXREPLIES)
697 /* XXX check also for unprintable chars? */
698 if (strpbrk(txt, "\r\n") != NULL)
709 return MI_FAILURE; /* oops */
710 (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc);
711 (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-",
713 SM_VA_START(ap, xcode);
714 txt = SM_VA_ARG(ap, char *);
717 (void) sm_strlcat2(buf, " ", txt, len);
718 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
722 (void) sm_strlcat2(buf, "\r\n", repl, len);
723 (void) sm_strlcat(buf, txt, len);
726 if (ctx->ctx_reply != NULL)
727 free(ctx->ctx_reply);
728 ctx->ctx_reply = buf;
734 ** SMFI_SETPRIV -- set private data
737 ** ctx -- Opaque context structure
738 ** privatedata -- pointer to private data
741 ** MI_SUCCESS/MI_FAILURE
745 smfi_setpriv(ctx, privatedata)
751 ctx->ctx_privdata = privatedata;
756 ** SMFI_GETPRIV -- get private data
759 ** ctx -- Opaque context structure
762 ** pointer to private data
771 return ctx->ctx_privdata;
775 ** SMFI_GETSYMVAL -- get the value of a macro
777 ** See explanation in mfapi.h about layout of the structures.
780 ** ctx -- Opaque context structure
781 ** symname -- name of macro
784 ** value of macro (NULL in case of failure)
788 smfi_getsymval(ctx, symname)
797 if (ctx == NULL || symname == NULL || *symname == '\0')
800 if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
807 if (strlen(symname) == 1)
810 braces[1] = *symname;
817 /* search backwards through the macro array */
818 for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
820 if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
821 ctx->ctx_mac_buf[i] == NULL)
823 while (s != NULL && *s != NULL)
825 if (strcmp(*s, symname) == 0)
827 if (one[0] != '\0' && strcmp(*s, one) == 0)
829 if (braces[0] != '\0' && strcmp(*s, braces) == 0)
831 ++s; /* skip over macro value */
832 ++s; /* points to next macro name */
839 ** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature
840 ** timeouts during long milter-side operations
843 ** ctx -- Opaque context structure
846 ** MI_SUCCESS/MI_FAILURE
853 struct timeval timeout;
858 timeout.tv_sec = ctx->ctx_timeout;
861 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0);
865 ** SMFI_VERSION -- return (runtime) version of libmilter
868 ** major -- (pointer to) major version
869 ** minor -- (pointer to) minor version
870 ** patchlevel -- (pointer to) patchlevel version
877 smfi_version(major, minor, patchlevel)
880 unsigned int *patchlevel;
883 *major = SM_LM_VRS_MAJOR(SMFI_VERSION);
885 *minor = SM_LM_VRS_MINOR(SMFI_VERSION);
886 if (patchlevel != NULL)
887 *patchlevel = SM_LM_VRS_PLVL(SMFI_VERSION);