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