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