xref: /netbsd-src/external/ibm-public/postfix/dist/src/postlogd/postlogd.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: postlogd.c,v 1.3 2022/10/08 16:12:47 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	postlogd 8
6 /* SUMMARY
7 /*	Postfix internal log server
8 /* SYNOPSIS
9 /*	\fBpostlogd\fR [generic Postfix daemon options]
10 /* DESCRIPTION
11 /*	This program logs events on behalf of Postfix programs
12 /*	when the maillog configuration parameter specifies a non-empty
13 /*	value.
14 /* BUGS
15 /*	Non-daemon Postfix programs don't know that they should log
16 /*	to the internal logging service before they have processed
17 /*	command-line options and main.cf parameters. These programs
18 /*	still log earlier events to the syslog service.
19 /*
20 /*	If Postfix is down, the non-daemon programs \fBpostfix\fR(1),
21 /*	\fBpostsuper\fR(1), \fBpostmulti\fR(1), and \fBpostlog\fR(1),
22 /*	will log directly to \fB$maillog_file\fR. These programs
23 /*	expect to run with root privileges, for example during
24 /*	Postfix start-up, reload, or shutdown.
25 /*
26 /*	Other non-daemon Postfix programs will never write directly to
27 /*	\fB$maillog_file\fR (also, logging to stdout would interfere
28 /*	with the operation of some of these programs). These programs
29 /*	can log to \fBpostlogd\fR(8) if they are run by the super-user,
30 /*	or if their executable file has set-gid permission. Do not
31 /*	set this permission on programs other than \fBpostdrop\fR(1),
32 /*	\fBpostqueue\fR(1) and (Postfix >= 3.7) \fBpostlog\fR(1).
33 /* CONFIGURATION PARAMETERS
34 /* .ad
35 /* .fi
36 /*	Changes to \fBmain.cf\fR are picked up automatically, as
37 /*	\fBpostlogd\fR(8) processes run for only a limited amount
38 /*	of time. Use the command "\fBpostfix reload\fR" to speed
39 /*	up a change.
40 /*
41 /*	The text below provides only a parameter summary. See
42 /*	\fBpostconf\fR(5) for more details including examples.
43 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
44 /*	The default location of the Postfix main.cf and master.cf
45 /*	configuration files.
46 /* .IP "\fBmaillog_file (empty)\fR"
47 /*	The name of an optional logfile that is written by the Postfix
48 /*	\fBpostlogd\fR(8) service.
49 /* .IP "\fBprocess_id (read-only)\fR"
50 /*	The process ID of a Postfix command or daemon process.
51 /* .IP "\fBprocess_name (read-only)\fR"
52 /*	The process name of a Postfix command or daemon process.
53 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
54 /*	A prefix that is prepended to the process name in syslog
55 /*	records, so that, for example, "smtpd" becomes "prefix/smtpd".
56 /* .IP "\fBservice_name (read-only)\fR"
57 /*	The master.cf service name of a Postfix daemon process.
58 /* .IP "\fBpostlogd_watchdog_timeout (10s)\fR"
59 /*	How much time a \fBpostlogd\fR(8) process may take to process a request
60 /*	before it is terminated by a built-in watchdog timer.
61 /* SEE ALSO
62 /*	postconf(5), configuration parameters
63 /*	syslogd(8), system logging
64 /* README_FILES
65 /* .ad
66 /* .fi
67 /*	Use "\fBpostconf readme_directory\fR" or
68 /*	"\fBpostconf html_directory\fR" to locate this information.
69 /* .na
70 /* .nf
71 /*	MAILLOG_README, Postfix logging to file or stdout
72 /* LICENSE
73 /* .ad
74 /* .fi
75 /*	The Secure Mailer license must be distributed with this software.
76 /* HISTORY
77 /* .ad
78 /* .fi
79 /*	This service was introduced with Postfix version 3.4.
80 /* AUTHOR(S)
81 /*	Wietse Venema
82 /*	Google, Inc.
83 /*	111 8th Avenue
84 /*	New York, NY 10011, USA
85 /*--*/
86 
87  /*
88   * System library.
89   */
90 #include <sys_defs.h>
91 
92  /*
93   * Utility library.
94   */
95 #include <logwriter.h>
96 #include <msg.h>
97 #include <msg_logger.h>
98 #include <stringops.h>
99 #include <vstream.h>
100 
101  /*
102   * Global library.
103   */
104 #include <mail_params.h>
105 #include <mail_task.h>
106 #include <mail_version.h>
107 #include <maillog_client.h>
108 
109  /*
110   * Server skeleton.
111   */
112 #include <mail_server.h>
113 
114  /*
115   * Tunable parameters.
116   */
117 int     var_postlogd_watchdog;
118 
119  /*
120   * Silly little macros.
121   */
122 #define STR(x)			vstring_str(x)
123 #define LEN(x)			VSTRING_LEN(x)
124 
125  /*
126   * Logfile stream.
127   */
128 static VSTREAM *postlogd_stream = 0;
129 
130 /* postlogd_fallback - log messages from postlogd(8) itself */
131 
postlogd_fallback(const char * buf)132 static void postlogd_fallback(const char *buf)
133 {
134     (void) logwriter_write(postlogd_stream, buf, strlen(buf));
135 }
136 
137 /* postlogd_service - perform service for client */
138 
postlogd_service(char * buf,ssize_t len,char * unused_service,char ** unused_argv)139 static void postlogd_service(char *buf, ssize_t len, char *unused_service,
140 			             char **unused_argv)
141 {
142 
143     if (postlogd_stream) {
144 	(void) logwriter_write(postlogd_stream, buf, len);
145     }
146 
147     /*
148      * After a configuration change that removes the maillog_file pathname,
149      * this service may still receive messages (after "postfix reload" or
150      * after process refresh) from programs that use the old maillog_file
151      * setting. Redirect those messages to the current logging mechanism.
152      */
153     else {
154 	char   *bp = buf;
155 	char   *progname_pid;
156 
157 	/*
158 	 * Avoid surprises: strip off the date, time, host, and program[pid]:
159 	 * prefix that were prepended by msg_logger(3). Then, hope that the
160 	 * current logging driver suppresses its own PID, when it sees that
161 	 * there is a PID embedded in the 'program name'.
162 	 */
163 	(void) mystrtok(&bp, CHARS_SPACE);	/* month */
164 	(void) mystrtok(&bp, CHARS_SPACE);	/* day */
165 	(void) mystrtok(&bp, CHARS_SPACE);	/* time */
166 	(void) mystrtok(&bp, CHARS_SPACE);	/* host */
167 	progname_pid = mystrtok(&bp, ":" CHARS_SPACE);	/* name[pid] sans ':' */
168 	bp += strspn(bp, CHARS_SPACE);
169 	if (progname_pid)
170 	    maillog_client_init(progname_pid, MAILLOG_CLIENT_FLAG_NONE);
171 	msg_info("%.*s", (int) (len - (bp - buf)), bp);
172 
173 	/*
174 	 * Restore the program name, in case postlogd(8) needs to log
175 	 * something about itself. We have to call maillog_client_init() in
176 	 * any case, because neither msg_syslog_init() nor openlog() make a
177 	 * copy of the name argument. We can't leave that pointing into the
178 	 * middle of the above message buffer.
179 	 */
180 	maillog_client_init(mail_task((char *) 0), MAILLOG_CLIENT_FLAG_NONE);
181     }
182 }
183 
184 /* pre_jail_init - pre-jail handling */
185 
pre_jail_init(char * unused_service_name,char ** argv)186 static void pre_jail_init(char *unused_service_name, char **argv)
187 {
188 
189     /*
190      * During process initialization, the postlogd daemon will log events to
191      * the postlog socket, so that they can be logged to file later. Once the
192      * postlogd daemon is handling requests, it will stop logging to the
193      * postlog socket and will instead write to the logfile, to avoid
194      * infinite recursion.
195      */
196 
197     /*
198      * Sanity check. This service takes no command-line arguments.
199      */
200     if (argv[0])
201 	msg_fatal("unexpected command-line argument: %s", argv[0]);
202 
203     /*
204      * After a configuration change that removes the maillog_file pathname,
205      * this service may still receive messages from processes that still use
206      * the old configuration. Those messages will have to be redirected to
207      * the current logging subsystem.
208      */
209     if (*var_maillog_file != 0) {
210 
211 	/*
212 	 * Instantiate the logwriter or bust.
213 	 */
214 	postlogd_stream = logwriter_open_or_die(var_maillog_file);
215 
216 	/*
217 	 * Inform the msg_logger client to stop using the postlog socket, and
218 	 * to call our logwriter.
219 	 */
220 	msg_logger_control(CA_MSG_LOGGER_CTL_FALLBACK_ONLY,
221 			   CA_MSG_LOGGER_CTL_FALLBACK_FN(postlogd_fallback),
222 			   CA_MSG_LOGGER_CTL_END);
223     }
224 }
225 
226 /* post_jail_init - post-jail initialization */
227 
post_jail_init(char * unused_name,char ** unused_argv)228 static void post_jail_init(char *unused_name, char **unused_argv)
229 {
230 
231     /*
232      * Prevent automatic process suicide after a limited number of client
233      * requests. It is OK to terminate after a limited amount of idle time.
234      */
235     var_use_limit = 0;
236 }
237 
238 MAIL_VERSION_STAMP_DECLARE;
239 
240 /* main - pass control to the multi-threaded skeleton */
241 
main(int argc,char ** argv)242 int     main(int argc, char **argv)
243 {
244     static const CONFIG_TIME_TABLE time_table[] = {
245 	VAR_POSTLOGD_WATCHDOG, DEF_POSTLOGD_WATCHDOG, &var_postlogd_watchdog, 10, 0,
246 	0,
247     };
248 
249     /*
250      * Fingerprint executables and core dumps.
251      */
252     MAIL_VERSION_STAMP_ALLOCATE;
253 
254     /*
255      * This is a datagram service, not a stream service, so that postlogd can
256      * restart immediately after "postfix reload" without requiring clients
257      * to resend messages. Those messages remain queued in the kernel until a
258      * new postlogd process retrieves them. It would be unreasonable to
259      * require that clients retransmit logs, especially in the case of a
260      * fatal or panic error.
261      */
262     dgram_server_main(argc, argv, postlogd_service,
263 		      CA_MAIL_SERVER_TIME_TABLE(time_table),
264 		      CA_MAIL_SERVER_PRE_INIT(pre_jail_init),
265 		      CA_MAIL_SERVER_POST_INIT(post_jail_init),
266 		      CA_MAIL_SERVER_SOLITARY,
267 		      CA_MAIL_SERVER_WATCHDOG(&var_postlogd_watchdog),
268 		      0);
269 }
270