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
fr_authinit(ifs)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 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 */
fr_checkauth(fin,passp)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 */
fr_newauth(m,fin)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 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
fr_auth_ioctl(data,cmd,mode,uid,ctx,ifs)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 */
fr_authunload(ifs)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 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 */
fr_authexpire(ifs)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
fr_preauthcmd(cmd,fr,frptr,ifs)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 */
fr_authflush(ifs)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 /* ------------------------------------------------------------------------ */
fr_authgeniter(token,itp,ifs)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
fr_authderef(faep)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