diff options
| author | itojun <itojun@NetBSD.org> | 2001-03-13 17:45:02 +0000 |
|---|---|---|
| committer | itojun <itojun@NetBSD.org> | 2001-03-13 17:45:02 +0000 |
| commit | 173b2f6655e38657f15bb57fe26dc23e8d054d4e (patch) | |
| tree | 04af30df8438e7c54ceb4e5f4bf0dff83788ce54 /gnu/dist/postfix/src/spawn | |
| parent | c7871f80bf97592f2ca4dd16d6d7708bec2c33a2 (diff) | |
postfix release-20010228
Diffstat (limited to 'gnu/dist/postfix/src/spawn')
| -rw-r--r-- | gnu/dist/postfix/src/spawn/.printfck | 25 | ||||
| -rw-r--r-- | gnu/dist/postfix/src/spawn/Makefile.in | 70 | ||||
| -rw-r--r-- | gnu/dist/postfix/src/spawn/spawn.c | 311 |
3 files changed, 406 insertions, 0 deletions
diff --git a/gnu/dist/postfix/src/spawn/.printfck b/gnu/dist/postfix/src/spawn/.printfck new file mode 100644 index 00000000000..66016ed453c --- /dev/null +++ b/gnu/dist/postfix/src/spawn/.printfck @@ -0,0 +1,25 @@ +been_here_xt 2 0 +bounce_append 5 0 +cleanup_out_format 1 0 +defer_append 5 0 +mail_command 1 0 +mail_print 1 0 +msg_error 0 0 +msg_fatal 0 0 +msg_info 0 0 +msg_panic 0 0 +msg_warn 0 0 +opened 4 0 +post_mail_fprintf 1 0 +qmgr_message_bounce 2 0 +rec_fprintf 2 0 +sent 4 0 +smtp_cmd 1 0 +smtp_mesg_fail 2 0 +smtp_printf 1 0 +smtp_rcpt_fail 3 0 +smtp_site_fail 2 0 +udp_syslog 1 0 +vstream_fprintf 1 0 +vstream_printf 0 0 +vstring_sprintf 1 0 diff --git a/gnu/dist/postfix/src/spawn/Makefile.in b/gnu/dist/postfix/src/spawn/Makefile.in new file mode 100644 index 00000000000..1269837e172 --- /dev/null +++ b/gnu/dist/postfix/src/spawn/Makefile.in @@ -0,0 +1,70 @@ +SHELL = /bin/sh +SRCS = spawn.c +OBJS = spawn.o +HDRS = +TESTSRC = +WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ + -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ + -Wunused +DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) +CFLAGS = $(DEBUG) $(OPT) $(DEFS) +TESTPROG= +PROG = spawn +INC_DIR = ../../include +LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a + +.c.o:; $(CC) $(CFLAGS) -c $*.c + +$(PROG): $(OBJS) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS) + +Makefile: Makefile.in + (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@ + +test: $(TESTPROG) + +update: ../../libexec/$(PROG) + +../../libexec/$(PROG): $(PROG) + cp $(PROG) ../../libexec + +printfck: $(OBJS) $(PROG) + rm -rf printfck + mkdir printfck + sed '1,/^# do not edit/!d' Makefile >printfck/Makefile + set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done + cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o` + +lint: + lint $(DEFS) $(SRCS) $(LINTFIX) + +clean: + rm -f *.o *core $(PROG) $(TESTPROG) junk + rm -rf printfck + +tidy: clean + +depend: $(MAKES) + (sed '1,/^# do not edit/!d' Makefile.in; \ + set -e; for i in [a-z][a-z0-9]*.c; do \ + $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \ + -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \ + done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in + @$(EXPORT) make -f Makefile.in Makefile 1>&2 + +# do not edit below this line - it is generated by 'make depend' +spawn.o: spawn.c +spawn.o: ../../include/sys_defs.h +spawn.o: ../../include/msg.h +spawn.o: ../../include/argv.h +spawn.o: ../../include/dict.h +spawn.o: ../../include/vstream.h +spawn.o: ../../include/vbuf.h +spawn.o: ../../include/mymalloc.h +spawn.o: ../../include/spawn_command.h +spawn.o: ../../include/split_at.h +spawn.o: ../../include/timed_wait.h +spawn.o: ../../include/set_eugid.h +spawn.o: ../../include/mail_params.h +spawn.o: ../../include/mail_server.h +spawn.o: ../../include/mail_conf.h diff --git a/gnu/dist/postfix/src/spawn/spawn.c b/gnu/dist/postfix/src/spawn/spawn.c new file mode 100644 index 00000000000..b63a63b7837 --- /dev/null +++ b/gnu/dist/postfix/src/spawn/spawn.c @@ -0,0 +1,311 @@ +/*++ +/* NAME +/* spawn 8 +/* SUMMARY +/* Postfix external command spawner +/* SYNOPSIS +/* \fBspawn\fR [generic Postfix daemon options] command_attributes... +/* DESCRIPTION +/* The \fBspawn\fR daemon provides the Postfix equivalent of \fBinetd\fR. +/* It listens on a port as specified in the Postfix \fBmaster.cf\fR file +/* and spawns an external command whenever a connection is established. +/* The connection can be made over local IPC (such as UNIX-domain +/* sockets) or over non-local IPC (such as TCP sockets). +/* The command\'s standard input, output and error streams are connected +/* directly to the communication endpoint. +/* +/* This daemon expects to be run from the \fBmaster\fR(8) process +/* manager. +/* COMMAND ATTRIBUTE SYNTAX +/* .ad +/* .fi +/* The external command attributes are given in the \fBmaster.cf\fR +/* file at the end of a service definition. The syntax is as follows: +/* .IP "\fBuser\fR=\fIusername\fR (required)" +/* .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR" +/* The external command is executed with the rights of the +/* specified \fIusername\fR. The software refuses to execute +/* commands with root privileges, or with the privileges of the +/* mail system owner. If \fIgroupname\fR is specified, the +/* corresponding group ID is used instead of the group ID of +/* of \fIusername\fR. +/* .IP "\fBargv\fR=\fIcommand\fR... (required)" +/* The command to be executed. This must be specified as the +/* last command attribute. +/* The command is executed directly, i.e. without interpretation of +/* shell meta characters by a shell command interpreter. +/* BUGS +/* In order to enforce standard Postfix process resource controls, +/* the \fBspawn\fR daemon runs only one external command at a time. +/* As such, it presents a noticeable overhead by wasting precious +/* process resources. The \fBspawn\fR daemon is expected to be +/* replaced by a more structural solution. +/* DIAGNOSTICS +/* The \fBspawn\fR daemon reports abnormal child exits. +/* Problems are logged to \fBsyslogd\fR(8). +/* SECURITY +/* .fi +/* .ad +/* This program needs root privilege in order to execute external +/* commands as the specified user. It is therefore security sensitive. +/* However the \fBspawn\fR daemon does not talk to the external command +/* and thus is not vulnerable to data-driven attacks. +/* CONFIGURATION PARAMETERS +/* .ad +/* .fi +/* The following \fBmain.cf\fR parameters are especially relevant to +/* this program. See the Postfix \fBmain.cf\fR file for syntax details +/* and for default values. Use the \fBpostfix reload\fR command after +/* a configuration change. +/* .SH Miscellaneous +/* .ad +/* .fi +/* .IP \fBexport_environment\fR +/* List of names of environment parameters that can be exported +/* to non-Postfix processes. +/* .IP \fBmail_owner\fR +/* The process privileges used while not running an external command. +/* .SH Resource control +/* .ad +/* .fi +/* .IP \fIservice\fB_command_time_limit\fR +/* The amount of time the command is allowed to run before it is +/* killed with force. The \fIservice\fR name is the name of the entry +/* in the \fBmaster.cf\fR file. The default time limit is given by the +/* global \fBcommand_time_limit\fR configuration parameter. +/* SEE ALSO +/* master(8) process manager +/* syslogd(8) system logging +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <sys/wait.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <pwd.h> +#include <grp.h> +#include <fcntl.h> +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif + +/* Utility library. */ + +#include <msg.h> +#include <argv.h> +#include <dict.h> +#include <mymalloc.h> +#include <spawn_command.h> +#include <split_at.h> +#include <timed_wait.h> +#include <set_eugid.h> + +/* Single server skeleton. */ + +#include <mail_params.h> +#include <mail_server.h> +#include <mail_conf.h> + +/* Application-specific. */ + + /* + * Tunable parameters. Values are taken from the config file, after + * prepending the service name to _name, and so on. + */ +int var_command_maxtime; /* system-wide */ + + /* + * For convenience. Instead of passing around lists of parameters, bundle + * them up in convenient structures. + */ +typedef struct { + char **argv; /* argument vector */ + uid_t uid; /* command privileges */ + gid_t gid; /* command privileges */ + int time_limit; /* per-service time limit */ +} SPAWN_ATTR; + +/* get_service_attr - get service attributes */ + +static void get_service_attr(SPAWN_ATTR *attr, char *service, char **argv) +{ + char *myname = "get_service_attr"; + struct passwd *pwd; + struct group *grp; + char *user; /* user name */ + char *group; /* group name */ + + /* + * Initialize. + */ + user = 0; + group = 0; + attr->argv = 0; + + /* + * Figure out the command time limit for this transport. + */ + attr->time_limit = + get_mail_conf_int2(service, "_time_limit", var_command_maxtime, 1, 0); + + /* + * Iterate over the command-line attribute list. + */ + for ( /* void */ ; *argv != 0; argv++) { + + /* + * user=username[:groupname] + */ + if (strncasecmp("user=", *argv, sizeof("user=") - 1) == 0) { + user = *argv + sizeof("user=") - 1; + if ((group = split_at(user, ':')) != 0) /* XXX clobbers argv */ + if (*group == 0) + group = 0; + if ((pwd = getpwnam(user)) == 0) + msg_fatal("%s: unknown username: %s", myname, user); + attr->uid = pwd->pw_uid; + if (group != 0) { + if ((grp = getgrnam(group)) == 0) + msg_fatal("%s: unknown group: %s", myname, group); + attr->gid = grp->gr_gid; + } else { + attr->gid = pwd->pw_gid; + } + } + + /* + * argv=command... + */ + else if (strncasecmp("argv=", *argv, sizeof("argv=") - 1) == 0) { + *argv += sizeof("argv=") - 1; /* XXX clobbers argv */ + attr->argv = argv; + break; + } + + /* + * Bad. + */ + else + msg_fatal("unknown attribute name: %s", *argv); + } + + /* + * Sanity checks. Verify that every member has an acceptable value. + */ + if (user == 0) + msg_fatal("missing user= attribute"); + if (attr->argv == 0) + msg_fatal("missing argv= attribute"); + if (attr->uid == 0) + msg_fatal("request to deliver as root"); + if (attr->uid == var_owner_uid) + msg_fatal("request to deliver as mail system owner"); + if (attr->gid == 0) + msg_fatal("request to use privileged group id %ld", (long) attr->gid); + if (attr->gid == var_owner_gid) + msg_fatal("request to use mail system owner group id %ld", (long) attr->gid); + + /* + * Give the poor tester a clue of what is going on. + */ + if (msg_verbose) + msg_info("%s: uid %ld, gid %ld; time %d", + myname, (long) attr->uid, (long) attr->gid, attr->time_limit); +} + +/* spawn_service - perform service for client */ + +static void spawn_service(VSTREAM *client_stream, char *service, char **argv) +{ + char *myname = "spawn_service"; + static SPAWN_ATTR attr; + WAIT_STATUS_T status; + ARGV *export_env; + + /* + * This routine runs whenever a client connects to the UNIX-domain socket + * dedicated to running an external command. + */ + if (msg_verbose) + msg_info("%s: service=%s, command=%s...", myname, service, argv[0]); + + /* + * Look up service attributes and config information only once. This is + * safe since the information comes from a trusted source. + */ + if (attr.argv == 0) { + get_service_attr(&attr, service, argv); + } + + /* + * Execute the command. + */ + export_env = argv_split(var_export_environ, ", \t\r\n"); + status = spawn_command(SPAWN_CMD_STDIN, vstream_fileno(client_stream), + SPAWN_CMD_STDOUT, vstream_fileno(client_stream), + SPAWN_CMD_STDERR, vstream_fileno(client_stream), + SPAWN_CMD_UID, attr.uid, + SPAWN_CMD_GID, attr.gid, + SPAWN_CMD_ARGV, attr.argv, + SPAWN_CMD_TIME_LIMIT, attr.time_limit, + SPAWN_CMD_EXPORT, export_env->argv, + SPAWN_CMD_END); + argv_free(export_env); + + /* + * Warn about unsuccessful completion. + */ + if (!NORMAL_EXIT_STATUS(status)) { + if (WIFEXITED(status)) + msg_warn("command %s exit status %d", + attr.argv[0], WEXITSTATUS(status)); + if (WIFSIGNALED(status)) + msg_warn("command %s killed by signal %d", + attr.argv[0], WTERMSIG(status)); + } +} + +/* pre_accept - see if tables have changed */ + +static void pre_accept(char *unused_name, char **unused_argv) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } +} + +/* drop_privileges - drop privileges most of the time */ + +static void drop_privileges(char *unused_name, char **unused_argv) +{ + set_eugid(var_owner_uid, var_owner_gid); +} + +/* main - pass control to the single-threaded skeleton */ + +int main(int argc, char **argv) +{ + static CONFIG_TIME_TABLE time_table[] = { + VAR_COMMAND_MAXTIME, DEF_COMMAND_MAXTIME, &var_command_maxtime, 1, 0, + 0, + }; + + single_server_main(argc, argv, spawn_service, + MAIL_SERVER_TIME_TABLE, time_table, + MAIL_SERVER_POST_INIT, drop_privileges, + MAIL_SERVER_PRE_ACCEPT, pre_accept, + 0); +} |
