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