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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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