1 /* 2 * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 7 * Use is subject to license terms. 8 */ 9 10 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #if defined(KERNEL) || defined(_KERNEL) 13 # undef KERNEL 14 # undef _KERNEL 15 # define KERNEL 1 16 # define _KERNEL 1 17 #endif 18 #include <sys/errno.h> 19 #include <sys/types.h> 20 #include <sys/param.h> 21 #include <sys/time.h> 22 #include <sys/file.h> 23 #if !defined(_KERNEL) 24 # include <stdio.h> 25 # include <stdlib.h> 26 # include <string.h> 27 # define _KERNEL 28 # ifdef __OpenBSD__ 29 struct file; 30 # endif 31 # include <sys/uio.h> 32 # undef _KERNEL 33 #endif 34 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 35 # include <sys/filio.h> 36 # include <sys/fcntl.h> 37 #else 38 # include <sys/ioctl.h> 39 #endif 40 #if !defined(linux) 41 # include <sys/protosw.h> 42 #endif 43 #include <sys/socket.h> 44 #if defined(_KERNEL) 45 # include <sys/systm.h> 46 # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) 47 # include <sys/mbuf.h> 48 # endif 49 #endif 50 #if defined(__SVR4) || defined(__svr4__) 51 # include <sys/filio.h> 52 # include <sys/byteorder.h> 53 # ifdef _KERNEL 54 # include <sys/dditypes.h> 55 # endif 56 # include <sys/stream.h> 57 # include <sys/kmem.h> 58 # include <sys/neti.h> 59 #endif 60 #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) 61 # include <sys/queue.h> 62 #endif 63 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 64 # include <machine/cpu.h> 65 #endif 66 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 67 # include <sys/proc.h> 68 #endif 69 #include <net/if.h> 70 #ifdef sun 71 # include <net/af.h> 72 #endif 73 #include <net/route.h> 74 #include <netinet/in.h> 75 #include <netinet/in_systm.h> 76 #include <netinet/ip.h> 77 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) 78 # define KERNEL 79 # define _KERNEL 80 # define NOT_KERNEL 81 #endif 82 #if !defined(linux) 83 # include <netinet/ip_var.h> 84 #endif 85 #ifdef NOT_KERNEL 86 # undef _KERNEL 87 # undef KERNEL 88 #endif 89 #include <netinet/tcp.h> 90 #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ 91 extern struct ifqueue ipintrq; /* ip packet input queue */ 92 #else 93 # if !defined(__hpux) && !defined(linux) 94 # if __FreeBSD_version >= 300000 95 # include <net/if_var.h> 96 # if __FreeBSD_version >= 500042 97 # define IF_QFULL _IF_QFULL 98 # define IF_DROP _IF_DROP 99 # endif /* __FreeBSD_version >= 500042 */ 100 # endif 101 # include <netinet/in_var.h> 102 # include <netinet/tcp_fsm.h> 103 # endif 104 #endif 105 #include <netinet/udp.h> 106 #include <netinet/ip_icmp.h> 107 #include "netinet/ip_compat.h" 108 #include <netinet/tcpip.h> 109 #include "netinet/ipf_stack.h" 110 #include "netinet/ip_fil.h" 111 #include "netinet/ip_auth.h" 112 #if !defined(MENTAT) && !defined(linux) 113 # include <net/netisr.h> 114 # ifdef __FreeBSD__ 115 # include <machine/cpufunc.h> 116 # endif 117 #endif 118 #if (__FreeBSD_version >= 300000) 119 # include <sys/malloc.h> 120 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 121 # include <sys/libkern.h> 122 # include <sys/systm.h> 123 # endif 124 #endif 125 /* END OF INCLUDES */ 126 127 #if !defined(lint) 128 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $"; 129 #endif 130 131 void fr_authderef __P((frauthent_t **)); 132 int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 133 134 135 int fr_authinit(ifs) 136 ipf_stack_t *ifs; 137 { 138 KMALLOCS(ifs->ifs_fr_auth, frauth_t *, 139 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 140 if (ifs->ifs_fr_auth != NULL) 141 bzero((char *)ifs->ifs_fr_auth, 142 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 143 else 144 return -1; 145 146 KMALLOCS(ifs->ifs_fr_authpkts, mb_t **, 147 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 148 if (ifs->ifs_fr_authpkts != NULL) 149 bzero((char *)ifs->ifs_fr_authpkts, 150 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 151 else 152 return -2; 153 154 MUTEX_INIT(&ifs->ifs_ipf_authmx, "ipf auth log mutex"); 155 RWLOCK_INIT(&ifs->ifs_ipf_auth, "ipf IP User-Auth rwlock"); 156 #if SOLARIS && defined(_KERNEL) 157 cv_init(&ifs->ifs_ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); 158 #endif 159 #if defined(linux) && defined(_KERNEL) 160 init_waitqueue_head(&fr_authnext_linux); 161 #endif 162 163 ifs->ifs_fr_auth_init = 1; 164 165 return 0; 166 } 167 168 169 /* 170 * Check if a packet has authorization. If the packet is found to match an 171 * authorization result and that would result in a feedback loop (i.e. it 172 * will end up returning FR_AUTH) then return FR_BLOCK instead. 173 */ 174 frentry_t *fr_checkauth(fin, passp) 175 fr_info_t *fin; 176 u_32_t *passp; 177 { 178 frentry_t *fr; 179 frauth_t *fra; 180 u_32_t pass; 181 u_short id; 182 ip_t *ip; 183 int i; 184 ipf_stack_t *ifs = fin->fin_ifs; 185 186 if (ifs->ifs_fr_auth_lock || !ifs->ifs_fr_authused) 187 return NULL; 188 189 ip = fin->fin_ip; 190 id = ip->ip_id; 191 192 READ_ENTER(&ifs->ifs_ipf_auth); 193 for (i = ifs->ifs_fr_authstart; i != ifs->ifs_fr_authend; ) { 194 /* 195 * index becomes -2 only after an SIOCAUTHW. Check this in 196 * case the same packet gets sent again and it hasn't yet been 197 * auth'd. 198 */ 199 fra = ifs->ifs_fr_auth + i; 200 if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 201 !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 202 /* 203 * Avoid feedback loop. 204 */ 205 if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) 206 pass = FR_BLOCK; 207 /* 208 * Create a dummy rule for the stateful checking to 209 * use and return. Zero out any values we don't 210 * trust from userland! 211 */ 212 if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 213 (fin->fin_flx & FI_FRAG))) { 214 KMALLOC(fr, frentry_t *); 215 if (fr) { 216 bcopy((char *)fra->fra_info.fin_fr, 217 (char *)fr, sizeof(*fr)); 218 fr->fr_grp = NULL; 219 fr->fr_ifa = fin->fin_ifp; 220 fr->fr_func = NULL; 221 fr->fr_ref = 1; 222 fr->fr_flags = pass; 223 fr->fr_ifas[1] = NULL; 224 fr->fr_ifas[2] = NULL; 225 fr->fr_ifas[3] = NULL; 226 } 227 } else 228 fr = fra->fra_info.fin_fr; 229 fin->fin_fr = fr; 230 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 231 WRITE_ENTER(&ifs->ifs_ipf_auth); 232 if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 233 fr->fr_next = ifs->ifs_fr_authlist; 234 ifs->ifs_fr_authlist = fr; 235 } 236 ifs->ifs_fr_authstats.fas_hits++; 237 fra->fra_index = -1; 238 ifs->ifs_fr_authused--; 239 if (i == ifs->ifs_fr_authstart) { 240 while (fra->fra_index == -1) { 241 i++; 242 fra++; 243 if (i == ifs->ifs_fr_authsize) { 244 i = 0; 245 fra = ifs->ifs_fr_auth; 246 } 247 ifs->ifs_fr_authstart = i; 248 if (i == ifs->ifs_fr_authend) 249 break; 250 } 251 if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) { 252 ifs->ifs_fr_authnext = 0; 253 ifs->ifs_fr_authstart = 0; 254 ifs->ifs_fr_authend = 0; 255 } 256 } 257 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 258 if (passp != NULL) 259 *passp = pass; 260 ATOMIC_INC64(ifs->ifs_fr_authstats.fas_hits); 261 return fr; 262 } 263 i++; 264 if (i == ifs->ifs_fr_authsize) 265 i = 0; 266 } 267 ifs->ifs_fr_authstats.fas_miss++; 268 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 269 ATOMIC_INC64(ifs->ifs_fr_authstats.fas_miss); 270 return NULL; 271 } 272 273 274 /* 275 * Check if we have room in the auth array to hold details for another packet. 276 * If we do, store it and wake up any user programs which are waiting to 277 * hear about these events. 278 */ 279 int fr_newauth(m, fin) 280 mb_t *m; 281 fr_info_t *fin; 282 { 283 #if defined(_KERNEL) && defined(MENTAT) 284 qpktinfo_t *qpi = fin->fin_qpi; 285 #endif 286 frauth_t *fra; 287 #if !defined(sparc) && !defined(m68k) 288 ip_t *ip; 289 #endif 290 int i; 291 ipf_stack_t *ifs = fin->fin_ifs; 292 293 if (ifs->ifs_fr_auth_lock) 294 return 0; 295 296 WRITE_ENTER(&ifs->ifs_ipf_auth); 297 if (ifs->ifs_fr_authstart > ifs->ifs_fr_authend) { 298 ifs->ifs_fr_authstats.fas_nospace++; 299 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 300 return 0; 301 } else { 302 if (ifs->ifs_fr_authused == ifs->ifs_fr_authsize) { 303 ifs->ifs_fr_authstats.fas_nospace++; 304 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 305 return 0; 306 } 307 } 308 309 ifs->ifs_fr_authstats.fas_added++; 310 ifs->ifs_fr_authused++; 311 i = ifs->ifs_fr_authend++; 312 if (ifs->ifs_fr_authend == ifs->ifs_fr_authsize) 313 ifs->ifs_fr_authend = 0; 314 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 315 316 fra = ifs->ifs_fr_auth + i; 317 fra->fra_index = i; 318 fra->fra_pass = 0; 319 fra->fra_age = ifs->ifs_fr_defaultauthage; 320 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 321 #if !defined(sparc) && !defined(m68k) 322 /* 323 * No need to copyback here as we want to undo the changes, not keep 324 * them. 325 */ 326 ip = fin->fin_ip; 327 # if defined(MENTAT) && defined(_KERNEL) 328 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 329 # endif 330 { 331 register u_short bo; 332 333 bo = ip->ip_len; 334 ip->ip_len = htons(bo); 335 bo = ip->ip_off; 336 ip->ip_off = htons(bo); 337 } 338 #endif 339 #if SOLARIS && defined(_KERNEL) 340 m->b_rptr -= qpi->qpi_off; 341 ifs->ifs_fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 342 cv_signal(&ifs->ifs_ipfauthwait); 343 #else 344 # if defined(BSD) && !defined(sparc) && (BSD >= 199306) 345 if (!fin->fin_out) { 346 ip->ip_len = htons(ip->ip_len); 347 ip->ip_off = htons(ip->ip_off); 348 } 349 # endif 350 ifs->ifs_fr_authpkts[i] = m; 351 WAKEUP(&ifs->ifs_fr_authnext, 0); 352 #endif 353 return 1; 354 } 355 356 357 int fr_auth_ioctl(data, cmd, mode, uid, ctx, ifs) 358 caddr_t data; 359 ioctlcmd_t cmd; 360 int mode,uid; 361 void *ctx; 362 ipf_stack_t *ifs; 363 { 364 mb_t *m; 365 #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 366 (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 367 struct ifqueue *ifq; 368 SPL_INT(s); 369 #endif 370 frauth_t auth, *au = &auth, *fra; 371 int i, error = 0, len; 372 char *t; 373 net_data_t net_data_p; 374 net_inject_t inj_data; 375 int ret; 376 377 switch (cmd) 378 { 379 case SIOCGENITER : 380 { 381 ipftoken_t *token; 382 ipfgeniter_t iter; 383 384 error = fr_inobj(data, &iter, IPFOBJ_GENITER); 385 if (error != 0) 386 break; 387 388 token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx, ifs); 389 if (token != NULL) 390 error = fr_authgeniter(token, &iter, ifs); 391 else 392 error = ESRCH; 393 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 394 395 break; 396 } 397 398 case SIOCSTLCK : 399 if (!(mode & FWRITE)) { 400 error = EPERM; 401 break; 402 } 403 fr_lock(data, &ifs->ifs_fr_auth_lock); 404 break; 405 406 case SIOCATHST: 407 ifs->ifs_fr_authstats.fas_faelist = ifs->ifs_fae_list; 408 error = fr_outobj(data, &ifs->ifs_fr_authstats, 409 IPFOBJ_AUTHSTAT); 410 break; 411 412 case SIOCIPFFL: 413 SPL_NET(s); 414 WRITE_ENTER(&ifs->ifs_ipf_auth); 415 i = fr_authflush(ifs); 416 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 417 SPL_X(s); 418 error = copyoutptr((char *)&i, data, sizeof(i)); 419 break; 420 421 case SIOCAUTHW: 422 fr_authioctlloop: 423 error = fr_inobj(data, au, IPFOBJ_FRAUTH); 424 READ_ENTER(&ifs->ifs_ipf_auth); 425 if ((ifs->ifs_fr_authnext != ifs->ifs_fr_authend) && 426 ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]) { 427 error = fr_outobj(data, 428 &ifs->ifs_fr_auth[ifs->ifs_fr_authnext], 429 IPFOBJ_FRAUTH); 430 if (auth.fra_len != 0 && auth.fra_buf != NULL) { 431 /* 432 * Copy packet contents out to user space if 433 * requested. Bail on an error. 434 */ 435 m = ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]; 436 len = MSGDSIZE(m); 437 if (len > auth.fra_len) 438 len = auth.fra_len; 439 auth.fra_len = len; 440 for (t = auth.fra_buf; m && (len > 0); ) { 441 i = MIN(M_LEN(m), len); 442 error = copyoutptr(MTOD(m, char *), 443 t, i); 444 len -= i; 445 t += i; 446 if (error != 0) 447 break; 448 } 449 } 450 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 451 if (error != 0) 452 break; 453 SPL_NET(s); 454 WRITE_ENTER(&ifs->ifs_ipf_auth); 455 ifs->ifs_fr_authnext++; 456 if (ifs->ifs_fr_authnext == ifs->ifs_fr_authsize) 457 ifs->ifs_fr_authnext = 0; 458 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 459 SPL_X(s); 460 return 0; 461 } 462 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 463 /* 464 * We exit ipf_global here because a program that enters in 465 * here will have a lock on it and goto sleep having this lock. 466 * If someone were to do an 'ipf -D' the system would then 467 * deadlock. The catch with releasing it here is that the 468 * caller of this function expects it to be held when we 469 * return so we have to reacquire it in here. 470 */ 471 RWLOCK_EXIT(&ifs->ifs_ipf_global); 472 473 MUTEX_ENTER(&ifs->ifs_ipf_authmx); 474 #ifdef _KERNEL 475 # if SOLARIS 476 error = 0; 477 if (!cv_wait_sig(&ifs->ifs_ipfauthwait, &ifs->ifs_ipf_authmx.ipf_lk)) 478 error = EINTR; 479 # else /* SOLARIS */ 480 # ifdef __hpux 481 { 482 lock_t *l; 483 484 l = get_sleep_lock(&ifs->ifs_fr_authnext); 485 error = sleep(&ifs->ifs_fr_authnext, PZERO+1); 486 spinunlock(l); 487 } 488 # else 489 # ifdef __osf__ 490 error = mpsleep(&ifs->ifs_fr_authnext, PSUSP|PCATCH, 491 "fr_authnext", 0, 492 &ifs->ifs_ipf_authmx, MS_LOCK_SIMPLE); 493 # else 494 error = SLEEP(&ifs->ifs_fr_authnext, "fr_authnext"); 495 # endif /* __osf__ */ 496 # endif /* __hpux */ 497 # endif /* SOLARIS */ 498 #endif 499 MUTEX_EXIT(&ifs->ifs_ipf_authmx); 500 READ_ENTER(&ifs->ifs_ipf_global); 501 if (error == 0) { 502 READ_ENTER(&ifs->ifs_ipf_auth); 503 goto fr_authioctlloop; 504 } 505 break; 506 507 case SIOCAUTHR: 508 error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); 509 if (error != 0) 510 return error; 511 SPL_NET(s); 512 WRITE_ENTER(&ifs->ifs_ipf_auth); 513 i = au->fra_index; 514 fra = ifs->ifs_fr_auth + i; 515 if ((i < 0) || (i >= ifs->ifs_fr_authsize) || 516 (fra->fra_info.fin_id != au->fra_info.fin_id)) { 517 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 518 SPL_X(s); 519 return ESRCH; 520 } 521 m = ifs->ifs_fr_authpkts[i]; 522 fra->fra_index = -2; 523 fra->fra_pass = au->fra_pass; 524 ifs->ifs_fr_authpkts[i] = NULL; 525 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 526 #ifdef _KERNEL 527 if (fra->fra_info.fin_v == 4) { 528 net_data_p = ifs->ifs_ipf_ipv4; 529 } else if (fra->fra_info.fin_v == 6) { 530 net_data_p = ifs->ifs_ipf_ipv6; 531 } else { 532 return (-1); 533 } 534 535 /* 536 * We're putting the packet back on the same interface 537 * queue that it was originally seen on so that it can 538 * progress through the system properly, with the result 539 * of the auth check done. 540 */ 541 inj_data.ni_physical = (phy_if_t)fra->fra_info.fin_ifp; 542 543 if ((m != NULL) && (au->fra_info.fin_out != 0)) { 544 # ifdef MENTAT 545 inj_data.ni_packet = m; 546 ret = net_inject(net_data_p, NI_QUEUE_OUT, &inj_data); 547 548 if (ret < 0) 549 ifs->ifs_fr_authstats.fas_sendfail++; 550 else 551 ifs->ifs_fr_authstats.fas_sendok++; 552 # else /* MENTAT */ 553 # if defined(linux) || defined(AIX) 554 # else 555 # if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \ 556 (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \ 557 (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) 558 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, 559 NULL); 560 # else 561 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 562 # endif 563 if (error != 0) 564 ifs->ifs_fr_authstats.fas_sendfail++; 565 else 566 ifs->ifs_fr_authstats.fas_sendok++; 567 # endif /* Linux */ 568 # endif /* MENTAT */ 569 } else if (m) { 570 # ifdef MENTAT 571 inj_data.ni_packet = m; 572 ret = net_inject(net_data_p, NI_QUEUE_IN, &inj_data); 573 # else /* MENTAT */ 574 # if defined(linux) || defined(AIX) 575 # else 576 # if (__FreeBSD_version >= 501000) 577 netisr_dispatch(NETISR_IP, m); 578 # else 579 # if (IRIX >= 60516) 580 ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; 581 # else 582 ifq = &ipintrq; 583 # endif 584 if (IF_QFULL(ifq)) { 585 IF_DROP(ifq); 586 FREE_MB_T(m); 587 error = ENOBUFS; 588 } else { 589 IF_ENQUEUE(ifq, m); 590 # if IRIX < 60500 591 schednetisr(NETISR_IP); 592 # endif 593 } 594 # endif 595 # endif /* Linux */ 596 # endif /* MENTAT */ 597 if (error != 0) 598 ifs->ifs_fr_authstats.fas_quefail++; 599 else 600 ifs->ifs_fr_authstats.fas_queok++; 601 } else 602 error = EINVAL; 603 # ifdef MENTAT 604 if (error != 0) 605 error = EINVAL; 606 # else /* MENTAT */ 607 /* 608 * If we experience an error which will result in the packet 609 * not being processed, make sure we advance to the next one. 610 */ 611 if (error == ENOBUFS) { 612 ifs->ifs_fr_authused--; 613 fra->fra_index = -1; 614 fra->fra_pass = 0; 615 if (i == ifs->ifs_fr_authstart) { 616 while (fra->fra_index == -1) { 617 i++; 618 if (i == ifs->ifs_fr_authsize) 619 i = 0; 620 ifs->ifs_fr_authstart = i; 621 if (i == ifs->ifs_fr_authend) 622 break; 623 } 624 if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) { 625 ifs->ifs_fr_authnext = 0; 626 ifs->ifs_fr_authstart = 0; 627 ifs->ifs_fr_authend = 0; 628 } 629 } 630 } 631 # endif /* MENTAT */ 632 #endif /* _KERNEL */ 633 SPL_X(s); 634 break; 635 636 default : 637 error = EINVAL; 638 break; 639 } 640 return error; 641 } 642 643 644 /* 645 * Free all network buffer memory used to keep saved packets. 646 */ 647 void fr_authunload(ifs) 648 ipf_stack_t *ifs; 649 { 650 register int i; 651 register frauthent_t *fae, **faep; 652 frentry_t *fr, **frp; 653 mb_t *m; 654 655 if (ifs->ifs_fr_auth != NULL) { 656 KFREES(ifs->ifs_fr_auth, 657 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 658 ifs->ifs_fr_auth = NULL; 659 } 660 661 if (ifs->ifs_fr_authpkts != NULL) { 662 for (i = 0; i < ifs->ifs_fr_authsize; i++) { 663 m = ifs->ifs_fr_authpkts[i]; 664 if (m != NULL) { 665 FREE_MB_T(m); 666 ifs->ifs_fr_authpkts[i] = NULL; 667 } 668 } 669 KFREES(ifs->ifs_fr_authpkts, 670 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 671 ifs->ifs_fr_authpkts = NULL; 672 } 673 674 faep = &ifs->ifs_fae_list; 675 while ((fae = *faep) != NULL) { 676 *faep = fae->fae_next; 677 KFREE(fae); 678 } 679 ifs->ifs_ipauth = NULL; 680 681 if (ifs->ifs_fr_authlist != NULL) { 682 for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) { 683 if (fr->fr_ref == 1) { 684 *frp = fr->fr_next; 685 KFREE(fr); 686 } else 687 frp = &fr->fr_next; 688 } 689 } 690 691 if (ifs->ifs_fr_auth_init == 1) { 692 # if SOLARIS && defined(_KERNEL) 693 cv_destroy(&ifs->ifs_ipfauthwait); 694 # endif 695 MUTEX_DESTROY(&ifs->ifs_ipf_authmx); 696 RW_DESTROY(&ifs->ifs_ipf_auth); 697 698 ifs->ifs_fr_auth_init = 0; 699 } 700 } 701 702 703 /* 704 * Slowly expire held auth records. Timeouts are set 705 * in expectation of this being called twice per second. 706 */ 707 void fr_authexpire(ifs) 708 ipf_stack_t *ifs; 709 { 710 register int i; 711 register frauth_t *fra; 712 register frauthent_t *fae, **faep; 713 register frentry_t *fr, **frp; 714 mb_t *m; 715 SPL_INT(s); 716 717 if (ifs->ifs_fr_auth_lock) 718 return; 719 720 SPL_NET(s); 721 WRITE_ENTER(&ifs->ifs_ipf_auth); 722 for (i = 0, fra = ifs->ifs_fr_auth; i < ifs->ifs_fr_authsize; i++, fra++) { 723 fra->fra_age--; 724 if ((fra->fra_age == 0) && (m = ifs->ifs_fr_authpkts[i])) { 725 FREE_MB_T(m); 726 ifs->ifs_fr_authpkts[i] = NULL; 727 ifs->ifs_fr_auth[i].fra_index = -1; 728 ifs->ifs_fr_authstats.fas_expire++; 729 ifs->ifs_fr_authused--; 730 } 731 } 732 733 for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) { 734 fae->fae_age--; 735 if (fae->fae_age == 0) { 736 *faep = fae->fae_next; 737 KFREE(fae); 738 ifs->ifs_fr_authstats.fas_expire++; 739 } else 740 faep = &fae->fae_next; 741 } 742 if (ifs->ifs_fae_list != NULL) 743 ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr; 744 else 745 ifs->ifs_ipauth = NULL; 746 747 for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) { 748 if (fr->fr_ref == 1) { 749 *frp = fr->fr_next; 750 KFREE(fr); 751 } else 752 frp = &fr->fr_next; 753 } 754 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 755 SPL_X(s); 756 } 757 758 int fr_preauthcmd(cmd, fr, frptr, ifs) 759 ioctlcmd_t cmd; 760 frentry_t *fr, **frptr; 761 ipf_stack_t *ifs; 762 { 763 frauthent_t *fae, **faep; 764 int error = 0; 765 SPL_INT(s); 766 767 if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) 768 return EIO; 769 770 for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) { 771 if (&fae->fae_fr == fr) 772 break; 773 else 774 faep = &fae->fae_next; 775 } 776 777 if (cmd == (ioctlcmd_t)SIOCRMAFR) { 778 if (fr == NULL || frptr == NULL) 779 error = EINVAL; 780 else if (fae == NULL) 781 error = ESRCH; 782 else { 783 SPL_NET(s); 784 WRITE_ENTER(&ifs->ifs_ipf_auth); 785 *faep = fae->fae_next; 786 if (ifs->ifs_ipauth == &fae->fae_fr) 787 ifs->ifs_ipauth = ifs->ifs_fae_list ? 788 &ifs->ifs_fae_list->fae_fr : NULL; 789 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 790 SPL_X(s); 791 792 KFREE(fae); 793 } 794 } else if (fr != NULL && frptr != NULL) { 795 KMALLOC(fae, frauthent_t *); 796 if (fae != NULL) { 797 bcopy((char *)fr, (char *)&fae->fae_fr, 798 sizeof(*fr)); 799 SPL_NET(s); 800 WRITE_ENTER(&ifs->ifs_ipf_auth); 801 fae->fae_age = ifs->ifs_fr_defaultauthage; 802 fae->fae_fr.fr_hits = 0; 803 fae->fae_fr.fr_next = *frptr; 804 fae->fae_ref = 1; 805 *frptr = &fae->fae_fr; 806 fae->fae_next = *faep; 807 *faep = fae; 808 ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr; 809 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 810 SPL_X(s); 811 } else 812 error = ENOMEM; 813 } else 814 error = EINVAL; 815 return error; 816 } 817 818 819 /* 820 * Flush held packets. 821 * Must already be properly SPL'ed and Locked on &ipf_auth. 822 * 823 */ 824 int fr_authflush(ifs) 825 ipf_stack_t *ifs; 826 { 827 register int i, num_flushed; 828 mb_t *m; 829 830 if (ifs->ifs_fr_auth_lock) 831 return -1; 832 833 num_flushed = 0; 834 835 for (i = 0 ; i < ifs->ifs_fr_authsize; i++) { 836 m = ifs->ifs_fr_authpkts[i]; 837 if (m != NULL) { 838 FREE_MB_T(m); 839 ifs->ifs_fr_authpkts[i] = NULL; 840 ifs->ifs_fr_auth[i].fra_index = -1; 841 /* perhaps add & use a flush counter inst.*/ 842 ifs->ifs_fr_authstats.fas_expire++; 843 ifs->ifs_fr_authused--; 844 num_flushed++; 845 } 846 } 847 848 ifs->ifs_fr_authstart = 0; 849 ifs->ifs_fr_authend = 0; 850 ifs->ifs_fr_authnext = 0; 851 852 return num_flushed; 853 } 854 855 /* ------------------------------------------------------------------------ */ 856 /* Function: fr_authgeniter */ 857 /* Returns: int - 0 == success, else error */ 858 /* Parameters: token(I) - pointer to ipftoken structure */ 859 /* itp(I) - pointer to ipfgeniter structure */ 860 /* */ 861 /* ------------------------------------------------------------------------ */ 862 int fr_authgeniter(token, itp, ifs) 863 ipftoken_t *token; 864 ipfgeniter_t *itp; 865 ipf_stack_t *ifs; 866 { 867 frauthent_t *fae, *next, zero; 868 int error; 869 870 if (itp->igi_data == NULL) 871 return EFAULT; 872 873 if (itp->igi_type != IPFGENITER_AUTH) 874 return EINVAL; 875 876 READ_ENTER(&ifs->ifs_ipf_auth); 877 878 /* 879 * Retrieve "previous" entry from token and find the next entry. 880 */ 881 fae = token->ipt_data; 882 if (fae == NULL) { 883 next = ifs->ifs_fae_list; 884 } else { 885 next = fae->fae_next; 886 } 887 888 /* 889 * If we found an entry, add reference to it and update token. 890 * Otherwise, zero out data to be returned and NULL out token. 891 */ 892 if (next != NULL) { 893 ATOMIC_INC(next->fae_ref); 894 token->ipt_data = next; 895 } else { 896 bzero(&zero, sizeof(zero)); 897 next = &zero; 898 token->ipt_data = NULL; 899 } 900 901 /* 902 * Safe to release the lock now that we have a reference. 903 */ 904 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 905 906 /* 907 * Copy out the data and clean up references and token as needed. 908 */ 909 error = COPYOUT(next, itp->igi_data, sizeof(*next)); 910 if (error != 0) 911 error = EFAULT; 912 if (token->ipt_data == NULL) { 913 ipf_freetoken(token, ifs); 914 } else { 915 if (fae != NULL) { 916 WRITE_ENTER(&ifs->ifs_ipf_auth); 917 fr_authderef(&fae); 918 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 919 } 920 if (next->fae_next == NULL) 921 ipf_freetoken(token, ifs); 922 } 923 return error; 924 } 925 926 927 void fr_authderef(faep) 928 frauthent_t **faep; 929 { 930 frauthent_t *fae; 931 932 fae = *faep; 933 *faep = NULL; 934 935 fae->fae_ref--; 936 if (fae->fae_ref == 0) { 937 KFREE(fae); 938 } 939 } 940