1 /* $NetBSD: evt.c,v 1.10 2010/10/21 06:15:28 tteras Exp $ */ 2 3 /* Id: evt.c,v 1.5 2006/06/22 20:11:35 manubsd Exp */ 4 5 /* 6 * Copyright (C) 2004 Emmanuel Dreyfus 7 * Copyright (C) 2008 Timo Teras 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the project nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "config.h" 36 37 #include <errno.h> 38 #include <string.h> 39 #include <stdio.h> 40 #include <time.h> 41 #include <unistd.h> 42 #include <stdlib.h> 43 #include <sys/queue.h> 44 #include <sys/socket.h> 45 46 #include "vmbuf.h" 47 #include "plog.h" 48 #include "misc.h" 49 #include "admin.h" 50 #include "handler.h" 51 #include "session.h" 52 #include "gcmalloc.h" 53 #include "evt.h" 54 #include "var.h" 55 56 #ifdef ENABLE_ADMINPORT 57 58 static EVT_LISTENER_LIST(evt_listeners); 59 60 struct evt_message { 61 struct admin_com adm; 62 struct evt_async evt; 63 }; 64 65 struct evt { 66 struct evtdump *dump; 67 TAILQ_ENTRY(evt) next; 68 }; 69 70 TAILQ_HEAD(evtlist, evt); 71 72 #define EVTLIST_MAX 32 73 74 static struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist); 75 static int evtlist_len = 0; 76 static int evtlist_inuse = 0; 77 78 static struct { 79 int newtype, oldtype; 80 } evttype_map[] = { 81 { EVT_RACOON_QUIT, EVTT_RACOON_QUIT }, 82 { EVT_PHASE1_UP, EVTT_PHASE1_UP }, 83 { EVT_PHASE1_DOWN, EVTT_PHASE1_DOWN }, 84 { EVT_PHASE1_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, 85 { EVT_PHASE1_NO_PROPOSAL, EVTT_PEERPH1_NOPROP }, 86 { EVT_PHASE1_AUTH_FAILED, EVTT_PEERPH1AUTH_FAILED }, 87 { EVT_PHASE1_DPD_TIMEOUT, EVTT_DPD_TIMEOUT }, 88 { EVT_PHASE1_PEER_DELETED, EVTT_PEER_DELETE }, 89 { EVT_PHASE1_MODE_CFG, EVTT_ISAKMP_CFG_DONE }, 90 { EVT_PHASE1_XAUTH_SUCCESS, EVTT_XAUTH_SUCCESS }, 91 { EVT_PHASE1_XAUTH_FAILED, EVTT_XAUTH_FAILED }, 92 { EVT_PHASE2_NO_PHASE1, -1 }, 93 { EVT_PHASE2_UP, EVTT_PHASE2_UP }, 94 { EVT_PHASE2_DOWN, EVTT_PHASE2_DOWN }, 95 { EVT_PHASE2_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, 96 }; 97 98 static void 99 evt_push(src, dst, type, optdata) 100 struct sockaddr *src; 101 struct sockaddr *dst; 102 int type; 103 vchar_t *optdata; 104 { 105 struct evtdump *evtdump; 106 struct evt *evt; 107 size_t len; 108 int i; 109 110 /* If admin socket is disabled, silently discard anything */ 111 if (adminsock_path == NULL || !evtlist_inuse) 112 return; 113 114 /* Map the event type to old */ 115 for (i = 0; i < sizeof(evttype_map) / sizeof(evttype_map[0]); i++) 116 if (evttype_map[i].newtype == type) 117 break; 118 if (i >= sizeof(evttype_map) / sizeof(evttype_map[0])) 119 return; 120 121 type = evttype_map[i].oldtype; 122 if (type < 0) 123 return; 124 125 /* If we are above the limit, don't record anything */ 126 if (evtlist_len > EVTLIST_MAX) { 127 plog(LLV_DEBUG, LOCATION, NULL, 128 "Cannot record event: event queue overflowed\n"); 129 return; 130 } 131 132 /* If we hit the limit, record an overflow event instead */ 133 if (evtlist_len == EVTLIST_MAX) { 134 plog(LLV_ERROR, LOCATION, NULL, 135 "Cannot record event: event queue overflow\n"); 136 src = NULL; 137 dst = NULL; 138 type = EVTT_OVERFLOW; 139 optdata = NULL; 140 } 141 142 len = sizeof(*evtdump); 143 if (optdata) 144 len += optdata->l; 145 146 if ((evtdump = racoon_malloc(len)) == NULL) { 147 plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", 148 strerror(errno)); 149 return; 150 } 151 152 if ((evt = racoon_malloc(sizeof(*evt))) == NULL) { 153 plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", 154 strerror(errno)); 155 racoon_free(evtdump); 156 return; 157 } 158 159 if (src) 160 memcpy(&evtdump->src, src, sysdep_sa_len(src)); 161 if (dst) 162 memcpy(&evtdump->dst, dst, sysdep_sa_len(dst)); 163 evtdump->len = len; 164 evtdump->type = type; 165 time(&evtdump->timestamp); 166 167 if (optdata) 168 memcpy(evtdump + 1, optdata->v, optdata->l); 169 170 evt->dump = evtdump; 171 TAILQ_INSERT_TAIL(&evtlist, evt, next); 172 173 evtlist_len++; 174 175 return; 176 } 177 178 static struct evtdump * 179 evt_pop(void) { 180 struct evtdump *evtdump; 181 struct evt *evt; 182 183 if ((evt = TAILQ_FIRST(&evtlist)) == NULL) 184 return NULL; 185 186 evtdump = evt->dump; 187 TAILQ_REMOVE(&evtlist, evt, next); 188 racoon_free(evt); 189 evtlist_len--; 190 191 return evtdump; 192 } 193 194 vchar_t * 195 evt_dump(void) { 196 struct evtdump *evtdump; 197 vchar_t *buf = NULL; 198 199 if (!evtlist_inuse) { 200 evtlist_inuse = 1; 201 plog(LLV_ERROR, LOCATION, NULL, 202 "evt_dump: deprecated event polling used\n"); 203 } 204 205 if ((evtdump = evt_pop()) != NULL) { 206 if ((buf = vmalloc(evtdump->len)) == NULL) { 207 plog(LLV_ERROR, LOCATION, NULL, 208 "evt_dump failed: %s\n", strerror(errno)); 209 return NULL; 210 } 211 memcpy(buf->v, evtdump, evtdump->len); 212 racoon_free(evtdump); 213 } 214 215 return buf; 216 } 217 218 static struct evt_message * 219 evtmsg_create(type, optdata) 220 int type; 221 vchar_t *optdata; 222 { 223 struct evt_message *e; 224 size_t len; 225 226 len = sizeof(struct evt_message); 227 if (optdata != NULL) 228 len += optdata->l; 229 230 if ((e = racoon_malloc(len)) == NULL) { 231 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate event: %s\n", 232 strerror(errno)); 233 return NULL; 234 } 235 236 memset(e, 0, sizeof(struct evt_message)); 237 e->adm.ac_len = len; 238 e->adm.ac_cmd = ADMIN_SHOW_EVT; 239 e->adm.ac_errno = 0; 240 e->adm.ac_proto = 0; 241 e->evt.ec_type = type; 242 time(&e->evt.ec_timestamp); 243 if (optdata != NULL) 244 memcpy(e + 1, optdata->v, optdata->l); 245 246 return e; 247 } 248 249 static void 250 evt_unsubscribe(l) 251 struct evt_listener *l; 252 { 253 plog(LLV_DEBUG, LOCATION, NULL, 254 "[%d] admin connection released\n", l->fd); 255 256 LIST_REMOVE(l, ll_chain); 257 unmonitor_fd(l->fd); 258 close(l->fd); 259 racoon_free(l); 260 } 261 262 static int 263 evt_unsubscribe_cb(ctx, fd) 264 void *ctx; 265 int fd; 266 { 267 evt_unsubscribe((struct evt_listener *) ctx); 268 return 0; 269 } 270 271 static void 272 evtmsg_broadcast(ll, e) 273 const struct evt_listener_list *ll; 274 struct evt_message *e; 275 { 276 struct evt_listener *l, *nl; 277 278 for (l = LIST_FIRST(ll); l != NULL; l = nl) { 279 nl = LIST_NEXT(l, ll_chain); 280 281 if (send(l->fd, e, e->adm.ac_len, MSG_DONTWAIT) < 0) { 282 plog(LLV_DEBUG, LOCATION, NULL, "Cannot send event to fd: %s\n", 283 strerror(errno)); 284 evt_unsubscribe(l); 285 } 286 } 287 } 288 289 void 290 evt_generic(type, optdata) 291 int type; 292 vchar_t *optdata; 293 { 294 struct evt_message *e; 295 296 if ((e = evtmsg_create(type, optdata)) == NULL) 297 return; 298 299 evtmsg_broadcast(&evt_listeners, e); 300 evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); 301 302 racoon_free(e); 303 } 304 305 void 306 evt_phase1(ph1, type, optdata) 307 const struct ph1handle *ph1; 308 int type; 309 vchar_t *optdata; 310 { 311 struct evt_message *e; 312 313 if ((e = evtmsg_create(type, optdata)) == NULL) 314 return; 315 316 if (ph1->local) 317 memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); 318 if (ph1->remote) 319 memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); 320 321 evtmsg_broadcast(&ph1->evt_listeners, e); 322 evtmsg_broadcast(&evt_listeners, e); 323 evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); 324 325 racoon_free(e); 326 } 327 328 void 329 evt_phase2(ph2, type, optdata) 330 const struct ph2handle *ph2; 331 int type; 332 vchar_t *optdata; 333 { 334 struct evt_message *e; 335 struct ph1handle *ph1 = ph2->ph1; 336 337 if ((e = evtmsg_create(type, optdata)) == NULL) 338 return; 339 340 if (ph1) { 341 if (ph1->local) 342 memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); 343 if (ph1->remote) 344 memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); 345 } 346 e->evt.ec_ph2msgid = ph2->msgid; 347 348 evtmsg_broadcast(&ph2->evt_listeners, e); 349 if (ph1) 350 evtmsg_broadcast(&ph1->evt_listeners, e); 351 evtmsg_broadcast(&evt_listeners, e); 352 evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); 353 354 racoon_free(e); 355 } 356 357 int 358 evt_subscribe(list, fd) 359 struct evt_listener_list *list; 360 int fd; 361 { 362 struct evt_listener *l; 363 364 if ((l = racoon_malloc(sizeof(*l))) == NULL) { 365 plog(LLV_ERROR, LOCATION, NULL, 366 "Cannot allocate event listener: %s\n", 367 strerror(errno)); 368 return errno; 369 } 370 371 if (list == NULL) 372 list = &evt_listeners; 373 374 LIST_INSERT_HEAD(list, l, ll_chain); 375 l->fd = fd; 376 monitor_fd(l->fd, evt_unsubscribe_cb, l, 0); 377 378 plog(LLV_DEBUG, LOCATION, NULL, 379 "[%d] admin connection is polling events\n", fd); 380 381 return -2; 382 } 383 384 void 385 evt_list_init(list) 386 struct evt_listener_list *list; 387 { 388 LIST_INIT(list); 389 } 390 391 void 392 evt_list_cleanup(list) 393 struct evt_listener_list *list; 394 { 395 while (!LIST_EMPTY(list)) 396 evt_unsubscribe(LIST_FIRST(list)); 397 } 398 399 #endif /* ENABLE_ADMINPORT */ 400