int main(int unused_argc, char **unused_argv) { VSTRING *extension = vstring_alloc(1); VSTRING *buf = vstring_alloc(1); ARGV *argv; char **cpp; mail_conf_read(); if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); vstream_printf("extension: (CR for none): "); vstream_fflush(VSTREAM_OUT); if (vstring_get_nonl(extension, VSTREAM_IN) == VSTREAM_EOF) exit(0); vstream_printf("print strings to be translated, one per line\n"); vstream_fflush(VSTREAM_OUT); while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { argv = mail_addr_crunch(STR(buf), VSTRING_LEN(extension) ? STR(extension) : 0); for (cpp = argv->argv; *cpp; cpp++) vstream_printf(" %s\n", *cpp); vstream_fflush(VSTREAM_OUT); } return (0); }
int main(int argc, char **argv) { VSTRING *buffer = vstring_alloc(100); MAPS *path; const char *result; char *extent; /* * Parse JCL. */ if (argc != 2) msg_fatal("usage: %s database", argv[0]); msg_verbose = 1; /* * Initialize. */ mail_conf_read(); path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX); while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { extent = 0; result = mail_addr_find(path, STR(buffer), &extent); vstream_printf("%s -> %s (%s)\n", STR(buffer), result ? result : path->error ? "(try again)" : "(not found)", extent ? extent : "null extension"); vstream_fflush(VSTREAM_OUT); if (extent) myfree(extent); } vstring_free(buffer); maps_free(path); return (0); }
int main(int argc, char **argv) { VSTRING *why = vstring_alloc(100); msg_vstream_init(argv[0], VSTREAM_ERR); if (argc != 2) msg_fatal("usage: %s file-to-be-locked", argv[0]); mail_conf_read(); if (dot_lockfile(argv[1], why) < 0) msg_fatal("%s", vstring_str(why)); dot_unlockfile(argv[1]); vstring_free(why); return (0); }
int main(int argc, char **argv) { int rc; if (argc != 3) msg_fatal("usage: %s mydestination domain", argv[0]); mail_conf_read(); myfree(var_mydest); var_mydest = mystrdup(argv[1]); vstream_printf("mydestination=%s destination=%s %s\n", argv[1], argv[2], (rc = resolve_local(argv[2])) > 0 ? "YES" : rc == 0 ? "NO" : "ERROR"); vstream_fflush(VSTREAM_OUT); return (0); }
int main(int argc, char **argv) { VSTRING *reply; int ch; char *rule; char *addr; msg_vstream_init(argv[0], VSTREAM_ERR); mail_conf_read(); msg_info("using config files in %s", var_config_dir); if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); while ((ch = GETOPT(argc, argv, "v")) > 0) { switch (ch) { case 'v': msg_verbose++; break; default: usage(argv[0]); } } reply = vstring_alloc(1); if (argc > optind) { for (;;) { if ((rule = argv[optind++]) == 0) break; if ((addr = argv[optind++]) == 0) usage(argv[0]); rewrite(rule, addr, reply); } } else { VSTRING *buffer = vstring_alloc(1); while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { if ((addr = split_at(STR(buffer), ' ')) == 0 || *(rule = STR(buffer)) == 0) usage(argv[0]); rewrite(rule, addr, reply); } vstring_free(buffer); } vstring_free(reply); exit(0); }
void master_vars_init(void) { char *path; static CONFIG_INT_TABLE int_table[] = { VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0, 0, }; static CONFIG_TIME_TABLE time_table[] = { VAR_THROTTLE_TIME, DEF_THROTTLE_TIME, &var_throttle_time, 1, 0, 0, }; mail_conf_read(); get_mail_conf_int_table(int_table); get_mail_conf_time_table(time_table); path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0); fset_master_ent(path); myfree(path); }
int main(int argc, char **argv) { VSTRING *buffer = vstring_alloc(1); char *cp; int ch; char *command; signal(SIGPIPE, SIG_IGN); msg_vstream_init(argv[0], VSTREAM_ERR); mail_conf_read(); msg_info("using config files in %s", var_config_dir); if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); while ((ch = GETOPT(argc, argv, "v")) > 0) { switch (ch) { case 'v': msg_verbose++; break; default: usage(argv[0]); } } if (argc - optind > 1) usage(argv[0]); while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { cp = STR(buffer); if ((command = mystrtok(&cp, " \t\r\n")) == 0) continue; if (strcmp(command, "query") == 0) query(cp, buffer); else if (strcmp(command, "update") == 0) update(cp); else msg_warn("unrecognized command: %s", command); } vstring_free(buffer); return (0); }
int main(int argc, char **argv) { VSTRING *inbuf = vstring_alloc(100); VSTRING *result = vstring_alloc(100); char *bufp; char *cmd; char *target; char *junk; mail_conf_read(); while (vstring_get_nonl(inbuf, VSTREAM_IN) != VSTREAM_EOF) { bufp = STR(inbuf); if (!isatty(0)) { vstream_printf("> %s\n", bufp); vstream_fflush(VSTREAM_OUT); } if (*bufp == '#') continue; if ((cmd = mystrtok(&bufp, " \t")) == 0) { vstream_printf("usage: file path|map maptype:mapname\n"); vstream_fflush(VSTREAM_OUT); continue; } target = mystrtok(&bufp, " \t"); junk = mystrtok(&bufp, " \t"); if (strcmp(cmd, "file") == 0 && target && !junk) { data_redirect_file(result, target); vstream_printf("%s -> %s\n", target, STR(result)); } else if (strcmp(cmd, "map") == 0 && target && !junk) { data_redirect_map(result, target); vstream_printf("%s -> %s\n", target, STR(result)); } else { vstream_printf("usage: file path|map maptype:mapname\n"); } vstream_fflush(VSTREAM_OUT); } vstring_free(inbuf); return (0); }
int main(int argc, char **argv) { VSTRING *buffer = vstring_alloc(100); MAPS *path; ARGV *result; /* * Parse JCL. */ if (argc != 2) msg_fatal("usage: %s database", argv[0]); /* * Initialize. */ #define UPDATE(dst, src) { myfree(dst); dst = mystrdup(src); } mail_conf_read(); msg_verbose = 1; if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX); while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { msg_info("=== Address extension on, extension propagation on ==="); UPDATE(var_rcpt_delim, "+"); if ((result = mail_addr_map(path, STR(buffer), 1)) != 0) argv_free(result); msg_info("=== Address extension on, extension propagation off ==="); if ((result = mail_addr_map(path, STR(buffer), 0)) != 0) argv_free(result); msg_info("=== Address extension off ==="); UPDATE(var_rcpt_delim, ""); if ((result = mail_addr_map(path, STR(buffer), 1)) != 0) argv_free(result); } vstring_free(buffer); maps_free(path); return (0); }
int main(int unused_ac, char **av) { ACL_VSTRING *inbuf = acl_vstring_alloc(10); int status; ARGV *argv = 0; ACL_EVENT *eventp = acl_event_new_select(1, 0); acl_msg_verbose = 3; mail_conf_read(); acl_msg_info("using config files in %s", var_config_dir); if (chdir(var_queue_dir) < 0) acl_msg_fatal("chdir %s: %s", var_queue_dir, acl_last_serror()); tls_mgr_open(eventp); while (acl_vstring_fgets_nonl(inbuf, ACL_VSTREAM_IN)) { argv = argv_split(STR(inbuf), " \t\r\n"); if (argv->argc == 0) { argv_free(argv); continue; } #define COMMAND(argv, str, len) \ (strcasecmp(argv->argv[0], str) == 0 && argv->argc == len) if (COMMAND(argv, "policy", 2)) { int cachable; status = tls_mgr_policy(argv->argv[1], &cachable); acl_vstream_printf("status=%d cachable=%d\n", status, cachable); } else if (COMMAND(argv, "seed", 2)) { ACL_VSTRING *buf = acl_vstring_alloc(10); ACL_VSTRING *hex = acl_vstring_alloc(10); int len = atoi(argv->argv[1]); status = tls_mgr_seed(buf, len); hex_encode(hex, STR(buf), LEN(buf)); acl_vstream_printf("status=%d seed=%s\n", status, STR(hex)); acl_vstring_free(hex); acl_vstring_free(buf); } else if (COMMAND(argv, "lookup", 3)) { ACL_VSTRING *buf = acl_vstring_alloc(10); status = tls_mgr_lookup(argv->argv[1], argv->argv[2], buf); acl_vstream_printf("status=%d session=%.*s\n", status, LEN(buf), STR(buf)); acl_vstring_free(buf); } else if (COMMAND(argv, "update", 4)) { status = tls_mgr_update(argv->argv[1], argv->argv[2], argv->argv[3], strlen(argv->argv[3])); acl_vstream_printf("status=%d\n", status); } else if (COMMAND(argv, "delete", 3)) { status = tls_mgr_delete(argv->argv[1], argv->argv[2]); acl_vstream_printf("status=%d\n", status); } else { acl_vstream_printf("usage:\n" "seed byte_count\n" "policy smtpd|smtp|lmtp\n" "lookup smtpd|smtp|lmtp cache_id\n" "update smtpd|smtp|lmtp cache_id session\n" "delete smtpd|smtp|lmtp cache_id\n"); } acl_vstream_fflush(ACL_VSTREAM_OUT); argv_free(argv); } acl_vstring_free(inbuf); acl_event_free(eventp); return (0); }
int main(int argc, char **argv) { struct stat st; char *slash; int c; int fd; int mode = PQ_MODE_DEFAULT; char *site_to_flush = 0; char *id_to_flush = 0; ARGV *import_env; int bad_site; /* * 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_UNAVAILABLE, "open /dev/null: %m"); /* * 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(unavailable); msg_syslog_init(mail_task("postqueue"), 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; /* * Parse JCL. This program is set-gid and must sanitize all command-line * parameters. The configuration directory argument is validated by the * mail configuration read routine. Don't do complex things until we have * completed initializations. */ while ((c = GETOPT(argc, argv, "c:fi:ps:v")) > 0) { switch (c) { case 'c': /* non-default configuration */ if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal_status(EX_UNAVAILABLE, "out of memory"); break; case 'f': /* flush queue */ if (mode != PQ_MODE_DEFAULT) usage(); mode = PQ_MODE_FLUSH_QUEUE; break; case 'i': /* flush queue file */ if (mode != PQ_MODE_DEFAULT) usage(); mode = PQ_MODE_FLUSH_FILE; id_to_flush = optarg; break; case 'p': /* traditional mailq */ if (mode != PQ_MODE_DEFAULT) usage(); mode = PQ_MODE_MAILQ_LIST; break; case 's': /* flush site */ if (mode != PQ_MODE_DEFAULT) usage(); mode = PQ_MODE_FLUSH_SITE; site_to_flush = optarg; break; case 'v': if (geteuid() == 0) msg_verbose++; break; default: usage(); } } if (argc > optind) usage(); /* * Further initialization... */ mail_conf_read(); /* Re-evaluate mail_task() after reading main.cf. */ msg_syslog_init(mail_task("postqueue"), LOG_PID, LOG_FACILITY); mail_dict_init(); /* proxy, sql, ldap */ get_mail_conf_str_table(str_table); /* * This program is designed to be set-gid, which makes it a potential * target for attack. If not running as root, strip the environment so we * don't have to trust the C library. If running as root, don't strip the * environment so that showq can receive non-default configuration * directory info when the mail system is down. */ if (geteuid() != 0) { import_env = mail_parm_split(VAR_IMPORT_ENVIRON, var_import_environ); clean_env(import_env->argv); argv_free(import_env); } if (chdir(var_queue_dir)) msg_fatal_status(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir); signal(SIGPIPE, SIG_IGN); /* End of initializations. */ /* * Further input validation. */ if (site_to_flush != 0) { bad_site = 0; if (*site_to_flush == '[') { bad_site = !valid_mailhost_literal(site_to_flush, DONT_GRIPE); } else { bad_site = !valid_hostname(site_to_flush, DONT_GRIPE); } if (bad_site) msg_fatal_status(EX_USAGE, "Cannot flush mail queue - invalid destination: \"%.100s%s\"", site_to_flush, strlen(site_to_flush) > 100 ? "..." : ""); } if (id_to_flush != 0) { if (!mail_queue_id_ok(id_to_flush)) msg_fatal_status(EX_USAGE, "Cannot flush queue ID - invalid name: \"%.100s%s\"", id_to_flush, strlen(id_to_flush) > 100 ? "..." : ""); } /* * Start processing. */ switch (mode) { default: msg_panic("unknown operation mode: %d", mode); /* NOTREACHED */ case PQ_MODE_MAILQ_LIST: show_queue(); exit(0); break; case PQ_MODE_FLUSH_SITE: flush_site(site_to_flush); exit(0); break; case PQ_MODE_FLUSH_FILE: flush_file(id_to_flush); exit(0); break; case PQ_MODE_FLUSH_QUEUE: flush_queue(); exit(0); break; case PQ_MODE_DEFAULT: usage(); /* 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); }
int main(int unused_argc, char **argv) { VSTRING *inbuf = vstring_alloc(1); char *bufp; char *cmd; ssize_t cmd_len; char *service; char *addr; int count; int rate; int msgs; int rcpts; int newtls; int auths; ANVIL_CLNT *anvil; msg_vstream_init(argv[0], VSTREAM_ERR); mail_conf_read(); msg_info("using config files in %s", var_config_dir); if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); msg_verbose++; anvil = anvil_clnt_create(); while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) { bufp = vstring_str(inbuf); if ((cmd = mystrtok(&bufp, " ")) == 0 || *bufp == 0 || (service = mystrtok(&bufp, " ")) == 0 || *service == 0 || (addr = mystrtok(&bufp, " ")) == 0 || *addr == 0 || mystrtok(&bufp, " ") != 0) { vstream_printf("bad command syntax\n"); usage(); vstream_fflush(VSTREAM_OUT); continue; } cmd_len = strlen(cmd); if (strncmp(cmd, ANVIL_REQ_CONN, cmd_len) == 0) { if (anvil_clnt_connect(anvil, service, addr, &count, &rate) != ANVIL_STAT_OK) msg_warn("error!"); else vstream_printf("count=%d, rate=%d\n", count, rate); } else if (strncmp(cmd, ANVIL_REQ_MAIL, cmd_len) == 0) { if (anvil_clnt_mail(anvil, service, addr, &msgs) != ANVIL_STAT_OK) msg_warn("error!"); else vstream_printf("rate=%d\n", msgs); } else if (strncmp(cmd, ANVIL_REQ_RCPT, cmd_len) == 0) { if (anvil_clnt_rcpt(anvil, service, addr, &rcpts) != ANVIL_STAT_OK) msg_warn("error!"); else vstream_printf("rate=%d\n", rcpts); } else if (strncmp(cmd, ANVIL_REQ_NTLS, cmd_len) == 0) { if (anvil_clnt_newtls(anvil, service, addr, &newtls) != ANVIL_STAT_OK) msg_warn("error!"); else vstream_printf("rate=%d\n", newtls); } else if (strncmp(cmd, ANVIL_REQ_AUTH, cmd_len) == 0) { if (anvil_clnt_auth(anvil, service, addr, &auths) != ANVIL_STAT_OK) msg_warn("error!"); else vstream_printf("rate=%d\n", auths); } else if (strncmp(cmd, ANVIL_REQ_NTLS_STAT, cmd_len) == 0) { if (anvil_clnt_newtls_stat(anvil, service, addr, &newtls) != ANVIL_STAT_OK) msg_warn("error!"); else vstream_printf("rate=%d\n", newtls); } else if (strncmp(cmd, ANVIL_REQ_DISC, cmd_len) == 0) { if (anvil_clnt_disconnect(anvil, service, addr) != ANVIL_STAT_OK) msg_warn("error!"); else vstream_printf("OK\n"); } else if (strncmp(cmd, ANVIL_REQ_LOOKUP, cmd_len) == 0) { if (anvil_clnt_lookup(anvil, service, addr, &count, &rate, &msgs, &rcpts, &newtls, &auths) != ANVIL_STAT_OK) msg_warn("error!"); else vstream_printf("count=%d, rate=%d msgs=%d rcpts=%d newtls=%d " "auths=%d\n", count, rate, msgs, rcpts, newtls, auths); } else { vstream_printf("bad command: \"%s\"\n", cmd); usage(); } vstream_fflush(VSTREAM_OUT); } vstring_free(inbuf); anvil_clnt_free(anvil); return (0); }
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) { char *class; char *service; char *request; int fd; struct stat st; char *slash; int c; /* * Fingerprint executables and core dumps. */ MAIL_VERSION_STAMP_ALLOCATE; /* * 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"); /* * Process environment options as early as we can. */ if (safe_getenv(CONF_ENV_VERB)) msg_verbose = 1; /* * Initialize. Set up logging, read the global configuration file and * extract configuration information. */ if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) argv[0] = slash + 1; msg_vstream_init(argv[0], VSTREAM_ERR); set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); /* * Parse JCL. */ while ((c = GETOPT(argc, argv, "c:v")) > 0) { switch (c) { default: usage(argv[0]); case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'v': msg_verbose++; break; } } if (argc != optind + 3) usage(argv[0]); class = argv[optind]; service = argv[optind + 1]; request = argv[optind + 2]; /* * Finish initializations. */ mail_conf_read(); if (chdir(var_queue_dir)) msg_fatal("chdir %s: %m", var_queue_dir); /* * Kick the service. */ if (mail_trigger(class, service, request, strlen(request)) < 0) { msg_warn("Cannot contact class %s service %s - perhaps the mail system is down", class, service); exit(1); } /* * Problem: With triggers over full duplex (i.e. non-FIFO) channels, we * must avoid closing the channel before the server has received the * request. Otherwise some hostile kernel may throw away the request. * * Solution: The trigger routine registers a read event handler that runs * when the server closes the channel. The event_drain() routine waits * for the event handler to run, but gives up when it takes too long. */ else {
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) { struct stat st; char *slash; int fd; int ch; const char *tag; int log_flags = 0; int level = MSG_INFO; /* * 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 diagnostics. */ if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) tag = mail_task(slash + 1); else tag = mail_task(argv[0]); if (isatty(STDERR_FILENO)) msg_vstream_init(tag, VSTREAM_ERR); msg_syslog_init(tag, LOG_PID, LOG_FACILITY); /* * Check the Postfix library version as soon as we enable logging. */ MAIL_VERSION_CHECK; /* * Parse switches. */ while ((ch = GETOPT(argc, argv, "c:ip:t:v")) > 0) { switch (ch) { default: msg_fatal("usage: %s [-c config_dir] [-i] [-p priority] [-t tag] [-v] [text]", tag); break; case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'i': log_flags |= LOG_PID; break; case 'p': level = level_map(optarg); break; case 't': tag = optarg; break; case 'v': msg_verbose++; break; } } /* * Process the main.cf file. This overrides any logging facility that was * specified with msg_syslog_init(); */ mail_conf_read(); if (tag == 0 && strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0) { if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) tag = mail_task(slash + 1); else tag = mail_task(argv[0]); } /* * Re-initialize the logging, this time with the tag specified in main.cf * or on the command line. */ if (tag != 0) { if (isatty(STDERR_FILENO)) msg_vstream_init(tag, VSTREAM_ERR); msg_syslog_init(tag, LOG_PID, LOG_FACILITY); } /* * Log the command line or log lines from standard input. */ if (argc > optind) { log_argv(level, argv + optind); } else { log_stream(level, VSTREAM_IN); } exit(0); }
int main(int argc, char **argv) { char *script; struct stat st; char *slash; int fd; int ch; ARGV *import_env; static const CONFIG_STR_TABLE str_table[] = { VAR_SENDMAIL_PATH, DEF_SENDMAIL_PATH, &var_sendmail_path, 1, 0, VAR_MAILQ_PATH, DEF_MAILQ_PATH, &var_mailq_path, 1, 0, VAR_NEWALIAS_PATH, DEF_NEWALIAS_PATH, &var_newalias_path, 1, 0, VAR_MANPAGE_DIR, DEF_MANPAGE_DIR, &var_manpage_dir, 1, 0, VAR_SAMPLE_DIR, DEF_SAMPLE_DIR, &var_sample_dir, 1, 0, VAR_README_DIR, DEF_README_DIR, &var_readme_dir, 1, 0, VAR_HTML_DIR, DEF_HTML_DIR, &var_html_dir, 1, 0, 0, }; int force_single_instance; ARGV *my_argv; /* * 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 diagnostics. XXX What if stdin is the system console during * boot time? It seems a bad idea to log startup errors to the console. * This is UNIX, a system that can run without hand holding. */ if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) argv[0] = slash + 1; if (isatty(STDERR_FILENO)) msg_vstream_init(argv[0], VSTREAM_ERR); msg_syslog_init(argv[0], LOG_PID, LOG_FACILITY); /* * Check the Postfix library version as soon as we enable logging. */ MAIL_VERSION_CHECK; /* * The mail system must be run by the superuser so it can revoke * privileges for selected operations. That's right - it takes privileges * to toss privileges. */ if (getuid() != 0) { msg_error("to submit mail, use the Postfix sendmail command"); msg_fatal("the postfix command is reserved for the superuser"); } if (unsafe() != 0) msg_fatal("the postfix command must not run as a set-uid process"); /* * Parse switches. */ while ((ch = GETOPT(argc, argv, "c:Dv")) > 0) { switch (ch) { default: msg_fatal("usage: %s [-c config_dir] [-Dv] command", argv[0]); case 'c': if (*optarg != '/') msg_fatal("-c requires absolute pathname"); check_setenv(CONF_ENV_PATH, optarg); break; case 'D': check_setenv(CONF_ENV_DEBUG, ""); break; case 'v': msg_verbose++; check_setenv(CONF_ENV_VERB, ""); break; } } force_single_instance = (getenv(CONF_ENV_PATH) != 0); /* * Copy a bunch of configuration parameters into the environment for easy * access by the maintenance shell script. */ mail_conf_read(); get_mail_conf_str_table(str_table); /* * Environment import filter, to enforce consistent behavior whether this * command is started by hand, or at system boot time. This is necessary * because some shell scripts use environment settings to override * main.cf settings. */ import_env = argv_split(var_import_environ, ", \t\r\n"); clean_env(import_env->argv); argv_free(import_env); check_setenv("PATH", ROOT_PATH); /* sys_defs.h */ check_setenv(CONF_ENV_PATH, var_config_dir);/* mail_conf.h */ check_setenv(VAR_COMMAND_DIR, var_command_dir); /* main.cf */ check_setenv(VAR_DAEMON_DIR, var_daemon_dir); /* main.cf */ check_setenv(VAR_DATA_DIR, var_data_dir); /* main.cf */ check_setenv(VAR_QUEUE_DIR, var_queue_dir); /* main.cf */ check_setenv(VAR_CONFIG_DIR, var_config_dir); /* main.cf */ /* * Do we want to keep adding things here as shell scripts evolve? */ check_setenv(VAR_MAIL_OWNER, var_mail_owner); /* main.cf */ check_setenv(VAR_SGID_GROUP, var_sgid_group); /* main.cf */ check_setenv(VAR_SENDMAIL_PATH, var_sendmail_path); /* main.cf */ check_setenv(VAR_MAILQ_PATH, var_mailq_path); /* main.cf */ check_setenv(VAR_NEWALIAS_PATH, var_newalias_path); /* main.cf */ check_setenv(VAR_MANPAGE_DIR, var_manpage_dir); /* main.cf */ check_setenv(VAR_SAMPLE_DIR, var_sample_dir); /* main.cf */ check_setenv(VAR_README_DIR, var_readme_dir); /* main.cf */ check_setenv(VAR_HTML_DIR, var_html_dir); /* main.cf */ /* * Make sure these directories exist. Run the maintenance scripts with as * current directory the mail database. */ if (chdir(var_command_dir)) msg_fatal("chdir(%s): %m", var_command_dir); if (chdir(var_daemon_dir)) msg_fatal("chdir(%s): %m", var_daemon_dir); if (chdir(var_queue_dir)) msg_fatal("chdir(%s): %m", var_queue_dir); /* * Run the management script. */ if (force_single_instance || argv_split(var_multi_conf_dirs, "\t\r\n, ")->argc == 0) { script = concatenate(var_daemon_dir, "/postfix-script", (char *) 0); if (optind < 1) msg_panic("bad optind value"); argv[optind - 1] = script; execvp(script, argv + optind - 1); msg_fatal("%s: %m", script); } /* * Hand off control to a multi-instance manager. */ else { if (*var_multi_wrapper == 0) msg_fatal("multi-instance support is requested, but %s is empty", VAR_MULTI_WRAPPER); my_argv = argv_split(var_multi_wrapper, " \t\r\n"); do { argv_add(my_argv, argv[optind], (char *) 0); } while (argv[optind++] != 0); execvp(my_argv->argv[0], my_argv->argv); msg_fatal("%s: %m", my_argv->argv[0]); } }
int main(int argc, char **argv) { char *class; char *service; char *request; int fd; struct stat st; char *slash; int c; /* * 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"); /* * Process environment options as early as we can. */ if (safe_getenv(CONF_ENV_VERB)) msg_verbose = 1; /* * Initialize. Set up logging, read the global configuration file and * extract configuration information. */ if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) argv[0] = slash + 1; msg_vstream_init(argv[0], VSTREAM_ERR); set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); /* * Parse JCL. */ while ((c = GETOPT(argc, argv, "c:v")) > 0) { switch (c) { default: usage(argv[0]); case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'v': msg_verbose++; break; } } if (argc != optind + 3) usage(argv[0]); class = argv[optind]; service = argv[optind + 1]; request = argv[optind + 2]; /* * Finish initializations. */ mail_conf_read(); if (chdir(var_queue_dir)) msg_fatal("chdir %s: %m", var_queue_dir); /* * Kick the service. */ if (mail_trigger(class, service, request, strlen(request)) < 0) { msg_warn("Cannot contact class %s service %s - perhaps the mail system is down", class, service); exit(1); } else {
int main(int argc, char **argv) { const char *verify_sender; const char *valid_sender; msg_vstream_init(argv[0], VSTREAM_ERR); /* * Prepare to talk to the address rewriting service. */ mail_conf_read(); vstream_printf("using config files in %s\n", var_config_dir); if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); /* * Parse JCL. */ if (argc != 3) msg_fatal("usage: %s address_verify_sender address_verify_sender_ttl", argv[0]); var_verify_sender = argv[1]; if (conv_time(argv[2], &var_verify_sender_ttl, 's') == 0) msg_fatal("bad time value: %s", argv[2]); verify_time = time((time_t *) 0); /* * Compute the current probe sender address. */ verify_sender = make_verify_sender_addr(); /* * Check two past time slots. */ if (var_verify_sender_ttl > 0) { verify_time -= 2 * var_verify_sender_ttl; vstream_printf("\"%s\" matches prev2: \"%s\"\n", verify_sender, (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ? valid_sender : "nope"); verify_time += var_verify_sender_ttl; vstream_printf("\"%s\" matches prev1: \"%s\"\n", verify_sender, (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ? valid_sender : "nope"); verify_time += var_verify_sender_ttl; } /* * Check the current time slot. */ vstream_printf("\"%s\" matches self: \"%s\"\n", verify_sender, (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ? valid_sender : "nope"); /* * Check two future time slots. */ if (var_verify_sender_ttl > 0) { verify_time += var_verify_sender_ttl; vstream_printf("\"%s\" matches next1: \"%s\"\n", verify_sender, (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ? valid_sender : "nope"); verify_time += var_verify_sender_ttl; vstream_printf("\"%s\" matches next2: \"%s\"\n", verify_sender, (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ? valid_sender : "nope"); } vstream_fflush(VSTREAM_OUT); exit(0); }
int main(int argc, char **argv) { char *path_name; int ch; int fd; char *slash; struct stat st; int postmap_flags = POSTMAP_FLAG_AS_OWNER | POSTMAP_FLAG_SAVE_PERM; int open_flags = O_RDWR | O_CREAT | O_TRUNC; int dict_flags = (DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST); char *query = 0; char *delkey = 0; int sequence = 0; int found; int force_utf8 = 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"); /* * Process environment options as early as we can. We are not set-uid, * and we are supposed to be running in a controlled environment. */ if (getenv(CONF_ENV_VERB)) msg_verbose = 1; /* * Initialize. Set up logging, read the global configuration file and * extract configuration information. */ if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) argv[0] = slash + 1; msg_vstream_init(argv[0], VSTREAM_ERR); msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY); /* * Check the Postfix library version as soon as we enable logging. */ MAIL_VERSION_CHECK; /* * Parse JCL. */ while ((ch = GETOPT(argc, argv, "Nbc:d:fhimnopq:rsuUvw")) > 0) { switch (ch) { default: usage(argv[0]); break; case 'N': dict_flags |= DICT_FLAG_TRY1NULL; dict_flags &= ~DICT_FLAG_TRY0NULL; break; case 'b': postmap_flags |= POSTMAP_FLAG_BODY_KEY; break; case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'd': if (sequence || query || delkey) msg_fatal("specify only one of -s -q or -d"); delkey = optarg; break; case 'f': dict_flags &= ~DICT_FLAG_FOLD_FIX; break; case 'h': postmap_flags |= POSTMAP_FLAG_HEADER_KEY; break; case 'i': open_flags &= ~O_TRUNC; break; case 'm': postmap_flags |= POSTMAP_FLAG_MIME_KEY; break; case 'n': dict_flags |= DICT_FLAG_TRY0NULL; dict_flags &= ~DICT_FLAG_TRY1NULL; break; case 'o': postmap_flags &= ~POSTMAP_FLAG_AS_OWNER; break; case 'p': postmap_flags &= ~POSTMAP_FLAG_SAVE_PERM; break; case 'q': if (sequence || query || delkey) msg_fatal("specify only one of -s -q or -d"); query = optarg; break; case 'r': dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_IGNORE); dict_flags |= DICT_FLAG_DUP_REPLACE; break; case 's': if (query || delkey) msg_fatal("specify only one of -s or -q or -d"); sequence = 1; break; case 'u': dict_flags &= ~DICT_FLAG_UTF8_REQUEST; break; case 'U': force_utf8 = 1; break; case 'v': msg_verbose++; break; case 'w': dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_REPLACE); dict_flags |= DICT_FLAG_DUP_IGNORE; break; } } mail_conf_read(); if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0) msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY); mail_dict_init(); if ((query == 0 || strcmp(query, "-") != 0) && (postmap_flags & POSTMAP_FLAG_ANY_KEY)) msg_fatal("specify -b -h or -m only with \"-q -\""); if ((postmap_flags & POSTMAP_FLAG_ANY_KEY) != 0 && (postmap_flags & POSTMAP_FLAG_ANY_KEY) == (postmap_flags & POSTMAP_FLAG_MIME_KEY)) msg_warn("ignoring -m option without -b or -h"); if ((postmap_flags & (POSTMAP_FLAG_ANY_KEY & ~POSTMAP_FLAG_MIME_KEY)) && force_utf8 == 0) dict_flags &= ~DICT_FLAG_UTF8_MASK; /* * Use the map type specified by the user, or fall back to a default * database type. */ if (delkey) { /* remove entry */ if (optind + 1 > argc) usage(argv[0]); if (strcmp(delkey, "-") == 0) exit(postmap_deletes(VSTREAM_IN, argv + optind, argc - optind, dict_flags | DICT_FLAG_LOCK) == 0); found = 0; while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { found |= postmap_delete(argv[optind], path_name, delkey, dict_flags | DICT_FLAG_LOCK); } else { found |= postmap_delete(var_db_type, argv[optind], delkey, dict_flags | DICT_FLAG_LOCK); } optind++; } exit(found ? 0 : 1); } else if (query) { /* query map(s) */ if (optind + 1 > argc) usage(argv[0]); if (strcmp(query, "-") == 0) exit(postmap_queries(VSTREAM_IN, argv + optind, argc - optind, postmap_flags, dict_flags | DICT_FLAG_LOCK) == 0); while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { found = postmap_query(argv[optind], path_name, query, dict_flags | DICT_FLAG_LOCK); } else { found = postmap_query(var_db_type, argv[optind], query, dict_flags | DICT_FLAG_LOCK); } if (found) exit(0); optind++; } exit(1); } else if (sequence) { while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { postmap_seq(argv[optind], path_name, dict_flags | DICT_FLAG_LOCK); } else { postmap_seq(var_db_type, argv[optind], dict_flags | DICT_FLAG_LOCK); } exit(0); } exit(1); } else { /* create/update map(s) */ if (optind + 1 > argc) usage(argv[0]); while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { postmap(argv[optind], path_name, postmap_flags, open_flags, dict_flags); } else { postmap(var_db_type, argv[optind], postmap_flags, open_flags, dict_flags); } optind++; } 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) { struct stat st; int fd; int c; VSTRING *buf; int status; MAIL_STREAM *dst; int rec_type; static char *segment_info[] = { REC_TYPE_POST_ENVELOPE, REC_TYPE_POST_CONTENT, REC_TYPE_POST_EXTRACT, "" }; char **expected; uid_t uid = getuid(); ARGV *import_env; const char *error_text; char *attr_name; char *attr_value; const char *errstr; char *junk; struct timeval start; int saved_errno; int from_count = 0; int rcpt_count = 0; int validate_input = 1; /* * 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. Censor the process name: it is provided by the user. */ argv[0] = "postdrop"; msg_vstream_init(argv[0], VSTREAM_ERR); msg_syslog_init(mail_task("postdrop"), 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; /* * Parse JCL. This program is set-gid and must sanitize all command-line * arguments. The configuration directory argument is validated by the * mail configuration read routine. Don't do complex things until we have * completed initializations. */ while ((c = GETOPT(argc, argv, "c:rv")) > 0) { switch (c) { case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'r': /* forward compatibility */ break; case 'v': if (geteuid() == 0) msg_verbose++; break; default: msg_fatal("usage: %s [-c config_dir] [-v]", argv[0]); } } /* * Read the global configuration file and extract configuration * information. Some claim that the user should supply the working * directory instead. That might be OK, given that this command needs * write permission in a subdirectory called "maildrop". However we still * need to reliably detect incomplete input, and so we must perform * record-level I/O. With that, we should also take the opportunity to * perform some sanity checks on the input. */ mail_conf_read(); /* Re-evaluate mail_task() after reading main.cf. */ msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY); get_mail_conf_str_table(str_table); /* * Mail submission access control. Should this be in the user-land gate, * or in the daemon process? */ mail_dict_init(); if ((errstr = check_user_acl_byuid(VAR_SUBMIT_ACL, var_submit_acl, uid)) != 0) msg_fatal("User %s(%ld) is not allowed to submit mail", errstr, (long) uid); /* * Stop run-away process accidents by limiting the queue file size. This * is not a defense against DOS attack. */ if (var_message_limit > 0 && get_file_limit() > var_message_limit) set_file_limit((off_t) var_message_limit); /* * This program is installed with setgid privileges. Strip the process * environment so that we don't have to trust the C library. */ import_env = mail_parm_split(VAR_IMPORT_ENVIRON, var_import_environ); clean_env(import_env->argv); argv_free(import_env); if (chdir(var_queue_dir)) msg_fatal("chdir %s: %m", var_queue_dir); if (msg_verbose) msg_info("chdir %s", var_queue_dir); /* * Set up signal handlers and a runtime error handler so that we can * clean up incomplete output. * * postdrop_sig() uses the in-kernel SIGINT handler address as an atomic * variable to prevent nested postdrop_sig() calls. For this reason, the * SIGINT handler must be configured before other signal handlers are * allowed to invoke postdrop_sig(). */ signal(SIGPIPE, SIG_IGN); signal(SIGXFSZ, SIG_IGN); signal(SIGINT, postdrop_sig); signal(SIGQUIT, postdrop_sig); if (signal(SIGTERM, SIG_IGN) == SIG_DFL) signal(SIGTERM, postdrop_sig); if (signal(SIGHUP, SIG_IGN) == SIG_DFL) signal(SIGHUP, postdrop_sig); msg_cleanup(postdrop_cleanup); /* End of initializations. */ /* * Don't trust the caller's time information. */ GETTIMEOFDAY(&start); /* * Create queue file. mail_stream_file() never fails. Send the queue ID * to the caller. Stash away a copy of the queue file name so we can * clean up in case of a fatal error or an interrupt. */ dst = mail_stream_file(MAIL_QUEUE_MAILDROP, MAIL_CLASS_PUBLIC, var_pickup_service, 0444); attr_print(VSTREAM_OUT, ATTR_FLAG_NONE, SEND_ATTR_STR(MAIL_ATTR_QUEUEID, dst->id), ATTR_TYPE_END); vstream_fflush(VSTREAM_OUT); postdrop_path = mystrdup(VSTREAM_PATH(dst->stream)); /* * Copy stdin to file. The format is checked so that we can recognize * incomplete input and cancel the operation. With the sanity checks * applied here, the pickup daemon could skip format checks and pass a * file descriptor to the cleanup daemon. These are by no means all * sanity checks - the cleanup service and queue manager services will * reject messages that lack required information. * * If something goes wrong, slurp up the input before responding to the * client, otherwise the client will give up after detecting SIGPIPE. * * Allow attribute records if the attribute specifies the MIME body type * (sendmail -B). */ vstream_control(VSTREAM_IN, CA_VSTREAM_CTL_PATH("stdin"), CA_VSTREAM_CTL_END); buf = vstring_alloc(100); expected = segment_info; /* Override time information from the untrusted caller. */ rec_fprintf(dst->stream, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT, REC_TYPE_TIME_ARG(start)); for (;;) { /* Don't allow PTR records. */ rec_type = rec_get_raw(VSTREAM_IN, buf, var_line_limit, REC_FLAG_NONE); if (rec_type == REC_TYPE_EOF) { /* request cancelled */ mail_stream_cleanup(dst); if (remove(postdrop_path)) msg_warn("uid=%ld: remove %s: %m", (long) uid, postdrop_path); else if (msg_verbose) msg_info("remove %s", postdrop_path); myfree(postdrop_path); postdrop_path = 0; exit(0); } if (rec_type == REC_TYPE_ERROR) msg_fatal("uid=%ld: malformed input", (long) uid); if (strchr(*expected, rec_type) == 0) msg_fatal("uid=%ld: unexpected record type: %d", (long) uid, rec_type); if (rec_type == **expected) expected++; /* Override time information from the untrusted caller. */ if (rec_type == REC_TYPE_TIME) continue; /* Check these at submission time instead of pickup time. */ if (rec_type == REC_TYPE_FROM) from_count++; if (rec_type == REC_TYPE_RCPT) rcpt_count++; /* Limit the attribute types that users may specify. */ if (rec_type == REC_TYPE_ATTR) { if ((error_text = split_nameval(vstring_str(buf), &attr_name, &attr_value)) != 0) { msg_warn("uid=%ld: ignoring malformed record: %s: %.200s", (long) uid, error_text, vstring_str(buf)); continue; } #define STREQ(x,y) (strcmp(x,y) == 0) if ((STREQ(attr_name, MAIL_ATTR_ENCODING) && (STREQ(attr_value, MAIL_ATTR_ENC_7BIT) || STREQ(attr_value, MAIL_ATTR_ENC_8BIT) || STREQ(attr_value, MAIL_ATTR_ENC_NONE))) || STREQ(attr_name, MAIL_ATTR_DSN_ENVID) || STREQ(attr_name, MAIL_ATTR_DSN_NOTIFY) || rec_attr_map(attr_name) || (STREQ(attr_name, MAIL_ATTR_RWR_CONTEXT) && (STREQ(attr_value, MAIL_ATTR_RWR_LOCAL) || STREQ(attr_value, MAIL_ATTR_RWR_REMOTE))) || STREQ(attr_name, MAIL_ATTR_TRACE_FLAGS)) { /* XXX */ rec_fprintf(dst->stream, REC_TYPE_ATTR, "%s=%s", attr_name, attr_value); } else { msg_warn("uid=%ld: ignoring attribute record: %.200s=%.200s", (long) uid, attr_name, attr_value); } continue; } if (REC_PUT_BUF(dst->stream, rec_type, buf) < 0) { /* rec_get() errors must not clobber errno. */ saved_errno = errno; while ((rec_type = rec_get_raw(VSTREAM_IN, buf, var_line_limit, REC_FLAG_NONE)) != REC_TYPE_END && rec_type != REC_TYPE_EOF) if (rec_type == REC_TYPE_ERROR) msg_fatal("uid=%ld: malformed input", (long) uid); validate_input = 0; errno = saved_errno; break; } if (rec_type == REC_TYPE_END) break; } vstring_free(buf); /* * As of Postfix 2.7 the pickup daemon discards mail without recipients. * Such mail may enter the maildrop queue when "postsuper -r" is invoked * before the queue manager deletes an already delivered message. Looking * at file ownership is not a good way to make decisions on what mail to * discard. Instead, the pickup server now requires that new submissions * always have at least one recipient record. * * The Postfix sendmail command already rejects mail without recipients. * However, in the future postdrop may receive mail via other programs, * so we add a redundant recipient check here for future proofing. * * The test for the sender address is just for consistency of error * reporting (report at submission time instead of pickup time). Besides * the segment terminator records, there aren't any other mandatory * records in a Postfix submission queue file. */ if (validate_input && (from_count == 0 || rcpt_count == 0)) { status = CLEANUP_STAT_BAD; mail_stream_cleanup(dst); } /* * Finish the file. */ else if ((status = mail_stream_finish(dst, (VSTRING *) 0)) != 0) { msg_warn("uid=%ld: %m", (long) uid); postdrop_cleanup(); } /* * Disable deletion on fatal error before reporting success, so the file * will not be deleted after we have taken responsibility for delivery. */ if (postdrop_path) { junk = postdrop_path; postdrop_path = 0; myfree(junk); } /* * Send the completion status to the caller and terminate. */ attr_print(VSTREAM_OUT, ATTR_FLAG_NONE, SEND_ATTR_INT(MAIL_ATTR_STATUS, status), SEND_ATTR_STR(MAIL_ATTR_WHY, ""), ATTR_TYPE_END); vstream_fflush(VSTREAM_OUT); exit(status); }
int main(int unused_ac, char **av) { VSTRING *inbuf = vstring_alloc(10); int status; ARGV *argv = 0; msg_vstream_init(av[0], VSTREAM_ERR); msg_verbose = 3; mail_conf_read(); msg_info("using config files in %s", var_config_dir); if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) { argv = argv_split(STR(inbuf), " \t\r\n"); if (argv->argc == 0) { argv_free(argv); continue; } #define COMMAND(argv, str, len) \ (strcasecmp(argv->argv[0], str) == 0 && argv->argc == len) if (COMMAND(argv, "policy", 2)) { int cachable; int timeout; status = tls_mgr_policy(argv->argv[1], &cachable, &timeout); vstream_printf("status=%d cachable=%d timeout=%d\n", status, cachable, timeout); } else if (COMMAND(argv, "seed", 2)) { VSTRING *buf = vstring_alloc(10); VSTRING *hex = vstring_alloc(10); int len = atoi(argv->argv[1]); status = tls_mgr_seed(buf, len); hex_encode(hex, STR(buf), LEN(buf)); vstream_printf("status=%d seed=%s\n", status, STR(hex)); vstring_free(hex); vstring_free(buf); } else if (COMMAND(argv, "lookup", 3)) { VSTRING *buf = vstring_alloc(10); status = tls_mgr_lookup(argv->argv[1], argv->argv[2], buf); vstream_printf("status=%d session=%.*s\n", status, LEN(buf), STR(buf)); vstring_free(buf); } else if (COMMAND(argv, "update", 4)) { status = tls_mgr_update(argv->argv[1], argv->argv[2], argv->argv[3], strlen(argv->argv[3])); vstream_printf("status=%d\n", status); } else if (COMMAND(argv, "delete", 3)) { status = tls_mgr_delete(argv->argv[1], argv->argv[2]); vstream_printf("status=%d\n", status); } else { vstream_printf("usage:\n" "seed byte_count\n" "policy smtpd|smtp|lmtp\n" "lookup smtpd|smtp|lmtp cache_id\n" "update smtpd|smtp|lmtp cache_id session\n" "delete smtpd|smtp|lmtp cache_id\n"); } vstream_fflush(VSTREAM_OUT); argv_free(argv); } vstring_free(inbuf); return (0); }
int main(int argc, char **argv) { VSTRING *buffer; VSTREAM *fp; int ch; int fd; struct stat st; int flags = 0; static char *queue_names[] = { MAIL_QUEUE_MAILDROP, MAIL_QUEUE_INCOMING, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_DEFERRED, MAIL_QUEUE_HOLD, MAIL_QUEUE_SAVED, 0, }; char **cpp; int tries; /* * Fingerprint executables and core dumps. */ MAIL_VERSION_STAMP_ALLOCATE; /* * 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, "bc:dehoqv")) > 0) { switch (ch) { case 'b': flags |= PC_FLAG_PRINT_BODY; break; case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) msg_fatal("out of memory"); break; case 'd': flags |= PC_FLAG_PRINT_RTYPE_DEC; break; case 'e': flags |= PC_FLAG_PRINT_ENV; break; case 'h': flags |= PC_FLAG_PRINT_HEADER; break; case 'o': flags |= PC_FLAG_PRINT_OFFSET; break; case 'q': flags |= PC_FLAG_SEARCH_QUEUE; break; case 'v': msg_verbose++; break; default: usage(argv[0]); } } if ((flags & PC_MASK_PRINT_ALL) == 0) flags |= PC_MASK_PRINT_ALL; /* * Further initialization... */ mail_conf_read(); /* * Initialize. */ buffer = vstring_alloc(10); /* * If no file names are given, copy stdin. */ if (argc == optind) { vstream_control(VSTREAM_IN, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END); postcat(VSTREAM_IN, buffer, flags); } /* * Copy the named queue files in the specified order. */ else if (flags & PC_FLAG_SEARCH_QUEUE) { if (chdir(var_queue_dir)) msg_fatal("chdir %s: %m", var_queue_dir); while (optind < argc) { if (!mail_queue_id_ok(argv[optind])) msg_fatal("bad mail queue ID: %s", argv[optind]); for (fp = 0, tries = 0; fp == 0 && tries < 2; tries++) for (cpp = queue_names; fp == 0 && *cpp != 0; cpp++) fp = mail_queue_open(*cpp, argv[optind], O_RDONLY, 0); if (fp == 0) msg_fatal("open queue file %s: %m", argv[optind]); postcat(fp, buffer, flags); if (vstream_fclose(fp)) msg_warn("close %s: %m", argv[optind]); optind++; } } /* * Copy the named files in the specified order. */ else { while (optind < argc) { if ((fp = vstream_fopen(argv[optind], O_RDONLY, 0)) == 0) msg_fatal("open %s: %m", argv[optind]); postcat(fp, buffer, flags); if (vstream_fclose(fp)) msg_warn("close %s: %m", argv[optind]); optind++; } } /* * Clean up. */ vstring_free(buffer); exit(0); }