1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * 5*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 6*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 7*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate */ 10*7c478bd9Sstevel@tonic-gate 11*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 12*7c478bd9Sstevel@tonic-gate 13*7c478bd9Sstevel@tonic-gate #include <sm/gen.h> 14*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: smfi.c,v 8.73 2004/09/20 21:26:57 ca Exp $") 15*7c478bd9Sstevel@tonic-gate #include <sm/varargs.h> 16*7c478bd9Sstevel@tonic-gate #include "libmilter.h" 17*7c478bd9Sstevel@tonic-gate 18*7c478bd9Sstevel@tonic-gate static int smfi_header __P((SMFICTX *, int, int, char *, char *)); 19*7c478bd9Sstevel@tonic-gate static int myisenhsc __P((const char *, int)); 20*7c478bd9Sstevel@tonic-gate 21*7c478bd9Sstevel@tonic-gate /* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */ 22*7c478bd9Sstevel@tonic-gate #define MAXREPLYLEN 980 /* max. length of a reply string */ 23*7c478bd9Sstevel@tonic-gate #define MAXREPLIES 32 /* max. number of reply strings */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate /* 26*7c478bd9Sstevel@tonic-gate ** SMFI_HEADER -- send a header to the MTA 27*7c478bd9Sstevel@tonic-gate ** 28*7c478bd9Sstevel@tonic-gate ** Parameters: 29*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 30*7c478bd9Sstevel@tonic-gate ** cmd -- Header modification command 31*7c478bd9Sstevel@tonic-gate ** hdridx -- Header index 32*7c478bd9Sstevel@tonic-gate ** headerf -- Header field name 33*7c478bd9Sstevel@tonic-gate ** headerv -- Header field value 34*7c478bd9Sstevel@tonic-gate ** 35*7c478bd9Sstevel@tonic-gate ** 36*7c478bd9Sstevel@tonic-gate ** Returns: 37*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 38*7c478bd9Sstevel@tonic-gate */ 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate static int 41*7c478bd9Sstevel@tonic-gate smfi_header(ctx, cmd, hdridx, headerf, headerv) 42*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 43*7c478bd9Sstevel@tonic-gate int cmd; 44*7c478bd9Sstevel@tonic-gate int hdridx; 45*7c478bd9Sstevel@tonic-gate char *headerf; 46*7c478bd9Sstevel@tonic-gate char *headerv; 47*7c478bd9Sstevel@tonic-gate { 48*7c478bd9Sstevel@tonic-gate size_t len, l1, l2, offset; 49*7c478bd9Sstevel@tonic-gate int r; 50*7c478bd9Sstevel@tonic-gate mi_int32 v; 51*7c478bd9Sstevel@tonic-gate char *buf; 52*7c478bd9Sstevel@tonic-gate struct timeval timeout; 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate if (headerf == NULL || *headerf == '\0' || headerv == NULL) 55*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 56*7c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 57*7c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 58*7c478bd9Sstevel@tonic-gate l1 = strlen(headerf) + 1; 59*7c478bd9Sstevel@tonic-gate l2 = strlen(headerv) + 1; 60*7c478bd9Sstevel@tonic-gate len = l1 + l2; 61*7c478bd9Sstevel@tonic-gate if (hdridx >= 0) 62*7c478bd9Sstevel@tonic-gate len += MILTER_LEN_BYTES; 63*7c478bd9Sstevel@tonic-gate buf = malloc(len); 64*7c478bd9Sstevel@tonic-gate if (buf == NULL) 65*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 66*7c478bd9Sstevel@tonic-gate offset = 0; 67*7c478bd9Sstevel@tonic-gate if (hdridx >= 0) 68*7c478bd9Sstevel@tonic-gate { 69*7c478bd9Sstevel@tonic-gate v = htonl(hdridx); 70*7c478bd9Sstevel@tonic-gate (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES); 71*7c478bd9Sstevel@tonic-gate offset += MILTER_LEN_BYTES; 72*7c478bd9Sstevel@tonic-gate } 73*7c478bd9Sstevel@tonic-gate (void) memcpy(buf + offset, headerf, l1); 74*7c478bd9Sstevel@tonic-gate (void) memcpy(buf + offset + l1, headerv, l2); 75*7c478bd9Sstevel@tonic-gate r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len); 76*7c478bd9Sstevel@tonic-gate free(buf); 77*7c478bd9Sstevel@tonic-gate return r; 78*7c478bd9Sstevel@tonic-gate } 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate /* 81*7c478bd9Sstevel@tonic-gate ** SMFI_ADDHEADER -- send a new header to the MTA 82*7c478bd9Sstevel@tonic-gate ** 83*7c478bd9Sstevel@tonic-gate ** Parameters: 84*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 85*7c478bd9Sstevel@tonic-gate ** headerf -- Header field name 86*7c478bd9Sstevel@tonic-gate ** headerv -- Header field value 87*7c478bd9Sstevel@tonic-gate ** 88*7c478bd9Sstevel@tonic-gate ** Returns: 89*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate int 93*7c478bd9Sstevel@tonic-gate smfi_addheader(ctx, headerf, headerv) 94*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 95*7c478bd9Sstevel@tonic-gate char *headerf; 96*7c478bd9Sstevel@tonic-gate char *headerv; 97*7c478bd9Sstevel@tonic-gate { 98*7c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_ADDHDRS)) 99*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv); 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /* 105*7c478bd9Sstevel@tonic-gate ** SMFI_INSHEADER -- send a new header to the MTA (to be inserted) 106*7c478bd9Sstevel@tonic-gate ** 107*7c478bd9Sstevel@tonic-gate ** Parameters: 108*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 109*7c478bd9Sstevel@tonic-gate ** hdridx -- index into header list where insertion should occur 110*7c478bd9Sstevel@tonic-gate ** headerf -- Header field name 111*7c478bd9Sstevel@tonic-gate ** headerv -- Header field value 112*7c478bd9Sstevel@tonic-gate ** 113*7c478bd9Sstevel@tonic-gate ** Returns: 114*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 115*7c478bd9Sstevel@tonic-gate */ 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate int 118*7c478bd9Sstevel@tonic-gate smfi_insheader(ctx, hdridx, headerf, headerv) 119*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 120*7c478bd9Sstevel@tonic-gate int hdridx; 121*7c478bd9Sstevel@tonic-gate char *headerf; 122*7c478bd9Sstevel@tonic-gate char *headerv; 123*7c478bd9Sstevel@tonic-gate { 124*7c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0) 125*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv); 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* 131*7c478bd9Sstevel@tonic-gate ** SMFI_CHGHEADER -- send a changed header to the MTA 132*7c478bd9Sstevel@tonic-gate ** 133*7c478bd9Sstevel@tonic-gate ** Parameters: 134*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 135*7c478bd9Sstevel@tonic-gate ** headerf -- Header field name 136*7c478bd9Sstevel@tonic-gate ** hdridx -- Header index value 137*7c478bd9Sstevel@tonic-gate ** headerv -- Header field value 138*7c478bd9Sstevel@tonic-gate ** 139*7c478bd9Sstevel@tonic-gate ** Returns: 140*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 141*7c478bd9Sstevel@tonic-gate */ 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate int 144*7c478bd9Sstevel@tonic-gate smfi_chgheader(ctx, headerf, hdridx, headerv) 145*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 146*7c478bd9Sstevel@tonic-gate char *headerf; 147*7c478bd9Sstevel@tonic-gate mi_int32 hdridx; 148*7c478bd9Sstevel@tonic-gate char *headerv; 149*7c478bd9Sstevel@tonic-gate { 150*7c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0) 151*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 152*7c478bd9Sstevel@tonic-gate if (headerv == NULL) 153*7c478bd9Sstevel@tonic-gate headerv = ""; 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv); 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate /* 159*7c478bd9Sstevel@tonic-gate ** SMFI_ADDRCPT -- send an additional recipient to the MTA 160*7c478bd9Sstevel@tonic-gate ** 161*7c478bd9Sstevel@tonic-gate ** Parameters: 162*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 163*7c478bd9Sstevel@tonic-gate ** rcpt -- recipient address 164*7c478bd9Sstevel@tonic-gate ** 165*7c478bd9Sstevel@tonic-gate ** Returns: 166*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate int 170*7c478bd9Sstevel@tonic-gate smfi_addrcpt(ctx, rcpt) 171*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 172*7c478bd9Sstevel@tonic-gate char *rcpt; 173*7c478bd9Sstevel@tonic-gate { 174*7c478bd9Sstevel@tonic-gate size_t len; 175*7c478bd9Sstevel@tonic-gate struct timeval timeout; 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate if (rcpt == NULL || *rcpt == '\0') 178*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 179*7c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_ADDRCPT)) 180*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 181*7c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 182*7c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 183*7c478bd9Sstevel@tonic-gate len = strlen(rcpt) + 1; 184*7c478bd9Sstevel@tonic-gate return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len); 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate ** SMFI_DELRCPT -- send a recipient to be removed to the MTA 189*7c478bd9Sstevel@tonic-gate ** 190*7c478bd9Sstevel@tonic-gate ** Parameters: 191*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 192*7c478bd9Sstevel@tonic-gate ** rcpt -- recipient address 193*7c478bd9Sstevel@tonic-gate ** 194*7c478bd9Sstevel@tonic-gate ** Returns: 195*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 196*7c478bd9Sstevel@tonic-gate */ 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate int 199*7c478bd9Sstevel@tonic-gate smfi_delrcpt(ctx, rcpt) 200*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 201*7c478bd9Sstevel@tonic-gate char *rcpt; 202*7c478bd9Sstevel@tonic-gate { 203*7c478bd9Sstevel@tonic-gate size_t len; 204*7c478bd9Sstevel@tonic-gate struct timeval timeout; 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate if (rcpt == NULL || *rcpt == '\0') 207*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 208*7c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_DELRCPT)) 209*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 210*7c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 211*7c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 212*7c478bd9Sstevel@tonic-gate len = strlen(rcpt) + 1; 213*7c478bd9Sstevel@tonic-gate return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len); 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate ** SMFI_REPLACEBODY -- send a body chunk to the MTA 218*7c478bd9Sstevel@tonic-gate ** 219*7c478bd9Sstevel@tonic-gate ** Parameters: 220*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 221*7c478bd9Sstevel@tonic-gate ** bodyp -- body chunk 222*7c478bd9Sstevel@tonic-gate ** bodylen -- length of body chunk 223*7c478bd9Sstevel@tonic-gate ** 224*7c478bd9Sstevel@tonic-gate ** Returns: 225*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 226*7c478bd9Sstevel@tonic-gate */ 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate int 229*7c478bd9Sstevel@tonic-gate smfi_replacebody(ctx, bodyp, bodylen) 230*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 231*7c478bd9Sstevel@tonic-gate unsigned char *bodyp; 232*7c478bd9Sstevel@tonic-gate int bodylen; 233*7c478bd9Sstevel@tonic-gate { 234*7c478bd9Sstevel@tonic-gate int len, off, r; 235*7c478bd9Sstevel@tonic-gate struct timeval timeout; 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate if (bodylen < 0 || 238*7c478bd9Sstevel@tonic-gate (bodyp == NULL && bodylen > 0)) 239*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 240*7c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_CHGBODY)) 241*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 242*7c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 243*7c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate /* split body chunk if necessary */ 246*7c478bd9Sstevel@tonic-gate off = 0; 247*7c478bd9Sstevel@tonic-gate while (bodylen > 0) 248*7c478bd9Sstevel@tonic-gate { 249*7c478bd9Sstevel@tonic-gate len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE : 250*7c478bd9Sstevel@tonic-gate bodylen; 251*7c478bd9Sstevel@tonic-gate if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY, 252*7c478bd9Sstevel@tonic-gate (char *) (bodyp + off), len)) != MI_SUCCESS) 253*7c478bd9Sstevel@tonic-gate return r; 254*7c478bd9Sstevel@tonic-gate off += len; 255*7c478bd9Sstevel@tonic-gate bodylen -= len; 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate return MI_SUCCESS; 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate /* 261*7c478bd9Sstevel@tonic-gate ** SMFI_QUARANTINE -- quarantine an envelope 262*7c478bd9Sstevel@tonic-gate ** 263*7c478bd9Sstevel@tonic-gate ** Parameters: 264*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 265*7c478bd9Sstevel@tonic-gate ** reason -- why? 266*7c478bd9Sstevel@tonic-gate ** 267*7c478bd9Sstevel@tonic-gate ** Returns: 268*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 269*7c478bd9Sstevel@tonic-gate */ 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate int 272*7c478bd9Sstevel@tonic-gate smfi_quarantine(ctx, reason) 273*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 274*7c478bd9Sstevel@tonic-gate char *reason; 275*7c478bd9Sstevel@tonic-gate { 276*7c478bd9Sstevel@tonic-gate size_t len; 277*7c478bd9Sstevel@tonic-gate int r; 278*7c478bd9Sstevel@tonic-gate char *buf; 279*7c478bd9Sstevel@tonic-gate struct timeval timeout; 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate if (reason == NULL || *reason == '\0') 282*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 283*7c478bd9Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_QUARANTINE)) 284*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 285*7c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 286*7c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 287*7c478bd9Sstevel@tonic-gate len = strlen(reason) + 1; 288*7c478bd9Sstevel@tonic-gate buf = malloc(len); 289*7c478bd9Sstevel@tonic-gate if (buf == NULL) 290*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 291*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, reason, len); 292*7c478bd9Sstevel@tonic-gate r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len); 293*7c478bd9Sstevel@tonic-gate free(buf); 294*7c478bd9Sstevel@tonic-gate return r; 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate /* 298*7c478bd9Sstevel@tonic-gate ** MYISENHSC -- check whether a string contains an enhanced status code 299*7c478bd9Sstevel@tonic-gate ** 300*7c478bd9Sstevel@tonic-gate ** Parameters: 301*7c478bd9Sstevel@tonic-gate ** s -- string with possible enhanced status code. 302*7c478bd9Sstevel@tonic-gate ** delim -- delim for enhanced status code. 303*7c478bd9Sstevel@tonic-gate ** 304*7c478bd9Sstevel@tonic-gate ** Returns: 305*7c478bd9Sstevel@tonic-gate ** 0 -- no enhanced status code. 306*7c478bd9Sstevel@tonic-gate ** >4 -- length of enhanced status code. 307*7c478bd9Sstevel@tonic-gate ** 308*7c478bd9Sstevel@tonic-gate ** Side Effects: 309*7c478bd9Sstevel@tonic-gate ** none. 310*7c478bd9Sstevel@tonic-gate */ 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate static int 313*7c478bd9Sstevel@tonic-gate myisenhsc(s, delim) 314*7c478bd9Sstevel@tonic-gate const char *s; 315*7c478bd9Sstevel@tonic-gate int delim; 316*7c478bd9Sstevel@tonic-gate { 317*7c478bd9Sstevel@tonic-gate int l, h; 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate if (s == NULL) 320*7c478bd9Sstevel@tonic-gate return 0; 321*7c478bd9Sstevel@tonic-gate if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 322*7c478bd9Sstevel@tonic-gate return 0; 323*7c478bd9Sstevel@tonic-gate h = 0; 324*7c478bd9Sstevel@tonic-gate l = 2; 325*7c478bd9Sstevel@tonic-gate while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 326*7c478bd9Sstevel@tonic-gate ++h; 327*7c478bd9Sstevel@tonic-gate if (h == 0 || s[l + h] != '.') 328*7c478bd9Sstevel@tonic-gate return 0; 329*7c478bd9Sstevel@tonic-gate l += h + 1; 330*7c478bd9Sstevel@tonic-gate h = 0; 331*7c478bd9Sstevel@tonic-gate while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 332*7c478bd9Sstevel@tonic-gate ++h; 333*7c478bd9Sstevel@tonic-gate if (h == 0 || s[l + h] != delim) 334*7c478bd9Sstevel@tonic-gate return 0; 335*7c478bd9Sstevel@tonic-gate return l + h; 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate /* 339*7c478bd9Sstevel@tonic-gate ** SMFI_SETREPLY -- set the reply code for the next reply to the MTA 340*7c478bd9Sstevel@tonic-gate ** 341*7c478bd9Sstevel@tonic-gate ** Parameters: 342*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 343*7c478bd9Sstevel@tonic-gate ** rcode -- The three-digit (RFC 821) SMTP reply code. 344*7c478bd9Sstevel@tonic-gate ** xcode -- The extended (RFC 2034) reply code. 345*7c478bd9Sstevel@tonic-gate ** message -- The text part of the SMTP reply. 346*7c478bd9Sstevel@tonic-gate ** 347*7c478bd9Sstevel@tonic-gate ** Returns: 348*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate int 352*7c478bd9Sstevel@tonic-gate smfi_setreply(ctx, rcode, xcode, message) 353*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 354*7c478bd9Sstevel@tonic-gate char *rcode; 355*7c478bd9Sstevel@tonic-gate char *xcode; 356*7c478bd9Sstevel@tonic-gate char *message; 357*7c478bd9Sstevel@tonic-gate { 358*7c478bd9Sstevel@tonic-gate size_t len; 359*7c478bd9Sstevel@tonic-gate char *buf; 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate if (rcode == NULL || ctx == NULL) 362*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate /* ### <sp> \0 */ 365*7c478bd9Sstevel@tonic-gate len = strlen(rcode) + 2; 366*7c478bd9Sstevel@tonic-gate if (len != 5) 367*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 368*7c478bd9Sstevel@tonic-gate if ((rcode[0] != '4' && rcode[0] != '5') || 369*7c478bd9Sstevel@tonic-gate !isascii(rcode[1]) || !isdigit(rcode[1]) || 370*7c478bd9Sstevel@tonic-gate !isascii(rcode[2]) || !isdigit(rcode[2])) 371*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 372*7c478bd9Sstevel@tonic-gate if (xcode != NULL) 373*7c478bd9Sstevel@tonic-gate { 374*7c478bd9Sstevel@tonic-gate if (!myisenhsc(xcode, '\0')) 375*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 376*7c478bd9Sstevel@tonic-gate len += strlen(xcode) + 1; 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate if (message != NULL) 379*7c478bd9Sstevel@tonic-gate { 380*7c478bd9Sstevel@tonic-gate size_t ml; 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate /* XXX check also for unprintable chars? */ 383*7c478bd9Sstevel@tonic-gate if (strpbrk(message, "\r\n") != NULL) 384*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 385*7c478bd9Sstevel@tonic-gate ml = strlen(message); 386*7c478bd9Sstevel@tonic-gate if (ml > MAXREPLYLEN) 387*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 388*7c478bd9Sstevel@tonic-gate len += ml + 1; 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate buf = malloc(len); 391*7c478bd9Sstevel@tonic-gate if (buf == NULL) 392*7c478bd9Sstevel@tonic-gate return MI_FAILURE; /* oops */ 393*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(buf, rcode, len); 394*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, " ", len); 395*7c478bd9Sstevel@tonic-gate if (xcode != NULL) 396*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, xcode, len); 397*7c478bd9Sstevel@tonic-gate if (message != NULL) 398*7c478bd9Sstevel@tonic-gate { 399*7c478bd9Sstevel@tonic-gate if (xcode != NULL) 400*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, " ", len); 401*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, message, len); 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate if (ctx->ctx_reply != NULL) 404*7c478bd9Sstevel@tonic-gate free(ctx->ctx_reply); 405*7c478bd9Sstevel@tonic-gate ctx->ctx_reply = buf; 406*7c478bd9Sstevel@tonic-gate return MI_SUCCESS; 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate /* 410*7c478bd9Sstevel@tonic-gate ** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA 411*7c478bd9Sstevel@tonic-gate ** 412*7c478bd9Sstevel@tonic-gate ** Parameters: 413*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 414*7c478bd9Sstevel@tonic-gate ** rcode -- The three-digit (RFC 821) SMTP reply code. 415*7c478bd9Sstevel@tonic-gate ** xcode -- The extended (RFC 2034) reply code. 416*7c478bd9Sstevel@tonic-gate ** txt, ... -- The text part of the SMTP reply, 417*7c478bd9Sstevel@tonic-gate ** MUST be terminated with NULL. 418*7c478bd9Sstevel@tonic-gate ** 419*7c478bd9Sstevel@tonic-gate ** Returns: 420*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 421*7c478bd9Sstevel@tonic-gate */ 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate int 424*7c478bd9Sstevel@tonic-gate #if SM_VA_STD 425*7c478bd9Sstevel@tonic-gate smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...) 426*7c478bd9Sstevel@tonic-gate #else /* SM_VA_STD */ 427*7c478bd9Sstevel@tonic-gate smfi_setmlreply(ctx, rcode, xcode, va_alist) 428*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 429*7c478bd9Sstevel@tonic-gate const char *rcode; 430*7c478bd9Sstevel@tonic-gate const char *xcode; 431*7c478bd9Sstevel@tonic-gate va_dcl 432*7c478bd9Sstevel@tonic-gate #endif /* SM_VA_STD */ 433*7c478bd9Sstevel@tonic-gate { 434*7c478bd9Sstevel@tonic-gate size_t len; 435*7c478bd9Sstevel@tonic-gate size_t rlen; 436*7c478bd9Sstevel@tonic-gate int args; 437*7c478bd9Sstevel@tonic-gate char *buf, *txt; 438*7c478bd9Sstevel@tonic-gate const char *xc; 439*7c478bd9Sstevel@tonic-gate char repl[16]; 440*7c478bd9Sstevel@tonic-gate SM_VA_LOCAL_DECL 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate if (rcode == NULL || ctx == NULL) 443*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate /* ### <sp> */ 446*7c478bd9Sstevel@tonic-gate len = strlen(rcode) + 1; 447*7c478bd9Sstevel@tonic-gate if (len != 4) 448*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 449*7c478bd9Sstevel@tonic-gate if ((rcode[0] != '4' && rcode[0] != '5') || 450*7c478bd9Sstevel@tonic-gate !isascii(rcode[1]) || !isdigit(rcode[1]) || 451*7c478bd9Sstevel@tonic-gate !isascii(rcode[2]) || !isdigit(rcode[2])) 452*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 453*7c478bd9Sstevel@tonic-gate if (xcode != NULL) 454*7c478bd9Sstevel@tonic-gate { 455*7c478bd9Sstevel@tonic-gate if (!myisenhsc(xcode, '\0')) 456*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 457*7c478bd9Sstevel@tonic-gate xc = xcode; 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate else 460*7c478bd9Sstevel@tonic-gate { 461*7c478bd9Sstevel@tonic-gate if (rcode[0] == '4') 462*7c478bd9Sstevel@tonic-gate xc = "4.0.0"; 463*7c478bd9Sstevel@tonic-gate else 464*7c478bd9Sstevel@tonic-gate xc = "5.0.0"; 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate /* add trailing space */ 468*7c478bd9Sstevel@tonic-gate len += strlen(xc) + 1; 469*7c478bd9Sstevel@tonic-gate rlen = len; 470*7c478bd9Sstevel@tonic-gate args = 0; 471*7c478bd9Sstevel@tonic-gate SM_VA_START(ap, xcode); 472*7c478bd9Sstevel@tonic-gate while ((txt = SM_VA_ARG(ap, char *)) != NULL) 473*7c478bd9Sstevel@tonic-gate { 474*7c478bd9Sstevel@tonic-gate size_t tl; 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate tl = strlen(txt); 477*7c478bd9Sstevel@tonic-gate if (tl > MAXREPLYLEN) 478*7c478bd9Sstevel@tonic-gate break; 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate /* this text, reply codes, \r\n */ 481*7c478bd9Sstevel@tonic-gate len += tl + 2 + rlen; 482*7c478bd9Sstevel@tonic-gate if (++args > MAXREPLIES) 483*7c478bd9Sstevel@tonic-gate break; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate /* XXX check also for unprintable chars? */ 486*7c478bd9Sstevel@tonic-gate if (strpbrk(txt, "\r\n") != NULL) 487*7c478bd9Sstevel@tonic-gate break; 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate SM_VA_END(ap); 490*7c478bd9Sstevel@tonic-gate if (txt != NULL) 491*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate /* trailing '\0' */ 494*7c478bd9Sstevel@tonic-gate ++len; 495*7c478bd9Sstevel@tonic-gate buf = malloc(len); 496*7c478bd9Sstevel@tonic-gate if (buf == NULL) 497*7c478bd9Sstevel@tonic-gate return MI_FAILURE; /* oops */ 498*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc); 499*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-", 500*7c478bd9Sstevel@tonic-gate xc, " "); 501*7c478bd9Sstevel@tonic-gate SM_VA_START(ap, xcode); 502*7c478bd9Sstevel@tonic-gate txt = SM_VA_ARG(ap, char *); 503*7c478bd9Sstevel@tonic-gate if (txt != NULL) 504*7c478bd9Sstevel@tonic-gate { 505*7c478bd9Sstevel@tonic-gate (void) sm_strlcat2(buf, " ", txt, len); 506*7c478bd9Sstevel@tonic-gate while ((txt = SM_VA_ARG(ap, char *)) != NULL) 507*7c478bd9Sstevel@tonic-gate { 508*7c478bd9Sstevel@tonic-gate if (--args <= 1) 509*7c478bd9Sstevel@tonic-gate repl[3] = ' '; 510*7c478bd9Sstevel@tonic-gate (void) sm_strlcat2(buf, "\r\n", repl, len); 511*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(buf, txt, len); 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate if (ctx->ctx_reply != NULL) 515*7c478bd9Sstevel@tonic-gate free(ctx->ctx_reply); 516*7c478bd9Sstevel@tonic-gate ctx->ctx_reply = buf; 517*7c478bd9Sstevel@tonic-gate SM_VA_END(ap); 518*7c478bd9Sstevel@tonic-gate return MI_SUCCESS; 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate /* 522*7c478bd9Sstevel@tonic-gate ** SMFI_SETPRIV -- set private data 523*7c478bd9Sstevel@tonic-gate ** 524*7c478bd9Sstevel@tonic-gate ** Parameters: 525*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 526*7c478bd9Sstevel@tonic-gate ** privatedata -- pointer to private data 527*7c478bd9Sstevel@tonic-gate ** 528*7c478bd9Sstevel@tonic-gate ** Returns: 529*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 530*7c478bd9Sstevel@tonic-gate */ 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate int 533*7c478bd9Sstevel@tonic-gate smfi_setpriv(ctx, privatedata) 534*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 535*7c478bd9Sstevel@tonic-gate void *privatedata; 536*7c478bd9Sstevel@tonic-gate { 537*7c478bd9Sstevel@tonic-gate if (ctx == NULL) 538*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 539*7c478bd9Sstevel@tonic-gate ctx->ctx_privdata = privatedata; 540*7c478bd9Sstevel@tonic-gate return MI_SUCCESS; 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate /* 544*7c478bd9Sstevel@tonic-gate ** SMFI_GETPRIV -- get private data 545*7c478bd9Sstevel@tonic-gate ** 546*7c478bd9Sstevel@tonic-gate ** Parameters: 547*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 548*7c478bd9Sstevel@tonic-gate ** 549*7c478bd9Sstevel@tonic-gate ** Returns: 550*7c478bd9Sstevel@tonic-gate ** pointer to private data 551*7c478bd9Sstevel@tonic-gate */ 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate void * 554*7c478bd9Sstevel@tonic-gate smfi_getpriv(ctx) 555*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 556*7c478bd9Sstevel@tonic-gate { 557*7c478bd9Sstevel@tonic-gate if (ctx == NULL) 558*7c478bd9Sstevel@tonic-gate return NULL; 559*7c478bd9Sstevel@tonic-gate return ctx->ctx_privdata; 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate /* 563*7c478bd9Sstevel@tonic-gate ** SMFI_GETSYMVAL -- get the value of a macro 564*7c478bd9Sstevel@tonic-gate ** 565*7c478bd9Sstevel@tonic-gate ** See explanation in mfapi.h about layout of the structures. 566*7c478bd9Sstevel@tonic-gate ** 567*7c478bd9Sstevel@tonic-gate ** Parameters: 568*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 569*7c478bd9Sstevel@tonic-gate ** symname -- name of macro 570*7c478bd9Sstevel@tonic-gate ** 571*7c478bd9Sstevel@tonic-gate ** Returns: 572*7c478bd9Sstevel@tonic-gate ** value of macro (NULL in case of failure) 573*7c478bd9Sstevel@tonic-gate */ 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate char * 576*7c478bd9Sstevel@tonic-gate smfi_getsymval(ctx, symname) 577*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 578*7c478bd9Sstevel@tonic-gate char *symname; 579*7c478bd9Sstevel@tonic-gate { 580*7c478bd9Sstevel@tonic-gate int i; 581*7c478bd9Sstevel@tonic-gate char **s; 582*7c478bd9Sstevel@tonic-gate char one[2]; 583*7c478bd9Sstevel@tonic-gate char braces[4]; 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate if (ctx == NULL || symname == NULL || *symname == '\0') 586*7c478bd9Sstevel@tonic-gate return NULL; 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}') 589*7c478bd9Sstevel@tonic-gate { 590*7c478bd9Sstevel@tonic-gate one[0] = symname[1]; 591*7c478bd9Sstevel@tonic-gate one[1] = '\0'; 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate else 594*7c478bd9Sstevel@tonic-gate one[0] = '\0'; 595*7c478bd9Sstevel@tonic-gate if (strlen(symname) == 1) 596*7c478bd9Sstevel@tonic-gate { 597*7c478bd9Sstevel@tonic-gate braces[0] = '{'; 598*7c478bd9Sstevel@tonic-gate braces[1] = *symname; 599*7c478bd9Sstevel@tonic-gate braces[2] = '}'; 600*7c478bd9Sstevel@tonic-gate braces[3] = '\0'; 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate else 603*7c478bd9Sstevel@tonic-gate braces[0] = '\0'; 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate /* search backwards through the macro array */ 606*7c478bd9Sstevel@tonic-gate for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i) 607*7c478bd9Sstevel@tonic-gate { 608*7c478bd9Sstevel@tonic-gate if ((s = ctx->ctx_mac_ptr[i]) == NULL || 609*7c478bd9Sstevel@tonic-gate ctx->ctx_mac_buf[i] == NULL) 610*7c478bd9Sstevel@tonic-gate continue; 611*7c478bd9Sstevel@tonic-gate while (s != NULL && *s != NULL) 612*7c478bd9Sstevel@tonic-gate { 613*7c478bd9Sstevel@tonic-gate if (strcmp(*s, symname) == 0) 614*7c478bd9Sstevel@tonic-gate return *++s; 615*7c478bd9Sstevel@tonic-gate if (one[0] != '\0' && strcmp(*s, one) == 0) 616*7c478bd9Sstevel@tonic-gate return *++s; 617*7c478bd9Sstevel@tonic-gate if (braces[0] != '\0' && strcmp(*s, braces) == 0) 618*7c478bd9Sstevel@tonic-gate return *++s; 619*7c478bd9Sstevel@tonic-gate ++s; /* skip over macro value */ 620*7c478bd9Sstevel@tonic-gate ++s; /* points to next macro name */ 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate return NULL; 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate /* 627*7c478bd9Sstevel@tonic-gate ** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature 628*7c478bd9Sstevel@tonic-gate ** timeouts during long milter-side operations 629*7c478bd9Sstevel@tonic-gate ** 630*7c478bd9Sstevel@tonic-gate ** Parameters: 631*7c478bd9Sstevel@tonic-gate ** ctx -- Opaque context structure 632*7c478bd9Sstevel@tonic-gate ** 633*7c478bd9Sstevel@tonic-gate ** Return value: 634*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 635*7c478bd9Sstevel@tonic-gate */ 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate int 638*7c478bd9Sstevel@tonic-gate smfi_progress(ctx) 639*7c478bd9Sstevel@tonic-gate SMFICTX *ctx; 640*7c478bd9Sstevel@tonic-gate { 641*7c478bd9Sstevel@tonic-gate struct timeval timeout; 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate if (ctx == NULL) 644*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 647*7c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0); 650*7c478bd9Sstevel@tonic-gate } 651