control.c revision 1.1
1/* $OpenBSD: control.c,v 1.1 2010/06/03 16:41:12 reyk Exp $ */ 2/* $vantronix: control.c,v 1.4 2010/05/14 07:35:52 reyk Exp $ */ 3 4/* 5 * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 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/queue.h> 22#include <sys/param.h> 23#include <sys/types.h> 24#include <sys/stat.h> 25#include <sys/socket.h> 26#include <sys/un.h> 27#include <sys/tree.h> 28 29#include <net/if.h> 30 31#include <errno.h> 32#include <event.h> 33#include <fcntl.h> 34#include <stdlib.h> 35#include <string.h> 36#include <unistd.h> 37#include <signal.h> 38 39#include "iked.h" 40 41#define CONTROL_BACKLOG 5 42 43struct ctl_connlist ctl_conns; 44 45void 46 control_accept(int, short, void *); 47struct ctl_conn 48 *control_connbyfd(int); 49void control_close(int); 50void control_dispatch_imsg(int, short, void *); 51void control_imsg_forward(struct imsg *); 52 53int 54control_init(struct iked *env, struct control_sock *cs) 55{ 56 struct sockaddr_un sun; 57 int fd; 58 mode_t old_umask, mode; 59 60 if (cs->cs_name == NULL) 61 return (0); 62 63 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 64 log_warn("%s: socket", __func__); 65 return (-1); 66 } 67 68 sun.sun_family = AF_UNIX; 69 if (strlcpy(sun.sun_path, cs->cs_name, 70 sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) { 71 log_warn("%s: %s name too long", __func__, cs->cs_name); 72 close(fd); 73 return (-1); 74 } 75 76 if (unlink(cs->cs_name) == -1) 77 if (errno != ENOENT) { 78 log_warn("%s: unlink %s", __func__, cs->cs_name); 79 close(fd); 80 return (-1); 81 } 82 83 if (cs->cs_restricted) { 84 old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 85 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 86 } else { 87 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 88 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP; 89 } 90 91 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 92 log_warn("%s: bind: %s", __func__, cs->cs_name); 93 close(fd); 94 (void)umask(old_umask); 95 return (-1); 96 } 97 (void)umask(old_umask); 98 99 if (chmod(cs->cs_name, mode) == -1) { 100 log_warn("%s: chmod", __func__); 101 close(fd); 102 (void)unlink(cs->cs_name); 103 return (-1); 104 } 105 106 socket_set_blockmode(fd, BM_NONBLOCK); 107 cs->cs_fd = fd; 108 cs->cs_env = env; 109 110 return (0); 111} 112 113int 114control_listen(struct control_sock *cs) 115{ 116 if (cs->cs_name == NULL) 117 return (0); 118 119 if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1) { 120 log_warn("%s: listen"); 121 return (-1); 122 } 123 124 event_set(&cs->cs_ev, cs->cs_fd, EV_READ | EV_PERSIST, 125 control_accept, cs->cs_env); 126 event_add(&cs->cs_ev, NULL); 127 128 return (0); 129} 130 131void 132control_cleanup(struct control_sock *cs) 133{ 134 if (cs->cs_name == NULL) 135 return; 136 (void)unlink(cs->cs_name); 137} 138 139/* ARGSUSED */ 140void 141control_accept(int listenfd, short event, void *arg) 142{ 143 struct iked *env = arg; 144 int connfd; 145 socklen_t len; 146 struct sockaddr_un sun; 147 struct ctl_conn *c; 148 149 len = sizeof(sun); 150 if ((connfd = accept(listenfd, 151 (struct sockaddr *)&sun, &len)) == -1) { 152 if (errno != EWOULDBLOCK && errno != EINTR) 153 log_warn("%s: accept"); 154 return; 155 } 156 157 socket_set_blockmode(connfd, BM_NONBLOCK); 158 159 if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 160 log_warn("%s", __func__); 161 close(connfd); 162 return; 163 } 164 165 imsg_init(&c->iev.ibuf, connfd); 166 c->iev.handler = control_dispatch_imsg; 167 c->iev.events = EV_READ; 168 event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 169 c->iev.handler, env); 170 event_add(&c->iev.ev, NULL); 171 172 TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 173} 174 175struct ctl_conn * 176control_connbyfd(int fd) 177{ 178 struct ctl_conn *c; 179 180 for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd; 181 c = TAILQ_NEXT(c, entry)) 182 ; /* nothing */ 183 184 return (c); 185} 186 187void 188control_close(int fd) 189{ 190 struct ctl_conn *c; 191 192 if ((c = control_connbyfd(fd)) == NULL) { 193 log_warn("%s: fd %d: not found", __func__, fd); 194 return; 195 } 196 197 msgbuf_clear(&c->iev.ibuf.w); 198 TAILQ_REMOVE(&ctl_conns, c, entry); 199 200 event_del(&c->iev.ev); 201 close(c->iev.ibuf.fd); 202 free(c); 203} 204 205/* ARGSUSED */ 206void 207control_dispatch_imsg(int fd, short event, void *arg) 208{ 209 struct iked *env = arg; 210 struct ctl_conn *c; 211 struct imsg imsg; 212 int n, v; 213 214 if ((c = control_connbyfd(fd)) == NULL) { 215 log_warn("%s: fd %d: not found", __func__, fd); 216 return; 217 } 218 219 switch (event) { 220 case EV_READ: 221 if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { 222 control_close(fd); 223 return; 224 } 225 break; 226 case EV_WRITE: 227 if (msgbuf_write(&c->iev.ibuf.w) < 0) { 228 control_close(fd); 229 return; 230 } 231 imsg_event_add(&c->iev); 232 return; 233 default: 234 fatalx("unknown event"); 235 } 236 237 for (;;) { 238 if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 239 control_close(fd); 240 return; 241 } 242 243 if (n == 0) 244 break; 245 246 control_imsg_forward(&imsg); 247 248 switch (imsg.hdr.type) { 249 case IMSG_CTL_NOTIFY: 250 if (c->flags & CTL_CONN_NOTIFY) { 251 log_debug("%s: " 252 "client requested notify more than once", 253 __func__); 254 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 255 0, 0, -1, NULL, 0); 256 break; 257 } 258 c->flags |= CTL_CONN_NOTIFY; 259 break; 260 case IMSG_CTL_VERBOSE: 261 IMSG_SIZE_CHECK(&imsg, &v); 262 263 memcpy(&v, imsg.data, sizeof(v)); 264 log_verbose(v); 265 266 imsg_forward_proc(env, &imsg, PROC_PARENT); 267 imsg_forward_proc(env, &imsg, PROC_IKEV1); 268 imsg_forward_proc(env, &imsg, PROC_IKEV2); 269 break; 270 case IMSG_CTL_RELOAD: 271 case IMSG_CTL_RESET: 272 imsg_forward_proc(env, &imsg, PROC_PARENT); 273 break; 274 default: 275 log_debug("%s: error handling imsg %d", 276 __func__, imsg.hdr.type); 277 break; 278 } 279 imsg_free(&imsg); 280 } 281 282 imsg_event_add(&c->iev); 283} 284 285void 286control_imsg_forward(struct imsg *imsg) 287{ 288 struct ctl_conn *c; 289 290 TAILQ_FOREACH(c, &ctl_conns, entry) 291 if (c->flags & CTL_CONN_NOTIFY) 292 imsg_compose(&c->iev.ibuf, imsg->hdr.type, 293 0, imsg->hdr.pid, -1, imsg->data, 294 imsg->hdr.len - IMSG_HEADER_SIZE); 295} 296