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