1/*++ 2/* NAME 3/* qmgr_message 3 4/* SUMMARY 5/* in-core message structures 6/* SYNOPSIS 7/* #include "qmgr.h" 8/* 9/* int qmgr_message_count; 10/* int qmgr_recipient_count; 11/* 12/* QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags, mode) 13/* const char *class; 14/* const char *name; 15/* int qflags; 16/* mode_t mode; 17/* 18/* QMGR_MESSAGE *qmgr_message_realloc(message) 19/* QMGR_MESSAGE *message; 20/* 21/* void qmgr_message_free(message) 22/* QMGR_MESSAGE *message; 23/* 24/* void qmgr_message_update_warn(message) 25/* QMGR_MESSAGE *message; 26/* 27/* void qmgr_message_kill_record(message, offset) 28/* QMGR_MESSAGE *message; 29/* long offset; 30/* DESCRIPTION 31/* This module performs en-gross operations on queue messages. 32/* 33/* qmgr_message_count is a global counter for the total number 34/* of in-core message structures (i.e. the total size of the 35/* `active' message queue). 36/* 37/* qmgr_recipient_count is a global counter for the total number 38/* of in-core recipient structures (i.e. the sum of all recipients 39/* in all in-core message structures). 40/* 41/* qmgr_message_alloc() creates an in-core message structure 42/* with sender and recipient information taken from the named queue 43/* file. A null result means the queue file could not be read or 44/* that the queue file contained incorrect information. A result 45/* QMGR_MESSAGE_LOCKED means delivery must be deferred. The number 46/* of recipients read from a queue file is limited by the global 47/* var_qmgr_rcpt_limit configuration parameter. When the limit 48/* is reached, the \fIrcpt_offset\fR structure member is set to 49/* the position where the read was terminated. Recipients are 50/* run through the resolver, and are assigned to destination 51/* queues. Recipients that cannot be assigned are deferred or 52/* bounced. Mail that has bounced twice is silently absorbed. 53/* A non-zero mode means change the queue file permissions. 54/* 55/* qmgr_message_realloc() resumes reading recipients from the queue 56/* file, and updates the recipient list and \fIrcpt_offset\fR message 57/* structure members. A null result means that the file could not be 58/* read or that the file contained incorrect information. 59/* 60/* qmgr_message_free() destroys an in-core message structure and makes 61/* the resources available for reuse. It is an error to destroy 62/* a message structure that is still referenced by queue entry structures. 63/* 64/* qmgr_message_update_warn() takes a closed message, opens it, updates 65/* the warning field, and closes it again. 66/* 67/* qmgr_message_kill_record() takes a closed message, opens it, updates 68/* the record type at the given offset to "killed", and closes the file. 69/* A killed envelope record is ignored. Killed records are not allowed 70/* inside the message content. 71/* DIAGNOSTICS 72/* Warnings: malformed message file. Fatal errors: out of memory. 73/* SEE ALSO 74/* envelope(3) message envelope parser 75/* LICENSE 76/* .ad 77/* .fi 78/* The Secure Mailer license must be distributed with this software. 79/* AUTHOR(S) 80/* Wietse Venema 81/* IBM T.J. Watson Research 82/* P.O. Box 704 83/* Yorktown Heights, NY 10598, USA 84/*--*/ 85 86/* System library. */ 87 88#include <sys_defs.h> 89#include <sys/stat.h> 90#include <stdlib.h> 91#include <stdio.h> /* sscanf() */ 92#include <fcntl.h> 93#include <errno.h> 94#include <unistd.h> 95#include <string.h> 96#include <ctype.h> 97 98#ifdef STRCASECMP_IN_STRINGS_H 99#include <strings.h> 100#endif 101 102/* Utility library. */ 103 104#include <msg.h> 105#include <mymalloc.h> 106#include <vstring.h> 107#include <vstream.h> 108#include <split_at.h> 109#include <valid_hostname.h> 110#include <argv.h> 111#include <stringops.h> 112#include <myflock.h> 113 114/* Global library. */ 115 116#include <dict.h> 117#include <mail_queue.h> 118#include <mail_params.h> 119#include <canon_addr.h> 120#include <record.h> 121#include <rec_type.h> 122#include <sent.h> 123#include <deliver_completed.h> 124#include <opened.h> 125#include <verp_sender.h> 126#include <mail_proto.h> 127#include <qmgr_user.h> 128#include <split_addr.h> 129#include <dsn_mask.h> 130#include <rec_attr_map.h> 131 132/* Client stubs. */ 133 134#include <rewrite_clnt.h> 135#include <resolve_clnt.h> 136 137/* Application-specific. */ 138 139#include "qmgr.h" 140 141int qmgr_message_count; 142int qmgr_recipient_count; 143 144/* qmgr_message_create - create in-core message structure */ 145 146static QMGR_MESSAGE *qmgr_message_create(const char *queue_name, 147 const char *queue_id, int qflags) 148{ 149 QMGR_MESSAGE *message; 150 151 message = (QMGR_MESSAGE *) mymalloc(sizeof(QMGR_MESSAGE)); 152 qmgr_message_count++; 153 message->flags = 0; 154 message->qflags = qflags; 155 message->tflags = 0; 156 message->tflags_offset = 0; 157 message->rflags = QMGR_READ_FLAG_DEFAULT; 158 message->fp = 0; 159 message->refcount = 0; 160 message->single_rcpt = 0; 161 message->arrival_time.tv_sec = message->arrival_time.tv_usec = 0; 162 message->create_time = 0; 163 GETTIMEOFDAY(&message->active_time); 164 message->data_offset = 0; 165 message->queue_id = mystrdup(queue_id); 166 message->queue_name = mystrdup(queue_name); 167 message->encoding = 0; 168 message->sender = 0; 169 message->dsn_envid = 0; 170 message->dsn_ret = 0; 171 message->filter_xport = 0; 172 message->inspect_xport = 0; 173 message->redirect_addr = 0; 174 message->data_size = 0; 175 message->cont_length = 0; 176 message->warn_offset = 0; 177 message->warn_time = 0; 178 message->rcpt_offset = 0; 179 message->verp_delims = 0; 180 message->client_name = 0; 181 message->client_addr = 0; 182 message->client_port = 0; 183 message->client_proto = 0; 184 message->client_helo = 0; 185 message->sasl_method = 0; 186 message->sasl_username = 0; 187 message->sasl_sender = 0; 188 message->log_ident = 0; 189 message->rewrite_context = 0; 190 recipient_list_init(&message->rcpt_list, RCPT_LIST_INIT_QUEUE); 191 return (message); 192} 193 194/* qmgr_message_close - close queue file */ 195 196static void qmgr_message_close(QMGR_MESSAGE *message) 197{ 198 vstream_fclose(message->fp); 199 message->fp = 0; 200} 201 202/* qmgr_message_open - open queue file */ 203 204static int qmgr_message_open(QMGR_MESSAGE *message) 205{ 206 207 /* 208 * Sanity check. 209 */ 210 if (message->fp) 211 msg_panic("%s: queue file is open", message->queue_id); 212 213 /* 214 * Open this queue file. Skip files that we cannot open. Back off when 215 * the system appears to be running out of resources. 216 */ 217 if ((message->fp = mail_queue_open(message->queue_name, 218 message->queue_id, 219 O_RDWR, 0)) == 0) { 220 if (errno != ENOENT) 221 msg_fatal("open %s %s: %m", message->queue_name, message->queue_id); 222 msg_warn("open %s %s: %m", message->queue_name, message->queue_id); 223 return (-1); 224 } 225 return (0); 226} 227 228/* qmgr_message_oldstyle_scan - support for Postfix < 1.0 queue files */ 229 230static void qmgr_message_oldstyle_scan(QMGR_MESSAGE *message) 231{ 232 VSTRING *buf; 233 long orig_offset, extra_offset; 234 int rec_type; 235 char *start; 236 237 /* 238 * Initialize. No early returns or we have a memory leak. 239 */ 240 buf = vstring_alloc(100); 241 if ((orig_offset = vstream_ftell(message->fp)) < 0) 242 msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp)); 243 244 /* 245 * Rewind to the very beginning to make sure we see all records. 246 */ 247 if (vstream_fseek(message->fp, 0, SEEK_SET) < 0) 248 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); 249 250 /* 251 * Scan through the old style queue file. Count the total number of 252 * recipients and find the data/extra sections offsets. Note that the new 253 * queue files require that data_size equals extra_offset - data_offset, 254 * so we set data_size to this as well and ignore the size record itself 255 * completely. 256 */ 257 for (;;) { 258 rec_type = rec_get(message->fp, buf, 0); 259 if (rec_type <= 0) 260 /* Report missing end record later. */ 261 break; 262 start = vstring_str(buf); 263 if (msg_verbose > 1) 264 msg_info("old-style scan record %c %s", rec_type, start); 265 if (rec_type == REC_TYPE_END) 266 break; 267 if (rec_type == REC_TYPE_MESG) { 268 if (message->data_offset == 0) { 269 if ((message->data_offset = vstream_ftell(message->fp)) < 0) 270 msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp)); 271 if ((extra_offset = atol(start)) <= message->data_offset) 272 msg_fatal("bad extra offset %s file %s", 273 start, VSTREAM_PATH(message->fp)); 274 if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0) 275 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); 276 message->data_size = extra_offset - message->data_offset; 277 } 278 continue; 279 } 280 } 281 282 /* 283 * Clean up. 284 */ 285 if (vstream_fseek(message->fp, orig_offset, SEEK_SET) < 0) 286 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); 287 vstring_free(buf); 288 289 /* 290 * Sanity checks. Verify that all required information was found, 291 * including the queue file end marker. 292 */ 293 if (message->data_offset == 0 || rec_type != REC_TYPE_END) 294 msg_fatal("%s: envelope records out of order", message->queue_id); 295} 296 297/* qmgr_message_read - read envelope records */ 298 299static int qmgr_message_read(QMGR_MESSAGE *message) 300{ 301 VSTRING *buf; 302 int rec_type; 303 long curr_offset; 304 long save_offset = message->rcpt_offset; /* save a flag */ 305 char *start; 306 int nrcpt = 0; 307 const char *error_text; 308 char *name; 309 char *value; 310 char *orig_rcpt = 0; 311 int count; 312 int dsn_notify = 0; 313 char *dsn_orcpt = 0; 314 int n; 315 int have_log_client_attr = 0; 316 317 /* 318 * Initialize. No early returns or we have a memory leak. 319 */ 320 buf = vstring_alloc(100); 321 322 /* 323 * If we re-open this file, skip over on-file recipient records that we 324 * already looked at, and refill the in-core recipient address list. 325 */ 326 if (message->rcpt_offset) { 327 if (message->rcpt_list.len) 328 msg_panic("%s: recipient list not empty on recipient reload", 329 message->queue_id); 330 if (vstream_fseek(message->fp, message->rcpt_offset, SEEK_SET) < 0) 331 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); 332 message->rcpt_offset = 0; 333 } 334 335 /* 336 * Read envelope records. XXX Rely on the front-end programs to enforce 337 * record size limits. Read up to var_qmgr_rcpt_limit recipients from the 338 * queue file, to protect against memory exhaustion. Recipient records 339 * may appear before or after the message content, so we keep reading 340 * from the queue file until we have enough recipients (rcpt_offset != 0) 341 * and until we know all the non-recipient information. 342 * 343 * When reading recipients from queue file, stop reading when we reach a 344 * per-message in-core recipient limit rather than a global in-core 345 * recipient limit. Use the global recipient limit only in order to stop 346 * opening queue files. The purpose is to achieve equal delay for 347 * messages with recipient counts up to var_qmgr_rcpt_limit recipients. 348 * 349 * If we would read recipients up to a global recipient limit, the average 350 * number of in-core recipients per message would asymptotically approach 351 * (global recipient limit)/(active queue size limit), which gives equal 352 * delay per recipient rather than equal delay per message. 353 * 354 * On the first open, we must examine all non-recipient records. 355 * 356 * Optimization: when we know that recipient records are not mixed with 357 * non-recipient records, as is typical with mailing list mail, then we 358 * can avoid having to examine all the queue file records before we can 359 * start deliveries. This avoids some file system thrashing with huge 360 * mailing lists. 361 */ 362 for (;;) { 363 if ((curr_offset = vstream_ftell(message->fp)) < 0) 364 msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp)); 365 if (curr_offset == message->data_offset && curr_offset > 0) { 366 if (vstream_fseek(message->fp, message->data_size, SEEK_CUR) < 0) 367 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); 368 curr_offset += message->data_size; 369 } 370 rec_type = rec_get_raw(message->fp, buf, 0, REC_FLAG_NONE); 371 start = vstring_str(buf); 372 if (msg_verbose > 1) 373 msg_info("record %c %s", rec_type, start); 374 if (rec_type == REC_TYPE_PTR) { 375 if ((rec_type = rec_goto(message->fp, start)) == REC_TYPE_ERROR) 376 break; 377 /* Need to update curr_offset after pointer jump. */ 378 continue; 379 } 380 if (rec_type <= 0) { 381 msg_warn("%s: message rejected: missing end record", 382 message->queue_id); 383 break; 384 } 385 if (rec_type == REC_TYPE_END) { 386 message->rflags |= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT; 387 break; 388 } 389 390 /* 391 * Map named attributes to pseudo record types, so that we don't have 392 * to pollute the queue file with records that are incompatible with 393 * past Postfix versions. Preferably, people should be able to back 394 * out from an upgrade without losing mail. 395 */ 396 if (rec_type == REC_TYPE_ATTR) { 397 if ((error_text = split_nameval(start, &name, &value)) != 0) { 398 msg_warn("%s: ignoring bad attribute: %s: %.200s", 399 message->queue_id, error_text, start); 400 rec_type = REC_TYPE_ERROR; 401 break; 402 } 403 if ((n = rec_attr_map(name)) != 0) { 404 start = value; 405 rec_type = n; 406 } 407 } 408 409 /* 410 * Process recipient records. 411 */ 412 if (rec_type == REC_TYPE_RCPT) { 413 /* See also below for code setting orig_rcpt etc. */ 414#define FUDGE(x) ((x) * (var_qmgr_fudge / 100.0)) 415 if (message->rcpt_offset == 0) { 416 recipient_list_add(&message->rcpt_list, curr_offset, 417 dsn_orcpt ? dsn_orcpt : "", 418 dsn_notify ? dsn_notify : 0, 419 orig_rcpt ? orig_rcpt : "", start); 420 if (dsn_orcpt) { 421 myfree(dsn_orcpt); 422 dsn_orcpt = 0; 423 } 424 if (orig_rcpt) { 425 myfree(orig_rcpt); 426 orig_rcpt = 0; 427 } 428 if (dsn_notify) 429 dsn_notify = 0; 430 if (message->rcpt_list.len >= FUDGE(var_qmgr_rcpt_limit)) { 431 if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0) 432 msg_fatal("vstream_ftell %s: %m", 433 VSTREAM_PATH(message->fp)); 434 if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT) 435 /* We already examined all non-recipient records. */ 436 break; 437 if (message->rflags & QMGR_READ_FLAG_MIXED_RCPT_OTHER) 438 /* Examine all remaining non-recipient records. */ 439 continue; 440 /* Optimizations for "pure recipient" record sections. */ 441 if (curr_offset > message->data_offset) { 442 /* We already examined all non-recipient records. */ 443 message->rflags |= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT; 444 break; 445 } 446 /* Examine non-recipient records in extracted segment. */ 447 if (vstream_fseek(message->fp, message->data_offset 448 + message->data_size, SEEK_SET) < 0) 449 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); 450 continue; 451 } 452 } 453 continue; 454 } 455 if (rec_type == REC_TYPE_DONE || rec_type == REC_TYPE_DRCP) { 456 if (message->rcpt_offset == 0) { 457 if (dsn_orcpt) { 458 myfree(dsn_orcpt); 459 dsn_orcpt = 0; 460 } 461 if (orig_rcpt) { 462 myfree(orig_rcpt); 463 orig_rcpt = 0; 464 } 465 if (dsn_notify) 466 dsn_notify = 0; 467 } 468 continue; 469 } 470 if (rec_type == REC_TYPE_DSN_ORCPT) { 471 /* See also above for code clearing dsn_orcpt. */ 472 if (dsn_orcpt != 0) { 473 msg_warn("%s: ignoring out-of-order DSN original recipient address <%.200s>", 474 message->queue_id, dsn_orcpt); 475 myfree(dsn_orcpt); 476 dsn_orcpt = 0; 477 } 478 if (message->rcpt_offset == 0) 479 dsn_orcpt = mystrdup(start); 480 continue; 481 } 482 if (rec_type == REC_TYPE_DSN_NOTIFY) { 483 /* See also above for code clearing dsn_notify. */ 484 if (dsn_notify != 0) { 485 msg_warn("%s: ignoring out-of-order DSN notify flags <%d>", 486 message->queue_id, dsn_notify); 487 dsn_notify = 0; 488 } 489 if (message->rcpt_offset == 0) { 490 if (!alldig(start) || (n = atoi(start)) == 0 || !DSN_NOTIFY_OK(n)) 491 msg_warn("%s: ignoring malformed DSN notify flags <%.200s>", 492 message->queue_id, start); 493 else 494 dsn_notify = n; 495 continue; 496 } 497 } 498 if (rec_type == REC_TYPE_ORCP) { 499 /* See also above for code clearing orig_rcpt. */ 500 if (orig_rcpt != 0) { 501 msg_warn("%s: ignoring out-of-order original recipient <%.200s>", 502 message->queue_id, orig_rcpt); 503 myfree(orig_rcpt); 504 orig_rcpt = 0; 505 } 506 if (message->rcpt_offset == 0) 507 orig_rcpt = mystrdup(start); 508 continue; 509 } 510 511 /* 512 * Process non-recipient records. 513 */ 514 if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT) 515 /* We already examined all non-recipient records. */ 516 continue; 517 if (rec_type == REC_TYPE_SIZE) { 518 if (message->data_offset == 0) { 519 if ((count = sscanf(start, "%ld %ld %d %d %ld", 520 &message->data_size, &message->data_offset, 521 &nrcpt, &message->rflags, 522 &message->cont_length)) >= 3) { 523 /* Postfix >= 1.0 (a.k.a. 20010228). */ 524 if (message->data_offset <= 0 || message->data_size <= 0) { 525 msg_warn("%s: invalid size record: %.100s", 526 message->queue_id, start); 527 rec_type = REC_TYPE_ERROR; 528 break; 529 } 530 if (message->rflags & ~QMGR_READ_FLAG_USER) { 531 msg_warn("%s: invalid flags in size record: %.100s", 532 message->queue_id, start); 533 rec_type = REC_TYPE_ERROR; 534 break; 535 } 536 } else if (count == 1) { 537 /* Postfix < 1.0 (a.k.a. 20010228). */ 538 qmgr_message_oldstyle_scan(message); 539 } else { 540 /* Can't happen. */ 541 msg_warn("%s: message rejected: weird size record", 542 message->queue_id); 543 rec_type = REC_TYPE_ERROR; 544 break; 545 } 546 } 547 /* Postfix < 2.4 compatibility. */ 548 if (message->cont_length == 0) { 549 message->cont_length = message->data_size; 550 } else if (message->cont_length < 0) { 551 msg_warn("%s: invalid size record: %.100s", 552 message->queue_id, start); 553 rec_type = REC_TYPE_ERROR; 554 break; 555 } 556 continue; 557 } 558 if (rec_type == REC_TYPE_TIME) { 559 if (message->arrival_time.tv_sec == 0) 560 REC_TYPE_TIME_SCAN(start, message->arrival_time); 561 continue; 562 } 563 if (rec_type == REC_TYPE_CTIME) { 564 if (message->create_time == 0) 565 message->create_time = atol(start); 566 continue; 567 } 568 if (rec_type == REC_TYPE_FILT) { 569 if (message->filter_xport != 0) 570 myfree(message->filter_xport); 571 message->filter_xport = mystrdup(start); 572 continue; 573 } 574 if (rec_type == REC_TYPE_INSP) { 575 if (message->inspect_xport != 0) 576 myfree(message->inspect_xport); 577 message->inspect_xport = mystrdup(start); 578 continue; 579 } 580 if (rec_type == REC_TYPE_RDR) { 581 if (message->redirect_addr != 0) 582 myfree(message->redirect_addr); 583 message->redirect_addr = mystrdup(start); 584 continue; 585 } 586 if (rec_type == REC_TYPE_FROM) { 587 if (message->sender == 0) { 588 message->sender = mystrdup(start); 589 opened(message->queue_id, message->sender, 590 message->cont_length, nrcpt, 591 "queue %s", message->queue_name); 592 } 593 continue; 594 } 595 if (rec_type == REC_TYPE_DSN_ENVID) { 596 if (message->dsn_envid == 0) 597 message->dsn_envid = mystrdup(start); 598 } 599 if (rec_type == REC_TYPE_DSN_RET) { 600 if (message->dsn_ret == 0) { 601 if (!alldig(start) || (n = atoi(start)) == 0 || !DSN_RET_OK(n)) 602 msg_warn("%s: ignoring malformed DSN RET flags in queue file record:%.100s", 603 message->queue_id, start); 604 else 605 message->dsn_ret = n; 606 } 607 } 608 if (rec_type == REC_TYPE_ATTR) { 609 /* Allow extra segment to override envelope segment info. */ 610 if (strcmp(name, MAIL_ATTR_ENCODING) == 0) { 611 if (message->encoding != 0) 612 myfree(message->encoding); 613 message->encoding = mystrdup(value); 614 } 615 616 /* 617 * Backwards compatibility. Before Postfix 2.3, the logging 618 * attributes were called client_name, etc. Now they are called 619 * log_client_name. etc., and client_name is used for the actual 620 * client information. To support old queue files, we accept both 621 * names for the purpose of logging; the new name overrides the 622 * old one. 623 * 624 * XXX Do not use the "legacy" client_name etc. attribute values for 625 * initializing the logging attributes, when this file already 626 * contains the "modern" log_client_name etc. logging attributes. 627 * Otherwise, logging attributes that are not present in the 628 * queue file would be set with information from the real client. 629 */ 630 else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_NAME) == 0) { 631 if (have_log_client_attr == 0 && message->client_name == 0) 632 message->client_name = mystrdup(value); 633 } else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_ADDR) == 0) { 634 if (have_log_client_attr == 0 && message->client_addr == 0) 635 message->client_addr = mystrdup(value); 636 } else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_PORT) == 0) { 637 if (have_log_client_attr == 0 && message->client_port == 0) 638 message->client_port = mystrdup(value); 639 } else if (strcmp(name, MAIL_ATTR_ACT_PROTO_NAME) == 0) { 640 if (have_log_client_attr == 0 && message->client_proto == 0) 641 message->client_proto = mystrdup(value); 642 } else if (strcmp(name, MAIL_ATTR_ACT_HELO_NAME) == 0) { 643 if (have_log_client_attr == 0 && message->client_helo == 0) 644 message->client_helo = mystrdup(value); 645 } 646 /* Original client attributes. */ 647 else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_NAME) == 0) { 648 if (message->client_name != 0) 649 myfree(message->client_name); 650 message->client_name = mystrdup(value); 651 have_log_client_attr = 1; 652 } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_ADDR) == 0) { 653 if (message->client_addr != 0) 654 myfree(message->client_addr); 655 message->client_addr = mystrdup(value); 656 have_log_client_attr = 1; 657 } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_PORT) == 0) { 658 if (message->client_port != 0) 659 myfree(message->client_port); 660 message->client_port = mystrdup(value); 661 have_log_client_attr = 1; 662 } else if (strcmp(name, MAIL_ATTR_LOG_PROTO_NAME) == 0) { 663 if (message->client_proto != 0) 664 myfree(message->client_proto); 665 message->client_proto = mystrdup(value); 666 have_log_client_attr = 1; 667 } else if (strcmp(name, MAIL_ATTR_LOG_HELO_NAME) == 0) { 668 if (message->client_helo != 0) 669 myfree(message->client_helo); 670 message->client_helo = mystrdup(value); 671 have_log_client_attr = 1; 672 } else if (strcmp(name, MAIL_ATTR_SASL_METHOD) == 0) { 673 if (message->sasl_method == 0) 674 message->sasl_method = mystrdup(value); 675 else 676 msg_warn("%s: ignoring multiple %s attribute: %s", 677 message->queue_id, MAIL_ATTR_SASL_METHOD, value); 678 } else if (strcmp(name, MAIL_ATTR_SASL_USERNAME) == 0) { 679 if (message->sasl_username == 0) 680 message->sasl_username = mystrdup(value); 681 else 682 msg_warn("%s: ignoring multiple %s attribute: %s", 683 message->queue_id, MAIL_ATTR_SASL_USERNAME, value); 684 } else if (strcmp(name, MAIL_ATTR_SASL_SENDER) == 0) { 685 if (message->sasl_sender == 0) 686 message->sasl_sender = mystrdup(value); 687 else 688 msg_warn("%s: ignoring multiple %s attribute: %s", 689 message->queue_id, MAIL_ATTR_SASL_SENDER, value); 690 } else if (strcmp(name, MAIL_ATTR_LOG_IDENT) == 0) { 691 if (message->log_ident == 0) 692 message->log_ident = mystrdup(value); 693 else 694 msg_warn("%s: ignoring multiple %s attribute: %s", 695 message->queue_id, MAIL_ATTR_LOG_IDENT, value); 696 } else if (strcmp(name, MAIL_ATTR_RWR_CONTEXT) == 0) { 697 if (message->rewrite_context == 0) 698 message->rewrite_context = mystrdup(value); 699 else 700 msg_warn("%s: ignoring multiple %s attribute: %s", 701 message->queue_id, MAIL_ATTR_RWR_CONTEXT, value); 702 } 703 704 /* 705 * Optional tracing flags (verify, sendmail -v, sendmail -bv). 706 * This record is killed after a trace logfile report is sent and 707 * after the logfile is deleted. 708 */ 709 else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) { 710 message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value)); 711 if (message->tflags == DEL_REQ_FLAG_RECORD) 712 message->tflags_offset = curr_offset; 713 else 714 message->tflags_offset = 0; 715 } 716 continue; 717 } 718 if (rec_type == REC_TYPE_WARN) { 719 if (message->warn_offset == 0) { 720 message->warn_offset = curr_offset; 721 REC_TYPE_WARN_SCAN(start, message->warn_time); 722 } 723 continue; 724 } 725 if (rec_type == REC_TYPE_VERP) { 726 if (message->verp_delims == 0) { 727 if (message->sender == 0 || message->sender[0] == 0) { 728 msg_warn("%s: ignoring VERP request for null sender", 729 message->queue_id); 730 } else if (verp_delims_verify(start) != 0) { 731 msg_warn("%s: ignoring bad VERP request: \"%.100s\"", 732 message->queue_id, start); 733 } else { 734 if (msg_verbose) 735 msg_info("%s: enabling VERP for sender \"%.100s\"", 736 message->queue_id, message->sender); 737 message->single_rcpt = 1; 738 message->verp_delims = mystrdup(start); 739 } 740 } 741 continue; 742 } 743 } 744 745 /* 746 * Grr. 747 */ 748 if (dsn_orcpt != 0) { 749 if (rec_type > 0) 750 msg_warn("%s: ignoring out-of-order DSN original recipient <%.200s>", 751 message->queue_id, dsn_orcpt); 752 myfree(orig_rcpt); 753 } 754 if (orig_rcpt != 0) { 755 if (rec_type > 0) 756 msg_warn("%s: ignoring out-of-order original recipient <%.200s>", 757 message->queue_id, orig_rcpt); 758 myfree(orig_rcpt); 759 } 760 761 /* 762 * Avoid clumsiness elsewhere in the program. When sending data across an 763 * IPC channel, sending an empty string is more convenient than sending a 764 * null pointer. 765 */ 766 if (message->dsn_envid == 0) 767 message->dsn_envid = mystrdup(""); 768 if (message->encoding == 0) 769 message->encoding = mystrdup(MAIL_ATTR_ENC_NONE); 770 if (message->client_name == 0) 771 message->client_name = mystrdup(""); 772 if (message->client_addr == 0) 773 message->client_addr = mystrdup(""); 774 if (message->client_port == 0) 775 message->client_port = mystrdup(""); 776 if (message->client_proto == 0) 777 message->client_proto = mystrdup(""); 778 if (message->client_helo == 0) 779 message->client_helo = mystrdup(""); 780 if (message->sasl_method == 0) 781 message->sasl_method = mystrdup(""); 782 if (message->sasl_username == 0) 783 message->sasl_username = mystrdup(""); 784 if (message->sasl_sender == 0) 785 message->sasl_sender = mystrdup(""); 786 if (message->log_ident == 0) 787 message->log_ident = mystrdup(""); 788 if (message->rewrite_context == 0) 789 message->rewrite_context = mystrdup(MAIL_ATTR_RWR_LOCAL); 790 /* Postfix < 2.3 compatibility. */ 791 if (message->create_time == 0) 792 message->create_time = message->arrival_time.tv_sec; 793 794 /* 795 * Clean up. 796 */ 797 vstring_free(buf); 798 799 /* 800 * Sanity checks. Verify that all required information was found, 801 * including the queue file end marker. 802 */ 803 if (rec_type <= 0) { 804 /* Already logged warning. */ 805 } else if (message->arrival_time.tv_sec == 0) { 806 msg_warn("%s: message rejected: missing arrival time record", 807 message->queue_id); 808 } else if (message->sender == 0) { 809 msg_warn("%s: message rejected: missing sender record", 810 message->queue_id); 811 } else if (message->data_offset == 0) { 812 msg_warn("%s: message rejected: missing size record", 813 message->queue_id); 814 } else { 815 return (0); 816 } 817 message->rcpt_offset = save_offset; /* restore flag */ 818 return (-1); 819} 820 821/* qmgr_message_update_warn - update the time of next delay warning */ 822 823void qmgr_message_update_warn(QMGR_MESSAGE *message) 824{ 825 826 /* 827 * XXX eventually this should let us schedule multiple warnings, right 828 * now it just allows for one. 829 */ 830 if (qmgr_message_open(message) 831 || vstream_fseek(message->fp, message->warn_offset, SEEK_SET) < 0 832 || rec_fprintf(message->fp, REC_TYPE_WARN, REC_TYPE_WARN_FORMAT, 833 REC_TYPE_WARN_ARG(0)) < 0 834 || vstream_fflush(message->fp)) 835 msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp)); 836 qmgr_message_close(message); 837} 838 839/* qmgr_message_kill_record - mark one message record as killed */ 840 841void qmgr_message_kill_record(QMGR_MESSAGE *message, long offset) 842{ 843 if (offset <= 0) 844 msg_panic("qmgr_message_kill_record: bad offset 0x%lx", offset); 845 if (qmgr_message_open(message) 846 || rec_put_type(message->fp, REC_TYPE_KILL, offset) < 0 847 || vstream_fflush(message->fp)) 848 msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp)); 849 qmgr_message_close(message); 850} 851 852/* qmgr_message_sort_compare - compare recipient information */ 853 854static int qmgr_message_sort_compare(const void *p1, const void *p2) 855{ 856 RECIPIENT *rcpt1 = (RECIPIENT *) p1; 857 RECIPIENT *rcpt2 = (RECIPIENT *) p2; 858 QMGR_QUEUE *queue1; 859 QMGR_QUEUE *queue2; 860 char *at1; 861 char *at2; 862 int result; 863 864 /* 865 * Compare most significant to least significant recipient attributes. 866 * The comparison function must be transitive, so NULL values need to be 867 * assigned an ordinal (we set NULL last). 868 */ 869 870 queue1 = rcpt1->u.queue; 871 queue2 = rcpt2->u.queue; 872 if (queue1 != 0 && queue2 == 0) 873 return (-1); 874 if (queue1 == 0 && queue2 != 0) 875 return (1); 876 if (queue1 != 0 && queue2 != 0) { 877 878 /* 879 * Compare message transport. 880 */ 881 if ((result = strcmp(queue1->transport->name, 882 queue2->transport->name)) != 0) 883 return (result); 884 885 /* 886 * Compare queue name (nexthop or recipient@nexthop). 887 */ 888 if ((result = strcmp(queue1->name, queue2->name)) != 0) 889 return (result); 890 } 891 892 /* 893 * Compare recipient domain. 894 */ 895 at1 = strrchr(rcpt1->address, '@'); 896 at2 = strrchr(rcpt2->address, '@'); 897 if (at1 == 0 && at2 != 0) 898 return (1); 899 if (at1 != 0 && at2 == 0) 900 return (-1); 901 if (at1 != 0 && at2 != 0 902 && (result = strcasecmp(at1, at2)) != 0) 903 return (result); 904 905 /* 906 * Compare recipient address. 907 */ 908 return (strcasecmp(rcpt1->address, rcpt2->address)); 909} 910 911/* qmgr_message_sort - sort message recipient addresses by domain */ 912 913static void qmgr_message_sort(QMGR_MESSAGE *message) 914{ 915 qsort((char *) message->rcpt_list.info, message->rcpt_list.len, 916 sizeof(message->rcpt_list.info[0]), qmgr_message_sort_compare); 917 if (msg_verbose) { 918 RECIPIENT_LIST list = message->rcpt_list; 919 RECIPIENT *rcpt; 920 921 msg_info("start sorted recipient list"); 922 for (rcpt = list.info; rcpt < list.info + list.len; rcpt++) 923 msg_info("qmgr_message_sort: %s", rcpt->address); 924 msg_info("end sorted recipient list"); 925 } 926} 927 928/* qmgr_resolve_one - resolve or skip one recipient */ 929 930static int qmgr_resolve_one(QMGR_MESSAGE *message, RECIPIENT *recipient, 931 const char *addr, RESOLVE_REPLY *reply) 932{ 933#define QMGR_REDIRECT(rp, tp, np) do { \ 934 (rp)->flags = 0; \ 935 vstring_strcpy((rp)->transport, (tp)); \ 936 vstring_strcpy((rp)->nexthop, (np)); \ 937 } while (0) 938 939 if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) == 0) 940 resolve_clnt_query_from(message->sender, addr, reply); 941 else 942 resolve_clnt_verify_from(message->sender, addr, reply); 943 if (reply->flags & RESOLVE_FLAG_FAIL) { 944 QMGR_REDIRECT(reply, MAIL_SERVICE_RETRY, 945 "4.3.0 address resolver failure"); 946 return (0); 947 } else if (reply->flags & RESOLVE_FLAG_ERROR) { 948 QMGR_REDIRECT(reply, MAIL_SERVICE_ERROR, 949 "5.1.3 bad address syntax"); 950 return (0); 951 } else { 952 return (0); 953 } 954} 955 956/* qmgr_message_resolve - resolve recipients */ 957 958static void qmgr_message_resolve(QMGR_MESSAGE *message) 959{ 960 static ARGV *defer_xport_argv; 961 RECIPIENT_LIST list = message->rcpt_list; 962 RECIPIENT *recipient; 963 QMGR_TRANSPORT *transport = 0; 964 QMGR_QUEUE *queue = 0; 965 RESOLVE_REPLY reply; 966 VSTRING *queue_name; 967 char *at; 968 char **cpp; 969 char *nexthop; 970 ssize_t len; 971 int status; 972 DSN dsn; 973 MSG_STATS stats; 974 DSN *saved_dsn; 975 976#define STREQ(x,y) (strcmp(x,y) == 0) 977#define STR vstring_str 978#define LEN VSTRING_LEN 979 980 resolve_clnt_init(&reply); 981 queue_name = vstring_alloc(1); 982 for (recipient = list.info; recipient < list.info + list.len; recipient++) { 983 984 /* 985 * Redirect overrides all else. But only once (per entire message). 986 * For consistency with the remainder of Postfix, rewrite the address 987 * to canonical form before resolving it. 988 */ 989 if (message->redirect_addr) { 990 if (recipient > list.info) { 991 recipient->u.queue = 0; 992 continue; 993 } 994 message->rcpt_offset = 0; 995 rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr, 996 reply.recipient); 997 RECIPIENT_UPDATE(recipient->address, STR(reply.recipient)); 998 if (qmgr_resolve_one(message, recipient, 999 recipient->address, &reply) < 0) 1000 continue; 1001 if (!STREQ(recipient->address, STR(reply.recipient))) 1002 RECIPIENT_UPDATE(recipient->address, STR(reply.recipient)); 1003 } 1004 1005 /* 1006 * Content filtering overrides the address resolver. 1007 * 1008 * XXX Bypass content_filter inspection for user-generated probes 1009 * (sendmail -bv). MTA-generated probes never have the "please filter 1010 * me" bits turned on, but we handle them here anyway for the sake of 1011 * future proofing. 1012 */ 1013#define FILTER_WITHOUT_NEXTHOP(filter, next) \ 1014 (((next) = split_at((filter), ':')) == 0 || *(next) == 0) 1015 1016#define RCPT_WITHOUT_DOMAIN(rcpt, next) \ 1017 ((next = strrchr(rcpt, '@')) == 0 || *++(next) == 0) 1018 1019 else if (message->filter_xport 1020 && (message->tflags & DEL_REQ_TRACE_ONLY_MASK) == 0) { 1021 reply.flags = 0; 1022 vstring_strcpy(reply.transport, message->filter_xport); 1023 if (FILTER_WITHOUT_NEXTHOP(STR(reply.transport), nexthop) 1024 && *(nexthop = var_def_filter_nexthop) == 0 1025 && RCPT_WITHOUT_DOMAIN(recipient->address, nexthop)) 1026 nexthop = var_myhostname; 1027 vstring_strcpy(reply.nexthop, nexthop); 1028 vstring_strcpy(reply.recipient, recipient->address); 1029 } 1030 1031 /* 1032 * Resolve the destination to (transport, nexthop, address). The 1033 * result address may differ from the one specified by the sender. 1034 */ 1035 else { 1036 if (qmgr_resolve_one(message, recipient, 1037 recipient->address, &reply) < 0) 1038 continue; 1039 if (!STREQ(recipient->address, STR(reply.recipient))) 1040 RECIPIENT_UPDATE(recipient->address, STR(reply.recipient)); 1041 } 1042 1043 /* 1044 * Bounce null recipients. This should never happen, but is most 1045 * likely the result of a fault in a different program, so aborting 1046 * the queue manager process does not help. 1047 */ 1048 if (recipient->address[0] == 0) { 1049 QMGR_REDIRECT(&reply, MAIL_SERVICE_ERROR, 1050 "5.1.3 null recipient address"); 1051 } 1052 1053 /* 1054 * Discard mail to the local double bounce address here, so this 1055 * system can run without a local delivery agent. They'd still have 1056 * to configure something for mail directed to the local postmaster, 1057 * though, but that is an RFC requirement anyway. 1058 * 1059 * XXX This lookup should be done in the resolver, and the mail should 1060 * be directed to a general-purpose null delivery agent. 1061 */ 1062 if (reply.flags & RESOLVE_CLASS_LOCAL) { 1063 at = strrchr(STR(reply.recipient), '@'); 1064 len = (at ? (at - STR(reply.recipient)) 1065 : strlen(STR(reply.recipient))); 1066 if (strncasecmp(STR(reply.recipient), var_double_bounce_sender, 1067 len) == 0 1068 && !var_double_bounce_sender[len]) { 1069 status = sent(message->tflags, message->queue_id, 1070 QMGR_MSG_STATS(&stats, message), recipient, 1071 "none", DSN_SIMPLE(&dsn, "2.0.0", 1072 "undeliverable postmaster notification discarded")); 1073 if (status == 0) { 1074 deliver_completed(message->fp, recipient->offset); 1075#if 0 1076 /* It's the default verification probe sender address. */ 1077 msg_warn("%s: undeliverable postmaster notification discarded", 1078 message->queue_id); 1079#endif 1080 } else 1081 message->flags |= status; 1082 continue; 1083 } 1084 } 1085 1086 /* 1087 * Optionally defer deliveries over specific transports, unless the 1088 * restriction is lifted temporarily. 1089 */ 1090 if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) { 1091 if (defer_xport_argv == 0) 1092 defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,"); 1093 for (cpp = defer_xport_argv->argv; *cpp; cpp++) 1094 if (strcmp(*cpp, STR(reply.transport)) == 0) 1095 break; 1096 if (*cpp) { 1097 QMGR_REDIRECT(&reply, MAIL_SERVICE_RETRY, 1098 "4.3.2 deferred transport"); 1099 } 1100 } 1101 1102 /* 1103 * Look up or instantiate the proper transport. 1104 */ 1105 if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) { 1106 if ((transport = qmgr_transport_find(STR(reply.transport))) == 0) 1107 transport = qmgr_transport_create(STR(reply.transport)); 1108 queue = 0; 1109 } 1110 1111 /* 1112 * This message is being flushed. If need-be unthrottle the 1113 * transport. 1114 */ 1115 if ((message->qflags & QMGR_FLUSH_EACH) != 0 1116 && QMGR_TRANSPORT_THROTTLED(transport)) 1117 qmgr_transport_unthrottle(transport); 1118 1119 /* 1120 * This transport is dead. Defer delivery to this recipient. 1121 */ 1122 if (QMGR_TRANSPORT_THROTTLED(transport)) { 1123 saved_dsn = transport->dsn; 1124 if ((transport = qmgr_error_transport(MAIL_SERVICE_RETRY)) != 0) { 1125 nexthop = qmgr_error_nexthop(saved_dsn); 1126 vstring_strcpy(reply.nexthop, nexthop); 1127 myfree(nexthop); 1128 queue = 0; 1129 } else { 1130 qmgr_defer_recipient(message, recipient, saved_dsn); 1131 continue; 1132 } 1133 } 1134 1135 /* 1136 * The nexthop destination provides the default name for the 1137 * per-destination queue. When the delivery agent accepts only one 1138 * recipient per delivery, give each recipient its own queue, so that 1139 * deliveries to different recipients of the same message can happen 1140 * in parallel, and so that we can enforce per-recipient concurrency 1141 * limits and prevent one recipient from tying up all the delivery 1142 * agent resources. We use recipient@nexthop as queue name rather 1143 * than the actual recipient domain name, so that one recipient in 1144 * multiple equivalent domains cannot evade the per-recipient 1145 * concurrency limit. Split the address on the recipient delimiter if 1146 * one is defined, so that extended addresses don't get extra 1147 * delivery slots. 1148 * 1149 * Fold the result to lower case so that we don't have multiple queues 1150 * for the same name. 1151 * 1152 * Important! All recipients in a queue must have the same nexthop 1153 * value. It is OK to have multiple queues with the same nexthop 1154 * value, but only when those queues are named after recipients. 1155 * 1156 * The single-recipient code below was written for local(8) like 1157 * delivery agents, and assumes that all domains that deliver to the 1158 * same (transport + nexthop) are aliases for $nexthop. Delivery 1159 * concurrency is changed from per-domain into per-recipient, by 1160 * changing the queue name from nexthop into localpart@nexthop. 1161 * 1162 * XXX This assumption is incorrect when different destinations share 1163 * the same (transport + nexthop). In reality, such transports are 1164 * rarely configured to use single-recipient deliveries. The fix is 1165 * to decouple the per-destination recipient limit from the 1166 * per-destination concurrency. 1167 */ 1168 vstring_strcpy(queue_name, STR(reply.nexthop)); 1169 if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0 1170 && strcmp(transport->name, MAIL_SERVICE_RETRY) != 0 1171 && transport->recipient_limit == 1) { 1172 /* Copy the recipient localpart. */ 1173 at = strrchr(STR(reply.recipient), '@'); 1174 len = (at ? (at - STR(reply.recipient)) 1175 : strlen(STR(reply.recipient))); 1176 vstring_strncpy(queue_name, STR(reply.recipient), len); 1177 /* Remove the address extension from the recipient localpart. */ 1178 if (*var_rcpt_delim && split_addr(STR(queue_name), *var_rcpt_delim)) 1179 vstring_truncate(queue_name, strlen(STR(queue_name))); 1180 /* Assume the recipient domain is equivalent to nexthop. */ 1181 vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop)); 1182 } 1183 lowercase(STR(queue_name)); 1184 1185 /* 1186 * This transport is alive. Find or instantiate a queue for this 1187 * recipient. 1188 */ 1189 if (queue == 0 || !STREQ(queue->name, STR(queue_name))) { 1190 if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0) 1191 queue = qmgr_queue_create(transport, STR(queue_name), 1192 STR(reply.nexthop)); 1193 } 1194 1195 /* 1196 * This message is being flushed. If need-be unthrottle the queue. 1197 */ 1198 if ((message->qflags & QMGR_FLUSH_EACH) != 0 1199 && QMGR_QUEUE_THROTTLED(queue)) 1200 qmgr_queue_unthrottle(queue); 1201 1202 /* 1203 * This queue is dead. Defer delivery to this recipient. 1204 */ 1205 if (QMGR_QUEUE_THROTTLED(queue)) { 1206 saved_dsn = queue->dsn; 1207 if ((queue = qmgr_error_queue(MAIL_SERVICE_RETRY, saved_dsn)) == 0) { 1208 qmgr_defer_recipient(message, recipient, saved_dsn); 1209 continue; 1210 } 1211 } 1212 1213 /* 1214 * This queue is alive. Bind this recipient to this queue instance. 1215 */ 1216 recipient->u.queue = queue; 1217 } 1218 resolve_clnt_free(&reply); 1219 vstring_free(queue_name); 1220} 1221 1222/* qmgr_message_assign - assign recipients to specific delivery requests */ 1223 1224static void qmgr_message_assign(QMGR_MESSAGE *message) 1225{ 1226 RECIPIENT_LIST list = message->rcpt_list; 1227 RECIPIENT *recipient; 1228 QMGR_ENTRY *entry = 0; 1229 QMGR_QUEUE *queue; 1230 1231 /* 1232 * Try to bundle as many recipients in a delivery request as we can. When 1233 * the recipient resolves to the same site and transport as the previous 1234 * recipient, do not create a new queue entry, just move that recipient 1235 * to the recipient list of the existing queue entry. All this provided 1236 * that we do not exceed the transport-specific limit on the number of 1237 * recipients per transaction. Skip recipients with a dead transport or 1238 * destination. 1239 */ 1240#define LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit))) 1241 1242 for (recipient = list.info; recipient < list.info + list.len; recipient++) { 1243 if ((queue = recipient->u.queue) != 0) { 1244 if (message->single_rcpt || entry == 0 || entry->queue != queue 1245 || !LIMIT_OK(entry->queue->transport->recipient_limit, 1246 entry->rcpt_list.len)) { 1247 entry = qmgr_entry_create(queue, message); 1248 } 1249 recipient_list_add(&entry->rcpt_list, recipient->offset, 1250 recipient->dsn_orcpt, recipient->dsn_notify, 1251 recipient->orig_addr, recipient->address); 1252 qmgr_recipient_count++; 1253 } 1254 } 1255 recipient_list_free(&message->rcpt_list); 1256 recipient_list_init(&message->rcpt_list, RCPT_LIST_INIT_QUEUE); 1257} 1258 1259/* qmgr_message_free - release memory for in-core message structure */ 1260 1261void qmgr_message_free(QMGR_MESSAGE *message) 1262{ 1263 if (message->refcount != 0) 1264 msg_panic("qmgr_message_free: reference len: %d", message->refcount); 1265 if (message->fp) 1266 msg_panic("qmgr_message_free: queue file is open"); 1267 myfree(message->queue_id); 1268 myfree(message->queue_name); 1269 if (message->dsn_envid) 1270 myfree(message->dsn_envid); 1271 if (message->encoding) 1272 myfree(message->encoding); 1273 if (message->sender) 1274 myfree(message->sender); 1275 if (message->verp_delims) 1276 myfree(message->verp_delims); 1277 if (message->filter_xport) 1278 myfree(message->filter_xport); 1279 if (message->inspect_xport) 1280 myfree(message->inspect_xport); 1281 if (message->redirect_addr) 1282 myfree(message->redirect_addr); 1283 if (message->client_name) 1284 myfree(message->client_name); 1285 if (message->client_addr) 1286 myfree(message->client_addr); 1287 if (message->client_port) 1288 myfree(message->client_port); 1289 if (message->client_proto) 1290 myfree(message->client_proto); 1291 if (message->client_helo) 1292 myfree(message->client_helo); 1293 if (message->sasl_method) 1294 myfree(message->sasl_method); 1295 if (message->sasl_username) 1296 myfree(message->sasl_username); 1297 if (message->sasl_sender) 1298 myfree(message->sasl_sender); 1299 if (message->log_ident) 1300 myfree(message->log_ident); 1301 if (message->rewrite_context) 1302 myfree(message->rewrite_context); 1303 recipient_list_free(&message->rcpt_list); 1304 qmgr_message_count--; 1305 myfree((char *) message); 1306} 1307 1308/* qmgr_message_alloc - create in-core message structure */ 1309 1310QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id, 1311 int qflags, mode_t mode) 1312{ 1313 const char *myname = "qmgr_message_alloc"; 1314 QMGR_MESSAGE *message; 1315 1316 if (msg_verbose) 1317 msg_info("%s: %s %s", myname, queue_name, queue_id); 1318 1319 /* 1320 * Create an in-core message structure. 1321 */ 1322 message = qmgr_message_create(queue_name, queue_id, qflags); 1323 1324 /* 1325 * Extract message envelope information: time of arrival, sender address, 1326 * recipient addresses. Skip files with malformed envelope information. 1327 */ 1328#define QMGR_LOCK_MODE (MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) 1329 1330 if (qmgr_message_open(message) < 0) { 1331 qmgr_message_free(message); 1332 return (0); 1333 } 1334 if (myflock(vstream_fileno(message->fp), INTERNAL_LOCK, QMGR_LOCK_MODE) < 0) { 1335 msg_info("%s: skipped, still being delivered", queue_id); 1336 qmgr_message_close(message); 1337 qmgr_message_free(message); 1338 return (QMGR_MESSAGE_LOCKED); 1339 } 1340 if (qmgr_message_read(message) < 0) { 1341 qmgr_message_close(message); 1342 qmgr_message_free(message); 1343 return (0); 1344 } else { 1345 1346 /* 1347 * We have validated the queue file content, so it is safe to modify 1348 * the file properties now. 1349 */ 1350 if (mode != 0 && fchmod(vstream_fileno(message->fp), mode) < 0) 1351 msg_fatal("fchmod %s: %m", VSTREAM_PATH(message->fp)); 1352 1353 /* 1354 * Reset the defer log. This code should not be here, but we must 1355 * reset the defer log *after* acquiring the exclusive lock on the 1356 * queue file and *before* resolving new recipients. Since all those 1357 * operations are encapsulated so nicely by this routine, the defer 1358 * log reset has to be done here as well. 1359 * 1360 * Note: it is safe to remove the defer logfile from a previous queue 1361 * run of this queue file, because the defer log contains information 1362 * about recipients that still exist in this queue file. 1363 */ 1364 if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT) 1365 msg_fatal("%s: %s: remove %s %s: %m", myname, 1366 queue_id, MAIL_QUEUE_DEFER, queue_id); 1367 qmgr_message_sort(message); 1368 qmgr_message_resolve(message); 1369 qmgr_message_sort(message); 1370 qmgr_message_assign(message); 1371 qmgr_message_close(message); 1372 return (message); 1373 } 1374} 1375 1376/* qmgr_message_realloc - refresh in-core message structure */ 1377 1378QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *message) 1379{ 1380 const char *myname = "qmgr_message_realloc"; 1381 1382 /* 1383 * Sanity checks. 1384 */ 1385 if (message->rcpt_offset <= 0) 1386 msg_panic("%s: invalid offset: %ld", myname, message->rcpt_offset); 1387 if (msg_verbose) 1388 msg_info("%s: %s %s offset %ld", myname, message->queue_name, 1389 message->queue_id, message->rcpt_offset); 1390 1391 /* 1392 * Extract recipient addresses. Skip files with malformed envelope 1393 * information. 1394 */ 1395 if (qmgr_message_open(message) < 0) 1396 return (0); 1397 if (qmgr_message_read(message) < 0) { 1398 qmgr_message_close(message); 1399 return (0); 1400 } else { 1401 qmgr_message_sort(message); 1402 qmgr_message_resolve(message); 1403 qmgr_message_sort(message); 1404 qmgr_message_assign(message); 1405 qmgr_message_close(message); 1406 return (message); 1407 } 1408} 1409