ip_auth.c revision 170268
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_auth.c 170268 2007-06-04 02:54:36Z darrenr $ */ 2 3/* 4 * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. 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# include <string.h> 23# define _KERNEL 24# ifdef __OpenBSD__ 25struct file; 26# endif 27# include <sys/uio.h> 28# undef _KERNEL 29#endif 30#if defined(_KERNEL) && (__FreeBSD_version >= 220000) 31# include <sys/filio.h> 32# include <sys/fcntl.h> 33#else 34# include <sys/ioctl.h> 35#endif 36#if !defined(linux) 37# include <sys/protosw.h> 38#endif 39#include <sys/socket.h> 40#if defined(_KERNEL) 41# include <sys/systm.h> 42# if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) 43# include <sys/mbuf.h> 44# endif 45#endif 46#if defined(__SVR4) || defined(__svr4__) 47# include <sys/filio.h> 48# include <sys/byteorder.h> 49# ifdef _KERNEL 50# include <sys/dditypes.h> 51# endif 52# include <sys/stream.h> 53# include <sys/kmem.h> 54#endif 55#if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199802) || \ 56 (__FreeBSD_version >= 400000) 57# include <sys/queue.h> 58#endif 59#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 60# include <machine/cpu.h> 61#endif 62#if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 63# include <sys/proc.h> 64#endif 65#include <net/if.h> 66#ifdef sun 67# include <net/af.h> 68#endif 69#include <net/route.h> 70#include <netinet/in.h> 71#include <netinet/in_systm.h> 72#include <netinet/ip.h> 73#if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) 74# define KERNEL 75# define _KERNEL 76# define NOT_KERNEL 77#endif 78#if !defined(linux) 79# include <netinet/ip_var.h> 80#endif 81#ifdef NOT_KERNEL 82# undef _KERNEL 83# undef KERNEL 84#endif 85#include <netinet/tcp.h> 86#if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ 87extern struct ifqueue ipintrq; /* ip packet input queue */ 88#else 89# if !defined(__hpux) && !defined(linux) 90# if __FreeBSD_version >= 300000 91# include <net/if_var.h> 92# if __FreeBSD_version >= 500042 93# define IF_QFULL _IF_QFULL 94# define IF_DROP _IF_DROP 95# endif /* __FreeBSD_version >= 500042 */ 96# endif 97# include <netinet/in_var.h> 98# include <netinet/tcp_fsm.h> 99# endif 100#endif 101#include <netinet/udp.h> 102#include <netinet/ip_icmp.h> 103#include "netinet/ip_compat.h" 104#include <netinet/tcpip.h> 105#include "netinet/ip_fil.h" 106#include "netinet/ip_auth.h" 107#if !defined(MENTAT) && !defined(linux) 108# include <net/netisr.h> 109# ifdef __FreeBSD__ 110# include <machine/cpufunc.h> 111# endif 112#endif 113#if (__FreeBSD_version >= 300000) 114# include <sys/malloc.h> 115# if defined(_KERNEL) && !defined(IPFILTER_LKM) 116# include <sys/libkern.h> 117# include <sys/systm.h> 118# endif 119#endif 120/* END OF INCLUDES */ 121 122#if !defined(lint) 123static const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_auth.c 170268 2007-06-04 02:54:36Z darrenr $"; 124/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.13 2006/03/29 11:19:55 darrenr Exp $"; */ 125#endif 126 127 128#if SOLARIS && defined(_KERNEL) 129extern kcondvar_t ipfauthwait; 130extern struct pollhead iplpollhead[IPL_LOGSIZE]; 131#endif /* SOLARIS */ 132#if defined(linux) && defined(_KERNEL) 133wait_queue_head_t fr_authnext_linux; 134#endif 135 136int fr_authsize = FR_NUMAUTH; 137int fr_authused = 0; 138int fr_defaultauthage = 600; 139int fr_auth_lock = 0; 140int fr_auth_init = 0; 141fr_authstat_t fr_authstats; 142static frauth_t *fr_auth = NULL; 143mb_t **fr_authpkts = NULL; 144int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; 145frauthent_t *fae_list = NULL; 146frentry_t *ipauth = NULL, 147 *fr_authlist = NULL; 148 149void fr_authderef __P((frauthent_t **)); 150int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *)); 151int fr_authreply __P((char *)); 152int fr_authwait __P((char *)); 153 154/* ------------------------------------------------------------------------ */ 155/* Function: fr_authinit */ 156/* Returns: int - 0 == success, else error */ 157/* Parameters: None */ 158/* */ 159/* Allocate memory and initialise data structures used in handling auth */ 160/* rules. */ 161/* ------------------------------------------------------------------------ */ 162int fr_authinit() 163{ 164 KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth)); 165 if (fr_auth != NULL) 166 bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth)); 167 else 168 return -1; 169 170 KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts)); 171 if (fr_authpkts != NULL) 172 bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 173 else 174 return -2; 175 176 MUTEX_INIT(&ipf_authmx, "ipf auth log mutex"); 177 RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock"); 178#if SOLARIS && defined(_KERNEL) 179 cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); 180#endif 181#if defined(linux) && defined(_KERNEL) 182 init_waitqueue_head(&fr_authnext_linux); 183#endif 184 185 fr_auth_init = 1; 186 187 return 0; 188} 189 190 191/* ------------------------------------------------------------------------ */ 192/* Function: fr_checkauth */ 193/* Returns: frentry_t* - pointer to ipf rule if match found, else NULL */ 194/* Parameters: fin(I) - pointer to ipftoken structure */ 195/* passp(I) - pointer to ipfgeniter structure */ 196/* */ 197/* Check if a packet has authorization. If the packet is found to match an */ 198/* authorization result and that would result in a feedback loop (i.e. it */ 199/* will end up returning FR_AUTH) then return FR_BLOCK instead. */ 200/* ------------------------------------------------------------------------ */ 201frentry_t *fr_checkauth(fin, passp) 202fr_info_t *fin; 203u_32_t *passp; 204{ 205 frentry_t *fr; 206 frauth_t *fra; 207 u_32_t pass; 208 u_short id; 209 ip_t *ip; 210 int i; 211 212 if (fr_auth_lock || !fr_authused) 213 return NULL; 214 215 ip = fin->fin_ip; 216 id = ip->ip_id; 217 218 READ_ENTER(&ipf_auth); 219 for (i = fr_authstart; i != fr_authend; ) { 220 /* 221 * index becomes -2 only after an SIOCAUTHW. Check this in 222 * case the same packet gets sent again and it hasn't yet been 223 * auth'd. 224 */ 225 fra = fr_auth + i; 226 if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 227 !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 228 /* 229 * Avoid feedback loop. 230 */ 231 if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) 232 pass = FR_BLOCK; 233 /* 234 * Create a dummy rule for the stateful checking to 235 * use and return. Zero out any values we don't 236 * trust from userland! 237 */ 238 if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 239 (fin->fin_flx & FI_FRAG))) { 240 KMALLOC(fr, frentry_t *); 241 if (fr) { 242 bcopy((char *)fra->fra_info.fin_fr, 243 (char *)fr, sizeof(*fr)); 244 fr->fr_grp = NULL; 245 fr->fr_ifa = fin->fin_ifp; 246 fr->fr_func = NULL; 247 fr->fr_ref = 1; 248 fr->fr_flags = pass; 249 fr->fr_ifas[1] = NULL; 250 fr->fr_ifas[2] = NULL; 251 fr->fr_ifas[3] = NULL; 252 } 253 } else 254 fr = fra->fra_info.fin_fr; 255 fin->fin_fr = fr; 256 RWLOCK_EXIT(&ipf_auth); 257 258 WRITE_ENTER(&ipf_auth); 259 /* 260 * fr_authlist is populated with the rules malloc'd 261 * above and only those. 262 */ 263 if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 264 fr->fr_next = fr_authlist; 265 fr_authlist = fr; 266 } 267 fr_authstats.fas_hits++; 268 fra->fra_index = -1; 269 fr_authused--; 270 if (i == fr_authstart) { 271 while (fra->fra_index == -1) { 272 i++; 273 fra++; 274 if (i == fr_authsize) { 275 i = 0; 276 fra = fr_auth; 277 } 278 fr_authstart = i; 279 if (i == fr_authend) 280 break; 281 } 282 if (fr_authstart == fr_authend) { 283 fr_authnext = 0; 284 fr_authstart = fr_authend = 0; 285 } 286 } 287 RWLOCK_EXIT(&ipf_auth); 288 if (passp != NULL) 289 *passp = pass; 290 ATOMIC_INC64(fr_authstats.fas_hits); 291 return fr; 292 } 293 i++; 294 if (i == fr_authsize) 295 i = 0; 296 } 297 fr_authstats.fas_miss++; 298 RWLOCK_EXIT(&ipf_auth); 299 ATOMIC_INC64(fr_authstats.fas_miss); 300 return NULL; 301} 302 303 304/* ------------------------------------------------------------------------ */ 305/* Function: fr_newauth */ 306/* Returns: int - 0 == success, else error */ 307/* Parameters: m(I) - pointer to mb_t with packet in it */ 308/* fin(I) - pointer to packet information */ 309/* */ 310/* Check if we have room in the auth array to hold details for another */ 311/* packet. If we do, store it and wake up any user programs which are */ 312/* waiting to hear about these events. */ 313/* ------------------------------------------------------------------------ */ 314int fr_newauth(m, fin) 315mb_t *m; 316fr_info_t *fin; 317{ 318#if defined(_KERNEL) && defined(MENTAT) 319 qpktinfo_t *qpi = fin->fin_qpi; 320#endif 321 frauth_t *fra; 322#if !defined(sparc) && !defined(m68k) 323 ip_t *ip; 324#endif 325 int i; 326 327 if (fr_auth_lock) 328 return 0; 329 330 WRITE_ENTER(&ipf_auth); 331 if (fr_authstart > fr_authend) { 332 fr_authstats.fas_nospace++; 333 RWLOCK_EXIT(&ipf_auth); 334 return 0; 335 } else { 336 if (fr_authused == fr_authsize) { 337 fr_authstats.fas_nospace++; 338 RWLOCK_EXIT(&ipf_auth); 339 return 0; 340 } 341 } 342 343 fr_authstats.fas_added++; 344 fr_authused++; 345 i = fr_authend++; 346 if (fr_authend == fr_authsize) 347 fr_authend = 0; 348 RWLOCK_EXIT(&ipf_auth); 349 350 fra = fr_auth + i; 351 fra->fra_index = i; 352 if (fin->fin_fr != NULL) 353 fra->fra_pass = fin->fin_fr->fr_flags; 354 else 355 fra->fra_pass = 0; 356 fra->fra_age = fr_defaultauthage; 357 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 358#if !defined(sparc) && !defined(m68k) 359 /* 360 * No need to copyback here as we want to undo the changes, not keep 361 * them. 362 */ 363 ip = fin->fin_ip; 364# if defined(MENTAT) && defined(_KERNEL) 365 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 366# endif 367 { 368 register u_short bo; 369 370 bo = ip->ip_len; 371 ip->ip_len = htons(bo); 372 bo = ip->ip_off; 373 ip->ip_off = htons(bo); 374 } 375#endif 376#if SOLARIS && defined(_KERNEL) 377 COPYIFNAME(fin->fin_ifp, fra->fra_info.fin_ifname); 378 m->b_rptr -= qpi->qpi_off; 379 fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 380 fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ 381 fra->fra_m = *fin->fin_mp; 382 fra->fra_info.fin_mp = &fra->fra_m; 383 cv_signal(&ipfauthwait); 384 pollwakeup(&iplpollhead[IPL_LOGAUTH], POLLIN|POLLRDNORM); 385#else 386 fr_authpkts[i] = m; 387 WAKEUP(&fr_authnext,0); 388#endif 389 return 1; 390} 391 392 393/* ------------------------------------------------------------------------ */ 394/* Function: fr_auth_ioctl */ 395/* Returns: int - 0 == success, else error */ 396/* Parameters: data(IO) - pointer to ioctl data */ 397/* cmd(I) - ioctl command */ 398/* mode(I) - mode flags associated with open descriptor */ 399/* uid(I) - uid associatd with application making the call */ 400/* ctx(I) - pointer for context */ 401/* */ 402/* This function handles all of the ioctls recognised by the auth component */ 403/* in IPFilter - ie ioctls called on an open fd for /dev/ipauth */ 404/* ------------------------------------------------------------------------ */ 405int fr_auth_ioctl(data, cmd, mode, uid, ctx) 406caddr_t data; 407ioctlcmd_t cmd; 408int mode, uid; 409void *ctx; 410{ 411 int error = 0, i; 412 SPL_INT(s); 413 414 switch (cmd) 415 { 416 case SIOCGENITER : 417 { 418 ipftoken_t *token; 419 ipfgeniter_t iter; 420 421 error = fr_inobj(data, &iter, IPFOBJ_GENITER); 422 if (error != 0) 423 break; 424 425 SPL_SCHED(s); 426 token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx); 427 if (token != NULL) 428 error = fr_authgeniter(token, &iter); 429 else 430 error = ESRCH; 431 RWLOCK_EXIT(&ipf_tokens); 432 SPL_X(s); 433 434 break; 435 } 436 437 case SIOCADAFR : 438 case SIOCRMAFR : 439 if (!(mode & FWRITE)) 440 error = EPERM; 441 else 442 error = frrequest(IPL_LOGAUTH, cmd, data, 443 fr_active, 1); 444 break; 445 446 case SIOCSTLCK : 447 if (!(mode & FWRITE)) { 448 error = EPERM; 449 break; 450 } 451 fr_lock(data, &fr_auth_lock); 452 break; 453 454 case SIOCATHST: 455 fr_authstats.fas_faelist = fae_list; 456 error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT); 457 break; 458 459 case SIOCIPFFL: 460 SPL_NET(s); 461 WRITE_ENTER(&ipf_auth); 462 i = fr_authflush(); 463 RWLOCK_EXIT(&ipf_auth); 464 SPL_X(s); 465 error = BCOPYOUT((char *)&i, data, sizeof(i)); 466 if (error != 0) 467 error = EFAULT; 468 break; 469 470 case SIOCAUTHW: 471 error = fr_authwait(data); 472 break; 473 474 case SIOCAUTHR: 475 error = fr_authreply(data); 476 break; 477 478 default : 479 error = EINVAL; 480 break; 481 } 482 return error; 483} 484 485 486/* ------------------------------------------------------------------------ */ 487/* Function: fr_authunload */ 488/* Returns: None */ 489/* Parameters: None */ 490/* */ 491/* Free all network buffer memory used to keep saved packets. */ 492/* ------------------------------------------------------------------------ */ 493void fr_authunload() 494{ 495 register int i; 496 register frauthent_t *fae, **faep; 497 frentry_t *fr, **frp; 498 mb_t *m; 499 500 if (fr_auth != NULL) { 501 KFREES(fr_auth, fr_authsize * sizeof(*fr_auth)); 502 fr_auth = NULL; 503 } 504 505 if (fr_authpkts != NULL) { 506 for (i = 0; i < fr_authsize; i++) { 507 m = fr_authpkts[i]; 508 if (m != NULL) { 509 FREE_MB_T(m); 510 fr_authpkts[i] = NULL; 511 } 512 } 513 KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 514 fr_authpkts = NULL; 515 } 516 517 faep = &fae_list; 518 while ((fae = *faep) != NULL) { 519 *faep = fae->fae_next; 520 KFREE(fae); 521 } 522 ipauth = NULL; 523 524 if (fr_authlist != NULL) { 525 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 526 if (fr->fr_ref == 1) { 527 *frp = fr->fr_next; 528 KFREE(fr); 529 } else 530 frp = &fr->fr_next; 531 } 532 } 533 534 if (fr_auth_init == 1) { 535# if SOLARIS && defined(_KERNEL) 536 cv_destroy(&ipfauthwait); 537# endif 538 MUTEX_DESTROY(&ipf_authmx); 539 RW_DESTROY(&ipf_auth); 540 541 fr_auth_init = 0; 542 } 543} 544 545 546/* ------------------------------------------------------------------------ */ 547/* Function: fr_authexpire */ 548/* Returns: None */ 549/* Parameters: None */ 550/* */ 551/* Slowly expire held auth records. Timeouts are set in expectation of */ 552/* this being called twice per second. */ 553/* ------------------------------------------------------------------------ */ 554void fr_authexpire() 555{ 556 frauthent_t *fae, **faep; 557 frentry_t *fr, **frp; 558 frauth_t *fra; 559 mb_t *m; 560 int i; 561 SPL_INT(s); 562 563 if (fr_auth_lock) 564 return; 565 566 SPL_NET(s); 567 WRITE_ENTER(&ipf_auth); 568 for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) { 569 fra->fra_age--; 570 if ((fra->fra_age == 0) && (m = fr_authpkts[i])) { 571 FREE_MB_T(m); 572 fr_authpkts[i] = NULL; 573 fr_auth[i].fra_index = -1; 574 fr_authstats.fas_expire++; 575 fr_authused--; 576 } 577 } 578 579 /* 580 * Expire pre-auth rules 581 */ 582 for (faep = &fae_list; ((fae = *faep) != NULL); ) { 583 fae->fae_age--; 584 if (fae->fae_age == 0) { 585 fr_authderef(&fae); 586 fr_authstats.fas_expire++; 587 } else 588 faep = &fae->fae_next; 589 } 590 if (fae_list != NULL) 591 ipauth = &fae_list->fae_fr; 592 else 593 ipauth = NULL; 594 595 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 596 if (fr->fr_ref == 1) { 597 *frp = fr->fr_next; 598 KFREE(fr); 599 } else 600 frp = &fr->fr_next; 601 } 602 RWLOCK_EXIT(&ipf_auth); 603 SPL_X(s); 604} 605 606 607/* ------------------------------------------------------------------------ */ 608/* Function: fr_preauthcmd */ 609/* Returns: int - 0 == success, else error */ 610/* Parameters: cmd(I) - ioctl command for rule */ 611/* fr(I) - pointer to ipf rule */ 612/* fptr(I) - pointer to caller's 'fr' */ 613/* */ 614/* ------------------------------------------------------------------------ */ 615int fr_preauthcmd(cmd, fr, frptr) 616ioctlcmd_t cmd; 617frentry_t *fr, **frptr; 618{ 619 frauthent_t *fae, **faep; 620 int error = 0; 621 SPL_INT(s); 622 623 if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) 624 return EIO; 625 626 for (faep = &fae_list; ((fae = *faep) != NULL); ) { 627 if (&fae->fae_fr == fr) 628 break; 629 else 630 faep = &fae->fae_next; 631 } 632 633 if (cmd == (ioctlcmd_t)SIOCRMAFR) { 634 if (fr == NULL || frptr == NULL) 635 error = EINVAL; 636 else if (fae == NULL) 637 error = ESRCH; 638 else { 639 SPL_NET(s); 640 WRITE_ENTER(&ipf_auth); 641 *faep = fae->fae_next; 642 if (ipauth == &fae->fae_fr) 643 ipauth = fae_list ? &fae_list->fae_fr : NULL; 644 RWLOCK_EXIT(&ipf_auth); 645 SPL_X(s); 646 647 KFREE(fae); 648 } 649 } else if (fr != NULL && frptr != NULL) { 650 KMALLOC(fae, frauthent_t *); 651 if (fae != NULL) { 652 bcopy((char *)fr, (char *)&fae->fae_fr, 653 sizeof(*fr)); 654 SPL_NET(s); 655 WRITE_ENTER(&ipf_auth); 656 fae->fae_age = fr_defaultauthage; 657 fae->fae_fr.fr_hits = 0; 658 fae->fae_fr.fr_next = *frptr; 659 fae->fae_ref = 1; 660 *frptr = &fae->fae_fr; 661 fae->fae_next = *faep; 662 *faep = fae; 663 ipauth = &fae_list->fae_fr; 664 RWLOCK_EXIT(&ipf_auth); 665 SPL_X(s); 666 } else 667 error = ENOMEM; 668 } else 669 error = EINVAL; 670 return error; 671} 672 673 674/* ------------------------------------------------------------------------ */ 675/* Function: fr_authflush */ 676/* Returns: int - number of auth entries flushed */ 677/* Parameters: None */ 678/* Locks: WRITE(ipf_auth) */ 679/* */ 680/* This function flushs the fr_authpkts array of any packet data with */ 681/* references still there. */ 682/* It is expected that the caller has already acquired the correct locks or */ 683/* set the priority level correctly for this to block out other code paths */ 684/* into these data structures. */ 685/* ------------------------------------------------------------------------ */ 686int fr_authflush() 687{ 688 register int i, num_flushed; 689 mb_t *m; 690 691 if (fr_auth_lock) 692 return -1; 693 694 num_flushed = 0; 695 696 for (i = 0 ; i < fr_authsize; i++) { 697 m = fr_authpkts[i]; 698 if (m != NULL) { 699 FREE_MB_T(m); 700 fr_authpkts[i] = NULL; 701 fr_auth[i].fra_index = -1; 702 /* perhaps add & use a flush counter inst.*/ 703 fr_authstats.fas_expire++; 704 fr_authused--; 705 num_flushed++; 706 } 707 } 708 709 fr_authstart = 0; 710 fr_authend = 0; 711 fr_authnext = 0; 712 713 return num_flushed; 714} 715 716 717/* ------------------------------------------------------------------------ */ 718/* Function: fr_auth_waiting */ 719/* Returns: int - number of packets in the auth queue */ 720/* Parameters: None */ 721/* */ 722/* Returns the numbers of packets queued up, waiting to be processed with */ 723/* a pair of SIOCAUTHW and SIOCAUTHR calls. */ 724/* ------------------------------------------------------------------------ */ 725int fr_auth_waiting() 726{ 727 return (fr_authnext != fr_authend) && fr_authpkts[fr_authnext]; 728} 729 730 731/* ------------------------------------------------------------------------ */ 732/* Function: fr_authgeniter */ 733/* Returns: int - 0 == success, else error */ 734/* Parameters: token(I) - pointer to ipftoken structure */ 735/* itp(I) - pointer to ipfgeniter structure */ 736/* */ 737/* ------------------------------------------------------------------------ */ 738int fr_authgeniter(token, itp) 739ipftoken_t *token; 740ipfgeniter_t *itp; 741{ 742 frauthent_t *fae, *next, zero; 743 int error; 744 745 if (itp->igi_data == NULL) 746 return EFAULT; 747 748 if (itp->igi_type != IPFGENITER_AUTH) 749 return EINVAL; 750 751 fae = token->ipt_data; 752 READ_ENTER(&ipf_auth); 753 if (fae == NULL) { 754 next = fae_list; 755 } else { 756 next = fae->fae_next; 757 } 758 759 if (next != NULL) { 760 /* 761 * If we find an auth entry to use, bump its reference count 762 * so that it can be used for is_next when we come back. 763 */ 764 ATOMIC_INC(next->fae_ref); 765 if (next->fae_next == NULL) { 766 ipf_freetoken(token); 767 token = NULL; 768 } else { 769 token->ipt_data = next; 770 } 771 } else { 772 bzero(&zero, sizeof(zero)); 773 next = &zero; 774 } 775 RWLOCK_EXIT(&ipf_auth); 776 777 /* 778 * If we had a prior pointer to an auth entry, release it. 779 */ 780 if (fae != NULL) { 781 WRITE_ENTER(&ipf_auth); 782 fr_authderef(&fae); 783 RWLOCK_EXIT(&ipf_auth); 784 } 785 786 /* 787 * This should arguably be via fr_outobj() so that the auth 788 * structure can (if required) be massaged going out. 789 */ 790 error = COPYOUT(next, itp->igi_data, sizeof(*next)); 791 if (error != 0) 792 error = EFAULT; 793 794 return error; 795} 796 797 798/* ------------------------------------------------------------------------ */ 799/* Function: fr_authderef */ 800/* Returns: None */ 801/* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */ 802/* Locks: WRITE(ipf_auth) */ 803/* */ 804/* This function unconditionally sets the pointer in the caller to NULL, */ 805/* to make it clear that it should no longer use that pointer, and drops */ 806/* the reference count on the structure by 1. If it reaches 0, free it up. */ 807/* ------------------------------------------------------------------------ */ 808void fr_authderef(faep) 809frauthent_t **faep; 810{ 811 frauthent_t *fae; 812 813 fae = *faep; 814 *faep = NULL; 815 816 fae->fae_ref--; 817 if (fae->fae_ref == 0) { 818 KFREE(fae); 819 } 820} 821 822 823/* ------------------------------------------------------------------------ */ 824/* Function: fr_authwait */ 825/* Returns: int - 0 == success, else error */ 826/* Parameters: data(I) - pointer to data from ioctl call */ 827/* */ 828/* This function is called when an application is waiting for a packet to */ 829/* match an "auth" rule by issuing an SIOCAUTHW ioctl. If there is already */ 830/* a packet waiting on the queue then we will return that _one_ immediately.*/ 831/* If there are no packets present in the queue (fr_authpkts) then we go to */ 832/* sleep. */ 833/* ------------------------------------------------------------------------ */ 834int fr_authwait(data) 835char *data; 836{ 837 frauth_t auth, *au = &auth; 838 int error, len, i; 839 mb_t *m; 840 char *t; 841#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 842 (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 843 SPL_INT(s); 844#endif 845 846fr_authioctlloop: 847 error = fr_inobj(data, au, IPFOBJ_FRAUTH); 848 if (error != 0) 849 return error; 850 851 /* 852 * XXX Locks are held below over calls to copyout...a better 853 * solution needs to be found so this isn't necessary. The situation 854 * we are trying to guard against here is an error in the copyout 855 * steps should not cause the packet to "disappear" from the queue. 856 */ 857 READ_ENTER(&ipf_auth); 858 859 /* 860 * If fr_authnext is not equal to fr_authend it will be because there 861 * is a packet waiting to be delt with in the fr_authpkts array. We 862 * copy as much of that out to user space as requested. 863 */ 864 if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { 865 error = fr_outobj(data, &fr_auth[fr_authnext], IPFOBJ_FRAUTH); 866 if (error != 0) 867 return error; 868 869 if (auth.fra_len != 0 && auth.fra_buf != NULL) { 870 /* 871 * Copy packet contents out to user space if 872 * requested. Bail on an error. 873 */ 874 m = fr_authpkts[fr_authnext]; 875 len = MSGDSIZE(m); 876 if (len > auth.fra_len) 877 len = auth.fra_len; 878 auth.fra_len = len; 879 880 for (t = auth.fra_buf; m && (len > 0); ) { 881 i = MIN(M_LEN(m), len); 882 error = copyoutptr(MTOD(m, char *), &t, i); 883 len -= i; 884 t += i; 885 if (error != 0) 886 return error; 887 m = m->m_next; 888 } 889 } 890 RWLOCK_EXIT(&ipf_auth); 891 if (error != 0) 892 return error; 893 894 SPL_NET(s); 895 WRITE_ENTER(&ipf_auth); 896 fr_authnext++; 897 if (fr_authnext == fr_authsize) 898 fr_authnext = 0; 899 RWLOCK_EXIT(&ipf_auth); 900 SPL_X(s); 901 902 return 0; 903 } 904 RWLOCK_EXIT(&ipf_auth); 905 906 /* 907 * We exit ipf_global here because a program that enters in 908 * here will have a lock on it and goto sleep having this lock. 909 * If someone were to do an 'ipf -D' the system would then 910 * deadlock. The catch with releasing it here is that the 911 * caller of this function expects it to be held when we 912 * return so we have to reacquire it in here. 913 */ 914 RWLOCK_EXIT(&ipf_global); 915 916 MUTEX_ENTER(&ipf_authmx); 917#ifdef _KERNEL 918# if SOLARIS 919 error = 0; 920 if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) 921 error = EINTR; 922# else /* SOLARIS */ 923# ifdef __hpux 924 { 925 lock_t *l; 926 927 l = get_sleep_lock(&fr_authnext); 928 error = sleep(&fr_authnext, PZERO+1); 929 spinunlock(l); 930 } 931# else 932# ifdef __osf__ 933 error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, 934 &ipf_authmx, MS_LOCK_SIMPLE); 935# else 936 error = SLEEP(&fr_authnext, "fr_authnext"); 937# endif /* __osf__ */ 938# endif /* __hpux */ 939# endif /* SOLARIS */ 940#endif 941 MUTEX_EXIT(&ipf_authmx); 942 READ_ENTER(&ipf_global); 943 if (error == 0) 944 goto fr_authioctlloop; 945 return error; 946} 947 948 949/* ------------------------------------------------------------------------ */ 950/* Function: fr_authreply */ 951/* Returns: int - 0 == success, else error */ 952/* Parameters: data(I) - pointer to data from ioctl call */ 953/* */ 954/* This function is called by an application when it wants to return a */ 955/* decision on a packet using the SIOCAUTHR ioctl. This is after it has */ 956/* received information using an SIOCAUTHW. The decision returned in the */ 957/* form of flags, the same as those used in each rule. */ 958/* ------------------------------------------------------------------------ */ 959int fr_authreply(data) 960char *data; 961{ 962 frauth_t auth, *au = &auth, *fra; 963 int error, i; 964 mb_t *m; 965 SPL_INT(s); 966 967 error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); 968 if (error != 0) 969 return error; 970 971 SPL_NET(s); 972 WRITE_ENTER(&ipf_auth); 973 974 i = au->fra_index; 975 fra = fr_auth + i; 976 error = 0; 977 978 /* 979 * Check the validity of the information being returned with two simple 980 * checks. First, the auth index value should be within the size of 981 * the array and second the packet id being returned should also match. 982 */ 983 if ((i < 0) || (i >= fr_authsize) || 984 (fra->fra_info.fin_id != au->fra_info.fin_id)) { 985 RWLOCK_EXIT(&ipf_auth); 986 SPL_X(s); 987 return ESRCH; 988 } 989 990 m = fr_authpkts[i]; 991 fra->fra_index = -2; 992 fra->fra_pass = au->fra_pass; 993 fr_authpkts[i] = NULL; 994 995 RWLOCK_EXIT(&ipf_auth); 996 997 /* 998 * Re-insert the packet back into the packet stream flowing through 999 * the kernel in a manner that will mean IPFilter sees the packet 1000 * again. This is not the same as is done with fastroute, 1001 * deliberately, as we want to resume the normal packet processing 1002 * path for it. 1003 */ 1004#ifdef _KERNEL 1005 if ((m != NULL) && (au->fra_info.fin_out != 0)) { 1006 error = ipf_inject(&fra->fra_info, m); 1007 if (error != 0) { 1008 error = ENOBUFS; 1009 fr_authstats.fas_sendfail++; 1010 } else { 1011 fr_authstats.fas_sendok++; 1012 } 1013 } else if (m) { 1014 error = ipf_inject(&fra->fra_info, m); 1015 if (error != 0) { 1016 error = ENOBUFS; 1017 fr_authstats.fas_quefail++; 1018 } else { 1019 fr_authstats.fas_queok++; 1020 } 1021 } else { 1022 error = EINVAL; 1023 } 1024 1025 /* 1026 * If we experience an error which will result in the packet 1027 * not being processed, make sure we advance to the next one. 1028 */ 1029 if (error == ENOBUFS) { 1030 fr_authused--; 1031 fra->fra_index = -1; 1032 fra->fra_pass = 0; 1033 if (i == fr_authstart) { 1034 while (fra->fra_index == -1) { 1035 i++; 1036 if (i == fr_authsize) 1037 i = 0; 1038 fr_authstart = i; 1039 if (i == fr_authend) 1040 break; 1041 } 1042 if (fr_authstart == fr_authend) { 1043 fr_authnext = 0; 1044 fr_authstart = fr_authend = 0; 1045 } 1046 } 1047 } 1048#endif /* _KERNEL */ 1049 SPL_X(s); 1050 1051 return 0; 1052} 1053