control.c revision 1.1
1/*	$OpenBSD: control.c,v 1.1 2004/01/01 23:46:47 henning Exp $ */
2
3/*
4 * Copyright (c) 2003 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/types.h>
20#include <sys/socket.h>
21#include <sys/un.h>
22#include <errno.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26
27#include "bgpd.h"
28#include "bgpdctl.h"
29#include "session.h"
30
31#define	CONTROL_BACKLOG	5
32
33struct {
34	int	fd;
35} control_state;
36
37struct ctl_conn	*control_connbyfd(int);
38
39int
40control_init(void)
41{
42	struct sockaddr_un	sun;
43	int			fd;
44
45	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
46		log_err("control_init: socket");
47		return (-1);
48	}
49
50	bzero(&sun, sizeof(sun));
51	sun.sun_family = AF_UNIX;
52	strlcpy(sun.sun_path, SOCKET_NAME, sizeof(sun.sun_path));
53	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
54		log_err("control_init: bind: %s", SOCKET_NAME);
55		return (-1);
56	}
57
58	control_state.fd = fd;
59
60	return (fd);
61}
62
63int
64control_listen(void)
65{
66	if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
67		log_err("control_listen: listen");
68		return (-1);
69	}
70
71	return (control_state.fd);
72}
73
74void
75control_shutdown(void)
76{
77	close(control_state.fd);
78}
79
80void
81control_cleanup(void)
82{
83	unlink(SOCKET_NAME);
84}
85
86void
87control_accept(int listenfd)
88{
89	int			 connfd;
90	socklen_t		 len;
91	struct sockaddr_un	 sun;
92	uid_t			 uid;
93	gid_t			 gid;
94	struct ctl_conn		*ctl_conn;
95
96	len = sizeof(sun);
97	if ((connfd = accept(listenfd,
98	    (struct sockaddr *)&sun, &len)) == -1) {
99		if (errno == EWOULDBLOCK || errno == EINTR)
100			return;
101		else
102			log_err("session_control_accept");
103	}
104
105	if (getpeereid(connfd, &uid, &gid) == -1) {
106		log_err("session_control_accept");
107		return;
108	}
109
110	if (uid) {
111		log_err("Connection to control socket with uid %ld", uid);
112		return;
113	}
114
115	if ((ctl_conn = malloc(sizeof(struct ctl_conn))) == NULL) {
116		log_err("session_control_accept");
117		return;
118	}
119
120	imsg_init(&ctl_conn->ibuf, connfd);
121
122	TAILQ_INSERT_TAIL(&ctl_conns, ctl_conn, entries);
123}
124
125struct ctl_conn *
126control_connbyfd(int fd)
127{
128	struct ctl_conn	*c;
129
130	for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->ibuf.sock != fd;
131	    c = TAILQ_NEXT(c, entries))
132		;	/* nothing */
133
134	return (c);
135}
136
137void
138control_close(int fd)
139{
140	struct ctl_conn	*c;
141
142	if ((c = control_connbyfd(fd)) == NULL) {
143		log_err("control_close: fd %d: not found", fd);
144		return;
145	}
146
147	TAILQ_REMOVE(&ctl_conns, c, entries);
148
149	close(c->ibuf.sock);
150	free(c);
151}
152
153int
154control_dispatch_msg(struct pollfd *pfd, int i)
155{
156	struct imsg		 imsg;
157	struct ctl_conn		*c;
158	int			 n;
159	struct peer		*p;
160
161	if ((c = control_connbyfd(pfd->fd)) == NULL) {
162		log_err("control_dispatch_msg: fd %d: not found", pfd->fd);
163		return (0);
164	}
165
166	if (imsg_read(&c->ibuf) == -1) {
167		control_close(pfd->fd);
168		return (1);
169	}
170
171	for (;;) {
172		if ((n = imsg_get(&c->ibuf, &imsg)) == -1) {
173			control_close(pfd->fd);
174			return (1);
175		}
176
177		if (n == 0)
178			break;
179
180		switch (imsg.hdr.type) {
181		case IMSG_CTL_SHOW_NEIGHBOR:
182			for (p = conf->peers; p != NULL; p = p->next)
183				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_NEIGHBOR,
184				    0, p, sizeof(struct peer));
185			break;
186		default:
187			break;
188		}
189		imsg_free(&imsg);
190	}
191
192	return (0);
193}
194