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