Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dist / ipf / netinet / ip_auth.c
blob1f77b51292c5c011bb7709c421db0b0515de5f3e
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 * Copyright 2008 Sun Microsystems, Inc.
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 #endif
57 #if (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802)) || \
58 (defined(__FreeBSD_version) &&(__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 #include <net/route.h>
69 #ifdef sun
70 # include <net/af.h>
71 #endif
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/ip_fil.h"
108 #include "netinet/ip_auth.h"
109 #if !defined(MENTAT) && !defined(linux)
110 # include <net/netisr.h>
111 # ifdef __FreeBSD__
112 # include <machine/cpufunc.h>
113 # endif
114 #endif
115 #if (__FreeBSD_version >= 300000)
116 # include <sys/malloc.h>
117 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
118 # include <sys/libkern.h>
119 # include <sys/systm.h>
120 # endif
121 #endif
122 /* END OF INCLUDES */
124 #if !defined(lint)
125 #if defined(__NetBSD__)
126 #include <sys/cdefs.h>
127 __KERNEL_RCSID(0, "$NetBSD$");
128 #else
129 static const char rcsid[] = "@(#)Id: ip_auth.c,v 2.73.2.33 2009/05/13 18:31:14 darrenr Exp";
130 #endif
131 #endif
134 #if SOLARIS && defined(_KERNEL)
135 extern kcondvar_t ipfauthwait;
136 extern struct pollhead iplpollhead[IPL_LOGSIZE];
137 #endif /* SOLARIS */
138 #if defined(linux) && defined(_KERNEL)
139 wait_queue_head_t fr_authnext_linux;
140 #endif
142 int fr_authsize = FR_NUMAUTH;
143 int fr_authused = 0;
144 int fr_authreplies = 0;
145 int fr_defaultauthage = 600;
146 int fr_auth_lock = 0;
147 int fr_auth_init = 0;
148 fr_authstat_t fr_authstats;
149 static frauth_t *fr_auth = NULL;
150 mb_t **fr_authpkts = NULL;
151 int fr_authstart = 0, fr_authend = 0, fr_authnext = 0;
152 frauthent_t *fae_list = NULL;
153 frentry_t *ipauth = NULL,
154 *fr_authlist = NULL;
156 void fr_authderef __P((frauthent_t **));
157 int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *));
158 int fr_authreply __P((char *));
159 int fr_authwait __P((char *));
161 /* ------------------------------------------------------------------------ */
162 /* Function: fr_authinit */
163 /* Returns: int - 0 == success, else error */
164 /* Parameters: None */
165 /* */
166 /* Allocate memory and initialise data structures used in handling auth */
167 /* rules. */
168 /* ------------------------------------------------------------------------ */
169 int fr_authinit()
171 KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth));
172 if (fr_auth != NULL)
173 bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth));
174 else
175 return -1;
177 KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts));
178 if (fr_authpkts != NULL)
179 bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
180 else
181 return -2;
183 MUTEX_INIT(&ipf_authmx, "ipf auth log mutex");
184 RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock");
185 #if SOLARIS && defined(_KERNEL)
186 cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL);
187 #endif
188 #if defined(linux) && defined(_KERNEL)
189 init_waitqueue_head(&fr_authnext_linux);
190 #endif
192 fr_auth_init = 1;
194 return 0;
198 /* ------------------------------------------------------------------------ */
199 /* Function: fr_checkauth */
200 /* Returns: frentry_t* - pointer to ipf rule if match found, else NULL */
201 /* Parameters: fin(I) - pointer to ipftoken structure */
202 /* passp(I) - pointer to ipfgeniter structure */
203 /* */
204 /* Check if a packet has authorization. If the packet is found to match an */
205 /* authorization result and that would result in a feedback loop (i.e. it */
206 /* will end up returning FR_AUTH) then return FR_BLOCK instead. */
207 /* ------------------------------------------------------------------------ */
208 frentry_t *fr_checkauth(fin, passp)
209 fr_info_t *fin;
210 u_32_t *passp;
212 frentry_t *fr;
213 frauth_t *fra;
214 u_32_t pass;
215 u_short id;
216 ip_t *ip;
217 int i;
219 if (fr_auth_lock || !fr_authused)
220 return NULL;
222 ip = fin->fin_ip;
223 id = ip->ip_id;
225 READ_ENTER(&ipf_auth);
226 for (i = fr_authstart; i != fr_authend; ) {
228 * index becomes -2 only after an SIOCAUTHW. Check this in
229 * case the same packet gets sent again and it hasn't yet been
230 * auth'd.
232 fra = fr_auth + i;
233 if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) &&
234 !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) {
236 * Avoid feedback loop.
238 if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass)))
239 pass = FR_BLOCK;
241 * Create a dummy rule for the stateful checking to
242 * use and return. Zero out any values we don't
243 * trust from userland!
245 if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) &&
246 (fin->fin_flx & FI_FRAG))) {
247 KMALLOC(fr, frentry_t *);
248 if (fr) {
249 bcopy((char *)fra->fra_info.fin_fr,
250 (char *)fr, sizeof(*fr));
251 fr->fr_grp = NULL;
252 fr->fr_ifa = fin->fin_ifp;
253 fr->fr_func = NULL;
254 fr->fr_ref = 1;
255 fr->fr_flags = pass;
256 fr->fr_ifas[1] = NULL;
257 fr->fr_ifas[2] = NULL;
258 fr->fr_ifas[3] = NULL;
260 } else
261 fr = fra->fra_info.fin_fr;
262 fin->fin_fr = fr;
263 fin->fin_flx |= fra->fra_flx;
264 RWLOCK_EXIT(&ipf_auth);
266 WRITE_ENTER(&ipf_auth);
268 * fr_authlist is populated with the rules malloc'd
269 * above and only those.
271 if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) {
272 fr->fr_next = fr_authlist;
273 fr_authlist = fr;
275 fr_authstats.fas_hits++;
276 fra->fra_index = -1;
277 fr_authused--;
278 fr_authreplies--;
279 if (i == fr_authstart) {
280 while (fra->fra_index == -1) {
281 i++;
282 fra++;
283 if (i == fr_authsize) {
284 i = 0;
285 fra = fr_auth;
287 fr_authstart = i;
288 if (i == fr_authend)
289 break;
291 if (fr_authstart == fr_authend) {
292 fr_authnext = 0;
293 fr_authstart = 0;
294 fr_authend = 0;
297 RWLOCK_EXIT(&ipf_auth);
298 if (passp != NULL)
299 *passp = pass;
300 ATOMIC_INC64(fr_authstats.fas_hits);
301 return fr;
303 i++;
304 if (i == fr_authsize)
305 i = 0;
307 fr_authstats.fas_miss++;
308 RWLOCK_EXIT(&ipf_auth);
309 ATOMIC_INC64(fr_authstats.fas_miss);
310 return NULL;
314 /* ------------------------------------------------------------------------ */
315 /* Function: fr_newauth */
316 /* Returns: int - 1 == success, 0 = did not put packet on auth queue */
317 /* Parameters: m(I) - pointer to mb_t with packet in it */
318 /* fin(I) - pointer to packet information */
319 /* */
320 /* Check if we have room in the auth array to hold details for another */
321 /* packet. If we do, store it and wake up any user programs which are */
322 /* waiting to hear about these events. */
323 /* ------------------------------------------------------------------------ */
324 int fr_newauth(m, fin)
325 mb_t *m;
326 fr_info_t *fin;
328 #if defined(_KERNEL) && defined(MENTAT)
329 qpktinfo_t *qpi = fin->fin_qpi;
330 #endif
331 frauth_t *fra;
332 #if !defined(sparc) && !defined(m68k)
333 ip_t *ip;
334 #endif
335 int i;
337 if (fr_auth_lock)
338 return 0;
340 WRITE_ENTER(&ipf_auth);
341 if (((fr_authend + 1) % fr_authsize) == fr_authstart) {
342 fr_authstats.fas_nospace++;
343 RWLOCK_EXIT(&ipf_auth);
344 return 0;
347 fr_authstats.fas_added++;
348 fr_authused++;
349 i = fr_authend++;
350 if (fr_authend == fr_authsize)
351 fr_authend = 0;
353 fra = fr_auth + i;
354 fra->fra_index = i;
355 if (fin->fin_fr != NULL)
356 fra->fra_pass = fin->fin_fr->fr_flags;
357 else
358 fra->fra_pass = 0;
359 fra->fra_age = fr_defaultauthage;
360 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
361 fra->fra_flx = fra->fra_info.fin_flx & (FI_STATE|FI_NATED);
362 fra->fra_info.fin_flx &= ~(FI_STATE|FI_NATED);
363 #if !defined(sparc) && !defined(m68k)
365 * No need to copyback here as we want to undo the changes, not keep
366 * them.
368 ip = fin->fin_ip;
369 # if defined(MENTAT) && defined(_KERNEL)
370 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4))
371 # endif
373 register u_short bo;
375 bo = ip->ip_len;
376 ip->ip_len = htons(bo);
377 bo = ip->ip_off;
378 ip->ip_off = htons(bo);
380 #endif
381 #if SOLARIS && defined(_KERNEL)
382 COPYIFNAME(fin->fin_v, fin->fin_ifp, fra->fra_info.fin_ifname);
383 m->b_rptr -= qpi->qpi_off;
384 # if !defined(_INET_IP_STACK_H)
385 fra->fra_q = qpi->qpi_q; /* The queue can disappear! */
386 # endif
387 fra->fra_m = *fin->fin_mp;
388 fra->fra_info.fin_mp = &fra->fra_m;
389 fr_authpkts[i] = fra->fra_m;
390 RWLOCK_EXIT(&ipf_auth);
391 cv_signal(&ipfauthwait);
392 pollwakeup(&iplpollhead[IPL_LOGAUTH], POLLIN|POLLRDNORM);
393 #else
394 fr_authpkts[i] = m;
395 RWLOCK_EXIT(&ipf_auth);
396 WAKEUP(&fr_authnext, 0);
397 #endif
398 return 1;
402 /* ------------------------------------------------------------------------ */
403 /* Function: fr_auth_ioctl */
404 /* Returns: int - 0 == success, else error */
405 /* Parameters: data(IO) - pointer to ioctl data */
406 /* cmd(I) - ioctl command */
407 /* mode(I) - mode flags associated with open descriptor */
408 /* uid(I) - uid associatd with application making the call */
409 /* ctx(I) - pointer for context */
410 /* */
411 /* This function handles all of the ioctls recognised by the auth component */
412 /* in IPFilter - ie ioctls called on an open fd for /dev/ipauth */
413 /* ------------------------------------------------------------------------ */
414 int fr_auth_ioctl(data, cmd, mode, uid, ctx)
415 void *data;
416 ioctlcmd_t cmd;
417 int mode, uid;
418 void *ctx;
420 int error = 0, i;
421 SPL_INT(s);
423 switch (cmd)
425 case SIOCGENITER :
427 ipftoken_t *token;
428 ipfgeniter_t iter;
430 error = fr_inobj(data, &iter, IPFOBJ_GENITER);
431 if (error != 0)
432 break;
434 SPL_SCHED(s);
435 token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx);
436 if (token != NULL) {
437 error = fr_authgeniter(token, &iter);
438 WRITE_ENTER(&ipf_tokens);
439 if (token->ipt_data == NULL)
440 ipf_freetoken(token);
441 else
442 ipf_dereftoken(token);
443 RWLOCK_EXIT(&ipf_tokens);
444 } else {
445 error = ESRCH;
447 SPL_X(s);
449 break;
452 case SIOCADAFR :
453 case SIOCRMAFR :
454 if (!(mode & FWRITE))
455 error = EPERM;
456 else
457 error = frrequest(IPL_LOGAUTH, cmd, data,
458 fr_active, 1);
459 break;
461 case SIOCSTLCK :
462 if (!(mode & FWRITE)) {
463 error = EPERM;
464 break;
466 error = fr_lock(data, &fr_auth_lock);
467 break;
469 case SIOCATHST:
470 fr_authstats.fas_faelist = fae_list;
471 error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT);
472 break;
474 case SIOCIPFFL:
475 SPL_NET(s);
476 WRITE_ENTER(&ipf_auth);
477 i = fr_authflush();
478 RWLOCK_EXIT(&ipf_auth);
479 SPL_X(s);
480 BCOPYOUT((char *)&i, data, sizeof(i));
481 break;
483 case SIOCAUTHW:
484 error = fr_authwait(data);
485 break;
487 case SIOCAUTHR:
488 error = fr_authreply(data);
489 break;
491 default :
492 error = EINVAL;
493 break;
495 return error;
499 /* ------------------------------------------------------------------------ */
500 /* Function: fr_authunload */
501 /* Returns: None */
502 /* Parameters: None */
503 /* */
504 /* Free all network buffer memory used to keep saved packets. */
505 /* ------------------------------------------------------------------------ */
506 void fr_authunload()
508 register int i;
509 register frauthent_t *fae, **faep;
510 frentry_t *fr, **frp;
511 mb_t *m;
513 if (fr_auth != NULL) {
514 KFREES(fr_auth, fr_authsize * sizeof(*fr_auth));
515 fr_auth = NULL;
518 if (fr_authpkts != NULL) {
519 for (i = 0; i < fr_authsize; i++) {
520 m = fr_authpkts[i];
521 if (m != NULL) {
522 FREE_MB_T(m);
523 fr_authpkts[i] = NULL;
526 KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
527 fr_authpkts = NULL;
530 faep = &fae_list;
531 while ((fae = *faep) != NULL) {
532 *faep = fae->fae_next;
533 KFREE(fae);
535 ipauth = NULL;
537 if (fr_authlist != NULL) {
538 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
539 if (fr->fr_ref == 1) {
540 *frp = fr->fr_next;
541 KFREE(fr);
542 } else
543 frp = &fr->fr_next;
547 if (fr_auth_init == 1) {
548 # if SOLARIS && defined(_KERNEL)
549 cv_destroy(&ipfauthwait);
550 # endif
551 MUTEX_DESTROY(&ipf_authmx);
552 RW_DESTROY(&ipf_auth);
554 fr_auth_init = 0;
559 /* ------------------------------------------------------------------------ */
560 /* Function: fr_authexpire */
561 /* Returns: None */
562 /* Parameters: None */
563 /* */
564 /* Slowly expire held auth records. Timeouts are set in expectation of */
565 /* this being called twice per second. */
566 /* ------------------------------------------------------------------------ */
567 void fr_authexpire()
569 frauthent_t *fae, **faep;
570 frentry_t *fr, **frp;
571 frauth_t *fra;
572 mb_t *m;
573 int i;
574 SPL_INT(s);
576 if (fr_auth_lock)
577 return;
579 SPL_NET(s);
580 WRITE_ENTER(&ipf_auth);
581 for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) {
582 fra->fra_age--;
583 if ((fra->fra_age == 0) && (fr_auth[i].fra_index != -1)) {
584 if ((m = fr_authpkts[i]) != NULL) {
585 FREE_MB_T(m);
586 fr_authpkts[i] = NULL;
587 } else if (fr_auth[i].fra_index == -2) {
588 fr_authreplies--;
591 fr_auth[i].fra_index = -1;
592 fr_authstats.fas_expire++;
593 fr_authused--;
598 * Expire pre-auth rules
600 for (faep = &fae_list; ((fae = *faep) != NULL); ) {
601 fae->fae_age--;
602 if (fae->fae_age == 0) {
603 fr_authderef(&fae);
604 fr_authstats.fas_expire++;
605 } else
606 faep = &fae->fae_next;
608 if (fae_list != NULL)
609 ipauth = &fae_list->fae_fr;
610 else
611 ipauth = NULL;
613 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
614 if (fr->fr_ref == 1) {
615 *frp = fr->fr_next;
616 KFREE(fr);
617 } else
618 frp = &fr->fr_next;
620 RWLOCK_EXIT(&ipf_auth);
621 SPL_X(s);
625 /* ------------------------------------------------------------------------ */
626 /* Function: fr_preauthcmd */
627 /* Returns: int - 0 == success, else error */
628 /* Parameters: cmd(I) - ioctl command for rule */
629 /* fr(I) - pointer to ipf rule */
630 /* fptr(I) - pointer to caller's 'fr' */
631 /* */
632 /* ------------------------------------------------------------------------ */
633 int fr_preauthcmd(cmd, fr, frptr)
634 ioctlcmd_t cmd;
635 frentry_t *fr, **frptr;
637 frauthent_t *fae, **faep;
638 int error = 0;
639 SPL_INT(s);
641 if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR))
642 return EIO;
644 for (faep = &fae_list; ((fae = *faep) != NULL); ) {
645 if (&fae->fae_fr == fr)
646 break;
647 else
648 faep = &fae->fae_next;
651 if (cmd == (ioctlcmd_t)SIOCRMAFR) {
652 if (fr == NULL || frptr == NULL)
653 error = EINVAL;
654 else if (fae == NULL)
655 error = ESRCH;
656 else {
657 SPL_NET(s);
658 WRITE_ENTER(&ipf_auth);
659 *faep = fae->fae_next;
660 if (ipauth == &fae->fae_fr)
661 ipauth = fae_list ? &fae_list->fae_fr : NULL;
662 RWLOCK_EXIT(&ipf_auth);
663 SPL_X(s);
665 KFREE(fae);
667 } else if (fr != NULL && frptr != NULL) {
668 KMALLOC(fae, frauthent_t *);
669 if (fae != NULL) {
670 bcopy((char *)fr, (char *)&fae->fae_fr,
671 sizeof(*fr));
672 SPL_NET(s);
673 WRITE_ENTER(&ipf_auth);
674 fae->fae_age = fr_defaultauthage;
675 fae->fae_fr.fr_hits = 0;
676 fae->fae_fr.fr_next = *frptr;
677 fae->fae_ref = 1;
678 *frptr = &fae->fae_fr;
679 fae->fae_next = *faep;
680 *faep = fae;
681 ipauth = &fae_list->fae_fr;
682 RWLOCK_EXIT(&ipf_auth);
683 SPL_X(s);
684 } else
685 error = ENOMEM;
686 } else
687 error = EINVAL;
688 return error;
692 /* ------------------------------------------------------------------------ */
693 /* Function: fr_authflush */
694 /* Returns: int - number of auth entries flushed */
695 /* Parameters: None */
696 /* Locks: WRITE(ipf_auth) */
697 /* */
698 /* This function flushs the fr_authpkts array of any packet data with */
699 /* references still there. */
700 /* It is expected that the caller has already acquired the correct locks or */
701 /* set the priority level correctly for this to block out other code paths */
702 /* into these data structures. */
703 /* ------------------------------------------------------------------------ */
704 int fr_authflush()
706 register int i, num_flushed;
707 mb_t *m;
709 if (fr_auth_lock)
710 return -1;
712 num_flushed = 0;
714 for (i = 0 ; i < fr_authsize; i++) {
715 if (fr_auth[i].fra_index != -1) {
716 m = fr_authpkts[i];
717 if (m != NULL) {
718 FREE_MB_T(m);
719 fr_authpkts[i] = NULL;
722 fr_auth[i].fra_index = -1;
723 /* perhaps add & use a flush counter inst.*/
724 fr_authstats.fas_expire++;
725 num_flushed++;
729 fr_authstart = 0;
730 fr_authend = 0;
731 fr_authnext = 0;
732 fr_authused = 0;
733 fr_authreplies = 0;
735 return num_flushed;
739 /* ------------------------------------------------------------------------ */
740 /* Function: fr_auth_waiting */
741 /* Returns: int - 0 = no pakcets wiating, 1 = packets waiting. */
742 /* Parameters: None */
743 /* */
744 /* Simple truth check to see if there are any packets waiting in the auth */
745 /* queue. */
746 /* ------------------------------------------------------------------------ */
747 int fr_auth_waiting()
749 return (fr_authused != 0);
753 /* ------------------------------------------------------------------------ */
754 /* Function: fr_authgeniter */
755 /* Returns: int - 0 == success, else error */
756 /* Parameters: token(I) - pointer to ipftoken structure */
757 /* itp(I) - pointer to ipfgeniter structure */
758 /* */
759 /* ------------------------------------------------------------------------ */
760 int fr_authgeniter(token, itp)
761 ipftoken_t *token;
762 ipfgeniter_t *itp;
764 frauthent_t *fae, *next, zero;
765 int error;
767 if (itp->igi_data == NULL)
768 return EFAULT;
770 if (itp->igi_type != IPFGENITER_AUTH)
771 return EINVAL;
773 READ_ENTER(&ipf_auth);
776 * Retrieve "previous" entry from token and find the next entry.
778 fae = token->ipt_data;
779 if (fae == NULL) {
780 next = fae_list;
781 } else {
782 next = fae->fae_next;
786 * If we found an entry, add reference to it and update token.
787 * Otherwise, zero out data to be returned and NULL out token.
789 if (next != NULL) {
790 ATOMIC_INC(next->fae_ref);
791 token->ipt_data = next;
792 } else {
793 bzero(&zero, sizeof(zero));
794 next = &zero;
795 token->ipt_data = NULL;
799 * Safe to release the lock now that we have a reference.
801 RWLOCK_EXIT(&ipf_auth);
804 * Copy out the data and clean up references and token as needed.
806 error = COPYOUT(next, itp->igi_data, sizeof(*next));
807 if (error != 0)
808 error = EFAULT;
811 * Clean up reference and token.
813 if (token->ipt_data != NULL) {
814 if (fae != NULL) {
815 WRITE_ENTER(&ipf_auth);
816 fr_authderef(&fae);
817 RWLOCK_EXIT(&ipf_auth);
819 if (next->fae_next == NULL)
820 token->ipt_data = NULL;
822 return error;
826 /* ------------------------------------------------------------------------ */
827 /* Function: fr_authderef */
828 /* Returns: None */
829 /* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */
830 /* Locks: WRITE(ipf_auth) */
831 /* */
832 /* This function unconditionally sets the pointer in the caller to NULL, */
833 /* to make it clear that it should no longer use that pointer, and drops */
834 /* the reference count on the structure by 1. If it reaches 0, free it up. */
835 /* ------------------------------------------------------------------------ */
836 void fr_authderef(faep)
837 frauthent_t **faep;
839 frauthent_t *fae;
841 fae = *faep;
842 *faep = NULL;
844 fae->fae_ref--;
845 if (fae->fae_ref == 0) {
846 KFREE(fae);
851 /* ------------------------------------------------------------------------ */
852 /* Function: fr_authwait */
853 /* Returns: int - 0 == success, else error */
854 /* Parameters: data(I) - pointer to data from ioctl call */
855 /* */
856 /* This function is called when an application is waiting for a packet to */
857 /* match an "auth" rule by issuing an SIOCAUTHW ioctl. If there is already */
858 /* a packet waiting on the queue then we will return that _one_ immediately.*/
859 /* If there are no packets present in the queue (fr_authpkts) then we go to */
860 /* sleep. */
861 /* ------------------------------------------------------------------------ */
862 int fr_authwait(data)
863 char *data;
865 frauth_t auth, *au = &auth;
866 int error, len, i;
867 mb_t *m;
868 char *t;
869 SPL_INT(s);
871 fr_authioctlloop:
872 error = fr_inobj(data, au, IPFOBJ_FRAUTH);
873 if (error != 0)
874 return error;
877 * XXX Locks are held below over calls to copyout...a better
878 * solution needs to be found so this isn't necessary. The situation
879 * we are trying to guard against here is an error in the copyout
880 * steps should not cause the packet to "disappear" from the queue.
882 SPL_NET(s);
883 READ_ENTER(&ipf_auth);
886 * If fr_authnext is not equal to fr_authend it will be because there
887 * is a packet waiting to be delt with in the fr_authpkts array. We
888 * copy as much of that out to user space as requested.
890 if (fr_authused > fr_authreplies) {
891 while (fr_authpkts[fr_authnext] == NULL) {
892 fr_authnext++;
893 if (fr_authnext == fr_authsize)
894 fr_authnext = 0;
897 error = fr_outobj(data, &fr_auth[fr_authnext], IPFOBJ_FRAUTH);
898 if (error != 0) {
899 RWLOCK_EXIT(&ipf_auth);
900 SPL_X(s);
901 return error;
904 if (auth.fra_len != 0 && auth.fra_buf != NULL) {
906 * Copy packet contents out to user space if
907 * requested. Bail on an error.
909 m = fr_authpkts[fr_authnext];
910 len = MSGDSIZE(m);
911 if (len > auth.fra_len)
912 len = auth.fra_len;
913 auth.fra_len = len;
915 for (t = auth.fra_buf; m && (len > 0); ) {
916 i = MIN(M_LEN(m), len);
917 error = copyoutptr(MTOD(m, char *), &t, i);
918 len -= i;
919 t += i;
920 if (error != 0) {
921 RWLOCK_EXIT(&ipf_auth);
922 SPL_X(s);
923 return error;
925 m = m->m_next;
928 RWLOCK_EXIT(&ipf_auth);
930 SPL_NET(s);
931 WRITE_ENTER(&ipf_auth);
932 fr_authnext++;
933 if (fr_authnext == fr_authsize)
934 fr_authnext = 0;
935 RWLOCK_EXIT(&ipf_auth);
936 SPL_X(s);
938 return 0;
940 RWLOCK_EXIT(&ipf_auth);
941 SPL_X(s);
943 MUTEX_ENTER(&ipf_authmx);
944 #ifdef _KERNEL
945 # if SOLARIS
946 error = 0;
947 if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk))
948 error = EINTR;
949 # else /* SOLARIS */
950 # ifdef __hpux
952 lock_t *l;
954 l = get_sleep_lock(&fr_authnext);
955 error = sleep(&fr_authnext, PZERO+1);
956 spinunlock(l);
958 # else
959 # ifdef __osf__
960 error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0,
961 &ipf_authmx, MS_LOCK_SIMPLE);
962 # else
963 error = SLEEP(&fr_authnext, "fr_authnext");
964 # endif /* __osf__ */
965 # endif /* __hpux */
966 # endif /* SOLARIS */
967 #endif
968 MUTEX_EXIT(&ipf_authmx);
969 if (error == 0)
970 goto fr_authioctlloop;
971 return error;
975 /* ------------------------------------------------------------------------ */
976 /* Function: fr_authreply */
977 /* Returns: int - 0 == success, else error */
978 /* Parameters: data(I) - pointer to data from ioctl call */
979 /* */
980 /* This function is called by an application when it wants to return a */
981 /* decision on a packet using the SIOCAUTHR ioctl. This is after it has */
982 /* received information using an SIOCAUTHW. The decision returned in the */
983 /* form of flags, the same as those used in each rule. */
984 /* ------------------------------------------------------------------------ */
985 int fr_authreply(data)
986 char *data;
988 frauth_t auth, *au = &auth, *fra;
989 fr_info_t fin;
990 int error, i;
991 mb_t *m;
992 SPL_INT(s);
994 error = fr_inobj(data, &auth, IPFOBJ_FRAUTH);
995 if (error != 0)
996 return error;
998 SPL_NET(s);
999 WRITE_ENTER(&ipf_auth);
1001 i = au->fra_index;
1002 fra = fr_auth + i;
1003 error = 0;
1006 * Check the validity of the information being returned with two simple
1007 * checks. First, the auth index value should be within the size of
1008 * the array and second the packet id being returned should also match.
1010 if ((i < 0) || (i >= fr_authsize) ||
1011 (fra->fra_info.fin_id != au->fra_info.fin_id)) {
1012 RWLOCK_EXIT(&ipf_auth);
1013 SPL_X(s);
1014 return ESRCH;
1017 m = fr_authpkts[i];
1018 fra->fra_index = -2;
1019 fra->fra_pass = au->fra_pass;
1020 fr_authpkts[i] = NULL;
1021 fr_authreplies++;
1022 bcopy(&fra->fra_info, &fin, sizeof(fin));
1024 RWLOCK_EXIT(&ipf_auth);
1027 * Re-insert the packet back into the packet stream flowing through
1028 * the kernel in a manner that will mean IPFilter sees the packet
1029 * again. This is not the same as is done with fastroute,
1030 * deliberately, as we want to resume the normal packet processing
1031 * path for it.
1033 #ifdef _KERNEL
1034 if ((m != NULL) && (au->fra_info.fin_out != 0)) {
1035 error = ipf_inject(&fin, m);
1036 if (error != 0) {
1037 error = ENOBUFS;
1038 fr_authstats.fas_sendfail++;
1039 } else {
1040 fr_authstats.fas_sendok++;
1042 } else if (m) {
1043 error = ipf_inject(&fin, m);
1044 if (error != 0) {
1045 error = ENOBUFS;
1046 fr_authstats.fas_quefail++;
1047 } else {
1048 fr_authstats.fas_queok++;
1050 } else {
1051 error = EINVAL;
1055 * If we experience an error which will result in the packet
1056 * not being processed, make sure we advance to the next one.
1058 if (error == ENOBUFS) {
1059 WRITE_ENTER(&ipf_auth);
1061 * Check that the queue item has not been flushed
1062 * (and possible reused) yet.
1064 if ((fra->fra_index == -2) &&
1065 !bcmp((char *)&fin, (char *)&fra->fra_info, sizeof(fin))) {
1066 fr_authused--;
1067 fr_authreplies--;
1068 fra->fra_index = -1;
1069 fra->fra_pass = 0;
1070 if (i == fr_authstart) {
1071 while (fra->fra_index == -1) {
1072 i++;
1073 fra++;
1074 if (i == fr_authsize) {
1075 i = 0;
1076 fra = fr_auth;
1078 fr_authstart = i;
1079 if (i == fr_authend)
1080 break;
1082 if (fr_authstart == fr_authend) {
1083 fr_authnext = 0;
1084 fr_authstart = 0;
1085 fr_authend = 0;
1089 RWLOCK_EXIT(&ipf_auth);
1091 #endif /* _KERNEL */
1092 SPL_X(s);
1094 return 0;