1 /* 2 * Copyright (c) 1998-2006, 2008-2010, 2014 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 14 #include <sendmail.h> 15 16 SM_RCSID("@(#)$Id: usersmtp.c,v 8.488 2013-11-22 20:51:57 ca Exp $") 17 18 #include <sm/sendmail.h> 19 20 static void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); 21 static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); 22 static int smtprcptstat __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *)); 23 24 #if SASL 25 extern void *sm_sasl_malloc __P((unsigned long)); 26 extern void sm_sasl_free __P((void *)); 27 #endif 28 29 /* 30 ** USERSMTP -- run SMTP protocol from the user end. 31 ** 32 ** This protocol is described in RFC821. 33 */ 34 35 #define SMTPCLOSING 421 /* "Service Shutting Down" */ 36 37 #define ENHSCN(e, d) ((e) == NULL ? (d) : (e)) 38 39 #define ENHSCN_RPOOL(e, d, rpool) \ 40 ((e) == NULL ? (d) : sm_rpool_strdup_x(rpool, e)) 41 42 static char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 43 static char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 44 static bool SmtpNeedIntro; /* need "while talking" in transcript */ 45 46 /* 47 ** SMTPCCLRSE -- clear session related data in envelope 48 ** 49 ** Parameters: 50 ** e -- the envelope. 51 ** 52 ** Returns: 53 ** none. 54 */ 55 56 void 57 smtpclrse(e) 58 ENVELOPE *e; 59 { 60 SmtpError[0] = '\0'; 61 e->e_rcode = 0; 62 e->e_renhsc[0] = '\0'; 63 e->e_text = NULL; 64 65 /* 66 ** Reset to avoid access to potentially dangling pointer 67 ** via macvalue(). 68 */ 69 70 e->e_mci = NULL; 71 } 72 73 /* 74 ** SMTPINIT -- initialize SMTP. 75 ** 76 ** Opens the connection and sends the initial protocol. 77 ** 78 ** Parameters: 79 ** m -- mailer to create connection to. 80 ** mci -- the mailer connection info. 81 ** e -- the envelope. 82 ** onlyhelo -- send only helo command? 83 ** 84 ** Returns: 85 ** none. 86 ** 87 ** Side Effects: 88 ** creates connection and sends initial protocol. 89 */ 90 91 void 92 smtpinit(m, mci, e, onlyhelo) 93 MAILER *m; 94 register MCI *mci; 95 ENVELOPE *e; 96 bool onlyhelo; 97 { 98 register int r; 99 int state; 100 register char *p; 101 register char *hn; 102 #if _FFR_EXPAND_HELONAME 103 char hnbuf[MAXNAME + 1]; /* EAI:ok:EHLO name must be ASCII */ 104 #endif 105 char *enhsc; 106 107 enhsc = NULL; 108 if (tTd(18, 1)) 109 { 110 sm_dprintf("smtpinit "); 111 mci_dump(sm_debug_file(), mci, false); 112 } 113 114 /* 115 ** Open the connection to the mailer. 116 */ 117 118 SmtpError[0] = '\0'; 119 SmtpMsgBuffer[0] = '\0'; 120 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 121 if (CurHostName == NULL) 122 CurHostName = MyHostName; 123 SmtpNeedIntro = true; 124 state = mci->mci_state; 125 e->e_rcode = 0; 126 e->e_renhsc[0] = '\0'; 127 e->e_text = NULL; 128 switch (state) 129 { 130 case MCIS_MAIL: 131 case MCIS_RCPT: 132 case MCIS_DATA: 133 /* need to clear old information */ 134 smtprset(m, mci, e); 135 /* FALLTHROUGH */ 136 137 case MCIS_OPEN: 138 if (!onlyhelo) 139 return; 140 break; 141 142 case MCIS_ERROR: 143 case MCIS_QUITING: 144 case MCIS_SSD: 145 /* shouldn't happen */ 146 smtpquit(m, mci, e); 147 /* FALLTHROUGH */ 148 149 case MCIS_CLOSED: 150 syserr("451 4.4.0 smtpinit: state CLOSED (was %d)", state); 151 return; 152 153 case MCIS_OPENING: 154 break; 155 } 156 if (onlyhelo) 157 goto helo; 158 159 mci->mci_state = MCIS_OPENING; 160 clrsessenvelope(e); 161 162 /* 163 ** Get the greeting message. 164 ** This should appear spontaneously. Give it five minutes to 165 ** happen. 166 */ 167 168 SmtpPhase = mci->mci_phase = "client greeting"; 169 sm_setproctitle(true, e, "%s %s: %s", 170 qid_printname(e), CurHostName, mci->mci_phase); 171 r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL, XS_GREET); 172 if (r < 0) 173 goto tempfail1; 174 if (REPLYTYPE(r) == 4) 175 goto tempfail2; 176 if (REPLYTYPE(r) != 2) 177 goto unavailable; 178 179 /* 180 ** Send the HELO command. 181 ** My mother taught me to always introduce myself. 182 */ 183 184 helo: 185 if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags)) 186 mci->mci_flags |= MCIF_ESMTP; 187 if (mci->mci_heloname != NULL) 188 { 189 #if _FFR_EXPAND_HELONAME 190 expand(mci->mci_heloname, hnbuf, sizeof(hnbuf), e); 191 hn = hnbuf; 192 #else 193 hn = mci->mci_heloname; 194 #endif 195 } 196 else 197 hn = MyHostName; 198 199 tryhelo: 200 #if _FFR_IGNORE_EXT_ON_HELO 201 mci->mci_flags &= ~MCIF_HELO; 202 #endif 203 if (bitnset(M_LMTP, m->m_flags)) 204 { 205 smtpmessage("LHLO %s", m, mci, hn); 206 SmtpPhase = mci->mci_phase = "client LHLO"; 207 } 208 else if (bitset(MCIF_ESMTP, mci->mci_flags) && 209 !bitnset(M_FSMTP, m->m_flags)) 210 { 211 smtpmessage("EHLO %s", m, mci, hn); 212 SmtpPhase = mci->mci_phase = "client EHLO"; 213 } 214 else 215 { 216 smtpmessage("HELO %s", m, mci, hn); 217 SmtpPhase = mci->mci_phase = "client HELO"; 218 #if _FFR_IGNORE_EXT_ON_HELO 219 mci->mci_flags |= MCIF_HELO; 220 #endif 221 } 222 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), 223 CurHostName, mci->mci_phase); 224 r = reply(m, mci, e, 225 bitnset(M_LMTP, m->m_flags) ? TimeOuts.to_lhlo 226 : TimeOuts.to_helo, 227 helo_options, NULL, XS_EHLO); 228 if (r < 0) 229 goto tempfail1; 230 else if (REPLYTYPE(r) == 5) 231 { 232 if (bitset(MCIF_ESMTP, mci->mci_flags) && 233 !bitnset(M_LMTP, m->m_flags)) 234 { 235 /* try old SMTP instead */ 236 mci->mci_flags &= ~MCIF_ESMTP; 237 goto tryhelo; 238 } 239 goto unavailable; 240 } 241 else if (REPLYTYPE(r) != 2) 242 goto tempfail2; 243 244 /* 245 ** Check to see if we actually ended up talking to ourself. 246 ** This means we didn't know about an alias or MX, or we managed 247 ** to connect to an echo server. 248 */ 249 250 p = strchr(&SmtpReplyBuffer[4], ' '); 251 if (p != NULL) 252 *p = '\0'; 253 if (!bitnset(M_NOLOOPCHECK, m->m_flags) && 254 !bitnset(M_LMTP, m->m_flags) && 255 SM_STRCASEEQ(&SmtpReplyBuffer[4], MyHostName)) 256 { 257 syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)", 258 CurHostName); 259 mci_setstat(mci, EX_CONFIG, "5.3.5", 260 "553 5.3.5 system config error"); 261 mci->mci_errno = 0; 262 smtpquit(m, mci, e); 263 return; 264 } 265 266 /* 267 ** If this is expected to be another sendmail, send some internal 268 ** commands. 269 ** If we're running as MSP, "propagate" -v flag if possible. 270 */ 271 272 if ((UseMSP && Verbose && bitset(MCIF_VERB, mci->mci_flags)) 273 || bitnset(M_INTERNAL, m->m_flags)) 274 { 275 /* tell it to be verbose */ 276 smtpmessage("VERB", m, mci); 277 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc, 278 XS_DEFAULT); 279 if (r < 0) 280 goto tempfail1; 281 } 282 283 if (mci->mci_state != MCIS_CLOSED) 284 { 285 mci->mci_state = MCIS_OPEN; 286 return; 287 } 288 289 /* got a 421 error code during startup */ 290 291 tempfail1: 292 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.4.2"), NULL); 293 if (mci->mci_state != MCIS_CLOSED) 294 smtpquit(m, mci, e); 295 return; 296 297 tempfail2: 298 /* XXX should use code from other end iff ENHANCEDSTATUSCODES */ 299 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"), 300 SmtpReplyBuffer); 301 if (mci->mci_state != MCIS_CLOSED) 302 smtpquit(m, mci, e); 303 return; 304 305 unavailable: 306 mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer); 307 smtpquit(m, mci, e); 308 return; 309 } 310 /* 311 ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol 312 ** 313 ** Parameters: 314 ** line -- the response line. 315 ** firstline -- set if this is the first line of the reply. 316 ** m -- the mailer. 317 ** mci -- the mailer connection info. 318 ** e -- the envelope. 319 ** 320 ** Returns: 321 ** none. 322 */ 323 324 static void 325 esmtp_check(line, firstline, m, mci, e) 326 char *line; 327 bool firstline; 328 MAILER *m; 329 register MCI *mci; 330 ENVELOPE *e; 331 { 332 if (strstr(line, "ESMTP") != NULL) 333 mci->mci_flags |= MCIF_ESMTP; 334 335 /* 336 ** Dirty hack below. Quoting the author: 337 ** This was a response to people who wanted SMTP transmission to be 338 ** just-send-8 by default. Essentially, you could put this tag into 339 ** your greeting message to behave as though the F=8 flag was set on 340 ** the mailer. 341 */ 342 343 if (strstr(line, "8BIT-OK") != NULL) 344 mci->mci_flags |= MCIF_8BITOK; 345 } 346 347 #if SASL 348 /* specify prototype so compiler can check calls */ 349 static char *str_union __P((char *, char *, SM_RPOOL_T *)); 350 351 /* 352 ** STR_UNION -- create the union of two lists 353 ** 354 ** Parameters: 355 ** s1, s2 -- lists of items (separated by single blanks). 356 ** rpool -- resource pool from which result is allocated. 357 ** 358 ** Returns: 359 ** the union of both lists. 360 */ 361 362 static char * 363 str_union(s1, s2, rpool) 364 char *s1, *s2; 365 SM_RPOOL_T *rpool; 366 { 367 char *hr, *h1, *h, *res; 368 int l1, l2, rl; 369 370 if (SM_IS_EMPTY(s1)) 371 return s2; 372 if (SM_IS_EMPTY(s2)) 373 return s1; 374 l1 = strlen(s1); 375 l2 = strlen(s2); 376 rl = l1 + l2; 377 if (rl <= 0) 378 { 379 sm_syslog(LOG_WARNING, NOQID, 380 "str_union: stringlen1=%d, stringlen2=%d, sum=%d, status=overflow", 381 l1, l2, rl); 382 res = NULL; 383 } 384 else 385 res = (char *) sm_rpool_malloc(rpool, rl + 2); 386 if (res == NULL) 387 { 388 if (l1 > l2) 389 return s1; 390 return s2; 391 } 392 (void) sm_strlcpy(res, s1, rl); 393 hr = res + l1; 394 h1 = s2; 395 h = s2; 396 397 /* walk through s2 */ 398 while (h != NULL && *h1 != '\0') 399 { 400 /* is there something after the current word? */ 401 if ((h = strchr(h1, ' ')) != NULL) 402 *h = '\0'; 403 l1 = strlen(h1); 404 405 /* does the current word appear in s1 ? */ 406 if (iteminlist(h1, s1, " ") == NULL) 407 { 408 /* add space as delimiter */ 409 *hr++ = ' '; 410 411 /* copy the item */ 412 memcpy(hr, h1, l1); 413 414 /* advance pointer in result list */ 415 hr += l1; 416 *hr = '\0'; 417 } 418 if (h != NULL) 419 { 420 /* there are more items */ 421 *h = ' '; 422 h1 = h + 1; 423 } 424 } 425 return res; 426 } 427 #endif /* SASL */ 428 429 /* 430 ** HELO_OPTIONS -- process the options on a HELO line. 431 ** 432 ** Parameters: 433 ** line -- the response line. 434 ** firstline -- set if this is the first line of the reply. 435 ** m -- the mailer. 436 ** mci -- the mailer connection info. 437 ** e -- the envelope (unused). 438 ** 439 ** Returns: 440 ** none. 441 */ 442 443 static void 444 helo_options(line, firstline, m, mci, e) 445 char *line; 446 bool firstline; 447 MAILER *m; 448 register MCI *mci; 449 ENVELOPE *e; 450 { 451 register char *p; 452 #if _FFR_IGNORE_EXT_ON_HELO 453 static bool logged = false; 454 #endif 455 456 if (firstline) 457 { 458 mci_clr_extensions(mci); 459 #if _FFR_IGNORE_EXT_ON_HELO 460 logged = false; 461 #endif 462 return; 463 } 464 #if _FFR_IGNORE_EXT_ON_HELO 465 else if (bitset(MCIF_HELO, mci->mci_flags)) 466 { 467 if (LogLevel > 8 && !logged) 468 { 469 sm_syslog(LOG_WARNING, NOQID, 470 "server=%s [%s] returned extensions despite HELO command", 471 macvalue(macid("{server_name}"), e), 472 macvalue(macid("{server_addr}"), e)); 473 logged = true; 474 } 475 return; 476 } 477 #endif /* _FFR_IGNORE_EXT_ON_HELO */ 478 479 if (strlen(line) < 5) 480 return; 481 line += 4; 482 p = strpbrk(line, " ="); 483 if (p != NULL) 484 *p++ = '\0'; 485 if (SM_STRCASEEQ(line, "size")) 486 { 487 mci->mci_flags |= MCIF_SIZE; 488 if (p != NULL) 489 mci->mci_maxsize = atol(p); 490 } 491 else if (SM_STRCASEEQ(line, "8bitmime")) 492 { 493 mci->mci_flags |= MCIF_8BITMIME; 494 mci->mci_flags &= ~MCIF_7BIT; 495 } 496 else if (SM_STRCASEEQ(line, "expn")) 497 mci->mci_flags |= MCIF_EXPN; 498 else if (SM_STRCASEEQ(line, "dsn")) 499 mci->mci_flags |= MCIF_DSN; 500 else if (SM_STRCASEEQ(line, "enhancedstatuscodes")) 501 mci->mci_flags |= MCIF_ENHSTAT; 502 else if (SM_STRCASEEQ(line, "pipelining")) 503 mci->mci_flags |= MCIF_PIPELINED; 504 else if (SM_STRCASEEQ(line, "verb")) 505 mci->mci_flags |= MCIF_VERB; 506 #if USE_EAI 507 else if (SM_STRCASEEQ(line, "smtputf8")) 508 mci->mci_flags |= MCIF_EAI; 509 #endif 510 #if STARTTLS 511 else if (SM_STRCASEEQ(line, "starttls")) 512 mci->mci_flags |= MCIF_TLS; 513 #endif 514 else if (SM_STRCASEEQ(line, "deliverby")) 515 { 516 mci->mci_flags |= MCIF_DLVR_BY; 517 if (p != NULL) 518 mci->mci_min_by = atol(p); 519 } 520 #if SASL 521 else if (SM_STRCASEEQ(line, "auth")) 522 { 523 if (p != NULL && *p != '\0' && 524 !bitset(MCIF_AUTH2, mci->mci_flags)) 525 { 526 if (mci->mci_saslcap != NULL) 527 { 528 /* 529 ** Create the union with previous auth 530 ** offerings because we recognize "auth " 531 ** and "auth=" (old format). 532 */ 533 534 mci->mci_saslcap = str_union(mci->mci_saslcap, 535 p, mci->mci_rpool); 536 mci->mci_flags |= MCIF_AUTH2; 537 } 538 else 539 { 540 int l; 541 542 l = strlen(p) + 1; 543 mci->mci_saslcap = (char *) 544 sm_rpool_malloc(mci->mci_rpool, l); 545 if (mci->mci_saslcap != NULL) 546 { 547 (void) sm_strlcpy(mci->mci_saslcap, p, 548 l); 549 mci->mci_flags |= MCIF_AUTH; 550 } 551 } 552 } 553 if (tTd(95, 5)) 554 sm_syslog(LOG_DEBUG, NOQID, "AUTH flags=%lx, mechs=%s", 555 mci->mci_flags, mci->mci_saslcap); 556 } 557 #endif /* SASL */ 558 } 559 #if SASL 560 561 static int getsimple __P((void *, int, const char **, unsigned *)); 562 static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **)); 563 static int saslgetrealm __P((void *, int, const char **, const char **)); 564 static int readauth __P((char *, bool, SASL_AI_T *m, SM_RPOOL_T *)); 565 static int getauth __P((MCI *, ENVELOPE *, SASL_AI_T *)); 566 static char *removemech __P((char *, char *, SM_RPOOL_T *)); 567 static int attemptauth __P((MAILER *, MCI *, ENVELOPE *, SASL_AI_T *)); 568 569 static sasl_callback_t callbacks[] = 570 { 571 { SASL_CB_GETREALM, (sasl_callback_ft)&saslgetrealm, NULL }, 572 #define CB_GETREALM_IDX 0 573 { SASL_CB_PASS, (sasl_callback_ft)&getsecret, NULL }, 574 #define CB_PASS_IDX 1 575 { SASL_CB_USER, (sasl_callback_ft)&getsimple, NULL }, 576 #define CB_USER_IDX 2 577 { SASL_CB_AUTHNAME, (sasl_callback_ft)&getsimple, NULL }, 578 #define CB_AUTHNAME_IDX 3 579 { SASL_CB_VERIFYFILE, (sasl_callback_ft)&safesaslfile, NULL }, 580 #define CB_SAFESASL_IDX 4 581 { SASL_CB_LIST_END, NULL, NULL } 582 }; 583 584 /* 585 ** INIT_SASL_CLIENT -- initialize client side of Cyrus-SASL 586 ** 587 ** Parameters: 588 ** none. 589 ** 590 ** Returns: 591 ** SASL_OK -- if successful. 592 ** SASL error code -- otherwise. 593 ** 594 ** Side Effects: 595 ** checks/sets sasl_clt_init. 596 ** 597 ** Note: 598 ** Callbacks are ignored if sasl_client_init() has 599 ** been called before (by a library such as libnss_ldap) 600 */ 601 602 static bool sasl_clt_init = false; 603 604 static int 605 init_sasl_client() 606 { 607 int result; 608 609 if (sasl_clt_init) 610 return SASL_OK; 611 result = sasl_client_init(callbacks); 612 613 /* should we retry later again or just remember that it failed? */ 614 if (result == SASL_OK) 615 sasl_clt_init = true; 616 return result; 617 } 618 /* 619 ** STOP_SASL_CLIENT -- shutdown client side of Cyrus-SASL 620 ** 621 ** Parameters: 622 ** none. 623 ** 624 ** Returns: 625 ** none. 626 ** 627 ** Side Effects: 628 ** checks/sets sasl_clt_init. 629 */ 630 631 void 632 stop_sasl_client() 633 { 634 if (!sasl_clt_init) 635 return; 636 sasl_clt_init = false; 637 sasl_done(); 638 } 639 /* 640 ** GETSASLDATA -- process the challenges from the SASL protocol 641 ** 642 ** This gets the relevant sasl response data out of the reply 643 ** from the server. 644 ** 645 ** Parameters: 646 ** line -- the response line. 647 ** firstline -- set if this is the first line of the reply. 648 ** m -- the mailer. 649 ** mci -- the mailer connection info. 650 ** e -- the envelope (unused). 651 ** 652 ** Returns: 653 ** none. 654 */ 655 656 static void getsasldata __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); 657 658 static void 659 getsasldata(line, firstline, m, mci, e) 660 char *line; 661 bool firstline; 662 MAILER *m; 663 register MCI *mci; 664 ENVELOPE *e; 665 { 666 int len; 667 int result; 668 # if SASL < 20000 669 char *out; 670 # endif 671 672 /* if not a continue we don't care about it */ 673 len = strlen(line); 674 if ((len <= 4) || 675 (line[0] != '3') || 676 !isascii(line[1]) || !isdigit(line[1]) || 677 !isascii(line[2]) || !isdigit(line[2])) 678 { 679 SM_FREE(mci->mci_sasl_string); 680 return; 681 } 682 683 /* forget about "334 " */ 684 line += 4; 685 len -= 4; 686 # if SASL >= 20000 687 /* XXX put this into a macro/function? It's duplicated below */ 688 if (mci->mci_sasl_string != NULL) 689 { 690 if (mci->mci_sasl_string_len <= len) 691 { 692 sm_free(mci->mci_sasl_string); /* XXX */ 693 mci->mci_sasl_string = xalloc(len + 1); 694 } 695 } 696 else 697 mci->mci_sasl_string = xalloc(len + 1); 698 699 result = sasl_decode64(line, len, mci->mci_sasl_string, len + 1, 700 (unsigned int *) &mci->mci_sasl_string_len); 701 if (result != SASL_OK) 702 { 703 mci->mci_sasl_string_len = 0; 704 *mci->mci_sasl_string = '\0'; 705 } 706 # else /* SASL >= 20000 */ 707 out = (char *) sm_rpool_malloc_x(mci->mci_rpool, len + 1); 708 result = sasl_decode64(line, len, out, (unsigned int *) &len); 709 if (result != SASL_OK) 710 { 711 len = 0; 712 *out = '\0'; 713 } 714 715 /* 716 ** mci_sasl_string is "shared" with Cyrus-SASL library; hence 717 ** it can't be in an rpool unless we use the same memory 718 ** management mechanism (with same rpool!) for Cyrus SASL. 719 */ 720 721 if (mci->mci_sasl_string != NULL) 722 { 723 if (mci->mci_sasl_string_len <= len) 724 { 725 sm_free(mci->mci_sasl_string); /* XXX */ 726 mci->mci_sasl_string = xalloc(len + 1); 727 } 728 } 729 else 730 mci->mci_sasl_string = xalloc(len + 1); 731 732 memcpy(mci->mci_sasl_string, out, len); 733 mci->mci_sasl_string[len] = '\0'; 734 mci->mci_sasl_string_len = len; 735 # endif /* SASL >= 20000 */ 736 return; 737 } 738 /* 739 ** READAUTH -- read auth values from a file 740 ** 741 ** Parameters: 742 ** filename -- name of file to read. 743 ** safe -- if set, this is a safe read. 744 ** sai -- where to store auth_info. 745 ** rpool -- resource pool for sai. 746 ** 747 ** Returns: 748 ** EX_OK -- data successfully read. 749 ** EX_UNAVAILABLE -- no valid filename. 750 ** EX_TEMPFAIL -- temporary failure. 751 */ 752 753 static char *sasl_info_name[] = 754 { 755 "user id", 756 "authentication id", 757 "password", 758 "realm", 759 "mechlist" 760 }; 761 static int 762 readauth(filename, safe, sai, rpool) 763 char *filename; 764 bool safe; 765 SASL_AI_T *sai; 766 SM_RPOOL_T *rpool; 767 { 768 SM_FILE_T *f; 769 long sff; 770 pid_t pid; 771 int lc; 772 char *s; 773 char buf[MAXLINE]; 774 775 if (SM_IS_EMPTY(filename)) 776 return EX_UNAVAILABLE; 777 778 # if !_FFR_ALLOW_SASLINFO 779 /* 780 ** make sure we don't use a program that is not 781 ** accessible to the user who specified a different authinfo file. 782 ** However, currently we don't pass this info (authinfo file 783 ** specified by user) around, so we just turn off program access. 784 */ 785 786 if (filename[0] == '|') 787 { 788 auto int fd; 789 int i; 790 char *p; 791 char *argv[MAXPV + 1]; 792 793 i = 0; 794 for (p = strtok(&filename[1], " \t"); p != NULL; 795 p = strtok(NULL, " \t")) 796 { 797 if (i >= MAXPV) 798 break; 799 argv[i++] = p; 800 } 801 argv[i] = NULL; 802 pid = prog_open(argv, &fd, CurEnv); 803 if (pid < 0) 804 f = NULL; 805 else 806 f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 807 (void *) &fd, SM_IO_RDONLY, NULL); 808 } 809 else 810 # endif /* !_FFR_ALLOW_SASLINFO */ 811 /* "else" in #if code above */ 812 { 813 pid = -1; 814 sff = SFF_REGONLY|SFF_SAFEDIRPATH|SFF_NOWLINK 815 |SFF_NOGWFILES|SFF_NOWWFILES|SFF_NOWRFILES; 816 if (!bitnset(DBS_GROUPREADABLEAUTHINFOFILE, DontBlameSendmail)) 817 sff |= SFF_NOGRFILES; 818 if (DontLockReadFiles) 819 sff |= SFF_NOLOCK; 820 821 # if _FFR_ALLOW_SASLINFO 822 /* 823 ** XXX: make sure we don't read or open files that are not 824 ** accessible to the user who specified a different authinfo 825 ** file. 826 */ 827 828 sff |= SFF_MUSTOWN; 829 # else /* _FFR_ALLOW_SASLINFO */ 830 if (safe) 831 sff |= SFF_OPENASROOT; 832 # endif /* _FFR_ALLOW_SASLINFO */ 833 834 f = safefopen(filename, O_RDONLY, 0, sff); 835 } 836 if (f == NULL) 837 { 838 if (LogLevel > 5) 839 sm_syslog(LOG_ERR, NOQID, 840 "AUTH=client, error: can't open %s: %s", 841 filename, sm_errstring(errno)); 842 return EX_TEMPFAIL; 843 } 844 845 lc = 0; 846 while (lc <= SASL_MECHLIST && 847 sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0) 848 { 849 if (buf[0] != '#') 850 { 851 (*sai)[lc] = sm_rpool_strdup_x(rpool, buf); 852 if ((s = strchr((*sai)[lc], '\n')) != NULL) 853 *s = '\0'; 854 lc++; 855 } 856 } 857 858 (void) sm_io_close(f, SM_TIME_DEFAULT); 859 if (pid > 0) 860 (void) waitfor(pid); 861 if (lc < SASL_PASSWORD) 862 { 863 if (LogLevel > 8) 864 sm_syslog(LOG_ERR, NOQID, 865 "AUTH=client, error: can't read %s from %s", 866 sasl_info_name[lc + 1], filename); 867 return EX_TEMPFAIL; 868 } 869 return EX_OK; 870 } 871 872 /* 873 ** GETAUTH -- get authinfo from ruleset call 874 ** 875 ** {server_name}, {server_addr} must be set 876 ** 877 ** Parameters: 878 ** mci -- the mailer connection structure. 879 ** e -- the envelope (including the sender to specify). 880 ** sai -- pointer to authinfo (result). 881 ** 882 ** Returns: 883 ** EX_OK -- ruleset was successfully called, data may not 884 ** be available, sai must be checked. 885 ** EX_UNAVAILABLE -- ruleset unavailable (or failed). 886 ** EX_TEMPFAIL -- temporary failure (from ruleset). 887 ** 888 ** Side Effects: 889 ** Fills in sai if successful. 890 */ 891 892 static int 893 getauth(mci, e, sai) 894 MCI *mci; 895 ENVELOPE *e; 896 SASL_AI_T *sai; 897 { 898 int i, r, l, got, ret; 899 char **pvp; 900 char pvpbuf[PSBUFSIZE]; 901 902 r = rscap("authinfo", macvalue(macid("{server_name}"), e), 903 macvalue(macid("{server_addr}"), e), e, 904 &pvp, pvpbuf, sizeof(pvpbuf)); 905 906 if (r != EX_OK) 907 return EX_UNAVAILABLE; 908 909 /* other than expected return value: ok (i.e., no auth) */ 910 if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 911 return EX_OK; 912 if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0) 913 return EX_TEMPFAIL; 914 915 /* 916 ** parse the data, put it into sai 917 ** format: "TDstring" (including the '"' !) 918 ** where T is a tag: 'U', ... 919 ** D is a delimiter: ':' or '=' 920 */ 921 922 ret = EX_OK; /* default return value */ 923 i = 0; 924 got = 0; 925 while (i < SASL_ENTRIES) 926 { 927 if (pvp[i + 1] == NULL) 928 break; 929 if (pvp[i + 1][0] != '"') 930 break; 931 switch (pvp[i + 1][1]) 932 { 933 case 'U': 934 case 'u': 935 r = SASL_USER; 936 break; 937 case 'I': 938 case 'i': 939 r = SASL_AUTHID; 940 break; 941 case 'P': 942 case 'p': 943 r = SASL_PASSWORD; 944 break; 945 case 'R': 946 case 'r': 947 r = SASL_DEFREALM; 948 break; 949 case 'M': 950 case 'm': 951 r = SASL_MECHLIST; 952 break; 953 default: 954 goto fail; 955 } 956 l = strlen(pvp[i + 1]); 957 958 /* check syntax */ 959 if (l <= 3 || pvp[i + 1][l - 1] != '"') 960 goto fail; 961 962 /* remove closing quote */ 963 pvp[i + 1][l - 1] = '\0'; 964 965 /* remove "TD and " */ 966 l -= 4; 967 (*sai)[r] = (char *) sm_rpool_malloc(mci->mci_rpool, l + 1); 968 if ((*sai)[r] == NULL) 969 goto tempfail; 970 if (pvp[i + 1][2] == ':') 971 { 972 /* ':text' (just copy) */ 973 (void) sm_strlcpy((*sai)[r], pvp[i + 1] + 3, l + 1); 974 got |= 1 << r; 975 } 976 else if (pvp[i + 1][2] == '=') 977 { 978 unsigned int len; 979 980 /* '=base64' (decode) */ 981 # if SASL >= 20000 982 ret = sasl_decode64(pvp[i + 1] + 3, 983 (unsigned int) l, (*sai)[r], 984 (unsigned int) l + 1, &len); 985 # else /* SASL >= 20000 */ 986 ret = sasl_decode64(pvp[i + 1] + 3, 987 (unsigned int) l, (*sai)[r], &len); 988 # endif /* SASL >= 20000 */ 989 if (ret != SASL_OK) 990 goto fail; 991 got |= 1 << r; 992 } 993 else 994 goto fail; 995 if (tTd(95, 5)) 996 sm_syslog(LOG_DEBUG, NOQID, "getauth %s=%s", 997 sasl_info_name[r], (*sai)[r]); 998 ++i; 999 } 1000 1001 /* did we get the expected data? */ 1002 /* XXX: EXTERNAL mechanism only requires (and only uses) SASL_USER */ 1003 if (!(bitset(SASL_USER_BIT|SASL_AUTHID_BIT, got) && 1004 bitset(SASL_PASSWORD_BIT, got))) 1005 goto fail; 1006 1007 /* no authid? copy uid */ 1008 if (!bitset(SASL_AUTHID_BIT, got)) 1009 { 1010 l = strlen((*sai)[SASL_USER]) + 1; 1011 (*sai)[SASL_AUTHID] = (char *) sm_rpool_malloc(mci->mci_rpool, 1012 l + 1); 1013 if ((*sai)[SASL_AUTHID] == NULL) 1014 goto tempfail; 1015 (void) sm_strlcpy((*sai)[SASL_AUTHID], (*sai)[SASL_USER], l); 1016 } 1017 1018 /* no uid? copy authid */ 1019 if (!bitset(SASL_USER_BIT, got)) 1020 { 1021 l = strlen((*sai)[SASL_AUTHID]) + 1; 1022 (*sai)[SASL_USER] = (char *) sm_rpool_malloc(mci->mci_rpool, 1023 l + 1); 1024 if ((*sai)[SASL_USER] == NULL) 1025 goto tempfail; 1026 (void) sm_strlcpy((*sai)[SASL_USER], (*sai)[SASL_AUTHID], l); 1027 } 1028 return EX_OK; 1029 1030 tempfail: 1031 ret = EX_TEMPFAIL; 1032 fail: 1033 if (LogLevel > 8) 1034 sm_syslog(LOG_WARNING, NOQID, 1035 "AUTH=client, relay=%.64s [%.16s], authinfo %sfailed", 1036 macvalue(macid("{server_name}"), e), 1037 macvalue(macid("{server_addr}"), e), 1038 ret == EX_TEMPFAIL ? "temp" : ""); 1039 for (i = 0; i <= SASL_MECHLIST; i++) 1040 (*sai)[i] = NULL; /* just clear; rpool */ 1041 return ret; 1042 } 1043 1044 # if SASL >= 20000 1045 /* 1046 ** GETSIMPLE -- callback to get userid or authid 1047 ** 1048 ** Parameters: 1049 ** context -- sai 1050 ** id -- what to do 1051 ** result -- (pointer to) result 1052 ** len -- (pointer to) length of result 1053 ** 1054 ** Returns: 1055 ** OK/failure values 1056 */ 1057 1058 static int 1059 getsimple(context, id, result, len) 1060 void *context; 1061 int id; 1062 const char **result; 1063 unsigned *len; 1064 { 1065 SASL_AI_T *sai; 1066 1067 if (result == NULL || context == NULL) 1068 return SASL_BADPARAM; 1069 sai = (SASL_AI_T *) context; 1070 1071 switch (id) 1072 { 1073 case SASL_CB_USER: 1074 *result = (*sai)[SASL_USER]; 1075 if (tTd(95, 5)) 1076 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'", 1077 *result); 1078 if (len != NULL) 1079 *len = *result != NULL ? strlen(*result) : 0; 1080 break; 1081 1082 case SASL_CB_AUTHNAME: 1083 *result = (*sai)[SASL_AUTHID]; 1084 if (tTd(95, 5)) 1085 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'", 1086 *result); 1087 if (len != NULL) 1088 *len = *result != NULL ? strlen(*result) : 0; 1089 break; 1090 1091 case SASL_CB_LANGUAGE: 1092 *result = NULL; 1093 if (len != NULL) 1094 *len = 0; 1095 break; 1096 1097 default: 1098 return SASL_BADPARAM; 1099 } 1100 return SASL_OK; 1101 } 1102 /* 1103 ** GETSECRET -- callback to get password 1104 ** 1105 ** Parameters: 1106 ** conn -- connection information 1107 ** context -- sai 1108 ** id -- what to do 1109 ** psecret -- (pointer to) result 1110 ** 1111 ** Returns: 1112 ** OK/failure values 1113 */ 1114 1115 static int 1116 getsecret(conn, context, id, psecret) 1117 sasl_conn_t *conn; 1118 SM_UNUSED(void *context); 1119 int id; 1120 sasl_secret_t **psecret; 1121 { 1122 int len; 1123 char *authpass; 1124 MCI *mci; 1125 1126 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS) 1127 return SASL_BADPARAM; 1128 1129 mci = (MCI *) context; 1130 authpass = mci->mci_sai[SASL_PASSWORD]; 1131 len = strlen(authpass); 1132 1133 /* 1134 ** use an rpool because we are responsible for free()ing the secret, 1135 ** but we can't free() it until after the auth completes 1136 */ 1137 1138 *psecret = (sasl_secret_t *) sm_rpool_malloc(mci->mci_rpool, 1139 sizeof(sasl_secret_t) + 1140 len + 1); 1141 if (*psecret == NULL) 1142 return SASL_FAIL; 1143 (void) sm_strlcpy((char *) (*psecret)->data, authpass, len + 1); 1144 (*psecret)->len = (unsigned long) len; 1145 return SASL_OK; 1146 } 1147 # else /* SASL >= 20000 */ 1148 /* 1149 ** GETSIMPLE -- callback to get userid or authid 1150 ** 1151 ** Parameters: 1152 ** context -- sai 1153 ** id -- what to do 1154 ** result -- (pointer to) result 1155 ** len -- (pointer to) length of result 1156 ** 1157 ** Returns: 1158 ** OK/failure values 1159 */ 1160 1161 static int 1162 getsimple(context, id, result, len) 1163 void *context; 1164 int id; 1165 const char **result; 1166 unsigned *len; 1167 { 1168 char *h, *s; 1169 # if SASL > 10509 1170 bool addrealm; 1171 # endif 1172 size_t l; 1173 SASL_AI_T *sai; 1174 char *authid = NULL; 1175 1176 if (result == NULL || context == NULL) 1177 return SASL_BADPARAM; 1178 sai = (SASL_AI_T *) context; 1179 1180 /* 1181 ** Unfortunately it is not clear whether this routine should 1182 ** return a copy of a string or just a pointer to a string. 1183 ** The Cyrus-SASL plugins treat these return values differently, e.g., 1184 ** plugins/cram.c free()s authid, plugings/digestmd5.c does not. 1185 ** The best solution to this problem is to fix Cyrus-SASL, but it 1186 ** seems there is nobody who creates patches... Hello CMU!? 1187 ** The second best solution is to have flags that tell this routine 1188 ** whether to return an malloc()ed copy. 1189 ** The next best solution is to always return an malloc()ed copy, 1190 ** and suffer from some memory leak, which is ugly for persistent 1191 ** queue runners. 1192 ** For now we go with the last solution... 1193 ** We can't use rpools (which would avoid this particular problem) 1194 ** as explained in sasl.c. 1195 */ 1196 1197 switch (id) 1198 { 1199 case SASL_CB_USER: 1200 l = strlen((*sai)[SASL_USER]) + 1; 1201 s = sm_sasl_malloc(l); 1202 if (s == NULL) 1203 { 1204 if (len != NULL) 1205 *len = 0; 1206 *result = NULL; 1207 return SASL_NOMEM; 1208 } 1209 (void) sm_strlcpy(s, (*sai)[SASL_USER], l); 1210 *result = s; 1211 if (tTd(95, 5)) 1212 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'", 1213 *result); 1214 if (len != NULL) 1215 *len = *result != NULL ? strlen(*result) : 0; 1216 break; 1217 1218 case SASL_CB_AUTHNAME: 1219 h = (*sai)[SASL_AUTHID]; 1220 # if SASL > 10509 1221 /* XXX maybe other mechanisms too?! */ 1222 addrealm = (*sai)[SASL_MECH] != NULL && 1223 SM_STRCASEEQ((*sai)[SASL_MECH], "cram-md5"); 1224 1225 /* 1226 ** Add realm to authentication id unless authid contains 1227 ** '@' (i.e., a realm) or the default realm is empty. 1228 */ 1229 1230 if (addrealm && h != NULL && strchr(h, '@') == NULL) 1231 { 1232 /* has this been done before? */ 1233 if ((*sai)[SASL_ID_REALM] == NULL) 1234 { 1235 char *realm; 1236 1237 realm = (*sai)[SASL_DEFREALM]; 1238 1239 /* do not add an empty realm */ 1240 if (*realm == '\0') 1241 { 1242 authid = h; 1243 (*sai)[SASL_ID_REALM] = NULL; 1244 } 1245 else 1246 { 1247 l = strlen(h) + strlen(realm) + 2; 1248 1249 /* should use rpool, but from where? */ 1250 authid = sm_sasl_malloc(l); 1251 if (authid != NULL) 1252 { 1253 (void) sm_snprintf(authid, l, 1254 "%s@%s", 1255 h, realm); 1256 (*sai)[SASL_ID_REALM] = authid; 1257 } 1258 else 1259 { 1260 authid = h; 1261 (*sai)[SASL_ID_REALM] = NULL; 1262 } 1263 } 1264 } 1265 else 1266 authid = (*sai)[SASL_ID_REALM]; 1267 } 1268 else 1269 # endif /* SASL > 10509 */ 1270 authid = h; 1271 l = strlen(authid) + 1; 1272 s = sm_sasl_malloc(l); 1273 if (s == NULL) 1274 { 1275 if (len != NULL) 1276 *len = 0; 1277 *result = NULL; 1278 return SASL_NOMEM; 1279 } 1280 (void) sm_strlcpy(s, authid, l); 1281 *result = s; 1282 if (tTd(95, 5)) 1283 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'", 1284 *result); 1285 if (len != NULL) 1286 *len = authid ? strlen(authid) : 0; 1287 break; 1288 1289 case SASL_CB_LANGUAGE: 1290 *result = NULL; 1291 if (len != NULL) 1292 *len = 0; 1293 break; 1294 1295 default: 1296 return SASL_BADPARAM; 1297 } 1298 return SASL_OK; 1299 } 1300 /* 1301 ** GETSECRET -- callback to get password 1302 ** 1303 ** Parameters: 1304 ** conn -- connection information 1305 ** context -- sai 1306 ** id -- what to do 1307 ** psecret -- (pointer to) result 1308 ** 1309 ** Returns: 1310 ** OK/failure values 1311 */ 1312 1313 static int 1314 getsecret(conn, context, id, psecret) 1315 sasl_conn_t *conn; 1316 SM_UNUSED(void *context); 1317 int id; 1318 sasl_secret_t **psecret; 1319 { 1320 int len; 1321 char *authpass; 1322 SASL_AI_T *sai; 1323 1324 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS) 1325 return SASL_BADPARAM; 1326 1327 sai = (SASL_AI_T *) context; 1328 authpass = (*sai)[SASL_PASSWORD]; 1329 len = strlen(authpass); 1330 *psecret = (sasl_secret_t *) sm_sasl_malloc(sizeof(sasl_secret_t) + 1331 len + 1); 1332 if (*psecret == NULL) 1333 return SASL_FAIL; 1334 (void) sm_strlcpy((*psecret)->data, authpass, len + 1); 1335 (*psecret)->len = (unsigned long) len; 1336 return SASL_OK; 1337 } 1338 # endif /* SASL >= 20000 */ 1339 1340 /* 1341 ** SAFESASLFILE -- callback for sasl: is file safe? 1342 ** 1343 ** Parameters: 1344 ** context -- pointer to context between invocations (unused) 1345 ** file -- name of file to check 1346 ** type -- type of file to check 1347 ** 1348 ** Returns: 1349 ** SASL_OK -- file can be used 1350 ** SASL_CONTINUE -- don't use file 1351 ** SASL_FAIL -- failure (not used here) 1352 ** 1353 */ 1354 1355 int 1356 # if SASL > 10515 1357 safesaslfile(context, file, type) 1358 # else 1359 safesaslfile(context, file) 1360 # endif 1361 void *context; 1362 # if SASL >= 20000 1363 const char *file; 1364 # else 1365 char *file; 1366 # endif 1367 # if SASL > 10515 1368 # if SASL >= 20000 1369 sasl_verify_type_t type; 1370 # else 1371 int type; 1372 # endif 1373 # endif 1374 { 1375 long sff; 1376 int r; 1377 # if SASL <= 10515 1378 size_t len; 1379 # endif 1380 char *p; 1381 1382 if (SM_IS_EMPTY(file)) 1383 return SASL_OK; 1384 if (tTd(95, 16)) 1385 sm_dprintf("safesaslfile=%s\n", file); 1386 sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOWWFILES|SFF_ROOTOK; 1387 # if SASL <= 10515 1388 if ((p = strrchr(file, '/')) == NULL) 1389 p = file; 1390 else 1391 ++p; 1392 1393 /* everything beside libs and .conf files must not be readable */ 1394 len = strlen(p); 1395 if ((len <= 3 || strncmp(p, "lib", 3) != 0) && 1396 (len <= 5 || strncmp(p + len - 5, ".conf", 5) != 0)) 1397 { 1398 if (!bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail)) 1399 sff |= SFF_NORFILES; 1400 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail)) 1401 sff |= SFF_NOGWFILES; 1402 } 1403 # else /* SASL <= 10515 */ 1404 /* files containing passwords should be not readable */ 1405 if (type == SASL_VRFY_PASSWD) 1406 { 1407 if (bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail)) 1408 sff |= SFF_NOWRFILES; 1409 else 1410 sff |= SFF_NORFILES; 1411 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail)) 1412 sff |= SFF_NOGWFILES; 1413 } 1414 # endif /* SASL <= 10515 */ 1415 1416 p = (char *) file; 1417 if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff, 1418 S_IRUSR, NULL)) == 0) 1419 return SASL_OK; 1420 if (LogLevel > (r != ENOENT ? 8 : 10)) 1421 sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s", 1422 p, sm_errstring(r)); 1423 return SASL_CONTINUE; 1424 } 1425 1426 /* 1427 ** SASLGETREALM -- return the realm for SASL 1428 ** 1429 ** return the realm for the client 1430 ** 1431 ** Parameters: 1432 ** context -- context shared between invocations 1433 ** availrealms -- list of available realms 1434 ** {realm, realm, ...} 1435 ** result -- pointer to result 1436 ** 1437 ** Returns: 1438 ** failure/success 1439 */ 1440 1441 static int 1442 saslgetrealm(context, id, availrealms, result) 1443 void *context; 1444 int id; 1445 const char **availrealms; 1446 const char **result; 1447 { 1448 char *r; 1449 SASL_AI_T *sai; 1450 1451 sai = (SASL_AI_T *) context; 1452 if (sai == NULL) 1453 return SASL_FAIL; 1454 r = (*sai)[SASL_DEFREALM]; 1455 1456 if (LogLevel > 12) 1457 sm_syslog(LOG_INFO, NOQID, 1458 "AUTH=client, realm=%s, available realms=%s", 1459 r == NULL ? "<No Realm>" : r, 1460 (NULL == availrealms || SM_IS_EMPTY(*availrealms)) 1461 ? "<No Realms>" : *availrealms); 1462 1463 /* check whether context is in list */ 1464 if (availrealms != NULL && *availrealms != NULL) 1465 { 1466 if (iteminlist(context, (char *)(*availrealms + 1), " ,}") == 1467 NULL) 1468 { 1469 if (LogLevel > 8) 1470 sm_syslog(LOG_ERR, NOQID, 1471 "AUTH=client, realm=%s not in list=%s", 1472 r, *availrealms); 1473 return SASL_FAIL; 1474 } 1475 } 1476 *result = r; 1477 return SASL_OK; 1478 } 1479 /* 1480 ** ITEMINLIST -- does item appear in list? 1481 ** 1482 ** Check whether item appears in list (which must be separated by a 1483 ** character in delim) as a "word", i.e. it must appear at the begin 1484 ** of the list or after a space, and it must end with a space or the 1485 ** end of the list. 1486 ** 1487 ** Parameters: 1488 ** item -- item to search. 1489 ** list -- list of items. 1490 ** delim -- list of delimiters. 1491 ** 1492 ** Returns: 1493 ** pointer to occurrence (NULL if not found). 1494 */ 1495 1496 char * 1497 iteminlist(item, list, delim) 1498 char *item; 1499 char *list; 1500 char *delim; 1501 { 1502 char *s; 1503 int len; 1504 1505 if (SM_IS_EMPTY(list)) 1506 return NULL; 1507 if (SM_IS_EMPTY(item)) 1508 return NULL; 1509 s = list; 1510 len = strlen(item); 1511 while (s != NULL && *s != '\0') 1512 { 1513 if (sm_strncasecmp(s, item, len) == 0 && 1514 (s[len] == '\0' || strchr(delim, s[len]) != NULL)) 1515 return s; 1516 s = strpbrk(s, delim); 1517 if (s != NULL) 1518 while (*++s == ' ') 1519 continue; 1520 } 1521 return NULL; 1522 } 1523 /* 1524 ** REMOVEMECH -- remove item [rem] from list [list] 1525 ** 1526 ** Parameters: 1527 ** rem -- item to remove 1528 ** list -- list of items 1529 ** rpool -- resource pool from which result is allocated. 1530 ** 1531 ** Returns: 1532 ** pointer to new list (NULL in case of error). 1533 */ 1534 1535 static char * 1536 removemech(rem, list, rpool) 1537 char *rem; 1538 char *list; 1539 SM_RPOOL_T *rpool; 1540 { 1541 char *ret; 1542 char *needle; 1543 int len; 1544 1545 if (list == NULL) 1546 return NULL; 1547 if (SM_IS_EMPTY(rem)) 1548 { 1549 /* take out what? */ 1550 return NULL; 1551 } 1552 1553 /* find the item in the list */ 1554 if ((needle = iteminlist(rem, list, " ")) == NULL) 1555 { 1556 /* not in there: return original */ 1557 return list; 1558 } 1559 1560 /* length of string without rem */ 1561 len = strlen(list) - strlen(rem); 1562 if (len <= 0) 1563 { 1564 ret = (char *) sm_rpool_malloc_x(rpool, 1); 1565 *ret = '\0'; 1566 return ret; 1567 } 1568 ret = (char *) sm_rpool_malloc_x(rpool, len); 1569 memset(ret, '\0', len); 1570 1571 /* copy from start to removed item */ 1572 memcpy(ret, list, needle - list); 1573 1574 /* length of rest of string past removed item */ 1575 len = strlen(needle) - strlen(rem) - 1; 1576 if (len > 0) 1577 { 1578 /* not last item -- copy into string */ 1579 memcpy(ret + (needle - list), 1580 list + (needle - list) + strlen(rem) + 1, 1581 len); 1582 } 1583 else 1584 ret[(needle - list) - 1] = '\0'; 1585 return ret; 1586 } 1587 /* 1588 ** ATTEMPTAUTH -- try to AUTHenticate using one mechanism 1589 ** 1590 ** Parameters: 1591 ** m -- the mailer. 1592 ** mci -- the mailer connection structure. 1593 ** e -- the envelope (including the sender to specify). 1594 ** sai - sasl authinfo 1595 ** 1596 ** Returns: 1597 ** EX_OK -- authentication was successful. 1598 ** EX_NOPERM -- authentication failed. 1599 ** EX_IOERR -- authentication dialogue failed (I/O problem?). 1600 ** EX_TEMPFAIL -- temporary failure. 1601 ** 1602 */ 1603 1604 static int 1605 attemptauth(m, mci, e, sai) 1606 MAILER *m; 1607 MCI *mci; 1608 ENVELOPE *e; 1609 SASL_AI_T *sai; 1610 { 1611 int saslresult, smtpresult; 1612 # if SASL >= 20000 1613 sasl_ssf_t ssf; 1614 const char *auth_id; 1615 const char *out; 1616 # else /* SASL >= 20000 */ 1617 sasl_external_properties_t ssf; 1618 char *out; 1619 # endif /* SASL >= 20000 */ 1620 unsigned int outlen; 1621 sasl_interact_t *client_interact = NULL; 1622 char *mechusing; 1623 sasl_security_properties_t ssp; 1624 1625 /* MUST NOT be a multiple of 4: bug in some sasl_encode64() versions */ 1626 char in64[MAXOUTLEN + 1]; 1627 # if NETINET || (NETINET6 && SASL >= 20000) 1628 extern SOCKADDR CurHostAddr; 1629 # endif 1630 1631 /* no mechanism selected (yet) */ 1632 (*sai)[SASL_MECH] = NULL; 1633 1634 /* dispose old connection */ 1635 if (mci->mci_conn != NULL) 1636 sasl_dispose(&(mci->mci_conn)); 1637 1638 /* make a new client sasl connection */ 1639 # if SASL >= 20000 1640 /* 1641 ** We provide the callbacks again because global callbacks in 1642 ** sasl_client_init() are ignored if SASL has been initialized 1643 ** before, for example, by a library such as libnss-ldap. 1644 */ 1645 1646 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp" 1647 : "smtp", 1648 CurHostName, NULL, NULL, callbacks, 0, 1649 &mci->mci_conn); 1650 # else /* SASL >= 20000 */ 1651 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp" 1652 : "smtp", 1653 CurHostName, NULL, 0, &mci->mci_conn); 1654 # endif /* SASL >= 20000 */ 1655 if (saslresult != SASL_OK) 1656 return EX_TEMPFAIL; 1657 1658 /* set properties */ 1659 (void) memset(&ssp, '\0', sizeof(ssp)); 1660 1661 /* XXX should these be options settable via .cf ? */ 1662 ssp.max_ssf = MaxSLBits; 1663 ssp.maxbufsize = MAXOUTLEN; 1664 # if 0 1665 ssp.security_flags = SASL_SEC_NOPLAINTEXT; 1666 # endif 1667 saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp); 1668 if (saslresult != SASL_OK) 1669 return EX_TEMPFAIL; 1670 1671 # if SASL >= 20000 1672 /* external security strength factor, authentication id */ 1673 ssf = 0; 1674 auth_id = NULL; 1675 # if STARTTLS 1676 out = macvalue(macid("{cert_subject}"), e); 1677 if (out != NULL && *out != '\0') 1678 auth_id = out; 1679 out = macvalue(macid("{cipher_bits}"), e); 1680 if (out != NULL && *out != '\0') 1681 ssf = atoi(out); 1682 # endif /* STARTTLS */ 1683 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf); 1684 if (saslresult != SASL_OK) 1685 return EX_TEMPFAIL; 1686 saslresult = sasl_setprop(mci->mci_conn, SASL_AUTH_EXTERNAL, auth_id); 1687 if (saslresult != SASL_OK) 1688 return EX_TEMPFAIL; 1689 1690 # if NETINET || NETINET6 1691 /* set local/remote ipv4 addresses */ 1692 if (mci->mci_out != NULL && ( 1693 # if NETINET6 1694 CurHostAddr.sa.sa_family == AF_INET6 || 1695 # endif 1696 CurHostAddr.sa.sa_family == AF_INET)) 1697 { 1698 SOCKADDR_LEN_T addrsize; 1699 SOCKADDR saddr_l; 1700 char localip[60], remoteip[60]; 1701 1702 switch (CurHostAddr.sa.sa_family) 1703 { 1704 case AF_INET: 1705 addrsize = sizeof(struct sockaddr_in); 1706 break; 1707 # if NETINET6 1708 case AF_INET6: 1709 addrsize = sizeof(struct sockaddr_in6); 1710 break; 1711 # endif 1712 default: 1713 break; 1714 } 1715 if (iptostring(&CurHostAddr, addrsize, 1716 remoteip, sizeof(remoteip))) 1717 { 1718 if (sasl_setprop(mci->mci_conn, SASL_IPREMOTEPORT, 1719 remoteip) != SASL_OK) 1720 return EX_TEMPFAIL; 1721 } 1722 addrsize = sizeof(saddr_l); 1723 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, 1724 NULL), 1725 (struct sockaddr *) &saddr_l, &addrsize) == 0) 1726 { 1727 if (iptostring(&saddr_l, addrsize, 1728 localip, sizeof(localip))) 1729 { 1730 if (sasl_setprop(mci->mci_conn, 1731 SASL_IPLOCALPORT, 1732 localip) != SASL_OK) 1733 return EX_TEMPFAIL; 1734 } 1735 } 1736 } 1737 # endif /* NETINET || NETINET6 */ 1738 1739 /* start client side of sasl */ 1740 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap, 1741 &client_interact, 1742 &out, &outlen, 1743 (const char **) &mechusing); 1744 # else /* SASL >= 20000 */ 1745 /* external security strength factor, authentication id */ 1746 ssf.ssf = 0; 1747 ssf.auth_id = NULL; 1748 # if STARTTLS 1749 out = macvalue(macid("{cert_subject}"), e); 1750 if (out != NULL && *out != '\0') 1751 ssf.auth_id = out; 1752 out = macvalue(macid("{cipher_bits}"), e); 1753 if (out != NULL && *out != '\0') 1754 ssf.ssf = atoi(out); 1755 # endif /* STARTTLS */ 1756 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf); 1757 if (saslresult != SASL_OK) 1758 return EX_TEMPFAIL; 1759 1760 # if NETINET 1761 /* set local/remote ipv4 addresses */ 1762 if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET) 1763 { 1764 SOCKADDR_LEN_T addrsize; 1765 struct sockaddr_in saddr_l; 1766 1767 if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE, 1768 (struct sockaddr_in *) &CurHostAddr) 1769 != SASL_OK) 1770 return EX_TEMPFAIL; 1771 addrsize = sizeof(struct sockaddr_in); 1772 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, 1773 NULL), 1774 (struct sockaddr *) &saddr_l, &addrsize) == 0) 1775 { 1776 if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL, 1777 &saddr_l) != SASL_OK) 1778 return EX_TEMPFAIL; 1779 } 1780 } 1781 # endif /* NETINET */ 1782 1783 /* start client side of sasl */ 1784 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap, 1785 NULL, &client_interact, 1786 &out, &outlen, 1787 (const char **) &mechusing); 1788 # endif /* SASL >= 20000 */ 1789 1790 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE) 1791 { 1792 if (saslresult == SASL_NOMECH && LogLevel > 8) 1793 { 1794 sm_syslog(LOG_NOTICE, e->e_id, 1795 "AUTH=client, available mechanisms=%s do not fulfill requirements", mci->mci_saslcap); 1796 } 1797 return EX_TEMPFAIL; 1798 } 1799 1800 /* just point current mechanism to the data in the sasl library */ 1801 (*sai)[SASL_MECH] = mechusing; 1802 1803 /* send the info across the wire */ 1804 if (out == NULL 1805 /* login and digest-md5 up to 1.5.28 set out="" */ 1806 || (outlen == 0 && 1807 (SM_STRCASEEQ(mechusing, "login") || 1808 SM_STRCASEEQ(mechusing, "digest-md5"))) 1809 ) 1810 { 1811 /* no initial response */ 1812 smtpmessage("AUTH %s", m, mci, mechusing); 1813 } 1814 else if (outlen == 0) 1815 { 1816 /* 1817 ** zero-length initial response, per RFC 2554 4.: 1818 ** "Unlike a zero-length client answer to a 334 reply, a zero- 1819 ** length initial response is sent as a single equals sign" 1820 */ 1821 1822 smtpmessage("AUTH %s =", m, mci, mechusing); 1823 } 1824 else 1825 { 1826 saslresult = sasl_encode64(out, outlen, in64, sizeof(in64), 1827 NULL); 1828 if (saslresult != SASL_OK) /* internal error */ 1829 { 1830 if (LogLevel > 8) 1831 sm_syslog(LOG_ERR, e->e_id, 1832 "encode64 for AUTH failed"); 1833 return EX_TEMPFAIL; 1834 } 1835 smtpmessage("AUTH %s %s", m, mci, mechusing, in64); 1836 } 1837 # if SASL < 20000 1838 sm_sasl_free(out); /* XXX only if no rpool is used */ 1839 # endif 1840 1841 /* get the reply */ 1842 smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL, 1843 XS_AUTH); 1844 1845 for (;;) 1846 { 1847 /* check return code from server */ 1848 if (smtpresult == 235) 1849 { 1850 macdefine(&mci->mci_macro, A_TEMP, macid("{auth_type}"), 1851 mechusing); 1852 return EX_OK; 1853 } 1854 if (smtpresult == -1) 1855 return EX_IOERR; 1856 if (REPLYTYPE(smtpresult) == 5) 1857 return EX_NOPERM; /* ugly, but ... */ 1858 if (REPLYTYPE(smtpresult) != 3) 1859 { 1860 /* should we fail deliberately, see RFC 2554 4. ? */ 1861 /* smtpmessage("*", m, mci); */ 1862 return EX_TEMPFAIL; 1863 } 1864 1865 saslresult = sasl_client_step(mci->mci_conn, 1866 mci->mci_sasl_string, 1867 mci->mci_sasl_string_len, 1868 &client_interact, 1869 &out, &outlen); 1870 1871 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE) 1872 { 1873 if (tTd(95, 5)) 1874 sm_dprintf("AUTH FAIL=%s (%d)\n", 1875 sasl_errstring(saslresult, NULL, NULL), 1876 saslresult); 1877 1878 /* fail deliberately, see RFC 2554 4. */ 1879 smtpmessage("*", m, mci); 1880 1881 /* 1882 ** but we should only fail for this authentication 1883 ** mechanism; how to do that? 1884 */ 1885 1886 smtpresult = reply(m, mci, e, TimeOuts.to_auth, 1887 getsasldata, NULL, XS_AUTH); 1888 return EX_NOPERM; 1889 } 1890 1891 if (outlen > 0) 1892 { 1893 saslresult = sasl_encode64(out, outlen, in64, 1894 sizeof(in64), NULL); 1895 if (saslresult != SASL_OK) 1896 { 1897 /* give an error reply to the other side! */ 1898 smtpmessage("*", m, mci); 1899 return EX_TEMPFAIL; 1900 } 1901 } 1902 else 1903 in64[0] = '\0'; 1904 # if SASL < 20000 1905 sm_sasl_free(out); /* XXX only if no rpool is used */ 1906 # endif 1907 smtpmessage("%s", m, mci, in64); 1908 smtpresult = reply(m, mci, e, TimeOuts.to_auth, 1909 getsasldata, NULL, XS_AUTH); 1910 } 1911 /* NOTREACHED */ 1912 } 1913 /* 1914 ** SMTPAUTH -- try to AUTHenticate 1915 ** 1916 ** This will try mechanisms in the order the sasl library decided until: 1917 ** - there are no more mechanisms 1918 ** - a mechanism succeeds 1919 ** - the sasl library fails initializing 1920 ** 1921 ** Parameters: 1922 ** m -- the mailer. 1923 ** mci -- the mailer connection info. 1924 ** e -- the envelope. 1925 ** 1926 ** Returns: 1927 ** EX_OK -- authentication was successful 1928 ** EX_UNAVAILABLE -- authentication not possible, e.g., 1929 ** no data available. 1930 ** EX_NOPERM -- authentication failed. 1931 ** EX_TEMPFAIL -- temporary failure. 1932 ** 1933 ** Notice: AuthInfo is used for all connections, hence we must 1934 ** return EX_TEMPFAIL only if we really want to retry, i.e., 1935 ** iff getauth() tempfailed or getauth() was used and 1936 ** authentication tempfailed. 1937 */ 1938 1939 int 1940 smtpauth(m, mci, e) 1941 MAILER *m; 1942 MCI *mci; 1943 ENVELOPE *e; 1944 { 1945 int result; 1946 int i; 1947 bool usedgetauth; 1948 1949 mci->mci_sasl_auth = false; 1950 for (i = 0; i < SASL_MECH ; i++) 1951 mci->mci_sai[i] = NULL; 1952 1953 result = getauth(mci, e, &(mci->mci_sai)); 1954 if (result == EX_TEMPFAIL) 1955 return result; 1956 usedgetauth = true; 1957 1958 /* no data available: don't try to authenticate */ 1959 if (result == EX_OK && mci->mci_sai[SASL_AUTHID] == NULL) 1960 return result; 1961 if (result != EX_OK) 1962 { 1963 if (SASLInfo == NULL) 1964 return EX_UNAVAILABLE; 1965 1966 /* read authinfo from file */ 1967 result = readauth(SASLInfo, true, &(mci->mci_sai), 1968 mci->mci_rpool); 1969 if (result != EX_OK) 1970 return result; 1971 usedgetauth = false; 1972 } 1973 1974 /* check whether sufficient data is available */ 1975 if (mci->mci_sai[SASL_PASSWORD] == NULL || 1976 *(mci->mci_sai)[SASL_PASSWORD] == '\0') 1977 return EX_UNAVAILABLE; 1978 if ((mci->mci_sai[SASL_AUTHID] == NULL || 1979 *(mci->mci_sai)[SASL_AUTHID] == '\0') && 1980 (mci->mci_sai[SASL_USER] == NULL || 1981 *(mci->mci_sai)[SASL_USER] == '\0')) 1982 return EX_UNAVAILABLE; 1983 1984 /* set the context for the callback function to sai */ 1985 # if SASL >= 20000 1986 callbacks[CB_PASS_IDX].context = (void *) mci; 1987 # else 1988 callbacks[CB_PASS_IDX].context = (void *) &mci->mci_sai; 1989 # endif 1990 callbacks[CB_USER_IDX].context = (void *) &mci->mci_sai; 1991 callbacks[CB_AUTHNAME_IDX].context = (void *) &mci->mci_sai; 1992 callbacks[CB_GETREALM_IDX].context = (void *) &mci->mci_sai; 1993 # if 0 1994 callbacks[CB_SAFESASL_IDX].context = (void *) &mci->mci_sai; 1995 # endif 1996 1997 /* set default value for realm */ 1998 if ((mci->mci_sai)[SASL_DEFREALM] == NULL) 1999 (mci->mci_sai)[SASL_DEFREALM] = sm_rpool_strdup_x(e->e_rpool, 2000 macvalue('j', CurEnv)); 2001 2002 /* set default value for list of mechanism to use */ 2003 if ((mci->mci_sai)[SASL_MECHLIST] == NULL || 2004 *(mci->mci_sai)[SASL_MECHLIST] == '\0') 2005 (mci->mci_sai)[SASL_MECHLIST] = AuthMechanisms; 2006 2007 /* create list of mechanisms to try */ 2008 mci->mci_saslcap = intersect((mci->mci_sai)[SASL_MECHLIST], 2009 mci->mci_saslcap, mci->mci_rpool); 2010 2011 /* initialize sasl client library */ 2012 result = init_sasl_client(); 2013 if (result != SASL_OK) 2014 return usedgetauth ? EX_TEMPFAIL : EX_UNAVAILABLE; 2015 do 2016 { 2017 result = attemptauth(m, mci, e, &(mci->mci_sai)); 2018 if (result == EX_OK) 2019 mci->mci_sasl_auth = true; 2020 else if (result == EX_TEMPFAIL || result == EX_NOPERM) 2021 { 2022 mci->mci_saslcap = removemech((mci->mci_sai)[SASL_MECH], 2023 mci->mci_saslcap, 2024 mci->mci_rpool); 2025 if (mci->mci_saslcap == NULL || 2026 *(mci->mci_saslcap) == '\0') 2027 return usedgetauth ? result 2028 : EX_UNAVAILABLE; 2029 } 2030 else 2031 return result; 2032 } while (result != EX_OK); 2033 return result; 2034 } 2035 #endif /* SASL */ 2036 2037 /* 2038 ** SMTPMAILFROM -- send MAIL command 2039 ** 2040 ** Parameters: 2041 ** m -- the mailer. 2042 ** mci -- the mailer connection structure. 2043 ** e -- the envelope (including the sender to specify). 2044 ** 2045 ** Returns: 2046 ** exit status corresponding to mail status. 2047 */ 2048 2049 int 2050 smtpmailfrom(m, mci, e) 2051 MAILER *m; 2052 MCI *mci; 2053 ENVELOPE *e; 2054 { 2055 int r; 2056 char *bufp; 2057 char *bodytype; 2058 char *enhsc; 2059 char buf[MAXNAME_I + 1]; 2060 char optbuf[MAXLINE]; 2061 #if _FFR_8BITENVADDR 2062 int len, nlen; 2063 #endif 2064 2065 if (tTd(18, 2)) 2066 sm_dprintf("smtpmailfrom: CurHost=%s\n", CurHostName); 2067 enhsc = NULL; 2068 2069 /* 2070 ** Check if connection is gone, if so 2071 ** it's a tempfail and we use mci_errno 2072 ** for the reason. 2073 */ 2074 2075 if (mci->mci_state == MCIS_CLOSED) 2076 { 2077 errno = mci->mci_errno; 2078 return EX_TEMPFAIL; 2079 } 2080 2081 #if USE_EAI 2082 if (bitset(EF_RESPONSE, e->e_flags) && 2083 !bitnset(M_NO_NULL_FROM, m->m_flags)) 2084 buf[0] = '\0'; 2085 else 2086 { 2087 expand("\201g", buf, sizeof(buf), e); 2088 if (!addr_is_ascii(buf) && !e->e_smtputf8) 2089 e->e_smtputf8 = true; 2090 } 2091 2092 if (e->e_smtputf8 && !SMTPUTF8) 2093 { 2094 extern char MsgBuf[]; 2095 2096 /* XREF: format must be coordinated with giveresponse() */ 2097 usrerrenh("5.6.7", "504 SMTPUTF8 required but not enabled"); 2098 mci_setstat(mci, EX_NOTSTICKY, "5.6.7", MsgBuf); 2099 return EX_DATAERR; 2100 } 2101 2102 /* 2103 ** Abort right away if the message needs SMTPUTF8 2104 ** but the server does not advertise it. 2105 */ 2106 2107 if (e->e_smtputf8 && !bitset(MCIF_EAI, mci->mci_flags)) 2108 { 2109 extern char MsgBuf[]; 2110 2111 /* XREF: format must be coordinated with giveresponse() */ 2112 usrerrenh("5.6.7", "504 SMTPUTF8 required but not offered"); 2113 mci_setstat(mci, EX_NOTSTICKY, "5.6.7", MsgBuf); 2114 return EX_DATAERR; 2115 } 2116 #endif /* USE_EAI */ 2117 2118 /* set up appropriate options to include */ 2119 if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) 2120 { 2121 (void) sm_snprintf(optbuf, sizeof(optbuf), " SIZE=%ld", 2122 e->e_msgsize); 2123 bufp = &optbuf[strlen(optbuf)]; 2124 } 2125 else 2126 { 2127 optbuf[0] = '\0'; 2128 bufp = optbuf; 2129 } 2130 2131 #if USE_EAI 2132 if (e->e_smtputf8) 2133 { 2134 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2135 " SMTPUTF8"); 2136 bufp += strlen(bufp); 2137 } 2138 #endif /* USE_EAI */ 2139 2140 bodytype = e->e_bodytype; 2141 if (bitset(MCIF_8BITMIME, mci->mci_flags)) 2142 { 2143 if (bodytype == NULL && 2144 bitset(MM_MIME8BIT, MimeMode) && 2145 bitset(EF_HAS8BIT, e->e_flags) && 2146 !bitset(EF_DONT_MIME, e->e_flags) && 2147 !bitnset(M_8BITS, m->m_flags)) 2148 bodytype = "8BITMIME"; 2149 if (bodytype != NULL && 2150 SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7) 2151 { 2152 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2153 " BODY=%s", bodytype); 2154 bufp += strlen(bufp); 2155 } 2156 } 2157 else if (bitnset(M_8BITS, m->m_flags) || 2158 !bitset(EF_HAS8BIT, e->e_flags) || 2159 bitset(MCIF_8BITOK, mci->mci_flags)) 2160 { 2161 /* EMPTY */ 2162 /* just pass it through */ 2163 } 2164 #if MIME8TO7 2165 else if (bitset(MM_CVTMIME, MimeMode) && 2166 !bitset(EF_DONT_MIME, e->e_flags) && 2167 (!bitset(MM_PASS8BIT, MimeMode) || 2168 bitset(EF_IS_MIME, e->e_flags))) 2169 { 2170 /* must convert from 8bit MIME format to 7bit encoded */ 2171 mci->mci_flags |= MCIF_CVT8TO7; 2172 } 2173 #endif /* MIME8TO7 */ 2174 else if (!bitset(MM_PASS8BIT, MimeMode)) 2175 { 2176 /* cannot just send a 8-bit version */ 2177 extern char MsgBuf[]; 2178 2179 usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName); 2180 mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf); 2181 return EX_DATAERR; 2182 } 2183 2184 if (bitset(MCIF_DSN, mci->mci_flags)) 2185 { 2186 if (e->e_envid != NULL && 2187 SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7) 2188 { 2189 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2190 " ENVID=%s", e->e_envid); 2191 bufp += strlen(bufp); 2192 } 2193 2194 /* RET= parameter */ 2195 if (bitset(EF_RET_PARAM, e->e_flags) && 2196 SPACELEFT(optbuf, bufp) > 9) 2197 { 2198 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2199 " RET=%s", 2200 bitset(EF_NO_BODY_RETN, e->e_flags) ? 2201 "HDRS" : "FULL"); 2202 bufp += strlen(bufp); 2203 } 2204 } 2205 2206 if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL && 2207 SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7 2208 #if SASL 2209 && (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth) 2210 #endif 2211 ) 2212 { 2213 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2214 " AUTH=%s", e->e_auth_param); 2215 bufp += strlen(bufp); 2216 } 2217 2218 /* 2219 ** 17 is the max length required, we could use log() to compute 2220 ** the exact length (and check IS_DLVR_TRACE()) 2221 */ 2222 2223 if (bitset(MCIF_DLVR_BY, mci->mci_flags) && 2224 IS_DLVR_BY(e) && SPACELEFT(optbuf, bufp) > 17) 2225 { 2226 long dby; 2227 2228 /* 2229 ** Avoid problems with delays (for R) since the check 2230 ** in deliver() whether min-deliver-time is sufficient. 2231 ** Alternatively we could pass the computed time to this 2232 ** function. 2233 */ 2234 2235 dby = e->e_deliver_by - (curtime() - e->e_ctime); 2236 if (dby <= 0 && IS_DLVR_RETURN(e)) 2237 dby = mci->mci_min_by <= 0 ? 1 : mci->mci_min_by; 2238 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2239 " BY=%ld;%c%s", 2240 dby, 2241 IS_DLVR_RETURN(e) ? 'R' : 'N', 2242 IS_DLVR_TRACE(e) ? "T" : ""); 2243 bufp += strlen(bufp); 2244 } 2245 2246 /* 2247 ** Send the MAIL command. 2248 ** Designates the sender. 2249 */ 2250 2251 mci->mci_state = MCIS_MAIL; 2252 2253 #if !USE_EAI 2254 if (bitset(EF_RESPONSE, e->e_flags) && 2255 !bitnset(M_NO_NULL_FROM, m->m_flags)) 2256 buf[0] = '\0'; 2257 else 2258 expand("\201g", buf, sizeof(buf), e); 2259 #endif /* !USE_EAI */ 2260 #if _FFR_8BITENVADDR 2261 if (tTd(18, 11)) 2262 sm_dprintf("mail_expand=%s\n", buf); 2263 len = sizeof(buf); 2264 nlen = dequote_internal_chars(buf, buf, len); 2265 /* check length! but that's a bit late... */ 2266 if (nlen > MAXNAME) 2267 sm_syslog(LOG_ERR, e->e_id, "MAIL too long: %d", nlen); 2268 if (tTd(18, 11)) 2269 sm_dprintf("mail2=%s\n", buf); 2270 #endif /* _FFR_8BITENVADDR */ 2271 if (buf[0] == '<') 2272 { 2273 /* strip off <angle brackets> (put back on below) */ 2274 bufp = &buf[strlen(buf) - 1]; 2275 if (*bufp == '>') 2276 *bufp = '\0'; 2277 bufp = &buf[1]; 2278 } 2279 else 2280 bufp = buf; 2281 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 2282 !bitnset(M_FROMPATH, m->m_flags)) 2283 { 2284 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 2285 } 2286 else 2287 { 2288 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 2289 *bufp == '@' ? ',' : ':', bufp, optbuf); 2290 } 2291 SmtpPhase = mci->mci_phase = "client MAIL"; 2292 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), 2293 CurHostName, mci->mci_phase); 2294 r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc, XS_MAIL); 2295 if (r < 0) 2296 { 2297 /* communications failure */ 2298 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 2299 return EX_TEMPFAIL; 2300 } 2301 else if (r == SMTPCLOSING) 2302 { 2303 /* service shutting down: handled by reply() */ 2304 return EX_TEMPFAIL; 2305 } 2306 else if (REPLYTYPE(r) == 4) 2307 { 2308 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)), 2309 SmtpReplyBuffer); 2310 return EX_TEMPFAIL; 2311 } 2312 else if (REPLYTYPE(r) == 2) 2313 { 2314 return EX_OK; 2315 } 2316 else if (r == 501) 2317 { 2318 /* syntax error in arguments */ 2319 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"), 2320 SmtpReplyBuffer); 2321 return EX_DATAERR; 2322 } 2323 else if (r == 553) 2324 { 2325 /* mailbox name not allowed */ 2326 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"), 2327 SmtpReplyBuffer); 2328 return EX_DATAERR; 2329 } 2330 else if (r == 552) 2331 { 2332 /* exceeded storage allocation */ 2333 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"), 2334 SmtpReplyBuffer); 2335 if (bitset(MCIF_SIZE, mci->mci_flags)) 2336 e->e_flags |= EF_NO_BODY_RETN; 2337 return EX_UNAVAILABLE; 2338 } 2339 else if (REPLYTYPE(r) == 5) 2340 { 2341 /* unknown error */ 2342 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"), 2343 SmtpReplyBuffer); 2344 return EX_UNAVAILABLE; 2345 } 2346 2347 if (LogLevel > 1) 2348 { 2349 sm_syslog(LOG_CRIT, e->e_id, 2350 "%.100s: SMTP MAIL protocol error: %s", 2351 CurHostName, 2352 shortenstring(SmtpReplyBuffer, 403)); 2353 } 2354 2355 /* protocol error -- close up */ 2356 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"), 2357 SmtpReplyBuffer); 2358 smtpquit(m, mci, e); 2359 return EX_PROTOCOL; 2360 } 2361 /* 2362 ** SMTPRCPT -- designate recipient. 2363 ** 2364 ** Parameters: 2365 ** to -- address of recipient. 2366 ** m -- the mailer we are sending to. 2367 ** mci -- the connection info for this transaction. 2368 ** e -- the envelope for this transaction. 2369 ** 2370 ** Returns: 2371 ** exit status corresponding to recipient status. 2372 ** 2373 ** Side Effects: 2374 ** Sends the mail via SMTP. 2375 */ 2376 2377 int 2378 smtprcpt(to, m, mci, e, ctladdr, xstart) 2379 ADDRESS *to; 2380 register MAILER *m; 2381 MCI *mci; 2382 ENVELOPE *e; 2383 ADDRESS *ctladdr; 2384 time_t xstart; 2385 { 2386 char *bufp; 2387 char optbuf[MAXLINE]; 2388 char *rcpt; 2389 #if _FFR_8BITENVADDR 2390 char buf[MAXNAME + 1]; /* EAI:ok */ 2391 int len, nlen; 2392 #endif 2393 2394 #if PIPELINING 2395 /* 2396 ** If there is status waiting from the other end, read it. 2397 ** This should normally happen because of SMTP pipelining. 2398 */ 2399 2400 while (mci->mci_nextaddr != NULL && 2401 sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0) 2402 { 2403 int r; 2404 2405 r = smtprcptstat(mci->mci_nextaddr, m, mci, e); 2406 if (r != EX_OK) 2407 { 2408 markfailure(e, mci->mci_nextaddr, mci, r, false); 2409 giveresponse(r, mci->mci_nextaddr->q_status, m, mci, 2410 ctladdr, xstart, e, to); 2411 } 2412 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain; 2413 } 2414 #endif /* PIPELINING */ 2415 2416 /* 2417 ** Check if connection is gone, if so 2418 ** it's a tempfail and we use mci_errno 2419 ** for the reason. 2420 */ 2421 2422 if (mci->mci_state == MCIS_CLOSED) 2423 { 2424 errno = mci->mci_errno; 2425 return EX_TEMPFAIL; 2426 } 2427 2428 optbuf[0] = '\0'; 2429 bufp = optbuf; 2430 2431 /* 2432 ** Warning: in the following it is assumed that the free space 2433 ** in bufp is sizeof(optbuf) 2434 */ 2435 2436 if (bitset(MCIF_DSN, mci->mci_flags)) 2437 { 2438 if (IS_DLVR_NOTIFY(e) && 2439 !bitset(MCIF_DLVR_BY, mci->mci_flags)) 2440 { 2441 /* RFC 2852: 4.1.4.2 */ 2442 if (!bitset(QHASNOTIFY, to->q_flags)) 2443 to->q_flags |= QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY; 2444 else if (bitset(QPINGONSUCCESS, to->q_flags) || 2445 bitset(QPINGONFAILURE, to->q_flags) || 2446 bitset(QPINGONDELAY, to->q_flags)) 2447 to->q_flags |= QPINGONDELAY; 2448 } 2449 2450 /* NOTIFY= parameter */ 2451 if (bitset(QHASNOTIFY, to->q_flags) && 2452 bitset(QPRIMARY, to->q_flags) && 2453 !bitnset(M_LOCALMAILER, m->m_flags)) 2454 { 2455 bool firstone = true; 2456 2457 (void) sm_strlcat(bufp, " NOTIFY=", sizeof(optbuf)); 2458 if (bitset(QPINGONSUCCESS, to->q_flags)) 2459 { 2460 (void) sm_strlcat(bufp, "SUCCESS", sizeof(optbuf)); 2461 firstone = false; 2462 } 2463 if (bitset(QPINGONFAILURE, to->q_flags)) 2464 { 2465 if (!firstone) 2466 (void) sm_strlcat(bufp, ",", 2467 sizeof(optbuf)); 2468 (void) sm_strlcat(bufp, "FAILURE", sizeof(optbuf)); 2469 firstone = false; 2470 } 2471 if (bitset(QPINGONDELAY, to->q_flags)) 2472 { 2473 if (!firstone) 2474 (void) sm_strlcat(bufp, ",", 2475 sizeof(optbuf)); 2476 (void) sm_strlcat(bufp, "DELAY", sizeof(optbuf)); 2477 firstone = false; 2478 } 2479 if (firstone) 2480 (void) sm_strlcat(bufp, "NEVER", sizeof(optbuf)); 2481 bufp += strlen(bufp); 2482 } 2483 2484 /* ORCPT= parameter */ 2485 if (to->q_orcpt != NULL && 2486 SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7) 2487 { 2488 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2489 " ORCPT=%s", to->q_orcpt); 2490 bufp += strlen(bufp); 2491 } 2492 } 2493 2494 rcpt = to->q_user; 2495 #if _FFR_8BITENVADDR 2496 if (tTd(18, 11)) 2497 sm_dprintf("rcpt=%s\n", rcpt); 2498 len = sizeof(buf); 2499 nlen = dequote_internal_chars(rcpt, buf, len); 2500 rcpt = buf; 2501 /* check length! but that's a bit late... */ 2502 if (nlen > MAXNAME) 2503 sm_syslog(LOG_ERR, e->e_id, "RCPT too long: %d", nlen); 2504 if (tTd(18, 11)) 2505 sm_dprintf("rcpt2=%s\n", rcpt); 2506 #endif /* _FFR_8BITENVADDR */ 2507 2508 smtpmessage("RCPT To:<%s>%s", m, mci, rcpt, optbuf); 2509 mci->mci_state = MCIS_RCPT; 2510 2511 SmtpPhase = mci->mci_phase = "client RCPT"; 2512 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), 2513 CurHostName, mci->mci_phase); 2514 2515 #if PIPELINING 2516 /* 2517 ** If running SMTP pipelining, we will pick up status later 2518 */ 2519 2520 if (bitset(MCIF_PIPELINED, mci->mci_flags)) 2521 return EX_OK; 2522 #endif /* PIPELINING */ 2523 2524 return smtprcptstat(to, m, mci, e); 2525 } 2526 /* 2527 ** SMTPRCPTSTAT -- get recipient status 2528 ** 2529 ** This is only called during SMTP pipelining 2530 ** 2531 ** Parameters: 2532 ** to -- address of recipient. 2533 ** m -- mailer being sent to. 2534 ** mci -- the mailer connection information. 2535 ** e -- the envelope for this message. 2536 ** 2537 ** Returns: 2538 ** EX_* -- protocol status 2539 */ 2540 2541 static int 2542 smtprcptstat(to, m, mci, e) 2543 ADDRESS *to; 2544 MAILER *m; 2545 register MCI *mci; 2546 register ENVELOPE *e; 2547 { 2548 int r; 2549 int save_errno; 2550 char *enhsc; 2551 2552 /* 2553 ** Check if connection is gone, if so 2554 ** it's a tempfail and we use mci_errno 2555 ** for the reason. 2556 */ 2557 2558 if (mci->mci_state == MCIS_CLOSED) 2559 { 2560 errno = mci->mci_errno; 2561 return EX_TEMPFAIL; 2562 } 2563 2564 enhsc = NULL; 2565 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc, XS_RCPT); 2566 save_errno = errno; 2567 to->q_rstatus = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer); 2568 to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool); 2569 if (!bitnset(M_LMTP, m->m_flags)) 2570 to->q_statmta = mci->mci_host; 2571 if (r < 0 || REPLYTYPE(r) == 4) 2572 { 2573 mci->mci_retryrcpt = true; 2574 errno = save_errno; 2575 return EX_TEMPFAIL; 2576 } 2577 else if (REPLYTYPE(r) == 2) 2578 { 2579 char *t; 2580 2581 if ((t = mci->mci_tolist) != NULL) 2582 { 2583 char *p; 2584 2585 *t++ = ','; 2586 for (p = to->q_paddr; *p != '\0'; *t++ = *p++) 2587 continue; 2588 *t = '\0'; 2589 mci->mci_tolist = t; 2590 } 2591 mci->mci_okrcpts++; 2592 return EX_OK; 2593 } 2594 else if (r == 550) 2595 { 2596 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.1", e->e_rpool); 2597 return EX_NOUSER; 2598 } 2599 else if (r == 551) 2600 { 2601 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.6", e->e_rpool); 2602 return EX_NOUSER; 2603 } 2604 else if (r == 553) 2605 { 2606 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.3", e->e_rpool); 2607 return EX_NOUSER; 2608 } 2609 else if (REPLYTYPE(r) == 5) 2610 { 2611 return EX_UNAVAILABLE; 2612 } 2613 2614 if (LogLevel > 1) 2615 { 2616 sm_syslog(LOG_CRIT, e->e_id, 2617 "%.100s: SMTP RCPT protocol error: %s", 2618 CurHostName, 2619 shortenstring(SmtpReplyBuffer, 403)); 2620 } 2621 2622 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"), 2623 SmtpReplyBuffer); 2624 return EX_PROTOCOL; 2625 } 2626 /* 2627 ** SMTPDATA -- send the data and clean up the transaction. 2628 ** 2629 ** Parameters: 2630 ** m -- mailer being sent to. 2631 ** mci -- the mailer connection information. 2632 ** e -- the envelope for this message. 2633 ** 2634 ** Returns: 2635 ** exit status corresponding to DATA command. 2636 */ 2637 2638 int 2639 smtpdata(m, mci, e, ctladdr, xstart) 2640 MAILER *m; 2641 register MCI *mci; 2642 register ENVELOPE *e; 2643 ADDRESS *ctladdr; 2644 time_t xstart; 2645 { 2646 register int r; 2647 int rstat; 2648 int xstat; 2649 int timeout; 2650 char *enhsc; 2651 2652 /* 2653 ** Check if connection is gone, if so 2654 ** it's a tempfail and we use mci_errno 2655 ** for the reason. 2656 */ 2657 2658 if (mci->mci_state == MCIS_CLOSED) 2659 { 2660 errno = mci->mci_errno; 2661 return EX_TEMPFAIL; 2662 } 2663 2664 enhsc = NULL; 2665 2666 /* 2667 ** Send the data. 2668 ** First send the command and check that it is ok. 2669 ** Then send the data (if there are valid recipients). 2670 ** Follow it up with a dot to terminate. 2671 ** Finally get the results of the transaction. 2672 */ 2673 2674 /* send the command and check ok to proceed */ 2675 smtpmessage("DATA", m, mci); 2676 2677 #if PIPELINING 2678 if (mci->mci_nextaddr != NULL) 2679 { 2680 char *oldto = e->e_to; 2681 2682 /* pick up any pending RCPT responses for SMTP pipelining */ 2683 while (mci->mci_nextaddr != NULL) 2684 { 2685 e->e_to = mci->mci_nextaddr->q_paddr; 2686 r = smtprcptstat(mci->mci_nextaddr, m, mci, e); 2687 if (r != EX_OK) 2688 { 2689 markfailure(e, mci->mci_nextaddr, mci, r, 2690 false); 2691 giveresponse(r, mci->mci_nextaddr->q_status, m, 2692 mci, ctladdr, xstart, e, 2693 mci->mci_nextaddr); 2694 if (r == EX_TEMPFAIL) 2695 mci->mci_nextaddr->q_state = QS_RETRY; 2696 } 2697 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain; 2698 } 2699 e->e_to = oldto; 2700 2701 /* 2702 ** Connection might be closed in response to a RCPT command, 2703 ** i.e., the server responded with 421. In that case (at 2704 ** least) one RCPT has a temporary failure, hence we don't 2705 ** need to check mci_okrcpts (as it is done below) to figure 2706 ** out which error to return. 2707 */ 2708 2709 if (mci->mci_state == MCIS_CLOSED) 2710 { 2711 errno = mci->mci_errno; 2712 return EX_TEMPFAIL; 2713 } 2714 } 2715 #endif /* PIPELINING */ 2716 2717 /* now proceed with DATA phase */ 2718 SmtpPhase = mci->mci_phase = "client DATA 354"; 2719 mci->mci_state = MCIS_DATA; 2720 sm_setproctitle(true, e, "%s %s: %s", 2721 qid_printname(e), CurHostName, mci->mci_phase); 2722 r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc, XS_DATA); 2723 if (r < 0 || REPLYTYPE(r) == 4) 2724 { 2725 if (r >= 0) 2726 smtpquit(m, mci, e); 2727 errno = mci->mci_errno; 2728 return EX_TEMPFAIL; 2729 } 2730 else if (REPLYTYPE(r) == 5) 2731 { 2732 smtprset(m, mci, e); 2733 if (mci->mci_okrcpts <= 0 && mci->mci_retryrcpt) 2734 return EX_TEMPFAIL; 2735 return EX_UNAVAILABLE; 2736 } 2737 else if (REPLYTYPE(r) != 3) 2738 { 2739 if (LogLevel > 1) 2740 { 2741 sm_syslog(LOG_CRIT, e->e_id, 2742 "%.100s: SMTP DATA-1 protocol error: %s", 2743 CurHostName, 2744 shortenstring(SmtpReplyBuffer, 403)); 2745 } 2746 smtprset(m, mci, e); 2747 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"), 2748 SmtpReplyBuffer); 2749 if (mci->mci_okrcpts <= 0 && mci->mci_retryrcpt) 2750 return EX_TEMPFAIL; 2751 return EX_PROTOCOL; 2752 } 2753 2754 if (mci->mci_okrcpts > 0) 2755 { 2756 /* 2757 ** Set timeout around data writes. Make it at least 2758 ** large enough for DNS timeouts on all recipients 2759 ** plus some fudge factor. The main thing is 2760 ** that it should not be infinite. 2761 */ 2762 2763 if (tTd(18, 101)) 2764 { 2765 /* simulate a DATA timeout */ 2766 timeout = 10; 2767 } 2768 else 2769 timeout = DATA_PROGRESS_TIMEOUT * 1000; 2770 sm_io_setinfo(mci->mci_out, SM_IO_WHAT_TIMEOUT, &timeout); 2771 2772 /* 2773 ** Output the actual message. 2774 */ 2775 2776 if (!(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER)) 2777 goto writeerr; 2778 2779 if (tTd(18, 101)) 2780 { 2781 /* simulate a DATA timeout */ 2782 (void) sleep(2); 2783 } 2784 2785 if (!(*e->e_putbody)(mci, e, NULL)) 2786 goto writeerr; 2787 2788 /* 2789 ** Cleanup after sending message. 2790 */ 2791 } 2792 2793 #if _FFR_CATCH_BROKEN_MTAS 2794 if (sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0) 2795 { 2796 /* terminate the message */ 2797 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s", 2798 m->m_eol); 2799 if (TrafficLogFile != NULL) 2800 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 2801 "%05d >>> .\n", (int) CurrentPid); 2802 if (Verbose) 2803 nmessage(">>> ."); 2804 2805 sm_syslog(LOG_CRIT, e->e_id, 2806 "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot", 2807 CurHostName); 2808 mci->mci_errno = EIO; 2809 mci->mci_state = MCIS_ERROR; 2810 mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL); 2811 smtpquit(m, mci, e); 2812 return EX_PROTOCOL; 2813 } 2814 #endif /* _FFR_CATCH_BROKEN_MTAS */ 2815 2816 if (sm_io_error(mci->mci_out)) 2817 { 2818 /* error during processing -- don't send the dot */ 2819 mci->mci_errno = EIO; 2820 mci->mci_state = MCIS_ERROR; 2821 mci_setstat(mci, EX_IOERR, "4.4.2", NULL); 2822 smtpquit(m, mci, e); 2823 return EX_IOERR; 2824 } 2825 2826 /* terminate the message */ 2827 if (sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s.%s", 2828 bitset(MCIF_INLONGLINE, mci->mci_flags) ? m->m_eol : "", 2829 m->m_eol) == SM_IO_EOF) 2830 goto writeerr; 2831 if (TrafficLogFile != NULL) 2832 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 2833 "%05d >>> .\n", (int) CurrentPid); 2834 if (Verbose) 2835 nmessage(">>> ."); 2836 2837 /* check for the results of the transaction */ 2838 SmtpPhase = mci->mci_phase = "client DATA status"; 2839 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), 2840 CurHostName, mci->mci_phase); 2841 if (bitnset(M_LMTP, m->m_flags)) 2842 return EX_OK; 2843 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_EOM); 2844 if (r < 0) 2845 return EX_TEMPFAIL; 2846 if (mci->mci_state == MCIS_DATA) 2847 mci->mci_state = MCIS_OPEN; 2848 xstat = EX_NOTSTICKY; 2849 if (r == 452) 2850 rstat = EX_TEMPFAIL; 2851 else if (REPLYTYPE(r) == 4) 2852 rstat = xstat = EX_TEMPFAIL; 2853 else if (REPLYTYPE(r) == 2) 2854 rstat = xstat = EX_OK; 2855 else if (REPLYCLASS(r) != 5) 2856 rstat = xstat = EX_PROTOCOL; 2857 else if (REPLYTYPE(r) == 5) 2858 rstat = EX_UNAVAILABLE; 2859 else 2860 rstat = EX_PROTOCOL; 2861 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), 2862 SmtpReplyBuffer); 2863 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 2864 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) 2865 r += 5; 2866 else 2867 r = 4; 2868 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]); 2869 SmtpPhase = mci->mci_phase = "idle"; 2870 sm_setproctitle(true, e, "%s: %s", CurHostName, mci->mci_phase); 2871 if (rstat != EX_PROTOCOL) 2872 return rstat; 2873 if (LogLevel > 1) 2874 { 2875 sm_syslog(LOG_CRIT, e->e_id, 2876 "%.100s: SMTP DATA-2 protocol error: %s", 2877 CurHostName, 2878 shortenstring(SmtpReplyBuffer, 403)); 2879 } 2880 return rstat; 2881 2882 writeerr: 2883 mci->mci_errno = errno; 2884 mci->mci_state = MCIS_ERROR; 2885 mci_setstat(mci, bitset(MCIF_NOTSTICKY, mci->mci_flags) 2886 ? EX_NOTSTICKY: EX_TEMPFAIL, 2887 "4.4.2", NULL); 2888 mci->mci_flags &= ~MCIF_NOTSTICKY; 2889 2890 /* 2891 ** If putbody() couldn't finish due to a timeout, 2892 ** rewind it here in the timeout handler. See 2893 ** comments at the end of putbody() for reasoning. 2894 */ 2895 2896 if (e->e_dfp != NULL) 2897 (void) bfrewind(e->e_dfp); 2898 2899 errno = mci->mci_errno; 2900 syserr("+451 4.4.1 timeout writing message to %s", CurHostName); 2901 smtpquit(m, mci, e); 2902 return EX_TEMPFAIL; 2903 } 2904 2905 /* 2906 ** SMTPGETSTAT -- get status code from DATA in LMTP 2907 ** 2908 ** Parameters: 2909 ** m -- the mailer to which we are sending the message. 2910 ** mci -- the mailer connection structure. 2911 ** e -- the current envelope. 2912 ** 2913 ** Returns: 2914 ** The exit status corresponding to the reply code. 2915 */ 2916 2917 int 2918 smtpgetstat(m, mci, e) 2919 MAILER *m; 2920 MCI *mci; 2921 ENVELOPE *e; 2922 { 2923 int r; 2924 int off; 2925 int status, xstat; 2926 char *enhsc; 2927 2928 enhsc = NULL; 2929 2930 /* check for the results of the transaction */ 2931 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DATA2); 2932 if (r < 0) 2933 return EX_TEMPFAIL; 2934 xstat = EX_NOTSTICKY; 2935 if (REPLYTYPE(r) == 4) 2936 status = EX_TEMPFAIL; 2937 else if (REPLYTYPE(r) == 2) 2938 status = xstat = EX_OK; 2939 else if (REPLYCLASS(r) != 5) 2940 status = xstat = EX_PROTOCOL; 2941 else if (REPLYTYPE(r) == 5) 2942 status = EX_UNAVAILABLE; 2943 else 2944 status = EX_PROTOCOL; 2945 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 2946 (off = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) 2947 off += 5; 2948 else 2949 off = 4; 2950 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[off]); 2951 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), SmtpReplyBuffer); 2952 if (LogLevel > 1 && status == EX_PROTOCOL) 2953 { 2954 sm_syslog(LOG_CRIT, e->e_id, 2955 "%.100s: SMTP DATA-3 protocol error: %s", 2956 CurHostName, 2957 shortenstring(SmtpReplyBuffer, 403)); 2958 } 2959 return status; 2960 } 2961 /* 2962 ** SMTPQUIT -- close the SMTP connection. 2963 ** 2964 ** Parameters: 2965 ** m -- a pointer to the mailer. 2966 ** mci -- the mailer connection information. 2967 ** e -- the current envelope. 2968 ** 2969 ** Returns: 2970 ** none. 2971 ** 2972 ** Side Effects: 2973 ** sends the final protocol and closes the connection. 2974 */ 2975 2976 void 2977 smtpquit(m, mci, e) 2978 register MAILER *m; 2979 register MCI *mci; 2980 ENVELOPE *e; 2981 { 2982 bool oldSuprErrs = SuprErrs; 2983 int rcode; 2984 char *oldcurhost; 2985 2986 if (mci->mci_state == MCIS_CLOSED) 2987 { 2988 mci_close(mci, "smtpquit:1"); 2989 return; 2990 } 2991 2992 oldcurhost = CurHostName; 2993 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 2994 if (CurHostName == NULL) 2995 CurHostName = MyHostName; 2996 2997 /* 2998 ** Suppress errors here -- we may be processing a different 2999 ** job when we do the quit connection, and we don't want the 3000 ** new job to be penalized for something that isn't it's 3001 ** problem. 3002 */ 3003 3004 SuprErrs = true; 3005 3006 /* send the quit message if we haven't gotten I/O error */ 3007 if (mci->mci_state != MCIS_ERROR && 3008 mci->mci_state != MCIS_QUITING) 3009 { 3010 SmtpPhase = "client QUIT"; 3011 mci->mci_state = MCIS_QUITING; 3012 smtpmessage("QUIT", m, mci); 3013 (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL, XS_QUIT); 3014 SuprErrs = oldSuprErrs; 3015 if (mci->mci_state == MCIS_CLOSED) 3016 goto end; 3017 } 3018 3019 /* now actually close the connection and pick up the zombie */ 3020 rcode = endmailer(mci, e, NULL); 3021 if (rcode != EX_OK) 3022 { 3023 char *mailer = NULL; 3024 3025 if (mci->mci_mailer != NULL && 3026 mci->mci_mailer->m_name != NULL) 3027 mailer = mci->mci_mailer->m_name; 3028 3029 /* look for naughty mailers */ 3030 sm_syslog(LOG_ERR, e->e_id, 3031 "smtpquit: mailer%s%s exited with exit value %d", 3032 mailer == NULL ? "" : " ", 3033 mailer == NULL ? "" : mailer, 3034 rcode); 3035 } 3036 3037 SuprErrs = oldSuprErrs; 3038 3039 end: 3040 CurHostName = oldcurhost; 3041 return; 3042 } 3043 /* 3044 ** SMTPRSET -- send a RSET (reset) command 3045 ** 3046 ** Parameters: 3047 ** m -- a pointer to the mailer. 3048 ** mci -- the mailer connection information. 3049 ** e -- the current envelope. 3050 ** 3051 ** Returns: 3052 ** none. 3053 ** 3054 ** Side Effects: 3055 ** closes the connection if there is no reply to RSET. 3056 */ 3057 3058 void 3059 smtprset(m, mci, e) 3060 register MAILER *m; 3061 register MCI *mci; 3062 ENVELOPE *e; 3063 { 3064 int r; 3065 3066 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 3067 if (CurHostName == NULL) 3068 CurHostName = MyHostName; 3069 3070 /* 3071 ** Check if connection is gone, if so 3072 ** it's a tempfail and we use mci_errno 3073 ** for the reason. 3074 */ 3075 3076 if (mci->mci_state == MCIS_CLOSED) 3077 { 3078 errno = mci->mci_errno; 3079 return; 3080 } 3081 3082 SmtpPhase = "client RSET"; 3083 smtpmessage("RSET", m, mci); 3084 r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL, XS_DEFAULT); 3085 if (r < 0) 3086 return; 3087 3088 /* 3089 ** Any response is deemed to be acceptable. 3090 ** The standard does not state the proper action 3091 ** to take when a value other than 250 is received. 3092 ** 3093 ** However, if 421 is returned for the RSET, leave 3094 ** mci_state alone (MCIS_SSD can be set in reply() 3095 ** and MCIS_CLOSED can be set in smtpquit() if 3096 ** reply() gets a 421 and calls smtpquit()). 3097 */ 3098 3099 if (mci->mci_state != MCIS_SSD && mci->mci_state != MCIS_CLOSED) 3100 mci->mci_state = MCIS_OPEN; 3101 else if (mci->mci_exitstat == EX_OK) 3102 mci_setstat(mci, EX_TEMPFAIL, "4.5.0", NULL); 3103 } 3104 /* 3105 ** SMTPPROBE -- check the connection state 3106 ** 3107 ** Parameters: 3108 ** mci -- the mailer connection information. 3109 ** 3110 ** Returns: 3111 ** none. 3112 ** 3113 ** Side Effects: 3114 ** closes the connection if there is no reply to RSET. 3115 */ 3116 3117 int 3118 smtpprobe(mci) 3119 register MCI *mci; 3120 { 3121 int r; 3122 MAILER *m = mci->mci_mailer; 3123 ENVELOPE *e; 3124 extern ENVELOPE BlankEnvelope; 3125 3126 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 3127 if (CurHostName == NULL) 3128 CurHostName = MyHostName; 3129 3130 e = &BlankEnvelope; 3131 SmtpPhase = "client probe"; 3132 smtpmessage("RSET", m, mci); 3133 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL, XS_DEFAULT); 3134 if (REPLYTYPE(r) != 2) 3135 smtpquit(m, mci, e); 3136 return r; 3137 } 3138 /* 3139 ** REPLY -- read arpanet reply 3140 ** 3141 ** Parameters: 3142 ** m -- the mailer we are reading the reply from. 3143 ** mci -- the mailer connection info structure. 3144 ** e -- the current envelope. 3145 ** timeout -- the timeout for reads. 3146 ** pfunc -- processing function called on each line of response. 3147 ** If null, no special processing is done. 3148 ** enhstat -- optional, returns enhanced error code string (if set) 3149 ** rtype -- type of SmtpMsgBuffer: does it contains secret data? 3150 ** 3151 ** Returns: 3152 ** reply code it reads. 3153 ** 3154 ** Side Effects: 3155 ** flushes the mail file. 3156 */ 3157 3158 int 3159 reply(m, mci, e, timeout, pfunc, enhstat, rtype) 3160 MAILER *m; 3161 MCI *mci; 3162 ENVELOPE *e; 3163 time_t timeout; 3164 void (*pfunc) __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); 3165 char **enhstat; 3166 int rtype; 3167 { 3168 register char *bufp; 3169 register int r; 3170 bool firstline = true; 3171 char junkbuf[MAXLINE]; 3172 static char enhstatcode[ENHSCLEN]; 3173 int save_errno; 3174 3175 /* 3176 ** Flush the output before reading response. 3177 ** 3178 ** For SMTP pipelining, it would be better if we didn't do 3179 ** this if there was already data waiting to be read. But 3180 ** to do it properly means pushing it to the I/O library, 3181 ** since it really needs to be done below the buffer layer. 3182 */ 3183 3184 if (mci->mci_out != NULL) 3185 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT); 3186 3187 if (tTd(18, 1)) 3188 { 3189 char *what; 3190 3191 if (SmtpMsgBuffer[0] != '\0') 3192 what = SmtpMsgBuffer; 3193 else if (SmtpPhase != NULL && SmtpPhase[0] != '\0') 3194 what = SmtpPhase; 3195 else if (XS_GREET == rtype) 3196 what = "greeting"; 3197 else 3198 what = "unknown"; 3199 sm_dprintf("reply to %s\n", what); 3200 } 3201 3202 /* 3203 ** Read the input line, being careful not to hang. 3204 */ 3205 3206 bufp = SmtpReplyBuffer; 3207 (void) set_tls_rd_tmo(timeout); 3208 for (;;) 3209 { 3210 register char *p; 3211 3212 /* actually do the read */ 3213 if (e->e_xfp != NULL) /* for debugging */ 3214 (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 3215 3216 /* if we are in the process of closing just give the code */ 3217 if (mci->mci_state == MCIS_CLOSED) 3218 return SMTPCLOSING; 3219 3220 /* don't try to read from a non-existent fd */ 3221 if (mci->mci_in == NULL) 3222 { 3223 if (mci->mci_errno == 0) 3224 mci->mci_errno = EBADF; 3225 3226 /* errors on QUIT should be ignored */ 3227 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0) 3228 { 3229 errno = mci->mci_errno; 3230 mci_close(mci, "reply:1"); 3231 return -1; 3232 } 3233 mci->mci_state = MCIS_ERROR; 3234 smtpquit(m, mci, e); 3235 errno = mci->mci_errno; 3236 return -1; 3237 } 3238 3239 if (mci->mci_out != NULL) 3240 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT); 3241 3242 /* get the line from the other side */ 3243 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 3244 save_errno = errno; 3245 mci->mci_lastuse = curtime(); 3246 3247 if (p == NULL) 3248 { 3249 bool oldholderrs; 3250 extern char MsgBuf[]; 3251 3252 /* errors on QUIT should be ignored */ 3253 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0) 3254 { 3255 mci_close(mci, "reply:2"); 3256 return -1; 3257 } 3258 3259 /* if the remote end closed early, fake an error */ 3260 errno = save_errno; 3261 if (errno == 0) 3262 { 3263 (void) sm_snprintf(SmtpReplyBuffer, 3264 sizeof(SmtpReplyBuffer), 3265 "421 4.4.1 Connection reset by %s", 3266 CURHOSTNAME); 3267 #ifdef ECONNRESET 3268 errno = ECONNRESET; 3269 #else 3270 errno = EPIPE; 3271 #endif 3272 } 3273 3274 mci->mci_errno = errno; 3275 oldholderrs = HoldErrs; 3276 HoldErrs = true; 3277 usrerr("451 4.4.1 reply: read error from %s", 3278 CURHOSTNAME); 3279 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf); 3280 3281 /* if debugging, pause so we can see state */ 3282 if (tTd(18, 100)) 3283 (void) pause(); 3284 mci->mci_state = MCIS_ERROR; 3285 smtpquit(m, mci, e); 3286 #if XDEBUG 3287 { 3288 char wbuf[MAXLINE]; 3289 3290 p = wbuf; 3291 if (e->e_to != NULL) 3292 { 3293 (void) sm_snprintf(p, 3294 SPACELEFT(wbuf, p), 3295 "%s... ", 3296 shortenstring(e->e_to, MAXSHORTSTR)); 3297 p += strlen(p); 3298 } 3299 (void) sm_snprintf(p, SPACELEFT(wbuf, p), 3300 "reply(%.100s) during %s", 3301 CURHOSTNAME, SmtpPhase); 3302 checkfd012(wbuf); 3303 } 3304 #endif /* XDEBUG */ 3305 HoldErrs = oldholderrs; 3306 errno = save_errno; 3307 return -1; 3308 } 3309 fixcrlf(bufp, true); 3310 3311 /* EHLO failure is not a real error */ 3312 if (e->e_xfp != NULL && (bufp[0] == '4' || 3313 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 3314 { 3315 /* serious error -- log the previous command */ 3316 if (SmtpNeedIntro) 3317 { 3318 /* inform user who we are chatting with */ 3319 (void) sm_io_fprintf(CurEnv->e_xfp, 3320 SM_TIME_DEFAULT, 3321 "... while talking to %s:\n", 3322 CURHOSTNAME); 3323 SmtpNeedIntro = false; 3324 } 3325 if (SmtpMsgBuffer[0] != '\0') 3326 { 3327 (void) sm_io_fprintf(e->e_xfp, 3328 SM_TIME_DEFAULT, 3329 ">>> %s\n", 3330 (rtype == XS_STARTTLS) 3331 ? "STARTTLS dialogue" 3332 : ((rtype == XS_AUTH) 3333 ? "AUTH dialogue" 3334 : SmtpMsgBuffer)); 3335 SmtpMsgBuffer[0] = '\0'; 3336 } 3337 3338 /* now log the message as from the other side */ 3339 (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 3340 "<<< %s\n", bufp); 3341 } 3342 3343 /* display the input for verbose mode */ 3344 if (Verbose) 3345 nmessage("050 %s", bufp); 3346 3347 /* ignore improperly formatted input */ 3348 if (!ISSMTPREPLY(bufp)) 3349 continue; 3350 3351 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 3352 enhstat != NULL && 3353 extenhsc(bufp + 4, ' ', enhstatcode) > 0) 3354 *enhstat = enhstatcode; 3355 3356 /* process the line */ 3357 if (pfunc != NULL) 3358 (*pfunc)(bufp, firstline, m, mci, e); 3359 3360 /* decode the reply code */ 3361 r = atoi(bufp); 3362 3363 /* extra semantics: 0xx codes are "informational" */ 3364 if (r < 100) 3365 { 3366 firstline = false; 3367 continue; 3368 } 3369 if (REPLYTYPE(r) > 3 && firstline 3370 #if _FFR_PROXY 3371 && 3372 (e->e_sendmode != SM_PROXY 3373 || (e->e_sendmode == SM_PROXY 3374 && (e->e_rcode == 0 || REPLYTYPE(e->e_rcode) < 5)) 3375 ) 3376 #endif 3377 ) 3378 { 3379 int o = -1; 3380 /* 3381 ** ignore error iff: DATA, 5xy error, but we had 3382 ** "retryable" recipients. XREF: smtpdata() 3383 */ 3384 3385 if (!(rtype == XS_DATA && REPLYTYPE(r) == 5 && 3386 mci->mci_okrcpts <= 0 && mci->mci_retryrcpt)) 3387 { 3388 o = extenhsc(bufp + 4, ' ', enhstatcode); 3389 if (o > 0) 3390 { 3391 sm_strlcpy(e->e_renhsc, enhstatcode, 3392 sizeof(e->e_renhsc)); 3393 3394 /* skip SMTP reply code, delimiters */ 3395 o += 5; 3396 } 3397 else 3398 o = 4; 3399 3400 /* 3401 ** Don't use this for reply= logging 3402 ** if it was for QUIT. 3403 ** (Note: use the debug option to 3404 ** reproduce the original error.) 3405 */ 3406 3407 if (rtype != XS_QUIT || tTd(87, 101)) 3408 { 3409 e->e_rcode = r; 3410 e->e_text = sm_rpool_strdup_x( 3411 e->e_rpool, bufp + o); 3412 } 3413 } 3414 if (tTd(87, 2)) 3415 { 3416 sm_dprintf("user: e=%p, offset=%d, bufp=%s, rcode=%d, enhstat=%s, rtype=%d, text=%s\n" 3417 , (void *)e, o, bufp, r, e->e_renhsc 3418 , rtype, e->e_text); 3419 } 3420 } 3421 #if _FFR_REPLY_MULTILINE 3422 # if _FFR_REPLY_MULTILINE > 200 3423 # define MLLIMIT _FFR_REPLY_MULTILINE 3424 # else 3425 # define MLLIMIT 1024 3426 # endif 3427 if ((REPLYTYPE(r) > 3 && !firstline && e->e_text != NULL && 3428 rtype != XS_QUIT) || tTd(87, 101)) 3429 { 3430 int len; 3431 char *new; 3432 3433 /* skip the same stuff or use o? */ 3434 /* but o is a local variable in the block above */ 3435 len = strlen(e->e_text) + strlen(bufp) + 3; 3436 if (len < MLLIMIT && 3437 (new = (char *) sm_rpool_malloc(e->e_rpool, len)) 3438 != NULL) 3439 { 3440 sm_strlcpyn(new, len, 3, e->e_text, "; ", 3441 bufp /* + o */); 3442 e->e_text = new; 3443 } 3444 } 3445 #endif /* _FFR_REPLY_MULTILINE */ 3446 3447 firstline = false; 3448 3449 /* if no continuation lines, return this line */ 3450 if (bufp[3] != '-') 3451 break; 3452 3453 /* first line of real reply -- ignore rest */ 3454 bufp = junkbuf; 3455 } 3456 3457 /* 3458 ** Now look at SmtpReplyBuffer -- only care about the first 3459 ** line of the response from here on out. 3460 */ 3461 3462 /* save temporary failure messages for posterity */ 3463 if (SmtpReplyBuffer[0] == '4') 3464 (void) sm_strlcpy(SmtpError, SmtpReplyBuffer, sizeof(SmtpError)); 3465 3466 /* reply code 421 is "Service Shutting Down" */ 3467 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD && 3468 mci->mci_state != MCIS_QUITING) 3469 { 3470 /* send the quit protocol */ 3471 mci->mci_state = MCIS_SSD; 3472 smtpquit(m, mci, e); 3473 } 3474 3475 return r; 3476 } 3477 /* 3478 ** SMTPMESSAGE -- send message to server 3479 ** 3480 ** Parameters: 3481 ** f -- format 3482 ** m -- the mailer to control formatting. 3483 ** a, b, c -- parameters 3484 ** 3485 ** Returns: 3486 ** none. 3487 ** 3488 ** Side Effects: 3489 ** writes message to mci->mci_out. 3490 */ 3491 3492 /*VARARGS1*/ 3493 void 3494 #ifdef __STDC__ 3495 smtpmessage(char *f, MAILER *m, MCI *mci, ...) 3496 #else /* __STDC__ */ 3497 smtpmessage(f, m, mci, va_alist) 3498 char *f; 3499 MAILER *m; 3500 MCI *mci; 3501 va_dcl 3502 #endif /* __STDC__ */ 3503 { 3504 SM_VA_LOCAL_DECL 3505 3506 SM_VA_START(ap, mci); 3507 (void) sm_vsnprintf(SmtpMsgBuffer, sizeof(SmtpMsgBuffer), f, ap); 3508 SM_VA_END(ap); 3509 3510 if (tTd(18, 1) || Verbose) 3511 nmessage(">>> %s", SmtpMsgBuffer); 3512 if (TrafficLogFile != NULL) 3513 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 3514 "%05d >>> %s\n", (int) CurrentPid, 3515 SmtpMsgBuffer); 3516 if (mci->mci_out != NULL) 3517 { 3518 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s%s", 3519 SmtpMsgBuffer, m == NULL ? "\r\n" 3520 : m->m_eol); 3521 } 3522 else if (tTd(18, 1)) 3523 { 3524 sm_dprintf("smtpmessage: NULL mci_out\n"); 3525 } 3526 } 3527