1/*	$NetBSD: postkick.c,v 1.4 2022/10/08 16:12:47 christos Exp $	*/
2
3/*++
4/* NAME
5/*	postkick 1
6/* SUMMARY
7/*	kick a Postfix service
8/* SYNOPSIS
9/* .fi
10/*	\fBpostkick\fR [\fB-c \fIconfig_dir\fR] [\fB-v\fR]
11/*	\fIclass service request\fR
12/* DESCRIPTION
13/*	The \fBpostkick\fR(1) command sends \fIrequest\fR to the
14/*	specified \fIservice\fR over a local transport channel.
15/*	This command makes Postfix private IPC accessible
16/*	for use in, for example, shell scripts.
17/*
18/*	Options:
19/* .IP "\fB-c\fR \fIconfig_dir\fR"
20/*	Read the \fBmain.cf\fR configuration file in the named directory
21/*	instead of the default configuration directory.
22/* .IP \fB-v\fR
23/*	Enable verbose logging for debugging purposes. Multiple \fB-v\fR
24/*	options make the software increasingly verbose.
25/* .PP
26/*	Arguments:
27/* .IP \fIclass\fR
28/*	Name of a class of local transport channel endpoints,
29/*	either \fBpublic\fR (accessible by any local user) or
30/*	\fBprivate\fR (administrative access only).
31/* .IP \fIservice\fR
32/*	The name of a local transport endpoint within the named class.
33/* .IP \fIrequest\fR
34/*	A string. The list of valid requests is service-specific.
35/* DIAGNOSTICS
36/*	Problems and transactions are logged to the standard error
37/*	stream.
38/* ENVIRONMENT
39/* .ad
40/* .fi
41/* .IP \fBMAIL_CONFIG\fR
42/*	Directory with Postfix configuration files.
43/* .IP \fBMAIL_VERBOSE\fR
44/*	Enable verbose logging for debugging purposes.
45/* CONFIGURATION PARAMETERS
46/* .ad
47/* .fi
48/*	The following \fBmain.cf\fR parameters are especially relevant to
49/*	this program.
50/*	The text below provides only a parameter summary. See
51/*	\fBpostconf\fR(5) for more details including examples.
52/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
53/*	The default location of the Postfix main.cf and master.cf
54/*	configuration files.
55/* .IP "\fBapplication_event_drain_time (100s)\fR"
56/*	How long the \fBpostkick\fR(1) command waits for a request to enter the
57/*	Postfix daemon process input buffer before giving up.
58/* .IP "\fBimport_environment (see 'postconf -d' output)\fR"
59/*	The list of environment parameters that a privileged Postfix
60/*	process will import from a non-Postfix parent process, or name=value
61/*	environment overrides.
62/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
63/*	The location of the Postfix top-level queue directory.
64/* FILES
65/*	/var/spool/postfix/private, private class endpoints
66/*	/var/spool/postfix/public, public class endpoints
67/* SEE ALSO
68/*	qmgr(8), queue manager trigger protocol
69/*	pickup(8), local pickup daemon
70/*	postconf(5), configuration parameters
71/* LICENSE
72/* .ad
73/* .fi
74/*	The Secure Mailer license must be distributed with this software.
75/* AUTHOR(S)
76/*	Wietse Venema
77/*	IBM T.J. Watson Research
78/*	P.O. Box 704
79/*	Yorktown Heights, NY 10598, USA
80/*
81/*	Wietse Venema
82/*	Google, Inc.
83/*	111 8th Avenue
84/*	New York, NY 10011, USA
85/*--*/
86
87/* System library. */
88
89#include <sys_defs.h>
90#include <sys/stat.h>
91#include <fcntl.h>
92#include <unistd.h>
93#include <string.h>
94#include <stdlib.h>
95
96/* Utility library. */
97
98#include <msg.h>
99#include <mymalloc.h>
100#include <vstream.h>
101#include <msg_vstream.h>
102#include <safe.h>
103#include <events.h>
104#include <warn_stat.h>
105#include <clean_env.h>
106
107/* Global library. */
108
109#include <mail_proto.h>
110#include <mail_params.h>
111#include <mail_version.h>
112#include <mail_conf.h>
113#include <mail_parm_split.h>
114
115static NORETURN usage(char *myname)
116{
117    msg_fatal("usage: %s [-c config_dir] [-v] class service request", myname);
118}
119
120MAIL_VERSION_STAMP_DECLARE;
121
122int     main(int argc, char **argv)
123{
124    char   *class;
125    char   *service;
126    char   *request;
127    int     fd;
128    struct stat st;
129    char   *slash;
130    int     c;
131    ARGV   *import_env;
132
133    /*
134     * Fingerprint executables and core dumps.
135     */
136    MAIL_VERSION_STAMP_ALLOCATE;
137
138    /*
139     * To minimize confusion, make sure that the standard file descriptors
140     * are open before opening anything else. XXX Work around for 44BSD where
141     * fstat can return EBADF on an open file descriptor.
142     */
143    for (fd = 0; fd < 3; fd++)
144	if (fstat(fd, &st) == -1
145	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
146	    msg_fatal("open /dev/null: %m");
147
148    /*
149     * Process environment options as early as we can.
150     */
151    if (safe_getenv(CONF_ENV_VERB))
152	msg_verbose = 1;
153
154    /*
155     * Initialize. Set up logging. Read the global configuration file after
156     * parsing command-line arguments.
157     */
158    if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
159	argv[0] = slash + 1;
160    msg_vstream_init(argv[0], VSTREAM_ERR);
161    set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
162
163    /*
164     * Check the Postfix library version as soon as we enable logging.
165     */
166    MAIL_VERSION_CHECK;
167
168    /*
169     * Parse JCL.
170     */
171    while ((c = GETOPT(argc, argv, "c:v")) > 0) {
172	switch (c) {
173	default:
174	    usage(argv[0]);
175	case 'c':
176	    if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
177		msg_fatal("out of memory");
178	    break;
179	case 'v':
180	    msg_verbose++;
181	    break;
182	}
183    }
184    if (argc != optind + 3)
185	usage(argv[0]);
186    class = argv[optind];
187    service = argv[optind + 1];
188    request = argv[optind + 2];
189
190    /*
191     * Finish initializations.
192     */
193    mail_conf_read();
194    /* Enforce consistent operation of different Postfix parts. */
195    import_env = mail_parm_split(VAR_IMPORT_ENVIRON, var_import_environ);
196    update_env(import_env->argv);
197    argv_free(import_env);
198    if (chdir(var_queue_dir))
199	msg_fatal("chdir %s: %m", var_queue_dir);
200
201    /*
202     * Kick the service.
203     */
204    if (mail_trigger(class, service, request, strlen(request)) < 0) {
205	msg_warn("Cannot contact class %s service %s - perhaps the mail system is down",
206		 class, service);
207	exit(1);
208    }
209
210    /*
211     * Problem: With triggers over full duplex (i.e. non-FIFO) channels, we
212     * must avoid closing the channel before the server has received the
213     * request. Otherwise some hostile kernel may throw away the request.
214     *
215     * Solution: The trigger routine registers a read event handler that runs
216     * when the server closes the channel. The event_drain() routine waits
217     * for the event handler to run, but gives up when it takes too long.
218     */
219    else {
220	event_drain(var_event_drain);
221	exit(0);
222    }
223}
224