int main(int argc, char **argv) { int ch; int fd; struct stat st; int junk; ARGV *ext_argv = 0; int param_class = PC_PARAM_MASK_CLASS; static const NAME_MASK param_class_table[] = { "builtin", PC_PARAM_FLAG_BUILTIN, "service", PC_PARAM_FLAG_SERVICE, "user", PC_PARAM_FLAG_USER, "all", PC_PARAM_MASK_CLASS, 0, }; /* * Fingerprint executables and core dumps. */ MAIL_VERSION_STAMP_ALLOCATE; /* * Be consistent with file permissions. */ umask(022); /* * To minimize confusion, make sure that the standard file descriptors * are open before opening anything else. XXX Work around for 44BSD where * fstat can return EBADF on an open file descriptor. */ for (fd = 0; fd < 3; fd++) if (fstat(fd, &st) == -1 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* * Set up logging. */ msg_vstream_init(argv[0], VSTREAM_ERR); /* * Parse JCL. */ while ((ch = GETOPT(argc, argv, "aAbc:C:deEf#hlmMntv")) > 0) { switch (ch) { case 'a': cmd_mode |= SHOW_SASL_SERV; break; case 'A': cmd_mode |= SHOW_SASL_CLNT; break; case 'b': if (ext_argv) msg_fatal("specify one of -b and -t"); ext_argv = argv_alloc(2); argv_add(ext_argv, "bounce", "-SVnexpand_templates", (char *) 0); break; case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'C': param_class = name_mask_opt("-C option", param_class_table, optarg, NAME_MASK_ANY_CASE | NAME_MASK_FATAL); break; case 'd': cmd_mode |= SHOW_DEFS; break; case 'e': cmd_mode |= EDIT_MAIN; break; case 'f': cmd_mode |= FOLD_LINE; break; /* * People, this does not work unless you properly handle default * settings. For example, fast_flush_domains = $relay_domains * must not evaluate to the empty string when relay_domains is * left at its default setting of $mydestination. */ #if 0 case 'E': cmd_mode |= SHOW_EVAL; break; #endif case '#': cmd_mode = COMMENT_OUT; break; case 'h': cmd_mode &= ~SHOW_NAME; break; case 'l': cmd_mode |= SHOW_LOCKS; break; case 'm': cmd_mode |= SHOW_MAPS; break; case 'M': cmd_mode |= SHOW_MASTER; break; case 'n': cmd_mode |= SHOW_NONDEF; break; case 't': if (ext_argv) msg_fatal("specify one of -b and -t"); ext_argv = argv_alloc(2); argv_add(ext_argv, "bounce", "-SVndump_templates", (char *) 0); break; case 'v': msg_verbose++; break; default: msg_fatal("usage: %s [-a (server SASL types)] [-A (client SASL types)] [-b (bounce templates)] [-c config_dir] [-C param_class] [-d (defaults)] [-e (edit)] [-f (fold lines)] [-# (comment-out)] [-h (no names)] [-l (lock types)] [-m (map types)] [-M (master.cf)] [-n (non-defaults)] [-v] [name...]", argv[0]); } } /* * Sanity check. */ junk = (cmd_mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | SHOW_LOCKS | EDIT_MAIN | SHOW_SASL_SERV | SHOW_SASL_CLNT | COMMENT_OUT | SHOW_MASTER)); if (junk != 0 && ((junk != SHOW_DEFS && junk != SHOW_NONDEF && junk != SHOW_MAPS && junk != SHOW_LOCKS && junk != EDIT_MAIN && junk != SHOW_SASL_SERV && junk != SHOW_SASL_CLNT && junk != COMMENT_OUT && junk != SHOW_MASTER) || ext_argv != 0)) msg_fatal("specify one of -a, -A, -b, -d, -e, -#, -l, -m, -M and -n"); /* * Display bounce template information and exit. */ if (ext_argv) { if (argv[optind]) { if (argv[optind + 1]) msg_fatal("options -b and -t require at most one template file"); argv_add(ext_argv, "-o", concatenate(VAR_BOUNCE_TMPL, "=", argv[optind], (char *) 0), (char *) 0); } /* Grr... */ argv_add(ext_argv, "-o", concatenate(VAR_QUEUE_DIR, "=", ".", (char *) 0), (char *) 0); mail_conf_read(); mail_run_replace(var_daemon_dir, ext_argv->argv); /* NOTREACHED */ } /* * If showing map types, show them and exit */ if (cmd_mode & SHOW_MAPS) { mail_dict_init(); show_maps(); } /* * If showing locking methods, show them and exit */ else if (cmd_mode & SHOW_LOCKS) { show_locks(); } /* * If showing master.cf entries, show them and exit */ else if (cmd_mode & SHOW_MASTER) { read_master(FAIL_ON_OPEN_ERROR); show_master(cmd_mode, argv + optind); } /* * If showing SASL plug-in types, show them and exit */ else if (cmd_mode & SHOW_SASL_SERV) { show_sasl(SHOW_SASL_SERV); } else if (cmd_mode & SHOW_SASL_CLNT) { show_sasl(SHOW_SASL_CLNT); } /* * Edit main.cf. */ else if (cmd_mode & (EDIT_MAIN | COMMENT_OUT)) { edit_parameters(cmd_mode, argc - optind, argv + optind); } else if (cmd_mode == DEF_MODE && argv[optind] && strchr(argv[optind], '=')) { edit_parameters(cmd_mode | EDIT_MAIN, argc - optind, argv + optind); } /* * If showing non-default values, read main.cf. */ else { if ((cmd_mode & SHOW_DEFS) == 0) { read_parameters(); set_parameters(); } register_builtin_parameters(); /* * Add service-dependent parameters (service names from master.cf) * and user-defined parameters ($name macros in parameter values in * main.cf and master.cf, but only if those names have a name=value * in main.cf or master.cf). */ read_master(WARN_ON_OPEN_ERROR); register_service_parameters(); if ((cmd_mode & SHOW_DEFS) == 0) register_user_parameters(); /* * Show the requested values. */ show_parameters(cmd_mode, param_class, argv + optind); /* * Flag unused parameters. This makes no sense with "postconf -d", * because that ignores all the user-specified parameters and * user-specified macro expansions in main.cf. */ if ((cmd_mode & SHOW_DEFS) == 0) { flag_unused_main_parameters(); flag_unused_master_parameters(); } } vstream_fflush(VSTREAM_OUT); exit(0); }
int main(int argc, char **argv) { int ch; int fd; struct stat st; ARGV *ext_argv = 0; int param_class = PCF_PARAM_MASK_CLASS; static const NAME_MASK param_class_table[] = { "builtin", PCF_PARAM_FLAG_BUILTIN, "service", PCF_PARAM_FLAG_SERVICE, "user", PCF_PARAM_FLAG_USER, "all", PCF_PARAM_MASK_CLASS, 0, }; ARGV *override_params = 0; /* * Fingerprint executables and core dumps. */ MAIL_VERSION_STAMP_ALLOCATE; /* * Be consistent with file permissions. */ umask(022); /* * To minimize confusion, make sure that the standard file descriptors * are open before opening anything else. XXX Work around for 44BSD where * fstat can return EBADF on an open file descriptor. */ for (fd = 0; fd < 3; fd++) if (fstat(fd, &st) == -1 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* * Set up logging. */ msg_vstream_init(argv[0], VSTREAM_ERR); /* * Parse JCL. */ while ((ch = GETOPT(argc, argv, "aAbc:C:deEfFhlmMno:pPtvxX#")) > 0) { switch (ch) { case 'a': pcf_cmd_mode |= PCF_SHOW_SASL_SERV; break; case 'A': pcf_cmd_mode |= PCF_SHOW_SASL_CLNT; break; case 'b': pcf_cmd_mode |= PCF_EXP_DSN_TEMPL; if (ext_argv) msg_fatal("specify one of -b and -t"); ext_argv = argv_alloc(2); argv_add(ext_argv, "bounce", "-SVnexpand_templates", (char *) 0); break; case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'C': param_class = name_mask_opt("-C option", param_class_table, optarg, NAME_MASK_ANY_CASE | NAME_MASK_FATAL); break; case 'd': pcf_cmd_mode |= PCF_SHOW_DEFS; break; case 'e': pcf_cmd_mode |= PCF_EDIT_CONF; break; case 'f': pcf_cmd_mode |= PCF_FOLD_LINE; break; case 'F': pcf_cmd_mode |= PCF_MASTER_FLD; break; case '#': pcf_cmd_mode |= PCF_COMMENT_OUT; break; case 'h': pcf_cmd_mode |= PCF_HIDE_NAME; break; case 'l': pcf_cmd_mode |= PCF_SHOW_LOCKS; break; case 'm': pcf_cmd_mode |= PCF_SHOW_MAPS; break; case 'M': pcf_cmd_mode |= PCF_MASTER_ENTRY; break; case 'n': pcf_cmd_mode |= PCF_SHOW_NONDEF; break; case 'o': pcf_cmd_mode |= PCF_MAIN_OVER; if (override_params == 0) override_params = argv_alloc(2); argv_add(override_params, optarg, (char *) 0); break; case 'p': pcf_cmd_mode |= PCF_MAIN_PARAM; break; case 'P': pcf_cmd_mode |= PCF_MASTER_PARAM; break; case 't': pcf_cmd_mode |= PCF_DUMP_DSN_TEMPL; if (ext_argv) msg_fatal("specify one of -b and -t"); ext_argv = argv_alloc(2); argv_add(ext_argv, "bounce", "-SVndump_templates", (char *) 0); break; case 'x': pcf_cmd_mode |= PCF_SHOW_EVAL; break; case 'X': /* This is irreversible, therefore require two-finger action. */ pcf_cmd_mode |= PCF_EDIT_EXCL; break; case 'v': msg_verbose++; break; default: usage(argv[0]); } } /* * Make all options explicit, before checking their compatibility. */ #define PCF_MAIN_OR_MASTER \ (PCF_MAIN_PARAM | PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM) if ((pcf_cmd_mode & pcf_incompat_options[0]) == 0) pcf_cmd_mode |= PCF_MAIN_PARAM; if ((pcf_cmd_mode & PCF_MAIN_OR_MASTER) && argv[optind] && strchr(argv[optind], '=')) pcf_cmd_mode |= PCF_EDIT_CONF; /* * Sanity check. */ pcf_check_exclusive_options(pcf_cmd_mode); pcf_check_compat_options(pcf_cmd_mode); if ((pcf_cmd_mode & PCF_EDIT_CONF) && argc == optind) msg_fatal("-e requires name=value argument"); /* * Display bounce template information and exit. */ if (ext_argv) { if (argv[optind]) { if (argv[optind + 1]) msg_fatal("options -b and -t require at most one template file"); argv_add(ext_argv, "-o", concatenate(VAR_BOUNCE_TMPL, "=", argv[optind], (char *) 0), (char *) 0); } /* Grr... */ argv_add(ext_argv, "-o", concatenate(VAR_QUEUE_DIR, "=", ".", (char *) 0), (char *) 0); mail_conf_read(); mail_run_replace(var_daemon_dir, ext_argv->argv); /* NOTREACHED */ } /* * If showing map types, show them and exit */ if (pcf_cmd_mode & PCF_SHOW_MAPS) { mail_dict_init(); pcf_show_maps(); } /* * If showing locking methods, show them and exit */ else if (pcf_cmd_mode & PCF_SHOW_LOCKS) { pcf_show_locks(); } /* * If showing master.cf entries, show them and exit */ else if ((pcf_cmd_mode & (PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM)) && !(pcf_cmd_mode & (PCF_EDIT_CONF | PCF_EDIT_EXCL | PCF_COMMENT_OUT))) { pcf_read_master(PCF_FAIL_ON_OPEN_ERROR); pcf_read_parameters(); if (override_params) pcf_set_parameters(override_params->argv); pcf_register_builtin_parameters(basename(argv[0]), getpid()); pcf_register_service_parameters(); pcf_register_user_parameters(); if (pcf_cmd_mode & PCF_MASTER_FLD) pcf_show_master_fields(VSTREAM_OUT, pcf_cmd_mode, argc - optind, argv + optind); else if (pcf_cmd_mode & PCF_MASTER_PARAM) pcf_show_master_params(VSTREAM_OUT, pcf_cmd_mode, argc - optind, argv + optind); else pcf_show_master_entries(VSTREAM_OUT, pcf_cmd_mode, argc - optind, argv + optind); } /* * If showing SASL plug-in types, show them and exit */ else if (pcf_cmd_mode & PCF_SHOW_SASL_SERV) { pcf_show_sasl(PCF_SHOW_SASL_SERV); } else if (pcf_cmd_mode & PCF_SHOW_SASL_CLNT) { pcf_show_sasl(PCF_SHOW_SASL_CLNT); } /* * Edit main.cf or master.cf. */ else if (pcf_cmd_mode & (PCF_EDIT_CONF | PCF_COMMENT_OUT | PCF_EDIT_EXCL)) { if (optind == argc) msg_fatal("missing service argument"); if (pcf_cmd_mode & (PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM)) { pcf_edit_master(pcf_cmd_mode, argc - optind, argv + optind); } else { pcf_edit_main(pcf_cmd_mode, argc - optind, argv + optind); } } /* * If showing non-default values, read main.cf. */ else { if ((pcf_cmd_mode & PCF_SHOW_DEFS) == 0) { pcf_read_parameters(); if (override_params) pcf_set_parameters(override_params->argv); } pcf_register_builtin_parameters(basename(argv[0]), getpid()); /* * Add service-dependent parameters (service names from master.cf) * and user-defined parameters ($name macros in parameter values in * main.cf and master.cf, but only if those names have a name=value * in main.cf or master.cf). */ pcf_read_master(PCF_WARN_ON_OPEN_ERROR); pcf_register_service_parameters(); if ((pcf_cmd_mode & PCF_SHOW_DEFS) == 0) pcf_register_user_parameters(); /* * Show the requested values. */ pcf_show_parameters(VSTREAM_OUT, pcf_cmd_mode, param_class, argv + optind); /* * Flag unused parameters. This makes no sense with "postconf -d", * because that ignores all the user-specified parameters and * user-specified macro expansions in main.cf. */ if ((pcf_cmd_mode & PCF_SHOW_DEFS) == 0) { pcf_flag_unused_main_parameters(); pcf_flag_unused_master_parameters(); } } vstream_fflush(VSTREAM_OUT); exit(0); }
int main(int argc, char **argv) { static char *full_name = 0; /* sendmail -F */ struct stat st; char *slash; char *sender = 0; /* sendmail -f */ int c; int fd; int mode; ARGV *ext_argv; int debug_me = 0; int err; int n; int flags = SM_FLAG_DEFAULT; char *site_to_flush = 0; char *id_to_flush = 0; char *encoding = 0; char *qtime = 0; const char *errstr; uid_t uid; const char *rewrite_context = MAIL_ATTR_RWR_LOCAL; int dsn_notify = 0; int dsn_ret = 0; const char *dsn_envid = 0; int saved_optind; /* * Fingerprint executables and core dumps. */ MAIL_VERSION_STAMP_ALLOCATE; /* * Be consistent with file permissions. */ umask(022); /* * To minimize confusion, make sure that the standard file descriptors * are open before opening anything else. XXX Work around for 44BSD where * fstat can return EBADF on an open file descriptor. */ for (fd = 0; fd < 3; fd++) if (fstat(fd, &st) == -1 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal_status(EX_OSERR, "open /dev/null: %m"); /* * The CDE desktop calendar manager leaks a parent file descriptor into * the child process. For the sake of sendmail compatibility we have to * close the file descriptor otherwise mail notification will hang. */ for ( /* void */ ; fd < 100; fd++) (void) close(fd); /* * Process environment options as early as we can. We might be called * from a set-uid (set-gid) program, so be careful with importing * environment variables. */ if (safe_getenv(CONF_ENV_VERB)) msg_verbose = 1; if (safe_getenv(CONF_ENV_DEBUG)) debug_me = 1; /* * Initialize. Set up logging, read the global configuration file and * extract configuration information. Set up signal handlers so that we * can clean up incomplete output. */ if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) argv[0] = slash + 1; msg_vstream_init(argv[0], VSTREAM_ERR); msg_cleanup(tempfail); msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY); set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); /* * Check the Postfix library version as soon as we enable logging. */ MAIL_VERSION_CHECK; /* * Some sites mistakenly install Postfix sendmail as set-uid root. Drop * set-uid privileges only when root, otherwise some systems will not * reset the saved set-userid, which would be a security vulnerability. */ if (geteuid() == 0 && getuid() != 0) { msg_warn("the Postfix sendmail command has set-uid root file permissions"); msg_warn("or the command is run from a set-uid root process"); msg_warn("the Postfix sendmail command must be installed without set-uid root file permissions"); set_ugid(getuid(), getgid()); } /* * Further initialization. Load main.cf first, so that command-line * options can override main.cf settings. Pre-scan the argument list so * that we load the right main.cf file. */ #define GETOPT_LIST "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx" saved_optind = optind; while (argv[OPTIND] != 0) { if (strcmp(argv[OPTIND], "-q") == 0) { /* not getopt compatible */ optind++; continue; } if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0) break; if (c == 'C') { VSTRING *buf = vstring_alloc(1); if (setenv(CONF_ENV_PATH, strcmp(sane_basename(buf, optarg), MAIN_CONF_FILE) == 0 ? sane_dirname(buf, optarg) : optarg, 1) < 0) msg_fatal_status(EX_UNAVAILABLE, "out of memory"); vstring_free(buf); } } optind = saved_optind; mail_conf_read(); /* Re-evaluate mail_task() after reading main.cf. */ msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY); get_mail_conf_str_table(str_table); if (chdir(var_queue_dir)) msg_fatal_status(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir); signal(SIGPIPE, SIG_IGN); /* * Optionally start the debugger on ourself. This must be done after * reading the global configuration file, because that file specifies * what debugger command to execute. */ if (debug_me) debug_process(); /* * The default mode of operation is determined by the process name. It * can, however, be changed via command-line options (for example, * "newaliases -bp" will show the mail queue). */ if (strcmp(argv[0], "mailq") == 0) { mode = SM_MODE_MAILQ; } else if (strcmp(argv[0], "newaliases") == 0) { mode = SM_MODE_NEWALIAS; } else if (strcmp(argv[0], "smtpd") == 0) { mode = SM_MODE_DAEMON; } else { mode = SM_MODE_ENQUEUE; } /* * Parse JCL. Sendmail has been around for a long time, and has acquired * a large number of options in the course of time. Some options such as * -q are not parsable with GETOPT() and get special treatment. */ #define OPTIND (optind > 0 ? optind : 1) while (argv[OPTIND] != 0) { if (strcmp(argv[OPTIND], "-q") == 0) { if (mode == SM_MODE_DAEMON) msg_warn("ignoring -q option in daemon mode"); else mode = SM_MODE_FLUSHQ; optind++; continue; } if (strcmp(argv[OPTIND], "-V") == 0 && argv[OPTIND + 1] != 0 && strlen(argv[OPTIND + 1]) == 2) { msg_warn("option -V is deprecated with Postfix 2.3; " "specify -XV instead"); argv[OPTIND] = "-XV"; } if (strncmp(argv[OPTIND], "-V", 2) == 0 && strlen(argv[OPTIND]) == 4) { msg_warn("option %s is deprecated with Postfix 2.3; " "specify -X%s instead", argv[OPTIND], argv[OPTIND] + 1); argv[OPTIND] = concatenate("-X", argv[OPTIND] + 1, (char *) 0); } if (strcmp(argv[OPTIND], "-XV") == 0) { verp_delims = var_verp_delims; optind++; continue; } if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0) break; switch (c) { default: if (msg_verbose) msg_info("-%c option ignored", c); break; case 'n': msg_fatal_status(EX_USAGE, "-%c option not supported", c); case 'B': if (strcmp(optarg, "8BITMIME") == 0)/* RFC 1652 */ encoding = MAIL_ATTR_ENC_8BIT; else if (strcmp(optarg, "7BIT") == 0) /* RFC 1652 */ encoding = MAIL_ATTR_ENC_7BIT; else msg_fatal_status(EX_USAGE, "-B option needs 8BITMIME or 7BIT"); break; case 'F': /* full name */ full_name = optarg; break; case 'G': /* gateway submission */ rewrite_context = MAIL_ATTR_RWR_REMOTE; break; case 'I': /* newaliases */ mode = SM_MODE_NEWALIAS; break; case 'N': if ((dsn_notify = dsn_notify_mask(optarg)) == 0) msg_warn("bad -N option value -- ignored"); break; case 'R': if ((dsn_ret = dsn_ret_code(optarg)) == 0) msg_warn("bad -R option value -- ignored"); break; case 'V': /* DSN, was: VERP */ if (strlen(optarg) > 100) msg_warn("too long -V option value -- ignored"); else if (!allprint(optarg)) msg_warn("bad syntax in -V option value -- ignored"); else dsn_envid = optarg; break; case 'X': switch (*optarg) { default: msg_fatal_status(EX_USAGE, "unsupported: -%c%c", c, *optarg); case 'V': /* VERP */ if (verp_delims_verify(optarg + 1) != 0) msg_fatal_status(EX_USAGE, "-V requires two characters from %s", var_verp_filter); verp_delims = optarg + 1; break; } break; case 'b': switch (*optarg) { default: msg_fatal_status(EX_USAGE, "unsupported: -%c%c", c, *optarg); case 'd': /* daemon mode */ case 'l': /* daemon mode */ if (mode == SM_MODE_FLUSHQ) msg_warn("ignoring -q option in daemon mode"); mode = SM_MODE_DAEMON; break; case 'h': /* print host status */ case 'H': /* flush host status */ mode = SM_MODE_IGNORE; break; case 'i': /* newaliases */ mode = SM_MODE_NEWALIAS; break; case 'm': /* deliver mail */ mode = SM_MODE_ENQUEUE; break; case 'p': /* mailq */ mode = SM_MODE_MAILQ; break; case 's': /* stand-alone mode */ mode = SM_MODE_USER; break; case 'v': /* expand recipients */ flags |= DEL_REQ_FLAG_USR_VRFY; break; } break; case 'f': sender = optarg; break; case 'i': flags &= ~SM_FLAG_AEOF; break; case 'o': switch (*optarg) { default: if (msg_verbose) msg_info("-%c%c option ignored", c, *optarg); break; case 'A': if (optarg[1] == 0) msg_fatal_status(EX_USAGE, "-oA requires pathname"); myfree(var_alias_db_map); var_alias_db_map = mystrdup(optarg + 1); set_mail_conf_str(VAR_ALIAS_DB_MAP, var_alias_db_map); break; case '7': case '8': break; case 'i': flags &= ~SM_FLAG_AEOF; break; case 'm': break; } break; case 'r': /* obsoleted by -f */ sender = optarg; break; case 'q': if (ISDIGIT(optarg[0])) { qtime = optarg; } else if (optarg[0] == 'R') { site_to_flush = optarg + 1; if (*site_to_flush == 0) msg_fatal_status(EX_USAGE, "specify: -qRsitename"); } else if (optarg[0] == 'I') { id_to_flush = optarg + 1; if (*id_to_flush == 0) msg_fatal_status(EX_USAGE, "specify: -qIqueueid"); } else { msg_fatal_status(EX_USAGE, "-q%c is not implemented", optarg[0]); } break; case 't': flags |= SM_FLAG_XRCPT; break; case 'v': msg_verbose++; break; case '?': msg_fatal_status(EX_USAGE, "usage: %s [options]", argv[0]); } } /* * Look for conflicting options and arguments. */ if ((flags & SM_FLAG_XRCPT) && mode != SM_MODE_ENQUEUE) msg_fatal_status(EX_USAGE, "-t can be used only in delivery mode"); if (site_to_flush && mode != SM_MODE_ENQUEUE) msg_fatal_status(EX_USAGE, "-qR can be used only in delivery mode"); if (id_to_flush && mode != SM_MODE_ENQUEUE) msg_fatal_status(EX_USAGE, "-qI can be used only in delivery mode"); if (flags & DEL_REQ_FLAG_USR_VRFY) { if (flags & SM_FLAG_XRCPT) msg_fatal_status(EX_USAGE, "-t option cannot be used with -bv"); if (dsn_notify) msg_fatal_status(EX_USAGE, "-N option cannot be used with -bv"); if (dsn_ret) msg_fatal_status(EX_USAGE, "-R option cannot be used with -bv"); if (msg_verbose == 1) msg_fatal_status(EX_USAGE, "-v option cannot be used with -bv"); } /* * The -v option plays double duty. One requests verbose delivery, more * than one requests verbose logging. */ if (msg_verbose == 1 && mode == SM_MODE_ENQUEUE) { msg_verbose = 0; flags |= DEL_REQ_FLAG_RECORD; } /* * Start processing. Everything is delegated to external commands. */ if (qtime && mode != SM_MODE_DAEMON) exit(0); switch (mode) { default: msg_panic("unknown operation mode: %d", mode); /* NOTREACHED */ case SM_MODE_ENQUEUE: if (site_to_flush) { if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "flush site requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postqueue", "-s", site_to_flush, (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ } else if (id_to_flush) { if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "flush queue_id requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postqueue", "-i", id_to_flush, (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ } else { enqueue(flags, encoding, dsn_envid, dsn_ret, dsn_notify, rewrite_context, sender, full_name, argv + OPTIND); exit(0); /* NOTREACHED */ } break; case SM_MODE_MAILQ: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "display queue mode requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postqueue", "-p", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ case SM_MODE_FLUSHQ: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "flush queue mode requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postqueue", "-f", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ case SM_MODE_DAEMON: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "daemon mode requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postfix", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_add(ext_argv, "start", (char *) 0); argv_terminate(ext_argv); err = (mail_run_background(var_command_dir, ext_argv->argv) < 0); argv_free(ext_argv); exit(err); break; case SM_MODE_NEWALIAS: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "alias initialization mode requires no recipient"); if (*var_alias_db_map == 0) return (0); ext_argv = argv_alloc(2); argv_add(ext_argv, "postalias", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_split_append(ext_argv, var_alias_db_map, CHARS_COMMA_SP); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ case SM_MODE_USER: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "stand-alone mode requires no recipient"); /* The actual enforcement happens in the postdrop command. */ if ((errstr = check_user_acl_byuid(VAR_SUBMIT_ACL, var_submit_acl, uid = getuid())) != 0) msg_fatal_status(EX_NOPERM, "User %s(%ld) is not allowed to submit mail", errstr, (long) uid); ext_argv = argv_alloc(2); argv_add(ext_argv, "smtpd", "-S", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_daemon_dir, ext_argv->argv); /* NOTREACHED */ case SM_MODE_IGNORE: exit(0); /* NOTREACHED */ } }
int main(int argc, char **argv) { int ch; int fd; struct stat st; int junk; ARGV *ext_argv = 0; /* * Fingerprint executables and core dumps. */ MAIL_VERSION_STAMP_ALLOCATE; /* * Be consistent with file permissions. */ umask(022); /* * To minimize confusion, make sure that the standard file descriptors * are open before opening anything else. XXX Work around for 44BSD where * fstat can return EBADF on an open file descriptor. */ for (fd = 0; fd < 3; fd++) if (fstat(fd, &st) == -1 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* * Set up logging. */ msg_vstream_init(argv[0], VSTREAM_ERR); /* * Parse JCL. */ while ((ch = GETOPT(argc, argv, "aAbc:deE#hmlntv")) > 0) { switch (ch) { case 'a': cmd_mode |= SHOW_SASL_SERV; break; case 'A': cmd_mode |= SHOW_SASL_CLNT; break; case 'b': if (ext_argv) msg_fatal("specify one of -b and -t"); ext_argv = argv_alloc(2); argv_add(ext_argv, "bounce", "-SVnexpand_templates", (char *) 0); break; case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'd': cmd_mode |= SHOW_DEFS; break; case 'e': cmd_mode |= EDIT_MAIN; break; /* * People, this does not work unless you properly handle default * settings. For example, fast_flush_domains = $relay_domains * must not evaluate to the empty string when relay_domains is * left at its default setting of $mydestination. */ #if 0 case 'E': cmd_mode |= SHOW_EVAL; break; #endif case '#': cmd_mode = COMMENT_OUT; break; case 'h': cmd_mode &= ~SHOW_NAME; break; case 'l': cmd_mode |= SHOW_LOCKS; break; case 'm': cmd_mode |= SHOW_MAPS; break; case 'n': cmd_mode |= SHOW_NONDEF; break; case 't': if (ext_argv) msg_fatal("specify one of -b and -t"); ext_argv = argv_alloc(2); argv_add(ext_argv, "bounce", "-SVndump_templates", (char *) 0); break; case 'v': msg_verbose++; break; default: msg_fatal("usage: %s [-a (server SASL types)] [-A (client SASL types)] [-b (bounce templates)] [-c config_dir] [-d (defaults)] [-e (edit)] [-# (comment-out)] [-h (no names)] [-l (lock types)] [-m (map types)] [-n (non-defaults)] [-v] [name...]", argv[0]); } } /* * Sanity check. */ junk = (cmd_mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | SHOW_LOCKS | EDIT_MAIN | SHOW_SASL_SERV | SHOW_SASL_CLNT | COMMENT_OUT)); if (junk != 0 && ((junk != SHOW_DEFS && junk != SHOW_NONDEF && junk != SHOW_MAPS && junk != SHOW_LOCKS && junk != EDIT_MAIN && junk != SHOW_SASL_SERV && junk != SHOW_SASL_CLNT && junk != COMMENT_OUT) || ext_argv != 0)) msg_fatal("specify one of -a, -A, -b, -d, -e, -#, -m, -l and -n"); /* * Display bounce template information and exit. */ if (ext_argv) { if (argv[optind]) { if (argv[optind + 1]) msg_fatal("options -b and -t require at most one template file"); argv_add(ext_argv, "-o", concatenate(VAR_BOUNCE_TMPL, "=", argv[optind], (char *) 0), (char *) 0); } /* Grr... */ argv_add(ext_argv, "-o", concatenate(VAR_QUEUE_DIR, "=", ".", (char *) 0), (char *) 0); mail_conf_read(); mail_run_replace(var_daemon_dir, ext_argv->argv); /* NOTREACHED */ } /* * If showing map types, show them and exit */ if (cmd_mode & SHOW_MAPS) { mail_dict_init(); show_maps(); } /* * If showing locking methods, show them and exit */ else if (cmd_mode & SHOW_LOCKS) { show_locks(); } /* * If showing SASL plug-in types, show them and exit */ else if (cmd_mode & SHOW_SASL_SERV) { show_sasl(SHOW_SASL_SERV); } else if (cmd_mode & SHOW_SASL_CLNT) { show_sasl(SHOW_SASL_CLNT); } /* * Edit main.cf. */ else if (cmd_mode & (EDIT_MAIN | COMMENT_OUT)) { edit_parameters(cmd_mode, argc - optind, argv + optind); } /* * If showing non-default values, read main.cf. */ else { if ((cmd_mode & SHOW_DEFS) == 0) { read_parameters(); set_parameters(); } /* * Throw together all parameters and show the asked values. */ hash_parameters(); show_parameters(cmd_mode, argv + optind); } vstream_fflush(VSTREAM_OUT); exit(0); }