summaryrefslogtreecommitdiffstats
path: root/src/postlogd/postlogd.c
blob: 4c6db6362b047b805d68da9fecea756734f635b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/*++
/* NAME
/*	postlogd 8
/* SUMMARY
/*	Postfix internal log server
/* SYNOPSIS
/*	\fBpostlogd\fR [generic Postfix daemon options]
/* DESCRIPTION
/*	This program logs events on behalf of Postfix programs
/*	when the maillog configuration parameter specifies a non-empty
/*	value.
/* BUGS
/*	Non-daemon Postfix programs don't know that they should log
/*	to the internal logging service before they have processed
/*	command-line options and main.cf parameters. These programs
/*	still log earlier events to the syslog service.
/*
/*	If Postfix is down, the non-daemon programs \fBpostfix\fR(1),
/*	\fBpostsuper\fR(1), \fBpostmulti\fR(1), and \fBpostlog\fR(1),
/*	will log directly to \fB$maillog_file\fR. These programs
/*	expect to run with root privileges, for example during
/*	Postfix start-up, reload, or shutdown.
/*
/*	Other non-daemon Postfix programs will never write directly to
/*	\fB$maillog_file\fR (also, logging to stdout would interfere
/*	with the operation of some of these programs). These programs
/*	can log to \fBpostlogd\fR(8) if they are run by the super-user,
/*	or if their executable file has set-gid permission. Do not
/*	set this permission on programs other than \fBpostdrop\fR(1)
/*	and \fBpostqueue\fR(1).
/* CONFIGURATION PARAMETERS
/* .ad
/* .fi
/*	Changes to \fBmain.cf\fR are picked up automatically, as
/*	\fBpostlogd\fR(8) processes run for only a limited amount
/*	of time. Use the command "\fBpostfix reload\fR" to speed
/*	up a change.
/*
/*	The text below provides only a parameter summary. See
/*	\fBpostconf\fR(5) for more details including examples.
/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
/*	The default location of the Postfix main.cf and master.cf
/*	configuration files.
/* .IP "\fBmaillog_file (empty)\fR"
/*	The name of an optional logfile that is written by the Postfix
/*	\fBpostlogd\fR(8) service.
/* .IP "\fBprocess_id (read-only)\fR"
/*	The process ID of a Postfix command or daemon process.
/* .IP "\fBprocess_name (read-only)\fR"
/*	The process name of a Postfix command or daemon process.
/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
/*	A prefix that is prepended to the process name in syslog
/*	records, so that, for example, "smtpd" becomes "prefix/smtpd".
/* .IP "\fBservice_name (read-only)\fR"
/*	The master.cf service name of a Postfix daemon process.
/* .IP "\fBpostlogd_watchdog_timeout (10s)\fR"
/*	How much time a \fBpostlogd\fR(8) process may take to process a request
/*	before it is terminated by a built-in watchdog timer.
/* SEE ALSO
/*	postconf(5), configuration parameters
/*	syslogd(8), system logging
/* README_FILES
/* .ad
/* .fi
/*	Use "\fBpostconf readme_directory\fR" or
/*	"\fBpostconf html_directory\fR" to locate this information.
/* .na
/* .nf
/*	MAILLOG_README, Postfix logging to file or stdout
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* HISTORY
/* .ad
/* .fi
/*	This service was introduced with Postfix version 3.4.
/* AUTHOR(S)
/*	Wietse Venema
/*	Google, Inc.
/*	111 8th Avenue
/*	New York, NY 10011, USA
/*--*/

 /*
  * System library.
  */
#include <sys_defs.h>

 /*
  * Utility library.
  */
#include <logwriter.h>
#include <msg.h>
#include <msg_logger.h>
#include <stringops.h>
#include <vstream.h>

 /*
  * Global library.
  */
#include <mail_params.h>
#include <mail_task.h>
#include <mail_version.h>
#include <maillog_client.h>

 /*
  * Server skeleton.
  */
#include <mail_server.h>

 /*
  * Tunable parameters.
  */
int     var_postlogd_watchdog;

 /*
  * Silly little macros.
  */
#define STR(x)			vstring_str(x)
#define LEN(x)			VSTRING_LEN(x)

 /*
  * Logfile stream.
  */
static VSTREAM *postlogd_stream = 0;

/* postlogd_fallback - log messages from postlogd(8) itself */

static void postlogd_fallback(const char *buf)
{
    (void) logwriter_write(postlogd_stream, buf, strlen(buf));
}

/* postlogd_service - perform service for client */

