1 /* 2 * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 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. 8 * 9 */ 10 11 #ifndef lint 12 static char id[] = "@(#)$Id: smfi.c,v 8.28.4.6 2000/06/28 23:48:56 gshapiro Exp $"; 13 #endif /* ! lint */ 14 15 #if _FFR_MILTER 16 #include "libmilter.h" 17 #include "sendmail/useful.h" 18 19 /* 20 ** SMFI_ADDHEADER -- send a new header to the MTA 21 ** 22 ** Parameters: 23 ** ctx -- Opaque context structure 24 ** headerf -- Header field name 25 ** headerv -- Header field value 26 ** 27 ** Returns: 28 ** MI_SUCCESS/MI_FAILURE 29 */ 30 31 int 32 smfi_addheader(ctx, headerf, headerv) 33 SMFICTX *ctx; 34 char *headerf; 35 char *headerv; 36 { 37 /* do we want to copy the stuff or have a special mi_wr_cmd call? */ 38 size_t len, l1, l2; 39 int r; 40 char *buf; 41 struct timeval timeout; 42 43 if (headerf == NULL || *headerf == '\0' || headerv == NULL) 44 return MI_FAILURE; 45 if (!mi_sendok(ctx, SMFIF_ADDHDRS)) 46 return MI_FAILURE; 47 timeout.tv_sec = ctx->ctx_timeout; 48 timeout.tv_usec = 0; 49 l1 = strlen(headerf); 50 l2 = strlen(headerv); 51 len = l1 + l2 + 2; 52 buf = malloc(len); 53 if (buf == NULL) 54 return MI_FAILURE; 55 (void) memcpy(buf, headerf, l1 + 1); 56 (void) memcpy(buf + l1 + 1, headerv, l2 + 1); 57 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDHEADER, buf, len); 58 free(buf); 59 return r; 60 } 61 62 /* 63 ** SMFI_CHGHEADER -- send a changed header to the MTA 64 ** 65 ** Parameters: 66 ** ctx -- Opaque context structure 67 ** headerf -- Header field name 68 ** hdridx -- Header index value 69 ** headerv -- Header field value 70 ** 71 ** Returns: 72 ** MI_SUCCESS/MI_FAILURE 73 */ 74 75 int 76 smfi_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 124 int 125 smfi_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 152 int 153 smfi_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 181 int 182 smfi_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 */ 225 static int 226 myisenhsc(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 263 int 264 smfi_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 309 int 310 smfi_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 329 void * 330 smfi_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 350 char * 351 smfi_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