1 /* $OpenBSD: control.c,v 1.8 2012/04/05 17:31:36 deraadt 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 43 struct ctl_connlist ctl_conns; 44 45 void 46 control_accept(int, short, void *); 47 struct ctl_conn 48 *control_connbyfd(int); 49 void control_close(int, struct control_sock *); 50 void control_dispatch_imsg(int, short, void *); 51 void control_imsg_forward(struct imsg *); 52 53 int 54 control_init(struct privsep *ps, struct control_sock *cs) 55 { 56 struct iked *env = ps->ps_env; 57 struct sockaddr_un sun; 58 int fd; 59 mode_t old_umask, mode; 60 61 if (cs->cs_name == NULL) 62 return (0); 63 64 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 65 log_warn("%s: socket", __func__); 66 return (-1); 67 } 68 69 sun.sun_family = AF_UNIX; 70 if (strlcpy(sun.sun_path, cs->cs_name, 71 sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) { 72 log_warn("%s: %s name too long", __func__, cs->cs_name); 73 close(fd); 74 return (-1); 75 } 76 77 if (unlink(cs->cs_name) == -1) 78 if (errno != ENOENT) { 79 log_warn("%s: unlink %s", __func__, cs->cs_name); 80 close(fd); 81 return (-1); 82 } 83 84 if (cs->cs_restricted) { 85 old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 86 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 87 } else { 88 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 89 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP; 90 } 91 92 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 93 log_warn("%s: bind: %s", __func__, cs->cs_name); 94 close(fd); 95 (void)umask(old_umask); 96 return (-1); 97 } 98 (void)umask(old_umask); 99 100 if (chmod(cs->cs_name, mode) == -1) { 101 log_warn("%s: chmod", __func__); 102 close(fd); 103 (void)unlink(cs->cs_name); 104 return (-1); 105 } 106 107 socket_set_blockmode(fd, BM_NONBLOCK); 108 cs->cs_fd = fd; 109 cs->cs_env = env; 110 111 return (0); 112 } 113 114 int 115 control_listen(struct control_sock *cs) 116 { 117 if (cs->cs_name == NULL) 118 return (0); 119 120 if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1) { 121 log_warn("%s: listen", __func__); 122 return (-1); 123 } 124 125 event_set(&cs->cs_ev, cs->cs_fd, EV_READ, 126 control_accept, cs); 127 event_add(&cs->cs_ev, NULL); 128 evtimer_set(&cs->cs_evt, control_accept, cs); 129 130 return (0); 131 } 132 133 void 134 control_cleanup(struct control_sock *cs) 135 { 136 if (cs->cs_name == NULL) 137 return; 138 event_del(&cs->cs_ev); 139 event_del(&cs->cs_evt); 140 (void)unlink(cs->cs_name); 141 } 142 143 /* ARGSUSED */ 144 void 145 control_accept(int listenfd, short event, void *arg) 146 { 147 struct control_sock *cs = arg; 148 int connfd; 149 socklen_t len; 150 struct sockaddr_un sun; 151 struct ctl_conn *c; 152 153 event_add(&cs->cs_ev, NULL); 154 if ((event & EV_TIMEOUT)) 155 return; 156 157 len = sizeof(sun); 158 if ((connfd = accept(listenfd, 159 (struct sockaddr *)&sun, &len)) == -1) { 160 /* 161 * Pause accept if we are out of file descriptors, or 162 * libevent will haunt us here too. 163 */ 164 if (errno == ENFILE || errno == EMFILE) { 165 struct timeval evtpause = { 1, 0 }; 166 167 event_del(&cs->cs_ev); 168 evtimer_add(&cs->cs_evt, &evtpause); 169 } else if (errno != EWOULDBLOCK && errno != EINTR) 170 log_warn("%s: accept", __func__); 171 return; 172 } 173 174 socket_set_blockmode(connfd, BM_NONBLOCK); 175 176 if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 177 log_warn("%s", __func__); 178 close(connfd); 179 return; 180 } 181 182 imsg_init(&c->iev.ibuf, connfd); 183 c->iev.handler = control_dispatch_imsg; 184 c->iev.events = EV_READ; 185 c->iev.data = cs; 186 event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 187 c->iev.handler, c->iev.data); 188 event_add(&c->iev.ev, NULL); 189 190 TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 191 } 192 193 struct ctl_conn * 194 control_connbyfd(int fd) 195 { 196 struct ctl_conn *c; 197 198 for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd; 199 c = TAILQ_NEXT(c, entry)) 200 ; /* nothing */ 201 202 return (c); 203 } 204 205 void 206 control_close(int fd, struct control_sock *cs) 207 { 208 struct ctl_conn *c; 209 210 if ((c = control_connbyfd(fd)) == NULL) { 211 log_warn("%s: fd %d: not found", __func__, fd); 212 return; 213 } 214 215 msgbuf_clear(&c->iev.ibuf.w); 216 TAILQ_REMOVE(&ctl_conns, c, entry); 217 218 event_del(&c->iev.ev); 219 close(c->iev.ibuf.fd); 220 221 /* Some file descriptors are available again. */ 222 if (evtimer_pending(&cs->cs_evt, NULL)) { 223 evtimer_del(&cs->cs_evt); 224 event_add(&cs->cs_ev, NULL); 225 } 226 227 free(c); 228 } 229 230 /* ARGSUSED */ 231 void 232 control_dispatch_imsg(int fd, short event, void *arg) 233 { 234 struct control_sock *cs = arg; 235 struct iked *env = cs->cs_env; 236 struct ctl_conn *c; 237 struct imsg imsg; 238 int n, v; 239 240 if ((c = control_connbyfd(fd)) == NULL) { 241 log_warn("%s: fd %d: not found", __func__, fd); 242 return; 243 } 244 245 switch (event) { 246 case EV_READ: 247 if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { 248 control_close(fd, cs); 249 return; 250 } 251 break; 252 case EV_WRITE: 253 if (msgbuf_write(&c->iev.ibuf.w) < 0) { 254 control_close(fd, cs); 255 return; 256 } 257 imsg_event_add(&c->iev); 258 return; 259 default: 260 fatalx("unknown event"); 261 } 262 263 for (;;) { 264 if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 265 control_close(fd, cs); 266 return; 267 } 268 269 if (n == 0) 270 break; 271 272 control_imsg_forward(&imsg); 273 274 switch (imsg.hdr.type) { 275 case IMSG_CTL_NOTIFY: 276 if (c->flags & CTL_CONN_NOTIFY) { 277 log_debug("%s: " 278 "client requested notify more than once", 279 __func__); 280 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 281 0, 0, -1, NULL, 0); 282 break; 283 } 284 c->flags |= CTL_CONN_NOTIFY; 285 break; 286 case IMSG_CTL_VERBOSE: 287 IMSG_SIZE_CHECK(&imsg, &v); 288 289 memcpy(&v, imsg.data, sizeof(v)); 290 log_verbose(v); 291 292 proc_forward_imsg(env, &imsg, PROC_PARENT); 293 proc_forward_imsg(env, &imsg, PROC_IKEV2); 294 proc_forward_imsg(env, &imsg, PROC_IKEV1); 295 break; 296 case IMSG_CTL_RELOAD: 297 case IMSG_CTL_RESET: 298 case IMSG_CTL_COUPLE: 299 case IMSG_CTL_DECOUPLE: 300 case IMSG_CTL_ACTIVE: 301 case IMSG_CTL_PASSIVE: 302 proc_forward_imsg(env, &imsg, PROC_PARENT); 303 break; 304 default: 305 log_debug("%s: error handling imsg %d", 306 __func__, imsg.hdr.type); 307 break; 308 } 309 imsg_free(&imsg); 310 } 311 312 imsg_event_add(&c->iev); 313 } 314 315 void 316 control_imsg_forward(struct imsg *imsg) 317 { 318 struct ctl_conn *c; 319 320 TAILQ_FOREACH(c, &ctl_conns, entry) 321 if (c->flags & CTL_CONN_NOTIFY) 322 imsg_compose(&c->iev.ibuf, imsg->hdr.type, 323 0, imsg->hdr.pid, -1, imsg->data, 324 imsg->hdr.len - IMSG_HEADER_SIZE); 325 } 326