Use correct version number.
[dragonfly.git] / contrib / sendmail-8.13.7 / libmilter / smfi.c
blob63bf1743df9526737e68b7b26f6d8f106256da93
1 /*
2 * Copyright (c) 1999-2005 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
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.
9 */
11 #include <sm/gen.h>
12 SM_RCSID("@(#)$Id: smfi.c,v 8.74 2005/03/30 00:44:07 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
26 ** Parameters:
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 ** Returns:
35 ** MI_SUCCESS/MI_FAILURE
38 static int
39 smfi_header(ctx, cmd, hdridx, headerf, headerv)
40 SMFICTX *ctx;
41 int cmd;
42 int hdridx;
43 char *headerf;
44 char *headerv;
46 size_t len, l1, l2, offset;
47 int r;
48 mi_int32 v;
49 char *buf;
50 struct timeval timeout;
52 if (headerf == NULL || *headerf == '\0' || headerv == NULL)
53 return MI_FAILURE;
54 timeout.tv_sec = ctx->ctx_timeout;
55 timeout.tv_usec = 0;
56 l1 = strlen(headerf) + 1;
57 l2 = strlen(headerv) + 1;
58 len = l1 + l2;
59 if (hdridx >= 0)
60 len += MILTER_LEN_BYTES;
61 buf = malloc(len);
62 if (buf == NULL)
63 return MI_FAILURE;
64 offset = 0;
65 if (hdridx >= 0)
67 v = htonl(hdridx);
68 (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
69 offset += MILTER_LEN_BYTES;
71 (void) memcpy(buf + offset, headerf, l1);
72 (void) memcpy(buf + offset + l1, headerv, l2);
73 r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
74 free(buf);
75 return r;
79 ** SMFI_ADDHEADER -- send a new header to the MTA
81 ** Parameters:
82 ** ctx -- Opaque context structure
83 ** headerf -- Header field name
84 ** headerv -- Header field value
86 ** Returns:
87 ** MI_SUCCESS/MI_FAILURE
90 int
91 smfi_addheader(ctx, headerf, headerv)
92 SMFICTX *ctx;
93 char *headerf;
94 char *headerv;
96 if (!mi_sendok(ctx, SMFIF_ADDHDRS))
97 return MI_FAILURE;
99 return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv);
103 ** SMFI_INSHEADER -- send a new header to the MTA (to be inserted)
105 ** Parameters:
106 ** ctx -- Opaque context structure
107 ** hdridx -- index into header list where insertion should occur
108 ** headerf -- Header field name
109 ** headerv -- Header field value
111 ** Returns:
112 ** MI_SUCCESS/MI_FAILURE
116 smfi_insheader(ctx, hdridx, headerf, headerv)
117 SMFICTX *ctx;
118 int hdridx;
119 char *headerf;
120 char *headerv;
122 if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0)
123 return MI_FAILURE;
125 return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv);
129 ** SMFI_CHGHEADER -- send a changed header to the MTA
131 ** Parameters:
132 ** ctx -- Opaque context structure
133 ** headerf -- Header field name
134 ** hdridx -- Header index value
135 ** headerv -- Header field value
137 ** Returns:
138 ** MI_SUCCESS/MI_FAILURE
142 smfi_chgheader(ctx, headerf, hdridx, headerv)
143 SMFICTX *ctx;
144 char *headerf;
145 mi_int32 hdridx;
146 char *headerv;
148 if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0)
149 return MI_FAILURE;
150 if (headerv == NULL)
151 headerv = "";
153 return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv);
157 ** SMFI_ADDRCPT -- send an additional recipient to the MTA
159 ** Parameters:
160 ** ctx -- Opaque context structure
161 ** rcpt -- recipient address
163 ** Returns:
164 ** MI_SUCCESS/MI_FAILURE
168 smfi_addrcpt(ctx, rcpt)
169 SMFICTX *ctx;
170 char *rcpt;
172 size_t len;
173 struct timeval timeout;
175 if (rcpt == NULL || *rcpt == '\0')
176 return MI_FAILURE;
177 if (!mi_sendok(ctx, SMFIF_ADDRCPT))
178 return MI_FAILURE;
179 timeout.tv_sec = ctx->ctx_timeout;
180 timeout.tv_usec = 0;
181 len = strlen(rcpt) + 1;
182 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
186 ** SMFI_DELRCPT -- send a recipient to be removed to the MTA
188 ** Parameters:
189 ** ctx -- Opaque context structure
190 ** rcpt -- recipient address
192 ** Returns:
193 ** MI_SUCCESS/MI_FAILURE
197 smfi_delrcpt(ctx, rcpt)
198 SMFICTX *ctx;
199 char *rcpt;
201 size_t len;
202 struct timeval timeout;
204 if (rcpt == NULL || *rcpt == '\0')
205 return MI_FAILURE;
206 if (!mi_sendok(ctx, SMFIF_DELRCPT))
207 return MI_FAILURE;
208 timeout.tv_sec = ctx->ctx_timeout;
209 timeout.tv_usec = 0;
210 len = strlen(rcpt) + 1;
211 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
215 ** SMFI_REPLACEBODY -- send a body chunk to the MTA
217 ** Parameters:
218 ** ctx -- Opaque context structure
219 ** bodyp -- body chunk
220 ** bodylen -- length of body chunk
222 ** Returns:
223 ** MI_SUCCESS/MI_FAILURE
227 smfi_replacebody(ctx, bodyp, bodylen)
228 SMFICTX *ctx;
229 unsigned char *bodyp;
230 int bodylen;
232 int len, off, r;
233 struct timeval timeout;
235 if (bodylen < 0 ||
236 (bodyp == NULL && bodylen > 0))
237 return MI_FAILURE;
238 if (!mi_sendok(ctx, SMFIF_CHGBODY))
239 return MI_FAILURE;
240 timeout.tv_sec = ctx->ctx_timeout;
241 timeout.tv_usec = 0;
243 /* split body chunk if necessary */
244 off = 0;
247 len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
248 bodylen;
249 if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
250 (char *) (bodyp + off), len)) != MI_SUCCESS)
251 return r;
252 off += len;
253 bodylen -= len;
254 } while (bodylen > 0);
255 return MI_SUCCESS;
259 ** SMFI_QUARANTINE -- quarantine an envelope
261 ** Parameters:
262 ** ctx -- Opaque context structure
263 ** reason -- why?
265 ** Returns:
266 ** MI_SUCCESS/MI_FAILURE
270 smfi_quarantine(ctx, reason)
271 SMFICTX *ctx;
272 char *reason;
274 size_t len;
275 int r;
276 char *buf;
277 struct timeval timeout;
279 if (reason == NULL || *reason == '\0')
280 return MI_FAILURE;
281 if (!mi_sendok(ctx, SMFIF_QUARANTINE))
282 return MI_FAILURE;
283 timeout.tv_sec = ctx->ctx_timeout;
284 timeout.tv_usec = 0;
285 len = strlen(reason) + 1;
286 buf = malloc(len);
287 if (buf == NULL)
288 return MI_FAILURE;
289 (void) memcpy(buf, reason, len);
290 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len);
291 free(buf);
292 return r;
296 ** MYISENHSC -- check whether a string contains an enhanced status code
298 ** Parameters:
299 ** s -- string with possible enhanced status code.
300 ** delim -- delim for enhanced status code.
302 ** Returns:
303 ** 0 -- no enhanced status code.
304 ** >4 -- length of enhanced status code.
306 ** Side Effects:
307 ** none.
310 static int
311 myisenhsc(s, delim)
312 const char *s;
313 int delim;
315 int l, h;
317 if (s == NULL)
318 return 0;
319 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
320 return 0;
321 h = 0;
322 l = 2;
323 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
324 ++h;
325 if (h == 0 || s[l + h] != '.')
326 return 0;
327 l += h + 1;
328 h = 0;
329 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
330 ++h;
331 if (h == 0 || s[l + h] != delim)
332 return 0;
333 return l + h;
337 ** SMFI_SETREPLY -- set the reply code for the next reply to the MTA
339 ** Parameters:
340 ** ctx -- Opaque context structure
341 ** rcode -- The three-digit (RFC 821) SMTP reply code.
342 ** xcode -- The extended (RFC 2034) reply code.
343 ** message -- The text part of the SMTP reply.
345 ** Returns:
346 ** MI_SUCCESS/MI_FAILURE
350 smfi_setreply(ctx, rcode, xcode, message)
351 SMFICTX *ctx;
352 char *rcode;
353 char *xcode;
354 char *message;
356 size_t len;
357 char *buf;
359 if (rcode == NULL || ctx == NULL)
360 return MI_FAILURE;
362 /* ### <sp> \0 */
363 len = strlen(rcode) + 2;
364 if (len != 5)
365 return MI_FAILURE;
366 if ((rcode[0] != '4' && rcode[0] != '5') ||
367 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
368 !isascii(rcode[2]) || !isdigit(rcode[2]))
369 return MI_FAILURE;
370 if (xcode != NULL)
372 if (!myisenhsc(xcode, '\0'))
373 return MI_FAILURE;
374 len += strlen(xcode) + 1;
376 if (message != NULL)
378 size_t ml;
380 /* XXX check also for unprintable chars? */
381 if (strpbrk(message, "\r\n") != NULL)
382 return MI_FAILURE;
383 ml = strlen(message);
384 if (ml > MAXREPLYLEN)
385 return MI_FAILURE;
386 len += ml + 1;
388 buf = malloc(len);
389 if (buf == NULL)
390 return MI_FAILURE; /* oops */
391 (void) sm_strlcpy(buf, rcode, len);
392 (void) sm_strlcat(buf, " ", len);
393 if (xcode != NULL)
394 (void) sm_strlcat(buf, xcode, len);
395 if (message != NULL)
397 if (xcode != NULL)
398 (void) sm_strlcat(buf, " ", len);
399 (void) sm_strlcat(buf, message, len);
401 if (ctx->ctx_reply != NULL)
402 free(ctx->ctx_reply);
403 ctx->ctx_reply = buf;
404 return MI_SUCCESS;
408 ** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA
410 ** Parameters:
411 ** ctx -- Opaque context structure
412 ** rcode -- The three-digit (RFC 821) SMTP reply code.
413 ** xcode -- The extended (RFC 2034) reply code.
414 ** txt, ... -- The text part of the SMTP reply,
415 ** MUST be terminated with NULL.
417 ** Returns:
418 ** MI_SUCCESS/MI_FAILURE
422 #if SM_VA_STD
423 smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
424 #else /* SM_VA_STD */
425 smfi_setmlreply(ctx, rcode, xcode, va_alist)
426 SMFICTX *ctx;
427 const char *rcode;
428 const char *xcode;
429 va_dcl
430 #endif /* SM_VA_STD */
432 size_t len;
433 size_t rlen;
434 int args;
435 char *buf, *txt;
436 const char *xc;
437 char repl[16];
438 SM_VA_LOCAL_DECL
440 if (rcode == NULL || ctx == NULL)
441 return MI_FAILURE;
443 /* ### <sp> */
444 len = strlen(rcode) + 1;
445 if (len != 4)
446 return MI_FAILURE;
447 if ((rcode[0] != '4' && rcode[0] != '5') ||
448 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
449 !isascii(rcode[2]) || !isdigit(rcode[2]))
450 return MI_FAILURE;
451 if (xcode != NULL)
453 if (!myisenhsc(xcode, '\0'))
454 return MI_FAILURE;
455 xc = xcode;
457 else
459 if (rcode[0] == '4')
460 xc = "4.0.0";
461 else
462 xc = "5.0.0";
465 /* add trailing space */
466 len += strlen(xc) + 1;
467 rlen = len;
468 args = 0;
469 SM_VA_START(ap, xcode);
470 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
472 size_t tl;
474 tl = strlen(txt);
475 if (tl > MAXREPLYLEN)
476 break;
478 /* this text, reply codes, \r\n */
479 len += tl + 2 + rlen;
480 if (++args > MAXREPLIES)
481 break;
483 /* XXX check also for unprintable chars? */
484 if (strpbrk(txt, "\r\n") != NULL)
485 break;
487 SM_VA_END(ap);
488 if (txt != NULL)
489 return MI_FAILURE;
491 /* trailing '\0' */
492 ++len;
493 buf = malloc(len);
494 if (buf == NULL)
495 return MI_FAILURE; /* oops */
496 (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc);
497 (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-",
498 xc, " ");
499 SM_VA_START(ap, xcode);
500 txt = SM_VA_ARG(ap, char *);
501 if (txt != NULL)
503 (void) sm_strlcat2(buf, " ", txt, len);
504 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
506 if (--args <= 1)
507 repl[3] = ' ';
508 (void) sm_strlcat2(buf, "\r\n", repl, len);
509 (void) sm_strlcat(buf, txt, len);
512 if (ctx->ctx_reply != NULL)
513 free(ctx->ctx_reply);
514 ctx->ctx_reply = buf;
515 SM_VA_END(ap);
516 return MI_SUCCESS;
520 ** SMFI_SETPRIV -- set private data
522 ** Parameters:
523 ** ctx -- Opaque context structure
524 ** privatedata -- pointer to private data
526 ** Returns:
527 ** MI_SUCCESS/MI_FAILURE
531 smfi_setpriv(ctx, privatedata)
532 SMFICTX *ctx;
533 void *privatedata;
535 if (ctx == NULL)
536 return MI_FAILURE;
537 ctx->ctx_privdata = privatedata;
538 return MI_SUCCESS;
542 ** SMFI_GETPRIV -- get private data
544 ** Parameters:
545 ** ctx -- Opaque context structure
547 ** Returns:
548 ** pointer to private data
551 void *
552 smfi_getpriv(ctx)
553 SMFICTX *ctx;
555 if (ctx == NULL)
556 return NULL;
557 return ctx->ctx_privdata;
561 ** SMFI_GETSYMVAL -- get the value of a macro
563 ** See explanation in mfapi.h about layout of the structures.
565 ** Parameters:
566 ** ctx -- Opaque context structure
567 ** symname -- name of macro
569 ** Returns:
570 ** value of macro (NULL in case of failure)
573 char *
574 smfi_getsymval(ctx, symname)
575 SMFICTX *ctx;
576 char *symname;
578 int i;
579 char **s;
580 char one[2];
581 char braces[4];
583 if (ctx == NULL || symname == NULL || *symname == '\0')
584 return NULL;
586 if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
588 one[0] = symname[1];
589 one[1] = '\0';
591 else
592 one[0] = '\0';
593 if (strlen(symname) == 1)
595 braces[0] = '{';
596 braces[1] = *symname;
597 braces[2] = '}';
598 braces[3] = '\0';
600 else
601 braces[0] = '\0';
603 /* search backwards through the macro array */
604 for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
606 if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
607 ctx->ctx_mac_buf[i] == NULL)
608 continue;
609 while (s != NULL && *s != NULL)
611 if (strcmp(*s, symname) == 0)
612 return *++s;
613 if (one[0] != '\0' && strcmp(*s, one) == 0)
614 return *++s;
615 if (braces[0] != '\0' && strcmp(*s, braces) == 0)
616 return *++s;
617 ++s; /* skip over macro value */
618 ++s; /* points to next macro name */
621 return NULL;
625 ** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature
626 ** timeouts during long milter-side operations
628 ** Parameters:
629 ** ctx -- Opaque context structure
631 ** Return value:
632 ** MI_SUCCESS/MI_FAILURE
636 smfi_progress(ctx)
637 SMFICTX *ctx;
639 struct timeval timeout;
641 if (ctx == NULL)
642 return MI_FAILURE;
644 timeout.tv_sec = ctx->ctx_timeout;
645 timeout.tv_usec = 0;
647 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0);