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