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