1 /* 2 * Copyright (c) 1999-2006 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.82 2007/01/20 06:37:19 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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_MINOR(SMFI_VERSION); 890 return MI_SUCCESS; 891 } 892