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 - 1 == success, 0 = did not put packet on auth queue */ 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 fra = fr_auth + i; 343 fra->fra_index = i; 344 RWLOCK_EXIT(&ipf_auth); 345 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 MUTEX_ENTER(&ipf_authmx); 907#ifdef _KERNEL 908# if SOLARIS 909 error = 0; 910 if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) 911 error = EINTR; 912# else /* SOLARIS */ 913# ifdef __hpux 914 { 915 lock_t *l; 916 917 l = get_sleep_lock(&fr_authnext); 918 error = sleep(&fr_authnext, PZERO+1); 919 spinunlock(l); 920 } 921# else 922# ifdef __osf__ 923 error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, 924 &ipf_authmx, MS_LOCK_SIMPLE); 925# else 926 error = SLEEP(&fr_authnext, "fr_authnext"); 927# endif /* __osf__ */ 928# endif /* __hpux */ 929# endif /* SOLARIS */ 930#endif 931 MUTEX_EXIT(&ipf_authmx); 932 if (error == 0) 933 goto fr_authioctlloop; 934 return error; 935} 936 937 938/* ------------------------------------------------------------------------ */ 939/* Function: fr_authreply */ 940/* Returns: int - 0 == success, else error */ 941/* Parameters: data(I) - pointer to data from ioctl call */ 942/* */ 943/* This function is called by an application when it wants to return a */ 944/* decision on a packet using the SIOCAUTHR ioctl. This is after it has */ 945/* received information using an SIOCAUTHW. The decision returned in the */ 946/* form of flags, the same as those used in each rule. */ 947/* ------------------------------------------------------------------------ */ 948int fr_authreply(data) 949char *data; 950{ 951 frauth_t auth, *au = &auth, *fra; 952 int error, i; 953 mb_t *m; 954 SPL_INT(s); 955 956 error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); 957 if (error != 0) 958 return error; 959 960 SPL_NET(s); 961 WRITE_ENTER(&ipf_auth); 962 963 i = au->fra_index; 964 fra = fr_auth + i; 965 error = 0; 966 967 /* 968 * Check the validity of the information being returned with two simple 969 * checks. First, the auth index value should be within the size of 970 * the array and second the packet id being returned should also match. 971 */ 972 if ((i < 0) || (i >= fr_authsize) || 973 (fra->fra_info.fin_id != au->fra_info.fin_id)) { 974 RWLOCK_EXIT(&ipf_auth); 975 SPL_X(s); 976 return ESRCH; 977 } 978 979 m = fr_authpkts[i]; 980 fra->fra_index = -2; 981 fra->fra_pass = au->fra_pass; 982 fr_authpkts[i] = NULL; 983 984 RWLOCK_EXIT(&ipf_auth); 985 986 /* 987 * Re-insert the packet back into the packet stream flowing through 988 * the kernel in a manner that will mean IPFilter sees the packet 989 * again. This is not the same as is done with fastroute, 990 * deliberately, as we want to resume the normal packet processing 991 * path for it. 992 */ 993#ifdef _KERNEL 994 if ((m != NULL) && (au->fra_info.fin_out != 0)) { 995 error = ipf_inject(&fra->fra_info, m); 996 if (error != 0) { 997 error = ENOBUFS; 998 fr_authstats.fas_sendfail++; 999 } else { 1000 fr_authstats.fas_sendok++; 1001 } 1002 } else if (m) { 1003 error = ipf_inject(&fra->fra_info, m); 1004 if (error != 0) { 1005 error = ENOBUFS; 1006 fr_authstats.fas_quefail++; 1007 } else { 1008 fr_authstats.fas_queok++; 1009 } 1010 } else { 1011 error = EINVAL; 1012 } 1013 1014 /* 1015 * If we experience an error which will result in the packet 1016 * not being processed, make sure we advance to the next one. 1017 */ 1018 if (error == ENOBUFS) { 1019 WRITE_ENTER(&ipf_auth); 1020 fr_authused--; 1021 fra->fra_index = -1; 1022 fra->fra_pass = 0; 1023 if (i == fr_authstart) { 1024 while (fra->fra_index == -1) { 1025 i++; 1026 if (i == fr_authsize) 1027 i = 0; 1028 fr_authstart = i; 1029 if (i == fr_authend) 1030 break; 1031 } 1032 if (fr_authstart == fr_authend) { 1033 fr_authnext = 0; 1034 fr_authstart = fr_authend = 0; 1035 } 1036 } 1037 RWLOCK_EXIT(&ipf_auth); 1038 } 1039#endif /* _KERNEL */ 1040 SPL_X(s); 1041 1042 return 0; 1043}
|