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