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