1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8 #if defined(KERNEL) || defined(_KERNEL) 9 # undef KERNEL 10 # undef _KERNEL 11 # define KERNEL 1 12 # define _KERNEL 1 13 #endif 14 #include <sys/errno.h> 15 #include <sys/types.h> 16 #include <sys/param.h> 17 #include <sys/time.h> 18 #include <sys/file.h> 19 #if !defined(_KERNEL) 20 # include <stdio.h> 21 # include <stdlib.h> 22 # ifdef _STDC_C99 23 # include <stdbool.h> 24 # endif 25 # include <string.h> 26 # define _KERNEL 27 # include <sys/uio.h> 28 # undef _KERNEL 29 #endif 30 #if defined(_KERNEL) && defined(__FreeBSD__) 31 # include <sys/filio.h> 32 # include <sys/fcntl.h> 33 #else 34 # include <sys/ioctl.h> 35 #endif 36 # include <sys/protosw.h> 37 #include <sys/socket.h> 38 #if defined(_KERNEL) 39 # include <sys/systm.h> 40 # if !defined(__SVR4) 41 # include <sys/mbuf.h> 42 # endif 43 #endif 44 #if defined(__SVR4) 45 # include <sys/filio.h> 46 # include <sys/byteorder.h> 47 # ifdef _KERNEL 48 # include <sys/dditypes.h> 49 # endif 50 # include <sys/stream.h> 51 # include <sys/kmem.h> 52 #endif 53 #if defined(__FreeBSD__) 54 # include <sys/queue.h> 55 #endif 56 #if defined(__NetBSD__) 57 # include <machine/cpu.h> 58 #endif 59 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 60 # include <sys/proc.h> 61 #endif 62 #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 400000) && \ 63 !defined(_KERNEL) 64 # include <stdbool.h> 65 #endif 66 #include <net/if.h> 67 #ifdef sun 68 # include <net/af.h> 69 #endif 70 #include <netinet/in.h> 71 #include <netinet/in_systm.h> 72 #include <netinet/ip.h> 73 # include <netinet/ip_var.h> 74 #if !defined(_KERNEL) 75 # define KERNEL 76 # define _KERNEL 77 # define NOT_KERNEL 78 #endif 79 #ifdef NOT_KERNEL 80 # undef _KERNEL 81 # undef KERNEL 82 #endif 83 #include <netinet/tcp.h> 84 #if defined(__FreeBSD__) 85 # include <net/if_var.h> 86 # define IF_QFULL _IF_QFULL 87 # define IF_DROP _IF_DROP 88 #endif 89 #include <netinet/in_var.h> 90 #include <netinet/tcp_fsm.h> 91 #include <netinet/udp.h> 92 #include <netinet/ip_icmp.h> 93 #include "netinet/ip_compat.h" 94 #include <netinet/tcpip.h> 95 #include "netinet/ip_fil.h" 96 #include "netinet/ip_auth.h" 97 #if !SOLARIS 98 # include <net/netisr.h> 99 # ifdef __FreeBSD__ 100 # include <machine/cpufunc.h> 101 # endif 102 #endif 103 #if defined(__FreeBSD__) 104 # include <sys/malloc.h> 105 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 106 # include <sys/libkern.h> 107 # include <sys/systm.h> 108 # endif 109 #endif 110 /* END OF INCLUDES */ 111 112 #if !defined(lint) 113 static const char rcsid[] = "@(#)$FreeBSD$"; 114 /* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.24 2007/09/09 11:32:04 darrenr Exp $"; */ 115 #endif 116 117 118 static void ipf_auth_deref(frauthent_t **); 119 static void ipf_auth_deref_unlocked(ipf_auth_softc_t *, frauthent_t **); 120 static int ipf_auth_geniter(ipf_main_softc_t *, ipftoken_t *, 121 ipfgeniter_t *, ipfobj_t *); 122 static int ipf_auth_reply(ipf_main_softc_t *, ipf_auth_softc_t *, char *); 123 static int ipf_auth_wait(ipf_main_softc_t *, ipf_auth_softc_t *, char *); 124 static int ipf_auth_flush(void *); 125 126 127 /* ------------------------------------------------------------------------ */ 128 /* Function: ipf_auth_main_load */ 129 /* Returns: int - 0 == success, else error */ 130 /* Parameters: None */ 131 /* */ 132 /* A null-op function that exists as a placeholder so that the flow in */ 133 /* other functions is obvious. */ 134 /* ------------------------------------------------------------------------ */ 135 int 136 ipf_auth_main_load(void) 137 { 138 return (0); 139 } 140 141 142 /* ------------------------------------------------------------------------ */ 143 /* Function: ipf_auth_main_unload */ 144 /* Returns: int - 0 == success, else error */ 145 /* Parameters: None */ 146 /* */ 147 /* A null-op function that exists as a placeholder so that the flow in */ 148 /* other functions is obvious. */ 149 /* ------------------------------------------------------------------------ */ 150 int 151 ipf_auth_main_unload(void) 152 { 153 return (0); 154 } 155 156 157 /* ------------------------------------------------------------------------ */ 158 /* Function: ipf_auth_soft_create */ 159 /* Returns: int - NULL = failure, else success */ 160 /* Parameters: softc(I) - pointer to soft context data */ 161 /* */ 162 /* Create a structre to store all of the run-time data for packet auth in */ 163 /* and initialise some fields to their defaults. */ 164 /* ------------------------------------------------------------------------ */ 165 void * 166 ipf_auth_soft_create(ipf_main_softc_t *softc) 167 { 168 ipf_auth_softc_t *softa; 169 170 KMALLOC(softa, ipf_auth_softc_t *); 171 if (softa == NULL) 172 return (NULL); 173 174 bzero((char *)softa, sizeof(*softa)); 175 176 softa->ipf_auth_size = FR_NUMAUTH; 177 softa->ipf_auth_defaultage = 600; 178 179 RWLOCK_INIT(&softa->ipf_authlk, "ipf IP User-Auth rwlock"); 180 MUTEX_INIT(&softa->ipf_auth_mx, "ipf auth log mutex"); 181 #if SOLARIS && defined(_KERNEL) 182 cv_init(&softa->ipf_auth_wait, "ipf auth condvar", CV_DRIVER, NULL); 183 #endif 184 185 return (softa); 186 } 187 188 /* ------------------------------------------------------------------------ */ 189 /* Function: ipf_auth_soft_init */ 190 /* Returns: int - 0 == success, else error */ 191 /* Parameters: softc(I) - pointer to soft context data */ 192 /* arg(I) - opaque pointer to auth context data */ 193 /* */ 194 /* Allocate memory and initialise data structures used in handling auth */ 195 /* rules. */ 196 /* ------------------------------------------------------------------------ */ 197 int 198 ipf_auth_soft_init(ipf_main_softc_t *softc, void *arg) 199 { 200 ipf_auth_softc_t *softa = arg; 201 202 KMALLOCS(softa->ipf_auth, frauth_t *, 203 softa->ipf_auth_size * sizeof(*softa->ipf_auth)); 204 if (softa->ipf_auth == NULL) 205 return (-1); 206 bzero((char *)softa->ipf_auth, 207 softa->ipf_auth_size * sizeof(*softa->ipf_auth)); 208 209 KMALLOCS(softa->ipf_auth_pkts, mb_t **, 210 softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts)); 211 if (softa->ipf_auth_pkts == NULL) 212 return (-2); 213 bzero((char *)softa->ipf_auth_pkts, 214 softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts)); 215 216 217 return (0); 218 } 219 220 221 /* ------------------------------------------------------------------------ */ 222 /* Function: ipf_auth_soft_fini */ 223 /* Returns: int - 0 == success, else error */ 224 /* Parameters: softc(I) - pointer to soft context data */ 225 /* arg(I) - opaque pointer to auth context data */ 226 /* */ 227 /* Free all network buffer memory used to keep saved packets that have been */ 228 /* connectedd to the soft soft context structure *but* do not free that: it */ 229 /* is free'd by _destroy(). */ 230 /* ------------------------------------------------------------------------ */ 231 int 232 ipf_auth_soft_fini(ipf_main_softc_t *softc, void *arg) 233 { 234 ipf_auth_softc_t *softa = arg; 235 frauthent_t *fae, **faep; 236 frentry_t *fr, **frp; 237 mb_t *m; 238 int i; 239 240 if (softa->ipf_auth != NULL) { 241 KFREES(softa->ipf_auth, 242 softa->ipf_auth_size * sizeof(*softa->ipf_auth)); 243 softa->ipf_auth = NULL; 244 } 245 246 if (softa->ipf_auth_pkts != NULL) { 247 for (i = 0; i < softa->ipf_auth_size; i++) { 248 m = softa->ipf_auth_pkts[i]; 249 if (m != NULL) { 250 FREE_MB_T(m); 251 softa->ipf_auth_pkts[i] = NULL; 252 } 253 } 254 KFREES(softa->ipf_auth_pkts, 255 softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts)); 256 softa->ipf_auth_pkts = NULL; 257 } 258 259 faep = &softa->ipf_auth_entries; 260 while ((fae = *faep) != NULL) { 261 *faep = fae->fae_next; 262 KFREE(fae); 263 } 264 softa->ipf_auth_ip = NULL; 265 266 if (softa->ipf_auth_rules != NULL) { 267 for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) { 268 if (fr->fr_ref == 1) { 269 *frp = fr->fr_next; 270 MUTEX_DESTROY(&fr->fr_lock); 271 KFREE(fr); 272 } else 273 frp = &fr->fr_next; 274 } 275 } 276 277 return (0); 278 } 279 280 281 /* ------------------------------------------------------------------------ */ 282 /* Function: ipf_auth_soft_destroy */ 283 /* Returns: void */ 284 /* Parameters: softc(I) - pointer to soft context data */ 285 /* arg(I) - opaque pointer to auth context data */ 286 /* */ 287 /* Undo what was done in _create() - i.e. free the soft context data. */ 288 /* ------------------------------------------------------------------------ */ 289 void 290 ipf_auth_soft_destroy(ipf_main_softc_t *softc, void *arg) 291 { 292 ipf_auth_softc_t *softa = arg; 293 294 #if SOLARIS && defined(_KERNEL) 295 cv_destroy(&softa->ipf_auth_wait); 296 #endif 297 MUTEX_DESTROY(&softa->ipf_auth_mx); 298 RW_DESTROY(&softa->ipf_authlk); 299 300 KFREE(softa); 301 } 302 303 304 /* ------------------------------------------------------------------------ */ 305 /* Function: ipf_auth_setlock */ 306 /* Returns: void */ 307 /* Paramters: arg(I) - pointer to soft context data */ 308 /* tmp(I) - value to assign to auth lock */ 309 /* */ 310 /* ------------------------------------------------------------------------ */ 311 void 312 ipf_auth_setlock(void *arg, int tmp) 313 { 314 ipf_auth_softc_t *softa = arg; 315 316 softa->ipf_auth_lock = tmp; 317 } 318 319 320 /* ------------------------------------------------------------------------ */ 321 /* Function: ipf_auth_check */ 322 /* Returns: frentry_t* - pointer to ipf rule if match found, else NULL */ 323 /* Parameters: fin(I) - pointer to ipftoken structure */ 324 /* passp(I) - pointer to ipfgeniter structure */ 325 /* */ 326 /* Check if a packet has authorization. If the packet is found to match an */ 327 /* authorization result and that would result in a feedback loop (i.e. it */ 328 /* will end up returning FR_AUTH) then return FR_BLOCK instead. */ 329 /* ------------------------------------------------------------------------ */ 330 frentry_t * 331 ipf_auth_check(fr_info_t *fin, u_32_t *passp) 332 { 333 ipf_main_softc_t *softc = fin->fin_main_soft; 334 ipf_auth_softc_t *softa = softc->ipf_auth_soft; 335 frentry_t *fr; 336 frauth_t *fra; 337 u_32_t pass; 338 u_short id; 339 ip_t *ip; 340 int i; 341 342 if (softa->ipf_auth_lock || !softa->ipf_auth_used) 343 return (NULL); 344 345 ip = fin->fin_ip; 346 id = ip->ip_id; 347 348 READ_ENTER(&softa->ipf_authlk); 349 for (i = softa->ipf_auth_start; i != softa->ipf_auth_end; ) { 350 /* 351 * index becomes -2 only after an SIOCAUTHW. Check this in 352 * case the same packet gets sent again and it hasn't yet been 353 * auth'd. 354 */ 355 fra = softa->ipf_auth + i; 356 if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 357 !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 358 /* 359 * Avoid feedback loop. 360 */ 361 if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) { 362 pass = FR_BLOCK; 363 fin->fin_reason = FRB_AUTHFEEDBACK; 364 } 365 /* 366 * Create a dummy rule for the stateful checking to 367 * use and return. Zero out any values we don't 368 * trust from userland! 369 */ 370 if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 371 (fin->fin_flx & FI_FRAG))) { 372 KMALLOC(fr, frentry_t *); 373 if (fr) { 374 bcopy((char *)fra->fra_info.fin_fr, 375 (char *)fr, sizeof(*fr)); 376 fr->fr_grp = NULL; 377 fr->fr_ifa = fin->fin_ifp; 378 fr->fr_func = NULL; 379 fr->fr_ref = 1; 380 fr->fr_flags = pass; 381 fr->fr_ifas[1] = NULL; 382 fr->fr_ifas[2] = NULL; 383 fr->fr_ifas[3] = NULL; 384 MUTEX_INIT(&fr->fr_lock, 385 "ipf auth rule"); 386 } 387 } else 388 fr = fra->fra_info.fin_fr; 389 fin->fin_fr = fr; 390 fin->fin_flx |= fra->fra_flx; 391 RWLOCK_EXIT(&softa->ipf_authlk); 392 393 WRITE_ENTER(&softa->ipf_authlk); 394 /* 395 * ipf_auth_rules is populated with the rules malloc'd 396 * above and only those. 397 */ 398 if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 399 fr->fr_next = softa->ipf_auth_rules; 400 softa->ipf_auth_rules = fr; 401 } 402 softa->ipf_auth_stats.fas_hits++; 403 fra->fra_index = -1; 404 softa->ipf_auth_used--; 405 softa->ipf_auth_replies--; 406 if (i == softa->ipf_auth_start) { 407 while (fra->fra_index == -1) { 408 i++; 409 fra++; 410 if (i == softa->ipf_auth_size) { 411 i = 0; 412 fra = softa->ipf_auth; 413 } 414 softa->ipf_auth_start = i; 415 if (i == softa->ipf_auth_end) 416 break; 417 } 418 if (softa->ipf_auth_start == 419 softa->ipf_auth_end) { 420 softa->ipf_auth_next = 0; 421 softa->ipf_auth_start = 0; 422 softa->ipf_auth_end = 0; 423 } 424 } 425 RWLOCK_EXIT(&softa->ipf_authlk); 426 if (passp != NULL) 427 *passp = pass; 428 softa->ipf_auth_stats.fas_hits++; 429 return (fr); 430 } 431 i++; 432 if (i == softa->ipf_auth_size) 433 i = 0; 434 } 435 RWLOCK_EXIT(&softa->ipf_authlk); 436 softa->ipf_auth_stats.fas_miss++; 437 return (NULL); 438 } 439 440 441 /* ------------------------------------------------------------------------ */ 442 /* Function: ipf_auth_new */ 443 /* Returns: int - 1 == success, 0 = did not put packet on auth queue */ 444 /* Parameters: m(I) - pointer to mb_t with packet in it */ 445 /* fin(I) - pointer to packet information */ 446 /* */ 447 /* Check if we have room in the auth array to hold details for another */ 448 /* packet. If we do, store it and wake up any user programs which are */ 449 /* waiting to hear about these events. */ 450 /* ------------------------------------------------------------------------ */ 451 int 452 ipf_auth_new(mb_t *m, fr_info_t *fin) 453 { 454 ipf_main_softc_t *softc = fin->fin_main_soft; 455 ipf_auth_softc_t *softa = softc->ipf_auth_soft; 456 #if defined(_KERNEL) && SOLARIS 457 qpktinfo_t *qpi = fin->fin_qpi; 458 #endif 459 frauth_t *fra; 460 #if !defined(sparc) && !defined(m68k) 461 ip_t *ip; 462 #endif 463 int i; 464 465 if (softa->ipf_auth_lock) 466 return (0); 467 468 WRITE_ENTER(&softa->ipf_authlk); 469 if (((softa->ipf_auth_end + 1) % softa->ipf_auth_size) == 470 softa->ipf_auth_start) { 471 softa->ipf_auth_stats.fas_nospace++; 472 RWLOCK_EXIT(&softa->ipf_authlk); 473 return (0); 474 } 475 476 softa->ipf_auth_stats.fas_added++; 477 softa->ipf_auth_used++; 478 i = softa->ipf_auth_end++; 479 if (softa->ipf_auth_end == softa->ipf_auth_size) 480 softa->ipf_auth_end = 0; 481 482 fra = softa->ipf_auth + i; 483 fra->fra_index = i; 484 if (fin->fin_fr != NULL) 485 fra->fra_pass = fin->fin_fr->fr_flags; 486 else 487 fra->fra_pass = 0; 488 fra->fra_age = softa->ipf_auth_defaultage; 489 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 490 fra->fra_flx = fra->fra_info.fin_flx & (FI_STATE|FI_NATED); 491 fra->fra_info.fin_flx &= ~(FI_STATE|FI_NATED); 492 #if !defined(sparc) && !defined(m68k) 493 /* 494 * No need to copyback here as we want to undo the changes, not keep 495 * them. 496 */ 497 ip = fin->fin_ip; 498 # if SOLARIS && defined(_KERNEL) 499 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 500 # endif 501 { 502 register u_short bo; 503 504 bo = ip->ip_len; 505 ip->ip_len = htons(bo); 506 bo = ip->ip_off; 507 ip->ip_off = htons(bo); 508 } 509 #endif 510 #if SOLARIS && defined(_KERNEL) 511 COPYIFNAME(fin->fin_v, fin->fin_ifp, fra->fra_info.fin_ifname); 512 m->b_rptr -= qpi->qpi_off; 513 fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ 514 fra->fra_m = *fin->fin_mp; 515 fra->fra_info.fin_mp = &fra->fra_m; 516 softa->ipf_auth_pkts[i] = *(mblk_t **)fin->fin_mp; 517 RWLOCK_EXIT(&softa->ipf_authlk); 518 cv_signal(&softa->ipf_auth_wait); 519 pollwakeup(&softc->ipf_poll_head[IPL_LOGAUTH], POLLIN|POLLRDNORM); 520 #else 521 softa->ipf_auth_pkts[i] = m; 522 RWLOCK_EXIT(&softa->ipf_authlk); 523 WAKEUP(&softa->ipf_auth_next, 0); 524 #endif 525 return (1); 526 } 527 528 529 /* ------------------------------------------------------------------------ */ 530 /* Function: ipf_auth_ioctl */ 531 /* Returns: int - 0 == success, else error */ 532 /* Parameters: data(IO) - pointer to ioctl data */ 533 /* cmd(I) - ioctl command */ 534 /* mode(I) - mode flags associated with open descriptor */ 535 /* uid(I) - uid associatd with application making the call */ 536 /* ctx(I) - pointer for context */ 537 /* */ 538 /* This function handles all of the ioctls recognised by the auth component */ 539 /* in IPFilter - ie ioctls called on an open fd for /dev/ipf_auth */ 540 /* ------------------------------------------------------------------------ */ 541 int 542 ipf_auth_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, 543 int mode, int uid, void *ctx) 544 { 545 ipf_auth_softc_t *softa = softc->ipf_auth_soft; 546 int error = 0, i; 547 SPL_INT(s); 548 549 switch (cmd) 550 { 551 case SIOCGENITER : 552 { 553 ipftoken_t *token; 554 ipfgeniter_t iter; 555 ipfobj_t obj; 556 557 error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER); 558 if (error != 0) 559 break; 560 561 SPL_SCHED(s); 562 token = ipf_token_find(softc, IPFGENITER_AUTH, uid, ctx); 563 if (token != NULL) 564 error = ipf_auth_geniter(softc, token, &iter, &obj); 565 else { 566 WRITE_ENTER(&softc->ipf_tokens); 567 ipf_token_deref(softc, token); 568 RWLOCK_EXIT(&softc->ipf_tokens); 569 IPFERROR(10001); 570 error = ESRCH; 571 } 572 SPL_X(s); 573 574 break; 575 } 576 577 case SIOCADAFR : 578 case SIOCRMAFR : 579 if (!(mode & FWRITE)) { 580 IPFERROR(10002); 581 error = EPERM; 582 } else 583 error = frrequest(softc, IPL_LOGAUTH, cmd, data, 584 softc->ipf_active, 1); 585 break; 586 587 case SIOCSTLCK : 588 if (!(mode & FWRITE)) { 589 IPFERROR(10003); 590 error = EPERM; 591 } else { 592 error = ipf_lock(data, &softa->ipf_auth_lock); 593 } 594 break; 595 596 case SIOCATHST: 597 softa->ipf_auth_stats.fas_faelist = softa->ipf_auth_entries; 598 error = ipf_outobj(softc, data, &softa->ipf_auth_stats, 599 IPFOBJ_AUTHSTAT); 600 break; 601 602 case SIOCIPFFL: 603 SPL_NET(s); 604 WRITE_ENTER(&softa->ipf_authlk); 605 i = ipf_auth_flush(softa); 606 RWLOCK_EXIT(&softa->ipf_authlk); 607 SPL_X(s); 608 error = BCOPYOUT(&i, data, sizeof(i)); 609 if (error != 0) { 610 IPFERROR(10004); 611 error = EFAULT; 612 } 613 break; 614 615 case SIOCAUTHW: 616 error = ipf_auth_wait(softc, softa, data); 617 break; 618 619 case SIOCAUTHR: 620 error = ipf_auth_reply(softc, softa, data); 621 break; 622 623 default : 624 IPFERROR(10005); 625 error = EINVAL; 626 break; 627 } 628 return (error); 629 } 630 631 632 /* ------------------------------------------------------------------------ */ 633 /* Function: ipf_auth_expire */ 634 /* Returns: None */ 635 /* Parameters: None */ 636 /* */ 637 /* Slowly expire held auth records. Timeouts are set in expectation of */ 638 /* this being called twice per second. */ 639 /* ------------------------------------------------------------------------ */ 640 void 641 ipf_auth_expire(ipf_main_softc_t *softc) 642 { 643 ipf_auth_softc_t *softa = softc->ipf_auth_soft; 644 frauthent_t *fae, **faep; 645 frentry_t *fr, **frp; 646 frauth_t *fra; 647 mb_t *m; 648 int i; 649 SPL_INT(s); 650 651 if (softa->ipf_auth_lock) 652 return; 653 SPL_NET(s); 654 WRITE_ENTER(&softa->ipf_authlk); 655 for (i = 0, fra = softa->ipf_auth; i < softa->ipf_auth_size; 656 i++, fra++) { 657 fra->fra_age--; 658 if ((fra->fra_age == 0) && 659 (softa->ipf_auth[i].fra_index != -1)) { 660 if ((m = softa->ipf_auth_pkts[i]) != NULL) { 661 FREE_MB_T(m); 662 softa->ipf_auth_pkts[i] = NULL; 663 } else if (softa->ipf_auth[i].fra_index == -2) { 664 softa->ipf_auth_replies--; 665 } 666 softa->ipf_auth[i].fra_index = -1; 667 softa->ipf_auth_stats.fas_expire++; 668 softa->ipf_auth_used--; 669 } 670 } 671 672 /* 673 * Expire pre-auth rules 674 */ 675 for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) { 676 fae->fae_age--; 677 if (fae->fae_age == 0) { 678 ipf_auth_deref(&fae); 679 softa->ipf_auth_stats.fas_expire++; 680 } else 681 faep = &fae->fae_next; 682 } 683 if (softa->ipf_auth_entries != NULL) 684 softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr; 685 else 686 softa->ipf_auth_ip = NULL; 687 688 for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) { 689 if (fr->fr_ref == 1) { 690 *frp = fr->fr_next; 691 MUTEX_DESTROY(&fr->fr_lock); 692 KFREE(fr); 693 } else 694 frp = &fr->fr_next; 695 } 696 RWLOCK_EXIT(&softa->ipf_authlk); 697 SPL_X(s); 698 } 699 700 701 /* ------------------------------------------------------------------------ */ 702 /* Function: ipf_auth_precmd */ 703 /* Returns: int - 0 == success, else error */ 704 /* Parameters: cmd(I) - ioctl command for rule */ 705 /* fr(I) - pointer to ipf rule */ 706 /* fptr(I) - pointer to caller's 'fr' */ 707 /* */ 708 /* ------------------------------------------------------------------------ */ 709 int 710 ipf_auth_precmd(ipf_main_softc_t *softc, ioctlcmd_t cmd, frentry_t *fr, 711 frentry_t **frptr) 712 { 713 ipf_auth_softc_t *softa = softc->ipf_auth_soft; 714 frauthent_t *fae, **faep; 715 int error = 0; 716 SPL_INT(s); 717 718 if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) { 719 IPFERROR(10006); 720 return (EIO); 721 } 722 723 for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) { 724 if (&fae->fae_fr == fr) 725 break; 726 else 727 faep = &fae->fae_next; 728 } 729 730 if (cmd == (ioctlcmd_t)SIOCRMAFR) { 731 if (fr == NULL || frptr == NULL) { 732 IPFERROR(10007); 733 error = EINVAL; 734 735 } else if (fae == NULL) { 736 IPFERROR(10008); 737 error = ESRCH; 738 739 } else { 740 SPL_NET(s); 741 WRITE_ENTER(&softa->ipf_authlk); 742 *faep = fae->fae_next; 743 if (softa->ipf_auth_ip == &fae->fae_fr) 744 softa->ipf_auth_ip = softa->ipf_auth_entries ? 745 &softa->ipf_auth_entries->fae_fr : NULL; 746 RWLOCK_EXIT(&softa->ipf_authlk); 747 SPL_X(s); 748 749 KFREE(fae); 750 } 751 } else if (fr != NULL && frptr != NULL) { 752 KMALLOC(fae, frauthent_t *); 753 if (fae != NULL) { 754 bcopy((char *)fr, (char *)&fae->fae_fr, 755 sizeof(*fr)); 756 SPL_NET(s); 757 WRITE_ENTER(&softa->ipf_authlk); 758 fae->fae_age = softa->ipf_auth_defaultage; 759 fae->fae_fr.fr_hits = 0; 760 fae->fae_fr.fr_next = *frptr; 761 fae->fae_ref = 1; 762 *frptr = &fae->fae_fr; 763 fae->fae_next = *faep; 764 *faep = fae; 765 softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr; 766 RWLOCK_EXIT(&softa->ipf_authlk); 767 SPL_X(s); 768 } else { 769 IPFERROR(10009); 770 error = ENOMEM; 771 } 772 } else { 773 IPFERROR(10010); 774 error = EINVAL; 775 } 776 return (error); 777 } 778 779 780 /* ------------------------------------------------------------------------ */ 781 /* Function: ipf_auth_flush */ 782 /* Returns: int - number of auth entries flushed */ 783 /* Parameters: None */ 784 /* Locks: WRITE(ipf_authlk) */ 785 /* */ 786 /* This function flushs the ipf_auth_pkts array of any packet data with */ 787 /* references still there. */ 788 /* It is expected that the caller has already acquired the correct locks or */ 789 /* set the priority level correctly for this to block out other code paths */ 790 /* into these data structures. */ 791 /* ------------------------------------------------------------------------ */ 792 static int 793 ipf_auth_flush(void *arg) 794 { 795 ipf_auth_softc_t *softa = arg; 796 int i, num_flushed; 797 mb_t *m; 798 799 if (softa->ipf_auth_lock) 800 return (-1); 801 802 num_flushed = 0; 803 804 for (i = 0 ; i < softa->ipf_auth_size; i++) { 805 if (softa->ipf_auth[i].fra_index != -1) { 806 m = softa->ipf_auth_pkts[i]; 807 if (m != NULL) { 808 FREE_MB_T(m); 809 softa->ipf_auth_pkts[i] = NULL; 810 } 811 812 softa->ipf_auth[i].fra_index = -1; 813 /* perhaps add & use a flush counter inst.*/ 814 softa->ipf_auth_stats.fas_expire++; 815 num_flushed++; 816 } 817 } 818 819 softa->ipf_auth_start = 0; 820 softa->ipf_auth_end = 0; 821 softa->ipf_auth_next = 0; 822 softa->ipf_auth_used = 0; 823 softa->ipf_auth_replies = 0; 824 825 return (num_flushed); 826 } 827 828 829 /* ------------------------------------------------------------------------ */ 830 /* Function: ipf_auth_waiting */ 831 /* Returns: int - number of packets in the auth queue */ 832 /* Parameters: None */ 833 /* */ 834 /* Simple truth check to see if there are any packets waiting in the auth */ 835 /* queue. */ 836 /* ------------------------------------------------------------------------ */ 837 int 838 ipf_auth_waiting(ipf_main_softc_t *softc) 839 { 840 ipf_auth_softc_t *softa = softc->ipf_auth_soft; 841 842 return (softa->ipf_auth_used != 0); 843 } 844 845 846 /* ------------------------------------------------------------------------ */ 847 /* Function: ipf_auth_geniter */ 848 /* Returns: int - 0 == success, else error */ 849 /* Parameters: token(I) - pointer to ipftoken structure */ 850 /* itp(I) - pointer to ipfgeniter structure */ 851 /* objp(I) - pointer to ipf object destription */ 852 /* */ 853 /* Iterate through the list of entries in the auth queue list. */ 854 /* objp is used here to get the location of where to do the copy out to. */ 855 /* Stomping over various fields with new information will not harm anything */ 856 /* ------------------------------------------------------------------------ */ 857 static int 858 ipf_auth_geniter(ipf_main_softc_t *softc, ipftoken_t *token, 859 ipfgeniter_t *itp, ipfobj_t *objp) 860 { 861 ipf_auth_softc_t *softa = softc->ipf_auth_soft; 862 frauthent_t *fae, *next, zero; 863 int error; 864 865 if (itp->igi_data == NULL) { 866 IPFERROR(10011); 867 return (EFAULT); 868 } 869 870 if (itp->igi_type != IPFGENITER_AUTH) { 871 IPFERROR(10012); 872 return (EINVAL); 873 } 874 875 objp->ipfo_type = IPFOBJ_FRAUTH; 876 objp->ipfo_ptr = itp->igi_data; 877 objp->ipfo_size = sizeof(frauth_t); 878 879 READ_ENTER(&softa->ipf_authlk); 880 881 fae = token->ipt_data; 882 if (fae == NULL) { 883 next = softa->ipf_auth_entries; 884 } else { 885 next = fae->fae_next; 886 } 887 888 /* 889 * If we found an auth entry to use, bump its reference count 890 * so that it can be used for is_next when we come back. 891 */ 892 if (next != NULL) { 893 ATOMIC_INC(next->fae_ref); 894 token->ipt_data = next; 895 } else { 896 bzero(&zero, sizeof(zero)); 897 next = &zero; 898 token->ipt_data = NULL; 899 } 900 901 RWLOCK_EXIT(&softa->ipf_authlk); 902 903 error = ipf_outobjk(softc, objp, next); 904 if (fae != NULL) 905 ipf_auth_deref_unlocked(softa, &fae); 906 907 if (next->fae_next == NULL) 908 ipf_token_mark_complete(token); 909 return (error); 910 } 911 912 913 /* ------------------------------------------------------------------------ */ 914 /* Function: ipf_auth_deref_unlocked */ 915 /* Returns: None */ 916 /* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */ 917 /* */ 918 /* Wrapper for ipf_auth_deref for when a write lock on ipf_authlk is not */ 919 /* held. */ 920 /* ------------------------------------------------------------------------ */ 921 static void 922 ipf_auth_deref_unlocked(ipf_auth_softc_t *softa, frauthent_t **faep) 923 { 924 WRITE_ENTER(&softa->ipf_authlk); 925 ipf_auth_deref(faep); 926 RWLOCK_EXIT(&softa->ipf_authlk); 927 } 928 929 930 /* ------------------------------------------------------------------------ */ 931 /* Function: ipf_auth_deref */ 932 /* Returns: None */ 933 /* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */ 934 /* Locks: WRITE(ipf_authlk) */ 935 /* */ 936 /* This function unconditionally sets the pointer in the caller to NULL, */ 937 /* to make it clear that it should no longer use that pointer, and drops */ 938 /* the reference count on the structure by 1. If it reaches 0, free it up. */ 939 /* ------------------------------------------------------------------------ */ 940 static void 941 ipf_auth_deref(frauthent_t **faep) 942 { 943 frauthent_t *fae; 944 945 fae = *faep; 946 *faep = NULL; 947 948 fae->fae_ref--; 949 if (fae->fae_ref == 0) { 950 KFREE(fae); 951 } 952 } 953 954 955 /* ------------------------------------------------------------------------ */ 956 /* Function: ipf_auth_wait_pkt */ 957 /* Returns: int - 0 == success, else error */ 958 /* Parameters: data(I) - pointer to data from ioctl call */ 959 /* */ 960 /* This function is called when an application is waiting for a packet to */ 961 /* match an "auth" rule by issuing an SIOCAUTHW ioctl. If there is already */ 962 /* a packet waiting on the queue then we will return that _one_ immediately.*/ 963 /* If there are no packets present in the queue (ipf_auth_pkts) then we go */ 964 /* to sleep. */ 965 /* ------------------------------------------------------------------------ */ 966 static int 967 ipf_auth_wait(ipf_main_softc_t *softc, ipf_auth_softc_t *softa, char *data) 968 { 969 frauth_t auth, *au = &auth; 970 int error, len, i; 971 mb_t *m; 972 char *t; 973 SPL_INT(s); 974 975 ipf_auth_ioctlloop: 976 error = ipf_inobj(softc, data, NULL, au, IPFOBJ_FRAUTH); 977 if (error != 0) 978 return (error); 979 980 /* 981 * XXX Locks are held below over calls to copyout...a better 982 * solution needs to be found so this isn't necessary. The situation 983 * we are trying to guard against here is an error in the copyout 984 * steps should not cause the packet to "disappear" from the queue. 985 */ 986 SPL_NET(s); 987 READ_ENTER(&softa->ipf_authlk); 988 989 /* 990 * If ipf_auth_next is not equal to ipf_auth_end it will be because 991 * there is a packet waiting to be delt with in the ipf_auth_pkts 992 * array. We copy as much of that out to user space as requested. 993 */ 994 if (softa->ipf_auth_used > 0) { 995 while (softa->ipf_auth_pkts[softa->ipf_auth_next] == NULL) { 996 softa->ipf_auth_next++; 997 if (softa->ipf_auth_next == softa->ipf_auth_size) 998 softa->ipf_auth_next = 0; 999 } 1000 1001 error = ipf_outobj(softc, data, 1002 &softa->ipf_auth[softa->ipf_auth_next], 1003 IPFOBJ_FRAUTH); 1004 if (error != 0) { 1005 RWLOCK_EXIT(&softa->ipf_authlk); 1006 SPL_X(s); 1007 return (error); 1008 } 1009 1010 if (auth.fra_len != 0 && auth.fra_buf != NULL) { 1011 /* 1012 * Copy packet contents out to user space if 1013 * requested. Bail on an error. 1014 */ 1015 m = softa->ipf_auth_pkts[softa->ipf_auth_next]; 1016 len = MSGDSIZE(m); 1017 if (len > auth.fra_len) 1018 len = auth.fra_len; 1019 auth.fra_len = len; 1020 1021 for (t = auth.fra_buf; m && (len > 0); ) { 1022 i = MIN(M_LEN(m), len); 1023 error = copyoutptr(softc, MTOD(m, char *), 1024 &t, i); 1025 len -= i; 1026 t += i; 1027 if (error != 0) { 1028 RWLOCK_EXIT(&softa->ipf_authlk); 1029 SPL_X(s); 1030 return (error); 1031 } 1032 m = m->m_next; 1033 } 1034 } 1035 RWLOCK_EXIT(&softa->ipf_authlk); 1036 1037 SPL_NET(s); 1038 WRITE_ENTER(&softa->ipf_authlk); 1039 softa->ipf_auth_next++; 1040 if (softa->ipf_auth_next == softa->ipf_auth_size) 1041 softa->ipf_auth_next = 0; 1042 RWLOCK_EXIT(&softa->ipf_authlk); 1043 SPL_X(s); 1044 1045 return (0); 1046 } 1047 RWLOCK_EXIT(&softa->ipf_authlk); 1048 SPL_X(s); 1049 1050 MUTEX_ENTER(&softa->ipf_auth_mx); 1051 #ifdef _KERNEL 1052 # if SOLARIS 1053 error = 0; 1054 if (!cv_wait_sig(&softa->ipf_auth_wait, &softa->ipf_auth_mx.ipf_lk)) { 1055 IPFERROR(10014); 1056 error = EINTR; 1057 } 1058 # else /* SOLARIS */ 1059 error = SLEEP(&softa->ipf_auth_next, "ipf_auth_next"); 1060 # endif /* SOLARIS */ 1061 #endif 1062 MUTEX_EXIT(&softa->ipf_auth_mx); 1063 if (error == 0) 1064 goto ipf_auth_ioctlloop; 1065 return (error); 1066 } 1067 1068 1069 /* ------------------------------------------------------------------------ */ 1070 /* Function: ipf_auth_reply */ 1071 /* Returns: int - 0 == success, else error */ 1072 /* Parameters: data(I) - pointer to data from ioctl call */ 1073 /* */ 1074 /* This function is called by an application when it wants to return a */ 1075 /* decision on a packet using the SIOCAUTHR ioctl. This is after it has */ 1076 /* received information using an SIOCAUTHW. The decision returned in the */ 1077 /* form of flags, the same as those used in each rule. */ 1078 /* ------------------------------------------------------------------------ */ 1079 static int 1080 ipf_auth_reply(ipf_main_softc_t *softc, ipf_auth_softc_t *softa, char *data) 1081 { 1082 frauth_t auth, *au = &auth, *fra; 1083 fr_info_t fin; 1084 int error, i; 1085 mb_t *m; 1086 SPL_INT(s); 1087 1088 error = ipf_inobj(softc, data, NULL, &auth, IPFOBJ_FRAUTH); 1089 if (error != 0) 1090 return (error); 1091 1092 SPL_NET(s); 1093 WRITE_ENTER(&softa->ipf_authlk); 1094 1095 i = au->fra_index; 1096 fra = softa->ipf_auth + i; 1097 error = 0; 1098 1099 /* 1100 * Check the validity of the information being returned with two simple 1101 * checks. First, the auth index value should be within the size of 1102 * the array and second the packet id being returned should also match. 1103 */ 1104 if ((i < 0) || (i >= softa->ipf_auth_size)) { 1105 RWLOCK_EXIT(&softa->ipf_authlk); 1106 SPL_X(s); 1107 IPFERROR(10015); 1108 return (ESRCH); 1109 } 1110 if (fra->fra_info.fin_id != au->fra_info.fin_id) { 1111 RWLOCK_EXIT(&softa->ipf_authlk); 1112 SPL_X(s); 1113 IPFERROR(10019); 1114 return (ESRCH); 1115 } 1116 1117 m = softa->ipf_auth_pkts[i]; 1118 fra->fra_index = -2; 1119 fra->fra_pass = au->fra_pass; 1120 softa->ipf_auth_pkts[i] = NULL; 1121 softa->ipf_auth_replies++; 1122 bcopy(&fra->fra_info, &fin, sizeof(fin)); 1123 1124 RWLOCK_EXIT(&softa->ipf_authlk); 1125 1126 /* 1127 * Re-insert the packet back into the packet stream flowing through 1128 * the kernel in a manner that will mean IPFilter sees the packet 1129 * again. This is not the same as is done with fastroute, 1130 * deliberately, as we want to resume the normal packet processing 1131 * path for it. 1132 */ 1133 #ifdef _KERNEL 1134 if ((m != NULL) && (au->fra_info.fin_out != 0)) { 1135 error = ipf_inject(&fin, m); 1136 if (error != 0) { 1137 IPFERROR(10016); 1138 error = ENOBUFS; 1139 softa->ipf_auth_stats.fas_sendfail++; 1140 } else { 1141 softa->ipf_auth_stats.fas_sendok++; 1142 } 1143 } else if (m) { 1144 error = ipf_inject(&fin, m); 1145 if (error != 0) { 1146 IPFERROR(10017); 1147 error = ENOBUFS; 1148 softa->ipf_auth_stats.fas_quefail++; 1149 } else { 1150 softa->ipf_auth_stats.fas_queok++; 1151 } 1152 } else { 1153 IPFERROR(10018); 1154 error = EINVAL; 1155 } 1156 1157 /* 1158 * If we experience an error which will result in the packet 1159 * not being processed, make sure we advance to the next one. 1160 */ 1161 if (error == ENOBUFS) { 1162 WRITE_ENTER(&softa->ipf_authlk); 1163 softa->ipf_auth_used--; 1164 fra->fra_index = -1; 1165 fra->fra_pass = 0; 1166 if (i == softa->ipf_auth_start) { 1167 while (fra->fra_index == -1) { 1168 i++; 1169 if (i == softa->ipf_auth_size) 1170 i = 0; 1171 softa->ipf_auth_start = i; 1172 if (i == softa->ipf_auth_end) 1173 break; 1174 } 1175 if (softa->ipf_auth_start == softa->ipf_auth_end) { 1176 softa->ipf_auth_next = 0; 1177 softa->ipf_auth_start = 0; 1178 softa->ipf_auth_end = 0; 1179 } 1180 } 1181 RWLOCK_EXIT(&softa->ipf_authlk); 1182 } 1183 #endif /* _KERNEL */ 1184 SPL_X(s); 1185 1186 return (0); 1187 } 1188 1189 1190 u_32_t 1191 ipf_auth_pre_scanlist(ipf_main_softc_t *softc, fr_info_t *fin, u_32_t pass) 1192 { 1193 ipf_auth_softc_t *softa = softc->ipf_auth_soft; 1194 1195 if (softa->ipf_auth_ip != NULL) 1196 return (ipf_scanlist(fin, softc->ipf_pass)); 1197 1198 return (pass); 1199 } 1200 1201 1202 frentry_t ** 1203 ipf_auth_rulehead(ipf_main_softc_t *softc) 1204 { 1205 ipf_auth_softc_t *softa = softc->ipf_auth_soft; 1206 1207 return (&softa->ipf_auth_ip); 1208 } 1209