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.437.2.5 2002/08/16 16:48:11 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 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 (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 # if SASL < 20000 607 char *out; 608 # endif /* SASL < 20000 */ 609 610 /* if not a continue we don't care about it */ 611 len = strlen(line); 612 if ((len <= 4) || 613 (line[0] != '3') || 614 !isascii(line[1]) || !isdigit(line[1]) || 615 !isascii(line[2]) || !isdigit(line[2])) 616 { 617 SM_FREE_CLR(mci->mci_sasl_string); 618 return; 619 } 620 621 /* forget about "334 " */ 622 line += 4; 623 len -= 4; 624 # if SASL >= 20000 625 /* XXX put this into a macro/function? It's duplicated below */ 626 if (mci->mci_sasl_string != NULL) 627 { 628 if (mci->mci_sasl_string_len <= len) 629 { 630 sm_free(mci->mci_sasl_string); /* XXX */ 631 mci->mci_sasl_string = xalloc(len + 1); 632 } 633 } 634 else 635 mci->mci_sasl_string = xalloc(len + 1); 636 637 result = sasl_decode64(line, len, mci->mci_sasl_string, len + 1, 638 (unsigned int *) &mci->mci_sasl_string_len); 639 if (result != SASL_OK) 640 { 641 mci->mci_sasl_string_len = 0; 642 *mci->mci_sasl_string = '\0'; 643 } 644 # else /* SASL >= 20000 */ 645 out = (char *) sm_rpool_malloc_x(mci->mci_rpool, len + 1); 646 result = sasl_decode64(line, len, out, (unsigned int *) &len); 647 if (result != SASL_OK) 648 { 649 len = 0; 650 *out = '\0'; 651 } 652 653 /* 654 ** mci_sasl_string is "shared" with Cyrus-SASL library; hence 655 ** it can't be in an rpool unless we use the same memory 656 ** management mechanism (with same rpool!) for Cyrus SASL. 657 */ 658 659 if (mci->mci_sasl_string != NULL) 660 { 661 if (mci->mci_sasl_string_len <= len) 662 { 663 sm_free(mci->mci_sasl_string); /* XXX */ 664 mci->mci_sasl_string = xalloc(len + 1); 665 } 666 } 667 else 668 mci->mci_sasl_string = xalloc(len + 1); 669 670 memcpy(mci->mci_sasl_string, out, len); 671 mci->mci_sasl_string[len] = '\0'; 672 mci->mci_sasl_string_len = len; 673 # endif /* SASL >= 20000 */ 674 return; 675 } 676 /* 677 ** READAUTH -- read auth values from a file 678 ** 679 ** Parameters: 680 ** filename -- name of file to read. 681 ** safe -- if set, this is a safe read. 682 ** sai -- where to store auth_info. 683 ** rpool -- resource pool for sai. 684 ** 685 ** Returns: 686 ** EX_OK -- data succesfully read. 687 ** EX_UNAVAILABLE -- no valid filename. 688 ** EX_TEMPFAIL -- temporary failure. 689 */ 690 691 static char *sasl_info_name[] = 692 { 693 "user id", 694 "authentication id", 695 "password", 696 "realm", 697 "mechlist" 698 }; 699 static int 700 readauth(filename, safe, sai, rpool) 701 char *filename; 702 bool safe; 703 SASL_AI_T *sai; 704 SM_RPOOL_T *rpool; 705 { 706 SM_FILE_T *f; 707 long sff; 708 pid_t pid; 709 int lc; 710 char *s; 711 char buf[MAXLINE]; 712 713 if (filename == NULL || filename[0] == '\0') 714 return EX_UNAVAILABLE; 715 716 #if !_FFR_ALLOW_SASLINFO 717 /* 718 ** make sure we don't use a program that is not 719 ** accesible to the user who specified a different authinfo file. 720 ** However, currently we don't pass this info (authinfo file 721 ** specified by user) around, so we just turn off program access. 722 */ 723 724 if (filename[0] == '|') 725 { 726 auto int fd; 727 int i; 728 char *p; 729 char *argv[MAXPV + 1]; 730 731 i = 0; 732 for (p = strtok(&filename[1], " \t"); p != NULL; 733 p = strtok(NULL, " \t")) 734 { 735 if (i >= MAXPV) 736 break; 737 argv[i++] = p; 738 } 739 argv[i] = NULL; 740 pid = prog_open(argv, &fd, CurEnv); 741 if (pid < 0) 742 f = NULL; 743 else 744 f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 745 (void *) &fd, SM_IO_RDONLY, NULL); 746 } 747 else 748 #endif /* !_FFR_ALLOW_SASLINFO */ 749 { 750 pid = -1; 751 sff = SFF_REGONLY|SFF_SAFEDIRPATH|SFF_NOWLINK 752 |SFF_NOGWFILES|SFF_NOWWFILES|SFF_NOWRFILES; 753 # if _FFR_GROUPREADABLEAUTHINFOFILE 754 if (!bitnset(DBS_GROUPREADABLEAUTHINFOFILE, DontBlameSendmail)) 755 # endif /* _FFR_GROUPREADABLEAUTHINFOFILE */ 756 sff |= SFF_NOGRFILES; 757 if (DontLockReadFiles) 758 sff |= SFF_NOLOCK; 759 760 #if _FFR_ALLOW_SASLINFO 761 /* 762 ** XXX: make sure we don't read or open files that are not 763 ** accesible to the user who specified a different authinfo 764 ** file. 765 */ 766 767 sff |= SFF_MUSTOWN; 768 #else /* _FFR_ALLOW_SASLINFO */ 769 if (safe) 770 sff |= SFF_OPENASROOT; 771 #endif /* _FFR_ALLOW_SASLINFO */ 772 773 f = safefopen(filename, O_RDONLY, 0, sff); 774 } 775 if (f == NULL) 776 { 777 if (LogLevel > 5) 778 sm_syslog(LOG_ERR, NOQID, 779 "AUTH=client, error: can't open %s: %s", 780 filename, sm_errstring(errno)); 781 return EX_TEMPFAIL; 782 } 783 784 lc = 0; 785 while (lc <= SASL_MECHLIST && 786 sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 787 { 788 if (buf[0] != '#') 789 { 790 (*sai)[lc] = sm_rpool_strdup_x(rpool, buf); 791 if ((s = strchr((*sai)[lc], '\n')) != NULL) 792 *s = '\0'; 793 lc++; 794 } 795 } 796 797 (void) sm_io_close(f, SM_TIME_DEFAULT); 798 if (pid > 0) 799 (void) waitfor(pid); 800 if (lc < SASL_PASSWORD) 801 { 802 if (LogLevel > 8) 803 sm_syslog(LOG_ERR, NOQID, 804 "AUTH=client, error: can't read %s from %s", 805 sasl_info_name[lc + 1], filename); 806 return EX_TEMPFAIL; 807 } 808 return EX_OK; 809 } 810 811 /* 812 ** GETAUTH -- get authinfo from ruleset call 813 ** 814 ** {server_name}, {server_addr} must be set 815 ** 816 ** Parameters: 817 ** mci -- the mailer connection structure. 818 ** e -- the envelope (including the sender to specify). 819 ** sai -- pointer to authinfo (result). 820 ** 821 ** Returns: 822 ** EX_OK -- ruleset was succesfully called, data may not 823 ** be available, sai must be checked. 824 ** EX_UNAVAILABLE -- ruleset unavailable (or failed). 825 ** EX_TEMPFAIL -- temporary failure (from ruleset). 826 ** 827 ** Side Effects: 828 ** Fills in sai if successful. 829 */ 830 831 static int 832 getauth(mci, e, sai) 833 MCI *mci; 834 ENVELOPE *e; 835 SASL_AI_T *sai; 836 { 837 int i, r, l, got, ret; 838 char **pvp; 839 char pvpbuf[PSBUFSIZE]; 840 841 r = rscap("authinfo", macvalue(macid("{server_name}"), e), 842 macvalue(macid("{server_addr}"), e), e, 843 &pvp, pvpbuf, sizeof(pvpbuf)); 844 845 if (r != EX_OK) 846 return EX_UNAVAILABLE; 847 848 /* other than expected return value: ok (i.e., no auth) */ 849 if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 850 return EX_OK; 851 if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0) 852 return EX_TEMPFAIL; 853 854 /* 855 ** parse the data, put it into sai 856 ** format: "TDstring" (including the '"' !) 857 ** where T is a tag: 'U', ... 858 ** D is a delimiter: ':' or '=' 859 */ 860 861 ret = EX_OK; /* default return value */ 862 i = 0; 863 got = 0; 864 while (i < SASL_ENTRIES) 865 { 866 if (pvp[i + 1] == NULL) 867 break; 868 if (pvp[i + 1][0] != '"') 869 break; 870 switch (pvp[i + 1][1]) 871 { 872 case 'U': 873 case 'u': 874 r = SASL_USER; 875 break; 876 case 'I': 877 case 'i': 878 r = SASL_AUTHID; 879 break; 880 case 'P': 881 case 'p': 882 r = SASL_PASSWORD; 883 break; 884 case 'R': 885 case 'r': 886 r = SASL_DEFREALM; 887 break; 888 case 'M': 889 case 'm': 890 r = SASL_MECHLIST; 891 break; 892 default: 893 goto fail; 894 } 895 l = strlen(pvp[i + 1]); 896 897 /* check syntax */ 898 if (l <= 3 || pvp[i + 1][l - 1] != '"') 899 goto fail; 900 901 /* remove closing quote */ 902 pvp[i + 1][l - 1] = '\0'; 903 904 /* remove "TD and " */ 905 l -= 4; 906 (*sai)[r] = (char *) sm_rpool_malloc(mci->mci_rpool, l + 1); 907 if ((*sai)[r] == NULL) 908 goto tempfail; 909 if (pvp[i + 1][2] == ':') 910 { 911 /* ':text' (just copy) */ 912 (void) sm_strlcpy((*sai)[r], pvp[i + 1] + 3, l + 1); 913 got |= 1 << r; 914 } 915 else if (pvp[i + 1][2] == '=') 916 { 917 unsigned int len; 918 919 /* '=base64' (decode) */ 920 # if SASL >= 20000 921 ret = sasl_decode64(pvp[i + 1] + 3, 922 (unsigned int) l, (*sai)[r], 923 (unsigned int) l + 1, &len); 924 # else /* SASL >= 20000 */ 925 ret = sasl_decode64(pvp[i + 1] + 3, 926 (unsigned int) l, (*sai)[r], &len); 927 # endif /* SASL >= 20000 */ 928 if (ret != SASL_OK) 929 goto fail; 930 got |= 1 << r; 931 } 932 else 933 goto fail; 934 if (tTd(95, 5)) 935 sm_syslog(LOG_DEBUG, NOQID, "getauth %s=%s", 936 sasl_info_name[r], (*sai)[r]); 937 ++i; 938 } 939 940 /* did we get the expected data? */ 941 /* XXX: EXTERNAL mechanism only requires (and only uses) SASL_USER */ 942 if (!(bitset(SASL_USER_BIT|SASL_AUTHID_BIT, got) && 943 bitset(SASL_PASSWORD_BIT, got))) 944 goto fail; 945 946 /* no authid? copy uid */ 947 if (!bitset(SASL_AUTHID_BIT, got)) 948 { 949 l = strlen((*sai)[SASL_USER]) + 1; 950 (*sai)[SASL_AUTHID] = (char *) sm_rpool_malloc(mci->mci_rpool, 951 l + 1); 952 if ((*sai)[SASL_AUTHID] == NULL) 953 goto tempfail; 954 (void) sm_strlcpy((*sai)[SASL_AUTHID], (*sai)[SASL_USER], l); 955 } 956 957 /* no uid? copy authid */ 958 if (!bitset(SASL_USER_BIT, got)) 959 { 960 l = strlen((*sai)[SASL_AUTHID]) + 1; 961 (*sai)[SASL_USER] = (char *) sm_rpool_malloc(mci->mci_rpool, 962 l + 1); 963 if ((*sai)[SASL_USER] == NULL) 964 goto tempfail; 965 (void) sm_strlcpy((*sai)[SASL_USER], (*sai)[SASL_AUTHID], l); 966 } 967 return EX_OK; 968 969 tempfail: 970 ret = EX_TEMPFAIL; 971 fail: 972 if (LogLevel > 8) 973 sm_syslog(LOG_WARNING, NOQID, 974 "AUTH=client, relay=%.64s [%.16s], authinfo %sfailed", 975 macvalue(macid("{server_name}"), e), 976 macvalue(macid("{server_addr}"), e), 977 ret == EX_TEMPFAIL ? "temp" : ""); 978 for (i = 0; i <= SASL_MECHLIST; i++) 979 (*sai)[i] = NULL; /* just clear; rpool */ 980 return ret; 981 } 982 983 # if SASL >= 20000 984 /* 985 ** GETSIMPLE -- callback to get userid or authid 986 ** 987 ** Parameters: 988 ** context -- sai 989 ** id -- what to do 990 ** result -- (pointer to) result 991 ** len -- (pointer to) length of result 992 ** 993 ** Returns: 994 ** OK/failure values 995 */ 996 997 static int 998 getsimple(context, id, result, len) 999 void *context; 1000 int id; 1001 const char **result; 1002 unsigned *len; 1003 { 1004 SASL_AI_T *sai; 1005 1006 if (result == NULL || context == NULL) 1007 return SASL_BADPARAM; 1008 sai = (SASL_AI_T *) context; 1009 1010 switch (id) 1011 { 1012 case SASL_CB_USER: 1013 *result = (*sai)[SASL_USER]; 1014 if (tTd(95, 5)) 1015 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'", 1016 *result); 1017 if (len != NULL) 1018 *len = *result != NULL ? strlen(*result) : 0; 1019 break; 1020 1021 case SASL_CB_AUTHNAME: 1022 *result = (*sai)[SASL_AUTHID]; 1023 if (tTd(95, 5)) 1024 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'", 1025 *result); 1026 if (len != NULL) 1027 *len = *result != NULL ? strlen(*result) : 0; 1028 break; 1029 1030 case SASL_CB_LANGUAGE: 1031 *result = NULL; 1032 if (len != NULL) 1033 *len = 0; 1034 break; 1035 1036 default: 1037 return SASL_BADPARAM; 1038 } 1039 return SASL_OK; 1040 } 1041 /* 1042 ** GETSECRET -- callback to get password 1043 ** 1044 ** Parameters: 1045 ** conn -- connection information 1046 ** context -- sai 1047 ** id -- what to do 1048 ** psecret -- (pointer to) result 1049 ** 1050 ** Returns: 1051 ** OK/failure values 1052 */ 1053 1054 static int 1055 getsecret(conn, context, id, psecret) 1056 sasl_conn_t *conn; 1057 SM_UNUSED(void *context); 1058 int id; 1059 sasl_secret_t **psecret; 1060 { 1061 int len; 1062 char *authpass; 1063 MCI *mci; 1064 1065 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS) 1066 return SASL_BADPARAM; 1067 1068 mci = (MCI *) context; 1069 authpass = mci->mci_sai[SASL_PASSWORD]; 1070 len = strlen(authpass); 1071 1072 /* 1073 ** use an rpool because we are responsible for free()ing the secret, 1074 ** but we can't free() it until after the auth completes 1075 */ 1076 1077 *psecret = (sasl_secret_t *) sm_rpool_malloc(mci->mci_rpool, 1078 sizeof(sasl_secret_t) + 1079 len + 1); 1080 if (*psecret == NULL) 1081 return SASL_FAIL; 1082 (void) sm_strlcpy((*psecret)->data, authpass, len + 1); 1083 (*psecret)->len = (unsigned long) len; 1084 return SASL_OK; 1085 } 1086 # else /* SASL >= 20000 */ 1087 /* 1088 ** GETSIMPLE -- callback to get userid or authid 1089 ** 1090 ** Parameters: 1091 ** context -- sai 1092 ** id -- what to do 1093 ** result -- (pointer to) result 1094 ** len -- (pointer to) length of result 1095 ** 1096 ** Returns: 1097 ** OK/failure values 1098 */ 1099 1100 static int 1101 getsimple(context, id, result, len) 1102 void *context; 1103 int id; 1104 const char **result; 1105 unsigned *len; 1106 { 1107 char *h, *s; 1108 # if SASL > 10509 1109 bool addrealm; 1110 # endif /* SASL > 10509 */ 1111 size_t l; 1112 SASL_AI_T *sai; 1113 char *authid = NULL; 1114 1115 if (result == NULL || context == NULL) 1116 return SASL_BADPARAM; 1117 sai = (SASL_AI_T *) context; 1118 1119 /* 1120 ** Unfortunately it is not clear whether this routine should 1121 ** return a copy of a string or just a pointer to a string. 1122 ** The Cyrus-SASL plugins treat these return values differently, e.g., 1123 ** plugins/cram.c free()s authid, plugings/digestmd5.c does not. 1124 ** The best solution to this problem is to fix Cyrus-SASL, but it 1125 ** seems there is nobody who creates patches... Hello CMU!? 1126 ** The second best solution is to have flags that tell this routine 1127 ** whether to return an malloc()ed copy. 1128 ** The next best solution is to always return an malloc()ed copy, 1129 ** and suffer from some memory leak, which is ugly for persistent 1130 ** queue runners. 1131 ** For now we go with the last solution... 1132 ** We can't use rpools (which would avoid this particular problem) 1133 ** as explained in sasl.c. 1134 */ 1135 1136 switch (id) 1137 { 1138 case SASL_CB_USER: 1139 l = strlen((*sai)[SASL_USER]) + 1; 1140 s = sm_sasl_malloc(l); 1141 if (s == NULL) 1142 { 1143 if (len != NULL) 1144 *len = 0; 1145 *result = NULL; 1146 return SASL_NOMEM; 1147 } 1148 (void) sm_strlcpy(s, (*sai)[SASL_USER], l); 1149 *result = s; 1150 if (tTd(95, 5)) 1151 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'", 1152 *result); 1153 if (len != NULL) 1154 *len = *result != NULL ? strlen(*result) : 0; 1155 break; 1156 1157 case SASL_CB_AUTHNAME: 1158 h = (*sai)[SASL_AUTHID]; 1159 # if SASL > 10509 1160 /* XXX maybe other mechanisms too?! */ 1161 addrealm = (*sai)[SASL_MECH] != NULL && 1162 sm_strcasecmp((*sai)[SASL_MECH], "CRAM-MD5") == 0; 1163 1164 /* 1165 ** Add realm to authentication id unless authid contains 1166 ** '@' (i.e., a realm) or the default realm is empty. 1167 */ 1168 1169 if (addrealm && h != NULL && strchr(h, '@') == NULL) 1170 { 1171 /* has this been done before? */ 1172 if ((*sai)[SASL_ID_REALM] == NULL) 1173 { 1174 char *realm; 1175 1176 realm = (*sai)[SASL_DEFREALM]; 1177 1178 /* do not add an empty realm */ 1179 if (*realm == '\0') 1180 { 1181 authid = h; 1182 (*sai)[SASL_ID_REALM] = NULL; 1183 } 1184 else 1185 { 1186 l = strlen(h) + strlen(realm) + 2; 1187 1188 /* should use rpool, but from where? */ 1189 authid = sm_sasl_malloc(l); 1190 if (authid != NULL) 1191 { 1192 (void) sm_snprintf(authid, l, 1193 "%s@%s", 1194 h, realm); 1195 (*sai)[SASL_ID_REALM] = authid; 1196 } 1197 else 1198 { 1199 authid = h; 1200 (*sai)[SASL_ID_REALM] = NULL; 1201 } 1202 } 1203 } 1204 else 1205 authid = (*sai)[SASL_ID_REALM]; 1206 } 1207 else 1208 # endif /* SASL > 10509 */ 1209 authid = h; 1210 l = strlen(authid) + 1; 1211 s = sm_sasl_malloc(l); 1212 if (s == NULL) 1213 { 1214 if (len != NULL) 1215 *len = 0; 1216 *result = NULL; 1217 return SASL_NOMEM; 1218 } 1219 (void) sm_strlcpy(s, authid, l); 1220 *result = s; 1221 if (tTd(95, 5)) 1222 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'", 1223 *result); 1224 if (len != NULL) 1225 *len = authid ? strlen(authid) : 0; 1226 break; 1227 1228 case SASL_CB_LANGUAGE: 1229 *result = NULL; 1230 if (len != NULL) 1231 *len = 0; 1232 break; 1233 1234 default: 1235 return SASL_BADPARAM; 1236 } 1237 return SASL_OK; 1238 } 1239 /* 1240 ** GETSECRET -- callback to get password 1241 ** 1242 ** Parameters: 1243 ** conn -- connection information 1244 ** context -- sai 1245 ** id -- what to do 1246 ** psecret -- (pointer to) result 1247 ** 1248 ** Returns: 1249 ** OK/failure values 1250 */ 1251 1252 static int 1253 getsecret(conn, context, id, psecret) 1254 sasl_conn_t *conn; 1255 SM_UNUSED(void *context); 1256 int id; 1257 sasl_secret_t **psecret; 1258 { 1259 int len; 1260 char *authpass; 1261 SASL_AI_T *sai; 1262 1263 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS) 1264 return SASL_BADPARAM; 1265 1266 sai = (SASL_AI_T *) context; 1267 authpass = (*sai)[SASL_PASSWORD]; 1268 len = strlen(authpass); 1269 *psecret = (sasl_secret_t *) sm_sasl_malloc(sizeof(sasl_secret_t) + 1270 len + 1); 1271 if (*psecret == NULL) 1272 return SASL_FAIL; 1273 (void) sm_strlcpy((*psecret)->data, authpass, len + 1); 1274 (*psecret)->len = (unsigned long) len; 1275 return SASL_OK; 1276 } 1277 # endif /* SASL >= 20000 */ 1278 1279 /* 1280 ** SAFESASLFILE -- callback for sasl: is file safe? 1281 ** 1282 ** Parameters: 1283 ** context -- pointer to context between invocations (unused) 1284 ** file -- name of file to check 1285 ** type -- type of file to check 1286 ** 1287 ** Returns: 1288 ** SASL_OK -- file can be used 1289 ** SASL_CONTINUE -- don't use file 1290 ** SASL_FAIL -- failure (not used here) 1291 ** 1292 */ 1293 1294 int 1295 #if SASL > 10515 1296 safesaslfile(context, file, type) 1297 #else /* SASL > 10515 */ 1298 safesaslfile(context, file) 1299 #endif /* SASL > 10515 */ 1300 void *context; 1301 # if SASL >= 20000 1302 const char *file; 1303 # else /* SASL >= 20000 */ 1304 char *file; 1305 # endif /* SASL >= 20000 */ 1306 #if SASL > 10515 1307 # if SASL >= 20000 1308 sasl_verify_type_t type; 1309 # else /* SASL >= 20000 */ 1310 int type; 1311 # endif /* SASL >= 20000 */ 1312 #endif /* SASL > 10515 */ 1313 { 1314 long sff; 1315 int r; 1316 #if SASL <= 10515 1317 size_t len; 1318 #endif /* SASL <= 10515 */ 1319 char *p; 1320 1321 if (file == NULL || *file == '\0') 1322 return SASL_OK; 1323 sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOWWFILES|SFF_ROOTOK; 1324 #if SASL <= 10515 1325 if ((p = strrchr(file, '/')) == NULL) 1326 p = file; 1327 else 1328 ++p; 1329 1330 /* everything beside libs and .conf files must not be readable */ 1331 len = strlen(p); 1332 if ((len <= 3 || strncmp(p, "lib", 3) != 0) && 1333 (len <= 5 || strncmp(p + len - 5, ".conf", 5) != 0)) 1334 { 1335 if (!bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail)) 1336 sff |= SFF_NORFILES; 1337 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail)) 1338 sff |= SFF_NOGWFILES; 1339 } 1340 #else /* SASL <= 10515 */ 1341 /* files containing passwords should be not readable */ 1342 if (type == SASL_VRFY_PASSWD) 1343 { 1344 if (bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail)) 1345 sff |= SFF_NOWRFILES; 1346 else 1347 sff |= SFF_NORFILES; 1348 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail)) 1349 sff |= SFF_NOGWFILES; 1350 } 1351 #endif /* SASL <= 10515 */ 1352 1353 p = (char *) file; 1354 if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff, 1355 S_IRUSR, NULL)) == 0) 1356 return SASL_OK; 1357 if (LogLevel > (r != ENOENT ? 8 : 10)) 1358 sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s", 1359 p, sm_errstring(r)); 1360 return SASL_CONTINUE; 1361 } 1362 1363 /* 1364 ** SASLGETREALM -- return the realm for SASL 1365 ** 1366 ** return the realm for the client 1367 ** 1368 ** Parameters: 1369 ** context -- context shared between invocations 1370 ** availrealms -- list of available realms 1371 ** {realm, realm, ...} 1372 ** result -- pointer to result 1373 ** 1374 ** Returns: 1375 ** failure/success 1376 */ 1377 1378 static int 1379 saslgetrealm(context, id, availrealms, result) 1380 void *context; 1381 int id; 1382 const char **availrealms; 1383 const char **result; 1384 { 1385 char *r; 1386 SASL_AI_T *sai; 1387 1388 sai = (SASL_AI_T *) context; 1389 if (sai == NULL) 1390 return SASL_FAIL; 1391 r = (*sai)[SASL_DEFREALM]; 1392 1393 if (LogLevel > 12) 1394 sm_syslog(LOG_INFO, NOQID, 1395 "AUTH=client, realm=%s, available realms=%s", 1396 r == NULL ? "<No Realm>" : r, 1397 (availrealms == NULL || *availrealms == NULL) 1398 ? "<No Realms>" : *availrealms); 1399 1400 /* check whether context is in list */ 1401 if (availrealms != NULL && *availrealms != NULL) 1402 { 1403 if (iteminlist(context, (char *)(*availrealms + 1), " ,}") == 1404 NULL) 1405 { 1406 if (LogLevel > 8) 1407 sm_syslog(LOG_ERR, NOQID, 1408 "AUTH=client, realm=%s not in list=%s", 1409 r, *availrealms); 1410 return SASL_FAIL; 1411 } 1412 } 1413 *result = r; 1414 return SASL_OK; 1415 } 1416 /* 1417 ** ITEMINLIST -- does item appear in list? 1418 ** 1419 ** Check whether item appears in list (which must be separated by a 1420 ** character in delim) as a "word", i.e. it must appear at the begin 1421 ** of the list or after a space, and it must end with a space or the 1422 ** end of the list. 1423 ** 1424 ** Parameters: 1425 ** item -- item to search. 1426 ** list -- list of items. 1427 ** delim -- list of delimiters. 1428 ** 1429 ** Returns: 1430 ** pointer to occurrence (NULL if not found). 1431 */ 1432 1433 char * 1434 iteminlist(item, list, delim) 1435 char *item; 1436 char *list; 1437 char *delim; 1438 { 1439 char *s; 1440 int len; 1441 1442 if (list == NULL || *list == '\0') 1443 return NULL; 1444 if (item == NULL || *item == '\0') 1445 return NULL; 1446 s = list; 1447 len = strlen(item); 1448 while (s != NULL && *s != '\0') 1449 { 1450 if (sm_strncasecmp(s, item, len) == 0 && 1451 (s[len] == '\0' || strchr(delim, s[len]) != NULL)) 1452 return s; 1453 s = strpbrk(s, delim); 1454 if (s != NULL) 1455 while (*++s == ' ') 1456 continue; 1457 } 1458 return NULL; 1459 } 1460 /* 1461 ** REMOVEMECH -- remove item [rem] from list [list] 1462 ** 1463 ** Parameters: 1464 ** rem -- item to remove 1465 ** list -- list of items 1466 ** rpool -- resource pool from which result is allocated. 1467 ** 1468 ** Returns: 1469 ** pointer to new list (NULL in case of error). 1470 */ 1471 1472 static char * 1473 removemech(rem, list, rpool) 1474 char *rem; 1475 char *list; 1476 SM_RPOOL_T *rpool; 1477 { 1478 char *ret; 1479 char *needle; 1480 int len; 1481 1482 if (list == NULL) 1483 return NULL; 1484 if (rem == NULL || *rem == '\0') 1485 { 1486 /* take out what? */ 1487 return NULL; 1488 } 1489 1490 /* find the item in the list */ 1491 if ((needle = iteminlist(rem, list, " ")) == NULL) 1492 { 1493 /* not in there: return original */ 1494 return list; 1495 } 1496 1497 /* length of string without rem */ 1498 len = strlen(list) - strlen(rem); 1499 if (len <= 0) 1500 { 1501 ret = (char *) sm_rpool_malloc_x(rpool, 1); 1502 *ret = '\0'; 1503 return ret; 1504 } 1505 ret = (char *) sm_rpool_malloc_x(rpool, len); 1506 memset(ret, '\0', len); 1507 1508 /* copy from start to removed item */ 1509 memcpy(ret, list, needle - list); 1510 1511 /* length of rest of string past removed item */ 1512 len = strlen(needle) - strlen(rem) - 1; 1513 if (len > 0) 1514 { 1515 /* not last item -- copy into string */ 1516 memcpy(ret + (needle - list), 1517 list + (needle - list) + strlen(rem) + 1, 1518 len); 1519 } 1520 else 1521 ret[(needle - list) - 1] = '\0'; 1522 return ret; 1523 } 1524 /* 1525 ** ATTEMPTAUTH -- try to AUTHenticate using one mechanism 1526 ** 1527 ** Parameters: 1528 ** m -- the mailer. 1529 ** mci -- the mailer connection structure. 1530 ** e -- the envelope (including the sender to specify). 1531 ** sai - sasl authinfo 1532 ** 1533 ** Returns: 1534 ** EX_OK -- authentication was successful. 1535 ** EX_NOPERM -- authentication failed. 1536 ** EX_IOERR -- authentication dialogue failed (I/O problem?). 1537 ** EX_TEMPFAIL -- temporary failure. 1538 ** 1539 */ 1540 1541 static int 1542 attemptauth(m, mci, e, sai) 1543 MAILER *m; 1544 MCI *mci; 1545 ENVELOPE *e; 1546 SASL_AI_T *sai; 1547 { 1548 int saslresult, smtpresult; 1549 # if SASL >= 20000 1550 sasl_ssf_t ssf; 1551 const char *auth_id; 1552 const char *out; 1553 # else /* SASL >= 20000 */ 1554 sasl_external_properties_t ssf; 1555 char *out; 1556 # endif /* SASL >= 20000 */ 1557 unsigned int outlen; 1558 sasl_interact_t *client_interact = NULL; 1559 char *mechusing; 1560 sasl_security_properties_t ssp; 1561 char in64[MAXOUTLEN]; 1562 #if NETINET || (NETINET6 && SASL >= 20000) 1563 extern SOCKADDR CurHostAddr; 1564 #endif /* NETINET || (NETINET6 && SASL >= 20000) */ 1565 1566 /* no mechanism selected (yet) */ 1567 (*sai)[SASL_MECH] = NULL; 1568 1569 /* dispose old connection */ 1570 if (mci->mci_conn != NULL) 1571 sasl_dispose(&(mci->mci_conn)); 1572 1573 /* make a new client sasl connection */ 1574 # if SASL >= 20000 1575 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp" 1576 : "smtp", 1577 CurHostName, NULL, NULL, NULL, 0, 1578 &mci->mci_conn); 1579 # else /* SASL >= 20000 */ 1580 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp" 1581 : "smtp", 1582 CurHostName, NULL, 0, &mci->mci_conn); 1583 # endif /* SASL >= 20000 */ 1584 if (saslresult != SASL_OK) 1585 return EX_TEMPFAIL; 1586 1587 /* set properties */ 1588 (void) memset(&ssp, '\0', sizeof ssp); 1589 1590 /* XXX should these be options settable via .cf ? */ 1591 # if STARTTLS 1592 #endif /* STARTTLS */ 1593 { 1594 ssp.max_ssf = MaxSLBits; 1595 ssp.maxbufsize = MAXOUTLEN; 1596 # if 0 1597 ssp.security_flags = SASL_SEC_NOPLAINTEXT; 1598 # endif /* 0 */ 1599 } 1600 saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp); 1601 if (saslresult != SASL_OK) 1602 return EX_TEMPFAIL; 1603 1604 # if SASL >= 20000 1605 /* external security strength factor, authentication id */ 1606 ssf = 0; 1607 auth_id = NULL; 1608 # if STARTTLS 1609 out = macvalue(macid("{cert_subject}"), e); 1610 if (out != NULL && *out != '\0') 1611 auth_id = out; 1612 out = macvalue(macid("{cipher_bits}"), e); 1613 if (out != NULL && *out != '\0') 1614 ssf = atoi(out); 1615 # endif /* STARTTLS */ 1616 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf); 1617 if (saslresult != SASL_OK) 1618 return EX_TEMPFAIL; 1619 saslresult = sasl_setprop(mci->mci_conn, SASL_AUTH_EXTERNAL, auth_id); 1620 if (saslresult != SASL_OK) 1621 return EX_TEMPFAIL; 1622 1623 # if NETINET || NETINET6 1624 /* set local/remote ipv4 addresses */ 1625 if (mci->mci_out != NULL && ( 1626 # if NETINET6 1627 CurHostAddr.sa.sa_family == AF_INET6 || 1628 # endif /* NETINET6 */ 1629 CurHostAddr.sa.sa_family == AF_INET)) 1630 { 1631 SOCKADDR_LEN_T addrsize; 1632 SOCKADDR saddr_l; 1633 char localip[60], remoteip[60]; 1634 1635 switch (CurHostAddr.sa.sa_family) 1636 { 1637 case AF_INET: 1638 addrsize = sizeof(struct sockaddr_in); 1639 break; 1640 # if NETINET6 1641 case AF_INET6: 1642 addrsize = sizeof(struct sockaddr_in6); 1643 break; 1644 # endif /* NETINET6 */ 1645 default: 1646 break; 1647 } 1648 if (iptostring(&CurHostAddr, addrsize, 1649 remoteip, sizeof remoteip)) 1650 { 1651 if (sasl_setprop(mci->mci_conn, SASL_IPREMOTEPORT, 1652 remoteip) != SASL_OK) 1653 return EX_TEMPFAIL; 1654 } 1655 addrsize = sizeof(saddr_l); 1656 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, 1657 NULL), 1658 (struct sockaddr *) &saddr_l, &addrsize) == 0) 1659 { 1660 if (iptostring(&saddr_l, addrsize, 1661 localip, sizeof localip)) 1662 { 1663 if (sasl_setprop(mci->mci_conn, 1664 SASL_IPLOCALPORT, 1665 localip) != SASL_OK) 1666 return EX_TEMPFAIL; 1667 } 1668 } 1669 } 1670 # endif /* NETINET || NETINET6 */ 1671 1672 /* start client side of sasl */ 1673 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap, 1674 &client_interact, 1675 &out, &outlen, 1676 (const char **) &mechusing); 1677 # else /* SASL >= 20000 */ 1678 /* external security strength factor, authentication id */ 1679 ssf.ssf = 0; 1680 ssf.auth_id = NULL; 1681 # if STARTTLS 1682 out = macvalue(macid("{cert_subject}"), e); 1683 if (out != NULL && *out != '\0') 1684 ssf.auth_id = out; 1685 out = macvalue(macid("{cipher_bits}"), e); 1686 if (out != NULL && *out != '\0') 1687 ssf.ssf = atoi(out); 1688 # endif /* STARTTLS */ 1689 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf); 1690 if (saslresult != SASL_OK) 1691 return EX_TEMPFAIL; 1692 1693 # if NETINET 1694 /* set local/remote ipv4 addresses */ 1695 if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET) 1696 { 1697 SOCKADDR_LEN_T addrsize; 1698 struct sockaddr_in saddr_l; 1699 1700 if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE, 1701 (struct sockaddr_in *) &CurHostAddr) 1702 != SASL_OK) 1703 return EX_TEMPFAIL; 1704 addrsize = sizeof(struct sockaddr_in); 1705 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, 1706 NULL), 1707 (struct sockaddr *) &saddr_l, &addrsize) == 0) 1708 { 1709 if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL, 1710 &saddr_l) != SASL_OK) 1711 return EX_TEMPFAIL; 1712 } 1713 } 1714 # endif /* NETINET */ 1715 1716 /* start client side of sasl */ 1717 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap, 1718 NULL, &client_interact, 1719 &out, &outlen, 1720 (const char **) &mechusing); 1721 # endif /* SASL >= 20000 */ 1722 1723 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE) 1724 { 1725 if (saslresult == SASL_NOMECH && LogLevel > 8) 1726 { 1727 sm_syslog(LOG_NOTICE, e->e_id, 1728 "AUTH=client, available mechanisms do not fulfill requirements"); 1729 } 1730 return EX_TEMPFAIL; 1731 } 1732 1733 /* just point current mechanism to the data in the sasl library */ 1734 (*sai)[SASL_MECH] = mechusing; 1735 1736 /* send the info across the wire */ 1737 if (out == NULL 1738 #if _FFR_SASL_INITIAL_WORKAROUND 1739 /* login and digest-md5 up to 1.5.28 set out="" */ 1740 || (outlen == 0 && 1741 (sm_strcasecmp(mechusing, "LOGIN") == 0 || 1742 sm_strcasecmp(mechusing, "DIGEST-MD5") == 0)) 1743 #endif /* _FFR_SASL_INITIAL_WORKAROUND */ 1744 ) 1745 { 1746 /* no initial response */ 1747 smtpmessage("AUTH %s", m, mci, mechusing); 1748 } 1749 else if (outlen == 0) 1750 { 1751 /* 1752 ** zero-length initial response, per RFC 2554 4.: 1753 ** "Unlike a zero-length client answer to a 334 reply, a zero- 1754 ** length initial response is sent as a single equals sign" 1755 */ 1756 1757 smtpmessage("AUTH %s =", m, mci, mechusing); 1758 } 1759 else 1760 { 1761 saslresult = sasl_encode64(out, outlen, in64, MAXOUTLEN, NULL); 1762 if (saslresult != SASL_OK) /* internal error */ 1763 { 1764 if (LogLevel > 8) 1765 sm_syslog(LOG_ERR, e->e_id, 1766 "encode64 for AUTH failed"); 1767 return EX_TEMPFAIL; 1768 } 1769 smtpmessage("AUTH %s %s", m, mci, mechusing, in64); 1770 } 1771 # if SASL < 20000 1772 sm_sasl_free(out); /* XXX only if no rpool is used */ 1773 # endif /* SASL < 20000 */ 1774 1775 /* get the reply */ 1776 smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL); 1777 1778 for (;;) 1779 { 1780 /* check return code from server */ 1781 if (smtpresult == 235) 1782 { 1783 macdefine(&mci->mci_macro, A_TEMP, macid("{auth_type}"), 1784 mechusing); 1785 return EX_OK; 1786 } 1787 if (smtpresult == -1) 1788 return EX_IOERR; 1789 if (REPLYTYPE(smtpresult) == 5) 1790 return EX_NOPERM; /* ugly, but ... */ 1791 if (REPLYTYPE(smtpresult) != 3) 1792 { 1793 /* should we fail deliberately, see RFC 2554 4. ? */ 1794 /* smtpmessage("*", m, mci); */ 1795 return EX_TEMPFAIL; 1796 } 1797 1798 saslresult = sasl_client_step(mci->mci_conn, 1799 mci->mci_sasl_string, 1800 mci->mci_sasl_string_len, 1801 &client_interact, 1802 &out, &outlen); 1803 1804 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE) 1805 { 1806 if (tTd(95, 5)) 1807 sm_dprintf("AUTH FAIL=%s (%d)\n", 1808 sasl_errstring(saslresult, NULL, NULL), 1809 saslresult); 1810 1811 /* fail deliberately, see RFC 2554 4. */ 1812 smtpmessage("*", m, mci); 1813 1814 /* 1815 ** but we should only fail for this authentication 1816 ** mechanism; how to do that? 1817 */ 1818 1819 smtpresult = reply(m, mci, e, TimeOuts.to_auth, 1820 getsasldata, NULL); 1821 return EX_NOPERM; 1822 } 1823 1824 if (outlen > 0) 1825 { 1826 saslresult = sasl_encode64(out, outlen, in64, 1827 MAXOUTLEN, NULL); 1828 if (saslresult != SASL_OK) 1829 { 1830 /* give an error reply to the other side! */ 1831 smtpmessage("*", m, mci); 1832 return EX_TEMPFAIL; 1833 } 1834 } 1835 else 1836 in64[0] = '\0'; 1837 # if SASL < 20000 1838 sm_sasl_free(out); /* XXX only if no rpool is used */ 1839 # endif /* SASL < 20000 */ 1840 smtpmessage("%s", m, mci, in64); 1841 smtpresult = reply(m, mci, e, TimeOuts.to_auth, 1842 getsasldata, NULL); 1843 } 1844 /* NOTREACHED */ 1845 } 1846 /* 1847 ** SMTPAUTH -- try to AUTHenticate 1848 ** 1849 ** This will try mechanisms in the order the sasl library decided until: 1850 ** - there are no more mechanisms 1851 ** - a mechanism succeeds 1852 ** - the sasl library fails initializing 1853 ** 1854 ** Parameters: 1855 ** m -- the mailer. 1856 ** mci -- the mailer connection info. 1857 ** e -- the envelope. 1858 ** 1859 ** Returns: 1860 ** EX_OK -- authentication was successful 1861 ** EX_UNAVAILABLE -- authentication not possible, e.g., 1862 ** no data available. 1863 ** EX_NOPERM -- authentication failed. 1864 ** EX_TEMPFAIL -- temporary failure. 1865 ** 1866 ** Notice: AuthInfo is used for all connections, hence we must 1867 ** return EX_TEMPFAIL only if we really want to retry, i.e., 1868 ** iff getauth() tempfailed or getauth() was used and 1869 ** authentication tempfailed. 1870 */ 1871 1872 int 1873 smtpauth(m, mci, e) 1874 MAILER *m; 1875 MCI *mci; 1876 ENVELOPE *e; 1877 { 1878 int result; 1879 int i; 1880 bool usedgetauth; 1881 1882 mci->mci_sasl_auth = false; 1883 for (i = 0; i < SASL_MECH ; i++) 1884 mci->mci_sai[i] = NULL; 1885 1886 result = getauth(mci, e, &(mci->mci_sai)); 1887 if (result == EX_TEMPFAIL) 1888 return result; 1889 usedgetauth = true; 1890 1891 /* no data available: don't try to authenticate */ 1892 if (result == EX_OK && mci->mci_sai[SASL_AUTHID] == NULL) 1893 return result; 1894 if (result != EX_OK) 1895 { 1896 if (SASLInfo == NULL) 1897 return EX_UNAVAILABLE; 1898 1899 /* read authinfo from file */ 1900 result = readauth(SASLInfo, true, &(mci->mci_sai), 1901 mci->mci_rpool); 1902 if (result != EX_OK) 1903 return result; 1904 usedgetauth = false; 1905 } 1906 1907 /* check whether sufficient data is available */ 1908 if (mci->mci_sai[SASL_PASSWORD] == NULL || 1909 *(mci->mci_sai)[SASL_PASSWORD] == '\0') 1910 return EX_UNAVAILABLE; 1911 if ((mci->mci_sai[SASL_AUTHID] == NULL || 1912 *(mci->mci_sai)[SASL_AUTHID] == '\0') && 1913 (mci->mci_sai[SASL_USER] == NULL || 1914 *(mci->mci_sai)[SASL_USER] == '\0')) 1915 return EX_UNAVAILABLE; 1916 1917 /* set the context for the callback function to sai */ 1918 # if SASL >= 20000 1919 callbacks[CB_PASS_IDX].context = (void *) mci; 1920 # else /* SASL >= 20000 */ 1921 callbacks[CB_PASS_IDX].context = (void *) &mci->mci_sai; 1922 # endif /* SASL >= 20000 */ 1923 callbacks[CB_USER_IDX].context = (void *) &mci->mci_sai; 1924 callbacks[CB_AUTHNAME_IDX].context = (void *) &mci->mci_sai; 1925 callbacks[CB_GETREALM_IDX].context = (void *) &mci->mci_sai; 1926 #if 0 1927 callbacks[CB_SAFESASL_IDX].context = (void *) &mci->mci_sai; 1928 #endif /* 0 */ 1929 1930 /* set default value for realm */ 1931 if ((mci->mci_sai)[SASL_DEFREALM] == NULL) 1932 (mci->mci_sai)[SASL_DEFREALM] = sm_rpool_strdup_x(e->e_rpool, 1933 macvalue('j', CurEnv)); 1934 1935 /* set default value for list of mechanism to use */ 1936 if ((mci->mci_sai)[SASL_MECHLIST] == NULL || 1937 *(mci->mci_sai)[SASL_MECHLIST] == '\0') 1938 (mci->mci_sai)[SASL_MECHLIST] = AuthMechanisms; 1939 1940 /* create list of mechanisms to try */ 1941 mci->mci_saslcap = intersect((mci->mci_sai)[SASL_MECHLIST], 1942 mci->mci_saslcap, mci->mci_rpool); 1943 1944 /* initialize sasl client library */ 1945 result = init_sasl_client(); 1946 if (result != SASL_OK) 1947 return usedgetauth ? EX_TEMPFAIL : EX_UNAVAILABLE; 1948 do 1949 { 1950 result = attemptauth(m, mci, e, &(mci->mci_sai)); 1951 if (result == EX_OK) 1952 mci->mci_sasl_auth = true; 1953 else if (result == EX_TEMPFAIL || result == EX_NOPERM) 1954 { 1955 mci->mci_saslcap = removemech((mci->mci_sai)[SASL_MECH], 1956 mci->mci_saslcap, 1957 mci->mci_rpool); 1958 if (mci->mci_saslcap == NULL || 1959 *(mci->mci_saslcap) == '\0') 1960 return usedgetauth ? result 1961 : EX_UNAVAILABLE; 1962 } 1963 else 1964 return result; 1965 } while (result != EX_OK); 1966 return result; 1967 } 1968 #endif /* SASL */ 1969 1970 /* 1971 ** SMTPMAILFROM -- send MAIL command 1972 ** 1973 ** Parameters: 1974 ** m -- the mailer. 1975 ** mci -- the mailer connection structure. 1976 ** e -- the envelope (including the sender to specify). 1977 */ 1978 1979 int 1980 smtpmailfrom(m, mci, e) 1981 MAILER *m; 1982 MCI *mci; 1983 ENVELOPE *e; 1984 { 1985 int r; 1986 char *bufp; 1987 char *bodytype; 1988 char *enhsc; 1989 char buf[MAXNAME + 1]; 1990 char optbuf[MAXLINE]; 1991 1992 if (tTd(18, 2)) 1993 sm_dprintf("smtpmailfrom: CurHost=%s\n", CurHostName); 1994 enhsc = NULL; 1995 1996 /* 1997 ** Check if connection is gone, if so 1998 ** it's a tempfail and we use mci_errno 1999 ** for the reason. 2000 */ 2001 2002 if (mci->mci_state == MCIS_CLOSED) 2003 { 2004 errno = mci->mci_errno; 2005 return EX_TEMPFAIL; 2006 } 2007 2008 /* set up appropriate options to include */ 2009 if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0) 2010 { 2011 (void) sm_snprintf(optbuf, sizeof optbuf, " SIZE=%ld", 2012 e->e_msgsize); 2013 bufp = &optbuf[strlen(optbuf)]; 2014 } 2015 else 2016 { 2017 optbuf[0] = '\0'; 2018 bufp = optbuf; 2019 } 2020 2021 bodytype = e->e_bodytype; 2022 if (bitset(MCIF_8BITMIME, mci->mci_flags)) 2023 { 2024 if (bodytype == NULL && 2025 bitset(MM_MIME8BIT, MimeMode) && 2026 bitset(EF_HAS8BIT, e->e_flags) && 2027 !bitset(EF_DONT_MIME, e->e_flags) && 2028 !bitnset(M_8BITS, m->m_flags)) 2029 bodytype = "8BITMIME"; 2030 if (bodytype != NULL && 2031 SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7) 2032 { 2033 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2034 " BODY=%s", bodytype); 2035 bufp += strlen(bufp); 2036 } 2037 } 2038 else if (bitnset(M_8BITS, m->m_flags) || 2039 !bitset(EF_HAS8BIT, e->e_flags) || 2040 bitset(MCIF_8BITOK, mci->mci_flags)) 2041 { 2042 /* EMPTY */ 2043 /* just pass it through */ 2044 } 2045 #if MIME8TO7 2046 else if (bitset(MM_CVTMIME, MimeMode) && 2047 !bitset(EF_DONT_MIME, e->e_flags) && 2048 (!bitset(MM_PASS8BIT, MimeMode) || 2049 bitset(EF_IS_MIME, e->e_flags))) 2050 { 2051 /* must convert from 8bit MIME format to 7bit encoded */ 2052 mci->mci_flags |= MCIF_CVT8TO7; 2053 } 2054 #endif /* MIME8TO7 */ 2055 else if (!bitset(MM_PASS8BIT, MimeMode)) 2056 { 2057 /* cannot just send a 8-bit version */ 2058 extern char MsgBuf[]; 2059 2060 usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName); 2061 mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf); 2062 return EX_DATAERR; 2063 } 2064 2065 if (bitset(MCIF_DSN, mci->mci_flags)) 2066 { 2067 if (e->e_envid != NULL && 2068 SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7) 2069 { 2070 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2071 " ENVID=%s", e->e_envid); 2072 bufp += strlen(bufp); 2073 } 2074 2075 /* RET= parameter */ 2076 if (bitset(EF_RET_PARAM, e->e_flags) && 2077 SPACELEFT(optbuf, bufp) > 9) 2078 { 2079 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2080 " RET=%s", 2081 bitset(EF_NO_BODY_RETN, e->e_flags) ? 2082 "HDRS" : "FULL"); 2083 bufp += strlen(bufp); 2084 } 2085 } 2086 2087 if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL && 2088 SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7 2089 #if SASL 2090 && (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth) 2091 #endif /* SASL */ 2092 ) 2093 { 2094 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2095 " AUTH=%s", e->e_auth_param); 2096 bufp += strlen(bufp); 2097 } 2098 2099 /* 2100 ** 17 is the max length required, we could use log() to compute 2101 ** the exact length (and check IS_DLVR_TRACE()) 2102 */ 2103 2104 if (bitset(MCIF_DLVR_BY, mci->mci_flags) && 2105 IS_DLVR_BY(e) && SPACELEFT(optbuf, bufp) > 17) 2106 { 2107 long dby; 2108 2109 /* 2110 ** Avoid problems with delays (for R) since the check 2111 ** in deliver() whether min-deliver-time is sufficient. 2112 ** Alternatively we could pass the computed time to this 2113 ** function. 2114 */ 2115 2116 dby = e->e_deliver_by - (curtime() - e->e_ctime); 2117 if (dby <= 0 && IS_DLVR_RETURN(e)) 2118 dby = mci->mci_min_by <= 0 ? 1 : mci->mci_min_by; 2119 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2120 " BY=%ld;%c%s", 2121 dby, 2122 IS_DLVR_RETURN(e) ? 'R' : 'N', 2123 IS_DLVR_TRACE(e) ? "T" : ""); 2124 bufp += strlen(bufp); 2125 } 2126 2127 /* 2128 ** Send the MAIL command. 2129 ** Designates the sender. 2130 */ 2131 2132 mci->mci_state = MCIS_MAIL; 2133 2134 if (bitset(EF_RESPONSE, e->e_flags) && 2135 !bitnset(M_NO_NULL_FROM, m->m_flags)) 2136 buf[0] = '\0'; 2137 else 2138 expand("\201g", buf, sizeof buf, e); 2139 if (buf[0] == '<') 2140 { 2141 /* strip off <angle brackets> (put back on below) */ 2142 bufp = &buf[strlen(buf) - 1]; 2143 if (*bufp == '>') 2144 *bufp = '\0'; 2145 bufp = &buf[1]; 2146 } 2147 else 2148 bufp = buf; 2149 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) || 2150 !bitnset(M_FROMPATH, m->m_flags)) 2151 { 2152 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf); 2153 } 2154 else 2155 { 2156 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, 2157 *bufp == '@' ? ',' : ':', bufp, optbuf); 2158 } 2159 SmtpPhase = mci->mci_phase = "client MAIL"; 2160 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), 2161 CurHostName, mci->mci_phase); 2162 r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc); 2163 if (r < 0) 2164 { 2165 /* communications failure */ 2166 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 2167 return EX_TEMPFAIL; 2168 } 2169 else if (r == SMTPCLOSING) 2170 { 2171 /* service shutting down: handled by reply() */ 2172 return EX_TEMPFAIL; 2173 } 2174 else if (REPLYTYPE(r) == 4) 2175 { 2176 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)), 2177 SmtpReplyBuffer); 2178 return EX_TEMPFAIL; 2179 } 2180 else if (REPLYTYPE(r) == 2) 2181 { 2182 return EX_OK; 2183 } 2184 else if (r == 501) 2185 { 2186 /* syntax error in arguments */ 2187 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"), 2188 SmtpReplyBuffer); 2189 return EX_DATAERR; 2190 } 2191 else if (r == 553) 2192 { 2193 /* mailbox name not allowed */ 2194 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"), 2195 SmtpReplyBuffer); 2196 return EX_DATAERR; 2197 } 2198 else if (r == 552) 2199 { 2200 /* exceeded storage allocation */ 2201 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"), 2202 SmtpReplyBuffer); 2203 if (bitset(MCIF_SIZE, mci->mci_flags)) 2204 e->e_flags |= EF_NO_BODY_RETN; 2205 return EX_UNAVAILABLE; 2206 } 2207 else if (REPLYTYPE(r) == 5) 2208 { 2209 /* unknown error */ 2210 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"), 2211 SmtpReplyBuffer); 2212 return EX_UNAVAILABLE; 2213 } 2214 2215 if (LogLevel > 1) 2216 { 2217 sm_syslog(LOG_CRIT, e->e_id, 2218 "%.100s: SMTP MAIL protocol error: %s", 2219 CurHostName, 2220 shortenstring(SmtpReplyBuffer, 403)); 2221 } 2222 2223 /* protocol error -- close up */ 2224 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"), 2225 SmtpReplyBuffer); 2226 smtpquit(m, mci, e); 2227 return EX_PROTOCOL; 2228 } 2229 /* 2230 ** SMTPRCPT -- designate recipient. 2231 ** 2232 ** Parameters: 2233 ** to -- address of recipient. 2234 ** m -- the mailer we are sending to. 2235 ** mci -- the connection info for this transaction. 2236 ** e -- the envelope for this transaction. 2237 ** 2238 ** Returns: 2239 ** exit status corresponding to recipient status. 2240 ** 2241 ** Side Effects: 2242 ** Sends the mail via SMTP. 2243 */ 2244 2245 int 2246 smtprcpt(to, m, mci, e, ctladdr, xstart) 2247 ADDRESS *to; 2248 register MAILER *m; 2249 MCI *mci; 2250 ENVELOPE *e; 2251 ADDRESS *ctladdr; 2252 time_t xstart; 2253 { 2254 char *bufp; 2255 char optbuf[MAXLINE]; 2256 2257 #if PIPELINING 2258 /* 2259 ** If there is status waiting from the other end, read it. 2260 ** This should normally happen because of SMTP pipelining. 2261 */ 2262 2263 while (mci->mci_nextaddr != NULL && 2264 sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL)) 2265 { 2266 int r; 2267 2268 r = smtprcptstat(mci->mci_nextaddr, m, mci, e); 2269 if (r != EX_OK) 2270 { 2271 markfailure(e, mci->mci_nextaddr, mci, r, false); 2272 giveresponse(r, mci->mci_nextaddr->q_status, m, mci, 2273 ctladdr, xstart, e, to); 2274 } 2275 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain; 2276 } 2277 #endif /* PIPELINING */ 2278 2279 /* 2280 ** Check if connection is gone, if so 2281 ** it's a tempfail and we use mci_errno 2282 ** for the reason. 2283 */ 2284 2285 if (mci->mci_state == MCIS_CLOSED) 2286 { 2287 errno = mci->mci_errno; 2288 return EX_TEMPFAIL; 2289 } 2290 2291 optbuf[0] = '\0'; 2292 bufp = optbuf; 2293 2294 /* 2295 ** Warning: in the following it is assumed that the free space 2296 ** in bufp is sizeof optbuf 2297 */ 2298 2299 if (bitset(MCIF_DSN, mci->mci_flags)) 2300 { 2301 if (IS_DLVR_NOTIFY(e) && 2302 !bitset(MCIF_DLVR_BY, mci->mci_flags)) 2303 { 2304 /* RFC 2852: 4.1.4.2 */ 2305 if (!bitset(QHASNOTIFY, to->q_flags)) 2306 to->q_flags |= QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY; 2307 else if (bitset(QPINGONSUCCESS, to->q_flags) || 2308 bitset(QPINGONFAILURE, to->q_flags) || 2309 bitset(QPINGONDELAY, to->q_flags)) 2310 to->q_flags |= QPINGONDELAY; 2311 } 2312 2313 /* NOTIFY= parameter */ 2314 if (bitset(QHASNOTIFY, to->q_flags) && 2315 bitset(QPRIMARY, to->q_flags) && 2316 !bitnset(M_LOCALMAILER, m->m_flags)) 2317 { 2318 bool firstone = true; 2319 2320 (void) sm_strlcat(bufp, " NOTIFY=", sizeof optbuf); 2321 if (bitset(QPINGONSUCCESS, to->q_flags)) 2322 { 2323 (void) sm_strlcat(bufp, "SUCCESS", sizeof optbuf); 2324 firstone = false; 2325 } 2326 if (bitset(QPINGONFAILURE, to->q_flags)) 2327 { 2328 if (!firstone) 2329 (void) sm_strlcat(bufp, ",", 2330 sizeof optbuf); 2331 (void) sm_strlcat(bufp, "FAILURE", sizeof optbuf); 2332 firstone = false; 2333 } 2334 if (bitset(QPINGONDELAY, to->q_flags)) 2335 { 2336 if (!firstone) 2337 (void) sm_strlcat(bufp, ",", 2338 sizeof optbuf); 2339 (void) sm_strlcat(bufp, "DELAY", sizeof optbuf); 2340 firstone = false; 2341 } 2342 if (firstone) 2343 (void) sm_strlcat(bufp, "NEVER", sizeof optbuf); 2344 bufp += strlen(bufp); 2345 } 2346 2347 /* ORCPT= parameter */ 2348 if (to->q_orcpt != NULL && 2349 SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7) 2350 { 2351 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp), 2352 " ORCPT=%s", to->q_orcpt); 2353 bufp += strlen(bufp); 2354 } 2355 } 2356 2357 smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf); 2358 mci->mci_state = MCIS_RCPT; 2359 2360 SmtpPhase = mci->mci_phase = "client RCPT"; 2361 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), 2362 CurHostName, mci->mci_phase); 2363 2364 #if PIPELINING 2365 /* 2366 ** If running SMTP pipelining, we will pick up status later 2367 */ 2368 2369 if (bitset(MCIF_PIPELINED, mci->mci_flags)) 2370 return EX_OK; 2371 #endif /* PIPELINING */ 2372 2373 return smtprcptstat(to, m, mci, e); 2374 } 2375 /* 2376 ** SMTPRCPTSTAT -- get recipient status 2377 ** 2378 ** This is only called during SMTP pipelining 2379 ** 2380 ** Parameters: 2381 ** to -- address of recipient. 2382 ** m -- mailer being sent to. 2383 ** mci -- the mailer connection information. 2384 ** e -- the envelope for this message. 2385 ** 2386 ** Returns: 2387 ** EX_* -- protocol status 2388 */ 2389 2390 static int 2391 smtprcptstat(to, m, mci, e) 2392 ADDRESS *to; 2393 MAILER *m; 2394 register MCI *mci; 2395 register ENVELOPE *e; 2396 { 2397 int r; 2398 int save_errno; 2399 char *enhsc; 2400 2401 /* 2402 ** Check if connection is gone, if so 2403 ** it's a tempfail and we use mci_errno 2404 ** for the reason. 2405 */ 2406 2407 if (mci->mci_state == MCIS_CLOSED) 2408 { 2409 errno = mci->mci_errno; 2410 return EX_TEMPFAIL; 2411 } 2412 2413 enhsc = NULL; 2414 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc); 2415 save_errno = errno; 2416 to->q_rstatus = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer); 2417 to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool); 2418 if (!bitnset(M_LMTP, m->m_flags)) 2419 to->q_statmta = mci->mci_host; 2420 if (r < 0 || REPLYTYPE(r) == 4) 2421 { 2422 mci->mci_retryrcpt = true; 2423 errno = save_errno; 2424 return EX_TEMPFAIL; 2425 } 2426 else if (REPLYTYPE(r) == 2) 2427 { 2428 char *t; 2429 2430 if ((t = mci->mci_tolist) != NULL) 2431 { 2432 char *p; 2433 2434 *t++ = ','; 2435 for (p = to->q_paddr; *p != '\0'; *t++ = *p++) 2436 continue; 2437 *t = '\0'; 2438 mci->mci_tolist = t; 2439 } 2440 #if PIPELINING 2441 mci->mci_okrcpts++; 2442 #endif /* PIPELINING */ 2443 return EX_OK; 2444 } 2445 else if (r == 550) 2446 { 2447 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.1", e->e_rpool); 2448 return EX_NOUSER; 2449 } 2450 else if (r == 551) 2451 { 2452 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.6", e->e_rpool); 2453 return EX_NOUSER; 2454 } 2455 else if (r == 553) 2456 { 2457 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.3", e->e_rpool); 2458 return EX_NOUSER; 2459 } 2460 else if (REPLYTYPE(r) == 5) 2461 { 2462 return EX_UNAVAILABLE; 2463 } 2464 2465 if (LogLevel > 1) 2466 { 2467 sm_syslog(LOG_CRIT, e->e_id, 2468 "%.100s: SMTP RCPT protocol error: %s", 2469 CurHostName, 2470 shortenstring(SmtpReplyBuffer, 403)); 2471 } 2472 2473 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"), 2474 SmtpReplyBuffer); 2475 return EX_PROTOCOL; 2476 } 2477 /* 2478 ** SMTPDATA -- send the data and clean up the transaction. 2479 ** 2480 ** Parameters: 2481 ** m -- mailer being sent to. 2482 ** mci -- the mailer connection information. 2483 ** e -- the envelope for this message. 2484 ** 2485 ** Returns: 2486 ** exit status corresponding to DATA command. 2487 */ 2488 2489 static jmp_buf CtxDataTimeout; 2490 static SM_EVENT *volatile DataTimeout = NULL; 2491 2492 int 2493 smtpdata(m, mci, e, ctladdr, xstart) 2494 MAILER *m; 2495 register MCI *mci; 2496 register ENVELOPE *e; 2497 ADDRESS *ctladdr; 2498 time_t xstart; 2499 { 2500 register int r; 2501 int rstat; 2502 int xstat; 2503 time_t timeout; 2504 char *enhsc; 2505 2506 /* 2507 ** Check if connection is gone, if so 2508 ** it's a tempfail and we use mci_errno 2509 ** for the reason. 2510 */ 2511 2512 if (mci->mci_state == MCIS_CLOSED) 2513 { 2514 errno = mci->mci_errno; 2515 return EX_TEMPFAIL; 2516 } 2517 2518 enhsc = NULL; 2519 2520 /* 2521 ** Send the data. 2522 ** First send the command and check that it is ok. 2523 ** Then send the data (if there are valid recipients). 2524 ** Follow it up with a dot to terminate. 2525 ** Finally get the results of the transaction. 2526 */ 2527 2528 /* send the command and check ok to proceed */ 2529 smtpmessage("DATA", m, mci); 2530 2531 #if PIPELINING 2532 if (mci->mci_nextaddr != NULL) 2533 { 2534 char *oldto = e->e_to; 2535 2536 /* pick up any pending RCPT responses for SMTP pipelining */ 2537 while (mci->mci_nextaddr != NULL) 2538 { 2539 int r; 2540 2541 e->e_to = mci->mci_nextaddr->q_paddr; 2542 r = smtprcptstat(mci->mci_nextaddr, m, mci, e); 2543 if (r != EX_OK) 2544 { 2545 markfailure(e, mci->mci_nextaddr, mci, r, 2546 false); 2547 giveresponse(r, mci->mci_nextaddr->q_status, m, 2548 mci, ctladdr, xstart, e, 2549 mci->mci_nextaddr); 2550 if (r == EX_TEMPFAIL) 2551 mci->mci_nextaddr->q_state = QS_RETRY; 2552 } 2553 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain; 2554 } 2555 e->e_to = oldto; 2556 } 2557 #endif /* PIPELINING */ 2558 2559 /* now proceed with DATA phase */ 2560 SmtpPhase = mci->mci_phase = "client DATA 354"; 2561 mci->mci_state = MCIS_DATA; 2562 sm_setproctitle(true, e, "%s %s: %s", 2563 qid_printname(e), CurHostName, mci->mci_phase); 2564 r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc); 2565 if (r < 0 || REPLYTYPE(r) == 4) 2566 { 2567 if (r >= 0) 2568 smtpquit(m, mci, e); 2569 errno = mci->mci_errno; 2570 return EX_TEMPFAIL; 2571 } 2572 else if (REPLYTYPE(r) == 5) 2573 { 2574 smtprset(m, mci, e); 2575 #if PIPELINING 2576 if (mci->mci_okrcpts <= 0) 2577 return mci->mci_retryrcpt ? EX_TEMPFAIL 2578 : EX_UNAVAILABLE; 2579 #endif /* PIPELINING */ 2580 return EX_UNAVAILABLE; 2581 } 2582 else if (REPLYTYPE(r) != 3) 2583 { 2584 if (LogLevel > 1) 2585 { 2586 sm_syslog(LOG_CRIT, e->e_id, 2587 "%.100s: SMTP DATA-1 protocol error: %s", 2588 CurHostName, 2589 shortenstring(SmtpReplyBuffer, 403)); 2590 } 2591 smtprset(m, mci, e); 2592 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"), 2593 SmtpReplyBuffer); 2594 #if PIPELINING 2595 if (mci->mci_okrcpts <= 0) 2596 return mci->mci_retryrcpt ? EX_TEMPFAIL 2597 : EX_PROTOCOL; 2598 #endif /* PIPELINING */ 2599 return EX_PROTOCOL; 2600 } 2601 2602 #if PIPELINING 2603 if (mci->mci_okrcpts > 0) 2604 { 2605 #endif /* PIPELINING */ 2606 2607 /* 2608 ** Set timeout around data writes. Make it at least large 2609 ** enough for DNS timeouts on all recipients plus some fudge 2610 ** factor. The main thing is that it should not be infinite. 2611 */ 2612 2613 if (setjmp(CtxDataTimeout) != 0) 2614 { 2615 mci->mci_errno = errno; 2616 mci->mci_state = MCIS_ERROR; 2617 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); 2618 2619 /* 2620 ** If putbody() couldn't finish due to a timeout, 2621 ** rewind it here in the timeout handler. See 2622 ** comments at the end of putbody() for reasoning. 2623 */ 2624 2625 if (e->e_dfp != NULL) 2626 (void) bfrewind(e->e_dfp); 2627 2628 errno = mci->mci_errno; 2629 syserr("451 4.4.1 timeout writing message to %s", CurHostName); 2630 smtpquit(m, mci, e); 2631 return EX_TEMPFAIL; 2632 } 2633 2634 if (tTd(18, 101)) 2635 { 2636 /* simulate a DATA timeout */ 2637 timeout = 1; 2638 } 2639 else 2640 timeout = DATA_PROGRESS_TIMEOUT; 2641 2642 DataTimeout = sm_setevent(timeout, datatimeout, 0); 2643 2644 2645 /* 2646 ** Output the actual message. 2647 */ 2648 2649 (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); 2650 2651 if (tTd(18, 101)) 2652 { 2653 /* simulate a DATA timeout */ 2654 (void) sleep(2); 2655 } 2656 2657 (*e->e_putbody)(mci, e, NULL); 2658 2659 /* 2660 ** Cleanup after sending message. 2661 */ 2662 2663 if (DataTimeout != NULL) 2664 sm_clrevent(DataTimeout); 2665 2666 #if PIPELINING 2667 } 2668 #endif /* PIPELINING */ 2669 2670 #if _FFR_CATCH_BROKEN_MTAS 2671 if (sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL)) 2672 { 2673 /* terminate the message */ 2674 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s", 2675 m->m_eol); 2676 if (TrafficLogFile != NULL) 2677 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 2678 "%05d >>> .\n", (int) CurrentPid); 2679 if (Verbose) 2680 nmessage(">>> ."); 2681 2682 sm_syslog(LOG_CRIT, e->e_id, 2683 "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot", 2684 CurHostName); 2685 mci->mci_errno = EIO; 2686 mci->mci_state = MCIS_ERROR; 2687 mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL); 2688 smtpquit(m, mci, e); 2689 return EX_PROTOCOL; 2690 } 2691 #endif /* _FFR_CATCH_BROKEN_MTAS */ 2692 2693 if (sm_io_error(mci->mci_out)) 2694 { 2695 /* error during processing -- don't send the dot */ 2696 mci->mci_errno = EIO; 2697 mci->mci_state = MCIS_ERROR; 2698 mci_setstat(mci, EX_IOERR, "4.4.2", NULL); 2699 smtpquit(m, mci, e); 2700 return EX_IOERR; 2701 } 2702 2703 /* terminate the message */ 2704 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s", m->m_eol); 2705 if (TrafficLogFile != NULL) 2706 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 2707 "%05d >>> .\n", (int) CurrentPid); 2708 if (Verbose) 2709 nmessage(">>> ."); 2710 2711 /* check for the results of the transaction */ 2712 SmtpPhase = mci->mci_phase = "client DATA status"; 2713 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), 2714 CurHostName, mci->mci_phase); 2715 if (bitnset(M_LMTP, m->m_flags)) 2716 return EX_OK; 2717 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc); 2718 if (r < 0) 2719 return EX_TEMPFAIL; 2720 mci->mci_state = MCIS_OPEN; 2721 xstat = EX_NOTSTICKY; 2722 if (r == 452) 2723 rstat = EX_TEMPFAIL; 2724 else if (REPLYTYPE(r) == 4) 2725 rstat = xstat = EX_TEMPFAIL; 2726 else if (REPLYTYPE(r) == 2) 2727 rstat = xstat = EX_OK; 2728 else if (REPLYCLASS(r) != 5) 2729 rstat = xstat = EX_PROTOCOL; 2730 else if (REPLYTYPE(r) == 5) 2731 rstat = EX_UNAVAILABLE; 2732 else 2733 rstat = EX_PROTOCOL; 2734 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), 2735 SmtpReplyBuffer); 2736 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 2737 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) 2738 r += 5; 2739 else 2740 r = 4; 2741 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]); 2742 SmtpPhase = mci->mci_phase = "idle"; 2743 sm_setproctitle(true, e, "%s: %s", CurHostName, mci->mci_phase); 2744 if (rstat != EX_PROTOCOL) 2745 return rstat; 2746 if (LogLevel > 1) 2747 { 2748 sm_syslog(LOG_CRIT, e->e_id, 2749 "%.100s: SMTP DATA-2 protocol error: %s", 2750 CurHostName, 2751 shortenstring(SmtpReplyBuffer, 403)); 2752 } 2753 return rstat; 2754 } 2755 2756 static void 2757 datatimeout() 2758 { 2759 int save_errno = errno; 2760 2761 /* 2762 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2763 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2764 ** DOING. 2765 */ 2766 2767 if (DataProgress) 2768 { 2769 time_t timeout; 2770 2771 /* check back again later */ 2772 if (tTd(18, 101)) 2773 { 2774 /* simulate a DATA timeout */ 2775 timeout = 1; 2776 } 2777 else 2778 timeout = DATA_PROGRESS_TIMEOUT; 2779 2780 /* reset the timeout */ 2781 DataTimeout = sm_sigsafe_setevent(timeout, datatimeout, 0); 2782 DataProgress = false; 2783 } 2784 else 2785 { 2786 /* event is done */ 2787 DataTimeout = NULL; 2788 } 2789 2790 /* if no progress was made or problem resetting event, die now */ 2791 if (DataTimeout == NULL) 2792 { 2793 errno = ETIMEDOUT; 2794 longjmp(CtxDataTimeout, 1); 2795 } 2796 errno = save_errno; 2797 } 2798 /* 2799 ** SMTPGETSTAT -- get status code from DATA in LMTP 2800 ** 2801 ** Parameters: 2802 ** m -- the mailer to which we are sending the message. 2803 ** mci -- the mailer connection structure. 2804 ** e -- the current envelope. 2805 ** 2806 ** Returns: 2807 ** The exit status corresponding to the reply code. 2808 */ 2809 2810 int 2811 smtpgetstat(m, mci, e) 2812 MAILER *m; 2813 MCI *mci; 2814 ENVELOPE *e; 2815 { 2816 int r; 2817 int status, xstat; 2818 char *enhsc; 2819 2820 enhsc = NULL; 2821 2822 /* check for the results of the transaction */ 2823 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc); 2824 if (r < 0) 2825 return EX_TEMPFAIL; 2826 xstat = EX_NOTSTICKY; 2827 if (REPLYTYPE(r) == 4) 2828 status = EX_TEMPFAIL; 2829 else if (REPLYTYPE(r) == 2) 2830 status = xstat = EX_OK; 2831 else if (REPLYCLASS(r) != 5) 2832 status = xstat = EX_PROTOCOL; 2833 else if (REPLYTYPE(r) == 5) 2834 status = EX_UNAVAILABLE; 2835 else 2836 status = EX_PROTOCOL; 2837 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 2838 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) 2839 r += 5; 2840 else 2841 r = 4; 2842 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]); 2843 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), 2844 SmtpReplyBuffer); 2845 if (LogLevel > 1 && status == EX_PROTOCOL) 2846 { 2847 sm_syslog(LOG_CRIT, e->e_id, 2848 "%.100s: SMTP DATA-3 protocol error: %s", 2849 CurHostName, 2850 shortenstring(SmtpReplyBuffer, 403)); 2851 } 2852 return status; 2853 } 2854 /* 2855 ** SMTPQUIT -- close the SMTP connection. 2856 ** 2857 ** Parameters: 2858 ** m -- a pointer to the mailer. 2859 ** mci -- the mailer connection information. 2860 ** e -- the current envelope. 2861 ** 2862 ** Returns: 2863 ** none. 2864 ** 2865 ** Side Effects: 2866 ** sends the final protocol and closes the connection. 2867 */ 2868 2869 void 2870 smtpquit(m, mci, e) 2871 register MAILER *m; 2872 register MCI *mci; 2873 ENVELOPE *e; 2874 { 2875 bool oldSuprErrs = SuprErrs; 2876 int rcode; 2877 char *oldcurhost; 2878 2879 if (mci->mci_state == MCIS_CLOSED) 2880 return; 2881 2882 oldcurhost = CurHostName; 2883 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 2884 if (CurHostName == NULL) 2885 CurHostName = MyHostName; 2886 2887 #if PIPELINING 2888 mci->mci_okrcpts = 0; 2889 #endif /* PIPELINING */ 2890 2891 /* 2892 ** Suppress errors here -- we may be processing a different 2893 ** job when we do the quit connection, and we don't want the 2894 ** new job to be penalized for something that isn't it's 2895 ** problem. 2896 */ 2897 2898 SuprErrs = true; 2899 2900 /* send the quit message if we haven't gotten I/O error */ 2901 if (mci->mci_state != MCIS_ERROR && 2902 mci->mci_state != MCIS_QUITING) 2903 { 2904 SmtpPhase = "client QUIT"; 2905 mci->mci_state = MCIS_QUITING; 2906 smtpmessage("QUIT", m, mci); 2907 (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL); 2908 SuprErrs = oldSuprErrs; 2909 if (mci->mci_state == MCIS_CLOSED) 2910 goto end; 2911 } 2912 2913 /* now actually close the connection and pick up the zombie */ 2914 rcode = endmailer(mci, e, NULL); 2915 if (rcode != EX_OK) 2916 { 2917 char *mailer = NULL; 2918 2919 if (mci->mci_mailer != NULL && 2920 mci->mci_mailer->m_name != NULL) 2921 mailer = mci->mci_mailer->m_name; 2922 2923 /* look for naughty mailers */ 2924 sm_syslog(LOG_ERR, e->e_id, 2925 "smtpquit: mailer%s%s exited with exit value %d", 2926 mailer == NULL ? "" : " ", 2927 mailer == NULL ? "" : mailer, 2928 rcode); 2929 } 2930 2931 SuprErrs = oldSuprErrs; 2932 2933 end: 2934 CurHostName = oldcurhost; 2935 return; 2936 } 2937 /* 2938 ** SMTPRSET -- send a RSET (reset) command 2939 ** 2940 ** Parameters: 2941 ** m -- a pointer to the mailer. 2942 ** mci -- the mailer connection information. 2943 ** e -- the current envelope. 2944 ** 2945 ** Returns: 2946 ** none. 2947 ** 2948 ** Side Effects: 2949 ** closes the connection if there is no reply to RSET. 2950 */ 2951 2952 void 2953 smtprset(m, mci, e) 2954 register MAILER *m; 2955 register MCI *mci; 2956 ENVELOPE *e; 2957 { 2958 int r; 2959 2960 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 2961 if (CurHostName == NULL) 2962 CurHostName = MyHostName; 2963 2964 #if PIPELINING 2965 mci->mci_okrcpts = 0; 2966 #endif /* PIPELINING */ 2967 2968 /* 2969 ** Check if connection is gone, if so 2970 ** it's a tempfail and we use mci_errno 2971 ** for the reason. 2972 */ 2973 2974 if (mci->mci_state == MCIS_CLOSED) 2975 { 2976 errno = mci->mci_errno; 2977 return; 2978 } 2979 2980 SmtpPhase = "client RSET"; 2981 smtpmessage("RSET", m, mci); 2982 r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL); 2983 if (r < 0) 2984 return; 2985 2986 /* 2987 ** Any response is deemed to be acceptable. 2988 ** The standard does not state the proper action 2989 ** to take when a value other than 250 is received. 2990 ** 2991 ** However, if 421 is returned for the RSET, leave 2992 ** mci_state as MCIS_SSD (set in reply()). 2993 */ 2994 2995 if (mci->mci_state != MCIS_SSD) 2996 mci->mci_state = MCIS_OPEN; 2997 } 2998 /* 2999 ** SMTPPROBE -- check the connection state 3000 ** 3001 ** Parameters: 3002 ** mci -- the mailer connection information. 3003 ** 3004 ** Returns: 3005 ** none. 3006 ** 3007 ** Side Effects: 3008 ** closes the connection if there is no reply to RSET. 3009 */ 3010 3011 int 3012 smtpprobe(mci) 3013 register MCI *mci; 3014 { 3015 int r; 3016 MAILER *m = mci->mci_mailer; 3017 ENVELOPE *e; 3018 extern ENVELOPE BlankEnvelope; 3019 3020 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 3021 if (CurHostName == NULL) 3022 CurHostName = MyHostName; 3023 3024 e = &BlankEnvelope; 3025 SmtpPhase = "client probe"; 3026 smtpmessage("RSET", m, mci); 3027 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL); 3028 if (REPLYTYPE(r) != 2) 3029 smtpquit(m, mci, e); 3030 return r; 3031 } 3032 /* 3033 ** REPLY -- read arpanet reply 3034 ** 3035 ** Parameters: 3036 ** m -- the mailer we are reading the reply from. 3037 ** mci -- the mailer connection info structure. 3038 ** e -- the current envelope. 3039 ** timeout -- the timeout for reads. 3040 ** pfunc -- processing function called on each line of response. 3041 ** If null, no special processing is done. 3042 ** enhstat -- optional, returns enhanced error code string (if set) 3043 ** 3044 ** Returns: 3045 ** reply code it reads. 3046 ** 3047 ** Side Effects: 3048 ** flushes the mail file. 3049 */ 3050 3051 int 3052 reply(m, mci, e, timeout, pfunc, enhstat) 3053 MAILER *m; 3054 MCI *mci; 3055 ENVELOPE *e; 3056 time_t timeout; 3057 void (*pfunc)(); 3058 char **enhstat; 3059 { 3060 register char *bufp; 3061 register int r; 3062 bool firstline = true; 3063 char junkbuf[MAXLINE]; 3064 static char enhstatcode[ENHSCLEN]; 3065 int save_errno; 3066 3067 /* 3068 ** Flush the output before reading response. 3069 ** 3070 ** For SMTP pipelining, it would be better if we didn't do 3071 ** this if there was already data waiting to be read. But 3072 ** to do it properly means pushing it to the I/O library, 3073 ** since it really needs to be done below the buffer layer. 3074 */ 3075 3076 if (mci->mci_out != NULL) 3077 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT); 3078 3079 if (tTd(18, 1)) 3080 sm_dprintf("reply\n"); 3081 3082 /* 3083 ** Read the input line, being careful not to hang. 3084 */ 3085 3086 bufp = SmtpReplyBuffer; 3087 for (;;) 3088 { 3089 register char *p; 3090 3091 /* actually do the read */ 3092 if (e->e_xfp != NULL) /* for debugging */ 3093 (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 3094 3095 /* if we are in the process of closing just give the code */ 3096 if (mci->mci_state == MCIS_CLOSED) 3097 return SMTPCLOSING; 3098 3099 /* don't try to read from a non-existant fd */ 3100 if (mci->mci_in == NULL) 3101 { 3102 if (mci->mci_errno == 0) 3103 mci->mci_errno = EBADF; 3104 3105 /* errors on QUIT should be ignored */ 3106 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0) 3107 { 3108 errno = mci->mci_errno; 3109 return -1; 3110 } 3111 mci->mci_state = MCIS_ERROR; 3112 smtpquit(m, mci, e); 3113 errno = mci->mci_errno; 3114 return -1; 3115 } 3116 3117 if (mci->mci_out != NULL) 3118 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT); 3119 3120 /* get the line from the other side */ 3121 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase); 3122 save_errno = errno; 3123 mci->mci_lastuse = curtime(); 3124 3125 if (p == NULL) 3126 { 3127 bool oldholderrs; 3128 extern char MsgBuf[]; 3129 3130 /* errors on QUIT should be ignored */ 3131 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0) 3132 return -1; 3133 3134 /* if the remote end closed early, fake an error */ 3135 errno = save_errno; 3136 if (errno == 0) 3137 { 3138 (void) sm_snprintf(SmtpReplyBuffer, 3139 sizeof SmtpReplyBuffer, 3140 "421 4.4.1 Connection reset by %s", 3141 CURHOSTNAME); 3142 #ifdef ECONNRESET 3143 errno = ECONNRESET; 3144 #else /* ECONNRESET */ 3145 errno = EPIPE; 3146 #endif /* ECONNRESET */ 3147 } 3148 3149 mci->mci_errno = errno; 3150 oldholderrs = HoldErrs; 3151 HoldErrs = true; 3152 usrerr("451 4.4.1 reply: read error from %s", 3153 CURHOSTNAME); 3154 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf); 3155 3156 /* if debugging, pause so we can see state */ 3157 if (tTd(18, 100)) 3158 (void) pause(); 3159 mci->mci_state = MCIS_ERROR; 3160 smtpquit(m, mci, e); 3161 #if XDEBUG 3162 { 3163 char wbuf[MAXLINE]; 3164 3165 p = wbuf; 3166 if (e->e_to != NULL) 3167 { 3168 (void) sm_snprintf(p, 3169 SPACELEFT(wbuf, p), 3170 "%s... ", 3171 shortenstring(e->e_to, MAXSHORTSTR)); 3172 p += strlen(p); 3173 } 3174 (void) sm_snprintf(p, SPACELEFT(wbuf, p), 3175 "reply(%.100s) during %s", 3176 CURHOSTNAME, SmtpPhase); 3177 checkfd012(wbuf); 3178 } 3179 #endif /* XDEBUG */ 3180 HoldErrs = oldholderrs; 3181 errno = save_errno; 3182 return -1; 3183 } 3184 fixcrlf(bufp, true); 3185 3186 /* EHLO failure is not a real error */ 3187 if (e->e_xfp != NULL && (bufp[0] == '4' || 3188 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0))) 3189 { 3190 /* serious error -- log the previous command */ 3191 if (SmtpNeedIntro) 3192 { 3193 /* inform user who we are chatting with */ 3194 (void) sm_io_fprintf(CurEnv->e_xfp, 3195 SM_TIME_DEFAULT, 3196 "... while talking to %s:\n", 3197 CURHOSTNAME); 3198 SmtpNeedIntro = false; 3199 } 3200 if (SmtpMsgBuffer[0] != '\0') 3201 (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 3202 ">>> %s\n", SmtpMsgBuffer); 3203 SmtpMsgBuffer[0] = '\0'; 3204 3205 /* now log the message as from the other side */ 3206 (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 3207 "<<< %s\n", bufp); 3208 } 3209 3210 /* display the input for verbose mode */ 3211 if (Verbose) 3212 nmessage("050 %s", bufp); 3213 3214 /* ignore improperly formatted input */ 3215 if (!ISSMTPREPLY(bufp)) 3216 continue; 3217 3218 if (bitset(MCIF_ENHSTAT, mci->mci_flags) && 3219 enhstat != NULL && 3220 extenhsc(bufp + 4, ' ', enhstatcode) > 0) 3221 *enhstat = enhstatcode; 3222 3223 /* process the line */ 3224 if (pfunc != NULL) 3225 (*pfunc)(bufp, firstline, m, mci, e); 3226 3227 firstline = false; 3228 3229 /* decode the reply code */ 3230 r = atoi(bufp); 3231 3232 /* extra semantics: 0xx codes are "informational" */ 3233 if (r < 100) 3234 continue; 3235 3236 /* if no continuation lines, return this line */ 3237 if (bufp[3] != '-') 3238 break; 3239 3240 /* first line of real reply -- ignore rest */ 3241 bufp = junkbuf; 3242 } 3243 3244 /* 3245 ** Now look at SmtpReplyBuffer -- only care about the first 3246 ** line of the response from here on out. 3247 */ 3248 3249 /* save temporary failure messages for posterity */ 3250 if (SmtpReplyBuffer[0] == '4') 3251 (void) sm_strlcpy(SmtpError, SmtpReplyBuffer, sizeof SmtpError); 3252 3253 /* reply code 421 is "Service Shutting Down" */ 3254 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD && 3255 mci->mci_state != MCIS_QUITING) 3256 { 3257 /* send the quit protocol */ 3258 mci->mci_state = MCIS_SSD; 3259 smtpquit(m, mci, e); 3260 } 3261 3262 return r; 3263 } 3264 /* 3265 ** SMTPMESSAGE -- send message to server 3266 ** 3267 ** Parameters: 3268 ** f -- format 3269 ** m -- the mailer to control formatting. 3270 ** a, b, c -- parameters 3271 ** 3272 ** Returns: 3273 ** none. 3274 ** 3275 ** Side Effects: 3276 ** writes message to mci->mci_out. 3277 */ 3278 3279 /*VARARGS1*/ 3280 void 3281 #ifdef __STDC__ 3282 smtpmessage(char *f, MAILER *m, MCI *mci, ...) 3283 #else /* __STDC__ */ 3284 smtpmessage(f, m, mci, va_alist) 3285 char *f; 3286 MAILER *m; 3287 MCI *mci; 3288 va_dcl 3289 #endif /* __STDC__ */ 3290 { 3291 SM_VA_LOCAL_DECL 3292 3293 SM_VA_START(ap, mci); 3294 (void) sm_vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap); 3295 SM_VA_END(ap); 3296 3297 if (tTd(18, 1) || Verbose) 3298 nmessage(">>> %s", SmtpMsgBuffer); 3299 if (TrafficLogFile != NULL) 3300 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 3301 "%05d >>> %s\n", (int) CurrentPid, 3302 SmtpMsgBuffer); 3303 if (mci->mci_out != NULL) 3304 { 3305 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s%s", 3306 SmtpMsgBuffer, m == NULL ? "\r\n" 3307 : m->m_eol); 3308 } 3309 else if (tTd(18, 1)) 3310 { 3311 sm_dprintf("smtpmessage: NULL mci_out\n"); 3312 } 3313 } 3314