static void postlogd_service(char *buf, ssize_t len, char *unused_service,
			             char **unused_argv)
{

    if (postlogd_stream) {
	(void) logwriter_write(postlogd_stream, buf, len);
    }

    /*
     * After a configuration change that removes the maillog_file pathname,
     * this service may still receive messages (after "postfix reload" or
     * after process refresh) from programs that use the old maillog_file
     * setting. Redirect those messages to the current logging mechanism.
     */
    else {
	char   *bp = buf;
	char   *progname_pid;

	/*
	 * Avoid surprises: strip off the date, time, host, and program[pid]:
	 * prefix that were prepended by msg_logger(3). Then, hope that the
	 * current logging driver suppresses its own PID, when it sees that
	 * there is a PID embedded in the 'program name'.
	 */
	(void) mystrtok(&bp, CHARS_SPACE);	/* month */
	(void) mystrtok(&bp, CHARS_SPACE);	/* day */
	(void) mystrtok(&bp, CHARS_SPACE);	/* time */
	(void) mystrtok(&bp, CHARS_SPACE);	/* host */
	progname_pid = mystrtok(&bp, ":" CHARS_SPACE);	/* name[pid] sans ':' */
	bp += strspn(bp, CHARS_SPACE);
	if (progname_pid)
	    maillog_client_init(progname_pid, MAILLOG_CLIENT_FLAG_NONE);
	msg_info("%.*s", (int) (len - (bp - buf)), bp);

	/*
	 * Restore the program name, in case postlogd(8) needs to log
	 * something about itself. We have to call maillog_client_init() in
	 * any case, because neither msg_syslog_init() nor openlog() make a
	 * copy of the name argument. We can't leave that pointing into the
	 * middle of the above message buffer.
	 */
	maillog_client_init(mail_task((char *) 0), MAILLOG_CLIENT_FLAG_NONE);
    }
}

/* pre_jail_init - pre-jail handling */

static void pre_jail_init(char *unused_service_name, char **argv)
{

    /*
     * During process initialization, the postlogd daemon will log events to
     * the postlog socket, so that they can be logged to file later. Once the
     * postlogd daemon is handling requests, it will stop logging to the
     * postlog socket and will instead write to the logfile, to avoid
     * infinite recursion.
     */

    /*
     * Sanity check. This service takes no command-line arguments.
     */
    if (argv[0])
	msg_fatal("unexpected command-line argument: %s", argv[0]);

    /*
     * After a configuration change that removes the maillog_file pathname,
     * this service may still receive messages from processes that still use
     * the old configuration. Those messages will have to be redirected to
     * the current logging subsystem.
     */
    if (*var_maillog_file != 0) {

	/*
	 * Instantiate the logwriter or bust.
	 */
	postlogd_stream = logwriter_open_or_die(var_maillog_file);

	/*
	 * Inform the msg_logger client to stop using the postlog socket, and
	 * to call our logwriter.
	 */
	msg_logger_control(CA_MSG_LOGGER_CTL_FALLBACK_ONLY,
			   CA_MSG_LOGGER_CTL_FALLBACK_FN(postlogd_fallback),
			   CA_MSG_LOGGER_CTL_END);
    }
}

/* post_jail_init - post-jail initialization */

static void post_jail_init(char *unused_name, char **unused_argv)
{

    /*
     * Prevent automatic process suicide after a limited number of client
     * requests. It is OK to terminate after a limited amount of idle time.
     */
    var_use_limit = 0;
}

MAIL_VERSION_STAMP_DECLARE;

/* main - pass control to the multi-threaded skeleton */

int     main(int argc, char **argv)
{
    static const CONFIG_TIME_TABLE time_table[] = {
	VAR_POSTLOGD_WATCHDOG, DEF_POSTLOGD_WATCHDOG, &var_postlogd_watchdog, 10, 0,
	0,
    };

    /*
     * Fingerprint executables and core dumps.
     */
    MAIL_VERSION_STAMP_ALLOCATE;

    /*
     * This is a datagram service, not a stream service, so that postlogd can
     * restart immediately after "postfix reload" without requiring clients
     * to resend messages. Those messages remain queued in the kernel until a
     * new postlogd process retrieves them. It would be unreasonable to
     * require that clients retransmit logs, especially in the case of a
     * fatal or panic error.
     */
    dgram_server_main(argc, argv, postlogd_service,
		      CA_MAIL_SERVER_TIME_TABLE(time_table),
		      CA_MAIL_SERVER_PRE_INIT(pre_jail_init),
		      CA_MAIL_SERVER_POST_INIT(post_jail_init),
		      CA_MAIL_SERVER_SOLITARY,
		      CA_MAIL_SERVER_WATCHDOG(&var_postlogd_watchdog),
		      0);
}