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