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