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