1 /*
2 * Copyright (c) 1999-2007 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 #pragma ident "%Z%%M% %I% %E% SMI"
12
13 #include <sm/gen.h>
14 SM_RCSID("@(#)$Id: smfi.c,v 8.83 2007/04/23 16:44:39 ca Exp $")
15 #include <sm/varargs.h>
16 #include "libmilter.h"
17
18 static int smfi_header __P((SMFICTX *, int, int, char *, char *));
19 static int myisenhsc __P((const char *, int));
20
21 /* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */
22 #define MAXREPLYLEN 980 /* max. length of a reply string */
23 #define MAXREPLIES 32 /* max. number of reply strings */
24
25 /*
26 ** SMFI_HEADER -- send a header to the MTA
27 **
28 ** Parameters:
29 ** ctx -- Opaque context structure
30 ** cmd -- Header modification command
31 ** hdridx -- Header index
32 ** headerf -- Header field name
33 ** headerv -- Header field value
34 **
35 ** Returns:
36 ** MI_SUCCESS/MI_FAILURE
37 */
38
39 static int
smfi_header(ctx,cmd,hdridx,headerf,headerv)40 smfi_header(ctx, cmd, hdridx, headerf, headerv)
41 SMFICTX *ctx;
42 int cmd;
43 int hdridx;
44 char *headerf;
45 char *headerv;
46 {
47 size_t len, l1, l2, offset;
48 int r;
49 mi_int32 v;
50 char *buf;
51 struct timeval timeout;
52
53 if (headerf == NULL || *headerf == '\0' || headerv == NULL)
54 return MI_FAILURE;
55 timeout.tv_sec = ctx->ctx_timeout;
56 timeout.tv_usec = 0;
57 l1 = strlen(headerf) + 1;
58 l2 = strlen(headerv) + 1;
59 len = l1 + l2;
60 if (hdridx >= 0)
61 len += MILTER_LEN_BYTES;
62 buf = malloc(len);
63 if (buf == NULL)
64 return MI_FAILURE;
65 offset = 0;
66 if (hdridx >= 0)
67 {
68 v = htonl(hdridx);
69 (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
70 offset += MILTER_LEN_BYTES;
71 }
72 (void) memcpy(buf + offset, headerf, l1);
73 (void) memcpy(buf + offset + l1, headerv, l2);
74 r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
75 free(buf);
76 return r;
77 }
78
79 /*
80 ** SMFI_ADDHEADER -- send a new header to the MTA
81 **
82 ** Parameters:
83 ** ctx -- Opaque context structure
84 ** headerf -- Header field name
85 ** headerv -- Header field value
86 **
87 ** Returns:
88 ** MI_SUCCESS/MI_FAILURE
89 */
90
91 int
smfi_addheader(ctx,headerf,headerv)92 smfi_addheader(ctx, headerf, headerv)
93 SMFICTX *ctx;
94 char *headerf;
95 char *headerv;
96 {
97 if (!mi_sendok(ctx, SMFIF_ADDHDRS))
98 return MI_FAILURE;
99
100 return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv);
101 }
102
103 /*
104 ** SMFI_INSHEADER -- send a new header to the MTA (to be inserted)
105 **
106 ** Parameters:
107 ** ctx -- Opaque context structure
108 ** hdridx -- index into header list where insertion should occur
109 ** headerf -- Header field name
110 ** headerv -- Header field value
111 **
112 ** Returns:
113 ** MI_SUCCESS/MI_FAILURE
114 */
115
116 int
smfi_insheader(ctx,hdridx,headerf,headerv)117 smfi_insheader(ctx, hdridx, headerf, headerv)
118 SMFICTX *ctx;
119 int hdridx;
120 char *headerf;
121 char *headerv;
122 {
123 if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0)
124 return MI_FAILURE;
125
126 return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv);
127 }
128
129 /*
130 ** SMFI_CHGHEADER -- send a changed header to the MTA
131 **
132 ** Parameters:
133 ** ctx -- Opaque context structure
134 ** headerf -- Header field name
135 ** hdridx -- Header index value
136 ** headerv -- Header field value
137 **
138 ** Returns:
139 ** MI_SUCCESS/MI_FAILURE
140 */
141
142 int
smfi_chgheader(ctx,headerf,hdridx,headerv)143 smfi_chgheader(ctx, headerf, hdridx, headerv)
144 SMFICTX *ctx;
145 char *headerf;
146 mi_int32 hdridx;
147 char *headerv;
148 {
149 if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0)
150 return MI_FAILURE;
151 if (headerv == NULL)
152 headerv = "";
153
154 return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv);
155 }
156
157 #if 0
158 /*
159 ** BUF_CRT_SEND -- construct buffer to send from arguments
160 **
161 ** Parameters:
162 ** ctx -- Opaque context structure
163 ** cmd -- command
164 ** arg0 -- first argument
165 ** argv -- list of arguments (NULL terminated)
166 **
167 ** Returns:
168 ** MI_SUCCESS/MI_FAILURE
169 */
170
171 static int
172 buf_crt_send __P((SMFICTX *, int cmd, char *, char **));
173
174 static int
175 buf_crt_send(ctx, cmd, arg0, argv)
176 SMFICTX *ctx;
177 int cmd;
178 char *arg0;
179 char **argv;
180 {
181 size_t len, l0, l1, offset;
182 int r;
183 char *buf, *arg, **argvl;
184 struct timeval timeout;
185
186 if (arg0 == NULL || *arg0 == '\0')
187 return MI_FAILURE;
188 timeout.tv_sec = ctx->ctx_timeout;
189 timeout.tv_usec = 0;
190 l0 = strlen(arg0) + 1;
191 len = l0;
192 argvl = argv;
193 while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0')
194 {
195 l1 = strlen(arg) + 1;
196 len += l1;
197 SM_ASSERT(len > l1);
198 }
199
200 buf = malloc(len);
201 if (buf == NULL)
202 return MI_FAILURE;
203 (void) memcpy(buf, arg0, l0);
204 offset = l0;
205
206 argvl = argv;
207 while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0')
208 {
209 l1 = strlen(arg) + 1;
210 SM_ASSERT(offset < len);
211 SM_ASSERT(offset + l1 <= len);
212 (void) memcpy(buf + offset, arg, l1);
213 offset += l1;
214 SM_ASSERT(offset > l1);
215 }
216
217 r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
218 free(buf);
219 return r;
220 }
221 #endif /* 0 */
222
223 /*
224 ** SEND2 -- construct buffer to send from arguments
225 **
226 ** Parameters:
227 ** ctx -- Opaque context structure
228 ** cmd -- command
229 ** arg0 -- first argument
230 ** argv -- list of arguments (NULL terminated)
231 **
232 ** Returns:
233 ** MI_SUCCESS/MI_FAILURE
234 */
235
236 static int
237 send2 __P((SMFICTX *, int cmd, char *, char *));
238
239 static int
send2(ctx,cmd,arg0,arg1)240 send2(ctx, cmd, arg0, arg1)
241 SMFICTX *ctx;
242 int cmd;
243 char *arg0;
244 char *arg1;
245 {
246 size_t len, l0, l1, offset;
247 int r;
248 char *buf;
249 struct timeval timeout;
250
251 if (arg0 == NULL || *arg0 == '\0')
252 return MI_FAILURE;
253 timeout.tv_sec = ctx->ctx_timeout;
254 timeout.tv_usec = 0;
255 l0 = strlen(arg0) + 1;
256 len = l0;
257 if (arg1 != NULL)
258 {
259 l1 = strlen(arg1) + 1;
260 len += l1;
261 SM_ASSERT(len > l1);
262 }
263
264 buf = malloc(len);
265 if (buf == NULL)
266 return MI_FAILURE;
267 (void) memcpy(buf, arg0, l0);
268 offset = l0;
269
270 if (arg1 != NULL)
271 {
272 l1 = strlen(arg1) + 1;
273 SM_ASSERT(offset < len);
274 SM_ASSERT(offset + l1 <= len);
275 (void) memcpy(buf + offset, arg1, l1);
276 offset += l1;
277 SM_ASSERT(offset > l1);
278 }
279
280 r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
281 free(buf);
282 return r;
283 }
284
285 /*
286 ** SMFI_CHGFROM -- change enveloper sender ("from") address
287 **
288 ** Parameters:
289 ** ctx -- Opaque context structure
290 ** from -- new envelope sender address ("MAIL From")
291 ** args -- ESMTP arguments
292 **
293 ** Returns:
294 ** MI_SUCCESS/MI_FAILURE
295 */
296
297 int
smfi_chgfrom(ctx,from,args)298 smfi_chgfrom(ctx, from, args)
299 SMFICTX *ctx;
300 char *from;
301 char *args;
302 {
303 if (from == NULL || *from == '\0')
304 return MI_FAILURE;
305 if (!mi_sendok(ctx, SMFIF_CHGFROM))
306 return MI_FAILURE;
307 return send2(ctx, SMFIR_CHGFROM, from, args);
308 }
309
310 /*
311 ** SMFI_SETSYMLIST -- set list of macros that the MTA should send.
312 **
313 ** Parameters:
314 ** ctx -- Opaque context structure
315 ** where -- SMTP stage
316 ** macros -- list of macros
317 **
318 ** Returns:
319 ** MI_SUCCESS/MI_FAILURE
320 */
321
322 int
smfi_setsymlist(ctx,where,macros)323 smfi_setsymlist(ctx, where, macros)
324 SMFICTX *ctx;
325 int where;
326 char *macros;
327 {
328 SM_ASSERT(ctx != NULL);
329
330 if (macros == NULL || *macros == '\0')
331 return MI_FAILURE;
332 if (where < SMFIM_FIRST || where > SMFIM_LAST)
333 return MI_FAILURE;
334 if (where < 0 || where >= MAX_MACROS_ENTRIES)
335 return MI_FAILURE;
336
337 if (ctx->ctx_mac_list[where] != NULL)
338 return MI_FAILURE;
339
340 ctx->ctx_mac_list[where] = strdup(macros);
341 if (ctx->ctx_mac_list[where] == NULL)
342 return MI_FAILURE;
343
344 return MI_SUCCESS;
345 }
346
347 /*
348 ** SMFI_ADDRCPT_PAR -- send an additional recipient to the MTA
349 **
350 ** Parameters:
351 ** ctx -- Opaque context structure
352 ** rcpt -- recipient address
353 ** args -- ESMTP arguments
354 **
355 ** Returns:
356 ** MI_SUCCESS/MI_FAILURE
357 */
358
359 int
smfi_addrcpt_par(ctx,rcpt,args)360 smfi_addrcpt_par(ctx, rcpt, args)
361 SMFICTX *ctx;
362 char *rcpt;
363 char *args;
364 {
365 if (rcpt == NULL || *rcpt == '\0')
366 return MI_FAILURE;
367 if (!mi_sendok(ctx, SMFIF_ADDRCPT_PAR))
368 return MI_FAILURE;
369 return send2(ctx, SMFIR_ADDRCPT_PAR, rcpt, args);
370 }
371
372 /*
373 ** SMFI_ADDRCPT -- send an additional recipient to the MTA
374 **
375 ** Parameters:
376 ** ctx -- Opaque context structure
377 ** rcpt -- recipient address
378 **
379 ** Returns:
380 ** MI_SUCCESS/MI_FAILURE
381 */
382
383 int
smfi_addrcpt(ctx,rcpt)384 smfi_addrcpt(ctx, rcpt)
385 SMFICTX *ctx;
386 char *rcpt;
387 {
388 size_t len;
389 struct timeval timeout;
390
391 if (rcpt == NULL || *rcpt == '\0')
392 return MI_FAILURE;
393 if (!mi_sendok(ctx, SMFIF_ADDRCPT))
394 return MI_FAILURE;
395 timeout.tv_sec = ctx->ctx_timeout;
396 timeout.tv_usec = 0;
397 len = strlen(rcpt) + 1;
398 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
399 }
400
401 /*
402 ** SMFI_DELRCPT -- send a recipient to be removed to the MTA
403 **
404 ** Parameters:
405 ** ctx -- Opaque context structure
406 ** rcpt -- recipient address
407 **
408 ** Returns:
409 ** MI_SUCCESS/MI_FAILURE
410 */
411
412 int
smfi_delrcpt(ctx,rcpt)413 smfi_delrcpt(ctx, rcpt)
414 SMFICTX *ctx;
415 char *rcpt;
416 {
417 size_t len;
418 struct timeval timeout;
419
420 if (rcpt == NULL || *rcpt == '\0')
421 return MI_FAILURE;
422 if (!mi_sendok(ctx, SMFIF_DELRCPT))
423 return MI_FAILURE;
424 timeout.tv_sec = ctx->ctx_timeout;
425 timeout.tv_usec = 0;
426 len = strlen(rcpt) + 1;
427 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
428 }
429
430 /*
431 ** SMFI_REPLACEBODY -- send a body chunk to the MTA
432 **
433 ** Parameters:
434 ** ctx -- Opaque context structure
435 ** bodyp -- body chunk
436 ** bodylen -- length of body chunk
437 **
438 ** Returns:
439 ** MI_SUCCESS/MI_FAILURE
440 */
441
442 int
smfi_replacebody(ctx,bodyp,bodylen)443 smfi_replacebody(ctx, bodyp, bodylen)
444 SMFICTX *ctx;
445 unsigned char *bodyp;
446 int bodylen;
447 {
448 int len, off, r;
449 struct timeval timeout;
450
451 if (bodylen < 0 ||
452 (bodyp == NULL && bodylen > 0))
453 return MI_FAILURE;
454 if (!mi_sendok(ctx, SMFIF_CHGBODY))
455 return MI_FAILURE;
456 timeout.tv_sec = ctx->ctx_timeout;
457 timeout.tv_usec = 0;
458
459 /* split body chunk if necessary */
460 off = 0;
461 do
462 {
463 len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
464 bodylen;
465 if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
466 (char *) (bodyp + off), len)) != MI_SUCCESS)
467 return r;
468 off += len;
469 bodylen -= len;
470 } while (bodylen > 0);
471 return MI_SUCCESS;
472 }
473
474 /*
475 ** SMFI_QUARANTINE -- quarantine an envelope
476 **
477 ** Parameters:
478 ** ctx -- Opaque context structure
479 ** reason -- why?
480 **
481 ** Returns:
482 ** MI_SUCCESS/MI_FAILURE
483 */
484
485 int
smfi_quarantine(ctx,reason)486 smfi_quarantine(ctx, reason)
487 SMFICTX *ctx;
488 char *reason;
489 {
490 size_t len;
491 int r;
492 char *buf;
493 struct timeval timeout;
494
495 if (reason == NULL || *reason == '\0')
496 return MI_FAILURE;
497 if (!mi_sendok(ctx, SMFIF_QUARANTINE))
498 return MI_FAILURE;
499 timeout.tv_sec = ctx->ctx_timeout;
500 timeout.tv_usec = 0;
501 len = strlen(reason) + 1;
502 buf = malloc(len);
503 if (buf == NULL)
504 return MI_FAILURE;
505 (void) memcpy(buf, reason, len);
506 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len);
507 free(buf);
508 return r;
509 }
510
511 /*
512 ** MYISENHSC -- check whether a string contains an enhanced status code
513 **
514 ** Parameters:
515 ** s -- string with possible enhanced status code.
516 ** delim -- delim for enhanced status code.
517 **
518 ** Returns:
519 ** 0 -- no enhanced status code.
520 ** >4 -- length of enhanced status code.
521 **
522 ** Side Effects:
523 ** none.
524 */
525
526 static int
myisenhsc(s,delim)527 myisenhsc(s, delim)
528 const char *s;
529 int delim;
530 {
531 int l, h;
532
533 if (s == NULL)
534 return 0;
535 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
536 return 0;
537 h = 0;
538 l = 2;
539 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
540 ++h;
541 if (h == 0 || s[l + h] != '.')
542 return 0;
543 l += h + 1;
544 h = 0;
545 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
546 ++h;
547 if (h == 0 || s[l + h] != delim)
548 return 0;
549 return l + h;
550 }
551
552 /*
553 ** SMFI_SETREPLY -- set the reply code for the next reply to the MTA
554 **
555 ** Parameters:
556 ** ctx -- Opaque context structure
557 ** rcode -- The three-digit (RFC 821) SMTP reply code.
558 ** xcode -- The extended (RFC 2034) reply code.
559 ** message -- The text part of the SMTP reply.
560 **
561 ** Returns:
562 ** MI_SUCCESS/MI_FAILURE
563 */
564
565 int
smfi_setreply(ctx,rcode,xcode,message)566 smfi_setreply(ctx, rcode, xcode, message)
567 SMFICTX *ctx;
568 char *rcode;
569 char *xcode;
570 char *message;
571 {
572 size_t len;
573 char *buf;
574
575 if (rcode == NULL || ctx == NULL)
576 return MI_FAILURE;
577
578 /* ### <sp> \0 */
579 len = strlen(rcode) + 2;
580 if (len != 5)
581 return MI_FAILURE;
582 if ((rcode[0] != '4' && rcode[0] != '5') ||
583 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
584 !isascii(rcode[2]) || !isdigit(rcode[2]))
585 return MI_FAILURE;
586 if (xcode != NULL)
587 {
588 if (!myisenhsc(xcode, '\0'))
589 return MI_FAILURE;
590 len += strlen(xcode) + 1;
591 }
592 if (message != NULL)
593 {
594 size_t ml;
595
596 /* XXX check also for unprintable chars? */
597 if (strpbrk(message, "\r\n") != NULL)
598 return MI_FAILURE;
599 ml = strlen(message);
600 if (ml > MAXREPLYLEN)
601 return MI_FAILURE;
602 len += ml + 1;
603 }
604 buf = malloc(len);
605 if (buf == NULL)
606 return MI_FAILURE; /* oops */
607 (void) sm_strlcpy(buf, rcode, len);
608 (void) sm_strlcat(buf, " ", len);
609 if (xcode != NULL)
610 (void) sm_strlcat(buf, xcode, len);
611 if (message != NULL)
612 {
613 if (xcode != NULL)
614 (void) sm_strlcat(buf, " ", len);
615 (void) sm_strlcat(buf, message, len);
616 }
617 if (ctx->ctx_reply != NULL)
618 free(ctx->ctx_reply);
619 ctx->ctx_reply = buf;
620 return MI_SUCCESS;
621 }
622
623 /*
624 ** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA
625 **
626 ** Parameters:
627 ** ctx -- Opaque context structure
628 ** rcode -- The three-digit (RFC 821) SMTP reply code.
629 ** xcode -- The extended (RFC 2034) reply code.
630 ** txt, ... -- The text part of the SMTP reply,
631 ** MUST be terminated with NULL.
632 **
633 ** Returns:
634 ** MI_SUCCESS/MI_FAILURE
635 */
636
637 int
638 #if SM_VA_STD
smfi_setmlreply(SMFICTX * ctx,const char * rcode,const char * xcode,...)639 smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
640 #else /* SM_VA_STD */
641 smfi_setmlreply(ctx, rcode, xcode, va_alist)
642 SMFICTX *ctx;
643 const char *rcode;
644 const char *xcode;
645 va_dcl
646 #endif /* SM_VA_STD */
647 {
648 size_t len;
649 size_t rlen;
650 int args;
651 char *buf, *txt;
652 const char *xc;
653 char repl[16];
654 SM_VA_LOCAL_DECL
655
656 if (rcode == NULL || ctx == NULL)
657 return MI_FAILURE;
658
659 /* ### <sp> */
660 len = strlen(rcode) + 1;
661 if (len != 4)
662 return MI_FAILURE;
663 if ((rcode[0] != '4' && rcode[0] != '5') ||
664 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
665 !isascii(rcode[2]) || !isdigit(rcode[2]))
666 return MI_FAILURE;
667 if (xcode != NULL)
668 {
669 if (!myisenhsc(xcode, '\0'))
670 return MI_FAILURE;
671 xc = xcode;
672 }
673 else
674 {
675 if (rcode[0] == '4')
676 xc = "4.0.0";
677 else
678 xc = "5.0.0";
679 }
680
681 /* add trailing space */
682 len += strlen(xc) + 1;
683 rlen = len;
684 args = 0;
685 SM_VA_START(ap, xcode);
686 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
687 {
688 size_t tl;
689
690 tl = strlen(txt);
691 if (tl > MAXREPLYLEN)
692 break;
693
694 /* this text, reply codes, \r\n */
695 len += tl + 2 + rlen;
696 if (++args > MAXREPLIES)
697 break;
698
699 /* XXX check also for unprintable chars? */
700 if (strpbrk(txt, "\r\n") != NULL)
701 break;
702 }
703 SM_VA_END(ap);
704 if (txt != NULL)
705 return MI_FAILURE;
706
707 /* trailing '\0' */
708 ++len;
709 buf = malloc(len);
710 if (buf == NULL)
711 return MI_FAILURE; /* oops */
712 (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc);
713 (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-",
714 xc, " ");
715 SM_VA_START(ap, xcode);
716 txt = SM_VA_ARG(ap, char *);
717 if (txt != NULL)
718 {
719 (void) sm_strlcat2(buf, " ", txt, len);
720 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
721 {
722 if (--args <= 1)
723 repl[3] = ' ';
724 (void) sm_strlcat2(buf, "\r\n", repl, len);
725 (void) sm_strlcat(buf, txt, len);
726 }
727 }
728 if (ctx->ctx_reply != NULL)
729 free(ctx->ctx_reply);
730 ctx->ctx_reply = buf;
731 SM_VA_END(ap);
732 return MI_SUCCESS;
733 }
734
735 /*
736 ** SMFI_SETPRIV -- set private data
737 **
738 ** Parameters:
739 ** ctx -- Opaque context structure
740 ** privatedata -- pointer to private data
741 **
742 ** Returns:
743 ** MI_SUCCESS/MI_FAILURE
744 */
745
746 int
smfi_setpriv(ctx,privatedata)747 smfi_setpriv(ctx, privatedata)
748 SMFICTX *ctx;
749 void *privatedata;
750 {
751 if (ctx == NULL)
752 return MI_FAILURE;
753 ctx->ctx_privdata = privatedata;
754 return MI_SUCCESS;
755 }
756
757 /*
758 ** SMFI_GETPRIV -- get private data
759 **
760 ** Parameters:
761 ** ctx -- Opaque context structure
762 **
763 ** Returns:
764 ** pointer to private data
765 */
766
767 void *
smfi_getpriv(ctx)768 smfi_getpriv(ctx)
769 SMFICTX *ctx;
770 {
771 if (ctx == NULL)
772 return NULL;
773 return ctx->ctx_privdata;
774 }
775
776 /*
777 ** SMFI_GETSYMVAL -- get the value of a macro
778 **
779 ** See explanation in mfapi.h about layout of the structures.
780 **
781 ** Parameters:
782 ** ctx -- Opaque context structure
783 ** symname -- name of macro
784 **
785 ** Returns:
786 ** value of macro (NULL in case of failure)
787 */
788
789 char *
smfi_getsymval(ctx,symname)790 smfi_getsymval(ctx, symname)
791 SMFICTX *ctx;
792 char *symname;
793 {
794 int i;
795 char **s;
796 char one[2];
797 char braces[4];
798
799 if (ctx == NULL || symname == NULL || *symname == '\0')
800 return NULL;
801
802 if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
803 {
804 one[0] = symname[1];
805 one[1] = '\0';
806 }
807 else
808 one[0] = '\0';
809 if (strlen(symname) == 1)
810 {
811 braces[0] = '{';
812 braces[1] = *symname;
813 braces[2] = '}';
814 braces[3] = '\0';
815 }
816 else
817 braces[0] = '\0';
818
819 /* search backwards through the macro array */
820 for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
821 {
822 if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
823 ctx->ctx_mac_buf[i] == NULL)
824 continue;
825 while (s != NULL && *s != NULL)
826 {
827 if (strcmp(*s, symname) == 0)
828 return *++s;
829 if (one[0] != '\0' && strcmp(*s, one) == 0)
830 return *++s;
831 if (braces[0] != '\0' && strcmp(*s, braces) == 0)
832 return *++s;
833 ++s; /* skip over macro value */
834 ++s; /* points to next macro name */
835 }
836 }
837 return NULL;
838 }
839
840 /*
841 ** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature
842 ** timeouts during long milter-side operations
843 **
844 ** Parameters:
845 ** ctx -- Opaque context structure
846 **
847 ** Return value:
848 ** MI_SUCCESS/MI_FAILURE
849 */
850
851 int
smfi_progress(ctx)852 smfi_progress(ctx)
853 SMFICTX *ctx;
854 {
855 struct timeval timeout;
856
857 if (ctx == NULL)
858 return MI_FAILURE;
859
860 timeout.tv_sec = ctx->ctx_timeout;
861 timeout.tv_usec = 0;
862
863 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0);
864 }
865
866 /*
867 ** SMFI_VERSION -- return (runtime) version of libmilter
868 **
869 ** Parameters:
870 ** major -- (pointer to) major version
871 ** minor -- (pointer to) minor version
872 ** patchlevel -- (pointer to) patchlevel version
873 **
874 ** Return value:
875 ** MI_SUCCESS
876 */
877
878 int
smfi_version(major,minor,patchlevel)879 smfi_version(major, minor, patchlevel)
880 unsigned int *major;
881 unsigned int *minor;
882 unsigned int *patchlevel;
883 {
884 if (major != NULL)
885 *major = SM_LM_VRS_MAJOR(SMFI_VERSION);
886 if (minor != NULL)
887 *minor = SM_LM_VRS_MINOR(SMFI_VERSION);
888 if (patchlevel != NULL)
889 *patchlevel = SM_LM_VRS_PLVL(SMFI_VERSION);
890 return MI_SUCCESS;
891 }
892