smfi.c revision 64562
1235368Sgnn/* 2235368Sgnn * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. 3235368Sgnn * All rights reserved. 4235368Sgnn * 5235368Sgnn * By using this file, you agree to the terms and conditions set 6235368Sgnn * forth in the LICENSE file which can be found at the top level of 7235368Sgnn * the sendmail distribution. 8235368Sgnn * 9235368Sgnn */ 10235368Sgnn 11235368Sgnn#ifndef lint 12235368Sgnnstatic char id[] = "@(#)$Id: smfi.c,v 8.28.4.6 2000/06/28 23:48:56 gshapiro Exp $"; 13235368Sgnn#endif /* ! lint */ 14235368Sgnn 15235368Sgnn#if _FFR_MILTER 16235368Sgnn#include "libmilter.h" 17235368Sgnn#include "sendmail/useful.h" 18235368Sgnn 19235368Sgnn/* 20235368Sgnn** SMFI_ADDHEADER -- send a new header to the MTA 21235368Sgnn** 22235368Sgnn** Parameters: 23235368Sgnn** ctx -- Opaque context structure 24235368Sgnn** headerf -- Header field name 25235368Sgnn** headerv -- Header field value 26235368Sgnn** 27235368Sgnn** Returns: 28235368Sgnn** MI_SUCCESS/MI_FAILURE 29235368Sgnn*/ 30235368Sgnn 31235368Sgnnint 32235368Sgnnsmfi_addheader(ctx, headerf, headerv) 33235368Sgnn SMFICTX *ctx; 34235368Sgnn char *headerf; 35235368Sgnn char *headerv; 36235368Sgnn{ 37235368Sgnn /* do we want to copy the stuff or have a special mi_wr_cmd call? */ 38235368Sgnn size_t len, l1, l2; 39235368Sgnn int r; 40235368Sgnn char *buf; 41235368Sgnn struct timeval timeout; 42235368Sgnn 43235368Sgnn if (headerf == NULL || *headerf == '\0' || headerv == NULL) 44235368Sgnn return MI_FAILURE; 45235368Sgnn if (!mi_sendok(ctx, SMFIF_ADDHDRS)) 46235368Sgnn return MI_FAILURE; 47235368Sgnn timeout.tv_sec = ctx->ctx_timeout; 48235368Sgnn timeout.tv_usec = 0; 49235368Sgnn l1 = strlen(headerf); 50235368Sgnn l2 = strlen(headerv); 51235368Sgnn len = l1 + l2 + 2; 52235368Sgnn buf = malloc(len); 53235368Sgnn if (buf == NULL) 54235368Sgnn return MI_FAILURE; 55235368Sgnn (void) memcpy(buf, headerf, l1 + 1); 56235368Sgnn (void) memcpy(buf + l1 + 1, headerv, l2 + 1); 57235368Sgnn r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDHEADER, buf, len); 58235368Sgnn free(buf); 59235368Sgnn return r; 60235368Sgnn} 61235368Sgnn 62235368Sgnn/* 63235368Sgnn** SMFI_CHGHEADER -- send a changed header to the MTA 64235368Sgnn** 65235368Sgnn** Parameters: 66235368Sgnn** ctx -- Opaque context structure 67235368Sgnn** headerf -- Header field name 68235368Sgnn** hdridx -- Header index value 69235368Sgnn** headerv -- Header field value 70235368Sgnn** 71235368Sgnn** Returns: 72235368Sgnn** MI_SUCCESS/MI_FAILURE 73*/ 74 75int 76smfi_chgheader(ctx, headerf, hdridx, headerv) 77 SMFICTX *ctx; 78 char *headerf; 79 mi_int32 hdridx; 80 char *headerv; 81{ 82 /* do we want to copy the stuff or have a special mi_wr_cmd call? */ 83 size_t len, l1, l2; 84 int r; 85 mi_int32 v; 86 char *buf; 87 struct timeval timeout; 88 89 if (headerf == NULL || *headerf == '\0') 90 return MI_FAILURE; 91 if (hdridx < 0) 92 return MI_FAILURE; 93 if (!mi_sendok(ctx, SMFIF_CHGHDRS)) 94 return MI_FAILURE; 95 timeout.tv_sec = ctx->ctx_timeout; 96 timeout.tv_usec = 0; 97 if (headerv == NULL) 98 headerv = ""; 99 l1 = strlen(headerf); 100 l2 = strlen(headerv); 101 len = l1 + l2 + 2 + MILTER_LEN_BYTES; 102 buf = malloc(len); 103 if (buf == NULL) 104 return MI_FAILURE; 105 v = htonl(hdridx); 106 (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES); 107 (void) memcpy(buf + MILTER_LEN_BYTES, headerf, l1 + 1); 108 (void) memcpy(buf + MILTER_LEN_BYTES + l1 + 1, headerv, l2 + 1); 109 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_CHGHEADER, buf, len); 110 free(buf); 111 return r; 112} 113/* 114** SMFI_ADDRCPT -- send an additional recipient to the MTA 115** 116** Parameters: 117** ctx -- Opaque context structure 118** rcpt -- recipient address 119** 120** Returns: 121** MI_SUCCESS/MI_FAILURE 122*/ 123 124int 125smfi_addrcpt(ctx, rcpt) 126 SMFICTX *ctx; 127 char *rcpt; 128{ 129 size_t len; 130 struct timeval timeout; 131 132 if (rcpt == NULL || *rcpt == '\0') 133 return MI_FAILURE; 134 if (!mi_sendok(ctx, SMFIF_ADDRCPT)) 135 return MI_FAILURE; 136 timeout.tv_sec = ctx->ctx_timeout; 137 timeout.tv_usec = 0; 138 len = strlen(rcpt) + 1; 139 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len); 140} 141/* 142** SMFI_DELRCPT -- send a recipient to be removed to the MTA 143** 144** Parameters: 145** ctx -- Opaque context structure 146** rcpt -- recipient address 147** 148** Returns: 149** MI_SUCCESS/MI_FAILURE 150*/ 151 152int 153smfi_delrcpt(ctx, rcpt) 154 SMFICTX *ctx; 155 char *rcpt; 156{ 157 size_t len; 158 struct timeval timeout; 159 160 if (rcpt == NULL || *rcpt == '\0') 161 return MI_FAILURE; 162 if (!mi_sendok(ctx, SMFIF_DELRCPT)) 163 return MI_FAILURE; 164 timeout.tv_sec = ctx->ctx_timeout; 165 timeout.tv_usec = 0; 166 len = strlen(rcpt) + 1; 167 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len); 168} 169/* 170** SMFI_REPLACEBODY -- send a body chunk to the MTA 171** 172** Parameters: 173** ctx -- Opaque context structure 174** bodyp -- body chunk 175** bodylen -- length of body chunk 176** 177** Returns: 178** MI_SUCCESS/MI_FAILURE 179*/ 180 181int 182smfi_replacebody(ctx, bodyp, bodylen) 183 SMFICTX *ctx; 184 u_char *bodyp; 185 int bodylen; 186{ 187 int len, off, r; 188 struct timeval timeout; 189 190 if (bodyp == NULL && bodylen > 0) 191 return MI_FAILURE; 192 if (!mi_sendok(ctx, SMFIF_CHGBODY)) 193 return MI_FAILURE; 194 timeout.tv_sec = ctx->ctx_timeout; 195 timeout.tv_usec = 0; 196 197 /* split body chunk if necessary */ 198 off = 0; 199 while (bodylen > 0) 200 { 201 len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE : 202 bodylen; 203 if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY, 204 (char *) (bodyp + off), len)) != MI_SUCCESS) 205 return r; 206 off += len; 207 bodylen -= len; 208 } 209 return MI_SUCCESS; 210} 211/* 212** MYISENHSC -- check whether a string contains an enhanced status code 213** 214** Parameters: 215** s -- string with possible enhanced status code. 216** delim -- delim for enhanced status code. 217** 218** Returns: 219** 0 -- no enhanced status code. 220** >4 -- length of enhanced status code. 221** 222** Side Effects: 223** none. 224*/ 225static int 226myisenhsc(s, delim) 227 const char *s; 228 int delim; 229{ 230 int l, h; 231 232 if (s == NULL) 233 return 0; 234 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 235 return 0; 236 h = 0; 237 l = 2; 238 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 239 ++h; 240 if (h == 0 || s[l + h] != '.') 241 return 0; 242 l += h + 1; 243 h = 0; 244 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 245 ++h; 246 if (h == 0 || s[l + h] != delim) 247 return 0; 248 return l + h; 249} 250/* 251** SMFI_SETREPLY -- set the reply code for the next reply to the MTA 252** 253** Parameters: 254** ctx -- Opaque context structure 255** rcode -- The three-digit (RFC 821) SMTP reply code. 256** xcode -- The extended (RFC 2034) reply code. 257** message -- The text part of the SMTP reply. 258** 259** Returns: 260** MI_SUCCESS/MI_FAILURE 261*/ 262 263int 264smfi_setreply(ctx, rcode, xcode, message) 265 SMFICTX *ctx; 266 char *rcode; 267 char *xcode; 268 char *message; 269{ 270 size_t len, l1, l2, l3; 271 char *buf; 272 273 if (rcode == NULL || ctx == NULL) 274 return MI_FAILURE; 275 l1 = strlen(rcode) + 1; 276 if (l1 != 4) 277 return MI_FAILURE; 278 if ((rcode[0] != '4' && rcode[0] != '5') || 279 !isascii(rcode[1]) || !isdigit(rcode[1]) || 280 !isascii(rcode[2]) || !isdigit(rcode[2])) 281 return MI_FAILURE; 282 l2 = xcode == NULL ? 1 : strlen(xcode) + 1; 283 if (xcode != NULL && !myisenhsc(xcode, '\0')) 284 return MI_FAILURE; 285 l3 = message == NULL ? 1 : strlen(message) + 1; 286 len = l1 + l2 + l3; 287 buf = malloc(len); 288 if (buf == NULL) 289 return MI_FAILURE; /* oops */ 290 (void) snprintf(buf, len, "%s %s %s", rcode, 291 xcode == NULL ? "" : xcode, 292 message == NULL ? "" : message); 293 if (ctx->ctx_reply != NULL) 294 free(ctx->ctx_reply); 295 ctx->ctx_reply = buf; 296 return MI_SUCCESS; 297} 298/* 299** SMFI_SETPRIV -- set private data 300** 301** Parameters: 302** ctx -- Opaque context structure 303** privatedata -- pointer to private data 304** 305** Returns: 306** MI_SUCCESS/MI_FAILURE 307*/ 308 309int 310smfi_setpriv(ctx, privatedata) 311 SMFICTX *ctx; 312 void *privatedata; 313{ 314 if (ctx == NULL) 315 return MI_FAILURE; 316 ctx->ctx_privdata = privatedata; 317 return MI_SUCCESS; 318} 319/* 320** SMFI_GETPRIV -- get private data 321** 322** Parameters: 323** ctx -- Opaque context structure 324** 325** Returns: 326** pointer to private data 327*/ 328 329void * 330smfi_getpriv(ctx) 331 SMFICTX *ctx; 332{ 333 if (ctx == NULL) 334 return NULL; 335 return ctx->ctx_privdata; 336} 337/* 338** SMFI_GETSYMVAL -- get the value of a macro 339** 340** See explanation in mfapi.h about layout of the structures. 341** 342** Parameters: 343** ctx -- Opaque context structure 344** symname -- name of macro 345** 346** Returns: 347** value of macro (NULL in case of failure) 348*/ 349 350char * 351smfi_getsymval(ctx, symname) 352 SMFICTX *ctx; 353 char *symname; 354{ 355 int i; 356 char **s; 357 char one[2]; 358 char braces[4]; 359 360 if (ctx == NULL || symname == NULL || *symname == '\0') 361 return NULL; 362 363 if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}') 364 { 365 one[0] = symname[1]; 366 one[1] = '\0'; 367 } 368 else 369 one[0] = '\0'; 370 if (strlen(symname) == 1) 371 { 372 braces[0] = '{'; 373 braces[1] = *symname; 374 braces[2] = '}'; 375 braces[3] = '\0'; 376 } 377 else 378 braces[0] = '\0'; 379 380 /* search backwards through the macro array */ 381 for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i) 382 { 383 if ((s = ctx->ctx_mac_ptr[i]) == NULL || 384 ctx->ctx_mac_buf[i] == NULL) 385 continue; 386 while (s != NULL && *s != NULL) 387 { 388 if (strcmp(*s, symname) == 0) 389 return *++s; 390 if (one[0] != '\0' && strcmp(*s, one) == 0) 391 return *++s; 392 if (braces[0] != '\0' && strcmp(*s, braces) == 0) 393 return *++s; 394 ++s; /* skip over macro value */ 395 ++s; /* points to next macro name */ 396 } 397 } 398 return NULL; 399} 400#endif /* _FFR_MILTER */ 401