1 /*	$NetBSD: ip_auth.c,v 1.5 2014/05/30 02:16:17 rmind Exp $	*/
2 
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define        KERNEL	1
12 # define        _KERNEL	1
13 #endif
14 #if defined(__NetBSD__)
15 #include <sys/cdefs.h>
16 #endif
17 #include <sys/errno.h>
18 #include <sys/types.h>
19 #include <sys/param.h>
20 #include <sys/time.h>
21 #include <sys/file.h>
22 #if !defined(_KERNEL)
23 # include <stdio.h>
24 # include <stdlib.h>
25 # ifdef _STDC_C99
26 #  include <stdbool.h>
27 # endif
28 # include <string.h>
29 # define _KERNEL
30 # ifdef __OpenBSD__
31 struct file;
32 # endif
33 # include <sys/uio.h>
34 # undef _KERNEL
35 #endif
36 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
37 # include <sys/filio.h>
38 # include <sys/fcntl.h>
39 #else
40 # include <sys/ioctl.h>
41 #endif
42 #if !defined(linux)
43 # include <sys/protosw.h>
44 #endif
45 #include <sys/socket.h>
46 #if defined(_KERNEL)
47 # include <sys/systm.h>
48 # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux)
49 #  include <sys/mbuf.h>
50 # endif
51 #endif
52 #if defined(__SVR4) || defined(__svr4__)
53 # include <sys/filio.h>
54 # include <sys/byteorder.h>
55 # ifdef _KERNEL
56 #  include <sys/dditypes.h>
57 # endif
58 # include <sys/stream.h>
59 # include <sys/kmem.h>
60 #endif
61 #if (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802)) || \
62     (defined(__FreeBSD_version) &&(__FreeBSD_version >= 400000))
63 # include <sys/queue.h>
64 #endif
65 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
66 # include <machine/cpu.h>
67 #endif
68 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
69 # include <sys/proc.h>
70 #endif
71 #if defined(__NetBSD_Version__) &&  (__NetBSD_Version__ >= 400000) && \
72      !defined(_KERNEL)
73 # include <stdbool.h>
74 #endif
75 #include <net/if.h>
76 #include <net/route.h>
77 #ifdef sun
78 # include <net/af.h>
79 #endif
80 #include <netinet/in.h>
81 #include <netinet/in_systm.h>
82 #include <netinet/ip.h>
83 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi)
84 # define	KERNEL
85 # define	_KERNEL
86 # define	NOT_KERNEL
87 #endif
88 #if !defined(linux)
89 # include <netinet/ip_var.h>
90 #endif
91 #ifdef	NOT_KERNEL
92 # undef	_KERNEL
93 # undef	KERNEL
94 #endif
95 #include <netinet/tcp.h>
96 #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */
97 extern struct ifqueue   ipintrq;		/* ip packet input queue */
98 #else
99 # if !defined(__hpux) && !defined(linux)
100 #  if __FreeBSD_version >= 300000
101 #   include <net/if_var.h>
102 #   if __FreeBSD_version >= 500042
103 #    define IF_QFULL _IF_QFULL
104 #    define IF_DROP _IF_DROP
105 #   endif /* __FreeBSD_version >= 500042 */
106 #  endif
107 #  include <netinet/in_var.h>
108 #  include <netinet/tcp_fsm.h>
109 # endif
110 #endif
111 #include <netinet/udp.h>
112 #include <netinet/ip_icmp.h>
113 #include "netinet/ip_compat.h"
114 #include <netinet/tcpip.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 #if defined(__NetBSD__)
134 __KERNEL_RCSID(0, "$NetBSD: ip_auth.c,v 1.5 2014/05/30 02:16:17 rmind Exp $");
135 #else
136 static const char rcsid[] = "@(#)Id: ip_auth.c,v 1.1.1.2 2012/07/22 13:45:08 darrenr Exp";
137 #endif
138 #endif
139 
140 
141 typedef	struct ipf_auth_softc_s {
142 #if SOLARIS && defined(_KERNEL)
143 	kcondvar_t	ipf_auth_wait;
144 #endif /* SOLARIS */
145 #if defined(linux) && defined(_KERNEL)
146 	wait_queue_head_t ipf_auth_next_linux;
147 #endif
148 	ipfrwlock_t	ipf_authlk;
149 	ipfmutex_t	ipf_auth_mx;
150 	int		ipf_auth_size;
151 	int		ipf_auth_used;
152 	int		ipf_auth_replies;
153 	int		ipf_auth_defaultage;
154 	int		ipf_auth_lock;
155 	ipf_authstat_t	ipf_auth_stats;
156 	frauth_t	*ipf_auth;
157 	mb_t		**ipf_auth_pkts;
158 	int		ipf_auth_start;
159 	int		ipf_auth_end;
160 	int		ipf_auth_next;
161 	frauthent_t	*ipf_auth_entries;
162 	frentry_t	*ipf_auth_ip;
163 	frentry_t	*ipf_auth_rules;
164 } ipf_auth_softc_t;
165 
166 
167 static void ipf_auth_deref(frauthent_t **);
168 static void ipf_auth_deref_unlocked(ipf_auth_softc_t *, frauthent_t **);
169 static int ipf_auth_geniter(ipf_main_softc_t *, ipftoken_t *,
170 				 ipfgeniter_t *, ipfobj_t *);
171 static int ipf_auth_reply(ipf_main_softc_t *, ipf_auth_softc_t *, char *);
172 static int ipf_auth_wait(ipf_main_softc_t *, ipf_auth_softc_t *, char *);
173 static int ipf_auth_flush(void *);
174 
175 
176 /* ------------------------------------------------------------------------ */
177 /* Function:    ipf_auth_main_load                                          */
178 /* Returns:     int - 0 == success, else error                              */
179 /* Parameters:  None                                                        */
180 /*                                                                          */
181 /* A null-op function that exists as a placeholder so that the flow in      */
182 /* other functions is obvious.                                              */
183 /* ------------------------------------------------------------------------ */
184 int
ipf_auth_main_load(void)185 ipf_auth_main_load(void)
186 {
187 	return 0;
188 }
189 
190 
191 /* ------------------------------------------------------------------------ */
192 /* Function:    ipf_auth_main_unload                                        */
193 /* Returns:     int - 0 == success, else error                              */
194 /* Parameters:  None                                                        */
195 /*                                                                          */
196 /* A null-op function that exists as a placeholder so that the flow in      */
197 /* other functions is obvious.                                              */
198 /* ------------------------------------------------------------------------ */
199 int
ipf_auth_main_unload(void)200 ipf_auth_main_unload(void)
201 {
202 	return 0;
203 }
204 
205 
206 /* ------------------------------------------------------------------------ */
207 /* Function:    ipf_auth_soft_create                                        */
208 /* Returns:     int - NULL = failure, else success                          */
209 /* Parameters:  softc(I) - pointer to soft context data                     */
210 /*                                                                          */
211 /* Create a structre to store all of the run-time data for packet auth in   */
212 /* and initialise some fields to their defaults.                            */
213 /* ------------------------------------------------------------------------ */
214 void *
ipf_auth_soft_create(ipf_main_softc_t * softc)215 ipf_auth_soft_create(ipf_main_softc_t *softc)
216 {
217 	ipf_auth_softc_t *softa;
218 
219 	KMALLOC(softa, ipf_auth_softc_t *);
220 	if (softa == NULL)
221 		return NULL;
222 
223 	bzero((char *)softa, sizeof(*softa));
224 
225 	softa->ipf_auth_size = FR_NUMAUTH;
226 	softa->ipf_auth_defaultage = 600;
227 
228 	RWLOCK_INIT(&softa->ipf_authlk, "ipf IP User-Auth rwlock");
229 	MUTEX_INIT(&softa->ipf_auth_mx, "ipf auth log mutex");
230 #if SOLARIS && defined(_KERNEL)
231 	cv_init(&softa->ipf_auth_wait, "ipf auth condvar", CV_DRIVER, NULL);
232 #endif
233 
234 	return softa;
235 }
236 
237 /* ------------------------------------------------------------------------ */
238 /* Function:    ipf_auth_soft_init                                          */
239 /* Returns:     int - 0 == success, else error                              */
240 /* Parameters:  softc(I) - pointer to soft context data                     */
241 /*              arg(I)   - opaque pointer to auth context data              */
242 /*                                                                          */
243 /* Allocate memory and initialise data structures used in handling auth     */
244 /* rules.                                                                   */
245 /* ------------------------------------------------------------------------ */
246 int
ipf_auth_soft_init(ipf_main_softc_t * softc,void * arg)247 ipf_auth_soft_init(ipf_main_softc_t *softc, void *arg)
248 {
249 	ipf_auth_softc_t *softa = arg;
250 
251 	KMALLOCS(softa->ipf_auth, frauth_t *,
252 		 softa->ipf_auth_size * sizeof(*softa->ipf_auth));
253 	if (softa->ipf_auth == NULL)
254 		return -1;
255 	bzero((char *)softa->ipf_auth,
256 	      softa->ipf_auth_size * sizeof(*softa->ipf_auth));
257 
258 	KMALLOCS(softa->ipf_auth_pkts, mb_t **,
259 		 softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
260 	if (softa->ipf_auth_pkts == NULL)
261 		return -2;
262 	bzero((char *)softa->ipf_auth_pkts,
263 	      softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
264 
265 #if defined(linux) && defined(_KERNEL)
266 	init_waitqueue_head(&softa->ipf_auth_next_linux);
267 #endif
268 
269 	return 0;
270 }
271 
272 
273 /* ------------------------------------------------------------------------ */
274 /* Function:    ipf_auth_soft_fini                                          */
275 /* Returns:     int - 0 == success, else error                              */
276 /* Parameters:  softc(I) - pointer to soft context data                     */
277 /*              arg(I)   - opaque pointer to auth context data              */
278 /*                                                                          */
279 /* Free all network buffer memory used to keep saved packets that have been */
280 /* connectedd to the soft soft context structure *but* do not free that: it */
281 /* is free'd by _destroy().                                                 */
282 /* ------------------------------------------------------------------------ */
283 int
ipf_auth_soft_fini(ipf_main_softc_t * softc,void * arg)284 ipf_auth_soft_fini(ipf_main_softc_t *softc, void *arg)
285 {
286 	ipf_auth_softc_t *softa = arg;
287 	frauthent_t *fae, **faep;
288 	frentry_t *fr, **frp;
289 	mb_t *m;
290 	int i;
291 
292 	if (softa->ipf_auth != NULL) {
293 		KFREES(softa->ipf_auth,
294 		       softa->ipf_auth_size * sizeof(*softa->ipf_auth));
295 		softa->ipf_auth = NULL;
296 	}
297 
298 	if (softa->ipf_auth_pkts != NULL) {
299 		for (i = 0; i < softa->ipf_auth_size; i++) {
300 			m = softa->ipf_auth_pkts[i];
301 			if (m != NULL) {
302 				FREE_MB_T(m);
303 				softa->ipf_auth_pkts[i] = NULL;
304 			}
305 		}
306 		KFREES(softa->ipf_auth_pkts,
307 		       softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
308 		softa->ipf_auth_pkts = NULL;
309 	}
310 
311 	faep = &softa->ipf_auth_entries;
312 	while ((fae = *faep) != NULL) {
313 		*faep = fae->fae_next;
314 		KFREE(fae);
315 	}
316 	softa->ipf_auth_ip = NULL;
317 
318 	if (softa->ipf_auth_rules != NULL) {
319 		for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) {
320 			if (fr->fr_ref == 1) {
321 				*frp = fr->fr_next;
322 				MUTEX_DESTROY(&fr->fr_lock);
323 				KFREE(fr);
324 			} else
325 				frp = &fr->fr_next;
326 		}
327 	}
328 
329 	return 0;
330 }
331 
332 
333 /* ------------------------------------------------------------------------ */
334 /* Function:    ipf_auth_soft_destroy                                       */
335 /* Returns:     void                                                        */
336 /* Parameters:  softc(I) - pointer to soft context data                     */
337 /*              arg(I)   - opaque pointer to auth context data              */
338 /*                                                                          */
339 /* Undo what was done in _create() - i.e. free the soft context data.       */
340 /* ------------------------------------------------------------------------ */
341 void
ipf_auth_soft_destroy(ipf_main_softc_t * softc,void * arg)342 ipf_auth_soft_destroy(ipf_main_softc_t *softc, void *arg)
343 {
344 	ipf_auth_softc_t *softa = arg;
345 
346 # if SOLARIS && defined(_KERNEL)
347 	cv_destroy(&softa->ipf_auth_wait);
348 # endif
349 	MUTEX_DESTROY(&softa->ipf_auth_mx);
350 	RW_DESTROY(&softa->ipf_authlk);
351 
352 	KFREE(softa);
353 }
354 
355 
356 /* ------------------------------------------------------------------------ */
357 /* Function:    ipf_auth_setlock                                            */
358 /* Returns:     void                                                        */
359 /* Paramters:   arg(I) - pointer to soft context data                       */
360 /*              tmp(I) - value to assign to auth lock                       */
361 /*                                                                          */
362 /* ------------------------------------------------------------------------ */
363 void
ipf_auth_setlock(void * arg,int tmp)364 ipf_auth_setlock(void *arg, int tmp)
365 {
366 	ipf_auth_softc_t *softa = arg;
367 
368 	softa->ipf_auth_lock = tmp;
369 }
370 
371 
372 /* ------------------------------------------------------------------------ */
373 /* Function:    ipf_auth_check                                              */
374 /* Returns:     frentry_t* - pointer to ipf rule if match found, else NULL  */
375 /* Parameters:  fin(I)   - pointer to ipftoken structure                    */
376 /*              passp(I) - pointer to ipfgeniter structure                  */
377 /*                                                                          */
378 /* Check if a packet has authorization.  If the packet is found to match an */
379 /* authorization result and that would result in a feedback loop (i.e. it   */
380 /* will end up returning FR_AUTH) then return FR_BLOCK instead.             */
381 /* ------------------------------------------------------------------------ */
382 frentry_t *
ipf_auth_check(fr_info_t * fin,u_32_t * passp)383 ipf_auth_check(fr_info_t *fin, u_32_t *passp)
384 {
385 	ipf_main_softc_t *softc = fin->fin_main_soft;
386 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
387 	frentry_t *fr;
388 	frauth_t *fra;
389 	u_32_t pass;
390 	u_short id;
391 	ip_t *ip;
392 	int i;
393 
394 	if (softa->ipf_auth_lock || !softa->ipf_auth_used)
395 		return NULL;
396 
397 	ip = fin->fin_ip;
398 	id = ip->ip_id;
399 
400 	READ_ENTER(&softa->ipf_authlk);
401 	for (i = softa->ipf_auth_start; i != softa->ipf_auth_end; ) {
402 		/*
403 		 * index becomes -2 only after an SIOCAUTHW.  Check this in
404 		 * case the same packet gets sent again and it hasn't yet been
405 		 * auth'd.
406 		 */
407 		fra = softa->ipf_auth + i;
408 		if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) &&
409 		    !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) {
410 			/*
411 			 * Avoid feedback loop.
412 			 */
413 			if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) {
414 				pass = FR_BLOCK;
415 				fin->fin_reason = FRB_AUTHFEEDBACK;
416 			}
417 			/*
418 			 * Create a dummy rule for the stateful checking to
419 			 * use and return.  Zero out any values we don't
420 			 * trust from userland!
421 			 */
422 			if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) &&
423 			     (fin->fin_flx & FI_FRAG))) {
424 				KMALLOC(fr, frentry_t *);
425 				if (fr) {
426 					bcopy((char *)fra->fra_info.fin_fr,
427 					      (char *)fr, sizeof(*fr));
428 					fr->fr_grp = NULL;
429 					fr->fr_ifa = fin->fin_ifp;
430 					fr->fr_func = NULL;
431 					fr->fr_ref = 1;
432 					fr->fr_flags = pass;
433 					fr->fr_ifas[1] = NULL;
434 					fr->fr_ifas[2] = NULL;
435 					fr->fr_ifas[3] = NULL;
436 					MUTEX_INIT(&fr->fr_lock,
437 						   "ipf auth rule");
438 				}
439 			} else
440 				fr = fra->fra_info.fin_fr;
441 			fin->fin_fr = fr;
442 			fin->fin_flx |= fra->fra_flx;
443 			RWLOCK_EXIT(&softa->ipf_authlk);
444 
445 			WRITE_ENTER(&softa->ipf_authlk);
446 			/*
447 			 * ipf_auth_rules is populated with the rules malloc'd
448 			 * above and only those.
449 			 */
450 			if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) {
451 				fr->fr_next = softa->ipf_auth_rules;
452 				softa->ipf_auth_rules = fr;
453 			}
454 			softa->ipf_auth_stats.fas_hits++;
455 			fra->fra_index = -1;
456 			softa->ipf_auth_used--;
457 			softa->ipf_auth_replies--;
458 			if (i == softa->ipf_auth_start) {
459 				while (fra->fra_index == -1) {
460 					i++;
461 					fra++;
462 					if (i == softa->ipf_auth_size) {
463 						i = 0;
464 						fra = softa->ipf_auth;
465 					}
466 					softa->ipf_auth_start = i;
467 					if (i == softa->ipf_auth_end)
468 						break;
469 				}
470 				if (softa->ipf_auth_start ==
471 				    softa->ipf_auth_end) {
472 					softa->ipf_auth_next = 0;
473 					softa->ipf_auth_start = 0;
474 					softa->ipf_auth_end = 0;
475 				}
476 			}
477 			RWLOCK_EXIT(&softa->ipf_authlk);
478 			if (passp != NULL)
479 				*passp = pass;
480 			softa->ipf_auth_stats.fas_hits++;
481 			return fr;
482 		}
483 		i++;
484 		if (i == softa->ipf_auth_size)
485 			i = 0;
486 	}
487 	RWLOCK_EXIT(&softa->ipf_authlk);
488 	softa->ipf_auth_stats.fas_miss++;
489 	return NULL;
490 }
491 
492 
493 /* ------------------------------------------------------------------------ */
494 /* Function:    ipf_auth_new                                                */
495 /* Returns:     int - 1 == success, 0 = did not put packet on auth queue    */
496 /* Parameters:  m(I)   - pointer to mb_t with packet in it                  */
497 /*              fin(I) - pointer to packet information                      */
498 /*                                                                          */
499 /* Check if we have room in the auth array to hold details for another      */
500 /* packet. If we do, store it and wake up any user programs which are       */
501 /* waiting to hear about these events.                                      */
502 /* ------------------------------------------------------------------------ */
503 int
ipf_auth_new(mb_t * m,fr_info_t * fin)504 ipf_auth_new(mb_t *m, fr_info_t *fin)
505 {
506 	ipf_main_softc_t *softc = fin->fin_main_soft;
507 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
508 #if defined(_KERNEL) && defined(MENTAT)
509 	qpktinfo_t *qpi = fin->fin_qpi;
510 #endif
511 	frauth_t *fra;
512 #if !defined(sparc) && !defined(m68k)
513 	ip_t *ip;
514 #endif
515 	int i;
516 
517 	if (softa->ipf_auth_lock)
518 		return 0;
519 
520 	WRITE_ENTER(&softa->ipf_authlk);
521 	if (((softa->ipf_auth_end + 1) % softa->ipf_auth_size) ==
522 	    softa->ipf_auth_start) {
523 		softa->ipf_auth_stats.fas_nospace++;
524 		RWLOCK_EXIT(&softa->ipf_authlk);
525 		return 0;
526 	}
527 
528 	softa->ipf_auth_stats.fas_added++;
529 	softa->ipf_auth_used++;
530 	i = softa->ipf_auth_end++;
531 	if (softa->ipf_auth_end == softa->ipf_auth_size)
532 		softa->ipf_auth_end = 0;
533 
534 	fra = softa->ipf_auth + i;
535 	fra->fra_index = i;
536 	if (fin->fin_fr != NULL)
537 		fra->fra_pass = fin->fin_fr->fr_flags;
538 	else
539 		fra->fra_pass = 0;
540 	fra->fra_age = softa->ipf_auth_defaultage;
541 	bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
542 	fra->fra_flx = fra->fra_info.fin_flx & (FI_STATE|FI_NATED);
543 	fra->fra_info.fin_flx &= ~(FI_STATE|FI_NATED);
544 #if !defined(sparc) && !defined(m68k)
545 	/*
546 	 * No need to copyback here as we want to undo the changes, not keep
547 	 * them.
548 	 */
549 	ip = fin->fin_ip;
550 # if defined(MENTAT) && defined(_KERNEL)
551 	if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4))
552 # endif
553 	{
554 		register u_short bo;
555 
556 		bo = ip->ip_len;
557 		ip->ip_len = htons(bo);
558 		bo = ip->ip_off;
559 		ip->ip_off = htons(bo);
560 	}
561 #endif
562 #if SOLARIS && defined(_KERNEL)
563 	COPYIFNAME(fin->fin_v, fin->fin_ifp, fra->fra_info.fin_ifname);
564 	m->b_rptr -= qpi->qpi_off;
565 	fra->fra_q = qpi->qpi_q;	/* The queue can disappear! */
566 	fra->fra_m = *fin->fin_mp;
567 	fra->fra_info.fin_mp = &fra->fra_m;
568 	softa->ipf_auth_pkts[i] = *(mblk_t **)fin->fin_mp;
569 	RWLOCK_EXIT(&softa->ipf_authlk);
570 	cv_signal(&softa->ipf_auth_wait);
571 	pollwakeup(&softc->ipf_poll_head[IPL_LOGAUTH], POLLIN|POLLRDNORM);
572 #else
573 	softa->ipf_auth_pkts[i] = m;
574 	RWLOCK_EXIT(&softa->ipf_authlk);
575 	WAKEUP(&softa->ipf_auth_next, 0);
576 #endif
577 	return 1;
578 }
579 
580 
581 /* ------------------------------------------------------------------------ */
582 /* Function:    ipf_auth_ioctl                                              */
583 /* Returns:     int - 0 == success, else error                              */
584 /* Parameters:  data(IO) - pointer to ioctl data                            */
585 /*              cmd(I)   - ioctl command                                    */
586 /*              mode(I)  - mode flags associated with open descriptor       */
587 /*              uid(I)   - uid associatd with application making the call   */
588 /*              ctx(I)   - pointer for context                              */
589 /*                                                                          */
590 /* This function handles all of the ioctls recognised by the auth component */
591 /* in IPFilter - ie ioctls called on an open fd for /dev/ipf_auth           */
592 /* ------------------------------------------------------------------------ */
593 int
ipf_auth_ioctl(ipf_main_softc_t * softc,void * data,ioctlcmd_t cmd,int mode,int uid,void * ctx)594 ipf_auth_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode,
595     int uid, void *ctx)
596 {
597 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
598 	int error = 0, i;
599 	SPL_INT(s);
600 
601 	switch (cmd)
602 	{
603 	case SIOCGENITER :
604 	    {
605 		ipftoken_t *token;
606 		ipfgeniter_t iter;
607 		ipfobj_t obj;
608 
609 		error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
610 		if (error != 0)
611 			break;
612 
613 		SPL_SCHED(s);
614 		token = ipf_token_find(softc, IPFGENITER_AUTH, uid, ctx);
615 		if (token != NULL)
616 			error = ipf_auth_geniter(softc, token, &iter, &obj);
617 		else {
618 			WRITE_ENTER(&softc->ipf_tokens);
619 			ipf_token_deref(softc, token);
620 			RWLOCK_EXIT(&softc->ipf_tokens);
621 			IPFERROR(10001);
622 			error = ESRCH;
623 		}
624 		SPL_X(s);
625 
626 		break;
627 	    }
628 
629 	case SIOCADAFR :
630 	case SIOCRMAFR :
631 		if (!(mode & FWRITE)) {
632 			IPFERROR(10002);
633 			error = EPERM;
634 		} else
635 			error = frrequest(softc, IPL_LOGAUTH, cmd, data,
636 					  softc->ipf_active, 1);
637 		break;
638 
639 	case SIOCSTLCK :
640 		if (!(mode & FWRITE)) {
641 			IPFERROR(10003);
642 			error = EPERM;
643 		} else {
644 			error = ipf_lock(data, &softa->ipf_auth_lock);
645 		}
646 		break;
647 
648 	case SIOCATHST:
649 		softa->ipf_auth_stats.fas_faelist = softa->ipf_auth_entries;
650 		error = ipf_outobj(softc, data, &softa->ipf_auth_stats,
651 				   IPFOBJ_AUTHSTAT);
652 		break;
653 
654 	case SIOCIPFFL:
655 		SPL_NET(s);
656 		WRITE_ENTER(&softa->ipf_authlk);
657 		i = ipf_auth_flush(softa);
658 		RWLOCK_EXIT(&softa->ipf_authlk);
659 		SPL_X(s);
660 		error = BCOPYOUT(&i, data, sizeof(i));
661 		if (error != 0) {
662 			IPFERROR(10004);
663 			error = EFAULT;
664 		}
665 		break;
666 
667 	case SIOCAUTHW:
668 		error = ipf_auth_wait(softc, softa, data);
669 		break;
670 
671 	case SIOCAUTHR:
672 		error = ipf_auth_reply(softc, softa, data);
673 		break;
674 
675 	default :
676 		IPFERROR(10005);
677 		error = EINVAL;
678 		break;
679 	}
680 	return error;
681 }
682 
683 
684 /* ------------------------------------------------------------------------ */
685 /* Function:    ipf_auth_expire                                             */
686 /* Returns:     None                                                        */
687 /* Parameters:  None                                                        */
688 /*                                                                          */
689 /* Slowly expire held auth records.  Timeouts are set in expectation of     */
690 /* this being called twice per second.                                      */
691 /* ------------------------------------------------------------------------ */
692 void
ipf_auth_expire(ipf_main_softc_t * softc)693 ipf_auth_expire(ipf_main_softc_t *softc)
694 {
695 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
696 	frauthent_t *fae, **faep;
697 	frentry_t *fr, **frp;
698 	frauth_t *fra;
699 	mb_t *m;
700 	int i;
701 	SPL_INT(s);
702 
703 	if (softa->ipf_auth_lock)
704 		return;
705 	SPL_NET(s);
706 	WRITE_ENTER(&softa->ipf_authlk);
707 	for (i = 0, fra = softa->ipf_auth; i < softa->ipf_auth_size;
708 	     i++, fra++) {
709 		fra->fra_age--;
710 		if ((fra->fra_age == 0) &&
711 		    (softa->ipf_auth[i].fra_index != -1)) {
712 			if ((m = softa->ipf_auth_pkts[i]) != NULL) {
713 				FREE_MB_T(m);
714 				softa->ipf_auth_pkts[i] = NULL;
715 			} else if (softa->ipf_auth[i].fra_index == -2) {
716 				softa->ipf_auth_replies--;
717 			}
718 			softa->ipf_auth[i].fra_index = -1;
719 			softa->ipf_auth_stats.fas_expire++;
720 			softa->ipf_auth_used--;
721 		}
722 	}
723 
724 	/*
725 	 * Expire pre-auth rules
726 	 */
727 	for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) {
728 		fae->fae_age--;
729 		if (fae->fae_age == 0) {
730 			ipf_auth_deref(&fae);
731 			softa->ipf_auth_stats.fas_expire++;
732 		} else
733 			faep = &fae->fae_next;
734 	}
735 	if (softa->ipf_auth_entries != NULL)
736 		softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr;
737 	else
738 		softa->ipf_auth_ip = NULL;
739 
740 	for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) {
741 		if (fr->fr_ref == 1) {
742 			*frp = fr->fr_next;
743 			MUTEX_DESTROY(&fr->fr_lock);
744 			KFREE(fr);
745 		} else
746 			frp = &fr->fr_next;
747 	}
748 	RWLOCK_EXIT(&softa->ipf_authlk);
749 	SPL_X(s);
750 }
751 
752 
753 /* ------------------------------------------------------------------------ */
754 /* Function:    ipf_auth_precmd                                             */
755 /* Returns:     int - 0 == success, else error                              */
756 /* Parameters:  cmd(I)  - ioctl command for rule                            */
757 /*              fr(I)   - pointer to ipf rule                               */
758 /*              fptr(I) - pointer to caller's 'fr'                          */
759 /*                                                                          */
760 /* ------------------------------------------------------------------------ */
761 int
ipf_auth_precmd(ipf_main_softc_t * softc,ioctlcmd_t cmd,frentry_t * fr,frentry_t ** frptr)762 ipf_auth_precmd(ipf_main_softc_t *softc, ioctlcmd_t cmd, frentry_t *fr,
763     frentry_t **frptr)
764 {
765 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
766 	frauthent_t *fae, **faep;
767 	int error = 0;
768 	SPL_INT(s);
769 
770 	if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) {
771 		IPFERROR(10006);
772 		return EIO;
773 	}
774 
775 	for (faep = &softa->ipf_auth_entries; ((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 			IPFERROR(10007);
785 			error = EINVAL;
786 
787 		} else if (fae == NULL) {
788 			IPFERROR(10008);
789 			error = ESRCH;
790 
791 		} else {
792 			SPL_NET(s);
793 			WRITE_ENTER(&softa->ipf_authlk);
794 			*faep = fae->fae_next;
795 			if (softa->ipf_auth_ip == &fae->fae_fr)
796 				softa->ipf_auth_ip = softa->ipf_auth_entries ?
797 				    &softa->ipf_auth_entries->fae_fr : NULL;
798 			RWLOCK_EXIT(&softa->ipf_authlk);
799 			SPL_X(s);
800 
801 			KFREE(fae);
802 		}
803 	} else if (fr != NULL && frptr != NULL) {
804 		KMALLOC(fae, frauthent_t *);
805 		if (fae != NULL) {
806 			bcopy((char *)fr, (char *)&fae->fae_fr,
807 			      sizeof(*fr));
808 			SPL_NET(s);
809 			WRITE_ENTER(&softa->ipf_authlk);
810 			fae->fae_age = softa->ipf_auth_defaultage;
811 			fae->fae_fr.fr_hits = 0;
812 			fae->fae_fr.fr_next = *frptr;
813 			fae->fae_ref = 1;
814 			*frptr = &fae->fae_fr;
815 			fae->fae_next = *faep;
816 			*faep = fae;
817 			softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr;
818 			RWLOCK_EXIT(&softa->ipf_authlk);
819 			SPL_X(s);
820 		} else {
821 			IPFERROR(10009);
822 			error = ENOMEM;
823 		}
824 	} else {
825 		IPFERROR(10010);
826 		error = EINVAL;
827 	}
828 	return error;
829 }
830 
831 
832 /* ------------------------------------------------------------------------ */
833 /* Function:    ipf_auth_flush                                              */
834 /* Returns:     int - number of auth entries flushed                        */
835 /* Parameters:  None                                                        */
836 /* Locks:       WRITE(ipf_authlk)                                           */
837 /*                                                                          */
838 /* This function flushs the ipf_auth_pkts array of any packet data with     */
839 /* references still there.                                                  */
840 /* It is expected that the caller has already acquired the correct locks or */
841 /* set the priority level correctly for this to block out other code paths  */
842 /* into these data structures.                                              */
843 /* ------------------------------------------------------------------------ */
844 static int
ipf_auth_flush(void * arg)845 ipf_auth_flush(void *arg)
846 {
847 	ipf_auth_softc_t *softa = arg;
848 	int i, num_flushed;
849 	mb_t *m;
850 
851 	if (softa->ipf_auth_lock)
852 		return -1;
853 
854 	num_flushed = 0;
855 
856 	for (i = 0 ; i < softa->ipf_auth_size; i++) {
857 		if (softa->ipf_auth[i].fra_index != -1) {
858 			m = softa->ipf_auth_pkts[i];
859 			if (m != NULL) {
860 				FREE_MB_T(m);
861 				softa->ipf_auth_pkts[i] = NULL;
862 			}
863 
864 			softa->ipf_auth[i].fra_index = -1;
865 			/* perhaps add & use a flush counter inst.*/
866 			softa->ipf_auth_stats.fas_expire++;
867 			num_flushed++;
868 		}
869 	}
870 
871 	softa->ipf_auth_start = 0;
872 	softa->ipf_auth_end = 0;
873 	softa->ipf_auth_next = 0;
874 	softa->ipf_auth_used = 0;
875 	softa->ipf_auth_replies = 0;
876 
877 	return num_flushed;
878 }
879 
880 
881 /* ------------------------------------------------------------------------ */
882 /* Function:    ipf_auth_waiting                                            */
883 /* Returns:     int - number of packets in the auth queue                   */
884 /* Parameters:  None                                                        */
885 /*                                                                          */
886 /* Simple truth check to see if there are any packets waiting in the auth   */
887 /* queue.                                                                   */
888 /* ------------------------------------------------------------------------ */
889 int
ipf_auth_waiting(ipf_main_softc_t * softc)890 ipf_auth_waiting(ipf_main_softc_t *softc)
891 {
892 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
893 
894 	return (softa->ipf_auth_used != 0);
895 }
896 
897 
898 /* ------------------------------------------------------------------------ */
899 /* Function:    ipf_auth_geniter                                            */
900 /* Returns:     int - 0 == success, else error                              */
901 /* Parameters:  token(I) - pointer to ipftoken structure                    */
902 /*              itp(I)   - pointer to ipfgeniter structure                  */
903 /*              objp(I)  - pointer to ipf object destription                */
904 /*                                                                          */
905 /* Iterate through the list of entries in the auth queue list.              */
906 /* objp is used here to get the location of where to do the copy out to.    */
907 /* Stomping over various fields with new information will not harm anything */
908 /* ------------------------------------------------------------------------ */
909 static int
ipf_auth_geniter(ipf_main_softc_t * softc,ipftoken_t * token,ipfgeniter_t * itp,ipfobj_t * objp)910 ipf_auth_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp,
911     ipfobj_t *objp)
912 {
913 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
914 	frauthent_t *fae, *next, zero;
915 	int error;
916 
917 	if (itp->igi_data == NULL) {
918 		IPFERROR(10011);
919 		return EFAULT;
920 	}
921 
922 	if (itp->igi_type != IPFGENITER_AUTH) {
923 		IPFERROR(10012);
924 		return EINVAL;
925 	}
926 
927 	objp->ipfo_type = IPFOBJ_FRAUTH;
928 	objp->ipfo_ptr = itp->igi_data;
929 	objp->ipfo_size = sizeof(frauth_t);
930 
931 	READ_ENTER(&softa->ipf_authlk);
932 
933 	fae = token->ipt_data;
934 	if (fae == NULL) {
935 		next = softa->ipf_auth_entries;
936 	} else {
937 		next = fae->fae_next;
938 	}
939 
940 	/*
941 	 * If we found an auth entry to use, bump its reference count
942 	 * so that it can be used for is_next when we come back.
943 	 */
944 	if (next != NULL) {
945 		ATOMIC_INC(next->fae_ref);
946 		token->ipt_data = next;
947 	} else {
948 		bzero(&zero, sizeof(zero));
949 		next = &zero;
950 		token->ipt_data = NULL;
951 	}
952 
953 	RWLOCK_EXIT(&softa->ipf_authlk);
954 
955 	error = ipf_outobjk(softc, objp, next);
956 	if (fae != NULL)
957 		ipf_auth_deref_unlocked(softa, &fae);
958 
959 	if (next->fae_next == NULL)
960 		ipf_token_mark_complete(token);
961 	return error;
962 }
963 
964 
965 /* ------------------------------------------------------------------------ */
966 /* Function:    ipf_auth_deref_unlocked                                     */
967 /* Returns:     None                                                        */
968 /* Parameters:  faep(IO) - pointer to caller's frauthent_t pointer          */
969 /*                                                                          */
970 /* Wrapper for ipf_auth_deref for when a write lock on ipf_authlk is not    */
971 /* held.                                                                    */
972 /* ------------------------------------------------------------------------ */
973 static void
ipf_auth_deref_unlocked(ipf_auth_softc_t * softa,frauthent_t ** faep)974 ipf_auth_deref_unlocked(ipf_auth_softc_t *softa, frauthent_t **faep)
975 {
976 	WRITE_ENTER(&softa->ipf_authlk);
977 	ipf_auth_deref(faep);
978 	RWLOCK_EXIT(&softa->ipf_authlk);
979 }
980 
981 
982 /* ------------------------------------------------------------------------ */
983 /* Function:    ipf_auth_deref                                              */
984 /* Returns:     None                                                        */
985 /* Parameters:  faep(IO) - pointer to caller's frauthent_t pointer          */
986 /* Locks:       WRITE(ipf_authlk)                                           */
987 /*                                                                          */
988 /* This function unconditionally sets the pointer in the caller to NULL,    */
989 /* to make it clear that it should no longer use that pointer, and drops    */
990 /* the reference count on the structure by 1.  If it reaches 0, free it up. */
991 /* ------------------------------------------------------------------------ */
992 static void
ipf_auth_deref(frauthent_t ** faep)993 ipf_auth_deref(frauthent_t **faep)
994 {
995 	frauthent_t *fae;
996 
997 	fae = *faep;
998 	*faep = NULL;
999 
1000 	fae->fae_ref--;
1001 	if (fae->fae_ref == 0) {
1002 		KFREE(fae);
1003 	}
1004 }
1005 
1006 
1007 /* ------------------------------------------------------------------------ */
1008 /* Function:    ipf_auth_wait_pkt                                           */
1009 /* Returns:     int - 0 == success, else error                              */
1010 /* Parameters:  data(I) - pointer to data from ioctl call                   */
1011 /*                                                                          */
1012 /* This function is called when an application is waiting for a packet to   */
1013 /* match an "auth" rule by issuing an SIOCAUTHW ioctl.  If there is already */
1014 /* a packet waiting on the queue then we will return that _one_ immediately.*/
1015 /* If there are no packets present in the queue (ipf_auth_pkts) then we go  */
1016 /* to sleep.                                                                */
1017 /* ------------------------------------------------------------------------ */
1018 static int
ipf_auth_wait(ipf_main_softc_t * softc,ipf_auth_softc_t * softa,char * data)1019 ipf_auth_wait(ipf_main_softc_t *softc, ipf_auth_softc_t *softa, char *data)
1020 {
1021 	frauth_t auth, *au = &auth;
1022 	int error, len, i;
1023 	mb_t *m;
1024 	char *t;
1025 	SPL_INT(s);
1026 
1027 ipf_auth_ioctlloop:
1028 	error = ipf_inobj(softc, data, NULL, au, IPFOBJ_FRAUTH);
1029 	if (error != 0)
1030 		return error;
1031 
1032 	/*
1033 	 * XXX Locks are held below over calls to copyout...a better
1034 	 * solution needs to be found so this isn't necessary.  The situation
1035 	 * we are trying to guard against here is an error in the copyout
1036 	 * steps should not cause the packet to "disappear" from the queue.
1037 	 */
1038 	SPL_NET(s);
1039 	READ_ENTER(&softa->ipf_authlk);
1040 
1041 	/*
1042 	 * If ipf_auth_next is not equal to ipf_auth_end it will be because
1043 	 * there is a packet waiting to be delt with in the ipf_auth_pkts
1044 	 * array.  We copy as much of that out to user space as requested.
1045 	 */
1046 	if (softa->ipf_auth_used > 0) {
1047 		while (softa->ipf_auth_pkts[softa->ipf_auth_next] == NULL) {
1048 			softa->ipf_auth_next++;
1049 			if (softa->ipf_auth_next == softa->ipf_auth_size)
1050 				softa->ipf_auth_next = 0;
1051 		}
1052 
1053 		error = ipf_outobj(softc, data,
1054 				   &softa->ipf_auth[softa->ipf_auth_next],
1055 				   IPFOBJ_FRAUTH);
1056 		if (error != 0) {
1057 			RWLOCK_EXIT(&softa->ipf_authlk);
1058 			SPL_X(s);
1059 			return error;
1060 		}
1061 
1062 		if (auth.fra_len != 0 && auth.fra_buf != NULL) {
1063 			/*
1064 			 * Copy packet contents out to user space if
1065 			 * requested.  Bail on an error.
1066 			 */
1067 			m = softa->ipf_auth_pkts[softa->ipf_auth_next];
1068 			len = MSGDSIZE(m);
1069 			if (len > auth.fra_len)
1070 				len = auth.fra_len;
1071 			auth.fra_len = len;
1072 
1073 			for (t = auth.fra_buf; m && (len > 0); ) {
1074 				i = MIN(M_LEN(m), len);
1075 				error = copyoutptr(softc, MTOD(m, char *),
1076 						   &t, i);
1077 				len -= i;
1078 				t += i;
1079 				if (error != 0) {
1080 					RWLOCK_EXIT(&softa->ipf_authlk);
1081 					SPL_X(s);
1082 					return error;
1083 				}
1084 				m = m->m_next;
1085 			}
1086 		}
1087 		RWLOCK_EXIT(&softa->ipf_authlk);
1088 
1089 		SPL_NET(s);
1090 		WRITE_ENTER(&softa->ipf_authlk);
1091 		softa->ipf_auth_next++;
1092 		if (softa->ipf_auth_next == softa->ipf_auth_size)
1093 			softa->ipf_auth_next = 0;
1094 		RWLOCK_EXIT(&softa->ipf_authlk);
1095 		SPL_X(s);
1096 
1097 		return 0;
1098 	}
1099 	RWLOCK_EXIT(&softa->ipf_authlk);
1100 	SPL_X(s);
1101 
1102 	MUTEX_ENTER(&softa->ipf_auth_mx);
1103 #ifdef	_KERNEL
1104 # if	SOLARIS
1105 	error = 0;
1106 	if (!cv_wait_sig(&softa->ipf_auth_wait, &softa->ipf_auth_mx.ipf_lk)) {
1107 		IPFERROR(10014);
1108 		error = EINTR;
1109 	}
1110 # else /* SOLARIS */
1111 #  ifdef __hpux
1112 	{
1113 	lock_t *l;
1114 
1115 	l = get_sleep_lock(&softa->ipf_auth_next);
1116 	error = sleep(&softa->ipf_auth_next, PZERO+1);
1117 	spinunlock(l);
1118 	}
1119 #  else
1120 #   ifdef __osf__
1121 	error = mpsleep(&softa->ipf_auth_next, PSUSP|PCATCH, "ipf_auth_next",
1122 			0, &softa->ipf_auth_mx, MS_LOCK_SIMPLE);
1123 #   else
1124 	error = SLEEP(&softa->ipf_auth_next, "ipf_auth_next");
1125 #   endif /* __osf__ */
1126 #  endif /* __hpux */
1127 # endif /* SOLARIS */
1128 #endif
1129 	MUTEX_EXIT(&softa->ipf_auth_mx);
1130 	if (error == 0)
1131 		goto ipf_auth_ioctlloop;
1132 	return error;
1133 }
1134 
1135 
1136 /* ------------------------------------------------------------------------ */
1137 /* Function:    ipf_auth_reply                                              */
1138 /* Returns:     int - 0 == success, else error                              */
1139 /* Parameters:  data(I) - pointer to data from ioctl call                   */
1140 /*                                                                          */
1141 /* This function is called by an application when it wants to return a      */
1142 /* decision on a packet using the SIOCAUTHR ioctl.  This is after it has    */
1143 /* received information using an SIOCAUTHW.  The decision returned in the   */
1144 /* form of flags, the same as those used in each rule.                      */
1145 /* ------------------------------------------------------------------------ */
1146 static int
ipf_auth_reply(ipf_main_softc_t * softc,ipf_auth_softc_t * softa,char * data)1147 ipf_auth_reply(ipf_main_softc_t *softc, ipf_auth_softc_t *softa, char *data)
1148 {
1149 	frauth_t auth, *au = &auth, *fra;
1150 	fr_info_t fin;
1151 	int error, i;
1152 #ifdef _KERNEL
1153 	mb_t *m;
1154 #endif
1155 	SPL_INT(s);
1156 
1157 	error = ipf_inobj(softc, data, NULL, &auth, IPFOBJ_FRAUTH);
1158 	if (error != 0)
1159 		return error;
1160 
1161 	SPL_NET(s);
1162 	WRITE_ENTER(&softa->ipf_authlk);
1163 
1164 	i = au->fra_index;
1165 	fra = softa->ipf_auth + i;
1166 	error = 0;
1167 
1168 	/*
1169 	 * Check the validity of the information being returned with two simple
1170 	 * checks.  First, the auth index value should be within the size of
1171 	 * the array and second the packet id being returned should also match.
1172 	 */
1173 	if ((i < 0) || (i >= softa->ipf_auth_size)) {
1174 		RWLOCK_EXIT(&softa->ipf_authlk);
1175 		SPL_X(s);
1176 		IPFERROR(10015);
1177 		return ESRCH;
1178 	}
1179 	if  (fra->fra_info.fin_id != au->fra_info.fin_id) {
1180 		RWLOCK_EXIT(&softa->ipf_authlk);
1181 		SPL_X(s);
1182 		IPFERROR(10019);
1183 		return ESRCH;
1184 	}
1185 
1186 	fra->fra_index = -2;
1187 	fra->fra_pass = au->fra_pass;
1188 #ifdef	_KERNEL
1189 	m = softa->ipf_auth_pkts[i];
1190 #endif
1191 	softa->ipf_auth_pkts[i] = NULL;
1192 	softa->ipf_auth_replies++;
1193 	bcopy(&fra->fra_info, &fin, sizeof(fin));
1194 
1195 	RWLOCK_EXIT(&softa->ipf_authlk);
1196 
1197 	/*
1198 	 * Re-insert the packet back into the packet stream flowing through
1199 	 * the kernel in a manner that will mean IPFilter sees the packet
1200 	 * again.  This is not the same as is done with fastroute,
1201 	 * deliberately, as we want to resume the normal packet processing
1202 	 * path for it.
1203 	 */
1204 #ifdef	_KERNEL
1205 	if ((m != NULL) && (au->fra_info.fin_out != 0)) {
1206 		error = ipf_inject(&fin, m);
1207 		if (error != 0) {
1208 			IPFERROR(10016);
1209 			error = ENOBUFS;
1210 			softa->ipf_auth_stats.fas_sendfail++;
1211 		} else {
1212 			softa->ipf_auth_stats.fas_sendok++;
1213 		}
1214 	} else if (m) {
1215 		error = ipf_inject(&fin, m);
1216 		if (error != 0) {
1217 			IPFERROR(10017);
1218 			error = ENOBUFS;
1219 			softa->ipf_auth_stats.fas_quefail++;
1220 		} else {
1221 			softa->ipf_auth_stats.fas_queok++;
1222 		}
1223 	} else {
1224 		IPFERROR(10018);
1225 		error = EINVAL;
1226 	}
1227 
1228 	/*
1229 	 * If we experience an error which will result in the packet
1230 	 * not being processed, make sure we advance to the next one.
1231 	 */
1232 	if (error == ENOBUFS) {
1233 		WRITE_ENTER(&softa->ipf_authlk);
1234 		softa->ipf_auth_used--;
1235 		fra->fra_index = -1;
1236 		fra->fra_pass = 0;
1237 		if (i == softa->ipf_auth_start) {
1238 			while (fra->fra_index == -1) {
1239 				i++;
1240 				if (i == softa->ipf_auth_size)
1241 					i = 0;
1242 				softa->ipf_auth_start = i;
1243 				if (i == softa->ipf_auth_end)
1244 					break;
1245 			}
1246 			if (softa->ipf_auth_start == softa->ipf_auth_end) {
1247 				softa->ipf_auth_next = 0;
1248 				softa->ipf_auth_start = 0;
1249 				softa->ipf_auth_end = 0;
1250 			}
1251 		}
1252 		RWLOCK_EXIT(&softa->ipf_authlk);
1253 	}
1254 #endif /* _KERNEL */
1255 	SPL_X(s);
1256 
1257 	return 0;
1258 }
1259 
1260 
1261 u_32_t
ipf_auth_pre_scanlist(ipf_main_softc_t * softc,fr_info_t * fin,u_32_t pass)1262 ipf_auth_pre_scanlist(ipf_main_softc_t *softc, fr_info_t *fin, u_32_t pass)
1263 {
1264 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
1265 
1266 	if (softa->ipf_auth_ip != NULL)
1267 		return ipf_scanlist(fin, softc->ipf_pass);
1268 
1269 	return pass;
1270 }
1271 
1272 
1273 frentry_t **
ipf_auth_rulehead(ipf_main_softc_t * softc)1274 ipf_auth_rulehead(ipf_main_softc_t *softc)
1275 {
1276 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
1277 
1278 	return &softa->ipf_auth_ip;
1279 }
1280