17c478bd9Sstevel@tonic-gate /* 2*49218d4fSjbeck * Copyright (c) 1999-2005 Sendmail, Inc. and its suppliers. 37c478bd9Sstevel@tonic-gate * All rights reserved. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 67c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 77c478bd9Sstevel@tonic-gate * the sendmail distribution. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate */ 107c478bd9Sstevel@tonic-gate 117c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 127c478bd9Sstevel@tonic-gate 137c478bd9Sstevel@tonic-gate #include <sm/gen.h> 14*49218d4fSjbeck SM_RCSID("@(#)$Id: smfi.c,v 8.74 2005/03/30 00:44:07 ca Exp $") 157c478bd9Sstevel@tonic-gate #include <sm/varargs.h> 167c478bd9Sstevel@tonic-gate #include "libmilter.h" 177c478bd9Sstevel@tonic-gate 187c478bd9Sstevel@tonic-gate static int smfi_header __P((SMFICTX *, int, int, char *, char *)); 197c478bd9Sstevel@tonic-gate static int myisenhsc __P((const char *, int)); 207c478bd9Sstevel@tonic-gate 217c478bd9Sstevel@tonic-gate /* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */ 227c478bd9Sstevel@tonic-gate #define MAXREPLYLEN 980 /* max. length of a reply string */ 237c478bd9Sstevel@tonic-gate #define MAXREPLIES 32 /* max. number of reply strings */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 267c478bd9Sstevel@tonic-gate ** SMFI_HEADER -- send a header to the MTA 277c478bd9Sstevel@tonic-gate ** 287c478bd9Sstevel@tonic-gate ** Parameters: 297c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 307c478bd9Sstevel@tonic-gate ** cmd -- Header modification command 317c478bd9Sstevel@tonic-gate ** hdridx -- Header index 327c478bd9Sstevel@tonic-gate ** headerf -- Header field name 337c478bd9Sstevel@tonic-gate ** headerv -- Header field value 347c478bd9Sstevel@tonic-gate ** 357c478bd9Sstevel@tonic-gate ** 367c478bd9Sstevel@tonic-gate ** Returns: 377c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate static int 417c478bd9Sstevel@tonic-gate smfi_header(ctx, cmd, hdridx, headerf, headerv) 427c478bd9Sstevel@tonic-gate SMFICTX *ctx; 437c478bd9Sstevel@tonic-gate int cmd; 447c478bd9Sstevel@tonic-gate int hdridx; 457c478bd9Sstevel@tonic-gate char *headerf; 467c478bd9Sstevel@tonic-gate char *headerv; 477c478bd9Sstevel@tonic-gate { 487c478bd9Sstevel@tonic-gate size_t len, l1, l2, offset; 497c478bd9Sstevel@tonic-gate int r; 507c478bd9Sstevel@tonic-gate mi_int32 v; 517c478bd9Sstevel@tonic-gate char *buf; 527c478bd9Sstevel@tonic-gate struct timeval timeout; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate if (headerf == NULL || *headerf == '\0' || headerv == NULL) 557c478bd9Sstevel@tonic-gate return MI_FAILURE; 567c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 577c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 587c478bd9Sstevel@tonic-gate l1 = strlen(headerf) + 1; 597c478bd9Sstevel@tonic-gate l2 = strlen(headerv) + 1; 607c478bd9Sstevel@tonic-gate len = l1 + l2; 617c478bd9Sstevel@tonic-gate if (hdridx >= 0) 627c478bd9Sstevel@tonic-gate len += MILTER_LEN_BYTES; 637c478bd9Sstevel@tonic-gate buf = malloc(len); 647c478bd9Sstevel@tonic-gate if (buf == NULL) 657c478bd9Sstevel@tonic-gate return MI_FAILURE; 667c478bd9Sstevel@tonic-gate offset = 0; 677c478bd9Sstevel@tonic-gate if (hdridx >= 0) 687c478bd9Sstevel@tonic-gate { 697c478bd9Sstevel@tonic-gate v = htonl(hdridx); 707c478bd9Sstevel@tonic-gate (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES); 717c478bd9Sstevel@tonic-gate offset += MILTER_LEN_BYTES; 727c478bd9Sstevel@tonic-gate } 737c478bd9Sstevel@tonic-gate (void) memcpy(buf + offset, headerf, l1); 747c478bd9Sstevel@tonic-gate (void) memcpy(buf + offset + l1, headerv, l2); 757c478bd9Sstevel@tonic-gate r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len); 767c478bd9Sstevel@tonic-gate free(buf); 777c478bd9Sstevel@tonic-gate return r; 787c478bd9Sstevel@tonic-gate } 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate ** SMFI_ADDHEADER -- send a new header to the MTA 827c478bd9Sstevel@tonic-gate ** 837c478bd9Sstevel@tonic-gate ** Parameters: 847c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 857c478bd9Sstevel@tonic-gate ** headerf -- Header field name 867c478bd9Sstevel@tonic-gate ** headerv -- Header field value 877c478bd9Sstevel@tonic-gate ** 887c478bd9Sstevel@tonic-gate ** Returns: 897c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate int 937c478bd9Sstevel@tonic-gate smfi_addheader(ctx, headerf, headerv) 947c478bd9Sstevel@tonic-gate SMFICTX *ctx; 957c478bd9Sstevel@tonic-gate char *headerf; 967c478bd9Sstevel@tonic-gate char *headerv; 977c478bd9Sstevel@tonic-gate { 987c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_ADDHDRS)) 997c478bd9Sstevel@tonic-gate return MI_FAILURE; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* 1057c478bd9Sstevel@tonic-gate ** SMFI_INSHEADER -- send a new header to the MTA (to be inserted) 1067c478bd9Sstevel@tonic-gate ** 1077c478bd9Sstevel@tonic-gate ** Parameters: 1087c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 1097c478bd9Sstevel@tonic-gate ** hdridx -- index into header list where insertion should occur 1107c478bd9Sstevel@tonic-gate ** headerf -- Header field name 1117c478bd9Sstevel@tonic-gate ** headerv -- Header field value 1127c478bd9Sstevel@tonic-gate ** 1137c478bd9Sstevel@tonic-gate ** Returns: 1147c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate int 1187c478bd9Sstevel@tonic-gate smfi_insheader(ctx, hdridx, headerf, headerv) 1197c478bd9Sstevel@tonic-gate SMFICTX *ctx; 1207c478bd9Sstevel@tonic-gate int hdridx; 1217c478bd9Sstevel@tonic-gate char *headerf; 1227c478bd9Sstevel@tonic-gate char *headerv; 1237c478bd9Sstevel@tonic-gate { 1247c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0) 1257c478bd9Sstevel@tonic-gate return MI_FAILURE; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate ** SMFI_CHGHEADER -- send a changed header to the MTA 1327c478bd9Sstevel@tonic-gate ** 1337c478bd9Sstevel@tonic-gate ** Parameters: 1347c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 1357c478bd9Sstevel@tonic-gate ** headerf -- Header field name 1367c478bd9Sstevel@tonic-gate ** hdridx -- Header index value 1377c478bd9Sstevel@tonic-gate ** headerv -- Header field value 1387c478bd9Sstevel@tonic-gate ** 1397c478bd9Sstevel@tonic-gate ** Returns: 1407c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate int 1447c478bd9Sstevel@tonic-gate smfi_chgheader(ctx, headerf, hdridx, headerv) 1457c478bd9Sstevel@tonic-gate SMFICTX *ctx; 1467c478bd9Sstevel@tonic-gate char *headerf; 1477c478bd9Sstevel@tonic-gate mi_int32 hdridx; 1487c478bd9Sstevel@tonic-gate char *headerv; 1497c478bd9Sstevel@tonic-gate { 1507c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0) 1517c478bd9Sstevel@tonic-gate return MI_FAILURE; 1527c478bd9Sstevel@tonic-gate if (headerv == NULL) 1537c478bd9Sstevel@tonic-gate headerv = ""; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* 1597c478bd9Sstevel@tonic-gate ** SMFI_ADDRCPT -- send an additional recipient to the MTA 1607c478bd9Sstevel@tonic-gate ** 1617c478bd9Sstevel@tonic-gate ** Parameters: 1627c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 1637c478bd9Sstevel@tonic-gate ** rcpt -- recipient address 1647c478bd9Sstevel@tonic-gate ** 1657c478bd9Sstevel@tonic-gate ** Returns: 1667c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate int 1707c478bd9Sstevel@tonic-gate smfi_addrcpt(ctx, rcpt) 1717c478bd9Sstevel@tonic-gate SMFICTX *ctx; 1727c478bd9Sstevel@tonic-gate char *rcpt; 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate size_t len; 1757c478bd9Sstevel@tonic-gate struct timeval timeout; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate if (rcpt == NULL || *rcpt == '\0') 1787c478bd9Sstevel@tonic-gate return MI_FAILURE; 1797c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_ADDRCPT)) 1807c478bd9Sstevel@tonic-gate return MI_FAILURE; 1817c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 1827c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 1837c478bd9Sstevel@tonic-gate len = strlen(rcpt) + 1; 1847c478bd9Sstevel@tonic-gate return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate ** SMFI_DELRCPT -- send a recipient to be removed to the MTA 1897c478bd9Sstevel@tonic-gate ** 1907c478bd9Sstevel@tonic-gate ** Parameters: 1917c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 1927c478bd9Sstevel@tonic-gate ** rcpt -- recipient address 1937c478bd9Sstevel@tonic-gate ** 1947c478bd9Sstevel@tonic-gate ** Returns: 1957c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate int 1997c478bd9Sstevel@tonic-gate smfi_delrcpt(ctx, rcpt) 2007c478bd9Sstevel@tonic-gate SMFICTX *ctx; 2017c478bd9Sstevel@tonic-gate char *rcpt; 2027c478bd9Sstevel@tonic-gate { 2037c478bd9Sstevel@tonic-gate size_t len; 2047c478bd9Sstevel@tonic-gate struct timeval timeout; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate if (rcpt == NULL || *rcpt == '\0') 2077c478bd9Sstevel@tonic-gate return MI_FAILURE; 2087c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_DELRCPT)) 2097c478bd9Sstevel@tonic-gate return MI_FAILURE; 2107c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 2117c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 2127c478bd9Sstevel@tonic-gate len = strlen(rcpt) + 1; 2137c478bd9Sstevel@tonic-gate return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate ** SMFI_REPLACEBODY -- send a body chunk to the MTA 2187c478bd9Sstevel@tonic-gate ** 2197c478bd9Sstevel@tonic-gate ** Parameters: 2207c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 2217c478bd9Sstevel@tonic-gate ** bodyp -- body chunk 2227c478bd9Sstevel@tonic-gate ** bodylen -- length of body chunk 2237c478bd9Sstevel@tonic-gate ** 2247c478bd9Sstevel@tonic-gate ** Returns: 2257c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate int 2297c478bd9Sstevel@tonic-gate smfi_replacebody(ctx, bodyp, bodylen) 2307c478bd9Sstevel@tonic-gate SMFICTX *ctx; 2317c478bd9Sstevel@tonic-gate unsigned char *bodyp; 2327c478bd9Sstevel@tonic-gate int bodylen; 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate int len, off, r; 2357c478bd9Sstevel@tonic-gate struct timeval timeout; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate if (bodylen < 0 || 2387c478bd9Sstevel@tonic-gate (bodyp == NULL && bodylen > 0)) 2397c478bd9Sstevel@tonic-gate return MI_FAILURE; 2407c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_CHGBODY)) 2417c478bd9Sstevel@tonic-gate return MI_FAILURE; 2427c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 2437c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* split body chunk if necessary */ 2467c478bd9Sstevel@tonic-gate off = 0; 247*49218d4fSjbeck do 2487c478bd9Sstevel@tonic-gate { 2497c478bd9Sstevel@tonic-gate len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE : 2507c478bd9Sstevel@tonic-gate bodylen; 2517c478bd9Sstevel@tonic-gate if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY, 2527c478bd9Sstevel@tonic-gate (char *) (bodyp + off), len)) != MI_SUCCESS) 2537c478bd9Sstevel@tonic-gate return r; 2547c478bd9Sstevel@tonic-gate off += len; 2557c478bd9Sstevel@tonic-gate bodylen -= len; 256*49218d4fSjbeck } while (bodylen > 0); 2577c478bd9Sstevel@tonic-gate return MI_SUCCESS; 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate /* 2617c478bd9Sstevel@tonic-gate ** SMFI_QUARANTINE -- quarantine an envelope 2627c478bd9Sstevel@tonic-gate ** 2637c478bd9Sstevel@tonic-gate ** Parameters: 2647c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 2657c478bd9Sstevel@tonic-gate ** reason -- why? 2667c478bd9Sstevel@tonic-gate ** 2677c478bd9Sstevel@tonic-gate ** Returns: 2687c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate int 2727c478bd9Sstevel@tonic-gate smfi_quarantine(ctx, reason) 2737c478bd9Sstevel@tonic-gate SMFICTX *ctx; 2747c478bd9Sstevel@tonic-gate char *reason; 2757c478bd9Sstevel@tonic-gate { 2767c478bd9Sstevel@tonic-gate size_t len; 2777c478bd9Sstevel@tonic-gate int r; 2787c478bd9Sstevel@tonic-gate char *buf; 2797c478bd9Sstevel@tonic-gate struct timeval timeout; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate if (reason == NULL || *reason == '\0') 2827c478bd9Sstevel@tonic-gate return MI_FAILURE; 2837c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_QUARANTINE)) 2847c478bd9Sstevel@tonic-gate return MI_FAILURE; 2857c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 2867c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 2877c478bd9Sstevel@tonic-gate len = strlen(reason) + 1; 2887c478bd9Sstevel@tonic-gate buf = malloc(len); 2897c478bd9Sstevel@tonic-gate if (buf == NULL) 2907c478bd9Sstevel@tonic-gate return MI_FAILURE; 2917c478bd9Sstevel@tonic-gate (void) memcpy(buf, reason, len); 2927c478bd9Sstevel@tonic-gate r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len); 2937c478bd9Sstevel@tonic-gate free(buf); 2947c478bd9Sstevel@tonic-gate return r; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate ** MYISENHSC -- check whether a string contains an enhanced status code 2997c478bd9Sstevel@tonic-gate ** 3007c478bd9Sstevel@tonic-gate ** Parameters: 3017c478bd9Sstevel@tonic-gate ** s -- string with possible enhanced status code. 3027c478bd9Sstevel@tonic-gate ** delim -- delim for enhanced status code. 3037c478bd9Sstevel@tonic-gate ** 3047c478bd9Sstevel@tonic-gate ** Returns: 3057c478bd9Sstevel@tonic-gate ** 0 -- no enhanced status code. 3067c478bd9Sstevel@tonic-gate ** >4 -- length of enhanced status code. 3077c478bd9Sstevel@tonic-gate ** 3087c478bd9Sstevel@tonic-gate ** Side Effects: 3097c478bd9Sstevel@tonic-gate ** none. 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate static int 3137c478bd9Sstevel@tonic-gate myisenhsc(s, delim) 3147c478bd9Sstevel@tonic-gate const char *s; 3157c478bd9Sstevel@tonic-gate int delim; 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate int l, h; 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if (s == NULL) 3207c478bd9Sstevel@tonic-gate return 0; 3217c478bd9Sstevel@tonic-gate if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 3227c478bd9Sstevel@tonic-gate return 0; 3237c478bd9Sstevel@tonic-gate h = 0; 3247c478bd9Sstevel@tonic-gate l = 2; 3257c478bd9Sstevel@tonic-gate while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 3267c478bd9Sstevel@tonic-gate ++h; 3277c478bd9Sstevel@tonic-gate if (h == 0 || s[l + h] != '.') 3287c478bd9Sstevel@tonic-gate return 0; 3297c478bd9Sstevel@tonic-gate l += h + 1; 3307c478bd9Sstevel@tonic-gate h = 0; 3317c478bd9Sstevel@tonic-gate while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 3327c478bd9Sstevel@tonic-gate ++h; 3337c478bd9Sstevel@tonic-gate if (h == 0 || s[l + h] != delim) 3347c478bd9Sstevel@tonic-gate return 0; 3357c478bd9Sstevel@tonic-gate return l + h; 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate ** SMFI_SETREPLY -- set the reply code for the next reply to the MTA 3407c478bd9Sstevel@tonic-gate ** 3417c478bd9Sstevel@tonic-gate ** Parameters: 3427c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 3437c478bd9Sstevel@tonic-gate ** rcode -- The three-digit (RFC 821) SMTP reply code. 3447c478bd9Sstevel@tonic-gate ** xcode -- The extended (RFC 2034) reply code. 3457c478bd9Sstevel@tonic-gate ** message -- The text part of the SMTP reply. 3467c478bd9Sstevel@tonic-gate ** 3477c478bd9Sstevel@tonic-gate ** Returns: 3487c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 3497c478bd9Sstevel@tonic-gate */ 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate int 3527c478bd9Sstevel@tonic-gate smfi_setreply(ctx, rcode, xcode, message) 3537c478bd9Sstevel@tonic-gate SMFICTX *ctx; 3547c478bd9Sstevel@tonic-gate char *rcode; 3557c478bd9Sstevel@tonic-gate char *xcode; 3567c478bd9Sstevel@tonic-gate char *message; 3577c478bd9Sstevel@tonic-gate { 3587c478bd9Sstevel@tonic-gate size_t len; 3597c478bd9Sstevel@tonic-gate char *buf; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate if (rcode == NULL || ctx == NULL) 3627c478bd9Sstevel@tonic-gate return MI_FAILURE; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* ### <sp> \0 */ 3657c478bd9Sstevel@tonic-gate len = strlen(rcode) + 2; 3667c478bd9Sstevel@tonic-gate if (len != 5) 3677c478bd9Sstevel@tonic-gate return MI_FAILURE; 3687c478bd9Sstevel@tonic-gate if ((rcode[0] != '4' && rcode[0] != '5') || 3697c478bd9Sstevel@tonic-gate !isascii(rcode[1]) || !isdigit(rcode[1]) || 3707c478bd9Sstevel@tonic-gate !isascii(rcode[2]) || !isdigit(rcode[2])) 3717c478bd9Sstevel@tonic-gate return MI_FAILURE; 3727c478bd9Sstevel@tonic-gate if (xcode != NULL) 3737c478bd9Sstevel@tonic-gate { 3747c478bd9Sstevel@tonic-gate if (!myisenhsc(xcode, '\0')) 3757c478bd9Sstevel@tonic-gate return MI_FAILURE; 3767c478bd9Sstevel@tonic-gate len += strlen(xcode) + 1; 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate if (message != NULL) 3797c478bd9Sstevel@tonic-gate { 3807c478bd9Sstevel@tonic-gate size_t ml; 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* XXX check also for unprintable chars? */ 3837c478bd9Sstevel@tonic-gate if (strpbrk(message, "\r\n") != NULL) 3847c478bd9Sstevel@tonic-gate return MI_FAILURE; 3857c478bd9Sstevel@tonic-gate ml = strlen(message); 3867c478bd9Sstevel@tonic-gate if (ml > MAXREPLYLEN) 3877c478bd9Sstevel@tonic-gate return MI_FAILURE; 3887c478bd9Sstevel@tonic-gate len += ml + 1; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate buf = malloc(len); 3917c478bd9Sstevel@tonic-gate if (buf == NULL) 3927c478bd9Sstevel@tonic-gate return MI_FAILURE; /* oops */ 3937c478bd9Sstevel@tonic-gate (void) sm_strlcpy(buf, rcode, len); 3947c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, " ", len); 3957c478bd9Sstevel@tonic-gate if (xcode != NULL) 3967c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, xcode, len); 3977c478bd9Sstevel@tonic-gate if (message != NULL) 3987c478bd9Sstevel@tonic-gate { 3997c478bd9Sstevel@tonic-gate if (xcode != NULL) 4007c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, " ", len); 4017c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, message, len); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate if (ctx->ctx_reply != NULL) 4047c478bd9Sstevel@tonic-gate free(ctx->ctx_reply); 4057c478bd9Sstevel@tonic-gate ctx->ctx_reply = buf; 4067c478bd9Sstevel@tonic-gate return MI_SUCCESS; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate ** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA 4117c478bd9Sstevel@tonic-gate ** 4127c478bd9Sstevel@tonic-gate ** Parameters: 4137c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 4147c478bd9Sstevel@tonic-gate ** rcode -- The three-digit (RFC 821) SMTP reply code. 4157c478bd9Sstevel@tonic-gate ** xcode -- The extended (RFC 2034) reply code. 4167c478bd9Sstevel@tonic-gate ** txt, ... -- The text part of the SMTP reply, 4177c478bd9Sstevel@tonic-gate ** MUST be terminated with NULL. 4187c478bd9Sstevel@tonic-gate ** 4197c478bd9Sstevel@tonic-gate ** Returns: 4207c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate int 4247c478bd9Sstevel@tonic-gate #if SM_VA_STD 4257c478bd9Sstevel@tonic-gate smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...) 4267c478bd9Sstevel@tonic-gate #else /* SM_VA_STD */ 4277c478bd9Sstevel@tonic-gate smfi_setmlreply(ctx, rcode, xcode, va_alist) 4287c478bd9Sstevel@tonic-gate SMFICTX *ctx; 4297c478bd9Sstevel@tonic-gate const char *rcode; 4307c478bd9Sstevel@tonic-gate const char *xcode; 4317c478bd9Sstevel@tonic-gate va_dcl 4327c478bd9Sstevel@tonic-gate #endif /* SM_VA_STD */ 4337c478bd9Sstevel@tonic-gate { 4347c478bd9Sstevel@tonic-gate size_t len; 4357c478bd9Sstevel@tonic-gate size_t rlen; 4367c478bd9Sstevel@tonic-gate int args; 4377c478bd9Sstevel@tonic-gate char *buf, *txt; 4387c478bd9Sstevel@tonic-gate const char *xc; 4397c478bd9Sstevel@tonic-gate char repl[16]; 4407c478bd9Sstevel@tonic-gate SM_VA_LOCAL_DECL 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate if (rcode == NULL || ctx == NULL) 4437c478bd9Sstevel@tonic-gate return MI_FAILURE; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* ### <sp> */ 4467c478bd9Sstevel@tonic-gate len = strlen(rcode) + 1; 4477c478bd9Sstevel@tonic-gate if (len != 4) 4487c478bd9Sstevel@tonic-gate return MI_FAILURE; 4497c478bd9Sstevel@tonic-gate if ((rcode[0] != '4' && rcode[0] != '5') || 4507c478bd9Sstevel@tonic-gate !isascii(rcode[1]) || !isdigit(rcode[1]) || 4517c478bd9Sstevel@tonic-gate !isascii(rcode[2]) || !isdigit(rcode[2])) 4527c478bd9Sstevel@tonic-gate return MI_FAILURE; 4537c478bd9Sstevel@tonic-gate if (xcode != NULL) 4547c478bd9Sstevel@tonic-gate { 4557c478bd9Sstevel@tonic-gate if (!myisenhsc(xcode, '\0')) 4567c478bd9Sstevel@tonic-gate return MI_FAILURE; 4577c478bd9Sstevel@tonic-gate xc = xcode; 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate else 4607c478bd9Sstevel@tonic-gate { 4617c478bd9Sstevel@tonic-gate if (rcode[0] == '4') 4627c478bd9Sstevel@tonic-gate xc = "4.0.0"; 4637c478bd9Sstevel@tonic-gate else 4647c478bd9Sstevel@tonic-gate xc = "5.0.0"; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* add trailing space */ 4687c478bd9Sstevel@tonic-gate len += strlen(xc) + 1; 4697c478bd9Sstevel@tonic-gate rlen = len; 4707c478bd9Sstevel@tonic-gate args = 0; 4717c478bd9Sstevel@tonic-gate SM_VA_START(ap, xcode); 4727c478bd9Sstevel@tonic-gate while ((txt = SM_VA_ARG(ap, char *)) != NULL) 4737c478bd9Sstevel@tonic-gate { 4747c478bd9Sstevel@tonic-gate size_t tl; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate tl = strlen(txt); 4777c478bd9Sstevel@tonic-gate if (tl > MAXREPLYLEN) 4787c478bd9Sstevel@tonic-gate break; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* this text, reply codes, \r\n */ 4817c478bd9Sstevel@tonic-gate len += tl + 2 + rlen; 4827c478bd9Sstevel@tonic-gate if (++args > MAXREPLIES) 4837c478bd9Sstevel@tonic-gate break; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* XXX check also for unprintable chars? */ 4867c478bd9Sstevel@tonic-gate if (strpbrk(txt, "\r\n") != NULL) 4877c478bd9Sstevel@tonic-gate break; 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate SM_VA_END(ap); 4907c478bd9Sstevel@tonic-gate if (txt != NULL) 4917c478bd9Sstevel@tonic-gate return MI_FAILURE; 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /* trailing '\0' */ 4947c478bd9Sstevel@tonic-gate ++len; 4957c478bd9Sstevel@tonic-gate buf = malloc(len); 4967c478bd9Sstevel@tonic-gate if (buf == NULL) 4977c478bd9Sstevel@tonic-gate return MI_FAILURE; /* oops */ 4987c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc); 4997c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-", 5007c478bd9Sstevel@tonic-gate xc, " "); 5017c478bd9Sstevel@tonic-gate SM_VA_START(ap, xcode); 5027c478bd9Sstevel@tonic-gate txt = SM_VA_ARG(ap, char *); 5037c478bd9Sstevel@tonic-gate if (txt != NULL) 5047c478bd9Sstevel@tonic-gate { 5057c478bd9Sstevel@tonic-gate (void) sm_strlcat2(buf, " ", txt, len); 5067c478bd9Sstevel@tonic-gate while ((txt = SM_VA_ARG(ap, char *)) != NULL) 5077c478bd9Sstevel@tonic-gate { 5087c478bd9Sstevel@tonic-gate if (--args <= 1) 5097c478bd9Sstevel@tonic-gate repl[3] = ' '; 5107c478bd9Sstevel@tonic-gate (void) sm_strlcat2(buf, "\r\n", repl, len); 5117c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, txt, len); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate if (ctx->ctx_reply != NULL) 5157c478bd9Sstevel@tonic-gate free(ctx->ctx_reply); 5167c478bd9Sstevel@tonic-gate ctx->ctx_reply = buf; 5177c478bd9Sstevel@tonic-gate SM_VA_END(ap); 5187c478bd9Sstevel@tonic-gate return MI_SUCCESS; 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate ** SMFI_SETPRIV -- set private data 5237c478bd9Sstevel@tonic-gate ** 5247c478bd9Sstevel@tonic-gate ** Parameters: 5257c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 5267c478bd9Sstevel@tonic-gate ** privatedata -- pointer to private data 5277c478bd9Sstevel@tonic-gate ** 5287c478bd9Sstevel@tonic-gate ** Returns: 5297c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 5307c478bd9Sstevel@tonic-gate */ 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate int 5337c478bd9Sstevel@tonic-gate smfi_setpriv(ctx, privatedata) 5347c478bd9Sstevel@tonic-gate SMFICTX *ctx; 5357c478bd9Sstevel@tonic-gate void *privatedata; 5367c478bd9Sstevel@tonic-gate { 5377c478bd9Sstevel@tonic-gate if (ctx == NULL) 5387c478bd9Sstevel@tonic-gate return MI_FAILURE; 5397c478bd9Sstevel@tonic-gate ctx->ctx_privdata = privatedata; 5407c478bd9Sstevel@tonic-gate return MI_SUCCESS; 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* 5447c478bd9Sstevel@tonic-gate ** SMFI_GETPRIV -- get private data 5457c478bd9Sstevel@tonic-gate ** 5467c478bd9Sstevel@tonic-gate ** Parameters: 5477c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 5487c478bd9Sstevel@tonic-gate ** 5497c478bd9Sstevel@tonic-gate ** Returns: 5507c478bd9Sstevel@tonic-gate ** pointer to private data 5517c478bd9Sstevel@tonic-gate */ 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate void * 5547c478bd9Sstevel@tonic-gate smfi_getpriv(ctx) 5557c478bd9Sstevel@tonic-gate SMFICTX *ctx; 5567c478bd9Sstevel@tonic-gate { 5577c478bd9Sstevel@tonic-gate if (ctx == NULL) 5587c478bd9Sstevel@tonic-gate return NULL; 5597c478bd9Sstevel@tonic-gate return ctx->ctx_privdata; 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate /* 5637c478bd9Sstevel@tonic-gate ** SMFI_GETSYMVAL -- get the value of a macro 5647c478bd9Sstevel@tonic-gate ** 5657c478bd9Sstevel@tonic-gate ** See explanation in mfapi.h about layout of the structures. 5667c478bd9Sstevel@tonic-gate ** 5677c478bd9Sstevel@tonic-gate ** Parameters: 5687c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 5697c478bd9Sstevel@tonic-gate ** symname -- name of macro 5707c478bd9Sstevel@tonic-gate ** 5717c478bd9Sstevel@tonic-gate ** Returns: 5727c478bd9Sstevel@tonic-gate ** value of macro (NULL in case of failure) 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate char * 5767c478bd9Sstevel@tonic-gate smfi_getsymval(ctx, symname) 5777c478bd9Sstevel@tonic-gate SMFICTX *ctx; 5787c478bd9Sstevel@tonic-gate char *symname; 5797c478bd9Sstevel@tonic-gate { 5807c478bd9Sstevel@tonic-gate int i; 5817c478bd9Sstevel@tonic-gate char **s; 5827c478bd9Sstevel@tonic-gate char one[2]; 5837c478bd9Sstevel@tonic-gate char braces[4]; 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate if (ctx == NULL || symname == NULL || *symname == '\0') 5867c478bd9Sstevel@tonic-gate return NULL; 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}') 5897c478bd9Sstevel@tonic-gate { 5907c478bd9Sstevel@tonic-gate one[0] = symname[1]; 5917c478bd9Sstevel@tonic-gate one[1] = '\0'; 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate else 5947c478bd9Sstevel@tonic-gate one[0] = '\0'; 5957c478bd9Sstevel@tonic-gate if (strlen(symname) == 1) 5967c478bd9Sstevel@tonic-gate { 5977c478bd9Sstevel@tonic-gate braces[0] = '{'; 5987c478bd9Sstevel@tonic-gate braces[1] = *symname; 5997c478bd9Sstevel@tonic-gate braces[2] = '}'; 6007c478bd9Sstevel@tonic-gate braces[3] = '\0'; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate else 6037c478bd9Sstevel@tonic-gate braces[0] = '\0'; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* search backwards through the macro array */ 6067c478bd9Sstevel@tonic-gate for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i) 6077c478bd9Sstevel@tonic-gate { 6087c478bd9Sstevel@tonic-gate if ((s = ctx->ctx_mac_ptr[i]) == NULL || 6097c478bd9Sstevel@tonic-gate ctx->ctx_mac_buf[i] == NULL) 6107c478bd9Sstevel@tonic-gate continue; 6117c478bd9Sstevel@tonic-gate while (s != NULL && *s != NULL) 6127c478bd9Sstevel@tonic-gate { 6137c478bd9Sstevel@tonic-gate if (strcmp(*s, symname) == 0) 6147c478bd9Sstevel@tonic-gate return *++s; 6157c478bd9Sstevel@tonic-gate if (one[0] != '\0' && strcmp(*s, one) == 0) 6167c478bd9Sstevel@tonic-gate return *++s; 6177c478bd9Sstevel@tonic-gate if (braces[0] != '\0' && strcmp(*s, braces) == 0) 6187c478bd9Sstevel@tonic-gate return *++s; 6197c478bd9Sstevel@tonic-gate ++s; /* skip over macro value */ 6207c478bd9Sstevel@tonic-gate ++s; /* points to next macro name */ 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate return NULL; 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* 6277c478bd9Sstevel@tonic-gate ** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature 6287c478bd9Sstevel@tonic-gate ** timeouts during long milter-side operations 6297c478bd9Sstevel@tonic-gate ** 6307c478bd9Sstevel@tonic-gate ** Parameters: 6317c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 6327c478bd9Sstevel@tonic-gate ** 6337c478bd9Sstevel@tonic-gate ** Return value: 6347c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate int 6387c478bd9Sstevel@tonic-gate smfi_progress(ctx) 6397c478bd9Sstevel@tonic-gate SMFICTX *ctx; 6407c478bd9Sstevel@tonic-gate { 6417c478bd9Sstevel@tonic-gate struct timeval timeout; 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate if (ctx == NULL) 6447c478bd9Sstevel@tonic-gate return MI_FAILURE; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 6477c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0); 6507c478bd9Sstevel@tonic-gate } 651