| 1 |
/* Mixmaster version 3 -- (C) 1999 Anonymizer Inc. |
/* Mixmaster version 3.0 -- (C) 1999 - 2004 Anonymizer Inc. and others. |
| 2 |
|
|
| 3 |
Mixmaster may be redistributed and modified under certain conditions. |
Mixmaster may be redistributed and modified under certain conditions. |
| 4 |
This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF |
This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF |
| 6 |
details. |
details. |
| 7 |
|
|
| 8 |
Socket-based mail transport services |
Socket-based mail transport services |
| 9 |
$Id: mail.c,v 1.7 2002/08/07 17:27:01 weaselp Exp $ */ |
$Id$ */ |
| 10 |
|
|
| 11 |
|
|
| 12 |
#include "mix3.h" |
#include "mix3.h" |
| 21 |
#include <netinet/in.h> |
#include <netinet/in.h> |
| 22 |
#include <arpa/inet.h> |
#include <arpa/inet.h> |
| 23 |
#include <netdb.h> |
#include <netdb.h> |
| 24 |
|
#endif /* defined(UNIX) && defined(USE_SOCK) */ |
| 25 |
|
|
| 26 |
#include <fcntl.h> |
#include <fcntl.h> |
| 27 |
#endif |
#include <time.h> |
| 28 |
|
#include <sys/stat.h> |
| 29 |
|
#include <errno.h> |
| 30 |
|
|
| 31 |
|
|
| 32 |
int sendinfofile(char *name, char *logname, BUFFER *address, BUFFER *header) |
int sendinfofile(char *name, char *logname, BUFFER *address, BUFFER *header) |
| 33 |
{ |
{ |
| 97 |
return(err); |
return(err); |
| 98 |
} |
} |
| 99 |
|
|
| 100 |
|
/* Returns true if more than one of the recipients in the |
| 101 |
|
* rcpt buffer is a remailer |
| 102 |
|
*/ |
| 103 |
|
int has_more_than_one_remailer(BUFFER *rcpts) |
| 104 |
|
{ |
| 105 |
|
BUFFER *newlinelist; |
| 106 |
|
BUFFER *line; |
| 107 |
|
int remailers = 0; |
| 108 |
|
REMAILER type1[MAXREM]; |
| 109 |
|
REMAILER type2[MAXREM]; |
| 110 |
|
int num1; |
| 111 |
|
int num2; |
| 112 |
|
int i; |
| 113 |
|
|
| 114 |
|
newlinelist = buf_new(); |
| 115 |
|
line = buf_new(); |
| 116 |
|
|
| 117 |
|
num1 = t1_rlist(type1, NULL); |
| 118 |
|
num2 = mix2_rlist(type2, NULL); |
| 119 |
|
|
| 120 |
|
rfc822_addr(rcpts, newlinelist); |
| 121 |
|
|
| 122 |
|
while (buf_getline(newlinelist, line) != -1) { |
| 123 |
|
int found = 0; |
| 124 |
|
printf("%s\n", line->data); |
| 125 |
|
|
| 126 |
|
for (i = 0; i < num2; i++) |
| 127 |
|
if (strcmp(type2[i].addr, line->data) == 0) { |
| 128 |
|
found = 1; |
| 129 |
|
break; |
| 130 |
|
} |
| 131 |
|
if (!found) |
| 132 |
|
for (i = 0; i < num1; i++) |
| 133 |
|
if (strcmp(type1[i].addr, line->data) == 0) { |
| 134 |
|
found = 1; |
| 135 |
|
break; |
| 136 |
|
} |
| 137 |
|
if (found) |
| 138 |
|
remailers++; |
| 139 |
|
} |
| 140 |
|
printf("found %d\n", remailers); |
| 141 |
|
|
| 142 |
|
buf_free(newlinelist); |
| 143 |
|
buf_free(line); |
| 144 |
|
|
| 145 |
|
return(remailers > 1); |
| 146 |
|
} |
| 147 |
|
|
| 148 |
int sendmail(BUFFER *message, char *from, BUFFER *address) |
int sendmail(BUFFER *message, char *from, BUFFER *address) |
| 149 |
{ |
{ |
| 150 |
/* returns: 0: ok 1: problem, try again -1: failed */ |
/* returns: 0: ok 1: problem, try again -1: failed */ |
| 151 |
|
|
| 152 |
BUFFER *head, *block; |
BUFFER *head, *block, *rcpt; |
| 153 |
FILE *f; |
FILE *f; |
| 154 |
int err = -1; |
int err = -1; |
| 155 |
|
int rcpt_cnt; |
| 156 |
|
|
| 157 |
head = buf_new(); |
head = buf_new(); |
| 158 |
|
rcpt = buf_new(); |
| 159 |
|
|
| 160 |
block = readdestblk( ); |
block = readdestblk( ); |
| 161 |
if ( !block ) block = buf_new( ); |
if ( !block ) block = buf_new( ); |
| 172 |
if (address != NULL) |
if (address != NULL) |
| 173 |
buf_appendf(head, "To: %b\n", address); |
buf_appendf(head, "To: %b\n", address); |
| 174 |
|
|
| 175 |
|
if (PRECEDENCE[0]) |
| 176 |
|
buf_appendf(head, "Precedence: %s\n", PRECEDENCE); |
| 177 |
|
|
| 178 |
buf_rewind(message); |
buf_rewind(message); |
| 179 |
|
|
| 180 |
if (SMTPRELAY[0]) |
/* search recipient addresses */ |
| 181 |
|
if (address == NULL) { |
| 182 |
|
BUFFER *field, *content; |
| 183 |
|
field = buf_new(); |
| 184 |
|
content = buf_new(); |
| 185 |
|
|
| 186 |
|
rcpt_cnt = 0; |
| 187 |
|
while (buf_getheader(message, field, content) == 0) { |
| 188 |
|
if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) { |
| 189 |
|
int thislinercpts = 1; |
| 190 |
|
char *tmp = content->data; |
| 191 |
|
while ((tmp = strchr(tmp+1, ','))) |
| 192 |
|
thislinercpts ++; |
| 193 |
|
rcpt_cnt += thislinercpts; |
| 194 |
|
|
| 195 |
|
if ( rcpt->data[0] ) |
| 196 |
|
buf_appends(rcpt, ", "); |
| 197 |
|
buf_cat(rcpt, content); |
| 198 |
|
} |
| 199 |
|
} |
| 200 |
|
buf_free(field); |
| 201 |
|
buf_free(content); |
| 202 |
|
} else if (address->data[0]) { |
| 203 |
|
char *tmp = address->data; |
| 204 |
|
rcpt_cnt = 1; |
| 205 |
|
while ((tmp = strchr(tmp+1, ','))) |
| 206 |
|
rcpt_cnt ++; |
| 207 |
|
|
| 208 |
|
buf_set(rcpt, address); |
| 209 |
|
} else |
| 210 |
|
rcpt_cnt = 0; |
| 211 |
|
|
| 212 |
|
buf_rewind(message); |
| 213 |
|
|
| 214 |
|
if ( ! rcpt_cnt ) { |
| 215 |
|
errlog(NOTICE, "No recipients found.\n"); |
| 216 |
|
err = 0; |
| 217 |
|
} else if ( rcpt_cnt > MAXRECIPIENTS ) { |
| 218 |
|
errlog(NOTICE, "Too many recipients. Dropping message.\n"); |
| 219 |
|
err = 0; |
| 220 |
|
} else if ( rcpt_cnt > 1 && has_more_than_one_remailer(rcpt) ) { |
| 221 |
|
errlog(NOTICE, "Message is destined to more than one remailer. Dropping.\n"); |
| 222 |
|
err = 0; |
| 223 |
|
} else if ( REMAIL && strcmp(REMAILERADDR, rcpt->data) == 0) { |
| 224 |
|
buf_cat(head, message); |
| 225 |
|
errlog(LOG, "Message loops back to us; storing in pool rather than sending it.\n"); |
| 226 |
|
err = pool_add(head, "inf"); |
| 227 |
|
} else if (SMTPRELAY[0]) |
| 228 |
err = smtpsend(head, message, from); |
err = smtpsend(head, message, from); |
| 229 |
else if (strieq(SENDMAIL, "outfile")) { |
else if (strieq(SENDMAIL, "outfile")) { |
| 230 |
char path[PATHMAX]; |
char path[PATHMAX]; |
| 231 |
FILE *f = NULL; |
FILE *f = NULL; |
| 232 |
|
#ifdef SHORTNAMES |
| 233 |
int i; |
int i; |
|
|
|
| 234 |
for (i = 0; i < 10000; i++) { |
for (i = 0; i < 10000; i++) { |
| 235 |
sprintf(path, "%s%cout%i.txt", POOLDIR, DIRSEP, i); |
snprintf(path, PATHMAX, "%s%cout%i.txt", POOLDIR, DIRSEP, i); |
| 236 |
f = fopen(path, "r"); |
f = fopen(path, "r"); |
| 237 |
if (f) |
if (f) |
| 238 |
fclose(f); |
fclose(f); |
| 240 |
break; |
break; |
| 241 |
} |
} |
| 242 |
f = fopen(path, "w"); |
f = fopen(path, "w"); |
| 243 |
|
#else /* end of SHORTNAMES */ |
| 244 |
|
static unsigned long namecounter = 0; |
| 245 |
|
struct stat statbuf; |
| 246 |
|
int count; |
| 247 |
|
char hostname[64]; |
| 248 |
|
|
| 249 |
|
hostname[0] = '\0'; |
| 250 |
|
gethostname(hostname, 63); |
| 251 |
|
hostname[63] = '\0'; |
| 252 |
|
|
| 253 |
|
/* Step 2: Stat the file. Wait for ENOENT as a response. */ |
| 254 |
|
for (count = 0;; count++) { |
| 255 |
|
snprintf(path, PATHMAX, "%s%cout.%lu.%u_%lu.%s,S=%lu.txt", |
| 256 |
|
POOLDIR, DIRSEP, time(NULL), getpid(), namecounter++, hostname, head->length + message->length); |
| 257 |
|
|
| 258 |
|
if (stat(path, &statbuf) == 0) |
| 259 |
|
errno = EEXIST; |
| 260 |
|
else if (errno == ENOENT) { /* create the file (at least try) */ |
| 261 |
|
f = fopen(path, "w"); |
| 262 |
|
if (f != NULL) |
| 263 |
|
break; /* we managed to open the file */ |
| 264 |
|
} |
| 265 |
|
if (count > 5) |
| 266 |
|
break; /* Too many retries - give up */ |
| 267 |
|
#ifdef WIN32 |
| 268 |
|
Sleep(2000); /* sleep and retry */ |
| 269 |
|
#else /* end of WIN32 */ |
| 270 |
|
sleep(2); /* sleep and retry */ |
| 271 |
|
#endif /* else not WIN32 */ |
| 272 |
|
} |
| 273 |
|
#endif /* else not SHORTNAMES */ |
| 274 |
if (f != NULL) { |
if (f != NULL) { |
| 275 |
err = buf_write(head, f); |
err = buf_write(head, f); |
| 276 |
err = buf_write(message, f); |
err = buf_write(message, f); |
| 293 |
end: |
end: |
| 294 |
buf_free(block); |
buf_free(block); |
| 295 |
buf_free(head); |
buf_free(head); |
| 296 |
|
buf_free(rcpt); |
| 297 |
return (err); |
return (err); |
| 298 |
} |
} |
| 299 |
|
|
| 316 |
{ |
{ |
| 317 |
WSACleanup(); |
WSACleanup(); |
| 318 |
} |
} |
| 319 |
#endif |
#endif /* WIN32 */ |
| 320 |
|
|
| 321 |
SOCKET opensocket(char *hostname, int port) |
SOCKET opensocket(char *hostname, int port) |
| 322 |
{ |
{ |
| 346 |
{ |
{ |
| 347 |
return (close(s)); |
return (close(s)); |
| 348 |
} |
} |
| 349 |
#endif |
#endif /* ifndef WIN32 */ |
| 350 |
|
|
| 351 |
int sock_getline(SOCKET s, BUFFER *line) |
int sock_getline(SOCKET s, BUFFER *line) |
| 352 |
{ |
{ |
| 379 |
} while (p < b->length); |
} while (p < b->length); |
| 380 |
return (0); |
return (0); |
| 381 |
} |
} |
| 382 |
#else |
#else /* end of USE_SOCK */ |
| 383 |
SOCKET opensocket(char *hostname, int port) |
SOCKET opensocket(char *hostname, int port) |
| 384 |
{ |
{ |
| 385 |
return (INVALID_SOCKET); |
return (INVALID_SOCKET); |
| 399 |
{ |
{ |
| 400 |
return (-1); |
return (-1); |
| 401 |
} |
} |
| 402 |
#endif |
#endif /* else not USE_SOCK */ |
| 403 |
|
|
| 404 |
/* send messages by SMTP ************************************************/ |
/* send messages by SMTP ************************************************/ |
| 405 |
|
|
| 406 |
static int sock_getsmtp(SOCKET s, BUFFER *line) |
static int sock_getsmtp(SOCKET s, BUFFER *response) |
| 407 |
{ |
{ |
| 408 |
int ret; |
int ret; |
| 409 |
|
BUFFER *line; |
| 410 |
|
line = buf_new(); |
| 411 |
|
|
| 412 |
do |
buf_clear(response); |
| 413 |
|
do { |
| 414 |
ret = sock_getline(s, line); |
ret = sock_getline(s, line); |
| 415 |
while (line->length >= 4 && line->data[3] == '-'); |
buf_cat(response, line); |
| 416 |
|
} while (line->length >= 4 && line->data[3] == '-'); |
| 417 |
|
buf_free(line); |
| 418 |
return (ret); |
return (ret); |
| 419 |
} |
} |
| 420 |
|
|
| 421 |
SOCKET smtp_open(void) |
SOCKET smtp_open(void) |
| 422 |
{ |
{ |
| 423 |
int s = INVALID_SOCKET; |
int s = INVALID_SOCKET; |
| 424 |
|
int esmtp = 0; |
| 425 |
BUFFER *line; |
BUFFER *line; |
| 426 |
|
|
| 427 |
#ifdef USE_SOCK |
#ifdef USE_SOCK |
| 430 |
if (s != INVALID_SOCKET) { |
if (s != INVALID_SOCKET) { |
| 431 |
line = buf_new(); |
line = buf_new(); |
| 432 |
sock_getsmtp(s, line); |
sock_getsmtp(s, line); |
| 433 |
|
if (bufifind(line, "ESMTP")) |
| 434 |
|
esmtp = 1; |
| 435 |
if (line->data[0] != '2') { |
if (line->data[0] != '2') { |
| 436 |
errlog(ERRORMSG, "SMTP relay not ready. %b\n", line); |
errlog(ERRORMSG, "SMTP relay not ready. %b\n", line); |
| 437 |
closesocket(s); |
closesocket(s); |
| 438 |
s = INVALID_SOCKET; |
s = INVALID_SOCKET; |
| 439 |
} else { |
} else { |
| 440 |
errlog(DEBUGINFO, "Opening SMTP connection.\n"); |
errlog(DEBUGINFO, "Opening SMTP connection.\n"); |
| 441 |
buf_sets(line, "HELO "); |
if (esmtp) |
| 442 |
|
buf_sets(line, "EHLO "); |
| 443 |
|
else |
| 444 |
|
buf_sets(line, "HELO "); |
| 445 |
if (HELONAME[0]) |
if (HELONAME[0]) |
| 446 |
buf_appends(line, HELONAME); |
buf_appends(line, HELONAME); |
| 447 |
else if (strchr(ENVFROM, '@')) |
else if (strchr(ENVFROM, '@')) |
| 460 |
else |
else |
| 461 |
buf_appends(line, SHORTNAME); |
buf_appends(line, SHORTNAME); |
| 462 |
} |
} |
| 463 |
|
buf_chop(line); |
| 464 |
buf_appends(line, "\r\n"); |
buf_appends(line, "\r\n"); |
| 465 |
sock_cat(s, line); |
sock_cat(s, line); |
| 466 |
sock_getsmtp(s, line); |
sock_getsmtp(s, line); |
| 468 |
errlog(ERRORMSG, "SMTP relay refuses HELO: %b\n", line); |
errlog(ERRORMSG, "SMTP relay refuses HELO: %b\n", line); |
| 469 |
closesocket(s); |
closesocket(s); |
| 470 |
s = INVALID_SOCKET; |
s = INVALID_SOCKET; |
| 471 |
|
} else if (SMTPUSERNAME[0] && esmtp && bufifind(line, "AUTH") && bufifind(line, "LOGIN")) { |
| 472 |
|
buf_sets(line, "AUTH LOGIN\r\n"); |
| 473 |
|
sock_cat(s, line); |
| 474 |
|
sock_getsmtp(s, line); |
| 475 |
|
if (!bufleft(line, "334")) { |
| 476 |
|
errlog(ERRORMSG, "SMTP AUTH fails: %b\n", line); |
| 477 |
|
goto err; |
| 478 |
|
} |
| 479 |
|
buf_sets(line, SMTPUSERNAME); |
| 480 |
|
encode(line, 0); |
| 481 |
|
buf_appends(line, "\r\n"); |
| 482 |
|
sock_cat(s, line); |
| 483 |
|
sock_getsmtp(s, line); |
| 484 |
|
if (!bufleft(line, "334")) { |
| 485 |
|
errlog(ERRORMSG, "SMTP username rejected: %b\n", line); |
| 486 |
|
goto err; |
| 487 |
|
} |
| 488 |
|
buf_sets(line, SMTPPASSWORD); |
| 489 |
|
encode(line, 0); |
| 490 |
|
buf_appends(line, "\r\n"); |
| 491 |
|
sock_cat(s, line); |
| 492 |
|
sock_getsmtp(s, line); |
| 493 |
|
if (!bufleft(line, "235")) |
| 494 |
|
errlog(ERRORMSG, "SMTP authentication failed: %b\n", line); |
| 495 |
} |
} |
| 496 |
} |
} |
| 497 |
|
err: |
| 498 |
buf_free(line); |
buf_free(line); |
| 499 |
} |
} |
| 500 |
#endif |
#endif /* USE_SOCK */ |
| 501 |
return (s); |
return (s); |
| 502 |
} |
} |
| 503 |
|
|
| 517 |
errlog(WARNING, "SMTP quit failed: %b\n", line); |
errlog(WARNING, "SMTP quit failed: %b\n", line); |
| 518 |
closesocket(s); |
closesocket(s); |
| 519 |
buf_free(line); |
buf_free(line); |
| 520 |
#endif |
#endif /* USE_SOCK */ |
| 521 |
return (ret); |
return (ret); |
| 522 |
} |
} |
| 523 |
|
|
| 535 |
while (buf_getheader(head, field, content) == 0) |
while (buf_getheader(head, field, content) == 0) |
| 536 |
if (bufieq(field, "to")) |
if (bufieq(field, "to")) |
| 537 |
#ifdef BROKEN_MTA |
#ifdef BROKEN_MTA |
| 538 |
if (!bufifind(rcpt, content->data)) |
if (!bufifind(rcpt, content->data)) |
| 539 |
/* Do not add the same recipient twice. |
/* Do not add the same recipient twice. |
| 540 |
Needed for brain-dead MTAs. */ |
Needed for brain-dead MTAs. */ |
| 541 |
#endif //BROKEN_MTA |
#endif /* BROKEN_MTA */ |
| 542 |
rfc822_addr(content, rcpt); |
rfc822_addr(content, rcpt); |
| 543 |
buf_rewind(head); |
buf_rewind(head); |
| 544 |
|
|
| 545 |
while (buf_isheader(message) && buf_getheader(message, field, content) == 0) { |
while (buf_isheader(message) && buf_getheader(message, field, content) == 0) { |
| 546 |
if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) { |
if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) { |
| 547 |
#ifdef BROKEN_MTA |
#ifdef BROKEN_MTA |
| 548 |
if (!bufifind(rcpt, content->data)) |
if (!bufifind(rcpt, content->data)) |
| 549 |
/* Do not add the same recipient twice. |
/* Do not add the same recipient twice. |
| 550 |
Needed for brain-dead MTAs. */ |
Needed for brain-dead MTAs. */ |
| 551 |
#endif //BROKEN_MTA |
#endif /* BROKEN_MTA */ |
| 552 |
rfc822_addr(content, rcpt); |
rfc822_addr(content, rcpt); |
| 553 |
} |
} |
| 554 |
if (!bufieq(field, "bcc")) |
if (!bufieq(field, "bcc")) |
| 582 |
errlog(ERRORMSG, "SMTP relay error: %b\n", line); |
errlog(ERRORMSG, "SMTP relay error: %b\n", line); |
| 583 |
goto end; |
goto end; |
| 584 |
} |
} |
| 585 |
|
if (bufleft(line, "530")) { |
| 586 |
|
errlog(ERRORMSG, "SMTP authentication required: %b\n", line); |
| 587 |
|
goto end; |
| 588 |
|
} |
| 589 |
} |
} |
| 590 |
|
|
| 591 |
buf_sets(line, "DATA\r\n"); |
buf_sets(line, "DATA\r\n"); |
| 623 |
buf_free(field); |
buf_free(field); |
| 624 |
buf_free(content); |
buf_free(content); |
| 625 |
buf_free(rcpt); |
buf_free(rcpt); |
| 626 |
#endif |
#endif /* USE_SOCK */ |
| 627 |
return (ret); |
return (ret); |
| 628 |
} |
} |
| 629 |
|
|
| 674 |
SOCKET server = INVALID_SOCKET; |
SOCKET server = INVALID_SOCKET; |
| 675 |
BUFFER *line; |
BUFFER *line; |
| 676 |
int authenticated = 0; |
int authenticated = 0; |
| 677 |
char c, md[33]; |
char md[33]; |
| 678 |
|
int c; |
| 679 |
|
|
| 680 |
line = buf_new(); |
line = buf_new(); |
| 681 |
server = opensocket(host, 110); |
server = opensocket(host, 110); |
| 849 |
f = mix_openfile(POP3CONF, "r"); |
f = mix_openfile(POP3CONF, "r"); |
| 850 |
if (f != NULL) |
if (f != NULL) |
| 851 |
while (fgets(cfg, sizeof(cfg), f) != NULL) { |
while (fgets(cfg, sizeof(cfg), f) != NULL) { |
| 852 |
|
if (cfg[0] == '#') |
| 853 |
|
continue; |
| 854 |
if (strchr(cfg, '@')) |
if (strchr(cfg, '@')) |
| 855 |
strchr(cfg, '@')[0] = ' '; |
strchr(cfg, '@')[0] = ' '; |
| 856 |
if (sscanf(cfg, "%127s %127s %127s %4s", user, host, pass, auth) < 3) |
if (sscanf(cfg, "%127s %127s %127s %4s", user, host, pass, auth) < 3) |
| 896 |
buf_free(line); |
buf_free(line); |
| 897 |
buf_free(msg); |
buf_free(msg); |
| 898 |
} |
} |
| 899 |
#endif |
#endif /* USE_SOCK */ |