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