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