xref: /openbsd/usr.sbin/smtpd/config.c (revision a6445c1d)
1 /*	$OpenBSD: config.c,v 1.31 2014/05/01 15:50:20 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/tree.h>
22 #include <sys/socket.h>
23 #include <sys/resource.h>
24 
25 #include <event.h>
26 #include <imsg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 #include <openssl/ssl.h>
33 
34 #include "smtpd.h"
35 #include "log.h"
36 #include "ssl.h"
37 
38 extern int profiling;
39 
40 static int pipes[PROC_COUNT][PROC_COUNT];
41 
42 void
43 purge_config(uint8_t what)
44 {
45 	struct listener	*l;
46 	struct table	*t;
47 	struct rule	*r;
48 	struct pki	*p;
49 	const char	*k;
50 	void		*iter_dict;
51 
52 	if (what & PURGE_LISTENERS) {
53 		while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) {
54 			TAILQ_REMOVE(env->sc_listeners, l, entry);
55 			free(l);
56 		}
57 		free(env->sc_listeners);
58 		env->sc_listeners = NULL;
59 	}
60 	if (what & PURGE_TABLES) {
61 		while (dict_root(env->sc_tables_dict, NULL, (void **)&t))
62 			table_destroy(t);
63 		free(env->sc_tables_dict);
64 		env->sc_tables_dict = NULL;
65 	}
66 	if (what & PURGE_RULES) {
67 		while ((r = TAILQ_FIRST(env->sc_rules)) != NULL) {
68 			TAILQ_REMOVE(env->sc_rules, r, r_entry);
69 			free(r);
70 		}
71 		free(env->sc_rules);
72 		env->sc_rules = NULL;
73 	}
74 	if (what & PURGE_PKI) {
75 		while (dict_poproot(env->sc_pki_dict, (void **)&p)) {
76 			explicit_bzero(p->pki_cert, p->pki_cert_len);
77 			free(p->pki_cert);
78 			if (p->pki_key) {
79 				explicit_bzero(p->pki_key, p->pki_key_len);
80 				free(p->pki_key);
81 			}
82 			if (p->pki_pkey)
83 				EVP_PKEY_free(p->pki_pkey);
84 			free(p);
85 		}
86 		free(env->sc_pki_dict);
87 		env->sc_pki_dict = NULL;
88 	} else if (what & PURGE_PKI_KEYS) {
89 		iter_dict = NULL;
90 		while (dict_iter(env->sc_pki_dict, &iter_dict, &k,
91 		    (void **)&p)) {
92 			explicit_bzero(p->pki_cert, p->pki_cert_len);
93 			free(p->pki_cert);
94 			p->pki_cert = NULL;
95 			if (p->pki_key) {
96 				explicit_bzero(p->pki_key, p->pki_key_len);
97 				free(p->pki_key);
98 				p->pki_key = NULL;
99 			}
100 			if (p->pki_pkey)
101 				EVP_PKEY_free(p->pki_pkey);
102 			p->pki_pkey = NULL;
103 		}
104 	}
105 }
106 
107 void
108 init_pipes(void)
109 {
110 	int	 i, j, sockpair[2];
111 
112 	for (i = 0; i < PROC_COUNT; i++)
113 		for (j = i + 1; j < PROC_COUNT; j++) {
114 			if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
115 			    sockpair) == -1)
116 				fatal("socketpair");
117 			pipes[i][j] = sockpair[0];
118 			pipes[j][i] = sockpair[1];
119 			session_socket_blockmode(pipes[i][j], BM_NONBLOCK);
120 			session_socket_blockmode(pipes[j][i], BM_NONBLOCK);
121 		}
122 }
123 
124 void
125 config_process(enum smtp_proc_type proc)
126 {
127 	struct rlimit rl;
128 
129 	smtpd_process = proc;
130 	setproctitle("%s", proc_title(proc));
131 
132 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
133 		fatal("fdlimit: getrlimit");
134 	rl.rlim_cur = rl.rlim_max;
135 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
136 		fatal("fdlimit: setrlimit");
137 }
138 
139 void
140 config_peer(enum smtp_proc_type proc)
141 {
142 	struct mproc	*p;
143 
144 	if (proc == smtpd_process)
145 		fatal("config_peers: cannot peer with oneself");
146 
147 	p = xcalloc(1, sizeof *p, "config_peer");
148 	p->proc = proc;
149 	p->name = xstrdup(proc_name(proc), "config_peer");
150 	p->handler = imsg_dispatch;
151 
152 	mproc_init(p, pipes[smtpd_process][proc]);
153 	mproc_enable(p);
154 	pipes[smtpd_process][proc] = -1;
155 
156 	if (proc == PROC_CONTROL)
157 		p_control = p;
158 	else if (proc == PROC_LKA)
159 		p_lka = p;
160 	else if (proc == PROC_PARENT)
161 		p_parent = p;
162 	else if (proc == PROC_QUEUE)
163 		p_queue = p;
164 	else if (proc == PROC_SCHEDULER)
165 		p_scheduler = p;
166 	else if (proc == PROC_PONY)
167 		p_pony = p;
168 	else if (proc == PROC_CA)
169 		p_ca = p;
170 	else
171 		fatalx("bad peer");
172 }
173 
174 static void process_stat_event(int, short, void *);
175 
176 void
177 config_done(void)
178 {
179 	static struct event	ev;
180 	struct timeval		tv;
181 	unsigned int		i, j;
182 
183 	for (i = 0; i < PROC_COUNT; i++) {
184 		for (j = 0; j < PROC_COUNT; j++) {
185 			if (i == j || pipes[i][j] == -1)
186 				continue;
187 			close(pipes[i][j]);
188 			pipes[i][j] = -1;
189 		}
190 	}
191 
192 	if (smtpd_process == PROC_CONTROL)
193 		return;
194 
195 	if (!(profiling & PROFILE_BUFFERS))
196 		return;
197 
198 	evtimer_set(&ev, process_stat_event, &ev);
199 	tv.tv_sec = 0;
200 	tv.tv_usec = 0;
201 	evtimer_add(&ev, &tv);
202 }
203 
204 static void
205 process_stat(struct mproc *p)
206 {
207 	char			buf[1024];
208 	struct stat_value	value;
209 
210 	if (p == NULL)
211 		return;
212 
213 	value.type = STAT_COUNTER;
214 	(void)snprintf(buf, sizeof buf, "buffer.%s.%s",
215 	    proc_name(smtpd_process),
216 	    proc_name(p->proc));
217 	value.u.counter = p->bytes_queued_max;
218 	p->bytes_queued_max = p->bytes_queued;
219 	stat_set(buf, &value);
220 }
221 
222 static void
223 process_stat_event(int fd, short ev, void *arg)
224 {
225 	struct event	*e = arg;
226 	struct timeval	 tv;
227 
228 	process_stat(p_control);
229 	process_stat(p_lka);
230 	process_stat(p_parent);
231 	process_stat(p_queue);
232 	process_stat(p_scheduler);
233 	process_stat(p_pony);
234 	process_stat(p_ca);
235 
236 	tv.tv_sec = 1;
237 	tv.tv_usec = 0;
238 	evtimer_add(e, &tv);
239 }
240