1/*++ 2/* NAME 3/* postdrop 1 4/* SUMMARY 5/* Postfix mail posting utility 6/* SYNOPSIS 7/* \fBpostdrop\fR [\fB-rv\fR] [\fB-c \fIconfig_dir\fR] 8/* DESCRIPTION 9/* The \fBpostdrop\fR(1) command creates a file in the \fBmaildrop\fR 10/* directory and copies its standard input to the file. 11/* 12/* Options: 13/* .IP "\fB-c \fIconfig_dir\fR" 14/* The \fBmain.cf\fR configuration file is in the named directory 15/* instead of the default configuration directory. See also the 16/* MAIL_CONFIG environment setting below. 17/* .IP \fB-r\fR 18/* Use a Postfix-internal protocol for reading the message from 19/* standard input, and for reporting status information on standard 20/* output. This is currently the only supported method. 21/* .IP \fB-v\fR 22/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR 23/* options make the software increasingly verbose. As of Postfix 2.3, 24/* this option is available for the super-user only. 25/* SECURITY 26/* .ad 27/* .fi 28/* The command is designed to run with set-group ID privileges, so 29/* that it can write to the \fBmaildrop\fR queue directory and so that 30/* it can connect to Postfix daemon processes. 31/* DIAGNOSTICS 32/* Fatal errors: malformed input, I/O error, out of memory. Problems 33/* are logged to \fBsyslogd\fR(8) and to the standard error stream. 34/* When the input is incomplete, or when the process receives a HUP, 35/* INT, QUIT or TERM signal, the queue file is deleted. 36/* ENVIRONMENT 37/* .ad 38/* .fi 39/* .IP MAIL_CONFIG 40/* Directory with the \fBmain.cf\fR file. In order to avoid exploitation 41/* of set-group ID privileges, a non-standard directory is allowed only 42/* if: 43/* .RS 44/* .IP \(bu 45/* The name is listed in the standard \fBmain.cf\fR file with the 46/* \fBalternate_config_directories\fR configuration parameter. 47/* .IP \(bu 48/* The command is invoked by the super-user. 49/* .RE 50/* CONFIGURATION PARAMETERS 51/* .ad 52/* .fi 53/* The following \fBmain.cf\fR parameters are especially relevant to 54/* this program. 55/* The text below provides only a parameter summary. See 56/* \fBpostconf\fR(5) for more details including examples. 57/* .IP "\fBalternate_config_directories (empty)\fR" 58/* A list of non-default Postfix configuration directories that may 59/* be specified with "-c config_directory" on the command line, or 60/* via the MAIL_CONFIG environment parameter. 61/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR" 62/* The default location of the Postfix main.cf and master.cf 63/* configuration files. 64/* .IP "\fBimport_environment (see 'postconf -d' output)\fR" 65/* The list of environment parameters that a Postfix process will 66/* import from a non-Postfix parent process. 67/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR" 68/* The location of the Postfix top-level queue directory. 69/* .IP "\fBsyslog_facility (mail)\fR" 70/* The syslog facility of Postfix logging. 71/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR" 72/* The mail system name that is prepended to the process name in syslog 73/* records, so that "smtpd" becomes, for example, "postfix/smtpd". 74/* .IP "\fBtrigger_timeout (10s)\fR" 75/* The time limit for sending a trigger to a Postfix daemon (for 76/* example, the \fBpickup\fR(8) or \fBqmgr\fR(8) daemon). 77/* .PP 78/* Available in Postfix version 2.2 and later: 79/* .IP "\fBauthorized_submit_users (static:anyone)\fR" 80/* List of users who are authorized to submit mail with the \fBsendmail\fR(1) 81/* command (and with the privileged \fBpostdrop\fR(1) helper command). 82/* FILES 83/* /var/spool/postfix/maildrop, maildrop queue 84/* SEE ALSO 85/* sendmail(1), compatibility interface 86/* postconf(5), configuration parameters 87/* syslogd(8), system logging 88/* LICENSE 89/* .ad 90/* .fi 91/* The Secure Mailer license must be distributed with this software. 92/* AUTHOR(S) 93/* Wietse Venema 94/* IBM T.J. Watson Research 95/* P.O. Box 704 96/* Yorktown Heights, NY 10598, USA 97/*--*/ 98 99/* System library. */ 100 101#include <sys_defs.h> 102#include <sys/stat.h> 103#include <unistd.h> 104#include <stdlib.h> 105#include <stdio.h> /* remove() */ 106#include <string.h> 107#include <stdlib.h> 108#include <signal.h> 109#include <syslog.h> 110#include <errno.h> 111#include <warn_stat.h> 112 113/* Utility library. */ 114 115#include <msg.h> 116#include <mymalloc.h> 117#include <vstream.h> 118#include <vstring.h> 119#include <msg_vstream.h> 120#include <msg_syslog.h> 121#include <argv.h> 122#include <iostuff.h> 123#include <stringops.h> 124 125/* Global library. */ 126 127#include <mail_proto.h> 128#include <mail_queue.h> 129#include <mail_params.h> 130#include <mail_version.h> 131#include <mail_conf.h> 132#include <mail_task.h> 133#include <clean_env.h> 134#include <mail_stream.h> 135#include <cleanup_user.h> 136#include <record.h> 137#include <rec_type.h> 138#include <user_acl.h> 139#include <rec_attr_map.h> 140 141/* Application-specific. */ 142 143 /* 144 * WARNING WARNING WARNING 145 * 146 * This software is designed to run set-gid. In order to avoid exploitation of 147 * privilege, this software should not run any external commands, nor should 148 * it take any information from the user unless that information can be 149 * properly sanitized. To get an idea of how much information a process can 150 * inherit from a potentially hostile user, examine all the members of the 151 * process structure (typically, in /usr/include/sys/proc.h): the current 152 * directory, open files, timers, signals, environment, command line, umask, 153 * and so on. 154 */ 155 156 /* 157 * Local mail submission access list. 158 */ 159char *var_submit_acl; 160 161static const CONFIG_STR_TABLE str_table[] = { 162 VAR_SUBMIT_ACL, DEF_SUBMIT_ACL, &var_submit_acl, 0, 0, 163 0, 164}; 165 166 /* 167 * Queue file name. Global, so that the cleanup routine can find it when 168 * called by the run-time error handler. 169 */ 170static char *postdrop_path; 171 172/* postdrop_sig - catch signal and clean up */ 173 174static void postdrop_sig(int sig) 175{ 176 177 /* 178 * This is the fatal error handler. Don't try to do anything fancy. 179 * 180 * msg_vstream does not allocate memory, but msg_syslog may indirectly in 181 * syslog(), so it should not be called from a user-triggered signal 182 * handler. 183 * 184 * Assume atomic signal() updates, even when emulated with sigaction(). We 185 * use the in-kernel SIGINT handler address as an atomic variable to 186 * prevent nested postdrop_sig() calls. For this reason, main() must 187 * configure postdrop_sig() as SIGINT handler before other signal 188 * handlers are allowed to invoke postdrop_sig(). 189 */ 190 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 191 (void) signal(SIGQUIT, SIG_IGN); 192 (void) signal(SIGTERM, SIG_IGN); 193 (void) signal(SIGHUP, SIG_IGN); 194 if (postdrop_path) { 195 (void) remove(postdrop_path); 196 postdrop_path = 0; 197 } 198 /* Future proofing. If you need exit() here then you broke Postfix. */ 199 if (sig) 200 _exit(sig); 201 } 202} 203 204/* postdrop_cleanup - callback for the runtime error handler */ 205 206static void postdrop_cleanup(void) 207{ 208 postdrop_sig(0); 209} 210 211MAIL_VERSION_STAMP_DECLARE; 212 213/* main - the main program */ 214 215int main(int argc, char **argv) 216{ 217 struct stat st; 218 int fd; 219 int c; 220 VSTRING *buf; 221 int status; 222 MAIL_STREAM *dst; 223 int rec_type; 224 static char *segment_info[] = { 225 REC_TYPE_POST_ENVELOPE, REC_TYPE_POST_CONTENT, REC_TYPE_POST_EXTRACT, "" 226 }; 227 char **expected; 228 uid_t uid = getuid(); 229 ARGV *import_env; 230 const char *error_text; 231 char *attr_name; 232 char *attr_value; 233 const char *errstr; 234 char *junk; 235 struct timeval start; 236 int saved_errno; 237 int from_count = 0; 238 int rcpt_count = 0; 239 int validate_input = 1; 240 241 /* 242 * Fingerprint executables and core dumps. 243 */ 244 MAIL_VERSION_STAMP_ALLOCATE; 245 246 /* 247 * Be consistent with file permissions. 248 */ 249 umask(022); 250 251 /* 252 * To minimize confusion, make sure that the standard file descriptors 253 * are open before opening anything else. XXX Work around for 44BSD where 254 * fstat can return EBADF on an open file descriptor. 255 */ 256 for (fd = 0; fd < 3; fd++) 257 if (fstat(fd, &st) == -1 258 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) 259 msg_fatal("open /dev/null: %m"); 260 261 /* 262 * Set up logging. Censor the process name: it is provided by the user. 263 */ 264 argv[0] = "postdrop"; 265 msg_vstream_init(argv[0], VSTREAM_ERR); 266 msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY); 267 set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); 268 269 /* 270 * Check the Postfix library version as soon as we enable logging. 271 */ 272 MAIL_VERSION_CHECK; 273 274 /* 275 * Parse JCL. This program is set-gid and must sanitize all command-line 276 * arguments. The configuration directory argument is validated by the 277 * mail configuration read routine. Don't do complex things until we have 278 * completed initializations. 279 */ 280 while ((c = GETOPT(argc, argv, "c:rv")) > 0) { 281 switch (c) { 282 case 'c': 283 if (setenv(CONF_ENV_PATH, optarg, 1) < 0) 284 msg_fatal("out of memory"); 285 break; 286 case 'r': /* forward compatibility */ 287 break; 288 case 'v': 289 if (geteuid() == 0) 290 msg_verbose++; 291 break; 292 default: 293 msg_fatal("usage: %s [-c config_dir] [-v]", argv[0]); 294 } 295 } 296 297 /* 298 * Read the global configuration file and extract configuration 299 * information. Some claim that the user should supply the working 300 * directory instead. That might be OK, given that this command needs 301 * write permission in a subdirectory called "maildrop". However we still 302 * need to reliably detect incomplete input, and so we must perform 303 * record-level I/O. With that, we should also take the opportunity to 304 * perform some sanity checks on the input. 305 */ 306 mail_conf_read(); 307 if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0) 308 msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY); 309 get_mail_conf_str_table(str_table); 310 311 /* 312 * Mail submission access control. Should this be in the user-land gate, 313 * or in the daemon process? 314 */ 315 if ((errstr = check_user_acl_byuid(var_submit_acl, uid)) != 0) 316 msg_fatal("User %s(%ld) is not allowed to submit mail", 317 errstr, (long) uid); 318 319 /* 320 * Stop run-away process accidents by limiting the queue file size. This 321 * is not a defense against DOS attack. 322 */ 323 if (var_message_limit > 0 && get_file_limit() > var_message_limit) 324 set_file_limit((off_t) var_message_limit); 325 326 /* 327 * This program is installed with setgid privileges. Strip the process 328 * environment so that we don't have to trust the C library. 329 */ 330 import_env = argv_split(var_import_environ, ", \t\r\n"); 331 clean_env(import_env->argv); 332 argv_free(import_env); 333 334 if (chdir(var_queue_dir)) 335 msg_fatal("chdir %s: %m", var_queue_dir); 336 if (msg_verbose) 337 msg_info("chdir %s", var_queue_dir); 338 339 /* 340 * Set up signal handlers and a runtime error handler so that we can 341 * clean up incomplete output. 342 * 343 * postdrop_sig() uses the in-kernel SIGINT handler address as an atomic 344 * variable to prevent nested postdrop_sig() calls. For this reason, the 345 * SIGINT handler must be configured before other signal handlers are 346 * allowed to invoke postdrop_sig(). 347 */ 348 signal(SIGPIPE, SIG_IGN); 349 signal(SIGXFSZ, SIG_IGN); 350 351 signal(SIGINT, postdrop_sig); 352 signal(SIGQUIT, postdrop_sig); 353 if (signal(SIGTERM, SIG_IGN) == SIG_DFL) 354 signal(SIGTERM, postdrop_sig); 355 if (signal(SIGHUP, SIG_IGN) == SIG_DFL) 356 signal(SIGHUP, postdrop_sig); 357 msg_cleanup(postdrop_cleanup); 358 359 /* End of initializations. */ 360 361 /* 362 * Don't trust the caller's time information. 363 */ 364 GETTIMEOFDAY(&start); 365 366 /* 367 * Create queue file. mail_stream_file() never fails. Send the queue ID 368 * to the caller. Stash away a copy of the queue file name so we can 369 * clean up in case of a fatal error or an interrupt. 370 */ 371 dst = mail_stream_file(MAIL_QUEUE_MAILDROP, MAIL_CLASS_PUBLIC, 372 var_pickup_service, 0444); 373 attr_print(VSTREAM_OUT, ATTR_FLAG_NONE, 374 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, dst->id, 375 ATTR_TYPE_END); 376 vstream_fflush(VSTREAM_OUT); 377 postdrop_path = mystrdup(VSTREAM_PATH(dst->stream)); 378 379 /* 380 * Copy stdin to file. The format is checked so that we can recognize 381 * incomplete input and cancel the operation. With the sanity checks 382 * applied here, the pickup daemon could skip format checks and pass a 383 * file descriptor to the cleanup daemon. These are by no means all 384 * sanity checks - the cleanup service and queue manager services will 385 * reject messages that lack required information. 386 * 387 * If something goes wrong, slurp up the input before responding to the 388 * client, otherwise the client will give up after detecting SIGPIPE. 389 * 390 * Allow attribute records if the attribute specifies the MIME body type 391 * (sendmail -B). 392 */ 393 vstream_control(VSTREAM_IN, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END); 394 buf = vstring_alloc(100); 395 expected = segment_info; 396 /* Override time information from the untrusted caller. */ 397 rec_fprintf(dst->stream, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT, 398 REC_TYPE_TIME_ARG(start)); 399 for (;;) { 400 /* Don't allow PTR records. */ 401 rec_type = rec_get_raw(VSTREAM_IN, buf, var_line_limit, REC_FLAG_NONE); 402 if (rec_type == REC_TYPE_EOF) { /* request cancelled */ 403 mail_stream_cleanup(dst); 404 if (remove(postdrop_path)) 405 msg_warn("uid=%ld: remove %s: %m", (long) uid, postdrop_path); 406 else if (msg_verbose) 407 msg_info("remove %s", postdrop_path); 408 myfree(postdrop_path); 409 postdrop_path = 0; 410 exit(0); 411 } 412 if (rec_type == REC_TYPE_ERROR) 413 msg_fatal("uid=%ld: malformed input", (long) uid); 414 if (strchr(*expected, rec_type) == 0) 415 msg_fatal("uid=%ld: unexpected record type: %d", (long) uid, rec_type); 416 if (rec_type == **expected) 417 expected++; 418 /* Override time information from the untrusted caller. */ 419 if (rec_type == REC_TYPE_TIME) 420 continue; 421 /* Check these at submission time instead of pickup time. */ 422 if (rec_type == REC_TYPE_FROM) 423 from_count++; 424 if (rec_type == REC_TYPE_RCPT) 425 rcpt_count++; 426 /* Limit the attribute types that users may specify. */ 427 if (rec_type == REC_TYPE_ATTR) { 428 if ((error_text = split_nameval(vstring_str(buf), &attr_name, 429 &attr_value)) != 0) { 430 msg_warn("uid=%ld: ignoring malformed record: %s: %.200s", 431 (long) uid, error_text, vstring_str(buf)); 432 continue; 433 } 434#define STREQ(x,y) (strcmp(x,y) == 0) 435 436 if ((STREQ(attr_name, MAIL_ATTR_ENCODING) 437 && (STREQ(attr_value, MAIL_ATTR_ENC_7BIT) 438 || STREQ(attr_value, MAIL_ATTR_ENC_8BIT) 439 || STREQ(attr_value, MAIL_ATTR_ENC_NONE))) 440 || STREQ(attr_name, MAIL_ATTR_DSN_ENVID) 441 || STREQ(attr_name, MAIL_ATTR_DSN_NOTIFY) 442 || rec_attr_map(attr_name) 443 || (STREQ(attr_name, MAIL_ATTR_RWR_CONTEXT) 444 && (STREQ(attr_value, MAIL_ATTR_RWR_LOCAL) 445 || STREQ(attr_value, MAIL_ATTR_RWR_REMOTE))) 446 || STREQ(attr_name, MAIL_ATTR_TRACE_FLAGS)) { /* XXX */ 447 rec_fprintf(dst->stream, REC_TYPE_ATTR, "%s=%s", 448 attr_name, attr_value); 449 } else { 450 msg_warn("uid=%ld: ignoring attribute record: %.200s=%.200s", 451 (long) uid, attr_name, attr_value); 452 } 453 continue; 454 } 455 if (REC_PUT_BUF(dst->stream, rec_type, buf) < 0) { 456 /* rec_get() errors must not clobber errno. */ 457 saved_errno = errno; 458 while ((rec_type = rec_get_raw(VSTREAM_IN, buf, var_line_limit, 459 REC_FLAG_NONE)) != REC_TYPE_END 460 && rec_type != REC_TYPE_EOF) 461 if (rec_type == REC_TYPE_ERROR) 462 msg_fatal("uid=%ld: malformed input", (long) uid); 463 validate_input = 0; 464 errno = saved_errno; 465 break; 466 } 467 if (rec_type == REC_TYPE_END) 468 break; 469 } 470 vstring_free(buf); 471 472 /* 473 * As of Postfix 2.7 the pickup daemon discards mail without recipients. 474 * Such mail may enter the maildrop queue when "postsuper -r" is invoked 475 * before the queue manager deletes an already delivered message. Looking 476 * at file ownership is not a good way to make decisions on what mail to 477 * discard. Instead, the pickup server now requires that new submissions 478 * always have at least one recipient record. 479 * 480 * The Postfix sendmail command already rejects mail without recipients. 481 * However, in the future postdrop may receive mail via other programs, 482 * so we add a redundant recipient check here for future proofing. 483 * 484 * The test for the sender address is just for consistency of error 485 * reporting (report at submission time instead of pickup time). Besides 486 * the segment terminator records, there aren't any other mandatory 487 * records in a Postfix submission queue file. 488 */ 489 if (validate_input && (from_count == 0 || rcpt_count == 0)) { 490 status = CLEANUP_STAT_BAD; 491 mail_stream_cleanup(dst); 492 } 493 494 /* 495 * Finish the file. 496 */ 497 else if ((status = mail_stream_finish(dst, (VSTRING *) 0)) != 0) { 498 msg_warn("uid=%ld: %m", (long) uid); 499 postdrop_cleanup(); 500 } 501 502 /* 503 * Disable deletion on fatal error before reporting success, so the file 504 * will not be deleted after we have taken responsibility for delivery. 505 */ 506 if (postdrop_path) { 507 junk = postdrop_path; 508 postdrop_path = 0; 509 myfree(junk); 510 } 511 512 /* 513 * Send the completion status to the caller and terminate. 514 */ 515 attr_print(VSTREAM_OUT, ATTR_FLAG_NONE, 516 ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, 517 ATTR_TYPE_STR, MAIL_ATTR_WHY, "", 518 ATTR_TYPE_END); 519 vstream_fflush(VSTREAM_OUT); 520 exit(status); 521} 522