ip_auth.c revision 172776
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_auth.c 172776 2007-10-18 21:52:14Z 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 172776 2007-10-18 21:52:14Z darrenr $"; 124/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.24 2007/09/09 11:32:04 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_authend + 1) % fr_authsize) == fr_authstart) { 332 fr_authstats.fas_nospace++; 333 RWLOCK_EXIT(&ipf_auth); 334 return 0; 335 } 336 337 fr_authstats.fas_added++; 338 fr_authused++; 339 i = fr_authend++; 340 if (fr_authend == fr_authsize) 341 fr_authend = 0; 342 RWLOCK_EXIT(&ipf_auth); 343 344 fra = fr_auth + i; 345 fra->fra_index = i; 346 if (fin->fin_fr != NULL) 347 fra->fra_pass = fin->fin_fr->fr_flags; 348 else 349 fra->fra_pass = 0; 350 fra->fra_age = fr_defaultauthage; 351 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 352#if !defined(sparc) && !defined(m68k) 353 /* 354 * No need to copyback here as we want to undo the changes, not keep 355 * them. 356 */ 357 ip = fin->fin_ip; 358# if defined(MENTAT) && defined(_KERNEL) 359 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 360# endif 361 { 362 register u_short bo; 363 364 bo = ip->ip_len; 365 ip->ip_len = htons(bo); 366 bo = ip->ip_off; 367 ip->ip_off = htons(bo); 368 } 369#endif 370#if SOLARIS && defined(_KERNEL) 371 COPYIFNAME(fin->fin_v, fin->fin_ifp, fra->fra_info.fin_ifname); 372 m->b_rptr -= qpi->qpi_off; 373 fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 374# if !defined(_INET_IP_STACK_H) 375 fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ 376# endif 377 fra->fra_m = *fin->fin_mp; 378 fra->fra_info.fin_mp = &fra->fra_m; 379 cv_signal(&ipfauthwait); 380 pollwakeup(&iplpollhead[IPL_LOGAUTH], POLLIN|POLLRDNORM); 381#else 382 fr_authpkts[i] = m; 383 WAKEUP(&fr_authnext,0); 384#endif 385 return 1; 386} 387 388 389/* ------------------------------------------------------------------------ */ 390/* Function: fr_auth_ioctl */ 391/* Returns: int - 0 == success, else error */ 392/* Parameters: data(IO) - pointer to ioctl data */ 393/* cmd(I) - ioctl command */ 394/* mode(I) - mode flags associated with open descriptor */ 395/* uid(I) - uid associatd with application making the call */ 396/* ctx(I) - pointer for context */ 397/* */ 398/* This function handles all of the ioctls recognised by the auth component */ 399/* in IPFilter - ie ioctls called on an open fd for /dev/ipauth */ 400/* ------------------------------------------------------------------------ */ 401int fr_auth_ioctl(data, cmd, mode, uid, ctx) 402caddr_t data; 403ioctlcmd_t cmd; 404int mode, uid; 405void *ctx; 406{ 407 int error = 0, i; 408 SPL_INT(s); 409 410 switch (cmd) 411 { 412 case SIOCGENITER : 413 { 414 ipftoken_t *token; 415 ipfgeniter_t iter; 416 417 error = fr_inobj(data, &iter, IPFOBJ_GENITER); 418 if (error != 0) 419 break; 420 421 SPL_SCHED(s); 422 token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx); 423 if (token != NULL) 424 error = fr_authgeniter(token, &iter); 425 else 426 error = ESRCH; 427 RWLOCK_EXIT(&ipf_tokens); 428 SPL_X(s); 429 430 break; 431 } 432 433 case SIOCADAFR : 434 case SIOCRMAFR : 435 if (!(mode & FWRITE)) 436 error = EPERM; 437 else 438 error = frrequest(IPL_LOGAUTH, cmd, data, 439 fr_active, 1); 440 break; 441 442 case SIOCSTLCK : 443 if (!(mode & FWRITE)) { 444 error = EPERM; 445 break; 446 } 447 error = fr_lock(data, &fr_auth_lock); 448 break; 449 450 case SIOCATHST: 451 fr_authstats.fas_faelist = fae_list; 452 error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT); 453 break; 454 455 case SIOCIPFFL: 456 SPL_NET(s); 457 WRITE_ENTER(&ipf_auth); 458 i = fr_authflush(); 459 RWLOCK_EXIT(&ipf_auth); 460 SPL_X(s); 461 error = BCOPYOUT((char *)&i, data, sizeof(i)); 462 if (error != 0) 463 error = EFAULT; 464 break; 465 466 case SIOCAUTHW: 467 error = fr_authwait(data); 468 break; 469 470 case SIOCAUTHR: 471 error = fr_authreply(data); 472 break; 473 474 default : 475 error = EINVAL; 476 break; 477 } 478 return error; 479} 480 481 482/* ------------------------------------------------------------------------ */ 483/* Function: fr_authunload */ 484/* Returns: None */ 485/* Parameters: None */ 486/* */ 487/* Free all network buffer memory used to keep saved packets. */ 488/* ------------------------------------------------------------------------ */ 489void fr_authunload() 490{ 491 register int i; 492 register frauthent_t *fae, **faep; 493 frentry_t *fr, **frp; 494 mb_t *m; 495 496 if (fr_auth != NULL) { 497 KFREES(fr_auth, fr_authsize * sizeof(*fr_auth)); 498 fr_auth = NULL; 499 } 500 501 if (fr_authpkts != NULL) { 502 for (i = 0; i < fr_authsize; i++) { 503 m = fr_authpkts[i]; 504 if (m != NULL) { 505 FREE_MB_T(m); 506 fr_authpkts[i] = NULL; 507 } 508 } 509 KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 510 fr_authpkts = NULL; 511 } 512 513 faep = &fae_list; 514 while ((fae = *faep) != NULL) { 515 *faep = fae->fae_next; 516 KFREE(fae); 517 } 518 ipauth = NULL; 519 520 if (fr_authlist != NULL) { 521 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 522 if (fr->fr_ref == 1) { 523 *frp = fr->fr_next; 524 KFREE(fr); 525 } else 526 frp = &fr->fr_next; 527 } 528 } 529 530 if (fr_auth_init == 1) { 531# if SOLARIS && defined(_KERNEL) 532 cv_destroy(&ipfauthwait); 533# endif 534 MUTEX_DESTROY(&ipf_authmx); 535 RW_DESTROY(&ipf_auth); 536 537 fr_auth_init = 0; 538 } 539} 540 541 542/* ------------------------------------------------------------------------ */ 543/* Function: fr_authexpire */ 544/* Returns: None */ 545/* Parameters: None */ 546/* */ 547/* Slowly expire held auth records. Timeouts are set in expectation of */ 548/* this being called twice per second. */ 549/* ------------------------------------------------------------------------ */ 550void fr_authexpire() 551{ 552 frauthent_t *fae, **faep; 553 frentry_t *fr, **frp; 554 frauth_t *fra; 555 mb_t *m; 556 int i; 557 SPL_INT(s); 558 559 if (fr_auth_lock) 560 return; 561 562 SPL_NET(s); 563 WRITE_ENTER(&ipf_auth); 564 for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) { 565 fra->fra_age--; 566 if ((fra->fra_age == 0) && (m = fr_authpkts[i])) { 567 FREE_MB_T(m); 568 fr_authpkts[i] = NULL; 569 fr_auth[i].fra_index = -1; 570 fr_authstats.fas_expire++; 571 fr_authused--; 572 } 573 } 574 575 /* 576 * Expire pre-auth rules 577 */ 578 for (faep = &fae_list; ((fae = *faep) != NULL); ) { 579 fae->fae_age--; 580 if (fae->fae_age == 0) { 581 fr_authderef(&fae); 582 fr_authstats.fas_expire++; 583 } else 584 faep = &fae->fae_next; 585 } 586 if (fae_list != NULL) 587 ipauth = &fae_list->fae_fr; 588 else 589 ipauth = NULL; 590 591 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 592 if (fr->fr_ref == 1) { 593 *frp = fr->fr_next; 594 KFREE(fr); 595 } else 596 frp = &fr->fr_next; 597 } 598 RWLOCK_EXIT(&ipf_auth); 599 SPL_X(s); 600} 601 602 603/* ------------------------------------------------------------------------ */ 604/* Function: fr_preauthcmd */ 605/* Returns: int - 0 == success, else error */ 606/* Parameters: cmd(I) - ioctl command for rule */ 607/* fr(I) - pointer to ipf rule */ 608/* fptr(I) - pointer to caller's 'fr' */ 609/* */ 610/* ------------------------------------------------------------------------ */ 611int fr_preauthcmd(cmd, fr, frptr) 612ioctlcmd_t cmd; 613frentry_t *fr, **frptr; 614{ 615 frauthent_t *fae, **faep; 616 int error = 0; 617 SPL_INT(s); 618 619 if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) 620 return EIO; 621 622 for (faep = &fae_list; ((fae = *faep) != NULL); ) { 623 if (&fae->fae_fr == fr) 624 break; 625 else 626 faep = &fae->fae_next; 627 } 628 629 if (cmd == (ioctlcmd_t)SIOCRMAFR) { 630 if (fr == NULL || frptr == NULL) 631 error = EINVAL; 632 else if (fae == NULL) 633 error = ESRCH; 634 else { 635 SPL_NET(s); 636 WRITE_ENTER(&ipf_auth); 637 *faep = fae->fae_next; 638 if (ipauth == &fae->fae_fr) 639 ipauth = fae_list ? &fae_list->fae_fr : NULL; 640 RWLOCK_EXIT(&ipf_auth); 641 SPL_X(s); 642 643 KFREE(fae); 644 } 645 } else if (fr != NULL && frptr != NULL) { 646 KMALLOC(fae, frauthent_t *); 647 if (fae != NULL) { 648 bcopy((char *)fr, (char *)&fae->fae_fr, 649 sizeof(*fr)); 650 SPL_NET(s); 651 WRITE_ENTER(&ipf_auth); 652 fae->fae_age = fr_defaultauthage; 653 fae->fae_fr.fr_hits = 0; 654 fae->fae_fr.fr_next = *frptr; 655 fae->fae_ref = 1; 656 *frptr = &fae->fae_fr; 657 fae->fae_next = *faep; 658 *faep = fae; 659 ipauth = &fae_list->fae_fr; 660 RWLOCK_EXIT(&ipf_auth); 661 SPL_X(s); 662 } else 663 error = ENOMEM; 664 } else 665 error = EINVAL; 666 return error; 667} 668 669 670/* ------------------------------------------------------------------------ */ 671/* Function: fr_authflush */ 672/* Returns: int - number of auth entries flushed */ 673/* Parameters: None */ 674/* Locks: WRITE(ipf_auth) */ 675/* */ 676/* This function flushs the fr_authpkts array of any packet data with */ 677/* references still there. */ 678/* It is expected that the caller has already acquired the correct locks or */ 679/* set the priority level correctly for this to block out other code paths */ 680/* into these data structures. */ 681/* ------------------------------------------------------------------------ */ 682int fr_authflush() 683{ 684 register int i, num_flushed; 685 mb_t *m; 686 687 if (fr_auth_lock) 688 return -1; 689 690 num_flushed = 0; 691 692 for (i = 0 ; i < fr_authsize; i++) { 693 m = fr_authpkts[i]; 694 if (m != NULL) { 695 FREE_MB_T(m); 696 fr_authpkts[i] = NULL; 697 fr_auth[i].fra_index = -1; 698 /* perhaps add & use a flush counter inst.*/ 699 fr_authstats.fas_expire++; 700 fr_authused--; 701 num_flushed++; 702 } 703 } 704 705 fr_authstart = 0; 706 fr_authend = 0; 707 fr_authnext = 0; 708 709 return num_flushed; 710} 711 712 713/* ------------------------------------------------------------------------ */ 714/* Function: fr_auth_waiting */ 715/* Returns: int - 0 = no pakcets wiating, 1 = packets waiting. */ 716/* Parameters: None */ 717/* */ 718/* Simple truth check to see if there are any packets waiting in the auth */ 719/* queue. */ 720/* ------------------------------------------------------------------------ */ 721int fr_auth_waiting() 722{ 723 return (fr_authused != 0); 724} 725 726 727/* ------------------------------------------------------------------------ */ 728/* Function: fr_authgeniter */ 729/* Returns: int - 0 == success, else error */ 730/* Parameters: token(I) - pointer to ipftoken structure */ 731/* itp(I) - pointer to ipfgeniter structure */ 732/* */ 733/* ------------------------------------------------------------------------ */ 734int fr_authgeniter(token, itp) 735ipftoken_t *token; 736ipfgeniter_t *itp; 737{ 738 frauthent_t *fae, *next, zero; 739 int error; 740 741 if (itp->igi_data == NULL) 742 return EFAULT; 743 744 if (itp->igi_type != IPFGENITER_AUTH) 745 return EINVAL; 746 747 fae = token->ipt_data; 748 READ_ENTER(&ipf_auth); 749 if (fae == NULL) { 750 next = fae_list; 751 } else { 752 next = fae->fae_next; 753 } 754 755 if (next != NULL) { 756 /* 757 * If we find an auth entry to use, bump its reference count 758 * so that it can be used for is_next when we come back. 759 */ 760 ATOMIC_INC(next->fae_ref); 761 if (next->fae_next == NULL) { 762 ipf_freetoken(token); 763 token = NULL; 764 } else { 765 token->ipt_data = next; 766 } 767 } else { 768 bzero(&zero, sizeof(zero)); 769 next = &zero; 770 } 771 RWLOCK_EXIT(&ipf_auth); 772 773 /* 774 * If we had a prior pointer to an auth entry, release it. 775 */ 776 if (fae != NULL) { 777 WRITE_ENTER(&ipf_auth); 778 fr_authderef(&fae); 779 RWLOCK_EXIT(&ipf_auth); 780 } 781 782 /* 783 * This should arguably be via fr_outobj() so that the auth 784 * structure can (if required) be massaged going out. 785 */ 786 error = COPYOUT(next, itp->igi_data, sizeof(*next)); 787 if (error != 0) 788 error = EFAULT; 789 790 return error; 791} 792 793 794/* ------------------------------------------------------------------------ */ 795/* Function: fr_authderef */ 796/* Returns: None */ 797/* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */ 798/* Locks: WRITE(ipf_auth) */ 799/* */ 800/* This function unconditionally sets the pointer in the caller to NULL, */ 801/* to make it clear that it should no longer use that pointer, and drops */ 802/* the reference count on the structure by 1. If it reaches 0, free it up. */ 803/* ------------------------------------------------------------------------ */ 804void fr_authderef(faep) 805frauthent_t **faep; 806{ 807 frauthent_t *fae; 808 809 fae = *faep; 810 *faep = NULL; 811 812 fae->fae_ref--; 813 if (fae->fae_ref == 0) { 814 KFREE(fae); 815 } 816} 817 818 819/* ------------------------------------------------------------------------ */ 820/* Function: fr_authwait */ 821/* Returns: int - 0 == success, else error */ 822/* Parameters: data(I) - pointer to data from ioctl call */ 823/* */ 824/* This function is called when an application is waiting for a packet to */ 825/* match an "auth" rule by issuing an SIOCAUTHW ioctl. If there is already */ 826/* a packet waiting on the queue then we will return that _one_ immediately.*/ 827/* If there are no packets present in the queue (fr_authpkts) then we go to */ 828/* sleep. */ 829/* ------------------------------------------------------------------------ */ 830int fr_authwait(data) 831char *data; 832{ 833 frauth_t auth, *au = &auth; 834 int error, len, i; 835 mb_t *m; 836 char *t; 837#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 838 (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 839 SPL_INT(s); 840#endif 841 842fr_authioctlloop: 843 error = fr_inobj(data, au, IPFOBJ_FRAUTH); 844 if (error != 0) 845 return error; 846 847 /* 848 * XXX Locks are held below over calls to copyout...a better 849 * solution needs to be found so this isn't necessary. The situation 850 * we are trying to guard against here is an error in the copyout 851 * steps should not cause the packet to "disappear" from the queue. 852 */ 853 READ_ENTER(&ipf_auth); 854 855 /* 856 * If fr_authnext is not equal to fr_authend it will be because there 857 * is a packet waiting to be delt with in the fr_authpkts array. We 858 * copy as much of that out to user space as requested. 859 */ 860 if (fr_authused > 0) { 861 while (fr_authpkts[fr_authnext] == NULL) { 862 fr_authnext++; 863 if (fr_authnext == fr_authsize) 864 fr_authnext = 0; 865 } 866 867 error = fr_outobj(data, &fr_auth[fr_authnext], IPFOBJ_FRAUTH); 868 if (error != 0) 869 return error; 870 871 if (auth.fra_len != 0 && auth.fra_buf != NULL) { 872 /* 873 * Copy packet contents out to user space if 874 * requested. Bail on an error. 875 */ 876 m = fr_authpkts[fr_authnext]; 877 len = MSGDSIZE(m); 878 if (len > auth.fra_len) 879 len = auth.fra_len; 880 auth.fra_len = len; 881 882 for (t = auth.fra_buf; m && (len > 0); ) { 883 i = MIN(M_LEN(m), len); 884 error = copyoutptr(MTOD(m, char *), &t, i); 885 len -= i; 886 t += i; 887 if (error != 0) 888 return error; 889 m = m->m_next; 890 } 891 } 892 RWLOCK_EXIT(&ipf_auth); 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