| 1 |  |  | /*	$OpenBSD: smtpd.c,v 1.290 2017/09/08 16:51:22 eric Exp $	*/ | 
    
    | 2 |  |  |  | 
    
    | 3 |  |  | /* | 
    
    | 4 |  |  |  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> | 
    
    | 5 |  |  |  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> | 
    
    | 6 |  |  |  * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> | 
    
    | 7 |  |  |  * | 
    
    | 8 |  |  |  * Permission to use, copy, modify, and distribute this software for any | 
    
    | 9 |  |  |  * purpose with or without fee is hereby granted, provided that the above | 
    
    | 10 |  |  |  * copyright notice and this permission notice appear in all copies. | 
    
    | 11 |  |  |  * | 
    
    | 12 |  |  |  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 
    
    | 13 |  |  |  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 
    
    | 14 |  |  |  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 
    
    | 15 |  |  |  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
    
    | 16 |  |  |  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 
    
    | 17 |  |  |  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 
    
    | 18 |  |  |  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
    
    | 19 |  |  |  */ | 
    
    | 20 |  |  |  | 
    
    | 21 |  |  | #include <sys/types.h> | 
    
    | 22 |  |  | #include <sys/queue.h> | 
    
    | 23 |  |  | #include <sys/tree.h> | 
    
    | 24 |  |  | #include <sys/socket.h> | 
    
    | 25 |  |  | #include <sys/wait.h> | 
    
    | 26 |  |  | #include <sys/stat.h> | 
    
    | 27 |  |  | #include <sys/uio.h> | 
    
    | 28 |  |  | #include <sys/mman.h> | 
    
    | 29 |  |  |  | 
    
    | 30 |  |  | #include <bsd_auth.h> | 
    
    | 31 |  |  | #include <dirent.h> | 
    
    | 32 |  |  | #include <err.h> | 
    
    | 33 |  |  | #include <errno.h> | 
    
    | 34 |  |  | #include <event.h> | 
    
    | 35 |  |  | #include <fcntl.h> | 
    
    | 36 |  |  | #include <fts.h> | 
    
    | 37 |  |  | #include <imsg.h> | 
    
    | 38 |  |  | #include <inttypes.h> | 
    
    | 39 |  |  | #include <login_cap.h> | 
    
    | 40 |  |  | #include <paths.h> | 
    
    | 41 |  |  | #include <poll.h> | 
    
    | 42 |  |  | #include <pwd.h> | 
    
    | 43 |  |  | #include <signal.h> | 
    
    | 44 |  |  | #include <stdio.h> | 
    
    | 45 |  |  | #include <limits.h> | 
    
    | 46 |  |  | #include <stdlib.h> | 
    
    | 47 |  |  | #include <string.h> | 
    
    | 48 |  |  | #include <time.h> | 
    
    | 49 |  |  | #include <unistd.h> | 
    
    | 50 |  |  |  | 
    
    | 51 |  |  | #include <openssl/ssl.h> | 
    
    | 52 |  |  | #include <openssl/evp.h> | 
    
    | 53 |  |  |  | 
    
    | 54 |  |  | #include "smtpd.h" | 
    
    | 55 |  |  | #include "log.h" | 
    
    | 56 |  |  | #include "ssl.h" | 
    
    | 57 |  |  |  | 
    
    | 58 |  |  | #define SMTPD_MAXARG 32 | 
    
    | 59 |  |  |  | 
    
    | 60 |  |  | static void parent_imsg(struct mproc *, struct imsg *); | 
    
    | 61 |  |  | static void usage(void); | 
    
    | 62 |  |  | static int smtpd(void); | 
    
    | 63 |  |  | static void parent_shutdown(void); | 
    
    | 64 |  |  | static void parent_send_config(int, short, void *); | 
    
    | 65 |  |  | static void parent_send_config_lka(void); | 
    
    | 66 |  |  | static void parent_send_config_pony(void); | 
    
    | 67 |  |  | static void parent_send_config_ca(void); | 
    
    | 68 |  |  | static void parent_sig_handler(int, short, void *); | 
    
    | 69 |  |  | static void forkmda(struct mproc *, uint64_t, struct deliver *); | 
    
    | 70 |  |  | static int parent_forward_open(char *, char *, uid_t, gid_t); | 
    
    | 71 |  |  | static struct child *child_add(pid_t, int, const char *); | 
    
    | 72 |  |  | static struct mproc *start_child(int, char **, char *); | 
    
    | 73 |  |  | static struct mproc *setup_peer(enum smtp_proc_type, pid_t, int); | 
    
    | 74 |  |  | static void setup_peers(struct mproc *, struct mproc *); | 
    
    | 75 |  |  | static void setup_done(struct mproc *); | 
    
    | 76 |  |  | static void setup_proc(void); | 
    
    | 77 |  |  | static struct mproc *setup_peer(enum smtp_proc_type, pid_t, int); | 
    
    | 78 |  |  | static int imsg_wait(struct imsgbuf *, struct imsg *, int); | 
    
    | 79 |  |  |  | 
    
    | 80 |  |  | static void	offline_scan(int, short, void *); | 
    
    | 81 |  |  | static int	offline_add(char *); | 
    
    | 82 |  |  | static void	offline_done(void); | 
    
    | 83 |  |  | static int	offline_enqueue(char *); | 
    
    | 84 |  |  |  | 
    
    | 85 |  |  | static void	purge_task(void); | 
    
    | 86 |  |  | static int	parent_auth_user(const char *, const char *); | 
    
    | 87 |  |  | static void	load_pki_tree(void); | 
    
    | 88 |  |  | static void	load_pki_keys(void); | 
    
    | 89 |  |  |  | 
    
    | 90 |  |  | enum child_type { | 
    
    | 91 |  |  | 	CHILD_DAEMON, | 
    
    | 92 |  |  | 	CHILD_MDA, | 
    
    | 93 |  |  | 	CHILD_ENQUEUE_OFFLINE, | 
    
    | 94 |  |  | }; | 
    
    | 95 |  |  |  | 
    
    | 96 |  |  | struct child { | 
    
    | 97 |  |  | 	pid_t			 pid; | 
    
    | 98 |  |  | 	enum child_type		 type; | 
    
    | 99 |  |  | 	const char		*title; | 
    
    | 100 |  |  | 	int			 mda_out; | 
    
    | 101 |  |  | 	uint64_t		 mda_id; | 
    
    | 102 |  |  | 	char			*path; | 
    
    | 103 |  |  | 	char			*cause; | 
    
    | 104 |  |  | }; | 
    
    | 105 |  |  |  | 
    
    | 106 |  |  | struct offline { | 
    
    | 107 |  |  | 	TAILQ_ENTRY(offline)	 entry; | 
    
    | 108 |  |  | 	char			*path; | 
    
    | 109 |  |  | }; | 
    
    | 110 |  |  |  | 
    
    | 111 |  |  | #define OFFLINE_READMAX		20 | 
    
    | 112 |  |  | #define OFFLINE_QUEUEMAX	5 | 
    
    | 113 |  |  | static size_t			offline_running = 0; | 
    
    | 114 |  |  | TAILQ_HEAD(, offline)		offline_q; | 
    
    | 115 |  |  |  | 
    
    | 116 |  |  | static struct event		config_ev; | 
    
    | 117 |  |  | static struct event		offline_ev; | 
    
    | 118 |  |  | static struct timeval		offline_timeout; | 
    
    | 119 |  |  |  | 
    
    | 120 |  |  | static pid_t			purge_pid = -1; | 
    
    | 121 |  |  |  | 
    
    | 122 |  |  | extern char	**environ; | 
    
    | 123 |  |  | void		(*imsg_callback)(struct mproc *, struct imsg *); | 
    
    | 124 |  |  |  | 
    
    | 125 |  |  | enum smtp_proc_type	smtpd_process; | 
    
    | 126 |  |  |  | 
    
    | 127 |  |  | struct smtpd	*env = NULL; | 
    
    | 128 |  |  |  | 
    
    | 129 |  |  | struct mproc	*p_control = NULL; | 
    
    | 130 |  |  | struct mproc	*p_lka = NULL; | 
    
    | 131 |  |  | struct mproc	*p_parent = NULL; | 
    
    | 132 |  |  | struct mproc	*p_queue = NULL; | 
    
    | 133 |  |  | struct mproc	*p_scheduler = NULL; | 
    
    | 134 |  |  | struct mproc	*p_pony = NULL; | 
    
    | 135 |  |  | struct mproc	*p_ca = NULL; | 
    
    | 136 |  |  |  | 
    
    | 137 |  |  | const char	*backend_queue = "fs"; | 
    
    | 138 |  |  | const char	*backend_scheduler = "ramqueue"; | 
    
    | 139 |  |  | const char	*backend_stat = "ram"; | 
    
    | 140 |  |  |  | 
    
    | 141 |  |  | int	profiling = 0; | 
    
    | 142 |  |  | int	debug = 0; | 
    
    | 143 |  |  | int	foreground = 0; | 
    
    | 144 |  |  | int	control_socket = -1; | 
    
    | 145 |  |  |  | 
    
    | 146 |  |  | struct tree	 children; | 
    
    | 147 |  |  |  | 
    
    | 148 |  |  | static void | 
    
    | 149 |  |  | parent_imsg(struct mproc *p, struct imsg *imsg) | 
    
    | 150 |  |  | { | 
    
    | 151 |  |  | 	struct forward_req	*fwreq; | 
    
    | 152 |  |  | 	struct deliver		 deliver; | 
    
    | 153 |  |  | 	struct child		*c; | 
    
    | 154 |  |  | 	struct msg		 m; | 
    
    | 155 |  |  | 	const void		*data; | 
    
    | 156 |  |  | 	const char		*username, *password, *cause; | 
    
    | 157 |  |  | 	uint64_t		 reqid; | 
    
    | 158 |  |  | 	size_t			 sz; | 
    
    | 159 |  |  | 	void			*i; | 
    
    | 160 |  |  | 	int			 fd, n, v, ret; | 
    
    | 161 |  |  |  | 
    
    | 162 |  |  | 	if (imsg == NULL) | 
    
    | 163 |  |  | 		fatalx("process %s socket closed", p->name); | 
    
    | 164 |  |  |  | 
    
    | 165 |  |  | 	if (p->proc == PROC_LKA) { | 
    
    | 166 |  |  | 		switch (imsg->hdr.type) { | 
    
    | 167 |  |  | 		case IMSG_LKA_OPEN_FORWARD: | 
    
    | 168 |  |  | 			CHECK_IMSG_DATA_SIZE(imsg, sizeof *fwreq); | 
    
    | 169 |  |  | 			fwreq = imsg->data; | 
    
    | 170 |  |  | 			fd = parent_forward_open(fwreq->user, fwreq->directory, | 
    
    | 171 |  |  | 			    fwreq->uid, fwreq->gid); | 
    
    | 172 |  |  | 			fwreq->status = 0; | 
    
    | 173 |  |  | 			if (fd == -1 && errno != ENOENT) { | 
    
    | 174 |  |  | 				if (errno == EAGAIN) | 
    
    | 175 |  |  | 					fwreq->status = -1; | 
    
    | 176 |  |  | 			} | 
    
    | 177 |  |  | 			else | 
    
    | 178 |  |  | 				fwreq->status = 1; | 
    
    | 179 |  |  | 			m_compose(p, IMSG_LKA_OPEN_FORWARD, 0, 0, fd, | 
    
    | 180 |  |  | 			    fwreq, sizeof *fwreq); | 
    
    | 181 |  |  | 			return; | 
    
    | 182 |  |  |  | 
    
    | 183 |  |  | 		case IMSG_LKA_AUTHENTICATE: | 
    
    | 184 |  |  | 			/* | 
    
    | 185 |  |  | 			 * If we reached here, it means we want root to lookup | 
    
    | 186 |  |  | 			 * system user. | 
    
    | 187 |  |  | 			 */ | 
    
    | 188 |  |  | 			m_msg(&m, imsg); | 
    
    | 189 |  |  | 			m_get_id(&m, &reqid); | 
    
    | 190 |  |  | 			m_get_string(&m, &username); | 
    
    | 191 |  |  | 			m_get_string(&m, &password); | 
    
    | 192 |  |  | 			m_end(&m); | 
    
    | 193 |  |  |  | 
    
    | 194 |  |  | 			ret = parent_auth_user(username, password); | 
    
    | 195 |  |  |  | 
    
    | 196 |  |  | 			m_create(p, IMSG_LKA_AUTHENTICATE, 0, 0, -1); | 
    
    | 197 |  |  | 			m_add_id(p, reqid); | 
    
    | 198 |  |  | 			m_add_int(p, ret); | 
    
    | 199 |  |  | 			m_close(p); | 
    
    | 200 |  |  | 			return; | 
    
    | 201 |  |  | 		} | 
    
    | 202 |  |  | 	} | 
    
    | 203 |  |  |  | 
    
    | 204 |  |  | 	if (p->proc == PROC_PONY) { | 
    
    | 205 |  |  | 		switch (imsg->hdr.type) { | 
    
    | 206 |  |  | 		case IMSG_MDA_FORK: | 
    
    | 207 |  |  | 			m_msg(&m, imsg); | 
    
    | 208 |  |  | 			m_get_id(&m, &reqid); | 
    
    | 209 |  |  | 			m_get_data(&m, &data, &sz); | 
    
    | 210 |  |  | 			m_end(&m); | 
    
    | 211 |  |  | 			if (sz != sizeof(deliver)) | 
    
    | 212 |  |  | 				fatalx("expected deliver"); | 
    
    | 213 |  |  | 			memmove(&deliver, data, sz); | 
    
    | 214 |  |  | 			forkmda(p, reqid, &deliver); | 
    
    | 215 |  |  | 			return; | 
    
    | 216 |  |  |  | 
    
    | 217 |  |  | 		case IMSG_MDA_KILL: | 
    
    | 218 |  |  | 			m_msg(&m, imsg); | 
    
    | 219 |  |  | 			m_get_id(&m, &reqid); | 
    
    | 220 |  |  | 			m_get_string(&m, &cause); | 
    
    | 221 |  |  | 			m_end(&m); | 
    
    | 222 |  |  |  | 
    
    | 223 |  |  | 			i = NULL; | 
    
    | 224 |  |  | 			while ((n = tree_iter(&children, &i, NULL, (void**)&c))) | 
    
    | 225 |  |  | 				if (c->type == CHILD_MDA && | 
    
    | 226 |  |  | 				    c->mda_id == reqid && | 
    
    | 227 |  |  | 				    c->cause == NULL) | 
    
    | 228 |  |  | 					break; | 
    
    | 229 |  |  | 			if (!n) { | 
    
    | 230 |  |  | 				log_debug("debug: smtpd: " | 
    
    | 231 |  |  | 				    "kill request: proc not found"); | 
    
    | 232 |  |  | 				return; | 
    
    | 233 |  |  | 			} | 
    
    | 234 |  |  |  | 
    
    | 235 |  |  | 			c->cause = xstrdup(cause, "parent_imsg"); | 
    
    | 236 |  |  | 			log_debug("debug: smtpd: kill requested for %u: %s", | 
    
    | 237 |  |  | 			    c->pid, c->cause); | 
    
    | 238 |  |  | 			kill(c->pid, SIGTERM); | 
    
    | 239 |  |  | 			return; | 
    
    | 240 |  |  | 		} | 
    
    | 241 |  |  | 	} | 
    
    | 242 |  |  |  | 
    
    | 243 |  |  | 	if (p->proc == PROC_CONTROL) { | 
    
    | 244 |  |  | 		switch (imsg->hdr.type) { | 
    
    | 245 |  |  | 		case IMSG_CTL_VERBOSE: | 
    
    | 246 |  |  | 			m_msg(&m, imsg); | 
    
    | 247 |  |  | 			m_get_int(&m, &v); | 
    
    | 248 |  |  | 			m_end(&m); | 
    
    | 249 |  |  | 			log_trace_verbose(v); | 
    
    | 250 |  |  | 			return; | 
    
    | 251 |  |  |  | 
    
    | 252 |  |  | 		case IMSG_CTL_PROFILE: | 
    
    | 253 |  |  | 			m_msg(&m, imsg); | 
    
    | 254 |  |  | 			m_get_int(&m, &v); | 
    
    | 255 |  |  | 			m_end(&m); | 
    
    | 256 |  |  | 			profiling = v; | 
    
    | 257 |  |  | 			return; | 
    
    | 258 |  |  | 		} | 
    
    | 259 |  |  | 	} | 
    
    | 260 |  |  |  | 
    
    | 261 |  |  | 	errx(1, "parent_imsg: unexpected %s imsg from %s", | 
    
    | 262 |  |  | 	    imsg_to_str(imsg->hdr.type), proc_title(p->proc)); | 
    
    | 263 |  |  | } | 
    
    | 264 |  |  |  | 
    
    | 265 |  |  | static void | 
    
    | 266 |  |  | usage(void) | 
    
    | 267 |  |  | { | 
    
    | 268 |  |  | 	extern char	*__progname; | 
    
    | 269 |  |  |  | 
    
    | 270 |  |  | 	fprintf(stderr, "usage: %s [-dFhnv] [-D macro=value] " | 
    
    | 271 |  |  | 	    "[-f file] [-P system] [-T trace]\n", __progname); | 
    
    | 272 |  |  | 	exit(1); | 
    
    | 273 |  |  | } | 
    
    | 274 |  |  |  | 
    
    | 275 |  |  | static void | 
    
    | 276 |  |  | parent_shutdown(void) | 
    
    | 277 |  |  | { | 
    
    | 278 |  |  | 	pid_t pid; | 
    
    | 279 |  |  |  | 
    
    | 280 |  |  | 	mproc_clear(p_ca); | 
    
    | 281 |  |  | 	mproc_clear(p_pony); | 
    
    | 282 |  |  | 	mproc_clear(p_control); | 
    
    | 283 |  |  | 	mproc_clear(p_lka); | 
    
    | 284 |  |  | 	mproc_clear(p_scheduler); | 
    
    | 285 |  |  | 	mproc_clear(p_queue); | 
    
    | 286 |  |  |  | 
    
    | 287 |  |  | 	do { | 
    
    | 288 |  |  | 		pid = waitpid(WAIT_MYPGRP, NULL, 0); | 
    
    | 289 |  |  | 	} while (pid != -1 || (pid == -1 && errno == EINTR)); | 
    
    | 290 |  |  |  | 
    
    | 291 |  |  | 	unlink(SMTPD_SOCKET); | 
    
    | 292 |  |  |  | 
    
    | 293 |  |  | 	log_info("Exiting"); | 
    
    | 294 |  |  | 	exit(0); | 
    
    | 295 |  |  | } | 
    
    | 296 |  |  |  | 
    
    | 297 |  |  | static void | 
    
    | 298 |  |  | parent_send_config(int fd, short event, void *p) | 
    
    | 299 |  |  | { | 
    
    | 300 |  |  | 	parent_send_config_lka(); | 
    
    | 301 |  |  | 	parent_send_config_pony(); | 
    
    | 302 |  |  | 	parent_send_config_ca(); | 
    
    | 303 |  |  | 	purge_config(PURGE_PKI); | 
    
    | 304 |  |  | } | 
    
    | 305 |  |  |  | 
    
    | 306 |  |  | static void | 
    
    | 307 |  |  | parent_send_config_pony(void) | 
    
    | 308 |  |  | { | 
    
    | 309 |  |  | 	log_debug("debug: parent_send_config: configuring pony process"); | 
    
    | 310 |  |  | 	m_compose(p_pony, IMSG_CONF_START, 0, 0, -1, NULL, 0); | 
    
    | 311 |  |  | 	m_compose(p_pony, IMSG_CONF_END, 0, 0, -1, NULL, 0); | 
    
    | 312 |  |  | } | 
    
    | 313 |  |  |  | 
    
    | 314 |  |  | void | 
    
    | 315 |  |  | parent_send_config_lka() | 
    
    | 316 |  |  | { | 
    
    | 317 |  |  | 	log_debug("debug: parent_send_config_ruleset: reloading"); | 
    
    | 318 |  |  | 	m_compose(p_lka, IMSG_CONF_START, 0, 0, -1, NULL, 0); | 
    
    | 319 |  |  | 	m_compose(p_lka, IMSG_CONF_END, 0, 0, -1, NULL, 0); | 
    
    | 320 |  |  | } | 
    
    | 321 |  |  |  | 
    
    | 322 |  |  | static void | 
    
    | 323 |  |  | parent_send_config_ca(void) | 
    
    | 324 |  |  | { | 
    
    | 325 |  |  | 	log_debug("debug: parent_send_config: configuring ca process"); | 
    
    | 326 |  |  | 	m_compose(p_ca, IMSG_CONF_START, 0, 0, -1, NULL, 0); | 
    
    | 327 |  |  | 	m_compose(p_ca, IMSG_CONF_END, 0, 0, -1, NULL, 0); | 
    
    | 328 |  |  | } | 
    
    | 329 |  |  |  | 
    
    | 330 |  |  | static void | 
    
    | 331 |  |  | parent_sig_handler(int sig, short event, void *p) | 
    
    | 332 |  |  | { | 
    
    | 333 |  |  | 	struct child	*child; | 
    
    | 334 |  |  | 	int		 status, fail; | 
    
    | 335 |  |  | 	pid_t		 pid; | 
    
    | 336 |  |  | 	char		*cause; | 
    
    | 337 |  |  |  | 
    
    | 338 |  |  | 	switch (sig) { | 
    
    | 339 |  |  | 	case SIGTERM: | 
    
    | 340 |  |  | 	case SIGINT: | 
    
    | 341 |  |  | 		log_debug("debug: got signal %d", sig); | 
    
    | 342 |  |  | 		parent_shutdown(); | 
    
    | 343 |  |  | 		/* NOT REACHED */ | 
    
    | 344 |  |  |  | 
    
    | 345 |  |  | 	case SIGCHLD: | 
    
    | 346 |  |  | 		do { | 
    
    | 347 |  |  | 			int len; | 
    
    | 348 |  |  |  | 
    
    | 349 |  |  | 			pid = waitpid(-1, &status, WNOHANG); | 
    
    | 350 |  |  | 			if (pid <= 0) | 
    
    | 351 |  |  | 				continue; | 
    
    | 352 |  |  |  | 
    
    | 353 |  |  | 			fail = 0; | 
    
    | 354 |  |  | 			if (WIFSIGNALED(status)) { | 
    
    | 355 |  |  | 				fail = 1; | 
    
    | 356 |  |  | 				len = asprintf(&cause, "terminated; signal %d", | 
    
    | 357 |  |  | 				    WTERMSIG(status)); | 
    
    | 358 |  |  | 			} else if (WIFEXITED(status)) { | 
    
    | 359 |  |  | 				if (WEXITSTATUS(status) != 0) { | 
    
    | 360 |  |  | 					fail = 1; | 
    
    | 361 |  |  | 					len = asprintf(&cause, | 
    
    | 362 |  |  | 					    "exited abnormally"); | 
    
    | 363 |  |  | 				} else | 
    
    | 364 |  |  | 					len = asprintf(&cause, "exited okay"); | 
    
    | 365 |  |  | 			} else | 
    
    | 366 |  |  | 				/* WIFSTOPPED or WIFCONTINUED */ | 
    
    | 367 |  |  | 				continue; | 
    
    | 368 |  |  |  | 
    
    | 369 |  |  | 			if (len == -1) | 
    
    | 370 |  |  | 				fatal("asprintf"); | 
    
    | 371 |  |  |  | 
    
    | 372 |  |  | 			if (pid == purge_pid) | 
    
    | 373 |  |  | 				purge_pid = -1; | 
    
    | 374 |  |  |  | 
    
    | 375 |  |  | 			child = tree_pop(&children, pid); | 
    
    | 376 |  |  | 			if (child == NULL) | 
    
    | 377 |  |  | 				goto skip; | 
    
    | 378 |  |  |  | 
    
    | 379 |  |  | 			switch (child->type) { | 
    
    | 380 |  |  | 			case CHILD_DAEMON: | 
    
    | 381 |  |  | 				if (fail) | 
    
    | 382 |  |  | 					log_warnx("warn: lost child: %s %s", | 
    
    | 383 |  |  | 					    child->title, cause); | 
    
    | 384 |  |  | 				break; | 
    
    | 385 |  |  |  | 
    
    | 386 |  |  | 			case CHILD_MDA: | 
    
    | 387 |  |  | 				if (WIFSIGNALED(status) && | 
    
    | 388 |  |  | 				    WTERMSIG(status) == SIGALRM) { | 
    
    | 389 |  |  | 					char *tmp; | 
    
    | 390 |  |  | 					if (asprintf(&tmp, | 
    
    | 391 |  |  | 					    "terminated; timeout") != -1) { | 
    
    | 392 |  |  | 						free(cause); | 
    
    | 393 |  |  | 						cause = tmp; | 
    
    | 394 |  |  | 					} | 
    
    | 395 |  |  | 				} | 
    
    | 396 |  |  | 				else if (child->cause && | 
    
    | 397 |  |  | 				    WIFSIGNALED(status) && | 
    
    | 398 |  |  | 				    WTERMSIG(status) == SIGTERM) { | 
    
    | 399 |  |  | 					free(cause); | 
    
    | 400 |  |  | 					cause = child->cause; | 
    
    | 401 |  |  | 					child->cause = NULL; | 
    
    | 402 |  |  | 				} | 
    
    | 403 |  |  | 				free(child->cause); | 
    
    | 404 |  |  | 				log_debug("debug: smtpd: mda process done " | 
    
    | 405 |  |  | 				    "for session %016"PRIx64 ": %s", | 
    
    | 406 |  |  | 				    child->mda_id, cause); | 
    
    | 407 |  |  | 				m_create(p_pony, IMSG_MDA_DONE, 0, 0, | 
    
    | 408 |  |  | 				    child->mda_out); | 
    
    | 409 |  |  | 				m_add_id(p_pony, child->mda_id); | 
    
    | 410 |  |  | 				m_add_string(p_pony, cause); | 
    
    | 411 |  |  | 				m_close(p_pony); | 
    
    | 412 |  |  | 				/* free(cause); */ | 
    
    | 413 |  |  | 				break; | 
    
    | 414 |  |  |  | 
    
    | 415 |  |  | 			case CHILD_ENQUEUE_OFFLINE: | 
    
    | 416 |  |  | 				if (fail) | 
    
    | 417 |  |  | 					log_warnx("warn: smtpd: " | 
    
    | 418 |  |  | 					    "couldn't enqueue offline " | 
    
    | 419 |  |  | 					    "message %s; smtpctl %s", | 
    
    | 420 |  |  | 					    child->path, cause); | 
    
    | 421 |  |  | 				else | 
    
    | 422 |  |  | 					unlink(child->path); | 
    
    | 423 |  |  | 				free(child->path); | 
    
    | 424 |  |  | 				offline_done(); | 
    
    | 425 |  |  | 				break; | 
    
    | 426 |  |  |  | 
    
    | 427 |  |  | 			default: | 
    
    | 428 |  |  | 				fatalx("smtpd: unexpected child type"); | 
    
    | 429 |  |  | 			} | 
    
    | 430 |  |  | 			free(child); | 
    
    | 431 |  |  |     skip: | 
    
    | 432 |  |  | 			free(cause); | 
    
    | 433 |  |  | 		} while (pid > 0 || (pid == -1 && errno == EINTR)); | 
    
    | 434 |  |  |  | 
    
    | 435 |  |  | 		break; | 
    
    | 436 |  |  | 	default: | 
    
    | 437 |  |  | 		fatalx("smtpd: unexpected signal"); | 
    
    | 438 |  |  | 	} | 
    
    | 439 |  |  | } | 
    
    | 440 |  |  |  | 
    
    | 441 |  |  | int | 
    
    | 442 |  |  | main(int argc, char *argv[]) | 
    
    | 443 |  |  | { | 
    
    | 444 |  |  | 	int		 c, i; | 
    
    | 445 |  |  | 	int		 opts, flags; | 
    
    | 446 |  |  | 	const char	*conffile = CONF_FILE; | 
    
    | 447 |  |  | 	int		 save_argc = argc; | 
    
    | 448 |  |  | 	char		**save_argv = argv; | 
    
    | 449 |  |  | 	char		*rexec = NULL; | 
    
    | 450 |  |  | 	struct smtpd	 conf; | 
    
    | 451 |  |  |  | 
    
    | 452 |  |  | 	env = &conf; | 
    
    | 453 |  |  |  | 
    
    | 454 |  |  | 	flags = 0; | 
    
    | 455 |  |  | 	opts = 0; | 
    
    | 456 |  |  | 	debug = 0; | 
    
    | 457 |  |  | 	tracing = 0; | 
    
    | 458 |  |  |  | 
    
    | 459 |  |  | 	log_init(1, LOG_MAIL); | 
    
    | 460 |  |  |  | 
    
    | 461 |  |  | 	TAILQ_INIT(&offline_q); | 
    
    | 462 |  |  |  | 
    
    | 463 |  |  | 	while ((c = getopt(argc, argv, "B:dD:hnP:f:FT:vx:")) != -1) { | 
    
    | 464 |  |  | 		switch (c) { | 
    
    | 465 |  |  | 		case 'B': | 
    
    | 466 |  |  | 			if (strstr(optarg, "queue=") == optarg) | 
    
    | 467 |  |  | 				backend_queue = strchr(optarg, '=') + 1; | 
    
    | 468 |  |  | 			else if (strstr(optarg, "scheduler=") == optarg) | 
    
    | 469 |  |  | 				backend_scheduler = strchr(optarg, '=') + 1; | 
    
    | 470 |  |  | 			else if (strstr(optarg, "stat=") == optarg) | 
    
    | 471 |  |  | 				backend_stat = strchr(optarg, '=') + 1; | 
    
    | 472 |  |  | 			else | 
    
    | 473 |  |  | 				log_warnx("warn: " | 
    
    | 474 |  |  | 				    "invalid backend specifier %s", | 
    
    | 475 |  |  | 				    optarg); | 
    
    | 476 |  |  | 			break; | 
    
    | 477 |  |  | 		case 'd': | 
    
    | 478 |  |  | 			foreground = 1; | 
    
    | 479 |  |  | 			foreground_log = 1; | 
    
    | 480 |  |  | 			break; | 
    
    | 481 |  |  | 		case 'D': | 
    
    | 482 |  |  | 			if (cmdline_symset(optarg) < 0) | 
    
    | 483 |  |  | 				log_warnx("warn: " | 
    
    | 484 |  |  | 				    "could not parse macro definition %s", | 
    
    | 485 |  |  | 				    optarg); | 
    
    | 486 |  |  | 			break; | 
    
    | 487 |  |  | 		case 'h': | 
    
    | 488 |  |  | 			log_info("version: " SMTPD_NAME " " SMTPD_VERSION); | 
    
    | 489 |  |  | 			usage(); | 
    
    | 490 |  |  | 			break; | 
    
    | 491 |  |  | 		case 'n': | 
    
    | 492 |  |  | 			debug = 2; | 
    
    | 493 |  |  | 			opts |= SMTPD_OPT_NOACTION; | 
    
    | 494 |  |  | 			break; | 
    
    | 495 |  |  | 		case 'f': | 
    
    | 496 |  |  | 			conffile = optarg; | 
    
    | 497 |  |  | 			break; | 
    
    | 498 |  |  | 		case 'F': | 
    
    | 499 |  |  | 			foreground = 1; | 
    
    | 500 |  |  | 			break; | 
    
    | 501 |  |  |  | 
    
    | 502 |  |  | 		case 'T': | 
    
    | 503 |  |  | 			if (!strcmp(optarg, "imsg")) | 
    
    | 504 |  |  | 				tracing |= TRACE_IMSG; | 
    
    | 505 |  |  | 			else if (!strcmp(optarg, "io")) | 
    
    | 506 |  |  | 				tracing |= TRACE_IO; | 
    
    | 507 |  |  | 			else if (!strcmp(optarg, "smtp")) | 
    
    | 508 |  |  | 				tracing |= TRACE_SMTP; | 
    
    | 509 |  |  | 			else if (!strcmp(optarg, "mfa") || | 
    
    | 510 |  |  | 			    !strcmp(optarg, "filter") || | 
    
    | 511 |  |  | 			    !strcmp(optarg, "filters")) | 
    
    | 512 |  |  | 				tracing |= TRACE_FILTERS; | 
    
    | 513 |  |  | 			else if (!strcmp(optarg, "mta") || | 
    
    | 514 |  |  | 			    !strcmp(optarg, "transfer")) | 
    
    | 515 |  |  | 				tracing |= TRACE_MTA; | 
    
    | 516 |  |  | 			else if (!strcmp(optarg, "bounce") || | 
    
    | 517 |  |  | 			    !strcmp(optarg, "bounces")) | 
    
    | 518 |  |  | 				tracing |= TRACE_BOUNCE; | 
    
    | 519 |  |  | 			else if (!strcmp(optarg, "scheduler")) | 
    
    | 520 |  |  | 				tracing |= TRACE_SCHEDULER; | 
    
    | 521 |  |  | 			else if (!strcmp(optarg, "lookup")) | 
    
    | 522 |  |  | 				tracing |= TRACE_LOOKUP; | 
    
    | 523 |  |  | 			else if (!strcmp(optarg, "stat") || | 
    
    | 524 |  |  | 			    !strcmp(optarg, "stats")) | 
    
    | 525 |  |  | 				tracing |= TRACE_STAT; | 
    
    | 526 |  |  | 			else if (!strcmp(optarg, "rules")) | 
    
    | 527 |  |  | 				tracing |= TRACE_RULES; | 
    
    | 528 |  |  | 			else if (!strcmp(optarg, "mproc")) | 
    
    | 529 |  |  | 				tracing |= TRACE_MPROC; | 
    
    | 530 |  |  | 			else if (!strcmp(optarg, "expand")) | 
    
    | 531 |  |  | 				tracing |= TRACE_EXPAND; | 
    
    | 532 |  |  | 			else if (!strcmp(optarg, "table") || | 
    
    | 533 |  |  | 			    !strcmp(optarg, "tables")) | 
    
    | 534 |  |  | 				tracing |= TRACE_TABLES; | 
    
    | 535 |  |  | 			else if (!strcmp(optarg, "queue")) | 
    
    | 536 |  |  | 				tracing |= TRACE_QUEUE; | 
    
    | 537 |  |  | 			else if (!strcmp(optarg, "all")) | 
    
    | 538 |  |  | 				tracing |= ~TRACE_DEBUG; | 
    
    | 539 |  |  | 			else if (!strcmp(optarg, "profstat")) | 
    
    | 540 |  |  | 				profiling |= PROFILE_TOSTAT; | 
    
    | 541 |  |  | 			else if (!strcmp(optarg, "profile-imsg")) | 
    
    | 542 |  |  | 				profiling |= PROFILE_IMSG; | 
    
    | 543 |  |  | 			else if (!strcmp(optarg, "profile-queue")) | 
    
    | 544 |  |  | 				profiling |= PROFILE_QUEUE; | 
    
    | 545 |  |  | 			else | 
    
    | 546 |  |  | 				log_warnx("warn: unknown trace flag \"%s\"", | 
    
    | 547 |  |  | 				    optarg); | 
    
    | 548 |  |  | 			break; | 
    
    | 549 |  |  | 		case 'P': | 
    
    | 550 |  |  | 			if (!strcmp(optarg, "smtp")) | 
    
    | 551 |  |  | 				flags |= SMTPD_SMTP_PAUSED; | 
    
    | 552 |  |  | 			else if (!strcmp(optarg, "mta")) | 
    
    | 553 |  |  | 				flags |= SMTPD_MTA_PAUSED; | 
    
    | 554 |  |  | 			else if (!strcmp(optarg, "mda")) | 
    
    | 555 |  |  | 				flags |= SMTPD_MDA_PAUSED; | 
    
    | 556 |  |  | 			break; | 
    
    | 557 |  |  | 		case 'v': | 
    
    | 558 |  |  | 			tracing |=  TRACE_DEBUG; | 
    
    | 559 |  |  | 			break; | 
    
    | 560 |  |  | 		case 'x': | 
    
    | 561 |  |  | 			rexec = optarg; | 
    
    | 562 |  |  | 			break; | 
    
    | 563 |  |  | 		default: | 
    
    | 564 |  |  | 			usage(); | 
    
    | 565 |  |  | 		} | 
    
    | 566 |  |  | 	} | 
    
    | 567 |  |  |  | 
    
    | 568 |  |  | 	argv += optind; | 
    
    | 569 |  |  | 	argc -= optind; | 
    
    | 570 |  |  |  | 
    
    | 571 |  |  | 	if (argc || *argv) | 
    
    | 572 |  |  | 		usage(); | 
    
    | 573 |  |  |  | 
    
    | 574 |  |  | 	ssl_init(); | 
    
    | 575 |  |  |  | 
    
    | 576 |  |  | 	if (parse_config(&conf, conffile, opts)) | 
    
    | 577 |  |  | 		exit(1); | 
    
    | 578 |  |  |  | 
    
    | 579 |  |  | 	if (strlcpy(env->sc_conffile, conffile, PATH_MAX) | 
    
    | 580 |  |  | 	    >= PATH_MAX) | 
    
    | 581 |  |  | 		errx(1, "config file exceeds PATH_MAX"); | 
    
    | 582 |  |  |  | 
    
    | 583 |  |  | 	if (env->sc_opts & SMTPD_OPT_NOACTION) { | 
    
    | 584 |  |  | 		if (env->sc_queue_key && | 
    
    | 585 |  |  | 		    crypto_setup(env->sc_queue_key, | 
    
    | 586 |  |  | 		    strlen(env->sc_queue_key)) == 0) { | 
    
    | 587 |  |  | 			fatalx("crypto_setup:" | 
    
    | 588 |  |  | 			    "invalid key for queue encryption"); | 
    
    | 589 |  |  | 		} | 
    
    | 590 |  |  | 		load_pki_tree(); | 
    
    | 591 |  |  | 		load_pki_keys(); | 
    
    | 592 |  |  | 		fprintf(stderr, "configuration OK\n"); | 
    
    | 593 |  |  | 		exit(0); | 
    
    | 594 |  |  | 	} | 
    
    | 595 |  |  |  | 
    
    | 596 |  |  | 	env->sc_flags |= flags; | 
    
    | 597 |  |  |  | 
    
    | 598 |  |  | 	/* check for root privileges */ | 
    
    | 599 |  |  | 	if (geteuid()) | 
    
    | 600 |  |  | 		errx(1, "need root privileges"); | 
    
    | 601 |  |  |  | 
    
    | 602 |  |  | 	log_init(foreground_log, LOG_MAIL); | 
    
    | 603 |  |  | 	log_trace_verbose(tracing); | 
    
    | 604 |  |  | 	load_pki_tree(); | 
    
    | 605 |  |  | 	load_pki_keys(); | 
    
    | 606 |  |  |  | 
    
    | 607 |  |  | 	log_debug("debug: using \"%s\" queue backend", backend_queue); | 
    
    | 608 |  |  | 	log_debug("debug: using \"%s\" scheduler backend", backend_scheduler); | 
    
    | 609 |  |  | 	log_debug("debug: using \"%s\" stat backend", backend_stat); | 
    
    | 610 |  |  |  | 
    
    | 611 |  |  | 	if (env->sc_hostname[0] == '\0') | 
    
    | 612 |  |  | 		errx(1, "machine does not have a hostname set"); | 
    
    | 613 |  |  | 	env->sc_uptime = time(NULL); | 
    
    | 614 |  |  |  | 
    
    | 615 |  |  | 	if (rexec == NULL) { | 
    
    | 616 |  |  | 		smtpd_process = PROC_PARENT; | 
    
    | 617 |  |  |  | 
    
    | 618 |  |  | 		if (env->sc_queue_flags & QUEUE_ENCRYPTION) { | 
    
    | 619 |  |  | 			if (env->sc_queue_key == NULL) { | 
    
    | 620 |  |  | 				char	*password; | 
    
    | 621 |  |  |  | 
    
    | 622 |  |  | 				password = getpass("queue key: "); | 
    
    | 623 |  |  | 				if (password == NULL) | 
    
    | 624 |  |  | 					err(1, "getpass"); | 
    
    | 625 |  |  |  | 
    
    | 626 |  |  | 				env->sc_queue_key = strdup(password); | 
    
    | 627 |  |  | 				explicit_bzero(password, strlen(password)); | 
    
    | 628 |  |  | 				if (env->sc_queue_key == NULL) | 
    
    | 629 |  |  | 					err(1, "strdup"); | 
    
    | 630 |  |  | 			} | 
    
    | 631 |  |  | 			else { | 
    
    | 632 |  |  | 				char   *buf = NULL; | 
    
    | 633 |  |  | 				size_t	sz = 0; | 
    
    | 634 |  |  | 				ssize_t	len; | 
    
    | 635 |  |  |  | 
    
    | 636 |  |  | 				if (strcasecmp(env->sc_queue_key, "stdin") == 0) { | 
    
    | 637 |  |  | 					if ((len = getline(&buf, &sz, stdin)) == -1) | 
    
    | 638 |  |  | 						err(1, "getline"); | 
    
    | 639 |  |  | 					if (buf[len - 1] == '\n') | 
    
    | 640 |  |  | 						buf[len - 1] = '\0'; | 
    
    | 641 |  |  | 					env->sc_queue_key = buf; | 
    
    | 642 |  |  | 				} | 
    
    | 643 |  |  | 			} | 
    
    | 644 |  |  | 		} | 
    
    | 645 |  |  |  | 
    
    | 646 |  |  | 		log_info("info: %s %s starting", SMTPD_NAME, SMTPD_VERSION); | 
    
    | 647 |  |  |  | 
    
    | 648 |  |  | 		if (!foreground) | 
    
    | 649 |  |  | 			if (daemon(0, 0) == -1) | 
    
    | 650 |  |  | 				err(1, "failed to daemonize"); | 
    
    | 651 |  |  |  | 
    
    | 652 |  |  | 		/* setup all processes */ | 
    
    | 653 |  |  |  | 
    
    | 654 |  |  | 		p_ca = start_child(save_argc, save_argv, "ca"); | 
    
    | 655 |  |  | 		p_ca->proc = PROC_CA; | 
    
    | 656 |  |  |  | 
    
    | 657 |  |  | 		p_control = start_child(save_argc, save_argv, "control"); | 
    
    | 658 |  |  | 		p_control->proc = PROC_CONTROL; | 
    
    | 659 |  |  |  | 
    
    | 660 |  |  | 		p_lka = start_child(save_argc, save_argv, "lka"); | 
    
    | 661 |  |  | 		p_lka->proc = PROC_LKA; | 
    
    | 662 |  |  |  | 
    
    | 663 |  |  | 		p_pony = start_child(save_argc, save_argv, "pony"); | 
    
    | 664 |  |  | 		p_pony->proc = PROC_PONY; | 
    
    | 665 |  |  |  | 
    
    | 666 |  |  | 		p_queue = start_child(save_argc, save_argv, "queue"); | 
    
    | 667 |  |  | 		p_queue->proc = PROC_QUEUE; | 
    
    | 668 |  |  |  | 
    
    | 669 |  |  | 		p_scheduler = start_child(save_argc, save_argv, "scheduler"); | 
    
    | 670 |  |  | 		p_scheduler->proc = PROC_SCHEDULER; | 
    
    | 671 |  |  |  | 
    
    | 672 |  |  | 		setup_peers(p_control, p_ca); | 
    
    | 673 |  |  | 		setup_peers(p_control, p_lka); | 
    
    | 674 |  |  | 		setup_peers(p_control, p_pony); | 
    
    | 675 |  |  | 		setup_peers(p_control, p_queue); | 
    
    | 676 |  |  | 		setup_peers(p_control, p_scheduler); | 
    
    | 677 |  |  | 		setup_peers(p_pony, p_ca); | 
    
    | 678 |  |  | 		setup_peers(p_pony, p_lka); | 
    
    | 679 |  |  | 		setup_peers(p_pony, p_queue); | 
    
    | 680 |  |  | 		setup_peers(p_queue, p_lka); | 
    
    | 681 |  |  | 		setup_peers(p_queue, p_scheduler); | 
    
    | 682 |  |  |  | 
    
    | 683 |  |  | 		if (env->sc_queue_key) { | 
    
    | 684 |  |  | 			if (imsg_compose(&p_queue->imsgbuf, IMSG_SETUP_KEY, 0, | 
    
    | 685 |  |  | 			    0, -1, env->sc_queue_key, strlen(env->sc_queue_key) | 
    
    | 686 |  |  | 			    + 1) == -1) | 
    
    | 687 |  |  | 				fatal("imsg_compose"); | 
    
    | 688 |  |  | 			if (imsg_flush(&p_queue->imsgbuf) == -1) | 
    
    | 689 |  |  | 				fatal("imsg_flush"); | 
    
    | 690 |  |  | 		} | 
    
    | 691 |  |  |  | 
    
    | 692 |  |  | 		setup_done(p_ca); | 
    
    | 693 |  |  | 		setup_done(p_control); | 
    
    | 694 |  |  | 		setup_done(p_lka); | 
    
    | 695 |  |  | 		setup_done(p_pony); | 
    
    | 696 |  |  | 		setup_done(p_queue); | 
    
    | 697 |  |  | 		setup_done(p_scheduler); | 
    
    | 698 |  |  |  | 
    
    | 699 |  |  | 		log_debug("smtpd: setup done"); | 
    
    | 700 |  |  |  | 
    
    | 701 |  |  | 		return smtpd(); | 
    
    | 702 |  |  | 	} | 
    
    | 703 |  |  |  | 
    
    | 704 |  |  | 	if (!strcmp(rexec, "ca")) { | 
    
    | 705 |  |  | 		smtpd_process = PROC_CA; | 
    
    | 706 |  |  | 		setup_proc(); | 
    
    | 707 |  |  |  | 
    
    | 708 |  |  | 		return ca(); | 
    
    | 709 |  |  | 	} | 
    
    | 710 |  |  |  | 
    
    | 711 |  |  | 	else if (!strcmp(rexec, "control")) { | 
    
    | 712 |  |  | 		smtpd_process = PROC_CONTROL; | 
    
    | 713 |  |  | 		setup_proc(); | 
    
    | 714 |  |  |  | 
    
    | 715 |  |  | 		/* the control socket ensures that only one smtpd instance is running */ | 
    
    | 716 |  |  | 		control_socket = control_create_socket(); | 
    
    | 717 |  |  |  | 
    
    | 718 |  |  | 		env->sc_stat = stat_backend_lookup(backend_stat); | 
    
    | 719 |  |  | 		if (env->sc_stat == NULL) | 
    
    | 720 |  |  | 			errx(1, "could not find stat backend \"%s\"", backend_stat); | 
    
    | 721 |  |  |  | 
    
    | 722 |  |  | 		return control(); | 
    
    | 723 |  |  | 	} | 
    
    | 724 |  |  |  | 
    
    | 725 |  |  | 	else if (!strcmp(rexec, "lka")) { | 
    
    | 726 |  |  | 		smtpd_process = PROC_LKA; | 
    
    | 727 |  |  | 		setup_proc(); | 
    
    | 728 |  |  |  | 
    
    | 729 |  |  | 		return lka(); | 
    
    | 730 |  |  | 	} | 
    
    | 731 |  |  |  | 
    
    | 732 |  |  | 	else if (!strcmp(rexec, "pony")) { | 
    
    | 733 |  |  | 		smtpd_process = PROC_PONY; | 
    
    | 734 |  |  | 		setup_proc(); | 
    
    | 735 |  |  |  | 
    
    | 736 |  |  | 		return pony(); | 
    
    | 737 |  |  | 	} | 
    
    | 738 |  |  |  | 
    
    | 739 |  |  | 	else if (!strcmp(rexec, "queue")) { | 
    
    | 740 |  |  | 		smtpd_process = PROC_QUEUE; | 
    
    | 741 |  |  | 		setup_proc(); | 
    
    | 742 |  |  |  | 
    
    | 743 |  |  | 		if (env->sc_queue_flags & QUEUE_COMPRESSION) | 
    
    | 744 |  |  | 			env->sc_comp = compress_backend_lookup("gzip"); | 
    
    | 745 |  |  |  | 
    
    | 746 |  |  | 		if (!queue_init(backend_queue, 1)) | 
    
    | 747 |  |  | 			errx(1, "could not initialize queue backend"); | 
    
    | 748 |  |  |  | 
    
    | 749 |  |  | 		return queue(); | 
    
    | 750 |  |  | 	} | 
    
    | 751 |  |  |  | 
    
    | 752 |  |  | 	else if (!strcmp(rexec, "scheduler")) { | 
    
    | 753 |  |  | 		smtpd_process = PROC_SCHEDULER; | 
    
    | 754 |  |  | 		setup_proc(); | 
    
    | 755 |  |  |  | 
    
    | 756 |  |  | 		for (i = 0; i < MAX_BOUNCE_WARN; i++) { | 
    
    | 757 |  |  | 			if (env->sc_bounce_warn[i] == 0) | 
    
    | 758 |  |  | 				break; | 
    
    | 759 |  |  | 			log_debug("debug: bounce warning after %s", | 
    
    | 760 |  |  | 			    duration_to_text(env->sc_bounce_warn[i])); | 
    
    | 761 |  |  | 		} | 
    
    | 762 |  |  |  | 
    
    | 763 |  |  | 		return scheduler(); | 
    
    | 764 |  |  | 	} | 
    
    | 765 |  |  |  | 
    
    | 766 |  |  | 	fatalx("bad rexec: %s", rexec); | 
    
    | 767 |  |  |  | 
    
    | 768 |  |  | 	return (1); | 
    
    | 769 |  |  | } | 
    
    | 770 |  |  |  | 
    
    | 771 |  |  | static struct mproc * | 
    
    | 772 |  |  | start_child(int save_argc, char **save_argv, char *rexec) | 
    
    | 773 |  |  | { | 
    
    | 774 |  |  | 	struct mproc *p; | 
    
    | 775 |  |  | 	char *argv[SMTPD_MAXARG]; | 
    
    | 776 |  |  | 	int sp[2], argc = 0; | 
    
    | 777 |  |  | 	pid_t pid; | 
    
    | 778 |  |  |  | 
    
    | 779 |  |  | 	if (save_argc >= SMTPD_MAXARG - 2) | 
    
    | 780 |  |  | 		fatalx("too many arguments"); | 
    
    | 781 |  |  |  | 
    
    | 782 |  |  | 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) | 
    
    | 783 |  |  | 		fatal("socketpair"); | 
    
    | 784 |  |  |  | 
    
    | 785 |  |  | 	io_set_nonblocking(sp[0]); | 
    
    | 786 |  |  | 	io_set_nonblocking(sp[1]); | 
    
    | 787 |  |  |  | 
    
    | 788 |  |  | 	switch (pid = fork()) { | 
    
    | 789 |  |  | 	case -1: | 
    
    | 790 |  |  | 		fatal("%s: fork", save_argv[0]); | 
    
    | 791 |  |  | 	case 0: | 
    
    | 792 |  |  | 		break; | 
    
    | 793 |  |  | 	default: | 
    
    | 794 |  |  | 		close(sp[0]); | 
    
    | 795 |  |  | 		p = calloc(1, sizeof(*p)); | 
    
    | 796 |  |  | 		if (p == NULL) | 
    
    | 797 |  |  | 			fatal("calloc"); | 
    
    | 798 |  |  | 		if((p->name = strdup(rexec)) == NULL) | 
    
    | 799 |  |  | 			fatal("strdup"); | 
    
    | 800 |  |  | 		mproc_init(p, sp[1]); | 
    
    | 801 |  |  | 		p->pid = pid; | 
    
    | 802 |  |  | 		p->handler = parent_imsg; | 
    
    | 803 |  |  | 		return p; | 
    
    | 804 |  |  | 	} | 
    
    | 805 |  |  |  | 
    
    | 806 |  |  | 	if (dup2(sp[0], 3) == -1) | 
    
    | 807 |  |  | 		fatal("%s: dup2", rexec); | 
    
    | 808 |  |  |  | 
    
    | 809 |  |  | 	if (closefrom(4) == -1) | 
    
    | 810 |  |  | 		fatal("%s: closefrom", rexec); | 
    
    | 811 |  |  |  | 
    
    | 812 |  |  | 	for (argc = 0; argc < save_argc; argc++) | 
    
    | 813 |  |  | 		argv[argc] = save_argv[argc]; | 
    
    | 814 |  |  | 	argv[argc++] = "-x"; | 
    
    | 815 |  |  | 	argv[argc++] = rexec; | 
    
    | 816 |  |  | 	argv[argc++] = NULL; | 
    
    | 817 |  |  |  | 
    
    | 818 |  |  | 	execvp(argv[0], argv); | 
    
    | 819 |  |  | 	fatal("%s: execvp", rexec); | 
    
    | 820 |  |  | } | 
    
    | 821 |  |  |  | 
    
    | 822 |  |  | static void | 
    
    | 823 |  |  | setup_peers(struct mproc *a, struct mproc *b) | 
    
    | 824 |  |  | { | 
    
    | 825 |  |  | 	int sp[2]; | 
    
    | 826 |  |  |  | 
    
    | 827 |  |  | 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) | 
    
    | 828 |  |  | 		fatal("socketpair"); | 
    
    | 829 |  |  |  | 
    
    | 830 |  |  | 	io_set_nonblocking(sp[0]); | 
    
    | 831 |  |  | 	io_set_nonblocking(sp[1]); | 
    
    | 832 |  |  |  | 
    
    | 833 |  |  | 	if (imsg_compose(&a->imsgbuf, IMSG_SETUP_PEER, b->proc, b->pid, sp[0], | 
    
    | 834 |  |  | 	    NULL, 0) == -1) | 
    
    | 835 |  |  | 		fatal("imsg_compose"); | 
    
    | 836 |  |  | 	if (imsg_flush(&a->imsgbuf) == -1) | 
    
    | 837 |  |  | 		fatal("imsg_flush"); | 
    
    | 838 |  |  |  | 
    
    | 839 |  |  | 	if (imsg_compose(&b->imsgbuf, IMSG_SETUP_PEER, a->proc, a->pid, sp[1], | 
    
    | 840 |  |  | 	    NULL, 0) == -1) | 
    
    | 841 |  |  | 		fatal("imsg_compose"); | 
    
    | 842 |  |  | 	if (imsg_flush(&b->imsgbuf) == -1) | 
    
    | 843 |  |  | 		fatal("imsg_flush"); | 
    
    | 844 |  |  | } | 
    
    | 845 |  |  |  | 
    
    | 846 |  |  | static void | 
    
    | 847 |  |  | setup_done(struct mproc *p) | 
    
    | 848 |  |  | { | 
    
    | 849 |  |  | 	struct imsg imsg; | 
    
    | 850 |  |  |  | 
    
    | 851 |  |  | 	if (imsg_compose(&p->imsgbuf, IMSG_SETUP_DONE, 0, 0, -1, NULL, 0) == -1) | 
    
    | 852 |  |  | 		fatal("imsg_compose"); | 
    
    | 853 |  |  | 	if (imsg_flush(&p->imsgbuf) == -1) | 
    
    | 854 |  |  | 		fatal("imsg_flush"); | 
    
    | 855 |  |  |  | 
    
    | 856 |  |  | 	if (imsg_wait(&p->imsgbuf, &imsg, 10000) == -1) | 
    
    | 857 |  |  | 		fatal("imsg_wait"); | 
    
    | 858 |  |  |  | 
    
    | 859 |  |  | 	if (imsg.hdr.type != IMSG_SETUP_DONE) | 
    
    | 860 |  |  | 		fatalx("expect IMSG_SETUP_DONE"); | 
    
    | 861 |  |  |  | 
    
    | 862 |  |  | 	log_debug("setup_done: %s[%d] done", p->name, p->pid); | 
    
    | 863 |  |  |  | 
    
    | 864 |  |  | 	imsg_free(&imsg); | 
    
    | 865 |  |  | } | 
    
    | 866 |  |  |  | 
    
    | 867 |  |  | static void | 
    
    | 868 |  |  | setup_proc(void) | 
    
    | 869 |  |  | { | 
    
    | 870 |  |  | 	struct imsgbuf *ibuf; | 
    
    | 871 |  |  | 	struct imsg imsg; | 
    
    | 872 |  |  |         int setup = 1; | 
    
    | 873 |  |  |  | 
    
    | 874 |  |  | 	log_procinit(proc_title(smtpd_process)); | 
    
    | 875 |  |  |  | 
    
    | 876 |  |  | 	p_parent = calloc(1, sizeof(*p_parent)); | 
    
    | 877 |  |  | 	if (p_parent == NULL) | 
    
    | 878 |  |  | 		fatal("calloc"); | 
    
    | 879 |  |  | 	if((p_parent->name = strdup("parent")) == NULL) | 
    
    | 880 |  |  | 		fatal("strdup"); | 
    
    | 881 |  |  | 	p_parent->proc = PROC_PARENT; | 
    
    | 882 |  |  | 	p_parent->handler = imsg_dispatch; | 
    
    | 883 |  |  | 	mproc_init(p_parent, 3); | 
    
    | 884 |  |  |  | 
    
    | 885 |  |  | 	ibuf = &p_parent->imsgbuf; | 
    
    | 886 |  |  |  | 
    
    | 887 |  |  | 	while (setup) { | 
    
    | 888 |  |  | 		if (imsg_wait(ibuf, &imsg, 10000) == -1) | 
    
    | 889 |  |  | 			fatal("imsg_wait"); | 
    
    | 890 |  |  |  | 
    
    | 891 |  |  | 		switch (imsg.hdr.type) { | 
    
    | 892 |  |  | 		case IMSG_SETUP_KEY: | 
    
    | 893 |  |  | 			env->sc_queue_key = strdup(imsg.data); | 
    
    | 894 |  |  | 			break; | 
    
    | 895 |  |  | 		case IMSG_SETUP_PEER: | 
    
    | 896 |  |  | 			setup_peer(imsg.hdr.peerid, imsg.hdr.pid, imsg.fd); | 
    
    | 897 |  |  | 			break; | 
    
    | 898 |  |  | 		case IMSG_SETUP_DONE: | 
    
    | 899 |  |  | 			setup = 0; | 
    
    | 900 |  |  | 			break; | 
    
    | 901 |  |  | 		default: | 
    
    | 902 |  |  | 			fatal("bad imsg %d", imsg.hdr.type); | 
    
    | 903 |  |  | 		} | 
    
    | 904 |  |  | 		imsg_free(&imsg); | 
    
    | 905 |  |  | 	} | 
    
    | 906 |  |  |  | 
    
    | 907 |  |  | 	if (imsg_compose(ibuf, IMSG_SETUP_DONE, 0, 0, -1, NULL, 0) == -1) | 
    
    | 908 |  |  | 		fatal("imsg_compose"); | 
    
    | 909 |  |  |  | 
    
    | 910 |  |  | 	if (imsg_flush(ibuf) == -1) | 
    
    | 911 |  |  | 		fatal("imsg_flush"); | 
    
    | 912 |  |  |  | 
    
    | 913 |  |  | 	log_debug("setup_proc: %s done", proc_title(smtpd_process)); | 
    
    | 914 |  |  | } | 
    
    | 915 |  |  |  | 
    
    | 916 |  |  | static struct mproc * | 
    
    | 917 |  |  | setup_peer(enum smtp_proc_type proc, pid_t pid, int sock) | 
    
    | 918 |  |  | { | 
    
    | 919 |  |  | 	struct mproc *p, **pp; | 
    
    | 920 |  |  |  | 
    
    | 921 |  |  | 	log_debug("setup_peer: %s -> %s[%u] fd=%d", proc_title(smtpd_process), | 
    
    | 922 |  |  | 	    proc_title(proc), pid, sock); | 
    
    | 923 |  |  |  | 
    
    | 924 |  |  | 	if (sock == -1) | 
    
    | 925 |  |  | 		fatalx("peer socket not received"); | 
    
    | 926 |  |  |  | 
    
    | 927 |  |  | 	switch (proc) { | 
    
    | 928 |  |  | 	case PROC_LKA: | 
    
    | 929 |  |  | 		pp = &p_lka; | 
    
    | 930 |  |  | 		break; | 
    
    | 931 |  |  | 	case PROC_QUEUE: | 
    
    | 932 |  |  | 		pp = &p_queue; | 
    
    | 933 |  |  | 		break; | 
    
    | 934 |  |  | 	case PROC_CONTROL: | 
    
    | 935 |  |  | 		pp = &p_control; | 
    
    | 936 |  |  | 		break; | 
    
    | 937 |  |  | 	case PROC_SCHEDULER: | 
    
    | 938 |  |  | 		pp = &p_scheduler; | 
    
    | 939 |  |  | 		break; | 
    
    | 940 |  |  | 	case PROC_PONY: | 
    
    | 941 |  |  | 		pp = &p_pony; | 
    
    | 942 |  |  | 		break; | 
    
    | 943 |  |  | 	case PROC_CA: | 
    
    | 944 |  |  | 		pp = &p_ca; | 
    
    | 945 |  |  | 		break; | 
    
    | 946 |  |  | 	default: | 
    
    | 947 |  |  | 		fatalx("unknown peer"); | 
    
    | 948 |  |  | 	} | 
    
    | 949 |  |  |  | 
    
    | 950 |  |  | 	if (*pp) | 
    
    | 951 |  |  | 		fatalx("peer already set"); | 
    
    | 952 |  |  |  | 
    
    | 953 |  |  | 	p = calloc(1, sizeof(*p)); | 
    
    | 954 |  |  | 	if (p == NULL) | 
    
    | 955 |  |  | 		fatal("calloc"); | 
    
    | 956 |  |  | 	if((p->name = strdup(proc_title(proc))) == NULL) | 
    
    | 957 |  |  | 		fatal("strdup"); | 
    
    | 958 |  |  | 	mproc_init(p, sock); | 
    
    | 959 |  |  | 	p->pid = pid; | 
    
    | 960 |  |  | 	p->proc = proc; | 
    
    | 961 |  |  | 	p->handler = imsg_dispatch; | 
    
    | 962 |  |  |  | 
    
    | 963 |  |  | 	*pp = p; | 
    
    | 964 |  |  |  | 
    
    | 965 |  |  | 	return p; | 
    
    | 966 |  |  | } | 
    
    | 967 |  |  |  | 
    
    | 968 |  |  | static int | 
    
    | 969 |  |  | imsg_wait(struct imsgbuf *ibuf, struct imsg *imsg, int timeout) | 
    
    | 970 |  |  | { | 
    
    | 971 |  |  | 	struct pollfd pfd[1]; | 
    
    | 972 |  |  | 	ssize_t n; | 
    
    | 973 |  |  |  | 
    
    | 974 |  |  | 	pfd[0].fd = ibuf->fd; | 
    
    | 975 |  |  | 	pfd[0].events = POLLIN; | 
    
    | 976 |  |  |  | 
    
    | 977 |  |  | 	while (1) { | 
    
    | 978 |  |  | 		if ((n = imsg_get(ibuf, imsg)) == -1) | 
    
    | 979 |  |  | 			return -1; | 
    
    | 980 |  |  | 		if (n) | 
    
    | 981 |  |  | 			return 1; | 
    
    | 982 |  |  |  | 
    
    | 983 |  |  | 		n = poll(pfd, 1, timeout); | 
    
    | 984 |  |  | 		if (n == -1) | 
    
    | 985 |  |  | 			return -1; | 
    
    | 986 |  |  | 		if (n == 0) { | 
    
    | 987 |  |  | 			errno = ETIMEDOUT; | 
    
    | 988 |  |  | 			return -1; | 
    
    | 989 |  |  | 		} | 
    
    | 990 |  |  |  | 
    
    | 991 |  |  | 		if (((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) || n == 0) | 
    
    | 992 |  |  | 			return -1; | 
    
    | 993 |  |  | 	} | 
    
    | 994 |  |  | } | 
    
    | 995 |  |  |  | 
    
    | 996 |  |  | int | 
    
    | 997 |  |  | smtpd(void) { | 
    
    | 998 |  |  | 	struct event	 ev_sigint; | 
    
    | 999 |  |  | 	struct event	 ev_sigterm; | 
    
    | 1000 |  |  | 	struct event	 ev_sigchld; | 
    
    | 1001 |  |  | 	struct event	 ev_sighup; | 
    
    | 1002 |  |  | 	struct timeval	 tv; | 
    
    | 1003 |  |  |  | 
    
    | 1004 |  |  | 	imsg_callback = parent_imsg; | 
    
    | 1005 |  |  |  | 
    
    | 1006 |  |  | 	tree_init(&children); | 
    
    | 1007 |  |  |  | 
    
    | 1008 |  |  | 	child_add(p_queue->pid, CHILD_DAEMON, proc_title(PROC_QUEUE)); | 
    
    | 1009 |  |  | 	child_add(p_control->pid, CHILD_DAEMON, proc_title(PROC_CONTROL)); | 
    
    | 1010 |  |  | 	child_add(p_lka->pid, CHILD_DAEMON, proc_title(PROC_LKA)); | 
    
    | 1011 |  |  | 	child_add(p_scheduler->pid, CHILD_DAEMON, proc_title(PROC_SCHEDULER)); | 
    
    | 1012 |  |  | 	child_add(p_pony->pid, CHILD_DAEMON, proc_title(PROC_PONY)); | 
    
    | 1013 |  |  | 	child_add(p_ca->pid, CHILD_DAEMON, proc_title(PROC_CA)); | 
    
    | 1014 |  |  |  | 
    
    | 1015 |  |  | 	event_init(); | 
    
    | 1016 |  |  |  | 
    
    | 1017 |  |  | 	signal_set(&ev_sigint, SIGINT, parent_sig_handler, NULL); | 
    
    | 1018 |  |  | 	signal_set(&ev_sigterm, SIGTERM, parent_sig_handler, NULL); | 
    
    | 1019 |  |  | 	signal_set(&ev_sigchld, SIGCHLD, parent_sig_handler, NULL); | 
    
    | 1020 |  |  | 	signal_set(&ev_sighup, SIGHUP, parent_sig_handler, NULL); | 
    
    | 1021 |  |  | 	signal_add(&ev_sigint, NULL); | 
    
    | 1022 |  |  | 	signal_add(&ev_sigterm, NULL); | 
    
    | 1023 |  |  | 	signal_add(&ev_sigchld, NULL); | 
    
    | 1024 |  |  | 	signal_add(&ev_sighup, NULL); | 
    
    | 1025 |  |  | 	signal(SIGPIPE, SIG_IGN); | 
    
    | 1026 |  |  |  | 
    
    | 1027 |  |  | 	config_peer(PROC_CONTROL); | 
    
    | 1028 |  |  | 	config_peer(PROC_LKA); | 
    
    | 1029 |  |  | 	config_peer(PROC_QUEUE); | 
    
    | 1030 |  |  | 	config_peer(PROC_CA); | 
    
    | 1031 |  |  | 	config_peer(PROC_PONY); | 
    
    | 1032 |  |  |  | 
    
    | 1033 |  |  | 	evtimer_set(&config_ev, parent_send_config, NULL); | 
    
    | 1034 |  |  | 	memset(&tv, 0, sizeof(tv)); | 
    
    | 1035 |  |  | 	evtimer_add(&config_ev, &tv); | 
    
    | 1036 |  |  |  | 
    
    | 1037 |  |  | 	/* defer offline scanning for a second */ | 
    
    | 1038 |  |  | 	evtimer_set(&offline_ev, offline_scan, NULL); | 
    
    | 1039 |  |  | 	offline_timeout.tv_sec = 1; | 
    
    | 1040 |  |  | 	offline_timeout.tv_usec = 0; | 
    
    | 1041 |  |  | 	evtimer_add(&offline_ev, &offline_timeout); | 
    
    | 1042 |  |  |  | 
    
    | 1043 |  |  | 	purge_task(); | 
    
    | 1044 |  |  |  | 
    
    | 1045 |  |  | 	if (pledge("stdio rpath wpath cpath fattr flock tmppath " | 
    
    | 1046 |  |  | 	    "getpw sendfd proc exec id inet unix", NULL) == -1) | 
    
    | 1047 |  |  | 		err(1, "pledge"); | 
    
    | 1048 |  |  |  | 
    
    | 1049 |  |  | 	event_dispatch(); | 
    
    | 1050 |  |  | 	fatalx("exited event loop"); | 
    
    | 1051 |  |  |  | 
    
    | 1052 |  |  | 	return (0); | 
    
    | 1053 |  |  | } | 
    
    | 1054 |  |  |  | 
    
    | 1055 |  |  | static void | 
    
    | 1056 |  |  | load_pki_tree(void) | 
    
    | 1057 |  |  | { | 
    
    | 1058 |  |  | 	struct pki	*pki; | 
    
    | 1059 |  |  | 	struct ca	*sca; | 
    
    | 1060 |  |  | 	const char	*k; | 
    
    | 1061 |  |  | 	void		*iter_dict; | 
    
    | 1062 |  |  |  | 
    
    | 1063 |  |  | 	log_debug("debug: init ssl-tree"); | 
    
    | 1064 |  |  | 	iter_dict = NULL; | 
    
    | 1065 |  |  | 	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) { | 
    
    | 1066 |  |  | 		log_debug("info: loading pki information for %s", k); | 
    
    | 1067 |  |  | 		if (pki->pki_cert_file == NULL) | 
    
    | 1068 |  |  | 			fatalx("load_pki_tree: missing certificate file"); | 
    
    | 1069 |  |  | 		if (pki->pki_key_file == NULL) | 
    
    | 1070 |  |  | 			fatalx("load_pki_tree: missing key file"); | 
    
    | 1071 |  |  |  | 
    
    | 1072 |  |  | 		if (!ssl_load_certificate(pki, pki->pki_cert_file)) | 
    
    | 1073 |  |  | 			fatalx("load_pki_tree: failed to load certificate file"); | 
    
    | 1074 |  |  | 	} | 
    
    | 1075 |  |  |  | 
    
    | 1076 |  |  | 	log_debug("debug: init ca-tree"); | 
    
    | 1077 |  |  | 	iter_dict = NULL; | 
    
    | 1078 |  |  | 	while (dict_iter(env->sc_ca_dict, &iter_dict, &k, (void **)&sca)) { | 
    
    | 1079 |  |  | 		log_debug("info: loading CA information for %s", k); | 
    
    | 1080 |  |  | 		if (!ssl_load_cafile(sca, sca->ca_cert_file)) | 
    
    | 1081 |  |  | 			fatalx("load_pki_tree: failed to load CA file"); | 
    
    | 1082 |  |  | 	} | 
    
    | 1083 |  |  | } | 
    
    | 1084 |  |  |  | 
    
    | 1085 |  |  | void | 
    
    | 1086 |  |  | load_pki_keys(void) | 
    
    | 1087 |  |  | { | 
    
    | 1088 |  |  | 	struct pki	*pki; | 
    
    | 1089 |  |  | 	const char	*k; | 
    
    | 1090 |  |  | 	void		*iter_dict; | 
    
    | 1091 |  |  |  | 
    
    | 1092 |  |  | 	log_debug("debug: init ssl-tree"); | 
    
    | 1093 |  |  | 	iter_dict = NULL; | 
    
    | 1094 |  |  | 	while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) { | 
    
    | 1095 |  |  | 		log_debug("info: loading pki keys for %s", k); | 
    
    | 1096 |  |  |  | 
    
    | 1097 |  |  | 		if (!ssl_load_keyfile(pki, pki->pki_key_file, k)) | 
    
    | 1098 |  |  | 			fatalx("load_pki_keys: failed to load key file"); | 
    
    | 1099 |  |  | 	} | 
    
    | 1100 |  |  | } | 
    
    | 1101 |  |  |  | 
    
    | 1102 |  |  | int | 
    
    | 1103 |  |  | fork_proc_backend(const char *key, const char *conf, const char *procname) | 
    
    | 1104 |  |  | { | 
    
    | 1105 |  |  | 	pid_t		pid; | 
    
    | 1106 |  |  | 	int		sp[2]; | 
    
    | 1107 |  |  | 	char		path[PATH_MAX]; | 
    
    | 1108 |  |  | 	char		name[PATH_MAX]; | 
    
    | 1109 |  |  | 	char		*arg; | 
    
    | 1110 |  |  |  | 
    
    | 1111 |  |  | 	if (strlcpy(name, conf, sizeof(name)) >= sizeof(name)) { | 
    
    | 1112 |  |  | 		log_warnx("warn: %s-proc: conf too long", key); | 
    
    | 1113 |  |  | 		return (0); | 
    
    | 1114 |  |  | 	} | 
    
    | 1115 |  |  |  | 
    
    | 1116 |  |  | 	arg = strchr(name, ':'); | 
    
    | 1117 |  |  | 	if (arg) | 
    
    | 1118 |  |  | 		*arg++ = '\0'; | 
    
    | 1119 |  |  |  | 
    
    | 1120 |  |  | 	if (snprintf(path, sizeof(path), PATH_LIBEXEC "/%s-%s", key, name) >= | 
    
    | 1121 |  |  | 	    (ssize_t)sizeof(path)) { | 
    
    | 1122 |  |  | 		log_warn("warn: %s-proc: exec path too long", key); | 
    
    | 1123 |  |  | 		return (-1); | 
    
    | 1124 |  |  | 	} | 
    
    | 1125 |  |  |  | 
    
    | 1126 |  |  | 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) { | 
    
    | 1127 |  |  | 		log_warn("warn: %s-proc: socketpair", key); | 
    
    | 1128 |  |  | 		return (-1); | 
    
    | 1129 |  |  | 	} | 
    
    | 1130 |  |  |  | 
    
    | 1131 |  |  | 	if ((pid = fork()) == -1) { | 
    
    | 1132 |  |  | 		log_warn("warn: %s-proc: fork", key); | 
    
    | 1133 |  |  | 		close(sp[0]); | 
    
    | 1134 |  |  | 		close(sp[1]); | 
    
    | 1135 |  |  | 		return (-1); | 
    
    | 1136 |  |  | 	} | 
    
    | 1137 |  |  |  | 
    
    | 1138 |  |  | 	if (pid == 0) { | 
    
    | 1139 |  |  | 		/* child process */ | 
    
    | 1140 |  |  | 		dup2(sp[0], STDIN_FILENO); | 
    
    | 1141 |  |  | 		if (closefrom(STDERR_FILENO + 1) < 0) | 
    
    | 1142 |  |  | 			exit(1); | 
    
    | 1143 |  |  |  | 
    
    | 1144 |  |  | 		if (procname == NULL) | 
    
    | 1145 |  |  | 			procname = name; | 
    
    | 1146 |  |  |  | 
    
    | 1147 |  |  | 		execl(path, procname, arg, (char *)NULL); | 
    
    | 1148 |  |  | 		err(1, "execl: %s", path); | 
    
    | 1149 |  |  | 	} | 
    
    | 1150 |  |  |  | 
    
    | 1151 |  |  | 	/* parent process */ | 
    
    | 1152 |  |  | 	close(sp[0]); | 
    
    | 1153 |  |  |  | 
    
    | 1154 |  |  | 	return (sp[1]); | 
    
    | 1155 |  |  | } | 
    
    | 1156 |  |  |  | 
    
    | 1157 |  |  | struct child * | 
    
    | 1158 |  |  | child_add(pid_t pid, int type, const char *title) | 
    
    | 1159 |  |  | { | 
    
    | 1160 |  |  | 	struct child	*child; | 
    
    | 1161 |  |  |  | 
    
    | 1162 |  |  | 	if ((child = calloc(1, sizeof(*child))) == NULL) | 
    
    | 1163 |  |  | 		fatal("smtpd: child_add: calloc"); | 
    
    | 1164 |  |  |  | 
    
    | 1165 |  |  | 	child->pid = pid; | 
    
    | 1166 |  |  | 	child->type = type; | 
    
    | 1167 |  |  | 	child->title = title; | 
    
    | 1168 |  |  |  | 
    
    | 1169 |  |  | 	tree_xset(&children, pid, child); | 
    
    | 1170 |  |  |  | 
    
    | 1171 |  |  | 	return (child); | 
    
    | 1172 |  |  | } | 
    
    | 1173 |  |  |  | 
    
    | 1174 |  |  | static void | 
    
    | 1175 |  |  | purge_task(void) | 
    
    | 1176 |  |  | { | 
    
    | 1177 |  |  | 	struct passwd	*pw; | 
    
    | 1178 |  |  | 	DIR		*d; | 
    
    | 1179 |  |  | 	int		 n; | 
    
    | 1180 |  |  | 	uid_t		 uid; | 
    
    | 1181 |  |  | 	gid_t		 gid; | 
    
    | 1182 |  |  |  | 
    
    | 1183 |  |  | 	n = 0; | 
    
    | 1184 |  |  | 	if ((d = opendir(PATH_SPOOL PATH_PURGE))) { | 
    
    | 1185 |  |  | 		while (readdir(d) != NULL) | 
    
    | 1186 |  |  | 			n++; | 
    
    | 1187 |  |  | 		closedir(d); | 
    
    | 1188 |  |  | 	} else | 
    
    | 1189 |  |  | 		log_warn("warn: purge_task: opendir"); | 
    
    | 1190 |  |  |  | 
    
    | 1191 |  |  | 	if (n > 2) { | 
    
    | 1192 |  |  | 		switch (purge_pid = fork()) { | 
    
    | 1193 |  |  | 		case -1: | 
    
    | 1194 |  |  | 			log_warn("warn: purge_task: fork"); | 
    
    | 1195 |  |  | 			break; | 
    
    | 1196 |  |  | 		case 0: | 
    
    | 1197 |  |  | 			if ((pw = getpwnam(SMTPD_QUEUE_USER)) == NULL) | 
    
    | 1198 |  |  | 				fatalx("unknown user " SMTPD_QUEUE_USER); | 
    
    | 1199 |  |  | 			if (chroot(PATH_SPOOL PATH_PURGE) == -1) | 
    
    | 1200 |  |  | 				fatal("smtpd: chroot"); | 
    
    | 1201 |  |  | 			if (chdir("/") == -1) | 
    
    | 1202 |  |  | 				fatal("smtpd: chdir"); | 
    
    | 1203 |  |  | 			uid = pw->pw_uid; | 
    
    | 1204 |  |  | 			gid = pw->pw_gid; | 
    
    | 1205 |  |  | 			if (setgroups(1, &gid) || | 
    
    | 1206 |  |  | 			    setresgid(gid, gid, gid) || | 
    
    | 1207 |  |  | 			    setresuid(uid, uid, uid)) | 
    
    | 1208 |  |  | 				fatal("smtpd: cannot drop privileges"); | 
    
    | 1209 |  |  | 			rmtree("/", 1); | 
    
    | 1210 |  |  | 			_exit(0); | 
    
    | 1211 |  |  | 			break; | 
    
    | 1212 |  |  | 		default: | 
    
    | 1213 |  |  | 			break; | 
    
    | 1214 |  |  | 		} | 
    
    | 1215 |  |  | 	} | 
    
    | 1216 |  |  | } | 
    
    | 1217 |  |  |  | 
    
    | 1218 |  |  | static void | 
    
    | 1219 |  |  | forkmda(struct mproc *p, uint64_t id, struct deliver *deliver) | 
    
    | 1220 |  |  | { | 
    
    | 1221 |  |  | 	char		 ebuf[128], sfn[32]; | 
    
    | 1222 |  |  | 	struct delivery_backend	*db; | 
    
    | 1223 |  |  | 	struct child	*child; | 
    
    | 1224 |  |  | 	pid_t		 pid; | 
    
    | 1225 |  |  | 	int		 allout, pipefd[2]; | 
    
    | 1226 |  |  |  | 
    
    | 1227 |  |  | 	log_debug("debug: smtpd: forking mda for session %016"PRIx64 | 
    
    | 1228 |  |  | 	    ": \"%s\" as %s", id, deliver->to, deliver->user); | 
    
    | 1229 |  |  |  | 
    
    | 1230 |  |  | 	db = delivery_backend_lookup(deliver->mode); | 
    
    | 1231 |  |  | 	if (db == NULL) { | 
    
    | 1232 |  |  | 		(void)snprintf(ebuf, sizeof ebuf, "could not find delivery backend"); | 
    
    | 1233 |  |  | 		m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1); | 
    
    | 1234 |  |  | 		m_add_id(p_pony, id); | 
    
    | 1235 |  |  | 		m_add_string(p_pony, ebuf); | 
    
    | 1236 |  |  | 		m_close(p_pony); | 
    
    | 1237 |  |  | 		return; | 
    
    | 1238 |  |  | 	} | 
    
    | 1239 |  |  |  | 
    
    | 1240 |  |  | 	if (deliver->userinfo.uid == 0 && !db->allow_root) { | 
    
    | 1241 |  |  | 		(void)snprintf(ebuf, sizeof ebuf, "not allowed to deliver to: %s", | 
    
    | 1242 |  |  | 		    deliver->user); | 
    
    | 1243 |  |  | 		m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1); | 
    
    | 1244 |  |  | 		m_add_id(p_pony, id); | 
    
    | 1245 |  |  | 		m_add_string(p_pony, ebuf); | 
    
    | 1246 |  |  | 		m_close(p_pony); | 
    
    | 1247 |  |  | 		return; | 
    
    | 1248 |  |  | 	} | 
    
    | 1249 |  |  |  | 
    
    | 1250 |  |  | 	if (pipe(pipefd) < 0) { | 
    
    | 1251 |  |  | 		(void)snprintf(ebuf, sizeof ebuf, "pipe: %s", strerror(errno)); | 
    
    | 1252 |  |  | 		m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1); | 
    
    | 1253 |  |  | 		m_add_id(p_pony, id); | 
    
    | 1254 |  |  | 		m_add_string(p_pony, ebuf); | 
    
    | 1255 |  |  | 		m_close(p_pony); | 
    
    | 1256 |  |  | 		return; | 
    
    | 1257 |  |  | 	} | 
    
    | 1258 |  |  |  | 
    
    | 1259 |  |  | 	/* prepare file which captures stdout and stderr */ | 
    
    | 1260 |  |  | 	(void)strlcpy(sfn, "/tmp/smtpd.out.XXXXXXXXXXX", sizeof(sfn)); | 
    
    | 1261 |  |  | 	allout = mkstemp(sfn); | 
    
    | 1262 |  |  | 	if (allout < 0) { | 
    
    | 1263 |  |  | 		(void)snprintf(ebuf, sizeof ebuf, "mkstemp: %s", strerror(errno)); | 
    
    | 1264 |  |  | 		m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1); | 
    
    | 1265 |  |  | 		m_add_id(p_pony, id); | 
    
    | 1266 |  |  | 		m_add_string(p_pony, ebuf); | 
    
    | 1267 |  |  | 		m_close(p_pony); | 
    
    | 1268 |  |  | 		close(pipefd[0]); | 
    
    | 1269 |  |  | 		close(pipefd[1]); | 
    
    | 1270 |  |  | 		return; | 
    
    | 1271 |  |  | 	} | 
    
    | 1272 |  |  | 	unlink(sfn); | 
    
    | 1273 |  |  |  | 
    
    | 1274 |  |  | 	pid = fork(); | 
    
    | 1275 |  |  | 	if (pid < 0) { | 
    
    | 1276 |  |  | 		(void)snprintf(ebuf, sizeof ebuf, "fork: %s", strerror(errno)); | 
    
    | 1277 |  |  | 		m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1); | 
    
    | 1278 |  |  | 		m_add_id(p_pony, id); | 
    
    | 1279 |  |  | 		m_add_string(p_pony, ebuf); | 
    
    | 1280 |  |  | 		m_close(p_pony); | 
    
    | 1281 |  |  | 		close(pipefd[0]); | 
    
    | 1282 |  |  | 		close(pipefd[1]); | 
    
    | 1283 |  |  | 		close(allout); | 
    
    | 1284 |  |  | 		return; | 
    
    | 1285 |  |  | 	} | 
    
    | 1286 |  |  |  | 
    
    | 1287 |  |  | 	/* parent passes the child fd over to mda */ | 
    
    | 1288 |  |  | 	if (pid > 0) { | 
    
    | 1289 |  |  | 		child = child_add(pid, CHILD_MDA, NULL); | 
    
    | 1290 |  |  | 		child->mda_out = allout; | 
    
    | 1291 |  |  | 		child->mda_id = id; | 
    
    | 1292 |  |  | 		close(pipefd[0]); | 
    
    | 1293 |  |  | 		m_create(p, IMSG_MDA_FORK, 0, 0, pipefd[1]); | 
    
    | 1294 |  |  | 		m_add_id(p, id); | 
    
    | 1295 |  |  | 		m_close(p); | 
    
    | 1296 |  |  | 		return; | 
    
    | 1297 |  |  | 	} | 
    
    | 1298 |  |  |  | 
    
    | 1299 |  |  | 	if (chdir(deliver->userinfo.directory) < 0 && chdir("/") < 0) | 
    
    | 1300 |  |  | 		err(1, "chdir"); | 
    
    | 1301 |  |  | 	if (setgroups(1, &deliver->userinfo.gid) || | 
    
    | 1302 |  |  | 	    setresgid(deliver->userinfo.gid, deliver->userinfo.gid, deliver->userinfo.gid) || | 
    
    | 1303 |  |  | 	    setresuid(deliver->userinfo.uid, deliver->userinfo.uid, deliver->userinfo.uid)) | 
    
    | 1304 |  |  | 		err(1, "forkmda: cannot drop privileges"); | 
    
    | 1305 |  |  | 	if (dup2(pipefd[0], STDIN_FILENO) < 0 || | 
    
    | 1306 |  |  | 	    dup2(allout, STDOUT_FILENO) < 0 || | 
    
    | 1307 |  |  | 	    dup2(allout, STDERR_FILENO) < 0) | 
    
    | 1308 |  |  | 		err(1, "forkmda: dup2"); | 
    
    | 1309 |  |  | 	if (closefrom(STDERR_FILENO + 1) < 0) | 
    
    | 1310 |  |  | 		err(1, "closefrom"); | 
    
    | 1311 |  |  | 	if (setsid() < 0) | 
    
    | 1312 |  |  | 		err(1, "setsid"); | 
    
    | 1313 |  |  | 	if (signal(SIGPIPE, SIG_DFL) == SIG_ERR || | 
    
    | 1314 |  |  | 	    signal(SIGINT, SIG_DFL) == SIG_ERR || | 
    
    | 1315 |  |  | 	    signal(SIGTERM, SIG_DFL) == SIG_ERR || | 
    
    | 1316 |  |  | 	    signal(SIGCHLD, SIG_DFL) == SIG_ERR || | 
    
    | 1317 |  |  | 	    signal(SIGHUP, SIG_DFL) == SIG_ERR) | 
    
    | 1318 |  |  | 		err(1, "signal"); | 
    
    | 1319 |  |  |  | 
    
    | 1320 |  |  | 	/* avoid hangs by setting 5m timeout */ | 
    
    | 1321 |  |  | 	alarm(300); | 
    
    | 1322 |  |  |  | 
    
    | 1323 |  |  | 	db->open(deliver); | 
    
    | 1324 |  |  | } | 
    
    | 1325 |  |  |  | 
    
    | 1326 |  |  | static void | 
    
    | 1327 |  |  | offline_scan(int fd, short ev, void *arg) | 
    
    | 1328 |  |  | { | 
    
    | 1329 |  |  | 	char		*path_argv[2]; | 
    
    | 1330 |  |  | 	FTS		*fts = arg; | 
    
    | 1331 |  |  | 	FTSENT		*e; | 
    
    | 1332 |  |  | 	int		 n = 0; | 
    
    | 1333 |  |  |  | 
    
    | 1334 |  |  | 	path_argv[0] = PATH_SPOOL PATH_OFFLINE; | 
    
    | 1335 |  |  | 	path_argv[1] = NULL; | 
    
    | 1336 |  |  |  | 
    
    | 1337 |  |  | 	if (fts == NULL) { | 
    
    | 1338 |  |  | 		log_debug("debug: smtpd: scanning offline queue..."); | 
    
    | 1339 |  |  | 		fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL); | 
    
    | 1340 |  |  | 		if (fts == NULL) { | 
    
    | 1341 |  |  | 			log_warn("fts_open: %s", path_argv[0]); | 
    
    | 1342 |  |  | 			return; | 
    
    | 1343 |  |  | 		} | 
    
    | 1344 |  |  | 	} | 
    
    | 1345 |  |  |  | 
    
    | 1346 |  |  | 	while ((e = fts_read(fts)) != NULL) { | 
    
    | 1347 |  |  | 		if (e->fts_info != FTS_F) | 
    
    | 1348 |  |  | 			continue; | 
    
    | 1349 |  |  |  | 
    
    | 1350 |  |  | 		/* offline files must be at depth 1 */ | 
    
    | 1351 |  |  | 		if (e->fts_level != 1) | 
    
    | 1352 |  |  | 			continue; | 
    
    | 1353 |  |  |  | 
    
    | 1354 |  |  | 		/* offline file group must match parent directory group */ | 
    
    | 1355 |  |  | 		if (e->fts_statp->st_gid != e->fts_parent->fts_statp->st_gid) | 
    
    | 1356 |  |  | 			continue; | 
    
    | 1357 |  |  |  | 
    
    | 1358 |  |  | 		if (e->fts_statp->st_size == 0) { | 
    
    | 1359 |  |  | 			if (unlink(e->fts_accpath) == -1) | 
    
    | 1360 |  |  | 				log_warnx("warn: smtpd: could not unlink %s", e->fts_accpath); | 
    
    | 1361 |  |  | 			continue; | 
    
    | 1362 |  |  | 		} | 
    
    | 1363 |  |  |  | 
    
    | 1364 |  |  | 		if (offline_add(e->fts_name)) { | 
    
    | 1365 |  |  | 			log_warnx("warn: smtpd: " | 
    
    | 1366 |  |  | 			    "could not add offline message %s", e->fts_name); | 
    
    | 1367 |  |  | 			continue; | 
    
    | 1368 |  |  | 		} | 
    
    | 1369 |  |  |  | 
    
    | 1370 |  |  | 		if ((n++) == OFFLINE_READMAX) { | 
    
    | 1371 |  |  | 			evtimer_set(&offline_ev, offline_scan, fts); | 
    
    | 1372 |  |  | 			offline_timeout.tv_sec = 0; | 
    
    | 1373 |  |  | 			offline_timeout.tv_usec = 100000; | 
    
    | 1374 |  |  | 			evtimer_add(&offline_ev, &offline_timeout); | 
    
    | 1375 |  |  | 			return; | 
    
    | 1376 |  |  | 		} | 
    
    | 1377 |  |  | 	} | 
    
    | 1378 |  |  |  | 
    
    | 1379 |  |  | 	log_debug("debug: smtpd: offline scanning done"); | 
    
    | 1380 |  |  | 	fts_close(fts); | 
    
    | 1381 |  |  | } | 
    
    | 1382 |  |  |  | 
    
    | 1383 |  |  | static int | 
    
    | 1384 |  |  | offline_enqueue(char *name) | 
    
    | 1385 |  |  | { | 
    
    | 1386 |  |  | 	char		*path; | 
    
    | 1387 |  |  | 	struct stat	 sb; | 
    
    | 1388 |  |  | 	pid_t		 pid; | 
    
    | 1389 |  |  | 	struct child	*child; | 
    
    | 1390 |  |  | 	struct passwd	*pw; | 
    
    | 1391 |  |  | 	int		 pathlen; | 
    
    | 1392 |  |  |  | 
    
    | 1393 |  |  | 	pathlen = asprintf(&path, "%s/%s", PATH_SPOOL PATH_OFFLINE, name); | 
    
    | 1394 |  |  | 	if (pathlen == -1) { | 
    
    | 1395 |  |  | 		log_warnx("warn: smtpd: asprintf"); | 
    
    | 1396 |  |  | 		return (-1); | 
    
    | 1397 |  |  | 	} | 
    
    | 1398 |  |  |  | 
    
    | 1399 |  |  | 	if (pathlen >= PATH_MAX) { | 
    
    | 1400 |  |  | 		log_warnx("warn: smtpd: pathname exceeds PATH_MAX"); | 
    
    | 1401 |  |  | 		free(path); | 
    
    | 1402 |  |  | 		return (-1); | 
    
    | 1403 |  |  | 	} | 
    
    | 1404 |  |  |  | 
    
    | 1405 |  |  | 	log_debug("debug: smtpd: enqueueing offline message %s", path); | 
    
    | 1406 |  |  |  | 
    
    | 1407 |  |  | 	if ((pid = fork()) == -1) { | 
    
    | 1408 |  |  | 		log_warn("warn: smtpd: fork"); | 
    
    | 1409 |  |  | 		free(path); | 
    
    | 1410 |  |  | 		return (-1); | 
    
    | 1411 |  |  | 	} | 
    
    | 1412 |  |  |  | 
    
    | 1413 |  |  | 	if (pid == 0) { | 
    
    | 1414 |  |  | 		char	*envp[2], *p = NULL, *tmp; | 
    
    | 1415 |  |  | 		int	 fd; | 
    
    | 1416 |  |  | 		FILE	*fp; | 
    
    | 1417 |  |  | 		size_t	 sz = 0; | 
    
    | 1418 |  |  | 		ssize_t	 len; | 
    
    | 1419 |  |  | 		arglist	 args; | 
    
    | 1420 |  |  |  | 
    
    | 1421 |  |  | 		if (closefrom(STDERR_FILENO + 1) == -1) | 
    
    | 1422 |  |  | 			_exit(1); | 
    
    | 1423 |  |  |  | 
    
    | 1424 |  |  | 		memset(&args, 0, sizeof(args)); | 
    
    | 1425 |  |  |  | 
    
    | 1426 |  |  | 		if ((fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK)) == -1) { | 
    
    | 1427 |  |  | 			log_warn("warn: smtpd: open: %s", path); | 
    
    | 1428 |  |  | 			_exit(1); | 
    
    | 1429 |  |  | 		} | 
    
    | 1430 |  |  |  | 
    
    | 1431 |  |  | 		if (fstat(fd, &sb) == -1) { | 
    
    | 1432 |  |  | 			log_warn("warn: smtpd: fstat: %s", path); | 
    
    | 1433 |  |  | 			_exit(1); | 
    
    | 1434 |  |  | 		} | 
    
    | 1435 |  |  |  | 
    
    | 1436 |  |  | 		if (!S_ISREG(sb.st_mode)) { | 
    
    | 1437 |  |  | 			log_warnx("warn: smtpd: file %s (uid %d) not regular", | 
    
    | 1438 |  |  | 			    path, sb.st_uid); | 
    
    | 1439 |  |  | 			_exit(1); | 
    
    | 1440 |  |  | 		} | 
    
    | 1441 |  |  |  | 
    
    | 1442 |  |  | 		if (sb.st_nlink != 1) { | 
    
    | 1443 |  |  | 			log_warnx("warn: smtpd: file %s is hard-link", path); | 
    
    | 1444 |  |  | 			_exit(1); | 
    
    | 1445 |  |  | 		} | 
    
    | 1446 |  |  |  | 
    
    | 1447 |  |  | 		pw = getpwuid(sb.st_uid); | 
    
    | 1448 |  |  | 		if (pw == NULL) { | 
    
    | 1449 |  |  | 			log_warnx("warn: smtpd: getpwuid for uid %d failed", | 
    
    | 1450 |  |  | 			    sb.st_uid); | 
    
    | 1451 |  |  | 			_exit(1); | 
    
    | 1452 |  |  | 		} | 
    
    | 1453 |  |  |  | 
    
    | 1454 |  |  | 		if (setgroups(1, &pw->pw_gid) || | 
    
    | 1455 |  |  | 		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || | 
    
    | 1456 |  |  | 		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) | 
    
    | 1457 |  |  | 			_exit(1); | 
    
    | 1458 |  |  |  | 
    
    | 1459 |  |  | 		if ((fp = fdopen(fd, "r")) == NULL) | 
    
    | 1460 |  |  | 			_exit(1); | 
    
    | 1461 |  |  |  | 
    
    | 1462 |  |  | 		if (chdir(pw->pw_dir) == -1 && chdir("/") == -1) | 
    
    | 1463 |  |  | 			_exit(1); | 
    
    | 1464 |  |  |  | 
    
    | 1465 |  |  | 		if (setsid() == -1 || | 
    
    | 1466 |  |  | 		    signal(SIGPIPE, SIG_DFL) == SIG_ERR || | 
    
    | 1467 |  |  | 		    dup2(fileno(fp), STDIN_FILENO) == -1) | 
    
    | 1468 |  |  | 			_exit(1); | 
    
    | 1469 |  |  |  | 
    
    | 1470 |  |  | 		if ((len = getline(&p, &sz, fp)) == -1) | 
    
    | 1471 |  |  | 			_exit(1); | 
    
    | 1472 |  |  |  | 
    
    | 1473 |  |  | 		if (p[len - 1] != '\n') | 
    
    | 1474 |  |  | 			_exit(1); | 
    
    | 1475 |  |  | 		p[len - 1] = '\0'; | 
    
    | 1476 |  |  |  | 
    
    | 1477 |  |  | 		addargs(&args, "%s", "sendmail"); | 
    
    | 1478 |  |  | 		addargs(&args, "%s", "-S"); | 
    
    | 1479 |  |  |  | 
    
    | 1480 |  |  | 		while ((tmp = strsep(&p, "|")) != NULL) | 
    
    | 1481 |  |  | 			addargs(&args, "%s", tmp); | 
    
    | 1482 |  |  |  | 
    
    | 1483 |  |  | 		free(p); | 
    
    | 1484 |  |  | 		if (lseek(fileno(fp), len, SEEK_SET) == -1) | 
    
    | 1485 |  |  | 			_exit(1); | 
    
    | 1486 |  |  |  | 
    
    | 1487 |  |  | 		envp[0] = "PATH=" _PATH_DEFPATH; | 
    
    | 1488 |  |  | 		envp[1] = (char *)NULL; | 
    
    | 1489 |  |  | 		environ = envp; | 
    
    | 1490 |  |  |  | 
    
    | 1491 |  |  | 		execvp(PATH_SMTPCTL, args.list); | 
    
    | 1492 |  |  | 		_exit(1); | 
    
    | 1493 |  |  | 	} | 
    
    | 1494 |  |  |  | 
    
    | 1495 |  |  | 	offline_running++; | 
    
    | 1496 |  |  | 	child = child_add(pid, CHILD_ENQUEUE_OFFLINE, NULL); | 
    
    | 1497 |  |  | 	child->path = path; | 
    
    | 1498 |  |  |  | 
    
    | 1499 |  |  | 	return (0); | 
    
    | 1500 |  |  | } | 
    
    | 1501 |  |  |  | 
    
    | 1502 |  |  | static int | 
    
    | 1503 |  |  | offline_add(char *path) | 
    
    | 1504 |  |  | { | 
    
    | 1505 |  |  | 	struct offline	*q; | 
    
    | 1506 |  |  |  | 
    
    | 1507 |  |  | 	if (offline_running < OFFLINE_QUEUEMAX) | 
    
    | 1508 |  |  | 		/* skip queue */ | 
    
    | 1509 |  |  | 		return offline_enqueue(path); | 
    
    | 1510 |  |  |  | 
    
    | 1511 |  |  | 	q = malloc(sizeof(*q) + strlen(path) + 1); | 
    
    | 1512 |  |  | 	if (q == NULL) | 
    
    | 1513 |  |  | 		return (-1); | 
    
    | 1514 |  |  | 	q->path = (char *)q + sizeof(*q); | 
    
    | 1515 |  |  | 	memmove(q->path, path, strlen(path) + 1); | 
    
    | 1516 |  |  | 	TAILQ_INSERT_TAIL(&offline_q, q, entry); | 
    
    | 1517 |  |  |  | 
    
    | 1518 |  |  | 	return (0); | 
    
    | 1519 |  |  | } | 
    
    | 1520 |  |  |  | 
    
    | 1521 |  |  | static void | 
    
    | 1522 |  |  | offline_done(void) | 
    
    | 1523 |  |  | { | 
    
    | 1524 |  |  | 	struct offline	*q; | 
    
    | 1525 |  |  |  | 
    
    | 1526 |  |  | 	offline_running--; | 
    
    | 1527 |  |  |  | 
    
    | 1528 |  |  | 	while (offline_running < OFFLINE_QUEUEMAX) { | 
    
    | 1529 |  |  | 		if ((q = TAILQ_FIRST(&offline_q)) == NULL) | 
    
    | 1530 |  |  | 			break; /* all done */ | 
    
    | 1531 |  |  | 		TAILQ_REMOVE(&offline_q, q, entry); | 
    
    | 1532 |  |  | 		offline_enqueue(q->path); | 
    
    | 1533 |  |  | 		free(q); | 
    
    | 1534 |  |  | 	} | 
    
    | 1535 |  |  | } | 
    
    | 1536 |  |  |  | 
    
    | 1537 |  |  | static int | 
    
    | 1538 |  |  | parent_forward_open(char *username, char *directory, uid_t uid, gid_t gid) | 
    
    | 1539 |  |  | { | 
    
    | 1540 |  |  | 	char		pathname[PATH_MAX]; | 
    
    | 1541 |  |  | 	int		fd; | 
    
    | 1542 |  |  | 	struct stat	sb; | 
    
    | 1543 |  |  |  | 
    
    | 1544 |  |  | 	if (!bsnprintf(pathname, sizeof (pathname), "%s/.forward", | 
    
    | 1545 |  |  | 		directory)) { | 
    
    | 1546 |  |  | 		log_warnx("warn: smtpd: %s: pathname too large", pathname); | 
    
    | 1547 |  |  | 		return -1; | 
    
    | 1548 |  |  | 	} | 
    
    | 1549 |  |  |  | 
    
    | 1550 |  |  | 	if (stat(directory, &sb) < 0) { | 
    
    | 1551 |  |  | 		log_warn("warn: smtpd: parent_forward_open: %s", directory); | 
    
    | 1552 |  |  | 		return -1; | 
    
    | 1553 |  |  | 	} | 
    
    | 1554 |  |  | 	if (sb.st_mode & S_ISVTX) { | 
    
    | 1555 |  |  | 		log_warnx("warn: smtpd: parent_forward_open: %s is sticky", | 
    
    | 1556 |  |  | 		    directory); | 
    
    | 1557 |  |  | 		errno = EAGAIN; | 
    
    | 1558 |  |  | 		return -1; | 
    
    | 1559 |  |  | 	} | 
    
    | 1560 |  |  |  | 
    
    | 1561 |  |  | 	do { | 
    
    | 1562 |  |  | 		fd = open(pathname, O_RDONLY|O_NOFOLLOW|O_NONBLOCK); | 
    
    | 1563 |  |  | 	} while (fd == -1 && errno == EINTR); | 
    
    | 1564 |  |  | 	if (fd == -1) { | 
    
    | 1565 |  |  | 		if (errno == ENOENT) | 
    
    | 1566 |  |  | 			return -1; | 
    
    | 1567 |  |  | 		if (errno == EMFILE || errno == ENFILE || errno == EIO) { | 
    
    | 1568 |  |  | 			errno = EAGAIN; | 
    
    | 1569 |  |  | 			return -1; | 
    
    | 1570 |  |  | 		} | 
    
    | 1571 |  |  | 		if (errno == ELOOP) | 
    
    | 1572 |  |  | 			log_warnx("warn: smtpd: parent_forward_open: %s: " | 
    
    | 1573 |  |  | 			    "cannot follow symbolic links", pathname); | 
    
    | 1574 |  |  | 		else | 
    
    | 1575 |  |  | 			log_warn("warn: smtpd: parent_forward_open: %s", pathname); | 
    
    | 1576 |  |  | 		return -1; | 
    
    | 1577 |  |  | 	} | 
    
    | 1578 |  |  |  | 
    
    | 1579 |  |  | 	if (!secure_file(fd, pathname, directory, uid, 1)) { | 
    
    | 1580 |  |  | 		log_warnx("warn: smtpd: %s: unsecure file", pathname); | 
    
    | 1581 |  |  | 		close(fd); | 
    
    | 1582 |  |  | 		return -1; | 
    
    | 1583 |  |  | 	} | 
    
    | 1584 |  |  |  | 
    
    | 1585 |  |  | 	return fd; | 
    
    | 1586 |  |  | } | 
    
    | 1587 |  |  |  | 
    
    | 1588 |  |  | void | 
    
    | 1589 |  |  | imsg_dispatch(struct mproc *p, struct imsg *imsg) | 
    
    | 1590 |  |  | { | 
    
    | 1591 |  |  | 	struct timespec	t0, t1, dt; | 
    
    | 1592 |  |  | 	int		msg; | 
    
    | 1593 |  |  |  | 
    
    | 1594 |  |  | 	if (imsg == NULL) { | 
    
    | 1595 |  |  | 		imsg_callback(p, imsg); | 
    
    | 1596 |  |  | 		return; | 
    
    | 1597 |  |  | 	} | 
    
    | 1598 |  |  |  | 
    
    | 1599 |  |  | 	log_imsg(smtpd_process, p->proc, imsg); | 
    
    | 1600 |  |  |  | 
    
    | 1601 |  |  | 	if (profiling & PROFILE_IMSG) | 
    
    | 1602 |  |  | 		clock_gettime(CLOCK_MONOTONIC, &t0); | 
    
    | 1603 |  |  |  | 
    
    | 1604 |  |  | 	msg = imsg->hdr.type; | 
    
    | 1605 |  |  | 	imsg_callback(p, imsg); | 
    
    | 1606 |  |  |  | 
    
    | 1607 |  |  | 	if (profiling & PROFILE_IMSG) { | 
    
    | 1608 |  |  | 		clock_gettime(CLOCK_MONOTONIC, &t1); | 
    
    | 1609 |  |  | 		timespecsub(&t1, &t0, &dt); | 
    
    | 1610 |  |  |  | 
    
    | 1611 |  |  | 		log_debug("profile-imsg: %s %s %s %d %lld.%09ld", | 
    
    | 1612 |  |  | 		    proc_name(smtpd_process), | 
    
    | 1613 |  |  | 		    proc_name(p->proc), | 
    
    | 1614 |  |  | 		    imsg_to_str(msg), | 
    
    | 1615 |  |  | 		    (int)imsg->hdr.len, | 
    
    | 1616 |  |  | 		    (long long)dt.tv_sec, | 
    
    | 1617 |  |  | 		    dt.tv_nsec); | 
    
    | 1618 |  |  |  | 
    
    | 1619 |  |  | 		if (profiling & PROFILE_TOSTAT) { | 
    
    | 1620 |  |  | 			char	key[STAT_KEY_SIZE]; | 
    
    | 1621 |  |  | 			/* can't profstat control process yet */ | 
    
    | 1622 |  |  | 			if (smtpd_process == PROC_CONTROL) | 
    
    | 1623 |  |  | 				return; | 
    
    | 1624 |  |  |  | 
    
    | 1625 |  |  | 			if (!bsnprintf(key, sizeof key, | 
    
    | 1626 |  |  | 				"profiling.imsg.%s.%s.%s", | 
    
    | 1627 |  |  | 				proc_name(smtpd_process), | 
    
    | 1628 |  |  | 				proc_name(p->proc), | 
    
    | 1629 |  |  | 				imsg_to_str(msg))) | 
    
    | 1630 |  |  | 				return; | 
    
    | 1631 |  |  | 			stat_set(key, stat_timespec(&dt)); | 
    
    | 1632 |  |  | 		} | 
    
    | 1633 |  |  | 	} | 
    
    | 1634 |  |  | } | 
    
    | 1635 |  |  |  | 
    
    | 1636 |  |  | void | 
    
    | 1637 |  |  | log_imsg(int to, int from, struct imsg *imsg) | 
    
    | 1638 |  |  | { | 
    
    | 1639 |  |  |  | 
    
    | 1640 |  |  | 	if (to == PROC_CONTROL && imsg->hdr.type == IMSG_STAT_SET) | 
    
    | 1641 |  |  | 		return; | 
    
    | 1642 |  |  |  | 
    
    | 1643 |  |  | 	if (imsg->fd != -1) | 
    
    | 1644 |  |  | 		log_trace(TRACE_IMSG, "imsg: %s <- %s: %s (len=%zu, fd=%d)", | 
    
    | 1645 |  |  | 		    proc_name(to), | 
    
    | 1646 |  |  | 		    proc_name(from), | 
    
    | 1647 |  |  | 		    imsg_to_str(imsg->hdr.type), | 
    
    | 1648 |  |  | 		    imsg->hdr.len - IMSG_HEADER_SIZE, | 
    
    | 1649 |  |  | 		    imsg->fd); | 
    
    | 1650 |  |  | 	else | 
    
    | 1651 |  |  | 		log_trace(TRACE_IMSG, "imsg: %s <- %s: %s (len=%zu)", | 
    
    | 1652 |  |  | 		    proc_name(to), | 
    
    | 1653 |  |  | 		    proc_name(from), | 
    
    | 1654 |  |  | 		    imsg_to_str(imsg->hdr.type), | 
    
    | 1655 |  |  | 		    imsg->hdr.len - IMSG_HEADER_SIZE); | 
    
    | 1656 |  |  | } | 
    
    | 1657 |  |  |  | 
    
    | 1658 |  |  | const char * | 
    
    | 1659 |  |  | proc_title(enum smtp_proc_type proc) | 
    
    | 1660 |  |  | { | 
    
    | 1661 |  |  | 	switch (proc) { | 
    
    | 1662 |  |  | 	case PROC_PARENT: | 
    
    | 1663 |  |  | 		return "[priv]"; | 
    
    | 1664 |  |  | 	case PROC_LKA: | 
    
    | 1665 |  |  | 		return "lookup"; | 
    
    | 1666 |  |  | 	case PROC_QUEUE: | 
    
    | 1667 |  |  | 		return "queue"; | 
    
    | 1668 |  |  | 	case PROC_CONTROL: | 
    
    | 1669 |  |  | 		return "control"; | 
    
    | 1670 |  |  | 	case PROC_SCHEDULER: | 
    
    | 1671 |  |  | 		return "scheduler"; | 
    
    | 1672 |  |  | 	case PROC_PONY: | 
    
    | 1673 |  |  | 		return "pony express"; | 
    
    | 1674 |  |  | 	case PROC_CA: | 
    
    | 1675 |  |  | 		return "klondike"; | 
    
    | 1676 |  |  | 	default: | 
    
    | 1677 |  |  | 		return "unknown"; | 
    
    | 1678 |  |  | 	} | 
    
    | 1679 |  |  | } | 
    
    | 1680 |  |  |  | 
    
    | 1681 |  |  | const char * | 
    
    | 1682 |  |  | proc_name(enum smtp_proc_type proc) | 
    
    | 1683 |  |  | { | 
    
    | 1684 |  |  | 	switch (proc) { | 
    
    | 1685 |  |  | 	case PROC_PARENT: | 
    
    | 1686 |  |  | 		return "parent"; | 
    
    | 1687 |  |  | 	case PROC_LKA: | 
    
    | 1688 |  |  | 		return "lka"; | 
    
    | 1689 |  |  | 	case PROC_QUEUE: | 
    
    | 1690 |  |  | 		return "queue"; | 
    
    | 1691 |  |  | 	case PROC_CONTROL: | 
    
    | 1692 |  |  | 		return "control"; | 
    
    | 1693 |  |  | 	case PROC_SCHEDULER: | 
    
    | 1694 |  |  | 		return "scheduler"; | 
    
    | 1695 |  |  | 	case PROC_PONY: | 
    
    | 1696 |  |  | 		return "pony"; | 
    
    | 1697 |  |  | 	case PROC_CA: | 
    
    | 1698 |  |  | 		return "ca"; | 
    
    | 1699 |  |  | 	case PROC_CLIENT: | 
    
    | 1700 |  |  | 		return "client-proc"; | 
    
    | 1701 |  |  | 	default: | 
    
    | 1702 |  |  | 		return "unknown"; | 
    
    | 1703 |  |  | 	} | 
    
    | 1704 |  |  | } | 
    
    | 1705 |  |  |  | 
    
    | 1706 |  |  | #define CASE(x) case x : return #x | 
    
    | 1707 |  |  |  | 
    
    | 1708 |  |  | const char * | 
    
    | 1709 |  |  | imsg_to_str(int type) | 
    
    | 1710 |  |  | { | 
    
    | 1711 |  |  | 	static char	 buf[32]; | 
    
    | 1712 |  |  |  | 
    
    | 1713 |  |  | 	switch (type) { | 
    
    | 1714 |  |  | 	CASE(IMSG_NONE); | 
    
    | 1715 |  |  |  | 
    
    | 1716 |  |  | 	CASE(IMSG_CTL_OK); | 
    
    | 1717 |  |  | 	CASE(IMSG_CTL_FAIL); | 
    
    | 1718 |  |  |  | 
    
    | 1719 |  |  | 	CASE(IMSG_CTL_GET_DIGEST); | 
    
    | 1720 |  |  | 	CASE(IMSG_CTL_GET_STATS); | 
    
    | 1721 |  |  | 	CASE(IMSG_CTL_LIST_MESSAGES); | 
    
    | 1722 |  |  | 	CASE(IMSG_CTL_LIST_ENVELOPES); | 
    
    | 1723 |  |  | 	CASE(IMSG_CTL_MTA_SHOW_HOSTS); | 
    
    | 1724 |  |  | 	CASE(IMSG_CTL_MTA_SHOW_RELAYS); | 
    
    | 1725 |  |  | 	CASE(IMSG_CTL_MTA_SHOW_ROUTES); | 
    
    | 1726 |  |  | 	CASE(IMSG_CTL_MTA_SHOW_HOSTSTATS); | 
    
    | 1727 |  |  | 	CASE(IMSG_CTL_MTA_BLOCK); | 
    
    | 1728 |  |  | 	CASE(IMSG_CTL_MTA_UNBLOCK); | 
    
    | 1729 |  |  | 	CASE(IMSG_CTL_MTA_SHOW_BLOCK); | 
    
    | 1730 |  |  | 	CASE(IMSG_CTL_PAUSE_EVP); | 
    
    | 1731 |  |  | 	CASE(IMSG_CTL_PAUSE_MDA); | 
    
    | 1732 |  |  | 	CASE(IMSG_CTL_PAUSE_MTA); | 
    
    | 1733 |  |  | 	CASE(IMSG_CTL_PAUSE_SMTP); | 
    
    | 1734 |  |  | 	CASE(IMSG_CTL_PROFILE); | 
    
    | 1735 |  |  | 	CASE(IMSG_CTL_PROFILE_DISABLE); | 
    
    | 1736 |  |  | 	CASE(IMSG_CTL_PROFILE_ENABLE); | 
    
    | 1737 |  |  | 	CASE(IMSG_CTL_RESUME_EVP); | 
    
    | 1738 |  |  | 	CASE(IMSG_CTL_RESUME_MDA); | 
    
    | 1739 |  |  | 	CASE(IMSG_CTL_RESUME_MTA); | 
    
    | 1740 |  |  | 	CASE(IMSG_CTL_RESUME_SMTP); | 
    
    | 1741 |  |  | 	CASE(IMSG_CTL_RESUME_ROUTE); | 
    
    | 1742 |  |  | 	CASE(IMSG_CTL_REMOVE); | 
    
    | 1743 |  |  | 	CASE(IMSG_CTL_SCHEDULE); | 
    
    | 1744 |  |  | 	CASE(IMSG_CTL_SHOW_STATUS); | 
    
    | 1745 |  |  | 	CASE(IMSG_CTL_TRACE_DISABLE); | 
    
    | 1746 |  |  | 	CASE(IMSG_CTL_TRACE_ENABLE); | 
    
    | 1747 |  |  | 	CASE(IMSG_CTL_UPDATE_TABLE); | 
    
    | 1748 |  |  | 	CASE(IMSG_CTL_VERBOSE); | 
    
    | 1749 |  |  | 	CASE(IMSG_CTL_DISCOVER_EVPID); | 
    
    | 1750 |  |  | 	CASE(IMSG_CTL_DISCOVER_MSGID); | 
    
    | 1751 |  |  | 	CASE(IMSG_CTL_UNCORRUPT_MSGID); | 
    
    | 1752 |  |  |  | 
    
    | 1753 |  |  | 	CASE(IMSG_CTL_SMTP_SESSION); | 
    
    | 1754 |  |  |  | 
    
    | 1755 |  |  | 	CASE(IMSG_SETUP_KEY); | 
    
    | 1756 |  |  | 	CASE(IMSG_SETUP_PEER); | 
    
    | 1757 |  |  | 	CASE(IMSG_SETUP_DONE); | 
    
    | 1758 |  |  |  | 
    
    | 1759 |  |  | 	CASE(IMSG_CONF_START); | 
    
    | 1760 |  |  | 	CASE(IMSG_CONF_END); | 
    
    | 1761 |  |  |  | 
    
    | 1762 |  |  | 	CASE(IMSG_STAT_INCREMENT); | 
    
    | 1763 |  |  | 	CASE(IMSG_STAT_DECREMENT); | 
    
    | 1764 |  |  | 	CASE(IMSG_STAT_SET); | 
    
    | 1765 |  |  |  | 
    
    | 1766 |  |  | 	CASE(IMSG_LKA_AUTHENTICATE); | 
    
    | 1767 |  |  | 	CASE(IMSG_LKA_OPEN_FORWARD); | 
    
    | 1768 |  |  | 	CASE(IMSG_LKA_ENVELOPE_SUBMIT); | 
    
    | 1769 |  |  | 	CASE(IMSG_LKA_ENVELOPE_COMMIT); | 
    
    | 1770 |  |  |  | 
    
    | 1771 |  |  | 	CASE(IMSG_QUEUE_DELIVER); | 
    
    | 1772 |  |  | 	CASE(IMSG_QUEUE_DELIVERY_OK); | 
    
    | 1773 |  |  | 	CASE(IMSG_QUEUE_DELIVERY_TEMPFAIL); | 
    
    | 1774 |  |  | 	CASE(IMSG_QUEUE_DELIVERY_PERMFAIL); | 
    
    | 1775 |  |  | 	CASE(IMSG_QUEUE_DELIVERY_LOOP); | 
    
    | 1776 |  |  | 	CASE(IMSG_QUEUE_DISCOVER_EVPID); | 
    
    | 1777 |  |  | 	CASE(IMSG_QUEUE_DISCOVER_MSGID); | 
    
    | 1778 |  |  | 	CASE(IMSG_QUEUE_ENVELOPE_ACK); | 
    
    | 1779 |  |  | 	CASE(IMSG_QUEUE_ENVELOPE_COMMIT); | 
    
    | 1780 |  |  | 	CASE(IMSG_QUEUE_ENVELOPE_REMOVE); | 
    
    | 1781 |  |  | 	CASE(IMSG_QUEUE_ENVELOPE_SCHEDULE); | 
    
    | 1782 |  |  | 	CASE(IMSG_QUEUE_ENVELOPE_SUBMIT); | 
    
    | 1783 |  |  | 	CASE(IMSG_QUEUE_HOLDQ_HOLD); | 
    
    | 1784 |  |  | 	CASE(IMSG_QUEUE_HOLDQ_RELEASE); | 
    
    | 1785 |  |  | 	CASE(IMSG_QUEUE_MESSAGE_COMMIT); | 
    
    | 1786 |  |  | 	CASE(IMSG_QUEUE_MESSAGE_ROLLBACK); | 
    
    | 1787 |  |  | 	CASE(IMSG_QUEUE_SMTP_SESSION); | 
    
    | 1788 |  |  | 	CASE(IMSG_QUEUE_TRANSFER); | 
    
    | 1789 |  |  |  | 
    
    | 1790 |  |  | 	CASE(IMSG_MDA_DELIVERY_OK); | 
    
    | 1791 |  |  | 	CASE(IMSG_MDA_DELIVERY_TEMPFAIL); | 
    
    | 1792 |  |  | 	CASE(IMSG_MDA_DELIVERY_PERMFAIL); | 
    
    | 1793 |  |  | 	CASE(IMSG_MDA_DELIVERY_LOOP); | 
    
    | 1794 |  |  | 	CASE(IMSG_MDA_DELIVERY_HOLD); | 
    
    | 1795 |  |  | 	CASE(IMSG_MDA_DONE); | 
    
    | 1796 |  |  | 	CASE(IMSG_MDA_FORK); | 
    
    | 1797 |  |  | 	CASE(IMSG_MDA_HOLDQ_RELEASE); | 
    
    | 1798 |  |  | 	CASE(IMSG_MDA_LOOKUP_USERINFO); | 
    
    | 1799 |  |  | 	CASE(IMSG_MDA_KILL); | 
    
    | 1800 |  |  | 	CASE(IMSG_MDA_OPEN_MESSAGE); | 
    
    | 1801 |  |  |  | 
    
    | 1802 |  |  | 	CASE(IMSG_MTA_DELIVERY_OK); | 
    
    | 1803 |  |  | 	CASE(IMSG_MTA_DELIVERY_TEMPFAIL); | 
    
    | 1804 |  |  | 	CASE(IMSG_MTA_DELIVERY_PERMFAIL); | 
    
    | 1805 |  |  | 	CASE(IMSG_MTA_DELIVERY_LOOP); | 
    
    | 1806 |  |  | 	CASE(IMSG_MTA_DELIVERY_HOLD); | 
    
    | 1807 |  |  | 	CASE(IMSG_MTA_DNS_HOST); | 
    
    | 1808 |  |  | 	CASE(IMSG_MTA_DNS_HOST_END); | 
    
    | 1809 |  |  | 	CASE(IMSG_MTA_DNS_PTR); | 
    
    | 1810 |  |  | 	CASE(IMSG_MTA_DNS_MX); | 
    
    | 1811 |  |  | 	CASE(IMSG_MTA_DNS_MX_PREFERENCE); | 
    
    | 1812 |  |  | 	CASE(IMSG_MTA_HOLDQ_RELEASE); | 
    
    | 1813 |  |  | 	CASE(IMSG_MTA_LOOKUP_CREDENTIALS); | 
    
    | 1814 |  |  | 	CASE(IMSG_MTA_LOOKUP_SOURCE); | 
    
    | 1815 |  |  | 	CASE(IMSG_MTA_LOOKUP_HELO); | 
    
    | 1816 |  |  | 	CASE(IMSG_MTA_OPEN_MESSAGE); | 
    
    | 1817 |  |  | 	CASE(IMSG_MTA_SCHEDULE); | 
    
    | 1818 |  |  | 	CASE(IMSG_MTA_TLS_INIT); | 
    
    | 1819 |  |  | 	CASE(IMSG_MTA_TLS_VERIFY_CERT); | 
    
    | 1820 |  |  | 	CASE(IMSG_MTA_TLS_VERIFY_CHAIN); | 
    
    | 1821 |  |  | 	CASE(IMSG_MTA_TLS_VERIFY); | 
    
    | 1822 |  |  |  | 
    
    | 1823 |  |  | 	CASE(IMSG_SCHED_ENVELOPE_BOUNCE); | 
    
    | 1824 |  |  | 	CASE(IMSG_SCHED_ENVELOPE_DELIVER); | 
    
    | 1825 |  |  | 	CASE(IMSG_SCHED_ENVELOPE_EXPIRE); | 
    
    | 1826 |  |  | 	CASE(IMSG_SCHED_ENVELOPE_INJECT); | 
    
    | 1827 |  |  | 	CASE(IMSG_SCHED_ENVELOPE_REMOVE); | 
    
    | 1828 |  |  | 	CASE(IMSG_SCHED_ENVELOPE_TRANSFER); | 
    
    | 1829 |  |  |  | 
    
    | 1830 |  |  | 	CASE(IMSG_SMTP_AUTHENTICATE); | 
    
    | 1831 |  |  | 	CASE(IMSG_SMTP_DNS_PTR); | 
    
    | 1832 |  |  | 	CASE(IMSG_SMTP_MESSAGE_COMMIT); | 
    
    | 1833 |  |  | 	CASE(IMSG_SMTP_MESSAGE_CREATE); | 
    
    | 1834 |  |  | 	CASE(IMSG_SMTP_MESSAGE_ROLLBACK); | 
    
    | 1835 |  |  | 	CASE(IMSG_SMTP_MESSAGE_OPEN); | 
    
    | 1836 |  |  | 	CASE(IMSG_SMTP_CHECK_SENDER); | 
    
    | 1837 |  |  | 	CASE(IMSG_SMTP_EXPAND_RCPT); | 
    
    | 1838 |  |  | 	CASE(IMSG_SMTP_LOOKUP_HELO); | 
    
    | 1839 |  |  | 	CASE(IMSG_SMTP_TLS_INIT); | 
    
    | 1840 |  |  | 	CASE(IMSG_SMTP_TLS_VERIFY_CERT); | 
    
    | 1841 |  |  | 	CASE(IMSG_SMTP_TLS_VERIFY_CHAIN); | 
    
    | 1842 |  |  | 	CASE(IMSG_SMTP_TLS_VERIFY); | 
    
    | 1843 |  |  |  | 
    
    | 1844 |  |  | 	CASE(IMSG_SMTP_REQ_CONNECT); | 
    
    | 1845 |  |  | 	CASE(IMSG_SMTP_REQ_HELO); | 
    
    | 1846 |  |  | 	CASE(IMSG_SMTP_REQ_MAIL); | 
    
    | 1847 |  |  | 	CASE(IMSG_SMTP_REQ_RCPT); | 
    
    | 1848 |  |  | 	CASE(IMSG_SMTP_REQ_DATA); | 
    
    | 1849 |  |  | 	CASE(IMSG_SMTP_REQ_EOM); | 
    
    | 1850 |  |  | 	CASE(IMSG_SMTP_EVENT_RSET); | 
    
    | 1851 |  |  | 	CASE(IMSG_SMTP_EVENT_COMMIT); | 
    
    | 1852 |  |  | 	CASE(IMSG_SMTP_EVENT_ROLLBACK); | 
    
    | 1853 |  |  | 	CASE(IMSG_SMTP_EVENT_DISCONNECT); | 
    
    | 1854 |  |  |  | 
    
    | 1855 |  |  | 	CASE(IMSG_CA_PRIVENC); | 
    
    | 1856 |  |  | 	CASE(IMSG_CA_PRIVDEC); | 
    
    | 1857 |  |  | 	default: | 
    
    | 1858 |  |  | 		(void)snprintf(buf, sizeof(buf), "IMSG_??? (%d)", type); | 
    
    | 1859 |  |  |  | 
    
    | 1860 |  |  | 		return buf; | 
    
    | 1861 |  |  | 	} | 
    
    | 1862 |  |  | } | 
    
    | 1863 |  |  |  | 
    
    | 1864 |  |  | int | 
    
    | 1865 |  |  | parent_auth_user(const char *username, const char *password) | 
    
    | 1866 |  |  | { | 
    
    | 1867 |  |  | 	char	user[LOGIN_NAME_MAX]; | 
    
    | 1868 |  |  | 	char	pass[LINE_MAX]; | 
    
    | 1869 |  |  | 	int	ret; | 
    
    | 1870 |  |  |  | 
    
    | 1871 |  |  | 	(void)strlcpy(user, username, sizeof(user)); | 
    
    | 1872 |  |  | 	(void)strlcpy(pass, password, sizeof(pass)); | 
    
    | 1873 |  |  |  | 
    
    | 1874 |  |  | 	ret = auth_userokay(user, NULL, "auth-smtp", pass); | 
    
    | 1875 |  |  | 	if (ret) | 
    
    | 1876 |  |  | 		return LKA_OK; | 
    
    | 1877 |  |  | 	return LKA_PERMFAIL; | 
    
    | 1878 |  |  | } |