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