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