GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/relayd/control.c Lines: 4 216 1.9 %
Date: 2017-11-07 Branches: 1 116 0.9 %

Line Branch Exec Source
1
/*	$OpenBSD: control.c,v 1.56 2017/01/09 14:49:21 reyk Exp $	*/
2
3
/*
4
 * Copyright (c) 2003, 2004 Henning Brauer <henning@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/queue.h>
20
#include <sys/stat.h>
21
#include <sys/socket.h>
22
#include <sys/time.h>
23
#include <sys/un.h>
24
25
#include <errno.h>
26
#include <event.h>
27
#include <fcntl.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <unistd.h>
31
#include <imsg.h>
32
33
#include "relayd.h"
34
35
#define	CONTROL_BACKLOG	5
36
37
struct ctl_connlist ctl_conns;
38
39
void		 control_accept(int, short, void *);
40
void		 control_close(int, struct control_sock *);
41
42
int
43
control_init(struct privsep *ps, struct control_sock *cs)
44
{
45
	struct relayd		*env = ps->ps_env;
46
	struct sockaddr_un	 sun;
47
	int			 fd;
48
	mode_t			 old_umask, mode;
49
50
	if (cs->cs_name == NULL)
51
		return (0);
52
53
	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) {
54
		log_warn("%s: socket", __func__);
55
		return (-1);
56
	}
57
58
	sun.sun_family = AF_UNIX;
59
	if (strlcpy(sun.sun_path, cs->cs_name,
60
	    sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) {
61
		log_warn("%s: %s name too long", __func__, cs->cs_name);
62
		close(fd);
63
		return (-1);
64
	}
65
66
	if (unlink(cs->cs_name) == -1)
67
		if (errno != ENOENT) {
68
			log_warn("%s: unlink %s", __func__, cs->cs_name);
69
			close(fd);
70
			return (-1);
71
		}
72
73
	if (cs->cs_restricted) {
74
		old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
75
		mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
76
	} else {
77
		old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
78
		mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
79
	}
80
81
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
82
		log_warn("%s: bind: %s", __func__, cs->cs_name);
83
		close(fd);
84
		(void)umask(old_umask);
85
		return (-1);
86
	}
87
	(void)umask(old_umask);
88
89
	if (chmod(cs->cs_name, mode) == -1) {
90
		log_warn("%s: chmod", __func__);
91
		close(fd);
92
		(void)unlink(cs->cs_name);
93
		return (-1);
94
	}
95
96
	cs->cs_fd = fd;
97
	cs->cs_env = env;
98
99
	return (0);
100
}
101
102
int
103
control_listen(struct control_sock *cs)
104
{
105
	if (cs->cs_name == NULL)
106
		return (0);
107
108
	if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1) {
109
		log_warn("%s: listen", __func__);
110
		return (-1);
111
	}
112
113
	event_set(&cs->cs_ev, cs->cs_fd, EV_READ,
114
	    control_accept, cs);
115
	event_add(&cs->cs_ev, NULL);
116
	evtimer_set(&cs->cs_evt, control_accept, cs);
117
118
	return (0);
119
}
120
121
void
122
control_cleanup(struct control_sock *cs)
123
{
124
1924
	if (cs->cs_name == NULL)
125
		return;
126
962
	event_del(&cs->cs_ev);
127
962
	event_del(&cs->cs_evt);
128
1924
}
129
130
/* ARGSUSED */
131
void
132
control_accept(int listenfd, short event, void *arg)
133
{
134
	int			 connfd;
135
	socklen_t		 len;
136
	struct sockaddr_un	 sun;
137
	struct ctl_conn		*c;
138
	struct control_sock	*cs = arg;
139
140
	event_add(&cs->cs_ev, NULL);
141
	if ((event & EV_TIMEOUT))
142
		return;
143
144
	len = sizeof(sun);
145
	if ((connfd = accept4(listenfd,
146
	    (struct sockaddr *)&sun, &len, SOCK_NONBLOCK)) == -1) {
147
		/*
148
		 * Pause accept if we are out of file descriptors, or
149
		 * libevent will haunt us here too.
150
		 */
151
		if (errno == ENFILE || errno == EMFILE) {
152
			struct timeval evtpause = { 1, 0 };
153
154
			event_del(&cs->cs_ev);
155
			evtimer_add(&cs->cs_evt, &evtpause);
156
		} else if (errno != EWOULDBLOCK && errno != EINTR &&
157
		    errno != ECONNABORTED)
158
			log_warn("%s: accept", __func__);
159
		return;
160
	}
161
162
	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
163
		close(connfd);
164
		log_warn("%s: calloc", __func__);
165
		return;
166
	}
