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