1 /* 2 * Copyright (c) 1998-2000 Sendmail, 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 #ifndef lint 17 # if SMTP 18 static char id[] = "@(#)$Id: usersmtp.c,v 8.245.4.13 2000/09/26 00:46:21 gshapiro Exp $ (with SMTP)"; 19 # else /* SMTP */ 20 static char id[] = "@(#)$Id: usersmtp.c,v 8.245.4.13 2000/09/26 00:46:21 gshapiro Exp $ (without SMTP)"; 21 # endif /* SMTP */ 22 #endif /* ! lint */ 23 24 #include <sysexits.h> 25 26 #if SMTP 27 28 29 static void datatimeout __P((void)); 30 static void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); 31 static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); 32 33 /* 34 ** USERSMTP -- run SMTP protocol from the user end. 35 ** 36 ** This protocol is described in RFC821. 37 */ 38 39 # define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 40 # define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 41 # define SMTPCLOSING 421 /* "Service Shutting Down" */ 42 43 #define ENHSCN(e, d) (e) == NULL ? (d) : newstr(e) 44 45 static char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 46 static char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 47 static bool SmtpNeedIntro; /* need "while talking" in transcript */ 48 /* 49 ** SMTPINIT -- initialize SMTP. 50 ** 51 ** Opens the connection and sends the initial protocol. 52 ** 53 ** Parameters: 54 ** m -- mailer to create connection to. 55 ** mci -- the mailer connection info. 56 ** e -- the envelope. 57 ** onlyhelo -- send only helo command? 58 ** 59 ** Returns: 60 ** none. 61 ** 62 ** Side Effects: 63 ** creates connection and sends initial protocol. 64 */ 65 66 void 67 smtpinit(m, mci, e, onlyhelo) 68 MAILER *m; 69 register MCI *mci; 70 ENVELOPE *e; 71 bool onlyhelo; 72 { 73 register int r; 74 register char *p; 75 register char *hn; 76 char *enhsc; 77 78 enhsc = NULL; 79 if (tTd(18, 1)) 80 { 81 dprintf("smtpinit "); 82 mci_dump(mci, FALSE); 83 } 84 85 /* 86 ** Open the connection to the mailer. 87 */ 88 89 SmtpError[0] = '\0'; 90 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 91 if (CurHostName == NULL) 92 CurHostName = MyHostName; 93 SmtpNeedIntro = TRUE; 94 switch (mci->mci_state) 95 { 96 case MCIS_ACTIVE: 97 /* need to clear old information */ 98 smtprset(m, mci, e); 99 /* FALLTHROUGH */ 100 101 case MCIS_OPEN: 102 if (!onlyhelo) 103 return; 104 break; 105 106 case MCIS_ERROR: 107 case MCIS_QUITING: 108 case MCIS_SSD: 109 /* shouldn't happen */ 110 smtpquit(m, mci, e); 111 /* FALLTHROUGH */ 112 113 case MCIS_CLOSED: 114 syserr("451 4.4.0 smtpinit: state CLOSED"); 115 return; 116 117 case MCIS_OPENING: 118 break; 119 } 120 if (onlyhelo) 121 goto helo; 122 123 mci->mci_state = MCIS_OPENING; 124 125 /* 126 ** Get the greeting message. 127 ** This should appear spontaneously. Give it five minutes to 128 ** happen. 129 */ 130 131 SmtpPhase = mci->mci_phase = "client greeting"; 132 sm_setproctitle(TRUE, e, "%s %s: %s", 133 qid_printname(e), CurHostName, mci->mci_phase); 134 r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL); 135 if (r < 0) 136 goto tempfail1; 137 if (REPLYTYPE(r) == 4) 138 goto tempfail2; 139 if (REPLYTYPE(r) != 2) 140 goto unavailable; 141 142 /* 143 ** Send the HELO command. 144 ** My mother taught me to always introduce myself. 145 */ 146 147 helo: 148 if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags)) 149 mci->mci_flags |= MCIF_ESMTP; 150 hn = mci->mci_heloname ? mci->mci_heloname : MyHostName; 151 152 tryhelo: 153 if (bitnset(M_LMTP, m->m_flags)) 154 { 155 smtpmessage("LHLO %s", m, mci, hn); 156 SmtpPhase = mci->mci_phase = "client LHLO"; 157 } 158 else if (bitset(MCIF_ESMTP, mci->mci_flags)) 159 { 160 smtpmessage("EHLO %s", m, mci, hn); 161 SmtpPhase = mci->mci_phase = "client EHLO"; 162 } 163 else 164 { 165 smtpmessage("HELO %s", m, mci, hn); 166 SmtpPhase = mci->mci_phase = "client HELO"; 167 } 168 sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e), 169 CurHostName, mci->mci_phase); 170 r = reply(m, mci, e, TimeOuts.to_helo, helo_options, NULL); 171 if (r < 0) 172 goto tempfail1; 173 else if (REPLYTYPE(r) == 5) 174 { 175 if (bitset(MCIF_ESMTP, mci->mci_flags) && 176 !bitnset(M_LMTP, m->m_flags)) 177 { 178 /* try old SMTP instead */ 179 mci->mci_flags &= ~MCIF_ESMTP; 180 goto tryhelo; 181 } 182 goto unavailable; 183 } 184 else if (REPLYTYPE(r) != 2) 185 goto tempfail2; 186 187 /* 188 ** Check to see if we actually ended up talking to ourself. 189 ** This means we didn't know about an alias or MX, or we managed 190 ** to connect to an echo server. 191 */ 192 193 p = strchr(&SmtpReplyBuffer[4], ' '); 194 if (p != NULL) 195 *p = '\0'; 196 if (!bitnset(M_NOLOOPCHECK, m->m_flags) && 197 !bitnset(M_LMTP, m->m_flags) && 198 strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0) 199 { 200 syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)", 201 CurHostName); 202 mci_setstat(mci, EX_CONFIG, "5.3.5", "system config error"); 203 mci->mci_errno = 0; 204 smtpquit(m, mci, e); 205 return; 206 } 207 208 /* 209 ** If this is expected to be another sendmail, send some internal 210 ** commands. 211 */ 212 213 if (bitnset(M_INTERNAL, m->m_flags)) 214 { 215 /* tell it to be verbose */ 216 smtpmessage("VERB", m, mci); 217 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc); 218 if (r < 0) 219 goto tempfail1; 220 } 221 222 if (mci->mci_state != MCIS_CLOSED) 223 { 224 mci->mci_state = MCIS_OPEN; 225 return; 226 } 227 228 /* got a 421 error code during startup */ 229 230 tempfail1: 231 if (mci->mci_errno == 0) 232 mci->mci_errno = errno; 233 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.4.2"), NULL); 234 if (mci->mci_state != MCIS_CLOSED) 235 smtpquit(m, mci, e); 236 return; 237 238 tempfail2: 239 if (mci->mci_errno == 0) 240 mci->mci_errno = errno; 241 /* XXX should use code from other end iff ENHANCEDSTATUSCODES */ 242 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"), 243 SmtpReplyBuffer); 244 if (mci->mci_state != MCIS_CLOSED) 245 smtpquit(m, mci, e); 246 return; 247 248 unavailable: 249 mci->mci_errno = errno; 250 mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer); 251 smtpquit(m, mci, e); 252 return; 253 } 254 /* 255 ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol 256 ** 257 ** Parameters: 258 ** line -- the response line. 259 ** firstline -- set if this is the first line of the reply. 260 ** m -- the mailer. 261 ** mci -- the mailer connection info. 262 ** e -- the envelope. 263 ** 264 ** Returns: 265 ** none. 266 */ 267 268 static void 269 esmtp_check(line, firstline, m, mci, e) 270 char *line; 271 bool firstline; 272 MAILER *m; 273 register MCI *mci; 274 ENVELOPE *e; 275 { 276 if (strstr(line, "ESMTP") != NULL) 277 mci->mci_flags |= MCIF_ESMTP; 278 if (strstr(line, "8BIT-OK") != NULL) 279 mci->mci_flags |= MCIF_8BITOK; 280 } 281 # if SASL 282 /* 283 ** STR_UNION -- create the union of two lists 284 ** 285 ** Parameters: 286 ** s1, s2 -- lists of items (separated by single blanks). 287 ** 288 ** Returns: 289 ** the union of both lists. 290 */ 291 292 static char * 293 str_union(s1, s2) 294 char *s1, *s2; 295 { 296 char *hr, *h1, *h, *res; 297 int l1, l2, rl; 298 299 if (s1 == NULL || *s1 == '\0') 300 return s2; 301 if (s2 == NULL || *s2 == '\0') 302 return s1; 303 l1 = strlen(s1); 304 l2 = strlen(s2); 305 rl = l1 + l2; 306 res = (char *)malloc(rl + 2); 307 if (res == NULL) 308 { 309 if (l1 > l2) 310 return s1; 311 return s2; 312 } 313 (void) strlcpy(res, s1, rl); 314 hr = res; 315 h1 = s2; 316 h = s2; 317 318 /* walk through s2 */ 319 while (h != NULL && *h1 != '\0') 320 { 321 /* is there something after the current word? */ 322 if ((h = strchr(h1, ' ')) != NULL) 323 *h = '\0'; 324 l1 = strlen(h1); 325 326 /* does the current word appear in s1 ? */ 327 if (iteminlist(h1, s1, " ") == NULL) 328 { 329 /* add space as delimiter */ 330 *hr++ = ' '; 331 332 /* copy the item */ 333 memcpy(hr, h1, l1); 334 335 /* advance pointer in result list */ 336 hr += l1; 337 *hr = '\0'; 338 } 339 if (h != NULL) 340 { 341 /* there are more items */ 342 *h = ' '; 343 h1 = h + 1; 344 } 345 } 346 return res; 347 } 348 # endif /* SASL */ 349 /* 350 ** HELO_OPTIONS -- process the options on a HELO line. 351 ** 352 ** Parameters: 353 ** line -- the response line. 354 ** firstline -- set if this is the first line of the reply. 355 ** m -- the mailer. 356 ** mci -- the mailer connection info. 357 ** e -- the envelope. 358 ** 359 ** Returns: 360 ** none. 361 */ 362 363 static void 364 helo_options(line, firstline, m, mci, e) 365 char *line; 366 bool firstline; 367 MAILER *m; 368 register MCI *mci; 369 ENVELOPE *e; 370 { 371 register char *p; 372 373 if (firstline) 374 { 375 # if SASL 376 if (mci->mci_saslcap != NULL) 377 free(mci->mci_saslcap); 378 mci->mci_saslcap = NULL; 379 # endif /* SASL */ 380 return; 381 } 382 383 if (strlen(line) < (SIZE_T) 5) 384 return; 385 line += 4; 386 p = strpbrk(line, " ="); 387 if (p != NULL) 388 *p++ = '\0'; 389 if (strcasecmp(line, "size") == 0) 390 { 391 mci->mci_flags |= MCIF_SIZE; 392 if (p != NULL) 393 mci->mci_maxsize = atol(p); 394 } 395 else if (strcasecmp(line, "8bitmime") == 0) 396 { 397 mci->mci_flags |= MCIF_8BITMIME; 398 mci->mci_flags &= ~MCIF_7BIT; 399 } 400 else if (strcasecmp(line, "expn") == 0) 401 mci->mci_flags |= MCIF_EXPN; 402 else if (strcasecmp(line, "dsn") == 0) 403 mci->mci_flags |= MCIF_DSN; 404 else if (strcasecmp(line, "enhancedstatuscodes") == 0) 405 mci->mci_flags |= MCIF_ENHSTAT; 406 # if STARTTLS 407 else if (strcasecmp(line, "starttls") == 0) 408 mci->mci_flags |= MCIF_TLS; 409 # endif /* STARTTLS */ 410 # if SASL 411 else if (strcasecmp(line, "auth") == 0) 412 { 413 if (p != NULL && *p != '\0') 414 { 415 if (mci->mci_saslcap != NULL) 416 { 417 char *h; 418 419 /* 420 ** create the union with previous auth 421 ** offerings because we recognize "auth " 422 ** and "auth=" (old format). 423 */ 424 h = mci->mci_saslcap; 425 mci->mci_saslcap = str_union(h, p); 426 if (h != mci->mci_saslcap) 427 free(h); 428 mci->mci_flags |= MCIF_AUTH; 429 } 430 else 431 { 432 int l; 433 434 l = strlen(p) + 1; 435 mci->mci_saslcap = (char *)malloc(l); 436 437 /* XXX this may be leaked */ 438 if (mci->mci_saslcap != NULL) 439 { 440 (void) strlcpy(mci->mci_saslcap, p, l); 441 mci->mci_flags |= MCIF_AUTH; 442 } 443 } 444 } 445 } 446 # endif /* SASL */ 447 } 448 # if SASL 449 450 /* 451 ** GETSASLDATA -- process the challenges from the SASL protocol 452 ** 453 ** This gets the relevant sasl response data out of the reply 454 ** from the server 455 ** 456 ** Parameters: 457 ** line -- the response line. 458 ** firstline -- set if this is the first line of the reply. 459 ** m -- the mailer. 460 ** mci -- the mailer connection info. 461 ** e -- the envelope. 462 ** 463 ** Returns: 464 ** none. 465 */ 466 467 void 468 getsasldata(line, firstline, m, mci, e) 469 char *line; 470 bool firstline; 471 MAILER *m; 472 register MCI *mci; 473 ENVELOPE *e; 474 { 475 int len; 476 char *out; 477 int result; 478 479 /* if not a continue we don't care about it */ 480 if ((strlen(line) <= 4) || 481 (line[0] != '3') || 482 (line[1] != '3') || 483 (line[2] != '4')) 484 { 485 mci->mci_sasl_string = NULL; 486 return; 487 } 488 489 /* forget about "334 " */ 490 line += 4; 491 len = strlen(line); 492 493 out = xalloc(len + 1); 494 result = sasl_decode64(line, len, out, (u_int *)&len); 495 if (result != SASL_OK) 496 { 497 len = 0; 498 *out = '\0'; 499 } 500 if (mci->mci_sasl_string != NULL) 501 { 502 if (mci->mci_sasl_string_len <= len) 503 { 504 free(mci->mci_sasl_string); 505 mci->mci_sasl_string = xalloc(len + 1); 506 } 507 } 508 else 509 mci->mci_sasl_string = xalloc(len + 1); 510 /* XXX this is probably leaked */ 511 memcpy(mci->mci_sasl_string, out, len); 512 mci->mci_sasl_string[len] = '\0'; 513 mci->mci_sasl_string_len = len; 514 free(out); 515 return; 516 } 517 518 /* 519 ** READAUTH -- read auth value from a file 520 ** 521 ** Parameters: 522 ** l -- line to define. 523 ** filename -- name of file to read. 524 ** safe -- if set, this is a safe read. 525 ** 526 ** Returns: 527 ** line from file 528 ** 529 ** Side Effects: 530 ** overwrites local static buffer. The caller should copy 531 ** the result. 532 ** 533 */ 534 535 /* lines in authinfo file */ 536 # define SASL_USER 1 537 # define SASL_AUTHID 2 538 # define SASL_PASSWORD 3 539 # define SASL_DEFREALM 4 540 # define SASL_MECH 5 541 542 static char *sasl_info_name[] = 543 { 544 "", 545 "user id", 546 "authorization id", 547 "password", 548 "realm", 549 "mechanism" 550 }; 551 552 static char * 553 readauth(l, filename, safe) 554 int l; 555 char *filename; 556 bool safe; 557 { 558 FILE *f; 559 long sff; 560 pid_t pid; 561 int lc; 562 static char buf[MAXLINE]; 563 564 if (filename == NULL || filename[0] == '\0') 565 return ""; 566 #if !_FFR_ALLOW_SASLINFO 567 /* 568 ** make sure we don't use a program that is not 569 ** accesible to the user who specified a different authinfo file. 570 ** However, currently we don't pass this info (authinfo file 571 ** specified by user) around, so we just turn off program access. 572 */ 573 if (filename[0] == '|') 574 { 575 auto int fd; 576 int i; 577 char *p; 578 char *argv[MAXPV + 1]; 579 580 i = 0; 581 for (p = strtok(&filename[1], " \t"); p != NULL; 582 p = strtok(NULL, " \t")) 583 { 584 if (i >= MAXPV) 585 break; 586 argv[i++] = p; 587 } 588 argv[i] = NULL; 589 pid = prog_open(argv, &fd, CurEnv); 590 if (pid < 0) 591 f = NULL; 592 else 593 f = fdopen(fd, "r"); 594 } 595 else 596 #endif /* !_FFR_ALLOW_SASLINFO */ 597 { 598 pid = -1; 599 sff = SFF_REGONLY | SFF_SAFEDIRPATH | SFF_NOWLINK 600 | SFF_NOGWFILES | SFF_NOWWFILES | SFF_NORFILES; 601 if (DontLockReadFiles) 602 sff |= SFF_NOLOCK; 603 #if _FFR_ALLOW_SASLINFO 604 /* 605 ** XXX: make sure we don't read or open files that are not 606 ** accesible to the user who specified a different authinfo 607 ** file. 608 */ 609 sff |= SFF_MUSTOWN; 610 #else /* _FFR_ALLOW_SASLINFO */ 611 if (safe) 612 sff |= SFF_OPENASROOT; 613 #endif /* _FFR_ALLOW_SASLINFO */ 614 615 f = safefopen(filename, O_RDONLY, 0, sff); 616 } 617 if (f == NULL) 618 { 619 syserr("readauth: cannot open %s", filename); 620 return ""; 621 } 622 623 lc = 0; 624 while (lc < l && fgets(buf, sizeof buf, f) != NULL) 625 { 626 if (buf[0] != '#') 627 lc++; 628 } 629 630 (void) fclose(f); 631 if (pid > 0) 632 (void) waitfor(pid); 633 if (lc < l) 634 { 635 if (LogLevel >= 9) 636 sm_syslog(LOG_WARNING, NOQID, "SASL: error: can't read %s from %s", 637 sasl_info_name[l], filename); 638 return ""; 639 } 640 lc = strlen(buf) - 1; 641 if (lc >= 0) 642 buf[lc] = '\0'; 643 if (tTd(95, 6)) 644 dprintf("readauth(%s, %d) = '%s'\n", filename, l, buf); 645 return buf; 646 } 647 648 # ifndef __attribute__ 649 # define __attribute__(x) 650 # endif /* ! __attribute__ */ 651 652 static int getsimple __P((void *, int, const char **, unsigned *)); 653 static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **)); 654 static int saslgetrealm __P((void *, int, const char **, const char **)); 655 656 static sasl_callback_t callbacks[] = 657 { 658 { SASL_CB_GETREALM, &saslgetrealm, NULL }, 659 # define CB_GETREALM_IDX 0 660 { SASL_CB_PASS, &getsecret, NULL }, 661 # define CB_PASS_IDX 1 662 { SASL_CB_USER, &getsimple, NULL }, 663 # define CB_USER_IDX 2 664 { SASL_CB_AUTHNAME, &getsimple, NULL }, 665 # define CB_AUTHNAME_IDX 3 666 { SASL_CB_VERIFYFILE, &safesaslfile, NULL }, 667 { SASL_CB_LIST_END, NULL, NULL } 668 }; 669 670 /* 671 ** GETSIMPLE -- callback to get userid or authid 672 ** 673 ** Parameters: 674 ** context -- unused 675 ** id -- what to do 676 ** result -- (pointer to) result 677 ** len -- (pointer to) length of result 678 ** 679 ** Returns: 680 ** OK/failure values 681 */ 682 683 static int 684 getsimple(context, id, result, len) 685 void *context __attribute__((unused)); 686 int id; 687 const char **result; 688 unsigned *len; 689 { 690 char *h; 691 # if SASL > 10509 692 int addrealm; 693 static int addedrealm = FALSE; 694 # endif /* SASL > 10509 */ 695 static char *user = NULL; 696 static char *authid = NULL; 697 698 if (result == NULL) 699 return SASL_BADPARAM; 700 701 switch (id) 702 { 703 case SASL_CB_USER: 704 if (user == NULL) 705 { 706 h = readauth(SASL_USER, SASLInfo, TRUE); 707 user = newstr(h); 708 } 709 *result = user; 710 if (tTd(95, 5)) 711 dprintf("AUTH username '%s'\n", *result); 712 if (len != NULL) 713 *len = user ? strlen(user) : 0; 714 break; 715 716 case SASL_CB_AUTHNAME: 717 # if SASL > 10509 718 /* XXX maybe other mechanisms too?! */ 719 addrealm = context != NULL && 720 strcasecmp(context, "CRAM-MD5") == 0; 721 if (addedrealm != addrealm && authid != NULL) 722 { 723 # if SASL > 10522 724 /* 725 ** digest-md5 prior to 1.5.23 doesn't copy the 726 ** value it gets from the callback, but free()s 727 ** it later on 728 ** workaround: don't free() it here 729 ** this can cause a memory leak! 730 */ 731 free(authid); 732 # endif /* SASL > 10522 */ 733 authid = NULL; 734 addedrealm = addrealm; 735 } 736 # endif /* SASL > 10509 */ 737 if (authid == NULL) 738 { 739 h = readauth(SASL_AUTHID, SASLInfo, TRUE); 740 # if SASL > 10509 741 if (addrealm && strchr(h, '@') == NULL) 742 { 743 size_t l; 744 char *realm; 745 746 realm = callbacks[CB_GETREALM_IDX].context; 747 l = strlen(h) + strlen(realm) + 2; 748 authid = xalloc(l); 749 snprintf(authid, l, "%s@%s", h, realm); 750 } 751 else 752 # endif /* SASL > 10509 */ 753 authid = newstr(h); 754 } 755 *result = authid; 756 if (tTd(95, 5)) 757 dprintf("AUTH authid '%s'\n", *result); 758 if (len != NULL) 759 *len = authid ? strlen(authid) : 0; 760 break; 761 762 case SASL_CB_LANGUAGE: 763 *result = NULL; 764 if (len != NULL) 765 *len = 0; 766 break; 767 768 default: 769 return SASL_BADPARAM; 770 } 771 return SASL_OK; 772 } 773 774 /* 775 ** GETSECRET -- callback to get password 776 ** 777 ** Parameters: 778 ** conn -- connection information 779 ** context -- unused 780 ** id -- what to do 781 ** psecret -- (pointer to) result 782 ** 783 ** Returns: 784 ** OK/failure values 785 */ 786 787 static int 788 getsecret(conn, context, id, psecret) 789 sasl_conn_t *conn; 790 void *context __attribute__((unused)); 791 int id; 792 sasl_secret_t **psecret; 793 { 794 char *h; 795 int len; 796 static char *authpass = NULL; 797 798 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS) 799 return SASL_BADPARAM; 800 801 if (authpass == NULL) 802 { 803 h = readauth(SASL_PASSWORD, SASLInfo, TRUE); 804 authpass = newstr(h); 805 } 806 len = strlen(authpass); 807 *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len + 1); 808 if (*psecret == NULL) 809 return SASL_FAIL; 810 (void) strlcpy((*psecret)->data, authpass, len + 1); 811 (*psecret)->len = len; 812 return SASL_OK; 813 } 814 815 /* 816 ** SAFESASLFILE -- callback for sasl: is file safe? 817 ** 818 ** Parameters: 819 ** context -- pointer to context between invocations (unused) 820 ** file -- name of file to check 821 ** type -- type of file to check 822 ** 823 ** Returns: 824 ** SASL_OK: file can be used 825 ** SASL_CONTINUE: don't use file 826 ** SASL_FAIL: failure (not used here) 827 ** 828 */ 829 int 830 # if SASL > 10515 831 safesaslfile(context, file, type) 832 # else /* SASL > 10515 */ 833 safesaslfile(context, file) 834 # endif /* SASL > 10515 */ 835 void *context; 836 char *file; 837 # if SASL > 10515 838 int type; 839 # endif /* SASL > 10515 */ 840 { 841 long sff; 842 int r; 843 char *p; 844 845 if (file == NULL || *file == '\0') 846 return SASL_OK; 847 sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOGWFILES|SFF_NOWWFILES|SFF_ROOTOK; 848 if ((p = strrchr(file, '/')) == NULL) 849 p = file; 850 else 851 ++p; 852 853 # if SASL <= 10515 854 /* everything beside libs and .conf files must not be readable */ 855 r = strlen(p); 856 if ((r <= 3 || strncmp(p, "lib", 3) != 0) && 857 (r <= 5 || strncmp(p + r - 5, ".conf", 5) != 0) 858 # if _FFR_UNSAFE_SASL 859 && !bitnset(DBS_GROUPREADABLESASLFILE, DontBlameSendmail) 860 # endif /* _FFR_UNSAFE_SASL */ 861 ) 862 sff |= SFF_NORFILES; 863 # else /* SASL > 10515 */ 864 /* files containing passwords should be not readable */ 865 if (type == SASL_VRFY_PASSWD) 866 { 867 # if _FFR_UNSAFE_SASL 868 if (bitnset(DBS_GROUPREADABLESASLFILE, DontBlameSendmail)) 869 sff |= SFF_NOWRFILES; 870 else 871 # endif /* _FFR_UNSAFE_SASL */ 872 sff |= SFF_NORFILES; 873 } 874 # endif /* SASL <= 10515 */ 875 876 if ((r = safefile(file, RunAsUid, RunAsGid, RunAsUserName, sff, 877 S_IRUSR, NULL)) == 0) 878 return SASL_OK; 879 if (LogLevel >= 11 || (r != ENOENT && LogLevel >= 9)) 880 sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s", 881 file, errstring(r)); 882 return SASL_CONTINUE; 883 } 884 885 /* 886 ** SASLGETREALM -- return the realm for SASL 887 ** 888 ** return the realm for the client 889 ** 890 ** Parameters: 891 ** context -- context shared between invocations 892 ** here: realm to return 893 ** availrealms -- list of available realms 894 ** {realm, realm, ...} 895 ** result -- pointer to result 896 ** 897 ** Returns: 898 ** failure/success 899 */ 900 static int 901 saslgetrealm(context, id, availrealms, result) 902 void *context; 903 int id; 904 const char **availrealms; 905 const char **result; 906 { 907 if (LogLevel > 12) 908 sm_syslog(LOG_INFO, NOQID, "saslgetrealm: realm %s available realms %s", 909 context == NULL ? "<No Context>" : (char *) context, 910 (availrealms == NULL || *availrealms == NULL) ? "<No Realms>" : *availrealms); 911 if (context == NULL) 912 return SASL_FAIL; 913 914 /* check whether context is in list? */ 915 if (availrealms != NULL && *availrealms != NULL) 916 { 917 if (iteminlist(context, (char *)(*availrealms + 1), " ,}") == 918 NULL) 919 { 920 if (LogLevel > 8) 921 sm_syslog(LOG_ERR, NOQID, 922 "saslgetrealm: realm %s not in list %s", 923 context, *availrealms); 924 return SASL_FAIL; 925 } 926 } 927 *result = (char *)context; 928 return SASL_OK; 929 } 930 /* 931 ** ITEMINLIST -- does item appear in list? 932 ** 933 ** Check whether item appears in list (which must be separated by a 934 ** character in delim) as a "word", i.e. it must appear at the begin 935 ** of the list or after a space, and it must end with a space or the 936 ** end of the list. 937 ** 938 ** Parameters: 939 ** item -- item to search. 940 ** list -- list of items. 941 ** delim -- list of delimiters. 942 ** 943 ** Returns: 944 ** pointer to occurrence (NULL if not found). 945 */ 946 947 char * 948 iteminlist(item, list, delim) 949 char *item; 950 char *list; 951 char *delim; 952 { 953 char *s; 954 int len; 955 956 if (list == NULL || *list == '\0') 957 return NULL; 958 if (item == NULL || *item == '\0') 959 return NULL; 960 s = list; 961 len = strlen(item); 962 while (s != NULL && *s != '\0') 963 { 964 if (strncasecmp(s, item, len) == 0 && 965 (s[len] == '\0' || strchr(delim, s[len]) != NULL)) 966 return s; 967 s = strpbrk(s, delim); 968 if (s != NULL) 969 while (*++s == ' ') 970 continue; 971 } 972 return NULL; 973 } 974 /* 975 ** REMOVEMECH -- remove item [rem] from list [list] 976 ** 977 ** Parameters: 978 ** rem -- item to remove 979 ** list -- list of items 980 ** 981 ** Returns: 982 ** pointer to new list (NULL in case of error). 983 */ 984 985 char * 986 removemech(rem, list) 987 char *rem; 988 char *list; 989 { 990 char *ret; 991 char *needle; 992 int len; 993 994 if (list == NULL) 995 return NULL; 996 if (rem == NULL || *rem == '\0') 997 { 998 /* take out what? */ 999 return NULL; 1000 } 1001 1002 /* find the item in the list */ 1003 if ((needle = iteminlist(rem, list, " ")) == NULL) 1004 { 1005 /* not in there: return original */ 1006 return list; 1007 } 1008 1009 /* length of string without rem */ 1010 len = strlen(list) - strlen(rem); 1011 if (len == 0) 1012 { 1013 ret = xalloc(1); /* XXX leaked */ 1014 *ret = '\0'; 1015 return ret; 1016 } 1017 ret = xalloc(len); /* XXX leaked */ 1018 memset(ret, '\0', len); 1019 1020 /* copy from start to removed item */ 1021 memcpy(ret, list, needle - list); 1022 1023 /* length of rest of string past removed item */ 1024 len = strlen(needle) - strlen(rem) - 1; 1025 if (len > 0) 1026 { 1027 /* not last item -- copy into string */ 1028 memcpy(ret + (needle - list), 1029 list + (needle - list) + strlen(rem) + 1, 1030 len); 1031 } 1032 else 1033 ret[(needle - list) - 1] = '\0'; 1034 return ret; 1035 } 1036 /* 1037 ** INTERSECT -- create the intersection between two lists 1038 ** 1039 ** Parameters: 1040 ** s1, s2 -- lists of items (separated by single blanks). 1041 ** 1042 ** Returns: 1043 ** the intersection of both lists. 1044 */ 1045 1046 char * 1047 intersect(s1, s2) 1048 char *s1, *s2; 1049 { 1050 char *hr, *h1, *h, *res; 1051 int l1, l2, rl; 1052 1053 if (s1 == NULL || s2 == NULL) /* NULL string(s) -> NULL result */ 1054 return NULL; 1055 l1 = strlen(s1); 1056 l2 = strlen(s2); 1057 rl = min(l1, l2); 1058 res = (char *)malloc(rl + 1); 1059 if (res == NULL) 1060 return NULL; 1061 *res = '\0'; 1062 if (rl == 0) /* at least one string empty? */ 1063 return res; 1064 hr = res; 1065 h1 = s1; 1066 h = s1; 1067 1068 /* walk through s1 */ 1069 while (h != NULL && *h1 != '\0') 1070 { 1071 /* is there something after the current word? */ 1072 if ((h = strchr(h1, ' ')) != NULL) 1073 *h = '\0'; 1074 l1 = strlen(h1); 1075 1076 /* does the current word appear in s2 ? */ 1077 if (iteminlist(h1, s2, " ") != NULL) 1078 { 1079 /* add a blank if not first item */ 1080 if (hr != res) 1081 *hr++ = ' '; 1082 1083 /* copy the item */ 1084 memcpy(hr, h1, l1); 1085 1086 /* advance pointer in result list */ 1087 hr += l1; 1088 *hr = '\0'; 1089 } 1090 if (h != NULL) 1091 { 1092 /* there are more items */ 1093 *h = ' '; 1094 h1 = h + 1; 1095 } 1096 } 1097 return res; 1098 } 1099 /* 1100 ** ATTEMPTAUTH -- try to AUTHenticate using one mechanism 1101 ** 1102 ** Parameters: 1103 ** m -- the mailer. 1104 ** mci -- the mailer connection structure. 1105 ** e -- the envelope (including the sender to specify). 1106 ** mechused - filled in with mechanism used 1107 ** 1108 ** Returns: 1109 ** EX_OK/EX_TEMPFAIL 1110 */ 1111 1112 int 1113 attemptauth(m, mci, e, mechused) 1114 MAILER *m; 1115 MCI *mci; 1116 ENVELOPE *e; 1117 char **mechused; 1118 { 1119 int saslresult, smtpresult; 1120 sasl_external_properties_t ssf; 1121 sasl_interact_t *client_interact = NULL; 1122 char *out; 1123 unsigned int outlen; 1124 static char *mechusing; 1125 sasl_security_properties_t ssp; 1126 char in64[MAXOUTLEN]; 1127 # if NETINET 1128 extern SOCKADDR CurHostAddr; 1129 # endif /* NETINET */ 1130 1131 *mechused = NULL; 1132 if (mci->mci_conn != NULL) 1133 { 1134 sasl_dispose(&(mci->mci_conn)); 1135 1136 /* just in case, sasl_dispose() should take care of it */ 1137 mci->mci_conn = NULL; 1138 } 1139 1140 /* make a new client sasl connection */ 1141 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp" 1142 : "smtp", 1143 CurHostName, NULL, 0, &mci->mci_conn); 1144 1145 /* set properties */ 1146 (void) memset(&ssp, '\0', sizeof ssp); 1147 # if SFIO 1148 /* XXX should these be options settable via .cf ? */ 1149 /* ssp.min_ssf = 0; is default due to memset() */ 1150 { 1151 ssp.max_ssf = INT_MAX; 1152 ssp.maxbufsize = MAXOUTLEN; 1153 # if 0 1154 ssp.security_flags = SASL_SEC_NOPLAINTEXT; 1155 # endif /* 0 */ 1156 } 1157 # endif /* SFIO */ 1158 saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp); 1159 if (saslresult != SASL_OK) 1160 return EX_TEMPFAIL; 1161 1162 /* external security strength factor, authentication id */ 1163 ssf.ssf = 0; 1164 ssf.auth_id = NULL; 1165 # if _FFR_EXT_MECH 1166 out = macvalue(macid("{cert_subject}", NULL), e); 1167 if (out != NULL && *out != '\0') 1168 ssf.auth_id = out; 1169 out = macvalue(macid("{cipher_bits}", NULL), e); 1170 if (out != NULL && *out != '\0') 1171 ssf.ssf = atoi(out); 1172 # endif /* _FFR_EXT_MECH */ 1173 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf); 1174 if (saslresult != SASL_OK) 1175 return EX_TEMPFAIL; 1176 1177 # if NETINET 1178 /* set local/remote ipv4 addresses */ 1179 if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET) 1180 { 1181 SOCKADDR_LEN_T addrsize; 1182 struct sockaddr_in saddr_l; 1183 1184 if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE, 1185 (struct sockaddr_in *) &CurHostAddr) 1186 != SASL_OK) 1187 return EX_TEMPFAIL; 1188 addrsize = sizeof(struct sockaddr_in); 1189 if (getsockname(fileno(mci->mci_out), 1190 (struct sockaddr *) &saddr_l, &addrsize) != 0) 1191 { 1192 if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL, 1193 &saddr_l) != SASL_OK) 1194 return EX_TEMPFAIL; 1195 } 1196 } 1197 # endif /* NETINET */ 1198 1199 /* start client side of sasl */ 1200 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap, 1201 NULL, &client_interact, 1202 &out, &outlen, 1203 (const char **)&mechusing); 1204 callbacks[CB_AUTHNAME_IDX].context = mechusing; 1205 1206 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE) 1207 { 1208 # if SFIO 1209 if (saslresult == SASL_NOMECH && LogLevel > 8) 1210 { 1211 sm_syslog(LOG_NOTICE, e->e_id, 1212 "available AUTH mechanisms do not fulfill requirements"); 1213 } 1214 # endif /* SFIO */ 1215 return EX_TEMPFAIL; 1216 } 1217 1218 *mechused = mechusing; 1219 1220 /* send the info across the wire */ 1221 if (outlen > 0) 1222 { 1223 saslresult = sasl_encode64(out, outlen, in64, MAXOUTLEN, NULL); 1224 if (saslresult != SASL_OK) /* internal error */ 1225 { 1226 if (LogLevel > 8) 1227 sm_syslog(LOG_ERR, e->e_id, 1228 "encode64 for AUTH failed"); 1229 return EX_TEMPFAIL; 1230 } 1231 smtpmessage("AUTH %s %s", m, mci, mechusing, in64); 1232 } 1233 else 1234 { 1235 smtpmessage("AUTH %s", m, mci, mechusing); 1236 } 1237 1238 /* get the reply */ 1239 smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, getsasldata, NULL); 1240 /* which timeout? XXX */ 1241 1242 for (;;) 1243 { 1244 /* check return code from server */ 1245 if (smtpresult == 235) 1246 { 1247 define(macid("{auth_type}", NULL), 1248 newstr(mechusing), e); 1249 # if !SFIO 1250 if (LogLevel > 9) 1251 sm_syslog(LOG_INFO, NOQID, 1252 "SASL: outgoing connection to %.64s: mech=%.16s", 1253 mci->mci_host, mechusing); 1254 # endif /* !SFIO */ 1255 return EX_OK; 1256 } 1257 if (smtpresult == -1) 1258 return EX_IOERR; 1259 if (smtpresult != 334) 1260 return EX_TEMPFAIL; 1261 1262 saslresult = sasl_client_step(mci->mci_conn, 1263 mci->mci_sasl_string, 1264 mci->mci_sasl_string_len, 1265 &client_interact, 1266 &out, &outlen); 1267 1268 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE) 1269 { 1270 if (tTd(95, 5)) 1271 dprintf("AUTH FAIL: %s (%d)\n", 1272 sasl_errstring(saslresult, NULL, NULL), 1273 saslresult); 1274 1275 /* fail deliberately, see RFC 2254 4. */ 1276 smtpmessage("*", m, mci); 1277 1278 /* 1279 ** but we should only fail for this authentication 1280 ** mechanism; how to do that? 1281 */ 1282 1283 smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, 1284 getsasldata, NULL); 1285 return EX_TEMPFAIL; 1286 } 1287 1288 if (outlen > 0) 1289 { 1290 saslresult = sasl_encode64(out, outlen, in64, 1291 MAXOUTLEN, NULL); 1292 if (saslresult != SASL_OK) 1293 { 1294 /* give an error reply to the other side! */ 1295 smtpmessage("*", m, mci); 1296 return EX_TEMPFAIL; 1297 } 1298 } 1299 else 1300 in64[0] = '\0'; 1301 smtpmessage(in64, m, mci); 1302 smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, 1303 getsasldata, NULL); 1304 /* which timeout? XXX */ 1305 } 1306 /* NOTREACHED */ 1307 } 1308 1309 /* 1310 ** SMTPAUTH -- try to AUTHenticate 1311 ** 1312 ** This will try mechanisms in the order the sasl library decided until: 1313 ** - there are no more mechanisms 1314 ** - a mechanism succeeds 1315 ** - the sasl library fails initializing 1316 ** 1317 ** Parameters: 1318 ** m -- the mailer. 1319 ** mci -- the mailer connection info. 1320 ** e -- the envelope. 1321 ** 1322 ** Returns: 1323 ** EX_OK/EX_TEMPFAIL 1324 */ 1325 1326 int 1327 smtpauth(m, mci, e) 1328 MAILER *m; 1329 MCI *mci; 1330 ENVELOPE *e; 1331 { 1332 int result; 1333 char *mechused; 1334 char *h; 1335 static char *defrealm = NULL; 1336 static char *mechs = NULL; 1337 1338 mci->mci_sasl_auth = FALSE; 1339 if (defrealm == NULL) 1340 { 1341 h = readauth(SASL_DEFREALM, SASLInfo, TRUE); 1342 if (h != NULL && *h != '\0') 1343 defrealm = newstr(h); 1344 } 1345 if (defrealm == NULL || *defrealm == '\0') 1346 defrealm = newstr(macvalue('j', CurEnv)); 1347 callbacks[CB_GETREALM_IDX].context = defrealm; 1348 1349 # if _FFR_DEFAUTHINFO_MECHS 1350 if (mechs == NULL) 1351 { 1352 h = readauth(SASL_MECH, SASLInfo, TRUE); 1353 if (h != NULL && *h != '\0') 1354 mechs = newstr(h); 1355 } 1356 # endif /* _FFR_DEFAUTHINFO_MECHS */ 1357 if (mechs == NULL || *mechs == '\0') 1358 mechs = AuthMechanisms; 1359 mci->mci_saslcap = intersect(mechs, mci->mci_saslcap); 1360 1361 /* initialize sasl client library */ 1362 result = sasl_client_init(callbacks); 1363 if (result != SASL_OK) 1364 return EX_TEMPFAIL; 1365 do 1366 { 1367 result = attemptauth(m, mci, e, &mechused); 1368 if (result == EX_OK) 1369 mci->mci_sasl_auth = TRUE; 1370 else if (result == EX_TEMPFAIL) 1371 { 1372 mci->mci_saslcap = removemech(mechused, 1373 mci->mci_saslcap); 1374 if (mci->mci_saslcap == NULL || 1375 *(mci->mci_saslcap) == '\0') 1376 return EX_TEMPFAIL; 1377 } 1378 else /* all others for now */ 1379 return EX_TEMPFAIL; 1380 } while (result != EX_OK); 1381 return result; 1382 } 1383 # endif /* SASL */ 1384 1385 /* 1386 ** SMTPMAILFROM -- send MAIL command 1387 ** 1388 ** Parameters: 1389 ** m -- the mailer. 1390 ** mci -- the mailer connection structure. 1391 ** e -- the envelope (including the sender to specify). 1392 */ 1393 1394 int 1395 smtpmailfrom(m, mci, e) 1396 MAILER *m; 1397 MCI *mci; 1398 ENVELOPE *e; 1399 { 1400 int r; 1401 char *bufp; 1402 char *bodytype; 1403 char buf[MAXNAME + 1]; 1404 char optbuf[MAXLINE]; 1405 char *enhsc; 1406 1407 if (tTd(18, 2)) 1408 dprintf("smtpmailfrom: CurHost=%s\n", CurHostName); 1409 enhsc = NULL; 1410 1411 /* set up appropriate options to include */ 1412 if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) 1413 { 1414 snprintf(optbuf, sizeof optbuf, " SIZE=%ld", e->e_msgsize); 1415 bufp = &optbuf[strlen(optbuf)]; 1416 } 1417 else 1418 { 1419 optbuf[0] = '\0'; 1420 bufp = optbuf; 1421 } 1422 1423 bodytype = e->e_bodytype; 1424 if (bitset(MCIF_8BITMIME, mci->mci_flags)) 1425 { 1426 if (bodytype == NULL && 1427 bitset(MM_MIME8BIT, MimeMode) && 1428 bitset(EF_HAS8BIT, e->e_flags) && 1429 !bitset(EF_DONT_MIME, e->e_flags) && 1430 !bitnset(M_8BITS, m->m_flags)) 1431 bodytype = "8BITMIME"; 1432 if (bodytype != NULL && 1433 SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7) 1434 { 1435 snprintf(bufp, SPACELEFT(optbuf, bufp), 1436 " BODY=%s", bodytype); 1437 bufp += strlen(bufp); 1438 } 1439 } 1440 else if (bitnset(M_8BITS, m->m_flags) || 1441 !bitset(EF_HAS8BIT, e->e_flags) || 1442 bitset(MCIF_8BITOK, mci->mci_flags)) 1443 { 1444 /* EMPTY */ 1445 /* just pass it through */ 1446 } 1447 # if MIME8TO7 1448 else if (bitset(MM_CVTMIME, MimeMode) && 1449 !bitset(EF_DONT_MIME, e->e_flags) && 1450 (!bitset(MM_PASS8BIT, MimeMode) || 1451 bitset(EF_IS_MIME, e->e_flags))) 1452 { 1453 /* must convert from 8bit MIME format to 7bit encoded */ 1454 mci->mci_flags |= MCIF_CVT8TO7; 1455 } 1456 # endif /* MIME8TO7 */ 1457 else if (!bitset(MM_PASS8BIT, MimeMode)) 1458 { 1459 /* cannot just send a 8-bit version */ 1460 extern char MsgBuf[]; 1461 1462 usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName); 1463 mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf); 1464 return EX_DATAERR; 1465 } 1466 1467 if (bitset(MCIF_DSN, mci->mci_flags)) 1468 { 1469 if (e->e_envid != NULL && 1470 SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7) 1471 { 1472 snprintf(bufp, SPACELEFT(optbuf, bufp), 1473 " ENVID=%s", e->e_envid); 1474 bufp += strlen(bufp); 1475 } 1476 1477 /* RET= parameter */ 1478 if (bitset(EF_RET_PARAM, e->e_flags) && 1479 SPACELEFT(optbuf, bufp) > 9) 1480 { 1481 snprintf(bufp, SPACELEFT(optbuf, bufp), 1482 " RET=%s", 1483 bitset(EF_NO_BODY_RETN, e->e_flags) ? 1484 "HDRS" : "FULL"); 1485 bufp += strlen(bufp); 1486 } 1487 } 1488 1489 if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL && 1490 SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7 1491 # if SASL 1492 && (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth) 1493 # endif /* SASL */ 1494 ) 1495 { 1496 snprintf(bufp, SPACELEFT(optbuf, bufp), 1497 " AUTH=%s", e->e_auth_param); 1498 bufp += strlen(bufp); 1499 } 1500 1501 /* 1502 ** Send the MAIL command. 1503 ** Designates the sender. 1504 */ 1505 1506 mci->mci_state = MCIS_ACTIVE; 1507 1508 if (bitset(EF_RESPONSE, e->e_flags) && 1509 !bitnset(M_NO_NULL_FROM, m->m_flags)) 1510 buf[0] = '\0'; 1511 else 1512 expand("\201g", buf, sizeof buf, e); 1513 if (buf[0] == '<') 1514 { 1515 /* strip off <angle brackets> (put back on below) */ 1516 bufp = &buf[strlen(buf) - 1]; 1517 if (*bufp == '>') 1518 *bufp = '\0'; 1519 bufp = &buf[1]; 1520 } 1521 else 1522 bufp = buf; 1523 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 1524 !bitnset(M_FROMPATH, m->m_flags)) 1525 { 1526 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 1527 } 1528 else 1529 { 1530 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 1531 *bufp == '@' ? ',' : ':', bufp, optbuf); 1532 } 1533 SmtpPhase = mci->mci_phase = "client MAIL"; 1534 sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e), 1535 CurHostName, mci->mci_phase); 1536 r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc); 1537 if (r < 0) 1538 { 1539 /* communications failure */ 1540 mci->mci_errno = errno; 1541 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 1542 smtpquit(m, mci, e); 1543 return EX_TEMPFAIL; 1544 } 1545 else if (r == 421) 1546 { 1547 /* service shutting down */ 1548 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"), 1549 SmtpReplyBuffer); 1550 smtpquit(m, mci, e); 1551 return EX_TEMPFAIL; 1552 } 1553 else if (REPLYTYPE(r) == 4) 1554 { 1555 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)), 1556 SmtpReplyBuffer); 1557 return EX_TEMPFAIL; 1558 } 1559 else if (REPLYTYPE(r) == 2) 1560 { 1561 return EX_OK; 1562 } 1563 else if (r == 501) 1564 { 1565 /* syntax error in arguments */ 1566 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"), 1567 SmtpReplyBuffer); 1568 return EX_DATAERR; 1569 } 1570 else if (r == 553) 1571 { 1572 /* mailbox name not allowed */ 1573 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"), 1574 SmtpReplyBuffer); 1575 return EX_DATAERR; 1576 } 1577 else if (r == 552) 1578 { 1579 /* exceeded storage allocation */ 1580 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"), 1581 SmtpReplyBuffer); 1582 if (bitset(MCIF_SIZE, mci->mci_flags)) 1583 e->e_flags |= EF_NO_BODY_RETN; 1584 return EX_UNAVAILABLE; 1585 } 1586 else if (REPLYTYPE(r) == 5) 1587 { 1588 /* unknown error */ 1589 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"), 1590 SmtpReplyBuffer); 1591 return EX_UNAVAILABLE; 1592 } 1593 1594 if (LogLevel > 1) 1595 { 1596 sm_syslog(LOG_CRIT, e->e_id, 1597 "%.100s: SMTP MAIL protocol error: %s", 1598 CurHostName, 1599 shortenstring(SmtpReplyBuffer, 403)); 1600 } 1601 1602 /* protocol error -- close up */ 1603 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"), 1604 SmtpReplyBuffer); 1605 smtpquit(m, mci, e); 1606 return EX_PROTOCOL; 1607 } 1608 /* 1609 ** SMTPRCPT -- designate recipient. 1610 ** 1611 ** Parameters: 1612 ** to -- address of recipient. 1613 ** m -- the mailer we are sending to. 1614 ** mci -- the connection info for this transaction. 1615 ** e -- the envelope for this transaction. 1616 ** 1617 ** Returns: 1618 ** exit status corresponding to recipient status. 1619 ** 1620 ** Side Effects: 1621 ** Sends the mail via SMTP. 1622 */ 1623 1624 int 1625 smtprcpt(to, m, mci, e) 1626 ADDRESS *to; 1627 register MAILER *m; 1628 MCI *mci; 1629 ENVELOPE *e; 1630 { 1631 register int r; 1632 char *bufp; 1633 char optbuf[MAXLINE]; 1634 char *enhsc; 1635 1636 enhsc = NULL; 1637 optbuf[0] = '\0'; 1638 bufp = optbuf; 1639 1640 /* 1641 ** warning: in the following it is assumed that the free space 1642 ** in bufp is sizeof optbuf 1643 */ 1644 if (bitset(MCIF_DSN, mci->mci_flags)) 1645 { 1646 /* NOTIFY= parameter */ 1647 if (bitset(QHASNOTIFY, to->q_flags) && 1648 bitset(QPRIMARY, to->q_flags) && 1649 !bitnset(M_LOCALMAILER, m->m_flags)) 1650 { 1651 bool firstone = TRUE; 1652 1653 (void) strlcat(bufp, " NOTIFY=", sizeof optbuf); 1654 if (bitset(QPINGONSUCCESS, to->q_flags)) 1655 { 1656 (void) strlcat(bufp, "SUCCESS", sizeof optbuf); 1657 firstone = FALSE; 1658 } 1659 if (bitset(QPINGONFAILURE, to->q_flags)) 1660 { 1661 if (!firstone) 1662 (void) strlcat(bufp, ",", 1663 sizeof optbuf); 1664 (void) strlcat(bufp, "FAILURE", sizeof optbuf); 1665 firstone = FALSE; 1666 } 1667 if (bitset(QPINGONDELAY, to->q_flags)) 1668 { 1669 if (!firstone) 1670 (void) strlcat(bufp, ",", 1671 sizeof optbuf); 1672 (void) strlcat(bufp, "DELAY", sizeof optbuf); 1673 firstone = FALSE; 1674 } 1675 if (firstone) 1676 (void) strlcat(bufp, "NEVER", sizeof optbuf); 1677 bufp += strlen(bufp); 1678 } 1679 1680 /* ORCPT= parameter */ 1681 if (to->q_orcpt != NULL && 1682 SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7) 1683 { 1684 snprintf(bufp, SPACELEFT(optbuf, bufp), 1685 " ORCPT=%s", to->q_orcpt); 1686 bufp += strlen(bufp); 1687 } 1688 } 1689 1690 smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); 1691 1692 SmtpPhase = mci->mci_phase = "client RCPT"; 1693 sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e), 1694 CurHostName, mci->mci_phase); 1695 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc); 1696 to->q_rstatus = newstr(SmtpReplyBuffer); 1697 to->q_status = ENHSCN(enhsc, smtptodsn(r)); 1698 if (!bitnset(M_LMTP, m->m_flags)) 1699 to->q_statmta = mci->mci_host; 1700 if (r < 0 || REPLYTYPE(r) == 4) 1701 return EX_TEMPFAIL; 1702 else if (REPLYTYPE(r) == 2) 1703 return EX_OK; 1704 else if (r == 550) 1705 { 1706 to->q_status = ENHSCN(enhsc, "5.1.1"); 1707 return EX_NOUSER; 1708 } 1709 else if (r == 551) 1710 { 1711 to->q_status = ENHSCN(enhsc, "5.1.6"); 1712 return EX_NOUSER; 1713 } 1714 else if (r == 553) 1715 { 1716 to->q_status = ENHSCN(enhsc, "5.1.3"); 1717 return EX_NOUSER; 1718 } 1719 else if (REPLYTYPE(r) == 5) 1720 { 1721 return EX_UNAVAILABLE; 1722 } 1723 1724 if (LogLevel > 1) 1725 { 1726 sm_syslog(LOG_CRIT, e->e_id, 1727 "%.100s: SMTP RCPT protocol error: %s", 1728 CurHostName, 1729 shortenstring(SmtpReplyBuffer, 403)); 1730 } 1731 1732 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"), 1733 SmtpReplyBuffer); 1734 return EX_PROTOCOL; 1735 } 1736 /* 1737 ** SMTPDATA -- send the data and clean up the transaction. 1738 ** 1739 ** Parameters: 1740 ** m -- mailer being sent to. 1741 ** mci -- the mailer connection information. 1742 ** e -- the envelope for this message. 1743 ** 1744 ** Returns: 1745 ** exit status corresponding to DATA command. 1746 ** 1747 ** Side Effects: 1748 ** none. 1749 */ 1750 1751 static jmp_buf CtxDataTimeout; 1752 1753 int 1754 smtpdata(m, mci, e) 1755 MAILER *m; 1756 register MCI *mci; 1757 register ENVELOPE *e; 1758 { 1759 register int r; 1760 register EVENT *ev; 1761 int rstat; 1762 int xstat; 1763 time_t timeout; 1764 char *enhsc; 1765 1766 enhsc = NULL; 1767 /* 1768 ** Send the data. 1769 ** First send the command and check that it is ok. 1770 ** Then send the data. 1771 ** Follow it up with a dot to terminate. 1772 ** Finally get the results of the transaction. 1773 */ 1774 1775 /* send the command and check ok to proceed */ 1776 smtpmessage("DATA", m, mci); 1777 SmtpPhase = mci->mci_phase = "client DATA 354"; 1778 sm_setproctitle(TRUE, e, "%s %s: %s", 1779 qid_printname(e), CurHostName, mci->mci_phase); 1780 r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc); 1781 if (r < 0 || REPLYTYPE(r) == 4) 1782 { 1783 smtpquit(m, mci, e); 1784 return EX_TEMPFAIL; 1785 } 1786 else if (REPLYTYPE(r) == 5) 1787 { 1788 smtprset(m, mci, e); 1789 return EX_UNAVAILABLE; 1790 } 1791 else if (REPLYTYPE(r) != 3) 1792 { 1793 if (LogLevel > 1) 1794 { 1795 sm_syslog(LOG_CRIT, e->e_id, 1796 "%.100s: SMTP DATA-1 protocol error: %s", 1797 CurHostName, 1798 shortenstring(SmtpReplyBuffer, 403)); 1799 } 1800 smtprset(m, mci, e); 1801 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"), 1802 SmtpReplyBuffer); 1803 return EX_PROTOCOL; 1804 } 1805 1806 /* 1807 ** Set timeout around data writes. Make it at least large 1808 ** enough for DNS timeouts on all recipients plus some fudge 1809 ** factor. The main thing is that it should not be infinite. 1810 */ 1811 1812 if (setjmp(CtxDataTimeout) != 0) 1813 { 1814 mci->mci_errno = errno; 1815 mci->mci_state = MCIS_ERROR; 1816 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 1817 1818 /* 1819 ** If putbody() couldn't finish due to a timeout, 1820 ** rewind it here in the timeout handler. See 1821 ** comments at the end of putbody() for reasoning. 1822 */ 1823 1824 if (e->e_dfp != NULL) 1825 (void) bfrewind(e->e_dfp); 1826 1827 errno = mci->mci_errno; 1828 syserr("451 4.4.1 timeout writing message to %s", CurHostName); 1829 smtpquit(m, mci, e); 1830 return EX_TEMPFAIL; 1831 } 1832 1833 if (tTd(18, 101)) 1834 { 1835 /* simulate a DATA timeout */ 1836 timeout = 1; 1837 } 1838 else 1839 timeout = DATA_PROGRESS_TIMEOUT; 1840 1841 ev = setevent(timeout, datatimeout, 0); 1842 1843 1844 if (tTd(18, 101)) 1845 { 1846 /* simulate a DATA timeout */ 1847 (void) sleep(1); 1848 } 1849 1850 /* 1851 ** Output the actual message. 1852 */ 1853 1854 (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 1855 (*e->e_putbody)(mci, e, NULL); 1856 1857 /* 1858 ** Cleanup after sending message. 1859 */ 1860 1861 clrevent(ev); 1862 1863 # if _FFR_CATCH_BROKEN_MTAS 1864 { 1865 fd_set readfds; 1866 struct timeval timeout; 1867 1868 FD_ZERO(&readfds); 1869 FD_SET(fileno(mci->mci_in), &readfds); 1870 timeout.tv_sec = 0; 1871 timeout.tv_usec = 0; 1872 if (select(fileno(mci->mci_in) + 1, FDSET_CAST &readfds, 1873 NULL, NULL, &timeout) > 0 && 1874 FD_ISSET(fileno(mci->mci_in), &readfds)) 1875 { 1876 /* terminate the message */ 1877 fprintf(mci->mci_out, ".%s", m->m_eol); 1878 if (TrafficLogFile != NULL) 1879 fprintf(TrafficLogFile, "%05d >>> .\n", 1880 (int) getpid()); 1881 if (Verbose) 1882 nmessage(">>> ."); 1883 1884 mci->mci_errno = EIO; 1885 mci->mci_state = MCIS_ERROR; 1886 mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL); 1887 smtpquit(m, mci, e); 1888 return EX_PROTOCOL; 1889 } 1890 } 1891 # endif /* _FFR_CATCH_BROKEN_MTAS */ 1892 1893 if (ferror(mci->mci_out)) 1894 { 1895 /* error during processing -- don't send the dot */ 1896 mci->mci_errno = EIO; 1897 mci->mci_state = MCIS_ERROR; 1898 mci_setstat(mci, EX_IOERR, "4.4.2", NULL); 1899 smtpquit(m, mci, e); 1900 return EX_IOERR; 1901 } 1902 1903 /* terminate the message */ 1904 fprintf(mci->mci_out, ".%s", m->m_eol); 1905 if (TrafficLogFile != NULL) 1906 fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid()); 1907 if (Verbose) 1908 nmessage(">>> ."); 1909 1910 /* check for the results of the transaction */ 1911 SmtpPhase = mci->mci_phase = "client DATA status"; 1912 sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e), 1913 CurHostName, mci->mci_phase); 1914 if (bitnset(M_LMTP, m->m_flags)) 1915 return EX_OK; 1916 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc); 1917 if (r < 0) 1918 { 1919 smtpquit(m, mci, e); 1920 return EX_TEMPFAIL; 1921 } 1922 mci->mci_state = MCIS_OPEN; 1923 xstat = EX_NOTSTICKY; 1924 if (r == 452) 1925 rstat = EX_TEMPFAIL; 1926 else if (REPLYTYPE(r) == 4) 1927 rstat = xstat = EX_TEMPFAIL; 1928 else if (REPLYCLASS(r) != 5) 1929 rstat = xstat = EX_PROTOCOL; 1930 else if (REPLYTYPE(r) == 2) 1931 rstat = xstat = EX_OK; 1932 else if (REPLYTYPE(r) == 5) 1933 rstat = EX_UNAVAILABLE; 1934 else 1935 rstat = EX_PROTOCOL; 1936 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), 1937 SmtpReplyBuffer); 1938 if (e->e_statmsg != NULL) 1939 free(e->e_statmsg); 1940 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 1941 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) 1942 r += 5; 1943 else 1944 r = 4; 1945 e->e_statmsg = newstr(&SmtpReplyBuffer[r]); 1946 if (rstat != EX_PROTOCOL) 1947 return rstat; 1948 if (LogLevel > 1) 1949 { 1950 sm_syslog(LOG_CRIT, e->e_id, 1951 "%.100s: SMTP DATA-2 protocol error: %s", 1952 CurHostName, 1953 shortenstring(SmtpReplyBuffer, 403)); 1954 } 1955 return rstat; 1956 } 1957 1958 1959 static void 1960 datatimeout() 1961 { 1962 if (DataProgress) 1963 { 1964 time_t timeout; 1965 register EVENT *ev; 1966 1967 /* check back again later */ 1968 if (tTd(18, 101)) 1969 { 1970 /* simulate a DATA timeout */ 1971 timeout = 1; 1972 } 1973 else 1974 timeout = DATA_PROGRESS_TIMEOUT; 1975 1976 DataProgress = FALSE; 1977 ev = setevent(timeout, datatimeout, 0); 1978 } 1979 else 1980 { 1981 /* no progress, give up */ 1982 longjmp(CtxDataTimeout, 1); 1983 } 1984 } 1985 /* 1986 ** SMTPGETSTAT -- get status code from DATA in LMTP 1987 ** 1988 ** Parameters: 1989 ** m -- the mailer to which we are sending the message. 1990 ** mci -- the mailer connection structure. 1991 ** e -- the current envelope. 1992 ** 1993 ** Returns: 1994 ** The exit status corresponding to the reply code. 1995 */ 1996 1997 int 1998 smtpgetstat(m, mci, e) 1999 MAILER *m; 2000 MCI *mci; 2001 ENVELOPE *e; 2002 { 2003 int r; 2004 int status; 2005 char *enhsc; 2006 2007 enhsc = NULL; 2008 /* check for the results of the transaction */ 2009 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc); 2010 if (r < 0) 2011 { 2012 smtpquit(m, mci, e); 2013 return EX_TEMPFAIL; 2014 } 2015 if (REPLYTYPE(r) == 4) 2016 status = EX_TEMPFAIL; 2017 else if (REPLYCLASS(r) != 5) 2018 status = EX_PROTOCOL; 2019 else if (REPLYTYPE(r) == 2) 2020 status = EX_OK; 2021 else if (REPLYTYPE(r) == 5) 2022 status = EX_UNAVAILABLE; 2023 else 2024 status = EX_PROTOCOL; 2025 if (e->e_statmsg != NULL) 2026 free(e->e_statmsg); 2027 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 2028 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) 2029 r += 5; 2030 else 2031 r = 4; 2032 e->e_statmsg = newstr(&SmtpReplyBuffer[r]); 2033 mci_setstat(mci, status, ENHSCN(enhsc, smtptodsn(r)), 2034 SmtpReplyBuffer); 2035 if (LogLevel > 1 && status == EX_PROTOCOL) 2036 { 2037 sm_syslog(LOG_CRIT, e->e_id, 2038 "%.100s: SMTP DATA-3 protocol error: %s", 2039 CurHostName, 2040 shortenstring(SmtpReplyBuffer, 403)); 2041 } 2042 return status; 2043 } 2044 /* 2045 ** SMTPQUIT -- close the SMTP connection. 2046 ** 2047 ** Parameters: 2048 ** m -- a pointer to the mailer. 2049 ** mci -- the mailer connection information. 2050 ** e -- the current envelope. 2051 ** 2052 ** Returns: 2053 ** none. 2054 ** 2055 ** Side Effects: 2056 ** sends the final protocol and closes the connection. 2057 */ 2058 2059 void 2060 smtpquit(m, mci, e) 2061 register MAILER *m; 2062 register MCI *mci; 2063 ENVELOPE *e; 2064 { 2065 bool oldSuprErrs = SuprErrs; 2066 int rcode; 2067 2068 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 2069 if (CurHostName == NULL) 2070 CurHostName = MyHostName; 2071 2072 /* 2073 ** Suppress errors here -- we may be processing a different 2074 ** job when we do the quit connection, and we don't want the 2075 ** new job to be penalized for something that isn't it's 2076 ** problem. 2077 */ 2078 2079 SuprErrs = TRUE; 2080 2081 /* send the quit message if we haven't gotten I/O error */ 2082 if (mci->mci_state != MCIS_ERROR && 2083 mci->mci_state != MCIS_QUITING) 2084 { 2085 int origstate = mci->mci_state; 2086 2087 SmtpPhase = "client QUIT"; 2088 mci->mci_state = MCIS_QUITING; 2089 smtpmessage("QUIT", m, mci); 2090 (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL); 2091 SuprErrs = oldSuprErrs; 2092 if (mci->mci_state == MCIS_CLOSED || 2093 origstate == MCIS_CLOSED) 2094 return; 2095 } 2096 2097 /* now actually close the connection and pick up the zombie */ 2098 rcode = endmailer(mci, e, NULL); 2099 if (rcode != EX_OK) 2100 { 2101 char *mailer = NULL; 2102 2103 if (mci->mci_mailer != NULL && 2104 mci->mci_mailer->m_name != NULL) 2105 mailer = mci->mci_mailer->m_name; 2106 2107 /* look for naughty mailers */ 2108 sm_syslog(LOG_ERR, e->e_id, 2109 "smtpquit: mailer%s%s exited with exit value %d\n", 2110 mailer == NULL ? "" : " ", 2111 mailer == NULL ? "" : mailer, 2112 rcode); 2113 } 2114 2115 SuprErrs = oldSuprErrs; 2116 } 2117 /* 2118 ** SMTPRSET -- send a RSET (reset) command 2119 */ 2120 2121 void 2122 smtprset(m, mci, e) 2123 register MAILER *m; 2124 register MCI *mci; 2125 ENVELOPE *e; 2126 { 2127 int r; 2128 2129 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 2130 if (CurHostName == NULL) 2131 CurHostName = MyHostName; 2132 2133 SmtpPhase = "client RSET"; 2134 smtpmessage("RSET", m, mci); 2135 r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL); 2136 if (r < 0) 2137 mci->mci_state = MCIS_ERROR; 2138 else 2139 { 2140 /* 2141 ** Any response is deemed to be acceptable. 2142 ** The standard does not state the proper action 2143 ** to take when a value other than 250 is received. 2144 */ 2145 2146 mci->mci_state = MCIS_OPEN; 2147 return; 2148 } 2149 smtpquit(m, mci, e); 2150 } 2151 /* 2152 ** SMTPPROBE -- check the connection state 2153 */ 2154 2155 int 2156 smtpprobe(mci) 2157 register MCI *mci; 2158 { 2159 int r; 2160 MAILER *m = mci->mci_mailer; 2161 ENVELOPE *e; 2162 extern ENVELOPE BlankEnvelope; 2163 2164 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 2165 if (CurHostName == NULL) 2166 CurHostName = MyHostName; 2167 2168 e = &BlankEnvelope; 2169 SmtpPhase = "client probe"; 2170 smtpmessage("RSET", m, mci); 2171 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL); 2172 if (r < 0 || REPLYTYPE(r) != 2) 2173 smtpquit(m, mci, e); 2174 return r; 2175 } 2176 /* 2177 ** REPLY -- read arpanet reply 2178 ** 2179 ** Parameters: 2180 ** m -- the mailer we are reading the reply from. 2181 ** mci -- the mailer connection info structure. 2182 ** e -- the current envelope. 2183 ** timeout -- the timeout for reads. 2184 ** pfunc -- processing function called on each line of response. 2185 ** If null, no special processing is done. 2186 ** 2187 ** Returns: 2188 ** reply code it reads. 2189 ** 2190 ** Side Effects: 2191 ** flushes the mail file. 2192 */ 2193 2194 int 2195 reply(m, mci, e, timeout, pfunc, enhstat) 2196 MAILER *m; 2197 MCI *mci; 2198 ENVELOPE *e; 2199 time_t timeout; 2200 void (*pfunc)(); 2201 char **enhstat; 2202 { 2203 register char *bufp; 2204 register int r; 2205 bool firstline = TRUE; 2206 char junkbuf[MAXLINE]; 2207 static char enhstatcode[ENHSCLEN]; 2208 int save_errno; 2209 2210 if (mci->mci_out != NULL) 2211 (void) fflush(mci->mci_out); 2212 2213 if (tTd(18, 1)) 2214 dprintf("reply\n"); 2215 2216 /* 2217 ** Read the input line, being careful not to hang. 2218 */ 2219 2220 bufp = SmtpReplyBuffer; 2221 for (;;) 2222 { 2223 register char *p; 2224 2225 /* actually do the read */ 2226 if (e->e_xfp != NULL) 2227 (void) fflush(e->e_xfp); /* for debugging */ 2228 2229 /* if we are in the process of closing just give the code */ 2230 if (mci->mci_state == MCIS_CLOSED) 2231 return SMTPCLOSING; 2232 2233 if (mci->mci_out != NULL) 2234 (void) fflush(mci->mci_out); 2235 2236 /* get the line from the other side */ 2237 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 2238 mci->mci_lastuse = curtime(); 2239 2240 if (p == NULL) 2241 { 2242 bool oldholderrs; 2243 extern char MsgBuf[]; 2244 2245 /* if the remote end closed early, fake an error */ 2246 if (errno == 0) 2247 # ifdef ECONNRESET 2248 errno = ECONNRESET; 2249 # else /* ECONNRESET */ 2250 errno = EPIPE; 2251 # endif /* ECONNRESET */ 2252 2253 mci->mci_errno = errno; 2254 oldholderrs = HoldErrs; 2255 HoldErrs = TRUE; 2256 usrerr("451 4.4.1 reply: read error from %s", 2257 CurHostName == NULL ? "NO_HOST" : CurHostName); 2258 2259 /* errors on QUIT should not be persistent */ 2260 if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0) 2261 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf); 2262 2263 /* if debugging, pause so we can see state */ 2264 if (tTd(18, 100)) 2265 (void) pause(); 2266 mci->mci_state = MCIS_ERROR; 2267 save_errno = errno; 2268 smtpquit(m, mci, e); 2269 # if XDEBUG 2270 { 2271 char wbuf[MAXLINE]; 2272 int wbufleft = sizeof wbuf; 2273 2274 p = wbuf; 2275 if (e->e_to != NULL) 2276 { 2277 int plen; 2278 2279 snprintf(p, wbufleft, "%s... ", 2280 shortenstring(e->e_to, MAXSHORTSTR)); 2281 plen = strlen(p); 2282 p += plen; 2283 wbufleft -= plen; 2284 } 2285 snprintf(p, wbufleft, "reply(%.100s) during %s", 2286 CurHostName == NULL ? "NO_HOST" : CurHostName, 2287 SmtpPhase); 2288 checkfd012(wbuf); 2289 } 2290 # endif /* XDEBUG */ 2291 errno = save_errno; 2292 HoldErrs = oldholderrs; 2293 return -1; 2294 } 2295 fixcrlf(bufp, TRUE); 2296 2297 /* EHLO failure is not a real error */ 2298 if (e->e_xfp != NULL && (bufp[0] == '4' || 2299 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 2300 { 2301 /* serious error -- log the previous command */ 2302 if (SmtpNeedIntro) 2303 { 2304 /* inform user who we are chatting with */ 2305 fprintf(CurEnv->e_xfp, 2306 "... while talking to %s:\n", 2307 CurHostName == NULL ? "NO_HOST" : CurHostName); 2308 SmtpNeedIntro = FALSE; 2309 } 2310 if (SmtpMsgBuffer[0] != '\0') 2311 fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 2312 SmtpMsgBuffer[0] = '\0'; 2313 2314 /* now log the message as from the other side */ 2315 fprintf(e->e_xfp, "<<< %s\n", bufp); 2316 } 2317 2318 /* display the input for verbose mode */ 2319 if (Verbose) 2320 nmessage("050 %s", bufp); 2321 2322 /* ignore improperly formatted input */ 2323 if (!ISSMTPREPLY(bufp)) 2324 continue; 2325 2326 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 2327 enhstat != NULL && 2328 extenhsc(bufp + 4, ' ', enhstatcode) > 0) 2329 *enhstat = enhstatcode; 2330 2331 /* process the line */ 2332 if (pfunc != NULL) 2333 (*pfunc)(bufp, firstline, m, mci, e); 2334 2335 firstline = FALSE; 2336 2337 /* decode the reply code */ 2338 r = atoi(bufp); 2339 2340 /* extra semantics: 0xx codes are "informational" */ 2341 if (r < 100) 2342 continue; 2343 2344 /* if no continuation lines, return this line */ 2345 if (bufp[3] != '-') 2346 break; 2347 2348 /* first line of real reply -- ignore rest */ 2349 bufp = junkbuf; 2350 } 2351 2352 /* 2353 ** Now look at SmtpReplyBuffer -- only care about the first 2354 ** line of the response from here on out. 2355 */ 2356 2357 /* save temporary failure messages for posterity */ 2358 if (SmtpReplyBuffer[0] == '4' && 2359 (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0')) 2360 snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer); 2361 2362 /* reply code 421 is "Service Shutting Down" */ 2363 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 2364 { 2365 /* send the quit protocol */ 2366 mci->mci_state = MCIS_SSD; 2367 smtpquit(m, mci, e); 2368 } 2369 2370 return r; 2371 } 2372 /* 2373 ** SMTPMESSAGE -- send message to server 2374 ** 2375 ** Parameters: 2376 ** f -- format 2377 ** m -- the mailer to control formatting. 2378 ** a, b, c -- parameters 2379 ** 2380 ** Returns: 2381 ** none. 2382 ** 2383 ** Side Effects: 2384 ** writes message to mci->mci_out. 2385 */ 2386 2387 /*VARARGS1*/ 2388 void 2389 # ifdef __STDC__ 2390 smtpmessage(char *f, MAILER *m, MCI *mci, ...) 2391 # else /* __STDC__ */ 2392 smtpmessage(f, m, mci, va_alist) 2393 char *f; 2394 MAILER *m; 2395 MCI *mci; 2396 va_dcl 2397 # endif /* __STDC__ */ 2398 { 2399 VA_LOCAL_DECL 2400 2401 VA_START(mci); 2402 (void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap); 2403 VA_END; 2404 2405 if (tTd(18, 1) || Verbose) 2406 nmessage(">>> %s", SmtpMsgBuffer); 2407 if (TrafficLogFile != NULL) 2408 fprintf(TrafficLogFile, "%05d >>> %s\n", 2409 (int) getpid(), SmtpMsgBuffer); 2410 if (mci->mci_out != NULL) 2411 { 2412 fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 2413 m == NULL ? "\r\n" : m->m_eol); 2414 } 2415 else if (tTd(18, 1)) 2416 { 2417 dprintf("smtpmessage: NULL mci_out\n"); 2418 } 2419 } 2420 2421 #endif /* SMTP */ 2422