167
168
	imsg_init(&c->iev.ibuf, connfd);
169
	c->iev.handler = control_dispatch_imsg;
170
	c->iev.events = EV_READ;
171
	c->iev.data = cs;	/* proc.c cheats (reuses the handler) */
172
	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
173
	    c->iev.handler, cs);
174
	event_add(&c->iev.ev, NULL);
175
176
	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
177
}
178
179
struct ctl_conn *
180
control_connbyfd(int fd)
181
{
182
	struct ctl_conn	*c;
183
184
	TAILQ_FOREACH(c, &ctl_conns, entry) {
185
		if (c->iev.ibuf.fd == fd)
186
			break;
187
	}
188
189
	return (c);
190
}
191
192
void
193
control_close(int fd, struct control_sock *cs)
194
{
195
	struct ctl_conn	*c;
196
197
	if ((c = control_connbyfd(fd)) == NULL) {
198
		log_warn("%s: fd %d not found", __func__, fd);
199
		return;
200
	}
201
202
	msgbuf_clear(&c->iev.ibuf.w);
203
	TAILQ_REMOVE(&ctl_conns, c, entry);
204
205
	event_del(&c->iev.ev);
206
	close(c->iev.ibuf.fd);
207
208
	/* Some file descriptors are available again. */
209
	if (evtimer_pending(&cs->cs_evt, NULL)) {
210
		evtimer_del(&cs->cs_evt);
211
		event_add(&cs->cs_ev, NULL);
212
	}
213
214
	free(c);
215
}
216
217
/* ARGSUSED */
218
void
219
control_dispatch_imsg(int fd, short event, void *arg)
220
{
221
	struct control_sock	*cs = arg;
222
	struct ctl_conn		*c;
223
	struct imsg		 imsg;
224
	struct ctl_id		 id;
225
	int			 n;
226
	int			 verbose;
227
	struct relayd		*env = cs->cs_env;
228
	struct privsep		*ps = env->sc_ps;
229
230
	if ((c = control_connbyfd(fd)) == NULL) {
231
		log_warn("%s: fd %d not found", __func__, fd);
232
		return;
233
	}
234
235
	if (event & EV_READ) {
236
		if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) ||
237
		    n == 0) {
238
			control_close(fd, cs);
239
			return;
240
		}
241
	}
242
243
	if (event & EV_WRITE) {
244
		if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) {
245
			control_close(fd, cs);
246
			return;
247
		}
248
	}
249
250
	for (;;) {
251
		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
252
			control_close(fd, cs);
253
			return;
254
		}
255
256
		if (n == 0)
257
			break;
258
259
		if (c->waiting) {
260
			log_debug("%s: unexpected imsg %d",
261
			    __func__, imsg.hdr.type);
262
			imsg_free(&imsg);
263
			control_close(fd, cs);
264
			return;
265
		}
266
267
		switch (imsg.hdr.type) {
268
		case IMSG_CTL_SHOW_SUM:
269
			show(c);
270
			break;
271
		case IMSG_CTL_SESSION:
272
			show_sessions(c);
273
			break;
274
		case IMSG_CTL_RDR_DISABLE:
275
			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(id))
276
				fatalx("invalid imsg header len");
277
			memcpy(&id, imsg.data, sizeof(id));
278
			if (disable_rdr(c, &id))
279
				imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
280
				    0, ps->ps_instance + 1, -1, NULL, 0);
281
			else {
282
				memcpy(imsg.data, &id, sizeof(id));
283
				control_imsg_forward(ps, &imsg);
284
				imsg_compose_event(&c->iev, IMSG_CTL_OK,
285
				    0, ps->ps_instance + 1, -1, NULL, 0);
286
			}
287
			break;
288
		case IMSG_CTL_RDR_ENABLE:
289
			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(id))
290
				fatalx("invalid imsg header len");
291
			memcpy(&id, imsg.data, sizeof(id));
292
			if (enable_rdr(c, &id))
293
				imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
294
				    0, ps->ps_instance + 1, -1, NULL, 0);
295
			else {
296
				memcpy(imsg.data, &id, sizeof(id));
297
				control_imsg_forward(ps, &imsg);
298
				imsg_compose_event(&c->iev, IMSG_CTL_OK,
299
				    0, ps->ps_instance + 1, -1, NULL, 0);
300
			}
301
			break;
302
		case IMSG_CTL_TABLE_DISABLE:
303
			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(id))
304
				fatalx("invalid imsg header len");
305
			memcpy(&id, imsg.data, sizeof(id));
306
			if (disable_table(c, &id))
307
				imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
308
				    0, ps->ps_instance + 1, -1, NULL, 0);
