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