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