309
			else {
310
				memcpy(imsg.data, &id, sizeof(id));
311
				control_imsg_forward(ps, &imsg);
312
				imsg_compose_event(&c->iev, IMSG_CTL_OK,
313
				    0, ps->ps_instance + 1, -1, NULL, 0);
314
			}
315
			break;
316
		case IMSG_CTL_TABLE_ENABLE:
317
			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(id))
318
				fatalx("invalid imsg header len");
319
			memcpy(&id, imsg.data, sizeof(id));
320
			if (enable_table(c, &id))
321
				imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
322
				    0, ps->ps_instance + 1, -1, NULL, 0);
323
			else {
324
				memcpy(imsg.data, &id, sizeof(id));
325
				control_imsg_forward(ps, &imsg);
326
				imsg_compose_event(&c->iev, IMSG_CTL_OK,
327
				    0, ps->ps_instance + 1, -1, NULL, 0);
328
			}
329
			break;
330
		case IMSG_CTL_HOST_DISABLE:
331
			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(id))
332
				fatalx("invalid imsg header len");
333
			memcpy(&id, imsg.data, sizeof(id));
334
			if (disable_host(c, &id, NULL))
335
				imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
336
				    0, ps->ps_instance + 1, -1, NULL, 0);
337
			else {
338
				memcpy(imsg.data, &id, sizeof(id));
339
				control_imsg_forward(ps, &imsg);
340
				imsg_compose_event(&c->iev, IMSG_CTL_OK,
341
				    0, ps->ps_instance + 1, -1, NULL, 0);
342
			}
343
			break;
344
		case IMSG_CTL_HOST_ENABLE:
345
			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(id))
346
				fatalx("invalid imsg header len");
347
			memcpy(&id, imsg.data, sizeof(id));
348
			if (enable_host(c, &id, NULL))
349
				imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
350
				    0, ps->ps_instance + 1, -1, NULL, 0);
351
			else {
352
				memcpy(imsg.data, &id, sizeof(id));
353
				control_imsg_forward(ps, &imsg);
354
				imsg_compose_event(&c->iev, IMSG_CTL_OK,
355
				    0, ps->ps_instance + 1, -1, NULL, 0);
356
			}
357
			break;
358
		case IMSG_CTL_SHUTDOWN:
359
		case IMSG_CTL_RELOAD:
360
			proc_forward_imsg(env->sc_ps, &imsg, PROC_PARENT, -1);
361
			break;
362
		case IMSG_CTL_POLL:
363
			proc_compose(env->sc_ps, PROC_HCE,
364
			    IMSG_CTL_POLL, NULL, 0);
365
			imsg_compose_event(&c->iev, IMSG_CTL_OK,
366
			    0, ps->ps_instance + 1, -1, NULL, 0);
367
			break;
368
		case IMSG_CTL_NOTIFY:
369
			if (c->flags & CTL_CONN_NOTIFY) {
370
				log_debug("%s: "
371
				    "client requested notify more than once",
372
				    __func__);
373
				imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
374
				    0, ps->ps_instance + 1, -1, NULL, 0);
375
				break;
376
			}
377
			c->flags |= CTL_CONN_NOTIFY;
378
			break;
379
		case IMSG_CTL_VERBOSE:
380
			IMSG_SIZE_CHECK(&imsg, &verbose);
381
382
			memcpy(&verbose, imsg.data, sizeof(verbose));
383
384
			proc_forward_imsg(env->sc_ps, &imsg, PROC_PARENT, -1);
385
			proc_forward_imsg(env->sc_ps, &imsg, PROC_HCE, -1);
386
			proc_forward_imsg(env->sc_ps, &imsg, PROC_RELAY, -1);
387
388
			memcpy(imsg.data, &verbose, sizeof(verbose));
389
			control_imsg_forward(ps, &imsg);
390
			log_setverbose(verbose);
391
			break;
392
		default:
393
			log_debug("%s: error handling imsg %d",
394
			    __func__, imsg.hdr.type);
395
			break;
396
		}
397
		imsg_free(&imsg);
398
	}
399
400
	imsg_event_add(&c->iev);
401
}
402
403
void
404
control_imsg_forward(struct privsep *ps, struct imsg *imsg)
405
{
406
	struct ctl_conn *c;
407
408
	TAILQ_FOREACH(c, &ctl_conns, entry)
409
		if (c->flags & CTL_CONN_NOTIFY)
410
			imsg_compose_event(&c->iev, imsg->hdr.type,
411
			    0, ps->ps_instance + 1, -1, imsg->data,
412
			    imsg->hdr.len - IMSG_HEADER_SIZE);
413
}