int afmioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag, struct lwp *l) { int error = 0; struct atm_flowmap *flowmap; struct ifnet *ifp; /* check cmd for superuser only */ switch (cmd) { case AFM_GETFMAP: break; default: #if (__FreeBSD_version > 400000) error = suser(p); #else error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_AFMAP, NULL, NULL, NULL); #endif if (error) return (error); break; } /* lookup interface */ flowmap = (struct atm_flowmap *)addr; flowmap->af_ifname[IFNAMSIZ-1] = '\0'; ifp = ifunit(flowmap->af_ifname); if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) error = ENXIO; else error = ifp->if_ioctl(ifp, cmd, addr); return error; }
int altqioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag, struct lwp *l) { int unit = minor(dev); if (unit == 0) { struct ifnet *ifp; struct altqreq *typereq; struct tbrreq *tbrreq; int error; switch (cmd) { case ALTQGTYPE: case ALTQTBRGET: break; default: #if (__FreeBSD_version > 400000) if ((error = suser(p)) != 0) return (error); #else if ((error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_CONF, NULL, NULL, NULL)) != 0) return (error); #endif break; } switch (cmd) { case ALTQGTYPE: typereq = (struct altqreq *)addr; if ((ifp = ifunit(typereq->ifname)) == NULL) return (EINVAL); typereq->arg = (u_long)ifp->if_snd.altq_type; return (0); case ALTQTBRSET: tbrreq = (struct tbrreq *)addr; if ((ifp = ifunit(tbrreq->ifname)) == NULL) return (EINVAL); return tbr_set(&ifp->if_snd, &tbrreq->tb_prof); case ALTQTBRGET: tbrreq = (struct tbrreq *)addr; if ((ifp = ifunit(tbrreq->ifname)) == NULL) return (EINVAL); return tbr_get(&ifp->if_snd, &tbrreq->tb_prof); default: return (EINVAL); } } if (unit < naltqsw) return (*altqsw[unit].d_ioctl)(dev, cmd, addr, flag, l); return ENXIO; }
static int npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) { /* Available only for super-user. */ if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { return EPERM; } return 0; }
static int npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) { int error; /* Available only for super-user. */ if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { return EPERM; } switch (cmd) { case IOC_NPF_TABLE: error = npfctl_table(data); break; case IOC_NPF_RULE: error = npfctl_rule(cmd, data); break; case IOC_NPF_GETCONF: error = npfctl_getconf(cmd, data); break; case IOC_NPF_STATS: error = npfctl_stats(data); break; case IOC_NPF_SESSIONS_SAVE: error = npfctl_sessions_save(cmd, data); break; case IOC_NPF_SESSIONS_LOAD: error = npfctl_sessions_load(cmd, data); break; case IOC_NPF_SWITCH: error = npfctl_switch(data); break; case IOC_NPF_RELOAD: error = npfctl_reload(cmd, data); break; case IOC_NPF_VERSION: *(int *)data = NPF_VERSION; error = 0; break; default: error = ENOTTY; break; } return error; }
/* * tunnel open - must be superuser & the device must be * configured in */ static int tunopen(dev_t dev, int flag, int mode, struct lwp *l) { struct ifnet *ifp; struct tun_softc *tp; int s, error; error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE_TUN, KAUTH_REQ_NETWORK_INTERFACE_TUN_ADD, NULL, NULL, NULL); if (error) return (error); s = splnet(); tp = tun_find_unit(dev); if (tp == NULL) { (void)tun_clone_create(&tun_cloner, minor(dev)); tp = tun_find_unit(dev); if (tp == NULL) { error = ENXIO; goto out_nolock; } } if (tp->tun_flags & TUN_OPEN) { error = EBUSY; goto out; } ifp = &tp->tun_if; tp->tun_flags |= TUN_OPEN; TUNDEBUG("%s: open\n", ifp->if_xname); out: mutex_exit(&tp->tun_lock); out_nolock: splx(s); return (error); }
int cbqioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag, struct lwp *l) { int error = 0; /* check cmd for superuser only */ switch (cmd) { case CBQ_GETSTATS: /* currently only command that an ordinary user can call */ break; default: #if (__FreeBSD_version > 400000) error = suser(p); #else error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_CBQ, NULL, NULL, NULL); #endif if (error) return (error); break; } switch (cmd) { case CBQ_ENABLE: error = cbq_set_enable((struct cbq_interface *)addr, ENABLE); break; case CBQ_DISABLE: error = cbq_set_enable((struct cbq_interface *)addr, DISABLE); break; case CBQ_ADD_FILTER: error = cbq_add_filter((struct cbq_add_filter *)addr); break; case CBQ_DEL_FILTER: error = cbq_delete_filter((struct cbq_delete_filter *)addr); break; case CBQ_ADD_CLASS: error = cbq_add_class((struct cbq_add_class *)addr); break; case CBQ_DEL_CLASS: error = cbq_delete_class((struct cbq_delete_class *)addr); break; case CBQ_MODIFY_CLASS: error = cbq_modify_class((struct cbq_modify_class *)addr); break; case CBQ_CLEAR_HIERARCHY: error = cbq_clear_hierarchy((struct cbq_interface *)addr); break; case CBQ_IF_ATTACH: error = cbq_ifattach((struct cbq_interface *)addr); break; case CBQ_IF_DETACH: error = cbq_ifdetach((struct cbq_interface *)addr); break; case CBQ_GETSTATS: error = cbq_getstats((struct cbq_getstats *)addr); break; default: error = EINVAL; break; } return error; }
/* * Bind port from sin6 to in6p. */ static int in6_pcbbind_port(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l) { struct inpcbtable *table = in6p->in6p_table; struct socket *so = in6p->in6p_socket; int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); int error; if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || (so->so_options & SO_ACCEPTCONN) == 0)) wild = 1; if (sin6->sin6_port != 0) { enum kauth_network_req req; #ifndef IPNOPRIVPORTS if (ntohs(sin6->sin6_port) < IPV6PORT_RESERVED) req = KAUTH_REQ_NETWORK_BIND_PRIVPORT; else #endif /* IPNOPRIVPORTS */ req = KAUTH_REQ_NETWORK_BIND_PORT; error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_BIND, req, so, sin6, NULL); if (error) return (EACCES); } if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { /* * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; * allow compepte duplication of binding if * SO_REUSEPORT is set, or if SO_REUSEADDR is set * and a multicast address is bound on both * new and duplicated sockets. */ if (so->so_options & SO_REUSEADDR) reuseport = SO_REUSEADDR|SO_REUSEPORT; } if (sin6->sin6_port != 0) { if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { #ifdef INET struct inpcb *t; struct vestigial_inpcb vestige; t = in_pcblookup_port(table, *(struct in_addr *)&sin6->sin6_addr.s6_addr32[3], sin6->sin6_port, wild, &vestige); if (t && (reuseport & t->inp_socket->so_options) == 0) return (EADDRINUSE); if (!t && vestige.valid && !(reuseport && vestige.reuse_port)) return EADDRINUSE; #else return (EADDRNOTAVAIL); #endif } { struct in6pcb *t; struct vestigial_inpcb vestige; t = in6_pcblookup_port(table, &sin6->sin6_addr, sin6->sin6_port, wild, &vestige); if (t && (reuseport & t->in6p_socket->so_options) == 0) return (EADDRINUSE); if (!t && vestige.valid && !(reuseport && vestige.reuse_port)) return EADDRINUSE; } } if (sin6->sin6_port == 0) { int e; e = in6_pcbsetport(sin6, in6p, l); if (e != 0) return (e); } else { in6p->in6p_lport = sin6->sin6_port; in6_pcbstate(in6p, IN6P_BOUND); } LIST_REMOVE(&in6p->in6p_head, inph_lhash); LIST_INSERT_HEAD(IN6PCBHASH_PORT(table, in6p->in6p_lport), &in6p->in6p_head, inph_lhash); return (0); }
/* * Check whether the port picked by the port randomizer is available * and whether KAUTH approves of our choice. This part of the code * shamelessly copied from in_pcb.c. */ static bool check_suitable_port(uint16_t port, struct inpcb_hdr *inp_hdr, kauth_cred_t cred) { struct inpcbtable * const table = inp_hdr->inph_table; #ifdef INET vestigial_inpcb_t vestigial; #endif int error; #ifdef INET6 struct socket *so; int wild = 0; #endif DPRINTF("%s called for argument %d\n", __func__, port); switch (inp_hdr->inph_af) { #ifdef INET case AF_INET: { /* IPv4 */ struct inpcb *inp = (struct inpcb *)(void *)inp_hdr; struct inpcb *pcb; struct sockaddr_in sin; if (__BITMAP_ISSET(port, &inet4_reserve)) return false; sin.sin_addr = inp->inp_laddr; pcb = in_pcblookup_port(table, sin.sin_addr, htons(port), 1, &vestigial); DPRINTF("%s in_pcblookup_port returned %p and " "vestigial.valid %d\n", __func__, pcb, vestigial.valid); if ((!pcb) && (!vestigial.valid)) { enum kauth_network_req req; /* We have a free port. Check with the secmodel. */ if (inp->inp_flags & INP_LOWPORT) { #ifndef IPNOPRIVPORTS req = KAUTH_REQ_NETWORK_BIND_PRIVPORT; #else req = KAUTH_REQ_NETWORK_BIND_PORT; #endif } else req = KAUTH_REQ_NETWORK_BIND_PORT; sin.sin_port = port; error = kauth_authorize_network(cred, KAUTH_NETWORK_BIND, req, inp->inp_socket, &sin, NULL); DPRINTF("%s kauth_authorize_network returned %d\n", __func__, error); if (error == 0) { DPRINTF("%s port approved\n", __func__); return true; /* KAUTH agrees */ } } break; } #endif #ifdef INET6 case AF_INET6: { /* IPv6 */ struct in6pcb *in6p = (struct in6pcb *)(void *)inp_hdr; struct sockaddr_in6 sin6; void *t; if (__BITMAP_ISSET(port, &inet6_reserve)) return false; sin6.sin6_addr = in6p->in6p_laddr; so = in6p->in6p_socket; /* XXX: this is redundant when called from in6_pcbbind */ if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || (so->so_options & SO_ACCEPTCONN) == 0)) wild = 1; #ifdef INET if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) { t = in_pcblookup_port(table, *(struct in_addr *)&sin6.sin6_addr.s6_addr32[3], htons(port), wild, &vestigial); if (!t && vestigial.valid) { DPRINTF("%s in_pcblookup_port returned " "a result\n", __func__); return false; } } else #endif { t = in6_pcblookup_port(table, &sin6.sin6_addr, htons(port), wild, &vestigial); if (!t && vestigial.valid) { DPRINTF("%s in6_pcblookup_port returned " "a result\n", __func__); return false; } } if (t == NULL) { enum kauth_network_req req; /* We have a free port. Check with the secmodel. */ if (in6p->in6p_flags & IN6P_LOWPORT) { #ifndef IPNOPRIVPORTS req = KAUTH_REQ_NETWORK_BIND_PRIVPORT; #else req = KAUTH_REQ_NETWORK_BIND_PORT; #endif } else { req = KAUTH_REQ_NETWORK_BIND_PORT; } sin6.sin6_port = port; error = kauth_authorize_network(cred, KAUTH_NETWORK_BIND, req, so, &sin6, NULL); if (error) { /* Secmodel says no. Keep looking. */ DPRINTF("%s secmodel says no\n", __func__); return false; } DPRINTF("%s port approved\n", __func__); return true; } break; } #endif default: DPRINTF("%s unknown address family\n", __func__); return false; } return false; }