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 #include <sm/gen.h>
12 SM_RCSID("@(#)$Id: smfi.c,v 8.83 2007/04/23 16:44:39 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 l1 = strlen(arg1) + 1;
271 SM_ASSERT(offset < len);
272 SM_ASSERT(offset + l1 <= len);
273 (void) memcpy(buf + offset, arg1, l1);
274 offset += l1;
275 SM_ASSERT(offset > l1);
276 }
277
278 r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
279 free(buf);
280 return r;
281 }
282
283 /*
284 ** SMFI_CHGFROM -- change enveloper sender ("from") address
285 **
286 ** Parameters:
287 ** ctx -- Opaque context structure
288 ** from -- new envelope sender address ("MAIL From")
289 ** args -- ESMTP arguments
290 **
291 ** Returns:
292 ** MI_SUCCESS/MI_FAILURE
293 */
294
295 int
smfi_chgfrom(ctx,from,args)296 smfi_chgfrom(ctx, from, args)
297 SMFICTX *ctx;
298 char *from;
299 char *args;
300 {
301 if (from == NULL || *from == '\0')
302 return MI_FAILURE;
303 if (!mi_sendok(ctx, SMFIF_CHGFROM))
304 return MI_FAILURE;
305 return send2(ctx, SMFIR_CHGFROM, from, args);
306 }
307
308 /*
309 ** SMFI_SETSYMLIST -- set list of macros that the MTA should send.
310 **
311 ** Parameters:
312 ** ctx -- Opaque context structure
313 ** where -- SMTP stage
314 ** macros -- list of macros
315 **
316 ** Returns:
317 ** MI_SUCCESS/MI_FAILURE
318 */
319
320 int
smfi_setsymlist(ctx,where,macros)321 smfi_setsymlist(ctx, where, macros)
322 SMFICTX *ctx;
323 int where;
324 char *macros;
325 {
326 SM_ASSERT(ctx != NULL);
327
328 if (macros == NULL || *macros == '\0')
329 return MI_FAILURE;
330 if (where < SMFIM_FIRST || where > SMFIM_LAST)
331 return MI_FAILURE;
332 if (where < 0 || where >= MAX_MACROS_ENTRIES)
333 return MI_FAILURE;
334
335 if (ctx->ctx_mac_list[where] != NULL)
336 return MI_FAILURE;
337
338 ctx->ctx_mac_list[where] = strdup(macros);
339 if (ctx->ctx_mac_list[where] == NULL)
340 return MI_FAILURE;
341
342 return MI_SUCCESS;
343 }
344
345 /*
346 ** SMFI_ADDRCPT_PAR -- send an additional recipient to the MTA
347 **
348 ** Parameters:
349 ** ctx -- Opaque context structure
350 ** rcpt -- recipient address
351 ** args -- ESMTP arguments
352 **
353 ** Returns:
354 ** MI_SUCCESS/MI_FAILURE
355 */
356
357 int
smfi_addrcpt_par(ctx,rcpt,args)358 smfi_addrcpt_par(ctx, rcpt, args)
359 SMFICTX *ctx;
360 char *rcpt;
361 char *args;
362 {
363 if (rcpt == NULL || *rcpt == '\0')
364 return MI_FAILURE;
365 if (!mi_sendok(ctx, SMFIF_ADDRCPT_PAR))
366 return MI_FAILURE;
367 return send2(ctx, SMFIR_ADDRCPT_PAR, rcpt, args);
368 }
369
370 /*
371 ** SMFI_ADDRCPT -- send an additional recipient to the MTA
372 **
373 ** Parameters:
374 ** ctx -- Opaque context structure
375 ** rcpt -- recipient address
376 **
377 ** Returns:
378 ** MI_SUCCESS/MI_FAILURE
379 */
380
381 int
smfi_addrcpt(ctx,rcpt)382 smfi_addrcpt(ctx, rcpt)
383 SMFICTX *ctx;
384 char *rcpt;
385 {
386 size_t len;
387 struct timeval timeout;
388
389 if (rcpt == NULL || *rcpt == '\0')
390 return MI_FAILURE;
391 if (!mi_sendok(ctx, SMFIF_ADDRCPT))
392 return MI_FAILURE;
393 timeout.tv_sec = ctx->ctx_timeout;
394 timeout.tv_usec = 0;
395 len = strlen(rcpt) + 1;
396 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
397 }
398
399 /*
400 ** SMFI_DELRCPT -- send a recipient to be removed to the MTA
401 **
402 ** Parameters:
403 ** ctx -- Opaque context structure
404 ** rcpt -- recipient address
405 **
406 ** Returns:
407 ** MI_SUCCESS/MI_FAILURE
408 */
409
410 int
smfi_delrcpt(ctx,rcpt)411 smfi_delrcpt(ctx, rcpt)
412 SMFICTX *ctx;
413 char *rcpt;
414 {
415 size_t len;
416 struct timeval timeout;
417
418 if (rcpt == NULL || *rcpt == '\0')
419 return MI_FAILURE;
420 if (!mi_sendok(ctx, SMFIF_DELRCPT))
421 return MI_FAILURE;
422 timeout.tv_sec = ctx->ctx_timeout;
423 timeout.tv_usec = 0;
424 len = strlen(rcpt) + 1;
425 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
426 }
427
428 /*
429 ** SMFI_REPLACEBODY -- send a body chunk to the MTA
430 **
431 ** Parameters:
432 ** ctx -- Opaque context structure
433 ** bodyp -- body chunk
434 ** bodylen -- length of body chunk
435 **
436 ** Returns:
437 ** MI_SUCCESS/MI_FAILURE
438 */
439
440 int
smfi_replacebody(ctx,bodyp,bodylen)441 smfi_replacebody(ctx, bodyp, bodylen)
442 SMFICTX *ctx;
443 unsigned char *bodyp;
444 int bodylen;
445 {
446 int len, off, r;
447 struct timeval timeout;
448
449 if (bodylen < 0 ||
450 (bodyp == NULL && bodylen > 0))
451 return MI_FAILURE;
452 if (!mi_sendok(ctx, SMFIF_CHGBODY))
453 return MI_FAILURE;
454 timeout.tv_sec = ctx->ctx_timeout;
455 timeout.tv_usec = 0;
456
457 /* split body chunk if necessary */
458 off = 0;
459 do
460 {
461 len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
462 bodylen;
463 if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
464 (char *) (bodyp + off), len)) != MI_SUCCESS)
465 return r;
466 off += len;
467 bodylen -= len;
468 } while (bodylen > 0);
469 return MI_SUCCESS;
470 }
471
472 /*
473 ** SMFI_QUARANTINE -- quarantine an envelope
474 **
475 ** Parameters:
476 ** ctx -- Opaque context structure
477 ** reason -- why?
478 **
479 ** Returns:
480 ** MI_SUCCESS/MI_FAILURE
481 */
482
483 int
smfi_quarantine(ctx,reason)484 smfi_quarantine(ctx, reason)
485 SMFICTX *ctx;
486 char *reason;
487 {
488 size_t len;
489 int r;
490 char *buf;
491 struct timeval timeout;
492
493 if (reason == NULL || *reason == '\0')
494 return MI_FAILURE;
495 if (!mi_sendok(ctx, SMFIF_QUARANTINE))
496 return MI_FAILURE;
497 timeout.tv_sec = ctx->ctx_timeout;
498 timeout.tv_usec = 0;
499 len = strlen(reason) + 1;
500 buf = malloc(len);
501 if (buf == NULL)
502 return MI_FAILURE;
503 (void) memcpy(buf, reason, len);
504 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len);
505 free(buf);
506 return r;
507 }
508
509 /*
510 ** MYISENHSC -- check whether a string contains an enhanced status code
511 **
512 ** Parameters:
513 ** s -- string with possible enhanced status code.
514 ** delim -- delim for enhanced status code.
515 **
516 ** Returns:
517 ** 0 -- no enhanced status code.
518 ** >4 -- length of enhanced status code.
519 **
520 ** Side Effects:
521 ** none.
522 */
523
524 static int
myisenhsc(s,delim)525 myisenhsc(s, delim)
526 const char *s;
527 int delim;
528 {
529 int l, h;
530
531 if (s == NULL)
532 return 0;
533 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
534 return 0;
535 h = 0;
536 l = 2;
537 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
538 ++h;
539 if (h == 0 || s[l + h] != '.')
540 return 0;
541 l += h + 1;
542 h = 0;
543 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
544 ++h;
545 if (h == 0 || s[l + h] != delim)
546 return 0;
547 return l + h;
548 }
549
550 /*
551 ** SMFI_SETREPLY -- set the reply code for the next reply to the MTA
552 **
553 ** Parameters:
554 ** ctx -- Opaque context structure
555 ** rcode -- The three-digit (RFC 821) SMTP reply code.
556 ** xcode -- The extended (RFC 2034) reply code.
557 ** message -- The text part of the SMTP reply.
558 **
559 ** Returns:
560 ** MI_SUCCESS/MI_FAILURE
561 */
562
563 int
smfi_setreply(ctx,rcode,xcode,message)564 smfi_setreply(ctx, rcode, xcode, message)
565 SMFICTX *ctx;
566 char *rcode;
567 char *xcode;
568 char *message;
569 {
570 size_t len;
571 char *buf;
572
573 if (rcode == NULL || ctx == NULL)
574 return MI_FAILURE;
575
576 /* ### <sp> \0 */
577 len = strlen(rcode) + 2;
578 if (len != 5)
579 return MI_FAILURE;
580 if ((rcode[0] != '4' && rcode[0] != '5') ||
581 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
582 !isascii(rcode[2]) || !isdigit(rcode[2]))
583 return MI_FAILURE;
584 if (xcode != NULL)
585 {
586 if (!myisenhsc(xcode, '\0'))
587 return MI_FAILURE;
588 len += strlen(xcode) + 1;
589 }
590 if (message != NULL)
591 {
592 size_t ml;
593
594 /* XXX check also for unprintable chars? */
595 if (strpbrk(message, "\r\n") != NULL)
596 return MI_FAILURE;
597 ml = strlen(message);
598 if (ml > MAXREPLYLEN)
599 return MI_FAILURE;
600 len += ml + 1;
601 }
602 buf = malloc(len);
603 if (buf == NULL)
604 return MI_FAILURE; /* oops */
605 (void) sm_strlcpy(buf, rcode, len);
606 (void) sm_strlcat(buf, " ", len);
607 if (xcode != NULL)
608 (void) sm_strlcat(buf, xcode, len);
609 if (message != NULL)
610 {
611 if (xcode != NULL)
612 (void) sm_strlcat(buf, " ", len);
613 (void) sm_strlcat(buf, message, len);
614 }
615 if (ctx->ctx_reply != NULL)
616 free(ctx->ctx_reply);
617 ctx->ctx_reply = buf;
618 return MI_SUCCESS;
619 }
620
621 /*
622 ** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA
623 **
624 ** Parameters:
625 ** ctx -- Opaque context structure
626 ** rcode -- The three-digit (RFC 821) SMTP reply code.
627 ** xcode -- The extended (RFC 2034) reply code.
628 ** txt, ... -- The text part of the SMTP reply,
629 ** MUST be terminated with NULL.
630 **
631 ** Returns:
632 ** MI_SUCCESS/MI_FAILURE
633 */
634
635 int
636 #if SM_VA_STD
smfi_setmlreply(SMFICTX * ctx,const char * rcode,const char * xcode,...)637 smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
638 #else /* SM_VA_STD */
639 smfi_setmlreply(ctx, rcode, xcode, va_alist)
640 SMFICTX *ctx;
641 const char *rcode;
642 const char *xcode;
643 va_dcl
644 #endif /* SM_VA_STD */
645 {
646 size_t len;
647 size_t rlen;
648 int args;
649 char *buf, *txt;
650 const char *xc;
651 char repl[16];
652 SM_VA_LOCAL_DECL
653
654 if (rcode == NULL || ctx == NULL)
655 return MI_FAILURE;
656
657 /* ### <sp> */
658 len = strlen(rcode) + 1;
659 if (len != 4)
660 return MI_FAILURE;
661 if ((rcode[0] != '4' && rcode[0] != '5') ||
662 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
663 !isascii(rcode[2]) || !isdigit(rcode[2]))
664 return MI_FAILURE;
665 if (xcode != NULL)
666 {
667 if (!myisenhsc(xcode, '\0'))
668 return MI_FAILURE;
669 xc = xcode;
670 }
671 else
672 {
673 if (rcode[0] == '4')
674 xc = "4.0.0";
675 else
676 xc = "5.0.0";
677 }
678
679 /* add trailing space */
680 len += strlen(xc) + 1;
681 rlen = len;
682 args = 0;
683 SM_VA_START(ap, xcode);
684 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
685 {
686 size_t tl;
687
688 tl = strlen(txt);
689 if (tl > MAXREPLYLEN)
690 break;
691
692 /* this text, reply codes, \r\n */
693 len += tl + 2 + rlen;
694 if (++args > MAXREPLIES)
695 break;
696
697 /* XXX check also for unprintable chars? */
698 if (strpbrk(txt, "\r\n") != NULL)
699 break;
700 }
701 SM_VA_END(ap);
702 if (txt != NULL)
703 return MI_FAILURE;
704
705 /* trailing '\0' */
706 ++len;
707 buf = malloc(len);
708 if (buf == NULL)
709 return MI_FAILURE; /* oops */
710 (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc);
711 (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-",
712 xc, " ");
713 SM_VA_START(ap, xcode);
714 txt = SM_VA_ARG(ap, char *);
715 if (txt != NULL)
716 {
717 (void) sm_strlcat2(buf, " ", txt, len);
718 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
719 {
720 if (--args <= 1)
721 repl[3] = ' ';
722 (void) sm_strlcat2(buf, "\r\n", repl, len);
723 (void) sm_strlcat(buf, txt, len);
724 }
725 }
726 if (ctx->ctx_reply != NULL)
727 free(ctx->ctx_reply);
728 ctx->ctx_reply = buf;
729 SM_VA_END(ap);
730 return MI_SUCCESS;
731 }
732
733 /*
734 ** SMFI_SETPRIV -- set private data
735 **
736 ** Parameters:
737 ** ctx -- Opaque context structure
738 ** privatedata -- pointer to private data
739 **
740 ** Returns:
741 ** MI_SUCCESS/MI_FAILURE
742 */
743
744 int
smfi_setpriv(ctx,privatedata)745 smfi_setpriv(ctx, privatedata)
746 SMFICTX *ctx;
747 void *privatedata;
748 {
749 if (ctx == NULL)
750 return MI_FAILURE;
751 ctx->ctx_privdata = privatedata;
752 return MI_SUCCESS;
753 }
754
755 /*
756 ** SMFI_GETPRIV -- get private data
757 **
758 ** Parameters:
759 ** ctx -- Opaque context structure
760 **
761 ** Returns:
762 ** pointer to private data
763 */
764
765 void *
smfi_getpriv(ctx)766 smfi_getpriv(ctx)
767 SMFICTX *ctx;
768 {
769 if (ctx == NULL)
770 return NULL;
771 return ctx->ctx_privdata;
772 }
773
774 /*
775 ** SMFI_GETSYMVAL -- get the value of a macro
776 **
777 ** See explanation in mfapi.h about layout of the structures.
778 **
779 ** Parameters:
780 ** ctx -- Opaque context structure
781 ** symname -- name of macro
782 **
783 ** Returns:
784 ** value of macro (NULL in case of failure)
785 */
786
787 char *
smfi_getsymval(ctx,symname)788 smfi_getsymval(ctx, symname)
789 SMFICTX *ctx;
790 char *symname;
791 {
792 int i;
793 char **s;
794 char one[2];
795 char braces[4];
796
797 if (ctx == NULL || symname == NULL || *symname == '\0')
798 return NULL;
799
800 if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
801 {
802 one[0] = symname[1];
803 one[1] = '\0';
804 }
805 else
806 one[0] = '\0';
807 if (strlen(symname) == 1)
808 {
809 braces[0] = '{';
810 braces[1] = *symname;
811 braces[2] = '}';
812 braces[3] = '\0';
813 }
814 else
815 braces[0] = '\0';
816
817 /* search backwards through the macro array */
818 for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
819 {
820 if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
821 ctx->ctx_mac_buf[i] == NULL)
822 continue;
823 while (s != NULL && *s != NULL)
824 {
825 if (strcmp(*s, symname) == 0)
826 return *++s;
827 if (one[0] != '\0' && strcmp(*s, one) == 0)
828 return *++s;
829 if (braces[0] != '\0' && strcmp(*s, braces) == 0)
830 return *++s;
831 ++s; /* skip over macro value */
832 ++s; /* points to next macro name */
833 }
834 }
835 return NULL;
836 }
837
838 /*
839 ** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature
840 ** timeouts during long milter-side operations
841 **
842 ** Parameters:
843 ** ctx -- Opaque context structure
844 **
845 ** Return value:
846 ** MI_SUCCESS/MI_FAILURE
847 */
848
849 int
smfi_progress(ctx)850 smfi_progress(ctx)
851 SMFICTX *ctx;
852 {
853 struct timeval timeout;
854
855 if (ctx == NULL)
856 return MI_FAILURE;
857
858 timeout.tv_sec = ctx->ctx_timeout;
859 timeout.tv_usec = 0;
860
861 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0);
862 }
863
864 /*
865 ** SMFI_VERSION -- return (runtime) version of libmilter
866 **
867 ** Parameters:
868 ** major -- (pointer to) major version
869 ** minor -- (pointer to) minor version
870 ** patchlevel -- (pointer to) patchlevel version
871 **
872 ** Return value:
873 ** MI_SUCCESS
874 */
875
876 int
smfi_version(major,minor,patchlevel)877 smfi_version(major, minor, patchlevel)
878 unsigned int *major;
879 unsigned int *minor;
880 unsigned int *patchlevel;
881 {
882 if (major != NULL)
883 *major = SM_LM_VRS_MAJOR(SMFI_VERSION);
884 if (minor != NULL)
885 *minor = SM_LM_VRS_MINOR(SMFI_VERSION);
886 if (patchlevel != NULL)
887 *patchlevel = SM_LM_VRS_PLVL(SMFI_VERSION);
888 return MI_SUCCESS;
889 }
890