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