1 /* $NetBSD: qmqpd.c,v 1.5 2025/02/25 19:15:49 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* qmqpd 8 6 /* SUMMARY 7 /* Postfix QMQP server 8 /* SYNOPSIS 9 /* \fBqmqpd\fR [generic Postfix daemon options] 10 /* DESCRIPTION 11 /* The Postfix QMQP server receives one message per connection. 12 /* Each message is piped through the \fBcleanup\fR(8) 13 /* daemon, and is placed into the \fBincoming\fR queue as one 14 /* single queue file. The program expects to be run from the 15 /* \fBmaster\fR(8) process manager. 16 /* 17 /* The QMQP server implements one access policy: only explicitly 18 /* authorized client hosts are allowed to use the service. 19 /* SECURITY 20 /* .ad 21 /* .fi 22 /* The QMQP server is moderately security-sensitive. It talks to QMQP 23 /* clients and to DNS servers on the network. The QMQP server can be 24 /* run chrooted at fixed low privilege. 25 /* DIAGNOSTICS 26 /* Problems and transactions are logged to \fBsyslogd\fR(8) 27 /* or \fBpostlogd\fR(8). 28 /* BUGS 29 /* The QMQP protocol provides only one server reply per message 30 /* delivery. It is therefore not possible to reject individual 31 /* recipients. 32 /* 33 /* The QMQP protocol requires the server to receive the entire 34 /* message before replying. If a message is malformed, or if any 35 /* netstring component is longer than acceptable, Postfix replies 36 /* immediately and closes the connection. It is left up to the 37 /* client to handle the situation. 38 /* CONFIGURATION PARAMETERS 39 /* .ad 40 /* .fi 41 /* Changes to \fBmain.cf\fR are picked up automatically, as \fBqmqpd\fR(8) 42 /* processes run for only a limited amount of time. Use the command 43 /* "\fBpostfix reload\fR" to speed up a change. 44 /* 45 /* The text below provides only a parameter summary. See 46 /* \fBpostconf\fR(5) for more details including examples. 47 /* CONTENT INSPECTION CONTROLS 48 /* .ad 49 /* .fi 50 /* .IP "\fBcontent_filter (empty)\fR" 51 /* After the message is queued, send the entire message to the 52 /* specified \fItransport:destination\fR. 53 /* .IP "\fBreceive_override_options (empty)\fR" 54 /* Enable or disable recipient validation, built-in content 55 /* filtering, or address mapping. 56 /* SMTPUTF8 CONTROLS 57 /* .ad 58 /* .fi 59 /* Preliminary SMTPUTF8 support is introduced with Postfix 3.0. 60 /* .IP "\fBsmtputf8_enable (yes)\fR" 61 /* Enable preliminary SMTPUTF8 support for the protocols described 62 /* in RFC 6531, RFC 6532, and RFC 6533. 63 /* .IP "\fBsmtputf8_autodetect_classes (sendmail, verify)\fR" 64 /* Detect that a message requires SMTPUTF8 support for the specified 65 /* mail origin classes. 66 /* .PP 67 /* Available in Postfix version 3.2 and later: 68 /* .IP "\fBenable_idna2003_compatibility (no)\fR" 69 /* Enable 'transitional' compatibility between IDNA2003 and IDNA2008, 70 /* when converting UTF-8 domain names to/from the ASCII form that is 71 /* used for DNS lookups. 72 /* RESOURCE AND RATE CONTROLS 73 /* .ad 74 /* .fi 75 /* .IP "\fBline_length_limit (2048)\fR" 76 /* Upon input, long lines are chopped up into pieces of at most 77 /* this length; upon delivery, long lines are reconstructed. 78 /* .IP "\fBhopcount_limit (50)\fR" 79 /* The maximal number of Received: message headers that is allowed 80 /* in the primary message headers. 81 /* .IP "\fBmessage_size_limit (10240000)\fR" 82 /* The maximal size in bytes of a message, including envelope information. 83 /* .IP "\fBqmqpd_timeout (300s)\fR" 84 /* The time limit for sending or receiving information over the network. 85 /* TROUBLE SHOOTING CONTROLS 86 /* .ad 87 /* .fi 88 /* .IP "\fBdebug_peer_level (2)\fR" 89 /* The increment in verbose logging level when a nexthop destination, 90 /* remote client or server name or network address matches a pattern 91 /* given with the debug_peer_list parameter. 92 /* .IP "\fBdebug_peer_list (empty)\fR" 93 /* Optional list of nexthop destination, remote client or server 94 /* name or network address patterns that, if matched, cause the verbose 95 /* logging level to increase by the amount specified in $debug_peer_level. 96 /* .IP "\fBsoft_bounce (no)\fR" 97 /* Safety net to keep mail queued that would otherwise be returned to 98 /* the sender. 99 /* TARPIT CONTROLS 100 /* .ad 101 /* .fi 102 /* .IP "\fBqmqpd_error_delay (1s)\fR" 103 /* How long the Postfix QMQP server will pause before sending a negative 104 /* reply to the remote QMQP client. 105 /* MISCELLANEOUS CONTROLS 106 /* .ad 107 /* .fi 108 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR" 109 /* The default location of the Postfix main.cf and master.cf 110 /* configuration files. 111 /* .IP "\fBdaemon_timeout (18000s)\fR" 112 /* How much time a Postfix daemon process may take to handle a 113 /* request before it is terminated by a built-in watchdog timer. 114 /* .IP "\fBipc_timeout (3600s)\fR" 115 /* The time limit for sending or receiving information over an internal 116 /* communication channel. 117 /* .IP "\fBmax_idle (100s)\fR" 118 /* The maximum amount of time that an idle Postfix daemon process waits 119 /* for an incoming connection before terminating voluntarily. 120 /* .IP "\fBmax_use (100)\fR" 121 /* The maximal number of incoming connections that a Postfix daemon 122 /* process will service before terminating voluntarily. 123 /* .IP "\fBprocess_id (read-only)\fR" 124 /* The process ID of a Postfix command or daemon process. 125 /* .IP "\fBprocess_name (read-only)\fR" 126 /* The process name of a Postfix command or daemon process. 127 /* .IP "\fBqmqpd_authorized_clients (empty)\fR" 128 /* What remote QMQP clients are allowed to connect to the Postfix QMQP 129 /* server port. 130 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR" 131 /* The location of the Postfix top-level queue directory. 132 /* .IP "\fBsyslog_facility (mail)\fR" 133 /* The syslog facility of Postfix logging. 134 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR" 135 /* A prefix that is prepended to the process name in syslog 136 /* records, so that, for example, "smtpd" becomes "prefix/smtpd". 137 /* .IP "\fBverp_delimiter_filter (-=+)\fR" 138 /* The characters Postfix accepts as VERP delimiter characters on the 139 /* Postfix \fBsendmail\fR(1) command line and in SMTP commands. 140 /* .PP 141 /* Available in Postfix version 2.5 and later: 142 /* .IP "\fBqmqpd_client_port_logging (no)\fR" 143 /* Enable logging of the remote QMQP client port in addition to 144 /* the hostname and IP address. 145 /* .PP 146 /* Available in Postfix 3.3 and later: 147 /* .IP "\fBservice_name (read-only)\fR" 148 /* The master.cf service name of a Postfix daemon process. 149 /* SEE ALSO 150 /* https://cr.yp.to/proto/qmqp.html, QMQP protocol 151 /* cleanup(8), message canonicalization 152 /* master(8), process manager 153 /* postlogd(8), Postfix logging 154 /* syslogd(8), system logging 155 /* README FILES 156 /* .ad 157 /* .fi 158 /* Use "\fBpostconf readme_directory\fR" or 159 /* "\fBpostconf html_directory\fR" to locate this information. 160 /* .na 161 /* .nf 162 /* QMQP_README, Postfix ezmlm-idx howto. 163 /* LICENSE 164 /* .ad 165 /* .fi 166 /* The Secure Mailer license must be distributed with this software. 167 /* HISTORY 168 /* .ad 169 /* .fi 170 /* The qmqpd service was introduced with Postfix version 1.1. 171 /* AUTHOR(S) 172 /* Wietse Venema 173 /* IBM T.J. Watson Research 174 /* P.O. Box 704 175 /* Yorktown Heights, NY 10598, USA 176 /* 177 /* Wietse Venema 178 /* Google, Inc. 179 /* 111 8th Avenue 180 /* New York, NY 10011, USA 181 /*--*/ 182 183 /* System library. */ 184 185 #include <sys_defs.h> 186 #include <string.h> 187 #include <unistd.h> 188 #include <stdlib.h> 189 #include <ctype.h> 190 #include <stdarg.h> 191 192 /* Utility library. */ 193 194 #include <msg.h> 195 #include <mymalloc.h> 196 #include <vstring.h> 197 #include <vstream.h> 198 #include <netstring.h> 199 #include <dict.h> 200 #include <inet_proto.h> 201 202 /* Global library. */ 203 204 #include <mail_params.h> 205 #include <mail_version.h> 206 #include <record.h> 207 #include <rec_type.h> 208 #include <mail_proto.h> 209 #include <cleanup_user.h> 210 #include <mail_date.h> 211 #include <mail_conf.h> 212 #include <debug_peer.h> 213 #include <mail_stream.h> 214 #include <namadr_list.h> 215 #include <quote_822_local.h> 216 #include <match_parent_style.h> 217 #include <lex_822.h> 218 #include <verp_sender.h> 219 #include <input_transp.h> 220 #include <smtputf8.h> 221 222 /* Single-threaded server skeleton. */ 223 224 #include <mail_server.h> 225 226 /* Application-specific */ 227 228 #include <qmqpd.h> 229 230 /* 231 * Tunable parameters. Make sure that there is some bound on the length of a 232 * netstring, so that the mail system stays in control even when a malicious 233 * client sends netstrings of unreasonable length. The recipient count limit 234 * is enforced by the message size limit. 235 */ 236 int var_qmqpd_timeout; 237 int var_qmqpd_err_sleep; 238 char *var_filter_xport; 239 char *var_qmqpd_clients; 240 char *var_input_transp; 241 bool var_qmqpd_client_port_log; 242 243 /* 244 * Silly little macros. 245 */ 246 #define STR(x) vstring_str(x) 247 #define LEN(x) VSTRING_LEN(x) 248 249 #define DO_LOG 1 250 #define DONT_LOG 0 251 252 /* 253 * Access control. This service should be exposed only to explicitly 254 * authorized clients. There is no default authorization. 255 */ 256 static NAMADR_LIST *qmqpd_clients; 257 258 /* 259 * Transparency: before mail is queued, do we allow address mapping, 260 * automatic bcc, header/body checks? 261 */ 262 int qmqpd_input_transp_mask; 263 264 /* qmqpd_open_file - open a queue file */ 265 266 static void qmqpd_open_file(QMQPD_STATE *state) 267 { 268 int cleanup_flags; 269 270 /* 271 * Connect to the cleanup server. Log client name/address with queue ID. 272 */ 273 cleanup_flags = input_transp_cleanup(CLEANUP_FLAG_MASK_EXTERNAL, 274 qmqpd_input_transp_mask); 275 cleanup_flags |= smtputf8_autodetect(MAIL_SRC_MASK_QMQPD); 276 /* TODO(wietse) REQUIRETLS? */ 277 state->dest = mail_stream_service(MAIL_CLASS_PUBLIC, var_cleanup_service); 278 if (state->dest == 0 279 || attr_print(state->dest->stream, ATTR_FLAG_NONE, 280 SEND_ATTR_INT(MAIL_ATTR_FLAGS, cleanup_flags), 281 ATTR_TYPE_END) != 0) 282 msg_fatal("unable to connect to the %s %s service", 283 MAIL_CLASS_PUBLIC, var_cleanup_service); 284 state->cleanup = state->dest->stream; 285 state->queue_id = mystrdup(state->dest->id); 286 msg_info("%s: client=%s", state->queue_id, state->namaddr); 287 288 /* 289 * Record the time of arrival. Optionally, enable content filtering (not 290 * bloody likely, but present for the sake of consistency with all other 291 * Postfix points of entrance). 292 */ 293 rec_fprintf(state->cleanup, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT, 294 REC_TYPE_TIME_ARG(state->arrival_time)); 295 if (*var_filter_xport) 296 rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport); 297 } 298 299 /* qmqpd_read_content - receive message content */ 300 301 static void qmqpd_read_content(QMQPD_STATE *state) 302 { 303 state->where = "receiving message content"; 304 netstring_get(state->client, state->message, var_message_limit); 305 } 306 307 /* qmqpd_copy_sender - copy envelope sender */ 308 309 static void qmqpd_copy_sender(QMQPD_STATE *state) 310 { 311 char *end_prefix; 312 char *end_origin; 313 int verp_requested; 314 static char verp_delims[] = "-="; 315 316 /* 317 * If the sender address looks like prefix@origin-@[], then request 318 * variable envelope return path delivery, with an envelope sender 319 * address of prefi@origin, and with VERP delimiters of x and =. This 320 * way, the recipients will see envelope sender addresses that look like: 321 * prefixuser=domain@origin. 322 */ 323 state->where = "receiving sender address"; 324 netstring_get(state->client, state->buf, var_line_limit); 325 VSTRING_TERMINATE(state->buf); 326 verp_requested = 327 ((end_origin = vstring_end(state->buf) - 4) > STR(state->buf) 328 && strcmp(end_origin, "-@[]") == 0 329 && (end_prefix = strchr(STR(state->buf), '@')) != 0 /* XXX */ 330 && --end_prefix < end_origin - 2 /* non-null origin */ 331 && end_prefix > STR(state->buf)); /* non-null prefix */ 332 if (verp_requested) { 333 verp_delims[0] = end_prefix[0]; 334 if (verp_delims_verify(verp_delims) != 0) { 335 state->err |= CLEANUP_STAT_CONT; /* XXX */ 336 vstring_sprintf(state->why_rejected, "Invalid VERP delimiters: \"%s\". Need two characters from \"%s\"", 337 verp_delims, var_verp_filter); 338 } 339 memmove(end_prefix, end_prefix + 1, end_origin - end_prefix - 1); 340 vstring_truncate(state->buf, end_origin - STR(state->buf) - 1); 341 } 342 if (state->err == CLEANUP_STAT_OK 343 && REC_PUT_BUF(state->cleanup, REC_TYPE_FROM, state->buf) < 0) 344 state->err = CLEANUP_STAT_WRITE; 345 if (verp_requested) 346 if (state->err == CLEANUP_STAT_OK 347 && rec_put(state->cleanup, REC_TYPE_VERP, verp_delims, 2) < 0) 348 state->err = CLEANUP_STAT_WRITE; 349 state->sender = mystrndup(STR(state->buf), LEN(state->buf)); 350 } 351 352 /* qmqpd_write_attributes - save session attributes */ 353 354 static void qmqpd_write_attributes(QMQPD_STATE *state) 355 { 356 357 /* 358 * Logging attributes, also used for XFORWARD. 359 */ 360 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 361 MAIL_ATTR_LOG_CLIENT_NAME, state->name); 362 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 363 MAIL_ATTR_LOG_CLIENT_ADDR, state->rfc_addr); 364 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 365 MAIL_ATTR_LOG_CLIENT_PORT, state->port); 366 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 367 MAIL_ATTR_LOG_ORIGIN, state->namaddr); 368 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 369 MAIL_ATTR_LOG_PROTO_NAME, state->protocol); 370 371 /* 372 * For consistency with the smtpd Milter client, we need to provide the 373 * real client attributes to the cleanup Milter client. This does not 374 * matter much with qmqpd which speaks to trusted clients only, but we 375 * want to be sure that the cleanup input protocol is ready when a new 376 * type of network daemon is added to receive mail from the Internet. 377 * 378 * See also the comments in smtpd.c. 379 */ 380 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 381 MAIL_ATTR_ACT_CLIENT_NAME, state->name); 382 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 383 MAIL_ATTR_ACT_CLIENT_ADDR, state->addr); 384 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 385 MAIL_ATTR_ACT_CLIENT_PORT, state->port); 386 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%u", 387 MAIL_ATTR_ACT_CLIENT_AF, state->addr_family); 388 rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 389 MAIL_ATTR_ACT_PROTO_NAME, state->protocol); 390 391 /* XXX What about the address rewriting context? */ 392 } 393 394 /* qmqpd_copy_recipients - copy message recipients */ 395 396 static void qmqpd_copy_recipients(QMQPD_STATE *state) 397 { 398 int ch; 399 400 /* 401 * Remember the first recipient. We are done when we read the over-all 402 * netstring terminator. 403 * 404 * XXX This approach violates abstractions, but it is a heck of a lot more 405 * convenient than counting the over-all byte count down to zero, like 406 * qmail does. 407 */ 408 state->where = "receiving recipient address"; 409 while ((ch = VSTREAM_GETC(state->client)) != ',') { 410 vstream_ungetc(state->client, ch); 411 netstring_get(state->client, state->buf, var_line_limit); 412 if (state->err == CLEANUP_STAT_OK 413 && REC_PUT_BUF(state->cleanup, REC_TYPE_RCPT, state->buf) < 0) 414 state->err = CLEANUP_STAT_WRITE; 415 state->rcpt_count++; 416 if (state->recipient == 0) 417 state->recipient = mystrndup(STR(state->buf), LEN(state->buf)); 418 } 419 } 420 421 /* qmqpd_next_line - get line from buffer, return last char, newline, or -1 */ 422 423 static int qmqpd_next_line(VSTRING *message, char **start, int *len, 424 char **next) 425 { 426 char *beyond = STR(message) + LEN(message); 427 char *enough = *next + var_line_limit; 428 char *cp; 429 430 /* 431 * Stop at newline or at some limit. Don't look beyond the end of the 432 * buffer. 433 */ 434 #define UCHARPTR(x) ((unsigned char *) (x)) 435 436 for (cp = *start = *next; /* void */ ; cp++) { 437 if (cp >= beyond) 438 return ((*len = (*next = cp) - *start) > 0 ? UCHARPTR(cp)[-1] : -1); 439 if (*cp == '\n') 440 return ((*len = cp - *start), (*next = cp + 1), '\n'); 441 if (cp >= enough) 442 return ((*len = cp - *start), (*next = cp), UCHARPTR(cp)[-1]); 443 } 444 } 445 446 /* qmqpd_write_content - write the message content segment */ 447 448 static void qmqpd_write_content(QMQPD_STATE *state) 449 { 450 char *start; 451 char *next; 452 int len; 453 int rec_type; 454 int first = 1; 455 int ch; 456 457 /* 458 * Start the message content segment. Prepend our own Received: header to 459 * the message content. List the recipient only when a message has one 460 * recipient. Otherwise, don't list the recipient to avoid revealing Bcc: 461 * recipients that are supposed to be invisible. 462 */ 463 rec_fputs(state->cleanup, REC_TYPE_MESG, ""); 464 rec_fprintf(state->cleanup, REC_TYPE_NORM, "Received: from %s (%s [%s])", 465 state->name, state->name, state->rfc_addr); 466 if (state->rcpt_count == 1 && state->recipient) { 467 rec_fprintf(state->cleanup, REC_TYPE_NORM, 468 "\tby %s (%s) with %s id %s", 469 var_myhostname, var_mail_name, 470 state->protocol, state->queue_id); 471 quote_822_local(state->buf, state->recipient); 472 rec_fprintf(state->cleanup, REC_TYPE_NORM, 473 "\tfor <%s>; %s", STR(state->buf), 474 mail_date(state->arrival_time.tv_sec)); 475 } else { 476 rec_fprintf(state->cleanup, REC_TYPE_NORM, 477 "\tby %s (%s) with %s", 478 var_myhostname, var_mail_name, state->protocol); 479 rec_fprintf(state->cleanup, REC_TYPE_NORM, 480 "\tid %s; %s", state->queue_id, 481 mail_date(state->arrival_time.tv_sec)); 482 } 483 #ifdef RECEIVED_ENVELOPE_FROM 484 quote_822_local(state->buf, state->sender); 485 rec_fprintf(state->cleanup, REC_TYPE_NORM, 486 "\t(envelope-from <%s>)", STR(state->buf)); 487 #endif 488 489 /* 490 * Write the message content. 491 * 492 * XXX Force an empty record when the queue file content begins with 493 * whitespace, so that it won't be considered as being part of our own 494 * Received: header. What an ugly Kluge. 495 * 496 * XXX Deal with UNIX-style From_ lines at the start of message content just 497 * in case. 498 */ 499 for (next = STR(state->message); /* void */ ; /* void */ ) { 500 if ((ch = qmqpd_next_line(state->message, &start, &len, &next)) < 0) 501 break; 502 if (ch == '\n') 503 rec_type = REC_TYPE_NORM; 504 else 505 rec_type = REC_TYPE_CONT; 506 if (first) { 507 if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) { 508 rec_fprintf(state->cleanup, rec_type, 509 "X-Mailbox-Line: %.*s", len, start); 510 continue; 511 } 512 first = 0; 513 if (len > 0 && IS_SPACE_TAB(start[0])) 514 rec_put(state->cleanup, REC_TYPE_NORM, "", 0); 515 } 516 if (rec_put(state->cleanup, rec_type, start, len) < 0) { 517 state->err = CLEANUP_STAT_WRITE; 518 return; 519 } 520 } 521 } 522 523 /* qmqpd_close_file - close queue file */ 524 525 static void qmqpd_close_file(QMQPD_STATE *state) 526 { 527 528 /* 529 * Send the end-of-segment markers. 530 */ 531 if (state->err == CLEANUP_STAT_OK) 532 if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0 533 || rec_fputs(state->cleanup, REC_TYPE_END, "") < 0 534 || vstream_fflush(state->cleanup)) 535 state->err = CLEANUP_STAT_WRITE; 536 537 /* 538 * Finish the queue file or finish the cleanup conversation. 539 */ 540 if (state->err == 0) 541 state->err = mail_stream_finish(state->dest, state->why_rejected); 542 else 543 mail_stream_cleanup(state->dest); 544 state->dest = 0; 545 } 546 547 /* qmqpd_reply - send status to client and optionally log message */ 548 549 static void qmqpd_reply(QMQPD_STATE *state, int log_message, 550 int status_code, const char *fmt,...) 551 { 552 va_list ap; 553 554 /* 555 * Optionally change hard errors into retryable ones. Send the reply and 556 * optionally log it. Always insert a delay before reporting a problem. 557 * This slows down software run-away conditions. 558 */ 559 if (status_code == QMQPD_STAT_HARD && var_soft_bounce) 560 status_code = QMQPD_STAT_RETRY; 561 VSTRING_RESET(state->buf); 562 VSTRING_ADDCH(state->buf, status_code); 563 va_start(ap, fmt); 564 vstring_vsprintf_append(state->buf, fmt, ap); 565 va_end(ap); 566 NETSTRING_PUT_BUF(state->client, state->buf); 567 if (log_message) 568 (status_code == QMQPD_STAT_OK ? msg_info : msg_warn) ("%s: %s: %s", 569 state->queue_id, state->namaddr, STR(state->buf) + 1); 570 if (status_code != QMQPD_STAT_OK) 571 sleep(var_qmqpd_err_sleep); 572 netstring_fflush(state->client); 573 } 574 575 /* qmqpd_send_status - send mail transaction completion status */ 576 577 static void qmqpd_send_status(QMQPD_STATE *state) 578 { 579 580 /* 581 * One message may suffer from multiple errors, so complain only about 582 * the most severe error. 583 * 584 * See also: smtpd.c 585 */ 586 state->where = "sending completion status"; 587 588 if (state->err == CLEANUP_STAT_OK) { 589 qmqpd_reply(state, DONT_LOG, QMQPD_STAT_OK, 590 "Ok: queued as %s", state->queue_id); 591 } else if ((state->err & CLEANUP_STAT_DEFER) != 0) { 592 qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY, 593 "Error: %s", STR(state->why_rejected)); 594 } else if ((state->err & CLEANUP_STAT_BAD) != 0) { 595 qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY, 596 "Error: internal error %d", state->err); 597 } else if ((state->err & CLEANUP_STAT_SIZE) != 0) { 598 qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD, 599 "Error: message too large"); 600 } else if ((state->err & CLEANUP_STAT_HOPS) != 0) { 601 qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD, 602 "Error: too many hops"); 603 } else if ((state->err & CLEANUP_STAT_CONT) != 0) { 604 qmqpd_reply(state, DO_LOG, STR(state->why_rejected)[0] == '4' ? 605 QMQPD_STAT_RETRY : QMQPD_STAT_HARD, 606 "Error: %s", STR(state->why_rejected)); 607 } else if ((state->err & CLEANUP_STAT_WRITE) != 0) { 608 qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY, 609 "Error: queue file write error"); 610 } else if ((state->err & CLEANUP_STAT_RCPT) != 0) { 611 qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD, 612 "Error: no recipients specified"); 613 } else { 614 qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY, 615 "Error: internal error %d", state->err); 616 } 617 } 618 619 /* qmqpd_receive - receive QMQP message+sender+recipients */ 620 621 static void qmqpd_receive(QMQPD_STATE *state) 622 { 623 624 /* 625 * Open a queue file. This must be first so that we can simplify the 626 * error logging and always include the queue ID information. 627 */ 628 qmqpd_open_file(state); 629 630 /* 631 * Read and ignore the over-all netstring length indicator. 632 */ 633 state->where = "receiving QMQP packet header"; 634 (void) netstring_get_length(state->client); 635 636 /* 637 * XXX Read the message content into memory, because Postfix expects to 638 * store the sender before storing the message content. Fixing that 639 * requires changes to pickup, cleanup, qmgr, and perhaps elsewhere, so 640 * that will have to happen later when I have more time. However, QMQP is 641 * used for mailing list distribution, so the bulk of the volume is 642 * expected to be not message content but recipients, and recipients are 643 * not accumulated in memory. 644 */ 645 qmqpd_read_content(state); 646 647 /* 648 * Read and write the envelope sender. 649 */ 650 qmqpd_copy_sender(state); 651 652 /* 653 * Record some session attributes. 654 */ 655 qmqpd_write_attributes(state); 656 657 /* 658 * Read and write the envelope recipients, including the optional big 659 * brother recipient. 660 */ 661 qmqpd_copy_recipients(state); 662 663 /* 664 * Start the message content segment, prepend our own Received: header, 665 * and write the message content. 666 */ 667 if (state->err == 0) 668 qmqpd_write_content(state); 669 670 /* 671 * Close the queue file. 672 */ 673 qmqpd_close_file(state); 674 675 /* 676 * Report the completion status to the client. 677 */ 678 qmqpd_send_status(state); 679 } 680 681 /* qmqpd_proto - speak the QMQP "protocol" */ 682 683 static void qmqpd_proto(QMQPD_STATE *state) 684 { 685 int status; 686 687 netstring_setup(state->client, var_qmqpd_timeout); 688 689 switch (status = vstream_setjmp(state->client)) { 690 691 default: 692 msg_panic("qmqpd_proto: unknown status %d", status); 693 694 case NETSTRING_ERR_EOF: 695 state->reason = "lost connection"; 696 break; 697 698 case NETSTRING_ERR_TIME: 699 state->reason = "read/write timeout"; 700 break; 701 702 case NETSTRING_ERR_FORMAT: 703 state->reason = "netstring format error"; 704 if (vstream_setjmp(state->client) == 0) 705 if (state->reason && state->where) 706 qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s", 707 state->reason, state->where); 708 break; 709 710 case NETSTRING_ERR_SIZE: 711 state->reason = "netstring length exceeds storage limit"; 712 if (vstream_setjmp(state->client) == 0) 713 if (state->reason && state->where) 714 qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s", 715 state->reason, state->where); 716 break; 717 718 case 0: 719 720 /* 721 * See if we want to talk to this client at all. 722 */ 723 if (namadr_list_match(qmqpd_clients, state->name, state->addr) != 0) { 724 qmqpd_receive(state); 725 } else if (qmqpd_clients->error == 0) { 726 qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, 727 "Error: %s is not authorized to use this service", 728 state->namaddr); 729 } else { 730 qmqpd_reply(state, DONT_LOG, QMQPD_STAT_RETRY, 731 "Error: server configuration error"); 732 } 733 break; 734 } 735 736 /* 737 * Log abnormal session termination. Indicate the last recognized state 738 * before things went wrong. 739 */ 740 if (state->reason && state->where) 741 msg_info("%s: %s: %s while %s", 742 state->queue_id ? state->queue_id : "NOQUEUE", 743 state->namaddr, state->reason, state->where); 744 } 745 746 /* qmqpd_service - service one client */ 747 748 static void qmqpd_service(VSTREAM *stream, char *unused_service, char **argv) 749 { 750 QMQPD_STATE *state; 751 752 /* 753 * Sanity check. This service takes no command-line arguments. 754 */ 755 if (argv[0]) 756 msg_fatal("unexpected command-line argument: %s", argv[0]); 757 758 /* 759 * For sanity, require that at least one of INET or INET6 is enabled. 760 * Otherwise, we can't look up interface information, and we can't 761 * convert names or addresses. 762 */ 763 if (inet_proto_info()->ai_family_list[0] == 0) 764 msg_fatal("all network protocols are disabled (%s = %s)", 765 VAR_INET_PROTOCOLS, var_inet_protocols); 766 767 /* 768 * This routine runs when a client has connected to our network port. 769 * Look up and sanitize the peer name and initialize some connection- 770 * specific state. 771 */ 772 state = qmqpd_state_alloc(stream); 773 774 /* 775 * See if we need to turn on verbose logging for this client. 776 */ 777 debug_peer_check(state->name, state->addr); 778 779 /* 780 * Provide the QMQP service. 781 */ 782 msg_info("connect from %s", state->namaddr); 783 qmqpd_proto(state); 784 msg_info("disconnect from %s", state->namaddr); 785 786 /* 787 * After the client has gone away, clean up whatever we have set up at 788 * connection time. 789 */ 790 debug_peer_restore(); 791 qmqpd_state_free(state); 792 } 793 794 /* pre_accept - see if tables have changed */ 795 796 static void pre_accept(char *unused_name, char **unused_argv) 797 { 798 const char *table; 799 800 if ((table = dict_changed_name()) != 0) { 801 msg_info("table %s has changed -- restarting", table); 802 exit(0); 803 } 804 } 805 806 /* pre_jail_init - pre-jail initialization */ 807 808 static void pre_jail_init(char *unused_name, char **unused_argv) 809 { 810 debug_peer_init(); 811 qmqpd_clients = 812 namadr_list_init(VAR_QMQPD_CLIENTS, MATCH_FLAG_RETURN 813 | match_parent_style(VAR_QMQPD_CLIENTS), 814 var_qmqpd_clients); 815 } 816 817 /* post_jail_init - post-jail initialization */ 818 819 static void post_jail_init(char *unused_name, char **unused_argv) 820 { 821 822 /* 823 * Initialize the receive transparency options: do we want unknown 824 * recipient checks, do we want address mapping. 825 */ 826 qmqpd_input_transp_mask = 827 input_transp_mask(VAR_INPUT_TRANSP, var_input_transp); 828 } 829 830 MAIL_VERSION_STAMP_DECLARE; 831 832 /* main - the main program */ 833 834 int main(int argc, char **argv) 835 { 836 static const CONFIG_TIME_TABLE time_table[] = { 837 VAR_QMTPD_TMOUT, DEF_QMTPD_TMOUT, &var_qmqpd_timeout, 1, 0, 838 VAR_QMTPD_ERR_SLEEP, DEF_QMTPD_ERR_SLEEP, &var_qmqpd_err_sleep, 0, 0, 839 0, 840 }; 841 static const CONFIG_STR_TABLE str_table[] = { 842 VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0, 843 VAR_QMQPD_CLIENTS, DEF_QMQPD_CLIENTS, &var_qmqpd_clients, 0, 0, 844 VAR_INPUT_TRANSP, DEF_INPUT_TRANSP, &var_input_transp, 0, 0, 845 0, 846 }; 847 static const CONFIG_BOOL_TABLE bool_table[] = { 848 VAR_QMQPD_CLIENT_PORT_LOG, DEF_QMQPD_CLIENT_PORT_LOG, &var_qmqpd_client_port_log, 849 0, 850 }; 851 852 /* 853 * Fingerprint executables and core dumps. 854 */ 855 MAIL_VERSION_STAMP_ALLOCATE; 856 857 /* 858 * Pass control to the single-threaded service skeleton. 859 */ 860 single_server_main(argc, argv, qmqpd_service, 861 CA_MAIL_SERVER_TIME_TABLE(time_table), 862 CA_MAIL_SERVER_STR_TABLE(str_table), 863 CA_MAIL_SERVER_BOOL_TABLE(bool_table), 864 CA_MAIL_SERVER_PRE_INIT(pre_jail_init), 865 CA_MAIL_SERVER_PRE_ACCEPT(pre_accept), 866 CA_MAIL_SERVER_POST_INIT(post_jail_init), 867 0); 868 } 869