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.33 2001/05/23 18:53:09 ca Exp $ (with SMTP)"; 19 # else /* SMTP */ 20 static char id[] = "@(#)$Id: usersmtp.c,v 8.245.4.33 2001/05/23 18:53:09 ca 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 mci->mci_errno = EIO; 1877 mci->mci_state = MCIS_ERROR; 1878 mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL); 1879 smtpquit(m, mci, e); 1880 return EX_PROTOCOL; 1881 } 1882 } 1883 # endif /* _FFR_CATCH_BROKEN_MTAS */ 1884 1885 if (ferror(mci->mci_out)) 1886 { 1887 /* error during processing -- don't send the dot */ 1888 mci->mci_errno = EIO; 1889 mci->mci_state = MCIS_ERROR; 1890 mci_setstat(mci, EX_IOERR, "4.4.2", NULL); 1891 smtpquit(m, mci, e); 1892 return EX_IOERR; 1893 } 1894 1895 /* terminate the message */ 1896 fprintf(mci->mci_out, ".%s", m->m_eol); 1897 if (TrafficLogFile != NULL) 1898 fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid()); 1899 if (Verbose) 1900 nmessage(">>> ."); 1901 1902 /* check for the results of the transaction */ 1903 SmtpPhase = mci->mci_phase = "client DATA status"; 1904 sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e), 1905 CurHostName, mci->mci_phase); 1906 if (bitnset(M_LMTP, m->m_flags)) 1907 return EX_OK; 1908 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc); 1909 if (r < 0) 1910 { 1911 smtpquit(m, mci, e); 1912 return EX_TEMPFAIL; 1913 } 1914 mci->mci_state = MCIS_OPEN; 1915 xstat = EX_NOTSTICKY; 1916 if (r == 452) 1917 rstat = EX_TEMPFAIL; 1918 else if (REPLYTYPE(r) == 4) 1919 rstat = xstat = EX_TEMPFAIL; 1920 else if (REPLYCLASS(r) != 5) 1921 rstat = xstat = EX_PROTOCOL; 1922 else if (REPLYTYPE(r) == 2) 1923 rstat = xstat = EX_OK; 1924 else if (REPLYTYPE(r) == 5) 1925 rstat = EX_UNAVAILABLE; 1926 else 1927 rstat = EX_PROTOCOL; 1928 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), 1929 SmtpReplyBuffer); 1930 if (e->e_statmsg != NULL) 1931 sm_free(e->e_statmsg); 1932 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 1933 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) 1934 r += 5; 1935 else 1936 r = 4; 1937 e->e_statmsg = newstr(&SmtpReplyBuffer[r]); 1938 SmtpPhase = mci->mci_phase = "idle"; 1939 sm_setproctitle(TRUE, e, "%s: %s", CurHostName, mci->mci_phase); 1940 if (rstat != EX_PROTOCOL) 1941 return rstat; 1942 if (LogLevel > 1) 1943 { 1944 sm_syslog(LOG_CRIT, e->e_id, 1945 "%.100s: SMTP DATA-2 protocol error: %s", 1946 CurHostName, 1947 shortenstring(SmtpReplyBuffer, 403)); 1948 } 1949 return rstat; 1950 } 1951 1952 1953 static void 1954 datatimeout() 1955 { 1956 int save_errno = errno; 1957 1958 /* 1959 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 1960 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 1961 ** DOING. 1962 */ 1963 1964 if (DataProgress) 1965 { 1966 time_t timeout; 1967 1968 /* check back again later */ 1969 if (tTd(18, 101)) 1970 { 1971 /* simulate a DATA timeout */ 1972 timeout = 1; 1973 } 1974 else 1975 timeout = DATA_PROGRESS_TIMEOUT; 1976 1977 /* reset the timeout */ 1978 DataTimeout = sigsafe_setevent(timeout, datatimeout, 0); 1979 DataProgress = FALSE; 1980 } 1981 else 1982 { 1983 /* event is done */ 1984 DataTimeout = NULL; 1985 } 1986 1987 /* if no progress was made or problem resetting event, die now */ 1988 if (DataTimeout == NULL) 1989 { 1990 errno = ETIMEDOUT; 1991 longjmp(CtxDataTimeout, 1); 1992 } 1993 1994 errno = save_errno; 1995 } 1996 /* 1997 ** SMTPGETSTAT -- get status code from DATA in LMTP 1998 ** 1999 ** Parameters: 2000 ** m -- the mailer to which we are sending the message. 2001 ** mci -- the mailer connection structure. 2002 ** e -- the current envelope. 2003 ** 2004 ** Returns: 2005 ** The exit status corresponding to the reply code. 2006 */ 2007 2008 int 2009 smtpgetstat(m, mci, e) 2010 MAILER *m; 2011 MCI *mci; 2012 ENVELOPE *e; 2013 { 2014 int r; 2015 int status; 2016 char *enhsc; 2017 2018 enhsc = NULL; 2019 /* check for the results of the transaction */ 2020 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc); 2021 if (r < 0) 2022 { 2023 smtpquit(m, mci, e); 2024 return EX_TEMPFAIL; 2025 } 2026 if (REPLYTYPE(r) == 4) 2027 status = EX_TEMPFAIL; 2028 else if (REPLYCLASS(r) != 5) 2029 status = EX_PROTOCOL; 2030 else if (REPLYTYPE(r) == 2) 2031 status = EX_OK; 2032 else if (REPLYTYPE(r) == 5) 2033 status = EX_UNAVAILABLE; 2034 else 2035 status = EX_PROTOCOL; 2036 if (e->e_statmsg != NULL) 2037 sm_free(e->e_statmsg); 2038 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 2039 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) 2040 r += 5; 2041 else 2042 r = 4; 2043 e->e_statmsg = newstr(&SmtpReplyBuffer[r]); 2044 mci_setstat(mci, status, ENHSCN(enhsc, smtptodsn(r)), 2045 SmtpReplyBuffer); 2046 if (LogLevel > 1 && status == EX_PROTOCOL) 2047 { 2048 sm_syslog(LOG_CRIT, e->e_id, 2049 "%.100s: SMTP DATA-3 protocol error: %s", 2050 CurHostName, 2051 shortenstring(SmtpReplyBuffer, 403)); 2052 } 2053 return status; 2054 } 2055 /* 2056 ** SMTPQUIT -- close the SMTP connection. 2057 ** 2058 ** Parameters: 2059 ** m -- a pointer to the mailer. 2060 ** mci -- the mailer connection information. 2061 ** e -- the current envelope. 2062 ** 2063 ** Returns: 2064 ** none. 2065 ** 2066 ** Side Effects: 2067 ** sends the final protocol and closes the connection. 2068 */ 2069 2070 void 2071 smtpquit(m, mci, e) 2072 register MAILER *m; 2073 register MCI *mci; 2074 ENVELOPE *e; 2075 { 2076 bool oldSuprErrs = SuprErrs; 2077 int rcode; 2078 2079 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 2080 if (CurHostName == NULL) 2081 CurHostName = MyHostName; 2082 2083 /* 2084 ** Suppress errors here -- we may be processing a different 2085 ** job when we do the quit connection, and we don't want the 2086 ** new job to be penalized for something that isn't it's 2087 ** problem. 2088 */ 2089 2090 SuprErrs = TRUE; 2091 2092 /* send the quit message if we haven't gotten I/O error */ 2093 if (mci->mci_state != MCIS_ERROR && 2094 mci->mci_state != MCIS_QUITING) 2095 { 2096 int origstate = mci->mci_state; 2097 2098 SmtpPhase = "client QUIT"; 2099 mci->mci_state = MCIS_QUITING; 2100 smtpmessage("QUIT", m, mci); 2101 (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL); 2102 SuprErrs = oldSuprErrs; 2103 if (mci->mci_state == MCIS_CLOSED || 2104 origstate == MCIS_CLOSED) 2105 return; 2106 } 2107 2108 /* now actually close the connection and pick up the zombie */ 2109 rcode = endmailer(mci, e, NULL); 2110 if (rcode != EX_OK) 2111 { 2112 char *mailer = NULL; 2113 2114 if (mci->mci_mailer != NULL && 2115 mci->mci_mailer->m_name != NULL) 2116 mailer = mci->mci_mailer->m_name; 2117 2118 /* look for naughty mailers */ 2119 sm_syslog(LOG_ERR, e->e_id, 2120 "smtpquit: mailer%s%s exited with exit value %d", 2121 mailer == NULL ? "" : " ", 2122 mailer == NULL ? "" : mailer, 2123 rcode); 2124 } 2125 2126 SuprErrs = oldSuprErrs; 2127 } 2128 /* 2129 ** SMTPRSET -- send a RSET (reset) command 2130 ** 2131 ** Parameters: 2132 ** m -- a pointer to the mailer. 2133 ** mci -- the mailer connection information. 2134 ** e -- the current envelope. 2135 ** 2136 ** Returns: 2137 ** none. 2138 ** 2139 ** Side Effects: 2140 ** closes the connection if there is no reply to RSET. 2141 */ 2142 2143 void 2144 smtprset(m, mci, e) 2145 register MAILER *m; 2146 register MCI *mci; 2147 ENVELOPE *e; 2148 { 2149 int r; 2150 2151 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 2152 if (CurHostName == NULL) 2153 CurHostName = MyHostName; 2154 2155 SmtpPhase = "client RSET"; 2156 smtpmessage("RSET", m, mci); 2157 r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL); 2158 if (r < 0) 2159 mci->mci_state = MCIS_ERROR; 2160 else 2161 { 2162 /* 2163 ** Any response is deemed to be acceptable. 2164 ** The standard does not state the proper action 2165 ** to take when a value other than 250 is received. 2166 ** 2167 ** However, if 421 is returned for the RSET, leave 2168 ** mci_state as MCIS_SSD (set in reply()). 2169 */ 2170 2171 if (mci->mci_state != MCIS_SSD) 2172 mci->mci_state = MCIS_OPEN; 2173 return; 2174 } 2175 smtpquit(m, mci, e); 2176 } 2177 /* 2178 ** SMTPPROBE -- check the connection state 2179 ** 2180 ** Parameters: 2181 ** mci -- the mailer connection information. 2182 ** 2183 ** Returns: 2184 ** none. 2185 ** 2186 ** Side Effects: 2187 ** closes the connection if there is no reply to RSET. 2188 */ 2189 2190 int 2191 smtpprobe(mci) 2192 register MCI *mci; 2193 { 2194 int r; 2195 MAILER *m = mci->mci_mailer; 2196 ENVELOPE *e; 2197 extern ENVELOPE BlankEnvelope; 2198 2199 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 2200 if (CurHostName == NULL) 2201 CurHostName = MyHostName; 2202 2203 e = &BlankEnvelope; 2204 SmtpPhase = "client probe"; 2205 smtpmessage("RSET", m, mci); 2206 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL); 2207 if (r < 0 || REPLYTYPE(r) != 2) 2208 smtpquit(m, mci, e); 2209 return r; 2210 } 2211 /* 2212 ** REPLY -- read arpanet reply 2213 ** 2214 ** Parameters: 2215 ** m -- the mailer we are reading the reply from. 2216 ** mci -- the mailer connection info structure. 2217 ** e -- the current envelope. 2218 ** timeout -- the timeout for reads. 2219 ** pfunc -- processing function called on each line of response. 2220 ** If null, no special processing is done. 2221 ** 2222 ** Returns: 2223 ** reply code it reads. 2224 ** 2225 ** Side Effects: 2226 ** flushes the mail file. 2227 */ 2228 2229 int 2230 reply(m, mci, e, timeout, pfunc, enhstat) 2231 MAILER *m; 2232 MCI *mci; 2233 ENVELOPE *e; 2234 time_t timeout; 2235 void (*pfunc)(); 2236 char **enhstat; 2237 { 2238 register char *bufp; 2239 register int r; 2240 bool firstline = TRUE; 2241 char junkbuf[MAXLINE]; 2242 static char enhstatcode[ENHSCLEN]; 2243 int save_errno; 2244 2245 if (mci->mci_out != NULL) 2246 (void) fflush(mci->mci_out); 2247 2248 if (tTd(18, 1)) 2249 dprintf("reply\n"); 2250 2251 /* 2252 ** Read the input line, being careful not to hang. 2253 */ 2254 2255 bufp = SmtpReplyBuffer; 2256 for (;;) 2257 { 2258 register char *p; 2259 2260 /* actually do the read */ 2261 if (e->e_xfp != NULL) 2262 (void) fflush(e->e_xfp); /* for debugging */ 2263 2264 /* if we are in the process of closing just give the code */ 2265 if (mci->mci_state == MCIS_CLOSED) 2266 return SMTPCLOSING; 2267 2268 if (mci->mci_out != NULL) 2269 (void) fflush(mci->mci_out); 2270 2271 /* get the line from the other side */ 2272 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 2273 mci->mci_lastuse = curtime(); 2274 2275 if (p == NULL) 2276 { 2277 bool oldholderrs; 2278 extern char MsgBuf[]; 2279 2280 /* if the remote end closed early, fake an error */ 2281 if (errno == 0) 2282 # ifdef ECONNRESET 2283 errno = ECONNRESET; 2284 # else /* ECONNRESET */ 2285 errno = EPIPE; 2286 # endif /* ECONNRESET */ 2287 2288 mci->mci_errno = errno; 2289 oldholderrs = HoldErrs; 2290 HoldErrs = TRUE; 2291 usrerr("451 4.4.1 reply: read error from %s", 2292 CurHostName == NULL ? "NO_HOST" : CurHostName); 2293 2294 /* errors on QUIT should not be persistent */ 2295 if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0) 2296 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf); 2297 2298 /* if debugging, pause so we can see state */ 2299 if (tTd(18, 100)) 2300 (void) pause(); 2301 mci->mci_state = MCIS_ERROR; 2302 save_errno = errno; 2303 smtpquit(m, mci, e); 2304 # if XDEBUG 2305 { 2306 char wbuf[MAXLINE]; 2307 int wbufleft = sizeof wbuf; 2308 2309 p = wbuf; 2310 if (e->e_to != NULL) 2311 { 2312 int plen; 2313 2314 snprintf(p, wbufleft, "%s... ", 2315 shortenstring(e->e_to, MAXSHORTSTR)); 2316 plen = strlen(p); 2317 p += plen; 2318 wbufleft -= plen; 2319 } 2320 snprintf(p, wbufleft, "reply(%.100s) during %s", 2321 CurHostName == NULL ? "NO_HOST" : CurHostName, 2322 SmtpPhase); 2323 checkfd012(wbuf); 2324 } 2325 # endif /* XDEBUG */ 2326 errno = save_errno; 2327 HoldErrs = oldholderrs; 2328 return -1; 2329 } 2330 fixcrlf(bufp, TRUE); 2331 2332 /* EHLO failure is not a real error */ 2333 if (e->e_xfp != NULL && (bufp[0] == '4' || 2334 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 2335 { 2336 /* serious error -- log the previous command */ 2337 if (SmtpNeedIntro) 2338 { 2339 /* inform user who we are chatting with */ 2340 fprintf(CurEnv->e_xfp, 2341 "... while talking to %s:\n", 2342 CurHostName == NULL ? "NO_HOST" : CurHostName); 2343 SmtpNeedIntro = FALSE; 2344 } 2345 if (SmtpMsgBuffer[0] != '\0') 2346 fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 2347 SmtpMsgBuffer[0] = '\0'; 2348 2349 /* now log the message as from the other side */ 2350 fprintf(e->e_xfp, "<<< %s\n", bufp); 2351 } 2352 2353 /* display the input for verbose mode */ 2354 if (Verbose) 2355 nmessage("050 %s", bufp); 2356 2357 /* ignore improperly formatted input */ 2358 if (!ISSMTPREPLY(bufp)) 2359 continue; 2360 2361 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 2362 enhstat != NULL && 2363 extenhsc(bufp + 4, ' ', enhstatcode) > 0) 2364 *enhstat = enhstatcode; 2365 2366 /* process the line */ 2367 if (pfunc != NULL) 2368 (*pfunc)(bufp, firstline, m, mci, e); 2369 2370 firstline = FALSE; 2371 2372 /* decode the reply code */ 2373 r = atoi(bufp); 2374 2375 /* extra semantics: 0xx codes are "informational" */ 2376 if (r < 100) 2377 continue; 2378 2379 /* if no continuation lines, return this line */ 2380 if (bufp[3] != '-') 2381 break; 2382 2383 /* first line of real reply -- ignore rest */ 2384 bufp = junkbuf; 2385 } 2386 2387 /* 2388 ** Now look at SmtpReplyBuffer -- only care about the first 2389 ** line of the response from here on out. 2390 */ 2391 2392 /* save temporary failure messages for posterity */ 2393 if (SmtpReplyBuffer[0] == '4' && 2394 (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0')) 2395 snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer); 2396 2397 /* reply code 421 is "Service Shutting Down" */ 2398 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 2399 { 2400 /* send the quit protocol */ 2401 mci->mci_state = MCIS_SSD; 2402 smtpquit(m, mci, e); 2403 } 2404 2405 return r; 2406 } 2407 /* 2408 ** SMTPMESSAGE -- send message to server 2409 ** 2410 ** Parameters: 2411 ** f -- format 2412 ** m -- the mailer to control formatting. 2413 ** a, b, c -- parameters 2414 ** 2415 ** Returns: 2416 ** none. 2417 ** 2418 ** Side Effects: 2419 ** writes message to mci->mci_out. 2420 */ 2421 2422 /*VARARGS1*/ 2423 void 2424 # ifdef __STDC__ 2425 smtpmessage(char *f, MAILER *m, MCI *mci, ...) 2426 # else /* __STDC__ */ 2427 smtpmessage(f, m, mci, va_alist) 2428 char *f; 2429 MAILER *m; 2430 MCI *mci; 2431 va_dcl 2432 # endif /* __STDC__ */ 2433 { 2434 VA_LOCAL_DECL 2435 2436 VA_START(mci); 2437 (void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap); 2438 VA_END; 2439 2440 if (tTd(18, 1) || Verbose) 2441 nmessage(">>> %s", SmtpMsgBuffer); 2442 if (TrafficLogFile != NULL) 2443 fprintf(TrafficLogFile, "%05d >>> %s\n", 2444 (int) getpid(), SmtpMsgBuffer); 2445 if (mci->mci_out != NULL) 2446 { 2447 fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 2448 m == NULL ? "\r\n" : m->m_eol); 2449 } 2450 else if (tTd(18, 1)) 2451 { 2452 dprintf("smtpmessage: NULL mci_out\n"); 2453 } 2454 } 2455 2456 #endif /* SMTP */ 2457