Home | History | Annotate | Line # | Download | only in postlogd
      1 /*	$NetBSD: postlogd.c,v 1.4 2025/02/25 19:15:48 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_file configuration parameter specifies a
     13 /*	non-empty 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 not picked up automatically,
     37 /*	because \fBpostlogd\fR(8) terminates only after reaching
     38 /*	the \fBmax_idle\fR time limit.
     39 /*	Use the command "\fBpostfix reload\fR" to speed 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 /* .PP
     62 /*	Available in Postfix 3.9 and later:
     63 /* .IP "\fBmaillog_file_permissions (0600)\fR"
     64 /*	The file access permissions that will be set when the file
     65 /*	$maillog_file is created for the first time, or when the file is
     66 /*	created after an existing file is rotated.
     67 /* SEE ALSO
     68 /*	postconf(5), configuration parameters
     69 /*	syslogd(8), system logging
     70 /* README_FILES
     71 /* .ad
     72 /* .fi
     73 /*	Use "\fBpostconf readme_directory\fR" or
     74 /*	"\fBpostconf html_directory\fR" to locate this information.
     75 /* .na
     76 /* .nf
     77 /*	MAILLOG_README, Postfix logging to file or stdout
     78 /* LICENSE
     79 /* .ad
     80 /* .fi
     81 /*	The Secure Mailer license must be distributed with this software.
     82 /* HISTORY
     83 /* .ad
     84 /* .fi
     85 /*	This service was introduced with Postfix version 3.4.
     86 /* AUTHOR(S)
     87 /*	Wietse Venema
     88 /*	Google, Inc.
     89 /*	111 8th Avenue
     90 /*	New York, NY 10011, USA
     91 /*
     92 /*	Wietse Venema
     93 /*	porcupine.org
     94 /*--*/
     95 
     96  /*
     97   * System library.
     98   */
     99 #include <sys_defs.h>
    100 #include <sys/socket.h>
    101 
    102  /*
    103   * Utility library.
    104   */
    105 #include <logwriter.h>
    106 #include <msg.h>
    107 #include <msg_logger.h>
    108 #include <stringops.h>
    109 #include <vstream.h>
    110 
    111  /*
    112   * Global library.
    113   */
    114 #include <mail_params.h>
    115 #include <mail_task.h>
    116 #include <mail_version.h>
    117 #include <maillog_client.h>
    118 
    119  /*
    120   * Server skeleton.
    121   */
    122 #include <mail_server.h>
    123 
    124  /*
    125   * Tunable parameters.
    126   */
    127 int     var_postlogd_watchdog;
    128 
    129  /*
    130   * Silly little macros.
    131   */
    132 #define STR(x)			vstring_str(x)
    133 #define LEN(x)			VSTRING_LEN(x)
    134 
    135  /*
    136   * Logfile stream.
    137   */
    138 static VSTREAM *postlogd_stream = 0;
    139 
    140  /*
    141   * Receive buffer management.
    142   */
    143 #define DGRAM_BUF_SIZE	4096
    144 
    145 /* postlogd_fallback - log messages from postlogd(8) itself */
    146 
    147 static void postlogd_fallback(const char *buf)
    148 {
    149     (void) logwriter_write(postlogd_stream, buf, strlen(buf));
    150 }
    151 
    152 /* postlogd_service - perform service for client */
    153 
    154 static void postlogd_service(int sock, char *unused_service,
    155 			             char **unused_argv)
    156 {
    157     char    buf[DGRAM_BUF_SIZE];
    158     ssize_t len;
    159 
    160     if ((len = recv(sock, buf, sizeof(buf), 0)) < 0) {
    161 	msg_warn("failed to receive message with recv: %m");
    162 	return;
    163     }
    164     if (postlogd_stream) {
    165 	(void) logwriter_write(postlogd_stream, buf, len);
    166     }
    167 
    168     /*
    169      * After a configuration change that removes the maillog_file pathname,
    170      * this service may still receive messages (after "postfix reload" or
    171      * after process refresh) from programs that use the old maillog_file
    172      * setting. Redirect those messages to the current logging mechanism.
    173      */
    174     else {
    175 	char   *bp = buf;
    176 	char   *progname_pid;
    177 
    178 	/*
    179 	 * Avoid surprises: strip off the date, time, host, and program[pid]:
    180 	 * prefix that were prepended by msg_logger(3). Then, hope that the
    181 	 * current logging driver suppresses its own PID, when it sees that
    182 	 * there is a PID embedded in the 'program name'.
    183 	 */
    184 	(void) mystrtok(&bp, CHARS_SPACE);	/* month */
    185 	(void) mystrtok(&bp, CHARS_SPACE);	/* day */
    186 	(void) mystrtok(&bp, CHARS_SPACE);	/* time */
    187 	(void) mystrtok(&bp, CHARS_SPACE);	/* host */
    188 	progname_pid = mystrtok(&bp, ":" CHARS_SPACE);	/* name[pid] sans ':' */
    189 	bp += strspn(bp, CHARS_SPACE);
    190 	if (progname_pid)
    191 	    maillog_client_init(progname_pid, MAILLOG_CLIENT_FLAG_NONE);
    192 	msg_info("%.*s", (int) (len - (bp - buf)), bp);
    193 
    194 	/*
    195 	 * Restore the program name, in case postlogd(8) needs to log
    196 	 * something about itself. We have to call maillog_client_init() in
    197 	 * any case, because neither msg_syslog_init() nor openlog() make a
    198 	 * copy of the name argument. We can't leave that pointing into the
    199 	 * middle of the above message buffer.
    200 	 */
    201 	maillog_client_init(mail_task((char *) 0), MAILLOG_CLIENT_FLAG_NONE);
    202     }
    203 }
    204 
    205 /* pre_jail_init - pre-jail handling */
    206 
    207 static void pre_jail_init(char *unused_service_name, char **argv)
    208 {
    209 
    210     /*
    211      * During process initialization, the postlogd daemon will log events to
    212      * the postlog socket, so that they can be logged to file later. Once the
    213      * postlogd daemon is handling requests, it will stop logging to the
    214      * postlog socket and will instead write to the logfile, to avoid
    215      * infinite recursion.
    216      */
    217 
    218     /*
    219      * Sanity check. This service takes no command-line arguments.
    220      */
    221     if (argv[0])
    222 	msg_fatal("unexpected command-line argument: %s", argv[0]);
    223 
    224     /*
    225      * After a configuration change that removes the maillog_file pathname,
    226      * this service may still receive messages from processes that still use
    227      * the old configuration. Those messages will have to be redirected to
    228      * the current logging subsystem.
    229      */
    230     if (*var_maillog_file != 0) {
    231 
    232 	/*
    233 	 * Instantiate the logwriter or bust.
    234 	 */
    235 	postlogd_stream = logwriter_open_or_die(var_maillog_file);
    236 
    237 	/*
    238 	 * Inform the msg_logger client to stop using the postlog socket, and
    239 	 * to call our logwriter.
    240 	 */
    241 	msg_logger_control(CA_MSG_LOGGER_CTL_FALLBACK_ONLY,
    242 			   CA_MSG_LOGGER_CTL_FALLBACK_FN(postlogd_fallback),
    243 			   CA_MSG_LOGGER_CTL_END);
    244     }
    245 }
    246 
    247 /* post_jail_init - post-jail initialization */
    248 
    249 static void post_jail_init(char *unused_name, char **unused_argv)
    250 {
    251 
    252     /*
    253      * Prevent automatic process suicide after a limited number of client
    254      * requests. It is OK to terminate after a limited amount of idle time.
    255      */
    256     var_use_limit = 0;
    257 }
    258 
    259 MAIL_VERSION_STAMP_DECLARE;
    260 
    261 /* main - pass control to the multi-threaded skeleton */
    262 
    263 int     main(int argc, char **argv)
    264 {
    265     static const CONFIG_TIME_TABLE time_table[] = {
    266 	VAR_POSTLOGD_WATCHDOG, DEF_POSTLOGD_WATCHDOG, &var_postlogd_watchdog, 10, 0,
    267 	0,
    268     };
    269 
    270     /*
    271      * Fingerprint executables and core dumps.
    272      */
    273     MAIL_VERSION_STAMP_ALLOCATE;
    274 
    275     /*
    276      * This is a datagram service, not a stream service, so that postlogd can
    277      * restart immediately after "postfix reload" without requiring clients
    278      * to resend messages. Those messages remain queued in the kernel until a
    279      * new postlogd process retrieves them. It would be unreasonable to
    280      * require that clients retransmit logs, especially in the case of a
    281      * fatal or panic error.
    282      */
    283     dgram_server_main(argc, argv, postlogd_service,
    284 		      CA_MAIL_SERVER_TIME_TABLE(time_table),
    285 		      CA_MAIL_SERVER_PRE_INIT(pre_jail_init),
    286 		      CA_MAIL_SERVER_POST_INIT(post_jail_init),
    287 		      CA_MAIL_SERVER_SOLITARY,
    288 		      CA_MAIL_SERVER_WATCHDOG(&var_postlogd_watchdog),
    289 		      0);
    290 }
    291